Execution
Date 22 Jul 2025 13:02:43 +0100
Duration 00:00:03.11
Controller ssh-gw-4.layershift.com
User root
Versions
Ansible 2.16.11
ara 1.7.2 / 1.7.2
Python 3.10.10
Summary
1 Hosts
8 Tasks
8 Results
1 Plays
1 Files
0 Records

File: /home/ssh-gateway/ansible/kuly/get_mac_addresses.yaml

---
- name: Get physical interface behind bridge (if used) and save locally
  hosts: all
  become: true
  gather_facts: false

  vars:
    output_dir: "output"
    ignored_prefixes:
      - "lo"
      - "docker"
      - "veth"
      - "virbr"
      - "wl"
      - "wlan"
      - "tun"
      - "tap"

  tasks:
    - name: Get default route interface
      command: ip route show default
      register: default_route
      changed_when: false

    - name: Extract main interface from default route
      set_fact:
        main_interface: >-
          {{
            (default_route.stdout.split('dev')[1].split()[0])
            if 'dev' in default_route.stdout else ''
          }}
      when: default_route.stdout != ""

    - name: Fail if no default interface found
      fail:
        msg: "No default route found. Unable to determine main interface."
      when: default_route.stdout == "" or ("dev" not in default_route.stdout)

    - name: Check if interface is a bridge (br-*)
      set_fact:
        is_bridge: "{{ main_interface.startswith('br-') }}"

    - name: List slave interfaces of bridge using /sys/class/net/
      shell: >
        find "/sys/class/net/{{ main_interface }}/lower_*" -maxdepth 0 -type d |
        head -1 |
        xargs basename |
        sed 's/^lower_//'
      register: bridge_slave_result
      when: is_bridge | bool
      changed_when: false
      ignore_errors: yes

    - name: Set physical interface from bridge slave
      set_fact:
        physical_interface: "{{ bridge_slave_result.stdout }}"
      when: is_bridge | bool and bridge_slave_result.stdout != ""

    - name: Use main interface if not a bridge
      set_fact:
        physical_interface: "{{ main_interface }}"
      when: not (is_bridge | bool)

    - name: Fail if no physical interface found from bridge
      fail:
        msg: "Could not find any physical interface enslaved to bridge {{ main_interface }}"
      when: is_bridge | bool and (bridge_slave_result.stdout == "" or bridge_slave_result.stdout is undefined)

    - name: Check if physical interface matches ignored patterns
      set_fact:
        is_ignored: "{{ (ignored_prefixes | select('regex', '^' ~ physical_interface) | list | length) > 0 }}"

    - name: Fail if physical interface is ignored
      fail:
        msg: "Physical interface {{ physical_interface }} is ignored (e.g., virtual/wireless)."
      when: is_ignored | bool

    - name: Validate physical interface exists
      stat:
        path: "/sys/class/net/{{ physical_interface }}"
      register: phys_stat
      failed_when: not phys_stat.stat.exists

    - name: Get MAC address of physical interface
      command: "cat /sys/class/net/{{ physical_interface }}/address"
      register: mac_result
      changed_when: false

    - name: Set final MAC fact
      set_fact:
        mac_address: "{{ mac_result.stdout }}"

    # --- LOCAL TASKS: Save on Control Machine ---
    - name: Ensure local output directory exists
      delegate_to: localhost
      run_once: true
      file:
        path: "{{ output_dir }}"
        state: directory
        mode: '0755'

    - name: Write physical interface and MAC to local file
      delegate_to: localhost
      copy:
        content: |
          # Physical Interface Information
          hostname={{ inventory_hostname }}
          logical_interface={{ main_interface }}
          physical_interface={{ physical_interface }}
          mac_address={{ mac_address }}
        dest: "{{ output_dir }}/{{ inventory_hostname }}.txt"
      run_once: true

    - name: Confirm file saved locally
      delegate_to: localhost
      debug:
        msg: "Saved physical interface info for {{ inventory_hostname }} to {{ output_dir }}/{{ inventory_hostname }}.txt"
      run_once: true