From 5d1f45b0ea0c6880b02b4ff0c150e38f5e0befba Mon Sep 17 00:00:00 2001 From: Angus Salkeld Date: Thu, 4 Jul 2013 13:14:42 +1000 Subject: [PATCH] Make the waitcondition signed url more generic This will be used in a later patch, for alarms as well. blueprint watch-ceilometer Change-Id: I4b3a6be0effb975ddd8214741cfca6f40c493dbe --- heat/engine/resources/wait_condition.py | 62 ++--------------- heat/engine/signal_responder.py | 93 +++++++++++++++++++++++++ 2 files changed, 97 insertions(+), 58 deletions(-) create mode 100644 heat/engine/signal_responder.py diff --git a/heat/engine/resources/wait_condition.py b/heat/engine/resources/wait_condition.py index 035a69b7..097097dd 100644 --- a/heat/engine/resources/wait_condition.py +++ b/heat/engine/resources/wait_condition.py @@ -13,25 +13,20 @@ # License for the specific language governing permissions and limitations # under the License. -import urllib -import urlparse import json -from oslo.config import cfg - -from keystoneclient.contrib.ec2.utils import Ec2Signer - from heat.common import exception from heat.common import identifier from heat.engine import resource from heat.engine import scheduler +from heat.engine import signal_responder from heat.openstack.common import log as logging logger = logging.getLogger(__name__) -class WaitConditionHandle(resource.Resource): +class WaitConditionHandle(signal_responder.SignalResponder): ''' the main point of this class is to : have no dependancies (so the instance can reference it) @@ -41,62 +36,13 @@ class WaitConditionHandle(resource.Resource): ''' properties_schema = {} - def _sign_url(self, credentials, path): - """ - Create properly formatted and pre-signed URL using supplied credentials - See http://docs.amazonwebservices.com/AWSECommerceService/latest/DG/ - rest-signature.html - 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': unquoted_path, - 'params': {'SignatureMethod': 'HmacSHA256', - 'SignatureVersion': '2', - 'AWSAccessKeyId': credentials.access, - 'Timestamp': - self.created_time.strftime("%Y-%m-%dT%H:%M:%SZ") - }} - # Sign the request - signer = Ec2Signer(credentials.secret) - request['params']['Signature'] = signer.generate(request) - - qs = urllib.urlencode(request['params']) - url = "%s%s?%s" % (cfg.CONF.heat_waitcondition_server_url.lower(), - path, qs) - return url - - def handle_create(self): - # Create a keystone user so we can create a signed URL via FnGetRefId - user_id = self.keystone().create_stack_user( - self.physical_resource_name()) - kp = self.keystone().get_ec2_keypair(user_id) - if not kp: - raise exception.Error("Error creating ec2 keypair for user %s" % - user_id) - else: - self.resource_id_set(user_id) - - def handle_delete(self): - if self.resource_id is None: - return - self.keystone().delete_stack_user(self.resource_id) - def FnGetRefId(self): ''' Override the default resource FnGetRefId so we return the signed URL ''' if self.resource_id: - 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) + wc = signal_responder.WAITCONDITION + return unicode(self._get_signed_url(signal_type=wc)) else: return unicode(self.name) diff --git a/heat/engine/signal_responder.py b/heat/engine/signal_responder.py new file mode 100644 index 00000000..10a28457 --- /dev/null +++ b/heat/engine/signal_responder.py @@ -0,0 +1,93 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +import urllib +import urlparse + +from oslo.config import cfg + +from keystoneclient.contrib.ec2 import utils as ec2_utils + +from heat.common import exception +from heat.engine import resource + +from heat.openstack.common import log + +LOG = log.getLogger(__name__) +SIGNAL_TYPES = ( + WAITCONDITION, SIGNAL +) = ( + '/waitcondition', '/signal' +) + + +class SignalResponder(resource.Resource): + + def handle_create(self): + # Create a keystone user so we can create a signed URL via FnGetRefId + user_id = self.keystone().create_stack_user( + self.physical_resource_name()) + kp = self.keystone().get_ec2_keypair(user_id) + if not kp: + raise exception.Error("Error creating ec2 keypair for user %s" % + user_id) + else: + self.resource_id_set(user_id) + + def handle_delete(self): + if self.resource_id is None: + return + self.keystone().delete_stack_user(self.resource_id) + + def _get_signed_url(self, signal_type=SIGNAL): + """Create properly formatted and pre-signed URL. + + This uses the created user for the credentials. + + See http://docs.amazonwebservices.com/AWSECommerceService/latest/DG/ + restarter-signature.html + Also see boto/auth.py::QuerySignatureV2AuthHandler + + :param signal_type: either WAITCONDITION or SIGNAL. + """ + waitcond_url = cfg.CONF.heat_waitcondition_server_url + signal_url = waitcond_url.replace('/waitcondition', signal_type) + host_url = urlparse.urlparse(signal_url) + + path = self.identifier().arn_url_path() + credentials = self.keystone().get_ec2_keypair(self.resource_id) + + # 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': unquoted_path, + 'params': {'SignatureMethod': 'HmacSHA256', + 'SignatureVersion': '2', + 'AWSAccessKeyId': credentials.access, + 'Timestamp': + self.created_time.strftime("%Y-%m-%dT%H:%M:%SZ") + }} + # Sign the requested + signer = ec2_utils.Ec2Signer(credentials.secret) + request['params']['Signature'] = signer.generate(request) + + qs = urllib.urlencode(request['params']) + url = "%s%s?%s" % (signal_url.lower(), + path, qs) + return url -- 2.45.2