How-to guide / Author packages and clusters
Declare readiness for custom resources
Use a readiness declaration when a custom resource’s controller does not set a
standard Ready or Available condition. Declare the controller’s convention
on the CRD or CRD reference, then create resources through its typed builder:
21 widgetCrd = scope.mkCRD (22 scope.crd.fromKind "Widget" { spec.group = "widgets.example.com"; }23 // {24 readiness = {25 path = "/status/phase";26 equals = "Ready";27 };28 }29 );30
31 widget = self.widgetCrd.out.mkCR scope {32 name = "example";33 spec.size = "small";34 };path is a JSON pointer into the live custom resource. equals is the string
value that indicates readiness. In this example, Kix waits until
status.phase is Ready.
A controller that reports a condition instead of a plain status field takes the condition form:
1readiness = {2 condition = {3 type = "Bootstrapped";4 status = "True";5 };6};Kix then waits until status.conditions holds an entry with that type and
status. Use this form for operators such as StackGres (Bootstrapped) and
for Gateway API kinds (Accepted on a GatewayClass, Programmed on a
Gateway), which never set Ready or Available.
Keep this declaration in the package that owns or imports the CRD. Every custom
resource created through widgetCrd.out.mkCR then receives the same readiness
rule, along with its dependency on the CRD.
Declare the states that mean failure
Section titled “Declare the states that mean failure”Some controllers report that they reject a resource: Cilium sets Valid=False
on a network policy whose rules it cannot apply. Such a resource never becomes
ready until its spec changes, so waiting for it only delays the failure. List
those states in failed beside the ready rule, and kix deploy stops waiting
as soon as the controller reports one:
1readiness = {2 condition = {3 type = "Valid";4 status = "True";5 };6 failed = [7 {8 condition = {9 type = "Valid";10 status = "False";11 };12 }13 ];14};A failed entry is a condition (type, status, and an optional reason
that narrows the match) or a status field (path and equals, for a
controller that reports a phase such as Failed). Declare only states the
controller does not leave on its own. A Ready=False that the controller
retries, or a Pending while it waits for something else, is not one of
them: declaring it would fail deploys that would have succeeded.
A condition entry is read as the controller’s verdict on the spec, and the
failure message says to change the object. A path entry is read as a
runtime outcome, such as a backup that failed or a storage claim that was
lost, unless it sets rejected = true. Give a runtime outcome a hint that
says what to do next, and name in message the status fields to quote (one
JSON pointer or a list):
1failed = [2 {3 path = "/status/phase";4 equals = "FailedValidation";5 rejected = true;6 message = "/status/validationErrors";7 }8 {9 path = "/status/phase";10 equals = "Failed";11 message = "/status/failureReason";12 hint = "Velero does not run a failed backup again. Fix the cause shown in its status, then create the backup again under a new name.";13 }14];Kix trusts such a state once it knows the controller has seen the current
spec. It checks, in this order: the condition’s observedGeneration (or
status.observedGeneration) has reached metadata.generation; or, when the
controller reports no generation, the condition’s lastTransitionTime is
later than the moment this deploy applied the object (a state that changed
before the apply is the verdict on the previous spec, and Kix keeps waiting
for a new one); or, when the status carries neither field (a phase such as
status.phase = "Failed"), the state has held for ten seconds of polling. An
object the deploy left unchanged needs no such check. One case falls through
these checks: an object edited from one invalid spec to another may keep its
old transition time, because the condition did not change. Kix then waits
until the readiness timeout, and the timeout message still shows the current
reason. The failure message quotes the controller’s condition, reason, and
message, or the status fields the entry names, and ends with what to do next.
Check the generated custom resource
Section titled “Check the generated custom resource”Build the cluster as JSON and inspect the custom resource. The output excerpt shows the readiness annotation Kix generated from the declaration:
❱ kix build how-to-composition --output json
{
"apiVersion": "widgets.example.com/v1",
"kind": "Widget",
"metadata": {
"name": "example",
"annotations": {
"kix.run/readiness": "{\"equals\":\"Ready\",\"path\":\"/status/phase\"}"
}
},
"spec": {
"size": "small"
}
} Run the normal pre-deploy checks as well:
❱ kix check how-to-composition During deployment, Kix reads the live object at the declared path and waits for the expected value. Make the path match the status field written by the controller, including its exact capitalization.