diff --git a/ansible_bender/core.py b/ansible_bender/core.py index 3396e3f..d03f240 100644 --- a/ansible_bender/core.py +++ b/ansible_bender/core.py @@ -40,6 +40,7 @@ import sys import tempfile from pathlib import Path +import uuid import jsonschema import yaml @@ -173,6 +174,30 @@ def _get_path_our_site(self): # hence, let's add the site ab is installed in to sys.path return os.path.dirname(os.path.dirname(ansible_bender.__file__)) + def _correct_host_entries(self, playbook_path, tmpDir): + """ Correct the host entries in the playbook and all imported playbooks """ + tmp_pb_path = os.path.join(tmpDir, "ab_" + str(uuid.uuid4()) + ".yaml") + + with open(playbook_path, "r") as fd_r: + pb_dict = yaml.safe_load(fd_r) + + for idx, doc in enumerate(pb_dict): + imported_playbook = doc.get("import_playbook") + if imported_playbook: + import_base_path = os.path.dirname(playbook_path) + imported_playbook_path = os.path.join(import_base_path, imported_playbook) + logger.debug("Encountered import_playbook, correcting hosts entries in imported file: %s", imported_playbook_path) + doc["import_playbook"] = self._correct_host_entries(imported_playbook_path, tmpDir) + else: + host = doc["hosts"] + logger.debug("play[%s], host = %s", idx, host) + doc["hosts"] = self.builder.ansible_host + + with open(tmp_pb_path, "w") as fd: + yaml.safe_dump(pb_dict, fd) + + return tmp_pb_path + def build(self, db_path): """ run the playbook against the container @@ -204,15 +229,7 @@ def build(self, db_path): with open(a_cfg_path, "w") as fd: self._create_ansible_cfg(fd) - tmp_pb_path = os.path.join(tmp, "p.yaml") - with open(self.pb, "r") as fd_r: - pb_dict = yaml.safe_load(fd_r) - for idx, doc in enumerate(pb_dict): - host = doc["hosts"] - logger.debug("play[%s], host = %s", idx, host) - doc["hosts"] = self.builder.ansible_host - with open(tmp_pb_path, "w") as fd: - yaml.safe_dump(pb_dict, fd) + tmp_pb_path = self._correct_host_entries(self.pb, tmp) playbook_base = os.path.basename(self.pb).split(".", 1)[0] timestamp = datetime.datetime.now().strftime(TIMESTAMP_FORMAT) symlink_name = f".{playbook_base}-{timestamp}-{random_str()}.yaml" diff --git a/tests/data/import_playbook_basic.yaml b/tests/data/import_playbook_basic.yaml new file mode 100644 index 0000000..0431daa --- /dev/null +++ b/tests/data/import_playbook_basic.yaml @@ -0,0 +1,6 @@ +- import_playbook: imported_playbook.yaml + vars: + ansible_bender: + base_image: python:3.5-stretch + target_image: + name: test_img diff --git a/tests/data/import_playbook_recursive.yaml b/tests/data/import_playbook_recursive.yaml new file mode 100644 index 0000000..ecb2f00 --- /dev/null +++ b/tests/data/import_playbook_recursive.yaml @@ -0,0 +1,13 @@ +# doing a few different tasks including importing a playbook +- import_playbook: imported_playbook_upper.yaml + vars: + ansible_bender: + base_image: python:3.5-stretch + target_image: + name: test_img +- hosts: all + tasks: + - name: create a file + copy: + src: '{{ playbook_dir }}/a_bag_of_fun' + dest: /fun diff --git a/tests/data/imported_playbook.yaml b/tests/data/imported_playbook.yaml new file mode 100644 index 0000000..a2ff3d1 --- /dev/null +++ b/tests/data/imported_playbook.yaml @@ -0,0 +1,4 @@ +- hosts: all + tasks: + - debug: + msg: hi diff --git a/tests/data/imported_playbook_upper.yaml b/tests/data/imported_playbook_upper.yaml new file mode 100644 index 0000000..61a7efc --- /dev/null +++ b/tests/data/imported_playbook_upper.yaml @@ -0,0 +1,9 @@ +- hosts: all + tasks: + - debug: + msg: hello there +- import_playbook: imported_playbook.yaml +- hosts: all + tasks: + - debug: + msg: more hello diff --git a/tests/integration/test_api.py b/tests/integration/test_api.py index 3ba91e4..5e5e8c2 100644 --- a/tests/integration/test_api.py +++ b/tests/integration/test_api.py @@ -15,7 +15,7 @@ from ansible_bender.utils import random_str, run_cmd from tests.spellbook import (dont_cache_playbook_path, change_layering_playbook, data_dir, dont_cache_playbook_path_pre, non_ex_pb, multiplay_path, role_pb_path, roles_dir) -from ..spellbook import small_basic_playbook_path +from ..spellbook import small_basic_playbook_path, import_playbook_basic, import_playbook_recursive def test_build_db_metadata(application, build): @@ -327,3 +327,17 @@ def test_cache_python_interpreter(application, build, image_name, interpreter): build.python_interpreter = None flexmock(application.db).should_call("record_python_interpreter").never() application.build(build) + + +# test a few playbooks that uses import_playbook to verify that it works without exceptions/errors. +# Also checks that the correct number of layers are created as a minimum verification (based upon the instruction from all imported playbooks) +@pytest.mark.parametrize("playbook,num_layers", [ + (import_playbook_basic, 2), + (import_playbook_recursive, 5) +]) +def test_import_playbook_basic(application, build, playbook, num_layers): + build.playbook_path = playbook + application.build(build) + + build = application.db.get_build(build.build_id) + assert len(build.layers) == num_layers diff --git a/tests/spellbook.py b/tests/spellbook.py index f9e93bb..9b609a1 100644 --- a/tests/spellbook.py +++ b/tests/spellbook.py @@ -23,6 +23,8 @@ role_pb_path = os.path.join(data_dir, "role.yaml") playbook_with_unknown_keys = os.path.join(data_dir, "playbook_with_unknown_keys.yaml") playbook_wrong_type = os.path.join(data_dir, "pb_wrong_type.yaml") +import_playbook_basic = os.path.join(data_dir, "import_playbook_basic.yaml") +import_playbook_recursive = os.path.join(data_dir, "import_playbook_recursive.yaml") base_image = "docker.io/library/python:3-alpine"