From: Steven Hardy Date: Tue, 4 Dec 2012 16:33:51 +0000 (+0000) Subject: heat engine : convert WaitConditionHandle URL to ARN format X-Git-Tag: 2014.1~1094 X-Git-Url: https://review.fuel-infra.org/gitweb?a=commitdiff_plain;h=0d10276c911a9f391dd7414de1b238f116c39bba;p=openstack-build%2Fheat-build.git heat engine : convert WaitConditionHandle URL to ARN format Convert the WaitConditionHandle URL format to use the ARN format, the resulting URL will be similar to the AWS format fixes bug 1087799 Signed-off-by: Steven Hardy Change-Id: I04b1f6cd913c54c9f4fa82cc1e76be22a19fe2ea --- diff --git a/heat/api/cfn/v1/__init__.py b/heat/api/cfn/v1/__init__.py index bfe6d32c..fa33bfd5 100644 --- a/heat/api/cfn/v1/__init__.py +++ b/heat/api/cfn/v1/__init__.py @@ -75,7 +75,7 @@ class API(wsgi.Router): # This is not part of the main CFN API spec, hence handle it # separately via a different path waitcondition_controller = waitcondition.create_resource(conf) - mapper.connect('/waitcondition/:stack_id/resources/:resource_name', + mapper.connect('/waitcondition/{arn:.*}', controller=waitcondition_controller, action='update_waitcondition', conditions=dict(method=['PUT'])) diff --git a/heat/api/cfn/v1/waitcondition.py b/heat/api/cfn/v1/waitcondition.py index 9f93e1cd..a428d971 100644 --- a/heat/api/cfn/v1/waitcondition.py +++ b/heat/api/cfn/v1/waitcondition.py @@ -21,6 +21,7 @@ from heat.common import wsgi from heat.common import context from heat.rpc import client as rpc_client from heat.openstack.common import rpc +from heat.common import identifier def json_response(http_status, data): @@ -42,21 +43,23 @@ class WaitConditionController: self.options = options self.engine = rpc_client.EngineClient() - def update_waitcondition(self, req, body, stack_id, resource_name): + def update_waitcondition(self, req, body, arn): con = req.context + identity = identifier.ResourceIdentifier.from_arn(arn) [error, metadata] = self.engine.metadata_update(con, - stack_id=stack_id, - resource_name=resource_name, + stack_id=identity.stack_id, + resource_name=identity.resource_name, metadata=body) if error: if error == 'stack': return json_error(404, - 'The stack "%s" does not exist.' % stack_id) + 'The stack "%s" does not exist.' % identity.stack_id) else: return json_error(404, - 'The resource "%s" does not exist.' % resource_name) + 'The resource "%s" does not exist.' % + identity.resource_name) return json_response(201, { - 'resource': resource_name, + 'resource': identity.resource_name, 'metadata': body, }) diff --git a/heat/engine/resources/wait_condition.py b/heat/engine/resources/wait_condition.py index aa42f6f5..23c07e01 100644 --- a/heat/engine/resources/wait_condition.py +++ b/heat/engine/resources/wait_condition.py @@ -19,6 +19,7 @@ import urllib import urlparse from heat.common import exception +from heat.common import identifier from heat.engine import resource from heat.openstack.common import log as logging @@ -59,9 +60,14 @@ class WaitConditionHandle(resource.Resource): Also see boto/auth.py::QuerySignatureV2AuthHandler """ host_url = urlparse.urlparse(cfg.CONF.heat_waitcondition_server_url) + # Note the WSGI spec apparently means that the webob request we end up + # prcessing in the CFN API (ec2token.py) has an unquoted path, so we + # need to calculate the signature with the path component unquoted, but + # ensure the actual URL contains the quoted version... + unquoted_path = urllib.unquote(host_url.path + path) request = {'host': host_url.netloc.lower(), 'verb': 'PUT', - 'path': host_url.path + path, + 'path': unquoted_path, 'params': {'SignatureMethod': 'HmacSHA256', 'SignatureVersion': '2', 'AWSAccessKeyId': credentials.access, @@ -100,7 +106,7 @@ class WaitConditionHandle(resource.Resource): Override the default resource FnGetRefId so we return the signed URL ''' if self.resource_id: - urlpath = '/%s/resources/%s' % (self.stack.id, self.name) + urlpath = self.identifier().arn_url_path() ec2_creds = self.keystone().get_ec2_keypair(self.resource_id) signed_url = self._sign_url(ec2_creds, urlpath) return unicode(signed_url) @@ -148,7 +154,8 @@ class WaitCondition(resource.Resource): def _get_handle_resource_id(self): if self.resource_id is None: handle_url = self.properties['Handle'] - self.resource_id = handle_url.split('/')[-1].split('?')[0] + handle_id = identifier.ResourceIdentifier.from_arn_url(handle_url) + self.resource_id_set(handle_id.resource_name) return self.resource_id def _get_status_reason(self, handle): diff --git a/heat/tests/test_waitcondition.py b/heat/tests/test_waitcondition.py index 6179804e..03d0a6c2 100644 --- a/heat/tests/test_waitcondition.py +++ b/heat/tests/test_waitcondition.py @@ -27,6 +27,7 @@ from heat.tests import fakes import heat.db as db_api from heat.common import template_format +from heat.common import identifier from heat.engine import parser from heat.engine.resources import wait_condition as wc from heat.common import context @@ -99,6 +100,11 @@ class WaitConditionTest(unittest.TestCase): self.m.StubOutWithMock(wc.WaitConditionHandle, 'keystone') wc.WaitConditionHandle.keystone().MultipleTimes().AndReturn(self.fc) + id = identifier.ResourceIdentifier('test_tenant', stack.name, + stack.id, '', 'WaitHandle') + self.m.StubOutWithMock(wc.WaitConditionHandle, 'identifier') + wc.WaitConditionHandle.identifier().MultipleTimes().AndReturn(id) + self.m.ReplayAll() stack.create() @@ -130,6 +136,11 @@ class WaitConditionTest(unittest.TestCase): self.m.StubOutWithMock(wc.WaitConditionHandle, 'keystone') wc.WaitConditionHandle.keystone().MultipleTimes().AndReturn(self.fc) + id = identifier.ResourceIdentifier('test_tenant', stack.name, + stack.id, '', 'WaitHandle') + self.m.StubOutWithMock(wc.WaitConditionHandle, 'identifier') + wc.WaitConditionHandle.identifier().MultipleTimes().AndReturn(id) + self.m.ReplayAll() stack.create() @@ -186,6 +197,11 @@ class WaitConditionHandleTest(unittest.TestCase): self.m.StubOutWithMock(wc.WaitConditionHandle, 'keystone') wc.WaitConditionHandle.keystone().MultipleTimes().AndReturn(self.fc) + id = identifier.ResourceIdentifier('test_tenant', stack.name, + stack.id, '', 'WaitHandle') + self.m.StubOutWithMock(wc.WaitConditionHandle, 'identifier') + wc.WaitConditionHandle.identifier().MultipleTimes().AndReturn(id) + # Stub time to a fixed value so we can get an expected signature t = time.gmtime(1354196977) self.m.StubOutWithMock(time, 'gmtime') @@ -198,14 +214,18 @@ class WaitConditionHandleTest(unittest.TestCase): self.assertEqual(resource.state, 'CREATE_COMPLETE') expected_url = "".join( - ["http://127.0.0.1:8000/v1/waitcondition/STACKABCD1234", - "/resources/WaitHandle", - "?Timestamp=2012-11-29T13%3A49%3A37Z", - "&SignatureMethod=HmacSHA256", - "&AWSAccessKeyId=4567", - "&SignatureVersion=2", - "&Signature=", - "%2BY5r9xvxTzTrRkz%2Br5T1wGeFwoU1wTh2c5u8a2sCurQ%3D"]) + ['http://127.0.0.1:8000/v1/waitcondition/', + 'arn%3Aopenstack%3Aheat%3A%3Atest_tenant%3Astacks%2F', + 'test_stack2%2FSTACKABCD1234%2Fresources%2F', + 'WaitHandle?', + 'Timestamp=2012-11-29T13%3A49%3A37Z&', + 'SignatureMethod=HmacSHA256&', + 'AWSAccessKeyId=4567&', + 'SignatureVersion=2&', + 'Signature=', + 'ePyTwmC%2F1kSigeo%2Fha7kP8Avvb45G9Y7WOQWe4F%2BnXM%3D' + ]) + self.assertEqual(expected_url, resource.FnGetRefId()) self.assertEqual(resource.UPDATE_REPLACE,