Merge "Use Zaqar for software-config transport"
This commit is contained in:
commit
6a8fb271ca
|
@ -28,6 +28,8 @@ class ZaqarClientPlugin(client_plugin.ClientPlugin):
|
||||||
exceptions_module = zaqar_errors
|
exceptions_module = zaqar_errors
|
||||||
service_types = ['messaging']
|
service_types = ['messaging']
|
||||||
|
|
||||||
|
DEFAULT_TTL = 3600
|
||||||
|
|
||||||
def _create(self):
|
def _create(self):
|
||||||
return self.create_for_tenant(self.context.tenant_id)
|
return self.create_for_tenant(self.context.tenant_id)
|
||||||
|
|
||||||
|
|
|
@ -97,20 +97,24 @@ class SoftwareDeployment(signal_responder.SignalResponder):
|
||||||
DEPLOY_RESOURCE_NAME, DEPLOY_AUTH_URL,
|
DEPLOY_RESOURCE_NAME, DEPLOY_AUTH_URL,
|
||||||
DEPLOY_USERNAME, DEPLOY_PASSWORD,
|
DEPLOY_USERNAME, DEPLOY_PASSWORD,
|
||||||
DEPLOY_PROJECT_ID, DEPLOY_USER_ID,
|
DEPLOY_PROJECT_ID, DEPLOY_USER_ID,
|
||||||
DEPLOY_SIGNAL_VERB, DEPLOY_SIGNAL_TRANSPORT
|
DEPLOY_SIGNAL_VERB, DEPLOY_SIGNAL_TRANSPORT,
|
||||||
|
DEPLOY_QUEUE_ID
|
||||||
) = (
|
) = (
|
||||||
'deploy_server_id', 'deploy_action',
|
'deploy_server_id', 'deploy_action',
|
||||||
'deploy_signal_id', 'deploy_stack_id',
|
'deploy_signal_id', 'deploy_stack_id',
|
||||||
'deploy_resource_name', 'deploy_auth_url',
|
'deploy_resource_name', 'deploy_auth_url',
|
||||||
'deploy_username', 'deploy_password',
|
'deploy_username', 'deploy_password',
|
||||||
'deploy_project_id', 'deploy_user_id',
|
'deploy_project_id', 'deploy_user_id',
|
||||||
'deploy_signal_verb', 'deploy_signal_transport'
|
'deploy_signal_verb', 'deploy_signal_transport',
|
||||||
|
'deploy_queue_id'
|
||||||
)
|
)
|
||||||
|
|
||||||
SIGNAL_TRANSPORTS = (
|
SIGNAL_TRANSPORTS = (
|
||||||
CFN_SIGNAL, TEMP_URL_SIGNAL, HEAT_SIGNAL, NO_SIGNAL
|
CFN_SIGNAL, TEMP_URL_SIGNAL, HEAT_SIGNAL, NO_SIGNAL,
|
||||||
|
ZAQAR_SIGNAL
|
||||||
) = (
|
) = (
|
||||||
'CFN_SIGNAL', 'TEMP_URL_SIGNAL', 'HEAT_SIGNAL', 'NO_SIGNAL'
|
'CFN_SIGNAL', 'TEMP_URL_SIGNAL', 'HEAT_SIGNAL', 'NO_SIGNAL',
|
||||||
|
'ZAQAR_SIGNAL'
|
||||||
)
|
)
|
||||||
|
|
||||||
properties_schema = {
|
properties_schema = {
|
||||||
|
@ -199,6 +203,10 @@ class SoftwareDeployment(signal_responder.SignalResponder):
|
||||||
return self.properties[
|
return self.properties[
|
||||||
self.SIGNAL_TRANSPORT] == self.TEMP_URL_SIGNAL
|
self.SIGNAL_TRANSPORT] == self.TEMP_URL_SIGNAL
|
||||||
|
|
||||||
|
def _signal_transport_zaqar(self):
|
||||||
|
return self.properties.get(
|
||||||
|
self.SIGNAL_TRANSPORT) == self.ZAQAR_SIGNAL
|
||||||
|
|
||||||
def _build_properties(self, properties, config_id, action):
|
def _build_properties(self, properties, config_id, action):
|
||||||
props = {
|
props = {
|
||||||
'config_id': config_id,
|
'config_id': config_id,
|
||||||
|
@ -326,6 +334,17 @@ class SoftwareDeployment(signal_responder.SignalResponder):
|
||||||
container, object_name, '')
|
container, object_name, '')
|
||||||
return put_url
|
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):
|
def _delete_temp_url(self):
|
||||||
object_name = self.data().get('signal_object_name')
|
object_name = self.data().get('signal_object_name')
|
||||||
if not object_name:
|
if not object_name:
|
||||||
|
@ -342,6 +361,17 @@ class SoftwareDeployment(signal_responder.SignalResponder):
|
||||||
self.data_delete('signal_object_name')
|
self.data_delete('signal_object_name')
|
||||||
self.data_delete('signal_temp_url')
|
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 []
|
||||||
|
@ -419,7 +449,7 @@ class SoftwareDeployment(signal_responder.SignalResponder):
|
||||||
scl.TYPE: 'String',
|
scl.TYPE: 'String',
|
||||||
'value': 'PUT'
|
'value': 'PUT'
|
||||||
})
|
})
|
||||||
elif self._signal_transport_heat():
|
elif self._signal_transport_heat() or self._signal_transport_zaqar():
|
||||||
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'),
|
||||||
|
@ -446,6 +476,14 @@ class SoftwareDeployment(signal_responder.SignalResponder):
|
||||||
scl.TYPE: 'String',
|
scl.TYPE: 'String',
|
||||||
'value': self.stack.stack_user_project_id
|
'value': self.stack.stack_user_project_id
|
||||||
}])
|
}])
|
||||||
|
if self._signal_transport_zaqar():
|
||||||
|
inputs.append({
|
||||||
|
scl.NAME: self.DEPLOY_QUEUE_ID,
|
||||||
|
scl.DESCRIPTION: _('ID of queue to use for signaling '
|
||||||
|
'output values'),
|
||||||
|
scl.TYPE: 'String',
|
||||||
|
'value': self._get_queue_id()
|
||||||
|
})
|
||||||
|
|
||||||
return inputs
|
return inputs
|
||||||
|
|
||||||
|
@ -453,7 +491,7 @@ class SoftwareDeployment(signal_responder.SignalResponder):
|
||||||
if self._signal_transport_cfn():
|
if self._signal_transport_cfn():
|
||||||
self._create_user()
|
self._create_user()
|
||||||
self._create_keypair()
|
self._create_keypair()
|
||||||
if self._signal_transport_heat():
|
if self._signal_transport_heat() or self._signal_transport_zaqar():
|
||||||
self.password = uuid.uuid4().hex
|
self.password = uuid.uuid4().hex
|
||||||
self._create_user()
|
self._create_user()
|
||||||
return self._handle_action(self.CREATE)
|
return self._handle_action(self.CREATE)
|
||||||
|
@ -505,6 +543,8 @@ class SoftwareDeployment(signal_responder.SignalResponder):
|
||||||
self._delete_user()
|
self._delete_user()
|
||||||
elif self._signal_transport_temp_url():
|
elif self._signal_transport_temp_url():
|
||||||
self._delete_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:
|
||||||
|
|
|
@ -109,9 +109,9 @@ class Server(stack_user.StackUser):
|
||||||
)
|
)
|
||||||
|
|
||||||
_SOFTWARE_CONFIG_TRANSPORTS = (
|
_SOFTWARE_CONFIG_TRANSPORTS = (
|
||||||
POLL_SERVER_CFN, POLL_SERVER_HEAT, POLL_TEMP_URL
|
POLL_SERVER_CFN, POLL_SERVER_HEAT, POLL_TEMP_URL, ZAQAR_MESSAGE
|
||||||
) = (
|
) = (
|
||||||
'POLL_SERVER_CFN', 'POLL_SERVER_HEAT', 'POLL_TEMP_URL'
|
'POLL_SERVER_CFN', 'POLL_SERVER_HEAT', 'POLL_TEMP_URL', 'ZAQAR_MESSAGE'
|
||||||
)
|
)
|
||||||
|
|
||||||
ATTRIBUTES = (
|
ATTRIBUTES = (
|
||||||
|
@ -530,6 +530,21 @@ class Server(stack_user.StackUser):
|
||||||
'stack_id': self.stack.identifier().stack_path(),
|
'stack_id': self.stack.identifier().stack_path(),
|
||||||
'resource_name': self.name}
|
'resource_name': self.name}
|
||||||
}
|
}
|
||||||
|
if self.transport_zaqar_message():
|
||||||
|
queue_id = self.physical_resource_name()
|
||||||
|
self.data_set('metadata_queue_id', queue_id)
|
||||||
|
zaqar_plugin = self.client_plugin('zaqar')
|
||||||
|
zaqar = zaqar_plugin.create_for_tenant(
|
||||||
|
self.stack.stack_user_project_id)
|
||||||
|
queue = zaqar.queue(queue_id)
|
||||||
|
queue.post({'body': meta, 'ttl': zaqar_plugin.DEFAULT_TTL})
|
||||||
|
meta['os-collect-config'] = {'zaqar': {
|
||||||
|
'user_id': self._get_user_id(),
|
||||||
|
'password': self.password,
|
||||||
|
'auth_url': self.context.auth_url,
|
||||||
|
'project_id': self.stack.stack_user_project_id,
|
||||||
|
'queue_id': queue_id}
|
||||||
|
}
|
||||||
elif self.transport_poll_server_cfn():
|
elif self.transport_poll_server_cfn():
|
||||||
meta['os-collect-config'] = {'cfn': {
|
meta['os-collect-config'] = {'cfn': {
|
||||||
'metadata_url': '%s/v1/' % cfg.CONF.heat_metadata_server_url,
|
'metadata_url': '%s/v1/' % cfg.CONF.heat_metadata_server_url,
|
||||||
|
@ -577,7 +592,8 @@ class Server(stack_user.StackUser):
|
||||||
self._create_user()
|
self._create_user()
|
||||||
self._create_keypair()
|
self._create_keypair()
|
||||||
|
|
||||||
elif self.transport_poll_server_heat():
|
elif (self.transport_poll_server_heat() or
|
||||||
|
self.transport_zaqar_message()):
|
||||||
self.password = uuid.uuid4().hex
|
self.password = uuid.uuid4().hex
|
||||||
self._create_user()
|
self._create_user()
|
||||||
|
|
||||||
|
@ -621,6 +637,10 @@ class Server(stack_user.StackUser):
|
||||||
return self.properties[
|
return self.properties[
|
||||||
self.SOFTWARE_CONFIG_TRANSPORT] == self.POLL_TEMP_URL
|
self.SOFTWARE_CONFIG_TRANSPORT] == self.POLL_TEMP_URL
|
||||||
|
|
||||||
|
def transport_zaqar_message(self):
|
||||||
|
return self.properties.get(
|
||||||
|
self.SOFTWARE_CONFIG_TRANSPORT) == self.ZAQAR_MESSAGE
|
||||||
|
|
||||||
def get_software_config(self, ud_content):
|
def get_software_config(self, ud_content):
|
||||||
try:
|
try:
|
||||||
sc = self.rpc_client().show_software_config(
|
sc = self.rpc_client().show_software_config(
|
||||||
|
@ -1331,6 +1351,19 @@ class Server(stack_user.StackUser):
|
||||||
except Exception as ex:
|
except Exception as ex:
|
||||||
self.client_plugin('swift').ignore_not_found(ex)
|
self.client_plugin('swift').ignore_not_found(ex)
|
||||||
|
|
||||||
|
def _delete_queue(self):
|
||||||
|
queue_id = self.data().get('metadata_queue_id')
|
||||||
|
if not queue_id:
|
||||||
|
return
|
||||||
|
client_plugin = self.client_plugin('zaqar')
|
||||||
|
zaqar = client_plugin.create_for_tenant(
|
||||||
|
self.stack.stack_user_project_id)
|
||||||
|
try:
|
||||||
|
zaqar.queue(queue_id).delete()
|
||||||
|
except Exception as ex:
|
||||||
|
client_plugin.ignore_not_found(ex)
|
||||||
|
self.data_delete('metadata_queue_id')
|
||||||
|
|
||||||
def handle_delete(self):
|
def handle_delete(self):
|
||||||
|
|
||||||
if self.resource_id is None:
|
if self.resource_id is None:
|
||||||
|
@ -1339,6 +1372,7 @@ class Server(stack_user.StackUser):
|
||||||
if self.user_data_software_config():
|
if self.user_data_software_config():
|
||||||
self._delete_user()
|
self._delete_user()
|
||||||
self._delete_temp_url()
|
self._delete_temp_url()
|
||||||
|
self._delete_queue()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
self.client().servers.delete(self.resource_id)
|
self.client().servers.delete(self.resource_id)
|
||||||
|
|
|
@ -81,7 +81,7 @@ class SoftwareConfigService(service.Service):
|
||||||
result = [api.format_software_config(sd.config) for sd in all_sd_s]
|
result = [api.format_software_config(sd.config) for sd in all_sd_s]
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def _push_metadata_software_deployments(self, cnxt, server_id):
|
def _push_metadata_software_deployments(self, cnxt, server_id, sd):
|
||||||
rs = (resource_object.Resource.
|
rs = (resource_object.Resource.
|
||||||
get_by_physical_resource_id(cnxt, server_id))
|
get_by_physical_resource_id(cnxt, server_id))
|
||||||
if not rs:
|
if not rs:
|
||||||
|
@ -92,15 +92,24 @@ class SoftwareConfigService(service.Service):
|
||||||
rs.update_and_save({'rsrc_metadata': md})
|
rs.update_and_save({'rsrc_metadata': md})
|
||||||
|
|
||||||
metadata_put_url = None
|
metadata_put_url = None
|
||||||
|
metadata_queue_id = None
|
||||||
for rd in rs.data:
|
for rd in rs.data:
|
||||||
if rd.key == 'metadata_put_url':
|
if rd.key == 'metadata_put_url':
|
||||||
metadata_put_url = rd.value
|
metadata_put_url = rd.value
|
||||||
break
|
break
|
||||||
|
elif rd.key == 'metadata_queue_id':
|
||||||
|
metadata_queue_id = rd.value
|
||||||
|
break
|
||||||
if metadata_put_url:
|
if metadata_put_url:
|
||||||
json_md = jsonutils.dumps(md)
|
json_md = jsonutils.dumps(md)
|
||||||
requests.put(metadata_put_url, json_md)
|
requests.put(metadata_put_url, json_md)
|
||||||
|
elif metadata_queue_id:
|
||||||
|
zaqar_plugin = cnxt.clients.client_plugin('zaqar')
|
||||||
|
zaqar = zaqar_plugin.create_for_tenant(sd.stack_user_project_id)
|
||||||
|
queue = zaqar.queue(metadata_queue_id)
|
||||||
|
queue.post({'body': md, 'ttl': zaqar_plugin.DEFAULT_TTL})
|
||||||
|
|
||||||
def _refresh_software_deployment(self, cnxt, sd, deploy_signal_id):
|
def _refresh_swift_software_deployment(self, cnxt, sd, deploy_signal_id):
|
||||||
container, object_name = urlparse.urlparse(
|
container, object_name = urlparse.urlparse(
|
||||||
deploy_signal_id).path.split('/')[-2:]
|
deploy_signal_id).path.split('/')[-2:]
|
||||||
swift_plugin = cnxt.clients.client_plugin('swift')
|
swift_plugin = cnxt.clients.client_plugin('swift')
|
||||||
|
@ -146,6 +155,19 @@ class SoftwareConfigService(service.Service):
|
||||||
return software_deployment_object.SoftwareDeployment.get_by_id(
|
return software_deployment_object.SoftwareDeployment.get_by_id(
|
||||||
cnxt, sd.id)
|
cnxt, sd.id)
|
||||||
|
|
||||||
|
def _refresh_zaqar_software_deployment(self, cnxt, sd, deploy_queue_id):
|
||||||
|
zaqar_plugin = cnxt.clients.client_plugin('zaqar')
|
||||||
|
zaqar = zaqar_plugin.create_for_tenant(sd.stack_user_project_id)
|
||||||
|
queue = zaqar.queue(deploy_queue_id)
|
||||||
|
|
||||||
|
messages = list(queue.pop())
|
||||||
|
if messages:
|
||||||
|
self.signal_software_deployment(
|
||||||
|
cnxt, sd.id, messages[0].body, None)
|
||||||
|
|
||||||
|
return software_deployment_object.SoftwareDeployment.get_by_id(
|
||||||
|
cnxt, sd.id)
|
||||||
|
|
||||||
def show_software_deployment(self, cnxt, deployment_id):
|
def show_software_deployment(self, cnxt, deployment_id):
|
||||||
sd = software_deployment_object.SoftwareDeployment.get_by_id(
|
sd = software_deployment_object.SoftwareDeployment.get_by_id(
|
||||||
cnxt, deployment_id)
|
cnxt, deployment_id)
|
||||||
|
@ -154,8 +176,11 @@ class SoftwareConfigService(service.Service):
|
||||||
input_values = dict((i['name'], i['value']) for i in c['inputs'])
|
input_values = dict((i['name'], i['value']) for i in c['inputs'])
|
||||||
transport = input_values.get('deploy_signal_transport')
|
transport = input_values.get('deploy_signal_transport')
|
||||||
if transport == 'TEMP_URL_SIGNAL':
|
if transport == 'TEMP_URL_SIGNAL':
|
||||||
sd = self._refresh_software_deployment(
|
sd = self._refresh_swift_software_deployment(
|
||||||
cnxt, sd, input_values.get('deploy_signal_id'))
|
cnxt, sd, input_values.get('deploy_signal_id'))
|
||||||
|
elif transport == 'ZAQAR_SIGNAL':
|
||||||
|
sd = self._refresh_zaqar_software_deployment(
|
||||||
|
cnxt, sd, input_values.get('deploy_queue_id'))
|
||||||
return api.format_software_deployment(sd)
|
return api.format_software_deployment(sd)
|
||||||
|
|
||||||
def create_software_deployment(self, cnxt, server_id, config_id,
|
def create_software_deployment(self, cnxt, server_id, config_id,
|
||||||
|
@ -171,7 +196,7 @@ class SoftwareConfigService(service.Service):
|
||||||
'action': action,
|
'action': action,
|
||||||
'status': status,
|
'status': status,
|
||||||
'status_reason': status_reason})
|
'status_reason': status_reason})
|
||||||
self._push_metadata_software_deployments(cnxt, server_id)
|
self._push_metadata_software_deployments(cnxt, server_id, sd)
|
||||||
return api.format_software_deployment(sd)
|
return api.format_software_deployment(sd)
|
||||||
|
|
||||||
def signal_software_deployment(self, cnxt, deployment_id, details,
|
def signal_software_deployment(self, cnxt, deployment_id, details,
|
||||||
|
@ -262,7 +287,7 @@ class SoftwareConfigService(service.Service):
|
||||||
# only push metadata if this update resulted in the config_id
|
# only push metadata if this update resulted in the config_id
|
||||||
# changing, since metadata is just a list of configs
|
# changing, since metadata is just a list of configs
|
||||||
if config_id:
|
if config_id:
|
||||||
self._push_metadata_software_deployments(cnxt, sd.server_id)
|
self._push_metadata_software_deployments(cnxt, sd.server_id, sd)
|
||||||
|
|
||||||
return api.format_software_deployment(sd)
|
return api.format_software_deployment(sd)
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,7 @@ 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.clients.os import swift
|
from heat.engine.clients.os import swift
|
||||||
|
from heat.engine.clients.os import zaqar
|
||||||
from heat.engine import service
|
from heat.engine import service
|
||||||
from heat.engine import service_software_config
|
from heat.engine import service_software_config
|
||||||
from heat.objects import resource as resource_objects
|
from heat.objects import resource as resource_objects
|
||||||
|
@ -386,9 +387,9 @@ class SoftwareConfigServiceTest(common.HeatTestCase):
|
||||||
self.assertEqual(kwargs['input_values'], deployment['input_values'])
|
self.assertEqual(kwargs['input_values'], deployment['input_values'])
|
||||||
|
|
||||||
@mock.patch.object(service_software_config.SoftwareConfigService,
|
@mock.patch.object(service_software_config.SoftwareConfigService,
|
||||||
'_refresh_software_deployment')
|
'_refresh_swift_software_deployment')
|
||||||
def test_show_software_deployment_refresh(
|
def test_show_software_deployment_refresh(
|
||||||
self, _refresh_software_deployment):
|
self, _refresh_swift_software_deployment):
|
||||||
temp_url = ('http://192.0.2.1/v1/AUTH_a/b/c'
|
temp_url = ('http://192.0.2.1/v1/AUTH_a/b/c'
|
||||||
'?temp_url_sig=ctemp_url_expires=1234')
|
'?temp_url_sig=ctemp_url_expires=1234')
|
||||||
config = self._create_software_config(inputs=[
|
config = self._create_software_config(inputs=[
|
||||||
|
@ -409,13 +410,13 @@ class SoftwareConfigServiceTest(common.HeatTestCase):
|
||||||
deployment_id = deployment['id']
|
deployment_id = deployment['id']
|
||||||
sd = software_deployment_object.SoftwareDeployment.get_by_id(
|
sd = software_deployment_object.SoftwareDeployment.get_by_id(
|
||||||
self.ctx, deployment_id)
|
self.ctx, deployment_id)
|
||||||
_refresh_software_deployment.return_value = sd
|
_refresh_swift_software_deployment.return_value = sd
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
deployment,
|
deployment,
|
||||||
self.engine.show_software_deployment(self.ctx, deployment_id))
|
self.engine.show_software_deployment(self.ctx, deployment_id))
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
(self.ctx, sd, temp_url),
|
(self.ctx, sd, temp_url),
|
||||||
_refresh_software_deployment.call_args[0])
|
_refresh_swift_software_deployment.call_args[0])
|
||||||
|
|
||||||
def test_update_software_deployment_new_config(self):
|
def test_update_software_deployment_new_config(self):
|
||||||
|
|
||||||
|
@ -459,7 +460,10 @@ class SoftwareConfigServiceTest(common.HeatTestCase):
|
||||||
self.assertIsNotNone(updated)
|
self.assertIsNotNone(updated)
|
||||||
self.assertEqual('DEPLOY', updated['action'])
|
self.assertEqual('DEPLOY', updated['action'])
|
||||||
self.assertEqual('WAITING', updated['status'])
|
self.assertEqual('WAITING', updated['status'])
|
||||||
mock_push.assert_called_once_with(self.ctx, server_id)
|
|
||||||
|
sd = software_deployment_object.SoftwareDeployment.get_by_id(
|
||||||
|
self.ctx, deployment_id)
|
||||||
|
mock_push.assert_called_once_with(self.ctx, server_id, sd)
|
||||||
|
|
||||||
def test_update_software_deployment_fields(self):
|
def test_update_software_deployment_fields(self):
|
||||||
|
|
||||||
|
@ -529,7 +533,7 @@ class SoftwareConfigServiceTest(common.HeatTestCase):
|
||||||
}
|
}
|
||||||
|
|
||||||
self.engine.software_config._push_metadata_software_deployments(
|
self.engine.software_config._push_metadata_software_deployments(
|
||||||
self.ctx, '1234')
|
self.ctx, '1234', None)
|
||||||
rs.update_and_save.assert_called_once_with(
|
rs.update_and_save.assert_called_once_with(
|
||||||
{'rsrc_metadata': result_metadata})
|
{'rsrc_metadata': result_metadata})
|
||||||
put.side_effect = Exception('Unexpected requests.put')
|
put.side_effect = Exception('Unexpected requests.put')
|
||||||
|
@ -558,17 +562,56 @@ class SoftwareConfigServiceTest(common.HeatTestCase):
|
||||||
}
|
}
|
||||||
|
|
||||||
self.engine.software_config._push_metadata_software_deployments(
|
self.engine.software_config._push_metadata_software_deployments(
|
||||||
self.ctx, '1234')
|
self.ctx, '1234', None)
|
||||||
rs.update_and_save.assert_called_once_with(
|
rs.update_and_save.assert_called_once_with(
|
||||||
{'rsrc_metadata': result_metadata})
|
{'rsrc_metadata': result_metadata})
|
||||||
|
|
||||||
put.assert_called_once_with(
|
put.assert_called_once_with(
|
||||||
'http://192.168.2.2/foo/bar', json.dumps(result_metadata))
|
'http://192.168.2.2/foo/bar', json.dumps(result_metadata))
|
||||||
|
|
||||||
|
@mock.patch.object(service_software_config.SoftwareConfigService,
|
||||||
|
'metadata_software_deployments')
|
||||||
|
@mock.patch.object(service_software_config.resource_object.Resource,
|
||||||
|
'get_by_physical_resource_id')
|
||||||
|
@mock.patch.object(zaqar.ZaqarClientPlugin, 'create_for_tenant')
|
||||||
|
def test_push_metadata_software_deployments_queue(
|
||||||
|
self, plugin, res_get, md_sd):
|
||||||
|
rs = mock.Mock()
|
||||||
|
rs.rsrc_metadata = {'original': 'metadata'}
|
||||||
|
rd = mock.Mock()
|
||||||
|
rd.key = 'metadata_queue_id'
|
||||||
|
rd.value = '6789'
|
||||||
|
rs.data = [rd]
|
||||||
|
res_get.return_value = rs
|
||||||
|
sd = mock.Mock()
|
||||||
|
sd.stack_user_project_id = 'project1'
|
||||||
|
queue = mock.Mock()
|
||||||
|
zaqar_client = mock.Mock()
|
||||||
|
plugin.return_value = zaqar_client
|
||||||
|
zaqar_client.queue.return_value = queue
|
||||||
|
|
||||||
|
deployments = {'deploy': 'this'}
|
||||||
|
md_sd.return_value = deployments
|
||||||
|
|
||||||
|
result_metadata = {
|
||||||
|
'original': 'metadata',
|
||||||
|
'deployments': {'deploy': 'this'}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.engine.software_config._push_metadata_software_deployments(
|
||||||
|
self.ctx, '1234', sd)
|
||||||
|
rs.update_and_save.assert_called_once_with(
|
||||||
|
{'rsrc_metadata': result_metadata})
|
||||||
|
|
||||||
|
plugin.assert_called_once_with('project1')
|
||||||
|
zaqar_client.queue.assert_called_once_with('6789')
|
||||||
|
queue.post.assert_called_once_with(
|
||||||
|
{'body': result_metadata, 'ttl': 3600})
|
||||||
|
|
||||||
@mock.patch.object(service_software_config.SoftwareConfigService,
|
@mock.patch.object(service_software_config.SoftwareConfigService,
|
||||||
'signal_software_deployment')
|
'signal_software_deployment')
|
||||||
@mock.patch.object(swift.SwiftClientPlugin, '_create')
|
@mock.patch.object(swift.SwiftClientPlugin, '_create')
|
||||||
def test_refresh_software_deployment(self, scc, ssd):
|
def test_refresh_swift_software_deployment(self, scc, ssd):
|
||||||
temp_url = ('http://192.0.2.1/v1/AUTH_a/b/c'
|
temp_url = ('http://192.0.2.1/v1/AUTH_a/b/c'
|
||||||
'?temp_url_sig=ctemp_url_expires=1234')
|
'?temp_url_sig=ctemp_url_expires=1234')
|
||||||
container = 'b'
|
container = 'b'
|
||||||
|
@ -617,7 +660,7 @@ class SoftwareConfigServiceTest(common.HeatTestCase):
|
||||||
|
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
sd,
|
sd,
|
||||||
self.engine.software_config._refresh_software_deployment(
|
self.engine.software_config._refresh_swift_software_deployment(
|
||||||
self.ctx, sd, temp_url))
|
self.ctx, sd, temp_url))
|
||||||
sc.head_object.assert_called_once_with(container, object_name)
|
sc.head_object.assert_called_once_with(container, object_name)
|
||||||
# no call to get_object or signal_last_modified
|
# no call to get_object or signal_last_modified
|
||||||
|
@ -629,7 +672,7 @@ class SoftwareConfigServiceTest(common.HeatTestCase):
|
||||||
'Ouch', http_status=409)
|
'Ouch', http_status=409)
|
||||||
self.assertRaises(
|
self.assertRaises(
|
||||||
swift_exc.ClientException,
|
swift_exc.ClientException,
|
||||||
self.engine.software_config._refresh_software_deployment,
|
self.engine.software_config._refresh_swift_software_deployment,
|
||||||
self.ctx,
|
self.ctx,
|
||||||
sd,
|
sd,
|
||||||
temp_url)
|
temp_url)
|
||||||
|
@ -639,7 +682,7 @@ class SoftwareConfigServiceTest(common.HeatTestCase):
|
||||||
sc.head_object.side_effect = None
|
sc.head_object.side_effect = None
|
||||||
|
|
||||||
# first poll populates data signal_last_modified
|
# first poll populates data signal_last_modified
|
||||||
self.engine.software_config._refresh_software_deployment(
|
self.engine.software_config._refresh_swift_software_deployment(
|
||||||
self.ctx, sd, temp_url)
|
self.ctx, sd, temp_url)
|
||||||
sc.head_object.assert_called_with(container, object_name)
|
sc.head_object.assert_called_with(container, object_name)
|
||||||
sc.get_object.assert_called_once_with(container, object_name)
|
sc.get_object.assert_called_once_with(container, object_name)
|
||||||
|
@ -653,7 +696,7 @@ class SoftwareConfigServiceTest(common.HeatTestCase):
|
||||||
sd = software_deployment_object.SoftwareDeployment.get_by_id(
|
sd = software_deployment_object.SoftwareDeployment.get_by_id(
|
||||||
self.ctx, deployment_id)
|
self.ctx, deployment_id)
|
||||||
self.assertEqual(then, sd.updated_at)
|
self.assertEqual(then, sd.updated_at)
|
||||||
self.engine.software_config._refresh_software_deployment(
|
self.engine.software_config._refresh_swift_software_deployment(
|
||||||
self.ctx, sd, temp_url)
|
self.ctx, sd, temp_url)
|
||||||
sc.get_object.assert_called_once_with(container, object_name)
|
sc.get_object.assert_called_once_with(container, object_name)
|
||||||
# signal_software_deployment has not been called again
|
# signal_software_deployment has not been called again
|
||||||
|
@ -664,7 +707,7 @@ class SoftwareConfigServiceTest(common.HeatTestCase):
|
||||||
headers['last-modified'] = last_modified_2
|
headers['last-modified'] = last_modified_2
|
||||||
sc.head_object.return_value = headers
|
sc.head_object.return_value = headers
|
||||||
sc.get_object.return_value = (headers, '{"bar": "baz"}')
|
sc.get_object.return_value = (headers, '{"bar": "baz"}')
|
||||||
self.engine.software_config._refresh_software_deployment(
|
self.engine.software_config._refresh_swift_software_deployment(
|
||||||
self.ctx, sd, temp_url)
|
self.ctx, sd, temp_url)
|
||||||
|
|
||||||
# two calls to signal_software_deployment, for then and now
|
# two calls to signal_software_deployment, for then and now
|
||||||
|
@ -677,6 +720,40 @@ class SoftwareConfigServiceTest(common.HeatTestCase):
|
||||||
self.ctx, deployment_id, {'updated_at': now})
|
self.ctx, deployment_id, {'updated_at': now})
|
||||||
sd = software_deployment_object.SoftwareDeployment.get_by_id(
|
sd = software_deployment_object.SoftwareDeployment.get_by_id(
|
||||||
self.ctx, deployment_id)
|
self.ctx, deployment_id)
|
||||||
self.engine.software_config._refresh_software_deployment(
|
self.engine.software_config._refresh_swift_software_deployment(
|
||||||
self.ctx, sd, temp_url)
|
self.ctx, sd, temp_url)
|
||||||
self.assertEqual(2, len(ssd.mock_calls))
|
self.assertEqual(2, len(ssd.mock_calls))
|
||||||
|
|
||||||
|
@mock.patch.object(service_software_config.SoftwareConfigService,
|
||||||
|
'signal_software_deployment')
|
||||||
|
@mock.patch.object(zaqar.ZaqarClientPlugin, 'create_for_tenant')
|
||||||
|
def test_refresh_zaqar_software_deployment(self, plugin, ssd):
|
||||||
|
config = self._create_software_config(inputs=[
|
||||||
|
{
|
||||||
|
'name': 'deploy_signal_transport',
|
||||||
|
'type': 'String',
|
||||||
|
'value': 'ZAQAR_SIGNAL'
|
||||||
|
}, {
|
||||||
|
'name': 'deploy_queue_id',
|
||||||
|
'type': 'String',
|
||||||
|
'value': '6789'
|
||||||
|
}
|
||||||
|
])
|
||||||
|
|
||||||
|
queue = mock.Mock()
|
||||||
|
zaqar_client = mock.Mock()
|
||||||
|
plugin.return_value = zaqar_client
|
||||||
|
zaqar_client.queue.return_value = queue
|
||||||
|
queue.pop.return_value = [mock.Mock(body='ok')]
|
||||||
|
|
||||||
|
deployment = self._create_software_deployment(
|
||||||
|
status='IN_PROGRESS', config_id=config['id'])
|
||||||
|
|
||||||
|
deployment_id = deployment['id']
|
||||||
|
self.assertEqual(
|
||||||
|
deployment,
|
||||||
|
self.engine.show_software_deployment(self.ctx, deployment_id))
|
||||||
|
|
||||||
|
zaqar_client.queue.assert_called_once_with('6789')
|
||||||
|
queue.pop.assert_called_once()
|
||||||
|
ssd.assert_called_once_with(self.ctx, deployment_id, 'ok', None)
|
||||||
|
|
|
@ -27,6 +27,7 @@ from heat.engine.clients.os import glance
|
||||||
from heat.engine.clients.os import neutron
|
from heat.engine.clients.os import neutron
|
||||||
from heat.engine.clients.os import nova
|
from heat.engine.clients.os import nova
|
||||||
from heat.engine.clients.os import swift
|
from heat.engine.clients.os import swift
|
||||||
|
from heat.engine.clients.os import zaqar
|
||||||
from heat.engine import environment
|
from heat.engine import environment
|
||||||
from heat.engine import resource
|
from heat.engine import resource
|
||||||
from heat.engine.resources.openstack.nova import server as servers
|
from heat.engine.resources.openstack.nova import server as servers
|
||||||
|
@ -832,6 +833,75 @@ class ServersTest(common.HeatTestCase):
|
||||||
|
|
||||||
self.m.VerifyAll()
|
self.m.VerifyAll()
|
||||||
|
|
||||||
|
def test_server_create_software_config_zaqar(self):
|
||||||
|
return_server = self.fc.servers.list()[1]
|
||||||
|
stack_name = 'software_config_s'
|
||||||
|
(tmpl, stack) = self._setup_test_stack(stack_name)
|
||||||
|
|
||||||
|
props = tmpl.t['Resources']['WebServer']['Properties']
|
||||||
|
props['user_data_format'] = 'SOFTWARE_CONFIG'
|
||||||
|
props['software_config_transport'] = 'ZAQAR_MESSAGE'
|
||||||
|
|
||||||
|
resource_defns = tmpl.resource_definitions(stack)
|
||||||
|
server = servers.Server('WebServer',
|
||||||
|
resource_defns['WebServer'], stack)
|
||||||
|
|
||||||
|
ncp = self.patchobject(nova.NovaClientPlugin, '_create')
|
||||||
|
zcc = self.patchobject(zaqar.ZaqarClientPlugin, 'create_for_tenant')
|
||||||
|
zc = mock.Mock()
|
||||||
|
|
||||||
|
ncp.return_value = self.fc
|
||||||
|
zcc.return_value = zc
|
||||||
|
queue = mock.Mock()
|
||||||
|
zc.queue.return_value = queue
|
||||||
|
self._mock_get_image_id_success('F17-x86_64-gold', 744)
|
||||||
|
|
||||||
|
self.m.StubOutWithMock(self.fc.servers, 'create')
|
||||||
|
self.fc.servers.create(
|
||||||
|
image=744, flavor=3, key_name='test',
|
||||||
|
name=utils.PhysName(stack_name, server.name),
|
||||||
|
security_groups=[],
|
||||||
|
userdata=mox.IgnoreArg(), scheduler_hints=None,
|
||||||
|
meta=None, nics=None, availability_zone=None,
|
||||||
|
block_device_mapping=None, block_device_mapping_v2=None,
|
||||||
|
config_drive=None, disk_config=None, reservation_id=None,
|
||||||
|
files={}, admin_pass=None).AndReturn(
|
||||||
|
return_server)
|
||||||
|
|
||||||
|
self.m.ReplayAll()
|
||||||
|
scheduler.TaskRunner(server.create)()
|
||||||
|
|
||||||
|
metadata_queue_id = server.data().get('metadata_queue_id')
|
||||||
|
md = server.metadata_get()
|
||||||
|
queue_id = md['os-collect-config']['zaqar']['queue_id']
|
||||||
|
self.assertEqual(queue_id, metadata_queue_id)
|
||||||
|
|
||||||
|
self.assertEqual({
|
||||||
|
'os-collect-config': {
|
||||||
|
'zaqar': {
|
||||||
|
'user_id': '1234',
|
||||||
|
'password': server.password,
|
||||||
|
'auth_url': 'http://server.test:5000/v2.0',
|
||||||
|
'project_id': '8888',
|
||||||
|
'queue_id': queue_id
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'deployments': []
|
||||||
|
}, server.metadata_get())
|
||||||
|
|
||||||
|
zc.queue.assert_called_once_with(queue_id)
|
||||||
|
queue.post.assert_called_once_with(
|
||||||
|
{'body': server.metadata_get(), 'ttl': 3600})
|
||||||
|
|
||||||
|
zc.queue.reset_mock()
|
||||||
|
|
||||||
|
server._delete_queue()
|
||||||
|
|
||||||
|
zc.queue.assert_called_once_with(queue_id)
|
||||||
|
zc.queue.delete.assert_called_once()
|
||||||
|
|
||||||
|
self.m.VerifyAll()
|
||||||
|
|
||||||
@mock.patch.object(nova.NovaClientPlugin, '_create')
|
@mock.patch.object(nova.NovaClientPlugin, '_create')
|
||||||
def test_server_create_default_admin_pass(self, mock_client):
|
def test_server_create_default_admin_pass(self, mock_client):
|
||||||
return_server = self.fc.servers.list()[1]
|
return_server = self.fc.servers.list()[1]
|
||||||
|
|
|
@ -22,6 +22,7 @@ from heat.common import exception as exc
|
||||||
from heat.common.i18n import _
|
from heat.common.i18n import _
|
||||||
from heat.engine.clients.os import nova
|
from heat.engine.clients.os import nova
|
||||||
from heat.engine.clients.os import swift
|
from heat.engine.clients.os import swift
|
||||||
|
from heat.engine.clients.os import zaqar
|
||||||
from heat.engine.resources.openstack.heat import software_deployment as sd
|
from heat.engine.resources.openstack.heat import software_deployment as sd
|
||||||
from heat.engine import rsrc_defn
|
from heat.engine import rsrc_defn
|
||||||
from heat.engine import stack as parser
|
from heat.engine import stack as parser
|
||||||
|
@ -100,6 +101,22 @@ class SoftwareDeploymentTest(common.HeatTestCase):
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template_zaqar_signal = {
|
||||||
|
'HeatTemplateFormatVersion': '2012-12-12',
|
||||||
|
'Resources': {
|
||||||
|
'deployment_mysql': {
|
||||||
|
'Type': 'OS::Heat::SoftwareDeployment',
|
||||||
|
'Properties': {
|
||||||
|
'server': '9f1f0e00-05d2-4ca5-8602-95021f19c9d0',
|
||||||
|
'config': '48e8ade1-9196-42d5-89a2-f709fde42632',
|
||||||
|
'input_values': {'foo': 'bar', 'bink': 'bonk'},
|
||||||
|
'signal_transport': 'ZAQAR_SIGNAL',
|
||||||
|
'name': '00_run_me_first'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
template_delete_suspend_resume = {
|
template_delete_suspend_resume = {
|
||||||
'HeatTemplateFormatVersion': '2012-12-12',
|
'HeatTemplateFormatVersion': '2012-12-12',
|
||||||
'Resources': {
|
'Resources': {
|
||||||
|
@ -1042,6 +1059,69 @@ class SoftwareDeploymentTest(common.HeatTestCase):
|
||||||
for action in ('CREATE', 'UPDATE'):
|
for action in ('CREATE', 'UPDATE'):
|
||||||
self.assertIsNotNone(self.deployment._handle_action(action))
|
self.assertIsNotNone(self.deployment._handle_action(action))
|
||||||
|
|
||||||
|
def test_get_zaqar_queue(self):
|
||||||
|
dep_data = {}
|
||||||
|
|
||||||
|
zc = mock.MagicMock()
|
||||||
|
zcc = self.patch(
|
||||||
|
'heat.engine.clients.os.zaqar.ZaqarClientPlugin._create')
|
||||||
|
zcc.return_value = zc
|
||||||
|
|
||||||
|
self._create_stack(self.template_zaqar_signal)
|
||||||
|
|
||||||
|
def data_set(key, value, redact=False):
|
||||||
|
dep_data[key] = value
|
||||||
|
|
||||||
|
self.deployment.data_set = data_set
|
||||||
|
self.deployment.data = mock.Mock(return_value=dep_data)
|
||||||
|
|
||||||
|
self.deployment.id = 23
|
||||||
|
self.deployment.uuid = str(uuid.uuid4())
|
||||||
|
self.deployment.action = self.deployment.CREATE
|
||||||
|
|
||||||
|
queue_id = self.deployment._get_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, self.deployment._get_queue_id())
|
||||||
|
|
||||||
|
def test_delete_zaqar_queue(self):
|
||||||
|
queue_id = str(uuid.uuid4())
|
||||||
|
dep_data = {
|
||||||
|
'signal_queue_id': queue_id
|
||||||
|
}
|
||||||
|
self._create_stack(self.template_zaqar_signal)
|
||||||
|
|
||||||
|
self.deployment.data_delete = mock.MagicMock()
|
||||||
|
self.deployment.data = mock.Mock(return_value=dep_data)
|
||||||
|
|
||||||
|
zc = mock.MagicMock()
|
||||||
|
zcc = self.patch(
|
||||||
|
'heat.engine.clients.os.zaqar.ZaqarClientPlugin._create')
|
||||||
|
zcc.return_value = zc
|
||||||
|
|
||||||
|
self.deployment.id = 23
|
||||||
|
self.deployment.uuid = str(uuid.uuid4())
|
||||||
|
self.deployment._delete_queue()
|
||||||
|
zc.queue.assert_called_once_with(queue_id)
|
||||||
|
zc.queue.delete.assert_called_once()
|
||||||
|
self.assertEqual(
|
||||||
|
[mock.call('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.assertEqual(
|
||||||
|
[mock.call('signal_queue_id'), mock.call('signal_queue_id')],
|
||||||
|
self.deployment.data_delete.mock_calls)
|
||||||
|
|
||||||
|
dep_data.pop('signal_queue_id')
|
||||||
|
self.deployment.physical_resource_name = mock.Mock()
|
||||||
|
self.deployment._delete_queue()
|
||||||
|
self.assertEqual(2, len(self.deployment.data_delete.mock_calls))
|
||||||
|
|
||||||
|
|
||||||
class SoftwareDeploymentGroupTest(common.HeatTestCase):
|
class SoftwareDeploymentGroupTest(common.HeatTestCase):
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue