webentwicklung-frage-antwort-db.com.de

Verwenden von Ansible set_fact, um ein Wörterbuch aus den Registerergebnissen zu erstellen

In Ansible habe ich register verwendet, um die Ergebnisse einer Aufgabe in der Variablen people zu speichern. Das Zeug weglassen, das ich nicht brauche, es hat diese Struktur:

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

Ich möchte ein nachfolgendes set_fact Aufgabe zum Erzeugen einer neuen Variablen mit einem Wörterbuch wie diesem:

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

Ich denke, das könnte möglich sein, aber ich gehe bisher ohne Glück im Kreis herum.

55
Phil Gyford

Ich glaube, ich bin am Ende dort angekommen.

Die Aufgabe ist wie folgt:

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

Es durchläuft jedes Diktat (item) im Array people.results Und erstellt jedes Mal ein neues Diktat wie {Bob: "male"} Und combine()s dieses neuen Diktats im Array genders, das wie folgt endet:

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

Es wird davon ausgegangen, dass die Schlüssel (in diesem Fall das name) eindeutig sind.


Dann wurde mir klar, dass ich eigentlich eine Liste von Wörterbüchern haben wollte, da es viel einfacher zu sein scheint, mit with_items Durchzugehen:

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

Dadurch wird die vorhandene Liste weiterhin mit einer Liste kombiniert, die ein einzelnes Diktat enthält. Wir erhalten ein genders -Array wie folgt:

[
    {'name': 'Bob', 'gender': 'male'},
    {'name': 'Thelma', 'gender': 'female'}
]
97
Phil Gyford

Vielen Dank, Phil, für deine Lösung. für den fall, dass sich jemand in der gleichen situation wie ich befindet, hier eine (komplexere) variante:

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

Dies ergibt die folgende Ausgabe (für das Beispiel entfernt):

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

Wenn Sie noch weiter gehen, analysieren Sie die Listen in 'value':

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

Ein paar Dinge zu beachten:

  • in diesem Fall muss alles "abgeschnitten" werden (mit dem >- in YAML und -%} in Jinja ), sonst bekommst du eine Fehlermeldung wie:

    FAILED! => {"failed": true, "msg": "|combine expects dictionaries, got u\"  {u'...
    
  • offensichtlich ist der {% if .. alles andere als kugelsicher

  • im Postfix-Fall hätte val.split(',')|map('trim')|list zu val.split(', ') vereinfacht werden können, aber ich wollte darauf hinweisen, dass Sie |list benötigen, da sonst eine Fehlermeldung angezeigt wird mögen:

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

Hoffe das kann helfen.

11
bufh