О системе управления конфигурациями Ansible мы уже писали два года назад. Мы активно её используем в собственной практике и внимательно следим за всеми изменениями и обновлениями.
Конечно же, мы не могли оставить без внимания следующую новость: вышла в свет вторая бета-версия Ansible v2.0. Черновой вариант Ansible v2.0 был размещён на GitHub уже давно, а теперь наконец-то появился более или менее стабильный бета-релиз.
В этой статье мы расскажем о наиболее значимых нововведениях во второй версии.
Что нового
Никаких радикальных изменений во второй версии нет — об этом уже давно говорил один из разработчиков Ansible Джеймс Каммарата в докладе, прочитанном в этом году на конференции AnsibleFest в Нью-Йорке.
Появилось много новых модулей, а в некоторые из старых модулей были внесены изменения. Разработчики гарантируют стопроцентную совместимость со сценариями (Playbooks) для предыдущих версий.
Однако изменения затронули внутренние API, и тем, кто пользуется «самописными» плагинами, придётся эти плагины скорректировать. Разработчики уверяют (см. доклад по ссылке выше), что переход на новую версию должен произойти без особых проблем.
Подробный список всех изменений опубликован здесь.
Сообщения об ошибках
Система оповещения об ошибках в первой версии была довольно неудобной. Вот пример ошибки в имени модуля:
- hosts: all
gather_facts: no
tasks:
- debug: msg="hi"
- not_a_syntax_error_just_invalid_module: msg="error"
- debug: msg="bye"
При обнаружении этой ошибки первая версия выдавала весьма лаконичное сообщение:
ERROR: not_a_syntax_error_just_invalid_module is not a legal parameter in an Ansible
task or handler
Вторая же версия выдаёт гораздо более информативное сообщение и указывает место где была обнаружена ошибка:
ERROR! no action detected in task
The error appears to have been in '... .yml': line 5, column 44, but may
be elsewhere in the file depending on the exact syntax problem.
The offending line appears to be:
- debug: msg="hi"
- not_a_syntax_error_just_invalid_module: msg="error"
^ here
Это делает процесс работы с Ansible более удобным, а во многих случаях ещё и экономит время.
Блоки
Ещё одной интересной новацией являются блоки. Во многих языках программирования для обработки исключений используется конструкция try/except/finally. Похожая конструкция появилась и в Ansible:
- hosts: localhost
connection: local
gather_facts: no
tasks:
- block:
- command: /bin/false
- debug: msg="you shouldn't see me"
rescue:
- debug: msg="this is the rescue"
- command: /bin/false
- debug: msg="you shouldn't see this either"
always:
- debug: msg="this is the always block, it will always be seen"
Вывод при выполнении приведённого сценария будет выглядеть примерно так:
PLAY [<no name specified>] ******************************************************
TASK [command] ******************************************************************
fatal: [localhost]: FAILED! => ...
NO MORE HOSTS LEFT **************************************************************
CLEANUP TASK [debug msg=this is the rescue] *************************************
ok: [localhost] => {
"msg": "this is the rescue",
"changed": false
}
CLEANUP TASK [command] **********************************************************
fatal: [localhost]: FAILED! => ...
CLEANUP TASK [debug msg=this is the always block, it will always be seen] *******
ok: [localhost] => {
"msg": "this is the always block, it will always be seen",
"changed": false
}
Если при выполнении блока случится ошибка, то будут выполнены действия, указанные в секциях rescue и always. После этого выполнение сценария будет остановлено.
Стратегии
В новой версии Ansible можно выбирать, в какой последовательности будут выполняться содержащиеся в сценарии задания. Возможные варианты выполнения называются стратегиями (strategy). Существует два вида стратегий:
- линейная (linear)— работает так же, как и в предыдущей версии: выполнение нового задания начнётся после того, как текущее задание будет выполнено на всех хостах;
- произвольная (free) — на каждом хосте задание выполняется как можно быстрее и без учёта того, что происходит на других хостах.
Поясним сказанное конкретным примером и рассмотрим следующий фрагмент сценария:
- hosts: all
gather_facts: no
strategy: free
tasks:
- pause: seconds={{ 10 |random}}
- debug: msg="msg_1"
- pause: seconds={{ 10 |random}}
- debug: msg="msg_2"
- pause: seconds={{ 10 |random}}
- debug: msg="msg_3"
Если бы мы выбрали традиционную (линейную) стратегию, то при выполнении этого сценария увидели бы такой вывод (приводим в несколько сокращённом варианте):
TASK [debug msg=msg_1] **********************************************************
ok: [host3] => { "msg": "msg_1", "changed": false}
ok: [host4] => { "msg": "msg_1", "changed": false}
ok: [host2] => { "msg": "msg_1", "changed": false}
ok: [host1] => { "msg": "msg_1", "changed": false}
TASK [debug msg=msg_2] **********************************************************
ok: [host4] => {"msg": "msg_2", "changed": false}
ok: [host1] => {"msg": "msg_2", "changed": false}
ok: [host2] => {"msg": "msg_2", "changed": false}
ok: [host3] => {"msg": "msg_2", "changed": false}
TASK [debug msg=msg_3] **********************************************************
ok: [host1] => {"msg": "msg_3", "changed": false}
ok: [host2] => {"msg": "msg_3", "changed": false}
ok: [host3] => {"msg": "msg_3", "changed": false}
ok: [host4] => {"msg": "msg_3", "changed": false}
Задания выполняются в случайном порядке, но при этом выполнение заданий из группы msg_3 не будет начато до тех пор, пока не завершится выполнение заданий из группы msg_2.
Если же выбрана произвольная стратегия, вывод будет совсем другим:
PLAY [<no name specified>] ******************************************************
ok: [host3] => {"msg": "msg_1", "changed": false}
ok: [host4] => {"msg": "msg_1", "changed": false}
ok: [host2] => {"msg": "msg_1", "changed": false}
ok: [host4] => {"msg": "msg_2", "changed": false}
ok: [host2] => {"msg": "msg_2", "changed": false}
ok: [host4] => {"msg": "msg_3", "changed": false}
ok: [host1] => {"msg": "msg_1", "changed": false}
ok: [host2] => {"msg": "msg_3", "changed": false}
ok: [host3] => {"msg": "msg_2", "changed": false}
ok: [host3] => {"msg": "msg_3", "changed": false}
ok: [host1] => {"msg": "msg_2", "changed": false}
ok: [host1] => {"msg": "msg_3", "changed": false}
Как видим, все действия на хостах осуществляются в произвольном режиме. Благодаря этому нововведению многие сценарии будут выполняться гораздо быстрее.
В случае необходимости пользователь может определить и собственную стратегию — достаточно лишь написать соответствующий плагин. Правда, API для плагинов пока что работает нестабильно, да и документация оставляет желать лучшего.
Include + with
Очень часто новое — это хорошо забытое старое. В более ранних версиях Ansible уже были конструкции вида:
main.yml:
- hosts: localhost
connection: local
gather_facts: no
tasks:
- include: foo.yml some_var={{ item }}
with_items:
- a
- b
- c
foo.yml:
- debug: msg={{some_var}}
В версии 1.5 и всех последующих они уже были исключены. Во второй версии они вернулись.
Наследование блоков и ролей
Значения ‘become’ (пришло на замену ‘sudo’ c версии 1.9) и другие теперь могут быть присвоены блокам и ролям, и их будут наследовать все задания, включённые в эти блоки и роли:
- hosts: all
gather_facts: false
remote_user: testing
- roles: {role: foo , become_user: root}
tasks:
block:
- command: whoami
- command: do/something/privileged
- stat = path=/root/ .ssh/id_rsa
become_user: root
Как попробовать
Новая версия уже доступна для скачивания здесь. Кроме того, её можно собрать из исходного кода, размещённого на GitHub:
$ git clone https://github.com/ansible/ansible.git
$ cd ansible
$ git checkout v2.0.0-0.4.beta2
$ git submodule update --init
$ . hacking/env-setup
При желании можно собрать deb-пакет:
$ make deb
Или rpm-пакет:
$ make rpm
Заключение
Нововведения, появившиеся во второй версии, показывают, что в целом Ansible развивается в правильном направлении. Мы будем с интересом следить за его дальнейшим развитием.
А вы уже пробовали новую версию Ansible? Если пробовали, приглашаем поделиться впечатлениями в комментариях. Если мы забыли рассказать о каком-либо значимом нововведении — напишите нам, и мы обязательно добавим его в обзор. Также призываем сообщать обо всех замеченных ошибках разработчикам на Github, используя этот шаблон.
Читателей, не имеющих возможности оставлять комментарии здесь, приглашаем в наш блог.
Комментарии (13)
Kanedias
05.11.2015 22:41В свете недавних новостей вопрос к вам как в некоторой мере вовлечённому человеку: как вы относитесь к покупке Ansible компанией Red Hat? Как по вашему мнению это скажется на перспективах?
clickfreak
06.11.2015 02:17+3Скорее положительно. Минимум:
- у Федоры вся инфраструктура Ансиблом разворачивается, а это их тестовый полигон.
- Они им Openshift разворачивают
Так что точно не закапают :D Будут дальше улучшать интеграцию с Fedora/RHEL-based утилитами.
isden
06.11.2015 10:17> Стратегии
А есть же вот такое уже. Если кроме linear/free ничего больше нет, то зачем оно?clickfreak
06.11.2015 14:29+3async относится к выполнению таска, т.е. запустили таск и пошли дальше, причём сделали это на всей группе хостов синхронно.
Стратегии определяют последовательность выполнения задач в плее. Ранее, на группе хостов задачи всегда выполнялись синхронно, хост управления дожидался когда каждая выполнится на всех узлах прежде чем приступить к следующей. Теперь можно не ждать выполнения этих же тасков на всей группе хостов. Другими словами, это контроль асинхронности выполнения тасков относительно хостов.
Т.к. стратегии реализованы в виде плагинов, то можно реализовать свою специфичную логику (два важных таска — синхронно, следующие — асинхронно). Более подробно реализацию можно посмотреть в коде: github.com/ansible/ansible/blob/devel/lib/ansible/plugins/strategy
1it
А с тегами там уже все хорошо, не знаете?
clickfreak
Я пока проблем с тегами не замечал, а что с ними было не так?
1it
Ну вот например, такая конструкция в контексте плейбука или роли:
— roles: {role: foo, tags: [«one», «two»]}
не работает.
Было много обсуждений, но авторы вроде как ссылались, что исправление будет в версии 2.0.
clickfreak
проверил в 2.0 — работает, как со --skip-tags=, так и просто c --tags=
Честно говоря, ранее проблем с этим не замечал. В какой версии проявлялась проблема?
1it
Все верно, если указывать тег в консоли, то работает. Не работает есть прописывать в плейбуке и в зависимостях роли как я писал выше.
clickfreak
В плее в таком виде — работает:
Приведите, пожалуйста, более полный пример и где возникает ошибка. Особенно интересует часть про «в зависимостях роли».
1it
ansible 1.9.4
Не работает:
С плейбуками пробовал как в документации указано:
Так тоже не работало.
Ваш пример выше на какой версии работает?
clickfreak
В случае плейбуков мы, возможно, ожидаем разное поведение: это работает как отметка тегами сам факт выполнения роли, в то время как вам бы хотелось только выполнение конкретных тегов внутри роли. Верно?
Как отметка факта выполнения роли — работает уже давно, иначе бы у меня всё сразу поломалось :) в 2.0 тоже работает. Однако действительно есть неоднозначности и расхождения:
Что касается указания зависимостей в meta для выполнения конкретных тасков требуемых ролей: не работает ни в одной из версий.
Должен признать что раньше с тегами у нас не возникало никаких проблем, но, похоже, нужно копнуть эту тему поглубже и идти бодаться в issues :)
1it
Да, я декомпозирую роль инклудами и помечаю инклуды тегами, чтобы например не выполнять какой-нибудь кусок роли в определенных случаях.
Можно конечно использовать переменные, но мне кажется удобней настраивать логику выполнения тегами (субъективно).