From 152b03b09bee775221d89fea2470e46ce96fe187 Mon Sep 17 00:00:00 2001 From: Jason Dunsmore Date: Tue, 10 May 2016 14:29:38 -0500 Subject: [PATCH] Add default release names for template versions Release version names are easier for template authors to remember than seemingly arbitrary dates. It should also make it clearer to new Heat users that heat_template_version is not like a BIND zone file version (which would be incremented with each version of the template). Change-Id: Iae9b6a676702b2a115b18fdfb1ab2afbe5faacde blueprint support-alias-for-heat-template-version-names --- doc/source/template_guide/hot_spec.rst | 21 ++++++------- heat/common/exception.py | 5 ++++ heat/engine/service.py | 30 +++++++++++++++++-- heat/tests/test_engine_service.py | 29 +++++++++++++++--- heat/tests/test_template.py | 2 +- .../functional/test_templates.py | 2 +- setup.cfg | 5 ++-- 7 files changed, 73 insertions(+), 21 deletions(-) diff --git a/doc/source/template_guide/hot_spec.rst b/doc/source/template_guide/hot_spec.rst index b645ef855b..a646a0f11e 100644 --- a/doc/source/template_guide/hot_spec.rst +++ b/doc/source/template_guide/hot_spec.rst @@ -96,9 +96,10 @@ Heat template version ~~~~~~~~~~~~~~~~~~~~~ The value of ``heat_template_version`` tells Heat not only the format of the -template but also features that will be validated and supported. -For example, Heat currently supports the following values for the -``heat_template_version`` key: +template but also features that will be validated and supported. Beginning with +the Newton release, the version can be either the date of the Heat release or +the code name of the Heat release. Heat currently supports the following values +for the ``heat_template_version`` key: 2013-05-23 ---------- @@ -203,14 +204,14 @@ For example, Heat currently supports the following values for the str_replace str_split -2016-10-14 ----------- - The key with value ``2016-10-14`` indicates that the YAML document is a HOT - template and it may contain features added and/or removed up until the - Newton release. This version adds the ``yaql`` function which +2016-10-14 | newton +------------------- + The key with value ``2016-10-14`` or ``newton`` indicates that the YAML + document is a HOT template and it may contain features added and/or removed + up until the Newton release. This version adds the ``yaql`` function which can be used for evaluation of complex expressions, and also adds ``equals`` - function which can be used to compare whether two values are equal. - The complete list of supported functions is:: + function which can be used to compare whether two values are equal. The + complete list of supported functions is:: digest get_attr diff --git a/heat/common/exception.py b/heat/common/exception.py index c29295888a..c4b8d9c82a 100644 --- a/heat/common/exception.py +++ b/heat/common/exception.py @@ -500,3 +500,8 @@ class NoActionRequired(Exception): class InvalidServiceVersion(HeatException): msg_fmt = _("Invalid service %(service)s version %(version)s") + + +class InvalidTemplateVersions(HeatException): + msg_fmt = _('A template version alias %(version)s was added for a ' + 'template class that has no official YYYY-MM-DD version.') diff --git a/heat/engine/service.py b/heat/engine/service.py index 4c93abafa1..aa7453ee85 100644 --- a/heat/engine/service.py +++ b/heat/engine/service.py @@ -1462,15 +1462,39 @@ class EngineService(service.Service): return result def list_template_versions(self, cnxt): + def find_version_class(versions, cls): + for version in versions: + if version['class'] is cls: + return version + mgr = templatem._get_template_extension_manager() _template_classes = [(name, mgr[name].plugin) for name in mgr.names()] versions = [] - for t in _template_classes: + for t in sorted(_template_classes): # Sort to ensure dates come first if issubclass(t[1], cfntemplate.CfnTemplate): - versions.append({'version': t[0], 'type': 'cfn'}) + type = 'cfn' else: - versions.append({'version': t[0], 'type': 'hot'}) + type = 'hot' + + # Official versions are in '%Y-%m-%d' format. Default + # version aliases are the Heat release code name + try: + datetime.datetime.strptime(t[0].split('.')[-1], '%Y-%m-%d') + versions.append({'version': t[0], 'type': type, + 'class': t[1], 'aliases': []}) + except ValueError: + version = find_version_class(versions, t[1]) + if version is not None: + version['aliases'].append(t[0]) + else: + raise exception.InvalidTemplateVersions(version=t[0]) + + # 'class' was just used to find the version that the alias + # maps to. Remove it so it will not show up in the output + for version in versions: + del version['class'] + return versions def list_template_functions(self, cnxt, template_version): diff --git a/heat/tests/test_engine_service.py b/heat/tests/test_engine_service.py index 4dab0762d9..c487520590 100644 --- a/heat/tests/test_engine_service.py +++ b/heat/tests/test_engine_service.py @@ -934,11 +934,12 @@ class StackServiceTest(common.HeatTestCase): class DummyMgr(object): def names(self): - return ['a.b', 'c.d'] + return ['a.2012-12-12', 'c.newton', 'c.2016-10-14', + 'c.something'] def __getitem__(self, item): m = mock.MagicMock() - if item == 'a.b': + if item == 'a.2012-12-12': m.plugin = cfntemplate.CfnTemplate return m else: @@ -947,10 +948,30 @@ class StackServiceTest(common.HeatTestCase): templ_mock.return_value = DummyMgr() templates = self.eng.list_template_versions(self.ctx) - expected = [{'version': 'a.b', 'type': 'cfn'}, - {'version': 'c.d', 'type': 'hot'}] + expected = [{'version': 'a.2012-12-12', 'type': 'cfn', 'aliases': []}, + {'version': 'c.2016-10-14', + 'aliases': ['c.newton', 'c.something'], 'type': 'hot'}] self.assertEqual(expected, templates) + @mock.patch('heat.engine.template._get_template_extension_manager') + def test_list_template_versions_invalid_version(self, templ_mock): + + class DummyMgr(object): + def names(self): + return ['c.something'] + + def __getitem__(self, item): + m = mock.MagicMock() + if item == 'c.something': + m.plugin = cfntemplate.CfnTemplate + return m + + templ_mock.return_value = DummyMgr() + ret = self.assertRaises(exception.InvalidTemplateVersions, + self.eng.list_template_versions, self.ctx) + self.assertIn('A template version alias c.something was added', + six.text_type(ret)) + @mock.patch('heat.engine.template._get_template_extension_manager') def test_list_template_functions(self, templ_mock): diff --git a/heat/tests/test_template.py b/heat/tests/test_template.py index 34cae03c35..4199235869 100644 --- a/heat/tests/test_template.py +++ b/heat/tests/test_template.py @@ -522,7 +522,7 @@ class TemplateTest(common.HeatTestCase): template.Template, invalid_hot_version_tmp) valid_versions = ['2013-05-23', '2014-10-16', '2015-04-30', '2015-10-15', '2016-04-08', - '2016-10-14'] + '2016-10-14', 'newton'] ex_error_msg = ('The template version is invalid: ' '"heat_template_version: 2012-12-12". ' '"heat_template_version" should be one of: %s' diff --git a/heat_integrationtests/functional/test_templates.py b/heat_integrationtests/functional/test_templates.py index 82a1af4f72..9d36391c60 100644 --- a/heat_integrationtests/functional/test_templates.py +++ b/heat_integrationtests/functional/test_templates.py @@ -54,7 +54,7 @@ class TemplateAPITest(functional_base.FunctionalTestsBase): supported_template_versions = ["2013-05-23", "2014-10-16", "2015-04-30", "2015-10-15", "2012-12-12", "2010-09-09", - "2016-04-08", "2016-10-14"] + "2016-04-08", "2016-10-14", "newton"] for template in template_versions: self.assertIn(template.version.split(".")[1], supported_template_versions) diff --git a/setup.cfg b/setup.cfg index 3b4a3b67b2..7120179aa2 100644 --- a/setup.cfg +++ b/setup.cfg @@ -141,15 +141,16 @@ heat.event_sinks = zaqar-queue = heat.engine.clients.os.zaqar:ZaqarEventSink heat.templates = + AWSTemplateFormatVersion.2010-09-09 = heat.engine.cfn.template:CfnTemplate + HeatTemplateFormatVersion.2012-12-12 = heat.engine.cfn.template:HeatTemplate heat_template_version.2013-05-23 = heat.engine.hot.template:HOTemplate20130523 heat_template_version.2014-10-16 = heat.engine.hot.template:HOTemplate20141016 heat_template_version.2015-04-30 = heat.engine.hot.template:HOTemplate20150430 heat_template_version.2015-10-15 = heat.engine.hot.template:HOTemplate20151015 heat_template_version.2016-04-08 = heat.engine.hot.template:HOTemplate20160408 heat_template_version.2016-10-14 = heat.engine.hot.template:HOTemplate20161014 - HeatTemplateFormatVersion.2012-12-12 = heat.engine.cfn.template:HeatTemplate + heat_template_version.newton = heat.engine.hot.template:HOTemplate20161014 HeatTemplateFormatVersion.2016-10-14 = heat.engine.cfn.template:HeatTemplate20161014 - AWSTemplateFormatVersion.2010-09-09 = heat.engine.cfn.template:CfnTemplate [global] setup-hooks =