mirror of
https://github.com/kernelkit/infix.git
synced 2026-08-01 21:33:02 +02:00
bin: relocate src/show.py to bin/show/ -- all tools in one place
- relocate src/show.py to src/bin/show/ - Refactor container() to use run_sysrepo() instead of rolling its own - Replace sysrepocfg with copy which supports nacm - Rename run_sysrepocfg() -> get_json() Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
This commit is contained in:
@@ -141,7 +141,6 @@ BR2_PACKAGE_LOWDOWN=y
|
||||
BR2_PACKAGE_MCD=y
|
||||
BR2_PACKAGE_MDNS_ALIAS=y
|
||||
BR2_PACKAGE_ONIEPROM=y
|
||||
BR2_PACKAGE_SHOW=y
|
||||
BR2_PACKAGE_ROUSETTE=y
|
||||
BR2_PACKAGE_RAUC_INSTALLATION_STATUS=y
|
||||
IMAGE_ITB_AUX=y
|
||||
|
||||
@@ -141,7 +141,6 @@ BR2_PACKAGE_LOWDOWN=y
|
||||
BR2_PACKAGE_MCD=y
|
||||
BR2_PACKAGE_MDNS_ALIAS=y
|
||||
BR2_PACKAGE_ONIEPROM=y
|
||||
BR2_PACKAGE_SHOW=y
|
||||
BR2_PACKAGE_ROUSETTE=y
|
||||
BR2_PACKAGE_RAUC_INSTALLATION_STATUS=y
|
||||
IMAGE_ITB_AUX=y
|
||||
|
||||
@@ -178,7 +178,6 @@ BR2_PACKAGE_PODMAN=y
|
||||
BR2_PACKAGE_PODMAN_DRIVER_BTRFS=y
|
||||
BR2_PACKAGE_PODMAN_DRIVER_DEVICEMAPPER=y
|
||||
BR2_PACKAGE_PODMAN_DRIVER_VFS=y
|
||||
BR2_PACKAGE_SHOW=y
|
||||
BR2_PACKAGE_TETRIS=y
|
||||
BR2_PACKAGE_ROUSETTE=y
|
||||
BR2_PACKAGE_RAUC_INSTALLATION_STATUS=y
|
||||
|
||||
@@ -128,7 +128,6 @@ BR2_PACKAGE_CONFD=y
|
||||
BR2_PACKAGE_CONFD_TEST_MODE=y
|
||||
BR2_PACKAGE_GENCERT=y
|
||||
BR2_PACKAGE_STATD=y
|
||||
BR2_PACKAGE_SHOW=y
|
||||
BR2_PACKAGE_FACTORY=y
|
||||
BR2_PACKAGE_FINIT_PLUGIN_HOTPLUG=y
|
||||
BR2_PACKAGE_FINIT_PLUGIN_HOOK_SCRIPTS=y
|
||||
|
||||
@@ -203,7 +203,6 @@ BR2_PACKAGE_PODMAN=y
|
||||
BR2_PACKAGE_PODMAN_DRIVER_BTRFS=y
|
||||
BR2_PACKAGE_PODMAN_DRIVER_DEVICEMAPPER=y
|
||||
BR2_PACKAGE_PODMAN_DRIVER_VFS=y
|
||||
BR2_PACKAGE_SHOW=y
|
||||
BR2_PACKAGE_TETRIS=y
|
||||
BR2_PACKAGE_ROUSETTE=y
|
||||
BR2_PACKAGE_RAUC_INSTALLATION_STATUS=y
|
||||
|
||||
@@ -174,7 +174,6 @@ BR2_PACKAGE_PODMAN=y
|
||||
BR2_PACKAGE_PODMAN_DRIVER_BTRFS=y
|
||||
BR2_PACKAGE_PODMAN_DRIVER_DEVICEMAPPER=y
|
||||
BR2_PACKAGE_PODMAN_DRIVER_VFS=y
|
||||
BR2_PACKAGE_SHOW=y
|
||||
BR2_PACKAGE_TETRIS=y
|
||||
BR2_PACKAGE_ROUSETTE=y
|
||||
BR2_PACKAGE_RAUC_INSTALLATION_STATUS=y
|
||||
|
||||
@@ -143,7 +143,6 @@ BR2_PACKAGE_LOWDOWN=y
|
||||
BR2_PACKAGE_MCD=y
|
||||
BR2_PACKAGE_MDNS_ALIAS=y
|
||||
BR2_PACKAGE_ONIEPROM=y
|
||||
BR2_PACKAGE_SHOW=y
|
||||
BR2_PACKAGE_ROUSETTE=y
|
||||
BR2_PACKAGE_RAUC_INSTALLATION_STATUS=y
|
||||
IMAGE_ITB_AUX=y
|
||||
|
||||
@@ -34,7 +34,6 @@ source "$BR2_EXTERNAL_INFIX_PATH/package/podman/Config.in"
|
||||
source "$BR2_EXTERNAL_INFIX_PATH/package/python-libyang/Config.in"
|
||||
source "$BR2_EXTERNAL_INFIX_PATH/package/python-yangdoc/Config.in"
|
||||
source "$BR2_EXTERNAL_INFIX_PATH/package/skeleton-init-finit/Config.in"
|
||||
source "$BR2_EXTERNAL_INFIX_PATH/package/show/Config.in"
|
||||
source "$BR2_EXTERNAL_INFIX_PATH/package/tetris/Config.in"
|
||||
source "$BR2_EXTERNAL_INFIX_PATH/package/libyang-cpp/Config.in"
|
||||
source "$BR2_EXTERNAL_INFIX_PATH/package/sysrepo-cpp/Config.in"
|
||||
|
||||
+27
-2
@@ -10,7 +10,9 @@ BIN_SITE = $(BR2_EXTERNAL_INFIX_PATH)/src/bin
|
||||
BIN_LICENSE = BSD-3-Clause
|
||||
BIN_LICENSE_FILES = LICENSE
|
||||
BIN_REDISTRIBUTE = NO
|
||||
BIN_DEPENDENCIES = sysrepo libite
|
||||
BIN_DEPENDENCIES = sysrepo libite \
|
||||
host-python3 python3 host-python-pypa-build host-python-installer \
|
||||
host-python-poetry-core
|
||||
BIN_CONF_OPTS = --disable-silent-rules
|
||||
BIN_AUTORECONF = YES
|
||||
|
||||
@@ -19,7 +21,30 @@ CFLAGS="$(INFIX_CFLAGS)"
|
||||
endef
|
||||
|
||||
define BIN_PERMISSIONS
|
||||
/usr/bin/copy d 04750 root sysrepo - - - - -
|
||||
/usr/bin/copy d 04750 root klish - - - - -
|
||||
endef
|
||||
|
||||
define BIN_BUILD_PYTHON
|
||||
cd $(BIN_SITE) && \
|
||||
$(PKG_PYTHON_PEP517_ENV) $(HOST_DIR)/bin/python3 $(PKG_PYTHON_PEP517_BUILD_CMD) -o $(@D)/dist
|
||||
mkdir -p $(TARGET_DIR)/usr/bin
|
||||
rm -f $(TARGET_DIR)/usr/bin/show
|
||||
cd $(@D) && \
|
||||
$(HOST_DIR)/bin/python3 $(TOPDIR)/support/scripts/pyinstaller.py \
|
||||
dist/*.whl \
|
||||
--interpreter=/usr/bin/python3 \
|
||||
--script-kind=posix \
|
||||
--purelib=$(TARGET_DIR)/usr/lib/python$(PYTHON3_VERSION_MAJOR)/site-packages \
|
||||
--headers=$(TARGET_DIR)/usr/include/python$(PYTHON3_VERSION_MAJOR) \
|
||||
--scripts=$(TARGET_DIR)/usr/bin \
|
||||
--data=$(TARGET_DIR)
|
||||
endef
|
||||
BIN_POST_INSTALL_TARGET_HOOKS += BIN_BUILD_PYTHON
|
||||
|
||||
define BIN_INSTALL_BASH_COMPLETION
|
||||
install -D $(@D)/bash_completion.d/show \
|
||||
$(TARGET_DIR)/etc/bash_completion.d/show
|
||||
endef
|
||||
BIN_POST_INSTALL_TARGET_HOOKS += BIN_INSTALL_BASH_COMPLETION
|
||||
|
||||
$(eval $(autotools-package))
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
config BR2_PACKAGE_SHOW
|
||||
bool "show"
|
||||
help
|
||||
Tool to retrieve and present operational data from sysrepo.
|
||||
|
||||
https://github.com/kernelkit/infix
|
||||
@@ -1,19 +0,0 @@
|
||||
################################################################################
|
||||
#
|
||||
# show
|
||||
#
|
||||
################################################################################
|
||||
|
||||
SHOW_VERSION = 1.0
|
||||
SHOW_LICENSE = MIT
|
||||
SHOW_LICENSE_FILES = LICENSE
|
||||
SHOW_SITE_METHOD = local
|
||||
SHOW_SITE = $(BR2_EXTERNAL_INFIX_PATH)/src/show
|
||||
SHOW_REDISTRIBUTE = NO
|
||||
|
||||
define SHOW_INSTALL_TARGET_CMDS
|
||||
$(TARGET_MAKE_ENV) $(TARGET_CONFIGURE_OPTS) $(MAKE) -C $(@D) \
|
||||
DESTDIR="$(TARGET_DIR)" install
|
||||
endef
|
||||
|
||||
$(eval $(generic-package))
|
||||
@@ -0,0 +1,18 @@
|
||||
[tool.poetry]
|
||||
name = "infix-show"
|
||||
version = "1.0"
|
||||
description = "Infix show commands"
|
||||
license = "MIT"
|
||||
packages = [
|
||||
{ include = "show" }
|
||||
]
|
||||
authors = [
|
||||
"KernelKit developers"
|
||||
]
|
||||
|
||||
[build-system]
|
||||
requires = ["poetry-core>=1.0.0"]
|
||||
build-backend = "poetry.core.masonry.api"
|
||||
|
||||
[tool.poetry.scripts]
|
||||
show = "show:main"
|
||||
@@ -10,26 +10,25 @@ import argparse
|
||||
|
||||
RAW_OUTPUT = False
|
||||
|
||||
def run_sysrepocfg(xpath: str, datastore: str = "operational") -> dict:
|
||||
|
||||
def get_json(xpath: str, datastore: str = "operational") -> 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", datastore, "-x", safe_xpath
|
||||
], capture_output=True, text=True, check=True)
|
||||
result = subprocess.run(["copy", datastore, "-x", shlex.quote(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}")
|
||||
print(f"Error running copy: {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.")
|
||||
@@ -46,8 +45,9 @@ def cli_pretty(json_data: dict, command: str, *args: str):
|
||||
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")
|
||||
data = get_json("/infix-dhcp-server:dhcp-server")
|
||||
if not data:
|
||||
print("No interface data retrieved.")
|
||||
return
|
||||
@@ -57,8 +57,9 @@ def dhcp(args: List[str]) -> None:
|
||||
return
|
||||
cli_pretty(data, "show-dhcp-server")
|
||||
|
||||
|
||||
def hardware(args: List[str]) -> None:
|
||||
data = run_sysrepocfg("/ietf-hardware:hardware")
|
||||
data = get_json("/ietf-hardware:hardware")
|
||||
if not data:
|
||||
print("No hardware data retrieved.")
|
||||
return
|
||||
@@ -68,6 +69,7 @@ def hardware(args: List[str]) -> None:
|
||||
return
|
||||
cli_pretty(data, "show-hardware")
|
||||
|
||||
|
||||
def ntp(args: List[str]) -> None:
|
||||
# Create argument parser for ntp subcommands
|
||||
parser = argparse.ArgumentParser(prog='show ntp', add_help=False)
|
||||
@@ -97,8 +99,8 @@ def ntp(args: List[str]) -> None:
|
||||
|
||||
# Default: show ntp (no subcommand or address)
|
||||
# Fetch both client and server operational data
|
||||
client_data = run_sysrepocfg("/system-state/ntp")
|
||||
server_data = run_sysrepocfg("/ietf-ntp:ntp")
|
||||
client_data = get_json("/system-state/ntp")
|
||||
server_data = get_json("/ietf-ntp:ntp")
|
||||
|
||||
# Merge into single data structure
|
||||
data = {}
|
||||
@@ -121,8 +123,9 @@ def ntp(args: List[str]) -> None:
|
||||
# Default show ntp - summary view (no address support at top level)
|
||||
cli_pretty(data, "show-ntp")
|
||||
|
||||
|
||||
def ntp_tracking(args: List[str]) -> None:
|
||||
data = run_sysrepocfg("/ietf-ntp:ntp")
|
||||
data = get_json("/ietf-ntp:ntp")
|
||||
if not data:
|
||||
print("No ntp server data retrieved.")
|
||||
return
|
||||
@@ -132,8 +135,9 @@ def ntp_tracking(args: List[str]) -> None:
|
||||
return
|
||||
cli_pretty(data, "show-ntp-tracking")
|
||||
|
||||
|
||||
def ntp_source(args: List[str]) -> None:
|
||||
data = run_sysrepocfg("/ietf-ntp:ntp")
|
||||
data = get_json("/ietf-ntp:ntp")
|
||||
if not data:
|
||||
print("No ntp server data retrieved.")
|
||||
return
|
||||
@@ -148,6 +152,7 @@ def ntp_source(args: List[str]) -> None:
|
||||
else:
|
||||
cli_pretty(data, "show-ntp-source")
|
||||
|
||||
|
||||
def is_valid_interface_name(interface_name: str) -> bool:
|
||||
"""
|
||||
Validates a Linux network interface name.
|
||||
@@ -158,14 +163,15 @@ def is_valid_interface_name(interface_name: str) -> bool:
|
||||
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")
|
||||
data = get_json("/ietf-interfaces:interfaces")
|
||||
if not data:
|
||||
print("No interface data retrieved.")
|
||||
return
|
||||
|
||||
# Also fetch routing interface list for forwarding indication
|
||||
routing_data = run_sysrepocfg("/ietf-routing:routing")
|
||||
routing_data = get_json("/ietf-routing:routing")
|
||||
if routing_data:
|
||||
# Merge routing data into the main data structure
|
||||
data.update(routing_data)
|
||||
@@ -185,8 +191,9 @@ def interface(args: List[str]) -> None:
|
||||
else:
|
||||
print("Too many arguments provided. Only one interface name is expected.")
|
||||
|
||||
|
||||
def stp(args: List[str]) -> None:
|
||||
data = run_sysrepocfg("/ietf-interfaces:interfaces")
|
||||
data = get_json("/ietf-interfaces:interfaces")
|
||||
if not data:
|
||||
print("No interface data retrieved.")
|
||||
return
|
||||
@@ -196,8 +203,9 @@ def stp(args: List[str]) -> None:
|
||||
return
|
||||
cli_pretty(data, "show-bridge-stp")
|
||||
|
||||
|
||||
def software(args: List[str]) -> None:
|
||||
data = run_sysrepocfg("/ietf-system:system-state/infix-system:software")
|
||||
data = get_json("/ietf-system:system-state/infix-system:software")
|
||||
if not data:
|
||||
print("No software data retrieved.")
|
||||
return
|
||||
@@ -217,8 +225,9 @@ def software(args: List[str]) -> None:
|
||||
else:
|
||||
print("Too many arguments provided. Only one name is expected.")
|
||||
|
||||
|
||||
def boot_order(args: List[str]) -> None:
|
||||
data = run_sysrepocfg("/ietf-system:system-state/infix-system:software")
|
||||
data = get_json("/ietf-system:system-state/infix-system:software")
|
||||
if not data:
|
||||
print("No software data retrieved.")
|
||||
return
|
||||
@@ -230,8 +239,9 @@ def boot_order(args: List[str]) -> None:
|
||||
except (KeyError, TypeError):
|
||||
print("No boot order data available.")
|
||||
|
||||
|
||||
def services(args: List[str]) -> None:
|
||||
data = run_sysrepocfg("/ietf-system:system-state/infix-system:services")
|
||||
data = get_json("/ietf-system:system-state/infix-system:services")
|
||||
if not data:
|
||||
print("No service data retrieved.")
|
||||
return
|
||||
@@ -240,7 +250,8 @@ def services(args: List[str]) -> None:
|
||||
print(json.dumps(data, indent=2))
|
||||
return
|
||||
|
||||
cli_pretty(data, f"show-services")
|
||||
cli_pretty(data, "show-services")
|
||||
|
||||
|
||||
def container(args: List[str]) -> None:
|
||||
"""Handle show container [name]
|
||||
@@ -249,44 +260,39 @@ def container(args: List[str]) -> None:
|
||||
(none) - Show all containers in table format
|
||||
name - Show detailed view of specific container
|
||||
"""
|
||||
data = run_sysrepocfg("/infix-containers:containers")
|
||||
data = get_json("/infix-containers:containers")
|
||||
if not data:
|
||||
print("No container data retrieved.")
|
||||
return
|
||||
|
||||
# Fetch interface data for bridge resolution (both table and detailed views)
|
||||
# Fetch interface data for bridge resolution (table and detailed views)
|
||||
# Fetch operational interface data
|
||||
iface_oper = run_sysrepocfg("/ietf-interfaces:interfaces")
|
||||
iface_oper = get_json("/ietf-interfaces:interfaces")
|
||||
|
||||
# Also fetch config data for veth peer information (not in operational)
|
||||
try:
|
||||
result = subprocess.run([
|
||||
"sysrepocfg", "-f", "json", "-X", "-d", "running", "-x", "/ietf-interfaces:interfaces"
|
||||
], capture_output=True, text=True, check=True)
|
||||
iface_config = json.loads(result.stdout)
|
||||
iface_config = get_json("/ietf-interfaces:interfaces", "running")
|
||||
|
||||
# Merge config veth peer info into operational data
|
||||
if iface_oper and iface_config:
|
||||
oper_ifaces = iface_oper.get('ietf-interfaces:interfaces', {}).get('interface', [])
|
||||
config_ifaces = iface_config.get('ietf-interfaces:interfaces', {}).get('interface', [])
|
||||
# Merge config veth peer info into operational data
|
||||
if iface_oper and iface_config:
|
||||
oper_ifaces = iface_oper.get('ietf-interfaces:interfaces', {}).get('interface', [])
|
||||
config_ifaces = iface_config.get('ietf-interfaces:interfaces', {}).get('interface', [])
|
||||
|
||||
# Create a map of config interfaces
|
||||
config_map = {iface['name']: iface for iface in config_ifaces}
|
||||
# Create a map of config interfaces
|
||||
config_map = {iface['name']: iface for iface in config_ifaces}
|
||||
|
||||
# Merge veth peer info from config into operational
|
||||
for oper_iface in oper_ifaces:
|
||||
name = oper_iface.get('name')
|
||||
if name in config_map:
|
||||
config_iface = config_map[name]
|
||||
# Add veth peer if it exists in config but not in operational
|
||||
if 'infix-interfaces:veth' in config_iface and 'infix-interfaces:veth' not in oper_iface:
|
||||
oper_iface['infix-interfaces:veth'] = config_iface['infix-interfaces:veth']
|
||||
# Merge veth peer info from config into operational
|
||||
for oper_iface in oper_ifaces:
|
||||
name = oper_iface.get('name')
|
||||
if name in config_map:
|
||||
config_iface = config_map[name]
|
||||
# Add veth peer if it exists in config but not in operational
|
||||
if 'infix-interfaces:veth' in config_iface and 'infix-interfaces:veth' not in oper_iface:
|
||||
oper_iface['infix-interfaces:veth'] = config_iface['infix-interfaces:veth']
|
||||
|
||||
data.update(iface_oper)
|
||||
except (subprocess.CalledProcessError, json.JSONDecodeError):
|
||||
data.update(iface_oper)
|
||||
elif iface_oper:
|
||||
# If config fetch fails, just use operational data
|
||||
if iface_oper:
|
||||
data.update(iface_oper)
|
||||
data.update(iface_oper)
|
||||
|
||||
if RAW_OUTPUT:
|
||||
print(json.dumps(data, indent=2))
|
||||
@@ -300,6 +306,7 @@ def container(args: List[str]) -> None:
|
||||
else:
|
||||
print("Too many arguments provided. Expected: show container [name]")
|
||||
|
||||
|
||||
def bfd(args: List[str]) -> None:
|
||||
"""Handle show bfd [subcommand] [peer] [brief]
|
||||
|
||||
@@ -309,8 +316,7 @@ def bfd(args: List[str]) -> None:
|
||||
peers brief - Show BFD peers in brief format
|
||||
peer <addr> - Show specific BFD peer details
|
||||
"""
|
||||
# Fetch operational data from sysrepocfg
|
||||
data = run_sysrepocfg("/ietf-routing:routing/control-plane-protocols/control-plane-protocol")
|
||||
data = get_json("/ietf-routing:routing/control-plane-protocols/control-plane-protocol")
|
||||
if not data:
|
||||
print("No BFD data retrieved.")
|
||||
return
|
||||
@@ -344,7 +350,7 @@ def bfd(args: List[str]) -> None:
|
||||
|
||||
# For brief view, fetch interface data to show interface:ip format
|
||||
if brief_flag:
|
||||
ifaces_data = run_sysrepocfg("/ietf-interfaces:interfaces")
|
||||
ifaces_data = get_json("/ietf-interfaces:interfaces")
|
||||
if ifaces_data:
|
||||
data['_interfaces'] = ifaces_data
|
||||
|
||||
@@ -361,6 +367,7 @@ def bfd(args: List[str]) -> None:
|
||||
else:
|
||||
print(f"Unknown BFD subcommand: {subcommand}")
|
||||
|
||||
|
||||
def ospf(args: List[str]) -> None:
|
||||
"""Handle show ospf [subcommand] [ifname] [detail]
|
||||
|
||||
@@ -374,8 +381,7 @@ def ospf(args: List[str]) -> None:
|
||||
ifname - Interface name (for interfaces subcommand)
|
||||
detail - Show detailed information (Cisco-style)
|
||||
"""
|
||||
# Fetch operational data from sysrepocfg
|
||||
data = run_sysrepocfg("/ietf-routing:routing/control-plane-protocols/control-plane-protocol")
|
||||
data = get_json("/ietf-routing:routing/control-plane-protocols/control-plane-protocol")
|
||||
if not data:
|
||||
print("No OSPF data retrieved.")
|
||||
return
|
||||
@@ -407,12 +413,12 @@ def ospf(args: List[str]) -> None:
|
||||
data['_ifname'] = ifname
|
||||
# For detailed interface view, fetch additional data (interfaces and BFD)
|
||||
if subcommand == "interface" or subcommand == "interfaces":
|
||||
ifaces_data = run_sysrepocfg("/ietf-interfaces:interfaces")
|
||||
ifaces_data = get_json("/ietf-interfaces:interfaces")
|
||||
if ifaces_data:
|
||||
data['_interfaces'] = ifaces_data
|
||||
|
||||
# Fetch BFD data for per-interface status
|
||||
routing_data = run_sysrepocfg("/ietf-routing:routing/control-plane-protocols/control-plane-protocol")
|
||||
routing_data = get_json("/ietf-routing:routing/control-plane-protocols/control-plane-protocol")
|
||||
if routing_data:
|
||||
data['_routing'] = routing_data
|
||||
|
||||
@@ -428,6 +434,7 @@ def ospf(args: List[str]) -> None:
|
||||
else:
|
||||
print(f"Unknown OSPF subcommand: {subcommand}")
|
||||
|
||||
|
||||
def rip(args: List[str]) -> None:
|
||||
"""Handle show rip [subcommand] [ifname]
|
||||
|
||||
@@ -440,8 +447,7 @@ def rip(args: List[str]) -> None:
|
||||
Optional:
|
||||
ifname - Interface name (for interface subcommand)
|
||||
"""
|
||||
# Fetch operational data from sysrepocfg
|
||||
data = run_sysrepocfg("/ietf-routing:routing/control-plane-protocols/control-plane-protocol")
|
||||
data = get_json("/ietf-routing:routing/control-plane-protocols/control-plane-protocol")
|
||||
if not data:
|
||||
data = {}
|
||||
|
||||
@@ -469,10 +475,11 @@ def rip(args: List[str]) -> None:
|
||||
else:
|
||||
print(f"Unknown RIP subcommand: {subcommand}")
|
||||
|
||||
|
||||
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")
|
||||
data = get_json("/ietf-routing:routing/ribs")
|
||||
if not data:
|
||||
print("No route data retrieved.")
|
||||
return
|
||||
@@ -481,8 +488,9 @@ def routes(args: List[str]):
|
||||
return
|
||||
cli_pretty(data, "show-routing-table", "-i", ip_version)
|
||||
|
||||
|
||||
def lldp(args: List[str]):
|
||||
data = run_sysrepocfg("/ieee802-dot1ab-lldp:lldp")
|
||||
data = get_json("/ieee802-dot1ab-lldp:lldp")
|
||||
if not data:
|
||||
print("No lldp data retrieved.")
|
||||
return
|
||||
@@ -494,13 +502,13 @@ def lldp(args: List[str]):
|
||||
|
||||
def system(args: List[str]) -> None:
|
||||
# Get system state from sysrepo
|
||||
data = run_sysrepocfg("/ietf-system:system-state")
|
||||
data = get_json("/ietf-system:system-state")
|
||||
if not data:
|
||||
print("No system data retrieved.")
|
||||
return
|
||||
|
||||
# Get hardware data (including thermal sensors)
|
||||
hardware_data = run_sysrepocfg("/ietf-hardware:hardware")
|
||||
hardware_data = get_json("/ietf-hardware:hardware")
|
||||
|
||||
# Augment with runtime data
|
||||
runtime = {}
|
||||
@@ -596,8 +604,9 @@ def system(args: List[str]) -> None:
|
||||
|
||||
cli_pretty(data, "show-system")
|
||||
|
||||
|
||||
def nacm(args: List[str]) -> None:
|
||||
data = run_sysrepocfg("/ietf-netconf-acm:nacm", "running")
|
||||
data = get_json("/ietf-netconf-acm:nacm", "running")
|
||||
if not data:
|
||||
print("No NACM data retrieved.")
|
||||
return
|
||||
@@ -614,6 +623,7 @@ def nacm(args: List[str]) -> None:
|
||||
return
|
||||
cli_pretty(data, "show-nacm")
|
||||
|
||||
|
||||
def execute_command(command: str, args: List[str]):
|
||||
command_mapping = {
|
||||
'bfd': bfd,
|
||||
@@ -15,7 +15,7 @@ static int startup_save(sr_session_ctx_t *session, uint32_t sub_id, const char *
|
||||
if (systemf("runlevel >/dev/null 2>&1"))
|
||||
return SR_ERR_OK;
|
||||
|
||||
if (systemf("sysrepocfg -X/cfg/startup-config.cfg -d startup -f json"))
|
||||
if (systemf("copy startup /cfg/startup-config.cfg"))
|
||||
return SR_ERR_SYS;
|
||||
|
||||
return SR_ERR_OK;
|
||||
|
||||
@@ -650,12 +650,12 @@
|
||||
<PARAM name="limit" ptype="/UINT" help="Last N lines, default: all"/>
|
||||
</SWITCH>
|
||||
<ACTION sym="script" in="tty" out="tty" interrupt="true">
|
||||
sysrepocfg -X -d operational -x /infix-firewall:firewall -f json -t 60 | /usr/libexec/statd/cli-pretty show-firewall-log $KLISH_PARAM_limit |pager +G
|
||||
copy operational -x /infix-firewall:firewall | /usr/libexec/statd/cli-pretty show-firewall-log $KLISH_PARAM_limit |pager +G
|
||||
</ACTION>
|
||||
</COMMAND>
|
||||
<COMMAND name="matrix" help="Show firewall zone matrix">
|
||||
<ACTION sym="script" in="tty" out="tty" interrupt="true">
|
||||
sysrepocfg -X -d operational -x /infix-firewall:firewall -f json -t 60 | /usr/libexec/statd/cli-pretty show-firewall-matrix
|
||||
copy operational -x /infix-firewall:firewall | /usr/libexec/statd/cli-pretty show-firewall-matrix
|
||||
</ACTION>
|
||||
</COMMAND>
|
||||
<COMMAND name="zone" help="Show firewall zones">
|
||||
@@ -663,7 +663,7 @@
|
||||
<PARAM name="name" ptype="/FIREWALL_ZONES" help="Zone name"/>
|
||||
</SWITCH>
|
||||
<ACTION sym="script" in="tty" out="tty" interrupt="true">
|
||||
sysrepocfg -X -d operational -x /infix-firewall:firewall -f json -t 60 | /usr/libexec/statd/cli-pretty show-firewall-zone "$KLISH_PARAM_name" |pager
|
||||
copy operational -x /infix-firewall:firewall | /usr/libexec/statd/cli-pretty show-firewall-zone "$KLISH_PARAM_name" |pager
|
||||
</ACTION>
|
||||
</COMMAND>
|
||||
<COMMAND name="policy" help="Show firewall policies">
|
||||
@@ -671,7 +671,7 @@
|
||||
<PARAM name="name" ptype="/FIREWALL_POLICIES" help="Policy name"/>
|
||||
</SWITCH>
|
||||
<ACTION sym="script" in="tty" out="tty" interrupt="true">
|
||||
sysrepocfg -X -d operational -x /infix-firewall:firewall -f json -t 60 | /usr/libexec/statd/cli-pretty show-firewall-policy "$KLISH_PARAM_name" |pager
|
||||
copy operational -x /infix-firewall:firewall | /usr/libexec/statd/cli-pretty show-firewall-policy "$KLISH_PARAM_name" |pager
|
||||
</ACTION>
|
||||
</COMMAND>
|
||||
<COMMAND name="service" help="Show firewall services">
|
||||
@@ -679,12 +679,12 @@
|
||||
<PARAM name="name" ptype="/FIREWALL_SERVICES" help="Service name"/>
|
||||
</SWITCH>
|
||||
<ACTION sym="script" in="tty" out="tty" interrupt="true">
|
||||
sysrepocfg -X -d operational -x /infix-firewall:firewall -f json -t 60 | /usr/libexec/statd/cli-pretty show-firewall-service "$KLISH_PARAM_name" |pager
|
||||
copy operational -x /infix-firewall:firewall | /usr/libexec/statd/cli-pretty show-firewall-service "$KLISH_PARAM_name" |pager
|
||||
</ACTION>
|
||||
</COMMAND>
|
||||
</SWITCH>
|
||||
<ACTION sym="script" in="tty" out="tty" interrupt="true">
|
||||
sysrepocfg -X -d operational -x /infix-firewall:firewall -f json -t 60 | /usr/libexec/statd/cli-pretty show-firewall |pager
|
||||
copy operational -x /infix-firewall:firewall | /usr/libexec/statd/cli-pretty show-firewall |pager
|
||||
</ACTION>
|
||||
</COMMAND>
|
||||
</COMMAND>
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2025 Richard Alpe
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -1,11 +0,0 @@
|
||||
.PHONY: all clean distclean install
|
||||
|
||||
all:
|
||||
|
||||
clean:
|
||||
|
||||
distclean: clean
|
||||
|
||||
install:
|
||||
install -D show.py $(DESTDIR)/bin/show
|
||||
install -D bash_completion.d/show $(DESTDIR)/etc/bash_completion.d/show
|
||||
Reference in New Issue
Block a user