statd, show: fix several operational data reporting bugs

Three bugs found while testing modem support on hardware:

ietf_system.py: "interface": null written to DNS server entries when
  no interface is associated, causing LY_EVALID in the ietf-system
  schema validator.  Only include the key when the interface name is
  non-empty.

ietf_system.py: empty list inserts (user [], server [], options [],
  search []) overwrote configured data in the operational store instead
  of leaving it intact.  Guard each insert so operational data only
  shadows configured data when there is something to report.

show system: CPU temperature reported only the first sensor named
  exactly "cpu", "soc", or "core".  Platforms with multiple thermal
  zones (e.g. BPI-R4 exposes cpu and cpu1) always showed only one
  reading.  Collect all sensors whose name matches a CPU/SoC prefix
  and report the maximum.

statd.c: yanger parse errors logged without model name or libyang
  error string, making failures hard to diagnose.  Include both.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
This commit is contained in:
Joachim Wiberg
2026-06-07 20:50:29 +02:00
parent 314b0b425f
commit ffe5ed1e32
4 changed files with 23 additions and 22 deletions
+7 -8
View File
@@ -558,8 +558,9 @@ def system(args: List[str]) -> None:
runtime = {}
# Extract CPU temperature and fan speed from hardware components
cpu_temp = None
cpu_temps = []
fan_rpm = None
_cpu_prefixes = ("cpu", "soc", "core")
if hardware_data and "ietf-hardware:hardware" in hardware_data:
components = hardware_data.get("ietf-hardware:hardware", {}).get("component", [])
for component in components:
@@ -570,18 +571,16 @@ def system(args: List[str]) -> None:
name = component.get("name", "")
value_type = sensor_data.get("value-type")
# Only capture CPU/SoC temperature (ignore phy, sfp, etc.)
# Different platforms use different names: cpu, soc, core, etc.
if value_type == "celsius" and name in ("cpu", "soc", "core") and cpu_temp is None:
temp_millidegrees = sensor_data.get("value", 0)
cpu_temp = temp_millidegrees / 1000.0
# Capture all CPU/SoC temperatures (handles cpu, cpu1, soc, core0, etc.)
if value_type == "celsius" and any(name == p or name.startswith(p) for p in _cpu_prefixes):
cpu_temps.append(sensor_data.get("value", 0) / 1000.0)
# Capture fan speed if available
elif value_type == "rpm" and fan_rpm is None:
fan_rpm = sensor_data.get("value", 0)
if cpu_temp is not None:
runtime["cpu_temp"] = cpu_temp
if cpu_temps:
runtime["cpu_temp"] = max(cpu_temps)
if fan_rpm is not None:
runtime["fan_rpm"] = fan_rpm
+12 -9
View File
@@ -134,11 +134,10 @@ def add_dns(out):
try:
ipaddress.ip_address(ip)
servers.append({
"address": ip,
"origin": "dhcp",
"interface": iface
})
entry = {"address": ip, "origin": "dhcp"}
if iface:
entry["interface"] = iface
servers.append(entry)
except ValueError:
continue
@@ -146,9 +145,12 @@ def add_dns(out):
parts = line.split('#', 1)
search.extend(parts[0].split()[1:])
insert(out, "infix-system:dns-resolver", "options", options)
insert(out, "infix-system:dns-resolver", "server", servers)
insert(out, "infix-system:dns-resolver", "search", search)
if options:
insert(out, "infix-system:dns-resolver", "options", options)
if servers:
insert(out, "infix-system:dns-resolver", "server", servers)
if search:
insert(out, "infix-system:dns-resolver", "search", search)
def add_software_slots(out, data):
slots = []
@@ -357,7 +359,8 @@ def add_users(out):
users.append(user)
insert(out, "authentication", "user", users)
if users:
insert(out, "authentication", "user", users)
def add_clock(out):
clock = {}
+3 -2
View File
@@ -112,7 +112,8 @@ static int ly_add_yanger_data(const struct ly_ctx *ctx, struct lyd_node **parent
err = lyd_parse_data_fd(ctx, fd, LYD_JSON, LYD_PARSE_ONLY, 0, parent);
if (err)
ERROR("Error, parsing yanger data (%d): %s", err, ly_errmsg(ctx));
ERROR("Error, parsing yanger data (%d) for model '%s': %s", err,
yanger_args[1] ?: "?", ly_errmsg(ctx));
fclose(stream);
/* Note: fclose() already closes the underlying fd from fdopen() */
@@ -227,7 +228,7 @@ static int sr_generic_cb(sr_session_ctx_t *session, uint32_t, const char *model,
err = ly_add_yanger_data(ctx, parent, yanger_args);
if (err)
ERROR("Error adding yanger data");
ERROR("Error adding yanger data for xpath: %s", xpath);
sr_release_context(con);
+1 -3
View File
@@ -110,15 +110,13 @@
}
},
"infix-system:dns-resolver": {
"options": {},
"server": [
{
"address": "192.168.2.1",
"origin": "dhcp",
"interface": "e7"
}
],
"search": []
]
},
"clock": {
"boot-datetime": "2026-01-02T20:42:11+00:00",