在Ansible中,我使用const mongodb = require('mongodb');
const MongoClient = mongodb.MongoClient;
function randomIndex() {
return Math.ceil(Math.random() * 2100);
}
MongoClient.connect('mongodb://localhost/somedb').then(db => {
let collection = db.collection('somecollection');
db.on('close', err => console.log('close', err));
db.on('reconnect', () => console.trace('reconnect'));
setInterval(() => {
collection.find({
index: randomIndex()
}).limit(1).next()
.then(console.log)
.catch(console.log);
}, 1000);
});
将任务的结果保存在变量register
中。省略我不需要的东西,它有这样的结构:
people
我想使用后续{
"results": [
{
"item": {
"name": "Bob"
},
"stdout": "male"
},
{
"item": {
"name": "Thelma"
},
"stdout": "female"
}
]
}
任务生成一个带有这样字典的新变量:
set_fact
我想这可能是可能的,但到目前为止我还没有运气。
答案 0 :(得分:83)
我想我最终到了那里。
任务是这样的:
- name: Populate genders
set_fact:
genders: "{{ genders|default({}) | combine( {item.item.name: item.stdout} ) }}"
with_items: "{{ people.results }}"
它遍历item
数组中的每个词组(people.results
),每次创建一个新的词典,如{Bob: "male"}
,combine()
s新的词典, genders
数组,最终结果如下:
{
"Bob": "male",
"Thelma": "female"
}
它假定键(在这种情况下为name
)将是唯一的。
然后我意识到我实际上想要一个字典列表,因为使用with_items
循环似乎要容易得多:
- name: Populate genders
set_fact:
genders: "{{ genders|default([]) + [ {'name': item.item.name, 'gender': item.stdout} ] }}"
with_items: "{{ people.results }}"
这使现有列表与包含单个字典的列表保持组合。我们最终得到一个genders
数组:
[
{'name': 'Bob', 'gender': 'male'},
{'name': 'Thelma', 'gender': 'female'}
]
答案 1 :(得分:11)
谢谢Phil的解决方案;如果有人遇到与我相同的情况,这里有一个(更复杂的)变体:
---
# 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
这将给出以下输出(为示例剥离):
"postconf_d": {
"alias_database": "hash:/etc/aliases",
"alias_maps": "hash:/etc/aliases, nis:mail.aliases",
"allow_min_user": "no",
"allow_percent_hack": "yes"
}
更进一步,解析'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"
}
需要注意的一些事项:
在这种情况下,需要“修剪”所有内容(使用YAML中的>-
和Jinja中的-%}
,否则您将得到一个错误如:
FAILED! => {"failed": true, "msg": "|combine expects dictionaries, got u\" {u'...
显然{% if ..
远非防弹
在后缀的情况下,val.split(',')|map('trim')|list
可能已简化为val.split(', ')
,但我想指出您需要|list
的事实,否则您将获得错误如:
"|combine expects dictionaries, got u\"{u'...': <generator object do_map at ...
希望这可以提供帮助。