refactor ♻️: Refactored Wake-on-LAN task for specific bridge interface

Renamed `wol_interface` to `wol_bridge`, updated comments, and refactored task using `bridge link show` and `ethtool`. Added udev rules for persistence and set `Restart=always` for the service.
This commit is contained in:
2025-12-23 20:42:03 +01:00
parent ebc947ce9d
commit 963b0dff6a
3 changed files with 72 additions and 119 deletions

View File

@@ -1,8 +1,6 @@
# defaults/main.yml # defaults/main.yml
# Network interface to enable Wake-on-LAN on # Bridge interface to enable Wake-on-LAN on
wol_interface: "" # user override (physical NIC) wol_bridge: vmbr0
wol_detected_bridge: ""
wol_detected_phy: ""
# WOL mode: # WOL mode:
# g = magic packet (most common) # g = magic packet (most common)
@@ -12,4 +10,4 @@ wol_mode: "g"
wol_verify: true wol_verify: true
# Report MAC address for WOL senders # Report MAC address for WOL senders
wol_report_mac: true wol_report_mac: true

View File

@@ -5,156 +5,110 @@
state: present state: present
update_cache: yes update_cache: yes
- name: Gather network facts # ------------------------------------------------------------
ansible.builtin.setup: # Map vmbr0 → backing physical NIC
gather_subset: # ------------------------------------------------------------
- network - name: Get bridge link information
ansible.builtin.command: "bridge link show"
register: bridge_links
changed_when: false
failed_when: false
- name: Detect default route interface - name: Detect physical NIC backing vmbr0
ansible.builtin.set_fact: ansible.builtin.set_fact:
wol_detected_interface: "{{ ansible_default_ipv4.interface }}" wol_detected_phy: >-
when: wol_interface | default('') | length == 0
- name: Debug facts interface
ansible.builtin.debug:
msg:
- "Detected bridge {{ wol_detected_interface }}"
# - name: Debug facts
# ansible.builtin.debug:
# msg:
# - "{{ hostvars[inventory_hostname]['ansible_' + wol_detected_interface][interfaces] }}"
# - name: Detect physical NIC enslaved to bridge
# ansible.builtin.set_fact:
# wol_detected_phy: "{{ item }}"
# loop: "{{ ansible_interfaces }}"
# when:
# - wol_interface | default('') | length == 0
# - item != 'lo'
# - item is not match('^v')
# - item is match('^e')
# - hostvars[inventory_hostname]['ansible_' + item] is defined
# - hostvars[inventory_hostname]['ansible_' + item].module is defined
# - hostvars[inventory_hostname]['ansible_' + item].pciid is defined
# - hostvars[inventory_hostname]['ansible_' + item].type is defined
# - hostvars[inventory_hostname]['ansible_' + item].type == 'ether'
# - name: Detect physical NIC behind bridge
# ansible.builtin.set_fact:
# wol_detected_phy: "{{ ansible_facts[wol_detected_bridge].interfaces[0] }}"
# when:
# - wol_interface | default('') | length == 0
# - ansible_facts[wol_detected_bridge] is defined
# - ansible_facts[wol_detected_bridge].interfaces is defined
# - ansible_facts[wol_detected_bridge].interfaces | length > 0
- name: Detect physical NICs in bridge
ansible.builtin.set_fact:
wol_bridge_phys: >-
{{ {{
ansible_facts[wol_detected_interface].interfaces bridge_links.stdout_lines
| select('match', '^(e|en)') | select('search', wol_bridge)
| list | select('search', 'master ' ~ wol_bridge)
| map('regex_search', '^\\d+: ([^:@]+)', '\\1')
| select('string')
| first
}} }}
- name: Debug WoL interface selection - name: Fail if vmbr0 backing NIC could not be detected
ansible.builtin.debug:
msg:
- "Detected interface: {{ wol_detected_interface }}"
- "Detected physical NICs: {{ wol_detected_phys }}"
- name: Select physical NIC if exactly one found
ansible.builtin.set_fact:
wol_detected_phy: "{{ wol_bridge_phys[0] }}"
when: wol_bridge_phys | length == 1
- name: Select final WoL interface
ansible.builtin.set_fact:
wol_final_interface: >-
{{
wol_interface
if wol_interface | default('') | length > 0
else wol_detected_phy
}}
- name: Fail if multiple NICs are attached to bridge
ansible.builtin.fail: ansible.builtin.fail:
msg: > msg: >
Multiple physical NICs found in {{ wol_detected_bridge }}: Unable to detect physical NIC backing {{ wol_bridge }}.
{{ wol_bridge_phys }}.
Please set wol_interface explicitly. Please set wol_interface explicitly.
when: wol_bridge_phys | length > 1 when: wol_detected_phy | default('') | length == 0
- name: Fail if no physical NIC was detected # ------------------------------------------------------------
ansible.builtin.fail: # Validate WOL capability
msg: > # ------------------------------------------------------------
Unable to detect a physical NIC for Wake-on-LAN. - name: Check WOL capability on detected NIC
Detected bridge: {{ wol_detected_bridge | default('none') }}. ansible.builtin.command: "ethtool {{ wol_detected_phy }}"
Please set wol_interface explicitly.
when: wol_final_interface | default('') | length == 0
- name: Check WOL support on interface
ansible.builtin.command: ethtool {{ wol_final_interface }}
register: wol_capabilities register: wol_capabilities
changed_when: false changed_when: false
- name: Fail if NIC does not support Wake-on-LAN - name: Fail if NIC does not support Wake-on-LAN
ansible.builtin.fail: ansible.builtin.fail:
msg: "Interface {{ wol_final_interface }} does not support Wake-on-LAN." msg: "Interface {{ wol_detected_phy }} does not support Wake-on-LAN."
when: "'Wake-on:' not in wol_capabilities.stdout" when: "'Supports Wake-on: g' not in wol_capabilities.stdout"
- name: Create systemd service for Wake-on-LAN # ------------------------------------------------------------
ansible.builtin.template: # Enable WOL immediately
src: wol.service.j2 # ------------------------------------------------------------
dest: /etc/systemd/system/wol.service - name: Enable Wake-on-LAN immediately
ansible.builtin.command: >
ethtool -s {{ wol_detected_phy }} wol {{ wol_mode }}
changed_when: false
# ------------------------------------------------------------
# Persist WOL via udev (correct + recommended)
# ------------------------------------------------------------
- name: Create udev rule to persist Wake-on-LAN
ansible.builtin.copy:
dest: /etc/udev/rules.d/90-wol.rules
owner: root owner: root
group: root group: root
mode: '0644' mode: '0644'
notify: content: |
- Reload systemd and restart WOL ACTION=="add", SUBSYSTEM=="net", KERNEL=="{{ wol_detected_phy }}", RUN+="/sbin/ethtool -s {{ wol_detected_phy }} wol {{ wol_mode }}"
- name: Enable WOL immediately (without reboot) - name: Reload udev rules
ansible.builtin.command: ethtool -s {{ wol_final_interface }} wol {{ wol_mode }} ansible.builtin.command: udevadm control --reload
changed_when: false changed_when: false
- name: Trigger udev for network interfaces
ansible.builtin.command: udevadm trigger --subsystem-match=net
changed_when: false
# ------------------------------------------------------------
# Verification & Reporting
# ------------------------------------------------------------
- name: Verify Wake-on-LAN status - name: Verify Wake-on-LAN status
ansible.builtin.command: ethtool {{ wol_final_interface }} ansible.builtin.command: "ethtool {{ wol_detected_phy }}"
register: wol_status register: wol_status
changed_when: false changed_when: false
when: wol_verify when: wol_verify
- name: Get MAC address of WOL interface - name: Get MAC address
set_fact: ansible.builtin.set_fact:
wol_mac_address: >- wol_mac_address: "{{ ansible_facts.interfaces[wol_detected_phy].macaddress | default('') }}"
{{
ansible_facts['ansible_' + wol_final_interface]['macaddress'] - name: Fail if MAC address could not be detected
| default('') ansible.builtin.fail:
}} msg: "Unable to determine MAC address for interface {{ wol_detected_phy }}"
when:
- wol_report_mac
- wol_mac_address | length == 0
- name: Show WOL status - name: Show WOL status
ansible.builtin.debug: ansible.builtin.debug:
msg: "{{ wol_status.stdout_lines }}" msg: "{{ wol_status.stdout_lines }}"
when: wol_verify when: wol_verify
- name: Fail if MAC address could not be detected
fail:
msg: "Unable to determine MAC address for interface {{ wol_final_interface }}"
when:
- wol_report_mac
- wol_mac_address | length == 0
- name: Report Wake-on-LAN sender details - name: Report Wake-on-LAN sender details
ansible.builtin.debug: ansible.builtin.debug:
msg: msg:
- "Wake-on-LAN enabled on interface: {{ wol_final_interface }}" - "Wake-on-LAN enabled successfully"
- "Bridge: {{ wol_bridge }}"
- "Physical NIC: {{ wol_detected_phy }}"
- "MAC address: {{ wol_mac_address }}" - "MAC address: {{ wol_mac_address }}"
- "Example WOL commands:" - "Example commands:"
- " wakeonlan {{ wol_mac_address }}" - " wakeonlan {{ wol_mac_address }}"
- " etherwake {{ wol_mac_address }}" - " etherwake {{ wol_mac_address }}"
- "Home Assistant:" - "Home Assistant:"
- " mac: {{ wol_mac_address }}" - " mac: {{ wol_mac_address }}"
when: wol_report_mac when: wol_report_mac

View File

@@ -1,10 +1,11 @@
[Unit] [Unit]
Description=Enable Wake-on-LAN on {{ wol_interface_final }} Description=Enable Wake-on-LAN on {{ wol_final_interface }}
After=network.target After=network.target
[Service] [Service]
Type=oneshot Type=oneshot
ExecStart=/sbin/ethtool -s {{ wol_interface_final }} wol {{ wol_mode }} ExecStart=/sbin/ethtool -s {{ wol_final_interface }} wol {{ wol_mode }}
Restart=always
[Install] [Install]
WantedBy=multi-user.target WantedBy=multi-user.target