Utiliser un ensemble de faits possible pour créer un dictionnaire à partir des résultats de registre

Dans Ansible j'ai utilisé register pour enregistrer les résultats d'une tâche dans la variable people. Omettant les choses dont je n'ai pas besoin, il a cette structure:

{
    "results": [
        {
            "item": {
                "name": "Bob"
            },
            "stdout": "male"
        },
        {
            "item": {
                "name": "Thelma"
            },
            "stdout": "female"
        }
    ]
}

j'aimerais utiliser un subséquente set_fact tâche pour générer une nouvelle variable avec un dictionnaire comme ceci:

{
    "Bob": "male",
    "Thelma": "female"
}

je suppose que c'est peut-être possible, mais je tourne en rond sans succès jusqu'à présent.

35
demandé sur Phil Gyford 2016-02-24 18:00:00

2 réponses

je crois que j'y suis arrivé à la fin.

La tâche est comme ceci:

- name: Populate genders
  set_fact:
    genders: "{{ genders|default({}) | combine( {item.item.name: item.stdout} ) }}"
  with_items: "{{ people.results }}"

Il parcourt chacun des dicts (item)people.results array, chaque fois la création d'un nouveau dict comme {Bob: "male"} et combine()s que de nouvelles dict dans le genders array, qui se termine comme:

{
    "Bob": "male",
    "Thelma": "female"
}

Il assume les touches (name dans ce cas) sera unique.


j'ai alors réalisé que je voulais une liste de dictionnaires, comme il semble beaucoup plus facile à Boucler en utilisant with_items:

- name: Populate genders
  set_fact:
    genders: "{{ genders|default([]) + [ {'name': item.item.name, 'gender': item.stdout} ] }}"
  with_items: "{{ people.results }}"

cela permet de combiner la liste existante avec une liste contenant un seul dict. Nous nous retrouvons avec un genders array comme ceci:

[
    {'name': 'Bob', 'gender': 'male'},
    {'name': 'Thelma', 'gender': 'female'}
]
65
répondu Phil Gyford 2017-08-23 15:12:42

Merci Phil pour votre solution; au cas où quelqu'un se retrouve dans la même situation que moi, voici une variante (plus complexe):

---
# this is just to avoid a call to |default on each iteration
- set_fact:
    postconf_d: {}

- name: 'get postfix default configuration'
  command: 'postconf -d'
  register: command

# the answer of the command give a list of lines such as:
# "key = value" or "key =" when the value is null
- name: 'set postfix default configuration as fact'
  set_fact:
    postconf_d: >
      {{
        postconf_d |
        combine(
          dict([ item.partition('=')[::2]|map('trim') ])
        )
  with_items: command.stdout_lines

ceci donnera la sortie suivante (stripped pour l'exemple):

"postconf_d": {
    "alias_database": "hash:/etc/aliases", 
    "alias_maps": "hash:/etc/aliases, nis:mail.aliases",
    "allow_min_user": "no", 
    "allow_percent_hack": "yes"
}

aller encore plus loin, parcourir les listes dans la 'valeur':

- name: 'set postfix default configuration as fact'
  set_fact:
    postconf_d: >-
      {% set key, val = item.partition('=')[::2]|map('trim') -%}
      {% if ',' in val -%}
        {% set val = val.split(',')|map('trim')|list -%}
      {% endif -%}
      {{ postfix_default_main_cf | combine({key: val}) }}
  with_items: command.stdout_lines
...
"postconf_d": {
    "alias_database": "hash:/etc/aliases", 
    "alias_maps": [
        "hash:/etc/aliases", 
        "nis:mail.aliases"
    ], 
    "allow_min_user": "no", 
    "allow_percent_hack": "yes"
}

A peu de choses à noter:

  • dans ce cas, il est nécessaire de "couper" tout (en utilisant le >- YAML et -%} Jinja), sinon vous obtiendrez une erreur comme:

    FAILED! => {"failed": true, "msg": "|combine expects dictionaries, got u\"  {u'...
    
  • évidemment, le {% if .. est loin d'être à l'épreuve des balles

  • dans le cas de postfix,val.split(',')|map('trim')|list aurait pu être simplifié à val.split(', '), mais je voulais souligner le fait que vous aurez besoin d' |list sinon vous obtiendrez une erreur comme:

    "|combine expects dictionaries, got u\"{u'...': <generator object do_map at ...
    

j'Espère que cela peut aider.

9
répondu bufh 2017-07-27 06:20:54