Conditions¶
Conditions are the typed status entries in status.conditions of a CAPTF object. Each has a type, a status (True, False or Unknown), a machine-readable reason and a human-readable message. The type says what is being tracked, the status says how it stands, and the reason says why. This page lists every type and every reason CAPTF sets. To go from a stuck object to the right fix, start with Troubleshooting conditions, which adds the likely cause of each reason.
Five kinds carry conditions: TerraformCluster, TerraformMachine, TerraformMachinePool, TerraformMachineTemplate and TerraformClusterIdentity. Below, “all three” means the first three. The per-kind pages list which types each kind sets: TerraformCluster, TerraformMachine, TerraformMachinePool and TerraformClusterIdentity.
Read conditions¶
Ready is the only condition Cluster API reads. Cluster API mirrors it into InfrastructureReady on the owning Cluster, Machine or MachinePool. Every other type is informational: it explains why Ready is what it is, and nothing outside CAPTF acts on it.
List every condition of an object with jsonpath:
kubectl get terraformcluster -n <namespace> <name> \
-o jsonpath='{range .status.conditions[*]}{.type}{"\t"}{.status}{"\t"}{.reason}{"\t"}{.message}{"\n"}{end}'
kubectl describe prints the same list under Conditions:, with the events below it. To see the whole Cluster API tree, with each object’s Ready and the reason it is not ready, run clusterctl describe cluster <name>. See Observability for how conditions surface in events and metrics.
Most types follow normal polarity: True is healthy and False is a problem. Three types have negative polarity, where True is the problem or the unwanted state: Deleting, DriftDetected and DeletionBlocked. Paused is a state rather than a health reading: True means paused. A type that has no reason for Unknown is never Unknown. A type that is absent has not been set yet. In the Ready summary an absent input counts as Unknown, except Deleting.
Waiting is Unknown, not False
Waiting for a lease, for another object or for an approval sets Unknown. A wait never turns Ready False, and it never counts toward retry backoff.
Summary¶
| Type | Carried by | Polarity | Meaning |
|---|---|---|---|
Ready | All three, and TerraformClusterIdentity | Normal | Summary of the object’s other conditions. The one Cluster API reads. |
DependenciesReady | All three | Normal | The owner, cluster, exports, bootstrap data and variable sources the object waits for exist. |
IdentityAllowed | All three | Normal | The identity exists, allows the namespace and has its Secret. |
CredentialsMirrored | All three | Normal | The identity’s credentials are copied into the namespace for the Jobs. |
RunnerRBACReady | All three | Normal | The runner ServiceAccount and its RoleBinding exist. |
ApplyJobSucceeded | All three | Normal | Outcome of the newest apply or destroy, and why one waits or cannot start. |
StateReadable | All three | Normal | The Terraform state can be read. |
RestoreJobSucceeded | All three | Normal | Outcome of a state restore you requested. |
OutputsValid | All three | Normal | The module’s outputs satisfy the contract. |
InfrastructureHealthy | All three | Normal | The health the module reports. |
DriftJobSucceeded | All three | Normal | Outcome of the newest refresh or drift Job. |
DriftDetected | All three | Negative | The last drift check found differences. |
DeletionBlocked | TerraformCluster | Negative | A deleting cluster waits for its machines and pools. |
EndpointAvailable | TerraformCluster | Normal | A valid control-plane endpoint is known. |
AutoscalingActive | TerraformMachinePool | Normal | The module owns the pool’s desired count. |
CapacityResolved | TerraformMachineTemplate | Normal | Capacity and node info were read from the image’s labels. |
Paused | All three | State | The object or its Cluster is paused. |
Deleting | All three | Negative | The object is being deleted. |
Ready¶
Carried by TerraformCluster, TerraformMachine, TerraformMachinePool and TerraformClusterIdentity. Polarity: normal.
Ready summarizes other conditions; see Ready summarization for which. True means every input is True. False means at least one input is False, and Unknown means none is False but at least one is Unknown. The message names the inputs that decide it, and the input’s own reason, such as Provisioning, appears there, not in Ready’s reason. A TerraformClusterIdentity does not summarize: it sets Ready from whether its credentials Secret exists.
| Status | Reason | Meaning |
|---|---|---|
True | Ready | Every input is healthy. Nothing to do. |
True | SecretFound | Identity only: the Secret named by spec.secretRef exists. |
False | NotReady | An input is False. Read the message, then the named condition below. |
False | SecretNotFound | Identity only: the Secret does not exist, and objects that use the identity start no Job until it does. See the identity runbook. |
Unknown | ReadyUnknown | No input is False, but one is Unknown: the object waits for its owner, a first apply, a lease or an approval. Usually transient. |
DependenciesReady¶
Carried by all three. Polarity: normal.
The gates that must open before CAPTF renders inputs or starts a Job: the owner, the Cluster, the cluster’s infrastructure and exports, bootstrap data and variable sources. While a gate is closed, nothing is rendered or run. A deleting object skips the owner gates, so its destroy still runs.
| Status | Reason | Meaning |
|---|---|---|
True | DependenciesReady | Every gate is open. |
False | ClusterNotTerraform | The owning Cluster’s infrastructureRef is not a TerraformCluster. Nothing is rendered or run. Point the Cluster at a TerraformCluster, or move the object to the right one. |
False | OwnerMismatch | An ownerReference of the expected kind resolves to an object that does not reference this one back: a wrong or missing infrastructureRef, a UID mismatch, or a cluster.x-k8s.io/cluster-name label that disagrees with the owner. CAPTF treats the reference as forged or stale, so the object has no valid owner, no Job runs and nothing is written to the named owner or its Cluster. The message says which check failed. |
False | OwnerNotFound | The owner object is gone. Delete this object if it is orphaned. See deletion order. |
False | VariablesInvalid | A variablesFrom source has a key that is not a Terraform identifier or is reserved, or a value that is not UTF-8 or, for format json, not valid JSON. The message names the key, never the value. No Job starts until you correct the source. See module variables. |
False | VariablesSourceNotFound | A ConfigMap or Secret named in spec.variablesFrom, not marked optional, is missing or lacks the captf.io/variables=true label. No Job starts. See module variables. |
False | WaitingForOwnerMachine | A fresh TerraformMachine has only a non-controller control-plane ownerReference and no Machine one yet. Wait for Cluster API to set it. |
False | WaitingForOwnerMachinePool | A TerraformMachinePool has ownerReferences but none to a MachinePool yet. Wait for Cluster API to set it. |
Unknown | WaitingForOwner | The owner is not set yet. Wait, and check the object’s cluster.x-k8s.io/cluster-name label. |
Unknown | WaitingForClusterInfrastructure | The TerraformCluster is not provisioned yet. Read its ApplyJobSucceeded and Ready. |
Unknown | WaitingForClusterExports | The cluster module’s exports output is not readable. Check the TerraformCluster’s StateReadable and OutputsValid. |
Unknown | WaitingForBootstrapData | The Machine’s or MachinePool’s bootstrap data Secret is not set or not found. The bootstrap provider creates it, not CAPTF. See control planes. |
IdentityAllowed¶
Carried by all three. Polarity: normal.
Whether the resolved TerraformClusterIdentity exists, allows this namespace and has its credentials Secret. While it is not True, no Job starts, except that a deletion that needs no Job still finishes. See Identities and the identity runbook.
| Status | Reason | Meaning |
|---|---|---|
True | IdentityAllowed | The identity exists, allows the namespace and its Secret exists. |
False | IdentityNotFound | No identity resolved: none is set on the object or the cluster defaults, or the named one does not exist. Fix. |
False | NamespaceNotAllowed | The identity’s allowedNamespaces excludes this namespace. CAPTF revokes the mirror. Fix. |
False | SecretNotFound | The identity allows the namespace but its credentials Secret does not exist. Fix. |
Unknown | IdentityCheckFailed | CAPTF could not finish the check, for example because an API read failed. It usually clears by itself. Fix. |
CredentialsMirrored¶
Carried by all three. Polarity: normal.
Whether the identity’s credentials are copied into the object’s namespace as the mirror Secret that its Jobs mount.
| Status | Reason | Meaning |
|---|---|---|
True | Mirrored | The mirror exists and is current. |
False | MirrorFailed | Creating or updating the mirror failed, for example because a Secret with the mirror’s name belongs to something else. Fix. |
Unknown | MirrorPending | No mirror exists yet, either before the first mirror or because IdentityAllowed is not True. Fix that first. Details. |
RunnerRBACReady¶
Carried by all three. Polarity: normal. Never Unknown; until the controller first reaches it, the condition is absent and counts as Unknown in Ready.
Whether the runner ServiceAccount exists and is bound to the runner role in the object’s namespace. See RBAC.
| Status | Reason | Meaning |
|---|---|---|
True | RBACReady | The ServiceAccount and RoleBinding are in place. |
False | RBACFailed | Creating the ServiceAccount or the captf-runner RoleBinding failed, for example because a RoleBinding with that name is not CAPTF’s. Fix. |
False | ServiceAccountNotOptedIn | An override ServiceAccount lacks the captf.io/runner=true label. Label it, create it or drop the override; the controller retries every 30 seconds. Fix. |
ApplyJobSucceeded¶
Carried by all three. Polarity: normal.
The outcome of the newest apply, plan or destroy Job, and the reason one waits or cannot start. A plan Job stands for the apply it plans. After one has completed the status is not Unknown, except while the next operation waits for a lease or an approval. A running apply keeps the last result. The three lease reasons are shared with DriftJobSucceeded and RestoreJobSucceeded. To diagnose a failure, read status.lastRun and the Job’s pod logs; see Failing Jobs.
| Status | Reason | Meaning |
|---|---|---|
True | ApplySucceeded | The newest apply succeeded. |
True | DestroySucceeded | The destroy succeeded and cleanup follows. |
False | ApplyFailed | An apply Job failed, or disappeared while it ran because it was deleted before it finished. The message names the Job and the failed step. The controller retries with backoff. After a Job vanished, an apply of the current inputs stays due until one succeeds; this message outranks an older blocked or plan-changed apply. See retries. |
False | DestroyFailed | A destroy Job failed, or a destroy cannot be rendered because the durable inputs Secret is missing. It retries until it succeeds. If it cannot, see stuck destroy. |
False | DestructivePlanBlocked | An apply stopped before a plan that deletes or replaces resources, and no approval names it. On a TerraformCluster, which includes a drift remediation, the captf.io/approve-destructive-plan annotation does not name the inputs hash it renders, and no apply of that hash runs until it does or the inputs change. On a TerraformMachinePool, it is an apply of a change of the cluster’s exports that stopped, and the annotation does not name its approval hash (the inputs hash without bootstrap_data). The reason stays while the change waits. The pool keeps applying everything else with the exports of its last successful apply, and the condition reports that apply, True, again once the change is approved, or the exports change or return to the applied ones. A pool that cannot fall back to those exports waits for approval as a cluster does, and the message says why. See the destructive-plan guard. |
False | IdentityNotAllowed | No Job could be created because the identity does not allow the namespace or is gone. Allow the namespace again, or abandon a deleting object. |
False | ImageInvalid | The runner reported an image-layout error: no /captf/module or a non-executable command. Rebuild the image to the image contract. |
False | ImagePullFailed | The pod stayed in ErrImagePull or ImagePullBackOff past activeDeadlineSeconds. See image pull failures. |
False | InputsTooLarge | The rendered root module and variables exceed what a Secret can carry, so no Job starts. See size limits. |
False | JobDeadlineExceeded | The Job hit activeDeadlineSeconds. See deadlines. |
False | JobPolicyInvalid | The effective job policy, the object’s own merged over the cluster defaults and the built-in defaults, gives a lockTimeoutSeconds that is not below activeDeadlineSeconds, so no Job starts. See the merged-policy check. |
Unknown | NoApplyYet | No apply has completed yet. Check DependenciesReady, IdentityAllowed and the Jobs. |
Unknown | PlanAwaitingApproval | A TerraformCluster with applyPolicy: Manual waits for approval of the plan in status.plan, through the captf.io/approve-plan annotation naming its hash. See manual approval. |
Unknown | PlanChanged | An approved apply planned other changes than the approved plan and stopped before applying them. The new plan in status.plan waits for approval. See manual approval. |
Unknown | WaitingForClusterOperation | A machine’s or pool’s apply or destroy waits for its TerraformCluster’s to finish. |
Unknown | WaitingForMachineOperations | A TerraformCluster’s apply or destroy waits for the applies and destroys of its machines and pools in flight. New ones wait behind it. |
Unknown | WaitingForRunLease | Another live Job, such as one another manager instance started, holds the object’s run lease. No Job starts until it finishes. Never delete a Lease by hand. See leases. |
StateReadable¶
Carried by all three. Polarity: normal.
Whether CAPTF can read the object’s Terraform state from its backend Secrets. While it is False, no Job runs, and a deleting object’s deletion is held, except for StateLocked. See unreadable state and State.
| Status | Reason | Meaning |
|---|---|---|
True | StateRead | The state was read. |
False | StateCorrupt | The state cannot be decoded. Restore a backup taken before the damage. Fix. |
False | StateEncrypted | The state carries OpenTofu client-side encryption, which CAPTF does not support in v1. Fix. |
False | StateInconsistent | The state chunks disagree and do not form one complete state. Fix. |
False | StateLocked | Something other than the object’s own runner, such as a workstation, holds the state lock. Every Job waits lockTimeoutSeconds for it and then fails. See the stale-lock runbook. |
False | StateLost | The state Secret of an object that applied before is missing, or carries no inputs hash for an immutable kind. An object counts as having applied if it is provisioned, marked applied, digest-pinned or backed up on its own Secrets, which survive a clusterctl move. No Job runs until you restore the state. A deleting object keeps its finalizer until you restore it with captf.io/restore-state or abandon the infrastructure with captf.io/abandon-infrastructure. Fix. |
Unknown | StateNotFound | No state exists yet. The first apply creates it. Details. |
RestoreJobSucceeded¶
Carried by all three. Polarity: normal. Set only once you request a restore with the captf.io/restore-state annotation. Never feeds Ready.
The outcome of the newest state restore Job. A requested serial without a backup, or a restore that waits for a lease, is reported here too. See state restore.
| Status | Reason | Meaning |
|---|---|---|
True | StateRestored | The restore Job pushed the backup into the backend. |
False | RestoreBackupNotFound | The annotation names no existing backup, or is not a serial. No Job starts. Pick a serial from status.stateBackups. |
False | RestoreFailed | The restore Job failed. CAPTF does not retry it for the same serial, in status.lastRestoredSerial. To retry, remove the annotation, wait for lastRestoredSerial to clear and set it again. |
Unknown | WaitingForClusterOperation | A machine’s or pool’s restore waits for its TerraformCluster’s operation to finish. |
Unknown | WaitingForMachineOperations | A TerraformCluster’s restore waits for the operations of its machines and pools in flight. |
Unknown | WaitingForRunLease | Another live Job holds the object’s run lease. No Job starts until it finishes. |
OutputsValid¶
Carried by all three. Polarity: normal.
Whether the module’s outputs, read from state, satisfy the contract for the object’s role and the Cluster API field markers. See the module contract.
| Status | Reason | Meaning |
|---|---|---|
True | OutputsValid | The outputs are valid. |
True | InstancesTruncated | A pool’s instances output had more entries than the controller keeps, and CAPTF shortened it. The pool still provisions and nothing else about its outputs is invalid. See the MachinePool role. |
False | FailureDomainMismatch | A machine’s failure_domain output differs from the failure domain it requested. |
False | OutputsInvalid | An output violates the contract or a Cluster API marker. The message names it. |
False | OutputsMissing | A required output is not declared. Check the module with tfcapi-lint. |
False | ProviderIDChanged | provider_id changed after it was first written. It is immutable. Delete the Machine to replace the instance. |
Unknown | OutputsPending | Required outputs are null, so the first apply has not produced them yet. |
InfrastructureHealthy¶
Carried by all three. Polarity: normal.
The health the module reports, read from state at each refresh. After provisioning it is the input that moves Ready. See Drift and health.
| Status | Reason | Meaning |
|---|---|---|
True | Healthy | The health state is running and healthy. |
False | InstanceDegraded | The module reports degraded. |
False | InstancePending | The module reports pending. Refresh runs on a doubling schedule up to five minutes. |
False | InstanceStopped | The module reports stopped. |
False | InstanceTerminated | The module reports terminated, or the instance vanished. See terminated instances. |
False | InstanceUnhealthy | The state is running but healthy is false. |
False | Provisioning | The first apply started and the object is not provisioned yet. This starts the clock for a MachineHealthCheck. |
Unknown | HealthUnknown | The module reports unknown, an unrecognized state or no health at all. |
Unknown | ProviderIDMissing | provider_id turned null after provisioning, for the first time. CAPTF reports the instance terminated only if the next sample is null too. |
Unknown | WaitingForProvisioning | Before the first apply. |
To replace an unhealthy machine, see machine remediation.
DriftJobSucceeded¶
Carried by all three. Polarity: normal. Never feeds Ready.
The outcome of the newest refresh or drift Job. See Drift.
| Status | Reason | Meaning |
|---|---|---|
True | DriftChecked | The newest refresh or drift Job succeeded. |
False | DriftJobDeadlineExceeded | The drift Job hit activeDeadlineSeconds. Raise the deadline. |
False | DriftJobFailed | The drift Job failed. The check retries with backoff. Read the Job’s logs. |
Unknown | DriftJobRunning | A drift Job runs. |
Unknown | DriftNotChecked | No drift check has completed, or drift checks are disabled. |
Unknown | DurableInputsMissing | A refresh or drift Job is due but has nothing to run against: the durable inputs Secret captf-inputs-<kindshort>-<name> is gone, and the object renders no current inputs in its place (a TerraformMachine, which is immutable, never does). No refresh or drift check runs until you restore the Secret, so InfrastructureHealthy keeps its last reading and drift goes unchecked. |
Unknown | WaitingForRunLease | A refresh or drift Job waits for the object’s run lease, which another live Job holds. |
DriftDetected¶
Carried by all three. Polarity: negative. Never feeds Ready.
Whether the last drift check found the infrastructure differing from the desired inputs. True is the problem. See Drift.
| Status | Reason | Meaning |
|---|---|---|
True | DriftPending | Remediation is pending, or a cluster re-apply failed. The message names a failed, blocked or changed remediation Job. See the remediation cap. |
True | DriftRemediating | A remediation apply runs. |
True | DriftReported | The drift action is Report, so CAPTF reports the drift and changes nothing. Accept it or set the action to Remediate; see Remediate drift. |
False | NoDrift | The last check found no drift. |
Unknown | DriftNotChecked | No drift check has completed. CAPTF sets this on the first visit. |
DeletionBlocked¶
Carried by TerraformCluster. Polarity: negative. Never feeds Ready.
Whether a deleting TerraformCluster waits for dependents. CAPTF sets it on the first visit as False.
| Status | Reason | Meaning |
|---|---|---|
True | DependentsExist | TerraformMachines or TerraformMachinePools of the cluster still exist, so no destroy runs. The message names them. See the cluster waits for its machines. |
False | NotBlocked | Nothing blocks the deletion. |
EndpointAvailable¶
Carried by TerraformCluster. Polarity: normal. Never feeds Ready. Not set before the cluster is provisioned.
Whether a valid control-plane endpoint is known. See the cluster role.
| Status | Reason | Meaning |
|---|---|---|
True | EndpointAvailable | A valid endpoint exists. |
False | WaitingForEndpoint | The cluster is provisioned, and neither the module’s control_plane_endpoint output nor Cluster.spec.controlPlaneEndpoint has a valid endpoint. Output one from the module or set it on the Cluster. |
AutoscalingActive¶
Carried by TerraformMachinePool. Polarity: normal. Never Unknown. Never feeds Ready, and Cluster API does not mirror it to the MachinePool.
Whether the pool’s autoscaler annotations are present and valid, so the module owns the desired count. See Machine pools.
| Status | Reason | Meaning |
|---|---|---|
True | ReplicasManagedByModule | Both annotations are present and valid, and the controller writes the observed replicas back to MachinePool.spec.replicas. |
False | AutoscalingAnnotationsInvalid | An annotation is present but the pair is incomplete, unparsable or has min above max. The message names the problem. The pool still applies without autoscaling. |
False | AutoscalingDisabled | Neither annotation is set. MachinePool.spec.replicas is the only source of desired capacity. |
False | ReplicasManagedExternally | Both annotations are valid, but the MachinePool’s cluster.x-k8s.io/replicas-managed-by annotation names another controller. CAPTF does not write the observed replicas back, so the two controllers do not fight over spec.replicas. Choose one owner. |
CapacityResolved¶
Carried by TerraformMachineTemplate, which has no Ready condition. Polarity: normal. Never Unknown.
Whether the template’s capacity and node info were read from the module image’s labels. See Templates.
| Status | Reason | Meaning |
|---|---|---|
True | CapacityNotDeclared | The image carries neither label. Fine unless a ClusterClass autoscaler needs the capacity. |
True | CapacityResolved | Both labels parsed. |
False | CapacityLabelInvalid | A label is present but invalid. Fix the label in the image; see the image contract. |
False | ImageInspectFailed | The registry fetch or authentication failed. Fix the image reference or the credentials. The controller also emits a Warning event. |
Paused¶
Carried by all three. Polarity: a state, not a health reading. Never Unknown. Never feeds Ready.
Whether reconciliation is paused. A paused object does bookkeeping only and starts no Job. CAPTF sets it on the first visit.
| Status | Reason | Meaning |
|---|---|---|
True | Paused | The object or its Cluster is paused: spec.paused on the Cluster, or the cluster.x-k8s.io/paused annotation on the object. clusterctl move pauses on purpose. A deletion waits until you unpause; see pause stops a deletion. |
False | NotPaused | The object is not paused. |
Deleting¶
Carried by all three. Polarity: negative. Never Unknown.
Whether the object is being deleted. True makes Ready False. The message can say what the destroy waits for. CAPTF sets it on the first visit.
| Status | Reason | Meaning |
|---|---|---|
True | Deleting | The deletionTimestamp is set and no more specific reason applies. Wait for the destroy. If the object does not delete, follow my object will not delete. |
False | NotDeleting | The deletionTimestamp is not set. |
Ready summarization¶
Ready is built with the Cluster API SetSummaryCondition helper from the inputs below. Which inputs it uses depends on the kind and on whether status.initialization.provisioned has latched True; it latches once and stays. Deleting has negative polarity, so True there makes Ready False.
Before provisioning, all three kinds summarize the same nine inputs:
DependenciesReadyIdentityAllowedCredentialsMirroredRunnerRBACReadyApplyJobSucceededStateReadableOutputsValidInfrastructureHealthyDeleting
After provisioning, the inputs differ per kind:
| Kind | Inputs after provisioning |
|---|---|
TerraformCluster | InfrastructureHealthy, Deleting |
TerraformMachine | InfrastructureHealthy, Deleting |
TerraformMachinePool | InfrastructureHealthy, ApplyJobSucceeded, Deleting |
A failed re-apply does not flip a cluster’s or machine’s Ready
After provisioning, a TerraformCluster’s Ready ignores ApplyJobSucceeded. If it did not, a failed re-apply would flip the Cluster’s InfrastructureReady and suspend every MachineHealthCheck of the cluster. A TerraformMachine is immutable and behaves the same. A TerraformMachinePool is mutable and re-applied regularly, so a failed re-apply shows in its Ready.
These types never feed Ready: Paused, DriftDetected, DriftJobSucceeded, DeletionBlocked, EndpointAvailable, RestoreJobSucceeded and AutoscalingActive. An input that has not been set yet counts as Unknown, so a new object is Ready: Unknown, never True. Only Deleting is ignored while missing. Ready’s reason is always Ready, NotReady or ReadyUnknown.
A TerraformClusterIdentity does not summarize. It sets its own Ready from whether its credentials Secret exists (SecretFound or SecretNotFound).