Skip to content

fix(kubernetes): run the Talos reconcile Job in the main install phase - #3145

Merged
Aleksei Sviridkin (lexfrei) merged 1 commit into
mainfrom
fix/talos-tct-decouple-mainphase
Jun 30, 2026
Merged

fix(kubernetes): run the Talos reconcile Job in the main install phase#3145
Aleksei Sviridkin (lexfrei) merged 1 commit into
mainfrom
fix/talos-tct-decouple-mainphase

Conversation

@lexfrei

@lexfrei Aleksei Sviridkin (lexfrei) commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

What this PR does

The tenant worker MachineDeployment md0 intermittently never reaches status.replicas=2. CAPI blocks MachineSet creation until the TalosConfigTemplate that the deployment's bootstrap.configRef points to exists, and on failing installs that template is never created.

Root cause — an ordering deadlock

The TalosConfigTemplate is created only by the talos-reconcile post-install Helm hook (the chart can no longer render it at template time — three of its inputs are produced asynchronously after apply). A post-install hook runs only after Helm has applied the release's main resources and, when Helm waits, after they become Ready.

But the same release also emits in-tenant addon HelmReleases — notably cilium — whose readiness needs tenant worker nodes, and those nodes can only be created once this hook has produced the TalosConfigTemplate. So when the main-resource wait is in effect, the install deadlocks: it waits for cilium to be Ready, cilium waits for worker nodes, the nodes wait for the TalosConfigTemplate, and the template waits for the post-install hook — which never runs, because the install never finishes the wait that precedes the hook phase. The install times out and md0 never scales.

The release sets helm-install-disable-wait precisely to skip that main-resource wait so the hooks run, but its effect is unreliable — which is what makes the failure bimodal: when the wait is skipped the hook runs and the template lands in ~46s; when it is not, the deadlock strands the install.

A timestamped poller over a failing run (both kubernetes-latest and kubernetes-previous, 640 polls) captured: TalosConfigTemplate absent in 640/640 polls; both post-install hook Jobs (talos-reconcile and bootstrap-token) never created — the install never reached the post-install hook phase; all main resources applied (MachineDeployment, KubevirtMachineTemplate, MachineHealthCheck, WorkloadMonitor, child HelmReleases, Talos PKI/secrets) and the four hook inputs ready early and stable; the parent HelmRelease stuck at Running 'install' action 20m then looping into upgrade, with the cilium sub-release timing out on cilium-operator (which has no worker node to schedule on) — downstream of the missing template.

The fix

Render the talos-reconcile Job and its RBAC / ServiceAccount / egress CiliumNetworkPolicy as ordinary main-phase resources instead of post-install hooks. The Job is then created during the apply itself — not after the wait — and runs on the management cluster, which has nodes (unlike the tenant cilium-operator). It produces the TalosConfigTemplate, md0 scales, workers join, cilium goes Ready, and the main-resource wait (if any) closes within the install budget: the Job completes in tens of seconds, and node boot plus cilium readiness is a few minutes — comfortably inside the 20m install timeout. This works whether or not helm-install-disable-wait takes effect, so it does not depend on that annotation's reliability.

Because a main-phase Job is immutable, it carries a content-hash name suffix over its whole rendered spec (mirroring the KubevirtMachineTemplate idiom in cluster.yaml): an identical render keeps the same name and Helm no-ops it; any spec change yields a new name and a fresh Job, so no change ever lands on the same name and trips an immutable-field patch error. The applied TalosConfigTemplate keeps its stable <release>-<group> name (referenced by bootstrap.configRef), so an unchanged render re-applies a byte-identical template — a CAPI no-op that never rolls existing workers. The Job name is truncated to stay within the 63-char DNS-label limit while always preserving the hash. The runtime input-waits, the single kubectl apply of the template with a KamajiControlPlane ownerReference for GC, and the extraHostEntries are all unchanged.

helm-install-disable-wait's unreliable effectiveness is a real latent issue (it explains the created-vs-never bimodality), but this fix breaks the deadlock independent of it, so that is a separate follow-up rather than a blocker here.

Supersedes #3139 (a 10-minute wait-budget bump that treated the symptom; the deadlock is structural and a larger budget would not have helped).

Screenshots

Not applicable — no UI changes.

Testing

helm-unittest extended to pin: no helm.sh/hook on any of the seven talos-reconcile documents, the content-hash name, ttlSecondsAfterFinished, the preserved template apply + ownerReference + extraHostEntries, the hash rotating on a spec change, and the long-name truncation staying within 63 chars. Full chart suite green (128 tests). The applied template is byte-identical to the previous hook output (verified by diff), so existing tenants are upgrade-safe.

Release note

fix(kubernetes): create the tenant worker TalosConfigTemplate from a main-phase Job instead of a post-install hook, so worker MachineDeployments reliably scale during install

Summary by CodeRabbit

  • Bug Fixes
    • Improved Kubernetes addon install behavior by running reconcile work during the main chart phase, reducing readiness deadlocks and upgrade issues.
    • Added more reliable reconciliation handling with stable, change-detected job recreation and updated network access for the reconcile workload.
    • Refined chart and test guidance to match the new install flow and Helm behavior.

The talos-reconcile Job is the only thing that creates the
TalosConfigTemplate the worker MachineDeployment's bootstrap.configRef
points to; CAPI blocks MachineSet creation until it exists, so tenant
workers cannot scale until the Job has run.

The Job was a post-install/post-upgrade Helm hook, which runs only after
Helm has applied the release's main resources and, when Helm waits, after
they become Ready. But the same release emits in-tenant addon HelmReleases
— notably cilium — whose readiness needs worker nodes, and those nodes
need the TalosConfigTemplate this Job produces. So when the main-resource
wait is in effect the install deadlocks: it waits for cilium to be Ready,
cilium waits for workers, the workers wait for the template, and the
template waits for this hook — which never runs because the install never
finishes the wait that precedes the hook phase. The install times out and
the MachineDeployment never scales. The release sets
helm-install-disable-wait to skip that wait, but its effect is unreliable,
which makes the failure bimodal: the template lands in ~46s when the wait
is skipped, and the install is stranded when it is not.

Render the Job and its RBAC/ServiceAccount/egress policy as ordinary
main-phase resources. The Job is then created during the apply itself, not
after the wait, and runs on the management cluster where nodes exist
(unlike the tenant cilium-operator), so it produces the template, the
MachineDeployment scales, workers join, cilium goes Ready, and the wait
(if any) closes within the install budget — independent of whether
helm-install-disable-wait takes effect.

The Job is immutable, so it carries a content-hash name suffix over its
rendered spec (mirrors the KubevirtMachineTemplate idiom in cluster.yaml):
an identical render keeps the name and Helm no-ops it, while any spec
change yields a new name and a fresh Job, so no spec change ever lands on
the same name and triggers an immutable-field patch error. The applied
TalosConfigTemplate keeps its stable <release>-<group> name, so an
unchanged render re-applies a byte-identical template — a CAPI no-op that
never rolls existing workers.

Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Aleksei Sviridkin <f@lex.la>
@github-actions github-actions Bot added area/kubernetes Issues or PRs related to the tenant Kubernetes app kind/bug Categorizes issue or PR as related to a bug size/XL This PR changes 500-999 lines, ignoring generated files labels Jun 30, 2026
@gemini-code-assist

Copy link
Copy Markdown
Contributor

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request resolves a structural deadlock in the Kubernetes tenant installation process. Previously, the TalosConfigTemplate was generated by a post-install Helm hook, which caused installation failures when the release waited for tenant-side addons (like Cilium) that required worker nodes to be ready. By moving the talos-reconcile logic to a main-phase Job, the template is generated immediately, allowing worker nodes to scale and addons to reach readiness within the installation budget. The solution includes robust handling for Job immutability and ensures existing tenant upgrades remain safe.

Highlights

  • Structural Fix for Deadlock: Converted the talos-reconcile Helm hook into a main-phase Job. This ensures the TalosConfigTemplate is created during the apply phase, preventing a circular dependency deadlock where worker nodes wait for the template, and the template hook waits for worker-dependent addons like Cilium to become ready.
  • Immutable Job Management: Implemented a content-hash name suffix for the talos-reconcile Job. This allows the Job to remain immutable while ensuring that any change to the rendered spec triggers a new Job, avoiding immutable-field patch errors and enabling clean pruning of superseded Jobs.
  • Reliability Improvements: Removed reliance on helm-install-disable-wait for hook execution reliability. The Job now runs on the management cluster nodes, ensuring it executes independently of the tenant worker readiness state.
New Features

🧠 You can now enable Memory (public preview) to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment Gemini (@gemini-code-assist) Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize the Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counterproductive. You can react with 👍 and 👎 on Gemini (@gemini-code-assist) comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@coderabbitai

coderabbitai Bot commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

The talos-reconcile workload is converted from a Helm post-install/post-upgrade hook Job to a main-phase Job. Hook annotations are removed from all RBAC resources, a CiliumNetworkPolicy is added, the job spec is extracted into a named template with scoped per-nodeGroup context, and Jobs receive immutable content-hash-based names. Related comments across templates, tests, and platform config files are updated accordingly.

Changes

talos-reconcile hook → main-phase Job

Layer / File(s) Summary
RBAC, CiliumNetworkPolicy, named template, and Job rendering
packages/apps/kubernetes/templates/talos/talos-reconcile-job.yaml
Removes helm.sh/hook annotations from ServiceAccount, Role, RoleBinding, ClusterRole, and ClusterRoleBinding. Adds a CiliumNetworkPolicy for reconcile pod egress. Introduces kubernetes.talos-reconcile-job-spec named template with scoped per-nodeGroup context. Refactors Job rendering to hash the rendered spec, truncate name prefix to fit 63-char DNS label, and emit an immutable main-phase Job. DNS domain, certSANs, kubelet image/config, and installer image bindings are updated to use scoped context variables.
cluster.yaml and cilium.yaml comment updates
packages/apps/kubernetes/templates/cluster.yaml, packages/apps/kubernetes/templates/helmreleases/cilium.yaml
Inline comments updated to reference main-phase Job instead of post-install/post-upgrade hook for TalosConfigTemplate production, certSANs repatching, and Cilium ClusterIP seeding.
Test suite updates
packages/apps/kubernetes/tests/talos_templates_test.yaml, packages/apps/kubernetes/tests/cluster_test.yaml, packages/apps/kubernetes/tests/gpu_node_labels_test.yaml, packages/apps/kubernetes/tests/kubelet_reservation_test.yaml
talos_templates_test.yaml adds notExists assertions for helm.sh/hook on all RBAC documents, verifies immutable content-hash Job naming via regex, asserts TTL and command contents, and locks exact Job name suffixes for gpus-set/unset and truncation cases. Other test files update comments only.
Platform config and registry comment updates
packages/system/kubernetes-rd/cozyrds/kubernetes.yaml, pkg/config/config.go, pkg/registry/apps/application/rest.go
Comments updated to replace post-install-hook references with descriptions of the main-phase talos-reconcile Job and addon HelmRelease readiness deadlock scenario.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • cozystack/cozystack#2931: Introduced the talos-reconcile-job.yaml as a hook-scoped reconcile Job — this PR directly refactors that same file from hook to main-phase.
  • cozystack/cozystack#2571: Overlaps in pkg/registry/apps/application/rest.go convertApplicationToHelmRelease and pkg/config/config.go, which this PR also touches (comment updates).

Suggested labels

kind/regression

Suggested reviewers

  • kvaps
  • lllamnyp
  • androndo

🐇 No more hooks that block the way,
The main-phase Job is here to stay!
It hashes its spec with a six-char tail,
And applies TalosConfig without fail.
From hook to main — the rabbit cheers today! 🎉

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely summarizes the core change: moving the Talos reconcile Job to the main install phase.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/talos-tct-decouple-mainphase

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request refactors the talos-reconcile Job in the kubernetes application from a post-install/post-upgrade Helm hook to a main-phase Job. This change resolves a deadlock during installation where the main-resource wait blocks the hook from running while in-tenant addon HelmReleases (like Cilium) wait for worker nodes that require the TalosConfigTemplate produced by the Job. To prevent upgrade conflicts on this immutable resource, the Job is now rendered with a content-hash name suffix. The unit tests, comments, and documentation across the codebase have been updated to reflect this architectural shift. There are no review comments, and I have no additional feedback to provide.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/apps/kubernetes/templates/talos/talos-reconcile-job.yaml (1)

110-116: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Add kamajicontrolplanes/finalizers update permission

The Job sets blockOwnerDeletion: true on the KamajiControlPlane ownerReference, so the Role also needs update on kamajicontrolplanes/finalizers (scoped to {{ .Release.Name }}) or the TalosConfigTemplate apply can be forbidden.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/apps/kubernetes/templates/talos/talos-reconcile-job.yaml` around
lines 110 - 116, The Role for the Talos reconcile Job is missing the finalizer
update permission needed for the KamajiControlPlane ownerReference flow. Update
the RBAC rule in talos-reconcile-job.yaml for kamajicontrolplanes to include
update on the kamajicontrolplanes/finalizers subresource, scoped to {{
.Release.Name }}, alongside the existing get and patch permissions so the
TalosConfigTemplate apply is not forbidden.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/apps/kubernetes/templates/talos/talos-reconcile-job.yaml`:
- Around line 218-225: Add a client-side request timeout to every kubectl
invocation in the talos reconcile Job so a hung apiserver cannot bypass the
retry window. Update the kubectl calls in the wait loop and the later
patch/get/apply steps to pass a consistent --request-timeout value, using the
existing Job template logic where those commands are constructed. Make sure the
timeout is applied uniformly in the talos-reconcile-job.yaml flow so all kubectl
operations respect the same bounded failure behavior.

---

Outside diff comments:
In `@packages/apps/kubernetes/templates/talos/talos-reconcile-job.yaml`:
- Around line 110-116: The Role for the Talos reconcile Job is missing the
finalizer update permission needed for the KamajiControlPlane ownerReference
flow. Update the RBAC rule in talos-reconcile-job.yaml for kamajicontrolplanes
to include update on the kamajicontrolplanes/finalizers subresource, scoped to
{{ .Release.Name }}, alongside the existing get and patch permissions so the
TalosConfigTemplate apply is not forbidden.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 90426baa-a632-43df-bc6f-0f3e26eb793a

📥 Commits

Reviewing files that changed from the base of the PR and between 4404c5c and 32c4d60.

📒 Files selected for processing (10)
  • packages/apps/kubernetes/templates/cluster.yaml
  • packages/apps/kubernetes/templates/helmreleases/cilium.yaml
  • packages/apps/kubernetes/templates/talos/talos-reconcile-job.yaml
  • packages/apps/kubernetes/tests/cluster_test.yaml
  • packages/apps/kubernetes/tests/gpu_node_labels_test.yaml
  • packages/apps/kubernetes/tests/kubelet_reservation_test.yaml
  • packages/apps/kubernetes/tests/talos_templates_test.yaml
  • packages/system/kubernetes-rd/cozyrds/kubernetes.yaml
  • pkg/config/config.go
  • pkg/registry/apps/application/rest.go

Comment on lines +218 to +225
{{- /* Each pod attempt runs the ~10-minute (120 × 5s) input-wait loop, so this
backoffLimit sets the self-heal window to roughly 5 hours. The Job does
not block the install — when disable-wait is in effect Helm does not wait
on it, and when Helm does wait the Job completes in tens of seconds — so a
long retry budget costs nothing on the install path. It only governs how
long a Job whose inputs are unusually slow keeps retrying on its own
before giving up. Bounded (not infinite) so a permanently-broken input
eventually stops spawning pods. */}}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Static check: every kubectl call in the reconcile script should use a bounded request timeout.
rg -n -C2 'kubectl|request-timeout' packages/apps/kubernetes/templates/talos/talos-reconcile-job.yaml

Repository: cozystack/cozystack

Length of output: 2939


🏁 Script executed:

#!/bin/bash
sed -n '250,340p' packages/apps/kubernetes/templates/talos/talos-reconcile-job.yaml

Repository: cozystack/cozystack

Length of output: 5020


🌐 Web query:

kubectl --request-timeout default no timeout client-side request deadline docs

💡 Result:

The official documentation for kubectl specifies that the --request-timeout flag defaults to a value of "0" [1][2][3]. In this context, a value of zero explicitly means that there is no client-side timeout, and kubectl will not automatically give up on a request [1][2]. When the --request-timeout is set to 0, kubectl will wait indefinitely for a response from the API server [1][4]. If you wish to impose a deadline, you must explicitly provide a duration with a time unit, such as 1s, 2m, or 3h [1][3]. While some external guides or community resources may suggest that a default 30-second or 60-second timeout exists [5][6], these claims conflict with the official Kubernetes documentation which defines the default behavior as 0 (no timeout) [1][2][3]. It is important to distinguish between the client-side --request-timeout (which governs the kubectl client's patience) and server-side timeouts (governed by the kube-apiserver configuration), as misalignment between these two can lead to client-side errors like context deadline exceeded while the server continues processing the request [5].

Citations:


Add a client-side timeout to every kubectl call in this Job.

kubectl defaults to no request timeout, so a hung apiserver connection can block the pod forever and bypass the 120×5s retry window. Apply --request-timeout consistently to the wait loop and the later patch, get, and apply calls.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/apps/kubernetes/templates/talos/talos-reconcile-job.yaml` around
lines 218 - 225, Add a client-side request timeout to every kubectl invocation
in the talos reconcile Job so a hung apiserver cannot bypass the retry window.
Update the kubectl calls in the wait loop and the later patch/get/apply steps to
pass a consistent --request-timeout value, using the existing Job template logic
where those commands are constructed. Make sure the timeout is applied uniformly
in the talos-reconcile-job.yaml flow so all kubectl operations respect the same
bounded failure behavior.

@myasnikovdaniil myasnikovdaniil left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The fix is correct and the implementation is clean. The root-cause analysis is rigorous, the content-hash idiom mirrors the existing KubevirtMachineTemplate pattern, and the test coverage (128 tests, including hash-rotation and truncation cases) is strong. Approving with a few documentation-only suggestions below.

One design note not tied to a specific line: the ServiceAccount, Role, RoleBinding, ClusterRole, ClusterRoleBinding, and CiliumNetworkPolicy are now permanent main-phase resources (no hook-delete-policy). In the old version they were cleaned up after each successful run. This is intentional — the Job may be recreated after TTL expiry and needs its RBAC in place — but it is a behaviour change on upgrade (Helm adopts these from hook-managed to main-phase-managed via 3-way merge). A one-line note on the ServiceAccount would help future readers understand why the RBAC is permanent.

RBAC, ServiceAccount and egress CiliumNetworkPolicy are main-phase too;
the wait loop tolerates its dependencies (and its own network policy)
not yet being in place, so Helm's kind-ordered apply needs no explicit
sequencing. The bootstrap-token Job stays a post-install hook.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit / documentation: The comment says bootstrap-token "stays a post-install hook" but doesn't flag the ordering change. In the old version with DisableWait=true, hook-weight ordering (talos-reconcile weight 5 → bootstrap-token weight 10) guaranteed bootstrap-token only started after talos-reconcile completed. Now they run concurrently (talos-reconcile is main-phase; bootstrap-token fires as soon as Helm finishes applying resources, without waiting for this Job to finish). This is safe because bootstrap-token's backoffLimit: 10 handles a still-booting tenant apiserver, but a one-line note would prevent future readers from being surprised when they see bootstrap-token fail its first attempt on a fresh install.

spec:
backoffLimit: 5
{{- /* Each pod attempt runs the ~10-minute (120 × 5s) input-wait loop, so this
backoffLimit sets the self-heal window to roughly 5 hours. The Job does

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: The comment says "roughly 5 hours" — this is the worst-case when every attempt exhausts the 10-minute wait loop. In the normal path the first attempt succeeds in tens of seconds. Worth clarifying: worst-case 5 hours if inputs are permanently absent; in practice the first attempt succeeds in tens of seconds once Kamaji emits the Service and cert-manager issues the CAs.

TTL a Failed Job would keep the same content-hash name and be a no-op on
every later upgrade — Helm never patches the immutable Job, so it would
stay Failed until deleted by hand. No churn from the TTL: the repo runs no
Flux drift detection, so an interval reconcile never re-applies a cleared

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: The comment correctly states that Flux drift detection is off by default, so a cleared Job won't be recreated on interval reconciles. Worth adding a brief note that if drift detection is explicitly enabled (.spec.drift.detect: true on the HelmRelease), the cleared Job will be recreated every ~10 minutes. The kubectl apply is idempotent (CAPI no-op if the TCT is unchanged), so there is no correctness risk — just unexpected pod activity.

# Skip the readiness wait so the hook fires and the chicken-and-egg
# resolves.
# created without the TalosConfigTemplate the Job produces. Skip the
# readiness wait so the release settles and the chicken-and-egg resolves;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit / documentation: The comment says "the chicken-and-egg resolves" — this was accurate when DisableWait was required for correctness (old hook version). With this fix, the deadlock is broken independently of DisableWait. The annotation is now a performance optimisation (avoids blocking the HelmRelease for the 5-8 minutes it takes workers to boot and addons to become Ready), not a correctness requirement. A reader might ask "can I remove this now that the deadlock is fixed?" Suggest clarifying:

# Skip the readiness wait so the release does not block for 5-8 minutes on
# worker-boot + addon-readiness. The talos-reconcile main-phase Job breaks
# the install deadlock independently; DisableWait is a performance opt.

asserts:
- equal:
path: metadata.name
value: test-k8s-talos-reconcile-md0-6ddd7d

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: Hardcoded hash 6ddd7d (and ceb45e on line 197) will silently go stale if anyone edits the Job spec template without reading the full test-suite description. The test comment at the top of this block explains this well, but a short inline note — e.g. # BREAKING: update this hash when the Job spec changes — directly above each value: line would make the requirement visible to someone who edits the template and only runs the test to see what failed.

@lexfrei
Aleksei Sviridkin (lexfrei) merged commit 7c67aaf into main Jun 30, 2026
40 checks passed
@lexfrei
Aleksei Sviridkin (lexfrei) deleted the fix/talos-tct-decouple-mainphase branch June 30, 2026 09:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/kubernetes Issues or PRs related to the tenant Kubernetes app kind/bug Categorizes issue or PR as related to a bug size/XL This PR changes 500-999 lines, ignoring generated files

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants