From d2cd776732ad17c98d8902609a06a3ec9b5d1339 Mon Sep 17 00:00:00 2001 From: Bertrand Lanson Date: Sat, 3 Jun 2023 19:32:54 +0200 Subject: [PATCH] moved to ansible for testing ahead of testinfra deprecation in molecule --- molecule/default/molecule.yml | 2 +- molecule/default/tests/conftest.py | 22 --- molecule/default/tests/test_default.py | 43 ------ molecule/default/verify.yml | 117 ++++++++++++++++ molecule/with_custom_config/molecule.yml | 2 +- molecule/with_custom_config/tests/conftest.py | 22 --- .../with_custom_config/tests/test_default.py | 49 ------- molecule/with_custom_config/verify.yml | 126 ++++++++++++++++++ 8 files changed, 245 insertions(+), 138 deletions(-) delete mode 100644 molecule/default/tests/conftest.py delete mode 100644 molecule/default/tests/test_default.py create mode 100644 molecule/default/verify.yml delete mode 100644 molecule/with_custom_config/tests/conftest.py delete mode 100644 molecule/with_custom_config/tests/test_default.py create mode 100644 molecule/with_custom_config/verify.yml diff --git a/molecule/default/molecule.yml b/molecule/default/molecule.yml index 7a62eb2..49efc7f 100644 --- a/molecule/default/molecule.yml +++ b/molecule/default/molecule.yml @@ -20,7 +20,7 @@ provisioner: defaults: remote_tmp: /tmp/.ansible verifier: - name: testinfra + name: ansible scenario: name: default test_sequence: diff --git a/molecule/default/tests/conftest.py b/molecule/default/tests/conftest.py deleted file mode 100644 index f7ddb3f..0000000 --- a/molecule/default/tests/conftest.py +++ /dev/null @@ -1,22 +0,0 @@ -"""PyTest Fixtures.""" -from __future__ import absolute_import - -import os - -import pytest - - -def pytest_runtest_setup(item): - """Run tests only when under molecule with testinfra installed.""" - try: - import testinfra - except ImportError: - pytest.skip("Test requires testinfra", allow_module_level=True) - if "MOLECULE_INVENTORY_FILE" in os.environ: - pytest.testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner( - os.environ["MOLECULE_INVENTORY_FILE"] - ).get_hosts("all") - else: - pytest.skip( - "Test should run only from inside molecule.", allow_module_level=True - ) diff --git a/molecule/default/tests/test_default.py b/molecule/default/tests/test_default.py deleted file mode 100644 index baf2d9d..0000000 --- a/molecule/default/tests/test_default.py +++ /dev/null @@ -1,43 +0,0 @@ -"""Role testing files using testinfra.""" - - -def test_hosts_file(host): - """Validate /etc/hosts file.""" - etc_hosts = host.file("/etc/hosts") - assert etc_hosts.exists - assert etc_hosts.user == "root" - assert etc_hosts.group == "root" - -def test_docker_service(host): - """Validate docker service.""" - docker_service = host.service("docker.service") - assert docker_service.is_enabled - assert docker_service.is_running - assert docker_service.systemd_properties["Restart"] == "always" - assert docker_service.systemd_properties["FragmentPath"] == "/lib/systemd/system/docker.service" - -def test_docker_daemon(host): - """Validate /etc/docker/daemon.json file.""" - docker_daemon_file = host.file("/etc/docker/daemon.json") - assert docker_daemon_file.exists - assert docker_daemon_file.user == "root" - assert docker_daemon_file.group =="root" - assert docker_daemon_file.mode == 0o644 - assert docker_daemon_file.contains("{}") - -def test_docker_interaction(host): - """Validate interaction with docker.""" - docker_ps = host.check_output("docker ps") - assert docker_ps == "CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES" - -def test_docker_compose(host): - """Validate docker-compose installation""" - docker_compose_bin = host.file("/usr/local/bin/docker-compose") - assert not docker_compose_bin.exists - -def test_docker_python_package(host): - """Validate docker python package installation""" - pip_packages_list = host.pip.get_packages(pip_path='pip') - pip_outdated_list = host.pip.get_outdated_packages(pip_path='pip') - assert 'docker' not in pip_packages_list - assert 'docker' not in pip_outdated_list diff --git a/molecule/default/verify.yml b/molecule/default/verify.yml new file mode 100644 index 0000000..1b2eb4a --- /dev/null +++ b/molecule/default/verify.yml @@ -0,0 +1,117 @@ +--- +- name: Verify + hosts: all + gather_facts: false + tasks: + - name: "Test: file /etc/hosts" + block: + - name: "Stat file /etc/hosts" + ansible.builtin.stat: + path: "/etc/hosts" + register: stat_etc_hosts + + - name: "Verify file /etc/hosts" + ansible.builtin.assert: + that: + - stat_etc_hosts.stat.exists + - stat_etc_hosts.stat.isreg + - stat_etc_hosts.stat.pw_name == 'root' + - stat_etc_hosts.stat.gr_name == 'root' + + - name: "Test: service docker" + block: + - name: "Get service docker" + ansible.builtin.service_facts: + + - name: "Stat file /lib/systemd/system/docker.service" + ansible.builtin.stat: + path: "/lib/systemd/system/docker.service" + register: stat_lib_systemd_system_docker_service + + - name: "Verify service docker" + ansible.builtin.assert: + that: + - stat_lib_systemd_system_docker_service.stat.exists + - stat_lib_systemd_system_docker_service.stat.isreg + - stat_lib_systemd_system_docker_service.stat.pw_name == 'root' + - stat_lib_systemd_system_docker_service.stat.gr_name == 'root' + - stat_lib_systemd_system_docker_service.stat.mode == '0644' + - ansible_facts.services['docker.service'] is defined + - ansible_facts.services['docker.service']['source'] == 'systemd' + - ansible_facts.services['docker.service']['state'] == 'running' + - ansible_facts.services['docker.service']['status'] == 'enabled' + + - name: "Test: file /etc/docker/daemon.json" + block: + - name: "Stat directory /etc/docker" + ansible.builtin.stat: + path: "/etc/docker" + register: stat_etc_docker + + - name: "Stat file /etc/docker/daemon.json" + ansible.builtin.stat: + path: "/etc/docker/daemon.json" + register: stat_etc_docker_docker_json + + - name: "Slurp file /etc/docker/daemon.json" + ansible.builtin.slurp: + src: "/etc/docker/daemon.json" + register: slurp_etc_docker_docker_json + + - name: "Verify directory /etc/docker" + ansible.builtin.assert: + that: + - stat_etc_docker.stat.exists + - stat_etc_docker.stat.isdir + - stat_etc_docker.stat.pw_name == 'root' + - stat_etc_docker.stat.gr_name == 'root' + - stat_etc_docker.stat.mode == '0755' + - stat_etc_docker_docker_json.stat.exists + - stat_etc_docker_docker_json.stat.isreg + - stat_etc_docker_docker_json.stat.pw_name == 'root' + - stat_etc_docker_docker_json.stat.gr_name == 'root' + - stat_etc_docker_docker_json.stat.mode == '0644' + - (slurp_etc_docker_docker_json.content|b64decode) == '{}' + + - name: "Test: interaction docker" + block: + - name: "Command docker ps" + ansible.builtin.command: "docker ps" + changed_when: false + register: docker_ps + + - name: "Verify docker interaction" + ansible.builtin.assert: + that: + - docker_ps.stdout == 'CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES' + + - name: "Test: file /usr/local/bin/docker-compose" + block: + - name: "Stat file /usr/local/bin/docker-compose" + ansible.builtin.stat: + path: "/usr/local/bin/docker-compose" + register: stat_url_local_bin_docker_compose + + - name: "Verify file /usr/local/bin/docker-compose" + ansible.builtin.assert: + that: + - not stat_url_local_bin_docker_compose.stat.exists + + - name: "Test: python package docker" + block: + - name: "Command pip3 list -o" + ansible.builtin.command: "pip3 list -o" + changed_when: false + register: pip3_list_outdated + + - name: "Command pip3 list -u" + ansible.builtin.command: "pip3 list -u" + changed_when: false + register: pip3_list_uptodate + + + - name: "Verify python package docker" + ansible.builtin.assert: + that: + - "'docker' not in pip3_list_outdated.stdout" + - "'docker' not in pip3_list_uptodate.stdout" diff --git a/molecule/with_custom_config/molecule.yml b/molecule/with_custom_config/molecule.yml index 6132acb..4df62e9 100644 --- a/molecule/with_custom_config/molecule.yml +++ b/molecule/with_custom_config/molecule.yml @@ -20,7 +20,7 @@ provisioner: defaults: remote_tmp: /tmp/.ansible verifier: - name: testinfra + name: ansible scenario: name: with_custom_config test_sequence: diff --git a/molecule/with_custom_config/tests/conftest.py b/molecule/with_custom_config/tests/conftest.py deleted file mode 100644 index f7ddb3f..0000000 --- a/molecule/with_custom_config/tests/conftest.py +++ /dev/null @@ -1,22 +0,0 @@ -"""PyTest Fixtures.""" -from __future__ import absolute_import - -import os - -import pytest - - -def pytest_runtest_setup(item): - """Run tests only when under molecule with testinfra installed.""" - try: - import testinfra - except ImportError: - pytest.skip("Test requires testinfra", allow_module_level=True) - if "MOLECULE_INVENTORY_FILE" in os.environ: - pytest.testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner( - os.environ["MOLECULE_INVENTORY_FILE"] - ).get_hosts("all") - else: - pytest.skip( - "Test should run only from inside molecule.", allow_module_level=True - ) diff --git a/molecule/with_custom_config/tests/test_default.py b/molecule/with_custom_config/tests/test_default.py deleted file mode 100644 index 9b06a41..0000000 --- a/molecule/with_custom_config/tests/test_default.py +++ /dev/null @@ -1,49 +0,0 @@ -"""Role testing files using testinfra.""" -import re - -def test_hosts_file(host): - """Validate /etc/hosts file.""" - etc_hosts = host.file("/etc/hosts") - assert etc_hosts.exists - assert etc_hosts.user == "root" - assert etc_hosts.group == "root" - -def test_docker_service(host): - """Validate docker service.""" - docker_service = host.service("docker.service") - assert docker_service.is_enabled - assert docker_service.is_running - assert docker_service.systemd_properties["Restart"] == "always" - assert docker_service.systemd_properties["FragmentPath"] == "/lib/systemd/system/docker.service" - -def test_docker_daemon(host): - """Validate /etc/docker/daemon.json file.""" - docker_daemon_file = host.file("/etc/docker/daemon.json") - assert docker_daemon_file.exists - assert docker_daemon_file.user == "root" - assert docker_daemon_file.group =="root" - assert docker_daemon_file.mode == 0o644 - assert docker_daemon_file.contains("\"data-root\": \"/opt/docker\"") - -def test_docker_interaction(host): - """Validate interaction with docker.""" - docker_ps = host.check_output("docker ps") - assert docker_ps == "CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES" - -def test_docker_compose(host): - """Validate docker-compose installation""" - docker_compose_pattern = r'^Docker Compose version v\d+\.\d+\.\d+$' - docker_compose_bin = host.file("/usr/local/bin/docker-compose") - docker_compose_version = host.check_output("docker-compose --version") - assert docker_compose_bin.exists - assert docker_compose_bin.user == "root" - assert docker_compose_bin.group == "root" - assert docker_compose_bin.mode == 0o755 - assert re.match(docker_compose_pattern,docker_compose_version) is not None - -def test_docker_python_package(host): - """Validate docker python package installation""" - pip_packages_list = host.pip.get_packages(pip_path='pip') - pip_outdated_list = host.pip.get_outdated_packages(pip_path='pip') - assert 'docker' in pip_packages_list - assert 'docker' not in pip_outdated_list diff --git a/molecule/with_custom_config/verify.yml b/molecule/with_custom_config/verify.yml new file mode 100644 index 0000000..9c36bbe --- /dev/null +++ b/molecule/with_custom_config/verify.yml @@ -0,0 +1,126 @@ +--- +- name: Verify + hosts: all + gather_facts: false + tasks: + - name: "Test: file /etc/hosts" + block: + - name: "Stat file /etc/hosts" + ansible.builtin.stat: + path: "/etc/hosts" + register: stat_etc_hosts + + - name: "Verify file /etc/hosts" + ansible.builtin.assert: + that: + - stat_etc_hosts.stat.exists + - stat_etc_hosts.stat.isreg + - stat_etc_hosts.stat.pw_name == 'root' + - stat_etc_hosts.stat.gr_name == 'root' + + - name: "Test: service docker" + block: + - name: "Get service docker" + ansible.builtin.service_facts: + + - name: "Stat file /lib/systemd/system/docker.service" + ansible.builtin.stat: + path: "/lib/systemd/system/docker.service" + register: stat_lib_systemd_system_docker_service + + - name: "Verify service docker" + ansible.builtin.assert: + that: + - stat_lib_systemd_system_docker_service.stat.exists + - stat_lib_systemd_system_docker_service.stat.isreg + - stat_lib_systemd_system_docker_service.stat.pw_name == 'root' + - stat_lib_systemd_system_docker_service.stat.gr_name == 'root' + - stat_lib_systemd_system_docker_service.stat.mode == '0644' + - ansible_facts.services['docker.service'] is defined + - ansible_facts.services['docker.service']['source'] == 'systemd' + - ansible_facts.services['docker.service']['state'] == 'running' + - ansible_facts.services['docker.service']['status'] == 'enabled' + + - name: "Test: file /etc/docker/daemon.json" + block: + - name: "Stat directory /etc/docker" + ansible.builtin.stat: + path: "/etc/docker" + register: stat_etc_docker + + - name: "Stat file /etc/docker/daemon.json" + ansible.builtin.stat: + path: "/etc/docker/daemon.json" + register: stat_etc_docker_docker_json + + - name: "Slurp file /etc/docker/daemon.json" + ansible.builtin.slurp: + src: "/etc/docker/daemon.json" + register: slurp_etc_docker_docker_json + + - name: "Verify directory /etc/docker" + ansible.builtin.assert: + that: + - stat_etc_docker.stat.exists + - stat_etc_docker.stat.isdir + - stat_etc_docker.stat.pw_name == 'root' + - stat_etc_docker.stat.gr_name == 'root' + - stat_etc_docker.stat.mode == '0755' + - stat_etc_docker_docker_json.stat.exists + - stat_etc_docker_docker_json.stat.isreg + - stat_etc_docker_docker_json.stat.pw_name == 'root' + - stat_etc_docker_docker_json.stat.gr_name == 'root' + - stat_etc_docker_docker_json.stat.mode == '0644' + - "'\"data-root\": \"/opt/docker\"' in (slurp_etc_docker_docker_json.content|b64decode)" + + - name: "Test: interaction docker" + block: + - name: "Command docker ps" + ansible.builtin.command: "docker ps" + changed_when: false + register: docker_ps + + - name: "Verify docker interaction" + ansible.builtin.assert: + that: + - docker_ps.stdout == 'CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES' + + - name: "Test: file /usr/local/bin/docker-compose" + block: + - name: "Stat file /usr/local/bin/docker-compose" + ansible.builtin.stat: + path: "/usr/local/bin/docker-compose" + register: stat_url_local_bin_docker_compose + + - name: "Command docker-compose --version" + ansible.builtin.command: "docker-compose --version" + changed_when: false + register: docker_compose_version + + - name: "Verify file /usr/local/bin/docker-compose" + ansible.builtin.assert: + that: + - docker_compose_version.stdout | regex_search('^Docker Compose version v\\d+\\.\\d+\\.\\d+$') + - stat_url_local_bin_docker_compose.stat.exists + - stat_url_local_bin_docker_compose.stat.isreg + - stat_url_local_bin_docker_compose.stat.pw_name == 'root' + - stat_url_local_bin_docker_compose.stat.gr_name == 'root' + - stat_url_local_bin_docker_compose.stat.mode == '0755' + + - name: "Test: python package docker" + block: + - name: "Command pip3 list -o" + ansible.builtin.command: "pip3 list -o" + changed_when: false + register: pip3_list_outdated + + - name: "Command pip3 list -u" + ansible.builtin.command: "pip3 list -u" + changed_when: false + register: pip3_list_uptodate + + - name: "Verify python package docker" + ansible.builtin.assert: + that: + - "'docker' not in pip3_list_outdated.stdout" + - "'docker' in pip3_list_uptodate.stdout"