Core Concepts

Health Checks

How Wardn evaluates resource health after sync

Health Checks

After applying manifests, Wardn checks the health of each managed resource on the destination cluster. Health aggregates to the app level and surfaces in status.healthStatus, the API, and the UI.

Health States

StatusDescription
HealthyResource is functioning correctly
DegradedResource is in a failed or error state
ProgressingResource is being created or rolled out
MissingExpected resource doesn't exist on the cluster
UnknownHealth can't be determined (e.g. the GET itself errored)

Per-Resource Health Checks

The checker (operator/internal/health) has real logic for five kinds — everything else (Service, ConfigMap, Secret, Ingress, CRDs, ...) reports Healthy as long as it exists:

KindHealthyProgressingDegraded
DeploymentreadyReplicas ≥ spec.replicasSome ready but not all (e.g. 2/5 ready)readyReplicas = 0 with spec.replicas > 0, or ProgressDeadlineExceeded on the Deployment's Progressing condition
StatefulSetSame readyReplicas rulePartial readinessZero ready
DaemonSetSame readyReplicas rulePartial readinessZero ready
Jobsucceeded ≥ 1Still runningfailed > 0
Podphase Running or SucceededPending/Unknownphase Failed
Anything else✅ by default——

📋 Planned — there's no per-kind logic for Service (clusterIP/LB ingress), Ingress, or CRDs (e.g. a Ready condition check), and no CrashLoopBackOff/ImagePullBackOff detection inside workload checks yet. Those failures surface as Progressing (not-ready replicas), not Degraded.

A resource that doesn't exist on the destination cluster reports Missing.

Application-Level Health

The aggregate is the worst per-resource status, in this precedence order:

Degraded  >  Missing  >  Progressing  >  Unknown  >  Healthy

status.healthReason carries the first non-healthy resource's message (e.g. "Deployment api: 2/5 ready").

Viewing Health Status

# kubectl
kubectl get app my-app -n org-my-org -o jsonpath='{.status.healthStatus}'
kubectl get app my-app -n org-my-org -o jsonpath='{.status.healthReason}'

# API
curl -b cookies.txt http://localhost:8080/api/v1/apps/default/my-app | jq '.health'
curl -b cookies.txt "http://localhost:8080/api/v1/apps/default/my-app/status" | jq '.health_reason'

The dashboard shows health badges for each app and resource.

When Health Is Evaluated

  • After every apply inside the reconcile loop
  • On every periodic resync (~60s) — even when spec.freeze holds syncs, health keeps updating
  • After consumed operations (sync, deploy, restart, approve)

📋 notifications.onHealthDegraded exists in the CRD but the dispatcher never reads it — health transitions don't send Slack notifications yet.

Planned

  • Custom health rules per resource type
  • Service/Ingress/CRD-aware checks (LB ingress assigned, Ready conditions)
  • Ignoring specific resources from aggregation
  • Health-degraded notifications via onHealthDegraded

On this page