Upute: kako testirati antabilne uloge i saznati probleme prije proizvodnje

Pozdrav!

Radim kao DevOps inženjer u servisu za rezervacije hotela. Ostrovok.ru. U ovom članku želim govoriti o našem iskustvu u testiranju antabilnih uloga.

Na Ostrovok.ru koristimo ansible kao upravitelj konfiguracije. Nedavno smo došli do potrebe za testiranjem uloga, ali kako se pokazalo, nema toliko alata za to - možda je najpopularniji okvir Molecule, pa smo ga odlučili koristiti. No pokazalo se da njegova dokumentacija šuti o mnogim zamkama. Nismo mogli pronaći dovoljno detaljan priručnik na ruskom, pa smo odlučili napisati ovaj članak.

Upute: kako testirati antabilne uloge i saznati probleme prije proizvodnje

Molekula

Molekula - okvir za pomoć u testiranju mogućih uloga.

Pojednostavljeni opis: Molekula stvara instancu na platformi koju navedete (oblak, virtualni stroj, spremnik; za više detalja pogledajte odjeljak vozač), pokreće vašu ulogu na njemu, zatim pokreće testove i briše instancu. U slučaju kvara na jednom od koraka, Molecule će vas o tome obavijestiti.

Sada više.

Malo teorije

Razmotrite dva ključna entiteta molekule: scenarij i pokretač.

scenario

Skripta sadrži opis što, gdje, kako i kojim redoslijedom će se izvoditi. Jedna uloga može imati nekoliko skripti, a svaka je direktorij na putu <role>/molecule/<scenario>, koji sadrži opise radnji potrebnih za testiranje. Skripta mora biti uključena default, koji će se automatski stvoriti ako inicijalizirate ulogu s Molecule. Imena sljedećih skripti ovisi o vama.

Poziva se niz radnji testiranja u skripti matrica, a prema zadanim postavkama je:

(Koraci označeni ?, preskočeno prema zadanim postavkama ako nije navedeno od strane korisnika)

  • lint - trčanje lintera. Prema zadanim postavkama koriste se yamllint и flake8,
  • destroy - brisanje instanci od zadnjeg pokretanja Molecule (ako ih ima),
  • dependency? — instalacija anzibilne ovisnosti testirane uloge,
  • syntax - provjera sintakse korištenja uloge ansible-playbook --syntax-check,
  • create - stvaranje instance,
  • prepare? — priprema instance; npr. provjeri/instaliraj python2
  • converge — pokretanje priručnika koji se testira,
  • idempotence - ponovno pokretanje priručnika za test idempotencije,
  • side_effect? - radnje koje nisu izravno povezane s ulogom, ali su potrebne za testove,
  • verify - izvođenje testova dobivene konfiguracije pomoću testinfra(zadano) /goss/inspec,
  • cleanup? - (u novim verzijama) - grubo rečeno, "čišćenje" vanjske infrastrukture na koju utječe Molecule,
  • destroy - Brisanje instance.

Ovaj redoslijed pokriva većinu slučajeva, ali se može promijeniti ako je potrebno.

Svaki od gornjih koraka može se pokrenuti zasebno molecule <command>. Ali treba imati na umu da za svaku takvu cli-naredbu može postojati vlastiti slijed radnji, što možete saznati izvršavanjem molecule matrix <command>. Na primjer, prilikom pokretanja naredbe converge (pokrećući priručnik za igru ​​koji se testira), izvršit će se sljedeće radnje:

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

Redoslijed ovih radnji može se uređivati. Ako je nešto s popisa već učinjeno, bit će preskočeno. Trenutno stanje, kao i konfiguraciju instanci, Molecule pohranjuje u direktorij $TMPDIR/molecule/<role>/<scenario>.

Dodajte korake s ? možete opisati željene radnje u formatu ansible-playbook i napraviti naziv datoteke prema koraku: prepare.yml/side_effect.yml. Očekujte ove datoteke. Molekula će biti u mapi skripte.

vozač

Upravljački program je entitet u kojem se stvaraju testne instance.
Popis standardnih upravljačkih programa za koje Molecule ima spremne predloške je sljedeći: Azure, Docker, EC2, GCE, LXC, LXD, OpenStack, Vagrant, Delegated.

U većini slučajeva predlošci su datoteke create.yml и destroy.yml u mapi skripte koji opisuju stvaranje odnosno brisanje instance.
Iznimke su Docker i Vagrant, budući da se interakcije s njihovim modulima mogu dogoditi bez prethodno navedenih datoteka.

Vrijedi istaknuti Delegated driver, jer ako se koristi u datotekama za kreiranje i brisanje instance, opisan je samo rad s konfiguracijom instanci, ostalo bi trebao opisati inženjer.

Zadani upravljački program je Docker.

Sada prijeđimo na praksu i razmotrimo daljnje značajke.

Početak

Kao "zdravo svijetu", testirajmo jednostavnu instalacijsku ulogu nginxa. Odaberimo docker kao upravljački program - mislim da ga većina vas ima instaliran (i zapamtite da je docker zadani upravljački program).

pripremiti virtualenv i instalirajte u njega molecule:

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

Sljedeći korak je inicijalizacija nove uloge.
Inicijalizacija nove uloge, kao i nove skripte, vrši se naredbom 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

Ispalo je tipična ansible-uloga. Nadalje, sve interakcije s CLI molekulama se izvode iz korijena uloge.

Pogledajmo što se nalazi u imeniku uloga:

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

1 directory, 6 files

Analizirajmo konfiguraciju molecule/default/molecule.yml (zamijenite samo docker sliku):

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

zavisnost

Ovaj odjeljak opisuje izvor ovisnosti.

Moguće opcije: galaksija, vrijedi, školjka.

Shell je samo komandna ljuska koja se koristi u slučaju da galaxy i gilt ne zadovoljavaju vaše potrebe.

Neću se ovdje dugo zadržavati, dovoljno je opisano u dokumentacija.

vozač

Ime vozača. Naš je doker.

otpaci od prediva

Linter je yamllint.

Korisne opcije u ovom dijelu konfiguracije su mogućnost određivanja konfiguracijske datoteke za yamllint, prosljeđivanje varijabli okruženja ili onemogućavanje lintera:

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

platforme

Opisuje konfiguraciju instanci.
U slučaju dockera kao pokretačkog programa, Molecule se ponavlja kroz ovaj odjeljak, a svaki element popisa dostupan je u Dockerfile.j2 kao varijabla item.

U slučaju vozača koji zahtijeva create.yml и destroy.yml, odjeljak je dostupan u njima kao molecule_yml.platforms, a iteracije preko njega već su opisane u ovim datotekama.

Budući da Molecule omogućuje kontrolu nad instancama ansible modulima, popis mogućih postavki također treba potražiti tamo. Za docker se, na primjer, koristi modul docker_container_module. Koji se moduli koriste u drugim upravljačkim programima možete pronaći u dokumentacija.

Kao i primjeri korištenja raznih drajvera mogu se naći u testovima same Molekule.

Zamijenite ovdje centi:7 na ubuntu.

opskrbljivač

"Dobavljač" - subjekt koji upravlja instancama. U slučaju Molecule, ovo je ansible, podrška za druge nije planirana, tako da se ovaj odjeljak može nazvati ansible extended konfiguracija uz ogradu.
Ovdje možete navesti puno stvari, ja ću istaknuti glavne točke, po mom mišljenju:

  • knjige za igru: možete odrediti koje knjige s igrama treba koristiti u određenim fazama.

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

  • opcije_veze: mogućnosti veza

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

  • opcije: Ansible opcije i varijable okruženja

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

scenario

Naziv i opis sekvenci skripte.
Možete promijeniti zadanu matricu radnji bilo koje naredbe dodavanjem ključa <command>_sequence a kao vrijednost za to definiranjem popisa koraka koji su nam potrebni.
Recimo da želimo promijeniti redoslijed radnji prilikom pokretanja naredbe playbook run: molecule converge

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

ovjerovitelja

Postavljanje okvira za testove i lintera za njega. Zadani linter je testinfra и flake8. Moguće opcije su iste kao gore:

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

Vratimo se našoj ulozi. Uredimo datoteku tasks/main.yml na ovu vrstu:

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

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

I dodajte testove 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")

Gotovo, ostaje samo pokrenuti (iz korijena uloge, da vas podsjetim):

> molecule test

Dugi ispuh ispod spojlera:

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

Naša jednostavna uloga testirana je bez problema.
Vrijedno je zapamtiti da ako tijekom rada postoje problemi molecule test, a zatim ako niste promijenili zadani niz, Molecule će izbrisati instancu.

Sljedeće naredbe korisne su za otklanjanje pogrešaka:

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

Postojeća uloga

Dodavanje nove skripte postojećoj ulozi je iz imenika uloga sa sljedećim naredbama:

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

U slučaju da je ovo prvi scenarij u ulozi, onda parametar -s može se izostaviti jer će stvoriti skriptu default.

Zaključak

Kao što možete vidjeti, Molecule nije jako složen, a korištenjem vlastitih predložaka, postavljanje nove skripte može se svesti na uređivanje varijabli u knjigama za stvaranje i brisanje instanci. Molekula se besprijekorno integrira s CI sustavima, što vam omogućuje povećanje brzine razvoja smanjenjem vremena za ručno testiranje knjiga za igru.

Hvala vam na pažnji. Ako imate iskustva u testiranju ansibilnih uloga, a nije vezano uz Molecule, recite nam o tome u komentarima!

Izvor: www.habr.com

Dodajte komentar