diff options
author | Jenkins <jenkins@review.openstack.org> | 2014-06-10 14:31:41 +0000 |
---|---|---|
committer | Gerrit Code Review <review@openstack.org> | 2014-06-10 14:31:41 +0000 |
commit | 4097a8135bbb1fd302b024b1eba5735fe7e40faf (patch) | |
tree | 58c5caf5c8584cc5e5bdcd5e762406e67f876dc8 | |
parent | 4c1ea36dc2b1d9b922c60f6378d2e05d87c3dc06 (diff) | |
parent | 230ff8d82154bd1f3290ed136032f541090e1792 (diff) | |
download | ironic-4097a8135bbb1fd302b024b1eba5735fe7e40faf.tar.gz |
Merge "Return the HTTP Location for newly created resources"
-rw-r--r-- | ironic/api/controllers/link.py | 24 | ||||
-rw-r--r-- | ironic/api/controllers/v1/chassis.py | 3 | ||||
-rw-r--r-- | ironic/api/controllers/v1/node.py | 2 | ||||
-rw-r--r-- | ironic/api/controllers/v1/port.py | 3 | ||||
-rw-r--r-- | ironic/tests/api/v1/test_chassis.py | 6 | ||||
-rw-r--r-- | ironic/tests/api/v1/test_nodes.py | 16 | ||||
-rw-r--r-- | ironic/tests/api/v1/test_ports.py | 6 |
7 files changed, 50 insertions, 10 deletions
diff --git a/ironic/api/controllers/link.py b/ironic/api/controllers/link.py index 94052b9e0..ca98bdae4 100644 --- a/ironic/api/controllers/link.py +++ b/ironic/api/controllers/link.py @@ -13,11 +13,24 @@ # License for the specific language governing permissions and limitations # under the License. +import pecan from wsme import types as wtypes from ironic.api.controllers import base +def build_url(resource, resource_args, bookmark=False, base_url=None): + if base_url is None: + base_url = pecan.request.host_url + + template = '%(url)s/%(res)s' if bookmark else '%(url)s/v1/%(res)s' + # FIXME(lucasagomes): I'm getting a 404 when doing a GET on + # a nested resource that the URL ends with a '/'. + # https://groups.google.com/forum/#!topic/pecan-dev/QfSeviLg5qs + template += '%(args)s' if resource_args.startswith('?') else '/%(args)s' + return template % {'url': base_url, 'res': resource, 'args': resource_args} + + class Link(base.APIBase): """A link representation.""" @@ -33,11 +46,6 @@ class Link(base.APIBase): @classmethod def make_link(cls, rel_name, url, resource, resource_args, bookmark=False, type=wtypes.Unset): - template = '%s/%s' if bookmark else '%s/v1/%s' - # FIXME(lucasagomes): I'm getting a 404 when doing a GET on - # a nested resource that the URL ends with a '/'. - # https://groups.google.com/forum/#!topic/pecan-dev/QfSeviLg5qs - template += '%s' if resource_args.startswith('?') else '/%s' - - return Link(href=(template) % (url, resource, resource_args), - rel=rel_name, type=type) + href = build_url(resource, resource_args, + bookmark=bookmark, base_url=url) + return Link(href=href, rel=rel_name, type=type) diff --git a/ironic/api/controllers/v1/chassis.py b/ironic/api/controllers/v1/chassis.py index 3919e11f2..bb001deb6 100644 --- a/ironic/api/controllers/v1/chassis.py +++ b/ironic/api/controllers/v1/chassis.py @@ -206,7 +206,8 @@ class ChassisController(rest.RestController): :param chassis: a chassis within the request body. """ new_chassis = pecan.request.dbapi.create_chassis(chassis.as_dict()) - + # Set the HTTP Location Header + pecan.response.location = link.build_url('chassis', new_chassis.uuid) return Chassis.convert_with_links(new_chassis) @wsme.validate(types.uuid, [ChassisPatchType]) diff --git a/ironic/api/controllers/v1/node.py b/ironic/api/controllers/v1/node.py index 55913bbb7..04dea50fa 100644 --- a/ironic/api/controllers/v1/node.py +++ b/ironic/api/controllers/v1/node.py @@ -661,6 +661,8 @@ class NodesController(rest.RestController): new_node = objects.Node(context=pecan.request.context, **node.as_dict()) new_node.create() + # Set the HTTP Location Header + pecan.response.location = link.build_url('nodes', new_node.uuid) return Node.convert_with_links(new_node) @wsme.validate(types.uuid, [NodePatchType]) diff --git a/ironic/api/controllers/v1/port.py b/ironic/api/controllers/v1/port.py index 99c8b78c5..f8de4ee8a 100644 --- a/ironic/api/controllers/v1/port.py +++ b/ironic/api/controllers/v1/port.py @@ -278,7 +278,8 @@ class PortsController(rest.RestController): raise exception.OperationNotPermitted new_port = pecan.request.dbapi.create_port(port.as_dict()) - + # Set the HTTP Location Header + pecan.response.location = link.build_url('ports', new_port.uuid) return Port.convert_with_links(new_port) @wsme.validate(types.uuid, [PortPatchType]) diff --git a/ironic/tests/api/v1/test_chassis.py b/ironic/tests/api/v1/test_chassis.py index c1d64e6a2..466b5e2f6 100644 --- a/ironic/tests/api/v1/test_chassis.py +++ b/ironic/tests/api/v1/test_chassis.py @@ -19,6 +19,7 @@ import datetime import mock from oslo.config import cfg +from six.moves.urllib import parse as urlparse from ironic.common import utils from ironic.openstack.common import timeutils @@ -321,6 +322,11 @@ class TestPost(base.FunctionalTest): return_created_at = timeutils.parse_isotime( result['created_at']).replace(tzinfo=None) self.assertEqual(test_time, return_created_at) + # Check location header + self.assertIsNotNone(response.location) + expected_location = '/v1/chassis/%s' % cdict['uuid'] + self.assertEqual(urlparse.urlparse(response.location).path, + expected_location) def test_create_chassis_generate_uuid(self): cdict = apiutils.chassis_post_data() diff --git a/ironic/tests/api/v1/test_nodes.py b/ironic/tests/api/v1/test_nodes.py index e0cab62a0..f24fbefe6 100644 --- a/ironic/tests/api/v1/test_nodes.py +++ b/ironic/tests/api/v1/test_nodes.py @@ -19,6 +19,7 @@ import datetime import mock from oslo.config import cfg +from six.moves.urllib import parse as urlparse from testtools.matchers import HasLength from ironic.common import exception @@ -684,6 +685,11 @@ class TestPost(base.FunctionalTest): return_created_at = timeutils.parse_isotime( result['created_at']).replace(tzinfo=None) self.assertEqual(test_time, return_created_at) + # Check location header + self.assertIsNotNone(response.location) + expected_location = '/v1/nodes/%s' % ndict['uuid'] + self.assertEqual(urlparse.urlparse(response.location).path, + expected_location) def test_create_node_doesnt_contain_id(self): # FIXME(comstud): I'd like to make this test not use the @@ -784,6 +790,11 @@ class TestPost(base.FunctionalTest): response = self.post_json('/nodes', ndict) self.assertEqual('application/json', response.content_type) self.assertEqual(201, response.status_int) + # Check location header + self.assertIsNotNone(response.location) + expected_location = '/v1/nodes/%s' % ndict['uuid'] + self.assertEqual(urlparse.urlparse(response.location).path, + expected_location) def test_create_node_with_chassis_uuid(self): ndict = post_get_test_node(chassis_uuid=self.chassis.uuid) @@ -792,6 +803,11 @@ class TestPost(base.FunctionalTest): self.assertEqual(201, response.status_int) result = self.get_json('/nodes/%s' % ndict['uuid']) self.assertEqual(ndict['chassis_uuid'], result['chassis_uuid']) + # Check location header + self.assertIsNotNone(response.location) + expected_location = '/v1/nodes/%s' % ndict['uuid'] + self.assertEqual(urlparse.urlparse(response.location).path, + expected_location) def test_create_node_chassis_uuid_not_found(self): ndict = post_get_test_node( diff --git a/ironic/tests/api/v1/test_ports.py b/ironic/tests/api/v1/test_ports.py index 872be79a1..097c1f258 100644 --- a/ironic/tests/api/v1/test_ports.py +++ b/ironic/tests/api/v1/test_ports.py @@ -19,6 +19,7 @@ import datetime import mock from oslo.config import cfg +from six.moves.urllib import parse as urlparse from testtools.matchers import HasLength from ironic.common import exception @@ -453,6 +454,11 @@ class TestPost(base.FunctionalTest): return_created_at = timeutils.parse_isotime( result['created_at']).replace(tzinfo=None) self.assertEqual(test_time, return_created_at) + # Check location header + self.assertIsNotNone(response.location) + expected_location = '/v1/ports/%s' % pdict['uuid'] + self.assertEqual(urlparse.urlparse(response.location).path, + expected_location) def test_create_port_generate_uuid(self): pdict = post_get_test_port() |