英文:
json filter in creating a jinja2 template
问题
我正在尝试创建我的第一个 Jinja2 模板,从 JSON 字符串中提取一个字段,因为我正在创建 DHCP 预留文件。
以下是一个示例清单提供:
我想选择来自 MAC 地址的值,将其用作与 Ansible 主机匹配的接口字段的 Jinja2 值,该接口可以位于接口上的任何位置。
我应该如何操作
"TEST": {
"ansible_host": "192.171.130.8",
"interfaces": [
{
"ip_addresses": [
{
"address": "192.171.130.8/32",
}
],
"mac_address": "C8-F1-13-78-9E-E7"
},
{
"ip_addresses": [
{
"address": "192.171.130.80/32",
}
],
"mac_address": "85-9F-76-AE-57-10"
}
],
}
所以我想做类似以下的事情
{{ hostvars[host].interfaces.[ip_addresses.address = ansible_host].mac_address }}
但我不确定如何操作。
英文:
am trying to create my 1st jinja2 template that extracts a field from a json string as am trying to create DHCP reserveration file.
here is an example inventory feed.
I would like to select the value from the mac address to use as a value as jinja2 value for a field for the interface that matches the ansible host. which could be in any postion on the interfaces.
how would I go about it
"TEST": {
"ansible_host": "192.171.130.8",
"interfaces": [
{
"ip_addresses": [
{
"address": "192.171.130.8/32",
}
],
"mac_address": "C8-F1-13-78-9E-E7"
},
{
"ip_addresses": [
{
"address": "192.171.130.80/32",
}
],
"mac_address": "85-9F-76-AE-57-10"
}
],
}
so I would like to doe something like
{{ hostvars[host].interfaces.[ip_addresses.address = ansible_host].mac_address }}
but am not sure how to go about it.
答案1
得分: 2
这看起来是一个适合使用json_query
过滤器的良好候选项。我的第一个想法是这应该可以工作:
hostvars[host].interfaces | json_query("[?ip_addresses[].address == '192.171.130.8/32']")
但这会返回一个空列表。以下代码有点冗长,但会产生预期的结果:
hostvars[host].interfaces | json_query("[?ip_addresses[].address | contains(@, '192.171.130.8/32')]")
在一个playbook中:
- hosts: localhost
gather_facts: false
vars:
TEST:
"ansible_host": "192.171.130.8",
"interfaces": [
{
"ip_addresses": [
{
"address": "192.171.130.8/32"
}
],
"mac_address": "C8-F1-13-78-9E-E7"
},
{
"ip_addresses": [
{
"address": "192.171.130.80/32"
}
],
"mac_address": "85-9F-76-AE-57-10"
}
]
tasks:
- debug:
msg: >
{{ TEST.interfaces | json_query("[?ip_addresses[].address | contains(@, '192.171.130.8/32')]") }}
注意:请注意引号的使用;在这里,我使用了YAML折叠引号操作符(>
),因为表达式包含双引号和单引号,所以在表达式内部加上任何引号都需要转义。
运行上述playbook将产生以下结果:
ok: [localhost] => {
"msg": [
{
"ip_addresses": [
{
"address": "192.171.130.8/32"
}
],
"mac_address": "C8-F1-13-78-9E-E7"
}
]
}
由于你已经将所需的地址存储在变量中(ansible_host
),你可以改为写成:
tasks:
- debug:
msg: >
{{
hostvars[host].interfaces | json_query("[?ip_addresses[].address | contains(@, '%s/32')]" % ansible_host)
}}
我们的表达式返回一个包含单个字典的列表。如果你想要mac_address
字段,可以像处理任何其他Ansible数组变量一样处理结果:
tasks:
- debug:
msg: >
{{
(
hostvars[host].interfaces |
json_query("[?ip_addresses[].address | contains(@, '%s/32')]" % ansible_host)
)[0].mac_address
}}
英文:
This looks like a good candidate for the json_query
filter. My first thought was that this should work:
hostvars[host].interfaces | json_query("[?ip_addresses[].address == '192.171.130.8/32']")
But that returns an empty list. The following is a bit more verbose, but produces the expected result:
hostvars[host].interfaces|json_query("[?ip_addresses[].address | contains(@, '192.171.130.8/32')]")
In a playbook:
- hosts: localhost
gather_facts: false
vars:
TEST: {
"ansible_host": "192.171.130.8",
"interfaces": [
{
"ip_addresses": [
{
"address": "192.171.130.8/32",
}
],
"mac_address": "C8-F1-13-78-9E-E7"
},
{
"ip_addresses": [
{
"address": "192.171.130.80/32",
}
],
"mac_address": "85-9F-76-AE-57-10"
}
],
}
tasks:
- debug:
msg: >-
{{ TEST.interfaces | json_query("[?ip_addresses[].address | contains(@, '192.171.130.8/32')]") }}
NB: Watch your quoting; you'll note that here I've used the YAML folding quote operating (>
) because the expression contains both double quotes and single quotes, so putting either of those around the outside would mean escaping quotes inside the expression.
Running the above playbook produces:
ok: [localhost] => {
"msg": [
{
"ip_addresses": [
{
"address": "192.171.130.8/32"
}
],
"mac_address": "C8-F1-13-78-9E-E7"
}
]
}
Since you've got the desired address in a variable (ansible_host
), you would write instead:
tasks:
- debug:
msg: >-
{{
hostvars[host].interfaces | json_query("[?ip_addresses[].address | contains(@, '%s/32')]" % ansible_host)
}}
Our expression returns a list containing a single dictionary. If you want the mac_address
field, treat the result just like any other Ansible array variable:
tasks:
- debug:
msg: >-
{{
(
hostvars[host].interfaces |
json_query("[?ip_addresses[].address | contains(@, '%s/32')]" % ansible_host)
).0.mac_address
}}
答案2
得分: 1
以下是代码部分的翻译:
mac_ip_raw: "从MAC地址和IP列表创建字典"
mac_ip_query: '[].[mac地址, IP地址[].地址]'
mac_ip_raw:
85-9F-76-AE-57-10:
- 192.171.130.80/32
C8-F1-13-78-9E-E7:
- 192.171.130.8/32
mac_ip: "去掉子网掩码"
mac_ip:
85-9F-76-AE-57-10:
- 192.171.130.80
C8-F1-13-78-9E-E7:
- 192.171.130.8
my_mac: "测试哪个列表包含IP"
my_mac: C8-F1-13-78-9E-E7
希望这些翻译对你有所帮助。
英文:
Create the dictionary from the MAC addresses and lists of IPs
mac_ip_raw: "{{ dict(interfaces|json_query(mac_ip_query)) }}"
mac_ip_query: '[].[mac_address, ip_addresses[].address]'
gives
mac_ip_raw:
85-9F-76-AE-57-10:
- 192.171.130.80/32
C8-F1-13-78-9E-E7:
- 192.171.130.8/32
Get rid of the masks
mac_ip: "{{ dict(mac_ip_raw.keys()|
zip(mac_ip_raw.values()|
map('map', 'split', '/')|
map('map', 'first'))) }}"
gives
mac_ip:
85-9F-76-AE-57-10:
- 192.171.130.80
C8-F1-13-78-9E-E7:
- 192.171.130.8
Now, test which list contains the IP
my_mac: "{{ mac_ip|dict2items|
selectattr('value', 'contains', ansible_host)|
map(attribute='key')|first }}"
gives the expected result
my_mac: C8-F1-13-78-9E-E7
<hr>
<sup>
Example of a complete project for testing
shell> tree .
.
├── ansible.cfg
├── hosts
├── host_vars
│   └── srv1
│   └── interfaces.json
└── pb.yml
2 directories, 4 files
shell> cat ansible.cfg
[defaults]
gathering = explicit
collections_path = $HOME/.local/lib/python3.9/site-packages/
inventory = $PWD/hosts
roles_path = $PWD/roles
retry_files_enabled = false
stdout_callback = yaml
shell> cat hosts
srv1 ansible_host=192.171.130.8
shell> cat host_vars/srv1/interfaces.json
{
"interfaces":
[
{
"ip_addresses": [
{
"address": "192.171.130.8/32"
}
],
"mac_address": "C8-F1-13-78-9E-E7"
},
{
"ip_addresses": [
{
"address": "192.171.130.80/32"
}
],
"mac_address": "85-9F-76-AE-57-10"
}
]
}
shell> cat pb.yml
- hosts: all
vars:
mac_ip_raw: "{{ dict(interfaces|json_query(mac_ip_query)) }}"
mac_ip_query: '[].[mac_address, ip_addresses[].address]'
mac_ip: "{{ dict(mac_ip_raw.keys()|
zip(mac_ip_raw.values()|
map('map', 'split', '/')|
map('map', 'first'))) }}"
my_mac: "{{ mac_ip|dict2items|
selectattr('value', 'contains', ansible_host)|
map(attribute='key')|first }}"
tasks:
- debug:
var: ansible_host
- debug:
var: interfaces
- debug:
var: mac_ip_raw
- debug:
var: mac_ip
- debug:
var: my_mac
</sup>
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论