From 5e47ad06c63471bab6c235e00118bac14b276b44 Mon Sep 17 00:00:00 2001 From: Sebastian Neumann Date: Tue, 2 Apr 2024 14:36:52 +0200 Subject: [PATCH] First test Signed-off-by: Sebastian Neumann --- .gitignore | 2 + .zuul.yaml | 96 ++++++++++++++- molecule/delegated/molecule.yml | 13 ++- molecule/delegated/tests/util/__init__.py | 0 molecule/delegated/tests/util/util.py | 135 ++++++++++++++++++++++ molecule/requirements.txt | 3 +- 6 files changed, 244 insertions(+), 5 deletions(-) create mode 100644 molecule/delegated/tests/util/__init__.py create mode 100644 molecule/delegated/tests/util/util.py diff --git a/.gitignore b/.gitignore index 1774396..ad8f57f 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,5 @@ doc/build galaxy.yml osism-commons-*.tar.gz scripts/render-template.py +*.swp +.idea/* diff --git a/.zuul.yaml b/.zuul.yaml index b87c7c1..1b1fdf8 100644 --- a/.zuul.yaml +++ b/.zuul.yaml @@ -33,20 +33,110 @@ secret: SECRET_ANSIBLE_COLLECTION_VALIDATIONS pass-to-parent: true +- job: + name: abstract-ansible-collection-validations-molecule + parent: ansible-molecule + abstract: true + nodeset: + nodes: + - name: centos-9-stream + label: centos-9-stream + - name: debian-bookworm + label: debian-bookworm + - name: ubuntu-jammy-large + label: ubuntu-jammy-large + vars: + ansible_molecule_ansible_version: "9.4.0" + files: + - '^.zuul.yaml$' + - '^molecule\/delegated\/[^\/]*yml$' + - '^molecule\/requirements\.txt$' + +- job: + name: ansible-collection-validations-molecule-container_status + parent: abstract-ansible-collection-validations-molecule + vars: + ansible_role: container_status + files: + - '^roles\/container_status\/.*$' + - '^molecule\/delegated\/[a-zA-Z0-9_-]+\/container_status.*$' + +- job: + name: ansible-collection-validations-molecule-kernel_version + parent: abstract-ansible-collection-validations-molecule + vars: + ansible_role: kernel_version + files: + - '^roles\/kernel_version\/.*$' + - '^molecule\/delegated\/[a-zA-Z0-9_-]+\/kernel_version.*$' + +- job: + name: ansible-collection-validations-molecule-mysql_open_files_limit + parent: abstract-ansible-collection-validations-molecule + vars: + ansible_role: mysql_open_files_limit + files: + - '^roles\/kernel_version\/.*$' + - '^molecule\/delegated\/[a-zA-Z0-9_-]+\/mysql_open_files_limit.*$' + +- job: + name: ansible-collection-validations-molecule-refstack + parent: abstract-ansible-collection-validations-molecule + vars: + ansible_role: refstack + files: + - '^roles\/refstack\/.*$' + - '^molecule\/delegated\/[a-zA-Z0-9_-]+\/refstack.*$' + +- job: + name: ansible-collection-validations-molecule-system_encoding + parent: abstract-ansible-collection-validations-molecule + vars: + ansible_role: system_encoding + files: + - '^roles\/system_encoding\/.*$' + - '^molecule\/delegated\/[a-zA-Z0-9_-]+\/system_encoding.*$' + +- job: + name: ansible-collection-validations-molecule-ulimits + parent: abstract-ansible-collection-validations-molecule + vars: + ansible_role: ulimits + files: + - '^roles\/ulimits\/.*$' + - '^molecule\/delegated\/[a-zA-Z0-9_-]+\/ulimits.*$' + - project: merge-mode: squash-merge check: jobs: - - yamllint + - ansible-collection-validations-molecule-container_status + - ansible-collection-validations-molecule-kernel_version + - ansible-collection-validations-molecule-mysql_open_files_limit + - ansible-collection-validations-molecule-refstack + - ansible-collection-validations-molecule-system_encoding + - ansible-collection-validations-molecule-ulimits - ansible-lint + - flake8 + - python-black + - yamllint gate: jobs: - - yamllint + - ansible-collection-validations-molecule-container_status + - ansible-collection-validations-molecule-kernel_version + - ansible-collection-validations-molecule-mysql_open_files_limit + - ansible-collection-validations-molecule-refstack + - ansible-collection-validations-molecule-system_encoding + - ansible-collection-validations-molecule-ulimits - ansible-lint + - flake8 + - python-black + - yamllint periodic-daily: jobs: - - yamllint - ansible-lint + - python-black + - yamllint post: jobs: - ansible-collection-validations-container-image-osism-ansible-push: diff --git a/molecule/delegated/molecule.yml b/molecule/delegated/molecule.yml index 240c154..b9db1c4 100644 --- a/molecule/delegated/molecule.yml +++ b/molecule/delegated/molecule.yml @@ -3,7 +3,7 @@ dependency: name: shell command: ansible-galaxy collection install -v -f -r molecule/delegated/collections.yml -p ~/.ansible/collections driver: - name: delegated + name: default options: managed: false ansible_connection_options: @@ -20,6 +20,16 @@ provisioner: all: ansible_python_interpreter: /usr/bin/python3 molecule_role: "${ANSIBLE_ROLE}" + prepared_vars_path: "/tmp/ansible-molecule" +verifier: + name: testinfra + options: + v: 2 + additional_files_or_dirs: + - "${ANSIBLE_ROLE}.py" + - "${ANSIBLE_ROLE}/*.py" + env: + ROLE_NAME: "${ANSIBLE_ROLE}" scenario: name: delegated test_sequence: @@ -27,4 +37,5 @@ scenario: - create - prepare - converge + - verify - destroy diff --git a/molecule/delegated/tests/util/__init__.py b/molecule/delegated/tests/util/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/molecule/delegated/tests/util/util.py b/molecule/delegated/tests/util/util.py new file mode 100644 index 0000000..fffad32 --- /dev/null +++ b/molecule/delegated/tests/util/util.py @@ -0,0 +1,135 @@ +import os +import re +import urllib.request +import testinfra.utils.ansible_runner + + +def extract_url_from_variable(host, variable_name): + """Extracts a URL from a given Ansible configuration variable.""" + config_value = get_variable(host, variable_name) + match = re.search(r"https?://[\w./-]+", config_value) + if not match: + raise ValueError( + f"No valid URL found in the configuration variable: '{variable_name}'" + ) + return match.group(0) + + +def get_ansible(): + testinfra_runner = testinfra.utils.ansible_runner.AnsibleRunner( + os.environ["MOLECULE_INVENTORY_FILE"] + ) + testinfra_hosts = testinfra_runner.get_hosts("all") + + return testinfra_runner, testinfra_hosts + + +def get_variable(host, name, fact=False): + if fact: + ansible_facts = host.ansible("setup")["ansible_facts"] + + if name not in ansible_facts: + raise Exception(f"Fact {name} not found!") + + return ansible_facts[name] + + all_vars = host.ansible.get_variables() + if name in all_vars: + return all_vars[name] + + # debug_value = host.ansible("debug", f"var={name}")[name] + # if type(debug_value) is str and not debug_value.startswith('VARIABLE IS NOT DEFINED!'): + # return debug_value + # elif type(debug_value) is dict: + # return debug_value + + role_name = os.environ["ROLE_NAME"] + + test_vars = host.ansible( + "include_vars", f"../../molecule/delegated/vars/{role_name}.yml" + )["ansible_facts"] + if name in test_vars: + return test_vars[name] + + default_vars = host.ansible( + "include_vars", f"../../roles/{role_name}/defaults/main.yml" + )["ansible_facts"] + if name in default_vars: + return default_vars[name] + + raise Exception(f"Variable {name} not found!") + + +def get_role_variable(host, name, filename): + role_name = os.environ["ROLE_NAME"] + + path = f"../../roles/{role_name}/vars/{filename}" + variables = host.ansible("include_vars", path)["ansible_facts"] + + if name not in variables: + raise Exception(f"{name} not found in {path}") + + return variables[name] + + +def get_family_role_variable(host, name): + return get_role_variable( + host, name, get_variable(host, "ansible_os_family", True) + "-family.yml" + ) + + +def get_dist_role_variable(host, name): + return get_role_variable( + host, name, get_variable(host, "ansible_distribution", True) + "-dist.yml" + ) + + +def get_from_url(url, binary=False): + # Create a request object with a faked User-Agent header. + # Some websites like https://pkg.osquery.io/rpm/GPG need this, otherwise they will return http 403 forbidden. + req = urllib.request.Request( + url, headers={"User-Agent": "Mozilla/5.0 (Linux x86_64) Chrome/103.0.0.0"} + ) + # Open the URL with the custom request object + resource = urllib.request.urlopen(req) + + if not binary: + encoding = resource.headers.get_content_charset() + if encoding is None: + encoding = "utf-8" + content = resource.read().decode(encoding) + else: + content = resource.read() + + return content + + +def get_centos_repo_key(host, summary): + all_keys = host.run("rpm -qa gpg-pubkey | xargs -I{} sh -c 'rpm -qi {}'").stdout + split_on = "{}\nDescription :\n-----BEGIN PGP PUBLIC KEY BLOCK-----\n".format( + summary + ) + installed_key = all_keys.split(split_on)[1].split( + "-----END PGP PUBLIC KEY BLOCK-----" + )[0] + installed_key = "\n".join(installed_key.split("\n")[2:]) + + return installed_key + + +def jinja_replacement(original_variable, replacements): + original_variable = original_variable.replace("{{ ", "{").replace(" }}", "}") + original_variable = original_variable.format(**replacements) + + return original_variable + + +def jinja_list_concat(original_variable, lists): + if type(original_variable) is list: + return original_variable + + return_value = [] + for li in lists: + return_value += li + + return return_value diff --git a/molecule/requirements.txt b/molecule/requirements.txt index adc6df0..3c64680 100644 --- a/molecule/requirements.txt +++ b/molecule/requirements.txt @@ -1,2 +1,3 @@ molecule==24.2.0 -molecule-docker==2.1.0 +pytest==8.1.1 +pytest-testinfra==10.1.0