Release a stale state lock
Make sure an OpenTofu state lock is stale, then release it and plan the root again.
Use this runbook when a tofu plan or tofu apply comment on a pull request fails with a lock error, and the Atlantis pod that took the lock is gone. Atlantis holds a state lock for the length of a plan or apply. A pod killed mid-command leaves the lock behind, because the gcs backend sets no lock TTL.
warning
This runbook deletes a GCS lock object by hand. It is an exception to the GitOps rule because a lock object has no expiry, and only a delete releases it. Run it only when the owner asks, and only after you rule out a command that still runs.
Before you start#
- Read the lock's
ID,PathandCreatedtime from the "Lock Info" block in the pull request comment where the plan or apply failed. - Your Google account needs object delete rights on the state bucket that the root's
backend "gcs"block names in itsversions.tf. A root whose backend block also setsimpersonate_service_account, such asterraform/gcp/projects/bluenose, needs you to impersonate that account too. - Run
gcloud auth loginif you have not signed in interactively.
Release the lock#
Get the start time of the Atlantis pod.
kubectl --context offsite -n atlantis get pod atlantis-0 -o jsonpath='{.status.startTime}'Result: the pod's start time, in UTC.
If the lock's
Createdtime is before the pod's start time, a pod that is gone took the lock, and it is stale. IfCreatedis at or after the start time, the running pod may still hold it; stop, and read its logs instead.Check the pod for a running
tofuprocess.kubectl --context offsite -n atlantis exec atlantis-0 -c atlantis -- ps -eo pid,etime,argsResult: the process list.
If a
tofucommand appears, wait for it to finish. Do not release the lock while atofuprocess runs.
note
OpenTofu's gcs backend uses the lock object's generation number as its ID. tofu force-unlock deletes the object with that generation as a precondition, and the next step reproduces the same delete without a local tofu init.
Release the lock.
gcloud storage rm <path> --if-generation-match=<ID>Result: no output.
Ask Atlantis to plan the root again.
atlantis plan -d <root>Result: a new
Ran Plan forcomment on the pull request.
If something goes wrong#
| Symptom | Cause | Action |
|---|---|---|
gcloud storage rm fails with 412 conditionNotMet. | A newer lock replaced the one you read; the generation changed. | Read the Lock Info from the latest failed comment, and start over. |
Related#
- Apply an OpenTofu change: the normal path for a root change.
- OpenTofu and Atlantis: the roots, the state and the Atlantis server.
Linked from 3
- Apply an OpenTofu changeChange an OpenTofu root, check it on your machine, and apply it through Atlantis on the pull request.
- RunbooksStep-by-step procedures for the hosts, clusters, network, secrets and apps, grouped by area.
- Rebuild a cluster on TalosReplace a cluster's NixOS nodes with Talos Linux, bootstrap a fresh etcd, install Cilium and Flux, and restore the data that has a backup.