|
| 1 | +# CRD State Machines |
| 2 | + |
| 3 | +Each Burrito custom resource is driven by a state machine implemented in its |
| 4 | +reconciler (`internal/controllers/<crd>/states.go`). Burrito controllers are |
| 5 | +**level-based**: on every reconcile the controller *recomputes* the current state |
| 6 | +from a set of boolean conditions through an ordered `switch`. There are no stored |
| 7 | +transitions — a state's handler performs a side-effect (creating a `TerraformRun`, |
| 8 | +a runner pod, an annotation…), and the *next* reconcile observes the changed |
| 9 | +conditions and yields the next state. |
| 10 | + |
| 11 | +A practical consequence: some states are **transient triggers**. For example a |
| 12 | +`TerraformLayer` in `PlanNeeded` creates a run and, on the following reconcile, |
| 13 | +is seen as running and reported as `Idle` again. |
| 14 | + |
| 15 | +## TerraformRepository |
| 16 | + |
| 17 | +The repository controller keeps Git bundles in the datastore in sync with the |
| 18 | +remote. It has two states, decided by whether the last sync is too old or failed. |
| 19 | + |
| 20 | +- `Synced` — bundles are up to date; requeue at the repository sync interval. |
| 21 | +- `SyncNeeded` — fetch latest revisions per branch, store bundles, and annotate |
| 22 | + the affected layers. |
| 23 | + |
| 24 | +```mermaid |
| 25 | +stateDiagram-v2 |
| 26 | + [*] --> Synced |
| 27 | + Synced --> SyncNeeded: last sync too old / last sync failed |
| 28 | + SyncNeeded --> Synced: all branches synced successfully |
| 29 | + SyncNeeded --> SyncNeeded: sync error (requeue) |
| 30 | +``` |
| 31 | + |
| 32 | +## TerraformLayer |
| 33 | + |
| 34 | +The layer controller watches declared layers and creates `TerraformRun` resources |
| 35 | +to plan (drift detection) and, when auto-apply is enabled, to apply. The state is |
| 36 | +computed from conditions such as *is a run in flight*, *is a sync scheduled*, *is |
| 37 | +the last plan too old*, *is the last relevant commit planned*, *is the apply up to |
| 38 | +date*, and *has the last run reached its retry limit*. |
| 39 | + |
| 40 | +Because the first `switch` case is "a run is in flight → `Idle`", a layer with a |
| 41 | +running plan/apply is reported as `Idle`. `PlanNeeded` and `ApplyNeeded` are |
| 42 | +transient: their handler creates the run and the next reconcile returns to `Idle`. |
| 43 | + |
| 44 | +- `Idle` — nothing to do; requeue at the drift-detection interval. |
| 45 | +- `PlanNeeded` — create a plan `TerraformRun`. |
| 46 | +- `ApplyNeeded` — create an apply `TerraformRun` (only if auto-apply is enabled). |
| 47 | +- `MaxRetriesReached` — the last run exhausted its retries; manual intervention |
| 48 | + needed. |
| 49 | + |
| 50 | +```mermaid |
| 51 | +stateDiagram-v2 |
| 52 | + [*] --> Idle |
| 53 | + Idle --> PlanNeeded: plan outdated / new relevant commit / sync scheduled |
| 54 | + Idle --> ApplyNeeded: plan up to date but apply needed (autoApply on) |
| 55 | + PlanNeeded --> Idle: TerraformRun (plan) created — run in flight |
| 56 | + ApplyNeeded --> Idle: TerraformRun (apply) created — run in flight |
| 57 | + Idle --> MaxRetriesReached: last run exhausted its retries |
| 58 | + MaxRetriesReached --> Idle: new relevant commit / retry window reset |
| 59 | +``` |
| 60 | + |
| 61 | +## TerraformRun |
| 62 | + |
| 63 | +The run controller executes a plan or apply by creating runner pods, and handles |
| 64 | +retries with an exponential backoff grace period. `Succeeded` and `Failed` are |
| 65 | +terminal. |
| 66 | + |
| 67 | +- `Initial` — freshly created; sets the lease and launches the first runner pod. |
| 68 | +- `Running` — a runner pod is currently running. |
| 69 | +- `FailureGracePeriod` — the runner failed; wait (exponential backoff) before retry. |
| 70 | +- `Retrying` — grace period elapsed and retry limit not reached; launch a new pod. |
| 71 | +- `Succeeded` — the runner pod exited successfully (lease released). |
| 72 | +- `Failed` — retries exhausted (lease released). |
| 73 | + |
| 74 | +```mermaid |
| 75 | +stateDiagram-v2 |
| 76 | + [*] --> Initial |
| 77 | + Initial --> Running: runner pod created |
| 78 | + Running --> Succeeded: pod exited successfully |
| 79 | + Running --> FailureGracePeriod: pod failed, retry limit not reached |
| 80 | + FailureGracePeriod --> Retrying: grace period elapsed |
| 81 | + FailureGracePeriod --> Failed: retry limit reached |
| 82 | + Retrying --> Running: retry pod created |
| 83 | + Succeeded --> [*] |
| 84 | + Failed --> [*] |
| 85 | +``` |
| 86 | + |
| 87 | +## TerraformPullRequest |
| 88 | + |
| 89 | +The pull-request controller discovers layers affected by a PR/MR, waits for their |
| 90 | +plans, and posts a comment. Note that "comment up to date" is checked before |
| 91 | +"layers still planning", so a PR with an up-to-date comment is reported as `Idle`. |
| 92 | + |
| 93 | +- `DiscoveryNeeded` — a new commit was detected; (re)create the temporary layers |
| 94 | + affected by the PR. |
| 95 | +- `Planning` — the temporary layers are still planning. |
| 96 | +- `CommentNeeded` — plans finished; post/update the PR comment. |
| 97 | +- `Idle` — comment is up to date; nothing to do. |
| 98 | + |
| 99 | +```mermaid |
| 100 | +stateDiagram-v2 |
| 101 | + [*] --> DiscoveryNeeded |
| 102 | + DiscoveryNeeded --> Planning: temp layers created, commit discovered |
| 103 | + Planning --> CommentNeeded: all layers finished planning |
| 104 | + CommentNeeded --> Idle: comment posted on PR/MR |
| 105 | + Idle --> DiscoveryNeeded: new commit on the PR branch |
| 106 | +``` |
| 107 | + |
| 108 | +## How the CRDs interact |
| 109 | + |
| 110 | +The resources form a chain: the repository annotates layers with the latest |
| 111 | +relevant commit, layers create runs, runs create runner pods, and pods write plan |
| 112 | +and apply results back onto the layer's annotations. A pull request creates |
| 113 | +temporary layers and reports their plan results as a comment. |
| 114 | + |
| 115 | +```mermaid |
| 116 | +flowchart LR |
| 117 | + Repo[TerraformRepository] -->|annotates last relevant commit| Layer[TerraformLayer] |
| 118 | + Layer -->|creates on plan/apply needed| Run[TerraformRun] |
| 119 | + Run -->|creates runner| Pod[Runner Pod] |
| 120 | + Pod -->|updates plan/apply annotations| Layer |
| 121 | + PR[TerraformPullRequest] -->|creates temp layers| Layer |
| 122 | + PR -->|reads plan results, comments| Git[Git provider] |
| 123 | +``` |
0 commit comments