From a9a7b7016d9aff358966bf1edc52f860e0cdf0f5 Mon Sep 17 00:00:00 2001 From: Joachim Wiberg Date: Wed, 31 Jan 2024 10:42:50 +0100 Subject: [PATCH] statd: initial support for container-state information Also, add missing dependency on libite to packaging. Signed-off-by: Joachim Wiberg --- board/netconf/rootfs/libexec/infix/yanger | 42 ++++++++++ package/statd/Config.in | 1 + .../yang/infix-containers@2023-12-14.yang | 77 ++++++++++++++----- src/statd/statd.c | 16 ++++ 4 files changed, 117 insertions(+), 19 deletions(-) diff --git a/board/netconf/rootfs/libexec/infix/yanger b/board/netconf/rootfs/libexec/infix/yanger index d2de24a4..5cbe411c 100755 --- a/board/netconf/rootfs/libexec/infix/yanger +++ b/board/netconf/rootfs/libexec/infix/yanger @@ -438,6 +438,39 @@ def get_bridge_port_stp_state(ifname, iface_out, test): return None +def add_container(containers): + """In container-state we list *all* containers, not just ones managed in configuration.""" + cmd = ['podman', 'ps', '-a', '--format=json'] + + raw = run_json_cmd(cmd) + for entry in raw: + container = {} + container["name"] = entry["Names"][0] + container["id"] = entry["Id"] + container["image"] = entry["Image"] + container["image_id"] = entry["ImageID"] + container["running"] = entry["State"] == "running" + container["status"] = entry["Status"] + + # Bonus information, may not be available + if entry["Command"]: + container["command"] = " ".join(entry["Command"]) + + if entry["Networks"]: + container["networks"] = entry["Networks"] + + if entry["Ports"]: + container["ports"] = [] + for port in entry["Ports"]: + addr = "" + if port["host_ip"]: + addr = f"{port['host_ip']}:" + + publish = f"{addr}{port['host_port']}:{port['container_port']}/{port['protocol']}" + container["ports"].append(publish) + + containers.append(container) + def add_ip_link(ifname, iface_out, test): """Fetch interface link information from kernel""" if test: @@ -789,6 +822,15 @@ if __name__ == "__main__": } } add_hardware(yang_data["ietf-hardware:hardware"], args.test) + + elif args.model == 'infix-containers': + yang_data = { + "infix-containers:container-state": { + "container": [] + } + } + add_container(yang_data['infix-containers:container-state']['container']) + else: print(f"Unsupported model {args.model}", file=sys.stderr) sys.exit(1) diff --git a/package/statd/Config.in b/package/statd/Config.in index a3d4d4d2..8f3d185b 100644 --- a/package/statd/Config.in +++ b/package/statd/Config.in @@ -4,6 +4,7 @@ config BR2_PACKAGE_STATD select BR2_PACKAGE_LIBEV select BR2_PACKAGE_SYSREPO select BR2_PACKAGE_LIBSRX + select BR2_PACKAGE_LIBITE help Operational Status Daemon. Responsible for handling sysrepo operational run-time info. Such as interface state and address. diff --git a/src/confd/yang/infix-containers@2023-12-14.yang b/src/confd/yang/infix-containers@2023-12-14.yang index cc595901..b268409d 100644 --- a/src/confd/yang/infix-containers@2023-12-14.yang +++ b/src/confd/yang/infix-containers@2023-12-14.yang @@ -57,7 +57,7 @@ module infix-containers { key "name"; leaf name { - description "Name of the Docker container"; + description "Name of the container"; type string; } @@ -231,24 +231,6 @@ module infix-containers { } } - container statistics { - description "Statistics of the container"; - config false; - - leaf status { - description "Status of the Docker container"; - type enumeration { - enum running; - enum stopped; - } - } - - leaf created { - description "Creation timestamp of the container"; - type yang:date-and-time; - } - } - action start { description "Start a stopped container."; } @@ -260,4 +242,61 @@ module infix-containers { } } } + + /* + * Operational state data nodes + */ + + container container-state { + config false; + + list container { + key "name"; + + leaf name { + description "Name of the container."; + type string; + } + + leaf id { + description "Container ID, unique hash."; + type string; + } + + leaf comand { + description "Command being run by container."; + type string; + } + + leaf image { + description "Docker image used."; + type string; + } + + leaf image_id { + description "Docker image ID, exact hash used."; + type string; + } + + leaf-list networks { + description "CNI networks attached to container."; + type string; + } + + leaf-list ports { + description "Exposed ports: [[ip:][hostPort]:]containerPort[/protocol]"; + type string; + } + + leaf running { + description "Status of container, running or not."; + type boolean; + } + + leaf status { + description "Status of container, human friendly."; + type string; + } + } + } } diff --git a/src/statd/statd.c b/src/statd/statd.c index e7b9d4c1..f4bb494f 100644 --- a/src/statd/statd.c +++ b/src/statd/statd.c @@ -40,6 +40,7 @@ #define XPATH_ROUTING_TABLE "/ietf-routing:routing/ribs" #define XPATH_HARDWARE_BASE "/ietf-hardware:hardware" #define XPATH_ROUTING_OSPF XPATH_ROUTING_BASE "/ospf" +#define XPATH_CONTAIN_BASE "/infix-containers:container-state" TAILQ_HEAD(sub_head, sub); @@ -511,6 +512,12 @@ static int sub_to_ospf(struct statd *statd) { return subscribe(statd, "ietf-routing", XPATH_ROUTING_OSPF, "ospf", sr_ospf_cb); } + +static int sub_to_container(struct statd *statd) +{ + return subscribe(statd, "infix-containers", XPATH_CONTAIN_BASE, "container", sr_generic_cb); +} + int main(int argc, char *argv[]) { struct ev_signal sigint_watcher, sigusr1_watcher; @@ -573,12 +580,21 @@ int main(int argc, char *argv[]) sr_disconnect(sr_conn); return EXIT_FAILURE; } + err = sub_to_hardware(&statd); if (err) { ERROR("Error register for hardware status"); sr_disconnect(sr_conn); return EXIT_FAILURE; } + + err = sub_to_container(&statd); + if (err) { + ERROR("Error registering infix-container status"); + sr_disconnect(sr_conn); + return EXIT_FAILURE; + } + ev_signal_init(&sigint_watcher, sigint_cb, SIGINT); sigint_watcher.data = &statd; ev_signal_start(statd.ev_loop, &sigint_watcher);