В статье много информации об 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 с практикой на стендах.