From 12399ffc797e6b69f5ca2ba15134a09dff025318 Mon Sep 17 00:00:00 2001
From: Ruby Loo <ruby.loo@intel.com>
Date: Thu, 21 Sep 2017 10:11:53 -0400
Subject: [PATCH] Remove 'next' for GET /nodes?limit=1&instance_uuid=

For a "GET /nodes?limit=1&instance_uuid=<uuid>" request that has a
node that matches, the response would include a 'next' link.
(Note that the generated 'next' link happens to be incorrect; it
doesn't include 'instance_uuid'). However, at most one node can match
the specified instance UUID, so we should not be returning any 'next'
link.

This fixes it so no 'next' link is returned.

Change-Id: I4efe06652baf3423790c238d4a8d2bc5a736b3a5
Closes-Bug: #1718683
---
 ironic/api/controllers/v1/node.py             | 23 +++++++++++++++----
 .../unit/api/controllers/v1/test_node.py      | 16 +++++++++++++
 ...nk-for-instance-uuid-f46eafe5b575f3de.yaml |  8 +++++++
 3 files changed, 42 insertions(+), 5 deletions(-)
 create mode 100644 releasenotes/notes/next-link-for-instance-uuid-f46eafe5b575f3de.yaml

diff --git a/ironic/api/controllers/v1/node.py b/ironic/api/controllers/v1/node.py
index d3106f4153..775d4aeece 100644
--- a/ironic/api/controllers/v1/node.py
+++ b/ironic/api/controllers/v1/node.py
@@ -1310,8 +1310,20 @@ class NodesController(rest.RestController):
                 _("The sort_key value %(key)s is an invalid field for "
                   "sorting") % {'key': sort_key})
 
+        # The query parameters for the 'next' URL
+        parameters = {}
+
         if instance_uuid:
+            # NOTE(rloo) if instance_uuid is specified, the other query
+            # parameters are ignored. Since there can be at most one node that
+            # has this instance_uuid, we do not want to generate a 'next' link.
+
             nodes = self._get_nodes_by_instance(instance_uuid)
+
+            # NOTE(rloo) if limit==1 and len(nodes)==1 (see
+            # Collection.has_next()), a 'next' link will
+            # be generated, which we don't want.
+            limit = 0
         else:
             filters = {}
             if chassis_uuid:
@@ -1331,11 +1343,12 @@ class NodesController(rest.RestController):
                                       sort_key=sort_key, sort_dir=sort_dir,
                                       filters=filters)
 
-        parameters = {'sort_key': sort_key, 'sort_dir': sort_dir}
-        if associated:
-            parameters['associated'] = associated
-        if maintenance:
-            parameters['maintenance'] = maintenance
+            parameters = {'sort_key': sort_key, 'sort_dir': sort_dir}
+            if associated:
+                parameters['associated'] = associated
+            if maintenance:
+                parameters['maintenance'] = maintenance
+
         return NodeCollection.convert_with_links(nodes, limit,
                                                  url=resource_url,
                                                  fields=fields,
diff --git a/ironic/tests/unit/api/controllers/v1/test_node.py b/ironic/tests/unit/api/controllers/v1/test_node.py
index 84d6c1c4f0..3346b0431d 100644
--- a/ironic/tests/unit/api/controllers/v1/test_node.py
+++ b/ironic/tests/unit/api/controllers/v1/test_node.py
@@ -533,6 +533,22 @@ class TestListNodes(test_api_base.BaseApiTest):
         next_marker = data['nodes'][-1]['uuid']
         self.assertIn(next_marker, data['next'])
 
+    def test_collection_links_instance_uuid_param(self):
+        cfg.CONF.set_override('max_limit', 1, 'api')
+        nodes = []
+        for id in range(2):
+            node = obj_utils.create_test_node(
+                self.context,
+                uuid=uuidutils.generate_uuid(),
+                instance_uuid=uuidutils.generate_uuid(),
+                resource_class='tst_resource')
+            nodes.append(node)
+
+        query_str = 'instance_uuid=%s' % nodes[0].instance_uuid
+        data = self.get_json('/nodes?%s' % query_str)
+        self.assertEqual(1, len(data['nodes']))
+        self.assertNotIn('next', data)
+
     def test_sort_key(self):
         nodes = []
         for id in range(3):
diff --git a/releasenotes/notes/next-link-for-instance-uuid-f46eafe5b575f3de.yaml b/releasenotes/notes/next-link-for-instance-uuid-f46eafe5b575f3de.yaml
new file mode 100644
index 0000000000..a87723dcde
--- /dev/null
+++ b/releasenotes/notes/next-link-for-instance-uuid-f46eafe5b575f3de.yaml
@@ -0,0 +1,8 @@
+---
+fixes:
+  - |
+    Fixes a `bug <https://bugs.launchpad.net/ironic/+bug/1718683>`_
+    with the response for a
+    ``GET /nodes?limit=1&instance_uuid=<uuid>`` request. If a node matched,
+    a ``next`` link was returned, even though there are no more nodes that
+    will match. That link is no longer returned.