Инструкции: како да се тестираат точните улоги и да се дознаат проблемите пред производството

Здраво на сите!

Работам како инженер DevOps во услуга за резервации на хотели. Ostrovok.ru. Во оваа статија, сакам да зборувам за нашето искуство во тестирањето на соодветни улоги.

На Ostrovok.ru користиме ansible како менаџер за конфигурација. Неодамна, дојдовме до потреба да ги тестираме улогите, но како што се испостави, нема толку многу алатки за ова - најпопуларната, можеби, е рамката на Молекулата, па решивме да ја користиме. Но, се покажа дека неговата документација молчи за многу стапици. Не можевме да најдеме доволно детален прирачник на руски, па решивме да ја напишеме оваа статија.

Инструкции: како да се тестираат точните улоги и да се дознаат проблемите пред производството

молекула

Молекула - рамка која ќе помогне да се тестираат соодветните улоги.

Поедноставен опис: молекулата создава примерок на платформата што ја одредувате (облак, виртуелна машина, контејнер; за повеќе детали, видете го делот Возачот), ја извршува вашата улога на неа, потоа извршува тестови и ја брише инстанцата. Во случај на неуспех на еден од чекорите, Молекулата ќе ве информира за тоа.

Сега повеќе.

Малку теорија

Размислете за два клучни ентитети на молекулата: Сценарио и Возач.

Сценарио

Сценариото содржи опис што, каде, како и во кој редослед ќе се изведува. Една улога може да има неколку скрипти и секоја е директориум по патеката <role>/molecule/<scenario>, кој содржи описи на дејствата потребни за тестот. Скриптата мора да биде вклучена default, кој автоматски ќе се креира ако ја иницијализирате улогата со молекула. Имињата на следните скрипти зависи од вас.

Редоследот на тестирање акции во скрипта се нарекува матрица, и по дифолт е:

(Чекорите се означени ?, стандардно прескокнат ако не е одредено од корисникот)

  • lint - трчање линтери. Стандардно се користат yamllint и flake8,
  • destroy - бришење на примероци од последното лансирање на молекулата (ако има),
  • dependency? — инсталирање на разбирлива зависност на тестираната улога,
  • syntax - проверка на синтаксата на улогата користејќи ansible-playbook --syntax-check,
  • create - создавање на пример,
  • prepare? — подготовка на инстанцата; на пример, провери/инсталирај python2
  • converge — лансирање на книгата за игри што се тестира,
  • idempotence - рестартирање на книгата за тестот за идемпотенција,
  • side_effect? - дејствија кои не се директно поврзани со улогата, но неопходни за тестови,
  • verify - извршување на тестови на добиената конфигурација користејќи testinfra(стандардно) /goss/inspec,
  • cleanup? - (во нови верзии) - грубо кажано, „чистење“ на надворешната инфраструктура погодена од молекулата,
  • destroy - Бришење на пример.

Оваа низа ги опфаќа повеќето случаи, но може да се промени доколку е потребно.

Секој од горенаведените чекори може да се изврши одделно со molecule <command>. Но, треба да се разбере дека за секоја таква кли-команда може да има свој редослед на дејства, што можете да го дознаете со извршување molecule matrix <command>. На пример, кога ја извршувате командата converge (вклучувајќи ја книгата за игри што се тестира), ќе се извршат следните дејства:

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

Редоследот на овие дејства може да се уредува. Ако нешто од списокот е веќе направено, ќе се прескокне. Тековната состојба, како и конфигурацијата на примероците, Молекулата ја складира во директориумот $TMPDIR/molecule/<role>/<scenario>.

Додадете чекори со ? можете да ги опишете саканите дејства во формат ansible-playbook и да го направите името на датотеката според чекорот: prepare.yml/side_effect.yml. Очекувајте ги овие датотеки Молекулата ќе биде во папката скрипта.

Возачот

Возачот е ентитет каде што се креираат тест примери.
Списокот на стандардни двигатели за кои Molecule има подготвени шаблони е како што следува: Azure, Docker, EC2, GCE, LXC, LXD, OpenStack, Vagrant, Delegated.

Во повеќето случаи, шаблоните се датотеки create.yml и destroy.yml во папката скрипта што го опишува создавањето и бришењето на пример, соодветно.
Исклучоци се Docker и Vagrant, бидејќи интеракциите со нивните модули може да се случат без гореспоменатите датотеки.

Вреди да се истакне Делегираниот двигател, бидејќи ако се користи во датотеките за креирање и бришење на пример, се опишува само работа со конфигурација на примероци, а остатокот треба да го опише инженерот.

Стандардниот драјвер е Docker.

Сега да продолжиме да вежбаме и да разгледаме дополнителни карактеристики таму.

Getting Started

Како „здрав свет“, ајде да тестираме едноставна улога за инсталација на nginx. Ајде да го избереме докерот за драјвер - мислам дека повеќето од вас го имаат инсталирано (и запомнете дека докерот е стандардниот двигател).

Подгответе virtualenv и инсталирај во него molecule:

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

Следниот чекор е да се иницијализира новата улога.
Иницијализирање на нова улога, како и нова скрипта, се врши со помош на командата 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

Испадна типична одговорна улога. Понатаму, сите интеракции со CLI молекулите се направени од коренот на улогата.

Ајде да видиме што има во директориумот за улоги:

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

1 directory, 6 files

Ајде да ја анализираме конфигурацијата molecule/default/molecule.yml (заменете ја само докерската слика):

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

зависност

Овој дел го опишува изворот на зависностите.

Можни опции: галаксија, се однесува, школка.

Шел е само командна обвивка што се користи во случај галаксијата и позлата да не ги покриваат вашите потреби.

Нема да се задржам овде долго време, доволно е опишано во документација.

возачот

Името на возачот. Нашиот е докер.

лента

Линтерот е јамлинт.

Корисни опции во овој дел од конфигурацијата се способноста да се определи конфигурациска датотека за yamllint, променливи на околината за проследување или оневозможување на линтер:

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

платформи

Ја опишува конфигурацијата на примероците.
Во случај на докер како двигател, молекулата се повторува преку овој дел и секој елемент од листата е достапен во Dockerfile.j2 како променлива item.

Во случај на возач кој бара create.yml и destroy.yml, делот е достапен во нив како molecule_yml.platforms, и повторувањата над него се веќе опишани во овие датотеки.

Со оглед на тоа што Молекулата обезбедува контрола на инстанци на ансибилни модули, таму треба да се бара и списокот на можни поставки. За докер, на пример, се користи модулот docker_container_module. Во кои модули се користат други драјвери може да се најдат документација.

Како и примери за употреба на различни драјвери може да се најдат во тестовите на самата молекула.

Заменете овде центи: 7 на Ubuntu.

обезбедувач

„Добавувач“ - ентитет што управува со инстанци. Во случајот со Molecule, ова е оправдано, поддршката за другите не е планирана, така што овој дел може да се нарече неиздржлива проширена конфигурација со предупредување.
Овде можете да наведете многу работи, ќе ги истакнам главните точки, според мое мислење:

  • игротеки: можете да одредите кои книги за играње треба да се користат во одредени фази.

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

  • опции: Ansible опции и променливи на околината

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

сценарио

Име и опис на секвенците на скрипта.
Можете да ја промените стандардната акциона матрица на која било команда со додавање на клучот <command>_sequence и како вредност за него со дефинирање на листата на чекори кои ни се потребни.
Да речеме дека сакаме да го промениме редоследот на дејства кога ја извршуваме командата за извршување на Playbook: molecule converge

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

потврдувач

Поставување рамка за тестови и линтер за неа. Стандардниот линтер е testinfra и flake8. Можните опции се исти како погоре:

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

Да се ​​вратиме на нашата улога. Ајде да ја уредиме датотеката tasks/main.yml на овој вид:

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

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

И додадете тестови на 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")

Готово, останува само да се кандидира (од коренот на улогата, да ве потсетам):

> molecule test

Долг издув под спојлерот:

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

Нашата едноставна улога беше тестирана без проблеми.
Вреди да се запамети дека ако има проблеми за време на работата molecule test, тогаш ако не сте ја смениле стандардната секвенца, Молекулата ќе ја избрише инстанцата.

Следниве команди се корисни за дебагирање:

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

Постоечка улога

Додавање нова скрипта на постоечка улога е од директориумот за улоги со следните команди:

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

Во случај ова да е првото сценарио во улогата, тогаш параметарот -s може да се испушти бидејќи ќе создаде скрипта default.

Заклучок

Како што можете да видите, Молекулата не е многу сложена и со користење на ваши сопствени шаблони, распоредувањето на нова скрипта може да се сведе на уредување на променливи во книгите за создавање и бришење примери. Молекулата беспрекорно се интегрира со CI системите, што ви овозможува да ја зголемите брзината на развој со намалување на времето за рачно тестирање на книгите за играње.

Ви благодариме за вниманието. Ако имате искуство во тестирање на одговорни улоги, а не е поврзано со молекулата, кажете ни за тоа во коментарите!

Извор: www.habr.com

Додадете коментар