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.
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'}
]
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.