我正在尝试从 Debian 11 服务器创建接口名称及其 mac 地址列表,最初,我试图仅按顺序获取 mac 地址,但现在我意识到我需要一个如下所示的列表:
eth0 <SOME_MAC>
eth1 <SOME_MAC>
...
我想将此列表作为变量传递,然后在下一个任务中使用它在
10-persistent-net.link
目录中创建 /etc/systemd/network
文件。
我当前使用的任务是:
- name: Get mac addresses of all interfaces except local
debug:
msg: "{{ ansible_interfaces |
map('regex_replace','^','ansible_') |
map('extract',hostvars[inventory_hostname]) |
selectattr('macaddress','defined') |
map(attribute='macaddress') |
list }}"
如您所见,我正在使用
debug
模块来测试我的代码,但我不知道如何创建所需的列表并将其作为变量传递。
上面的代码给出了以下结果:
ok: [target1] =>
msg:
- 08:00:27:d6:08:1a
- 08:00:27:3a:3e:ff
- f6:ac:58:a9:35:33
- 08:00:27:3f:82:c2
- 08:00:27:64:6a:f8
ok: [target2] =>
msg:
- 08:00:27:34:70:60
- 42:04:1a:ff:6c:46
- 42:04:1a:ff:6c:46
- 08:00:27:d6:08:1a
- 08:00:27:9c:d7:af
- f6:ac:58:a9:35:33
任何有关使用哪个模块将列表作为变量传递以及如何首先创建列表的帮助都将受到赞赏。
请注意,我使用的是 Ansible v5.9.0,每个服务器可能有任意数量的接口,其中一些可能具有
ethx
接口名称格式,而另一些可能具有 enspx
、brx
等接口格式。
更新:根据评论中的建议,我必须提到,我需要为每个目标提供一个列表,该列表将在针对每个目标运行的自然主机循环任务中使用。
更新 2: 由于我是 Ansible 的新手,根据同事的建议,我的印象是,我需要将接口名称列表及其以空格分隔的 MAC 地址作为传递给下一个的变量。然而,通过评论和回答,我现在意识到我绝对走错了方向。请接受我的道歉,并将其归咎于我缺乏 Ansible 经验和知识。最后,事实证明,接口名称及其 MAC 地址的字典最适合 Ansible 中的此类操作。
获取变量列表
blacklist: [lo]
interfaces: "{{ ['ansible_'] |
product(ansible_interfaces|difference(blacklist)) |
map('join') }}"
获取变量的值并创建字典
devices: "{{ interfaces |
map('extract', vars) |
items2dict(key_name='device', value_name='macaddress') }}"
注释
devices:
docker0: 02:42:35:39:f7:f5
eth0: 80:3f:5d:14:b1:d3
eth1: e4:6f:13:f5:09:80
wlan0: 64:5d:86:5d:16:b9
xenbr0: 80:3f:5d:14:b1:d3
- debug:
msg: |-
{% for ifc, mac in devices.items() %}
{{ ifc }} {{ mac }}
{% endfor %}
给予
msg: |-
wlan0 64:5d:86:5d:16:b9
eth0 80:3f:5d:14:b1:d3
eth1 e4:6f:13:f5:09:80
xenbr0 80:3f:5d:14:b1:d3
docker0 02:42:35:39:f7:f5
可以看到Jinja的输出是没有顺序的。当您重复该任务时,该顺序甚至不会持久。如果您想对线路进行排序,请使用过滤器 sort。例如,
- debug:
msg: |-
{% for ifc, mac in devices.items()|sort %}
{{ ifc }} {{ mac }}
{% endfor %}
给予
msg: |-
docker0 02:42:35:39:f7:f5
eth0 80:3f:5d:14:b1:d3
eth1 e4:6f:13:f5:09:80
wlan0 64:5d:86:5d:16:b9
xenbr0 80:3f:5d:14:b1:d3
我就是这样做的。
请注意,我的示例使用
json_query
过滤器,它需要您的 ansible 控制器上的 pip install jmespath
。
---
- name: Create a formated list for all interfaces
hosts: all
vars:
elligible_interfaces: "{{ ansible_interfaces | reject('==', 'lo') }}"
interfaces_list_raw: >-
{{
hostvars[inventory_hostname]
| dict2items
| selectattr('value.device', 'defined')
| selectattr('value.device', 'in', elligible_interfaces)
| map(attribute='value')
}}
interface_query: >-
[].[device, macaddress]
interfaces_formated_list: >-
{{ interfaces_list_raw | json_query(interface_query) | map('join', ' ') }}
tasks:
- name: Show our calculated var
debug:
var: interfaces_formated_list
这可以针对我的本地主机运行:
$ ansible-playbook -i localhost, /tmp/test.yml
PLAY [Create a formated list for all interfaces] **************************************************************************************************
TASK [Gathering Facts] ****************************************************************************************************************************
ok: [localhost]
TASK [Show our calculated var] ********************************************************************************************************************
ok: [localhost] => {
"interfaces_formated_list": [
"docker0 02:42:98:b8:4e:75",
"enp4s0 50:3e:aa:14:17:8f",
"vboxnet0 0a:00:27:00:00:00",
"veth7201fce 92:ab:61:7e:df:65"
]
}
PLAY RECAP ****************************************************************************************************************************************
localhost : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
如您所见,这显示了您可能希望在用例中过滤掉的几个接口。您可以检查
interfaces_list_raw
并创建其他过滤器来实现您的目标。但至少你明白了。