¿Cómo escribo un controlador de Ansible con múltiples tareas?

81

En respuesta a un cambio, tengo varias tareas relacionadas que deberían ejecutarse. ¿Cómo escribo un controlador de Ansible con múltiples tareas?

Por ejemplo, me gustaría un controlador que reinicia un servicio solo si ya se inició:

- name: Restart conditionally
  shell: check_is_started.sh
  register: result

- name: Restart conditionally step 2
  service: name=service state=restarted
  when: result
timdiels
fuente

Respuestas:

95

Existe una solución adecuada a este problema a partir de Ansible 2.2.

Los controladores también pueden "escuchar" temas genéricos, y las tareas pueden notificar esos temas de la siguiente manera:

handlers:
    - name: restart memcached
      service: name=memcached state=restarted
      listen: "restart web services"
    - name: restart apache
      service: name=apache state=restarted
      listen: "restart web services"

tasks:
    - name: restart everything
      command: echo "this task will restart the web services"
      notify: "restart web services"

Este uso hace que sea mucho más fácil activar varios controladores. También desacopla a los controladores de sus nombres, lo que facilita compartir controladores entre libros de jugadas y roles.

Específicamente para la pregunta, esto debería funcionar:

- name: Check if restarted
  shell: check_is_started.sh
  register: result
  listen: Restart processes

- name: Restart conditionally step 2
  service: name=service state=restarted
  when: result
  listen: Restart processes

y en la tarea, notificar a los controladores a través de 'Reiniciar procesos'

http://docs.ansible.com/ansible/playbooks_intro.html#handlers-running-operations-on-change

mkadan
fuente
1
¿Esta solución permitiría usar block: y rescue: para manejar errores lanzando comandos?
user1767316
3
¿Se ejecutan las múltiples tareas en el orden indicado? Si una tarea depende de otra tarea, ¿debo usar notificar-escuchar dentro del controlador?
user26767
@ user26767 de la documentación vinculada:Notify handlers are always run in the same order they are defined, not in the order listed in the notify-statement. This is also the case for handlers using listen.
swenzel
55

En su archivo de controlador, encadene los diferentes pasos juntos usando notificar.

- name: Restart conditionally
  debug: msg=Step1
  changed_when: True
  notify: Restart conditionally step 2

- name: Restart conditionally step 2
  debug: msg=Step2
  changed_when: True
  notify: Restart conditionally step 3

- name: Restart conditionally step 3
  debug: msg=Step3

Luego, consúltelo desde una tarea con notify: Restart conditionally.

Tenga en cuenta que solo puede notificar a los controladores por debajo del actual. Entonces, por ejemplo, Restart conditionally step 2no puedo notificar Restart conditionally.

Fuente: #ansible en irc.freenode.net. No estoy seguro de si esto seguirá funcionando en el futuro, ya que no se menciona como una característica en la documentación oficial.

timdiels
fuente
Este método ayuda con un hecho para el que parece haber poca literatura: los controladores, una vez notificados, se ejecutarán incluso si uno de esos controladores falla. Usar notifyetiquetas diferentes para aquellas que quizás no desee ejecutar si falla un controlador anterior es una buena manera de "arreglar" esto si no quiere que sea así.
fbicknel
27

Editar: si tiene Ansible 2.2 o superior, use la respuesta de mkadan. La respuesta a continuación no funciona con las versiones más recientes de Ansible. También tenga en cuenta que, según el comentario de Enis Afgan a continuación, debido a un error, esta respuesta no funciona con las versiones de Ansible entre 2.0.2 y 2.1.2.


A partir de Ansible 2.0, puede utilizar una acción de inclusión en su controlador para ejecutar varias tareas.

Por ejemplo, coloque sus tareas en un archivo separado restart_tasks.yml(si usa roles, eso iría al subdirectorio de tareas, no al subdirectorio de controladores):

- name: Restart conditionally step 1
  shell: check_is_started.sh
  register: result

- name: Restart conditionally step 2
  service: name=service state=restarted
  when: result

Su controlador sería simplemente:

- name: Restart conditionally
  include: restart_tasks.yml

Fuente: tema de emisión en github: https://github.com/ansible/ansible/issues/14270

Alexander Klauer
fuente
5
Solo una nota que las versiones de Ansible entre 2.0.2 y 2.1.2 tienen un error donde esto no funciona: github.com/ansible/ansible/issues/15915
Enis Afgan
1
Para los futuros lectores, esto no me funcionó en Ansible 2.9.2. La solución fue reemplazada includepor include_tasks.
Martin Melka
@MartinMelka gracias, he agregado una advertencia en la parte superior de mi respuesta de que no está destinada a las versiones de Ansible> = 2.2.
Alexander Klauer
Genial, gracias :) Al diseñar nuevos controladores, la otra respuesta es mejor. Pero cuando el código de inventario de Ansible es antiguo y solo es necesario hacer pequeños cambios (como lo hice yo), el suyo aún puede ser útil con esta pequeña adición.
Martin Melka