Прерывание ansible playbook, если хост недоступен

Мне интересно, есть ли какой-нибудь достойный способ потребовать, чтобы все хосты, которые должен выполнять набор задач, были действительно доступны?

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


person Pierre Andersson    schedule 19.09.2014    source источник


Ответы (4)


Я собирался опубликовать вопрос, когда я увидел это. Ответ, предложенный Дунканом, не работает, по крайней мере, в моем случае. хост недоступен. Все мои плейбуки указывают max_fail_percentage равным 0.

Но ansible с радостью выполнит все задачи на хостах, до которых он сможет добраться, и выполнит действие. Чего я действительно хотел, так это того, что если какой-либо из хостов недоступен, не выполняйте никаких задач.

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

Начиная с первого шага в рамках запуска плейбуков, ansible собирает факты для всех хостов. И в случае, когда хост недоступен, он не сможет. Я пишу простую пьесу в самом начале моей пьесы, в которой используется факт. И в случае, если хост недоступен, эта задача завершится с ошибкой «Неопределенная переменная». Задача является просто фиктивной и всегда будет проходить, если все хосты доступны.

Смотрите ниже мой пример:

- name: Check Ansible connectivity to all hosts
  hosts: host_all
  user: "{{ remote_user }}"
  sudo: "{{ sudo_required }}"
  sudo_user: root
  connection: ssh # or paramiko
  max_fail_percentage: 0
  tasks:
    - name: check connectivity to hosts (Dummy task)
      shell: echo " {{ hostvars[item]['ansible_hostname'] }}"
      with_items: groups['host_all']
      register: cmd_output

    - name: debug ...
      debug: var=cmd_output

Если хост недоступен, вы получите сообщение об ошибке, как показано ниже:

TASK: [c.. ***************************************************** 
fatal: [172.22.191.160] => One or more undefined variables: 'dict object'    has no attribute 'ansible_hostname' 
fatal: [172.22.191.162] => One or more undefined variables: 'dict object' has no attribute 'ansible_hostname'

FATAL: all hosts have already failed -- aborting

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

person Zoro_77    schedule 03.07.2015
comment
Спасибо, в итоге я использовал это как предварительную задачу - person Jacob Evans; 08.06.2016

Вы можете объединить any_errors_fatal: true или max_fail_percentage: 0 с gather_facts: false, а затем запустить задачу, которая завершится ошибкой, если хост находится в автономном режиме. Что-то вроде этого в верхней части playbook должно делать то, что вам нужно:

- hosts: all
  gather_facts: false
  max_fail_percentage: 0
  tasks:
    - action: ping

Бонусом является то, что это также работает с опцией -l SUBSET для ограничения подходящих хостов.

person wilkystyle    schedule 28.01.2016
comment
зачем нужен сбор фактов? - person hbogert; 27.05.2016
comment
По умолчанию Ansible будет работать только с доступными хостами и определяет это при сборе фактов. Последующий ping всегда будет успешным, потому что Ansible пытается запустить playbook только на хостах, которые, как ему известно, уже запущены. - person wilkystyle; 28.05.2016
comment
Поведение ansible изменилось таким образом в версии 2.0, что больше не работает. - person hbogert; 11.06.2016
comment
На самом деле, уверен только в 2.1, а не в 2.0 (больше не мог редактировать предыдущий комментарий) - person hbogert; 11.06.2016

Вы можете добавить max_fail_percentage в свой плейбук - примерно так:

- hosts: all_boxes
  max_fail_percentage: 0
  roles:
    - common
  pre_tasks:
    - include: roles/common/tasks/start-time.yml
    - include: roles/common/tasks/debug.yml

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

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

  • hosts: webservers max_fail_percentage: 30 serial: 10 В приведенном выше примере, если более 3 из 10 серверов в группе выйдут из строя, остальная часть игры будет прервана.

Примечание. Установленный процент должен быть превышен, а не равен. Например, если серийный номер был установлен на 4, и вы хотите, чтобы задача прервалась, когда 2 из систем вышли из строя, процентное значение должно быть установлено на 49, а не на 50.

person Duncan Lock    schedule 16.12.2014

Вдохновленный другими вопросами/ответами. https://stackoverflow.com/a/55219490/457589

Использование ansible-playbook 2.7.8.

Проверка наличия ansible_facts для каждого требуемого хоста кажется мне более явной.

# my-playbook.yml
- hosts: myservers
  tasks:
    - name: Check ALL hosts are reacheable before doing the release
      fail:
        msg: >
          [REQUIRED] ALL hosts to be reachable, so flagging {{ inventory_hostname }} as failed,
          because host {{ item }} has no facts, meaning it is UNREACHABLE.
      when: "hostvars[item].ansible_facts|list|length == 0"
      with_items: "{{ groups.myservers }}"

    - debug:
        msg: "Will only run if all hosts are reacheable"
$ ansible-playbook -i my-inventory.yml my-playbook.yml

PLAY [myservers] *************************************************************************************************************************************************************************************************************

TASK [Gathering Facts] *********************************************************************************************************************************************************************************************************
fatal: [my-host-03]: UNREACHABLE! => {"changed": false, "msg": "Failed to connect to the host via ssh: ssh: Could not resolve hostname my-host-03: Name or service not known", "unreachable": true}
fatal: [my-host-04]: UNREACHABLE! => {"changed": false, "msg": "Failed to connect to the host via ssh: ssh: Could not resolve hostname my-host-04: Name or service not known", "unreachable": true}
ok: [my-host-02]
ok: [my-host-01]

TASK [Check ALL hosts are reacheable before doing the release] ********************************************************************************************************************************************************************************************************************
failed: [my-host-01] (item=my-host-03) => {"changed": false, "item": "my-host-03", "msg": "[REQUIRED] ALL hosts to be reachable, so flagging my-host-01 as failed, because host my-host-03 has no facts, meaning it is UNREACHABLE."}
failed: [my-host-01] (item=my-host-04) => {"changed": false, "item": "my-host-04", "msg": "[REQUIRED] ALL hosts to be reachable, so flagging my-host-01 as failed, because host my-host-04 has no facts, meaning it is UNREACHABLE."}
failed: [my-host-02] (item=my-host-03) => {"changed": false, "item": "my-host-03", "msg": "[REQUIRED] ALL hosts to be reachable, so flagging my-host-02 as failed, because host my-host-03 has no facts, meaning it is UNREACHABLE."}
failed: [my-host-02] (item=my-host-04) => {"changed": false, "item": "my-host-04", "msg": "[REQUIRED] ALL hosts to be reachable, so flagging my-host-02 as failed, because host my-host-04 has no facts, meaning it is UNREACHABLE."}
skipping: [my-host-01] => (item=my-host-01)
skipping: [my-host-01] => (item=my-host-02)
skipping: [my-host-02] => (item=my-host-01)
skipping: [my-host-02] => (item=my-host-02)
        to retry, use: --limit @./my-playbook.retry

PLAY RECAP *********************************************************************************************************************************************************************************************************************
my-host-01 : ok=1    changed=0    unreachable=0    failed=1
my-host-02 : ok=1    changed=0    unreachable=0    failed=1
my-host-03 : ok=0    changed=0    unreachable=1    failed=0
my-host-04 : ok=0    changed=0    unreachable=1    failed=0
person Julien    schedule 18.03.2019
comment
Также можно использовать это в pre_tasks:, если вы используете роли: - person Julien; 18.03.2019
comment
при использовании ansible-playbook 2.1.1.0 вместо этого можно использовать when: "'ansible_system' not in hostvars[item]" - person Julien; 18.03.2019