Firstlume Docs firstlume.io ENPT PT Talk to us

Runs and approval

A run is one plan, apply, destroy or drift execution of a stack. Each phase runs in its own Kubernetes Job, and the apply executes exactly what the plan produced.

Run lifecycle

queued ─▶ planning ─┬─▶ no_changes                       (no changes)
                    ├─▶ planned                          (type=plan)
                    ├─▶ awaiting_approval ─┬─▶ apply_queued ─▶ applying ─▶ applied
                    │                      └─▶ discarded
                    ├─▶ apply_queued                     (approval not required)
                    └─▶ drifted                          (type=drift)
any running phase ─▶ failed  |  queued/apply_queued ─▶ canceled

Start a run with its type:

curl -s -H "$H" $O/stacks/$ST/runs -d '{"type": "plan"}'

The types are plan, apply, destroy and drift. See Your first run for how $H, $O and $ST are set.

Queue and lock

Only one run at a time executes or waits for approval on each stack. The others wait in a queue, in order of arrival. The UI shows every active run in the organization on all screens, with runs waiting for approval highlighted.

Apply runs what was planned

The plan records the commit SHA and the plan file, encrypted in the database. The apply checks out that commit and applies that file. It also uses the plan's variables and the config.yaml from that commit. Changing a folder's variables between plan and apply has no effect on this run.

If the state changed after the plan, Terraform itself refuses the saved plan and the run fails, so plan again.

Review the changes

From the plan's structured output, Firstlume lists the changes by resource:

curl -s -H "$H" $O/runs/$RUN/changes | jq .

The run page groups them in this order, with a count per group:

  1. Will be deleted
  2. Will be replaced
  3. Will be updated
  4. Will be created

Each item shows the address, the type and the attributes that change. A replacement shows which attribute forces it, and the summary counts replacements apart: 1 delete · 1 replace · 2 update · 2 create. Values marked sensitive appear as (sensitive) and never reach the API or the UI. With Terragrunt run --all, each change also names its unit.

The full log stays available in the Logs view, live.

Approval

Approval is an inherited setting, require_approval, and it is required by default. Set it at the organization, on a folder or on a stack, in the UI or through the settings API. The rule is read when the plan finishes.

curl -s -X POST -H "$H" $O/runs/$RUN/approve -d '{"acknowledged": []}'
curl -s -X POST -H "$H" $O/runs/$RUN/discard

Today any member of the organization can approve. Approvers by person or group are planned.

Confirm each deletion or replacement

confirm_destructive is an inherited setting, off by default. When it is on:

  • each resource that will be deleted or replaced gets a checkbox in the UI, and the approve button unlocks once all are ticked
  • the server checks too: approval is refused with a 409 if any of those addresses is missing from acknowledged
  • the confirmed addresses are recorded in the run, with who approved

Follow the apply

During and after the apply, each resource on the list shows its state:

State Meaning
pending approved, hasn't started
applying running
done finished
failed failed, with Terraform's error on the resource
not_applied the apply ended before it started, which only happens when another resource failed

A resource marked not_applied will be in the next plan. A replacement shows its two stages, in the order they ran. The states come from Terraform's machine-readable output (apply -json), while the log stays readable text. An error that belongs to no resource, such as a provider or authentication failure, becomes the run's error.

What each run shows

  • Steps: checkout, init, plan, approval, apply and so on, each with status, duration and its own log
  • Commit: author, first line of the message and a link to the commit in Git
  • Configuration used: the config.yaml from the commit, the effective settings and the variable names, each with its origin. Secrets are hidden
  • State: which backend each unit used

When runs fail

If the executor stops sending heartbeats for FIRSTLUME_HEARTBEAT_TIMEOUT (10 minutes by default, controlPlane.heartbeatTimeout in Helm), the run is marked failed. If the pod dies, for example from running out of memory or hitting its deadline, the agent reports the failure.

Canceling

Runs that are queued (queued, apply_queued) can be canceled. Canceling a running run isn't supported, on purpose: interrupting an apply can corrupt the state.