我正在编写一个 Ansible 剧本,用于授予和拒绝对某些目录的访问。 Base 是用户词典的列表:
users:
- {name: 'user1', dirs: ['dir1', 'dir2']}
- {name: 'user2', dirs: ['dir1', 'dir3']}
- {name: 'user3', dirs: []}
作为辅助事实,我创建了任何用户记录中出现的所有目录的列表。
现在我想将此列表转换为两个新列表:
dirs_allowed:
- {'dir1': ['user1', 'user2']}
- {'dir2': ['user1']}
- {'dir3': ['user2']}
这个很简单,但我找不到这个问题的解决方案:
dirs_forbidden:
- {'dir1': ['user3']}
- {'dir2': ['user2', 'user3']}
- {'dir3': ['user1', 'user3']}
所以,我的问题是:如何获取“dirs”属性中没有当前目录(=所有目录上的 with_items 循环中的项目)的所有用户的列表?
当然可以使用任务中的辅助变量/事实或“何时”条件来完成此操作,但我真的很想自行转换列表,因为我想学习如何处理如此复杂的转换。其背后的想法是只提供一个字典作为输入,并从该字典中提取特定任务所需的所有内容,而中间没有大量的 set_fact-tasks ,这会使剧本难以阅读,并且可能会因为未定义的变量而失败,如果任务被移动到中间变量尚未设置的地方。
答案1
使用过滤器不同之处。例如
- set_fact:
users_all: "{{ users|json_query('[].name') }}"
- set_fact:
dirs_forbidden: "{{ dirs_forbidden|default([]) + [
{(item.keys()|list|first):
(users_all|difference(item.values()|list|first))}] }}"
loop: "{{ dirs_allowed }}"
- debug:
var: dirs_forbidden
给
"dirs_forbidden": [
{
"dir1": [
"user3"
]
},
{
"dir2": [
"user2",
"user3"
]
},
{
"dir3": [
"user1",
"user3"
]
}
]
FWIW。在这种情况下,使用字典可以使代码更简单。例如
- set_fact:
users_all: "{{ users|json_query('[].name') }}"
- set_fact:
dirs_all: "{{ users|
json_query('[].dirs')|flatten|unique }}"
- set_fact:
dirs_allowed: "{{ dirs_allowed|default({})|
combine({item: users|json_query(query)}) }}"
vars:
query: "[?dirs.contains(@, '{{ item }}')].name"
loop: "{{ dirs_all }}"
- debug:
var: dirs_allowed
- set_fact:
dirs_forbidden: "{{ dirs_forbidden|default({})|
combine({item: (users_all|difference(dirs_allowed[item]))}) }}"
loop: "{{ dirs_all }}"
- debug:
var: dirs_forbidden
给
"dirs_allowed": {
"dir1": [
"user1",
"user2"
],
"dir2": [
"user1"
],
"dir3": [
"user2"
]
}
"dirs_forbidden": {
"dir1": [
"user3"
],
"dir2": [
"user2",
"user3"
],
"dir3": [
"user1",
"user3"
]
}