Move signals to SignalResponder class
This change relocates the code that creates and deletes heat, swift and zaqar signals out of SoftwareDeployment and into SignalResponder, as a first step in making these signals available to all resources. As part of this change the structure of the Swift URLs was changed to match that of the SwiftSignal resource. Change-Id: Id5701b3696b0ab41433a3f158fabce1f36aabe16 Implements: blueprint uniform-resource-signals
This commit is contained in:
parent
74fe413631
commit
ca8effbbae
@ -13,7 +13,6 @@
|
|||||||
|
|
||||||
import copy
|
import copy
|
||||||
import six
|
import six
|
||||||
import uuid
|
|
||||||
|
|
||||||
from oslo_config import cfg
|
from oslo_config import cfg
|
||||||
from oslo_log import log as logging
|
from oslo_log import log as logging
|
||||||
@ -315,63 +314,6 @@ class SoftwareDeployment(signal_responder.SignalResponder):
|
|||||||
def _build_derived_options(self, action, source):
|
def _build_derived_options(self, action, source):
|
||||||
return source.get(sc.SoftwareConfig.OPTIONS)
|
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):
|
def _build_derived_inputs(self, action, source):
|
||||||
scl = sc.SoftwareConfig
|
scl = sc.SoftwareConfig
|
||||||
inputs = copy.deepcopy(source.get(scl.INPUTS)) or []
|
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 '
|
scl.DESCRIPTION: _('ID of signal to use for signaling '
|
||||||
'output values'),
|
'output values'),
|
||||||
scl.TYPE: 'String',
|
scl.TYPE: 'String',
|
||||||
'value': self._get_temp_url()
|
'value': self._get_swift_signal_url()
|
||||||
})
|
})
|
||||||
inputs.append({
|
inputs.append({
|
||||||
scl.NAME: self.DEPLOY_SIGNAL_VERB,
|
scl.NAME: self.DEPLOY_SIGNAL_VERB,
|
||||||
@ -450,31 +392,32 @@ class SoftwareDeployment(signal_responder.SignalResponder):
|
|||||||
'value': 'PUT'
|
'value': 'PUT'
|
||||||
})
|
})
|
||||||
elif self._signal_transport_heat() or self._signal_transport_zaqar():
|
elif self._signal_transport_heat() or self._signal_transport_zaqar():
|
||||||
|
creds = self._get_heat_signal_credentials()
|
||||||
inputs.extend([{
|
inputs.extend([{
|
||||||
scl.NAME: self.DEPLOY_AUTH_URL,
|
scl.NAME: self.DEPLOY_AUTH_URL,
|
||||||
scl.DESCRIPTION: _('URL for API authentication'),
|
scl.DESCRIPTION: _('URL for API authentication'),
|
||||||
scl.TYPE: 'String',
|
scl.TYPE: 'String',
|
||||||
'value': self.keystone().v3_endpoint
|
'value': creds['auth_url']
|
||||||
}, {
|
}, {
|
||||||
scl.NAME: self.DEPLOY_USERNAME,
|
scl.NAME: self.DEPLOY_USERNAME,
|
||||||
scl.DESCRIPTION: _('Username for API authentication'),
|
scl.DESCRIPTION: _('Username for API authentication'),
|
||||||
scl.TYPE: 'String',
|
scl.TYPE: 'String',
|
||||||
'value': self.physical_resource_name(),
|
'value': creds['username']
|
||||||
}, {
|
}, {
|
||||||
scl.NAME: self.DEPLOY_USER_ID,
|
scl.NAME: self.DEPLOY_USER_ID,
|
||||||
scl.DESCRIPTION: _('User ID for API authentication'),
|
scl.DESCRIPTION: _('User ID for API authentication'),
|
||||||
scl.TYPE: 'String',
|
scl.TYPE: 'String',
|
||||||
'value': self._get_user_id(),
|
'value': creds['user_id']
|
||||||
}, {
|
}, {
|
||||||
scl.NAME: self.DEPLOY_PASSWORD,
|
scl.NAME: self.DEPLOY_PASSWORD,
|
||||||
scl.DESCRIPTION: _('Password for API authentication'),
|
scl.DESCRIPTION: _('Password for API authentication'),
|
||||||
scl.TYPE: 'String',
|
scl.TYPE: 'String',
|
||||||
'value': self.password
|
'value': creds['password']
|
||||||
}, {
|
}, {
|
||||||
scl.NAME: self.DEPLOY_PROJECT_ID,
|
scl.NAME: self.DEPLOY_PROJECT_ID,
|
||||||
scl.DESCRIPTION: _('ID of project for API authentication'),
|
scl.DESCRIPTION: _('ID of project for API authentication'),
|
||||||
scl.TYPE: 'String',
|
scl.TYPE: 'String',
|
||||||
'value': self.stack.stack_user_project_id
|
'value': creds['project_id']
|
||||||
}])
|
}])
|
||||||
if self._signal_transport_zaqar():
|
if self._signal_transport_zaqar():
|
||||||
inputs.append({
|
inputs.append({
|
||||||
@ -482,31 +425,14 @@ class SoftwareDeployment(signal_responder.SignalResponder):
|
|||||||
scl.DESCRIPTION: _('ID of queue to use for signaling '
|
scl.DESCRIPTION: _('ID of queue to use for signaling '
|
||||||
'output values'),
|
'output values'),
|
||||||
scl.TYPE: 'String',
|
scl.TYPE: 'String',
|
||||||
'value': self._get_queue_id()
|
'value': self._get_zaqar_signal_queue_id()
|
||||||
})
|
})
|
||||||
|
|
||||||
return inputs
|
return inputs
|
||||||
|
|
||||||
def handle_create(self):
|
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)
|
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):
|
def check_create_complete(self, sd):
|
||||||
if not sd:
|
if not sd:
|
||||||
return True
|
return True
|
||||||
@ -536,15 +462,8 @@ class SoftwareDeployment(signal_responder.SignalResponder):
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
def _delete_resource(self):
|
def _delete_resource(self):
|
||||||
if self._signal_transport_cfn():
|
self._delete_signals()
|
||||||
self._delete_ec2_signed_url()
|
|
||||||
self._delete_user()
|
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()
|
|
||||||
|
|
||||||
derived_config_id = None
|
derived_config_id = None
|
||||||
if self.resource_id is not None:
|
if self.resource_id is not None:
|
||||||
|
@ -11,6 +11,8 @@
|
|||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
|
import uuid
|
||||||
|
|
||||||
from keystoneclient.contrib.ec2 import utils as ec2_utils
|
from keystoneclient.contrib.ec2 import utils as ec2_utils
|
||||||
from oslo_config import cfg
|
from oslo_config import cfg
|
||||||
from oslo_log import log as logging
|
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
|
# API operations as a consequence of handling a signal
|
||||||
requires_deferred_auth = True
|
requires_deferred_auth = True
|
||||||
|
|
||||||
def handle_create(self):
|
|
||||||
super(SignalResponder, self).handle_create()
|
|
||||||
self._create_keypair()
|
|
||||||
|
|
||||||
def handle_delete(self):
|
def handle_delete(self):
|
||||||
|
self._delete_signals()
|
||||||
super(SignalResponder, self).handle_delete()
|
super(SignalResponder, self).handle_delete()
|
||||||
|
|
||||||
|
def _delete_signals(self):
|
||||||
self._delete_ec2_signed_url()
|
self._delete_ec2_signed_url()
|
||||||
self._delete_heat_signal_url()
|
self._delete_heat_signal_url()
|
||||||
|
self._delete_swift_signal_url()
|
||||||
|
self._delete_zaqar_signal_queue()
|
||||||
|
|
||||||
def _delete_ec2_signed_url(self):
|
@property
|
||||||
self.data_delete('ec2_signed_url')
|
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):
|
def _get_ec2_signed_url(self, signal_type=SIGNAL):
|
||||||
"""Create properly formatted and pre-signed URL.
|
"""Create properly formatted and pre-signed URL.
|
||||||
@ -64,9 +91,19 @@ class SignalResponder(stack_user.StackUser):
|
|||||||
access_key = self.data().get('access_key')
|
access_key = self.data().get('access_key')
|
||||||
secret_key = self.data().get('secret_key')
|
secret_key = self.data().get('secret_key')
|
||||||
|
|
||||||
|
if not access_key or not secret_key:
|
||||||
|
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:
|
if not access_key or not secret_key:
|
||||||
LOG.warn(_LW('Cannot generate signed url, '
|
LOG.warn(_LW('Cannot generate signed url, '
|
||||||
'no stored access/secret key'))
|
'unable to create keypair'))
|
||||||
return
|
return
|
||||||
|
|
||||||
config_url = cfg.CONF.heat_waitcondition_server_url
|
config_url = cfg.CONF.heat_waitcondition_server_url
|
||||||
@ -106,14 +143,23 @@ class SignalResponder(stack_user.StackUser):
|
|||||||
self.data_set('ec2_signed_url', url)
|
self.data_set('ec2_signed_url', url)
|
||||||
return url
|
return url
|
||||||
|
|
||||||
def _delete_heat_signal_url(self):
|
def _delete_ec2_signed_url(self):
|
||||||
self.data_delete('heat_signal_url')
|
self.data_delete('ec2_signed_url')
|
||||||
|
self._delete_keypair()
|
||||||
|
|
||||||
def _get_heat_signal_url(self):
|
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')
|
stored = self.data().get('heat_signal_url')
|
||||||
if stored is not None:
|
if stored is not None:
|
||||||
return stored
|
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()
|
url = self.client_plugin('heat').get_heat_url()
|
||||||
host_url = urlparse.urlparse(url)
|
host_url = urlparse.urlparse(url)
|
||||||
path = self.identifier().url_path()
|
path = self.identifier().url_path()
|
||||||
@ -123,3 +169,84 @@ class SignalResponder(stack_user.StackUser):
|
|||||||
|
|
||||||
self.data_set('heat_signal_url', url)
|
self.data_set('heat_signal_url', url)
|
||||||
return 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')
|
||||||
|
@ -34,6 +34,10 @@ class StackUser(resource.Resource):
|
|||||||
self._create_user()
|
self._create_user()
|
||||||
|
|
||||||
def _create_user(self):
|
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
|
# Check for stack user project, create if not yet set
|
||||||
if not self.stack.stack_user_project_id:
|
if not self.stack.stack_user_project_id:
|
||||||
project_id = self.keystone().create_stack_domain_project(
|
project_id = self.keystone().create_stack_domain_project(
|
||||||
@ -85,6 +89,10 @@ class StackUser(resource.Resource):
|
|||||||
user_id = self._get_user_id()
|
user_id = self._get_user_id()
|
||||||
if user_id is None:
|
if user_id is None:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
# the user is going away, so we want the keypair gone as well
|
||||||
|
self._delete_keypair()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
self.keystone().delete_stack_domain_user(
|
self.keystone().delete_stack_domain_user(
|
||||||
user_id=user_id, project_id=self.stack.stack_user_project_id)
|
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)
|
self.keystone().delete_stack_user(user_id)
|
||||||
except kc_exception.NotFound:
|
except kc_exception.NotFound:
|
||||||
pass
|
pass
|
||||||
for data_key in ('credential_id', 'access_key', 'secret_key'):
|
self.data_delete('user_id')
|
||||||
self.data_delete(data_key)
|
|
||||||
|
|
||||||
def handle_suspend(self):
|
def handle_suspend(self):
|
||||||
user_id = self._get_user_id()
|
user_id = self._get_user_id()
|
||||||
@ -125,6 +132,9 @@ class StackUser(resource.Resource):
|
|||||||
# Subclasses may optionally call this in handle_create to create
|
# Subclasses may optionally call this in handle_create to create
|
||||||
# an ec2 keypair associated with the user, the resulting keys are
|
# an ec2 keypair associated with the user, the resulting keys are
|
||||||
# stored in resource_data
|
# stored in resource_data
|
||||||
|
if self.data().get('credential_id'):
|
||||||
|
return # a keypair was created already
|
||||||
|
|
||||||
user_id = self._get_user_id()
|
user_id = self._get_user_id()
|
||||||
kp = self.keystone().create_stack_domain_user_keypair(
|
kp = self.keystone().create_stack_domain_user_keypair(
|
||||||
user_id=user_id, project_id=self.stack.stack_user_project_id)
|
user_id=user_id, project_id=self.stack.stack_user_project_id)
|
||||||
@ -146,10 +156,12 @@ class StackUser(resource.Resource):
|
|||||||
def _delete_keypair(self):
|
def _delete_keypair(self):
|
||||||
# Subclasses may optionally call this to delete a keypair created
|
# Subclasses may optionally call this to delete a keypair created
|
||||||
# via _create_keypair
|
# via _create_keypair
|
||||||
user_id = self._get_user_id()
|
|
||||||
credential_id = self.data().get('credential_id')
|
credential_id = self.data().get('credential_id')
|
||||||
if not credential_id:
|
if not credential_id:
|
||||||
return
|
return
|
||||||
|
user_id = self._get_user_id()
|
||||||
|
if user_id is None:
|
||||||
|
return
|
||||||
|
|
||||||
try:
|
try:
|
||||||
self.keystone().delete_stack_domain_user_keypair(
|
self.keystone().delete_stack_domain_user_keypair(
|
||||||
|
@ -109,6 +109,7 @@ class FakeKeystoneClient(object):
|
|||||||
self.credential_id = credential_id
|
self.credential_id = credential_id
|
||||||
self.token = auth_token
|
self.token = auth_token
|
||||||
self.context = context
|
self.context = context
|
||||||
|
self.v3_endpoint = 'http://localhost:5000/v3'
|
||||||
|
|
||||||
class FakeCred(object):
|
class FakeCred(object):
|
||||||
id = self.credential_id
|
id = self.credential_id
|
||||||
|
@ -132,8 +132,11 @@ class ResourceWithRequiredProps(GenericResource):
|
|||||||
|
|
||||||
|
|
||||||
class SignalResource(signal_responder.SignalResponder):
|
class SignalResource(signal_responder.SignalResponder):
|
||||||
properties_schema = {}
|
properties_schema = {
|
||||||
attributes_schema = {'AlarmUrl': attributes.Schema('Get a signed webhook')}
|
'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):
|
def handle_create(self):
|
||||||
super(SignalResource, self).handle_create()
|
super(SignalResource, self).handle_create()
|
||||||
@ -144,8 +147,22 @@ class SignalResource(signal_responder.SignalResponder):
|
|||||||
{'type': self.type(), 'details': details})
|
{'type': self.type(), 'details': details})
|
||||||
|
|
||||||
def _resolve_attribute(self, name):
|
def _resolve_attribute(self, name):
|
||||||
if name == 'AlarmUrl' and self.resource_id is not None:
|
if self.resource_id is not None:
|
||||||
return six.text_type(self._get_ec2_signed_url())
|
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):
|
class StackUserResource(stack_user.StackUser):
|
||||||
|
@ -12,14 +12,15 @@
|
|||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
import datetime
|
import datetime
|
||||||
import six
|
import uuid
|
||||||
|
|
||||||
from keystoneclient import exceptions as kc_exceptions
|
from keystoneclient import exceptions as kc_exceptions
|
||||||
|
import mox
|
||||||
|
import six
|
||||||
|
|
||||||
from heat.common import exception
|
from heat.common import exception
|
||||||
from heat.common import template_format
|
from heat.common import template_format
|
||||||
from heat.engine import resource
|
from heat.engine import resource
|
||||||
from heat.engine.resources import stack_user
|
|
||||||
from heat.engine import scheduler
|
from heat.engine import scheduler
|
||||||
from heat.engine import stack as parser
|
from heat.engine import stack as parser
|
||||||
from heat.engine import template
|
from heat.engine import template
|
||||||
@ -30,13 +31,53 @@ from heat.tests import generic_resource
|
|||||||
from heat.tests import utils
|
from heat.tests import utils
|
||||||
|
|
||||||
|
|
||||||
test_template_signal = '''
|
test_cfn_template_signal = '''
|
||||||
{
|
{
|
||||||
"AWSTemplateFormatVersion" : "2010-09-09",
|
"AWSTemplateFormatVersion" : "2010-09-09",
|
||||||
"Description" : "Just a test.",
|
"Description" : "Just a test.",
|
||||||
"Parameters" : {},
|
"Parameters" : {},
|
||||||
"Resources" : {
|
"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"}
|
"resource_X" : {"Type" : "GenericResourceType"}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -52,11 +93,12 @@ class SignalTest(common.HeatTestCase):
|
|||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
super(SignalTest, self).tearDown()
|
super(SignalTest, self).tearDown()
|
||||||
|
|
||||||
def create_stack(self, stack_name='test_stack', stub=True):
|
def create_stack(self, templ=test_cfn_template_signal,
|
||||||
templ = template.Template(template_format.parse(test_template_signal))
|
stack_name='test_stack', stub=True):
|
||||||
|
tpl = template.Template(template_format.parse(templ))
|
||||||
ctx = utils.dummy_context()
|
ctx = utils.dummy_context()
|
||||||
ctx.tenant_id = 'test_tenant'
|
ctx.tenant_id = 'test_tenant'
|
||||||
stack = parser.Stack(ctx, stack_name, templ,
|
stack = parser.Stack(ctx, stack_name, tpl,
|
||||||
disable_rollback=True)
|
disable_rollback=True)
|
||||||
|
|
||||||
# Stub out the stack ID so we have a known value
|
# Stub out the stack ID so we have a known value
|
||||||
@ -67,23 +109,6 @@ class SignalTest(common.HeatTestCase):
|
|||||||
|
|
||||||
return stack
|
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):
|
def test_resource_data(self):
|
||||||
self.stub_keystoneclient(
|
self.stub_keystoneclient(
|
||||||
access='anaccesskey',
|
access='anaccesskey',
|
||||||
@ -97,6 +122,7 @@ class SignalTest(common.HeatTestCase):
|
|||||||
|
|
||||||
rsrc = self.stack['signal_handler']
|
rsrc = self.stack['signal_handler']
|
||||||
self.assertEqual((rsrc.CREATE, rsrc.COMPLETE), rsrc.state)
|
self.assertEqual((rsrc.CREATE, rsrc.COMPLETE), rsrc.state)
|
||||||
|
rsrc._create_keypair()
|
||||||
|
|
||||||
# Ensure the resource data has been stored correctly
|
# Ensure the resource data has been stored correctly
|
||||||
rs_data = resource_data_object.ResourceData.get_all(rsrc)
|
rs_data = resource_data_object.ResourceData.get_all(rsrc)
|
||||||
@ -174,8 +200,131 @@ class SignalTest(common.HeatTestCase):
|
|||||||
rsrc = self.stack['signal_handler']
|
rsrc = self.stack['signal_handler']
|
||||||
self.assertEqual((rsrc.CREATE, rsrc.COMPLETE), rsrc.state)
|
self.assertEqual((rsrc.CREATE, rsrc.COMPLETE), rsrc.state)
|
||||||
|
|
||||||
first_url = rsrc.FnGetAtt('AlarmUrl')
|
first_url = rsrc.FnGetAtt('signal')
|
||||||
second_url = rsrc.FnGetAtt('AlarmUrl')
|
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.assertEqual(first_url, second_url)
|
||||||
self.m.VerifyAll()
|
self.m.VerifyAll()
|
||||||
|
|
||||||
@ -190,6 +339,7 @@ class SignalTest(common.HeatTestCase):
|
|||||||
self.stack.create()
|
self.stack.create()
|
||||||
|
|
||||||
rsrc = self.stack['signal_handler']
|
rsrc = self.stack['signal_handler']
|
||||||
|
rsrc.resource_id_set('signal')
|
||||||
self.assertEqual((rsrc.CREATE, rsrc.COMPLETE), rsrc.state)
|
self.assertEqual((rsrc.CREATE, rsrc.COMPLETE), rsrc.state)
|
||||||
|
|
||||||
self.assertIn('http://server.test:8000/v1/signal',
|
self.assertIn('http://server.test:8000/v1/signal',
|
||||||
|
@ -979,22 +979,22 @@ class SoftwareDeploymentTest(common.HeatTestCase):
|
|||||||
self.deployment.id = 23
|
self.deployment.id = 23
|
||||||
self.deployment.uuid = str(uuid.uuid4())
|
self.deployment.uuid = str(uuid.uuid4())
|
||||||
self.deployment.action = self.deployment.CREATE
|
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(
|
temp_url_pattern = re.compile(
|
||||||
'^http://192.0.2.1/v1/AUTH_test_tenant_id/'
|
'^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*$')
|
'\\?temp_url_sig=.*&temp_url_expires=\\d*$')
|
||||||
self.assertRegex(temp_url, temp_url_pattern)
|
self.assertRegex(temp_url, temp_url_pattern)
|
||||||
m = temp_url_pattern.search(temp_url)
|
m = temp_url_pattern.search(temp_url)
|
||||||
object_name = m.group(2)
|
container = m.group(1)
|
||||||
self.assertEqual(container, m.group(1))
|
self.assertEqual(object_name, m.group(2))
|
||||||
self.assertEqual(dep_data['signal_object_name'], object_name)
|
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_container.assert_called_once_with(container)
|
||||||
sc.put_object.assert_called_once_with(container, object_name, '')
|
sc.put_object.assert_called_once_with(container, object_name, '')
|
||||||
@ -1002,7 +1002,7 @@ class SoftwareDeploymentTest(common.HeatTestCase):
|
|||||||
def test_delete_temp_url(self):
|
def test_delete_temp_url(self):
|
||||||
object_name = str(uuid.uuid4())
|
object_name = str(uuid.uuid4())
|
||||||
dep_data = {
|
dep_data = {
|
||||||
'signal_object_name': object_name
|
'swift_signal_object_name': object_name
|
||||||
}
|
}
|
||||||
self._create_stack(self.template_temp_url_signal)
|
self._create_stack(self.template_temp_url_signal)
|
||||||
|
|
||||||
@ -1021,31 +1021,34 @@ class SoftwareDeploymentTest(common.HeatTestCase):
|
|||||||
self.deployment.id = 23
|
self.deployment.id = 23
|
||||||
self.deployment.uuid = str(uuid.uuid4())
|
self.deployment.uuid = str(uuid.uuid4())
|
||||||
container = self.deployment.physical_resource_name()
|
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)
|
sc.delete_object.assert_called_once_with(container, object_name)
|
||||||
self.assertEqual(
|
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)
|
self.deployment.data_delete.mock_calls)
|
||||||
|
|
||||||
swift_exc = swift.SwiftClientPlugin.exceptions_module
|
swift_exc = swift.SwiftClientPlugin.exceptions_module
|
||||||
sc.delete_object.side_effect = swift_exc.ClientException(
|
sc.delete_object.side_effect = swift_exc.ClientException(
|
||||||
'Not found', http_status=404)
|
'Not found', http_status=404)
|
||||||
self.deployment._delete_temp_url()
|
self.deployment._delete_swift_signal_url()
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
[mock.call('signal_object_name'), mock.call('signal_temp_url'),
|
[mock.call('swift_signal_object_name'),
|
||||||
mock.call('signal_object_name'), mock.call('signal_temp_url')],
|
mock.call('swift_signal_url'),
|
||||||
|
mock.call('swift_signal_object_name'),
|
||||||
|
mock.call('swift_signal_url')],
|
||||||
self.deployment.data_delete.mock_calls)
|
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.physical_resource_name = mock.Mock()
|
||||||
self.deployment._delete_temp_url()
|
self.deployment._delete_swift_signal_url()
|
||||||
self.assertFalse(self.deployment.physical_resource_name.called)
|
self.assertFalse(self.deployment.physical_resource_name.called)
|
||||||
|
|
||||||
def test_handle_action_temp_url(self):
|
def test_handle_action_temp_url(self):
|
||||||
|
|
||||||
self._create_stack(self.template_temp_url_signal)
|
self._create_stack(self.template_temp_url_signal)
|
||||||
dep_data = {
|
dep_data = {
|
||||||
'signal_temp_url': (
|
'swift_signal_url': (
|
||||||
'http://192.0.2.1/v1/AUTH_a/b/c'
|
'http://192.0.2.1/v1/AUTH_a/b/c'
|
||||||
'?temp_url_sig=ctemp_url_expires=1234')
|
'?temp_url_sig=ctemp_url_expires=1234')
|
||||||
}
|
}
|
||||||
@ -1079,17 +1082,18 @@ class SoftwareDeploymentTest(common.HeatTestCase):
|
|||||||
self.deployment.uuid = str(uuid.uuid4())
|
self.deployment.uuid = str(uuid.uuid4())
|
||||||
self.deployment.action = self.deployment.CREATE
|
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(2, len(zc.queue.mock_calls))
|
||||||
self.assertEqual(queue_id, zc.queue.mock_calls[0][1][0])
|
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):
|
def test_delete_zaqar_queue(self):
|
||||||
queue_id = str(uuid.uuid4())
|
queue_id = str(uuid.uuid4())
|
||||||
dep_data = {
|
dep_data = {
|
||||||
'signal_queue_id': queue_id
|
'zaqar_signal_queue_id': queue_id
|
||||||
}
|
}
|
||||||
self._create_stack(self.template_zaqar_signal)
|
self._create_stack(self.template_zaqar_signal)
|
||||||
|
|
||||||
@ -1103,23 +1107,24 @@ class SoftwareDeploymentTest(common.HeatTestCase):
|
|||||||
|
|
||||||
self.deployment.id = 23
|
self.deployment.id = 23
|
||||||
self.deployment.uuid = str(uuid.uuid4())
|
self.deployment.uuid = str(uuid.uuid4())
|
||||||
self.deployment._delete_queue()
|
self.deployment._delete_zaqar_signal_queue()
|
||||||
zc.queue.assert_called_once_with(queue_id)
|
zc.queue.assert_called_once_with(queue_id)
|
||||||
zc.queue.delete.assert_called_once()
|
zc.queue.delete.assert_called_once()
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
[mock.call('signal_queue_id')],
|
[mock.call('zaqar_signal_queue_id')],
|
||||||
self.deployment.data_delete.mock_calls)
|
self.deployment.data_delete.mock_calls)
|
||||||
|
|
||||||
zaqar_exc = zaqar.ZaqarClientPlugin.exceptions_module
|
zaqar_exc = zaqar.ZaqarClientPlugin.exceptions_module
|
||||||
zc.queue.delete.side_effect = zaqar_exc.ResourceNotFound()
|
zc.queue.delete.side_effect = zaqar_exc.ResourceNotFound()
|
||||||
self.deployment._delete_queue()
|
self.deployment._delete_zaqar_signal_queue()
|
||||||
self.assertEqual(
|
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)
|
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.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))
|
self.assertEqual(2, len(self.deployment.data_delete.mock_calls))
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user