it-swarm.com.de

Set_facts und with_items zusammen in Ansible verwenden

Ich verwende derzeit Ansible 1.7.2. Ich habe das folgende Test-Playbook:

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

Die erste Aufgabe legt eine Tatsache fest, die eine Liste mit einem Element enthält. Die nachfolgenden Aufgaben werden mit weiteren Werten an diese Liste angehängt. Die ersten drei Aufgaben funktionieren wie erwartet, die letzte jedoch nicht. Hier ist die Ausgabe, wenn ich das ausführe:

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

Angesichts der with_items in Task 4 und der Tatsache, dass in der Ausgabe die Task korrekt über die Elemente in dieser Liste iteriert wird, hätte ich erwartet, dass das Ergebnis alle Zahlen von null bis sechs enthält. Aber diese letzte Aufgabe scheint nur zu sein, set_fact mit dem letzten Element in der Liste auszuwerten. Ist dies möglicherweise ein Fehler in Ansible?

Edit: Ich habe dies auch gerade auf Ansible 1.8 getestet und die Ausgabe war identisch.

52
Bruce P

Anscheinend funktioniert Ansible so, obwohl großes Interesse daran besteht, das Problem so zu beheben, dass es wie gewünscht funktioniert. Derzeit gibt es eine Pull-Anfrage mit der gewünschten Funktionalität, sodass diese hoffentlich irgendwann in Ansible integriert wird.

1
Bruce P

Es gibt eine Problemumgehung, die möglicherweise Abhilfe schafft. Sie können Ergebnisse für jede set_fact-Iteration "registrieren" und diese Ergebnisse dann einer Liste zuordnen:

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

Ausgabe:

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


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

Wie in anderen Kommentaren erwähnt, hat die hier angegebene Top-Lösung in Ansible 2.2 nicht funktioniert, insbesondere, wenn auch with_items.

Es scheint, dass der beabsichtigte Ansatz von OP jetzt mit einer geringfügigen Änderung der Angabe von item funktioniert.

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

Und ein längeres Beispiel, in dem ich den anfänglichen Fall behandelt habe, dass die Liste undefiniert ist, und ein optionales when hinzugefügt habe, weil das mich auch betrübt hat:

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

Jinja 2.6 verfügt nicht über die Kartenfunktion. Eine andere Möglichkeit wäre also:

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

Aktualisiert 2018-06-08: Meine vorherige Antwort war ein bisschen Hack, also bin ich zurückgekommen und habe mir das noch einmal angesehen. Dies ist ein sauberer Jinja2-Ansatz.

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

Ich füge diese Antwort als aktuell beste Antwort hinzu, da Ansible 2.2+ die ursprüngliche Frage nicht vollständig abdeckt. Dank Russ Huguley für Ihre Antwort bin ich in die richtige Richtung gegangen, aber es blieb mir eine verkettete Zeichenfolge und keine Liste übrig. Diese Lösung bekommt eine Liste, wird aber noch hackiger. Ich hoffe, dass dies sauberer gelöst wird.

- 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

Ich habe nach einer Antwort auf diese Frage gesucht. Ich fand das hilfreich. Das Muster war in der Dokumentation für with_items nicht ersichtlich.

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