¿Hay alguna manera de ejecutar bucles with_items en paralelo en Ansible?

12

Estoy ejecutando Ansible 2.2, pero puedo actualizar si me ayuda.

Vi esto y estaba muy emocionado, pero no parece estar en esta (o en ninguna) versión de la documentación de Ansible.

El problema que estoy tratando de resolver es que tengo 1000 usuarios que necesito administrar en una caja de Centos.

Lleva bastante tiempo ejecutar esta tarea en serie. Y aún más molesto, todo aparece como modificado porque el comando "caduca" en el módulo de usuario siempre marca la cosa como modificada.

esto también parecía prometedor, pero tomó la misma cantidad de tiempo ejecutar cada comando en el ciclo with_items y no fue más rápido (nunca me molesté en esperar lo suficiente para llegar al final).

Omitir tareas es rápido ahora (mucho más rápido que en Ansible 2.0), si no puedo encontrar la manera de hacer que esto funcione en paralelo, creo que volveré y descubriré cómo omitir tareas sin sentido y, si todo de lo contrario falla, escribiré mi propio módulo. Pero parece que debería poder hacer todo esto más rápido en Ansible.


Esto es lo que quiero ejecutar en paralelo, host_authorizationses una lista de nombres de usuario y otros datos.

  - name: Create/modify OS user accounts
    user: name={{ item.username }} group=sshusers shell=/bin/bash home="/home/selinux-modules/{{ item.username }}" state=present expires={{item.expiredate|default(omit)}}
    with_items: "{{ host_authorizations }}"
    tags: full_maintenance
Peter Turner
fuente
Proporcione un fragmento de código. De lo contrario, es difícil de ayudar.
030
@ 030 hay un fragmento, supongo que ayuda un poco al contexto. Me interesa más conceptualmente si realmente hay una manera de ejecutar tareas (en un bucle) en paralelo en el mismo host. Sé que podría hacer un montón de cosas individuales con async, pero no tanto con with_items.
Peter Turner el
Básicamente, si se deben crear 1000 usuarios, se debe terminar tan rápido como crear un solo usuario. Interesante, ¿por qué no usar algo como LDAP?
030
1
En serio, te diriges hacia un camino de dolor, no creo que nadie maneje más de una docena de cuentas con una base de cuentas local, tan pronto como crece el número de usuarios, supongo que todos se mudan a un sistema de contabilidad centralizado, generalmente algunos backend ldap (podría ser el directorio activo) y luego establezca el tiempo de caducidad y la clave pública como atributos de esta base central y luego use cosas como sss_ssh_authorizedkeys para permitir que el servidor ssh obtenga las claves autorizadas de esta base central.
Tensibai
2
No estoy de acuerdo en que esto es para lo que ansible es (sugerencia es que no hace la creación / gestión de usuarios en masa). Estoy de acuerdo con el punto de que las cuentas no deben administrarse en bases de cuentas locales a gran volumen (el hecho de que no sean cuentas humanas es irrelevante para el problema de todos modos)
Tensibai

Respuestas:

13

Como @webKnja mencionó, esto es posible con el asyncmodo. Recientemente lo descubrí y aprendí que puedes usarlo de 3 maneras diferentes según tus necesidades.

  1. Ejecute y sondee los resultados, observe el poll:5, Esto sondeará los resultados cada 5 segundos. Puede ahorrar algo de tiempo con este método.

    - name: My long runing task
      some_module_name:
        ip: "{{item.fabric}}"
        username: "{{user}}"
        password: "{{password}}"
        secret: "{{secret}}"
      loop: "{{zoning_list}}"
      register: _alias_vc_0
      async: 60
      poll: 5
    
  2. Dispara y olvida poll: 0 , esta es una opción muy rápida ya que Ansible solo está disparando esas tareas. La desventaja es que no sabemos cuál fue el resultado de la tarea, es decir changed: True/False. Por supuesto, es un inconveniente si te importan los comentarios;).

    name: My long runing task
    some_module_name:
      ip: "{{item.fabric}}"
      username: "{{user}}"
      password: "{{password}}"
      secret: "{{secret}}"
    loop: "{{zoning_list}}"
    register: _alias_vc_0
    async: 60
    poll: 0
    
  3. Dispara y olvida conasync_status , la sintaxis de la tarea es la misma que en el ejemplo 2, sin embargo, requerirá una tarea adicional async_status. Este es mi favorito, ya que es relativamente rápido (más rápido que el bucle normal o el execute and poll) y le permite capturar los comentarios, aunque tendrá que lidiar con nuevos registerpara usted async_task.

    retries: 20 - Cuántos intentos antes de fallar.

    delay: 2 - cuántos segundos esperar entre las encuestas.

    - name: My long runing task
      some_module_name:
        ip: "{{item.fabric}}"
        username: "{{user}}"
        password: "{{password}}"
        secret: "{{secret}}"
      loop: "{{zoning_list}}"
      register: _alias_vc_0
      async: 60
      poll: 0
    
    
    - name: Wait for My long running task to finish
      async_status:
        id: "{{ item.ansible_job_id }}"
      register: _jobs_alias_vc_0
      retries: 20
      delay: 2
      until: _jobs_alias_vc_0.finished
      loop: "{{_alias_vc_0.results}}"
    

Una palabra de precaución , dependiendo de la tarea que no pueda utilizar la asyncopción. Tenía ejemplos en los que interactuaba con un sistema que no podía manejar múltiples solicitudes para el mismo recurso. Encontré la asyncopción que funciona mejor si tengo que realizar la misma tarea en varios hosts. Ahí es donde pude "ahorrar" la mayor parte del tiempo.

Desde que publicó el enlace a la documentación de Ansible en la pregunta, no voy a hacer eso.

MMT
fuente
@chicks es posible que desee cambiar el pollvalor a 0 en el ejemplo 3. ¡Esta es una explicación increíble! Thnx.
Debanjan Basu
@DebanjanBasu Cualquiera puede hacer ediciones sugeridas. Podría ser yo quien lo apruebe en las colas de revisión, pero debería obtener crédito por la edición en sí.
pollitos
¡Las ediciones de un personaje no están permitidas tristemente! :(
Debanjan Basu
2
La opción 3 funciona muy bien, ¡gracias! Sin embargo, un comentario: a partir de al menos Ansible 2.8, async_statusrequiere jid, no id.
Edward Enseñe
4

Para responder a su pregunta: No, a partir de ahora Ansible no puede ejecutar bucles en paralelo.

En su newuserslugar, usaría , que está hecho para la creación masiva de usuarios. Crear un archivo con todos los usuarios en el mismo, copiarlo en el huésped, y correr newusers /path/to/user/listen una commandtarea.

simonz
fuente
3

Es posible lograr esto usando el asyncmodo. Encuentre algunas referencias sobre cómo hacer esto a continuación.

Refs:

---

- name: Run tasks in parallel
  hosts: localhost
  connection: local
  gather_facts: no
  tasks:
    - name: Pretend to create instances
      command: "sleep {{ item }}"  # Instead of calling a long running operation at a cloud provider, we just sleep.
      with_items:
        - 6
        - 8
        - 7
      register: _create_instances
      async: 600  # Maximum runtime in seconds. Adjust as needed.
      poll: 0  # Fire and continue (never poll)

    - name: Wait for creation to finish
      async_status:
        jid: "{{ item.ansible_job_id }}"
      register: _jobs
      until: _jobs.finished
      delay: 5  # Check every 5 seconds. Adjust as you like.
      retries: 10  # Retry up to 10 times. Adjust as needed.
      with_items: "{{ _create_instances.results }}"
webKnjaZ
fuente
Si bien esos enlaces pueden responder la pregunta si se rompen, no queda nada en su respuesta para futuros lectores, intente mostrar cómo esto ayudaría a resolver el problema con sus propias palabras / ejemplo y deje los enlaces solo para obtener información más detallada.
Tensibai
Sí, no puedo marcar esto como respuesta hasta A.) Lo pruebo y B.) El código relevante se coloca aquí. Pero gracias por señalarme en esta dirección, sin embargo.
Peter Turner
Lo siento, tenía prisa :)
webKnjaZ