RPC method to fetch deployments metadata

This method returns a list of software configs which are currently
deployed to a given server. Each config has the deployment input values
and current action inserted into it. This means that each config is
ephemeral and derived from the canonical config specified in the deployment
resource. The list of configs is sorted by config name. This allows the
template to control what order the configs are returned by setting the
'name' attribute of each deployment resource.

Having a separate RPC (and REST) method for deployment metadata also means
that servers will eventually be able to poll for deployment metadata directly,
avoiding the need to parse the stack for every poll.

partial blueprint hot-software-config-rest

Change-Id: I374f1e15d5255a3ad1264859fd845265cc60f218
This commit is contained in:
Steve Baker 2014-02-17 13:15:25 +13:00
parent 2d6d816938
commit 99a8fa9064
6 changed files with 69 additions and 20 deletions

View File

@ -338,11 +338,5 @@ def format_software_deployment(sd):
api.SOFTWARE_DEPLOYMENT_STATUS_REASON: sd.status_reason,
api.SOFTWARE_DEPLOYMENT_SIGNAL_ID: sd.signal_id,
api.SOFTWARE_DEPLOYMENT_CONFIG_ID: sd.config.id,
api.SOFTWARE_CONFIG_CONFIG: sd.config.config,
api.SOFTWARE_CONFIG_NAME: sd.config.name,
api.SOFTWARE_CONFIG_GROUP: sd.config.group,
api.SOFTWARE_CONFIG_INPUTS: sd.config.io['inputs'],
api.SOFTWARE_CONFIG_OUTPUTS: sd.config.io['outputs'],
api.SOFTWARE_CONFIG_OPTIONS: sd.config.io['options']
}
return result

View File

@ -1103,6 +1103,17 @@ class EngineService(service.Service):
result = [api.format_software_deployment(sd) for sd in all_sd]
return result
@request_context
def metadata_software_deployments(self, cnxt, server_id):
if not server_id:
raise ValueError(_('server_id must be specified'))
all_sd = db_api.software_deployment_get_all(cnxt, server_id)
# sort the configs by config name, to give the list of metadata a
# deterministic and controllable order.
all_sd_s = sorted(all_sd, key=lambda sd: sd.config.name)
result = [api.format_software_config(sd.config) for sd in all_sd_s]
return result
@rpc_common.client_exceptions(exception.NotFound)
@request_context
def show_software_deployment(self, cnxt, deployment_id):

View File

@ -200,7 +200,6 @@ SOFTWARE_CONFIG_KEYS = (
SOFTWARE_DEPLOYMENT_KEYS = (
SOFTWARE_DEPLOYMENT_ID,
SOFTWARE_DEPLOYMENT_CONFIG,
SOFTWARE_DEPLOYMENT_CONFIG_ID,
SOFTWARE_DEPLOYMENT_SERVER_ID,
SOFTWARE_DEPLOYMENT_INPUT_VALUES,
@ -211,7 +210,6 @@ SOFTWARE_DEPLOYMENT_KEYS = (
SOFTWARE_DEPLOYMENT_STATUS_REASON
) = (
'id',
'config',
'config_id',
'server_id',
'input_values',

View File

@ -392,6 +392,10 @@ class EngineClient(heat.openstack.common.rpc.proxy.RpcProxy):
return self.call(cnxt, self.make_msg('list_software_deployments',
server_id=server_id))
def metadata_software_deployments(self, cnxt, server_id):
return self.call(cnxt, self.make_msg('metadata_software_deployments',
server_id=server_id))
def show_software_deployment(self, cnxt, deployment_id):
return self.call(cnxt, self.make_msg('show_software_deployment',
deployment_id=deployment_id))

View File

@ -703,6 +703,9 @@ class FormatValidateParameterTest(HeatTestCase):
param_formated = api.format_validate_parameter(param)
self.assertEqual(self.expected, param_formated)
class FormatSoftwareConfigDeploymentTest(HeatTestCase):
def _dummy_software_config(self):
config = mock.Mock()
config.name = 'config_mysql'
@ -726,8 +729,8 @@ class FormatValidateParameterTest(HeatTestCase):
deployment.output_values = {'result': '0'}
deployment.action = 'INIT'
deployment.status = 'COMPLETE'
deployment.status_reason = None
deployment.signal_id = None
deployment.status_reason = 'Because'
deployment.signal_id = 'http://192.0.2.2/signal'
return deployment
def test_format_software_config(self):
@ -738,14 +741,22 @@ class FormatValidateParameterTest(HeatTestCase):
self.assertEqual([{'name': 'result'}], result['outputs'])
self.assertEqual({}, result['options'])
def test_format_software_config_none(self):
self.assertIsNone(api.format_software_config(None))
def test_format_software_deployment(self):
deployment = self._dummy_software_deployment()
result = api.format_software_deployment(deployment)
self.assertIsNotNone(result)
self.assertEqual(deployment.id, result['id'])
self.assertEqual(deployment.config.id, result['config_id'])
self.assertEqual(
deployment.config.io['inputs'], result['inputs'])
self.assertEqual(
deployment.config.io['outputs'], result['outputs'])
self.assertEqual(
deployment.config.io['options'], result['options'])
self.assertEqual(deployment.server_id, result['server_id'])
self.assertEqual(deployment.input_values, result['input_values'])
self.assertEqual(deployment.output_values, result['output_values'])
self.assertEqual(deployment.signal_id, result['signal_id'])
self.assertEqual(deployment.action, result['action'])
self.assertEqual(deployment.status, result['status'])
self.assertEqual(deployment.status_reason, result['status_reason'])
def test_format_software_deployment_none(self):
self.assertIsNone(api.format_software_deployment(None))

View File

@ -2614,12 +2614,16 @@ class SoftwareConfigServiceTest(HeatTestCase):
def _create_software_deployment(self, config_id=None, input_values={},
signal_id=None, action='INIT',
status='COMPLETE', status_reason=''):
status='COMPLETE', status_reason='',
config_group=None,
server_id=str(uuid.uuid4()),
config_name=None):
if config_id is None:
config = self._create_software_config()
config = self._create_software_config(group=config_group,
name=config_name)
config_id = config['id']
return self.engine.create_software_deployment(
self.ctx, str(uuid.uuid4()), config_id, input_values, signal_id,
self.ctx, server_id, config_id, input_values, signal_id,
action, status, status_reason)
def test_list_software_deployments(self):
@ -2636,6 +2640,34 @@ class SoftwareConfigServiceTest(HeatTestCase):
self.ctx, server_id=str(uuid.uuid4()))
self.assertEqual([], deployments)
def test_metadata_software_deployments(self):
server_id = str(uuid.uuid4())
d1 = self._create_software_deployment(config_group='mygroup',
server_id=server_id,
config_name='02_second')
d2 = self._create_software_deployment(config_group='mygroup',
server_id=server_id,
config_name='01_first')
d3 = self._create_software_deployment(config_group='myothergroup',
server_id=server_id,
config_name='03_third')
metadata = self.engine.metadata_software_deployments(
self.ctx, server_id=server_id)
self.assertEqual(3, len(metadata))
self.assertEqual('mygroup', metadata[1]['group'])
self.assertEqual('mygroup', metadata[0]['group'])
self.assertEqual('myothergroup', metadata[2]['group'])
self.assertEqual(d1['config_id'], metadata[1]['id'])
self.assertEqual(d2['config_id'], metadata[0]['id'])
self.assertEqual(d3['config_id'], metadata[2]['id'])
self.assertEqual('01_first', metadata[0]['name'])
self.assertEqual('02_second', metadata[1]['name'])
self.assertEqual('03_third', metadata[2]['name'])
deployments = self.engine.metadata_software_deployments(
self.ctx, server_id=str(uuid.uuid4()))
self.assertEqual([], deployments)
def test_show_software_deployment(self):
deployment_id = str(uuid.uuid4())
e = self.assertRaises(rpc_common.ClientException,
@ -2674,7 +2706,6 @@ class SoftwareConfigServiceTest(HeatTestCase):
deployment = self.engine.show_software_deployment(
self.ctx, deployment_id)
self.assertEqual(deployment_id, deployment['id'])
self.assertEqual(config['inputs'], deployment['inputs'])
self.assertEqual(kwargs['input_values'], deployment['input_values'])
def test_update_software_deployment(self):