web-dev-qa-db-fra.com

Ansible - Comment continuer à ajouter de nouvelles clés à un dictionnaire lors de l'utilisation du module set_fact avec with_items?

Je veux ajouter des clés à un dictionnaire lorsque j'utilise set_fact avec with_items. C'est un petit POC qui m'aidera à compléter d'autres travaux. J'ai essayé de généraliser le POC afin d'en supprimer tous les détails non pertinents.

Lorsque j'exécute le code suivant, il affiche un dictionnaire avec une seule clé qui correspond au dernier élément du paramètre with_items. Il semble qu’il recrée un nouveau dictionnaire ou remplace un dictionnaire existant pour chaque élément des éléments with_items. Je veux un seul dictionnaire avec toutes les clés.

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

Utilisez un plugin filter .

Commencez par créer un nouveau fichier dans votre répertoire de base ansible appelé filter_plugins/makedict.py.

Créez maintenant une nouvelle fonction appelée "makedict" (ou ce que vous voulez) qui prend une valeur et une liste et renvoie un nouveau dictionnaire dans lequel les clés sont les éléments de la liste et la valeur est toujours la même.

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

Maintenant, vous pouvez utiliser le nouveau filtre dans le livre de lecture pour obtenir le résultat souhaité:

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

Vous pouvez personnaliser l'emplacement du plugin de filtre en utilisant l'option filter_plugins dans ansible.cfg.

6
Ben Whaley

Cela peut aussi être fait sans avoir recours à des plugins, testés dans Ansible 2.2.

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

Alternativement, cela peut être écrit sans le one-liner complexe avec un fichier d'inclusion. 

  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 ) }}"

Sortie:

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

Des guillemets simples ' autour de {{ some_value }} sont nécessaires pour stocker explicitement les valeurs de chaîne.

Cette syntaxe peut également être utilisée pour ajouter un élément dict à l'aide de with_dict en faisant référence à item.key et item.value.

Des manipulations telles que l’ajout de préfixes et postfixes ou de hachages peuvent être effectuées à la même étape, par exemple

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

cela ne semble plus fonctionner sur ansible 2.5

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

ne renvoie que la dernière valeur {"dict":{"3": "some value"}}

Je vous suggère de faire ceci:

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

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

- debug: 
  var: final_dict
1