如何循环遍历 Ansible 中的 JSON 列表,并按单独列表中的值进行过滤?
How to loop over a JSON list in Ansible, filtered by values from a separate list?
我有一个用户字典列表,每个字典都包含用户名、gecos 等,还有一个组字典列表,每个字典都包含一个组成员列表。我需要一个 Ansible 任务来仅遍历与组列表中特定组的成员列表匹配的用户列表条目。
我怀疑我的问题与正确使用引号和 Jinja 定界符有关,以便在 Ansible -> Jinja -> JMESPath 层次结构中的适当级别对所有内容进行评估,但我无法准确确定我做错了什么。我已经尝试了下面的几十种变体,包括将子查询分解成它们自己的变量,但是没有有意义的反馈,我没有太多信息可以进行改进。
users.json:
{
"aws_users": [
{
"name": "userA",
"gecos": "User A"
},
{
"name": "userB",
"gecos": "User B"
},
{
"name": "userC",
"gecos": "User C"
}
]
}
groups.json:
{
"aws_groups": [
{
"name": "groupA",
"members": [
"userA",
"userC"
]
}
]
}
ansible.yml:
---
- hosts: 127.0.0.1
become: true
connection: local
gather_facts: no
vars_files:
- ../../config/groups.json
- ../../config/users.json
vars:
groupARoster: "{{ aws_groups | json_query('[?name==`groupA`].members | [0]') }}"
query: "aws_users[?contains(`{{ groupARoster }}`, name)]"
groupAUsers: "{{ aws_users | json_query(query) }}"
tasks:
- debug:
var: groupARoster
- debug:
var: query
- debug:
var: groupAUsers
# - name: Some looping thing
# command: ...
# loop: "{{ groupAusers }}"
输出:
PLAY [127.0.0.1] ***********************************************************************************************************************************************************************************************
TASK [debug] ***************************************************************************************************************************************************************************************************
ok: [127.0.0.1] => {
"groupARoster": [
"userA",
"userC"
]
}
TASK [debug] ***************************************************************************************************************************************************************************************************
ok: [127.0.0.1] => {
"query": "aws_users[?contains(`[u'userA', u'userC']`, name)]"
}
TASK [debug] ***************************************************************************************************************************************************************************************************
ok: [127.0.0.1] => {
"groupAUsers": ""
}
PLAY RECAP *****************************************************************************************************************************************************************************************************
127.0.0.1 : ok=3 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
期望输出(用于传递到 Ansible 循环参数):
"groupAUsers": [
{
"name": "userA",
"gecos": "User A"
},
{
"name": "userC",
"gecos": "User C"
}
]
除非你真的想为此使用 jmespath,IMO 有一个更简单的方法使用 selectattr
:
groupARoster: "{{ (aws_groups | selectattr('name', 'equalto', 'groupA') | list)[0].members }}"
groupAUsers: "{{ aws_users | selectattr('name', 'in', groupARoster) | list }}"
与此同时,json_query
仍然可以做到这一点。你真的很亲密。问题是您的中间查询。您正在将变量 aws_user
传递给 json_query
。因此,您传递的值中没有第一级 "aws_user"
键。您必须将其从查询中删除:
groupARoster: "{{ aws_groups | json_query('[?name==`groupA`].members | [0]') }}"
query: "[?contains(`{{ groupARoster }}`, name)]"
groupAUsers: "{{ aws_users | json_query(query) }}"
我有一个用户字典列表,每个字典都包含用户名、gecos 等,还有一个组字典列表,每个字典都包含一个组成员列表。我需要一个 Ansible 任务来仅遍历与组列表中特定组的成员列表匹配的用户列表条目。
我怀疑我的问题与正确使用引号和 Jinja 定界符有关,以便在 Ansible -> Jinja -> JMESPath 层次结构中的适当级别对所有内容进行评估,但我无法准确确定我做错了什么。我已经尝试了下面的几十种变体,包括将子查询分解成它们自己的变量,但是没有有意义的反馈,我没有太多信息可以进行改进。
users.json:
{
"aws_users": [
{
"name": "userA",
"gecos": "User A"
},
{
"name": "userB",
"gecos": "User B"
},
{
"name": "userC",
"gecos": "User C"
}
]
}
groups.json:
{
"aws_groups": [
{
"name": "groupA",
"members": [
"userA",
"userC"
]
}
]
}
ansible.yml:
---
- hosts: 127.0.0.1
become: true
connection: local
gather_facts: no
vars_files:
- ../../config/groups.json
- ../../config/users.json
vars:
groupARoster: "{{ aws_groups | json_query('[?name==`groupA`].members | [0]') }}"
query: "aws_users[?contains(`{{ groupARoster }}`, name)]"
groupAUsers: "{{ aws_users | json_query(query) }}"
tasks:
- debug:
var: groupARoster
- debug:
var: query
- debug:
var: groupAUsers
# - name: Some looping thing
# command: ...
# loop: "{{ groupAusers }}"
输出:
PLAY [127.0.0.1] ***********************************************************************************************************************************************************************************************
TASK [debug] ***************************************************************************************************************************************************************************************************
ok: [127.0.0.1] => {
"groupARoster": [
"userA",
"userC"
]
}
TASK [debug] ***************************************************************************************************************************************************************************************************
ok: [127.0.0.1] => {
"query": "aws_users[?contains(`[u'userA', u'userC']`, name)]"
}
TASK [debug] ***************************************************************************************************************************************************************************************************
ok: [127.0.0.1] => {
"groupAUsers": ""
}
PLAY RECAP *****************************************************************************************************************************************************************************************************
127.0.0.1 : ok=3 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
期望输出(用于传递到 Ansible 循环参数):
"groupAUsers": [
{
"name": "userA",
"gecos": "User A"
},
{
"name": "userC",
"gecos": "User C"
}
]
除非你真的想为此使用 jmespath,IMO 有一个更简单的方法使用 selectattr
:
groupARoster: "{{ (aws_groups | selectattr('name', 'equalto', 'groupA') | list)[0].members }}"
groupAUsers: "{{ aws_users | selectattr('name', 'in', groupARoster) | list }}"
与此同时,json_query
仍然可以做到这一点。你真的很亲密。问题是您的中间查询。您正在将变量 aws_user
传递给 json_query
。因此,您传递的值中没有第一级 "aws_user"
键。您必须将其从查询中删除:
groupARoster: "{{ aws_groups | json_query('[?name==`groupA`].members | [0]') }}"
query: "[?contains(`{{ groupARoster }}`, name)]"
groupAUsers: "{{ aws_users | json_query(query) }}"