summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJenkins <jenkins@review.openstack.org>2014-06-10 14:31:41 +0000
committerGerrit Code Review <review@openstack.org>2014-06-10 14:31:41 +0000
commit4097a8135bbb1fd302b024b1eba5735fe7e40faf (patch)
tree58c5caf5c8584cc5e5bdcd5e762406e67f876dc8
parent4c1ea36dc2b1d9b922c60f6378d2e05d87c3dc06 (diff)
parent230ff8d82154bd1f3290ed136032f541090e1792 (diff)
downloadironic-4097a8135bbb1fd302b024b1eba5735fe7e40faf.tar.gz
Merge "Return the HTTP Location for newly created resources"
-rw-r--r--ironic/api/controllers/link.py24
-rw-r--r--ironic/api/controllers/v1/chassis.py3
-rw-r--r--ironic/api/controllers/v1/node.py2
-rw-r--r--ironic/api/controllers/v1/port.py3
-rw-r--r--ironic/tests/api/v1/test_chassis.py6
-rw-r--r--ironic/tests/api/v1/test_nodes.py16
-rw-r--r--ironic/tests/api/v1/test_ports.py6
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()