Skip to content

Commit f2c9f56

Browse files
nleveeclaude
andcommitted
docs: merge state machines page back into architecture.md
Inline the CRD state machine diagrams and prose into the architecture "Controller state machines" section and drop the dedicated state-machines.md page (and its nav entry). Update the controllers AGENTS.md pointer and switch the mise install task to `uv sync`. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent 0984d8b commit f2c9f56

5 files changed

Lines changed: 121 additions & 128 deletions

File tree

docs/operator-manual/architecture.md

Lines changed: 119 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,11 +61,128 @@ For more details on how the repository controller works with Git bundles and rev
6161

6262
Each controller drives its resource through a state machine whose status is
6363
expressed using the [conditions standards defined by the community](https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#typical-status-properties).
64-
For the full state machines of each CRD, the conditions that drive them, and how
65-
the resources interact, see [CRD State Machines](./state-machines.md).
64+
Burrito controllers are **level-based**: on every reconcile the controller
65+
*recomputes* the current state from a set of boolean conditions through an ordered
66+
`switch`. There are no stored transitions — a state's handler performs a
67+
side-effect (creating a `TerraformRun`, a runner pod, an annotation…), and the
68+
*next* reconcile observes the changed conditions and yields the next state.
69+
70+
A practical consequence: some states are **transient triggers**. For example a
71+
`TerraformLayer` in `PlanNeeded` creates a run and, on the following reconcile,
72+
is seen as running and reported as `Idle` again.
73+
74+
#### TerraformRepository
75+
76+
The repository controller keeps Git bundles in the datastore in sync with the
77+
remote. It has two states, decided by whether the last sync is too old or failed.
78+
79+
- `Synced` — bundles are up to date; requeue at the repository sync interval.
80+
- `SyncNeeded` — fetch latest revisions per branch, store bundles, and annotate
81+
the affected layers.
82+
83+
```mermaid
84+
stateDiagram-v2
85+
[*] --> Synced
86+
Synced --> SyncNeeded: last sync too old / last sync failed
87+
SyncNeeded --> Synced: all branches synced successfully
88+
SyncNeeded --> SyncNeeded: sync error (requeue)
89+
```
90+
91+
#### TerraformLayer
92+
93+
The layer controller watches declared layers and creates `TerraformRun` resources
94+
to plan (drift detection) and, when auto-apply is enabled, to apply. The state is
95+
computed from conditions such as *is a run in flight*, *is a sync scheduled*, *is
96+
the last plan too old*, *is the last relevant commit planned*, *is the apply up to
97+
date*, and *has the last run reached its retry limit*.
98+
99+
Because the first `switch` case is "a run is in flight → `Idle`", a layer with a
100+
running plan/apply is reported as `Idle`. `PlanNeeded` and `ApplyNeeded` are
101+
transient: their handler creates the run and the next reconcile returns to `Idle`.
102+
103+
- `Idle` — nothing to do; requeue at the drift-detection interval.
104+
- `PlanNeeded` — create a plan `TerraformRun`.
105+
- `ApplyNeeded` — create an apply `TerraformRun` (only if auto-apply is enabled).
106+
- `MaxRetriesReached` — the last run exhausted its retries; manual intervention
107+
needed.
108+
109+
```mermaid
110+
stateDiagram-v2
111+
[*] --> Idle
112+
Idle --> PlanNeeded: plan outdated / new relevant commit / sync scheduled
113+
Idle --> ApplyNeeded: plan up to date but apply needed (autoApply on)
114+
PlanNeeded --> Idle: TerraformRun (plan) created — run in flight
115+
ApplyNeeded --> Idle: TerraformRun (apply) created — run in flight
116+
Idle --> MaxRetriesReached: last run exhausted its retries
117+
MaxRetriesReached --> Idle: new relevant commit / retry window reset
118+
```
119+
120+
#### TerraformRun
121+
122+
The run controller executes a plan or apply by creating runner pods, and handles
123+
retries with an exponential backoff grace period. `Succeeded` and `Failed` are
124+
terminal.
125+
126+
- `Initial` — freshly created; sets the lease and launches the first runner pod.
127+
- `Running` — a runner pod is currently running.
128+
- `FailureGracePeriod` — the runner failed; wait (exponential backoff) before retry.
129+
- `Retrying` — grace period elapsed and retry limit not reached; launch a new pod.
130+
- `Succeeded` — the runner pod exited successfully (lease released).
131+
- `Failed` — retries exhausted (lease released).
132+
133+
```mermaid
134+
stateDiagram-v2
135+
[*] --> Initial
136+
Initial --> Running: runner pod created
137+
Running --> Succeeded: pod exited successfully
138+
Running --> FailureGracePeriod: pod failed, retry limit not reached
139+
FailureGracePeriod --> Retrying: grace period elapsed
140+
FailureGracePeriod --> Failed: retry limit reached
141+
Retrying --> Running: retry pod created
142+
Succeeded --> [*]
143+
Failed --> [*]
144+
```
66145

67146
The `TerraformRun` controller also creates and deletes the [Kubernetes leases](https://kubernetes.io/docs/concepts/architecture/leases/) to avoid concurrent use of Terraform on the same layer.
68147

148+
#### TerraformPullRequest
149+
150+
The pull-request controller discovers layers affected by a PR/MR, waits for their
151+
plans, and posts a comment. Note that "comment up to date" is checked before
152+
"layers still planning", so a PR with an up-to-date comment is reported as `Idle`.
153+
154+
- `DiscoveryNeeded` — a new commit was detected; (re)create the temporary layers
155+
affected by the PR.
156+
- `Planning` — the temporary layers are still planning.
157+
- `CommentNeeded` — plans finished; post/update the PR comment.
158+
- `Idle` — comment is up to date; nothing to do.
159+
160+
```mermaid
161+
stateDiagram-v2
162+
[*] --> DiscoveryNeeded
163+
DiscoveryNeeded --> Planning: temp layers created, commit discovered
164+
Planning --> CommentNeeded: all layers finished planning
165+
CommentNeeded --> Idle: comment posted on PR/MR
166+
Idle --> DiscoveryNeeded: new commit on the PR branch
167+
```
168+
169+
#### How the CRDs interact
170+
171+
The resources form a chain: the repository annotates layers with the latest
172+
relevant commit, layers create runs, runs create runner pods, and pods write plan
173+
and apply results back onto the layer's annotations. A pull request creates
174+
temporary layers and reports their plan results as a comment.
175+
176+
```mermaid
177+
flowchart LR
178+
Repo[TerraformRepository] -->|annotates last relevant commit| Layer[TerraformLayer]
179+
Layer -->|creates on plan/apply needed| Run[TerraformRun]
180+
Run -->|creates runner| Pod[Runner Pod]
181+
Pod -->|updates plan/apply annotations| Layer
182+
PR[TerraformPullRequest] -->|creates temp layers| Layer
183+
PR -->|reads plan results, comments| Git[Git provider]
184+
```
185+
69186
### The runners
70187

71188
The runner implementation relies on [`tenv`](https://github.com/tofuutils/tenv), a tool from the community which allows us to dynamically download and use any version of Terraform, Terragrunt or OpenTofu (coming soon). Thus, we support any existing version of Terraform.

docs/operator-manual/state-machines.md

Lines changed: 0 additions & 123 deletions
This file was deleted.

internal/controllers/AGENTS.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,4 @@ custom resource: `terraformlayer/`, `terraformrun/`, `terraformrepository/`,
1515
- Use structured logging via the `logr.Logger` carried in `ctx` (`log.FromContext(ctx)`).
1616
- Propagate `ctx` and set timeouts on every external call (GitHub, GitLab, Terraform).
1717
- CRD shapes live in `api/v1alpha1`; never edit generated deepcopy code. After API changes run `make manifests && make generate`.
18-
- **State machines are documented.** When you change a reconciler's states or transitions (its `states.go` — the `GetState` switch, state structs, or the conditions in `conditions.go` that drive them), update the matching Mermaid diagram in [`docs/operator-manual/state-machines.md`](../../docs/operator-manual/state-machines.md) so it stays in sync.
18+
- **State machines are documented.** When you change a reconciler's states or transitions (its `states.go` — the `GetState` switch, state structs, or the conditions in `conditions.go` that drive them), update the matching Mermaid diagram in the "Controller state machines" section of [`docs/operator-manual/architecture.md`](../../docs/operator-manual/architecture.md) so it stays in sync.

mise.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ _.python.venv = { path = ".venv", create = true }
2222

2323
[tasks.install]
2424
description = "Install documentation dependencies"
25-
run = "uv pip install -r requirements.txt"
25+
run = "uv sync"
2626

2727
[tasks.mkdocs-serve]
2828
depends = "install"

mkdocs.yml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,6 @@ nav:
3838
- Operator Manual:
3939
- operator-manual/index.md
4040
- operator-manual/architecture.md
41-
- operator-manual/state-machines.md
4241
- operator-manual/user-authentication.md
4342
- operator-manual/repository-controller.md
4443
- Git Authentication:

0 commit comments

Comments
 (0)