From 675f8bc64fad223c4224a48d7f8b143958e6d89e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Harald=20Jens=C3=A5s?= Date: Mon, 11 May 2020 10:21:53 +0200 Subject: [PATCH] Jinja2 raise extension Extend Jinja2 envrionment with a raise method so that we can add logic in Jinja2 and raise errors. In jinja2 template the raise method can be used like this: {%- if condition %} {{ raise('MESSAGE') }} {%- endif %} Change-Id: Idaa1d570b129aa6c8c117b8087d1aad7ae987a47 --- ...nder-raise-extension-87c7ed150a252ff5.yaml | 12 ++++++++++++ tripleo_common/tests/utils/test_template.py | 19 +++++++++++++++++++ tripleo_common/utils/template.py | 8 ++++++-- 3 files changed, 37 insertions(+), 2 deletions(-) create mode 100644 releasenotes/notes/jinja2-template-render-raise-extension-87c7ed150a252ff5.yaml diff --git a/releasenotes/notes/jinja2-template-render-raise-extension-87c7ed150a252ff5.yaml b/releasenotes/notes/jinja2-template-render-raise-extension-87c7ed150a252ff5.yaml new file mode 100644 index 000000000..3b54f89a8 --- /dev/null +++ b/releasenotes/notes/jinja2-template-render-raise-extension-87c7ed150a252ff5.yaml @@ -0,0 +1,12 @@ +--- +other: + - | + The jinja2 template rendering function is extensended with a ``raise`` + method. This can be used to raise errors conditionally in the Jinja2 + templated tripleo-heat-tempaltes, for example in case some required property + is not defined in roles_data or network_data. The following example + demonstrates how to raise an error conditionally in a template:: + + {%- if condition %} + {{ raise('MESSAGE') }} + {%- endif %} diff --git a/tripleo_common/tests/utils/test_template.py b/tripleo_common/tests/utils/test_template.py index d9896c443..d74490d01 100644 --- a/tripleo_common/tests/utils/test_template.py +++ b/tripleo_common/tests/utils/test_template.py @@ -37,6 +37,11 @@ JINJA_SNIPPET = r""" DefaultPasswords: {get_attr: [DefaultPasswords, passwords]} {% endfor %}""" +JINJA_RAISE_CONFIG = r""" +# Jinja raise extension +{{ raise('MESSAGE') }} +""" + ROLE_DATA_YAML = r""" - name: CustomRole @@ -390,6 +395,20 @@ class ProcessTemplatesTest(base.TestCase): self.assertTrue( {'name': []} == template_utils.get_j2_excludes_file(swift)) + def test_j2_render_and_put_raise_in_template(self): + + # setup swift + swift = mock.MagicMock() + swift.get_object = mock.MagicMock() + swift.get_container = mock.MagicMock() + + # Test + args = (swift, JINJA_RAISE_CONFIG, {'role': 'CustomRole'}, + 'customrole-config.yaml', constants.DEFAULT_CONTAINER_NAME) + self.assertRaises(RuntimeError, + template_utils.j2_render_and_put, + *args) + def test_heat_resource_exists(self): heat_client = mock.MagicMock() stack = mock.MagicMock(stack_name='overcloud') diff --git a/tripleo_common/utils/template.py b/tripleo_common/utils/template.py index 44e7475f5..e1e74f3d7 100644 --- a/tripleo_common/utils/template.py +++ b/tripleo_common/utils/template.py @@ -64,14 +64,18 @@ class J2SwiftLoader(jinja2.BaseLoader): def j2_render_and_put(swift, j2_template, j2_data, yaml_f, container=constants.DEFAULT_CONTAINER_NAME): + def raise_helper(msg): + raise jinja2.exceptions.TemplateError(msg) + # Search for templates relative to the current template path first template_base = os.path.dirname(yaml_f) j2_loader = J2SwiftLoader(swift, container, template_base) try: # Render the j2 template - template = jinja2.Environment(loader=j2_loader).from_string( - j2_template) + jinja2_env = jinja2.Environment(loader=j2_loader) + jinja2_env.globals['raise'] = raise_helper + template = jinja2_env.from_string(j2_template) r_template = template.render(**j2_data) except jinja2.exceptions.TemplateError as ex: error_msg = ("Error rendering template %s : %s"