Ansible ofrece el loop, with_, y until palabras clave para ejecutar una tarea varias veces. Los ejemplos de bucles de uso común incluyen el cambio de propiedad en varios archivos y / o directorios con la módulo de archivo, creando múltiples usuarios con el módulo de usuarioy repetir un paso de sondeo hasta que se alcance un resultado determinado.

Nota

  • Agregamos loop en Ansible 2.5. Todavía no es un reemplazo completo para with_, pero lo recomendamos para la mayoría de los casos de uso.
  • No hemos desaprobado el uso de with_ – esa sintaxis seguirá siendo válida en el futuro previsible.
  • Buscamos mejorar loop sintaxis: vea esta página y la registro de cambios para actualizaciones.
  • Comparando loop y with_*
  • Bucles estándar

    • Iterando sobre una lista simple
    • Iterando sobre una lista de hashes
    • Iterando sobre un diccionario
  • Registrar variables con un bucle
  • Bucles complejos

    • Iterando sobre listas anidadas
    • Reintentar una tarea hasta que se cumpla una condición
    • Bucle sobre el inventario
  • Asegurar la entrada de la lista para loop: utilizando query en vez de lookup
  • Agregar controles a los bucles

    • Limitar la salida de bucle con label
    • Pausando dentro de un bucle
    • Seguimiento del progreso a través de un bucle con index_var
    • Definición de nombres de variables internas y externas con loop_var
    • Variables de bucle extendido
    • Accediendo al nombre de su loop_var
  • Migrando de with_X a loop

    • with_list
    • with_items
    • with_indexed_items
    • with_flattened
    • con nosotros
    • with_dict
    • with_sequence
    • with_subelements
    • with_nested / with_cartesian
    • with_random_choice

Comparando loop y with_*

  • los with_ las palabras clave se basan en Complementos de búsqueda – incluso items es una búsqueda.
  • los loop palabra clave es equivalente a with_list, y es la mejor opción para bucles simples.
  • los loop palabra clave no aceptará una cadena como entrada, consulte Asegurando la entrada de la lista para el bucle: usando una consulta en lugar de una búsqueda.
  • En general, cualquier uso de with_* cubierto de Migrando de with_X a loop se puede actualizar para usar loop.
  • Tenga cuidado al cambiar with_items para loop, como with_items realizó un aplanamiento implícito de un solo nivel. Puede que necesite utilizar flatten(1) con loop para que coincida con el resultado exacto. Por ejemplo, para obtener el mismo resultado que:
with_items:-1-[2,3]-4

necesitarías:

loop:" flatten(1) "
  • Alguna with_* declaración que requiere el uso lookup dentro de un bucle no debe convertirse para usar el loop palabra clave. Por ejemplo, en lugar de hacer:
loop:" lookup('fileglob', '*.txt', wantlist=True) "

es más limpio de mantener:

with_fileglob:'*.txt'

Bucles estándar

Iterando sobre una lista simple

Las tareas repetidas se pueden escribir como bucles estándar sobre una lista simple de cadenas. Puede definir la lista directamente en la tarea:

-name: Add several users
  ansible.builtin.user:name:" item "state: present
    groups:"wheel"loop:- testuser1
     - testuser2

Puede definir la lista en un archivo de variables, o en la sección ‘vars’ de su juego, luego consulte el nombre de la lista en la tarea:

loop:" somelist "

Cualquiera de estos ejemplos sería equivalente a:

-name: Add user testuser1
  ansible.builtin.user:name:"testuser1"state: present
    groups:"wheel"-name: Add user testuser2
  ansible.builtin.user:name:"testuser2"state: present
    groups:"wheel"

Puede pasar una lista directamente a un parámetro para algunos complementos. La mayoría de los módulos de embalaje, como mmm y apto, tiene esta capacidad. Cuando esté disponible, pasar la lista a un parámetro es mejor que recorrer la tarea. Por ejemplo:

-name: Optimal yum
  ansible.builtin.yum:name:"  list_of_packages  "state: present

-name: Non-optimal yum, slower and may cause issues with interdependencies
  ansible.builtin.yum:name:"  item  "state: present
  loop:"  list_of_packages  "

Comprobar el documentación del módulo para ver si puede pasar una lista a los parámetros de algún módulo en particular.

Iterando sobre una lista de hashes

Si tiene una lista de hashes, puede hacer referencia a subclaves en un bucle. Por ejemplo:

-name: Add several users
  ansible.builtin.user:name:" item.name "state: present
    groups:" item.groups "loop:-name:'testuser1',groups:'wheel'-name:'testuser2',groups:'root'

Al combinar condicionales con un bucle, el when: El estado de cuenta se procesa por separado para cada artículo. Ver Condicionales básicos con cuando por ejemplo.

Iterando sobre un diccionario

Para recorrer un dictado, use el dict2items:

-name: Using dict2items
  ansible.builtin.debug:msg:" item.key  -  item.value "loop:" dict2items "vars:tag_data:Environment: dev
      Application: payment

Aquí, estamos iterando sobre tag_data e imprimiendo la clave y el valor de la misma.

Registrar variables con un bucle

Puede registrar la salida de un bucle como una variable. Por ejemplo:

-name: Register loop output as a variable
  ansible.builtin.shell:"echo  item "loop:-"one"-"two"register: echo

Cuando usas register con un bucle, la estructura de datos colocada en la variable contendrá un results atributo que es una lista de todas las respuestas del módulo. Esto difiere de la estructura de datos devuelta al usar register sin un bucle:

"changed":true,"msg":"All items completed","results":["changed":true,"cmd":"echo "one" ","delta":"0:00:00.003110","end":"2013-12-19 12:00:05.187153","invocation":"module_args":"echo "one"","module_name":"shell","item":"one","rc":0,"start":"2013-12-19 12:00:05.184043","stderr":"","stdout":"one","changed":true,"cmd":"echo "two" ","delta":"0:00:00.002920","end":"2013-12-19 12:00:05.245502","invocation":"module_args":"echo "two"","module_name":"shell","item":"two","rc":0,"start":"2013-12-19 12:00:05.242582","stderr":"","stdout":"two"]

Los ciclos posteriores sobre la variable registrada para inspeccionar los resultados pueden verse así:

-name: Fail if return code is not 0
  ansible.builtin.fail:msg:"The command ( item.cmd ) did not have a 0 return code"when: item.rc != 0
  loop:" echo.results "

Durante la iteración, el resultado del elemento actual se colocará en la variable:

-name: Place the result of the current item in the variable
  ansible.builtin.shell: echo " item "
  loop:- one
    - two
  register: echo
  changed_when: echo.stdout != "one"

Bucles complejos

Iterando sobre listas anidadas

Puede utilizar expresiones Jinja2 para iterar sobre listas complejas. Por ejemplo, un bucle puede combinar listas anidadas:

-name: Give users access to multiple databases
  community.mysql.mysql_user:name:" item[0] "priv:" item[1] .*:ALL"append_privs: yes
    password:"foo"loop:"product(['clientdb', 'employeedb', 'providerdb'])"

Reintentar una tarea hasta que se cumpla una condición

Nuevo en la versión 1.4.

Puedes usar el until palabra clave para reintentar una tarea hasta que se cumpla una determinada condición. He aquí un ejemplo:

-name: Retry a task until a certain condition is met
  ansible.builtin.shell: /usr/bin/foo
  register: result
  until: result.stdout.find("all systems go") !=-1retries:5delay:10

Esta tarea se ejecuta hasta 5 veces con un retraso de 10 segundos entre cada intento. Si el resultado de cualquier intento tiene “todos los sistemas funcionan” en su salida estándar, la tarea se realiza correctamente. El valor predeterminado para “reintentos” es 3 y “retraso” es 5.

Para ver los resultados de los reintentos individuales, ejecute la obra con -vv.

Cuando ejecuta una tarea con until y registrar el resultado como una variable, la variable registrada incluirá una clave denominada “intentos”, que registra el número de reintentos de la tarea.

Nota

Debes configurar el until parámetro si desea reintentar una tarea. Si until no está definido, el valor de la retries el parámetro se fuerza a 1.

Bucle sobre el inventario

Para recorrer su inventario, o solo un subconjunto de él, puede usar un loop con el ansible_play_batch o groups variables:

-name: Show all the hosts in the inventory
  ansible.builtin.debug:msg:" item "loop:" groups['all'] "-name: Show all the hosts in the current play
  ansible.builtin.debug:msg:" item "loop:" ansible_play_batch "

También hay un complemento de búsqueda específico inventory_hostnames que se puede usar así:

-name: Show all the hosts in the inventory
  ansible.builtin.debug:msg:" item "loop:" query('inventory_hostnames', 'all') "-name: Show all the hosts matching the pattern, ie all but the group www
  ansible.builtin.debug:msg:" item "loop:" query('inventory_hostnames', 'all:!www') "

Puede encontrar más información sobre los patrones en Patrones: dirigidos a hosts y grupos.

Asegurar la entrada de la lista para loop: utilizando query en vez de lookup

los loop la palabra clave requiere una lista como entrada, pero la lookup palabra clave devuelve una cadena de valores separados por comas de forma predeterminada. Ansible 2.5 introdujo una nueva función Jinja2 llamada consulta que siempre devuelve una lista, ofreciendo una interfaz más simple y una salida más predecible de los complementos de búsqueda cuando se usa el loop palabra clave.

Puedes forzar lookup para devolver una lista a loop mediante el uso wantlist=True, o puedes usar query en lugar de.

Estos ejemplos hacen lo mismo:

loop:" query('inventory_hostnames', 'all') "loop:" lookup('inventory_hostnames', 'all', wantlist=True) "

Agregar controles a los bucles

Nuevo en la versión 2.1.

los loop_control La palabra clave le permite administrar sus bucles de manera útil.

Limitar la salida del lazo con label

Nuevo en la versión 2.2.

Cuando recorre estructuras de datos complejas, la salida de la consola de su tarea puede ser enorme. Para limitar la salida mostrada, use el label directiva con loop_control:

-name: Create servers
  digital_ocean:name:" item.name "state: present
  loop:-name: server1
      disks: 3gb
      ram: 15Gb
      network:nic01: 100Gb
        nic02: 10Gb
        ...loop_control:label:" item.name "

El resultado de esta tarea mostrará solo el name campo para cada item en lugar de todo el contenido de la multilínea item variable.

Nota

Esto es para hacer que la salida de la consola sea más legible, no para proteger los datos confidenciales. Si hay datos sensibles en loop, colocar no_log: yes en la tarea de prevenir la divulgación.

Pausando dentro de un bucle

Nuevo en la versión 2.2.

Para controlar el tiempo (en segundos) entre la ejecución de cada elemento en un ciclo de tareas, utilice el pause directiva con loop_control:

# main.yml-name: Create servers, pause 3s before creating next
  community.digitalocean.digital_ocean:name:" item "state: present
  loop:- server1
    - server2
  loop_control:pause:3

Seguimiento del progreso a través de un bucle con index_var

Nuevo en la versión 2.5.

Para realizar un seguimiento de dónde se encuentra en un bucle, utilice el index_var directiva con loop_control. Esta directiva especifica un nombre de variable para contener el índice de bucle actual:

-name: Count our fruit
  ansible.builtin.debug:msg:" item  with index  my_idx "loop:- apple
    - banana
    - pear
  loop_control:index_var: my_idx

Nota

index_var está indexado en 0.

Definición de nombres de variables internas y externas con loop_var

Nuevo en la versión 2.1.

Puede anidar dos tareas de bucle utilizando include_tasks. Sin embargo, por defecto Ansible establece la variable de bucle item para cada bucle. Esto significa que el bucle anidado interno sobrescribirá el valor de item desde el bucle exterior. Puede especificar el nombre de la variable para cada bucle usando loop_var con loop_control:

# main.yml-include_tasks: inner.yml
  loop:-1-2-3loop_control:loop_var: outer_item

# inner.yml-name: Print outer and inner items
  ansible.builtin.debug:msg:"outer item= outer_item  inner item= item "loop:- a
    - b
    - c

Nota

Si Ansible detecta que el ciclo actual está usando una variable que ya ha sido definida, generará un error para fallar la tarea.

Variables de bucle extendido

Nuevo en la versión 2.8.

A partir de Ansible 2.8, puede obtener información de bucle extendido utilizando el extended opción de control de bucle. Esta opción expondrá la siguiente información.

Variable

Descripción

ansible_loop.allitems

La lista de todos los elementos del bucle.

ansible_loop.index

La iteración actual del bucle. (1 indexado)

ansible_loop.index0

La iteración actual del bucle. (0 indexados)

ansible_loop.revindex

El número de iteraciones desde el final del ciclo (1 indexado)

ansible_loop.revindex0

El número de iteraciones desde el final del ciclo (0 indexado)

ansible_loop.first

True si es la primera iteración

ansible_loop.last

True si es la última iteración

ansible_loop.length

La cantidad de elementos en el bucle

ansible_loop.previtem

El elemento de la iteración anterior del ciclo. Indefinido durante la primera iteración.

ansible_loop.nextitem

El elemento de la siguiente iteración del bucle. Indefinido durante la última iteración.

loop_control:extended: yes

Accediendo al nombre de su loop_var

Nuevo en la versión 2.8.

A partir de Ansible 2.8, puede obtener el nombre del valor proporcionado a loop_control.loop_var utilizando el ansible_loop_var variable

Para los autores de roles, escribir roles que permitan bucles, en lugar de dictar los loop_var value, puede recopilar el valor a través de:

" lookup('vars', ansible_loop_var) "

Migrando de with_X a loop

En la mayoría de los casos, los bucles funcionan mejor con loop palabra clave en lugar de with_X bucles de estilo. los loop La sintaxis generalmente se expresa mejor usando filtros en lugar de un uso más complejo de query o lookup.

Estos ejemplos muestran cómo convertir muchos with_ bucles de estilo para loop y filtros.

with_list

with_list es reemplazado directamente por loop.

-name: with_list
  ansible.builtin.debug:msg:" item "with_list:- one
    - two

-name: with_list -> loop
  ansible.builtin.debug:msg:" item "loop:- one
    - two

with_items

with_items es reemplazado por loop y el flatten filtrar.

-name: with_items
  ansible.builtin.debug:msg:" item "with_items:" items "-name: with_items -> loop
  ansible.builtin.debug:msg:" item "loop:"flatten(levels=1) "

with_indexed_items

with_indexed_items es reemplazado por loop, los flatten filtrar y loop_control.index_var.

-name: with_indexed_items
  ansible.builtin.debug:msg:" item.0  -  item.1 "with_indexed_items:" items "-name: with_indexed_items -> loop
  ansible.builtin.debug:msg:" index  -  item "loop:"flatten(levels=1) "loop_control:index_var: index

with_flattened

with_flattened es reemplazado por loop y el flatten filtrar.

-name: with_flattened
  ansible.builtin.debug:msg:" item "with_flattened:" items "-name: with_flattened -> loop
  ansible.builtin.debug:msg:" item "loop:"flatten "

con nosotros

with_together es reemplazado por loop y el zip filtrar.

-name: with_together
  ansible.builtin.debug:msg:" item.0  -  item.1 "with_together:-" list_one "-" list_two "-name: with_together -> loop
  ansible.builtin.debug:msg:" item.0  -  item.1 "loop:" list_one"

Otro ejemplo con datos complejos

- name: with_together -> loop
  ansible.builtin.debug:
    msg: " item.0  -  item.1  -  item.2 "
  loop: "list "
  vars:
    data:
      - ['a', 'b', 'c']
      - ['d', 'e', 'f']
      - ['g', 'h', 'i']

with_dict

with_dict puede ser sustituido por loop y ya sea el dictsort o dict2items filtros.

- name: with_dict
  ansible.builtin.debug:
    msg: " item.key  -  item.value "
  with_dict: " dictionary "

- name: with_dict -> loop (option 1)
  ansible.builtin.debug:
    msg: " item.key  -  item.value "
  loop: "dict2items "

- name: with_dict -> loop (option 2)
  ansible.builtin.debug:
    msg: " item.0  -  item.1 "
  loop: " dictionary"

with_sequence

with_sequence es reemplazado por loop y el range función, y potencialmente el format filtrar.

- name: with_sequence
  ansible.builtin.debug:
    msg: " item "
  with_sequence: start=0 end=4 stride=2 format=testuser%02x

- name: with_sequence -> loop
  ansible.builtin.debug:
    msg: " 'testuser%02x' "
  # range is exclusive of the end point
  loop: "list "

with_subelements

with_subelements es reemplazado por loop y el subelements filtrar.

- name: with_subelements
  ansible.builtin.debug:
    msg: " item.0.name  -  item.1 "
  with_subelements:
    - " users "
    - mysql.hosts

- name: with_subelements -> loop
  ansible.builtin.debug:
    msg: " item.0.name  -  item.1 "
  loop: "subelements('mysql.hosts') "

with_nested / with_cartesian

with_nested y with_cartesian son reemplazados por bucle y el product filtrar.

- name: with_nested
  ansible.builtin.debug:
    msg: " item.0  -  item.1 "
  with_nested:
    - " list_one "
    - " list_two "

- name: with_nested -> loop
  ansible.builtin.debug:
    msg: " item.0  -  item.1 "
  loop: " list_one"

with_random_choice

with_random_choice se reemplaza por el solo uso de la random filtro, sin necesidad de loop.

- name: with_random_choice
  ansible.builtin.debug:
    msg: " item "
  with_random_choice: " my_list "

- name: with_random_choice -> loop (No loop is needed here)
  ansible.builtin.debug:
    msg: "random "
  tags: random

Ver también

Introducción a los libros de jugadas

Introducción a los libros de jugadas

Roles

Organización del libro de jugadas por roles

Consejos y trucos

Consejos y trucos para libros de jugadas

Condicionales

Declaraciones condicionales en los libros de jugadas

Usando Variables

Todo sobre variables

Lista de correo de usuarios

¿Tengo una pregunta? ¡Pasa por el grupo de google!

irc.freenode.net

#ansible canal de chat de IRC