mirror of
https://github.com/kernelkit/infix.git
synced 2026-07-22 09:13:01 +02:00
Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0ae395cff8 | ||
|
|
ab8b174eff |
+1
-1
Submodule buildroot updated: 33d2ca716f...74fc86b099
@@ -30,7 +30,7 @@ MODULES=(
|
||||
"infix-dhcp-client@2025-01-29.yang"
|
||||
"infix-dhcp-server@2025-01-29.yang"
|
||||
"infix-meta@2024-10-18.yang"
|
||||
"infix-system@2025-01-25.yang"
|
||||
"infix-system@2025-04-29.yang"
|
||||
"infix-services@2024-12-03.yang"
|
||||
"ieee802-ethernet-interface@2019-06-21.yang"
|
||||
"infix-ethernet-interface@2024-02-27.yang"
|
||||
|
||||
@@ -28,6 +28,11 @@ module infix-system {
|
||||
contact "kernelkit@googlegroups.com";
|
||||
description "Infix augments and deviations to ietf-system.";
|
||||
|
||||
revision 2025-04-29 {
|
||||
description "Add services status.";
|
||||
reference "internal";
|
||||
}
|
||||
|
||||
revision 2025-01-25 {
|
||||
description "Add DNS resolver status.";
|
||||
reference "internal";
|
||||
@@ -412,6 +417,99 @@ module infix-system {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
container services {
|
||||
description "List of monitored system services (processes)";
|
||||
config false;
|
||||
|
||||
list service {
|
||||
key "pid";
|
||||
description "Tracked system service processes.";
|
||||
|
||||
leaf pid {
|
||||
type uint32;
|
||||
description "Process ID (PID) of the service.";
|
||||
}
|
||||
|
||||
leaf name {
|
||||
type string;
|
||||
description "Name of the service or process.";
|
||||
}
|
||||
|
||||
leaf description {
|
||||
type string;
|
||||
description
|
||||
"Short description of the service.";
|
||||
}
|
||||
|
||||
leaf status {
|
||||
type enumeration {
|
||||
enum halted {
|
||||
description "Service is halted.";
|
||||
}
|
||||
enum missing {
|
||||
description "Service files or dependencies are missing.";
|
||||
}
|
||||
enum crashed {
|
||||
description "Service has crashed.";
|
||||
}
|
||||
enum stopped {
|
||||
description "Service has been manually stopped.";
|
||||
}
|
||||
enum busy {
|
||||
description "Service is busy.";
|
||||
}
|
||||
enum restart {
|
||||
description "Service is restarting.";
|
||||
}
|
||||
enum conflict {
|
||||
description "Service has a conflict preventing start.";
|
||||
}
|
||||
enum unknown {
|
||||
description "Service is in an unknown state.";
|
||||
}
|
||||
enum done {
|
||||
description "Service task has completed.";
|
||||
}
|
||||
enum failed {
|
||||
description "Service task has failed.";
|
||||
}
|
||||
enum active {
|
||||
description "Run/task type service is active.";
|
||||
}
|
||||
enum stopping {
|
||||
description "Service is in the process of stopping.";
|
||||
}
|
||||
enum teardown {
|
||||
description "Service is performing teardown operations.";
|
||||
}
|
||||
enum setup {
|
||||
description "Service is setting up.";
|
||||
}
|
||||
enum cleanup {
|
||||
description "Service is cleaning up.";
|
||||
}
|
||||
enum paused {
|
||||
description "Service is paused.";
|
||||
}
|
||||
enum waiting {
|
||||
description "Service is waiting for conditions.";
|
||||
}
|
||||
enum starting {
|
||||
description "Service is starting.";
|
||||
}
|
||||
enum running {
|
||||
description "Service is running.";
|
||||
}
|
||||
enum dead {
|
||||
description "Service process is dead.";
|
||||
}
|
||||
}
|
||||
description
|
||||
"Detailed current status of the process.";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
deviation "/sys:system/sys:hostname" {
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
class JsonData:
|
||||
@staticmethod
|
||||
def get(default, indata, *args):
|
||||
data = indata
|
||||
for arg in args:
|
||||
if arg in data:
|
||||
data = data.get(arg)
|
||||
else:
|
||||
return default
|
||||
|
||||
return data
|
||||
|
||||
|
||||
class Decore():
|
||||
@staticmethod
|
||||
def decorate(sgr, txt, restore="0"):
|
||||
return f"\033[{sgr}m{txt}\033[{restore}m"
|
||||
|
||||
@staticmethod
|
||||
def invert(txt):
|
||||
return Decore.decorate("7", txt)
|
||||
|
||||
@staticmethod
|
||||
def bold(txt):
|
||||
return Decore.decorate("1", txt)
|
||||
|
||||
@staticmethod
|
||||
def red(txt):
|
||||
return Decore.decorate("31", txt, "39")
|
||||
|
||||
@staticmethod
|
||||
def green(txt):
|
||||
return Decore.decorate("32", txt, "39")
|
||||
|
||||
@staticmethod
|
||||
def yellow(txt):
|
||||
return Decore.decorate("33", txt, "39")
|
||||
|
||||
@staticmethod
|
||||
def underline(txt):
|
||||
return Decore.decorate("4", txt, "24")
|
||||
|
||||
@staticmethod
|
||||
def gray_bg(txt):
|
||||
return Decore.decorate("100", txt)
|
||||
@@ -0,0 +1,111 @@
|
||||
import json
|
||||
|
||||
from common import Decore
|
||||
from common import JsonData
|
||||
from dataclasses import dataclass
|
||||
|
||||
class System:
|
||||
def __init__(self, cfg):
|
||||
self.services = self.Services(cfg)
|
||||
self.software = self.Software(cfg)
|
||||
|
||||
class Services:
|
||||
def __init__(self, cfg):
|
||||
self.cfg = cfg
|
||||
|
||||
def get(self):
|
||||
return self.cfg.run("/ietf-system:system-state/infix-system:services")
|
||||
|
||||
def pretty(self):
|
||||
data = self.get()
|
||||
return data if data else {}
|
||||
|
||||
class Software:
|
||||
class Slot:
|
||||
@dataclass
|
||||
class Pad:
|
||||
name: int = 10
|
||||
state: int = 10
|
||||
version: int = 23
|
||||
date: int = 25
|
||||
hash: int = 64
|
||||
|
||||
def __init__(self, data, version, date): # TODO: why is slot version and date on top level?
|
||||
self.pad = self.Pad()
|
||||
self.name = data.get('bootname', '')
|
||||
self.size = data.get('size', '')
|
||||
self.type = data.get('class', '')
|
||||
self.hash = data.get('sha256', '')
|
||||
self.state = data.get('state', '')
|
||||
self.version = version # TODO
|
||||
self.date = version # TODO
|
||||
|
||||
def print_detailed(self):
|
||||
"""Detailed information about one bundle"""
|
||||
print(f"Name : {self.name}")
|
||||
print(f"State : {self.state}")
|
||||
print(f"Version : {self.version}")
|
||||
print(f"Size : {self.size}")
|
||||
print(f"SHA-256 : {self.hash}")
|
||||
print(f"Installed : {self.date}")
|
||||
|
||||
@classmethod
|
||||
def print_hdr(cls):
|
||||
pad = cls.Pad()
|
||||
hdr = (f"{'NAME':<{pad.name}}"
|
||||
f"{'STATE':<{pad.state}}"
|
||||
f"{'VERSION':<{pad.version}}"
|
||||
f"{'DATE':<{pad.date}}")
|
||||
print(Decore.invert(hdr))
|
||||
|
||||
def print_slot_row(self):
|
||||
if self.type != "rootfs":
|
||||
return
|
||||
|
||||
"""Brief information about one bundle"""
|
||||
row = f"{self.name:<{self.pad.name}}"
|
||||
row += f"{self.state:<{self.pad.state}}"
|
||||
row += f"{self.version:<{self.pad.version}}"
|
||||
row += f"{self.date:<{self.pad.date}}"
|
||||
print(row)
|
||||
|
||||
|
||||
def __init__(self, cfg):
|
||||
self.cfg = cfg
|
||||
self.data = self.get()
|
||||
|
||||
self.slots = self.data.get("slot", [])
|
||||
self.version = JsonData.get('', self.data, 'bundle', 'version')
|
||||
self.date = JsonData.get('', self.data, 'installed', 'datetime')
|
||||
self.boot_order = self.data.get("boot-order", ["Unknown"])
|
||||
|
||||
def get(self):
|
||||
return self.cfg.run("/ietf-system:system-state/infix-system:software")
|
||||
|
||||
def pprint(self):
|
||||
software = self.data
|
||||
|
||||
print(Decore.invert("BOOT ORDER"))
|
||||
order = " ".join(boot.strip() for boot in self.boot_order)
|
||||
print(f"{order}\n")
|
||||
|
||||
self.Slot.print_hdr()
|
||||
for _slot in reversed(self.slots):
|
||||
slot = self.Slot(_slot, self.version, self.date)
|
||||
slot.print_slot_row()
|
||||
|
||||
def pprint_slot(self, name):
|
||||
match = next((slot for slot in self.slots if slot.get("bootname") == name), None)
|
||||
if match:
|
||||
slot = self.Slot(match, self.version, self.date)
|
||||
slot.print_detailed()
|
||||
|
||||
def show(self, args):
|
||||
if self.cfg.raw_output:
|
||||
print(json.dumps(self.data, indent=2))
|
||||
return
|
||||
|
||||
if args:
|
||||
self.pprint_slot(args[0])
|
||||
else:
|
||||
self.pprint()
|
||||
+23
-54
@@ -1,35 +1,17 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import re
|
||||
import subprocess
|
||||
import json
|
||||
from typing import List
|
||||
import os
|
||||
import shlex
|
||||
import argparse
|
||||
import subprocess
|
||||
|
||||
from sysrepocfg import Sysrepocfg
|
||||
from modules.system import System
|
||||
|
||||
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.")
|
||||
@@ -47,7 +29,7 @@ def cli_pretty(json_data: dict, command: str, *args: str):
|
||||
print(f"Error running cli-pretty: {e}")
|
||||
|
||||
def dhcp(args: List[str]) -> None:
|
||||
data = run_sysrepocfg("/infix-dhcp-server:dhcp-server")
|
||||
data = Sysrepocfg.run("/infix-dhcp-server:dhcp-server")
|
||||
if not data:
|
||||
print("No interface data retrieved.")
|
||||
return
|
||||
@@ -58,7 +40,7 @@ def dhcp(args: List[str]) -> None:
|
||||
cli_pretty(data, "show-dhcp-server")
|
||||
|
||||
def hardware(args: List[str]) -> None:
|
||||
data = run_sysrepocfg("/ietf-hardware:hardware")
|
||||
data = Sysrepocfg.run("/ietf-hardware:hardware")
|
||||
if not data:
|
||||
print("No hardware data retrieved.")
|
||||
return
|
||||
@@ -69,7 +51,7 @@ def hardware(args: List[str]) -> None:
|
||||
cli_pretty(data, "show-hardware")
|
||||
|
||||
def ntp(args: List[str]) -> None:
|
||||
data = run_sysrepocfg("/system-state/ntp")
|
||||
data = Sysrepocfg.run("/system-state/ntp")
|
||||
if not data:
|
||||
print("No ntp data retrieved.")
|
||||
return
|
||||
@@ -90,7 +72,7 @@ def is_valid_interface_name(interface_name: str) -> bool:
|
||||
return bool(re.match(pattern, interface_name))
|
||||
|
||||
def interface(args: List[str]) -> None:
|
||||
data = run_sysrepocfg("/ietf-interfaces:interfaces")
|
||||
data = Sysrepocfg.run("/ietf-interfaces:interfaces")
|
||||
if not data:
|
||||
print("No interface data retrieved.")
|
||||
return
|
||||
@@ -111,7 +93,7 @@ def interface(args: List[str]) -> None:
|
||||
print("Too many arguments provided. Only one interface name is expected.")
|
||||
|
||||
def stp(args: List[str]) -> None:
|
||||
data = run_sysrepocfg("/ietf-interfaces:interfaces")
|
||||
data = Sysrepocfg.run("/ietf-interfaces:interfaces")
|
||||
if not data:
|
||||
print("No interface data retrieved.")
|
||||
return
|
||||
@@ -121,31 +103,14 @@ 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")
|
||||
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 software(cfg : Sysrepocfg, args: List[str]) -> None:
|
||||
system = System(cfg)
|
||||
system.software.show(args)
|
||||
|
||||
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 = Sysrepocfg.run("/ietf-routing:routing/ribs")
|
||||
if not data:
|
||||
print("No route data retrieved.")
|
||||
return
|
||||
@@ -155,14 +120,14 @@ def routes(args: List[str]):
|
||||
cli_pretty(data, "show-routing-table", "-i", ip_version)
|
||||
|
||||
|
||||
def execute_command(command: str, args: List[str]):
|
||||
def execute_legacy_non_class_command(command: str, args: List[str]):
|
||||
|
||||
command_mapping = {
|
||||
'dhcp': dhcp,
|
||||
'hardware': hardware,
|
||||
'interface': interface,
|
||||
'ntp': ntp,
|
||||
'routes': routes,
|
||||
'software' : software,
|
||||
'stp': stp,
|
||||
}
|
||||
|
||||
@@ -171,7 +136,6 @@ def execute_command(command: str, args: List[str]):
|
||||
else:
|
||||
print(f"Unknown command: {command}")
|
||||
|
||||
|
||||
def main():
|
||||
global RAW_OUTPUT
|
||||
|
||||
@@ -179,11 +143,16 @@ def main():
|
||||
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")
|
||||
|
||||
parser.add_argument( "-f", "--datafile", default=None, type=str, help="Path to the input JSON data file")
|
||||
args = parser.parse_args()
|
||||
RAW_OUTPUT = args.raw
|
||||
|
||||
execute_command(args.command, args.args)
|
||||
RAW_OUTPUT = args.raw
|
||||
cfg = Sysrepocfg(args.datafile, args.raw)
|
||||
|
||||
if args.command == "software":
|
||||
software(cfg, args.args)
|
||||
else:
|
||||
execute_legacy_non_class_command(args.command, args.args)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
import shlex
|
||||
import sys
|
||||
import subprocess
|
||||
import json
|
||||
|
||||
class Sysrepocfg:
|
||||
def __init__(self, data_file=None, raw=False):
|
||||
self.data_file = data_file
|
||||
self.raw_output = raw
|
||||
|
||||
def _run(self, safe_xpath):
|
||||
try:
|
||||
result = subprocess.run([
|
||||
"sysrepocfg", "-f", "json", "-X", "-d", "operational", "-x", safe_xpath
|
||||
], capture_output=True, text=True, check=True)
|
||||
data = json.loads(result.stdout)
|
||||
if not data:
|
||||
sys.exit(f"Error, no data from sysrepo")
|
||||
return data
|
||||
except subprocess.CalledProcessError as e:
|
||||
sys.exit(f"Error, running sysrepocfg: {e}")
|
||||
except json.JSONDecodeError as e:
|
||||
sys.exit(f"Error, parsing JSON output: {e}")
|
||||
|
||||
|
||||
def _run_emulator(self, xpath):
|
||||
"""
|
||||
Emulates `sysrepocfg -X -x <xpath>` by extracting a subtree from the JSON file.
|
||||
|
||||
:param json_file: Path to the local JSON file containing sysrepo-style data.
|
||||
:param xpath: YANG-style XPath (e.g., '/ietf-interfaces:interfaces').
|
||||
:return: Extracted subtree or None if not found.
|
||||
"""
|
||||
with open(self.data_file, 'r') as f:
|
||||
data = json.load(f)
|
||||
|
||||
path_parts = xpath.strip('/').split('/')
|
||||
|
||||
node = data
|
||||
for part in path_parts:
|
||||
if isinstance(node, dict) and part in node:
|
||||
node = node[part]
|
||||
else:
|
||||
return None # Path doesn't exist
|
||||
|
||||
return node
|
||||
|
||||
|
||||
def run(self, 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)
|
||||
|
||||
if self.data_file is not None:
|
||||
return self._run_emulator(safe_xpath)
|
||||
|
||||
return self._run(safe_xpath)
|
||||
@@ -49,14 +49,6 @@ class PadRoute:
|
||||
else:
|
||||
raise ValueError(f"unknown IP version: {ipv}")
|
||||
|
||||
|
||||
class PadSoftware:
|
||||
name = 10
|
||||
date = 25
|
||||
hash = 64
|
||||
state = 10
|
||||
version = 23
|
||||
|
||||
class PadDhcpServer:
|
||||
ip = 17
|
||||
mac = 19
|
||||
@@ -287,40 +279,6 @@ class Route:
|
||||
row += f"{hop:<{PadRoute.next_hop}} "
|
||||
print(row)
|
||||
|
||||
|
||||
class Software:
|
||||
"""Software bundle class """
|
||||
def __init__(self, data):
|
||||
self.data = data
|
||||
self.name = data.get('bootname', '')
|
||||
self.size = data.get('size', '')
|
||||
self.type = data.get('class', '')
|
||||
self.hash = data.get('sha256', '')
|
||||
self.state = data.get('state', '')
|
||||
self.version = get_json_data('', self.data, 'bundle', 'version')
|
||||
self.date = get_json_data('', self.data, 'installed', 'datetime')
|
||||
|
||||
def is_rootfs(self):
|
||||
"""True if bundle type is 'rootfs'"""
|
||||
return self.type == "rootfs"
|
||||
|
||||
def print(self):
|
||||
"""Brief information about one bundle"""
|
||||
row = f"{self.name:<{PadSoftware.name}}"
|
||||
row += f"{self.state:<{PadSoftware.state}}"
|
||||
row += f"{self.version:<{PadSoftware.version}}"
|
||||
row += f"{self.date:<{PadSoftware.date}}"
|
||||
print(row)
|
||||
|
||||
def detail(self):
|
||||
"""Detailed information about one bundle"""
|
||||
print(f"Name : {self.name}")
|
||||
print(f"State : {self.state}")
|
||||
print(f"Version : {self.version}")
|
||||
print(f"Size : {self.size}")
|
||||
print(f"SHA-256 : {self.hash}")
|
||||
print(f"Installed : {self.date}")
|
||||
|
||||
class USBport:
|
||||
def __init__(self, data):
|
||||
self.data = data
|
||||
@@ -1159,45 +1117,6 @@ def show_routing_table(json, ip):
|
||||
route = Route(r, ip)
|
||||
route.print()
|
||||
|
||||
|
||||
def find_slot(_slots, name):
|
||||
for _slot in [Software(data) for data in _slots]:
|
||||
if _slot.name == name:
|
||||
return _slot
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def show_software(json, name):
|
||||
if not json.get("ietf-system:system-state", "infix-system:software"):
|
||||
print("Error, cannot find infix-system:software")
|
||||
sys.exit(1)
|
||||
|
||||
software = get_json_data({}, json, 'ietf-system:system-state', 'infix-system:software')
|
||||
slots = software.get("slot")
|
||||
boot_order = software.get("boot-order", ["Unknown"])
|
||||
if name:
|
||||
slot = find_slot(slots, name)
|
||||
if slot:
|
||||
slot.detail()
|
||||
else:
|
||||
print(Decore.invert("BOOT ORDER"))
|
||||
order=""
|
||||
for boot in boot_order:
|
||||
order+=f"{boot.strip()} "
|
||||
print(order)
|
||||
print("")
|
||||
|
||||
hdr = (f"{'NAME':<{PadSoftware.name}}"
|
||||
f"{'STATE':<{PadSoftware.state}}"
|
||||
f"{'VERSION':<{PadSoftware.version}}"
|
||||
f"{'DATE':<{PadSoftware.date}}")
|
||||
print(Decore.invert(hdr))
|
||||
for _s in reversed(slots):
|
||||
slot = Software(_s)
|
||||
if slot.is_rootfs():
|
||||
slot.print()
|
||||
|
||||
def show_hardware(json):
|
||||
if not json.get("ietf-hardware:hardware"):
|
||||
print(f"Error, top level \"ietf-hardware:component\" missing")
|
||||
@@ -1282,9 +1201,6 @@ def main():
|
||||
parser_show_bridge_stp = subparsers.add_parser('show-bridge-stp',
|
||||
help='Show spanning tree state')
|
||||
|
||||
parser_show_software = subparsers.add_parser('show-software', help='Show software versions')
|
||||
parser_show_software.add_argument('-n', '--name', help='Slotname')
|
||||
|
||||
parser_show_hardware = subparsers.add_parser('show-hardware', help='Show USB ports')
|
||||
|
||||
parser_show_ntp_sources = subparsers.add_parser('show-ntp', help='Show NTP sources')
|
||||
@@ -1301,8 +1217,6 @@ def main():
|
||||
show_interfaces(json_data, args.name)
|
||||
elif args.command == "show-routing-table":
|
||||
show_routing_table(json_data, args.ip)
|
||||
elif args.command == "show-software":
|
||||
show_software(json_data, args.name)
|
||||
elif args.command == "show-bridge-mdb":
|
||||
show_bridge_mdb(json_data)
|
||||
elif args.command == "show-bridge-stp":
|
||||
|
||||
@@ -177,6 +177,24 @@ def add_platform(out):
|
||||
|
||||
insert(out, "platform", platform)
|
||||
|
||||
def add_services(out):
|
||||
data = HOST.run_json(["initctl", "-j"], [])
|
||||
services = []
|
||||
|
||||
for d in data:
|
||||
if "pid" not in d or "status" not in d or "identity" not in d or "description" not in d:
|
||||
continue
|
||||
|
||||
entry = {
|
||||
"pid": d["pid"],
|
||||
"name": d["identity"],
|
||||
"status": d["status"],
|
||||
"description": d["description"]
|
||||
}
|
||||
services.append(entry)
|
||||
|
||||
insert(out, "infix-system:services", "service", services)
|
||||
|
||||
def add_software(out):
|
||||
software = {}
|
||||
try:
|
||||
@@ -291,5 +309,6 @@ def operational():
|
||||
add_dns(out_state)
|
||||
add_clock(out_state)
|
||||
add_platform(out_state)
|
||||
add_services(out_state)
|
||||
|
||||
return out
|
||||
|
||||
@@ -128,6 +128,148 @@
|
||||
"os-version": "v25.04.0-rc1-3-g8daf1571-dirty",
|
||||
"os-release": "v25.04.0-rc1-3-g8daf1571-dirty",
|
||||
"machine": "x86_64"
|
||||
},
|
||||
"infix-system:services": {
|
||||
"service": [
|
||||
{
|
||||
"pid": 1185,
|
||||
"name": "udevd",
|
||||
"status": "running",
|
||||
"description": "Device event daemon (udev)"
|
||||
},
|
||||
{
|
||||
"pid": 2248,
|
||||
"name": "dbus",
|
||||
"status": "running",
|
||||
"description": "D-Bus message bus daemon"
|
||||
},
|
||||
{
|
||||
"pid": 3039,
|
||||
"name": "confd",
|
||||
"status": "running",
|
||||
"description": "Configuration daemon"
|
||||
},
|
||||
{
|
||||
"pid": 3548,
|
||||
"name": "netopeer",
|
||||
"status": "running",
|
||||
"description": "NETCONF server"
|
||||
},
|
||||
{
|
||||
"pid": 2249,
|
||||
"name": "dnsmasq",
|
||||
"status": "running",
|
||||
"description": "DHCP/DNS proxy"
|
||||
},
|
||||
{
|
||||
"pid": 3559,
|
||||
"name": "tty:hvc0",
|
||||
"status": "running",
|
||||
"description": "Getty on hvc0"
|
||||
},
|
||||
{
|
||||
"pid": 2340,
|
||||
"name": "iitod",
|
||||
"status": "running",
|
||||
"description": "LED daemon"
|
||||
},
|
||||
{
|
||||
"pid": 3560,
|
||||
"name": "klishd",
|
||||
"status": "running",
|
||||
"description": "CLI backend daemon"
|
||||
},
|
||||
{
|
||||
"pid": 3617,
|
||||
"name": "mdns-alias",
|
||||
"status": "running",
|
||||
"description": "mDNS alias advertiser "
|
||||
},
|
||||
{
|
||||
"pid": 0,
|
||||
"name": "mstpd",
|
||||
"status": "stopped",
|
||||
"description": "Spanning Tree daemon"
|
||||
},
|
||||
{
|
||||
"pid": 3564,
|
||||
"name": "rauc",
|
||||
"status": "running",
|
||||
"description": "Software update service"
|
||||
},
|
||||
{
|
||||
"pid": 0,
|
||||
"name": "resolvconf",
|
||||
"status": "done",
|
||||
"description": "Update DNS configuration"
|
||||
},
|
||||
{
|
||||
"pid": 3472,
|
||||
"name": "statd",
|
||||
"status": "running",
|
||||
"description": "Status daemon"
|
||||
},
|
||||
{
|
||||
"pid": 3653,
|
||||
"name": "staticd",
|
||||
"status": "running",
|
||||
"description": "Static routing daemon"
|
||||
},
|
||||
{
|
||||
"pid": 2241,
|
||||
"name": "syslogd",
|
||||
"status": "running",
|
||||
"description": "System log daemon"
|
||||
},
|
||||
{
|
||||
"pid": 2242,
|
||||
"name": "watchdogd",
|
||||
"status": "running",
|
||||
"description": "System watchdog daemon"
|
||||
},
|
||||
{
|
||||
"pid": 3587,
|
||||
"name": "zebra",
|
||||
"status": "running",
|
||||
"description": "Zebra routing daemon"
|
||||
},
|
||||
{
|
||||
"pid": 3616,
|
||||
"name": "mdns",
|
||||
"status": "running",
|
||||
"description": "Avahi mDNS-SD daemon"
|
||||
},
|
||||
{
|
||||
"pid": 3618,
|
||||
"name": "chronyd",
|
||||
"status": "running",
|
||||
"description": "Chrony NTP v3/v4 daemon"
|
||||
},
|
||||
{
|
||||
"pid": 3633,
|
||||
"name": "lldpd",
|
||||
"status": "running",
|
||||
"description": "LLDP daemon (IEEE 802.1ab)"
|
||||
},
|
||||
{
|
||||
"pid": 3635,
|
||||
"name": "nginx",
|
||||
"status": "running",
|
||||
"description": "Web server"
|
||||
},
|
||||
{
|
||||
"pid": 3636,
|
||||
"name": "rousette",
|
||||
"status": "running",
|
||||
"description": "RESTCONF server"
|
||||
},
|
||||
{
|
||||
"pid": 3641,
|
||||
"name": "sshd",
|
||||
"status": "running",
|
||||
"description": "OpenSSH daemon"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,401 @@
|
||||
[
|
||||
{
|
||||
"identity": "udevd",
|
||||
"description": "Device event daemon (udev)",
|
||||
"type": "service",
|
||||
"forking": false,
|
||||
"status": "running",
|
||||
"origin": "/usr/lib/finit/system/10-hotplug.conf",
|
||||
"command": "udevd $UDEVD_ARGS",
|
||||
"environment": "-/etc/default/udevd",
|
||||
"restarts": 0,
|
||||
"pidfile": "/run/udevd.pid",
|
||||
"pid": 1185,
|
||||
"user": "root",
|
||||
"group": "root",
|
||||
"uptime": 1390,
|
||||
"runlevels": [ "S", 1, 2, 3, 4, 5, 7, 8, 9 ]
|
||||
},
|
||||
{
|
||||
"identity": "dbus",
|
||||
"description": "D-Bus message bus daemon",
|
||||
"type": "service",
|
||||
"forking": true,
|
||||
"status": "running",
|
||||
"origin": "/etc/finit.d/dbus.conf",
|
||||
"command": "/usr/bin/dbus-daemon --nofork --system --syslog-only",
|
||||
"condition": [ "+pid/syslogd" ],
|
||||
"restarts": 0,
|
||||
"pidfile": "/run/messagebus.pid",
|
||||
"pid": 2248,
|
||||
"user": "root",
|
||||
"group": "root",
|
||||
"uptime": 1390,
|
||||
"runlevels": [ "S", 1, 2, 3, 4, 5, 6, 7, 8, 9 ]
|
||||
},
|
||||
{
|
||||
"identity": "confd",
|
||||
"description": "Configuration daemon",
|
||||
"type": "service",
|
||||
"forking": false,
|
||||
"status": "running",
|
||||
"origin": "/etc/finit.d/enabled/confd.conf",
|
||||
"command": "sysrepo-plugind -f -p /run/confd.pid -n -v warning",
|
||||
"condition": [ "+run/bootstrap/success" ],
|
||||
"restarts": 0,
|
||||
"pidfile": "/run/confd.pid",
|
||||
"pid": 3039,
|
||||
"user": "root",
|
||||
"group": "root",
|
||||
"uptime": 1390,
|
||||
"runlevels": [ "S", 1, 2, 3, 4, 5 ]
|
||||
},
|
||||
{
|
||||
"identity": "netopeer",
|
||||
"description": "NETCONF server",
|
||||
"type": "service",
|
||||
"forking": false,
|
||||
"status": "running",
|
||||
"origin": "/etc/finit.d/enabled/confd.conf",
|
||||
"command": "netopeer2-server -F -t $CONFD_TIMEOUT -v 1",
|
||||
"environment": "/etc/default/confd",
|
||||
"condition": [ "+pid/confd" ],
|
||||
"restarts": 0,
|
||||
"pidfile": "/run/netopeer2-server.pid",
|
||||
"pid": 3548,
|
||||
"user": "root",
|
||||
"group": "root",
|
||||
"uptime": 1388,
|
||||
"runlevels": [ 1, 2, 3, 4, 5 ]
|
||||
},
|
||||
{
|
||||
"identity": "dnsmasq",
|
||||
"description": "DHCP/DNS proxy",
|
||||
"type": "service",
|
||||
"forking": false,
|
||||
"status": "running",
|
||||
"origin": "/etc/finit.d/enabled/dnsmasq.conf",
|
||||
"command": "dnsmasq -k -u root",
|
||||
"condition": [ "+pid/syslogd" ],
|
||||
"restarts": 0,
|
||||
"pidfile": "/run/dnsmasq.pid",
|
||||
"pid": 2249,
|
||||
"user": "root",
|
||||
"group": "root",
|
||||
"uptime": 1390,
|
||||
"runlevels": [ "S", 1, 2, 3, 4, 5 ]
|
||||
},
|
||||
{
|
||||
"identity": "tty:hvc0",
|
||||
"description": "Getty on hvc0",
|
||||
"type": "tty",
|
||||
"forking": false,
|
||||
"status": "running",
|
||||
"origin": "/etc/finit.d/enabled/getty.conf",
|
||||
"command": "/usr/libexec/finit/getty -p hvc0 0 xterm",
|
||||
"restarts": 0,
|
||||
"pidfile": "none",
|
||||
"pid": 3559,
|
||||
"user": "root",
|
||||
"group": "root",
|
||||
"uptime": 1388,
|
||||
"runlevels": [ 1, 2, 3, 4, 5, 7, 8, 9 ]
|
||||
},
|
||||
{
|
||||
"identity": "iitod",
|
||||
"description": "LED daemon",
|
||||
"type": "service",
|
||||
"forking": false,
|
||||
"status": "running",
|
||||
"origin": "/etc/finit.d/enabled/iitod.conf",
|
||||
"command": "iitod",
|
||||
"condition": [ "+usr/product", "+usr/led" ],
|
||||
"restarts": 0,
|
||||
"pidfile": "none",
|
||||
"pid": 2340,
|
||||
"user": "root",
|
||||
"group": "root",
|
||||
"uptime": 1390,
|
||||
"runlevels": [ "S", 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ]
|
||||
},
|
||||
{
|
||||
"identity": "klishd",
|
||||
"description": "CLI backend daemon",
|
||||
"type": "service",
|
||||
"forking": false,
|
||||
"status": "running",
|
||||
"origin": "/etc/finit.d/enabled/klish.conf",
|
||||
"command": "/usr/bin/klishd -d",
|
||||
"restarts": 0,
|
||||
"pidfile": "none",
|
||||
"pid": 3560,
|
||||
"user": "root",
|
||||
"group": "root",
|
||||
"uptime": 1388,
|
||||
"runlevels": [ 2, 3, 4, 5 ]
|
||||
},
|
||||
{
|
||||
"identity": "mdns-alias",
|
||||
"description": "mDNS alias advertiser ",
|
||||
"type": "service",
|
||||
"forking": false,
|
||||
"status": "running",
|
||||
"origin": "/etc/finit.d/enabled/mdns-alias.conf",
|
||||
"command": "mdns-alias $MDNS_ALIAS_ARGS",
|
||||
"environment": "-/etc/default/mdns-alias",
|
||||
"condition": [ "+service/mdns/running" ],
|
||||
"restarts": 0,
|
||||
"pidfile": "none",
|
||||
"pid": 3617,
|
||||
"user": "root",
|
||||
"group": "root",
|
||||
"uptime": 1388,
|
||||
"runlevels": [ 2, 3, 4, 5 ]
|
||||
},
|
||||
{
|
||||
"identity": "mstpd",
|
||||
"description": "Spanning Tree daemon",
|
||||
"type": "service",
|
||||
"forking": false,
|
||||
"status": "stopped",
|
||||
"exit": { "code": 0 },
|
||||
"origin": "/etc/finit.d/enabled/mstpd.conf",
|
||||
"command": "mstpd $MSTPD_ARGS",
|
||||
"environment": "-/etc/default/mstpd",
|
||||
"starts": 0,
|
||||
"restarts": 0,
|
||||
"pidfile": "none",
|
||||
"pid": 0,
|
||||
"user": "root",
|
||||
"group": "root",
|
||||
"uptime": 0,
|
||||
"runlevels": [ "S", 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ]
|
||||
},
|
||||
{
|
||||
"identity": "rauc",
|
||||
"description": "Software update service",
|
||||
"type": "service",
|
||||
"forking": false,
|
||||
"status": "running",
|
||||
"origin": "/etc/finit.d/enabled/rauc.conf",
|
||||
"command": "rauc service $RAUC_ARGS",
|
||||
"environment": "-/etc/default/rauc",
|
||||
"condition": [ "+service/dbus/running" ],
|
||||
"restarts": 0,
|
||||
"pidfile": "none",
|
||||
"pid": 3564,
|
||||
"user": "root",
|
||||
"group": "root",
|
||||
"uptime": 1388,
|
||||
"runlevels": [ 2, 3, 4, 5 ]
|
||||
},
|
||||
{
|
||||
"identity": "resolvconf",
|
||||
"description": "Update DNS configuration",
|
||||
"type": "task",
|
||||
"forking": false,
|
||||
"status": "done",
|
||||
"exit": { "code": 0 },
|
||||
"origin": "/etc/finit.d/enabled/resolvconf.conf",
|
||||
"command": "resolvconf -u",
|
||||
"condition": [ "+usr/bootstrap" ],
|
||||
"restarts": 2,
|
||||
"pidfile": "none",
|
||||
"pid": 0,
|
||||
"user": "root",
|
||||
"group": "root",
|
||||
"uptime": 0,
|
||||
"runlevels": [ "S", 1, 2, 3, 4, 5 ]
|
||||
},
|
||||
{
|
||||
"identity": "statd",
|
||||
"description": "Status daemon",
|
||||
"type": "service",
|
||||
"forking": false,
|
||||
"status": "running",
|
||||
"origin": "/etc/finit.d/enabled/statd.conf",
|
||||
"command": "statd -f -p /run/statd.pid -n",
|
||||
"condition": [ "+pid/confd" ],
|
||||
"restarts": 0,
|
||||
"pidfile": "/run/statd.pid",
|
||||
"pid": 3472,
|
||||
"user": "root",
|
||||
"group": "root",
|
||||
"uptime": 1389,
|
||||
"runlevels": [ "S", 1, 2, 3, 4, 5 ]
|
||||
},
|
||||
{
|
||||
"identity": "staticd",
|
||||
"description": "Static routing daemon",
|
||||
"type": "service",
|
||||
"forking": false,
|
||||
"status": "running",
|
||||
"origin": "/etc/finit.d/enabled/staticd.conf",
|
||||
"command": "staticd -A 127.0.0.1 -u frr -g frr -f /etc/frr/staticd.conf",
|
||||
"condition": [ "+pid/zebra" ],
|
||||
"restarts": 0,
|
||||
"pidfile": "/run/frr/staticd.pid",
|
||||
"pid": 3653,
|
||||
"user": "root",
|
||||
"group": "root",
|
||||
"uptime": 1388,
|
||||
"runlevels": [ 2, 3, 4, 5 ]
|
||||
},
|
||||
{
|
||||
"identity": "syslogd",
|
||||
"description": "System log daemon",
|
||||
"type": "service",
|
||||
"forking": false,
|
||||
"status": "running",
|
||||
"origin": "/etc/finit.d/enabled/sysklogd.conf",
|
||||
"command": "syslogd -F $SYSLOGD_ARGS",
|
||||
"environment": "-/etc/default/sysklogd",
|
||||
"condition": [ "+run/udevadm:post/success" ],
|
||||
"restarts": 0,
|
||||
"pidfile": "/run/syslogd.pid",
|
||||
"pid": 2241,
|
||||
"user": "root",
|
||||
"group": "root",
|
||||
"uptime": 1390,
|
||||
"runlevels": [ "S", 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ]
|
||||
},
|
||||
{
|
||||
"identity": "watchdogd",
|
||||
"description": "System watchdog daemon",
|
||||
"type": "service",
|
||||
"forking": false,
|
||||
"status": "running",
|
||||
"origin": "/etc/finit.d/enabled/watchdogd.conf",
|
||||
"command": "watchdogd -xns $WATCHDOGD_ARGS",
|
||||
"environment": "-/etc/default/watchdogd",
|
||||
"restarts": 0,
|
||||
"pidfile": "/run/watchdogd/pid",
|
||||
"pid": 2242,
|
||||
"user": "root",
|
||||
"group": "root",
|
||||
"uptime": 1390,
|
||||
"runlevels": [ "S", 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ]
|
||||
},
|
||||
{
|
||||
"identity": "zebra",
|
||||
"description": "Zebra routing daemon",
|
||||
"type": "service",
|
||||
"forking": true,
|
||||
"status": "running",
|
||||
"origin": "/etc/finit.d/enabled/zebra.conf",
|
||||
"command": "zebra $ZEBRA_ARGS",
|
||||
"environment": "-/etc/default/zebra",
|
||||
"restarts": 0,
|
||||
"pidfile": "/run/frr/zebra.pid",
|
||||
"pid": 3587,
|
||||
"user": "root",
|
||||
"group": "root",
|
||||
"uptime": 1388,
|
||||
"runlevels": [ 2, 3, 4, 5 ]
|
||||
},
|
||||
{
|
||||
"identity": "mdns",
|
||||
"description": "Avahi mDNS-SD daemon",
|
||||
"type": "service",
|
||||
"forking": false,
|
||||
"status": "running",
|
||||
"origin": "/etc/finit.d/enabled/avahi.conf",
|
||||
"command": "avahi-daemon -s $AVAHI_ARGS",
|
||||
"environment": "-/etc/default/avahi",
|
||||
"restarts": 0,
|
||||
"pidfile": "none",
|
||||
"pid": 3616,
|
||||
"user": "root",
|
||||
"group": "root",
|
||||
"uptime": 1388,
|
||||
"runlevels": [ 2, 3, 4, 5 ]
|
||||
},
|
||||
{
|
||||
"identity": "chronyd",
|
||||
"description": "Chrony NTP v3/v4 daemon",
|
||||
"type": "service",
|
||||
"forking": false,
|
||||
"status": "running",
|
||||
"origin": "/etc/finit.d/enabled/chronyd.conf",
|
||||
"command": "chronyd -n $CHRONY_ARGS",
|
||||
"environment": "-/etc/default/chronyd",
|
||||
"restarts": 0,
|
||||
"pidfile": "/run/chrony/chronyd.pid",
|
||||
"pid": 3618,
|
||||
"user": "root",
|
||||
"group": "root",
|
||||
"uptime": 1388,
|
||||
"runlevels": [ 2, 3, 4, 5 ]
|
||||
},
|
||||
{
|
||||
"identity": "lldpd",
|
||||
"description": "LLDP daemon (IEEE 802.1ab)",
|
||||
"type": "service",
|
||||
"forking": false,
|
||||
"status": "running",
|
||||
"origin": "/etc/finit.d/enabled/lldpd.conf",
|
||||
"command": "lldpd -d $LLDPD_ARGS",
|
||||
"environment": "-/etc/default/lldpd",
|
||||
"restarts": 0,
|
||||
"pidfile": "none",
|
||||
"pid": 3633,
|
||||
"user": "root",
|
||||
"group": "root",
|
||||
"uptime": 1388,
|
||||
"runlevels": [ 2, 3, 4, 5 ]
|
||||
},
|
||||
{
|
||||
"identity": "nginx",
|
||||
"description": "Web server",
|
||||
"type": "service",
|
||||
"forking": false,
|
||||
"status": "running",
|
||||
"origin": "/etc/finit.d/enabled/nginx.conf",
|
||||
"command": "nginx -g 'daemon off;' $NGINX_ARGS",
|
||||
"environment": "-/etc/default/nginx",
|
||||
"condition": [ "+usr/mkcert" ],
|
||||
"restarts": 0,
|
||||
"pidfile": "/run/nginx.pid",
|
||||
"pid": 3635,
|
||||
"user": "root",
|
||||
"group": "root",
|
||||
"uptime": 1388,
|
||||
"runlevels": [ 2, 3, 4, 5 ]
|
||||
},
|
||||
{
|
||||
"identity": "rousette",
|
||||
"description": "RESTCONF server",
|
||||
"type": "service",
|
||||
"forking": false,
|
||||
"status": "running",
|
||||
"origin": "/etc/finit.d/enabled/restconf.conf",
|
||||
"command": "rousette --syslog -t $CONFD_TIMEOUT",
|
||||
"environment": "/etc/default/confd",
|
||||
"condition": [ "+pid/confd" ],
|
||||
"restarts": 0,
|
||||
"pidfile": "none",
|
||||
"pid": 3636,
|
||||
"user": "root",
|
||||
"group": "root",
|
||||
"uptime": 1388,
|
||||
"runlevels": [ 1, 2, 3, 4, 5 ]
|
||||
},
|
||||
{
|
||||
"identity": "sshd",
|
||||
"description": "OpenSSH daemon",
|
||||
"type": "service",
|
||||
"forking": false,
|
||||
"status": "running",
|
||||
"origin": "/etc/finit.d/enabled/sshd.conf",
|
||||
"command": "/usr/sbin/sshd -D $SSHD_OPTS",
|
||||
"environment": "-/etc/default/sshd",
|
||||
"condition": [ "+pid/syslogd" ],
|
||||
"restarts": 0,
|
||||
"pidfile": "/run/sshd.pid",
|
||||
"pid": 3641,
|
||||
"user": "root",
|
||||
"group": "root",
|
||||
"uptime": 1388,
|
||||
"runlevels": [ 2, 3, 4, 5 ]
|
||||
}
|
||||
]
|
||||
Reference in New Issue
Block a user