From 1e82f2c2c35155e0c441e2c57a7b7c9cca208fce Mon Sep 17 00:00:00 2001 From: huangtianhua Date: Sun, 4 Jan 2015 16:04:22 +0800 Subject: [PATCH] Allow empty 'config' for software deployment Allow empty 'config' for software deployment resource. The use case would be for custom agents where the config is already baked into the image, so these agents would still want to: read input_values to feed into the baked-in config signal heat that deployment is complete, including output values Change-Id: I616640f7fa158576ca65ee7ed4075c38928a81a9 Closes-Bug: #1407387 --- .../software_config/software_deployment.py | 19 +++--- heat/tests/test_software_deployment.py | 68 +++++++++++++++++++ 2 files changed, 79 insertions(+), 8 deletions(-) diff --git a/heat/engine/resources/software_config/software_deployment.py b/heat/engine/resources/software_config/software_deployment.py index 496d732e59..aa9e8a94df 100644 --- a/heat/engine/resources/software_config/software_deployment.py +++ b/heat/engine/resources/software_config/software_deployment.py @@ -211,12 +211,15 @@ class SoftwareDeployment(signal_responder.SignalResponder): return derived_config[rpc_api.SOFTWARE_CONFIG_ID] def _handle_action(self, action): - config_id = self.properties.get(self.CONFIG) - config = self.rpc_client().show_software_config( - self.context, config_id) + if self.properties.get(self.CONFIG): + config = self.rpc_client().show_software_config( + self.context, self.properties.get(self.CONFIG)) + else: + config = {} if (action not in self.properties[self.DEPLOY_ACTIONS] - and not config[rpc_api.SOFTWARE_CONFIG_GROUP] == 'component'): + and not config.get( + rpc_api.SOFTWARE_CONFIG_GROUP) == 'component'): return props = self._build_properties( @@ -266,14 +269,14 @@ class SoftwareDeployment(signal_responder.SignalResponder): derived_options = self._build_derived_options(action, source) derived_config = self._build_derived_config( action, source, derived_inputs, derived_options) - derived_name = self.properties.get(self.NAME) or source[scl.NAME] + derived_name = self.properties.get(self.NAME) or source.get(scl.NAME) return { - scl.GROUP: source[scl.GROUP], - scl.CONFIG: derived_config, + scl.GROUP: source.get(scl.GROUP) or 'Heat::Ungrouped', + scl.CONFIG: derived_config or '', scl.OPTIONS: derived_options, scl.INPUTS: derived_inputs, scl.OUTPUTS: source.get(scl.OUTPUTS), - scl.NAME: derived_name + scl.NAME: derived_name or self.physical_resource_name() } def _build_derived_config(self, action, source, diff --git a/heat/tests/test_software_deployment.py b/heat/tests/test_software_deployment.py index a4163e737b..812d03634b 100644 --- a/heat/tests/test_software_deployment.py +++ b/heat/tests/test_software_deployment.py @@ -96,6 +96,20 @@ class SoftwareDeploymentTest(common.HeatTestCase): } } + template_no_config = { + 'HeatTemplateFormatVersion': '2012-12-12', + 'Resources': { + 'deployment_mysql': { + 'Type': 'OS::Heat::SoftwareDeployment', + 'Properties': { + 'server': '9f1f0e00-05d2-4ca5-8602-95021f19c9d0', + 'input_values': {'foo': 'bar', 'bink': 'bonk'}, + 'signal_transport': 'NO_SIGNAL', + } + } + } + } + def setUp(self): super(SoftwareDeploymentTest, self).setUp() self.ctx = utils.dummy_context() @@ -295,6 +309,60 @@ class SoftwareDeploymentTest(common.HeatTestCase): 'status_reason': 'Not waiting for outputs signal'}, self.rpc_client.create_software_deployment.call_args[1]) + def test_handle_create_without_config(self): + self._create_stack(self.template_no_config) + sd = self.mock_deployment() + derived_sc = self.mock_derived_software_config() + self.deployment.handle_create() + + self.assertEqual(sd['id'], self.deployment.resource_id) + self.assertEqual({ + 'config': '', + 'group': 'Heat::Ungrouped', + 'name': self.deployment.physical_resource_name(), + 'inputs': [{ + 'name': 'foo', + 'type': 'String', + 'value': 'bar' + }, { + 'name': 'bink', + 'type': 'String', + 'value': 'bonk' + }, { + 'description': 'ID of the server being deployed to', + 'name': 'deploy_server_id', + 'type': 'String', + 'value': '9f1f0e00-05d2-4ca5-8602-95021f19c9d0' + }, { + 'description': 'Name of the current action being deployed', + 'name': 'deploy_action', + 'type': 'String', + 'value': 'CREATE' + }, { + 'description': 'ID of the stack this deployment belongs to', + 'name': 'deploy_stack_id', + 'type': 'String', + 'value': ('software_deployment_test_stack' + '/42f6f66b-631a-44e7-8d01-e22fb54574a9') + }, { + 'description': 'Name of this deployment resource in the stack', + 'name': 'deploy_resource_name', + 'type': 'String', + 'value': 'deployment_mysql' + }], + 'options': None, + 'outputs': None + }, self.rpc_client.create_software_config.call_args[1]) + + self.assertEqual( + {'action': 'CREATE', + 'config_id': derived_sc['id'], + 'server_id': '9f1f0e00-05d2-4ca5-8602-95021f19c9d0', + 'stack_user_project_id': '65728b74-cfe7-4f17-9c15-11d4f686e591', + 'status': 'COMPLETE', + 'status_reason': 'Not waiting for outputs signal'}, + self.rpc_client.create_software_deployment.call_args[1]) + def test_handle_create_for_component(self): self._create_stack(self.template_no_signal)