SignalResponder store access/secret in resource data
We need to stop relying on the logic in heat_keystoneclient which assumes there is only one keypair per user, as this assumption may not remain true in future. So instead, store the access/secret key in the DB as resource data, which is probably better from a performance perspective anyway, and will also allow SignalResponder subclasses to potentially override the default credentials implementation more easily. Change-Id: I7952181f30c94848acf358ab34cf17b6281d43ac Partial-Bug: #1089261 blueprint: instance-users
This commit is contained in:
parent
151bfa1d11
commit
ba9c290212
|
@ -53,6 +53,11 @@ class SignalResponder(resource.Resource):
|
|||
if not kp:
|
||||
raise exception.Error(_("Error creating ec2 keypair for user %s") %
|
||||
user_id)
|
||||
else:
|
||||
db_api.resource_data_set(self, 'access_key', kp.access,
|
||||
redact=True)
|
||||
db_api.resource_data_set(self, 'secret_key', kp.secret,
|
||||
redact=True)
|
||||
|
||||
def handle_delete(self):
|
||||
if self.resource_id is None:
|
||||
|
@ -61,10 +66,11 @@ class SignalResponder(resource.Resource):
|
|||
self.keystone().delete_stack_user(self.resource_id)
|
||||
except clients.hkc.kc.exceptions.NotFound:
|
||||
pass
|
||||
try:
|
||||
db_api.resource_data_delete(self, 'ec2_signed_url')
|
||||
except exception.NotFound:
|
||||
pass
|
||||
for data_key in ('ec2_signed_url', 'access_key', 'secret_key'):
|
||||
try:
|
||||
db_api.resource_data_delete(self, data_key)
|
||||
except exception.NotFound:
|
||||
pass
|
||||
|
||||
def _get_signed_url(self, signal_type=SIGNAL):
|
||||
"""Create properly formatted and pre-signed URL.
|
||||
|
@ -87,7 +93,8 @@ class SignalResponder(resource.Resource):
|
|||
host_url = urlutils.urlparse(signal_url)
|
||||
|
||||
path = self.identifier().arn_url_path()
|
||||
credentials = self.keystone().get_ec2_keypair(self.resource_id)
|
||||
access_key = db_api.resource_data_get(self, 'access_key')
|
||||
secret_key = db_api.resource_data_get(self, 'secret_key')
|
||||
|
||||
# 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
|
||||
|
@ -99,12 +106,12 @@ class SignalResponder(resource.Resource):
|
|||
'path': unquoted_path,
|
||||
'params': {'SignatureMethod': 'HmacSHA256',
|
||||
'SignatureVersion': '2',
|
||||
'AWSAccessKeyId': credentials.access,
|
||||
'AWSAccessKeyId': access_key,
|
||||
'Timestamp':
|
||||
self.created_time.strftime("%Y-%m-%dT%H:%M:%SZ")
|
||||
}}
|
||||
# Sign the requested
|
||||
signer = ec2_utils.Ec2Signer(credentials.secret)
|
||||
# Sign the request
|
||||
signer = ec2_utils.Ec2Signer(secret_key)
|
||||
request['params']['Signature'] = signer.generate(request)
|
||||
|
||||
qs = urlutils.urlencode(request['params'])
|
||||
|
|
|
@ -1385,8 +1385,7 @@ class AutoScalingTest(HeatTestCase):
|
|||
self._stub_create(1)
|
||||
|
||||
self.m.StubOutWithMock(asc.ScalingPolicy, 'keystone')
|
||||
asc.ScalingPolicy.keystone().MultipleTimes().AndReturn(
|
||||
self.fc)
|
||||
asc.ScalingPolicy.keystone().MultipleTimes().AndReturn(self.fc)
|
||||
|
||||
self.m.ReplayAll()
|
||||
rsrc = self.create_scaling_group(t, stack, 'WebServerGroup')
|
||||
|
@ -1402,10 +1401,6 @@ class AutoScalingTest(HeatTestCase):
|
|||
self._stub_meta_expected(now, 'ChangeInCapacity : 1', 2)
|
||||
self._stub_create(1)
|
||||
|
||||
self.m.StubOutWithMock(asc.ScalingPolicy, 'keystone')
|
||||
asc.ScalingPolicy.keystone().MultipleTimes().AndReturn(
|
||||
self.fc)
|
||||
|
||||
self.m.ReplayAll()
|
||||
|
||||
# Trigger alarm
|
||||
|
|
|
@ -24,9 +24,12 @@ from heat.tests import utils
|
|||
from heat.common import exception
|
||||
from heat.common import template_format
|
||||
|
||||
from heat.db import api as db_api
|
||||
|
||||
from heat.engine import clients
|
||||
from heat.engine import parser
|
||||
from heat.engine import resource
|
||||
from heat.engine import scheduler
|
||||
from heat.engine import signal_responder as sr
|
||||
|
||||
from keystoneclient import exceptions as kc_exceptions
|
||||
|
@ -154,6 +157,34 @@ class SignalTest(HeatTestCase):
|
|||
self.assertIn('Error creating ec2 keypair', rsrc.status_reason)
|
||||
self.assertEqual('123xyz', rsrc.resource_id, '123xyz')
|
||||
|
||||
@utils.stack_delete_after
|
||||
def test_resource_data(self):
|
||||
self.stack = self.create_stack(stack_name='resource_data_test',
|
||||
stub=False)
|
||||
|
||||
self.m.StubOutWithMock(clients.OpenStackClients, 'keystone')
|
||||
clients.OpenStackClients.keystone().MultipleTimes().AndReturn(
|
||||
fakes.FakeKeystoneClient(
|
||||
access='anaccesskey', secret='verysecret'))
|
||||
self.m.ReplayAll()
|
||||
|
||||
self.stack.create()
|
||||
|
||||
rsrc = self.stack['signal_handler']
|
||||
self.assertEqual((rsrc.CREATE, rsrc.COMPLETE), rsrc.state)
|
||||
|
||||
# Ensure the resource data has been stored correctly
|
||||
rs_data = db_api.resource_data_get_all(rsrc)
|
||||
self.assertEqual('anaccesskey', rs_data.get('access_key'))
|
||||
self.assertEqual('verysecret', rs_data.get('secret_key'))
|
||||
self.assertEqual(2, len(rs_data.keys()))
|
||||
|
||||
# And that we remove it on delete
|
||||
scheduler.TaskRunner(rsrc.delete)()
|
||||
self.assertEqual((rsrc.DELETE, rsrc.COMPLETE), rsrc.state)
|
||||
rs_data = db_api.resource_data_get_all(rsrc)
|
||||
self.assertEqual(0, len(rs_data.keys()))
|
||||
|
||||
@utils.stack_delete_after
|
||||
def test_FnGetAtt_Alarm_Url(self):
|
||||
self.stack = self.create_stack()
|
||||
|
|
Loading…
Reference in New Issue