Ahoj všichni!
Pracuji jako DevOps inženýr ve službě rezervace hotelů. . V tomto článku bych chtěl sdělit naše zkušenosti s testováním ansible rolí.
Na Ostrovok.ru jako nástroj pro správu konfigurací používáme ansible. Nedávno jsme zjistili potřebu testování rolí, ale ukázalo se, že nástrojů pro to není tolik – nejpopulárnější, pravděpodobně, je framework Molecule, a tak jsme se rozhodli ho použít. Ale zjistili jsme, že jeho dokumentace zamlčuje mnoho úskalí. Nedařilo se nám najít dostatečně podrobný návod v češtině, a proto jsme se rozhodli napsat tento článek.

Molecule
– framework pro pomoc s testováním ansible rolí.
Zjednodušený popis: Molekula vytváří instanci na vámi uvedené platformě (cloud, virtuálka, kontejner; podrobněji viz oddíl ), spustí na ní vaši roli, poté provede testy a odstraní instanci. V případě selhání na jednom z kroků vás Molekula o tom informuje.
Nyní podrobněji.
Trochu teorie
Podíváme se na dvě klíčové entity Molekuly: Scenario a Driver.
Scenario
Scénář obsahuje popis toho, co, kde, jak a v jakém pořadí bude provedeno. Jedna role může mít více scénářů, a každý z nich je adresář na cestě /molecule/, který obsahuje popisy potřebných akcí pro test. Musí být přítomen scénář, který bude automaticky vytvořen, pokud roli inicializujete pomocí Molekuly. Jména následujících scénářů vybíráte podle svého uvážení. defaultPořadí akcí testování ve scénáři se nazývá
matrix , a ve výchozím nastavení je následující:(Kroky označené
, ve výchozím nastavení se přeskočí, pokud je uživatel nepopíše) ?lint
– spuštění linkerů. Ve výchozím nastavení se používajíyamllintflake8adestroy,– odstranění instancí z předchozího spuštění Molekuly (pokud nějaké zůstaly),syntaxdependency? — установка ansible-зависимости тестируемой роли,– kontrola syntaxe role pomocíansible-playbook --syntax-checkcreate,– vytvoření instance,– spuštění testovaného playbooku,připravit? — подготовка инстанса; например, проверка / установка python2convergeidempotence– opětovné spuštění playbooku pro testování idempotence,side_effect– spuštění testů rozumně konfigurovaného systému pomocí? — действия, не относящиеся непосредственно к роли, но нужные для тестов,verifytestinfra(ve výchozím nastavení) /gossinspec/– odstranění instance.,cleanup? — (в новых версиях) — грубо говоря, «очистка» внешней инфраструктуры, задетой Молекулой,– odstranění instancí z předchozího spuštění Molekuly (pokud nějaké zůstaly),Toto pořadí pokrývá většinu případů, ale v případě potřeby lze měnit.
Tato sekvence pokrývá většinu případů, ale v případě potřeby ji lze upravit.
Každý z výše uvedených kroků lze spustit samostatně pomocí molecule. Je však dobré mít na paměti, že pro každý takový příkaz CLI může existovat vlastní posloupnost akcí, kterou lze zjistit provedením molecule matrix. Například při spuštění příkazu converge (provádění testovaného playbooku) budou vykonány následující akce:
$ molecule matrix converge
...
└── default # název scénáře
├── dependency # instalace závislostí
├── create # vytvoření instance
├── prepare # přednastavení instance
└── converge # provedení playbookuPořadí těchto akcí lze upravit. Pokud bylo něco ze seznamu již provedeno, bude to přeskočeno. Aktuální stav a také konfiguraci instancí Molecule uchovává v adresáři $TMPDIR/molecule//.
Přidat kroky s ? lze tak, že požadované akce popíšete ve formátu Ansible playbooku a název souboru přizpůsobíte danému kroku: prepare.yml/side_effect.yml. Tyto soubory bude Molecule očekávat ve složce scénáře.
Driver
Driver je entita, ve které se vytvářejí instance pro testy.
Seznam standardních driverů, pro které má Molecule připravené šablony, je následující: Azure, Docker, EC2, GCE, LXC, LXD, OpenStack, Vagrant, Delegated.
Ve většině případů jsou šablony soubory create.yml a destroy.yml ve složce scénáře, které popisují vytvoření a odstranění instance odpovídajícím způsobem.
Výjimky tvoří Docker a Vagrant, protože interakce s jejich moduly může probíhat bez výše uvedených souborů.
Je dobré vyzdvihnout driver Delegated, protože v případě jeho použití jsou v souborech pro vytváření a odstranění instance popsány pouze operace s konfigurací instancí, zbytek by měl popsat inženýr.
Výchozím driverem je Docker.
Nyní přejdeme k praxi a dále se podíváme na specifika.
Začínáme
Jako "hello world" otestujeme jednoduchou roli pro instalaci nginx. Jako driver zvolíme Docker – myslím, že ho má většina z vás nainstalovaný (a pamatujme, že Docker je výchozí driver).
Připravíme virtualenv a nainstalujeme do něj molecule:
> pip install virtualenv
> virtualenv -p `which python2` venv
> source venv/bin/activate
> pip install molecule docker # molecule nainstaluje ansible jako závislost; docker pro driverDalším krokem je inicializace nové role.
Inicializace nové role, stejně jako nového scénáře, se provádí pomocí příkazu molecule init:
> molekula init role -r nginx
--> Inicializace nové role nginx...
Role byla úspěšně inicializována v /nginx.
> cd nginx
> tree -L 1
.
├── README.md
├── defaults
├── handlers
├── meta
├── molecule
├── tasks
└── vars
6 adresářů, 1 souborVznikla typická ansible role. Dále se veškeré interakce s CLI Molekuly provádějí z kořenového adresáře role.
Podívejme se, co se nachází v adresáři role:
> tree molecule/default/
molecule/default/
├── Dockerfile.j2 # Jinja šablona pro Dockerfile
├── INSTALL.rst. # Něco informací o instalaci potřebných závislostí
├── molecule.yml # Konfigurační soubor
├── playbook.yml # Hlavní skript pro spuštění role
└── tests # Adresář s testy fáze ověření
└── test_default.py
1 adresář, 6 souborůPodíváme se na konfiguraci molecule/default/molecule.yml (vyměníme pouze docker image):
---
dependency:
name: galaxy
driver:
name: docker
lint:
name: yamllint
platforms:
- name: instance
image: centos:7
provisioner:
name: ansible
lint:
name: ansible-lint
scenario:
name: default
verifier:
name: testinfra
lint:
name: flake8dependency
Tato sekce popisuje zdroj závislostí.
Možné varianty: , , shell.
Shell – to je prostě příkazový interpret, který se používá, pokud galaxy a gilt neuspokojují vaše potřeby.
Nechci se zde dlouho zastavovat, dostatek bylo popsáno v .
driver
Název ovladače. V našem případě je to docker.
– spuštění linkerů. Ve výchozím nastavení se používají
Jako linter se používá yamllint.
Užitečné možnosti v této části konfiguračního souboru – to je možnost uvést konfigurační soubor pro yamllint, předat proměnné prostředí nebo vypnout linter:
lint:
name: yamllint
options:
config-file: foo/bar
env:
FOO: bar
enabled: Falseplatforms
Popisuje konfiguraci instancí.
V případě, že je docker roli ovladač, Molekula iteruje přes tuto sekci, a každý prvek seznamu je dostupný v Dockerfile.j2 jako proměnná item.
V případě ovladače, u kterého jsou vyžadovány create.yml a destroy.yml, sekce je dostupná v nich jako molecule_yml.platforms, a iterace přes ni jsou popsány již v těchto souborech.
Protože Molekula poskytuje správu instancí pomocí ansible modulů, je třeba hledat seznam dostupných nastavení tam. Pro docker se například používá modul . Jaké moduly se používají u ostatních ovladačů, lze nalézt v .
A také příklady použití různých ovladačů lze nalézt .
Změníme zde centos:7 na ubuntu.
provisioner
„Poskytovatel“ – entita, která spravuje instance. V případě Molekuly je to ansible, podpora pro jiné plánována není, takže tuto sekci můžeme s výhradou nazvat rozšířenou konfigurací ansible.
Zde můžete uvést mnoho věcí, vyzdvihl bych hlavní, podle mého názoru, body:
- playbooks: můžete uvádět, jaké playbooky by měly být použity v určitých fázích.
provisioner:
name: ansible
playbooks:
create: create.yml
destroy: ..\/default\/destroy.yml
converge: playbook.yml
side_effect: side_effect.yml
cleanup: cleanup.yml- config_options:
provisioner:
name: ansible
config_options:
defaults:
fact_caching: jsonfile
ssh_connection:
scp_if_ssh: True- connection_options: parametry
provisioner:
name: ansible
connection_options:
ansible_ssh_common_args: "-o 'UserKnownHostsFile=\/dev\/null' -o 'ForwardAgent=yes'"- možnosti: parametry Ansible a proměnné prostředí
provisioner:
name: ansible
options:
vvv: true
diff: true
env:
FOO: BARscenario
Název a popis sekvencí scénáře.
Matice akcí výchozího příkazu lze změnit přidáním klíče <příkaz>_sequence a jako hodnotu pro něj určit požadovaný seznam kroků.
Představme si, že chceme změnit sekvenci akcí při spuštění příkazu pro běh playbooku: molecule converge
# изначально:
# - dependency
# - create
# - prepare
# - converge
scenario:
name: default
converge_sequence:
- create
- convergeverifier
Nastavení frameworku pro testy a linter k němu. Výchozí linter je (ve výchozím nastavení) / a destroy. Možné možnosti jsou podobné uvedeným výše:
verifier:
name: testinfra
additional_files_or_dirs:
- ..\/path\/to\/test_1.py
- ..\/path\/to\/test_2.py
- ..\/path\/to\/directory\/*
options:
n: 1
enabled: False
env:
FOO: bar
lint:
name: flake8
options:
benchmark: True
enabled: False
env:
FOO: barVraťme se k naší roli. Upravíme soubor tasks\/main.yml do takového tvaru:
---
- name: Nainstalovat nginx
apt:
name: nginx
state: present
- name: Spustit nginx
service:
name: nginx
state: started
A přidáme testy do molecule\/default\/tests\/test_default.py
def test_nginx_is_installed(host):
nginx = host.package("nginx")
assert nginx.is_installed
def test_nginx_running_and_enabled(host):
nginx = host.service("nginx")
assert nginx.is_running
assert nginx.is_enabled
def test_nginx_config(host):
host.run("nginx -t")
Hotovo, zbývá pouze spustit (z kořene role, připomínám):
> molecule testDlouhý výstup pod spoilerem:
--> Ověřování schématu /nginx/molecule/default/molecule.yml.
Ověření bylo úspěšné.
--> Testovací matice
└── default
├── lint
├── destroy
├── dependency
├── syntax
├── create
├── prepare
├── converge
├── idempotence
├── side_effect
├── verify
└── destroy
--> Scénář: 'default'
--> Akce: 'lint'
--> Provádění Yamllint na souborech nalezených v /nginx/...
Lintování proběhlo úspěšně.
--> Provádění Flake8 na souborech nalezených v /nginx/molecule/default/tests/...
Lintování proběhlo úspěšně.
--> Provádění Ansible Lint na /nginx/molecule/default/playbook.yml...
Lintování proběhlo úspěšně.
--> Scénář: 'default'
--> Akce: 'destroy'
HRA [Zničit] *****************************************************************
ÚKOL [Zničit instance molekuly] ********************************************
změněno: [localhost] => (item=None)
změněno: [localhost]
ÚKOL [Čekání na dokončení odstranit instance] *******************************
ok: [localhost] => (item=None)
ok: [localhost]
ÚKOL [Smazat dockerové sítě] ************************************************
SHRnutí HRY *****************************************************************
localhost : ok=2 změněno=1 nedostupné=0 selhalo=0
--> Scénář: 'default'
--> Akce: 'dependency'
Přeskočeno, chybí soubor s požadavky.
--> Scénář: 'default'
--> Akce: 'syntax'
playbook: /nginx/molecule/default/playbook.yml
--> Scénář: 'default'
--> Akce: 'create'
HRA [Vytvořit] **************************************************************
ÚKOL [Přihlášení do Docker registru] *******************************************
přeskočeno: [localhost] => (item=None)
ÚKOL [Vytvořit Dockerfile ze jmen obrazů] ***********************************
změněno: [localhost] => (item=None)
změněno: [localhost]
ÚKOL [Objevit místní Docker obrazy] ******************************************
ok: [localhost] => (item=None)
ok: [localhost]
ÚKOL [Vytvořit obraz kompatibilní s Ansible] ********************************
změněno: [localhost] => (item=None)
změněno: [localhost]
ÚKOL [Vytvořit dockerové sítě] ***********************************************
ÚKOL [Vytvořit instance molekuly] ********************************************
změněno: [localhost] => (item=None)
změněno: [localhost]
ÚKOL [Čekání na dokončení vytvoření instance] *******************************
změněno: [localhost] => (item=None)
změněno: [localhost]
SHRnutí HRY *****************************************************************
localhost : ok=5 změněno=4 nedostupné=0 selhalo=0
--> Scénář: 'default'
--> Akce: 'prepare'
Přeskočeno, skript pro přípravu není nakonfigurován.
--> Scénář: 'default'
--> Akce: 'converge'
HRA [Spojení] ****************************************************************
ÚKOL [Shromažďování faktů] ***************************************************
ok: [instance]
ÚKOL [nginx : Instalace nginx] ***********************************************
změněno: [instance]
ÚKOL [nginx : Spuštění nginx] *************************************************
změněno: [instance]
SHRnutí HRY *****************************************************************
instance : ok=3 změněno=2 nedostupné=0 selhalo=0
--> Scénář: 'default'
--> Akce: 'idempotence'
Idempotence proběhla úspěšně.
--> Scénář: 'default'
--> Akce: 'side_effect'
Přeskočeno, skript vedlejších efektů není nakonfigurován.
--> Scénář: 'default'
--> Akce: 'verify'
--> Provádění testů Testinfra nalezených v /nginx/molecule/default/tests/...
============================= testovací relace začíná ==============================
platforma darwin -- Python 2.7.15, pytest-4.3.0, py-1.8.0, pluggy-0.9.0
rootdir: /nginx/molecule/default, inifile:
pluginy: testinfra-1.16.0
shromážděno 4 položky
tests/test_default.py .... [100%]
========================== 4 prošlo za 27.23 sekund ===========================
Ověřování proběhlo úspěšně.
--> Scénář: 'default'
--> Akce: 'destroy'
HRA [Zničit] *****************************************************************
ÚKOL [Zničit instance molekuly] ********************************************
změněno: [localhost] => (item=None)
změněno: [localhost]
ÚKOL [Čekání na dokončení odstranění instance] *******************************
změněno: [localhost] => (item=None)
změněno: [localhost]
ÚKOL [Smazat dockerové sítě] ************************************************
SHRnutí HRY *****************************************************************
localhost : ok=2 změněno=2 nedostupné=0 selhalo=0
Naše jednoduchá role byla testována bez problémů.
Je třeba mít na paměti, že pokud se při práci vyskytnou problémy molecule test, tak pokud jste neměnili standardní pořadí, Molecule odstraní instanci.
Pro ladění jsou užitečné následující příkazy:
> molecule --debug # debug info. Při běžném spuštění Molecule skrývá logy.
> molecule converge # Udržuje instanci po proběhnutí testované role.
> molecule login # Přihlásit se do vytvořené instance.
> molecule --help # Úplný seznam příkazů.Existující role
Přidání nového scénáře k existující roli probíhá z adresáře role následujícími příkazy:
# полный список доступных параметров
> molecule init scenarion --help
# создание нового сценария
> molecule init scenario -r <role_name> -s <scenario_name>V případě, že se jedná o první scénář v roli, lze parametr -s vynechat, protože bude vytvořen scénář. default.
Závěr
Jak vidíte, Molecule není příliš složitá, a při použití vlastních šablon je možné zjednodušit nasazení nového scénáře na úpravu proměnných v playbookách pro vytváření a odstraňování instancí. Molecule se bez problémů integruje se systémy CI, což zvyšuje rychlost vývoje tím, že zkracuje čas potřebný na ruční testování playbooků.
Děkujeme za vaši pozornost. Pokud máte zkušenosti s testováním ansible rolí, které nejsou spojeny s Molecule — podělte se o ně v komentářích!
Zdroj: habr.com
