# Pods Panel, CalVer Versioning & Cluster Resources Fix **Date**: 2026-03-04 **Status**: Approved ## 1. CalVer Auto-Versioning **Scheme**: `YYYY.MM.PIPELINE_IID` (e.g. `2026.03.408`) ### Flow 1. CI compile jobs compute `FOXHUNT_VERSION` from `CI_COMMIT_TIMESTAMP` year.month + `CI_PIPELINE_IID` 2. Passed to rustc via `FOXHUNT_BUILD_VERSION` env var 3. `common/src/build_info.rs` exposes `pub fn version() -> &'static str` using `option_env!("FOXHUNT_BUILD_VERSION").unwrap_or(env!("CARGO_PKG_VERSION"))` 4. Each service populates `ServiceStatus.version` from `build_info::version()` 5. fxt shows version in TUI header bar and Services cockpit column ### Files changed - `.gitlab-ci.yml`: compute + export `FOXHUNT_BUILD_VERSION` in compile jobs (~10 lines) - `crates/common/src/build_info.rs`: new module, `version()` function - `crates/common/src/lib.rs`: re-export `build_info` - `services/api_gateway/src/grpc/monitoring_handler.rs`: populate `version` field from `build_info::version()` - All 7 service `main.rs` files: log version at startup - `bin/fxt/src/tui/cockpits/overview.rs`: show fxt version in header ## 2. Pods Cockpit (Key 7) ### Proto New streaming RPC in `monitoring.proto`: ```protobuf rpc SubscribeClusterPods(SubscribeClusterPodsRequest) returns (stream ClusterPodsResponse); message SubscribeClusterPodsRequest { uint32 interval_seconds = 1; // default 5 } message ClusterPodsResponse { repeated PodInfo pods = 1; int64 timestamp = 2; } message PodInfo { string name = 1; string service = 2; // app.kubernetes.io/name label string status = 3; // Running/Pending/CrashLoopBackOff/Completed/etc int32 restarts = 4; string age = 5; string node = 6; float cpu_millicores = 7; // from metrics-server (0 if unavailable) float memory_mb = 8; // from metrics-server (0 if unavailable) bool ready = 9; string version = 10; // from FOXHUNT_BUILD_VERSION env or image tag } ``` ### api_gateway implementation - Add `kube` crate dependency (K8s client library for Rust) - New `pods_handler.rs` module: list/watch pods in `foxhunt` namespace via K8s API - Extracts `app.kubernetes.io/name` label as service grouping key - Streams pod state every 5s (default interval) - Pod CPU/memory from metrics-server API (`/apis/metrics.k8s.io/v1beta1/namespaces/foxhunt/pods`) ### TUI cockpit - New `cockpits/pods.rs` as 7th cockpit (key 7) - **Default view**: service-grouped summary rows (`api-gateway: 1/1 Running, v2026.03.408`) - **Expanded view**: Tab/Enter on a service row expands to show individual pod rows with name, restarts, age, node, CPU/mem - Navigation: Up/Down to select service, Enter to expand/collapse ### NetworkPolicy - `api-gateway.yaml`: add egress to K8s API (`172.16.0.0/16:6443`) for pod listing ### RBAC - New Role + RoleBinding granting api_gateway SA `get`/`list`/`watch` on pods in foxhunt namespace ## 3. Cluster Resources Fix ### Root cause `monitoring_handler.rs:372-375` hardcodes `cpu_percent: 0.0, memory_used_mb: 0.0, memory_total_mb: 0.0` with comment "not yet scraped". ### Fix Query Prometheus for node-exporter metrics: - CPU: `sum(rate(node_cpu_seconds_total{mode!="idle"}[2m])) / count(node_cpu_seconds_total{mode="idle"}) * 100` - RAM used: `sum(node_memory_MemTotal_bytes - node_memory_MemAvailable_bytes) / 1024 / 1024` - RAM total: `sum(node_memory_MemTotal_bytes) / 1024 / 1024` ### Pre-requisite Prometheus NetworkPolicy needs egress to node IPs on port 9100 (node-exporter). Currently these targets are DOWN due to missing egress rule. Add `ipBlock: 172.16.0.0/16` port 9100 to prometheus NetworkPolicy. ## Dependencies - Prometheus networking fixes (completed 2026-03-04): Service selector, NetworkPolicy, api_gateway egress - node-exporter egress fix (part of this work) - `kube` crate added to api_gateway