Skip to content

Commit 016c19f

Browse files
committed
New error_chain() helper flattens the error source() chain. Idempotency sweep across the code base to make sure 409 tend to OK.
Signed-off-by: Erick Bourgeois <erick@jeb.ca>
1 parent a34abfa commit 016c19f

6 files changed

Lines changed: 420 additions & 218 deletions

File tree

.claude/CHANGELOG.md

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,103 @@ The format is based on the regulated environment requirements:
99

1010
---
1111

12+
## [2026-06-24 10:30] - Idempotency sweep: 409 AlreadyExists / duplicate finalizers no longer Error the ScheduledMachine
13+
14+
**Author:** Erick Bourgeois
15+
16+
### Changed
17+
- `src/reconcilers/helpers.rs` (`create_dynamic_resource`): treat a `409 AlreadyExists`
18+
from `api.create(...)` as success instead of propagating it. The bootstrap config,
19+
infrastructure object, and CAPI Machine are all created through this helper; a prior
20+
reconcile having created them IS the desired state.
21+
- `src/reconcilers/helpers.rs` (`add_finalizer`): only append our finalizer if it isn't
22+
already present — a double-call can no longer write a duplicate (which would wedge GC).
23+
- `src/reconcilers/helpers_tests.rs`: +3 unit tests (create 409 → Ok; create 500 still
24+
propagates; add_finalizer writes exactly one copy).
25+
- Audited the rest of the codebase for idempotency and confirmed it already holds: the
26+
only other `.create()` is a `SelfSubjectAccessReview` (a virtual auth check, never
27+
409s); all `.delete()` sites swallow 404; the kata ConfigMap uses `Patch::Apply` (SSA);
28+
Events go through the kube `recorder`; status/spec writes use `Patch::Merge`/`Apply`.
29+
30+
### Why
31+
On every reconcile after the first, `add_machine_to_cluster` re-issues the create and
32+
got `409 AlreadyExists` (e.g. `k0sworkerconfigs "…" already exists`). That bubbled up as
33+
`MachineCreationFailed`, flipping the ScheduledMachine into the **Error** phase — which
34+
skips ALL Active-phase work, including node-taint reconciliation. On the k0smotron
35+
workshop tier this presented as **Flag 1 (worker joins) passing but Flag 2 (the Node
36+
carries the spot taint) never happening**: the SM was wedged in Error, so it never ran
37+
`handle_active_phase`. Idempotent create is standard controller behavior and fixes it.
38+
39+
### Impact
40+
- [ ] Breaking change
41+
- [x] Requires cluster rollout
42+
- [ ] Config change only
43+
- [ ] Documentation only
44+
45+
## [2026-06-24 03:10] - Fix Mermaid flow diagrams broken by special characters
46+
47+
**Author:** Erick Bourgeois
48+
49+
### Changed
50+
- `docs/architecture/calm/architecture.json`: escaped Mermaid-hostile characters in
51+
three flow transition descriptions using Mermaid entity codes (which render as the
52+
literal characters):
53+
- `flow-emergency-reclaim` t1: `reclaim-requested="true"``reclaim-requested=#quot;true#quot;`.
54+
The embedded double quotes terminated the Mermaid label string early, causing a parse
55+
error that left the **Emergency Reclaim** diagram blank on the docs site.
56+
- `flow-kata-config-delivery` t2: `/etc/5spot/kata-config/<key>``…/#lt;key#gt;`.
57+
- `flow-kata-config-delivery` t5: `restart <restartService>``restart #lt;restartService#gt;`.
58+
Raw `<…>` placeholders were parsed as HTML tags and silently dropped from the rendered label.
59+
- `docs/src/architecture/flows.md`: regenerated via `make calm-diagrams` (auto-generated;
60+
not hand-edited).
61+
- `docs/src/concepts/kata-config-delivery.md`: hand-written `sequenceDiagram` — replaced a
62+
`;` with `,` inside a `Note over Agent,Host: …` label. Mermaid treats `;` as a statement
63+
separator even inside note text, so it split the note mid-string and failed the whole
64+
diagram to parse.
65+
66+
### Why
67+
The `flows.md.hbs` template emits transition descriptions verbatim into `flowchart` node
68+
labels (`t1["…"]`). Mermaid cannot contain an unescaped `"` inside a quoted label, and
69+
treats `<…>` as HTML — so these characters either broke parsing (Emergency Reclaim) or
70+
ate label text (Kata Config Delivery). Fixing at the source-of-truth `architecture.json`
71+
keeps the diagrams correct after every regeneration. The `phase -> …` arrows in other
72+
flows contain only `>` and render fine, so they were left unchanged.
73+
74+
### Impact
75+
- [ ] Breaking change
76+
- [ ] Requires cluster rollout
77+
- [ ] Config change only
78+
- [x] Documentation only
79+
80+
---
81+
82+
## [2026-06-24 02:30] - Surface the real cause of child-cluster connection failures (error_chain)
83+
84+
**Author:** Erick Bourgeois
85+
86+
### Changed
87+
- `src/reconcilers/helpers.rs`: new `error_chain(&dyn Error)` helper that flattens an
88+
error's `source()` chain into one string, and wired it into all six child-cluster
89+
failure logs (taint GET/PATCH/reconcile, kata clear/stamp). These previously logged
90+
only the terse top-level `Display` ("client error (Connect)"), hiding the real cause.
91+
- `src/reconcilers/helpers_tests.rs`: +2 unit tests for `error_chain` (multi-level
92+
source chain; single error with no source).
93+
94+
### Why
95+
A k0smotron-hosted control plane (workshop k0smotron tier) exposes a self-signed API
96+
server cert that **rustls** (5-Spot's TLS backend, kube 3.1 default) rejects where
97+
OpenSSL/curl `-k` accept it — so 5-Spot's child client fails to taint/drain the worker
98+
Node with `client error (Connect)`, with no visible cause. Logging the full chain makes
99+
the exact rustls reason (unknown issuer / SAN mismatch / unsupported signature) visible
100+
so the fix can target it (a proper cert, `tls_server_name`, or `insecure-skip-tls-verify`
101+
on the child kubeconfig — kube already honors the latter via `Config::accept_invalid_certs`).
102+
103+
### Impact
104+
- [ ] Breaking change
105+
- [ ] Requires cluster rollout
106+
- [ ] Config change only
107+
- [x] Diagnostics only (no behavior change)
108+
12109
## [2026-06-23 11:45] - Ship the spot-schedule provider binaries in the image (ADR 0009 providers were unrunnable)
13110

14111
**Author:** Erick Bourgeois

0 commit comments

Comments
 (0)