From 3d0656aab60b04c70ae91f673881a446fdaf4751 Mon Sep 17 00:00:00 2001 From: Aljosha Friemann Date: Thu, 30 Jan 2020 16:27:04 +0100 Subject: [PATCH] [#23] fail properly for undefined values during generation --- k8t/cli.py | 13 +++++--- k8t/engine.py | 6 ++-- k8t/filters.py | 82 ++++++++++++++++++++++++++++++++++++++++++++++ k8t/util.py | 69 +++----------------------------------- tests/engine.py | 16 +++++++++ tests/filters.py | 42 ++++++++++++++++++++++++ tests/templates.py | 16 +++++++++ tests/util.py | 27 +-------------- 8 files changed, 173 insertions(+), 98 deletions(-) create mode 100644 k8t/filters.py create mode 100644 tests/engine.py create mode 100644 tests/filters.py create mode 100644 tests/templates.py diff --git a/k8t/cli.py b/k8t/cli.py index 9ae743f..5ebb502 100644 --- a/k8t/cli.py +++ b/k8t/cli.py @@ -13,6 +13,7 @@ import click import coloredlogs +from jinja2.exceptions import UndefinedError from termcolor import colored import k8t @@ -130,10 +131,14 @@ def cli_gen(method, value_files, cli_values, cname, ename, directory): # pylint if not validated: sys.exit(1) - for template_path in templates: - print("---") - print("# Source: {}".format(template_path)) - print(eng.get_template(template_path).render(vals)) + try: + for template_path in templates: + print("---") + print("# Source: {}".format(template_path)) + print(eng.get_template(template_path).render(vals)) + except UndefinedError as err: + print(colored("✗ -> {}".format(err), "red")) + sys.exit(1) @root.group(help="Code scaffolding commands.") diff --git a/k8t/engine.py b/k8t/engine.py index 6fc3832..b624b30 100644 --- a/k8t/engine.py +++ b/k8t/engine.py @@ -9,11 +9,11 @@ import logging -from jinja2 import Environment, FileSystemLoader +from jinja2 import Environment, FileSystemLoader, StrictUndefined +from k8t.filters import b64decode, b64encode, envvar, hashf, random_password from k8t.project import find_files from k8t.secrets import get_secret -from k8t.util import b64decode, b64encode, envvar, hashf, random_password LOGGER = logging.getLogger(__name__) @@ -24,7 +24,7 @@ def build(path: str, cluster: str, environment: str): LOGGER.debug( "building template environment") - env = Environment(loader=FileSystemLoader(template_paths)) + env = Environment(undefined=StrictUndefined, loader=FileSystemLoader(template_paths)) env.filters["b64decode"] = b64decode env.filters["b64encode"] = b64encode diff --git a/k8t/filters.py b/k8t/filters.py new file mode 100644 index 0000000..11c8322 --- /dev/null +++ b/k8t/filters.py @@ -0,0 +1,82 @@ +# -*- coding: utf-8 -*- +# ISC License +# +# Copyright 2019 FL Fintech E GmbH +# +# Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +# +# Copyright © 2020 Clark Germany GmbH +# Author: Aljosha Friemann + +import base64 +import hashlib +import os +import string +from typing import Any + +try: + from secrets import choice +except ImportError: + from random import SystemRandom + + choice = SystemRandom().choice + + +def random_password(length: int) -> str: + return "".join( + choice(string.ascii_lowercase + string.digits) for _ in range(length) + ) + + +def envvar(key: str, default=None) -> str: + return os.environ.get(key, default) + + +def b64encode(value: Any) -> str: + result = None + + if isinstance(value, str): + result = base64.b64encode(value.encode()).decode() + elif isinstance(value, int): + result = base64.b64encode(str(value).encode()).decode() + elif isinstance(value, bytes): + result = base64.b64encode(value).decode() + else: + raise TypeError("invalid input: {}".format(value)) + + return result + + +def b64decode(value: Any) -> str: + result = None + + if isinstance(value, str): + result = base64.b64decode(value.encode()).decode() + elif isinstance(value, bytes): + result = base64.b64decode(value).decode() + else: + raise TypeError("invalid input: {}".format(value)) + + return result + +def hashf(value, method="sha256"): + try: + hash_method = getattr(hashlib, method)() + except AttributeError: + raise RuntimeError("No such hash method: {}".format(method)) + + if isinstance(value, str): + hash_method.update(value.encode()) + elif isinstance(value, bytes): + hash_method.update(value) + else: + raise TypeError("invalid input: {}".format(value)) + + return hash_method.hexdigest() + + + +# vim: fenc=utf-8:ts=4:sw=4:expandtab diff --git a/k8t/util.py b/k8t/util.py index 16a1da9..371d2d4 100644 --- a/k8t/util.py +++ b/k8t/util.py @@ -7,33 +7,17 @@ # # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -import base64 import copy -import hashlib import logging import os -import string from functools import reduce -from typing import Any, Dict, List +from typing import Dict, List import yaml from simple_tools.interaction import confirm LOGGER = logging.getLogger(__name__) -try: - from secrets import choice -except ImportError: - from random import SystemRandom - - choice = SystemRandom().choice - - -def random_password(length: int) -> str: - return "".join( - choice(string.ascii_lowercase + string.digits) for _ in range(length) - ) - # def include_file(name: str): # fpath = find_file(name, path, cluster, environment) @@ -42,48 +26,6 @@ def random_password(length: int) -> str: # return s.read() -def b64encode(value: Any) -> str: - result = None - - if isinstance(value, str): - result = base64.b64encode(value.encode()).decode() - elif isinstance(value, int): - result = base64.b64encode(str(value).encode()).decode() - elif isinstance(value, bytes): - result = base64.b64encode(value).decode() - else: - raise TypeError("invalid input: {}".format(value)) - - return result - - -def b64decode(value: Any) -> str: - result = None - - if isinstance(value, str): - result = base64.b64decode(value.encode()).decode() - elif isinstance(value, bytes): - result = base64.b64decode(value).decode() - else: - raise TypeError("invalid input: {}".format(value)) - - return result - - -def hashf(value, method="sha256"): - try: - hash_method = getattr(hashlib, method)() - except AttributeError: - raise RuntimeError("No such hash method: {}".format(method)) - - if isinstance(value, str): - hash_method.update(value.encode()) - elif isinstance(value, bytes): - hash_method.update(value) - else: - raise TypeError("invalid input: {}".format(value)) - - return hash_method.hexdigest() def touch(fname: str, mode=0o666, dir_fd=None, **kwargs) -> None: @@ -159,9 +101,6 @@ def load_yaml(path: str) -> dict: return yaml.safe_load(stream) or dict() -def envvar(key: str, default=None) -> str: - return os.environ.get(key, default) - def envvalues() -> Dict: prefix: str = 'K8T_VALUE_' @@ -174,14 +113,14 @@ def envvalues() -> Dict: return values -def list_files(directory: str, files=False, directories=False) -> List[str]: +def list_files(directory: str, include_files=False, include_directories=False) -> List[str]: result = [] for _, dirs, files in os.walk(directory): - if files: + if include_files: result.extend(files) - if directories: + if include_directories: result.extend(dirs) break diff --git a/tests/engine.py b/tests/engine.py new file mode 100644 index 0000000..efc7de2 --- /dev/null +++ b/tests/engine.py @@ -0,0 +1,16 @@ +# -*- coding: utf-8 -*- +# ISC License +# +# Copyright 2019 FL Fintech E GmbH +# +# Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +# +# Copyright © 2020 Clark Germany GmbH +# Author: Aljosha Friemann + +from k8t.engine import build + +# vim: fenc=utf-8:ts=4:sw=4:expandtab diff --git a/tests/filters.py b/tests/filters.py new file mode 100644 index 0000000..10b0721 --- /dev/null +++ b/tests/filters.py @@ -0,0 +1,42 @@ +# -*- coding: utf-8 -*- +# ISC License +# +# Copyright 2019 FL Fintech E GmbH +# +# Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +# +# Copyright © 2020 Clark Germany GmbH +# Author: Aljosha Friemann + +import random + +from k8t.filters import b64decode, b64encode, hashf, random_password + + +def test_b64encode(): + string = "foobar" + + encoded = b64encode(string) + + assert encoded != string + assert b64decode(encoded) == string + + +def test_random_password(): + length = int(random.uniform(1, 200)) + + assert len(random_password(length)) == length + assert random_password(length) != random_password(length) + + +def test_hashf(): + string = "foobar" + + assert hashf(string) != string + assert hashf(string) == hashf(string) + assert hashf(string) != hashf("foobaz") + +# vim: fenc=utf-8:ts=4:sw=4:expandtab diff --git a/tests/templates.py b/tests/templates.py new file mode 100644 index 0000000..0a99a3e --- /dev/null +++ b/tests/templates.py @@ -0,0 +1,16 @@ +# -*- coding: utf-8 -*- +# ISC License +# +# Copyright 2019 FL Fintech E GmbH +# +# Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +# +# Copyright © 2020 Clark Germany GmbH +# Author: Aljosha Friemann + +from k8t.templates import analyze + +# vim: fenc=utf-8:ts=4:sw=4:expandtab diff --git a/tests/util.py b/tests/util.py index 57a24fe..5330fda 100644 --- a/tests/util.py +++ b/tests/util.py @@ -9,8 +9,7 @@ import random -from k8t.util import (b64decode, b64encode, deep_merge, hashf, merge, - random_password) +from k8t.util import deep_merge, merge def test_merge_memory_safety(): @@ -48,27 +47,3 @@ def test_deep_merge(): assert ( deep_merge(dict_c, dict_b, dict_a) == dict(foo=dict(a=1, b=2), baz=4, bar=dict(a=3, c=9))) - - -def test_b64encode(): - string = "foobar" - - encoded = b64encode(string) - - assert encoded != string - assert b64decode(encoded) == string - - -def test_random_password(): - length = int(random.uniform(1, 200)) - - assert len(random_password(length)) == length - assert random_password(length) != random_password(length) - - -def test_hashf(): - string = "foobar" - - assert hashf(string) != string - assert hashf(string) == hashf(string) - assert hashf(string) != hashf("foobaz")