web-dev-qa-db-fra.com

Utiliser set_facts et with_items ensemble dans Ansible

J'utilise actuellement Ansible 1.7.2. J'ai le testbook suivant:

---
- 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 première tâche définit un fait qui est une liste avec un élément. Les tâches suivantes s'ajoutent à cette liste avec plus de valeurs. Les trois premières tâches fonctionnent comme prévu, mais pas la dernière. Voici le résultat lorsque je lance ceci:

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

Compte tenu des éléments with_items de la tâche 4 et du fait que la sortie affiche la tâche correctement itérée sur les éléments de cette liste, je me serais attendu à ce que le résultat contienne tous les nombres de zéro à six. Mais cette dernière tâche ne semble évaluer que set_fact avec le dernier élément de la liste. Est-ce éventuellement un bug dans Ansible?

Edit: Je viens également de tester cela sur ansible 1.8 et la sortie était identique.

52
Bruce P

On dirait que ce comportement est le mode de fonctionnement actuel d’Ansible, bien que l’intérêt de le réparer fonctionne comme souhaité. Il y a actuellement un demande d'extraction avec la fonctionnalité désirée, donc j'espère que cela sera éventuellement intégré à Ansible.

1
Bruce P

Il existe une solution de contournement qui peut aider. Vous pouvez "enregistrer" les résultats pour chaque itération set_fact, puis les mapper à la liste:

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

Sortie:

< TASK: debug var=foo >
 ---------------------
    \   ^__^
     \  (oo)\_______
        (__)\       )\/\
            ||----w |
            ||     ||


ok: [localhost] => {
    "var": {
        "foo": [
            "four", 
            "five", 
            "six"
        ]
    }
}
77
serge

Comme mentionné dans les commentaires d'autres personnes, la solution proposée en priorité ici ne fonctionnait pas pour moi dans Ansible 2.2, en particulier lorsque vous utilisiez également with_items.

Il semble que l'approche envisagée par OP fonctionne maintenant avec un léger changement dans la citation de item.

- set_fact: something="{{ something + [ item ] }}"
  with_items:
    - one
    - two
    - three

Et un exemple plus long où j'ai traité le cas initial de la liste non définie et ajouté un facultatif when parce que cela me causait également du chagrin:

- set_fact: something="{{ something|default([]) + [ item ] }}"
  with_items:
    - one
    - two
    - three
  when: item.name in allowed_things.item_list
11
stacyhorton

Jinja 2.6 n'a pas la fonction de carte. Donc, une autre façon de faire serait:

set_fact: foo="{% for i in bar_result.results %}{{ i.ansible_facts.foo_item }}{%endfor%}"
7
Russ Huguley

Mise à jour 2018-06-08: Ma réponse précédente était un peu de bidouillage alors je suis revenu et ai regardé à nouveau. C'est une approche plus propre de Jinja2.

- name: Set fact 4
  set_fact:
    foo: "{% for i in foo_result.results %}{% do foo.append(i) %}{% endfor %}{{ foo }}"

J'ajoute cette réponse car la meilleure réponse actuelle pour Ansible 2.2+ ne couvre pas complètement la question initiale. Merci à Russ Huguley pour votre réponse, cela m'a permis d'aller dans la bonne direction, mais cela m'a laissé une chaîne concaténée, pas une liste. Cette solution obtient une liste mais devient encore plus compliquée. J'espère que cela sera résolu d'une manière plus propre.

- 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(',') }}"
3
Sam Coffland

Je cherchais une réponse à cette question. J'ai trouvé cela utile. Le modèle n'était pas apparent dans la documentation 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
2
Grant Strachan