From 2e522f2ab47ebe08399d1e0fa29ffe613f992d31 Mon Sep 17 00:00:00 2001 From: Liam Young Date: Wed, 18 Apr 2018 07:35:55 +0000 Subject: [PATCH] Render local charm overlay from string Stop requiring the charm to ship with a boiler plate overlay for setting a relative path for local charm location. Instead render the overlay from a string var. As part of this some of the template rendering code was refactored. --- .../test_zaza_charm_lifecycle_deploy.py | 54 +++++++++--- zaza/charm_lifecycle/deploy.py | 82 ++++++++++++++++--- 2 files changed, 113 insertions(+), 23 deletions(-) diff --git a/unit_tests/test_zaza_charm_lifecycle_deploy.py b/unit_tests/test_zaza_charm_lifecycle_deploy.py index 96e49a4..982cc57 100644 --- a/unit_tests/test_zaza_charm_lifecycle_deploy.py +++ b/unit_tests/test_zaza_charm_lifecycle_deploy.py @@ -30,6 +30,29 @@ class TestCharmLifecycleDeploy(ut_utils.BaseTestCase): {'OS_VIP04': '10.10.0.2'} ) + def test_get_charm_config_contex(self): + self.patch_object(lc_deploy.utils, 'get_charm_config') + self.get_charm_config.return_value = { + 'charm_name': 'mycharm'} + self.assertEqual( + lc_deploy.get_charm_config_contex(), + {'charm_location': '../../../mycharm', 'charm_name': 'mycharm'}) + + def test_get_template_overlay_context(self): + self.patch_object(lc_deploy, 'get_template_context_from_env') + self.patch_object(lc_deploy, 'get_charm_config_contex') + self.get_template_context_from_env.return_value = { + 'OS_VIP04': '10.10.0.2'} + self.get_charm_config_contex.return_value = { + 'charm_location': '../../../mycharm', + 'charm_name': 'mycharm'} + self.assertEqual( + lc_deploy.get_template_overlay_context(), + { + 'OS_VIP04': '10.10.0.2', + 'charm_location': '../../../mycharm', + 'charm_name': 'mycharm'}) + def test_get_overlay_template_dir(self): self.assertEqual( lc_deploy.get_overlay_template_dir(), @@ -69,19 +92,27 @@ class TestCharmLifecycleDeploy(ut_utils.BaseTestCase): jinja2.exceptions.TemplateNotFound(name='bob') self.assertIsNone(lc_deploy.get_template('mybundle.yaml')) - def test_render_overlay(self): - self.patch_object(lc_deploy, 'get_template_context_from_env') + def test_render_template(self): + self.patch_object(lc_deploy, 'get_template_overlay_context') template_mock = mock.MagicMock() template_mock.render.return_value = 'Template contents' - self.patch_object(lc_deploy, 'get_template') - self.get_template.return_value = template_mock m = mock.mock_open() with mock.patch('zaza.charm_lifecycle.deploy.open', m, create=True): - lc_deploy.render_overlay('mybundle.yaml', '/tmp/') + lc_deploy.render_template(template_mock, '/tmp/mybundle.yaml') m.assert_called_once_with('/tmp/mybundle.yaml', 'w') handle = m() handle.write.assert_called_once_with('Template contents') + def test_render_overlay(self): + self.patch_object(lc_deploy, 'render_template') + template_mock = mock.MagicMock() + self.patch_object(lc_deploy, 'get_template') + self.get_template.return_value = template_mock + lc_deploy.render_overlay('my_overlay.yaml', '/tmp/special-dir') + self.render_template.assert_called_once_with( + template_mock, + '/tmp/special-dir/my_overlay.yaml') + def test_render_overlay_no_template(self): self.patch_object(lc_deploy, 'get_template') self.get_template.return_value = None @@ -89,23 +120,24 @@ class TestCharmLifecycleDeploy(ut_utils.BaseTestCase): def test_render_overlays(self): RESP = { - 'local-charm-overlay.yaml': '/tmp/local-charm-overlay.yaml', 'mybundles/mybundle.yaml': '/tmp/mybundle.yaml'} + self.patch_object(lc_deploy, 'render_local_overlay') + self.render_local_overlay.return_value = '/tmp/local-overlay.yaml' self.patch_object(lc_deploy, 'render_overlay') self.render_overlay.side_effect = lambda x, y: RESP[x] self.assertEqual( lc_deploy.render_overlays('mybundles/mybundle.yaml', '/tmp'), - ['/tmp/local-charm-overlay.yaml', '/tmp/mybundle.yaml']) + ['/tmp/local-overlay.yaml', '/tmp/mybundle.yaml']) def test_render_overlays_missing(self): - RESP = { - 'local-charm-overlay.yaml': None, - 'mybundles/mybundle.yaml': '/tmp/mybundle.yaml'} + RESP = {'mybundles/mybundle.yaml': None} self.patch_object(lc_deploy, 'render_overlay') + self.patch_object(lc_deploy, 'render_local_overlay') + self.render_local_overlay.return_value = '/tmp/local.yaml' self.render_overlay.side_effect = lambda x, y: RESP[x] self.assertEqual( lc_deploy.render_overlays('mybundles/mybundle.yaml', '/tmp'), - ['/tmp/mybundle.yaml']) + ['/tmp/local.yaml']) def test_deploy_bundle(self): self.patch_object(lc_deploy, 'render_overlays') diff --git a/zaza/charm_lifecycle/deploy.py b/zaza/charm_lifecycle/deploy.py index 81cb774..a516963 100755 --- a/zaza/charm_lifecycle/deploy.py +++ b/zaza/charm_lifecycle/deploy.py @@ -11,7 +11,6 @@ import juju_wait import zaza.charm_lifecycle.utils as utils DEFAULT_OVERLAY_TEMPLATE_DIR = 'tests/bundles/overlays' -DEFAULT_OVERLAYS = ['local-charm-overlay.yaml'] VALID_ENVIRONMENT_KEY_PREFIXES = [ 'FIP_RANGE', 'GATEWAY', @@ -20,11 +19,15 @@ VALID_ENVIRONMENT_KEY_PREFIXES = [ 'OS_', 'VIP_RANGE', ] +LOCAL_OVERLAY_TEMPLATE = """ +applications: + {{ charm_name }}: + charm: {{ charm_location }} +""" def is_valid_env_key(key): """Check if key is a valid environment variable name for use with template - rendering :param key: List of configure functions functions :type key: str @@ -49,6 +52,34 @@ def get_template_context_from_env(): return {k: v for k, v in os.environ.items() if is_valid_env_key(k)} +def get_charm_config_contex(): + """Return settings from charm config file + + :returns: Context for template rendering + :rtype: dict + """ + test_config = utils.get_charm_config() + ctxt = { + 'charm_name': test_config['charm_name'], + 'charm_location': '../../../{}'.format(test_config['charm_name'])} + return ctxt + + +def get_template_overlay_context(): + """Combine contexts which can be used for overlay template rendering + + :returns: Context for template rendering + :rtype: dict + """ + context = {} + contexts = [ + get_template_context_from_env(), + get_charm_config_contex()] + for c in contexts: + context.update(c) + return context + + def get_overlay_template_dir(): """Return the directory to look for overlay template files in. @@ -96,6 +127,19 @@ def get_template(target_file): return template +def render_template(template, target_file): + """Render the template to the file supplied + + :param template: Template to be rendered + :type template: jinja2.Template + :param target_file: File name for rendered template + :type target_file: str + """ + with open(target_file, "w") as fh: + fh.write( + template.render(get_template_overlay_context())) + + def render_overlay(overlay_name, target_dir): """Render the overlay template in the directory supplied @@ -112,9 +156,24 @@ def render_overlay(overlay_name, target_dir): rendered_template_file = os.path.join( target_dir, os.path.basename(overlay_name)) - with open(rendered_template_file, "w") as fh: - fh.write( - template.render(get_template_context_from_env())) + render_template(template, rendered_template_file) + return rendered_template_file + + +def render_local_overlay(target_dir): + """Render the local overlay template in the directory supplied + + :param target_dir: Directory to render overlay in + :type overlay_name: str + :returns: Path to rendered overlay + :rtype: str + """ + template = jinja2.Environment(loader=jinja2.BaseLoader).from_string( + LOCAL_OVERLAY_TEMPLATE) + rendered_template_file = os.path.join( + target_dir, + os.path.basename('local-charm-overlay.yaml')) + render_template(template, rendered_template_file) return rendered_template_file @@ -125,14 +184,13 @@ def render_overlays(bundle, target_dir): :type bundle: str :param target_dir: Directory to render overlay in :type overlay_name: str - :returns: Path to rendered overlay - :rtype: str + :returns: List of rendered overlays + :rtype: [str, str,...] """ - overlays = [] - for overlay in DEFAULT_OVERLAYS + [bundle]: - rendered_overlay = render_overlay(overlay, target_dir) - if rendered_overlay: - overlays.append(rendered_overlay) + overlays = [render_local_overlay(target_dir)] + rendered_bundle_overlay = render_overlay(bundle, target_dir) + if rendered_bundle_overlay: + overlays.append(rendered_bundle_overlay) return overlays