brokkr-agent::deployment_health
Rust
Deployment Health Checker Module
Monitors the health of deployed Kubernetes resources and reports status to the broker. Detects common issues like ImagePullBackOff, CrashLoopBackOff, OOMKilled, and other problematic conditions.
Structs
Section titled “Structs”struct DeploymentHealthStatus
Section titled “struct DeploymentHealthStatus”pub
Derives: Debug, Clone, Serialize, Deserialize
Health status for a deployment object
Fields
Section titled “Fields”| Name | Type | Description |
|---|---|---|
id |
Uuid |
The deployment object ID |
status |
String |
Overall health status: healthy, degraded, failing, unknown |
summary |
HealthSummary |
Structured health summary |
checked_at |
DateTime<Utc> |
When the health was checked |
struct HealthSummary
Section titled “struct HealthSummary”pub
Derives: Debug, Clone, Default, Serialize, Deserialize
Summary of health information for a deployment
Fields
Section titled “Fields”| Name | Type | Description |
|---|---|---|
pods_ready |
usize |
Number of pods in ready state |
pods_total |
usize |
Total number of pods |
conditions |
Vec<String> |
List of detected problematic conditions |
resources |
Vec<ResourceHealth> |
Per-resource health details |
struct ResourceHealth
Section titled “struct ResourceHealth”pub
Derives: Debug, Clone, Serialize, Deserialize
Health status of an individual resource
Fields
Section titled “Fields”| Name | Type | Description |
|---|---|---|
kind |
String |
Kind of the resource (e.g., “Pod”, “Deployment”) |
name |
String |
Name of the resource |
namespace |
String |
Namespace of the resource |
ready |
bool |
Whether the resource is ready |
message |
Option<String> |
Human-readable status message |
struct HealthChecker
Section titled “struct HealthChecker”pub
Checks deployment health for Kubernetes resources
Methods
Section titled “Methods”pub
fn new(k8s_client: Client) -> SelfCreates a new HealthChecker instance watching the whole cluster
Source
pub fn new(k8s_client: Client) -> Self { Self { k8s_client, watch_namespace: None, } }with_watch_namespace
Section titled “with_watch_namespace”pub
fn with_watch_namespace(mut self, namespace: Option<String>) -> SelfRestricts pod discovery to a single namespace when namespace is Some (for namespace-scoped RBAC deployments).
Source
pub fn with_watch_namespace(mut self, namespace: Option<String>) -> Self { self.watch_namespace = namespace; self }check_deployment_object
Section titled “check_deployment_object”pub async
async fn check_deployment_object( &self, deployment_object_id: Uuid,) -> Result<DeploymentHealthStatus, Box<dyn std::error::Error + Send + Sync>>Checks the health of a specific deployment object by ID.
Source
pub async fn check_deployment_object( &self, deployment_object_id: Uuid, ) -> Result<DeploymentHealthStatus, Box<dyn std::error::Error + Send + Sync>> { let mut grouped = self.discover_pods(&[deployment_object_id]).await?; let pods = grouped.remove(&deployment_object_id).unwrap_or_default(); Ok(self.analyze_pods(deployment_object_id, &pods)) }check_deployment_objects
Section titled “check_deployment_objects”pub async
async fn check_deployment_objects( &self, deployment_object_ids: &[Uuid],) -> Vec<DeploymentHealthStatus>Checks health for multiple deployment objects with one cluster-wide pod-discovery pass.
Source
pub async fn check_deployment_objects( &self, deployment_object_ids: &[Uuid], ) -> Vec<DeploymentHealthStatus> { let grouped = match self.discover_pods(deployment_object_ids).await { Ok(grouped) => grouped, Err(e) => { warn!("Failed to discover pods for health checking: {}", e); // Report everything as unknown on discovery error return deployment_object_ids .iter() .map(|&id| DeploymentHealthStatus { id, status: "unknown".to_string(), summary: HealthSummary::default(), checked_at: Utc::now(), }) .collect(); } };
deployment_object_ids .iter() .map(|&id| { let pods = grouped.get(&id).map(|v| v.as_slice()).unwrap_or(&[]); self.analyze_pods(id, pods) }) .collect() }struct PodAttributor
Section titled “struct PodAttributor”pub
Attributes pods to the Brokkr deployment object that produced them.
A pod is attributed to a deployment object when, in order:
- it carries the
brokkr.io/deployment-object-idlabel (manual opt-in, the historical mechanism), - it carries the key as an annotation directly (bare
Podmanifests applied by Brokkr are stamped with it), - an object in its ownerReference chain carries the annotation — pods created by controllers (Deployment→ReplicaSet→Pod, Job→Pod, StatefulSet/DaemonSet→Pod) resolve to the Brokkr-applied top-level object (BROKKR-T-0191).
Step 3 is the case that matters in practice: Brokkr stamps the key as an annotation on the top-level applied object only and never injects it into pod templates, so neither a label selector nor a direct annotation match finds the pods of a Deployment/StatefulSet/Job. Both continuous health checking and on-demand diagnostics resolve pods through this type so the two always agree on what belongs to a deployment object (BROKKR-T-0299).
One instance corresponds to one discovery pass: API discovery is built lazily on first owner walk and owner-chain results (including misses) are memoized, so pods sharing a ReplicaSet cost a single lookup.
Methods
Section titled “Methods”pub
fn new(client: Client) -> SelfCreates an attributor bound to a Kubernetes client.
Source
pub fn new(client: Client) -> Self { Self { fetcher: KubeOwnerFetcher { client, discovery: None, }, cache: HashMap::new(), } }deployment_object_of
Section titled “deployment_object_of”pub async
async fn deployment_object_of(&mut self, pod: &Pod) -> Option<Uuid>Resolves the deployment object a single pod belongs to, if any.
Source
pub async fn deployment_object_of(&mut self, pod: &Pod) -> Option<Uuid> { match pod_direct_doid(pod) { Some(id) => Some(id), None => resolve_owner_doid(&mut self.fetcher, pod, &mut self.cache).await, } }group_by_deployment_object
Section titled “group_by_deployment_object”pub async
async fn group_by_deployment_object( &mut self, pods: impl IntoIterator<Item = Pod>, wanted: &HashSet<Uuid>,) -> HashMap<Uuid, Vec<Pod>>Groups pods by the deployment object they belong to, keeping only the ids in wanted. Pods that resolve to nothing are dropped.
Source
pub async fn group_by_deployment_object( &mut self, pods: impl IntoIterator<Item = Pod>, wanted: &HashSet<Uuid>, ) -> HashMap<Uuid, Vec<Pod>> { let mut grouped: HashMap<Uuid, Vec<Pod>> = HashMap::new(); for pod in pods { if let Some(id) = self.deployment_object_of(&pod).await && wanted.contains(&id) { grouped.entry(id).or_default().push(pod); } } grouped }pods_for
Section titled “pods_for”pub async
async fn pods_for( &mut self, pods: impl IntoIterator<Item = Pod>, deployment_object_id: Uuid,) -> Vec<Pod>Returns the subset of pods belonging to one deployment object.
Source
pub async fn pods_for( &mut self, pods: impl IntoIterator<Item = Pod>, deployment_object_id: Uuid, ) -> Vec<Pod> { let wanted: HashSet<Uuid> = HashSet::from([deployment_object_id]); self.group_by_deployment_object(pods, &wanted) .await .remove(&deployment_object_id) .unwrap_or_default() }struct HealthStatusUpdate
Section titled “struct HealthStatusUpdate”pub
Derives: Debug, Clone, Serialize, Deserialize
Request body for sending health status updates to the broker
Fields
Section titled “Fields”| Name | Type | Description |
|---|---|---|
deployment_objects |
Vec<DeploymentObjectHealthUpdate> |
List of deployment object health updates |
struct DeploymentObjectHealthUpdate
Section titled “struct DeploymentObjectHealthUpdate”pub
Derives: Debug, Clone, Serialize, Deserialize
Health update for a single deployment object (matches broker API)
Fields
Section titled “Fields”| Name | Type | Description |
|---|---|---|
id |
Uuid |
The deployment object ID |
status |
String |
Health status: healthy, degraded, failing, or unknown |
summary |
Option<HealthSummary> |
Structured health summary |
checked_at |
DateTime<Utc> |
When the health was checked |