Мастер: Ansible, Molecule и разработка через тестирование

Мастер: Ansible, Molecule и разработка через тестирование

by moiseevrus

Магия существовала с незапамятных времен. Он всегда был там, спрятанный у всех на виду, делая удивительные вещи возможными для тех, кто хотел открыть глаза и использовать его силу.

Вы не можете вспомнить, когда впервые использовали его, и все же кажется, что вы никогда не существовали без него. Вы уничтожали бесконечные армии врагов с помощью заклинаний и чар, а также строили с нуля впечатляющие чудеса. В результате вы известны своей непреодолимой силой в каждом из ваших воплощений во времени. Все знают о Волшебнике.

Эта близость к магии дает вам возможность видеть истинную природу вещей. Время, например, нелинейно (как считалось вплоть до конца 21 века). Иногда за этим трудно уследить…

 

Внезапно ты просыпаешься. Или вы приходите в сознание. Какой сейчас год?

  • Так что да, вывод по-прежнему красный, я действительно не знаю, что еще делать.
  • Какая?

Ты смотришь налево. Н сидит прямо там. Он смотрит на вас с легкой тревогой в глазах.

  • У тебя все нормально?
  • Да извини.
  • Как я уже говорил, я не знаю, почему это не работает.

Вы посмотрите на заклинание, которое он пытается сотворить. Его намерение ясно: он хочет поделиться работой своего клана со всеми разумными существами в этой реальности с помощью портала.

---

# task file for nginx

 

- name: Install nginx

  yum:

    name: nginx

    state: present

Понятно, почему он терпит неудачу. Он не принимает во внимание ограничения среды своего клана. Он должен сначала собрать требования своего заклинания, и он смотрит не туда. На самом деле он вообще не смотрит. Ответ прост. Тем не менее…

Вы задумываетесь на секунду, задаваясь вопросом, научил ли кто-нибудь N, как правильно произносить заклинание.

  • Как вы проверяете свою роль?
  • Хм…
  • Вы тестируете свою роль?
  • Да, конечно.
  • Как?
  • Я запускаю свой код на целевой машине, а затем надеюсь, что он не подведет.

Вы чувствуете себя преданным звуком его слов. Это неприемлемо. Целая стопка смертельных заклинаний появляется у вас в голове. Дыши, повторяешь ты про себя. В. Вне. Вы продолжаете идти.

  • Знакомы ли вы с концепцией разработки через тестирование?
  • Да, я всегда так работал, когда занимался разработкой с командой.
  • Значит, ты с ним знаком.
  • Конечно, L научил меня.

О, знакомое имя. Вам нравится L. Вы вместе сражались в Desaix, до того, как он начал обучать своих учеников военному искусству. Должно быть, он научил N кое-чему. Вы задаетесь вопросом, сможет ли он выжить в суде.

  • Почему бы вам не протестировать свой код таким образом?
  • Потому что это не Java, это Ansible.
  • Так?
  • Это не тоже самое.
  • Давай начнем сначала. Не возражаешь, если я возьму клавиатуру?
  • Нисколько.

Вы используете свою энергию, готовясь произнести свое первое заклинание. Вы снова чувствуете себя живым. Вы находитесь в знакомой местности. Прежде чем вы начнете работать, вам нужен пустой холст, игровая площадка для создания структуры и надежности вашей магии. Изолированное ограждение, которое позволит вам пробовать свои заклинания и которое также следует тем же правилам, что и целевая реальность для заклинания, которое вы пытаетесь создать.

  • Вы когда-нибудь слышали о молекуле?
  • …хм?
  • Это инструмент Python. Это позволяет вам тестировать код Ansible на разных уровнях, используя локальную инфраструктуру.
  • Местный? Как виртуальная машина?

Он быстрый. Время сделать выбор. Странник или кит? Кит действительно быстрее.

  • Не обязательно. Вы можете использовать разных провайдеров. Vagrant и Docker являются наиболее распространенными, если вы хотите работать локально. Мы собираемся использовать Docker, так как у контейнеров более быстрое время запуска.
  • Давай, Докер!

Кит это. Вы концентрируетесь и произносите свое первое заклинание.

$ molecule init role --role-name nginx --driver-name docker

Вы чувствуете поток энергии. В небе образуется водоворот голубой воды, из которого появляется Кит. Он плывет по воздуху, смотрит на вас обоих и громко поет свою песню. Пустой корпус материализуется из воздуха, запирая вас и N внутри него. Кит исчезает из водоворота там, где он появился, прямо перед тем, как сам водоворот исчезает в небытии так же быстро, как и появился.

--> Initializing new role nginx…

 

nginx/

├── README.md

├── defaults

│   └── main.yml

├── handlers

│   └── main.yml

├── meta

│   └── main.yml

├── molecule

│   └── default

│       ├── Dockerfile.j2

│       ├── INSTALL.rst

│       ├── create.yml

│       ├── destroy.yml

│       ├── molecule.yml

│       ├── playbook.yml

│       └── tests

│           └── test_default.py

├── tasks

│   └── main.yml

└── vars

    └── main.yml

Вы чувствуете необходимость проверить N. Он смотрит на то, что вы произвели, и хмурит брови.

  • Что вы думаете? Это стандартная структура ролей, не так ли? – наивно спросишь ты
  • Да, за исключением каталога molecule со всем этим.

Хороший. Он понимает, что есть разница. Как легко объяснить тот факт, что для управления таким ограждением нужны промежуточные заклинания, чтобы и создать его, и разрушить по желанию? Вы решаете, что сейчас это не важно, вы вернетесь к этому позже.

  • Не думайте об этом пока. Давайте посмотрим, правильно ли работает наш тестовый фреймворк.

Вы концентрируетесь и накладываете заклинание на ограждение/детскую площадку.

$ molecule test

--> Test matrix

└── default

    ├── destroy

    ├── dependency

    ├── syntax

    ├── create

    ├── converge

    ├── idempotence

    ├── lint

    ├── side_effect

    ├── verify

    └── destroy

N впечатлен фейерверком. У него так много вопросов. Вы чувствуете себя вне себя от радости, но даете ему секунду, чтобы он мог собраться с мыслями.

  • Тестовая матрица? По умолчанию? И что это все за вещи?
  • Когда я говорил о тестировании кода Ansible на разных уровнях, я имел в виду именно это. Сценарий по умолчанию — это то, что выполняется, когда вы набираете «тест молекулы» на своем терминале, и он содержит все эти действия: уничтожение, зависимость, синтаксис, создание, сходимость, идемпотентность…
  • Да, я умею читать.

Снарки. Он хочет, чтобы вы знали, что он не ребенок. Он созерцает структуру корпуса. Вы ждете некоторое время, пока он снова не начнет говорить.

  • Эти… действия выполняются по порядку?
  • Да, если вы не говорите иначе.
  • Что ты имеешь в виду?

Вы решаете, что сейчас самое время спуститься в кроличью нору.

  • Так как я набрал `тест молекулы`, молекула выполняет тестовую последовательность по умолчанию, которая соответствует всем этим действиям. Мы также можем переопределить разные последовательности для разных целей, если тестовая последовательность по умолчанию не удовлетворяет нашим критериям тестирования.
  • Разные последовательности? Как пропустить все тесты? Или выполнение только… скажем… линтинга?
  • Конечно.

Вы поднимаете руку и щелкаете пальцами. Вы слышите звуки деформации, когда корпус каким-то образом смещается. Все выглядит одинаково, но все ощущается по-другому.

# 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

  test_sequence:

    - lint

verifier:

  name: testinfra

  lint:

    name: flake8

Вы делаете глубокий вдох и снова произносите заклинание.

 $  molecule test

--> Test matrix

└── default

    └── lint

--> Scenario: 'default'

--> Action: 'lint'

--> Executing Yamllint on files found in /private/tmp/test/nginx/...

Lint completed successfully.

--> Executing Flake8 on files found in /private/tmp/test/nginx/molecule/default/tests/...

Lint completed successfully.

--> Executing Ansible Lint on /private/tmp/test/nginx/molecule/default/playbook.yml...

Lint completed successfully.

Как только вы закончите, вы оглянетесь на N. Он поймет, куда вы идете.

  • Это было быстрее.
  • Да.
  • Я думаю, что мы должны добавить некоторые действия обратно.
  • Я согласен. Какие?
  • Позвольте мне увидеть первую тестовую матрицу, которую мы увидели.

Он тщательно изучает игровые заклинания.

  • Почему действие уничтожения выполняется первым?
  • Потому что все дело в том, чтобы иметь возможность проверить, работает ли ваша роль во вновь созданной инфраструктуре.
  • Да, но это займет больше времени, если мне нужно будет создавать и уничтожать контейнер каждый раз, когда я запускаю свой тест, верно?

Хороший. Он соединяет точки, видя нестандартно. Вы решаете, что теперь вам нравится N немного больше. Достаточно, чтобы продолжить игру.

  • Да, но мы займемся этим позже. Просто сконцентрируйтесь на действиях, которые мы должны выполнить, чтобы полностью проверить свою роль.
  • Хорошо, тогда нам нужно «уничтожить»… что такое «зависимость»?
  • Это позволяет вам вытягивать зависимости из галактики, если они вам нужны.
  • Ах, давай пропустим это тогда. В чем разница между «синтаксисом» и «вортом»?
  • Действие `syntax` запускает ваш плейбук, используя встроенную в Ansible опцию `–syntax-check`, тогда как `lint` проверяет ваши файлы, используя flake8, yamllint и ansible-lint.
  • Итак, `create` использует файл create.yml, который мы только что видели в каталоге molecule внутри роли, верно?
  • Да. Он создает контейнер Docker, подходящий для использования Ansible. И `destroy` использует файл destroy.yml. Они оба являются плейбуками, поэтому Ansible управляет этими действиями.
  • Ешь свою собачью еду, хорошо. Итак, `conerge` выполняет мою роль в контейнере?
  • Вот так.
  • Как насчет «побочного эффекта» и «проверки»?
  • `side-effect` позволяет вам создавать ситуации, в которых вы сможете протестировать больше вещей, например, отказоустойчивость HA. Я не думаю, что он нам понадобится в этой ситуации. А «проверить» — вот где происходит все волшебство. Вот где выполняются наши модульные тесты.
  • Модульные тесты? Какая?
  • Вы увидите через секунду.
  • Хорошо. Итак, я думаю, нам понадобятся `destroy`, `syntax`, `lint`, `create`, `converge`, `verify` и снова `destroy`. Нет, подождите. Без уничтожения в конце. Вот почему это в начале.
  • Как хочешь.

Вы замечаете, что чего-то не хватает, но решаете продолжать, чтобы воспользоваться синергией. Вы вернетесь к этому, в конце концов. Ты снова щелкаешь пальцами, меняя вложение в соответствии с его словами.

# molecule.yml

...

scenario:

  name: default

  test_sequence:

    - destroy

    - syntax

    - lint

    - create

    - converge

    - verify

Вы накладываете заклинание еще раз, используя измененную реальность ограждения. Фейерверк появляется еще раз, на этот раз немного меньше.

 $  molecule test

--> Test matrix

└── default

    ├── destroy

    ├── syntax

    ├── lint

    ├── create

    ├── converge

    └── verify

Н кажется счастливым. Он понимает, как это работает. Вы пользуетесь его мотивацией, чтобы дать ему больше знаний.

  • Это будет нашим полным тестовым сценарием. Однако мы не собираемся запускать все это каждый раз при тестировании.
  • Хм? Почему бы и нет? Что мы делаем вместо этого?

Знание – сила. Все это знают. Если вы можете быстрее приобретать знания, вы также можете быстрее приобретать силу.

  • Потому что мы хотим, чтобы наш цикл обратной связи был как можно короче и быстрее. Итак, мы собираемся «создать» наши ресурсы, «свести» их с нашей ролью Ansible и «проверить», что результаты соответствуют нашим ожиданиям. Вы можете сделать это, набрав «молекула создать», «молекула сходится» и «молекула проверить». Затем, если все заработает, мы запустим всю нашу тестовую последовательность.

Ты позволяешь этому впитаться какое-то время, надеясь, что он не сдастся. Вы смотрите за окно. Идет дождь. Тебе нравится дождь. По крайней мере, на Земле. Это лучше, чем на Венере, где кожа с твоих костей плавится, если ты не накладываешь вокруг себя защитные чары. То есть, если температура или давление не получить вас в первую очередь. Н не сдается. Он смотрит на тебя.

  • Ладно, думаю, у меня есть. Давайте создадим контейнер.

Вы снова начинаете призывать Кита, но на этот раз слышите только его песню. Он такой же громкий, как и раньше. Ограждение исчезает и снова появляется вокруг вас.

$ molecule create

--> Test matrix

└── default

    └── create

--> Scenario: 'default'

--> Action: 'create'

Смотришь на N и думаешь о следующих шагах. Это покажется ему знакомым.

  • Запустим наши тесты. Они расположены в файле test_default.py в каталоге molecule.

Вы громко хлопаете в ладоши. Когда вы разделяете их, из них исходит поток блестящего зеленого света.

 $molecule verify

--> Test matrix

└── default

    └── verify

--> Scenario: 'default'

--> Action: 'verify'

--> Executing Testinfra tests found in /private/tmp/test/nginx/molecule/default/tests/...

Verifier completed successfully.

Все в порядке, пока. Вернемся к Н.

  • Каковы три этапа разработки через тестирование?
  • Красный, зеленый, рефакторинг.

L сделал свою работу правильно.

  • Превосходно. Что вы пытаетесь достичь?
  • Я хочу открыть свое веб-приложение с помощью nginx.
  • Что вам нужно для этого?
  • Ну, мне нужно установить nginx.
  • Тогда переходим к красному.

Вы создаёте сгусток энергии руками и используете его, чтобы создать правило в реальности вольера:

import os

 

import testinfra.utils.ansible_runner

 

testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner(

    os.environ['MOLECULE_INVENTORY_FILE']).get_hosts('all')

 

def test_nginx_is_installed(host):

    # Given

    nginx = host.package('nginx')

 

    # Then

    assert nginx.is_installed
  • Это кажется знакомым.
  • Это потому, что это так.

Вы хлопаете в ладоши, как минуту назад. Тем не менее, на этот раз появляется красный блестящий свет, когда вы их разделяете.

     $ molecule verify

 

    =================================== FAILURES ===================================

    _________________ test_nginx_is_installed[ansible://instance] __________________

 

    host = <testinfra.host.Host object at 0x10a9a7350>

 

        def test_nginx_is_installed(host):

            # Given

            nginx = host.package('nginx')

 

            # Then

    >       assert nginx.is_installed

    E       assert False

    E        +  where False = <package nginx>.is_installed

 

    tests/test_default.py:14: AssertionError
  • Видеть? Это красный. Были хороши. Что дальше?
  • Зеленый. Итак, теперь мы добавим задачу, которая нам нужна для установки сервера.

Вы закрываете глаза и концентрируетесь. Структура заклинания N была воссоздана с земли.

---

# tasks file for nginx

 

- name: Install nginx

  yum:

    name: nginx

    state: present

Возвращается на круги своя. Теперь это то же самое заклинание, которое было у N, когда он просил вас о помощи. Вы произносите заклинание, заранее зная, что произойдет.

 $molecule converge

--> Test matrix

 

└── default

    ├── create

    └── converge

--> Scenario: 'default'

--> Action: 'create'

Skipping, instances already created.

--> Scenario: 'default'

--> Action: 'converge'

 

    TASK [nginx : Install nginx] ***************************************************

    fatal: [instance]: FAILED! => {"changed": false, "failed": true, "msg": "No package matching 'nginx' found available, installed or updated", "rc": 126, "results": ["No package matching 'nginx' found available, installed or updated"]}

Никаких фейерверков. Н кажется обескураженным. Вы думаете о том, чтобы дать ему небольшой толчок. Он это заслужил. Дело не в самой магии, а в контексте. Он не получает исходники для своего портала из правильного индекса. Ему нужен кодекс Эпеля.

  • По крайней мере, теперь проще проверить.
  • Не грусти. Пакет nginx содержится в репозитории epel-release.
  • Какая? Ты мог бы сказать мне это с самого начала, не так ли?
  • Если бы я это сделал, мы бы не говорили о тестировании инфраструктуры, не так ли?

Он улыбается. Он входит в игру, чувствует настрой. Ему это нравится.

  • Давайте попробуем еще раз.

Вы снова изменяете структуру заклинания, указывая, что вы хотите, чтобы ваш портал был создан в соответствии с инструкциями кодекса Эпель.

---

# tasks file for nginx

 

- name: Install epel release

  yum:

    name: epel-release

    state: present

 

- name: Install nginx

  yum:

    name: nginx

    state: present

Вы произносите заклинание с новой структурой.

$ molecule converge

--> Test matrix

 

└── default

    ├── create

    └── converge

--> Scenario: 'default'

--> Action: 'create'

Skipping, instances already created.

--> Scenario: 'default'

--> Action: 'converge'

…

    PLAY RECAP *********************************************************************

    instance                   : ok=3    changed=2    unreachable=0    failed=0

Заклинание работает, или, по крайней мере, кажется, что оно работает. Фейерверки заставляют воздух вибрировать внутри ограждения. Н кажется счастливым. У него еще нет правильных рефлексов. Можешь ли ты винить его? Это его первое существование, и он только начинает играть с магией. Он не поймет, что его портал еще не активен, он просто ослеплен фейерверком. Пришло время для нового суда.

  • Превосходно! Думаю, мы закончили!
  • Ага. Вы пробовали?
  • Ок, посмотрим. Могу ли я как-то войти в контейнер?
  • Да, “молекулярный логин”.
[root@instance /]# curl localhost

curl: (7) Failed to connect to ::1: Cannot assign requested address
  • Хм. Но… ах, точно! Я так и не запустил службу.
  • Будьте моим гостем, добавьте недостающий код, необходимый для этого.

Он собирается изменить структуру заклинания, когда внезапно останавливается. Он смотрит на тебя.

  • Нет. Это неправильный путь. Разве я не могу сначала проверить это?

Он прошел испытание. Он может стать хорошим учеником. Вы начинаете понимать, почему L вообще начал преподавать.

  • Конечно, просто добавьте еще один тест.
  • Хорошо…
def test_nginx_is_running(host):

    # Given

    nginx = host.service('nginx')

 

    # Then

    assert nginx.is_running
  • Кстати, я люблю писать тесты на Python. Это намного проще, чем в Java.
  • Не позволяй L услышать, как ты это говоришь. Попытайся.

Вы знаете, что Кит не позволит N уйти с рук, но вы хотите увидеть, как он попытается. Неудача — это часть процесса обучения. Это едва ли не важнее успеха. Это единственный способ научиться вставать и продолжать попытки.

$ molecule verify

    E       AssertionError: Unexpected exit code 1 for CommandResult(command=u'systemctl is-active nginx', exit_status=1, stdout=u'', stderr=u'Failed to get D-Bus connection: Operation not permitted')

N хлопает в ладоши, как вы делали раньше, но света не появляется, когда он разводит руки. Он выглядит как ты, растерянный.

  • Хм, это не похоже на хороший красный цвет. Это не ошибка утверждения.
  • Нет, это не так. Testinfra (ваша библиотека модульного тестирования Python) использует Systemd, Upstart или SysV для проверки работы служб. Контейнеры Docker не имеют системы инициализации. У них есть Тини, но это работает по-другому.
  • Поэтому мне нужно изменить изображение, которое я использую. Есть ли образ Centos, включающий Systemd?
  • Да, это называется centos/systemd.
  • Иди разберись. Где я могу изменить это?
  • В файле molecule.yml. Вам нужно будет указать командную инструкцию контейнера, чтобы запустить Systemd, потому что Molecule переопределяет ее по умолчанию. Вам также понадобится привилегированный контейнер, так как Systemd требует CAP_SYS_ADMIN, а непривилегированные контейнеры не имеют такой возможности.
  • Хм, я не совсем все понял, но, думаю, завтра я снова спрошу тебя об этом. Позвольте мне повторить конфигурацию.
platforms:

  - name: instance

    image: centos/systemd

    privileged: True

    command: /usr/sbin/init

Кит обязательно примет это предложение. Вы знаете, что он больше не отклонит ваш вызов. N снова проверяет заклинание.

      $ molecule test

    =================================== FAILURES ===================================

    ____________ test_nginx_is_running_and_enabled[ansible://instance] _____________

 

    host = <testinfra.host.Host object at 0x110adff50>

 

        def test_nginx_is_running(host):

            # Given

            nginx = host.service('nginx')

 

            # Then

    >       assert nginx.is_running

    E       assert False

    E        +  where False = <service nginx>.is_running

 

    tests/test_default.py:20: AssertionError

 

    -- Docs: http://doc.pytest.org/en/latest/warnings.html

    ================ 1 failed, 1 passed, 1 warnings in 6.74 seconds ================
  • Готово, мы вернулись к красному цвету. Теперь я внесу изменения, чтобы запустить службу.

Вы улыбаетесь, когда видите N craft. Он еще не готов, но идет полным ходом. Вы чувствуете гордость за него.

  • Хорошо, я закончил. Что вы думаете?

Он показывает вам структуру своего заклинания.

---

# tasks file for nginx

 

- name: Install epel release

  yum:

    name: epel-release

    state: present

 

- name: Install nginx

  yum:

    name: nginx

    state: present

 

- name: Start nginx

  command: systemctl start nginx

Вся ваша ранее обретенная гордость оборачивается разочарованием. Это нелепо. Это не может быть серьезно. Он не может быть серьезным. Он должен понимать, что вы не можете бесконечно создавать порталы. Результаты могут быть катастрофическими.

Но потом… ты созерцаешь его. Ты понимаешь, что он устал. Идемпотентность также трудно понять. Бенджамин Пирс преподавал его более 50 лет в Гарварде. Ты помнишь, как Мерлин впервые привел тебя в такое ограждение. Одно только воспоминание об этом заставляет вас чувствовать мурашки по коже на затылке.

Вы решаете, что позволите ему продолжать, только в образовательных целях. Он поймет проблему со своим предложением.

  • Почему бы тебе не попробовать?

Он произносит заклинание сам.

$ molecule converge

--> Test matrix

└── default

    ├── create

    └── converge

--> Scenario: 'default'

--> Action: 'create'

Skipping, instances already created.

--> Scenario: 'default'

--> Action: 'converge'

 

    PLAY RECAP *********************************************************************

    instance                   : ok=4    changed=1    unreachable=0    failed=0

Сразу после фейерверка прямо перед вами обоими появляется зеленый портал. Кажется, это работает.

  • Большой. Я сейчас проверю.
 $ molecule verify

--> Test matrix

 

└── default

    └── verify

--> Scenario: 'default'

--> Action: 'verify'

--> Executing Testinfra tests found in /Users/sebiwi/stuff/test/nginx/molecule/default/tests/...

    ============================= test session starts ==============================

    ===================== 2 passed, 1 warnings in 6.70 seconds =====================

Verifier completed successfully.

Зеленый свет повсюду.

  • Идеальный! Зеленый!

Или это? Вы решаете дать ему небольшой толчок в правильном направлении.

  • Попробуйте запустить весь набор тестов.
  • Хорошо
 $molecule test

--> Test matrix

└── default

    ├── destroy

    ├── syntax

    ├── lint

    ├── create

    ├── converge

    └── verify

 

---> Scenario: 'default'

--> Action: 'lint'

--> Executing Yamllint on files found in /Users/sebiwi/stuff/test/nginx/...

Lint completed successfully.

--> Executing Flake8 on files found in /Users/sebiwi/stuff/test/nginx/molecule/default/tests/...

Lint completed successfully.

--> Executing Ansible Lint on /Users/sebiwi/stuff/test/nginx/molecule/default/playbook.yml...

    [ANSIBLE0012] Commands should not change things if nothing needs doing

    /Users/sebiwi/stuff/test/nginx/tasks/main.yml:14

    Task/Handler: Start nginx

Никаких фейерверков, никаких огней.

  • Какая? О, это просто ansible-lint, он часто не работает для таких вещей, я просто отключу его для этой задачи.

Вы недоверчиво смотрите, как N «исправляет» структуру заклинания.

---

# tasks file for nginx

 

- name: Install epel release

  yum:

    name: epel-release

    state: present

 

- name: Install nginx

  yum:

    name: nginx

    state: present

 

- name: Start nginx

  command: systemctl start nginx

  tags:

    - skip_ansible_lint

Он заканчивает модификации и снова произносит заклинание.

 $  molecule test

--> Test matrix

 

└── default

    ├── destroy

    ├── syntax

    ├── lint

    ├── create

    ├── converge

    └── verify

 

All steps completed successfully.

Он смотрит на тебя с гордостью. Вы встревожены. Он наивен и безрассуден. Вы понимаете, что пришло время разобраться с ситуацией.

  • Мы теперь зеленые. Думаю, мы закончили.
  • Не совсем. Раньше ansible-lint говорил, что вы что-то меняете, даже если ничего не нужно делать.
  • Да, это потому, что я запускал службу.
  • Да, но поскольку вы не используете модуль Ansible, вы выполняете действие каждый раз, когда запускаете свой плейбук.
  • Я думал, что Ansible идемпотентный.
  • Не совсем. Вы можете сделать идемпотентный код с помощью Ansible. Это не означает, что все, что вы с ним делаете, будет идемпотентным. Некоторые вещи не должны быть идемпотентными.
  • Как что?
  • Например, развертывание приложений. Вы развертываете новую версию приложения. Он предназначен для того, чтобы что-то изменить.
  • Я понимаю. Но эта роль должна быть идемпотентной.
  • Безусловно. Вы можете добавить новое действие в набор тестов сценария по умолчанию, чтобы проверить идемпотентность.

Вы закрываете глаза, когда снова меняете реальность ограждения вокруг себя.

scenario:

  name: default

  test_sequence:

    - destroy

    - syntax

    - lint

    - create

    - converge

    - idempotence

    - verify

Вы снова произносите заклинание.

$  molecule test

--> Test matrix

 

└── default

    ├── destroy

    ├── syntax

    ├── lint

    ├── create

    ├── converge

    ├── idempotence

    └── verify

 

--> Scenario: 'default'

--> Action: 'idempotence'

ERROR: Idempotence test failed because of the following tasks:

* [instance] => nginx : Start nginx

Н смотрит на тебя.

  • Так что на самом деле мы еще не были на зеленом поле.
  • Мы не были. Идемпотентность — это поведение нашего кода. Он также нуждается в тестировании.
  • Хотя я могу это исправить.
  • Покажите мне.

Вы передаете управление ограждением N. Он модифицирует структуру заклинания.

---

# tasks file for nginx

 

- name: Install epel release

  yum:

    name: epel-release

    state: present

 

- name: Install nginx

  yum:

    name: nginx

    state: present

 

- name: Start nginx

  service:

    name: nginx

    state: started

Вы улыбаетесь с облегчением.

  • Намного лучше. Попытайся.
  • Немедленно.
 $  molecule test

--> Test matrix

 

└── default

    ├── destroy

    ├── syntax

    ├── lint

    ├── create

    ├── converge

    ├── idempotence

    └── verify

 

All steps completed successfully.
  • А теперь мы зеленые.
  • Да!
  • Давайте продолжим наш подход TDD. Красный, зеленый и…?
  • Рефакторинг! Видите ли вы какие-либо возможные улучшения в этом коде?
  • Ну, вы могли бы использовать свою задачу «Запустить nginx» в качестве обработчика, который запускается при установке nginx, не так ли?
  • Да я мог.
---

# tasks file for nginx

 

- name: Install epel release

  yum:

    name: epel-release

    state: present

 

- name: Install nginx

  yum:

    name: nginx

    state: present

  notify: Start nginx

 

---

# handlers file for nginx

 

- name: Start nginx

  service:

    name: nginx

    state: started

 

 $  molecule test

--> Test matrix

 

└── default

    ├── destroy

    ├── syntax

    ├── lint

    ├── create

    ├── converge

    ├── idempotence

    └── verify

 

All steps completed successfully.

Н выглядит эйфоричным. Он применяет свой заслуженный военный опыт в совершенно другой ситуации, и это работает как волшебство. В вашем предложении есть небольшая загвоздка, но вы решаете, что позволите ему обнаружить это самому.

  • Вау, здорово получилось! Что-то еще?
  • У вас может быть только одна задача «ням» и перебор пакетов, которые вы хотите установить.
  • Хороший звонок.
---

# tasks file for nginx

 

- name: Install epel-release and nginx

  yum:

    name: "{{ item }}"

    state: present

  with_items:

    - epel-release

    - nginx

  notify:

    - Start nginx

 

$ molecule test

...

--> Scenario: 'default'

--> Action: 'converge'

 

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

 

    TASK [Gathering Facts] *********************************************************

    ok: [instance]

 

    TASK [nginx : Install epel-release and nginx] **********************************

    failed: [instance] (item=[u'epel-release', u'nginx']) => {"changed": false, "failed": true, "item": ["epel-release", "nginx"], "msg": "No package matching 'nginx' found available, installed or updated", "rc": 126, "results": ["No package matching 'nginx' found available, installed or updated"]}

 

    PLAY RECAP *********************************************************************

    instance                   : ok=1    changed=0    unreachable=0    failed=1
  • Хм. Думаю, мне нужно установить epel-release, прежде чем я смогу установить nginx. Это не сработает, если я сделаю и то, и другое одновременно.
  • Истинный.
  • Без тестов я бы этого не понял. Я бы сделал свой рефакторинг, и он бы заработал, так как epel-release уже был бы установлен на моей машине при попытке установить его вместе с nginx в одном задании.
  • Верно. Кроме того, с текущей структурой кода вы запускаете nginx не только после установки nginx, но и после установки epel-release.
  • Верно. Я не должен. Это был тест, не так ли?
  • Может быть.

N возвращает структуру заклинания в прежнюю форму. Вы чувствуете себя расслабленным. Вы всегда чувствуете себя так после создания чего-то впечатляющего. Вы чувствуете то же самое, что чувствовали, когда строили пирамиды, только в меньшей степени. Однако на этот раз настоящим создателем является N. Вы выступали только в качестве катализатора. Знания всегда были внутри N, ему просто нужно было услышать правильные вопросы.

N выглядит усталым, но он хочет продолжать.

  • Мы только что прошли полный цикл Red/Green/Refactor. Сладкий!
  • Вы хотите сделать еще один?
  • Абсолютно!
  • Что произойдет, если ваша виртуальная машина будет перезагружена?
  • Ничего, nginx все равно будет установлен.
  • Будет ли он работать?
  • О, нет. Это не будет. Угу.
  • Вы должны включить его тогда. Ты знаешь что делать.

N создает новое правило в реальности ограждения.

def test_nginx_is_enabled(host):

    # Given

    nginx = host.service('nginx')

 

    # Then

    assert nginx.is_enabled

Он хлопает в ладоши. Красный свет появляется повсюду.

$ molecule verify

--> Test matrix

└── default

    └── verify

--> Scenario: 'default'

--> Action: 'verify'

--> Executing Testinfra tests found in /Users/sebiwi/stuff/test/nginx/molecule/default/tests/…

 

    =================================== FAILURES ===================================

    __________________ test_nginx_is_enabled[ansible://instance] ___________________

 

    host = <testinfra.host.Host object at 0x103b20fd0>

 

       def test_nginx_is_enabled(host):
            # Given
            nginx = host.service('nginx')

            # Then
    >       assert nginx.is_enabled
    E       assert False
    E        +  where False = <service nginx>.is_enabled

    tests/test_default.py:28: AssertionError
    -- Docs: http://doc.pytest.org/en/latest/warnings.html
    ================ 1 failed, 2 passed, 1 warnings in 7.29 seconds ================
  • Красный.
  • Иди на Зеленого.

N изменяет структуру заклинания, чтобы она соответствовала ограничениям новой реальности. Теперь у него ясная голова, он знает, чего не хватает.

---

# handlers file for nginx

 

- name: Start nginx

  service:

    name: nginx

    state: started

    enabled: yes

 

 $  molecule test

--> Test matrix

 

└── default

    ├── destroy

    ├── syntax

    ├── lint

    ├── create

    ├── converge

    ├── idempotence

    └── verify

 

All steps completed successfully.

Зеленый портал появляется перед вами обоими. Вы знаете, что это устойчиво, вы оба тщательно его протестировали. Это настоящее заклинание волшебника. Люди сказали бы, что это один из ваших собственных. Н смотрит на тебя и улыбается.

Статья является переводом blog.octo.com

You may also like

Leave a Comment