From 99a8fa906404cf8d593b5eb0e2a50ad7a03f3fe9 Mon Sep 17 00:00:00 2001 From: Steve Baker Date: Mon, 17 Feb 2014 13:15:25 +1300 Subject: [PATCH] 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 --- heat/engine/api.py | 6 ----- heat/engine/service.py | 11 ++++++++ heat/rpc/api.py | 2 -- heat/rpc/client.py | 4 +++ heat/tests/test_engine_api_utils.py | 27 ++++++++++++++------ heat/tests/test_engine_service.py | 39 ++++++++++++++++++++++++++--- 6 files changed, 69 insertions(+), 20 deletions(-) diff --git a/heat/engine/api.py b/heat/engine/api.py index dfc598b191..223540a778 100644 --- a/heat/engine/api.py +++ b/heat/engine/api.py @@ -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 diff --git a/heat/engine/service.py b/heat/engine/service.py index 980ee23f25..c8330349a8 100644 --- a/heat/engine/service.py +++ b/heat/engine/service.py @@ -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): diff --git a/heat/rpc/api.py b/heat/rpc/api.py index 9745f94aab..05d3cbf37a 100644 --- a/heat/rpc/api.py +++ b/heat/rpc/api.py @@ -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', diff --git a/heat/rpc/client.py b/heat/rpc/client.py index 4558ce1f55..1531a594e6 100644 --- a/heat/rpc/client.py +++ b/heat/rpc/client.py @@ -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)) diff --git a/heat/tests/test_engine_api_utils.py b/heat/tests/test_engine_api_utils.py index 5ceb40617c..35c96677c2 100644 --- a/heat/tests/test_engine_api_utils.py +++ b/heat/tests/test_engine_api_utils.py @@ -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)) diff --git a/heat/tests/test_engine_service.py b/heat/tests/test_engine_service.py index dd93da785f..6e447a7c5e 100644 --- a/heat/tests/test_engine_service.py +++ b/heat/tests/test_engine_service.py @@ -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):