Juhised: kuidas testida võimalikke rolle ja saada teada probleemidest enne tootmist

Tere kõigile!

Töötan DevOpsi insenerina hotelli broneerimisteenuses. Ostrovok.ru. Selles artiklis tahan rääkida meie kogemustest võimalike rollide testimisel.

Ostrovok.ru-s kasutame konfiguratsioonihaldurina ansible'i. Hiljuti jõudsime rollide testimise vajaduseni, kuid nagu selgus, pole selleks nii palju tööriistu - kõige populaarsem on võib-olla raamistik Molecule, nii et otsustasime seda kasutada. Kuid selgus, et tema dokumentatsioon vaikib paljudest lõkse. Me ei leidnud piisavalt üksikasjalikku venekeelset juhendit, mistõttu otsustasime selle artikli kirjutada.

Juhised: kuidas testida võimalikke rolle ja saada teada probleemidest enne tootmist

Molekul

Molekul - raamistik, mis aitab testida võimalikke rolle.

Lihtsustatud kirjeldus: molekul loob eksemplari teie määratud platvormil (pilv, virtuaalmasin, konteiner; lisateabe saamiseks vaadake jaotist juht), käivitab sellel teie rolli, seejärel käivitab testid ja kustutab eksemplari. Kui mõnel etapil ebaõnnestub, teavitab molekul teid sellest.

Nüüd rohkem

Natuke teooriat

Mõelge molekuli kahele põhiolemile: stsenaarium ja draiver.

Stsenaarium

Stsenaarium sisaldab kirjeldust, mida, kus, kuidas ja millises järjestuses tehakse. Ühel rollil võib olla mitu skripti ja igaüks neist on tee ääres olev kataloog <role>/molecule/<scenario>, mis sisaldab testiks vajalike toimingute kirjeldusi. Skript peab olema lisatud default, mis luuakse automaatselt, kui lähtestate rolli molekuliga. Järgmiste skriptide nimed on teie otsustada.

Kutsutakse välja skripti testimistoimingute jada maatriksja vaikimisi on see:

(Sammud märgistatud ?, jäetakse vaikimisi vahele, kui kasutaja pole seda määranud)

  • lint - jooksvad linterid. Vaikimisi kasutatakse yamllint и flake8,
  • destroy - eksemplaride kustutamine molekuli viimasest käivitamisest (kui neid on),
  • dependency? — testitava rolli võimaliku sõltuvuse paigaldamine,
  • syntax - rolli süntaksi kontrollimine kasutades ansible-playbook --syntax-check,
  • create - eksemplari loomine,
  • prepare? — eksemplari ettevalmistamine; nt kontrollige/installige python2
  • converge — testitava mänguraamatu käivitamine,
  • idempotence - idempotentsuse testi juhendi taaskäivitamine,
  • side_effect? - toimingud, mis ei ole rolliga otseselt seotud, kuid on testimiseks vajalikud,
  • verify - saadud konfiguratsiooni testide käivitamine kasutades testinfra(vaikimisi) /goss/inspec,
  • cleanup? - (uutes versioonides) - jämedalt öeldes molekuli poolt mõjutatud välise infrastruktuuri "puhastamine",
  • destroy - Eksemplari kustutamine.

See järjestus hõlmab enamikku juhtudest, kuid vajadusel saab seda muuta.

Kõiki ülaltoodud samme saab käivitada eraldi molecule <command>. Kuid tuleb mõista, et iga sellise klikikäsu jaoks võib olla oma toimingute jada, mille saate teada täites molecule matrix <command>. Näiteks käsu käivitamisel converge (käitades testitavat mänguraamatut), tehakse järgmised toimingud:

$ molecule matrix converge
...
└── default         # название сценария
    ├── dependency  # установка зависимостей
    ├── create      # создание инстанса
    ├── prepare     # преднастройка инстанса
    └── converge    # прогон плейбука

Nende toimingute järjestust saab muuta. Kui midagi loendist on juba tehtud, jäetakse see vahele. Praeguse oleku ja eksemplaride konfiguratsiooni salvestab Molecule kataloogi $TMPDIR/molecule/<role>/<scenario>.

Lisage sammud koos ? saate kirjeldada soovitud toiminguid ansible-playbook formaadis ja määrata failinime vastavalt sammule: prepare.yml/side_effect.yml. Oodake neid faile Molekul asub skripti kaustas.

juht

Draiver on olem, kus luuakse testeksemplarid.
Standardsete draiverite loend, mille jaoks Moleculel on mallid valmis, on järgmine: Azure, Docker, EC2, GCE, LXC, LXD, OpenStack, Vagrant, Delegated.

Enamasti on mallid failid create.yml и destroy.yml skriptikaustas, mis kirjeldavad vastavalt eksemplari loomist ja kustutamist.
Erandiks on Docker ja Vagrant, kuna interaktsioonid nende moodulitega võivad toimuda ka ilma eelnimetatud failideta.

Eraldi tasub esile tõsta delegeeritud draiverit, kuna kui seda kasutatakse failides eksemplari loomise ja kustutamise jaoks, siis kirjeldatakse ainult tööd eksemplaride konfigureerimisega, ülejäänu peaks kirjeldama insener.

Vaikimisi draiver on Docker.

Liigume nüüd edasi praktika juurde ja kaalume edasisi funktsioone.

Alustamine

"Teremaailmana" testime lihtsat nginxi installirolli. Valime draiveriks dockeri – ma arvan, et enamikul teist on see installitud (ja pidage meeles, et docker on vaikedraiver).

Valmistama virtualenv ja installige sellesse molecule:

> pip install virtualenv
> virtualenv -p `which python2` venv
> source venv/bin/activate
> pip install molecule docker  # molecule установит ansible как зависимость; docker для драйвера

Järgmine samm on uue rolli initsialiseerimine.
Uue rolli ja ka uue skripti initsialiseerimine toimub käsu abil molecule init <params>:

> molecule init role -r nginx
--> Initializing new role nginx...
Initialized role in <path>/nginx successfully.
> cd nginx
> tree -L 1
.
├── README.md
├── defaults
├── handlers
├── meta
├── molecule
├── tasks
└── vars

6 directories, 1 file

See osutus tüüpiliseks ansible-rolliks. Lisaks on kõik interaktsioonid CLI molekulidega tehtud rolli juurtest.

Vaatame, mis on rollikataloogis:

> tree molecule/default/
molecule/default/
├── Dockerfile.j2  # Jinja-шаблон для Dockerfile
├── INSTALL.rst.   # Немного информации об установке зависимостей сценария
├── molecule.yml   # Файл конфигурации
├── playbook.yml   # Плейбук запуска роли
└── tests          # Директория с тестами стадии verify
    └── test_default.py

1 directory, 6 files

Analüüsime konfiguratsiooni molecule/default/molecule.yml (asenda ainult dokkimispilt):

---
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: flake8

sõltuvust

Selles jaotises kirjeldatakse sõltuvuste allikat.

Võimalikud valikud: galaktika, kullatud, kest.

Shell on lihtsalt käsukest, mida kasutatakse juhuks, kui galaxy ja gilt ei kata teie vajadusi.

Ma ei peatu siin pikalt, sellest on piisavalt kirjeldatud dokumentatsioon.

juht

Juhi nimi. Meie oma on dokk.

side

Linter on yamllint.

Kasulikud valikud selles konfiguratsiooniosas on võimalus määrata yamllinti konfiguratsioonifail, edastada keskkonnamuutujad või keelata linter:

lint:
  name: yamllint
  options:
    config-file: foo/bar
  env:
    FOO: bar
  enabled: False

platvormid

Kirjeldab eksemplaride konfiguratsiooni.
Dockeri kui draiveri puhul itereeritakse molekuli selles jaotises ja iga loendi element on saadaval Dockerfile.j2 muutujana item.

Juhi puhul, mis nõuab create.yml и destroy.yml, on jaotis neis saadaval kui molecule_yml.platforms, ja selle iteratsioone on nendes failides juba kirjeldatud.

Kuna Molecule võimaldab juhtida võimalike moodulite eksemplare, tuleks sealt otsida ka võimalike seadistuste loend. Näiteks dokkeri jaoks kasutatakse moodulit docker_container_module. Milliseid mooduleid teistes draiverites kasutatakse, leiate siit dokumentatsioon.

Samuti võib leida näiteid erinevate draiverite kasutamisest Molekuli enda testides.

Asendage siin centos:7 edasi ubuntu.

varustaja

"Tarnija" – olem, mis haldab eksemplare. Molecule'i puhul on see võimalik, teiste toetamine pole plaanis, seega võib seda osa mööndusega nimetada ansible laiendatud konfiguratsiooniks.
Siin saate palju asju täpsustada, toon välja minu arvates peamised punktid:

  • mänguraamatud: saate määrata, milliseid mänguraamatuid teatud etappidel kasutada.

provisioner:
  name: ansible
  playbooks:
    create: create.yml
    destroy: ../default/destroy.yml
    converge: playbook.yml
    side_effect: side_effect.yml
    cleanup: cleanup.yml

provisioner:
  name: ansible
  config_options:
    defaults:
      fact_caching: jsonfile
    ssh_connection:
      scp_if_ssh: True

provisioner:
  name: ansible  
  connection_options:
    ansible_ssh_common_args: "-o 'UserKnownHostsFile=/dev/null' -o 'ForwardAgent=yes'"

  • valikuid: võimalikud valikud ja keskkonnamuutujad

provisioner:
  name: ansible  
  options:
    vvv: true
    diff: true
  env:
    FOO: BAR

stsenaarium

Skriptijadade nimi ja kirjeldus.
Võtme lisamisega saate muuta mis tahes käsu vaiketoimingu maatriksit <command>_sequence ja selle väärtuseks, määratledes meile vajalike sammude loendi.
Oletame, et tahame mänguraamatu käivitamise käsu käivitamisel muuta toimingute järjestust: molecule converge

# изначально:
# - dependency
# - create
# - prepare
# - converge
scenario:
  name: default
  converge_sequence:
    - create
    - converge

Tõendaja

Testide raamistiku loomine ja sellele liide. Vaikimisi linter on testinfra и flake8. Võimalikud valikud on samad, mis eespool:

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: bar

Tuleme tagasi oma rolli juurde. Redigeerime faili tasks/main.yml seda tüüpi:

---
- name: Install nginx
  apt:
    name: nginx
    state: present

- name: Start nginx
  service:
    name: nginx
    state: started

Ja lisage teste 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")

Tehtud, jääb üle vaid joosta (rolli algusest, lubage mul teile meelde tuletada):

> molecule test

Pikk heitgaas spoileri all:

--> Validating schema <path>/nginx/molecule/default/molecule.yml.
Validation completed successfully.
--> Test matrix

└── default
    ├── lint
    ├── destroy
    ├── dependency
    ├── syntax
    ├── create
    ├── prepare
    ├── converge
    ├── idempotence
    ├── side_effect
    ├── verify
    └── destroy

--> Scenario: 'default'
--> Action: 'lint'
--> Executing Yamllint on files found in <path>/nginx/...
Lint completed successfully.
--> Executing Flake8 on files found in <path>/nginx/molecule/default/tests/...
Lint completed successfully.
--> Executing Ansible Lint on <path>/nginx/molecule/default/playbook.yml...
Lint completed successfully.
--> Scenario: 'default'
--> Action: 'destroy'

    PLAY [Destroy] *****************************************************************

    TASK [Destroy molecule instance(s)] ********************************************
    changed: [localhost] => (item=None)
    changed: [localhost]

    TASK [Wait for instance(s) deletion to complete] *******************************
    ok: [localhost] => (item=None)
    ok: [localhost]

    TASK [Delete docker network(s)] ************************************************

    PLAY RECAP *********************************************************************
    localhost                  : ok=2    changed=1    unreachable=0    failed=0

--> Scenario: 'default'
--> Action: 'dependency'
Skipping, missing the requirements file.
--> Scenario: 'default'
--> Action: 'syntax'

    playbook: <path>/nginx/molecule/default/playbook.yml

--> Scenario: 'default'
--> Action: 'create'

    PLAY [Create] ******************************************************************

    TASK [Log into a Docker registry] **********************************************
    skipping: [localhost] => (item=None)

    TASK [Create Dockerfiles from image names] *************************************
    changed: [localhost] => (item=None)
    changed: [localhost]

    TASK [Discover local Docker images] ********************************************
    ok: [localhost] => (item=None)
    ok: [localhost]

    TASK [Build an Ansible compatible image] ***************************************
    changed: [localhost] => (item=None)
    changed: [localhost]

    TASK [Create docker network(s)] ************************************************

    TASK [Create molecule instance(s)] *********************************************
    changed: [localhost] => (item=None)
    changed: [localhost]

    TASK [Wait for instance(s) creation to complete] *******************************
    changed: [localhost] => (item=None)
    changed: [localhost]

    PLAY RECAP *********************************************************************
    localhost                  : ok=5    changed=4    unreachable=0    failed=0

--> Scenario: 'default'
--> Action: 'prepare'
Skipping, prepare playbook not configured.
--> Scenario: 'default'
--> Action: 'converge'

    PLAY [Converge] ****************************************************************

    TASK [Gathering Facts] *********************************************************
    ok: [instance]

    TASK [nginx : Install nginx] ***************************************************
    changed: [instance]

    TASK [nginx : Start nginx] *****************************************************
    changed: [instance]

    PLAY RECAP *********************************************************************
    instance                   : ok=3    changed=2    unreachable=0    failed=0

--> Scenario: 'default'
--> Action: 'idempotence'
Idempotence completed successfully.
--> Scenario: 'default'
--> Action: 'side_effect'
Skipping, side effect playbook not configured.
--> Scenario: 'default'
--> Action: 'verify'
--> Executing Testinfra tests found in <path>/nginx/molecule/default/tests/...
    ============================= test session starts ==============================
    platform darwin -- Python 2.7.15, pytest-4.3.0, py-1.8.0, pluggy-0.9.0
    rootdir: <path>/nginx/molecule/default, inifile:
    plugins: testinfra-1.16.0
collected 4 items

    tests/test_default.py ....                                               [100%]

    ========================== 4 passed in 27.23 seconds ===========================
Verifier completed successfully.
--> Scenario: 'default'
--> Action: 'destroy'

    PLAY [Destroy] *****************************************************************

    TASK [Destroy molecule instance(s)] ********************************************
    changed: [localhost] => (item=None)
    changed: [localhost]

    TASK [Wait for instance(s) deletion to complete] *******************************
    changed: [localhost] => (item=None)
    changed: [localhost]

    TASK [Delete docker network(s)] ************************************************

    PLAY RECAP *********************************************************************
    localhost                  : ok=2    changed=2    unreachable=0    failed=0

Meie lihtsat rolli prooviti probleemideta.
Tasub meeles pidada, et kui töö käigus on probleeme molecule test, siis kui te vaikejada ei muutnud, kustutab molekul eksemplari.

Järgmised käsud on silumiseks kasulikud:

> molecule --debug <command> # debug info. При обычном запуске Молекула скрывает логи.
> molecule converge          # Оставляет инстанс после прогона тестируемой роли.
> molecule login             # Зайти в созданный инстанс.
> molecule --help            # Полный список команд.

Olemasolev roll

Uue skripti lisamine olemasolevale rollile on rollide kataloogist järgmiste käskudega:

# полный список доступных параметров
> molecule init scenarion --help
# создание нового сценария
> molecule init scenario -r <role_name> -s <scenario_name>

Kui see on rolli esimene stsenaarium, siis parameeter -s võib ära jätta, kuna see loob skripti default.

Järeldus

Nagu näete, pole molekul kuigi keeruline ja teie enda mallide abil saab uue skripti juurutamise taandada eksemplari loomise ja kustutamise juhendites muutujate redigeerimiseni. Molekul integreerub sujuvalt CI-süsteemidega, mis võimaldab teil suurendada arenduskiirust, vähendades mänguraamatute käsitsi testimiseks kuluvat aega.

Tänan tähelepanu eest. Kui teil on kogemusi sobivate rollide testimisel ja see pole molekuliga seotud, rääkige sellest meile kommentaarides!

Allikas: www.habr.com

Lisa kommentaar