summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJenkins <jenkins@review.openstack.org>2015-07-15 05:23:28 +0000
committerGerrit Code Review <review@openstack.org>2015-07-15 05:23:28 +0000
commit8fe749e8a052208ec8d61ca5b8254a09e64622db (patch)
tree8a093462a3cfc6d658a642e8f32fe1ac567339a7
parent9e352b3e93a070865ad979410530469bc245da01 (diff)
parentca8effbbae50392672d4474622ab3af770358828 (diff)
downloadheat-8fe749e8a052208ec8d61ca5b8254a09e64622db.tar.gz
Merge "Move signals to SignalResponder class"
-rw-r--r--heat/engine/resources/openstack/heat/software_deployment.py101
-rw-r--r--heat/engine/resources/signal_responder.py149
-rw-r--r--heat/engine/resources/stack_user.py20
-rw-r--r--heat/tests/fakes.py1
-rw-r--r--heat/tests/generic_resource.py25
-rw-r--r--heat/tests/test_signal.py202
-rw-r--r--heat/tests/test_software_deployment.py59
7 files changed, 394 insertions, 163 deletions
diff --git a/heat/engine/resources/openstack/heat/software_deployment.py b/heat/engine/resources/openstack/heat/software_deployment.py
index 0b87aea57..b782e8758 100644
--- a/heat/engine/resources/openstack/heat/software_deployment.py
+++ b/heat/engine/resources/openstack/heat/software_deployment.py
@@ -13,7 +13,6 @@
import copy
import six
-import uuid
from oslo_config import cfg
from oslo_log import log as logging
@@ -315,63 +314,6 @@ class SoftwareDeployment(signal_responder.SignalResponder):
def _build_derived_options(self, action, source):
return source.get(sc.SoftwareConfig.OPTIONS)
- def _get_temp_url(self):
- put_url = self.data().get('signal_temp_url')
- if put_url:
- return put_url
-
- container = self.physical_resource_name()
- object_name = str(uuid.uuid4())
-
- self.client('swift').put_container(container)
-
- put_url = self.client_plugin('swift').get_temp_url(
- container, object_name)
- self.data_set('signal_temp_url', put_url)
- self.data_set('signal_object_name', object_name)
-
- self.client('swift').put_object(
- container, object_name, '')
- return put_url
-
- def _get_queue_id(self):
- queue_id = self.data().get('signal_queue_id')
- if queue_id:
- return queue_id
-
- queue_id = self.physical_resource_name()
- zaqar = self.client('zaqar')
- zaqar.queue(queue_id).ensure_exists()
- self.data_set('signal_queue_id', queue_id)
- return queue_id
-
- def _delete_temp_url(self):
- object_name = self.data().get('signal_object_name')
- if not object_name:
- return
- try:
- container = self.physical_resource_name()
- swift = self.client('swift')
- swift.delete_object(container, object_name)
- headers = swift.head_container(container)
- if int(headers['x-container-object-count']) == 0:
- swift.delete_container(container)
- except Exception as ex:
- self.client_plugin('swift').ignore_not_found(ex)
- self.data_delete('signal_object_name')
- self.data_delete('signal_temp_url')
-
- def _delete_queue(self):
- queue_id = self.data().get('signal_queue_id')
- if not queue_id:
- return
- zaqar = self.client('zaqar')
- try:
- zaqar.queue(queue_id).delete()
- except Exception as ex:
- self.client_plugin('zaqar').ignore_not_found(ex)
- self.data_delete('signal_queue_id')
-
def _build_derived_inputs(self, action, source):
scl = sc.SoftwareConfig
inputs = copy.deepcopy(source.get(scl.INPUTS)) or []
@@ -440,7 +382,7 @@ class SoftwareDeployment(signal_responder.SignalResponder):
scl.DESCRIPTION: _('ID of signal to use for signaling '
'output values'),
scl.TYPE: 'String',
- 'value': self._get_temp_url()
+ 'value': self._get_swift_signal_url()
})
inputs.append({
scl.NAME: self.DEPLOY_SIGNAL_VERB,
@@ -450,31 +392,32 @@ class SoftwareDeployment(signal_responder.SignalResponder):
'value': 'PUT'
})
elif self._signal_transport_heat() or self._signal_transport_zaqar():
+ creds = self._get_heat_signal_credentials()
inputs.extend([{
scl.NAME: self.DEPLOY_AUTH_URL,
scl.DESCRIPTION: _('URL for API authentication'),
scl.TYPE: 'String',
- 'value': self.keystone().v3_endpoint
+ 'value': creds['auth_url']
}, {
scl.NAME: self.DEPLOY_USERNAME,
scl.DESCRIPTION: _('Username for API authentication'),
scl.TYPE: 'String',
- 'value': self.physical_resource_name(),
+ 'value': creds['username']
}, {
scl.NAME: self.DEPLOY_USER_ID,
scl.DESCRIPTION: _('User ID for API authentication'),
scl.TYPE: 'String',
- 'value': self._get_user_id(),
+ 'value': creds['user_id']
}, {
scl.NAME: self.DEPLOY_PASSWORD,
scl.DESCRIPTION: _('Password for API authentication'),
scl.TYPE: 'String',
- 'value': self.password
+ 'value': creds['password']
}, {
scl.NAME: self.DEPLOY_PROJECT_ID,
scl.DESCRIPTION: _('ID of project for API authentication'),
scl.TYPE: 'String',
- 'value': self.stack.stack_user_project_id
+ 'value': creds['project_id']
}])
if self._signal_transport_zaqar():
inputs.append({
@@ -482,31 +425,14 @@ class SoftwareDeployment(signal_responder.SignalResponder):
scl.DESCRIPTION: _('ID of queue to use for signaling '
'output values'),
scl.TYPE: 'String',
- 'value': self._get_queue_id()
+ 'value': self._get_zaqar_signal_queue_id()
})
return inputs
def handle_create(self):
- if self._signal_transport_cfn():
- self._create_user()
- self._create_keypair()
- if self._signal_transport_heat() or self._signal_transport_zaqar():
- self.password = uuid.uuid4().hex
- self._create_user()
return self._handle_action(self.CREATE)
- @property
- def password(self):
- return self.data().get('password')
-
- @password.setter
- def password(self, password):
- if password is None:
- self.data_delete('password')
- else:
- self.data_set('password', password, True)
-
def check_create_complete(self, sd):
if not sd:
return True
@@ -536,15 +462,8 @@ class SoftwareDeployment(signal_responder.SignalResponder):
return True
def _delete_resource(self):
- if self._signal_transport_cfn():
- self._delete_ec2_signed_url()
- self._delete_user()
- elif self._signal_transport_heat():
- self._delete_user()
- elif self._signal_transport_temp_url():
- self._delete_temp_url()
- elif self._signal_transport_zaqar():
- self._delete_queue()
+ self._delete_signals()
+ self._delete_user()
derived_config_id = None
if self.resource_id is not None:
diff --git a/heat/engine/resources/signal_responder.py b/heat/engine/resources/signal_responder.py
index 5693bf596..2579247fd 100644
--- a/heat/engine/resources/signal_responder.py
+++ b/heat/engine/resources/signal_responder.py
@@ -11,6 +11,8 @@
# License for the specific language governing permissions and limitations
# under the License.
+import uuid
+
from keystoneclient.contrib.ec2 import utils as ec2_utils
from oslo_config import cfg
from oslo_log import log as logging
@@ -36,17 +38,42 @@ class SignalResponder(stack_user.StackUser):
# API operations as a consequence of handling a signal
requires_deferred_auth = True
- def handle_create(self):
- super(SignalResponder, self).handle_create()
- self._create_keypair()
-
def handle_delete(self):
+ self._delete_signals()
super(SignalResponder, self).handle_delete()
+
+ def _delete_signals(self):
self._delete_ec2_signed_url()
self._delete_heat_signal_url()
+ self._delete_swift_signal_url()
+ self._delete_zaqar_signal_queue()
- def _delete_ec2_signed_url(self):
- self.data_delete('ec2_signed_url')
+ @property
+ def password(self):
+ return self.data().get('password')
+
+ @password.setter
+ def password(self, password):
+ if password is None:
+ self.data_delete('password')
+ else:
+ self.data_set('password', password, True)
+
+ def _get_heat_signal_credentials(self):
+ """Return OpenStack credentials that can be used to send a signal.
+
+ These credentials are for the user associated with this resource in
+ the heat stack user domain.
+ """
+ if self._get_user_id() is None:
+ if self.password is None:
+ self.password = uuid.uuid4().hex
+ self._create_user()
+ return {'auth_url': self.keystone().v3_endpoint,
+ 'username': self.physical_resource_name(),
+ 'user_id': self._get_user_id(),
+ 'password': self.password,
+ 'project_id': self.stack.stack_user_project_id}
def _get_ec2_signed_url(self, signal_type=SIGNAL):
"""Create properly formatted and pre-signed URL.
@@ -65,9 +92,19 @@ class SignalResponder(stack_user.StackUser):
secret_key = self.data().get('secret_key')
if not access_key or not secret_key:
- LOG.warn(_LW('Cannot generate signed url, '
- 'no stored access/secret key'))
- return
+ if self.id is None or self.action == self.DELETE:
+ # it is either too early or too late to do this
+ return
+ if self._get_user_id() is None:
+ self._create_user()
+ self._create_keypair()
+ access_key = self.data().get('access_key')
+ secret_key = self.data().get('secret_key')
+
+ if not access_key or not secret_key:
+ LOG.warn(_LW('Cannot generate signed url, '
+ 'unable to create keypair'))
+ return
config_url = cfg.CONF.heat_waitcondition_server_url
if config_url:
@@ -106,14 +143,23 @@ class SignalResponder(stack_user.StackUser):
self.data_set('ec2_signed_url', url)
return url
- def _delete_heat_signal_url(self):
- self.data_delete('heat_signal_url')
+ def _delete_ec2_signed_url(self):
+ self.data_delete('ec2_signed_url')
+ self._delete_keypair()
def _get_heat_signal_url(self):
+ """Return a heat-api signal URL for this resource.
+
+ This URL is not pre-signed, valid user credentials are required.
+ """
stored = self.data().get('heat_signal_url')
if stored is not None:
return stored
+ if self.id is None or self.action == self.DELETE:
+ # it is either too early or too late to do this
+ return
+
url = self.client_plugin('heat').get_heat_url()
host_url = urlparse.urlparse(url)
path = self.identifier().url_path()
@@ -123,3 +169,84 @@ class SignalResponder(stack_user.StackUser):
self.data_set('heat_signal_url', url)
return url
+
+ def _delete_heat_signal_url(self):
+ self.data_delete('heat_signal_url')
+
+ def _get_swift_signal_url(self):
+ """Create properly formatted and pre-signed Swift signal URL.
+
+ This uses a Swift pre-signed temp_url.
+ """
+ put_url = self.data().get('swift_signal_url')
+ if put_url:
+ return put_url
+
+ if self.id is None or self.action == self.DELETE:
+ # it is either too early or too late to do this
+ return
+
+ container = self.stack.id
+ object_name = self.physical_resource_name()
+
+ self.client('swift').put_container(container)
+
+ put_url = self.client_plugin('swift').get_temp_url(
+ container, object_name)
+ self.data_set('swift_signal_url', put_url)
+ self.data_set('swift_signal_object_name', object_name)
+
+ self.client('swift').put_object(
+ container, object_name, '')
+ return put_url
+
+ def _delete_swift_signal_url(self):
+ object_name = self.data().get('swift_signal_object_name')
+ if not object_name:
+ return
+ try:
+ container = self.physical_resource_name()
+ swift = self.client('swift')
+ swift.delete_object(container, object_name)
+ headers = swift.head_container(container)
+ if int(headers['x-container-object-count']) == 0:
+ swift.delete_container(container)
+ except Exception as ex:
+ self.client_plugin('swift').ignore_not_found(ex)
+ self.data_delete('swift_signal_object_name')
+ self.data_delete('swift_signal_url')
+
+ def _get_zaqar_signal_queue_id(self):
+ """Return a zaqar queue_id for signaling this resource.
+
+ This uses the created user for the credentials.
+ """
+ queue_id = self.data().get('zaqar_signal_queue_id')
+ if queue_id:
+ return queue_id
+
+ if self.id is None or self.action == self.DELETE:
+ # it is either too early or too late to do this
+ return
+
+ if self._get_user_id() is None:
+ if self.password is None:
+ self.password = uuid.uuid4().hex
+ self._create_user()
+
+ queue_id = self.physical_resource_name()
+ zaqar = self.client('zaqar')
+ zaqar.queue(queue_id).ensure_exists()
+ self.data_set('zaqar_signal_queue_id', queue_id)
+ return queue_id
+
+ def _delete_zaqar_signal_queue(self):
+ queue_id = self.data().get('zaqar_signal_queue_id')
+ if not queue_id:
+ return
+ zaqar = self.client('zaqar')
+ try:
+ zaqar.queue(queue_id).delete()
+ except Exception as ex:
+ self.client_plugin('zaqar').ignore_not_found(ex)
+ self.data_delete('zaqar_signal_queue_id')
diff --git a/heat/engine/resources/stack_user.py b/heat/engine/resources/stack_user.py
index b4c034f7a..d6aa26e6c 100644
--- a/heat/engine/resources/stack_user.py
+++ b/heat/engine/resources/stack_user.py
@@ -25,7 +25,7 @@ LOG = logging.getLogger(__name__)
class StackUser(resource.Resource):
# Subclasses create a user, and optionally keypair associated with a
- # resource in a stack. Users are created in the heat stack user domain
+ # resource in a stack. Users are created in the heat stack user domain
# (in a project specific to the stack)
def __init__(self, name, json_snippet, stack):
super(StackUser, self).__init__(name, json_snippet, stack)
@@ -34,6 +34,10 @@ class StackUser(resource.Resource):
self._create_user()
def _create_user(self):
+ if self.data().get('user_id'):
+ # a user has been created already
+ return
+
# Check for stack user project, create if not yet set
if not self.stack.stack_user_project_id:
project_id = self.keystone().create_stack_domain_project(
@@ -85,6 +89,10 @@ class StackUser(resource.Resource):
user_id = self._get_user_id()
if user_id is None:
return
+
+ # the user is going away, so we want the keypair gone as well
+ self._delete_keypair()
+
try:
self.keystone().delete_stack_domain_user(
user_id=user_id, project_id=self.stack.stack_user_project_id)
@@ -100,8 +108,7 @@ class StackUser(resource.Resource):
self.keystone().delete_stack_user(user_id)
except kc_exception.NotFound:
pass
- for data_key in ('credential_id', 'access_key', 'secret_key'):
- self.data_delete(data_key)
+ self.data_delete('user_id')
def handle_suspend(self):
user_id = self._get_user_id()
@@ -125,6 +132,9 @@ class StackUser(resource.Resource):
# Subclasses may optionally call this in handle_create to create
# an ec2 keypair associated with the user, the resulting keys are
# stored in resource_data
+ if self.data().get('credential_id'):
+ return # a keypair was created already
+
user_id = self._get_user_id()
kp = self.keystone().create_stack_domain_user_keypair(
user_id=user_id, project_id=self.stack.stack_user_project_id)
@@ -146,10 +156,12 @@ class StackUser(resource.Resource):
def _delete_keypair(self):
# Subclasses may optionally call this to delete a keypair created
# via _create_keypair
- user_id = self._get_user_id()
credential_id = self.data().get('credential_id')
if not credential_id:
return
+ user_id = self._get_user_id()
+ if user_id is None:
+ return
try:
self.keystone().delete_stack_domain_user_keypair(
diff --git a/heat/tests/fakes.py b/heat/tests/fakes.py
index 7d86ffd1e..02d5d9eda 100644
--- a/heat/tests/fakes.py
+++ b/heat/tests/fakes.py
@@ -109,6 +109,7 @@ class FakeKeystoneClient(object):
self.credential_id = credential_id
self.token = auth_token
self.context = context
+ self.v3_endpoint = 'http://localhost:5000/v3'
class FakeCred(object):
id = self.credential_id
diff --git a/heat/tests/generic_resource.py b/heat/tests/generic_resource.py
index 923dc31de..64865b4ce 100644
--- a/heat/tests/generic_resource.py
+++ b/heat/tests/generic_resource.py
@@ -136,8 +136,11 @@ class ResourceWithRequiredProps(GenericResource):
class SignalResource(signal_responder.SignalResponder):
- properties_schema = {}
- attributes_schema = {'AlarmUrl': attributes.Schema('Get a signed webhook')}
+ properties_schema = {
+ 'signal_transport': properties.Schema(properties.Schema.STRING,
+ default='CFN_SIGNAL')}
+ attributes_schema = {'AlarmUrl': attributes.Schema('Get a signed webhook'),
+ 'signal': attributes.Schema('Get a signal')}
def handle_create(self):
super(SignalResource, self).handle_create()
@@ -148,8 +151,22 @@ class SignalResource(signal_responder.SignalResponder):
{'type': self.type(), 'details': details})
def _resolve_attribute(self, name):
- if name == 'AlarmUrl' and self.resource_id is not None:
- return six.text_type(self._get_ec2_signed_url())
+ if self.resource_id is not None:
+ if self.properties['signal_transport'] == 'CFN_SIGNAL':
+ d = {'alarm_url': six.text_type(self._get_ec2_signed_url())}
+ elif self.properties['signal_transport'] == 'HEAT_SIGNAL':
+ d = self._get_heat_signal_credentials()
+ d['alarm_url'] = six.text_type(self._get_heat_signal_url())
+ elif self.properties['signal_transport'] == 'TEMP_URL_SIGNAL':
+ d = {'alarm_url': six.text_type(self._get_swift_signal_url())}
+ elif self.properties['signal_transport'] == 'ZAQAR_SIGNAL':
+ d = self._get_heat_signal_credentials()
+ d['queue_id'] = six.text_type(
+ self._get_zaqar_signal_queue_id())
+ if name == 'AlarmUrl':
+ return d['alarm_url']
+ elif name == 'signal':
+ return d
class StackUserResource(stack_user.StackUser):
diff --git a/heat/tests/test_signal.py b/heat/tests/test_signal.py
index fed3f6ff9..4082899cd 100644
--- a/heat/tests/test_signal.py
+++ b/heat/tests/test_signal.py
@@ -12,14 +12,15 @@
# under the License.
import datetime
-import six
+import uuid
from keystoneclient import exceptions as kc_exceptions
+import mox
+import six
from heat.common import exception
from heat.common import template_format
from heat.engine import resource
-from heat.engine.resources import stack_user
from heat.engine import scheduler
from heat.engine import stack as parser
from heat.engine import template
@@ -30,13 +31,53 @@ from heat.tests import generic_resource
from heat.tests import utils
-test_template_signal = '''
+test_cfn_template_signal = '''
{
"AWSTemplateFormatVersion" : "2010-09-09",
"Description" : "Just a test.",
"Parameters" : {},
"Resources" : {
- "signal_handler" : {"Type" : "SignalResourceType"},
+ "signal_handler" : {"Type" : "SignalResourceType",
+ "Properties": {"signal_transport": "CFN_SIGNAL"}},
+ "resource_X" : {"Type" : "GenericResourceType"}
+ }
+}
+'''
+
+test_heat_template_signal = '''
+{
+ "AWSTemplateFormatVersion" : "2010-09-09",
+ "Description" : "Just a test.",
+ "Parameters" : {},
+ "Resources" : {
+ "signal_handler" : {"Type" : "SignalResourceType",
+ "Properties": {"signal_transport": "HEAT_SIGNAL"}},
+ "resource_X" : {"Type" : "GenericResourceType"}
+ }
+}
+'''
+
+test_swift_template_signal = '''
+{
+ "AWSTemplateFormatVersion" : "2010-09-09",
+ "Description" : "Just a test.",
+ "Parameters" : {},
+ "Resources" : {
+ "signal_handler" : {"Type" : "SignalResourceType",
+ "Properties": {"signal_transport": "TEMP_URL_SIGNAL"}},
+ "resource_X" : {"Type" : "GenericResourceType"}
+ }
+}
+'''
+
+test_zaqar_template_signal = '''
+{
+ "AWSTemplateFormatVersion" : "2010-09-09",
+ "Description" : "Just a test.",
+ "Parameters" : {},
+ "Resources" : {
+ "signal_handler" : {"Type" : "SignalResourceType",
+ "Properties": {"signal_transport": "ZAQAR_SIGNAL"}},
"resource_X" : {"Type" : "GenericResourceType"}
}
}
@@ -52,11 +93,12 @@ class SignalTest(common.HeatTestCase):
def tearDown(self):
super(SignalTest, self).tearDown()
- def create_stack(self, stack_name='test_stack', stub=True):
- templ = template.Template(template_format.parse(test_template_signal))
+ def create_stack(self, templ=test_cfn_template_signal,
+ stack_name='test_stack', stub=True):
+ tpl = template.Template(template_format.parse(templ))
ctx = utils.dummy_context()
ctx.tenant_id = 'test_tenant'
- stack = parser.Stack(ctx, stack_name, templ,
+ stack = parser.Stack(ctx, stack_name, tpl,
disable_rollback=True)
# Stub out the stack ID so we have a known value
@@ -67,23 +109,6 @@ class SignalTest(common.HeatTestCase):
return stack
- def test_handle_create_fail_keypair_raise(self):
- self.stack = self.create_stack(stack_name='create_fail_keypair')
-
- self.m.StubOutWithMock(stack_user.StackUser, '_create_keypair')
- stack_user.StackUser._create_keypair().AndRaise(Exception('Failed'))
- self.m.ReplayAll()
-
- self.stack.create()
-
- rsrc = self.stack['signal_handler']
- rs_data = resource_data_object.ResourceData.get_all(rsrc)
- self.assertEqual((rsrc.CREATE, rsrc.FAILED), rsrc.state)
- self.assertIn('Failed', rsrc.status_reason)
- self.assertEqual('1234', rs_data.get('user_id'))
- self.assertIsNone(rsrc.resource_id)
- self.m.VerifyAll()
-
def test_resource_data(self):
self.stub_keystoneclient(
access='anaccesskey',
@@ -97,6 +122,7 @@ class SignalTest(common.HeatTestCase):
rsrc = self.stack['signal_handler']
self.assertEqual((rsrc.CREATE, rsrc.COMPLETE), rsrc.state)
+ rsrc._create_keypair()
# Ensure the resource data has been stored correctly
rs_data = resource_data_object.ResourceData.get_all(rsrc)
@@ -174,8 +200,131 @@ class SignalTest(common.HeatTestCase):
rsrc = self.stack['signal_handler']
self.assertEqual((rsrc.CREATE, rsrc.COMPLETE), rsrc.state)
- first_url = rsrc.FnGetAtt('AlarmUrl')
- second_url = rsrc.FnGetAtt('AlarmUrl')
+ first_url = rsrc.FnGetAtt('signal')
+ second_url = rsrc.FnGetAtt('signal')
+ self.assertEqual(first_url, second_url)
+ self.m.VerifyAll()
+
+ def test_FnGetAtt_Heat_Signal(self):
+ self.stack = self.create_stack(test_heat_template_signal)
+ self.m.StubOutWithMock(self.stack.clients.client_plugin('heat'),
+ 'get_heat_url')
+
+ self.stack.clients.client_plugin('heat').get_heat_url().AndReturn(
+ 'http://server.test:8004/v1')
+
+ self.m.ReplayAll()
+ self.stack.create()
+
+ rsrc = self.stack['signal_handler']
+ self.assertEqual((rsrc.CREATE, rsrc.COMPLETE), rsrc.state)
+
+ signal = rsrc.FnGetAtt('signal')
+ self.assertEqual('http://localhost:5000/v3', signal['auth_url'])
+ self.assertEqual('aprojectid', signal['project_id'])
+ self.assertEqual('1234', signal['user_id'])
+ self.assertIn('username', signal)
+ self.assertIn('password', signal)
+ self.m.VerifyAll()
+
+ def test_FnGetAtt_Heat_Signal_is_cached(self):
+ self.stack = self.create_stack(test_heat_template_signal)
+
+ self.m.ReplayAll()
+ self.stack.create()
+
+ rsrc = self.stack['signal_handler']
+ self.assertEqual((rsrc.CREATE, rsrc.COMPLETE), rsrc.state)
+
+ first_url = rsrc.FnGetAtt('signal')
+ second_url = rsrc.FnGetAtt('signal')
+ self.assertEqual(first_url, second_url)
+ self.m.VerifyAll()
+
+ def test_FnGetAtt_Zaqar_Signal(self):
+ self.stack = self.create_stack(test_zaqar_template_signal)
+
+ self.m.ReplayAll()
+ self.stack.create()
+
+ rsrc = self.stack['signal_handler']
+ self.assertEqual((rsrc.CREATE, rsrc.COMPLETE), rsrc.state)
+
+ signal = rsrc.FnGetAtt('signal')
+ self.assertEqual('http://localhost:5000/v3', signal['auth_url'])
+ self.assertEqual('aprojectid', signal['project_id'])
+ self.assertEqual('1234', signal['user_id'])
+ self.assertIn('username', signal)
+ self.assertIn('password', signal)
+ self.assertIn('queue_id', signal)
+ self.m.VerifyAll()
+
+ def test_FnGetAtt_Zaqar_Signal_is_cached(self):
+ self.stack = self.create_stack(test_zaqar_template_signal)
+
+ self.m.ReplayAll()
+ self.stack.create()
+
+ rsrc = self.stack['signal_handler']
+ self.assertEqual((rsrc.CREATE, rsrc.COMPLETE), rsrc.state)
+
+ first_url = rsrc.FnGetAtt('signal')
+ second_url = rsrc.FnGetAtt('signal')
+ self.assertEqual(first_url, second_url)
+ self.m.VerifyAll()
+
+ def test_FnGetAtt_Swift_Signal(self):
+ self.stack = self.create_stack(test_swift_template_signal)
+ self.m.StubOutWithMock(self.stack.clients.client('swift'),
+ 'put_container')
+ self.m.StubOutWithMock(self.stack.clients.client('swift'),
+ 'put_object')
+ self.m.StubOutWithMock(self.stack.clients.client_plugin('swift'),
+ 'get_temp_url')
+
+ self.stack.clients.client('swift').put_container(
+ mox.IgnoreArg()).AndReturn(None)
+ self.stack.clients.client_plugin('swift').get_temp_url(
+ mox.IgnoreArg(), mox.IgnoreArg()).AndReturn(
+ 'http://192.0.2.1/v1/AUTH_aprojectid/foo/bar')
+ self.stack.clients.client('swift').put_object(
+ mox.IgnoreArg(), mox.IgnoreArg(), mox.IgnoreArg()).AndReturn(None)
+
+ self.m.ReplayAll()
+ self.stack.create()
+
+ rsrc = self.stack['signal_handler']
+ self.assertEqual((rsrc.CREATE, rsrc.COMPLETE), rsrc.state)
+
+ self.assertEqual('http://192.0.2.1/v1/AUTH_aprojectid/foo/bar',
+ rsrc.FnGetAtt('AlarmUrl'))
+ self.m.VerifyAll()
+
+ def test_FnGetAtt_Swift_Signal_is_cached(self):
+ self.stack = self.create_stack(test_swift_template_signal)
+ self.m.StubOutWithMock(self.stack.clients.client('swift'),
+ 'put_container')
+ self.m.StubOutWithMock(self.stack.clients.client('swift'),
+ 'put_object')
+ self.m.StubOutWithMock(self.stack.clients.client_plugin('swift'),
+ 'get_temp_url')
+
+ self.stack.clients.client('swift').put_container(
+ mox.IgnoreArg()).AndReturn(None)
+ self.stack.clients.client_plugin('swift').get_temp_url(
+ mox.IgnoreArg(), mox.IgnoreArg()).AndReturn(
+ 'http://192.0.2.1/v1/AUTH_aprojectid/foo/' + uuid.uuid4().hex)
+ self.stack.clients.client('swift').put_object(
+ mox.IgnoreArg(), mox.IgnoreArg(), mox.IgnoreArg()).AndReturn(None)
+
+ self.m.ReplayAll()
+ self.stack.create()
+
+ rsrc = self.stack['signal_handler']
+ self.assertEqual((rsrc.CREATE, rsrc.COMPLETE), rsrc.state)
+
+ first_url = rsrc.FnGetAtt('signal')
+ second_url = rsrc.FnGetAtt('signal')
self.assertEqual(first_url, second_url)
self.m.VerifyAll()
@@ -190,6 +339,7 @@ class SignalTest(common.HeatTestCase):
self.stack.create()
rsrc = self.stack['signal_handler']
+ rsrc.resource_id_set('signal')
self.assertEqual((rsrc.CREATE, rsrc.COMPLETE), rsrc.state)
self.assertIn('http://server.test:8000/v1/signal',
diff --git a/heat/tests/test_software_deployment.py b/heat/tests/test_software_deployment.py
index b746092b3..45a4d073f 100644
--- a/heat/tests/test_software_deployment.py
+++ b/heat/tests/test_software_deployment.py
@@ -979,22 +979,22 @@ class SoftwareDeploymentTest(common.HeatTestCase):
self.deployment.id = 23
self.deployment.uuid = str(uuid.uuid4())
self.deployment.action = self.deployment.CREATE
- container = self.deployment.physical_resource_name()
+ object_name = self.deployment.physical_resource_name()
- temp_url = self.deployment._get_temp_url()
+ temp_url = self.deployment._get_swift_signal_url()
temp_url_pattern = re.compile(
'^http://192.0.2.1/v1/AUTH_test_tenant_id/'
- '(software_deployment_test_stack-deployment_mysql-.*)/(.*)'
+ '(.*)/(software_deployment_test_stack-deployment_mysql-.*)'
'\\?temp_url_sig=.*&temp_url_expires=\\d*$')
self.assertRegex(temp_url, temp_url_pattern)
m = temp_url_pattern.search(temp_url)
- object_name = m.group(2)
- self.assertEqual(container, m.group(1))
- self.assertEqual(dep_data['signal_object_name'], object_name)
+ container = m.group(1)
+ self.assertEqual(object_name, m.group(2))
+ self.assertEqual(dep_data['swift_signal_object_name'], object_name)
- self.assertEqual(dep_data['signal_temp_url'], temp_url)
+ self.assertEqual(dep_data['swift_signal_url'], temp_url)
- self.assertEqual(temp_url, self.deployment._get_temp_url())
+ self.assertEqual(temp_url, self.deployment._get_swift_signal_url())
sc.put_container.assert_called_once_with(container)
sc.put_object.assert_called_once_with(container, object_name, '')
@@ -1002,7 +1002,7 @@ class SoftwareDeploymentTest(common.HeatTestCase):
def test_delete_temp_url(self):
object_name = str(uuid.uuid4())
dep_data = {
- 'signal_object_name': object_name
+ 'swift_signal_object_name': object_name
}
self._create_stack(self.template_temp_url_signal)
@@ -1021,31 +1021,34 @@ class SoftwareDeploymentTest(common.HeatTestCase):
self.deployment.id = 23
self.deployment.uuid = str(uuid.uuid4())
container = self.deployment.physical_resource_name()
- self.deployment._delete_temp_url()
+ self.deployment._delete_swift_signal_url()
sc.delete_object.assert_called_once_with(container, object_name)
self.assertEqual(
- [mock.call('signal_object_name'), mock.call('signal_temp_url')],
+ [mock.call('swift_signal_object_name'),
+ mock.call('swift_signal_url')],
self.deployment.data_delete.mock_calls)
swift_exc = swift.SwiftClientPlugin.exceptions_module
sc.delete_object.side_effect = swift_exc.ClientException(
'Not found', http_status=404)
- self.deployment._delete_temp_url()
+ self.deployment._delete_swift_signal_url()
self.assertEqual(
- [mock.call('signal_object_name'), mock.call('signal_temp_url'),
- mock.call('signal_object_name'), mock.call('signal_temp_url')],
+ [mock.call('swift_signal_object_name'),
+ mock.call('swift_signal_url'),
+ mock.call('swift_signal_object_name'),
+ mock.call('swift_signal_url')],
self.deployment.data_delete.mock_calls)
- del(dep_data['signal_object_name'])
+ del(dep_data['swift_signal_object_name'])
self.deployment.physical_resource_name = mock.Mock()
- self.deployment._delete_temp_url()
+ self.deployment._delete_swift_signal_url()
self.assertFalse(self.deployment.physical_resource_name.called)
def test_handle_action_temp_url(self):
self._create_stack(self.template_temp_url_signal)
dep_data = {
- 'signal_temp_url': (
+ 'swift_signal_url': (
'http://192.0.2.1/v1/AUTH_a/b/c'
'?temp_url_sig=ctemp_url_expires=1234')
}
@@ -1079,17 +1082,18 @@ class SoftwareDeploymentTest(common.HeatTestCase):
self.deployment.uuid = str(uuid.uuid4())
self.deployment.action = self.deployment.CREATE
- queue_id = self.deployment._get_queue_id()
+ queue_id = self.deployment._get_zaqar_signal_queue_id()
self.assertEqual(2, len(zc.queue.mock_calls))
self.assertEqual(queue_id, zc.queue.mock_calls[0][1][0])
- self.assertEqual(queue_id, dep_data['signal_queue_id'])
+ self.assertEqual(queue_id, dep_data['zaqar_signal_queue_id'])
- self.assertEqual(queue_id, self.deployment._get_queue_id())
+ self.assertEqual(queue_id,
+ self.deployment._get_zaqar_signal_queue_id())
def test_delete_zaqar_queue(self):
queue_id = str(uuid.uuid4())
dep_data = {
- 'signal_queue_id': queue_id
+ 'zaqar_signal_queue_id': queue_id
}
self._create_stack(self.template_zaqar_signal)
@@ -1103,23 +1107,24 @@ class SoftwareDeploymentTest(common.HeatTestCase):
self.deployment.id = 23
self.deployment.uuid = str(uuid.uuid4())
- self.deployment._delete_queue()
+ self.deployment._delete_zaqar_signal_queue()
zc.queue.assert_called_once_with(queue_id)
self.assertTrue(zc.queue(self.deployment.uuid).delete.called)
self.assertEqual(
- [mock.call('signal_queue_id')],
+ [mock.call('zaqar_signal_queue_id')],
self.deployment.data_delete.mock_calls)
zaqar_exc = zaqar.ZaqarClientPlugin.exceptions_module
zc.queue.delete.side_effect = zaqar_exc.ResourceNotFound()
- self.deployment._delete_queue()
+ self.deployment._delete_zaqar_signal_queue()
self.assertEqual(
- [mock.call('signal_queue_id'), mock.call('signal_queue_id')],
+ [mock.call('zaqar_signal_queue_id'),
+ mock.call('zaqar_signal_queue_id')],
self.deployment.data_delete.mock_calls)
- dep_data.pop('signal_queue_id')
+ dep_data.pop('zaqar_signal_queue_id')
self.deployment.physical_resource_name = mock.Mock()
- self.deployment._delete_queue()
+ self.deployment._delete_zaqar_signal_queue()
self.assertEqual(2, len(self.deployment.data_delete.mock_calls))