diff options
author | Lucas Alvares Gomes <lucasagomes@gmail.com> | 2013-09-23 11:32:09 +0100 |
---|---|---|
committer | Lucas Alvares Gomes <lucasagomes@gmail.com> | 2013-09-23 11:32:09 +0100 |
commit | 59c2862d6561b4a2fed807f5e120dc50867aae1b (patch) | |
tree | 79147fa245d869e5022d7edc666a3b1349315db8 | |
parent | 92413d72460b1e664b6b21e1220d020cef32d62f (diff) | |
download | ironic-59c2862d6561b4a2fed807f5e120dc50867aae1b.tar.gz |
Collection named based on resource type
To be more consistent with other existing OpenStack APIs, the collection
name is now based on the requested resource type. Also, the link to the
next subset of the collection is now an attribute on the root document
of the request body.
Change-Id: Ie0f99d975b691aad7cd39fddd7d141f95c7912f8
Closes-Bug: #1227928
-rw-r--r-- | ironic/api/controllers/v1/chassis.py | 19 | ||||
-rw-r--r-- | ironic/api/controllers/v1/collection.py | 44 | ||||
-rw-r--r-- | ironic/api/controllers/v1/node.py | 19 | ||||
-rw-r--r-- | ironic/api/controllers/v1/port.py | 10 | ||||
-rw-r--r-- | ironic/tests/api/test_chassis.py | 30 | ||||
-rw-r--r-- | ironic/tests/api/test_nodes.py | 26 | ||||
-rw-r--r-- | ironic/tests/api/test_ports.py | 16 |
7 files changed, 78 insertions, 86 deletions
diff --git a/ironic/api/controllers/v1/chassis.py b/ironic/api/controllers/v1/chassis.py index 73f32c22d..30eafea42 100644 --- a/ironic/api/controllers/v1/chassis.py +++ b/ironic/api/controllers/v1/chassis.py @@ -91,15 +91,17 @@ class Chassis(base.APIBase): class ChassisCollection(collection.Collection): """API representation of a collection of chassis.""" - items = [Chassis] + chassis = [Chassis] "A list containing chassis objects" + def __init__(self, **kwargs): + self._type = 'chassis' + @classmethod def convert_with_links(cls, chassis, limit, **kwargs): collection = ChassisCollection() - collection.type = 'chassis' - collection.items = [Chassis.convert_with_links(ch) for ch in chassis] - collection.links = collection.make_links(limit, 'chassis', **kwargs) + collection.chassis = [Chassis.convert_with_links(ch) for ch in chassis] + collection.next = collection.get_next(limit, **kwargs) return collection @@ -200,10 +202,9 @@ class ChassisController(rest.RestController): sort_key=sort_key, sort_dir=sort_dir) collection = node.NodeCollection() - collection.type = 'node' - collection.items = [node.Node.convert_with_links(n) for n in nodes] + collection.nodes = [node.Node.convert_with_links(n) for n in nodes] resource_url = '/'.join(['chassis', chassis_uuid, 'nodes']) - collection.links = collection.make_links(limit, resource_url, - sort_key=sort_key, - sort_dir=sort_dir) + collection.next = collection.get_next(limit, url=resource_url, + sort_key=sort_key, + sort_dir=sort_dir) return collection diff --git a/ironic/api/controllers/v1/collection.py b/ironic/api/controllers/v1/collection.py index 1ce88c96d..10f2ff52d 100644 --- a/ironic/api/controllers/v1/collection.py +++ b/ironic/api/controllers/v1/collection.py @@ -25,29 +25,27 @@ from ironic.api.controllers.v1 import link class Collection(base.APIBase): - links = [link.Link] - "A list containing a link to retrieve the next subset of the collection" + next = wtypes.text + "A link to retrieve the next subset of the collection" - type = wtypes.text - "The type of the collection" - - def _check_items(self): - if not hasattr(self, 'items') or self.items == wtypes.Unset: - raise AttributeError(_("Collection items are uninitialized")) + @property + def collection(self): + return getattr(self, self._type) def has_next(self, limit): - self._check_items() - return len(self.items) and len(self.items) == limit - - def make_links(self, limit, res_name, **kwargs): - self._check_items() - links = [] - if self.has_next(limit): - q_args = ''.join(['%s=%s&' % (key, kwargs[key]) for key in kwargs]) - next_args = '?%(args)slimit=%(limit)d&marker=%(marker)s' % { - 'args': q_args, 'limit': limit, - 'marker': self.items[-1].uuid} - links = [link.Link.make_link('next', pecan.request.host_url, - res_name, next_args) - ] - return links + """Return whether collection has more items.""" + return len(self.collection) and len(self.collection) == limit + + def get_next(self, limit, url=None, **kwargs): + """Return a link to the next subset of the collection.""" + if not self.has_next(limit): + return wtypes.Unset + + resource_url = url or self._type + q_args = ''.join(['%s=%s&' % (key, kwargs[key]) for key in kwargs]) + next_args = '?%(args)slimit=%(limit)d&marker=%(marker)s' % { + 'args': q_args, 'limit': limit, + 'marker': self.collection[-1].uuid} + + return link.Link.make_link('next', pecan.request.host_url, + resource_url, next_args).href diff --git a/ironic/api/controllers/v1/node.py b/ironic/api/controllers/v1/node.py index b87108a11..54c8a22e7 100644 --- a/ironic/api/controllers/v1/node.py +++ b/ironic/api/controllers/v1/node.py @@ -245,15 +245,17 @@ class Node(base.APIBase): class NodeCollection(collection.Collection): """API representation of a collection of nodes.""" - items = [Node] + nodes = [Node] "A list containing nodes objects" + def __init__(self, **kwargs): + self._type = 'nodes' + @classmethod def convert_with_links(cls, nodes, limit, **kwargs): collection = NodeCollection() - collection.type = 'node' - collection.items = [Node.convert_with_links(n) for n in nodes] - collection.links = collection.make_links(limit, 'nodes', **kwargs) + collection.nodes = [Node.convert_with_links(n) for n in nodes] + collection.next = collection.get_next(limit, **kwargs) return collection @@ -425,10 +427,9 @@ class NodesController(rest.RestController): sort_key=sort_key, sort_dir=sort_dir) collection = port.PortCollection() - collection.type = 'port' - collection.items = [port.Port.convert_with_links(n) for n in ports] + collection.ports = [port.Port.convert_with_links(n) for n in ports] resource_url = '/'.join(['nodes', node_uuid, 'ports']) - collection.links = collection.make_links(limit, resource_url, - sort_key=sort_key, - sort_dir=sort_dir) + collection.next = collection.get_next(limit, url=resource_url, + sort_key=sort_key, + sort_dir=sort_dir) return collection diff --git a/ironic/api/controllers/v1/port.py b/ironic/api/controllers/v1/port.py index d4b6052b0..807a827eb 100644 --- a/ironic/api/controllers/v1/port.py +++ b/ironic/api/controllers/v1/port.py @@ -75,15 +75,17 @@ class Port(base.APIBase): class PortCollection(collection.Collection): """API representation of a collection of ports.""" - items = [Port] + ports = [Port] "A list containing ports objects" + def __init__(self, **kwargs): + self._type = 'ports' + @classmethod def convert_with_links(cls, ports, limit, **kwargs): collection = PortCollection() - collection.type = 'port' - collection.items = [Port.convert_with_links(p) for p in ports] - collection.links = collection.make_links(limit, 'ports', **kwargs) + collection.ports = [Port.convert_with_links(p) for p in ports] + collection.next = collection.get_next(limit, **kwargs) return collection diff --git a/ironic/tests/api/test_chassis.py b/ironic/tests/api/test_chassis.py index eb09d9fba..6a852c7d9 100644 --- a/ironic/tests/api/test_chassis.py +++ b/ironic/tests/api/test_chassis.py @@ -25,13 +25,13 @@ class TestListChassis(base.FunctionalTest): def test_empty(self): data = self.get_json('/chassis') - self.assertEqual([], data['items']) + self.assertEqual([], data['chassis']) def test_one(self): ndict = dbutils.get_test_chassis() chassis = self.dbapi.create_chassis(ndict) data = self.get_json('/chassis') - self.assertEqual(chassis['uuid'], data['items'][0]["uuid"]) + self.assertEqual(chassis['uuid'], data['chassis'][0]["uuid"]) def test_many(self): ch_list = [] @@ -41,9 +41,9 @@ class TestListChassis(base.FunctionalTest): chassis = self.dbapi.create_chassis(ndict) ch_list.append(chassis['uuid']) data = self.get_json('/chassis') - self.assertEqual(len(ch_list), len(data['items'])) + self.assertEqual(len(ch_list), len(data['chassis'])) - uuids = [n['uuid'] for n in data['items']] + uuids = [n['uuid'] for n in data['chassis']] self.assertEqual(ch_list.sort(), uuids.sort()) def test_links(self): @@ -63,12 +63,10 @@ class TestListChassis(base.FunctionalTest): ch = self.dbapi.create_chassis(ndict) chassis.append(ch['uuid']) data = self.get_json('/chassis/?limit=3') - self.assertEqual(data['type'], 'chassis') - self.assertEqual(len(data['items']), 3) + self.assertEqual(len(data['chassis']), 3) - next_marker = data['items'][-1]['uuid'] - next_link = [l['href'] for l in data['links'] if l['rel'] == 'next'][0] - self.assertIn(next_marker, next_link) + next_marker = data['chassis'][-1]['uuid'] + self.assertIn(next_marker, data['next']) def test_nodes_subresource_link(self): ndict = dbutils.get_test_chassis() @@ -87,15 +85,13 @@ class TestListChassis(base.FunctionalTest): self.dbapi.create_node(ndict) data = self.get_json('/chassis/%s/nodes' % cdict['uuid']) - self.assertEqual(data['type'], 'node') - self.assertEqual(len(data['items']), 2) - self.assertEqual(len(data['links']), 0) + self.assertEqual(len(data['nodes']), 2) + self.assertNotIn('next', data.keys()) # Test collection pagination data = self.get_json('/chassis/%s/nodes?limit=1' % cdict['uuid']) - self.assertEqual(data['type'], 'node') - self.assertEqual(len(data['items']), 1) - self.assertEqual(len(data['links']), 1) + self.assertEqual(len(data['nodes']), 1) + self.assertIn('next', data.keys()) class TestPatch(base.FunctionalTest): @@ -222,8 +218,8 @@ class TestPost(base.FunctionalTest): self.post_json('/chassis', cdict) result = self.get_json('/chassis') self.assertEqual(cdict['description'], - result['items'][0]['description']) - self.assertTrue(uuidutils.is_uuid_like(result['items'][0]['uuid'])) + result['chassis'][0]['description']) + self.assertTrue(uuidutils.is_uuid_like(result['chassis'][0]['uuid'])) class TestDelete(base.FunctionalTest): diff --git a/ironic/tests/api/test_nodes.py b/ironic/tests/api/test_nodes.py index 7513f81f0..337264648 100644 --- a/ironic/tests/api/test_nodes.py +++ b/ironic/tests/api/test_nodes.py @@ -31,13 +31,13 @@ class TestListNodes(base.FunctionalTest): def test_empty(self): data = self.get_json('/nodes') - self.assertEqual([], data['items']) + self.assertEqual([], data['nodes']) def test_one(self): ndict = dbutils.get_test_node() node = self.dbapi.create_node(ndict) data = self.get_json('/nodes') - self.assertEqual(node['uuid'], data['items'][0]["uuid"]) + self.assertEqual(node['uuid'], data['nodes'][0]["uuid"]) def test_many(self): nodes = [] @@ -47,9 +47,9 @@ class TestListNodes(base.FunctionalTest): node = self.dbapi.create_node(ndict) nodes.append(node['uuid']) data = self.get_json('/nodes') - self.assertEqual(len(nodes), len(data['items'])) + self.assertEqual(len(nodes), len(data['nodes'])) - uuids = [n['uuid'] for n in data['items']] + uuids = [n['uuid'] for n in data['nodes']] self.assertEqual(nodes.sort(), uuids.sort()) def test_links(self): @@ -69,12 +69,10 @@ class TestListNodes(base.FunctionalTest): node = self.dbapi.create_node(ndict) nodes.append(node['uuid']) data = self.get_json('/nodes/?limit=3') - self.assertEqual(data['type'], 'node') - self.assertEqual(len(data['items']), 3) + self.assertEqual(len(data['nodes']), 3) - next_marker = data['items'][-1]['uuid'] - next_link = [l['href'] for l in data['links'] if l['rel'] == 'next'][0] - self.assertIn(next_marker, next_link) + next_marker = data['nodes'][-1]['uuid'] + self.assertIn(next_marker, data['next']) def test_ports_subresource_link(self): ndict = dbutils.get_test_node() @@ -93,15 +91,13 @@ class TestListNodes(base.FunctionalTest): self.dbapi.create_port(pdict) data = self.get_json('/nodes/%s/ports' % ndict['uuid']) - self.assertEqual(data['type'], 'port') - self.assertEqual(len(data['items']), 2) - self.assertEqual(len(data['links']), 0) + self.assertEqual(len(data['ports']), 2) + self.assertNotIn('next', data.keys()) # Test collection pagination data = self.get_json('/nodes/%s/ports?limit=1' % ndict['uuid']) - self.assertEqual(data['type'], 'port') - self.assertEqual(len(data['items']), 1) - self.assertEqual(len(data['links']), 1) + self.assertEqual(len(data['ports']), 1) + self.assertIn('next', data.keys()) def test_state(self): ndict = dbutils.get_test_node() diff --git a/ironic/tests/api/test_ports.py b/ironic/tests/api/test_ports.py index 3885c45a2..74dc76eec 100644 --- a/ironic/tests/api/test_ports.py +++ b/ironic/tests/api/test_ports.py @@ -25,13 +25,13 @@ class TestListPorts(base.FunctionalTest): def test_empty(self): data = self.get_json('/ports') - self.assertEqual([], data['items']) + self.assertEqual([], data['ports']) def test_one(self): ndict = dbutils.get_test_port() port = self.dbapi.create_port(ndict) data = self.get_json('/ports') - self.assertEqual(port['uuid'], data['items'][0]["uuid"]) + self.assertEqual(port['uuid'], data['ports'][0]["uuid"]) def test_many(self): ports = [] @@ -41,9 +41,9 @@ class TestListPorts(base.FunctionalTest): port = self.dbapi.create_port(ndict) ports.append(port['uuid']) data = self.get_json('/ports') - self.assertEqual(len(ports), len(data['items'])) + self.assertEqual(len(ports), len(data['ports'])) - uuids = [n['uuid'] for n in data['items']] + uuids = [n['uuid'] for n in data['ports']] self.assertEqual(ports.sort(), uuids.sort()) def test_links(self): @@ -63,12 +63,10 @@ class TestListPorts(base.FunctionalTest): port = self.dbapi.create_port(ndict) ports.append(port['uuid']) data = self.get_json('/ports/?limit=3') - self.assertEqual(data['type'], 'port') - self.assertEqual(len(data['items']), 3) + self.assertEqual(len(data['ports']), 3) - next_marker = data['items'][-1]['uuid'] - next_link = [l['href'] for l in data['links'] if l['rel'] == 'next'][0] - self.assertIn(next_marker, next_link) + next_marker = data['ports'][-1]['uuid'] + self.assertIn(next_marker, data['next']) class TestPatch(base.FunctionalTest): |