Files
infix/src/show/show.py
T

191 lines
5.4 KiB
Python
Executable File

#!/usr/bin/env python3
import re
import subprocess
import json
from typing import List
import os
import shlex
import argparse
RAW_OUTPUT = False
def run_sysrepocfg(xpath: str) -> dict:
if not isinstance(xpath, str) or not xpath.startswith("/"):
print("Invalid XPATH. It must be a valid string starting with '/'.")
return {}
safe_xpath = shlex.quote(xpath)
try:
result = subprocess.run([
"sysrepocfg", "-f", "json", "-X", "-d", "operational", "-x", safe_xpath
], capture_output=True, text=True, check=True)
json_data = json.loads(result.stdout)
return json_data
except subprocess.CalledProcessError as e:
print(f"Error running sysrepocfg: {e}")
return {}
except json.JSONDecodeError as e:
print(f"Error parsing JSON output: {e}")
return {}
def cli_pretty(json_data: dict, command: str, *args: str):
if not command or not all(isinstance(arg, str) for arg in args):
print("Invalid command or arguments. All arguments must be strings.")
return
safe_args = [shlex.quote(arg) for arg in args]
try:
json_input = json.dumps(json_data) # Keep as string, not bytes
result = subprocess.run([
"/usr/libexec/statd/cli-pretty", command, *safe_args
], input=json_input, capture_output=True, text=True, check=True)
print(result.stdout, end="")
except subprocess.CalledProcessError as e:
print(f"Error running cli-pretty: {e}")
def dhcp(args: List[str]) -> None:
data = run_sysrepocfg("/infix-dhcp-server:dhcp-server")
if not data:
print("No interface data retrieved.")
return
if RAW_OUTPUT:
print(json.dumps(data, indent=2))
return
cli_pretty(data, "show-dhcp-server")
def hardware(args: List[str]) -> None:
data = run_sysrepocfg("/ietf-hardware:hardware")
if not data:
print("No hardware data retrieved.")
return
if RAW_OUTPUT:
print(json.dumps(data, indent=2))
return
cli_pretty(data, "show-hardware")
def ntp(args: List[str]) -> None:
data = run_sysrepocfg("/system-state/ntp")
if not data:
print("No ntp data retrieved.")
return
if RAW_OUTPUT:
print(json.dumps(data, indent=2))
return
cli_pretty(data, "show-ntp")
def is_valid_interface_name(interface_name: str) -> bool:
"""
Validates a Linux network interface name.
"""
if len(interface_name) > 15:
return False
pattern = r'^[a-zA-Z0-9._-]+$'
return bool(re.match(pattern, interface_name))
def interface(args: List[str]) -> None:
data = run_sysrepocfg("/ietf-interfaces:interfaces")
if not data:
print("No interface data retrieved.")
return
if RAW_OUTPUT:
print(json.dumps(data, indent=2))
return
if len(args) == 0 or not args[0]: # Treat "" as no arg.
cli_pretty(data, "show-interfaces")
elif len(args) == 1:
iface = args[0]
if is_valid_interface_name(iface):
cli_pretty(data, f"show-interfaces", "-n", iface)
else:
print(f"Invalid interface name: {iface}")
else:
print("Too many arguments provided. Only one interface name is expected.")
def stp(args: List[str]) -> None:
data = run_sysrepocfg("/ietf-interfaces:interfaces")
if not data:
print("No interface data retrieved.")
return
if RAW_OUTPUT:
print(json.dumps(data, indent=2))
return
cli_pretty(data, "show-bridge-stp")
def software(args: List[str]) -> None:
data = run_sysrepocfg("/ietf-system:system-state/infix-system:software")
if not data:
print("No software data retrieved.")
return
if RAW_OUTPUT:
print(json.dumps(data, indent=2))
return
if len(args) == 0 or not args[0]: # Treat "" as no arg.
cli_pretty(data, "show-software")
elif len(args) == 1:
name = args[0]
if name not in ("primary", "secondary"):
print(f"Invalid software name: {name}")
return
cli_pretty(data, f"show-software", "-n", name)
else:
print("Too many arguments provided. Only one name is expected.")
def routes(args: List[str]):
ip_version = args[0] if args and args[0] in ["ipv4", "ipv6"] else "ipv4"
data = run_sysrepocfg("/ietf-routing:routing/ribs")
if not data:
print("No route data retrieved.")
return
if RAW_OUTPUT:
print(json.dumps(data, indent=2))
return
cli_pretty(data, "show-routing-table", "-i", ip_version)
def execute_command(command: str, args: List[str]):
command_mapping = {
'dhcp': dhcp,
'hardware': hardware,
'interface': interface,
'ntp': ntp,
'routes': routes,
'software' : software,
'stp': stp,
}
if command in command_mapping:
command_mapping[command](args)
else:
print(f"Unknown command: {command}")
def main():
global RAW_OUTPUT
parser = argparse.ArgumentParser(description="Show operational data")
parser.add_argument('command', help="Command to execute")
parser.add_argument('args', nargs=argparse.REMAINDER, help="Additional arguments for the command")
parser.add_argument('-r', '--raw', action='store_true', help="Print raw JSON output from Sysrepo")
args = parser.parse_args()
RAW_OUTPUT = args.raw
execute_command(args.command, args.args)
if __name__ == "__main__":
main()