Ansible 2.0 b2: обзор новшеств

PR-1507

О системе управления конфигурациями 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 [] ******************************************************

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 [] ******************************************************  
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’ и другие теперь могут быть присвоены блокам и ролям, и их будут наследовать все задания, включённые в эти блоки и роли:

- 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

Заключение

Нововведения, появившиеся во второй версии, показывают, что в целом Ansible развивается в правильном направлении. Мы будем с интересом следить за его дальнейшим развитием.
А вы уже пробовали новую версию Ansible? Если пробовали, приглашаем поделиться впечатлениями в комментариях.