Подтвердить что ты не робот

Как ждать перезагрузки сервера с помощью Ansible?

Я пытаюсь перезапустить сервер и ждать, используя это:

- name: Restart server
  shell: reboot

- name: Wait for server to restart
  wait_for:
    port=22
    delay=1
    timeout=300

Но я получаю эту ошибку:

TASK: [iptables | Wait for server to restart] ********************************* 
fatal: [example.com] => failed to transfer file to /root/.ansible/tmp/ansible-tmp-1401138291.69-222045017562709/wait_for:
sftp> put /tmp/tmpApPR8k /root/.ansible/tmp/ansible-tmp-1401138291.69-222045017562709/wait_for

Connected to example.com.
Connection closed
4b9b3361

Ответ 1

Вы должны изменить задачу wait_for, которая будет выполняться как local_action, и указать хост, которого вы ждете. Например:

- name: Wait for server to restart
  local_action:
    module: wait_for
      host=192.168.50.4
      port=22
      delay=1
      timeout=300

Ответ 2

Ansible> = 2.7 (выпущен в октябре 2018 года)

Используйте новый модуль перезагрузки.

Нескончаемый <2,7

Перезапуск в качестве задачи

- name: restart server
  shell: 'sleep 1 && shutdown -r now "Reboot triggered by Ansible" && sleep 1'
  async: 1
  poll: 0
  become: true

Это запускает команду оболочки как асинхронную задачу, поэтому Ansible не будет ждать окончания команды. Обычно async param дает максимальное время для задачи, но, поскольку для poll установлено значение 0, Ansible никогда не будет опроса, если команда закончена - это сделает эту команду "огнем и забудет". Спящие до и после shutdown должны прерывать соединение SSH во время перезагрузки, пока Ansible все еще подключен к удаленному хосту.

Подождите, как задача

Вы можете просто использовать:

- name: Wait for server to restart
  local_action:
    module: wait_for
      host={{ inventory_hostname }}
      port=22
      delay=10
    become: false

.. но вы можете предпочесть использовать переменную {{ ansible_ssh_host }} качестве имени хоста и/или {{ ansible_ssh_port }} в качестве хоста и порта SSH, если вы используете такие записи, как:

hostname         ansible_ssh_host=some.other.name.com ansible_ssh_port=2222 

.. в вашем инвентаре (файл Ansible hosts).

Это запустит задачу wait_for на машине, на которой работает Ansible. Эта задача будет ждать, пока порт 22 станет открытым на вашем удаленном хосте, начиная с 10-секундной задержки.

Перезапустите и подождите, пока обработчики

Но я предлагаю использовать оба из них как обработчики, а не задачи.

Для этого есть две основные причины:

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

  • триггер только один раз - если вы используете обработчик для нескольких задач, и более 1 из них сделает какое-то изменение => запускает обработчик, то то, что делает обработчик, произойдет только один раз. Пример: если у вас есть обработчик перезапуска httpd, связанный с изменением конфигурации httpd и сертификатом SSL-сертификата, тогда в случае изменения настроек конфигурации и SSL-сертификата httpd будет перезагружен только один раз.

Подробнее о обработчиках читайте здесь.

Перезапуск и ожидание перезагрузки в качестве обработчиков:

  handlers:

    - name: Restart server
      command: 'sleep 1 && shutdown -r now "Reboot triggered by Ansible" && sleep 1'
      async: 1
      poll: 0
      ignore_errors: true
      become: true

    - name: Wait for server to restart
      local_action:
        module: wait_for
          host={{ inventory_hostname }}
          port=22
          delay=10
        become: false

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

  tasks:
    - name: Set hostname
        hostname: name=somename
        notify:
          - Restart server
          - Wait for server to restart

Обратите внимание, что обработчики выполняются в том порядке, в котором они определены, а не в том порядке, в котором они указаны в notify !

Ответ 3

Самое надежное, что у меня есть с 1.9.4 (это обновлено, оригинальная версия внизу):

- name: Example ansible play that requires reboot
  sudo: yes
  gather_facts: no
  hosts:
    - myhosts
  tasks:
    - name: example task that requires reboot
      yum: name=* state=latest
      notify: reboot sequence
  handlers:
    - name: reboot sequence
      changed_when: "true"
      debug: msg='trigger machine reboot sequence'
      notify:
        - get current time
        - reboot system
        - waiting for server to come back
        - verify a reboot was actually initiated
    - name: get current time
      command: /bin/date +%s
      register: before_reboot
      sudo: false
    - name: reboot system
      shell: sleep 2 && shutdown -r now "Ansible package updates triggered"
      async: 1
      poll: 0
      ignore_errors: true
    - name: waiting for server to come back
      local_action: wait_for host={{ inventory_hostname }} state=started delay=30 timeout=220
      sudo: false
    - name: verify a reboot was actually initiated
      # machine should have started after it has been rebooted
      shell: (( `date +%s` - `awk -F . '{print $1}' /proc/uptime` > {{ before_reboot.stdout }} ))
      sudo: false

Обратите внимание на параметр async. 1.8 и 2.0 могут жить с 0, но 1.9 хочет его 1. Вышеупомянутое также проверяет, действительно ли машина была перезагружена. Это хорошо, потому что однажды у меня была опечатка, которая не перезагрузилась и не указала на ошибку.

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

  • у вас есть прямой доступ к машинам
  • ваш компьютер доступен сразу после открытия порта 22

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

btw ответ, предлагающий использовать обработчики, хорош. +1 для обработчиков от меня (и я обновил ответ на использование обработчиков).

Здесь оригинальная версия, но это не так хорошо и не так надежно:

- name: Reboot
  sudo: yes
  gather_facts: no
  hosts:
    - OSEv3:children
  tasks:
    - name: get current uptime
      shell: cat /proc/uptime | awk -F . '{print $1}'
      register: uptime
      sudo: false
    - name: reboot system
      shell: sleep 2 && shutdown -r now "Ansible package updates triggered"
      async: 1
      poll: 0
      ignore_errors: true
    - name: waiting for server to come back
      local_action: wait_for host={{ inventory_hostname }} state=started delay=30 timeout=300
      sudo: false
    - name: verify a reboot was actually initiated
      # uptime after reboot should be smaller than before reboot
      shell: (( `cat /proc/uptime | awk -F . '{print $1}'` < {{ uptime.stdout }} ))
      sudo: false

Ответ 4

Обновление 2018 года

Начиная с 2.3, Ansible теперь поставляется с модулем wait_for_connection, который может использоваться именно для этой цели.

#
## Reboot
#

- name: (reboot) Reboot triggered
  command: /sbin/shutdown -r +1 "Ansible-triggered Reboot"
  async: 0
  poll: 0

- name: (reboot) Wait for server to restart
  wait_for_connection:
    delay: 75

Завершение работы -r +1 предотвращает возврат кода возврата из 1 и может привести к сбою задачи. Завершение работы выполняется как задача async, поэтому нам нужно отложить задачу wait_for_connection как минимум на 60 секунд. 75 дает нам буфер для этих случаев снежинок.

wait_for_connection - ждет, пока удаленная система не станет доступной/полезной

Ответ 5

Я хотел бы прокомментировать сообщение Shahar, что он лучше использует адрес жестко заданного хоста, чтобы он имел переменную для ссылки на текущий хост-интерфейс, который настраивает {{inventory_hostname}}, поэтому его код будет таким:

- name: Wait for server to restart
  local_action:
    module: wait_for
     host={{ inventory_hostname }}
     port=22
     delay=1
     timeout=300

Ответ 6

С более новыми версиями Ansible (то есть 1.9.1 в моем случае), параметры опроса и асинхронизации, установленные на 0, иногда недостаточны (может быть, зависит от того, какой дистрибутив настроен как возможно?). Как описано в https://github.com/ansible/ansible/issues/10616, обходной путь:

- name: Reboot
  shell: sleep 2 && shutdown -r now "Ansible updates triggered"
  async: 1
  poll: 0
  ignore_errors: true

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

Ответ 7

Через пробную версию и ошибку + много чтения это то, что в конечном итоге сработало для меня с использованием версии 2.0 Ansible:

$ ansible --version
ansible 2.0.0 (devel 974b69d236) last updated 2015/09/01 13:37:26 (GMT -400)
  lib/ansible/modules/core: (detached HEAD bbcfb1092a) last updated 2015/09/01 13:37:29 (GMT -400)
  lib/ansible/modules/extras: (detached HEAD b8803306d1) last updated 2015/09/01 13:37:29 (GMT -400)
  config file = /Users/sammingolelli/projects/git_repos/devops/ansible/playbooks/test-2/ansible.cfg
  configured module search path = None

Мое решение для отключения SELinux и перезагрузки node при необходимости:

---
- name: disable SELinux
  selinux: state=disabled
  register: st

- name: reboot if SELinux changed
  shell: shutdown -r now "Ansible updates triggered"
  async: 0
  poll: 0
  ignore_errors: true
  when: st.changed

- name: waiting for server to reboot
  wait_for: host="{{ ansible_ssh_host | default(inventory_hostname) }}" port={{ ansible_ssh_port | default(22) }} search_regex=OpenSSH delay=30 timeout=120
  connection: local
  sudo: false
  when: st.changed

# vim:ft=ansible:

Ответ 8

- wait_for:
    port: 22
    host: "{{ inventory_hostname }}"
  delegate_to: 127.0.0.1

Ответ 9

Если у вас еще нет настройки DNS для удаленного сервера, вы можете передать IP-адрес вместо переменной hostname:

- name: Restart server
  command: shutdown -r now

- name: Wait for server to restart successfully
  local_action:
    module: wait_for
      host={{ ansible_default_ipv4.address }}
      port=22
      delay=1
      timeout=120

Это две задачи, которые я добавил в конец моей загружаемой книги с возможностью замены (для установки 4 ГБ свопа на новые капли Digital Ocean.

Ответ 10

Я создал загрузочную роль reboot_server, которую можно динамически вызывать из других ролей:

- name: Reboot server if needed
  include_role:
    name: reboot_server
  vars:
    reboot_force: false

Содержание роли:

- name: Check if server restart is necessary
  stat:
    path: /var/run/reboot-required
  register: reboot_required

- name: Debug reboot_required
  debug: var=reboot_required

- name: Restart if it is needed
  shell: |
    sleep 2 && /sbin/shutdown -r now "Reboot triggered by Ansible"
  async: 1
  poll: 0
  ignore_errors: true
  when: reboot_required.stat.exists == true
  register: reboot
  become: true

- name: Force Restart
  shell: |
    sleep 2 && /sbin/shutdown -r now "Reboot triggered by Ansible"
  async: 1
  poll: 0
  ignore_errors: true
  when: reboot_force|default(false)|bool
  register: forced_reboot
  become: true

# # Debug reboot execution
# - name: Debug reboot var
#   debug: var=reboot

# - name: Debug forced_reboot var
#   debug: var=forced_reboot

# Don't assume the inventory_hostname is resolvable and delay 10 seconds at start
- name: Wait 300 seconds for port 22 to become open and contain "OpenSSH"
  wait_for:
    port: 22
    host: '{{ (ansible_ssh_host|default(ansible_host))|default(inventory_hostname) }}'
    search_regex: OpenSSH
    delay: 10
  connection: local
  when: reboot.changed or forced_reboot.changed

Первоначально он был разработан для работы с ОС Ubuntu.