Plan Approval¶
TerraformCluster guards two things before it changes infrastructure: a plan that deletes or replaces a resource waits for an approval, and with spec.applyPolicy: Manual every plan waits for one. This page is the how-to: the commands to review and approve. How the gates work, what the plan hash binds and what they do not cover are in the chapter Approvals and Gates.
Before you begin
- A
TerraformClusterwhose apply you want to guard or preview. kubectlaccess to annotate it and to read the logs of its Jobs. Anyone who can patch the object can approve; see who can approve.
The destructive-plan guard¶
Under the default applyPolicy: Automatic, every TerraformCluster apply, including a drift remediation, plans first and stops before applying if the plan deletes or replaces a resource. Nothing changes. ApplyJobSucceeded turns False/DestructivePlanBlocked and its message names the affected resources and the inputs hash. See The destructive-plan guard for the full behavior.
To approve:
- Read the plan:
kubectl logs job/<job> -n <namespace> -c source. The condition message lists what it deletes or replaces. -
Approve the inputs hash named in the condition:
kubectl annotate terraformcluster <name> -n <namespace> \ captf.io/approve-destructive-plan=<inputs-hash> --overwrite<name>and<namespace>are theTerraformCluster’s;<inputs-hash>is the hash from the condition message.
The approval covers exactly those inputs
The next change produces a new hash and is guarded again. The controller removes the annotation after the approved apply succeeds. lifecycle { prevent_destroy = true } in the module remains the stronger control for a resource that must never be replaced.
Plan preview: applyPolicy Manual¶
Set spec.applyPolicy: Manual on the TerraformCluster or its TerraformClusterTemplate to review every change except the first apply. Switching back to Automatic applies whatever was waiting.
- A change plans first.
ApplyJobSucceededbecomesUnknown/PlanAwaitingApprovalandstatus.planfills in. Nothing applies. -
Review
status.plan(counts, and up to 50 resources with their actions) and the plan Job’s log, which has the human-readable plan: -
Approve by naming the plan hash,
status.plan.planHash: -
The apply plans again and applies only if the new plan has the same hash. If anything changed, it stops with
PlanChangedand a new plan to approve. See Manual plan approval. - After the approved apply succeeds, the controller removes the annotation, clears
status.planand emitsPlanApplied.
Approving a plan also approves its deletes and replacements
captf.io/approve-destructive-plan is not needed under Manual. A plan with no changes needs no approval. A plan that only changes outputs, or only imports or moves, does.
Caveats¶
- The plan hash binds what each change does, including old and new values, so a plan with different values needs its own approval. It reveals no value; read values in the plan Job’s log. See What the plan hash binds.
- An approval is consumed only when the approved apply succeeds. A stale one can approve a later plan with the same hash. Remove it with
kubectl annotate terraformcluster <name> -n <namespace> captf.io/approve-plan-. - Hashes start with
p2:. After an upgrade from a release withp1:hashes, a waiting plan is planned again and needs a new approval. status.planis status, not durable state: afterclusterctl movethe controller plans again, and an approval still on the annotation applies if the new plan hashes the same.- In a GitOps setup, the annotation is set by a person, or by a pipeline after its own review of
status.planand the plan Job’s log. Do not keep it in Git: a controller that syncs annotations from Git would re-add a consumed approval.
What is not guarded¶
Neither gate applies to a TerraformMachine, and a TerraformMachinePool is guarded only when its apply renders a changed set of cluster exports (see Machine pools). Destroy, restore, refresh and drift Jobs are never gated. See Approvals and Gates and Limits.
Confirm it worked¶
- After approving a destructive plan,
kubectl describe terraformcluster <name> -n <namespace>showsApplyJobSucceededback toTrueand thecaptf.io/approve-destructive-planannotation gone. - After approving a plan under
Manual,status.planis empty andApplyJobSucceededisTrue/ApplySucceeded.