Главная

Sunday, 25 December 2022

Тестирование инфраструктуры с Testinfra #1.

Всем привет.

Создание модульных тестов для тестирования инфраструктуры - замечательная идея. Главное найти подхоящий инструмент с низким порогом вхождения. Я таких знаю два - это Testinfra  (Python) и Pester (Powershell). Разумеется оба бесплатны, но более простым для старта я считаю первый. Так что сегодня будет Testinfra.

С проектом Testinfra мы можем качественно улучшить наши приложения, которые мы используем в промышленной эксплуатации. Давайте выполним подключение к разным хостам и выполним несколько проверочных тестов.

Пожалуй начнем. Создайте новую виртуальную среду и активируйте ее:

$ python3 -m venv validator

$ source validator/bin/activate

Установите  pytest:

(validator) $ pip3 install pytest

Установите testinfra:

(validator) $ pip3 install pytest-testinfra

Установите paramiko:

(validator) $ pip3 install paramiko

Фикстуры pytest предоставляют всю тестовую функциональность проекта Testinfra.  Чтобы извлечь пользу из этого, вам необходимо правильно указать тип соединения. Поскольку  существуют различные типы соединений прикладных частей, то, если соединение не указано непосредственно, Testinfra использует определенные типы по умолчанию. Лучше указывать тип соединения явным образом в командной строке.

Вот список поддерживаемых Testinfra соединений на сегодня:

-local

$ py.test --sudo test_myinfra.py

-Paramiko (SSH-реализация на Python)

$ py.test --ssh-config=/path/to/ssh_config --hosts=server

-Docker;

$ py.test --hosts='docker://[user@]container_id_or_name'

-SSH;

$ py.test --ssh-config=/path/to/ssh_config --hosts='ssh://server'

-Podman;

$ py.test --hosts='podman://[user@]container_id_or_name'

-Salt;

$ py.test --hosts='salt://*'

-Ansible;

$ py.test --hosts='ansible://all' # tests all inventory hosts

-Kubernetes (через утилиту kubectl);

$ py.test --hosts='kubectl://mypod-a1b2c3'

-OpenShift;

$ py.test --hosts='openshift://mypod-a1b2c3'

-WinRM;

$ py.test --hosts='winrm://vagrant@127.0.0.1:2200?no_ssl=true&no_verify_ssl=true'

-LXC/LXD

$ py.test --hosts='lxc://container_name'

В меню справки pytest можно найти раздел testinfra с пояснениями по поводу имеющихся флагов. Это очень удобная возможность, которая обязана своим возникновением фреймворку pytest и его интеграции с Testinfra. Справку по обоим проектам можно получить с помощью одной и той же команды:

(validator) $ pytest --help

...

testinfra:

--connection=CONNECTION Remote connection backend (paramiko, ssh, safe-ssh, salt, docker, ansible)

--hosts=HOSTS Hosts list (comma separated)

--ssh-config=SSH_CONFIG SSH config file

--ssh-identity-file=SSH_IDENTITY_FILE SSH identify file

--sudo Use sudo

--sudo-user=SUDO_USER sudo user

--ansible-inventory=ANSIBLE_INVENTORY Ansible inventory file

--nagios Nagios plugin


Пусть даны два работающих сервера. Чтобы продемонстрировать опции соединений, проверим, работает ли на них CentOS 7, заглянув для этого в файл /etc/os-release. Вот как выглядит соответствующая тестовая функция (сохраненав файле test_remote.py):

def test_release_file(host):

release_file = host.file("/etc/os-release")

assert release_file.contains('CentOS')

assert release_file.contains('VERSION="7 (Core)"')

Это отдельная тестовая функция, которая принимает на входе фикстуру host и выполняется для всех указанных узлов.

Флаг --hosts позволяет указать список серверов со схемами соединения (например, в случае SSH — ssh://имя_хоста), допустимы также некоторые варианты с подстановками. Передавать в командной строке удаленные серверы неудобно, если тестировать за раз более чем один-два. Вот как выглядит тестирование двух серверов с помощью SSH:

(validator) $ pytest -v --hosts='ssh://Zabbix' test_remote.py


Выводимая при повышенном уровне детализации (флаг -v) информация демонстрирует, что Testinfra выполняет одну тестовую функцию для двух указанных в спецификации вызова серверов.

При настройке серверов важно обеспечить возможность соединения без пароля. Никаких запросов паролей быть не должно, а при использовании SSH желательно применять конфигурацию на основе ключей. При автоматизации подобных тестов (в качестве части задания в системе непрерывной интеграции, например) удобно генерировать серверы, определяя тип подключения и любые специальные инструкции. Testinfra может читать информацию о том, к каким серверам подключиться, из файла конфигурации SSH. При предыдущем запуске теста для создания этих серверов со специальными ключами и настройками соединений использовался Vagrant. Он может генерировать специализированные файлы конфигурации SSH для создаваемых им серверов (ssh-config):

Host Zabbix

    HostName 192.168.1.202

    User vagrant

    Port 22

    StrictHostKeyChecking no

    PasswordAuthentication no

    IdentitiesOnly no

    IdentityFile "/home/user1/.ssh/id_rsa"

    UserKnownHostsFile "/home/user1/.ssh/known_hosts"

    HostKeyAlias 192.168.1.202


(validator) $ pytest --hosts=default --ssh-config=ssh-config test_remote.py

Благодаря использованию флага --hosts=default можно не указывать серверы непосредственно в командной строке и читать их из конфигурации SSH. Даже без Vagrant применять конфигурацию SSH удобно при подключении к большому числу серверов с конкретными инструкциями.

Еще один вариант в случае, если узлы локальные, с доступом по SSH, или контейнеры Docker, Ansible. Для тестирования полезным окажется реестр хостов (подобный конфигурации SSH) с группировкой их по различным разделам. Можно также создавать группы хостов для выбора отдельных хостов для тестирования, вместо того чтобы тестировать сразу все.

Файл такого реестра (под названием hosts) для node1 и node2 из предыдущего примера выглядит так:

[all]

node1

node2

Если выполнять для всех хостов, команда меняется на следующую:

$ pytest --connection=ansible --ansible-inventory=hosts test_remote.py

Можно описать в реестре и отдельную группу, если требуется исключить какие-либо хосты из тестирования. Если оба наших узла представляют собой веб-серверы и входят в группу nginx, можно протестировать только эту группу с помощью следующей команды:

$ pytest --hosts='ansible://nginx' --connection=ansible --ansible-inventory=hosts test_remote.py

Для множества системных команд необходимы полномочия суперпользователя. Testinfra позволяет указывать флаг --sudo или --sudo-user для повышения полномочий. Флаг --sudo заставляет движок задействовать sudo при выполнении команд, а флаг --sudo-user позволяет выполнять команду от имени другого пользователя, с более высокими полномочиями. Можно применять и фикстуру напрямую.

Может показаться, что до сих пор для проверки наличия файлов и их содержимого в наших примерах использовалась только фикстура host. Однако такое впечатление обманчиво. Фикстура host включает в себя все прочие фикстуры проекта Testinfra, обладающие широкими возможностями. Это значит, что в нашем примере задействована фикстура host.file, имеющая много дополнительных возможностей. Можно использовать ее и напрямую:

In [1]: import testinfra

In [2]: host = testinfra.get_host('local://')

In [3]: node_file = host.file('/tmp')

In [4]: node_file.is_directory

Out[4]: True

In [5]: node_file.user

Out[5]: 'root'

Всеобъемлющая фикстура host использует обширный API проекта Testinfra, загружающий все возможности для каждого хоста, к которому подключается. Идея состоит в написании одного теста, применяемого для тестирования различных узлов, причем все - на основе одной и той же фикстуры host. Аргументов у фикстуры host несколько десятков.

Вот чаще всего используемые из них:

host.ansible — предоставляет полный доступ ко всем свойствам Ansible во время выполнения, например к хостам, реестру и переменным.

host.addr — сетевые утилиты, такие как проверки IPV4 и IPV6, проверки доступности и разрешимости хоста.

host.docker — прокси для API Docker для взаимодействия с контейнерами и проверки того, запущены ли они.

host.interface — вспомогательные функции для получения адресов для заданного интерфейса.

host.iptables — вспомогательные функции для верификации правил брандмауэра host.iptables.

host.mount_point — проверка точек монтирования, типов файловой системы в путях и вариантов монтирования.

host.package — удобна для выяснения того, установлен ли конкретный пакет, и если да, то какая версия.

host.process — проверка запущенных процессов.

host.sudo — позволяет выполнять команды с модификатором sudo или от имени другого пользователя.

host.system_info — разнообразные виды метаданных системы, например версия дистрибутива, выпуск и его кодовое наименование.

host.check_output — выполняет системную команду, проверяя выводимую ею информацию в случае успешного выполнения, может применяться в сочетании с host.sudo.

host.run — выполняет системную команду, позволяя проверять код возврата,

host.stderr и host.stdout.

host.run_expect — проверяет, соответствует ли код возврата ожидаемому.


Что касается типа подключения по WinRM к Windows-хостам то предварительно нужно еще добавить pywinrm:

(validator) $ pip3 install pywinrm

А вызов самого теста выполнить так:

py.test --hosts='winrm://admin:adminpsw@192.168.1.20?no_ssl=true&no_verify_ssl=true' 1.py

где 1.py содержит:

import winrm

def test_release_file(host):

    release_file = host.file('C:\Users\Admin\.gitconfig')

    assert release_file.contains('Admin')

Однако тут мне не повезло, на все свои попытки  я получал ошибку типа "NotImplementedError".

Поэтому вернусь я к ним позже, а нa сегодня все.

Успехов.


No comments:

Post a Comment

А что вы думаете по этому поводу?