Revert "Move deployment handle_signal to rpc call"

This reverts commit a63f634bfb.

This commit caused a regression in tripleo-ci whith a database
"Incorrect datetime value" error.

Change-Id: I55f9be8ffb319edb56371d8d370d58d02bdf3867
Closes-Bug: #1423126
This commit is contained in:
Derek Higgins 2015-02-18 12:00:17 +00:00
parent 6ae39a4699
commit b387a9f27a
6 changed files with 161 additions and 256 deletions

View File

@ -14,8 +14,8 @@
import copy
import uuid
from oslo.utils import timeutils
from oslo_log import log as logging
import six
from heat.common import exception
from heat.common.i18n import _
@ -448,9 +448,58 @@ class SoftwareDeployment(signal_responder.SignalResponder):
return self._check_complete()
def handle_signal(self, details):
return self.rpc_client().signal_software_deployment(
self.context, self.resource_id, details,
timeutils.strtime())
sd = self.rpc_client().show_software_deployment(
self.context, self.resource_id)
sc = self.rpc_client().show_software_config(
self.context, self.properties[self.CONFIG])
status = sd[rpc_api.SOFTWARE_DEPLOYMENT_STATUS]
if not status == self.IN_PROGRESS:
# output values are only expected when in an IN_PROGRESS state
return
details = details or {}
ov = sd[rpc_api.SOFTWARE_DEPLOYMENT_OUTPUT_VALUES] or {}
status = None
status_reasons = {}
status_code = details.get(self.STATUS_CODE)
if status_code and str(status_code) != '0':
status = self.FAILED
status_reasons[self.STATUS_CODE] = _(
'Deployment exited with non-zero status code: %s'
) % details.get(self.STATUS_CODE)
event_reason = 'deployment failed (%s)' % status_code
else:
event_reason = 'deployment succeeded'
for output in sc[rpc_api.SOFTWARE_CONFIG_OUTPUTS] or []:
out_key = output['name']
if out_key in details:
ov[out_key] = details[out_key]
if output.get('error_output', False):
status = self.FAILED
status_reasons[out_key] = details[out_key]
event_reason = 'deployment failed'
for out_key in self.ATTRIBUTES:
ov[out_key] = details.get(out_key)
if status == self.FAILED:
# build a status reason out of all of the values of outputs
# flagged as error_output
status_reasons = [' : '.join((k, six.text_type(status_reasons[k])))
for k in status_reasons]
status_reason = ', '.join(status_reasons)
else:
status = self.COMPLETE
status_reason = _('Outputs received')
self.rpc_client().update_software_deployment(
self.context, deployment_id=self.resource_id,
output_values=ov, status=status, status_reason=status_reason)
# Return a string describing the outcome of handling the signal data
return event_reason
def FnGetAtt(self, key, *path):
'''

View File

@ -1477,66 +1477,6 @@ class EngineService(service.Service):
self._push_metadata_software_deployments(cnxt, server_id)
return api.format_software_deployment(sd)
@request_context
def signal_software_deployment(self, cnxt, deployment_id, details,
updated_at):
if not deployment_id:
raise ValueError(_('deployment_id must be specified'))
sd = db_api.software_deployment_get(cnxt, deployment_id)
status = sd.status
if not status == rpc_api.SOFTWARE_DEPLOYMENT_IN_PROGRESS:
# output values are only expected when in an IN_PROGRESS state
return
details = details or {}
output_status_code = rpc_api.SOFTWARE_DEPLOYMENT_OUTPUT_STATUS_CODE
ov = sd.output_values or {}
status = None
status_reasons = {}
status_code = details.get(output_status_code)
if status_code and str(status_code) != '0':
status = rpc_api.SOFTWARE_DEPLOYMENT_FAILED
status_reasons[output_status_code] = _(
'Deployment exited with non-zero status code: %s'
) % details.get(output_status_code)
event_reason = 'deployment failed (%s)' % status_code
else:
event_reason = 'deployment succeeded'
for output in sd.config.config['outputs'] or []:
out_key = output['name']
if out_key in details:
ov[out_key] = details[out_key]
if output.get('error_output', False):
status = rpc_api.SOFTWARE_DEPLOYMENT_FAILED
status_reasons[out_key] = details[out_key]
event_reason = 'deployment failed'
for out_key in rpc_api.SOFTWARE_DEPLOYMENT_OUTPUTS:
ov[out_key] = details.get(out_key)
if status == rpc_api.SOFTWARE_DEPLOYMENT_FAILED:
# build a status reason out of all of the values of outputs
# flagged as error_output
status_reasons = [' : '.join((k, six.text_type(status_reasons[k])))
for k in status_reasons]
status_reason = ', '.join(status_reasons)
else:
status = rpc_api.SOFTWARE_DEPLOYMENT_COMPLETE
status_reason = _('Outputs received')
self.update_software_deployment(
cnxt, deployment_id=deployment_id,
output_values=ov, status=status, status_reason=status_reason,
config_id=None, input_values=None, action=None,
updated_at=updated_at)
# Return a string describing the outcome of handling the signal data
return event_reason
@request_context
def update_software_deployment(self, cnxt, deployment_id, config_id,
input_values, output_values, action,

View File

@ -235,26 +235,6 @@ SOFTWARE_DEPLOYMENT_KEYS = (
'updated_time'
)
SOFTWARE_DEPLOYMENT_STATUSES = (
SOFTWARE_DEPLOYMENT_IN_PROGRESS,
SOFTWARE_DEPLOYMENT_FAILED,
SOFTWARE_DEPLOYMENT_COMPLETE
) = (
'IN_PROGRESS',
'FAILED',
'COMPLETE'
)
SOFTWARE_DEPLOYMENT_OUTPUTS = (
SOFTWARE_DEPLOYMENT_OUTPUT_STDOUT,
SOFTWARE_DEPLOYMENT_OUTPUT_STDERR,
SOFTWARE_DEPLOYMENT_OUTPUT_STATUS_CODE
) = (
'deploy_stdout',
'deploy_stderr',
'deploy_status_code'
)
SNAPSHOT_KEYS = (
SNAPSHOT_ID,
SNAPSHOT_NAME,

View File

@ -546,15 +546,6 @@ class EngineClient(object):
return self.call(cnxt, self.make_msg('delete_software_deployment',
deployment_id=deployment_id))
def signal_software_deployment(self, cnxt, deployment_id, details,
updated_at=None):
return self.call(
cnxt, self.make_msg('signal_software_deployment',
deployment_id=deployment_id,
details=details,
updated_at=updated_at),
version='1.5')
def stack_snapshot(self, ctxt, stack_identity, name):
return self.call(ctxt, self.make_msg('stack_snapshot',
stack_identity=stack_identity,

View File

@ -3387,125 +3387,6 @@ class SoftwareConfigServiceTest(common.HeatTestCase):
deployment,
self.engine.show_software_deployment(self.ctx, deployment_id))
@mock.patch.object(service.EngineService,
'_push_metadata_software_deployments')
def test_signal_software_deployment(self, pmsd):
self.assertRaises(ValueError,
self.engine.signal_software_deployment,
self.ctx, None, {}, None)
deployment_id = str(uuid.uuid4())
ex = self.assertRaises(dispatcher.ExpectedException,
self.engine.signal_software_deployment,
self.ctx, deployment_id, {}, None)
self.assertEqual(exception.NotFound, ex.exc_info[0])
deployment = self._create_software_deployment()
deployment_id = deployment['id']
# signal is ignore unless deployment is IN_PROGRESS
self.assertIsNone(self.engine.signal_software_deployment(
self.ctx, deployment_id, {}, None))
# simple signal, no data
deployment = self._create_software_deployment(
action='INIT', status='IN_PROGRESS')
deployment_id = deployment['id']
self.assertEqual(
'deployment succeeded',
self.engine.signal_software_deployment(
self.ctx, deployment_id, {}, None))
sd = db_api.software_deployment_get(self.ctx, deployment_id)
self.assertEqual('COMPLETE', sd.status)
self.assertEqual('Outputs received', sd.status_reason)
self.assertEqual({
'deploy_status_code': None,
'deploy_stderr': None,
'deploy_stdout': None
}, sd.output_values)
self.assertIsNotNone(sd.updated_at)
# simple signal, some data
config = self._create_software_config(outputs=[{'name': 'foo'}])
deployment = self._create_software_deployment(
config_id=config['id'], action='INIT', status='IN_PROGRESS')
deployment_id = deployment['id']
result = self.engine.signal_software_deployment(
self.ctx,
deployment_id,
{'foo': 'bar', 'deploy_status_code': 0},
None)
self.assertEqual('deployment succeeded', result)
sd = db_api.software_deployment_get(self.ctx, deployment_id)
self.assertEqual('COMPLETE', sd.status)
self.assertEqual('Outputs received', sd.status_reason)
self.assertEqual({
'deploy_status_code': 0,
'foo': 'bar',
'deploy_stderr': None,
'deploy_stdout': None
}, sd.output_values)
self.assertIsNotNone(sd.updated_at)
# failed signal on deploy_status_code
config = self._create_software_config(outputs=[
{'name': 'foo'}])
deployment = self._create_software_deployment(
config_id=config['id'], action='INIT', status='IN_PROGRESS')
deployment_id = deployment['id']
result = self.engine.signal_software_deployment(
self.ctx,
deployment_id,
{
'foo': 'bar',
'deploy_status_code': -1,
'deploy_stderr': 'Its gone Pete Tong'
},
None)
self.assertEqual('deployment failed (-1)', result)
sd = db_api.software_deployment_get(self.ctx, deployment_id)
self.assertEqual('FAILED', sd.status)
self.assertEqual(
('deploy_status_code : Deployment exited with non-zero '
'status code: -1'),
sd.status_reason)
self.assertEqual({
'deploy_status_code': -1,
'foo': 'bar',
'deploy_stderr': 'Its gone Pete Tong',
'deploy_stdout': None
}, sd.output_values)
self.assertIsNotNone(sd.updated_at)
# failed signal on error_output foo
config = self._create_software_config(outputs=[
{'name': 'foo', 'error_output': True}])
deployment = self._create_software_deployment(
config_id=config['id'], action='INIT', status='IN_PROGRESS')
deployment_id = deployment['id']
result = self.engine.signal_software_deployment(
self.ctx,
deployment_id,
{
'foo': 'bar',
'deploy_status_code': -1,
'deploy_stderr': 'Its gone Pete Tong'
},
None)
self.assertEqual('deployment failed', result)
sd = db_api.software_deployment_get(self.ctx, deployment_id)
self.assertEqual('FAILED', sd.status)
self.assertEqual(
('foo : bar, deploy_status_code : Deployment exited with '
'non-zero status code: -1'),
sd.status_reason)
self.assertEqual({
'deploy_status_code': -1,
'foo': 'bar',
'deploy_stderr': 'Its gone Pete Tong',
'deploy_stdout': None
}, sd.output_values)
self.assertIsNotNone(sd.updated_at)
def test_create_software_deployment(self):
kwargs = {
'group': 'Heat::Chef',

View File

@ -641,91 +641,155 @@ class SoftwareDeploymentTest(common.HeatTestCase):
def test_handle_signal_ok_zero(self):
self._create_stack(self.template)
self.deployment.resource_id = 'c8a19429-7fde-47ea-a42f-40045488226c'
rpcc = self.rpc_client
rpcc.signal_software_deployment.return_value = 'deployment succeeded'
sc = {
'outputs': [
{'name': 'foo'},
{'name': 'foo2'},
{'name': 'failed', 'error_output': True}
]
}
sd = {
'output_values': {},
'status': self.deployment.IN_PROGRESS
}
self.rpc_client.show_software_deployment.return_value = sd
self.rpc_client.show_software_config.return_value = sc
details = {
'foo': 'bar',
'deploy_status_code': 0
}
ret = self.deployment.handle_signal(details)
self.assertEqual('deployment succeeded', ret)
ca = rpcc.signal_software_deployment.call_args[0]
self.assertEqual(self.ctx, ca[0])
self.assertEqual('c8a19429-7fde-47ea-a42f-40045488226c', ca[1])
self.assertEqual({'foo': 'bar', 'deploy_status_code': 0}, ca[2])
self.assertIsNotNone(ca[3])
self.assertEqual({
'deployment_id': 'c8a19429-7fde-47ea-a42f-40045488226c',
'output_values': {
'foo': 'bar',
'deploy_status_code': 0,
'deploy_stderr': None,
'deploy_stdout': None
},
'status': 'COMPLETE',
'status_reason': 'Outputs received'},
self.rpc_client.update_software_deployment.call_args[1])
def test_handle_signal_ok_str_zero(self):
self._create_stack(self.template)
self.deployment.resource_id = 'c8a19429-7fde-47ea-a42f-40045488226c'
rpcc = self.rpc_client
rpcc.signal_software_deployment.return_value = 'deployment succeeded'
sc = {
'outputs': [
{'name': 'foo'},
{'name': 'foo2'},
{'name': 'failed', 'error_output': True}
]
}
sd = {
'output_values': {},
'status': self.deployment.IN_PROGRESS
}
self.rpc_client.show_software_deployment.return_value = sd
self.rpc_client.show_software_config.return_value = sc
details = {
'foo': 'bar',
'deploy_status_code': '0'
}
ret = self.deployment.handle_signal(details)
self.assertEqual('deployment succeeded', ret)
ca = rpcc.signal_software_deployment.call_args[0]
self.assertEqual(self.ctx, ca[0])
self.assertEqual('c8a19429-7fde-47ea-a42f-40045488226c', ca[1])
self.assertEqual({'foo': 'bar', 'deploy_status_code': '0'}, ca[2])
self.assertIsNotNone(ca[3])
self.assertEqual({
'deployment_id': 'c8a19429-7fde-47ea-a42f-40045488226c',
'output_values': {
'foo': 'bar',
'deploy_status_code': '0',
'deploy_stderr': None,
'deploy_stdout': None
},
'status': 'COMPLETE',
'status_reason': 'Outputs received'},
self.rpc_client.update_software_deployment.call_args[1])
def test_handle_signal_failed(self):
self._create_stack(self.template)
self.deployment.resource_id = 'c8a19429-7fde-47ea-a42f-40045488226c'
rpcc = self.rpc_client
rpcc.signal_software_deployment.return_value = 'deployment failed'
sc = {
'outputs': [
{'name': 'foo'},
{'name': 'foo2'},
{'name': 'failed', 'error_output': True}
]
}
sd = {
'output_values': {},
'status': self.deployment.IN_PROGRESS
}
self.rpc_client.show_software_deployment.return_value = sd
self.rpc_client.show_software_config.return_value = sc
details = {'failed': 'no enough memory found.'}
ret = self.deployment.handle_signal(details)
self.assertEqual('deployment failed', ret)
ca = rpcc.signal_software_deployment.call_args[0]
self.assertEqual(self.ctx, ca[0])
self.assertEqual('c8a19429-7fde-47ea-a42f-40045488226c', ca[1])
self.assertEqual(details, ca[2])
self.assertIsNotNone(ca[3])
self.assertEqual({
'deployment_id': 'c8a19429-7fde-47ea-a42f-40045488226c',
'output_values': {
'deploy_status_code': None,
'deploy_stderr': None,
'deploy_stdout': None,
'failed': 'no enough memory found.'
},
'status': 'FAILED',
'status_reason': 'failed : no enough memory found.'},
self.rpc_client.update_software_deployment.call_args[1])
# Test bug 1332355, where details contains a translateable message
details = {'failed': _('need more memory.')}
ret = self.deployment.handle_signal(details)
self.assertEqual('deployment failed', ret)
ca = rpcc.signal_software_deployment.call_args[0]
self.assertEqual(self.ctx, ca[0])
self.assertEqual('c8a19429-7fde-47ea-a42f-40045488226c', ca[1])
self.assertEqual(details, ca[2])
self.assertIsNotNone(ca[3])
self.deployment.handle_signal(details)
self.assertEqual({
'deployment_id': 'c8a19429-7fde-47ea-a42f-40045488226c',
'output_values': {
'deploy_status_code': None,
'deploy_stderr': None,
'deploy_stdout': None,
'failed': 'need more memory.'
},
'status': 'FAILED',
'status_reason': 'failed : need more memory.'},
self.rpc_client.update_software_deployment.call_args[1])
def test_handle_status_code_failed(self):
self._create_stack(self.template)
self.deployment.resource_id = 'c8a19429-7fde-47ea-a42f-40045488226c'
rpcc = self.rpc_client
rpcc.signal_software_deployment.return_value = 'deployment failed'
sd = {
'outputs': [],
'output_values': {},
'status': self.deployment.IN_PROGRESS
}
self.rpc_client.show_software_deployment.return_value = sd
details = {
'deploy_stdout': 'A thing happened',
'deploy_stderr': 'Then it broke',
'deploy_status_code': -1
}
self.deployment.handle_signal(details)
ca = rpcc.signal_software_deployment.call_args[0]
self.assertEqual(self.ctx, ca[0])
self.assertEqual('c8a19429-7fde-47ea-a42f-40045488226c', ca[1])
self.assertEqual(details, ca[2])
self.assertIsNotNone(ca[3])
self.assertEqual(
'c8a19429-7fde-47ea-a42f-40045488226c',
self.rpc_client.show_software_deployment.call_args[0][1])
self.assertEqual({
'deployment_id': 'c8a19429-7fde-47ea-a42f-40045488226c',
'output_values': {
'deploy_stdout': 'A thing happened',
'deploy_stderr': 'Then it broke',
'deploy_status_code': -1
},
'status': 'FAILED',
'status_reason': ('deploy_status_code : Deployment exited '
'with non-zero status code: -1')},
self.rpc_client.update_software_deployment.call_args[1])
def test_handle_signal_not_waiting(self):
self._create_stack(self.template)
rpcc = self.rpc_client
rpcc.signal_software_deployment.return_value = None
sd = {
'status': self.deployment.COMPLETE
}
self.rpc_client.show_software_deployment.return_value = sd
details = None
self.assertIsNone(self.deployment.handle_signal(details))
ca = rpcc.signal_software_deployment.call_args[0]
self.assertEqual(self.ctx, ca[0])
self.assertIsNone(ca[1])
self.assertIsNone(ca[2])
self.assertIsNotNone(ca[3])
def test_fn_get_att(self):
self._create_stack(self.template)