Course outline

Argo CD / Automation, lifecycle, and trust / Lesson 10

Custom resource health as a versioned contract

Interpret status conditions and observed generation without making missing evidence healthy.

About 4 min readContent reviewed
On this page

Lesson goals

  • Explain the role and limits of custom Lua health assessment.
  • Design fixtures for stale, missing, progressing, and explicitly failed observations.

A custom kind needs domain meaning

A custom resource can expose status fields whose meaning belongs to its controller and API version. Argo CD cannot infer every business readiness contract from a field named Ready. ParcelPolicy is a synthetic kind whose controller is assumed to publish observedGeneration and a ready boolean for this lesson only. Real conditions may have different names, states, reasons, and transition rules. Review the actual CRD and controller documentation before writing health logic. A generic always-Healthy rule hides uncertainty and can release dependent work before the required state exists.

Current intent and old observations can differ

metadata.generation can identify a desired-spec generation, while a controller may report which generation its status reflects. A ready observation for an older generation may describe yesterday’s intent. The exact contract is kind-specific; do not assume every API implements observedGeneration identically. Missing status, delayed reconciliation, explicit failure, and successful current reconciliation need distinct handling. Health assessment should be bounded and should not query external systems or perform mutation as a side effect of merely reading status.

Read a limited illustrative health function

The Lua snippet below returns Progressing until the synthetic current-generation contract is met, then Healthy when ready is true. It is not installed in Argo CD and does not define a universal custom-resource policy. Release-3.1 custom checks receive obj and return supported status and optional message fields under documented configuration. Standard-library access is restricted by default under that model. Enabling broader libraries is not a prerequisite for this simple field check and should not be used as an indiscriminate fix.

lua An illustrative ParcelPolicy health script
local hs = { status = "Progressing", message = "Awaiting current observation" }
if obj.status ~= nil and obj.metadata ~= nil then
  if obj.status.observedGeneration == obj.metadata.generation then
    if obj.status.ready == true then
      hs.status = "Healthy"
      hs.message = "Current synthetic readiness observed"
    end
  end
end
return hs

This is specific to the declared synthetic fields and is not executed or configured. A real kind needs explicit failure and missing-generation decisions and representative fixtures; the snippet is not a complete general health customization.

Test one invariant in a separate local model

The complete Python model below rejects stale and absent observations before accepting current readiness. It models a declared invariant, not Lua evaluation, Argo CD aggregation, or Kubernetes controller behavior. Passing these cases does not prove that the Lua snippet is correct for a real CRD. Actual customization tests need the supported platform or project tooling in a separately authorized suitable environment. Retain fixtures for explicit failure, no status, old generation, false readiness, and current true readiness so future controller changes cannot silently weaken the contract.

python A synthetic current-observation invariant
def ready(generation, status):
    return bool(status is not None and status.get("observedGeneration") == generation and status.get("ready") is True)
print(ready(4, None))
print(ready(4, {"observedGeneration": 3, "ready": True}))
print(ready(4, {"observedGeneration": 4, "ready": True}))
Expected output
False
False
True

Only local dictionaries are evaluated. This does not execute Lua, validate an Argo CD customization, or observe a custom controller.

Health rules can change release behavior

A health customization can override existing assessment and influence later waves or application summaries. Treat its source and configuration as reviewed delivery code. Keep status messages useful and free of sensitive payloads. Avoid a massive wildcard script that guesses many unrelated kinds. If a controller changes its API or condition semantics, review the health rule and fixtures together. User-level verification still remains separate: even correct resource readiness may not establish that label creation and external carrier behavior satisfy the release promise.

Common errors and fixes

Missing custom status is returned as Healthy.

Why it happens
Absence of failure was confused with positive current evidence.
How to fix it
Represent waiting or unknown behavior explicitly under the supported health contract.
Prevent it next time
Test missing, stale, false, and failed observations.

A Ready result from an older generation permits dependent work.

Why it happens
Observation freshness was omitted from the kind’s declared readiness rule.
How to fix it
Check the controller’s generation contract before accepting readiness.
Prevent it next time
Version fixtures with CRD and controller semantics.

One wildcard health script assumes every custom kind has identical fields.

Why it happens
Different APIs are collapsed into an unverified universal rule.
How to fix it
Use small kind-specific reviewed logic and representative fixtures.
Prevent it next time
Assign ownership and review override scope.

Check your understanding

1. The synthetic status says ready=true for generation three while metadata generation is four. What does the local model decide?

Show worked solution

It returns false because the observation does not describe current intent. This is the declared synthetic rule, not a universal Kubernetes condition rule. Inspect the actual controller’s contract before applying equivalent logic to a real kind.

2. Does a passing Python invariant test establish a successful Lua customization on Argo CD?

Show worked solution

No. It verifies only the local Python behavior and expected values. Lua syntax, supported configuration, aggregation, and actual controller status need their own appropriate authorized validation. Keep the evidence claim at the level actually tested.

Key takeaways

  • Health depends on kind-specific current evidence.
  • Custom health logic is reviewed delivery behavior, not cosmetic status formatting.

Official references