diff options
| author | Viacheslav Hletenko <v.gletenko@vyos.io> | 2023-04-17 18:00:05 +0000 | 
|---|---|---|
| committer | Viacheslav Hletenko <v.gletenko@vyos.io> | 2023-04-17 18:00:05 +0000 | 
| commit | 0531ea22050d66e6da3adc87cad57ea527cea71b (patch) | |
| tree | 84dcc2f178823e09eaab9e4655836eab1199f263 | |
| parent | 8550b8dbdd445399e7f97f76319df7d66fcc2502 (diff) | |
| download | vyos-1x-0531ea22050d66e6da3adc87cad57ea527cea71b.tar.gz vyos-1x-0531ea22050d66e6da3adc87cad57ea527cea71b.zip | |
T5137: Refactoring show tech-support report
Split script to small functions for flexible output reports.
Improve header for commands.
Each funciton easily can be modified or extended.
Remove splitting command/output via percent symbol.
Remove old commands and directiories like /etc/rc.local, iptables,
brctl, etc.
Remove ethtool operation for subinterfaces.
Extend ethtool debug output.
Add correct nftables command.
| -rw-r--r-- | src/op_mode/show_techsupport_report.py | 703 | 
1 files changed, 284 insertions, 419 deletions
| diff --git a/src/op_mode/show_techsupport_report.py b/src/op_mode/show_techsupport_report.py index 13ed9a3c1..782004144 100644 --- a/src/op_mode/show_techsupport_report.py +++ b/src/op_mode/show_techsupport_report.py @@ -14,425 +14,290 @@  # You should have received a copy of the GNU General Public License  # along with this program.  If not, see <http://www.gnu.org/licenses/>. -from vyos.util import call  import os +from typing import List +from vyos.util import rc_cmd +from vyos.ifconfig import Section +from vyos.ifconfig import Interface -def header(cmd): -    print(16 * '-' + '\n' + cmd + '\n' + 16 * '-') -    return - - -# get intefaces info -interfaces_list = os.popen('ls /sys/class/net/ | grep eth').read().split() -bridges_list = os.popen('ls /sys/class/net/ | grep br').read().split() - -###################### THE PART OF CONFIGURATION ###################### - -cmd_list_conf = [ -    "VyOS Version and Package Changes%/opt/vyatta/bin/vyatta-op-cmd-wrapper show version all", -    "Configuration File%cat /opt/vyatta/etc/config/config.boot", -    "Running configuration%/opt/vyatta/bin/vyatta-op-cmd-wrapper show configuration", -    "Package Repository Configuration File%cat /etc/apt/sources.list", -    "User Startup Scripts%cat /etc/rc.local", -    "Quagga Configuration%vtysh -c 'show run'" -] - - -def CONFIGURATION(cmd): -    for command_line in cmd: -        line = command_line.split('%') -        head = line[0] -        command = line[1] -        header(head) -        call(command) -    return - - -###################### THE PART OF INTERFACES ###################### - -cmd_list_int = [ -    "Interfaces%/opt/vyatta/bin/vyatta-op-cmd-wrapper show interfaces", -    "Ethernet", -    "Interface statistics%ip -s link show", -    "Physical Interface statistics for%ethtool -S", -    "Physical Interface Details for %/opt/vyatta/bin/vyatta-op-cmd-wrapper show interfaces ethernet%ethtool -k $eth", -    "ARP Table (Total entries)%/opt/vyatta/bin/vyatta-op-cmd-wrapper show arp", -    "Number of incomplete entries in ARP table%show arp | grep incomplete | wc -l", -    "Bridges" -] - - -def INTERFACES(cmd): -    for command_line in cmd: -        line = command_line.split('%') -        head = line[0] -        if command_line.startswith("Ethernet"): -            header(command_line) -        elif command_line.startswith("Physical Interface statistics"): -            for command_interface in interfaces_list: -                header(f'{head} {command_interface}') -                call(f'{line[1]} {command_interface}') -        elif command_line.startswith("Physical Interface Details"): -            for command_interface in interfaces_list: -                header(f'{head} {command_interface}') -                call(f'{line[1]} {command_interface} physical') -                call(f'{line[2]} {command_interface}') -        elif command_line.startswith("Bridges"): -            header(command_line) -            for command_interface in bridges_list: -                header(f'Information for {command_interface}') -                call(f'/sbin/brctl showstp {command_interface}') -                call(f'/sbin/brctl showmacs {command_interface}') -        else: -            command = line[1] -            header(head) -            call(command) -    return - - -###################### THE PART OF ROUTING ###################### - -cmd_list_route = [ -    "show ip route bgp", -    "show ip route cache", -    "show ip route connected", -    "show ip route forward", -    "show ip route isis", -    "show ip route kernel", -    "show ip route ospf", -    "show ip route rip", -    "show ip route static", -    "show ip route summary", -    "show ip route supernets-only", -    "show ip route table", -    "show ip route tag", -    "show ip route vrf", -    "show ipv6 route bgp", -    "show ipv6 route cache", -    "show ipv6 route connected", -    "show ipv6 route forward", -    "show ipv6 route isis", -    "show ipv6 route kernel", -    "show ipv6 route ospf", -    "show ipv6 route rip", -    "show ipv6 route static", -    "show ipv6 route summary", -    "show ipv6 route supernets-only", -    "show ipv6 route table", -    "show ipv6 route tag", -    "show ipv6 route vrf", -] - - -def ROUTING(cmd): -    for command_line in cmd: -        head = command_line -        command = command_line -        header(head) -        call(f'/opt/vyatta/bin/vyatta-op-cmd-wrapper {command}') -    return - - -###################### THE PART OF IPTABLES ###################### - -cmd_list_iptables = [ -    "Filter Chain Details%sudo /sbin/iptables -L -vn", -    "Nat Chain Details%sudo /sbin/iptables -t nat -L -vn", -    "Mangle Chain Details%sudo /sbin/iptables -t mangle -L -vn", -    "Raw Chain Details%sudo /sbin/iptables -t raw -L -vn", -    "Save Iptables Rule-Set%sudo iptables-save -c" -] - - -def IPTABLES(cmd): -    for command_line in cmd: -        line = command_line.split('%') -        head = line[0] -        command = line[1] -        header(head) -        call(command) -    return - - -###################### THE PART OF SYSTEM ###################### - -cmd_list_system = [ -    "Show System Image Version%show system image version", -    "Show System Image Storage%show system image storage", -    "Current Time%date", -    "Installed Packages%dpkg -l", -    "Loaded Modules%cat /proc/modules", -    "CPU", -    "Installed CPU/s%lscpu", -    "Cumulative CPU Time Used by Running Processes%top -n1 -b -S", -    "Hardware Interrupt Counters%cat /proc/interrupts", -    "Load Average%cat /proc/loadavg" -] - - -def SYSTEM(cmd): -    for command_line in cmd: -        line = command_line.split('%') -        head = line[0] -        if command_line.startswith("CPU"): -            header(command_line) -        elif line[1].startswith("show"): -            header(head) -            command = line[1] -            call(f'/opt/vyatta/bin/vyatta-op-cmd-wrapper {command}') -        else: -            header(head) -            command = line[1] -            call(command) -    return - - -###################### THE PART OF PROCESSES ###################### - -cmd_list_processes = [ -    "Running Processes%ps -ef", -    "Memory", -    "Installed Memory%cat /proc/meminfo", -    " Memory Usage%free", -    "Storage", -    "Devices%cat /proc/devices", -    "Partitions%cat /proc/partitions", -    "Partitioning for disks%fdisk -l /dev/" -] - - -def PROCESSES(cmd): -    for command_line in cmd: -        line = command_line.split('%') -        head = line[0] -        if command_line.startswith("Memory"): -            header(command_line) -        elif command_line.startswith("Storage"): -            header(command_line) -        elif command_line.startswith("Partitioning for disks"): -            header(head) -            disks = set() -            with open('/proc/partitions') as partitions_file: -                for line in partitions_file: -                    fields = line.strip().split() -                    if len(fields) == 4 and fields[3].isalpha() and fields[3] != 'name': -                        disks.add(fields[3]) -                for disk in disks: -                    call(f'fdisk -l /dev/{disk}') -        else: -            header(head) -            command = line[1] -            call(command) -    return - - -###################### THE PART OF CORE SECTION ###################### - -cmd_list_core = [ -    "Mounts%cat /proc/mounts", -    "Diskstats%cat /proc/diskstats", -    "Hard Drive Usage%df -h -x squashfs", -    # "General System", -    "Boot Messages%cat /var/log/dmesg", -    "Recent Kernel messages (dmesg)%dmesg", -    "PCI Info%sudo lspci -vvx", -    "PCI Vendor and Device Codes%sudo lspci -nn", -    # "System Info%${vyatta_bindir}/vyatta-show-dmi", -    "GRUB Command line%cat /proc/cmdline", -    "Open Ports%sudo lsof -P -n -i", -    "System Startup Files%ls -l /etc/rc?.d", -    "Login History%last -ix", -    "Recent Log Messages%tail -n 250 /var/log/messages", -    "NTP%/opt/vyatta/bin/vyatta-op-cmd-wrapper show ntp", -] - - -def CORE(cmd): -    for command_line in cmd: -        line = command_line.split('%') -        command = line[1] -        header(line[0]) -        call(command) -    return - - -###################### THE PART OF VyOS INFORMATION ###################### - -cmd_list_vyos = [ -    "BGP", -    "header BGP Summary", -    "show ip bgp summary", -    "header BGP Neighbors", -    "show ip bgp neighbors", -    "header BGP Debugging Information", -    "show monitoring protocols bgp", -    "CLUSTERING", -    "Cluster Status", -    "show cluster status", -    "DHCP Server", -    "DHCP Leases", -    "show dhcp server leases", -    "DHCP Statistics", -    "show dhcp server statistics", -    "DHCP Client", -    "DHCP Client Leases", -    "show dhcp client leases", -    "DHCPV6 Server", -    "DHCPV6 Server Status", -    "show dhcpv6 server status", -    "DHCPV6 Server Leases", -    "show dhcpv6 server leases", -    "DHCPV6 Relay", -    "DHCPV6 Relay Status", -    "show dhcpv6 relay-agent status", -    "DHCPV6 Client", -    "DHCPV6 Client Leases", -    "show dhcpv6 client leases", -    "DNS", -    "DNS Dynamic Status", -    "show dns dynamic status", -    "DNS Forwarding Statistics", -    "show dns forwarding statistics", -    "DNS Forwarding Nameservers", -    "show dns forwarding nameservers", -    "FIREWALL", -    "Firewall Group", -    "show firewall group", -    "Firewall Summary", -    "show firewall summary", -    "Firewall Statistics", -    "show firewall statistics", -    "IPSec", -    "IPSec Status", -    "show vpn ipsec status", -    "IPSec sa", -    "show vpn ipsec sa", -    "IPSec sa Detail", -    "show vpn ipsec sa detail", -    "IPSec sa Statistics", -    "show vpn ipsec sa statistics", -    "/etc/ipsec.conf", -    "cat /etc/ipsec.conf", -    "/etc/ipsec.secrets", -    "cat /etc/ipsec.secrets", -    "NAT", -    "NAT Rules", -    "show nat rules", -    "NAT Statistics", -    "show nat statistics", -    "NAT Translations Detail", -    "show nat translations detail", -    "FlowAccounting", -    "show flow-accounting", -    "OPENVPN", -    "OpenVPN Interfaces", -    "show interfaces openvpn detail", -    "OpenVPN Server Status", -    "show openvpn status server", -    "OSPF", -    "OSPF Neighbor", -    "show ip ospf neighbor", -    "OSPF Route", -    "show ip ospf route", -    "OSPF Debugging Information", -    "show monitoring protocols ospf", -    "OSPFV3", -    "OSPFV3 Debugging Information", -    "show monitoring protocols ospfv3", -    "Policy", -    "IP Route Maps", -    "show ip protocol", -    "Route-Map", -    "show route-map", -    # header IP Access Lists -    # show ip access-lists -    "IP Community List", -    "show ip community-list", -    "Traffic Policy", -    "Current Traffic Policies", -    "show queueing", -    "RIP", -    "IP RIP", -    "show ip rip", -    "RIP Status", -    "show ip rip status", -    "RIP Debugging Information", -    "show monitoring protocols rip", -    "RIPNG", -    "RIPNG Debugging Information", -    "show monitoring protocols ripng", -    "VPN-L2TP", -    "VPN ike secrets", -    "show vpn ike secrets", -    "VPN rsa-keys", -    "show vpn ike rsa-keys", -    "VPN ike sa", -    "show vpn ike sa", -    "VPN ike Status", -    "show vpn ike status", -    "VPN Remote-Access", -    "show vpn remote-access", -    "VPN Debug Detail", -    "show vpn debug detail", -    "VPN-PPTP", -    "VPN Remote-Access", -    "show vpn remote-access", -    "VRRP", -    # XXX: not checking if configured, we'd have to walk all VIFs -    "show vrrp detail", -    "WAN LOAD BALANCING", -    "Wan Load Balance", -    "show wan-load-balance", -    "Wan Load Balance Status", -    "show wan-load-balance status", -    "Wan Load Balance Connection", -    "show wan-load-balance connection", -    "WEBPROXY/URL-FILTERING", -    "WebProxy Blacklist Categories", -    "show webproxy blacklist categories", -    "WebProxy Blacklist Domains", -    "show webproxy blacklist domains", -    "WebProxy Blacklist URLs", -    "show webproxy blacklist urls", -    "WebProxy Blacklist Log", -    "show webproxy blacklist log summary", -] - - -def VyOS(cmd): -    for command_line in cmd: -        if command_line.startswith("show"): -            call(f'/opt/vyatta/bin/vyatta-op-cmd-wrapper {command_line}') -        elif command_line.startswith("cat"): -            call(command_line) -        else: -            header(command_line) -    return - - -###################### execute all the commands ###################### - -header('CONFIGURATION') -CONFIGURATION(cmd_list_conf) - -header('INTERFACES') -INTERFACES(cmd_list_int) - -header('ROUTING') -ROUTING(cmd_list_route) - -header('IPTABLES') -IPTABLES(cmd_list_iptables) - -header('SYSTEM') -SYSTEM(cmd_list_system) - -header('PROCESSES') -PROCESSES(cmd_list_processes) - -header('CORE') -CORE(cmd_list_core) - -header('VyOS Information') -VyOS(cmd_list_vyos) + +def print_header(command: str) -> None: +    """Prints a command with headers '-'. + +    Example: + +    % print_header('Example command') + +    --------------- +    Example command +    --------------- +    """ +    header_length = len(command) * '-' +    print(f"\n{header_length}\n{command}\n{header_length}") + + +def execute_command(command: str, header_text: str) -> None: +    """Executes a command and prints the output with a header. + +    Example: +    % execute_command('uptime', "Uptime of the system") + +    -------------------- +    Uptime of the system +    -------------------- +    20:21:57 up  9:04,  5 users,  load average: 0.00, 0.00, 0.0 + +    """ +    print_header(header_text) +    try: +        rc, output = rc_cmd(command) +        print(output) +    except Exception as e: +        print(f"Error executing command: {command}") +        print(f"Error message: {e}") + + +def op(cmd: str) -> str: +    """Returns a command with the VyOS operational mode wrapper.""" +    return f'/opt/vyatta/bin/vyatta-op-cmd-wrapper {cmd}' + + +def get_ethernet_interfaces() -> List[Interface]: +    """Returns a list of Ethernet interfaces.""" +    return Section.interfaces('ethernet') + + +def show_version() -> None: +    """Prints the VyOS version and package changes.""" +    execute_command(op('show version'), 'VyOS Version and Package Changes') + + +def show_config_file() -> None: +    """Prints the contents of a configuration file with a header.""" +    execute_command('cat /opt/vyatta/etc/config/config.boot', 'Configuration file') + + +def show_running_config() -> None: +    """Prints the running configuration.""" +    execute_command(op('show configuration'), 'Running configuration') + + +def show_package_repository_config() -> None: +    """Prints the package repository configuration file.""" +    execute_command('cat /etc/apt/sources.list', 'Package Repository Configuration File') +    execute_command('ls -l /etc/apt/sources.list.d/', 'Repositories') + + +def show_user_startup_scripts() -> None: +    """Prints the user startup scripts.""" +    execute_command('cat /config/scripts/vyos-postconfig-bootup.script', 'User Startup Scripts') + + +def show_frr_config() -> None: +    """Prints the FRR configuration.""" +    execute_command('vtysh -c "show run"', 'FRR configuration') + + +def show_interfaces() -> None: +    """Prints the interfaces.""" +    execute_command(op('show interfaces'), 'Interfaces') + + +def show_interface_statistics() -> None: +    """Prints the interface statistics.""" +    execute_command('ip -s link show', 'Interface statistics') + + +def show_physical_interface_statistics() -> None: +    """Prints the physical interface statistics.""" +    execute_command('/usr/bin/true', 'Physical Interface statistics') +    for iface in get_ethernet_interfaces(): +        # Exclude vlans +        if '.' in iface: +            continue +        execute_command(f'ethtool --driver {iface}', f'ethtool --driver {iface}') +        execute_command(f'ethtool --statistics {iface}', f'ethtool --statistics {iface}') +        execute_command(f'ethtool --show-ring {iface}', f'ethtool --show-ring {iface}') +        execute_command(f'ethtool --show-coalesce {iface}', f'ethtool --show-coalesce {iface}') +        execute_command(f'ethtool --pause {iface}', f'ethtool --pause {iface}') +        execute_command(f'ethtool --show-features {iface}', f'ethtool --show-features {iface}') +        execute_command(f'ethtool --phy-statistics {iface}', f'ethtool --phy-statistics {iface}') +    execute_command('netstat --interfaces', 'netstat --interfaces') +    execute_command('netstat --listening', 'netstat --listening') +    execute_command('cat /proc/net/dev', 'cat /proc/net/dev') + + +def show_bridge() -> None: +    """Show bridge interfaces.""" +    execute_command(op('show bridge'), 'Show bridge') + + +def show_arp() -> None: +    """Prints ARP entries.""" +    execute_command(op('show arp'), 'ARP Table (Total entries)') +    execute_command(op('show ipv6 neighbors'), 'show ipv6 neighbors') + + +def show_route() -> None: +    """Prints routing information.""" + +    cmd_list_route = [ +        "show ip route bgp | head -108", +        "show ip route cache", +        "show ip route connected", +        "show ip route forward", +        "show ip route isis | head -108", +        "show ip route kernel", +        "show ip route ospf | head -108", +        "show ip route rip", +        "show ip route static", +        "show ip route summary", +        "show ip route supernets-only", +        "show ip route table all", +        "show ip route vrf all", +        "show ipv6 route bgp | head 108", +        "show ipv6 route cache", +        "show ipv6 route connected", +        "show ipv6 route forward", +        "show ipv6 route isis", +        "show ipv6 route kernel", +        "show ipv6 route ospf", +        "show ipv6 route rip", +        "show ipv6 route static", +        "show ipv6 route summary", +        "show ipv6 route table all", +        "show ipv6 route vrf all", +    ] +    for command in cmd_list_route: +        execute_command(op(command), command) + + +def show_firewall() -> None: +    """Prints firweall information.""" +    execute_command('sudo nft list ruleset', 'nft list ruleset') + + +def show_system() -> None: +    """Prints system parameters.""" +    execute_command(op('show system image version'), 'Show System Image Version') +    execute_command(op('show system image storage'), 'Show System Image Storage') + + +def show_date() -> None: +    """Print the current date.""" +    execute_command('date', 'Current Time') + + +def show_installed_packages() -> None: +    """Prints installed packages.""" +    execute_command('dpkg --list', 'Installed Packages') + + +def show_loaded_modules() -> None: +    """Prints loaded modules /proc/modules""" +    execute_command('cat /proc/modules', 'Loaded Modules') + + +def show_cpu_statistics() -> None: +    """Prints CPU statistics.""" +    execute_command('/usr/bin/true', 'CPU') +    execute_command('lscpu', 'Installed CPU\'s') +    execute_command('top --iterations 1 --batch-mode --accum-time-toggle', 'Cumulative CPU Time Used by Running Processes') +    execute_command('cat /proc/loadavg', 'Load Average') + + +def show_system_interrupts() -> None: +    """Prints system interrupts.""" +    execute_command('cat /proc/interrupts', 'Hardware Interrupt Counters') + + +def show_soft_irqs() -> None: +    """Prints soft IRQ's.""" +    execute_command('cat /proc/softirqs', 'Soft IRQ\'s') + + +def show_softnet_statistics() -> None: +    """Prints softnet statistics.""" +    execute_command('cat /proc/net/softnet_stat', 'cat /proc/net/softnet_stat') + + +def show_running_processes() -> None: +    """Prints current running processes""" +    execute_command('ps -ef', 'Running Processes') + + +def show_memory_usage() -> None: +    """Prints memory usage""" +    execute_command('/usr/bin/true', 'Memory') +    execute_command('cat /proc/meminfo', 'Installed Memory') +    execute_command('free', 'Memory Usage') + + +def list_disks(): +    disks = set() +    with open('/proc/partitions') as partitions_file: +        for line in partitions_file: +            fields = line.strip().split() +            if len(fields) == 4 and fields[3].isalpha() and fields[3] != 'name': +                disks.add(fields[3]) +    return disks + + +def show_storage() -> None: +    """Prints storage information.""" +    execute_command('cat /proc/devices', 'Devices') +    execute_command('cat /proc/partitions', 'Partitions') + +    for disk in list_disks(): +        execute_command(f'fdisk --list /dev/{disk}', f'Partitioning for disk {disk}') + + +def main(): +    # Configuration data +    show_version() +    show_config_file() +    show_running_config() +    show_package_repository_config() +    show_user_startup_scripts() +    show_frr_config() + +    # Interfaces +    show_interfaces() +    show_interface_statistics() +    show_physical_interface_statistics() +    show_bridge() +    show_arp() + +    # Routing +    show_route() + +    # Firewall +    show_firewall() + +    # System +    show_system() +    show_date() +    show_installed_packages() +    show_loaded_modules() + +    # CPU +    show_cpu_statistics() +    show_system_interrupts() +    show_soft_irqs() +    show_softnet_statistics() + +    # Memory +    show_memory_usage() + +    # Storage +    show_storage() + +    # Processes +    show_running_processes() + +    # TODO: Get information from clouds + + +if __name__ == "__main__": +    main() | 
