You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
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>
Copy file name to clipboardExpand all lines: docs/operator-manual/architecture.md
+119-2Lines changed: 119 additions & 2 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -61,11 +61,128 @@ For more details on how the repository controller works with Git bundles and rev
61
61
62
62
Each controller drives its resource through a state machine whose status is
63
63
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
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.
68
147
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.
PR -->|reads plan results, comments| Git[Git provider]
184
+
```
185
+
69
186
### The runners
70
187
71
188
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.
- Use structured logging via the `logr.Logger` carried in `ctx` (`log.FromContext(ctx)`).
16
16
- Propagate `ctx` and set timeouts on every external call (GitHub, GitLab, Terraform).
17
17
- 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.
0 commit comments