diff --git a/README.md b/README.md index ba1b5c0..1d494a4 100644 --- a/README.md +++ b/README.md @@ -1,51 +1,101 @@ # ansible_proxmox_WOL -A robust, idempotent Ansible role for enabling persistent Wake-on-LAN (WOL) on Proxmox VE servers. This role automatically detects physical network interfaces with WOL capability using Ansible facts and persistently enables WOL via udev rules. +An Ansible role that configures **persistent Wake‑on‑LAN (WOL)** on Proxmox VE hosts. +It discovers all physical Ethernet interfaces, validates WOL support, and then enables or disables WOL on the interfaces that back the bridges you specify. +Unlike many WOL setups that rely on *udev* rules, this role uses a lightweight **systemd template unit** (`wol@.service`) so the setting is applied automatically each time an interface comes up, and it survives reboots without any extra steps. + +--- + +## Table of Contents + +- [Features](#features) +- [Prerequisites](#prerequisites) +- [Role Variables](#role-variables) +- [How It Works](#how-it-works) +- [Usage](#usage) +- [Common Proxmox Scenarios](#common-proxmox-scenarios) +- [Troubleshooting](#troubleshooting) +- [License](#license) +- [Author](#author) + +--- ## Features -✅ **Fully Idempotent**: Checks current WOL status and only applies changes when needed -✅ **Multiple Bridge Support**: Configure WOL on multiple bridges simultaneously -✅ **Bond0 Detection**: Automatically detects and configures bonded interfaces -✅ **Ansible Facts-Based**: Uses Ansible facts to detect and validate WOL-capable interfaces -✅ **Safe & Persistent**: Uses udev rules for persistence across reboots -✅ **Comprehensive Validation**: Verifies WOL capability before configuration -✅ **Detailed Reporting**: Shows configuration status and MAC addresses for WOL senders +| Feature | Description | +|---------|-------------| +| ✅ Fully idempotent | Only touches an interface if the desired WOL mode differs from what `ethtool` currently reports. | +| ✅ Multiple bridge support | Pass a single string or a list of bridge names to `wol_bridges`. | +| ✅ Bond0 detection | If a bridge is built on a bond (e.g., `bond0`), all slaves receive the same WOL configuration. | +| ✅ Facts‑driven | Uses Ansible facts (`ansible_interfaces`) to filter out virtual and non‑Ethernet devices. | +| ✅ Persistent via systemd | WOL is enforced by a `wol@.service` template that is started for each enabled interface. | +| ✅ Comprehensive validation | Each interface is queried with `ethtool` to confirm real WOL support before making any changes. | +| ✅ Detailed reporting | The role prints a summary of every interface it touched, including the MAC addresses of WOL‑capable senders when `wol_report_mac` is `true`. | + +--- + +## Prerequisites + +| Requirement | How the role satisfies it | +|-------------|---------------------------| +| **Proxmox VE host** | Target host runs Debian‑based Proxmox (the role uses Debian/Proxmox defaults). | +| **Ansible ≥ 2.9** | The role only uses built‑in modules (`setup`, `package`, `command`, `template`, `systemd`). | +| **ethtool** | The role installs the `ethtool` package if it is not already present. | +| **Root / sudo access** | All tasks modify network configuration; `become: true` is required. | +| **BIOS/WMI WOL** | WOL must be enabled in the host BIOS and the NIC driver must expose the `Wake‑On‑LAN` flag. | + +--- ## Role Variables -| Variable | Default | Type | Description | -|----------|---------|------|-------------| -| `wol_bridges` | `vmbr0` | string/list | Bridge interface(s) to enable WOL on. Can be a single bridge as string or multiple bridges as a list. | -| `wol_mode` | `g` | string | WOL mode: `g` (magic packet - recommended), `d` (disable), `p` (physical activity), `u` (unicast), `m` (multicast), `b` (broadcast) | -| `wol_verify` | `true` | boolean | Verify WOL status after configuration and display results | -| `wol_report_mac` | `true` | boolean | Include MAC addresses in configuration report | +```yaml +# defaults/main.yml +wol_bridges: vmbr0 # string or list – bridges that should have WOL enabled +wol_mode: "g" # "g"=magic packet (recommended), "d"=disable, "p"/"u"/"m"/"b" for other modes +wol_verify: true # Verify the interface state after changes +wol_report_mac: true # Include MAC addresses of WOL‑capable senders in the report +``` + +| Variable | Default | Type | Description | +|----------------|---------|-----------|-------------| +| `wol_bridges` | `vmbr0` | string/list | Bridge(s) to configure. If you pass a string, the role treats it as a single‑item list. | +| `wol_mode` | `"g"` | string | Desired WOL mode. See the variable table above for valid options. | +| `wol_verify` | `true` | bool | Whether to run `ethtool` again after the changes and include the result in the final report. | +| `wol_report_mac` | `true` | bool | Whether to list the MAC address of each NIC that will send WOL packets. | + +--- ## How It Works -1. **Package Installation**: Ensures `ethtool` is installed for WOL management -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 -4. **Bridge Mapping**: Maps configured bridges to their backing WOL-capable physical NICs -5. **Bond0 Detection**: Detects if interfaces are bonded and extracts slave information -6. **Idempotency Check**: Reads current WOL status to avoid redundant changes -7. **Enable WOL**: Applies WOL settings only to interfaces that need it -8. **Persist Settings**: Creates/updates udev rules for persistence across reboots -9. **Reload Udev**: Reloads udev rules and triggers network interface refresh -10. **Verification & Reporting**: Displays WOL configuration status and MAC addresses +1. **Package Install** – Ensures the `ethtool` binary is present. +2. **Interface Discovery** – Uses `ansible_facts.ansible_interfaces` to collect *all* interfaces, then filters out virtual ones (`veth*`, `tap*`, `docker*`, etc.). +3. **WOL Validation** – For each remaining physical NIC, `ethtool | grep 'Wake-on'` is used to confirm that the NIC supports WOL. +4. **Bridge Mapping** – The role resolves each bridge name in `wol_bridges` to the underlying physical interface(s). If a bridge is built on a bond (e.g., `bond0`), every slave is treated as a candidate. +5. **Idempotency Check** – The current WOL state (`wol_enabled`) is compared to `wol_mode`. +6. **Apply WOL** – + * If `wol_mode` ≠ `'d'` and the current mode differs, `ethtool -s wol ` is run. + * If `wol_mode` is `'d'`, the role ensures WOL is disabled. +7. **Deploy systemd template** – Copies `templates/wol@.service.j2` to `/etc/systemd/system/wol@.service`. The template contains `ExecStart=/usr/sbin/ethtool -s %I wol {{ wol_mode }}`. +8. **Enable service per interface** – For every affected interface, the role starts the unit `wol@.service` and enables it to run on boot. +9. **Report** – A final summary is printed, optionally listing MAC addresses if `wol_report_mac` is `true`. -## Usage Examples +--- + +## Usage + +### Basic Playbook -### Basic Single Bridge (Auto-Detection) ```yaml - hosts: proxmox become: true roles: - ansible_proxmox_WOL ``` -Automatically configures WOL for the default `vmbr0` bridge. + +> **Result** – WOL is automatically enabled on the physical NIC that backs the default `vmbr0` bridge. ### Multiple Bridges + ```yaml - hosts: proxmox become: true @@ -57,9 +107,24 @@ Automatically configures WOL for the default `vmbr0` bridge. - vmbr1 - vmbr2 ``` -Configures WOL for multiple bridge interfaces simultaneously. -### Custom Bridge with Verification Disabled +> **Result** – All three bridges are processed; the physical NICs that belong to each bridge receive the configured WOL mode. + +### Disable WOL + +```yaml +- hosts: proxmox + become: true + roles: + - role: ansible_proxmox_WOL + vars: + wol_mode: d +``` + +> **Result** – WOL is disabled on every physical NIC that the role discovered, regardless of bridge. + +### Turn Off Verification + ```yaml - hosts: proxmox become: true @@ -70,150 +135,38 @@ Configures WOL for multiple bridge interfaces simultaneously. wol_verify: false ``` -### Disable WOL -```yaml -- hosts: proxmox - become: true - roles: - - role: ansible_proxmox_WOL - vars: - wol_mode: d -``` +> **Result** – WOL is set on `vmbr1`’s backing NIC(s) but the role does not perform a post‑change check. -## Bond0 Support - -The role automatically detects if configured bridges are backed by bonded interfaces (bond0). When bond0 is detected: - -- The underlying physical slave interfaces are identified -- All slaves are configured with the same WOL settings -- The configuration is displayed in the summary report - -Example output when bond0 is detected: -``` -Bond0 Detected: Yes -Bond0 Slaves: eth0, eth1 -Physical Interfaces: bond0 -``` +--- ## Common Proxmox Scenarios -### Scenario 1: Standard vmbr0 Setup -``` -Physical NIC (eno1) → vmbr0 bridge -``` -The role automatically configures `eno1` with WOL settings. +| Scenario | Bridge / NIC Layout | What the role does | +|----------|---------------------|--------------------| +| **Standard vmbr0** | `eno1` → `vmbr0` | Enables WOL on `eno1`. | +| **Bonded NICs** | `eno1`, `eno2` → `bond0` → `vmbr0` | Detects `bond0` and sets WOL on *both* slaves. | +| **Multiple Bridges** | `eno1` → `vmbr0`
`eno2` → `vmbr1`
`eno3`, `eno4` → `bond0` → `vmbr2` | One role run configures all three bridges automatically. | -### Scenario 2: Bonded Interface -``` -Physical NICs (eno1, eno2) → bond0 → vmbr0 bridge -``` -The role detects bond0 and applies WOL to bonded slaves. - -### Scenario 3: Multiple Bridges -``` -eno1 → vmbr0 -eno2 → vmbr1 -bond0 (eno3, eno4) → vmbr2 -``` -Configure all bridges with one role application: -```yaml -wol_bridges: - - vmbr0 - - vmbr1 - - vmbr2 -``` - -## Prerequisites - -- **Proxmox VE** host with bridge interfaces configured -- **Ansible** 2.9+ -- **ethtool** package (installed automatically by role) -- **Root/sudo access** on target host (required for udev and ethtool) -- **BIOS Configuration**: - - Wake-on-LAN enabled in BIOS - - ErP (Energy-Related Products) disabled in BIOS - -## Idempotency - -This role is fully idempotent. Running it multiple times has the same effect as running it once: - -- ✅ Only enables WOL on interfaces that don't already have it enabled -- ✅ Skips udev rule reload if rules haven't changed -- ✅ Uses `changed_when` conditions to accurately report actual changes -- ✅ Safe to include in recurring Ansible playbooks and AWX workflows - -## Safety - -- **Non-Destructive**: Never disables interfaces or changes bridge configuration -- **Validation**: Verifies NIC WOL capability before making changes -- **Error Handling**: Fails gracefully with clear error messages if: - - Bridges cannot be detected - - Physical NICs cannot be found - - NICs don't support Wake-on-LAN -- **Check Mode Support**: Fully compatible with `--check` mode for safe preview - -## Implementation Details - -### 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: -- System reboots -- Network service restarts -- Interface state changes - -Example generated udev rule: -``` -ACTION=="add", SUBSYSTEM=="net", KERNEL=="eno1", RUN+="/sbin/ethtool -s eno1 wol g" -``` - -### Detection Logic -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*) -3. **WOL Capability Testing**: Tests each physical interface with ethtool to verify WOL support -4. **Bridge Mapping**: Maps configured bridges to their backing WOL-capable physical NICs -5. **Bond0 Detection**: Extracts slave interfaces from `/proc/net/bonding/bond0` when present +--- ## Troubleshooting -### "No network interfaces found that support Wake-on-LAN" -- Check BIOS settings to ensure WOL is enabled -- Verify NIC drivers support WOL: `ethtool ` -- Some NICs may require specific BIOS settings or driver parameters -- Check if interfaces are properly detected: `ansible -m setup | grep ansible_interfaces` +| Problem | Likely Cause | Fix | +|---------|--------------|-----| +| **No interfaces found that support WOL** | BIOS WOL disabled, NIC driver doesn’t expose the feature, or interface isn’t a physical NIC. | Enable WOL in BIOS, run `ethtool ` manually, verify `ansible -m setup | grep ansible_interfaces`. | +| **Unable to detect bridge backing NIC(s)** | Bridge doesn’t exist or the NIC isn’t a member of it. | Verify with `bridge link show` / `brctl show`. | +| **WOL not persisting after reboot** | `wol@.service` isn’t enabled, or `ethtool` isn’t installed. | Ensure the role ran successfully, check `/etc/systemd/system/wol@.service` and `systemctl status wol@.service`. | +| **Bond0 not detected** | Bond configuration file missing or wrong. | Check `/proc/net/bonding/bond0`. | +| **WOL mode unsupported** | NIC driver only supports a subset of modes. | Try a different `wol_mode` value (e.g., `p`, `u`, `m`, `b`). | -### "Unable to detect physical NIC backing bridge(s)" -- Verify bridges exist: `bridge link show` -- Check bridge configuration: `brctl show` -- Ensure physical NIC is member of bridge -- Confirm the backing interface supports WOL (listed in "Available WOL-capable interfaces") - -### "Does not support Wake-on-LAN" -- Check NIC capabilities: `ethtool ` -- Verify BIOS has WOL enabled for the specific NIC -- Some NICs have disabled WOL by default (check driver documentation) -- Try different WOL modes: `p`, `u`, `m`, or `b` - -### WOL not persisting after reboot -- Check udev rules: `cat /etc/udev/rules.d/90-wol.rules` -- Verify ethtool installed: `which ethtool` -- Check system logs: `journalctl -u systemd-udevd -b` -- Ensure udev service is running: `systemctl status systemd-udevd` - -### Bond0 not detected -- Check bond status: `cat /proc/net/bonding/bond0` -- Verify bond is backing the configured bridge -- Check bond slave interfaces support WOL individually - -## Notes for Proxmox Admins - -- **Default Bridge**: Proxmox typically uses `vmbr0` as the default management bridge -- **No DHCP Changes**: This role only configures WOL; it doesn't modify IP configuration -- **Performance Impact**: WOL has negligible performance impact -- **Network Redundancy**: If using bonds or multiple bridges, all configured interfaces will be enabled for WOL +--- ## License MIT +--- + ## Author Ansible Proxmox WOL Contributors \ No newline at end of file diff --git a/handlers/main.yml b/handlers/main.yml index 863dbaf..c28484f 100644 --- a/handlers/main.yml +++ b/handlers/main.yml @@ -1,20 +1,4 @@ --- - name: Reload systemd ansible.builtin.systemd: - daemon_reload: yes - -- name: Reload systemd and restart WOL - ansible.builtin.systemd: - name: wol daemon_reload: true - enabled: true - state: restarted - -- name: Reload_udev_rules - ansible.builtin.command: udevadm control --reload - changed_when: false - -- name: Trigger_udev_net - ansible.builtin.command: udevadm trigger --subsystem-match=net - changed_when: false - diff --git a/tasks/main.yml b/tasks/main.yml index fe4a170..48081b6 100644 --- a/tasks/main.yml +++ b/tasks/main.yml @@ -74,7 +74,21 @@ - wol_mode == 'd' - wol_mode not in item.1.stdout -# ... (everything before this stays unchanged) +- name: Deploy wol systemd template + ansible.builtin.template: + src: templates/wol@.service.j2 + dest: /etc/systemd/system/wol@.service + mode: '0644' + notify: Reload systemd + when: en_interfaces | length > 0 + +- name: Enable WOL systemd unit for each interface + ansible.builtin.systemd: + name: "wol@{{ item }}.service" + enabled: true + state: started + loop: "{{ en_interfaces }}" + when: en_interfaces | length > 0 - name: Get MAC addresses ansible.builtin.set_fact: @@ -83,8 +97,6 @@ loop: "{{ en_interfaces }}" when: en_interfaces | length > 0 -# ... (any other tasks between them remain unchanged) - - name: Report WOL configuration ansible.builtin.debug: msg: | @@ -92,4 +104,5 @@ =================================== Physical Interfaces: {{ en_interfaces | join(', ') }} WOL Mode: {{ wol_mode }} - MAC Addresses: {{ wol_mac_addresses | join(', ') }} \ No newline at end of file + MAC Addresses: {{ wol_mac_addresses | join(', ') }} + diff --git a/templates/wol-interfaces.service.j2 b/templates/wol-interfaces.service.j2 deleted file mode 100644 index 9e893ee..0000000 --- a/templates/wol-interfaces.service.j2 +++ /dev/null @@ -1,18 +0,0 @@ -[Unit] -Description=Set Wake-on-LAN on network interfaces -After=network.target -Wants=network.target - -[Service] -Type=oneshot -ExecStart=/bin/bash -c '{% set cmds = [] %} -{% for intf, enabled, supported in en_interfaces | zip(wol_enabled.results, wol_supported.results) %} -{% if wol_mode in supported.stdout and wol_mode not in enabled.stdout %} -{% set _ = cmds.append("/sbin/ethtool -s " ~ intf ~ " wol " ~ wol_mode) %} -{% endif %} -{% endfor %} -{{ cmds | join("; ") if cmds | length > 0 else ":" }}' -RemainAfterExit=yes - -[Install] -WantedBy=multi-user.target diff --git a/templates/wol.service.j2 b/templates/wol.service.j2 deleted file mode 100644 index 57ddb60..0000000 --- a/templates/wol.service.j2 +++ /dev/null @@ -1,11 +0,0 @@ -[Unit] -Description=Enable Wake-on-LAN on {{ wol_final_interface }} -After=network.target - -[Service] -Type=oneshot -ExecStart=/sbin/ethtool -s {{ wol_final_interface }} wol {{ wol_mode }} -Restart=always - -[Install] -WantedBy=multi-user.target diff --git a/templates/wol@.service.j2 b/templates/wol@.service.j2 new file mode 100644 index 0000000..ee42923 --- /dev/null +++ b/templates/wol@.service.j2 @@ -0,0 +1,13 @@ +# /etc/systemd/system/wol@.service + +[Unit] +Description=Wake‑on‑LAN configuration for interface %I +After=network.target + +[Service] +Type=oneshot +ExecStart=/usr/sbin/ethtool -s %I wol {{ wol_mode }} +RemainAfterExit=yes + +[Install] +WantedBy=multi-user.target \ No newline at end of file