使用Ansible set_fact从寄存器结果创建字典

使用Ansible set_fact从寄存器结果创建字典,ansible,Ansible,在Ansible中,我使用register将任务结果保存在变量people中。省略我不需要的东西,它有这样的结构: { “结果”:[ { “项目”:{ “姓名”:“鲍勃” }, “stdout”:“男性” }, { “项目”:{ “名称”:“Thelma” }, “stdout”:“女性” } ] } 我想使用一个后续的set\u fact任务来生成一个新的变量,其字典如下: { “鲍勃”:“男”, “塞尔玛”:“女性” } 我想这可能是可能的,但到目前为止我一直在兜圈子,运气都不好。我想我

在Ansible中,我使用
register
将任务结果保存在变量
people
中。省略我不需要的东西,它有这样的结构:

{
“结果”:[
{
“项目”:{
“姓名”:“鲍勃”
},
“stdout”:“男性”
},
{
“项目”:{
“名称”:“Thelma”
},
“stdout”:“女性”
}
]
}
我想使用一个后续的
set\u fact
任务来生成一个新的变量,其字典如下:

{
“鲍勃”:“男”,
“塞尔玛”:“女性”
}

我想这可能是可能的,但到目前为止我一直在兜圈子,运气都不好。

我想我最终到达了那里

任务如下:

-名称:填充性别
设定事实:
genders:{{genders | default({})| combine({item.item.name:item.stdout})}
带_项:“{people.results}”
它循环遍历
人物中的每个dict(
)。结果
数组,每次创建一个新的dict,如
{Bob:“male”}
,然后
组合()
genders
数组中创建新的dict,结果如下:

{
“鲍勃”:“男”,
“塞尔玛”:“女性”
}
它假定键(本例中的
名称
)是唯一的


然后我意识到我实际上想要一个字典列表,因为使用
和\u项循环似乎要容易得多:

-名称:填充性别
设定事实:
性别:{{genders}默认值([])+[{'name':item.item.name,'gender':item.stdout}]}”
带_项:“{people.results}”
这将继续将现有列表与包含单个dict的列表相结合。我们最终得到一个
genders
数组,如下所示:

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

感谢Phil提供的解决方案;如果有人遇到与我相同的情况,这里有一个(更复杂的)变体:

---
#这只是为了避免在每次迭代中调用| default
-设定事实:
邮政编码:{}
-名称:“获取后缀默认配置”
命令:“postconf-d”
寄存器:命令
#命令的答案给出了一个行列表,例如:
#“key=value”或“key=”值为空时
-名称:“将后缀默认配置设置为事实”
设定事实:
邮政编码:>
{{
邮政编码|
结合(
dict([item.partition('=')[::2]| map('trim'))
)
带\u项:command.stdout\u行
这将给出以下输出(示例为剥离):

“邮政编码”:{
“别名数据库”:“哈希:/etc/alias”,
“别名映射”:“哈希:/etc/aliases,nis:mail.aliases”,
“允许用户”:“否”,
“允许百分比黑客”:“是”
}
更进一步,分析“值”中的列表:

-name:“将后缀默认配置设置为事实”
设定事实:
邮政编码:>-
{%set key,val=item.partition('=')[::2]| map('trim')-%}
{%if',在val-%}
{%set val=val.split(',')| map('trim')| list-%}
{%endif-%}
{{postfix_default_main_cf|combine({key:val}}}}
带\u项:command.stdout\u行
...
“邮政编码”:{
“别名数据库”:“哈希:/etc/alias”,
“别名映射”:[
“哈希:/etc/别名”,
“nis:mail.Alias”
], 
“允许用户”:“否”,
“允许百分比黑客”:“是”
}
需要注意的几件事:

  • 在这种情况下,需要“修剪”所有内容(使用中的
    -
    和中的
    -%}
    ),否则会出现如下错误:

    FAILED! => {"failed": true, "msg": "|combine expects dictionaries, got u\"  {u'...
    
    "|combine expects dictionaries, got u\"{u'...': <generator object do_map at ...
    
  • 显然,
    {%if..
    远不是防弹的

  • 在后缀的情况下,
    val.split(',')| map('trim')| list
    可以简化为
    val.split(',')
    ,但我想指出的是,您需要
    | list
    ,否则会出现如下错误:

    FAILED! => {"failed": true, "msg": "|combine expects dictionaries, got u\"  {u'...
    
    "|combine expects dictionaries, got u\"{u'...': <generator object do_map at ...
    

    “| combine需要字典,得到u\”{u'…”:如果使用默认筛选器,可以避免声明空字典。
    genders:{{genders | default({})| combine({item.item.name:item.stdout}}
    谢谢@smicyk-我在示例中添加了您方便的建议。第二个示例应该是:genders:
    ”{{genders | default([])+[{'name':item.item.name,'gender':item.stdout}}“
    ,使用默认数组而不是默认对象。感谢@OlivierLecrivain-我修复了该示例。无论如何,要在Ansible pre-2.0中执行此操作?请注意,由于Ansible v2.2,with_项需要显式jinja2包装。因此,第一个示例是:-名称:填充性别集_事实:性别:{{genders |默认({})|合并({item.item.name:item.stdout}}和{u items:{{people.results}}为
    -%}
    注释准备了很多坦克!我已经为此奋斗了好几个星期了。这是一个很好的提示!只需一个注释,除了最后需要的
    {%-…-%}之外,至少每行都有Ansible 2.4.3
    在开括号和关括号上都有破折号,否则这篇文章会被解读为字符串谢谢你的这篇技巧,
    -
    -%}
    奇怪的事情要想弄清楚是非常耗时的。我欠你的。谢谢。