State backend
Firstlume is the state backend of your stacks. It uses the http backend of Terraform and OpenTofu, with no plugin. Your code declares the backend, and Firstlume fills in the address and the credential on each run.
terraform {
backend "http" {}
}
In every run, the executor exports TF_HTTP_ADDRESS, TF_HTTP_LOCK_ADDRESS, TF_HTTP_UNLOCK_ADDRESS, TF_HTTP_USERNAME and TF_HTTP_PASSWORD, so nothing about the backend appears in your code.
With Terragrunt
In Terragrunt, each unit has its own state. The root.hcl builds each unit's address from FIRSTLUME_STATE_URL:
remote_state {
backend = "http"
generate = { path = "backend.tf", if_exists = "overwrite_terragrunt" }
config = {
address = "${get_env("FIRSTLUME_STATE_URL")}/${path_relative_to_include()}"
lock_address = "${get_env("FIRSTLUME_STATE_URL")}/${path_relative_to_include()}"
unlock_address = "${get_env("FIRSTLUME_STATE_URL")}/${path_relative_to_include()}"
}
}
A unit's key is its relative path, such as net or zone-a/node01. A plain Terraform stack has a single state at the root.
How it behaves
- Lock per unit. In a
run --all, each unit writes its state when its own apply finishes. If one unit fails, the others stay saved. - Plan doesn't write. The credential of the plan phase, and of drift, can only read and lock the state. Only the apply writes.
- Versions. Each write becomes an immutable version, encrypted with a key of its own. Writes that would lose state (a lower serial, or the lineage of another infrastructure) are refused.
- A run's locks are released when the phase ends, however it ends.
- A stack with resources in its state can't be deleted. Run a destroy or delete the state first, with
DELETE /api/v1/orgs/{org}/stacks/{id}/stateand the stack's name in the body as{"confirm": "<name>"}. Deleted state is kept for 30 days.
Code with no backend fails at Init. Its state would stay on the runner's disk and be lost. With
run --all, where Terragrunt initializes units during the plan, it fails at the end of the Plan step. The message names the unit.
Code with another backend keeps working. With
s3, for example, Firstlume's variables are ignored and the state stays where your code puts it.
More on state
- Where state lives: Postgres or an S3 bucket, chosen at installation
- The organization's bucket: an organization's own bucket
- State-only tokens: use this backend from outside Firstlume's runs
- Import existing state and Migrate a pipeline
The State tab in the UI, with versions, diff, rollback and forced unlock, is planned. Today the run page shows the backend each unit used, and the stack's Resources tab lists what is in the current state, with no attribute values.