web-dev-qa-db-fra.com

Comment attendre le redémarrage du serveur avec Ansible?

J'essaie de redémarrer le serveur et d'attendre, en utilisant ceci:

- name: Restart server
  Shell: reboot

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

Mais je reçois cette erreur:

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
40
ChocoDeveloper

Vous devez modifier la tâche wait_for pour qu'elle s'exécute en tant que local_action et spécifier l'hôte que vous attendez. Par exemple:

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

Ansible> = 2.7 (publié en octobre 2018)

Utilisez le nouveau reboot module.

Ansible <2.7

Redémarrer en tant que tâche

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

Ceci exécute la commande Shell en tant que tâche asynchrone . Ansible n'attendra donc pas la fin de la commande. En règle générale, async param donne le temps maximal pour la tâche, mais comme poll est défini sur 0, Ansible n'interrogera jamais si la commande est terminée. Cette commande sera ainsi "déclenchée et oubliée". Les couchages avant et après shutdown permettent d'éviter de rompre la connexion SSH lors du redémarrage alors qu'Ansible est toujours connecté à votre hôte distant.

Attendre comme une tâche

Vous pouvez simplement utiliser:

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

..mais vous préférerez peut-être utiliser la variable {{ ansible_ssh_Host }} comme nom d’hôte et/ou {{ ansible_ssh_port }} comme hôte SSH et le port si vous utilisez des entrées telles que:

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

..dans votre inventaire (fichier Ansible hosts).

Ceci exécutera le wait_for task sur la machine exécutant Ansible . Cette tâche attendra que le port 22 soit ouvert sur votre hôte distant, à compter de 10 secondes.

Redémarrez et attendez en tant que handlers

Mais je suggère d'utiliser les deux en tant que gestionnaires, pas de tâches.

Il y a 2 raisons principales de le faire:

  • réutilisation du code - vous pouvez utiliser un gestionnaire pour de nombreuses tâches. Exemple: déclencher le redémarrage du serveur après avoir changé le fuseau horaire et après avoir changé le noyau,

  • déclencher une seule fois - si vous utilisez un gestionnaire pour quelques tâches et que plus d'une d'entre elles apportent des modifications => déclenche le gestionnaire, le comportement de ce gestionnaire ne se produira qu'une seule fois. Exemple: si un gestionnaire de redémarrage httpd est associé aux modifications de configuration httpd et à la mise à jour du certificat SSL, dans ce cas, httpd ne sera redémarré qu'une seule fois. 

En savoir plus sur les handlers ici .

Redémarrage et attente du redémarrage en tant que gestionnaires:

  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

..et l'utiliser dans votre tâche dans une séquence, comme celle-ci, associée au redémarrage du gestionnaire de serveur:

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

Notez que les gestionnaires sont exécutés dans l'ordre dans lequel ils ont été définis et non dans l'ordre dans lequel ils sont répertoriés dans notify!

49
Greg Dubicki

Le plus fiable que j'ai avec la version 1.9.4 est (ceci est mis à jour, la version originale est en bas):

- 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

Notez l'option async. 1.8 et 2.0 peuvent vivre avec 0 mais 1.9 le veut 1. Ce qui précède vérifie également si la machine a réellement été redémarrée. C’est bien parce que j’ai eu une faute de frappe lorsqu’un redémarrage a échoué et aucune indication de cet échec.

Le gros problème est d’attendre que la machine soit opérationnelle. Cette version ne reste que 330 secondes et n'essaie jamais d'accéder à Host auparavant. Certaines autres réponses suggèrent d'utiliser le port 22. C'est bien si les deux sont vraies:

  • vous avez un accès direct aux machines
  • votre machine est accessible immédiatement après l'ouverture du port 22

Celles-ci ne sont pas toujours vraies et j'ai donc décidé de perdre 5 minutes de temps de calcul. J'espère que ansible étendra le module wait_for pour vérifier l'état de l'hôte afin d'éviter de perdre du temps.

en fait, la réponse suggérant d'utiliser des gestionnaires est Nice. +1 pour les gestionnaires de moi (et j'ai mis à jour la réponse pour utiliser des gestionnaires).

Voici la version originale mais ce n'est pas si bon et si fiable:

- 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
10
akostadinov

Mise à jour 2018

À partir de la version 2.3, Ansible est maintenant livré avec le module wait_for_connection, qui peut être utilisé exactement à cette fin.

#
## 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

Shutdown -r +1 empêche qu'un code de retour de 1 soit renvoyé et que la tâche échoue. L'arrêt est exécuté en tant que tâche asynchrone, nous devons donc retarder la tâche wait_for_connection d'au moins 60 secondes. 75 nous donne un tampon pour ces cas de flocon de neige.

wait_for_connection - Attend que le système distant soit accessible/utilisable

8
infrascripting

Je voulais commenter sur le post de Shahar, qu'il utilise une adresse de l'hôte codée en dur est mieux de lui donner une variable pour référencer l'hôte actuel, il est en train de configurer {{inventaire_hôte}}, de sorte que son code sera comme ça:

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

Avec les versions plus récentes d’Ansible (c’est-à-dire 1.9.1 dans mon cas), les paramètres poll et async configurés sur 0 ne suffisent parfois pas (cela peut dépendre de la distribution configurée ansible?). Comme expliqué dans https://github.com/ansible/ansible/issues/10616 , une solution de contournement est la suivante:

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

Et ensuite, attendez le redémarrage complet comme expliqué dans de nombreuses réponses de cette page.

5
amichaud

Par essais et erreurs + beaucoup de lecture, voici ce qui a finalement fonctionné pour moi avec la version 2.0 de 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

Ma solution pour désactiver SELinux et redémarrer un nœud en cas de besoin:

---
- 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:
4
slm

J'ai créé un rôle reboot_server ansible qui peut être appelé dynamiquement à partir d'autres rôles avec:

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

Le contenu du rôle est:

- 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

Cela a été conçu à l’origine pour fonctionner avec le système d’exploitation Ubuntu.

0
Gio Salvador

Je n'ai pas vu beaucoup de visibilité à ce sujet, mais un changement récent ( https://github.com/ansible/ansible/pull/43857 ) a ajouté le mot clé "ignore_unreachable". Cela vous permet de faire quelque chose comme ceci:

- name: restart server
  Shell: reboot
  ignore_unreachable: true

- name: wait for server to come back
  wait_for_connection: 
      timeout: 120

- name: the next action
  ...
0
bagelbyte

Si vous n'avez pas encore configuré DNS pour le serveur distant, vous pouvez transmettre l'adresse IP à la place d'un nom d'hôte variable:

- 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

Ce sont les deux tâches que j'ai ajoutées à la fin de mon ansible-swap playbook (pour installer 4 Go d’échange sur de nouvelles gouttelettes Digital Ocean.

0
Aaron Tribou
- wait_for:
    port: 22
    Host: "{{ inventory_hostname }}"
  delegate_to: 127.0.0.1
0
Moriarty