diff --git a/config/ansible/tasks/global/global.yml b/config/ansible/tasks/global/global.yml index 8978569..24f3f6f 100644 --- a/config/ansible/tasks/global/global.yml +++ b/config/ansible/tasks/global/global.yml @@ -27,6 +27,10 @@ ansible.builtin.import_tasks: tasks/global/openssh-server.yml become: true +- name: Include Utils tasks + ansible.builtin.import_tasks: tasks/global/utils.yml + become: true + - name: Ensure common packages are installed ansible.builtin.package: name: diff --git a/config/ansible/tasks/global/utils.yml b/config/ansible/tasks/global/utils.yml new file mode 100644 index 0000000..ea5f965 --- /dev/null +++ b/config/ansible/tasks/global/utils.yml @@ -0,0 +1,24 @@ +--- +- name: Load DOTFILES_PATH environment variable + ansible.builtin.set_fact: + dotfiles_path: "{{ lookup('env', 'DOTFILES_PATH') }}" + +- name: Ensure ~/.local/bin exists + ansible.builtin.file: + path: "{{ ansible_env.HOME }}/.local/bin" + state: directory + mode: "0755" + +- name: Scan utils folder and create symlinks in ~/.local/bin + ansible.builtin.find: + paths: "{{ dotfiles_path }}/config/ansible/tasks/global/utils" + file_type: file + register: utils_files + +- name: Create symlinks for utils scripts + ansible.builtin.file: + src: "{{ item.path }}" + dest: "{{ ansible_env.HOME }}/.local/bin/{{ item.path | basename }}" + state: link + loop: "{{ utils_files.files }}" + become: false diff --git a/config/ansible/tasks/global/utils/ipaddr b/config/ansible/tasks/global/utils/ipaddr new file mode 100755 index 0000000..9f19f75 --- /dev/null +++ b/config/ansible/tasks/global/utils/ipaddr @@ -0,0 +1,124 @@ +#!/usr/bin/env python3 + +import os +import subprocess +import argparse + +def get_physical_interfaces(): + """ + Retrieve a list of physical network interfaces on the system. + + This function checks the `/sys/class/net/` directory to identify physical + network interfaces. It determines if an interface is physical by verifying + the presence of a symbolic link to a `device` directory. + + Returns: + list: A list of strings, where each string is the name of a physical + network interface. + """ + interfaces_path = '/sys/class/net/' + physical_interfaces = [] + + for interface in os.listdir(interfaces_path): + if not os.path.islink(os.path.join(interfaces_path, interface, 'device')): + continue + physical_interfaces.append(interface) + + return physical_interfaces + +def get_virtual_interfaces(): + """ + Retrieves a list of virtual network interfaces on the system. + + This function scans the network interfaces available in the '/sys/class/net/' + directory and filters out physical interfaces and the loopback interface ('lo'). + It identifies virtual interfaces by checking if the 'device' path is not a + symbolic link. + + Returns: + list: A list of virtual network interface names as strings. + """ + interfaces_path = '/sys/class/net/' + virtual_interfaces = [] + + for interface in os.listdir(interfaces_path): + if os.path.islink(os.path.join(interfaces_path, interface, 'device')): + continue + if interface == 'lo': + continue + virtual_interfaces.append(interface) + + return virtual_interfaces + +def display_interface_details(show_all=False): + """ + Display details of network interfaces, including their IP address, subnet mask, + and MAC address, in a formatted table. + + Args: + show_all (bool): If True, includes both physical and virtual interfaces + in the output. Defaults to False, which only displays + physical interfaces. + + Output: + Prints a table with the following columns: + - Interface: The name of the network interface. + - IP Address: The IP address assigned to the interface. + - Subnet: The subnet mask associated with the IP address. + - MAC Address: The MAC address of the interface. + + Notes: + - The function uses the `ip` command to fetch interface details. + - If an interface does not have an IP address, "No IP" is displayed in the + IP Address column. + - If an error occurs while fetching details for an interface, an error + message is printed for that interface. + """ + interfaces = get_physical_interfaces() + + if show_all: + interfaces.extend(get_virtual_interfaces()) + interfaces.sort() + + # Define column widths based on expected maximum content length + col_widths = { + 'interface': 15, # Increased to accommodate longer interface names + 'ip': 18, # Increased for longer IP addresses + 'subnet': 10, + 'mac': 18 + } + + # Print header with proper formatting + print(f"{'Interface':<{col_widths['interface']}} {'IP Address':<{col_widths['ip']}} {'Subnet':<{col_widths['subnet']}} {'MAC Address':<{col_widths['mac']}}") + print("-" * (col_widths['interface'] + col_widths['ip'] + col_widths['subnet'] + col_widths['mac'])) + + for interface in interfaces: + try: + result = subprocess.run(['ip', '-br', 'addr', 'show', interface], + capture_output=True, text=True, check=True) + if result.returncode == 0: + parts = result.stdout.strip().split() + if len(parts) >= 3: + name = parts[0] + mac = parts[1] + ip_with_mask = parts[2] + + # Split IP/mask + if '/' in ip_with_mask: + ip = ip_with_mask.split('/')[0] + subnet = ip_with_mask.split('/')[1] + else: + ip = ip_with_mask + subnet = "" + + print(f"{name:<{col_widths['interface']}} {ip:<{col_widths['ip']}} {subnet:<{col_widths['subnet']}} {mac:<{col_widths['mac']}}") + else: + print(f"{interface:<{col_widths['interface']}} {'No IP':<{col_widths['ip']}} {'':<{col_widths['subnet']}} {parts[1] if len(parts) > 1 else 'N/A':<{col_widths['mac']}}") + except Exception as e: + print(f"Error fetching details for {interface}: {e}") + +if __name__ == "__main__": + parser = argparse.ArgumentParser(description='Display network interface information') + parser.add_argument('-a', '--all', action='store_true', help='Show all interfaces including virtual ones like Tailscale and WireGuard') + args = parser.parse_args() + display_interface_details(args.all) diff --git a/config/home-manager/flake.lock b/config/home-manager/flake.lock index 7e1db38..b28f606 100644 --- a/config/home-manager/flake.lock +++ b/config/home-manager/flake.lock @@ -39,11 +39,11 @@ }, "nixpkgs-unstable": { "locked": { - "lastModified": 1742669843, - "narHash": "sha256-G5n+FOXLXcRx+3hCJ6Rt6ZQyF1zqQ0DL0sWAMn2Nk0w=", + "lastModified": 1742889210, + "narHash": "sha256-hw63HnwnqU3ZQfsMclLhMvOezpM7RSB0dMAtD5/sOiw=", "owner": "nixos", "repo": "nixpkgs", - "rev": "1e5b653dff12029333a6546c11e108ede13052eb", + "rev": "698214a32beb4f4c8e3942372c694f40848b360d", "type": "github" }, "original": {