tower - Usando set_facts y with_items juntos en Ansible
ansible tutorial (6)
Actualizado 2018-06-08: mi respuesta anterior fue un poco de pirateo, así que volví y miré esto nuevamente. Este es un enfoque más limpio de Jinja2.
- name: Set fact 4
set_fact:
foo: "{% for i in foo_result.results %}{% do foo.append(i) %}{% endfor %}{{ foo }}"
Estoy agregando esta respuesta como la mejor respuesta actual para Ansible 2.2+ no cubre completamente la pregunta original. Gracias a Russ Huguley por su respuesta, esto me llevó en la dirección correcta, pero me dejó con una cadena concatenada, no una lista. Esta solución obtiene una lista pero se vuelve aún más hacky. Espero que esto se resuelva de una manera más limpia.
- name: build foo_string
set_fact:
foo_string: "{% for i in foo_result.results %}{{ i.ansible_facts.foo_item }}{% if not loop.last %},{% endif %}{%endfor%}"
- name: set fact foo
set_fact:
foo: "{{ foo_string.split('','') }}"
Actualmente estoy usando Ansible 1.7.2. Tengo el siguiente libro de jugadas de prueba:
---
- hosts: localhost
tasks:
- name: set fact 1
set_fact: foo="[ ''zero'' ]"
- name: set fact 2
set_fact: foo="{{ foo }} + [ ''one'' ]"
- name: set fact 3
set_fact: foo="{{ foo }} + [ ''two'', ''three'' ]"
- name: set fact 4
set_fact: foo="{{ foo }} + [ ''{{ item }}'' ]"
with_items:
- four
- five
- six
- debug: var=foo
La primera tarea establece un hecho que es una lista con un elemento. Las tareas posteriores se agregan a esa lista con más valores. Las primeras tres tareas funcionan como se esperaba, pero la última no. Aquí está la salida cuando ejecuto esto:
PLAY [localhost] **************************************************************
GATHERING FACTS ***************************************************************
ok: [localhost]
TASK: [set fact 1] ************************************************************
ok: [localhost]
TASK: [set fact 2] ************************************************************
ok: [localhost]
TASK: [set fact 3] ************************************************************
ok: [localhost]
TASK: [set fact 4] ************************************************************
ok: [localhost] => (item=four)
ok: [localhost] => (item=five)
ok: [localhost] => (item=six)
TASK: [debug var=foo] *********************************************************
ok: [localhost] => {
"foo": [
"zero",
"one",
"two",
"three",
"six"
]
}
PLAY RECAP ********************************************************************
localhost : ok=6 changed=0 unreachable=0 failed=0
Dados los elementos with_items en la tarea 4 y el hecho de que la salida muestra la tarea correctamente iterada sobre los elementos de esa lista, hubiera esperado que el resultado contuviera todos los números del cero al seis. Pero esa última tarea parece solo evaluar set_fact con el último elemento de la lista. ¿Es esto posiblemente un error en Ansible?
Editar: También acabo de probar esto en ansible 1.8 y la salida fue idéntica.
Como se mencionó en los comentarios de otras personas, la solución principal dada aquí no funcionaba para mí en Ansible 2.2, particularmente cuando también usaba
with_items
.
Parece que el enfoque previsto de OP funciona ahora con un ligero cambio en la cita del
item
.
- set_fact: something="{{ something + [ item ] }}"
with_items:
- one
- two
- three
Y un ejemplo más largo en el que manejé el caso inicial de que la lista no esté definida y agregué un opcional
when
porque eso también me estaba causando dolor:
- set_fact: something="{{ something|default([]) + [ item ] }}"
with_items:
- one
- two
- three
when: item.name in allowed_things.item_list
Estaba buscando una respuesta a esta pregunta. Encontré esto útil. El patrón no era aparente en la documentación de with_items.
https://github.com/ansible/ansible/issues/39389
- hosts: localhost
connection: local
gather_facts: no
tasks:
- name: set_fact
set_fact:
foo: "{{ foo }} + [ ''{{ item }}'' ]"
with_items:
- "one"
- "two"
- "three"
vars:
foo: []
- name: Print the var
debug:
var: foo
Hay una solución alternativa que puede ayudar. Puede "registrar" resultados para cada iteración set_fact y luego asignar esos resultados a la lista:
---
- hosts: localhost
tasks:
- name: set fact
set_fact: foo_item="{{ item }}"
with_items:
- four
- five
- six
register: foo_result
- name: make a list
set_fact: foo="{{ foo_result.results | map(attribute=''ansible_facts.foo_item'') | list }}"
- debug: var=foo
Salida:
< TASK: debug var=foo >
---------------------
/ ^__^
/ (oo)/_______
(__)/ )///
||----w |
|| ||
ok: [localhost] => {
"var": {
"foo": [
"four",
"five",
"six"
]
}
}
Jinja 2.6 no tiene la función de mapa. Entonces, una forma alternativa de hacer esto sería:
set_fact: foo="{% for i in bar_result.results %}{{ i.ansible_facts.foo_item }}{%endfor%}"
Parece que este comportamiento es el funcionamiento actual de Ansible, aunque hay mucho interés en arreglarlo para que funcione según lo deseado. Actualmente hay una solicitud de extracción con la funcionalidad deseada, así que espero que eventualmente se incorpore a Ansible.