diff --git a/heat/engine/cfn/template.py b/heat/engine/cfn/template.py index 476b66c7b8..6b705e428d 100644 --- a/heat/engine/cfn/template.py +++ b/heat/engine/cfn/template.py @@ -75,6 +75,9 @@ class CfnTemplateBase(template_common.CommonTemplate): 'deletion_policy': RES_DELETION_POLICY, 'update_policy': RES_UPDATE_POLICY} + HOT_TO_CFN_OUTPUT_ATTRS = {'description': OUTPUT_DESCRIPTION, + 'value': OUTPUT_VALUE} + def __getitem__(self, section): """Get the relevant section in the template.""" if section not in self.SECTIONS: @@ -157,6 +160,15 @@ class CfnTemplateBase(template_common.CommonTemplate): self.t[self.RESOURCES] = {} self.t[self.RESOURCES][name] = cfn_tmpl + def add_output(self, definition): + hot_op = definition.render_hot() + cfn_op = dict((self.HOT_TO_CFN_OUTPUT_ATTRS[k], v) + for k, v in hot_op.items()) + + if self.t.get(self.OUTPUTS) is None: + self.t[self.OUTPUTS] = {} + self.t[self.OUTPUTS][definition.name] = cfn_op + class CfnTemplate(CfnTemplateBase): diff --git a/heat/engine/hot/template.py b/heat/engine/hot/template.py index f8b3b88229..0a93bbc763 100644 --- a/heat/engine/hot/template.py +++ b/heat/engine/hot/template.py @@ -268,6 +268,11 @@ class HOTemplate20130523(template_common.CommonTemplate): self.t[self.RESOURCES] = {} self.t[self.RESOURCES][name] = definition.render_hot() + def add_output(self, definition): + if self.t.get(self.OUTPUTS) is None: + self.t[self.OUTPUTS] = {} + self.t[self.OUTPUTS][definition.name] = definition.render_hot() + class HOTemplate20141016(HOTemplate20130523): functions = { diff --git a/heat/engine/output.py b/heat/engine/output.py index 8fc7c84373..c74ce65b2b 100644 --- a/heat/engine/output.py +++ b/heat/engine/output.py @@ -11,6 +11,7 @@ # License for the specific language governing permissions and limitations # under the License. +import copy import six from heat.engine import function @@ -49,3 +50,10 @@ class OutputDefinition(object): return 'No description given' return six.text_type(self._description) + + def render_hot(self): + def items(): + if self._description is not None: + yield 'description', self._description + yield 'value', copy.deepcopy(self._value) + return dict(items()) diff --git a/heat/engine/template.py b/heat/engine/template.py index 92f395ef91..cb5551c4e9 100644 --- a/heat/engine/template.py +++ b/heat/engine/template.py @@ -255,6 +255,13 @@ class Template(collections.Mapping): """ pass + def add_output(self, definition): + """Add an output to the template. + + The output is passed as a OutputDefinition object. + """ + raise NotImplementedError + def remove_resource(self, name): """Remove a resource from the template.""" self.t.get(self.RESOURCES, {}).pop(name) diff --git a/heat/tests/test_hot.py b/heat/tests/test_hot.py index 8d4df604f3..cde940519f 100644 --- a/heat/tests/test_hot.py +++ b/heat/tests/test_hot.py @@ -1857,6 +1857,23 @@ conditions: self.assertEqual(hot_tpl['resources'], empty.t['resources']) + def test_add_output(self): + hot_tpl = template_format.parse(''' + heat_template_version: 2013-05-23 + outputs: + output1: + description: An output + value: bar + ''') + source = template.Template(hot_tpl) + empty = template.Template(copy.deepcopy(hot_tpl_empty)) + stack = parser.Stack(utils.dummy_context(), 'test_stack', source) + + for defn in six.itervalues(source.outputs(stack)): + empty.add_output(defn) + + self.assertEqual(hot_tpl['outputs'], empty.t['outputs']) + def test_filter(self): snippet = {'filter': [[None], [1, None, 4, 2, None]]} tmpl = template.Template(hot_ocata_tpl_empty) diff --git a/heat/tests/test_template.py b/heat/tests/test_template.py index 598629961c..d09c0804da 100644 --- a/heat/tests/test_template.py +++ b/heat/tests/test_template.py @@ -1429,6 +1429,23 @@ class TemplateTest(common.HeatTestCase): self.assertEqual(cfn_tpl['Resources'], empty.t['Resources']) + def test_add_output(self): + cfn_tpl = template_format.parse(''' + AWSTemplateFormatVersion: 2010-09-09 + Outputs: + output1: + Description: An output + Value: foo + ''') + source = template.Template(cfn_tpl) + empty = template.Template(copy.deepcopy(empty_template)) + stk = stack.Stack(self.ctx, 'test_stack', source) + + for defn in six.itervalues(source.outputs(stk)): + empty.add_output(defn) + + self.assertEqual(cfn_tpl['Outputs'], empty.t['Outputs']) + def test_create_empty_template_default_version(self): empty_template = template.Template.create_empty_template() self.assertEqual(hot_t.HOTemplate20150430, empty_template.__class__)