diff --git a/src/statd/python/yanger/infix_containers.py b/src/statd/python/yanger/infix_containers.py new file mode 100644 index 00000000..4289fb85 --- /dev/null +++ b/src/statd/python/yanger/infix_containers.py @@ -0,0 +1,76 @@ +from .common import LOG +from .host import HOST + +def podman_inspect(name): + """Call podman inspect {name}, return object at {path} or None.""" + cmd = ['podman', 'inspect', name] + try: + return HOST.run_json(cmd, default=[]) + except Exception as e: + LOG(f"Error running podman inspect: {e}") + return [] + +def podman_ps(): + """We list *all* containers, not just those in the configuraion.""" + return HOST.run_json("podman ps -a --format=json".split(), default=[]) + + +def network(ps, inspect): + net = {} + + # The 'podman ps' command lists ports even in host mode, but + # that's not applicable, so skip networks and port forwardings + networks = inspect.get("NetworkSettings", {}).get("Networks") + if networks and "host" in networks: + net = {"host": True} + else: + net = { + "interface": [{"name": net} for net in ps["Networks"]], + "publish": [] + } + + if (ps["State"] == "running") and ps["Ports"]: + for port in ps["Ports"]: + addr = "" + if port["host_ip"]: + addr = f"{port['host_ip']}:" + + pub = f"{addr}{port['host_port']}->{port['container_port']}/{port['protocol']}" + net["publish"].append(pub) + + return net + + +def container(ps): + out = { + "name": ps["Names"][0], + "id": ps["Id"], + "image": ps["Image"], + "image-id": ps["ImageID"], + "running": ps["State"] == "running", + "status": ps["Status"] + } + + # Bonus information, may not be available + if ps["Command"]: + out["command"] = " ".join(ps["Command"]) + + inspect = podman_inspect(out["name"]) + if inspect and isinstance(inspect, list) and len(inspect) > 0: + inspect = inspect[0] + else: + inspect = {} + + net = network(ps, inspect) + if net: + out["network"] = net + + return out + + +def operational(): + return { + "infix-containers:containers": { + "container": [container(ps) for ps in podman_ps()] + } + } diff --git a/src/statd/python/yanger/yanger.py b/src/statd/python/yanger/yanger.py index 9d1aea05..7d233739 100644 --- a/src/statd/python/yanger/yanger.py +++ b/src/statd/python/yanger/yanger.py @@ -552,70 +552,6 @@ def get_bridge_port_stp_state(ifname): return None -def container_inspect(name): - """Call podman inspect {name}, return object at {path} or None.""" - cmd = ['podman', 'inspect', name] - try: - return run_json_cmd(cmd, "", default=[]) - except Exception as e: - logging.error(f"Error running podman inspect: {e}") - return [] - - -def add_container(containers): - """We list *all* containers, not just those in the configuraion.""" - cmd = ['podman', 'ps', '-a', '--format=json'] - - raw = run_json_cmd(cmd, "", default=[]) - for entry in raw: - running = entry["State"] == "running" - - container = { - "name": entry["Names"][0], - "id": entry["Id"], - "image": entry["Image"], - "image-id": entry["ImageID"], - "running": running, - "status": entry["Status"] - } - - # Bonus information, may not be available - if entry["Command"]: - container["command"] = " ".join(entry["Command"]) - - # The 'podman ps' command lists ports even in host mode, but - # that's not applicable, so skip networks and port forwardings - cont = container_inspect(container["name"]) - if cont and isinstance(cont, list) and len(cont) > 0: - cont = cont[0] - else: - cont = {} - - networks = cont.get("NetworkSettings", {}).get("Networks") - if networks and "host" in networks: - container["network"] = {"host": True} - else: - container["network"] = { - "interface": [], - "publish": [] - } - - if entry["Networks"]: - for net in entry["Networks"]: - container["network"]["interface"].append({"name": net}) - - if running and entry["Ports"]: - for port in entry["Ports"]: - addr = "" - if port["host_ip"]: - addr = f"{port['host_ip']}:" - - pub = f"{addr}{port['host_port']}->{port['container_port']}/{port['protocol']}" - container["network"]["publish"].append(pub) - - containers.append(container) - - def get_brport_multicast(ifname): """Check if multicast snooping is enabled on bridge, default: nope""" data = run_json_cmd(['mctl', 'show', 'igmp', 'json'], "igmp-status.json", @@ -1154,13 +1090,8 @@ def main(): add_hardware(yang_data["ietf-hardware:hardware"]) elif args.model == 'infix-containers': - yang_data = { - "infix-containers:containers": { - "container": [] - } - } - add_container(yang_data['infix-containers:containers']['container']) - + from . import infix_containers + yang_data = infix_containers.operational() elif args.model == 'ietf-system': from . import ietf_system yang_data = ietf_system.operational() diff --git a/test/case/cli/system-output/podman-ps.json b/test/case/cli/system-output/run/podman_ps_-a_--format=json similarity index 100% rename from test/case/cli/system-output/podman-ps.json rename to test/case/cli/system-output/run/podman_ps_-a_--format=json