Skip to content

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.

pub

Derives: Debug, Clone, Serialize, Deserialize

Health status for a deployment object

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

pub

Derives: Debug, Clone, Default, Serialize, Deserialize

Summary of health information for a deployment

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

pub

Derives: Debug, Clone, Serialize, Deserialize

Health status of an individual resource

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

pub

Checks deployment health for Kubernetes resources

pub

fn new(k8s_client: Client) -> Self

Creates a new HealthChecker instance watching the whole cluster

Source
pub fn new(k8s_client: Client) -> Self {
Self {
k8s_client,
watch_namespace: None,
}
}

pub

fn with_watch_namespace(mut self, namespace: Option<String>) -> Self

Restricts 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
}

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))
}

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()
}

pub

Attributes pods to the Brokkr deployment object that produced them.

A pod is attributed to a deployment object when, in order:

  1. it carries the brokkr.io/deployment-object-id label (manual opt-in, the historical mechanism),
  2. it carries the key as an annotation directly (bare Pod manifests applied by Brokkr are stamped with it),
  3. 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.

pub

fn new(client: Client) -> Self

Creates an attributor bound to a Kubernetes client.

Source
pub fn new(client: Client) -> Self {
Self {
fetcher: KubeOwnerFetcher {
client,
discovery: None,
},
cache: HashMap::new(),
}
}

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,
}
}

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
}

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()
}

pub

Derives: Debug, Clone, Serialize, Deserialize

Request body for sending health status updates to the broker

Name Type Description
deployment_objects Vec<DeploymentObjectHealthUpdate> List of deployment object health updates

pub

Derives: Debug, Clone, Serialize, Deserialize

Health update for a single deployment object (matches broker API)

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