Use never expiring alarm_url for resource attributes

Don't use timestamp when generating ec2 signed url for alarm url
attributes of resource.

This will resolve the issue for new resources even if they are cached
in attributes or resource_data.

However, for existing stacks containing these resources the current
best option is to not cache these attributes and allow alarm resources
to be able to get a new never expiring urls in the next forced update.

Change-Id: If2ebc3deacb770294004ae023500367af603b59e
Task: 39985
Related-Bug: #1872737
(cherry picked from commit d0e44ded0a)
This commit is contained in:
Rabi Mishra 2020-06-05 23:30:09 +05:30
parent a4346b3287
commit eb8bfd530b
6 changed files with 21 additions and 16 deletions

View File

@ -85,7 +85,8 @@ class AWSScalingPolicy(heat_sp.AutoScalingPolicy):
attributes_schema = { attributes_schema = {
ALARM_URL: attributes.Schema( ALARM_URL: attributes.Schema(
_("A signed url to handle the alarm. (Heat extension)."), _("A signed url to handle the alarm. (Heat extension)."),
type=attributes.Schema.STRING type=attributes.Schema.STRING,
cache_mode=attributes.Schema.CACHE_NONE
), ),
} }
@ -101,7 +102,7 @@ class AWSScalingPolicy(heat_sp.AutoScalingPolicy):
def get_reference_id(self): def get_reference_id(self):
if self.resource_id is not None: if self.resource_id is not None:
return six.text_type(self._get_ec2_signed_url()) return six.text_type(self._get_ec2_signed_url(never_expire=True))
else: else:
return six.text_type(self.name) return six.text_type(self.name)

View File

@ -99,7 +99,8 @@ class AutoScalingPolicy(signal_responder.SignalResponder):
attributes_schema = { attributes_schema = {
ALARM_URL: attributes.Schema( ALARM_URL: attributes.Schema(
_("A signed url to handle the alarm."), _("A signed url to handle the alarm."),
type=attributes.Schema.STRING type=attributes.Schema.STRING,
cache_mode=attributes.Schema.CACHE_NONE
), ),
SIGNAL_URL: attributes.Schema( SIGNAL_URL: attributes.Schema(
_("A url to handle the alarm using native API."), _("A url to handle the alarm using native API."),
@ -186,7 +187,7 @@ class AutoScalingPolicy(signal_responder.SignalResponder):
if self.resource_id is None: if self.resource_id is None:
return return
if name == self.ALARM_URL: if name == self.ALARM_URL:
return six.text_type(self._get_ec2_signed_url()) return six.text_type(self._get_ec2_signed_url(never_expire=True))
elif name == self.SIGNAL_URL: elif name == self.SIGNAL_URL:
return six.text_type(self._get_heat_signal_url()) return six.text_type(self._get_heat_signal_url())

View File

@ -376,7 +376,8 @@ class Workflow(signal_responder.SignalResponder,
ALARM_URL: attributes.Schema( ALARM_URL: attributes.Schema(
_("A signed url to create executions for workflows specified in " _("A signed url to create executions for workflows specified in "
"Workflow resource."), "Workflow resource."),
type=attributes.Schema.STRING type=attributes.Schema.STRING,
cache_mode=attributes.Schema.CACHE_NONE
), ),
EXECUTIONS: attributes.Schema( EXECUTIONS: attributes.Schema(
_("List of workflows' executions, each of them is a dictionary " _("List of workflows' executions, each of them is a dictionary "
@ -661,7 +662,7 @@ class Workflow(signal_responder.SignalResponder,
self.INPUT: self.properties.get(self.INPUT)} self.INPUT: self.properties.get(self.INPUT)}
elif name == self.ALARM_URL and self.resource_id is not None: elif name == self.ALARM_URL and self.resource_id is not None:
return six.text_type(self._get_ec2_signed_url()) return six.text_type(self._get_ec2_signed_url(never_expire=True))
def resource_mapping(): def resource_mapping():

View File

@ -182,7 +182,8 @@ class SaharaJob(signal_responder.SignalResponder, resource.Resource):
DEFAULT_EXECUTION_URL: attributes.Schema( DEFAULT_EXECUTION_URL: attributes.Schema(
_("A signed url to create execution specified in " _("A signed url to create execution specified in "
"default_execution_data property."), "default_execution_data property."),
type=attributes.Schema.STRING type=attributes.Schema.STRING,
cache_mode=attributes.Schema.CACHE_NONE
), ),
EXECUTIONS: attributes.Schema( EXECUTIONS: attributes.Schema(
_("List of the job executions."), _("List of the job executions."),
@ -298,7 +299,7 @@ class SaharaJob(signal_responder.SignalResponder, resource.Resource):
def _resolve_attribute(self, name): def _resolve_attribute(self, name):
if name == self.DEFAULT_EXECUTION_URL: if name == self.DEFAULT_EXECUTION_URL:
return six.text_type(self._get_ec2_signed_url()) return six.text_type(self._get_ec2_signed_url(never_expire=True))
elif name == self.EXECUTIONS: elif name == self.EXECUTIONS:
try: try:
job_execs = self.client().job_executions.find( job_execs = self.client().job_executions.find(

View File

@ -114,7 +114,8 @@ class SignalResponder(stack_user.StackUser):
'region_name': (self.context.region_name or 'region_name': (self.context.region_name or
cfg.CONF.region_name_for_services)} cfg.CONF.region_name_for_services)}
def _get_ec2_signed_url(self, signal_type=SIGNAL): def _get_ec2_signed_url(self, signal_type=SIGNAL,
never_expire=False):
"""Create properly formatted and pre-signed URL. """Create properly formatted and pre-signed URL.
This uses the created user for the credentials. This uses the created user for the credentials.
@ -158,15 +159,16 @@ class SignalResponder(stack_user.StackUser):
# need to calculate the signature with the path component unquoted, but # need to calculate the signature with the path component unquoted, but
# ensure the actual URL contains the quoted version... # ensure the actual URL contains the quoted version...
unquoted_path = urlparse.unquote(host_url.path + path) unquoted_path = urlparse.unquote(host_url.path + path)
params = {'SignatureMethod': 'HmacSHA256',
'SignatureVersion': '2',
'AWSAccessKeyId': access_key}
if not never_expire:
params['Timestamp'] = timeutils.utcnow().strftime(
"%Y-%m-%dT%H:%M:%SZ")
request = {'host': host_url.netloc.lower(), request = {'host': host_url.netloc.lower(),
'verb': SIGNAL_VERB[signal_type], 'verb': SIGNAL_VERB[signal_type],
'path': unquoted_path, 'path': unquoted_path,
'params': {'SignatureMethod': 'HmacSHA256', 'params': params}
'SignatureVersion': '2',
'AWSAccessKeyId': access_key,
'Timestamp':
timeutils.utcnow().strftime("%Y-%m-%dT%H:%M:%SZ")
}}
# Sign the request # Sign the request
signer = ec2_utils.Ec2Signer(secret_key) signer = ec2_utils.Ec2Signer(secret_key)
request['params']['Signature'] = signer.generate(request) request['params']['Signature'] = signer.generate(request)

View File

@ -183,7 +183,6 @@ class ScalingPolicyAttrTest(common.HeatTestCase):
self.assertEqual('Signature', args[1].split('=')[0]) self.assertEqual('Signature', args[1].split('=')[0])
self.assertEqual('SignatureMethod', args[2].split('=')[0]) self.assertEqual('SignatureMethod', args[2].split('=')[0])
self.assertEqual('SignatureVersion', args[3].split('=')[0]) self.assertEqual('SignatureVersion', args[3].split('=')[0])
self.assertEqual('Timestamp', args[4].split('=')[0])
def test_signal_attribute(self): def test_signal_attribute(self):
heat_plugin = self.stack.clients.client_plugin('heat') heat_plugin = self.stack.clients.client_plugin('heat')