
В статье много информации об Ansible. Давайте посмотрим, как тестировать роли с помощью Molecule, Docker и Testinfra.
Molecule – это проект Red Hat, призванный помочь в тестировании ролей Ansible. Он обеспечивает поддержку тестирования с различными операционными системами и дистрибутивами. Molecule также является весьма разноплановым проектом, позволяющим использовать множество провайдеров виртуализации, тестовых фреймворков и тестовых сценариев. Такой подход обеспечивает последовательность в разработке и обслуживании ролей.
Приступаем к работе
Настройка вашей среды
Python3 и pip – это необходимые условия для Ansible и Molecule. Установка и настройка этих инструментов выходят за рамки данного руководства.
Следующие команды установят Ansible и Molecule с помощью pip. Для получения информации о других вариантах установки посетите соответствующие страницы документации Ansible и Molecule.
# install ansible python3 -m pip install --user ansible # Install the latest version of molecule from source python3 -m pip install -U git+https://github.com/ansible-community/molecule #install testinfra python3 -m pip install --user pytest-testinfra #install the molecule docker driver python3 -m pip install -U "molecule[docker]"
Вам также потребуется установить docker-ce вместе с плагином Docker для Molecule. Последняя команда в приведенном выше скрипте устанавливает плагин docker. Этот метод применим к установке любых плагинов molecule, которые вы планируете использовать. После этого Docker сможет выступать в качестве драйвера в Molecule.
Инициализация новой роли с помощью Molecule
Теперь, когда предустановки готовы, начнем с некоторых основ. Начните с запуска molecule init role sample.demo_role --driver-name docker --verifier-name testinfra. Вуаля, Молекула создаёт новую роль, уже настроенную в тестовом каталоге. Давайте посмотрим на каталог, а затем более подробно рассмотрим эту команду.
demo_role/ ├── defaults │ └── main.yml ├── files ├── handlers │ └── main.yml ├── meta │ └── main.yml ├── molecule │ └── default │ ├── converge.yml │ ├── molecule.yml │ └── tests │ ├── conftest.py │ ├── __pycache__ │ │ ├── conftest.cpython-38.pyc │ │ └── test_default.cpython-38.pyc │ └── test_default.py ├── README.md ├── tasks │ └── main.yml ├── templates ├── tests │ ├── inventory │ └── test.yml └── vars └── main.yml
Правда впечатляет? Molecule создал все необходимое для создания роли и одновременного ее тестирования.
Изучение команды и результатов её применения
Ниже описание команды и опций, которые мы использовали:
Molecule инициирует sample.demo_role
init role задействует ansible-galaxy для создания каталога шаблонов <NAME_SPACE>.<ROLE_NAME>. Команда также подготавливает каталог Molecule, чтобы помочь начать работу. В качестве альтернативы, если у вас уже есть роль, вы можете инициировать Molecule как сценарий с molecule init scenario -r <ROLE_NAME>.
--driver-name Docker
Указывает на то, какой драйвер следует использовать для вашей тестовой среды. Драйвер определяет, какую платформу или инфраструктуру развернуть для тестов. Несколько доступных драйверов включают podman, libvirt, Azure и многие другие. Независимо от вашего драйвера, необходимо установить модуль с помощью pip. Здесь мы сосредоточимся на использовании Docker.
--verifier-name testinfra
Указывает, какой верификатор вы хотите использовать для вашего сценария по умолчанию. Верификатор – это механизм, используемый для тестирования ваших ролей. Некоторые доступные опции включают Ansible, test infra и inspect. Хотя Ansible является верификатором по умолчанию, мы будем использовать testinfra для этой демонстрации.
Вот описание созданных файлов Molecule:
./molecule/default/molecule.yml
Это основной файл для Molecule. Используется для определения шагов тестирования, сценариев, зависимостей и других параметров конфигурации. Сгенерированный файл должен выглядеть следующим образом:
--- dependency: name: galaxy driver: name: docker platforms: - name: instance image: quay.io/centos/centos:stream8 pre_build_image: true provisioner: name: ansible verifier: name: testinfra
./molecule/default/converge.yml
Это плейбук, который Molecule запустит, чтобы обеспечить цели для тестирования. Ниже приведен файл, который создает Molecule. Если вы можете использовать этот файл в сборнике воспроизведения, вы можете использовать его здесь.
--- - name: Converge hosts: all tasks: - name: "Include sample.demo_role" include_role: name: "sample.demo_role"
./molecule/default/tests/test_default.py
Это исходный тестовый файл, созданный для test infra. Именно здесь мы будем проводить наши тесты для этой демо-версии. Однако вы не ограничены этим файлом или даже этим каталогом для ваших тестов. Тест по умолчанию показан ниже.
"""Role testing files using testinfra.""" def test_hosts_file(host): """Validate etc/hosts file""" f = host.file("etc/hosts") assert f.exists assert f.user == "root" assert f.group == "root"
Приступаем к практике
Каждая роль должна что-то выполнять. У нас есть роль, которая в настоящее время ничего не делает, давайте исправим это, добавив некоторые задачи в ./tasks/main.yml. В этой статье мы будем придерживаться основ, добавив лишь несколько вещей, для которых мы можем писать тесты. В данном случае несколько пакетов yum, пользователь и конфигурационный файл предусмотрены в приведенном ниже коде.
--- # tasks file for demo_role - name: install some packages yum: name: "{{ item.name }}-{{item.version}}.{{ item.arch }}" state: installed with_items: - { name: 'epel-release', version: '8-11.el8', arch: 'noarch' } - { name: 'htop', version: '3.0.5-1.el8', arch: 'x86_64' } - { name: 'nginx', version: '1.14.1-9.module_el8.0.0+1060+3ab382d3', arch: 'x86_64' } - { name: 'git', version: '2.31.1-2.el8', arch: 'x86_64' } - name: add webapp user ansible.builtin.user: name: webapp system: true - name: create an app directory owned by webapp ansible.builtin.file: path: /opt/webapp state: directory owner: webapp group: webapp - name: create app.conf owned by webapp ansible.builtin.file: path: /opt/webapp/app.conf state: touch owner: webapp group: webapp mode: '0755' access_time: preserve modification_time: preserve
Create и Converge
У нас есть роль, которая будет обрабатывать некоторые задачи, что же дальше? Во-первых, мы можем запустить команду molecule create в директории ./demo_role. Create использует настройки, определенные в конфигурации molecule.yml, чтобы определить драйвер и пл��тформу. Для этого примера Molecule будет использовать следующие строки в molecule.yml.
driver: name: docker platforms: - name: instance image: quay.io/centos/centos:stream8 pre_build_image: true
Он будет использовать Ansible для запуска контейнера Docker на основе образа quay.io/centos/centos:stream8, при необходимости извлекая его из реестра контейнеров.
Теперь, когда у нас есть цель и роль, давайте объединим их с molecule converge. Команда converge запускает плейбук converge.yml по отношению к целевой платформе.
INFO default scenario test matrix: dependency, create, prepare, converge INFO Performing prerun with role_name_check=0... INFO Set ANSIBLE_LIBRARY=/home/pcritchfield/.cache/ansible-compat/54dfe2/modules:/home/pcritchfield/.ansible/plugins/modules:/usr/share/ansible/plugins/modules INFO Set ANSIBLE_COLLECTIONS_PATH=/home/pcritchfield/.cache/ansible-compat/54dfe2/collections:/home/pcritchfield/.ansible/collections:/usr/share/ansible/collections INFO Set ANSIBLE_ROLES_PATH=/home/pcritchfield/.cache/ansible-compat/54dfe2/roles:/home/pcritchfield/.ansible/roles:/usr/share/ansible/roles:/etc/ansible/roles INFO Using /home/pcritchfield/.cache/ansible-compat/54dfe2/roles/sample.demo_role symlink to current repository in order to enable Ansible to find the role using its expected full name. INFO Running default > dependency WARNING Skipping, missing the requirements file. WARNING Skipping, missing the requirements file. INFO Running default > create WARNING Skipping, instances already created. INFO Running default > prepare WARNING Skipping, prepare playbook not configured. INFO Running default > converge INFO Sanity checks: 'docker' PLAY [Converge] **************************************************************** TASK [Gathering Facts] ********************************************************* ok: [instance] TASK [Include sample.demo_role] ************************************************ TASK [sample.demo_role : install some packages] ******************************** changed: [instance] => (item=epel-release) changed: [instance] => (item=htop) changed: [instance] => (item=nginx) changed: [instance] => (item=git) TASK [sample.demo_role : add webapp user] ************************************** changed: [instance] TASK [sample.demo_role : create an app directory owned by webapp] ************** changed: [instance] TASK [sample.demo_role : create an app directory owned by webapp] ************** changed: [instance] PLAY RECAP ********************************************************************* instance : ok=5 changed=4 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Глядя на этот результат, мы можем видеть, как выполняются шаги Molecule. На линии, показывающей INFO default scenario test matrix: dependency, create, prepare, converge. Это означает, что запуск molecule create не всегда является необходимым. Часто можно просто запустить команду converge, поскольку она уже включает create.
Написание тестов и Verify
Теперь, когда мы запустили converge и развернули контейнеры, давайте проведем несколько тестов. Используйте команду molecule verify, чтобы запустить тест по умолчанию test_default.py. Вы должны увидеть вывод, похожий на:
INFO default scenario test matrix: verify INFO Performing prerun with role_name_check=0... INFO Set ANSIBLE_LIBRARY=/home/pcritchfield/.cache/ansible-compat/54dfe2/modules:/home/pcritchfield/.ansible/plugins/modules:/usr/share/ansible/plugins/modules INFO Set ANSIBLE_COLLECTIONS_PATH=/home/pcritchfield/.cache/ansible-compat/54dfe2/collections:/home/pcritchfield/.ansible/collections:/usr/share/ansible/collections INFO Set ANSIBLE_ROLES_PATH=/home/pcritchfield/.cache/ansible-compat/54dfe2/roles:/home/pcritchfield/.ansible/roles:/usr/share/ansible/roles:/etc/ansible/roles INFO Using /home/pcritchfield/.cache/ansible-compat/54dfe2/roles/sample.demo_role symlink to current repository in order to enable Ansible to find the role using its expected full name. INFO Running default > verify INFO Executing Testinfra tests found in /home/pcritchfield/Projects/ansible_molecule/roles/demo_role/molecule/default/tests/... ============================= test session starts ============================== platform linux -- Python 3.8.10, pytest-7.1.2, pluggy-1.0.0 rootdir: /home/pcritchfield plugins: testinfra-6.8.0 collected 1 item molecule/default/tests/test_default.py . [100%] ============================== 1 passed in 1.50s =============================== INFO Verifier completed successfully.
Успешно! Наш тест по умолчанию работает и подтверждает, что root является пользователем. molecule verify также позволяет нам повторять наши тесты на существующем контейнере. Нет необходимости повторять create и converge.
Теперь давайте напишем несколько тестов, чтобы подтвердить, что наша роль выполняет то, что должна. Мы начнем с проверки того, что установлены соответствующие пакеты и версии. Добавьте следующее к ./molecule/default/tests/test_default.py:
import pytest # Confirm that specific packages and versions are installed @pytest.mark.parametrize("name,version", [ ("epel-release", "8"), ("htop", "3.0"), ("nginx", "1.14"), ("git", "2.31"), ]) def test_packages(host, name, version): pkg = host.package(name) assert pkg.is_installed assert pkg.version.startswith(version)
Для тех, кто новичок в тестировании, это может показаться многовато. К счастью, это довольно просто. Мы используем pytest для параметризации сопоставления имени и версии. Затем передаем это в test_packages и проверяем имя пакета и его версию. Использование карты позволяет нам написать один тест для всех пакетов. Продолжайте, сохраните этот файл и запустите molecule verify. Вы должны увидеть, что четыре теста были успешно выполнены.
======================= test session starts ======================== platform linux -- Python 3.8.10, pytest-7.1.2, pluggy-1.0.0 rootdir: /home/pcritchfield plugins: testinfra-6.8.0 collected 4 items molecule/default/tests/test_default.py .... [100%] ======================== 4 passed in 2.77s ========================= INFO Verifier completed successfully.
Далее мы можем протестировать для пользователя webapp и файла app.conf. Добавьте следующее к test_default.py:
# Test that the webapp user is available. @pytest.mark.parametrize("user,group", [ ("webapp", "webapp"), ]) def test_users(host, user, group): usr = host.user(user) assert usr.exists assert usr.group == group # Test that app.conf is present and has expected permissions @pytest.mark.parametrize("filename,owner,group,mode", [ ("/opt/webapp/app.conf", "webapp", "webapp", 0o755), ]) def test_file(host, filename, owner, group, mode): target = host.file(filename) assert target.exists assert target.user == owner assert target.group == group assert target.mode == mode
Запустите molecule verify еще раз, и теперь вы увидите шесть проходящих тестов:
======================= test session starts ======================== platform linux -- Python 3.8.10, pytest-7.1.2, pluggy-1.0.0 rootdir: /home/pcritchfield plugins: testinfra-6.8.0 collected 6 items molecule/default/tests/test_default.py ...... [100%] ======================== 6 passed in 4.09s =========================
Наконец, чтобы всё очистить, мы можем запустить molecule destroy. Это удаляет контейнеры, которые мы развернули и подготовили с помощью create или converge. Это дает нам прекрасную возможность начать все сначала. Обеспечивая уверенность в том, что мы получим последовательные развертывания при каждом использовании нашей demo_role.
Одна команда, чтобы управлять ими всеми
Одна последняя команда Molecule, которую мы рассмотрим, это molecule test. Команда test запустит весь сценарий: создание, конвергенцию, проверку и многое другое. Давайте посмотрим, что делает тест в качестве сценария по умолчанию. Запустите команду molecule matrix test, чтобы вывести списком все этапы, которые будет проходить test:
INFO Test matrix --- default: - dependency - lint - cleanup - destroy - syntax - create - prepare - converge - idempotence - side_effect - verify - cleanup - destroy
Обратите внимание, что происходит гораздо больше, чем просто выполнение тестов, включая компоновку, подготовку среды и тестирование на идемпотентность. Molecule запустит тесты на этапе проверки и очистит тестовую среду. Пробуйте и запускайте molecule test:
Вы можете найти демонстрационный код в этом посте на GitHub (https://github.com/PCritchfield/ansible/tree/master/ansible_molecule_pt1)
В следующий раз
В следующей статье мы углубимся в конфигурацию molecule.yml. Мы рассмотрим тестирование нескольких операционных систем, линтинг и идемпотентность.

Видеокурс Ansible: Infrastructure as Code с практикой на стендах.
