Hallo allemaal!
Ik werk als DevOps-engineer bij een hotelboekingsservice . In dit artikel wil ik onze ervaringen met het testen van Ansible-rollen delen.
Bij Ostrovok.ru gebruiken we Ansible als configuratiemanagementtool. Onlangs kwamen we tot de noodzaak om rollen te testen, maar het bleek dat er niet veel tools voor zijn — de meest populaire is waarschijnlijk het Molecule-framework, daarom hebben we besloten dit te gebruiken. Maar het bleek dat de documentatie veel verborgen valkuilen verdoezelt. We konden geen gedetailleerde handleiding in het Nederlands vinden, dus besloten we dit artikel te schrijven.

Molecule
is een framework dat helpt bij het testen van Ansible-rollen.
Eenvoudige beschrijving: Molecule creëert een instantie op het door u opgegeven platform (cloud, virtuele machine, container; zie het gedeelte ), voert uw rol op deze instantie uit, voert dan tests uit en verwijdert de instantie. In het geval van een mislukking in een van de stappen, zal Molecule u hiervan op de hoogte stellen.
Nu wat meer details.
Een beetje theorie
Laten we twee sleutelentiteiten van Molecule bekijken: Scenario en Driver.
Scenario
Een scenario bevat een beschrijving van wat, waar, hoe en in welke volgorde zal worden uitgevoerd. Een rol kan meerdere scenario's hebben, en elk is een directory onder /molecule/, die beschrijvingen van de benodigde acties voor de test bevat. Er moet altijd een scenario aanwezig zijn, dat automatisch wordt aangemaakt als u de rol met Molecule initieert. De namen van de volgende scenario's worden naar uw keuze gekozen. defaultDe reeks acties voor het testen in een scenario wordt genoemd
matrix , en standaard is deze als volgt:(Stappen gemarkeerd
, worden standaard overgeslagen als ze niet door de gebruiker zijn beschreven) ?lint
is het uitvoeren van linters. Standaard wordenflake8yamllintendestroy,is het verwijderen van instanties van de vorige Molecule-uitvoering (als die er zijn),syntaxdependency? — установка ansible-зависимости тестируемой роли,is de syntaxiscontrole van de rol met behulp vanansible-playbook --syntax-checkis het creëren van een instantie,,createprepareis het uitvoeren van het te testen playbook,? — подготовка инстанса; например, проверка / установка python2convergeidempotenceis het opnieuw uitvoeren van het playbook voor een test op idempotentie,side_effectverify? — действия, не относящиеся непосредственно к роли, но нужные для тестов,is het uitvoeren van tests op de verkregen configuratie met behulp vantestinfra(standaard) /gossinspec/cleanup,is het verwijderen van de instantie.? — (в новых версиях) — грубо говоря, «очистка» внешней инфраструктуры, задетой Молекулой,is het verwijderen van instanties van de vorige Molecule-uitvoering (als die er zijn),Deze volgorde dekt de meeste gevallen, maar kan indien nodig worden gewijzigd.
Deze reeks dekt de meeste gevallen, maar kan indien nodig worden aangepast.
Elke van de bovenstaande stappen kan afzonderlijk worden uitgevoerd met behulp van molecule. Maar men moet begrijpen dat er voor elke dergelijke cli-opdracht een specifieke volgorde van acties kan bestaan, die kan worden achterhaald door het uitvoeren van molecule matrix. Bijvoorbeeld, bij het uitvoeren van de opdracht converge (uitvoering van de te testen playbook) worden de volgende acties uitgevoerd:
$ molecule matrix converge
...
└── default # naam van het scenario
├── dependency # installeren van afhankelijkheden
├── create # aanmaken van de instantie
├── prepare # voorbereiden van de instantie
└── converge # uitvoeren van de playbookDe volgorde van deze acties kan worden bewerkt. Als iets uit de lijst al is uitgevoerd, wordt het overgeslagen. De huidige status, evenals de configuratie van de instanties, worden door Molecule opgeslagen in de directory $TMPDIR/molecule//.
Stappen met ? kun je toevoegen door de gewenste acties te beschrijven in het formaat van een ansible-playbook, en de bestandsnaam overeenkomstig te maken: prepare.yml/side_effect.yml. Molecule verwacht deze bestanden in de scenario-map.
Driver
Een driver is een entiteit waar instanties voor tests worden aangemaakt.
De lijst van standaarddragers waarvoor Molecule sjablonen heeft, is als volgt: Azure, Docker, EC2, GCE, LXC, LXD, OpenStack, Vagrant, Delegated.
In de meeste gevallen zijn de sjablonen bestanden create.yml en destroy.yml in de scenario-map die respectievelijk de creatie en verwijdering van een instantie beschrijven.
Uitzonderingen zijn Docker en Vagrant, aangezien de interactie met hun modules kan plaatsvinden zonder de eerder genoemde bestanden.
Het is belangrijk om de driver Delegated te benadrukken, omdat in het geval dat deze wordt gebruikt in de bestanden voor de creatie en verwijdering van de instantie alleen de configuratie van de instanties wordt beschreven, de rest moet door de ingenieur worden beschreven.
De standaard driver is Docker.
Laten we nu naar de praktijk gaan en verdere details daar bespreken.
Aan de slag
Als ‘hello world’ testen we een eenvoudige rol voor het installeren van nginx. Als driver kiezen we Docker - ik denk dat de meeste van jullie dit al hebben geïnstalleerd (en vergeet niet dat Docker de standaard driver is).
Laten we voorbereiden virtualenv en installeren in deze molecule:
> pip install virtualenv
> virtualenv -p `which python2` venv
> source venv/bin/activate
> pip install molecule docker # molecule installeert ansible als afhankelijkheid; docker voor de driverDe volgende stap is het initialiseren van een nieuwe rol.
Het initialiseren van een nieuwe rol, net als een nieuw scenario, gebeurt met het commando molecule init:
> molecule init role -r nginx
--> Initializing new role nginx...
Initialized role in /nginx successfully.
> cd nginx
> tree -L 1
.
├── README.md
├── defaults
├── handlers
├── meta
├── molecule
├── tasks
└── vars
6 directories, 1 fileWe hebben een typische Ansible-rol. Verder worden alle interacties met de Molecule CLI vanaf de hoofdrol uitgevoerd.
Laten we eens kijken wat er in de rolmap staat:
> tree molecule/default/
molecule/default/
├── Dockerfile.j2 # Jinja-sjabloon voor Dockerfile
├── INSTALL.rst. # Enige informatie over de installatie van dependencies
├── molecule.yml # Configuratiebestand
├── playbook.yml # Playbook voor het starten van de rol
└── tests # Map met tests voor de verificatiefase
└── test_default.py
1 directory, 6 filesLaten we de configuratie bekijken molecule/default/molecule.yml (alleen de docker image vervangen):
---
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
Deze sectie beschrijft de oorsprong van de dependencies.
Mogelijke opties: , , shell.
Shell is gewoon een command-line interface die wordt gebruikt als galaxy en gilt niet aan uw behoeften voldoen.
Ik zal hier niet lang bij stil staan, het is genoeg beschreven in .
driver
De naam van de driver. Dit is in ons geval docker.
is het uitvoeren van linters. Standaard worden
Als linter wordt yamllint gebruikt.
Handige opties in dit deel van de configuratie zijn de mogelijkheid om een configuratiebestand voor yamllint op te geven, omgevingsvariabelen door te geven, of de linter uit te schakelen:
lint:
name: yamllint
options:
config-file: foo/bar
env:
FOO: bar
enabled: Falseplatforms
Beschrijft de configuratie van de instanties.
In het geval van docker als de driver, iterates Molecule door deze sectie en elk element van de lijst is beschikbaar in Dockerfile.j2 als variabele item.
In het geval van een driver waarbij dwingend create.yml en destroy.yml, is de sectie in hen beschikbaar als molecule_yml.platforms, en de iteraties daarvan zijn al in deze bestanden beschreven.
Aangezien Molecule het beheer van instantiën aan Ansible-modules biedt, moet de lijst met mogelijke instellingen daar worden gezocht. Voor docker bijvoorbeeld, wordt de module . Welke modules worden gebruikt in de andere drivers, kan worden gevonden in .
Voorbeelden van het gebruik van verschillende drivers kunnen worden gevonden .
Laten we hier vervangen centos:7 en een werkende opdracht krijgen. ubuntu.
provisioner
"Leverancier" is een entiteit die instantiën beheert. In het geval van Molecule is dit Ansible, ondersteuning voor andere wordt niet gepland, dus deze sectie kan met enige voorzichtigheid als uitgebreide configuratie van Ansible worden beschouwd.
Hier kunnen veel dingen worden vermeld, maar ik zal de belangrijkste punten uitlichten, naar mijn mening:
- playbooks: het is mogelijk om aan te geven welke playbooks op specifieke momenten moeten worden gebruikt.
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: parameters
provisioner:
name: ansible
connection_options:
ansible_ssh_common_args: "-o 'UserKnownHostsFile=/dev/null' -o 'ForwardAgent=yes'"- options: Ansible parameters en omgevingsvariabelen
provisioner:
name: ansible
options:
vvv: true
diff: true
env:
FOO: BARscenario
Naam en beschrijving van scenario sequenties.
De standaardactie matrix van een specifiek commando kan worden gewijzigd door een sleutel toe te voegen _sequence en als waarde voor deze sleutel de gewenste lijst van stappen te definiëren.
Stel dat we de volgorde van acties willen wijzigen wanneer we het commando voor het uitvoeren van de playbook starten: molecule converge
# изначально:
# - dependency
# - create
# - prepare
# - converge
scenario:
name: default
converge_sequence:
- create
- convergeverifier
Instellen van het framework voor tests en de linter daarvan. Standaard wordt als linter gebruikt (standaard) / en destroy. Mogelijke opties zijn vergelijkbaar met de hierboven genoemde:
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: barLaten we terugkeren naar onze rol. We zullen het bestand bewerken tasks/main.yml tot de volgende vorm:
---
- name: Installeer nginx
apt:
name: nginx
state: present
- name: Start nginx
service:
name: nginx
state: started
En we voegen tests toe aan 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")
Klaar, we moeten alleen nog maar uitvoeren (vanuit de hoofdrol, ter herinnering):
> molecule testLange uitvoer onder de spoiler:
--> Het valideren van schema /nginx/molecule/default/molecule.yml.
Validatie succesvol voltooid.
--> Testmatrix
└── default
├── lint
├── vernietigen
├── afhankelijkheid
├── syntaxis
├── maken
├── voorbereiden
├── convergeren
├── idempotentie
├── neveneffect
├── verifiëren
└── vernietigen
--> Scenario: 'default'
--> Actie: 'lint'
--> Yamllint uitvoeren op bestanden gevonden in /nginx/...
Lint succesvol voltooid.
--> Flake8 uitvoeren op bestanden gevonden in /nginx/molecule/default/tests/...
Lint succesvol voltooid.
--> Ansible Lint uitvoeren op /nginx/molecule/default/playbook.yml...
Lint succesvol voltooid.
--> Scenario: 'default'
--> Actie: 'vernietigen'
SPEL [Vernietigen] *****************************************************************
TAK [Vernietig molecule-instantie(s)] ********************************************
gewijzigd: [localhost] => (item=None)
gewijzigd: [localhost]
TAK [Wacht op voltooiing van de verwijdering van instantie(s)] *******************************
ok: [localhost] => (item=None)
ok: [localhost]
TAK [Verwijder docker netwerk(en)] ************************************************
SPEL SAMENVATTING *********************************************************************
localhost : ok=2 gewijzigd=1 onbereikbaar=0 mislukt=0
--> Scenario: 'default'
--> Actie: 'afhankelijkheid'
Overgeslagen, het vereistenbestand ontbreekt.
--> Scenario: 'default'
--> Actie: 'syntaxis'
playbook: /nginx/molecule/default/playbook.yml
--> Scenario: 'default'
--> Actie: 'maken'
SPEL [Maken] ******************************************************************
TAK [Log in bij een Docker-register] **********************************************
overgeslagen: [localhost] => (item=None)
TAK [Maak Dockerfiles van afbeeldingsnamen] *************************************
gewijzigd: [localhost] => (item=None)
gewijzigd: [localhost]
TAK [Ontdek lokale Docker-afbeeldingen] ********************************************
ok: [localhost] => (item=None)
ok: [localhost]
TAK [Bouw een Ansible-compatibele afbeelding] ***************************************
gewijzigd: [localhost] => (item=None)
gewijzigd: [localhost]
TAK [Maak docker netwerk(en)] ************************************************
TAK [Maak molecule-instantie(s)] *********************************************
gewijzigd: [localhost] => (item=None)
gewijzigd: [localhost]
TAK [Wacht op voltooiing van de creatie van instantie(s)] *******************************
gewijzigd: [localhost] => (item=None)
gewijzigd: [localhost]
SPEL SAMENVATTING *********************************************************************
localhost : ok=5 gewijzigd=4 onbereikbaar=0 mislukt=0
--> Scenario: 'default'
--> Actie: 'voorbereiden'
Overgeslagen, voorbereidingsplaybook niet geconfigureerd.
--> Scenario: 'default'
--> Actie: 'convergeren'
SPEL [Convergeren] ****************************************************************
TAK [Feiten verzamelen] *********************************************************
ok: [instance]
TAK [nginx : Installeer nginx] ***************************************************
gewijzigd: [instance]
TAK [nginx : Start nginx] *****************************************************
gewijzigd: [instance]
SPEL SAMENVATTING *********************************************************************
instance : ok=3 gewijzigd=2 onbereikbaar=0 mislukt=0
--> Scenario: 'default'
--> Actie: 'idempotentie'
Idempotentie succesvol voltooid.
--> Scenario: 'default'
--> Actie: 'neveneffect'
Overgeslagen, neveneffectplaybook niet geconfigureerd.
--> Scenario: 'default'
--> Actie: 'verifiëren'
--> Voer Testinfra-tests uit gevonden in /nginx/molecule/default/tests/...
============================= test sessie begint ==============================
platform darwin -- Python 2.7.15, pytest-4.3.0, py-1.8.0, pluggy-0.9.0
rootdir: /nginx/molecule/default, inifile:
plugins: testinfra-1.16.0
verzamelde 4 items
tests/test_default.py .... [100%]
========================== 4 geslaagd in 27.23 seconden ===========================
Verifier succesvol voltooid.
--> Scenario: 'default'
--> Actie: 'vernietigen'
SPEL [Vernietigen] *****************************************************************
TAK [Vernietig molecule-instantie(s)] ********************************************
gewijzigd: [localhost] => (item=None)
gewijzigd: [localhost]
TAK [Wacht op voltooiing van de verwijdering van instantie(s)] *******************************
gewijzigd: [localhost] => (item=None)
gewijzigd: [localhost]
TAK [Verwijder docker netwerk(en)] ************************************************
SPEL SAMENVATTING *********************************************************************
localhost : ok=2 gewijzigd=2 onbereikbaar=0 mislukt=0
Onze eenvoudige rol werd probleemloos getest.
Het is belangrijk om te onthouden dat als er problemen optreden bij het werken molecule test, dan, als je de standaard volgorde niet hebt gewijzigd, Molecule de instantie zal verwijderen.
Voor debugging zijn de volgende commando's handig:
> molecule --debug # debug info. Bij een gewone uitvoering verbergt Molecule de logs.
> molecule converge # Houdt de instantie na het uitvoeren van de testrol.
> molecule login # Aanmelden bij de gemaakte instantie.
> molecule --help # Volledige lijst van commando's.Bestaande rol
Het toevoegen van een nieuw scenario aan een bestaande rol gebeurt uit de rolmap met de volgende commando's:
# полный список доступных параметров
> molecule init scenarion --help
# создание нового сценария
> molecule init scenario -r <role_name> -s <scenario_name>In het geval dat dit het eerste scenario in de rol is, kan de parameter -s worden weggelaten, aangezien er een scenario zal worden aangemaakt. default.
Conclusie
Zoals je ziet, is Molecule niet erg ingewikkeld, en met het gebruik van eigen sjablonen kun je het implementeren van een nieuw scenario reduceren tot het aanpassen van variabelen in de playbooks voor het maken en verwijderen van instanties. Molecule integreert probleemloos met CI-systemen, wat de ontwikkeling versnelt door de tijd voor handmatige testen van playbooks te verkorten.
Bedankt voor je aandacht. Als je ervaring hebt met het testen van ansible-rollen die niet gerelateerd zijn aan Molecule, laat het me weten in de reacties!
Bron: habr.com
