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

Комментарии (0)