Argo CD health checks
Without a custom health check, Argo CD reports every Migration as Healthy as soon as it applies.
This Lua health check maps the conditions to Argo CD's health states.
A failed migration then shows as Degraded in the UI and in notifications.
Add it to the argocd-cm ConfigMap, or to the equivalent resource.customizations block in your Argo CD Helm values:
apiVersion: v1
kind: ConfigMap
metadata:
name: argocd-cm
namespace: argocd
data:
resource.customizations.health.pgcopydb-operator.io_Migration: |
local hs = {}
hs.status = "Progressing"
hs.message = "no status yet"
if obj.status == nil then
return hs
end
if obj.status.phase == "Suspended" then
hs.status = "Suspended"
hs.message = "spec.suspend is set; work volume kept"
return hs
end
if obj.status.conditions ~= nil then
for _, c in ipairs(obj.status.conditions) do
if c.type == "Failed" and c.status == "True" then
hs.status = "Degraded"
hs.message = c.reason .. ": " .. c.message
return hs
end
if c.type == "Complete" and c.status == "True" then
hs.status = "Healthy"
hs.message = c.message
return hs
end
end
end
if obj.status.phase ~= nil then
hs.message = "phase: " .. obj.status.phase
end
return hs
The mapping:
Failed=TrueisDegraded.Complete=TrueisHealthy.- Phase
SuspendedisSuspended. - Everything else is
Progressing, with the current phase in the message.
Both terminal conditions are absorbing, so the health state settles once.
A passed dry run sets Complete=True with reason DryRunSucceeded, so it shows Healthy as well.
Match that reason in the Lua if you need to tell the two apart.
A verification mismatch does not set Failed, so a migration with Verified=False still reports Healthy.
Alert on Verified separately.
A live migration at CutoverPending stays Progressing here until you approve the cutover.
If you alert on stuck progress, give that phase its own mapping.
Extend the Lua with the condition reasons.
One caveat for GitOps-managed migrations: spec.cutover.approved: true is a timed action, and writes to the source must already be stopped when it lands.
Flipping it through a Git commit works, but mind your sync latency; kubectl patch at the moment of cutover gives you exact timing.