web-dev-qa-db-de.com

Ansible - Wie können neue Schlüssel zu einem Wörterbuch hinzugefügt werden, wenn das set_fact-Modul mit with_items verwendet wird?

Ich möchte einem Wörterbuch Schlüssel hinzufügen, wenn set_fact mit with_items verwendet wird. Dies ist ein kleiner POC, der mir helfen wird, andere Arbeiten abzuschließen. Ich habe versucht, den POC zu verallgemeinern, um alle irrelevanten Details daraus zu entfernen.

Wenn ich folgenden Code ausführen, wird ein Wörterbuch angezeigt, das nur einen Schlüssel enthält, der dem letzten Element des with_items entspricht. Es scheint, dass es ein neues Wörterbuch neu erstellt oder ein vorhandenes Wörterbuch für jedes Element in den with_items überschreibt. Ich möchte ein einziges Wörterbuch mit allen Schlüsseln.

Code:

---
- hosts: localhost
  connection: local
  vars:
      some_value: 12345
      dict: {}
  tasks:
     - set_fact: {
          dict: "{
             {{ item }}: {{ some_value }}
             }"
            }
       with_items:
          - 1
          - 2
          - 3
     - debug: msg="{{ dict }}"
13
Anand Patel

Verwenden Sie ein filter plugin .

Erstellen Sie zunächst eine neue Datei mit dem Namen filter_plugins/makedict.py in Ihrem verfügbaren Basisverzeichnis.

Erstellen Sie nun eine neue Funktion namens "makedict" (oder was immer Sie möchten), die einen Wert und eine Liste übernimmt und ein neues Wörterbuch zurückgibt, in dem die Schlüssel die Elemente der Liste sind und der Wert immer derselbe ist.

class FilterModule(object):
     def filters(self):
         return { 'makedict': lambda _val, _list: { k: _val for k in _list }  }

Jetzt können Sie den neuen Filter im Playbook verwenden, um das gewünschte Ergebnis zu erzielen:

- hosts: 127.0.0.1
  connection: local
  vars:
      my_value: 12345
      my_keys: [1, 2, 3]
  tasks:
    - set_fact: my_dict="{{ my_value | makedict(my_keys) }}"
    - debug: msg="{{ item.key }}={{ item.value }}"
      with_dict: "{{my_dict}}"

Sie können die Position des Filter-Plugins anpassen, indem Sie die Option filter_plugins in ansible.cfg verwenden.

6
Ben Whaley

Dies ist auch möglich, ohne auf in Ansible 2.2 getestete Plugins zurückzugreifen.

---
- hosts: localhost
  connection: local
  vars:
    some_value: 12345
    dict: {}
  tasks:
  - set_fact:
      dict: "{{ dict | combine( { item: some_value } ) }}"
    with_items:
      - 1
      - 2
      - 3
  - debug: msg="{{ dict }}"

Alternativ kann dies ohne den komplexen One-Liner mit einer Include-Datei geschrieben werden. 

  tasks:
  - include: append_dict.yml
    with_items: [1, 2, 3]

append_dict.yml:

- name: "Append dict: define helper variable"
  set_fact:
    _append_dict: "{ '{{ item }}': {{ some_value }} }"

- name: "Append dict: execute append"
  set_fact:
    dict: "{{ dict | combine( _append_dict ) }}"

Ausgabe:

TASK [debug]
*******************************************************************
ok: [localhost] => {
    "msg": {
        "1": "12345",
        "2": "12345",
        "3": "12345"
    }
}

Die Anführungszeichen ' um {{ some_value }} werden benötigt, um Zeichenfolgenwerte explizit zu speichern.

Diese Syntax kann auch verwendet werden, um dict elementweise mit with_dict anzuhängen, indem auf item.key und item.value verwiesen wird.

Manipulationen wie das Hinzufügen von Prä- und Postfixes oder Hashes können zum Beispiel im selben Schritt durchgeführt werden

    set_fact:
      dict: "{{ dict | combine( { item.key + key_postfix: item.value + '_' +  item.value | hash('md5') } ) }}"
22
Andreas

das scheint auf ansible 2.5 nicht mehr zu funktionieren

---
- hosts: localhost
  connection: local
  vars:
    some_value: 12345
    dict: {}
  tasks:
  - set_fact:
      dict: "{{ dict | combine( { item: some_value } ) }}"
    with_items:
      - 1
      - 2
      - 3
  - debug: msg="{{ dict }}"

gibt nur den letzten Wert zurück {"dict":{"3": "some value"}}

Ich schlage vor, Sie könnten das tun:

- set_fact:
    __dict: |
        {% for item in  [1,2,3] %}
        {{item}}: "value"
        {% endfor %}

- set_fact:
    final_dict: "{{__dict|from_yaml}}"

- debug: 
  var: final_dict
1