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
| Status | Description |
|---|---|
Healthy | Resource is functioning correctly |
Degraded | Resource is in a failed or error state |
Progressing | Resource is being created or rolled out |
Missing | Expected resource doesn't exist on the cluster |
Unknown | Health 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:
| Kind | Healthy | Progressing | Degraded |
|---|---|---|---|
| Deployment | readyReplicas ≥ spec.replicas | Some ready but not all (e.g. 2/5 ready) | readyReplicas = 0 with spec.replicas > 0, or ProgressDeadlineExceeded on the Deployment's Progressing condition |
| StatefulSet | Same readyReplicas rule | Partial readiness | Zero ready |
| DaemonSet | Same readyReplicas rule | Partial readiness | Zero ready |
| Job | succeeded ≥ 1 | Still running | failed > 0 |
| Pod | phase Running or Succeeded | Pending/Unknown | phase 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 > Healthystatus.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.freezeholds 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,
Readyconditions) - Ignoring specific resources from aggregation
- Health-degraded notifications via
onHealthDegraded
Related
- Sync Policies — how sync triggers work
- Configuration —
AppCRD spec - Operator Architecture — how the operator runs health checks