From 7221cd2eba592cdb2097b3af52f9c297a54aae60 Mon Sep 17 00:00:00 2001 From: Thomas Herve Date: Tue, 2 May 2017 16:05:05 +0200 Subject: [PATCH] Load all templates for generating parameter schema To be able to handle parameter defaults properly, we need to load all possible templates when merging the environments, to generate an approximate schema. Closes-Bug: #1669571 Change-Id: Idab781d3e6af92990c357a727aa60ec0aa8f5f05 --- heat/engine/service.py | 8 ++++---- heat/engine/template.py | 16 ++++++++++++++++ heat/tests/test_validate.py | 21 +++++++++++++++++++++ 3 files changed, 41 insertions(+), 4 deletions(-) diff --git a/heat/engine/service.py b/heat/engine/service.py index 7d372acf73..a970ba2b09 100644 --- a/heat/engine/service.py +++ b/heat/engine/service.py @@ -696,7 +696,7 @@ class EngineService(service.ServiceBase): else: tmpl = templatem.Template(template, files=files) env_util.merge_environments(environment_files, files, params, - tmpl.param_schemata()) + tmpl.all_param_schemata(files)) tmpl.env = environment.Environment(params) self._validate_new_stack(cnxt, stack_name, tmpl) @@ -891,7 +891,7 @@ class EngineService(service.ServiceBase): new_files.update(files or {}) tmpl = templatem.Template(new_template, files=new_files) env_util.merge_environments(environment_files, files, params, - tmpl.param_schemata()) + tmpl.all_param_schemata(files)) existing_env = current_stack.env.env_as_dict() existing_params = existing_env[env_fmt.PARAMETERS] clear_params = set(args.get(rpc_api.PARAM_CLEAR_PARAMETERS, [])) @@ -912,7 +912,7 @@ class EngineService(service.ServiceBase): else: tmpl = templatem.Template(template, files=files) env_util.merge_environments(environment_files, files, params, - tmpl.param_schemata()) + tmpl.all_param_schemata(files)) tmpl.env = environment.Environment(params) max_resources = cfg.CONF.max_resources_per_stack @@ -1221,7 +1221,7 @@ class EngineService(service.ServiceBase): tmpl = templatem.Template(template, files=files) env_util.merge_environments(environment_files, files, params, - tmpl.param_schemata()) + tmpl.all_param_schemata(files)) tmpl.env = environment.Environment(params) try: self._validate_template(cnxt, tmpl) diff --git a/heat/engine/template.py b/heat/engine/template.py index dbc8a47be2..44ea031989 100644 --- a/heat/engine/template.py +++ b/heat/engine/template.py @@ -23,6 +23,7 @@ from stevedore import extension from heat.common import exception from heat.common.i18n import _ +from heat.common import template_format from heat.engine import conditions from heat.engine import environment from heat.engine import function @@ -197,6 +198,21 @@ class Template(collections.Mapping): """Return a dict of parameters.Schema objects for the parameters.""" pass + def all_param_schemata(self, files): + schema = {} + files = files if files is not None else {} + for f in files.values(): + try: + data = template_format.parse(f) + except ValueError: + continue + else: + sub_tmpl = Template(data) + schema.update(sub_tmpl.param_schemata()) + # Parent template has precedence, so update the schema last. + schema.update(self.param_schemata()) + return schema + @abc.abstractmethod def get_section_name(self, section): """Return a correct section name.""" diff --git a/heat/tests/test_validate.py b/heat/tests/test_validate.py index ea31e1bae8..4b3f6a00b9 100644 --- a/heat/tests/test_validate.py +++ b/heat/tests/test_validate.py @@ -1016,6 +1016,27 @@ class ValidateTest(common.HeatTestCase): res['Parameters']['net_name']['Value']) self.assertNotIn('Default', res['Parameters']['net_name']) + def test_validate_parameters_nested(self): + t = template_format.parse(test_template_allowed_integers) + + other_template = test_template_no_default.replace( + 'net_name', 'net_name2') + + files = {'env1': 'parameter_defaults:\n net_name: net1', + 'env2': 'parameter_defaults:' + '\n net_name: net2' + '\n net_name2: net3', + 'tmpl1.yaml': test_template_no_default, + 'tmpl2.yaml': other_template} + params = {'parameters': {}, 'parameter_defaults': {}} + + self.engine.validate_template( + self.ctx, t, + params=params, + files=files, environment_files=['env1', 'env2']) + self.assertEqual('net2', params['parameter_defaults']['net_name']) + self.assertEqual('net3', params['parameter_defaults']['net_name2']) + def test_validate_hot_empty_parameters_valid(self): t = template_format.parse( """