From a73302a4f5615f76cea05820f1adbc81bf7983ab Mon Sep 17 00:00:00 2001 From: Brad Stein Date: Thu, 29 Jan 2026 14:54:42 -0300 Subject: [PATCH] snapshot: enrich node load and capacity --- atlasbot/snapshot/builder.py | 38 ++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/atlasbot/snapshot/builder.py b/atlasbot/snapshot/builder.py index a6edddb..f02e2bf 100644 --- a/atlasbot/snapshot/builder.py +++ b/atlasbot/snapshot/builder.py @@ -674,6 +674,21 @@ def _append_node_pods(lines: list[str], summary: dict[str, Any]) -> None: (item for item in node_pods if isinstance(item, dict)), key=lambda item: (-int(item.get("pods_total") or 0), item.get("node") or ""), )[:8] + max_entry = None + for entry in node_pods: + if not isinstance(entry, dict): + continue + pods_total = entry.get("pods_total") + try: + pods_value = int(pods_total) + except (TypeError, ValueError): + continue + if max_entry is None or pods_value > max_entry["pods_total"]: + max_entry = { + "node": entry.get("node"), + "pods_total": pods_value, + "namespaces_top": entry.get("namespaces_top") or [], + } parts = [] for item in top: node = item.get("node") @@ -689,6 +704,15 @@ def _append_node_pods(lines: list[str], summary: dict[str, Any]) -> None: parts.append(label) if parts: lines.append("node_pods_top: " + "; ".join(parts)) + if max_entry and isinstance(max_entry.get("node"), str): + ns_label = "" + namespaces = max_entry.get("namespaces_top") or [] + if namespaces: + ns_label = ", ".join([f"{name}={count}" for name, count in namespaces]) + label = f"{max_entry.get('node')}={max_entry.get('pods_total')}" + if ns_label: + label = f"{label} ({ns_label})" + lines.append("node_pods_max: " + label) def _append_pod_issues(lines: list[str], summary: dict[str, Any]) -> None: @@ -1297,6 +1321,8 @@ def _append_node_load_summary(lines: list[str], summary: dict[str, Any]) -> None node_load = summary.get("node_load_summary") if not isinstance(node_load, dict) or not node_load: return + hardware_by_node = summary.get("hardware_by_node") + hardware_by_node = hardware_by_node if isinstance(hardware_by_node, dict) else {} top = node_load.get("top") if isinstance(top, list) and top: parts = [] @@ -1311,6 +1337,8 @@ def _append_node_load_summary(lines: list[str], summary: dict[str, Any]) -> None net = entry.get("net") pods_total = entry.get("pods_total") label = f"{node} idx={_format_float(load)}" + if node and node in hardware_by_node: + label += f" hw={hardware_by_node.get(node)}" if isinstance(pods_total, (int, float)): label += f" pods={int(pods_total)}" label += f" cpu={_format_float(cpu)} ram={_format_float(ram)}" @@ -1382,6 +1410,16 @@ def _append_namespace_capacity_summary(lines: list[str], summary: dict[str, Any] mem_over = cap.get("mem_overcommitted") if cpu_over is not None or mem_over is not None: lines.append(f"namespace_overcommitted: cpu={cpu_over} mem={mem_over}") + cpu_over_names = cap.get("cpu_overcommitted_names") + if isinstance(cpu_over_names, list) and cpu_over_names: + names = [name for name in cpu_over_names if isinstance(name, str) and name] + if names: + lines.append("namespace_cpu_overcommitted_names: " + _format_names(names)) + mem_over_names = cap.get("mem_overcommitted_names") + if isinstance(mem_over_names, list) and mem_over_names: + names = [name for name in mem_over_names if isinstance(name, str) and name] + if names: + lines.append("namespace_mem_overcommitted_names: " + _format_names(names)) def _append_workloads_by_namespace(lines: list[str], summary: dict[str, Any]) -> None: