From a2c3e002970fa1b79922d9f58b2fe1270d05162a Mon Sep 17 00:00:00 2001 From: Steven Hardy Date: Wed, 26 Aug 2015 14:58:53 +0100 Subject: [PATCH] SoftwareDeploymentGroup allow arbitrary keys for attributes Since SoftwareDeploymentGroup is really a ResourceGroup, it's capable of resolving any attribute supported by SoftwareDeployment, including arbitrary outputs mapped to attributes. Exposing these via the SoftwareDeploymentGroup resource provides much better flexibility than forcing users to mangle everything via stdout. This has the side-effect of making the existing attributes somewhat redundant, e.g: get_attr: [a_sdg, deploy_stdouts] is exactly equivalent to this: get_attr: [a_sdg, deploy_stdout] The deploy_stdout attribute should be transparently reflected from the SoftwareDeployment resources via the normal ResourceGroup interfaces, so we could consider deprecating the existing attributes at some point. Change-Id: Ie3b89155d2be0050394eb7f7d5000331cde9aae0 Closes-Bug: #1488921 --- .../openstack/heat/software_deployment.py | 14 +++++++++- heat/tests/test_software_deployment.py | 28 +++++++++++++++++++ 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/heat/engine/resources/openstack/heat/software_deployment.py b/heat/engine/resources/openstack/heat/software_deployment.py index 6e27661371..620f138200 100644 --- a/heat/engine/resources/openstack/heat/software_deployment.py +++ b/heat/engine/resources/openstack/heat/software_deployment.py @@ -548,6 +548,16 @@ class SoftwareDeployment(signal_responder.SignalResponder): class SoftwareDeploymentGroup(resource_group.ResourceGroup): + ''' + This resource associates a group of servers with some configuration which + is to be deployed to all servers in the group. + + The properties work in a similar way to OS::Heat::SoftwareDeployment, + and in addition to the attributes documented, you may pass any + attribute supported by OS::Heat::SoftwareDeployment, including those + exposing arbitrary outputs, and return a map of deployment names to + the specified attribute. + ''' support_status = support.SupportStatus(version='5.0.0') @@ -644,7 +654,9 @@ class SoftwareDeploymentGroup(resource_group.ResourceGroup): elif key == self.STATUS_CODES: n_attr = SoftwareDeployment.STATUS_CODE else: - return None + # Allow any attribute valid for a single SoftwareDeployment + # including arbitrary outputs, so we can't validate here + n_attr = key rg_attr = rg.FnGetAtt(rg.ATTR_ATTRIBUTES, n_attr) return attributes.select_from_attribute(rg_attr, path) diff --git a/heat/tests/test_software_deployment.py b/heat/tests/test_software_deployment.py index ca74552c4e..b5e27e9c59 100644 --- a/heat/tests/test_software_deployment.py +++ b/heat/tests/test_software_deployment.py @@ -1333,6 +1333,34 @@ class SoftwareDeploymentGroupTest(common.HeatTestCase): mock.call('deploy_status_code'), ]) + def test_attributes_passthrough_key(self): + '''Prove attributes not in the schema pass-through.''' + stack = utils.parse_stack(self.template) + snip = stack.t.resource_definitions(stack)['deploy_mysql'] + resg = sd.SoftwareDeploymentGroup('test', snip, stack) + nested = self.patchobject(resg, 'nested') + server1 = mock.MagicMock() + server2 = mock.MagicMock() + nested.return_value = { + 'server1': server1, + 'server2': server2 + } + + server1.FnGetAtt.return_value = 'attr1' + server2.FnGetAtt.return_value = 'attr2' + self.assertEqual({ + 'server1': 'attr1', + 'server2': 'attr2' + }, resg.FnGetAtt('some_attr')) + + server1.FnGetAtt.assert_has_calls([ + mock.call('some_attr'), + ]) + + server2.FnGetAtt.assert_has_calls([ + mock.call('some_attr'), + ]) + def test_validate(self): stack = utils.parse_stack(self.template) snip = stack.t.resource_definitions(stack)['deploy_mysql']