Ansible-如何组合列表属性?
我有两个单独的清单。第一个是包含基本参数的列表(基本列表),第二个是包含特定机架参数的列表(开发列表)Ansible-如何组合列表属性?,ansible,jinja2,jq,ansible-inventory,Ansible,Jinja2,Jq,Ansible Inventory,我有两个单独的清单。第一个是包含基本参数的列表(基本列表),第二个是包含特定机架参数的列表(开发列表) "base_list": [ { "name": "kibana", "path": "kibana/conf/kibana.xml", "src": "/Users/ansible/inventories/_base/group_vars/kibana/conf/kibana.xml" }, { "nam
"base_list": [
{
"name": "kibana",
"path": "kibana/conf/kibana.xml",
"src": "/Users/ansible/inventories/_base/group_vars/kibana/conf/kibana.xml"
},
{
"name": "logstash",
"path": "logstash/conf/logstash.yml",
"src": "/Users/ansible/inventories/_base/group_vars/logstash/conf/logstash.yml"
},
{
"name": "grafana",
"path": "grafana/conf/grafana.json",
"src": "/Users/ansible/inventories/_base/group_vars/grafana/conf/grafana.json"
},
{
"name": "grafana",
"path": "grafana/conf/nginx.json",
"src": "/Users/ansible/inventories/_base/group_vars/grafana/conf/nginx.json"
},
{
"name": "grafana",
"path": "grafana/conf/config.json",
"src": "/Users/ansible/inventories/_base/group_vars/grafana/conf/config.json"
},
]
"dev_list": [
{
"name": "kibana",
"path": "kibana/conf/kibana.xml",
"src": "/Users/ansible/inventories/dev-st/group_vars/kibana/conf/kibana.xml"
},
{
"name": "logstash",
"path": "logstash/conf/jvm.options",
"src": "/Users/ansible/inventories/dev-st/group_vars/logstash/conf/jvm.options"
}
]
我的目标是将这两个列表结合起来,得到一个item.name和几个item.path和item.src。如下所示的路径:
"end_list": [
{
"name": "kibana",
"path": "kibana/conf/kibana.xml",
"src": "/Users/ansible/inventories/dev-st/group_vars/kibana/conf/kibana.xml"
},
{
"name": "logstash",
"path": [
"logstash/conf/logstash.yml",
"logstash/conf/jvm.options"
],
"src": [
"/Users/ansible/inventories/_base/group_vars/logstash/conf/logstash.yml",
"/Users/ansible/inventories/dev-st/group_vars/logstash/conf/jvm.options"
]
},
{
"name": "grafana",
"path": [
"grafana/conf/grafana.json",
"grafana/conf/nginx.json",
"grafana/conf/config.json"
]
"src": [
"/Users/ansible/inventories/_base/group_vars/grafana/conf/grafana.json",
"/Users/ansible/inventories/_base/group_vars/grafana/conf/nginx.json",
"/Users/ansible/inventories/_base/group_vars/grafana/conf/config.json"
]
},
]
{
'name': item.0.name,
'path': item.1.path|ternary([item.0.path, item.1.path], item.0.path),
'src': item.1.src|ternary([item.0.src, item.1.src], item.1.src)
}
做这件事的最佳方法是什么?使用自定义Python过滤器可能会更容易,但这里有一个使用Ansible内置过滤器的解决方案:
---
- hosts: localhost
gather_facts: false
vars:
"base_list": [
{
"name": "kibana",
"path": "kibana/conf/kibana.xml",
"src": "/Users/ansible/inventories/_base/group_vars/kibana/conf/kibana.xml"
},
{
"name": "logstash",
"path": "logstash/conf/logstash.yml",
"src": "/Users/ansible/inventories/_base/group_vars/logstash/conf/logstash.yml"
},
{
"name": "grafana",
"path": "grafana/conf/grafana.json",
"src": "/Users/ansible/inventories/_base/group_vars/grafana/conf/grafana.json"
},
]
"dev_list": [
{
"name": "kibana",
"path": "kibana/conf/kibana.xml",
"src": "/Users/ansible/inventories/dev-st/group_vars/kibana/conf/kibana.xml"
},
{
"name": "logstash",
"path": "logstash/conf/jvm.options",
"src": "/Users/ansible/inventories/dev-st/group_vars/logstash/conf/jvm.options"
}
]
tasks:
- set_fact:
end_list: >-
{{ end_list|default([]) + [
{
'name': item.0.name,
'path': item.1.path|ternary([item.0.path, item.1.path], item.0.path),
'src': item.1.src|ternary([item.0.src, item.1.src], item.1.src)
}
]}}
loop: >-
{{ base_list|zip_longest(dev_list,
fillvalue={'path': false, 'src': false})|list }}
- debug:
var: end_list
这是一个有点棘手的组合,所以我将尝试描述各个部分:
循环使用过滤器。给定列表list1=[1,2,3]
和list2=[11,12]
,list1 | zip|u longest(list2)
将生成[[1,11],[2,12],[3,None]]
(即默认情况下,zip|最长
将使用None
作为一个列表短于另一个列表的填充值)。通过设置fillvalue
参数,我们可以使用None
以外的值。在这种情况下
loop: >-
{{ base_list|zip_longest(dev_list,
fillvalue={'path': false, 'src': false})|list }}
…我们将填充值设置为一个字典,其中包含path
和src
的存根值,因为这使表达式的其余部分更简单
解决方案的核心当然是set\u fact
操作,其简化形式如下:
end_list: "{{ end_list|default([]) + [{...a dictionary...}] }}"
ok: [localhost] => {
"end_list": [
{
"name": "kibana",
"path": [
"kibana/conf/kibana.xml",
"kibana/conf/kibana.xml"
],
"src": [
"/Users/ansible/inventories/_base/group_vars/kibana/conf/kibana.xml",
"/Users/ansible/inventories/dev-st/group_vars/kibana/conf/kibana.xml"
]
},
{
"name": "logstash",
"path": [
"logstash/conf/logstash.yml",
"logstash/conf/jvm.options"
],
"src": [
"/Users/ansible/inventories/_base/group_vars/logstash/conf/logstash.yml",
"/Users/ansible/inventories/dev-st/group_vars/logstash/conf/jvm.options"
]
},
{
"name": "grafana",
"path": "grafana/conf/grafana.json",
"src": false
}
]
}
换句话说,对于循环的每次迭代
,这将向结束列表
附加一个新字典
我们创建的字典如下所示:
"end_list": [
{
"name": "kibana",
"path": "kibana/conf/kibana.xml",
"src": "/Users/ansible/inventories/dev-st/group_vars/kibana/conf/kibana.xml"
},
{
"name": "logstash",
"path": [
"logstash/conf/logstash.yml",
"logstash/conf/jvm.options"
],
"src": [
"/Users/ansible/inventories/_base/group_vars/logstash/conf/logstash.yml",
"/Users/ansible/inventories/dev-st/group_vars/logstash/conf/jvm.options"
]
},
{
"name": "grafana",
"path": [
"grafana/conf/grafana.json",
"grafana/conf/nginx.json",
"grafana/conf/config.json"
]
"src": [
"/Users/ansible/inventories/_base/group_vars/grafana/conf/grafana.json",
"/Users/ansible/inventories/_base/group_vars/grafana/conf/nginx.json",
"/Users/ansible/inventories/_base/group_vars/grafana/conf/config.json"
]
},
]
{
'name': item.0.name,
'path': item.1.path|ternary([item.0.path, item.1.path], item.0.path),
'src': item.1.src|ternary([item.0.src, item.1.src], item.1.src)
}
我们在这里使用三元过滤器,它将输入作为布尔值进行计算;如果它是true
,则选择第一个参数,否则选择第二个参数。这里我们利用传递给zip\u longest
过滤器的fillvalue
:如果dev\u list
比base\u list
短,我们将有一些item的项目。1.路径
和item.1.src
为false
,导致三元过滤器选择第二个值(无论是item.0.path
还是item.1.src
)。在其他情况下,我们通过组合base\u list
和dev\u list
中的每个值来构建一个列表
运行此剧本的结果如下所示:
end_list: "{{ end_list|default([]) + [{...a dictionary...}] }}"
ok: [localhost] => {
"end_list": [
{
"name": "kibana",
"path": [
"kibana/conf/kibana.xml",
"kibana/conf/kibana.xml"
],
"src": [
"/Users/ansible/inventories/_base/group_vars/kibana/conf/kibana.xml",
"/Users/ansible/inventories/dev-st/group_vars/kibana/conf/kibana.xml"
]
},
{
"name": "logstash",
"path": [
"logstash/conf/logstash.yml",
"logstash/conf/jvm.options"
],
"src": [
"/Users/ansible/inventories/_base/group_vars/logstash/conf/logstash.yml",
"/Users/ansible/inventories/dev-st/group_vars/logstash/conf/jvm.options"
]
},
{
"name": "grafana",
"path": "grafana/conf/grafana.json",
"src": false
}
]
}
让我知道这是否有帮助,以及生成的数据结构是否是您想要的。我不得不做一些假设,因为您的示例end\u list
包含无效语法,所以我猜测了您想要的内容。假设您有格式良好的json,并且这些都是根对象上的属性,那么jq是完美的按名称对数组的内容进行分组,然后生成相应的结果对象
$ jq '{
end_combine: (
.base_list + .dev_list
| group_by(.name)
| map({ name: .[0].name, path: map(.path), src: map(.src) })
)
}' input.json
这个Q有[jq]标记,但“预期输出”不是有效的JSON,所以我想知道JSON输出是否可以接受。你说得对,我的“预期输出”不正确。@larsks输出了正确的JSON。感谢您的回复和评论。但这并不是我想要得到的。事实证明,您只需要将第一个列表中的元素与第二个列表中的元素进行比较并对它们进行分组。如果第一个列表中的元素与第二个列表中的元素合并,则只从第二个列表(开发列表)。