Вероятно, это было бы проще с пользовательским фильтром 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
Это было немного сложно собрать, поэтому я попытаюсь описать различные части:
В цикле используется фильтр zip_longest . Учитывая списки list1=[1, 2, 3]
и list2=[11, 12]
, list1|zip_longest(list2)
будет выдавать [[1,11], [2,12], [3,None]]
(то есть по умолчанию zip_longest
будет использовать None
в качестве значения заполнения, если один список короче другого). Установив параметр fillvalue
, мы можем использовать значение, отличное от None
. В этом случае ...
loop: >-
{{ base_list|zip_longest(dev_list,
fillvalue={'path': false, 'src': false})|list }}
... Мы устанавливаем значение заполнения для словаря со значениями-заглушками для path
и src
, поскольку это облегчает оставшуюся часть выражения.
Мясо решения - это, конечно, действие set_fact
, которое в упрощенном виде выглядит так:
end_list: "{{ end_list|default([]) + [{...a dictionary...}] }}"
Другими словами, для каждой итерации loop
это добавит новый словарь к end_list
.
Мы создаем словарь так:
{
'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)
}
Мы используем здесь фильтр ternary
, который оценивает его входные данные как логическое значение; если это true
, он выбирает первый аргумент, иначе второй. Здесь мы используем преимущество fillvalue
, которое мы передали фильтру zip_longest
: если dev_list
меньше base_list
, у нас будет несколько элементов, для которых item.1.path
и item.1.src
равны false
, заставляя троичный фильтр выбирать второе значение (item.0.path
или item.1.src
). В других случаях мы строим список, комбинируя значения из каждого из base_list
и dev_list
.
Результат запуска этой пьесы выглядит следующим образом:
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
содержал неверный синтаксис, поэтому я решил, что вы хотите.