--- # ============================================================ # Install required packages # ============================================================ - name: Install required packages ansible.builtin.apt: name: - ethtool - wakeonlan state: present update_cache: true # ============================================================ # Detect physical NICs with WOL support using Ansible facts # ============================================================ - name: Gather network interface facts ansible.builtin.setup: gather_subset: - network when: ansible_facts.interfaces is not defined - name: Display interfaces ansible.builtin.debug: msg: > {{ ansible_facts.interfaces }} # - name: Get interfaces starting with "en" or "eth" # ansible.builtin.set_fact: # en_interfaces: "{{ ansible_facts.interfaces | select('match', '^eth|^ens|^enp') | unique | list }}" - name: Get interfaces starting with "en, "eth" or "nic" ansible.builtin.set_fact: en_interfaces: >- {{ ansible_facts.interfaces | select('match', '^(eth|en|nic)') | list }} - name: Display debug selected interfaces ansible.builtin.debug: msg: > {{ en_interfaces }} - name: Check supported Wake-on-LAN modes ansible.builtin.shell: | set -o pipefail ethtool {{ item }} | grep 'Supports Wake-on' | tail -1 | awk '{print $3}' args: executable: /bin/bash changed_when: false loop: "{{ en_interfaces }}" register: wol_supported when: en_interfaces | length > 0 - name: WOL | Check if enabled ansible.builtin.shell: | set -o pipefail ethtool {{ item }} | grep 'Wake-on' | tail -1 | awk '{print substr($0,length,1)}' args: executable: /bin/bash changed_when: false failed_when: false loop: "{{ en_interfaces }}" register: wol_enabled when: en_interfaces | length > 0 - name: "Set Wake-on-LAN to {{ wol_mode }}" ansible.builtin.command: "ethtool -s {{ item.0 }} wol {{ wol_mode }}" loop: "{{ en_interfaces | zip(wol_enabled.results, wol_supported.results) | list }}" loop_control: label: "{{ item.0 }}" when: - wol_mode not in item.1.stdout - wol_mode in item.2.stdout changed_when: true - name: "Disable Wake-on-LAN" ansible.builtin.command: "ethtool -s {{ item.0 }} wol {{ wol_mode }}" loop: "{{ en_interfaces | zip(wol_enabled.results, wol_supported.results) | list }}" loop_control: label: "{{ item.0 }}" when: - wol_mode == 'd' - wol_mode not in item.1.stdout changed_when: true - 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: wol_mac_addresses: >- {{ wol_mac_addresses | default([]) + [ hostvars[inventory_hostname]['ansible_' ~ item].macaddress ] }} loop: "{{ en_interfaces }}" when: en_interfaces | length > 0 - name: Report WOL configuration ansible.builtin.debug: msg: | Wake-on-LAN Configuration Summary: =================================== Physical Interfaces: {{ en_interfaces | join(', ') }} WOL Mode: {{ wol_mode }} MAC Addresses: {{ wol_mac_addresses | join(', ') }} - name: Start tcpdump to capture WOL packet become: true ansible.builtin.shell: | timeout 10 tcpdump -i {{ en_interfaces[0] }} -nn -c 1 \ 'udp and port {{ wol_port }} and (udp[8:4] = 0xffffffff)' register: tcpdump_result async: 12 poll: 0 - name: Give tcpdump time to start ansible.builtin.pause: seconds: 2 - name: Send WOL packet via shell ansible.builtin.shell: wakeonlan {{ wol_mac_addresses[0] }} # delegate_to: localhost - name: Send Wake-on-LAN packet from localhost community.general.wakeonlan: mac: "{{ wol_mac_addresses[0] }}" port: "{{ wol_port }}" broadcast: 255.255.255.255 # delegate_to: localhost - name: Wait for tcpdump to finish ansible.builtin.async_status: jid: "{{ tcpdump_result.ansible_job_id }}" register: tcpdump_status until: tcpdump_status.finished retries: 12 delay: 1 - name: Check if WOL packet was received ansible.builtin.assert: that: - tcpdump_status.rc == 0 success_msg: "✅ Wake-on-LAN magic packet received by host" fail_msg: "❌ Wake-on-LAN magic packet NOT detected"