docs 📝: Refactor README.md with detailed features, role variables, and usage examples.
Updated the README to provide comprehensive information on the Ansible Proxmox WOL role's features, variables, and usage examples.
This commit is contained in:
237
tasks/main.yml
237
tasks/main.yml
@@ -1,104 +1,237 @@
|
||||
---
|
||||
# ============================================================
|
||||
# Install required packages
|
||||
# ============================================================
|
||||
- name: Install required packages
|
||||
ansible.builtin.apt:
|
||||
name: ethtool
|
||||
state: present
|
||||
update_cache: yes
|
||||
|
||||
# ------------------------------------------------------------
|
||||
# Map vmbr0 → backing physical NIC
|
||||
# ------------------------------------------------------------
|
||||
# ============================================================
|
||||
# Normalize and validate configuration
|
||||
# ============================================================
|
||||
- name: Set WOL bridges list (handle string or list)
|
||||
ansible.builtin.set_fact:
|
||||
wol_bridges_list: "{{ wol_bridges if wol_bridges is iterable and wol_bridges is not string else [wol_bridges] }}"
|
||||
|
||||
- name: Validate WOL bridges list is not empty
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- wol_bridges_list | length > 0
|
||||
fail_msg: "wol_bridges must contain at least one bridge interface"
|
||||
|
||||
# ============================================================
|
||||
# Detect physical NICs for all bridges (including bond0)
|
||||
# ============================================================
|
||||
- name: Get bridge link information
|
||||
ansible.builtin.command: "bridge link show"
|
||||
register: bridge_links
|
||||
changed_when: false
|
||||
check_mode: false
|
||||
|
||||
- name: Get bond info
|
||||
ansible.builtin.command: "cat /proc/net/bonding/bond0"
|
||||
register: bond_info
|
||||
changed_when: false
|
||||
failed_when: false
|
||||
check_mode: false
|
||||
|
||||
- name: Show bridge_links.stdout_lines
|
||||
ansible.builtin.debug:
|
||||
msg: "{{ bridge_links.stdout_lines }}"
|
||||
|
||||
- name: "Detect physical NIC backing {{ wol_bridge }}"
|
||||
- name: Initialize detected interfaces dictionary
|
||||
ansible.builtin.set_fact:
|
||||
wol_detected_phy_candidates: >-
|
||||
wol_detected_interfaces: {}
|
||||
|
||||
- name: Detect physical NIC for each bridge
|
||||
ansible.builtin.set_fact:
|
||||
wol_detected_interfaces: >-
|
||||
{{
|
||||
bridge_links.stdout_lines
|
||||
| select('search', 'master ' ~ wol_bridge)
|
||||
| map('regex_replace', '^\\d+: ([^:@]+):.*$', '\\1')
|
||||
| reject('search', '^(veth|tap|fw)')
|
||||
| list
|
||||
}}
|
||||
wol_detected_interfaces | combine({
|
||||
item: (
|
||||
bridge_links.stdout_lines
|
||||
| select('search', 'master ' ~ item)
|
||||
| map('regex_replace', '^\\d+: ([^:@]+):.*$', '\\1')
|
||||
| reject('search', '^(veth|tap|fw)')
|
||||
| list
|
||||
) | first | default('')
|
||||
})
|
||||
}}
|
||||
loop: "{{ wol_bridges_list }}"
|
||||
loop_control:
|
||||
label: "{{ item }}"
|
||||
|
||||
- name: Select first physical NIC candidate
|
||||
ansible.builtin.set_fact:
|
||||
wol_detected_phy: "{{ wol_detected_phy_candidates[0] | default('') }}"
|
||||
- name: Check for bond0 backing
|
||||
block:
|
||||
- name: Detect if any bridge is backed by bond0
|
||||
ansible.builtin.set_fact:
|
||||
wol_has_bond0: "{{ wol_detected_interfaces.values() | select('search', 'bond0') | length > 0 }}"
|
||||
|
||||
- name: Fail if vmbr0 backing NIC could not be detected
|
||||
- name: Extract bond0 slaves if present
|
||||
ansible.builtin.set_fact:
|
||||
wol_bond0_slaves: >-
|
||||
{{
|
||||
(bond_info.stdout | regex_findall('Slave Interface: ([a-zA-Z0-9]+)')) | list
|
||||
}}
|
||||
when: wol_has_bond0 | default(false)
|
||||
when: bond_info.rc == 0
|
||||
|
||||
# ============================================================
|
||||
# Validate configuration and resolve to physical NICs
|
||||
# ============================================================
|
||||
- name: Fail if any bridge backing NIC could not be detected
|
||||
ansible.builtin.fail:
|
||||
msg: >
|
||||
Unable to detect physical NIC backing {{ wol_bridge }}.
|
||||
Please set wol_interface explicitly.
|
||||
Unable to detect physical NIC backing bridge(s): {{ unresolved_bridges | join(', ') }}.
|
||||
Please verify bridges exist or set wol_interfaces explicitly.
|
||||
Bridge output:
|
||||
{{ bridge_links.stdout_lines }}
|
||||
when: wol_detected_phy | default('') | length == 0
|
||||
{{ bridge_links.stdout_lines | join('\n') }}
|
||||
vars:
|
||||
unresolved_bridges: "{{ wol_detected_interfaces | dict2items | selectattr('value', 'equalto', '') | map(attribute='key') | list }}"
|
||||
when: unresolved_bridges | length > 0
|
||||
|
||||
# ------------------------------------------------------------
|
||||
- name: Build final WOL interfaces list (deduped physical NICs)
|
||||
ansible.builtin.set_fact:
|
||||
wol_final_interfaces: "{{ wol_detected_interfaces.values() | unique | list }}"
|
||||
|
||||
# ============================================================
|
||||
# Validate WOL capability
|
||||
# ------------------------------------------------------------
|
||||
- name: Check WOL capability on detected NIC
|
||||
ansible.builtin.command: "ethtool {{ wol_detected_phy }}"
|
||||
register: wol_capabilities
|
||||
# ============================================================
|
||||
- name: Check WOL capability on all detected NICs
|
||||
ansible.builtin.command: "ethtool {{ item }}"
|
||||
register: wol_capabilities_check
|
||||
changed_when: false
|
||||
failed_when: false
|
||||
loop: "{{ wol_final_interfaces }}"
|
||||
loop_control:
|
||||
label: "{{ item }}"
|
||||
|
||||
- name: Fail if NIC does not support Wake-on-LAN
|
||||
ansible.builtin.fail:
|
||||
msg: "Interface {{ wol_detected_phy }} does not support Wake-on-LAN."
|
||||
when: "'Supports Wake-on: g' not in wol_capabilities.stdout"
|
||||
- name: Validate all NICs support WOL
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- item.stdout is search('Supports Wake-on:.*[gGdDpPuU]')
|
||||
fail_msg: "Interface {{ item.item }} does not support Wake-on-LAN"
|
||||
loop: "{{ wol_capabilities_check.results }}"
|
||||
loop_control:
|
||||
label: "{{ item.item }}"
|
||||
|
||||
# ------------------------------------------------------------
|
||||
# Enable WOL immediately
|
||||
# ------------------------------------------------------------
|
||||
- name: Enable Wake-on-LAN immediately
|
||||
ansible.builtin.command: >
|
||||
ethtool -s {{ wol_detected_phy }} wol {{ wol_mode }}
|
||||
# ============================================================
|
||||
# Check current WOL status to ensure idempotency
|
||||
# ============================================================
|
||||
- name: Get current WOL status
|
||||
ansible.builtin.command: "ethtool {{ item }}"
|
||||
register: wol_current_status
|
||||
changed_when: false
|
||||
failed_when: false
|
||||
loop: "{{ wol_final_interfaces }}"
|
||||
loop_control:
|
||||
label: "{{ item }}"
|
||||
|
||||
# ------------------------------------------------------------
|
||||
# Persist WOL via udev (correct + recommended)
|
||||
# ------------------------------------------------------------
|
||||
- name: Create udev rule to persist Wake-on-LAN
|
||||
- name: Build list of NICs needing WOL enabled
|
||||
ansible.builtin.set_fact:
|
||||
wol_needs_enable: >-
|
||||
{{
|
||||
wol_current_status.results
|
||||
| selectattr('stdout', 'search', 'Wake-on: [^g]')
|
||||
| map(attribute='item')
|
||||
| list
|
||||
}}
|
||||
|
||||
# ============================================================
|
||||
# Enable WOL immediately (only if needed)
|
||||
# ============================================================
|
||||
- name: Enable Wake-on-LAN immediately on NICs
|
||||
ansible.builtin.command: "ethtool -s {{ item }} wol {{ wol_mode }}"
|
||||
register: wol_enable_result
|
||||
changed_when: true
|
||||
loop: "{{ wol_needs_enable }}"
|
||||
loop_control:
|
||||
label: "{{ item }}"
|
||||
when: wol_needs_enable | length > 0
|
||||
|
||||
# ============================================================
|
||||
# Persist WOL via udev rules (safe and idempotent)
|
||||
# ============================================================
|
||||
- name: Create udev rule content
|
||||
ansible.builtin.set_fact:
|
||||
wol_udev_rules: >-
|
||||
{{
|
||||
wol_final_interfaces
|
||||
| map('regex_replace', '^(.+)$', 'ACTION=="add", SUBSYSTEM=="net", KERNEL=="\1", RUN+="/sbin/ethtool -s \1 wol {{ wol_mode }}"')
|
||||
| list
|
||||
}}
|
||||
|
||||
- name: Create/Update udev rules file
|
||||
ansible.builtin.copy:
|
||||
dest: /etc/udev/rules.d/90-wol.rules
|
||||
owner: root
|
||||
group: root
|
||||
mode: '0644'
|
||||
content: |
|
||||
ACTION=="add", SUBSYSTEM=="net", KERNEL=="{{ wol_detected_phy }}", RUN+="/sbin/ethtool -s {{ wol_detected_phy }} wol {{ wol_mode }}"
|
||||
# Wake-on-LAN udev rules - Auto-generated by Ansible
|
||||
# Applies to: {{ wol_final_interfaces | join(', ') }}
|
||||
{% for rule in wol_udev_rules %}
|
||||
{{ rule }}
|
||||
{% endfor %}
|
||||
register: udev_rules_changed
|
||||
|
||||
- name: Reload udev rules
|
||||
ansible.builtin.command: udevadm control --reload
|
||||
changed_when: false
|
||||
when: udev_rules_changed is changed
|
||||
|
||||
- name: Trigger udev for network interfaces
|
||||
ansible.builtin.command: udevadm trigger --subsystem-match=net
|
||||
changed_when: false
|
||||
when: udev_rules_changed is changed
|
||||
|
||||
# ------------------------------------------------------------
|
||||
# ============================================================
|
||||
# Verification & Reporting
|
||||
# ------------------------------------------------------------
|
||||
# ============================================================
|
||||
- name: Verify Wake-on-LAN status
|
||||
ansible.builtin.command: "ethtool {{ wol_detected_phy }}"
|
||||
ansible.builtin.command: "ethtool {{ item }}"
|
||||
register: wol_status
|
||||
changed_when: false
|
||||
loop: "{{ wol_final_interfaces }}"
|
||||
loop_control:
|
||||
label: "{{ item }}"
|
||||
when: wol_verify
|
||||
|
||||
- name: Get MAC address
|
||||
ansible.builtin.set_fact:
|
||||
wol_mac_address: "{{ ansible_facts.interfaces[wol_detected_phy].macaddress | default('') }}"
|
||||
- name: Display WOL status per interface
|
||||
ansible.builtin.debug:
|
||||
msg: >
|
||||
Interface {{ item.item }} WOL Status:
|
||||
{{ item.stdout_lines | select('search', 'Wake-on:') | first | default('Status Unknown') }}
|
||||
loop: "{{ wol_status.results | default([]) }}"
|
||||
loop_control:
|
||||
label: "{{ item.item }}"
|
||||
when: wol_verify
|
||||
|
||||
- name: Fail if MAC address could not be detected
|
||||
ansible.builtin.fail:
|
||||
msg: "Unable to determine MAC address for interface {{ wol_detected_phy }}"
|
||||
- name: Get MAC addresses for all interfaces
|
||||
ansible.builtin.set_fact:
|
||||
wol_mac_addresses: >-
|
||||
{{
|
||||
wol_final_interfaces
|
||||
| map('extract', hostvars[inventory_hostname]['ansible_' ~ item] | default({}), 'macaddress')
|
||||
| list
|
||||
}}
|
||||
|
||||
- name: Report WOL configuration
|
||||
ansible.builtin.debug:
|
||||
msg: |
|
||||
Wake-on-LAN Configuration Summary:
|
||||
===================================
|
||||
Bridges Configured: {{ wol_bridges_list | join(', ') }}
|
||||
Physical Interfaces: {{ wol_final_interfaces | join(', ') }}
|
||||
WOL Mode: {{ wol_mode }}
|
||||
{% if wol_has_bond0 | default(false) %}
|
||||
Bond0 Detected: Yes
|
||||
Bond0 Slaves: {{ wol_bond0_slaves | join(', ') }}
|
||||
{% endif %}
|
||||
{% if wol_report_mac and wol_mac_addresses | length > 0 %}
|
||||
MAC Addresses:
|
||||
{% for iface, mac in (wol_final_interfaces | zip(wol_mac_addresses) | list) %}
|
||||
- {{ iface }}: {{ mac | default('Unable to detect') }}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
when:
|
||||
- wol_report_mac
|
||||
- wol_mac_address | length == 0
|
||||
|
||||
Reference in New Issue
Block a user