I'm trying to create a list of interface names along with their mac addresses from a Debian 11 server, initially, I was trying to get the mac addresses in order only but now I realize I need a list that looks like this:
eth0 <SOME_MAC>
eth1 <SOME_MAC>
...
I want to pass this list as a variable and then use it in the next task to create a 10-persistent-net.link
file in the /etc/systemd/network
directory.
The current task that I'm using is:
- 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 }}"
As you can see I'm using the debug
module to test out my code and I have no idea how to create my desired list and pass it as a variable.
The above code gives the following result:
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
Any help on which module to use to pass the list as a variable and how to create the list in the first place is appreciated.
Kindly Note that I'm using Ansible v5.9.0 and each server may have any number of interfaces, some of them may have ethx
interface name format while others may have enspx
, brx
etc interface format.
UPDATE: Per advice in a comment I must mention that I need one list for each target that will be used in a natural host loop task that will run against each target.
UPDATE 2: As I'm new to Ansible and per my coworker's advice I was under the impression that a list of interface names along with their MAC addresses separated by space is what I need as a variable to be passed to the next task, however, throughout comments and answers I now realize that I was absolutely heading in the wrong direction. Please accept my apology and blame it on my lack of experience and knowledge of Ansible. In the end, it turned out that a dictionary of interface names and their MAC addresses is what is most suitable for this kind of action in Ansible.
Get the list of the variables
blacklist: [lo]
interfaces: "{{ ['ansible_'] |
product(ansible_interfaces|difference(blacklist)) |
map('join') }}"
Get the values of the variables and create a dictionary
devices: "{{ interfaces |
map('extract', vars) |
items2dict(key_name='device', value_name='macaddress') }}"
Notes
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 %}
gives
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
You can see that the output of Jinja is not ordered. The order is not even persistent when you repeat the task. Use the filter sort if you want to order the lines. For example,
- debug:
msg: |-
{% for ifc, mac in devices.items()|sort %}
{{ ifc }} {{ mac }}
{% endfor %}
gives
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