Using Ansible set_fact to create a dictionary from register results
在ansible中,我使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | { "results": [ { "item": { "name":"Bob" }, "stdout":"male" }, { "item": { "name":"Thelma" }, "stdout":"female" } ] } |
我想使用后续的
1 2 3 4 | { "Bob":"male", "Thelma":"female" } |
我想这可能是有可能的,但到目前为止,我已经走投无路了。
我想我终于到了那里。
任务如下:
1 2 3 4 | - name: Populate genders set_fact: genders:"{{ genders|default({}) | combine( {item.item.name: item.stdout} ) }}" with_items:"{{ people.results }}" |
它循环遍历
1 2 3 4 | { "Bob":"male", "Thelma":"female" } |
它假定键(本例中的
然后我意识到我实际上想要一个字典列表,因为使用
1 2 3 4 | - name: Populate genders set_fact: genders:"{{ genders|default([]) + [ {'name': item.item.name, 'gender': item.stdout} ] }}" with_items:"{{ people.results }}" |
这会不断地将现有列表与包含单个dict的列表组合在一起。我们最终得到一个这样的
1 2 3 4 | [ {'name': 'Bob', 'gender': 'male'}, {'name': 'Thelma', 'gender': 'female'} ] |
感谢Phil提供的解决方案;如果有人遇到与我相同的情况,这里有一个(更复杂的)变体:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | --- # 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 |
这将提供以下输出(例如剥离):
1 2 3 4 5 6 | "postconf_d": { "alias_database":"hash:/etc/aliases", "alias_maps":"hash:/etc/aliases, nis:mail.aliases", "allow_min_user":"no", "allow_percent_hack":"yes" } |
更进一步,分析"value"中的列表:
1 2 3 4 5 6 7 8 9 10 | - 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 ... |
1 2 3 4 5 6 7 8 9 | "postconf_d": { "alias_database":"hash:/etc/aliases", "alias_maps": [ "hash:/etc/aliases", "nis:mail.aliases" ], "allow_min_user":"no", "allow_percent_hack":"yes" } |
需要注意的几点:
在这种情况下,需要"修剪"一切(使用yaml中的
>- 和jinja中的-%} ),否则会出现如下错误:1FAILED! => {"failed": true,"msg":"|combine expects dictionaries, got u" {u'...显然,
{% if .. 远不是防弹的。在后缀的情况下,
val.split(',')|map('trim')|list 可以简化为val.split(', ') ,但我想指出的是,你需要|list 否则你会得到如下错误:1"|combine expects dictionaries, got u"{u'...': <generator object do_map at ...
希望这能有所帮助。