Enhanced Status Detection
Before proceeding to the next apply wave — or declaring the whole set
reconciled — the reconciler must decide whether each dependent object has reached a
ready state. The check is performed by a status.StatusAnalyzer, which
you can override via ReconcilerOptions.StatusAnalyzer; when left unset, an optimized
kstatus-based analyzer is used. It is built on the
kstatus library, but
with important enhancements.
How vanilla kstatus works
For most resources (some built-in types have special logic), kstatus applies roughly the following algorithm.
Step 1 — observedGeneration check:
Does the object have status.observedGeneration?
→ Yes: Does status.observedGeneration equal metadata.generation?
→ Yes: proceed to the ready-condition check
→ No: object is NOT ready (generation mismatch)
→ No: proceed to the ready-condition check
Step 2 — ready-condition check:
Does the object have status.conditions[type == "Ready"]?
→ Yes: Is condition.status == "True"?
→ Yes: object is READY
→ No (False or Unknown): object is NOT ready
→ No: object is READY (absence of a Ready condition means "implicitly ready")
This works well for controllers that set status.observedGeneration and
status.conditions reliably and eagerly — ideally the object is born with an
impossible observedGeneration (e.g. -1), which the controller then updates together
with its conditions on every reconcile.
Why that is not sufficient
Real-world controllers frequently violate those assumptions, and vanilla kstatus then produces false positives — reporting an object ready when it is not:
- A controller may not set
status.observedGenerationimmediately after the object is created, leaving it absent for a short window. kstatus then skips the generation check and may observe a previous, outdated, state of theReadycondition. - A controller may set a
Readycondition lazily. kstatus interprets the absentReadycondition as “implicitly ready”. - A controller may never set a
Readycondition at all, using other condition types to signal readiness instead. kstatus interprets the absentReadycondition as “implicitly ready”.
For a framework that gates whole waves on readiness, such false positives are dangerous: subsequent waves could start against prerequisites that are not actually up.
How the framework enhances it
The framework lets you supply per-object status hints through the
…/status-hint annotation (prefix = reconciler name), which tighten the analysis:
has-observed-generation
Treat the object as having a status.observedGeneration field even if it is not yet
set. This forces the generation check for controllers that set the field lazily,
closing the window in which kstatus would otherwise skip it.
metadata:
annotations:
mycomponent-operator.mydomain.io/status-hint: has-observed-generation
has-ready-condition
Require a Ready condition. If it is absent, the object is treated as Unknown (not
ready) instead of “implicitly ready”.
metadata:
annotations:
mycomponent-operator.mydomain.io/status-hint: has-ready-condition
conditions=<list>
A semicolon-separated list of additional condition types that must all be present and
have status True for the object to count as ready.
metadata:
annotations:
mycomponent-operator.mydomain.io/status-hint: "conditions=Synced;Healthy"
Combining hints
Hints are combined as a comma-separated list:
metadata:
annotations:
mycomponent-operator.mydomain.io/status-hint: "has-observed-generation,has-ready-condition,conditions=Synced;Healthy"
See also
- Apply and Delete Waves — readiness is what gates progression between waves.
- Dependent Objects — the annotation reference, including
status-hint.