diff --git a/README.md b/README.md index f2d8109..56272e1 100644 --- a/README.md +++ b/README.md @@ -358,6 +358,22 @@ Command line keys `--tags` and `--skip-tags` can be specified multiple times, fo ``` k8s-handle deploy --section production --tags=tag1 --tags=tag2 --tags=tag3 ``` + +### Groups +You can make groups for templates. For example: +```yaml +production: + templates: + - group: + - template: my-configmap.yaml.j2 + - template: my-deployment.yaml.j2 + - template: my-service.yaml.j2 + tags: service-one + - group: + - template: my-job.yaml.j2 +``` +It is useful for creating different sets of templates for other environments, or tag a bunch of templates at once + ## Variables ### Required parameters k8s-handle needs several parameters to be set in order to connect to k8s, such as: diff --git a/k8s_handle/templating.py b/k8s_handle/templating.py index f0ed22c..3d29dc1 100644 --- a/k8s_handle/templating.py +++ b/k8s_handle/templating.py @@ -88,6 +88,21 @@ def __init__(self, templates_dir, tags=None, tags_skip=None): self._tags_skip = tags_skip self._env = get_env(self._templates_dir) + def _iterate_entries(self, entries, tags=None): + if tags is None: + tags = set() + + for entry in entries: + entry["tags"] = self._get_template_tags(entry).union(tags) + + if "group" not in entry.keys(): + if not self._evaluate_tags(entry.get("tags"), self._tags, self._tags_skip): + continue + yield entry + + for nested_entry in self._iterate_entries(entry.get("group", []), entry.get("tags")): + yield nested_entry + def generate_by_context(self, context): if context is None: raise RuntimeError('Can\'t generate templates from None context') @@ -98,13 +113,8 @@ def generate_by_context(self, context): if len(templates) == 0: return - templates = filter( - lambda i: self._evaluate_tags(self._get_template_tags(i), self._tags, self._tags_skip), - templates - ) - output = [] - for template in templates: + for template in self._iterate_entries(templates): try: path = self._generate_file(template, settings.TEMP_DIR, context) log.info('File "{}" successfully generated'.format(path)) @@ -147,7 +157,7 @@ def _generate_file(self, item, directory, context): @staticmethod def _get_template_tags(template): if 'tags' not in template: - return {'untagged'} + return set() tags = template['tags'] @@ -161,4 +171,7 @@ def _get_template_tags(template): @staticmethod def _evaluate_tags(tags, only_tags, skip_tags): + if only_tags is None and skip_tags is None: + return True + return tags.isdisjoint(skip_tags or []) and not tags.isdisjoint(only_tags or tags) diff --git a/tests/fixtures/config.yaml b/tests/fixtures/config.yaml index ed938b6..37b02b8 100644 --- a/tests/fixtures/config.yaml +++ b/tests/fixtures/config.yaml @@ -70,3 +70,11 @@ section_with_kubectl: - template: template2.yaml.j2 - template: template3.yaml.j2 - template: innerdir/template1.yaml.j2 + +test_groups: + templates: + - template: template1.yaml.j2 + - group: + - group: + - template: template2.yaml.j2 + - template: template3.yaml.j2 diff --git a/tests/test_templating.py b/tests/test_templating.py index 2328ac1..c2e88a4 100644 --- a/tests/test_templating.py +++ b/tests/test_templating.py @@ -57,7 +57,7 @@ def test_generate_templates(self): self.assertEqual(content, "{'ha_ha': 'included_var'}") with open(file_path_5, 'r') as f: content = f.read() - self.assertEqual(content, "test: |\n {{ hello world }}\n new\n line\n {{ hello world1 }}\n") + self.assertEqual(content, "test: |\n {{ hello world1 }}\n\n {{ hello world }}\n new\n line") def test_no_templates_in_kubectl(self): r = templating.Renderer(os.path.join(os.path.dirname(__file__), 'templates_tests')) @@ -128,3 +128,14 @@ def test_get_template_tags_unexpected_type(self): with self.assertRaises(TypeError) as context: r._get_template_tags(template) self.assertTrue('unexpected type' in str(context.exception)) + + def test_generate_group_templates(self): + r = templating.Renderer(os.path.join(os.path.dirname(__file__), 'templates_tests')) + context = config.load_context_section('test_groups') + r.generate_by_context(context) + file_path_1 = '{}/template1.yaml'.format(settings.TEMP_DIR) + file_path_2 = '{}/template2.yaml'.format(settings.TEMP_DIR) + file_path_3 = '{}/template3.yaml'.format(settings.TEMP_DIR) + self.assertTrue(os.path.exists(file_path_1)) + self.assertTrue(os.path.exists(file_path_2)) + self.assertTrue(os.path.exists(file_path_3))