docs 📝: Updated README.md for clarity and improved readability
Some checks failed
ansible-lint / Ansible Lint (push) Failing after 10s
Some checks failed
ansible-lint / Ansible Lint (push) Failing after 10s
Fixed minor grammatical errors and reorganized content in the README.md file.
This commit is contained in:
29
README.md
29
README.md
@@ -5,10 +5,10 @@ A robust, idempotent Ansible role for enabling persistent Wake-on-LAN (WOL) on P
|
|||||||
## Features
|
## Features
|
||||||
|
|
||||||
✅ **Fully Idempotent**: Checks current WOL status and only applies changes when needed
|
✅ **Fully Idempotent**: Checks current WOL status and only applies changes when needed
|
||||||
✅ **Multiple Bridge Support**: Configure WOL on multiple bridges simultaneously
|
✅ **Bridge Support**: Automatically detects physical interfaces backing configured bridges
|
||||||
✅ **Bond0 Detection**: Automatically detects and configures bonded interfaces
|
✅ **Bond0 Detection**: Automatically detects and configures bonded interfaces
|
||||||
✅ **Ansible Facts-Based**: Uses Ansible facts to detect and validate WOL-capable interfaces
|
✅ **Ansible Facts-Based**: Uses Ansible facts to detect and validate WOL-capable interfaces
|
||||||
✅ **Safe & Persistent**: Uses udev rules for persistence across reboots
|
✅ **Persistent**: Uses udev rules for persistence across reboots
|
||||||
✅ **Comprehensive Validation**: Verifies WOL capability before configuration
|
✅ **Comprehensive Validation**: Verifies WOL capability before configuration
|
||||||
✅ **Detailed Reporting**: Shows configuration status and MAC addresses for WOL senders
|
✅ **Detailed Reporting**: Shows configuration status and MAC addresses for WOL senders
|
||||||
|
|
||||||
@@ -25,12 +25,12 @@ A robust, idempotent Ansible role for enabling persistent Wake-on-LAN (WOL) on P
|
|||||||
|
|
||||||
1. **Package Installation**: Ensures `ethtool` is installed for WOL management
|
1. **Package Installation**: Ensures `ethtool` is installed for WOL management
|
||||||
2. **Interface Discovery**: Uses Ansible facts to identify all physical Ethernet interfaces
|
2. **Interface Discovery**: Uses Ansible facts to identify all physical Ethernet interfaces
|
||||||
3. **WOL Validation**: Tests each interface for Wake-on-LAN capability using ethtool
|
3. **Bridge Mapping**: Detects physical interfaces backing configured bridges
|
||||||
4. **Bridge Mapping**: Maps configured bridges to their backing WOL-capable physical NICs
|
4. **Bond0 Detection**: Identifies bonded interfaces and their slaves
|
||||||
5. **Bond0 Detection**: Detects if interfaces are bonded and extracts slave information
|
5. **WOL Validation**: Tests each interface for Wake-on-LAN capability using ethtool
|
||||||
6. **Idempotency Check**: Reads current WOL status to avoid redundant changes
|
6. **Idempotency Check**: Reads current WOL status to avoid redundant changes
|
||||||
7. **Enable WOL**: Applies WOL settings only to interfaces that need it
|
7. **Enable WOL**: Applies WOL settings only to interfaces that need it
|
||||||
8. **Persist Settings**: Creates/updates udev rules for persistence across reboots
|
8. **Persist Settings**: Creates udev rules for persistence across reboots
|
||||||
9. **Reload Udev**: Reloads udev rules and triggers network interface refresh
|
9. **Reload Udev**: Reloads udev rules and triggers network interface refresh
|
||||||
10. **Verification & Reporting**: Displays WOL configuration status and MAC addresses
|
10. **Verification & Reporting**: Displays WOL configuration status and MAC addresses
|
||||||
|
|
||||||
@@ -155,10 +155,7 @@ This role is fully idempotent. Running it multiple times has the same effect as
|
|||||||
## Implementation Details
|
## Implementation Details
|
||||||
|
|
||||||
### Persistence Method
|
### Persistence Method
|
||||||
WOL settings are persisted using udev rules at `/etc/udev/rules.d/90-wol.rules`. This is the most reliable method for Debian/Proxmox systems and survives:
|
WOL settings are persisted using udev rules at `/etc/udev/rules.d/90-wol.rules`. This ensures WOL is re-enabled whenever network interfaces are added or the system reboots.
|
||||||
- System reboots
|
|
||||||
- Network service restarts
|
|
||||||
- Interface state changes
|
|
||||||
|
|
||||||
Example generated udev rule:
|
Example generated udev rule:
|
||||||
```
|
```
|
||||||
@@ -167,10 +164,14 @@ ACTION=="add", SUBSYSTEM=="net", KERNEL=="eno1", RUN+="/sbin/ethtool -s eno1 wol
|
|||||||
|
|
||||||
### Detection Logic
|
### Detection Logic
|
||||||
1. **Interface Discovery**: Uses Ansible facts to enumerate all network interfaces
|
1. **Interface Discovery**: Uses Ansible facts to enumerate all network interfaces
|
||||||
2. **Physical Interface Filtering**: Filters for Ethernet interfaces, excluding virtual interfaces (veth, tap, fw*, docker, br*)
|
2. **Bridge Mapping**: Identifies physical interfaces backing configured bridges using `bridge link show`
|
||||||
3. **WOL Capability Testing**: Tests each physical interface with ethtool to verify WOL support
|
3. **Bond0 Detection**: Detects bonded interfaces and extracts slave information from `/proc/net/bonding/bond0`
|
||||||
4. **Bridge Mapping**: Maps configured bridges to their backing WOL-capable physical NICs
|
4. **WOL Capability Testing**: Tests each physical interface with ethtool to verify WOL support
|
||||||
5. **Bond0 Detection**: Extracts slave interfaces from `/proc/net/bonding/bond0` when present
|
5. **Idempotency Check**: Reads current WOL status to avoid redundant changes
|
||||||
|
6. **Enable WOL**: Applies WOL settings only to interfaces that need it
|
||||||
|
7. **Persist Settings**: Creates/updates udev rules for persistence
|
||||||
|
8. **Reload Udev**: Reloads udev rules and triggers network interface refresh
|
||||||
|
9. **Verification & Reporting**: Displays WOL configuration status and MAC addresses
|
||||||
|
|
||||||
## Troubleshooting
|
## Troubleshooting
|
||||||
|
|
||||||
|
|||||||
202
tasks/main.yml
202
tasks/main.yml
@@ -26,7 +26,7 @@
|
|||||||
# ansible.builtin.set_fact:
|
# ansible.builtin.set_fact:
|
||||||
# en_interfaces: "{{ ansible_facts.interfaces | select('match', '^eth|^ens|^enp') | unique | list }}"
|
# en_interfaces: "{{ ansible_facts.interfaces | select('match', '^eth|^ens|^enp') | unique | list }}"
|
||||||
|
|
||||||
- name: Get interfaces starting with "en or "eth"
|
- name: Get interfaces starting with "en" or "eth"
|
||||||
ansible.builtin.set_fact:
|
ansible.builtin.set_fact:
|
||||||
en_interfaces: >-
|
en_interfaces: >-
|
||||||
{{
|
{{
|
||||||
@@ -35,112 +35,152 @@
|
|||||||
| list
|
| list
|
||||||
}}
|
}}
|
||||||
|
|
||||||
- name: Display debug selected interfaces
|
# ============================================================
|
||||||
|
# Detect physical interfaces backing configured bridges
|
||||||
|
# ============================================================
|
||||||
|
- name: Get physical interfaces for configured bridges
|
||||||
|
ansible.builtin.command: bridge link show {{ item }}
|
||||||
|
register: bridge_links
|
||||||
|
loop: "{{ wol_bridges | list }}"
|
||||||
|
changed_when: false
|
||||||
|
failed_when: false
|
||||||
|
|
||||||
|
- name: Extract physical interfaces from bridge info
|
||||||
|
ansible.builtin.set_fact:
|
||||||
|
bridge_physical: >-
|
||||||
|
{{
|
||||||
|
bridge_links.results
|
||||||
|
| selectattr('rc', 'equalto', 0)
|
||||||
|
| map(attribute='stdout_lines')
|
||||||
|
| flatten
|
||||||
|
| map('regex_replace', '^\\d+: ([^ ]+).*', '\\1')
|
||||||
|
| select
|
||||||
|
| unique
|
||||||
|
| list
|
||||||
|
}}
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# Check for bond0 and get slaves
|
||||||
|
# ============================================================
|
||||||
|
- name: Check if bond0 exists
|
||||||
|
ansible.builtin.stat:
|
||||||
|
path: /proc/net/bonding/bond0
|
||||||
|
register: bond0_stat
|
||||||
|
|
||||||
|
- name: Get bond0 slaves
|
||||||
|
ansible.builtin.command: cat /proc/net/bonding/bond0 | grep "Slave Interface" | awk '{print $3}'
|
||||||
|
register: bond0_slaves
|
||||||
|
changed_when: false
|
||||||
|
when: bond0_stat.stat.exists
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# Set final list of interfaces to configure
|
||||||
|
# ============================================================
|
||||||
|
- name: Set final interfaces
|
||||||
|
ansible.builtin.set_fact:
|
||||||
|
wol_final_interfaces: >-
|
||||||
|
{{
|
||||||
|
(bridge_physical if bridge_physical else en_interfaces)
|
||||||
|
+ (bond0_slaves.stdout_lines if bond0_stat.stat.exists else [])
|
||||||
|
| unique
|
||||||
|
| list
|
||||||
|
}}
|
||||||
|
|
||||||
|
- name: Display selected interfaces
|
||||||
ansible.builtin.debug:
|
ansible.builtin.debug:
|
||||||
msg: >
|
msg: "Interfaces to configure for WOL: {{ wol_final_interfaces }}"
|
||||||
{{ en_interfaces }}
|
|
||||||
|
|
||||||
- name: Check supported Wake-on-LAN modes
|
- name: Check supported Wake-on-LAN modes
|
||||||
ansible.builtin.shell: "ethtool {{ item }} | grep 'Supports Wake-on' | tail -1 | awk '{print $3}'"
|
ansible.builtin.shell: "ethtool {{ item }} | grep 'Supports Wake-on' | tail -1 | awk '{print $3}'"
|
||||||
loop: "{{ en_interfaces }}"
|
loop: "{{ wol_final_interfaces }}"
|
||||||
register: wol_supported
|
register: wol_supported
|
||||||
changed_when: false
|
changed_when: false
|
||||||
when: en_interfaces | length > 0
|
when: wol_final_interfaces | length > 0
|
||||||
|
|
||||||
- name: WOL | Check if enabled
|
- name: Check if WOL is enabled
|
||||||
shell: >
|
ansible.builtin.shell: "ethtool {{ item }} | grep 'Wake-on' | tail -1 | awk '{print substr($0,length,1)}'"
|
||||||
ethtool {{ item }} | grep 'Wake-on' | tail -1 | awk '{print substr($0,length,1)}'
|
|
||||||
register: wol_enabled
|
register: wol_enabled
|
||||||
changed_when: false
|
changed_when: false
|
||||||
failed_when: false
|
failed_when: false
|
||||||
loop: "{{ en_interfaces }}"
|
loop: "{{ wol_final_interfaces }}"
|
||||||
when: en_interfaces | length > 0
|
when: wol_final_interfaces | length > 0
|
||||||
|
|
||||||
- name: "Set Wake-on-LAN to {{ wol_mode }}"
|
# ============================================================
|
||||||
|
# Enable or disable WOL as needed
|
||||||
|
# ============================================================
|
||||||
|
- name: Set Wake-on-LAN mode
|
||||||
ansible.builtin.command: "ethtool -s {{ item.0 }} wol {{ wol_mode }}"
|
ansible.builtin.command: "ethtool -s {{ item.0 }} wol {{ wol_mode }}"
|
||||||
loop: "{{ en_interfaces | zip(wol_enabled.results, wol_supported.results) | list }}"
|
loop: "{{ wol_final_interfaces | zip(wol_enabled.results, wol_supported.results) | list }}"
|
||||||
loop_control:
|
loop_control:
|
||||||
label: "{{ item.0 }}"
|
label: "{{ item.0 }}"
|
||||||
when:
|
when:
|
||||||
|
- item.1.stdout is defined
|
||||||
|
- item.2.stdout is defined
|
||||||
- wol_mode not in item.1.stdout
|
- wol_mode not in item.1.stdout
|
||||||
- wol_mode in item.2.stdout
|
- wol_mode in item.2.stdout
|
||||||
|
|
||||||
- name: "Disable Wake-on-LAN"
|
# ============================================================
|
||||||
ansible.builtin.command: "ethtool -s {{ item.0 }} wol {{ wol_mode }}"
|
# Create udev rules for persistence
|
||||||
loop: "{{ en_interfaces | zip(wol_enabled.results, wol_supported.results) | list }}"
|
# ============================================================
|
||||||
loop_control:
|
- name: Create udev rule for WOL persistence
|
||||||
label: "{{ item.0 }}"
|
|
||||||
when:
|
|
||||||
- wol_mode == 'd'
|
|
||||||
- wol_mode not in item.1.stdout
|
|
||||||
|
|
||||||
# -------------------------
|
|
||||||
# 4. Create systemd service for persistence
|
|
||||||
# -------------------------
|
|
||||||
- name: Create systemd service from template
|
|
||||||
ansible.builtin.template:
|
ansible.builtin.template:
|
||||||
src: wol-interfaces.service.j2
|
src: 90-wol.rules.j2
|
||||||
dest: /etc/systemd/system/wol-interfaces.service
|
dest: /etc/udev/rules.d/90-wol.rules
|
||||||
owner: root
|
owner: root
|
||||||
group: root
|
group: root
|
||||||
mode: '0644'
|
mode: '0644'
|
||||||
notify:
|
notify:
|
||||||
- Reload systemd
|
- Reload_udev_rules
|
||||||
|
- Trigger_udev_net
|
||||||
- name: Enable and start WoL service
|
|
||||||
ansible.builtin.systemd:
|
|
||||||
name: wol-interfaces.service
|
|
||||||
enabled: yes
|
|
||||||
state: started
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# # ============================================================
|
# ============================================================
|
||||||
# # Verification & Reporting
|
# Verification & Reporting
|
||||||
# # ============================================================
|
# ============================================================
|
||||||
# - name: Verify Wake-on-LAN status
|
- name: Verify Wake-on-LAN status
|
||||||
# ansible.builtin.command: "ethtool {{ item }}"
|
ansible.builtin.command: "ethtool {{ item }}"
|
||||||
# register: wol_status
|
register: wol_status
|
||||||
# changed_when: false
|
changed_when: false
|
||||||
# loop: "{{ wol_final_interfaces }}"
|
loop: "{{ wol_final_interfaces }}"
|
||||||
# loop_control:
|
loop_control:
|
||||||
# label: "{{ item }}"
|
label: "{{ item }}"
|
||||||
# when: wol_verify
|
when: wol_verify and wol_final_interfaces | length > 0
|
||||||
|
|
||||||
# - name: Display WOL status per interface
|
- name: Display WOL status per interface
|
||||||
# ansible.builtin.debug:
|
ansible.builtin.debug:
|
||||||
# msg: >
|
msg: >
|
||||||
# Interface {{ item.item }} WOL Status:
|
Interface {{ item.item }} WOL Status:
|
||||||
# {{ item.stdout_lines | select('search', 'Wake-on:') | first | default('Status Unknown') }}
|
{{ item.stdout_lines | select('search', 'Wake-on:') | first | default('Status Unknown') }}
|
||||||
# loop: "{{ wol_status.results | default([]) }}"
|
loop: "{{ wol_status.results | default([]) }}"
|
||||||
# loop_control:
|
loop_control:
|
||||||
# label: "{{ item.item }}"
|
label: "{{ item.item }}"
|
||||||
# when: wol_verify
|
when: wol_verify
|
||||||
|
|
||||||
# - name: Get MAC addresses for all interfaces
|
- name: Get MAC addresses for all interfaces
|
||||||
# ansible.builtin.set_fact:
|
ansible.builtin.set_fact:
|
||||||
# wol_mac_addresses: >-
|
wol_mac_addresses: >-
|
||||||
# {{
|
{{
|
||||||
# wol_final_interfaces
|
wol_final_interfaces
|
||||||
# | map('extract', hostvars[inventory_hostname]['ansible_' ~ item] | default({}), 'macaddress')
|
| map('extract', ansible_facts, attribute='macaddress')
|
||||||
# | list
|
| list
|
||||||
# }}
|
}}
|
||||||
|
|
||||||
# - name: Report WOL configuration
|
- name: Report WOL configuration
|
||||||
# ansible.builtin.debug:
|
ansible.builtin.debug:
|
||||||
# msg: |
|
msg: |
|
||||||
# Wake-on-LAN Configuration Summary:
|
Wake-on-LAN Configuration Summary:
|
||||||
# ===================================
|
===================================
|
||||||
# Bridges Configured: {{ wol_bridges_list | join(', ') }}
|
Bridges Configured: {{ wol_bridges | join(', ') }}
|
||||||
# Physical Interfaces: {{ wol_final_interfaces | join(', ') }}
|
Physical Interfaces: {{ wol_final_interfaces | join(', ') }}
|
||||||
# WOL Mode: {{ wol_mode }}
|
WOL Mode: {{ wol_mode }}
|
||||||
# {% if wol_has_bond0 | default(false) %}
|
{% if bond0_stat.stat.exists %}
|
||||||
# Bond0 Detected: Yes
|
Bond0 Detected: Yes
|
||||||
# Bond0 Slaves: {{ wol_bond0_slaves | join(', ') }}
|
Bond0 Slaves: {{ bond0_slaves.stdout_lines | join(', ') }}
|
||||||
# {% endif %}
|
{% endif %}
|
||||||
# {% if wol_report_mac and wol_mac_addresses | length > 0 %}
|
{% if wol_report_mac and wol_mac_addresses | length > 0 %}
|
||||||
# MAC Addresses:
|
MAC Addresses:
|
||||||
# {% for iface, mac in (wol_final_interfaces | zip(wol_mac_addresses) | list) %}
|
{% for iface, mac in (wol_final_interfaces | zip(wol_mac_addresses) | list) %}
|
||||||
# - {{ iface }}: {{ mac | default('Unable to detect') }}
|
- {{ iface }}: {{ mac | default('Unable to detect') }}
|
||||||
# {% endfor %}
|
{% endfor %}
|
||||||
# {% endif %}
|
{% endif %}
|
||||||
|
|||||||
3
templates/90-wol.rules.j2
Normal file
3
templates/90-wol.rules.j2
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
{% for interface in wol_final_interfaces %}
|
||||||
|
ACTION=="add", SUBSYSTEM=="net", KERNEL=="{{ interface }}", RUN+="/sbin/ethtool -s {{ interface }} wol {{ wol_mode }}"
|
||||||
|
{% endfor %}
|
||||||
Reference in New Issue
Block a user