Как выйти из Ansible playbook без ошибок при условии

Я хочу выйти без ошибки (я знаю о assert и fail), когда я отвечаю определенному условию. Следующий код завершается с ошибкой:

  tasks:

    - name: Check if there is something to upgrade
      shell: if apt-get --dry-run upgrade | grep -q "0 upgraded, 0 newly installed, 0 to remove and 0 not upgraded"; then echo "no"; else echo "yes"; fi
      register: upgrading

    - name: Exit if nothing to upgrade
      fail: msg="Nothing to upgrade"
      when: upgrading.stdout == "no"

Ответ 1

В Ansible 2.2 вы можете использовать end_play с модулем meta :

- meta: end_play

Вы также можете указать when для условного завершения игры:

- meta: end_play
  when: upgrading.stdout == "no"

Тем не менее, обратите внимание, что задача не указана в выходных данных ansible-playbook, независимо от того, заканчивается ли воспроизведение на самом деле. Кроме того, задача не учитывается в резюме. Таким образом, вы можете сделать что-то вроде:

- block:
    - name: "end play if nothing to upgrade"
      debug:
        msg: "nothing to upgrade, ending play"

    - meta: end_play
  when: upgrading.stdout == "no"

который объявит об окончании воспроизведения непосредственно перед его завершением, только при выполнении условия. Если условие не выполнено, вы увидите, что задание с именем end play if nothing to upgrade пропущено надлежащим образом, что предоставит пользователю дополнительную информацию о том, почему воспроизведение заканчивается или нет.

Конечно, это только завершит текущее воспроизведение, а не все остальные воспроизведения в списке воспроизведения.


ОБНОВЛЕНИЕ 20 июня 2019 г.:

Как уже упоминалось в комментариях, end_play заканчивает игру для всех хостов. В Ansible 2.8 end_host был добавлен в meta:

end_host (добавлен в Ansible 2.8) - это вариант end_play для каждого хоста. Заставляет игру заканчиваться для текущего хоста, не прерывая его.

Ответ 2

Лучшим и более логичным способом его решения может быть обратное и вместо того, чтобы потерпеть неудачу, если нет ничего, чтобы обновить (это отдельный шаг, который делает только это), вы могли бы добавить все свои задачи обновления с условной зависимостью на переменной upgrade. По существу просто добавьте

when: upgrading.changed

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

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

Ответ 3

Давайте используем то, что предложил Tymoteusz для ролей:

Разделите свою игру на две roles, где первая роль будет выполнять проверку (и устанавливает некоторый результат проверки переменной), а вторая будет действовать по результатам проверки.

Я создал aaa.yaml с этим контентом:

---
- hosts: all
  remote_user: root
  roles:
    - check
    - { role: doit, when: "check.stdout == '0'" }
...

тогда роль check в roles/check/tasks/main.yaml:

---
- name: "Check if we should continue"
  shell:
    echo $(( $RANDOM % 2 ))
  register: check
- debug:
    var: check.stdout
...

а затем роль doit в roles/doit/tasks/main.yaml:

---
- name: "Do it only on systems where check returned 0"
  command:
    date
...

И это был результат:

TASK [check : Check if we should continue] *************************************
Thursday 06 October 2016  21:49:49 +0200 (0:00:09.800)       0:00:09.832 ****** 
changed: [capsule.example.com]
changed: [monitoring.example.com]
changed: [satellite.example.com]
changed: [docker.example.com]

TASK [check : debug] ***********************************************************
Thursday 06 October 2016  21:49:55 +0200 (0:00:05.171)       0:00:15.004 ****** 
ok: [monitoring.example.com] => {
    "check.stdout": "0"
}
ok: [satellite.example.com] => {
    "check.stdout": "1"
}
ok: [capsule.example.com] => {
    "check.stdout": "0"
}
ok: [docker.example.com] => {
    "check.stdout": "0"
}

TASK [doit : Do it only on systems where check returned 0] *********************
Thursday 06 October 2016  21:49:55 +0200 (0:00:00.072)       0:00:15.076 ****** 
skipping: [satellite.example.com]
changed: [capsule.example.com]
changed: [docker.example.com]
changed: [monitoring.example.com]

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

Ответ 4

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

Сначала установите факт:

- name: Determine current version
  become: yes
  slurp:
    src: /opt/app/CHECKSUM
  register: version_check
  ignore_errors: yes

- set_fact:
  is_update_needed: "{{ ( version_check['checksum'] | b64decode != installer_file.stat.checksum)  }}"

Теперь включите ту часть, которая должна выполняться только при этом условии:

# update-app.yml can be placed in the same role folder
- import_tasks: update-app.yml
  when: is_update_needed

Ответ 5

Небольшая заметка: meta: end_play заканчивает только игру, а не книгу. Итак, эта пьеса:

---
- name: 1st play with end play
  hosts: localhost
  connection: local
  gather_facts: no
  tasks:
    - name: I'll always be printed
      debug:
        msg: next task terminates first play

    - name: Ending the 1st play now
      meta: end_play

    - name: I want to be printed!
      debug:
        msg: However I'm unreachable so this message won't appear in the output

- name: 2nd play
  hosts: localhost
  connection: local
  gather_facts: no
  tasks:
    - name: I will also be printed always
      debug:
        msg: "meta: end_play ended just the 1st play. This is 2nd one."

выдаст такой вывод:

$ ansible-playbook -i localhost, playbooks/end_play.yml 

PLAY [1st play with end play] **************************************************

TASK [I'll always be printed] **************************************************
ok: [localhost] => {
    "msg": "next task terminates first play"
}

PLAY [2nd play] ****************************************************************

TASK [I will also be printed always] *******************************************
ok: [localhost] => {
    "msg": "meta: end_play ended just the 1st play. This is 2nd one."
}

PLAY RECAP *********************************************************************
localhost                  : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0