fix(chart): reconcile the telemetry Collector in place once its token Secret exists - #1048
fix(chart): reconcile the telemetry Collector in place once its token Secret exists#1048LukasWodka wants to merge 6 commits into
Conversation
… Secret exists The <release>-telemetry-status record for skipped-no-token promised the skip "resolves itself once jobs-manager writes the Secret". Nothing performed that: the lookup deciding the Collector's three-state rule runs only inside a helm upgrade, and the hourly auto-upgrade tick upgraded only onto a NEWER published chart. Measured on a fresh edge: Secret present within minutes, three ticks, no DaemonSet, until a new chart happened to ship a day later. Tracked internally. Mechanism: with no newer chart to install, the tick now runs one tri-state decider (telemetry_reconcile_verdict): stored state skipped-no-token AND no Collector DaemonSet in the stored manifest AND the repo serves the deployed version AND a --dry-run=server of that same version resolves `enabled` -> a same-version `helm upgrade --version "$CURRENT"` with the normal flags. Any other state behaves as before; "cannot tell" (unreadable manifest, failed dry-run, contradictory record, version not served by the repo) never acts and is logged. Derived from the chart's own decider and helpers; nothing restated. Record: names the real trigger (the next auto-upgrade tick, schedule and repo read from autoUpgrade.*; or "run helm upgrade" when autoUpgrade is off) and says plainly that a version ahead of the repo's index cannot be re-rendered. Tests: scripts/tests/auto-upgrade-telemetry-reconcile.sh drives the rendered script through a stub helm (23 cases) and its -mutations.sh sibling proves all four gates red on their own regression; both registered in `make drift`. helm-unittest +7 (kubernetesProvider reaches skipped-no-token offline). Chart 1.9.116 -> 1.9.117. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
|
bugbot run |
…-same-version-reconcile
…e this PR was open Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
|
bugbot run |
… in the Helm unit tests job, refuse without the plugin The drift job has no helm-unittest plugin, so (d) read `unknown command "unittest"` as "suite reddened, but not on the honest-record test": a gate red for the wrong reason (measured 2026-09-11, run 34581907348). The script now has two modes: reconcile (default, `make drift`: baseline + a-c) and record (`make helm-unittest` + helm-unit.yaml: baseline + d), and record mode refuses rather than skips when the plugin is missing, so it can never go decorative. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
|
bugbot run |
…e under errexit+pipefail The pipefail early-close gate flagged `helm plugin list | grep -q unittest`. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
|
bugbot run |
saqlainsyed007
left a comment
There was a problem hiding this comment.
The chart change is correct and approvable on the merits — I traced it and found no blocking defect. The reconcile is the right shape: not a checksum/secret annotation (there's no rendered Collector to annotate yet, and the enable decision is a template lookup that only runs inside helm upgrade), but a tri-state, fail-closed same-version helm upgrade in the auto-upgrade tick, gated on a server-side --dry-run=server that runs the chart's real cluster lookups to detect the token Secret's arrival. No restart loop (post-reconcile the stored state flips to enabled, so the next tick is a no-op), no race with the normal upgrade path (reconcile runs only in the two exit 0 branches), Secret value never logged (--hide-secret), and the reader/writer names share single helpers pinned by a new wiring suite. Test coverage is excellent — a 23-case harness that drives the rendered script plus four mutation proofs.
The only red checks are PATH persist — ubuntu:22.04 and Prereqs — ubuntu:22.04, which are the known apt-mirror flake (remediated separately in the already-approved #1051), not a defect in this PR. Once those are re-run green (or #1051 lands), this is a clean approve. I left three low-severity inline notes (activeDeadlineSeconds buffer vs. the added dry-run, a trunc 63 omission in the new name helper, and a duplicated version-parse) — all optional cleanup, none blocking.
- tracebloc.telemetryStatusName now truncates/trims like its sibling tracebloc.telemetryCollectorName, so a long fullnameOverride/release name cannot leave the status ConfigMap name unbounded while the Collector's own name is capped at 63 chars. - Bound the same-version reconcile's server-side dry-run at --timeout 60s. It only templates/diffs against the API server and never waits on a rollout, so 60s is generous; left unbounded it shared helm's 5m default and could eat into the 300s repo-fetch buffer activeDeadlineSeconds reserves for the real --atomic upgrade that follows it on the same tick. - Extracted parse_repo_version() so the LATEST computation and the reconcile verdict's --version-pinned lookup share one awk pattern for helm search repo -o yaml output instead of two copies that could drift apart. Verified: scripts/tests/auto-upgrade-telemetry-reconcile.sh (23/23), scripts/tests/auto-upgrade-telemetry-reconcile-mutations.sh (4/4, including the pre-existing case (c) which now also covers the new dry-run timeout since it drives the real rendered bytes), helm unittest ./client (751/751, including telemetry_status_wiring_test.yaml), helm lint (0 failed), shellcheck -S warning -x on the extracted rendered script (clean). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
|
bugbot run |
There was a problem hiding this comment.
✅ Bugbot reviewed your changes and found no new issues!
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit 53ac19e. Configure here.
Summary
The
<release>-telemetry-statusrecord for theskipped-no-tokenstate promised that the skip "resolves itself once jobs-manager writes the Secret". Nothing performed that: thelookupdeciding the Collector's three-state rule runs only inside ahelm upgrade, and the hourly auto-upgrade tick only upgraded onto a newer published chart (already at latest; nothing to do/deployed version is ahead of repo … skipping). Measured on a fresh installer edge: the token Secret was present within minutes, three ticks passed, no DaemonSet — the Collector rendered a day later only because a new chart happened to ship. Tracked internally.This PR does two things together:
skipped-no-token(which, by the decider's construction, meanstelemetryCollector.enabledwas unset), the stored manifest carries no Collector DaemonSet, the repo serves the deployed chart version, and a server-side dry-run of that same version now resolvesenabled(the token Secret has arrived), the tick re-runshelm upgradepinned to--version "$CURRENT"with the exact flags and values discipline of the normal upgrade (--reset-then-reuse-values --atomic --cleanup-on-fail --timeout). It logs one line naming why. Any other state behaves exactly as before.autoUpgrade.schedule, repo fromautoUpgrade.repoUrl— never restated), or, withautoUpgrade.enabled: false, "runhelm upgradeon this release". Theskipped-incomplete-valuesbranch loses its "resolves itself" as well. No branch of the record promises a self-resolution any more.The condition, in one place
telemetry_reconcile_verdict()in the renderedauto-upgrade.shis the only decider — tri-state, and 2 never acts:0reconcile: stored stateskipped-no-tokenand no DaemonSet named$TELEMETRY_COLLECTOR_NAMEin the stored manifest and the repo serves$CURRENTandhelm upgrade … --version "$CURRENT" --reset-then-reuse-values --dry-run=server --hide-secretresolvesenabled.1nothing to do: any other stored state (enabled,disabled-by-operator,skipped-incomplete-values, no record at all — a release rendered by a chart predating it), or a dry-run that still saysskipped-no-token. Quiet, as today.2cannot tell:helm get manifestunreadable/empty, dry-run failed or rendered no record, the record contradicts the manifest (says skipped, DaemonSet present), the TELEMETRY_* names missing from env, or the deployed version is not served by the repo. Logged asreconcile: NOT re-rendering, cannot tell …, no upgrade.Derived, not restated. No Secret name, Class A rule or DaemonSet gate is copied into the script. The decision is read from the chart's own decider twice — the stored state out of
helm get manifest, the would-be state out of--dry-run=server(helm 3.13+; the image is pinned at 3.16.4), which runs the templates' reallookups (release-scoped, legacy and pre-override Secret names alike) against the cluster. The three names the awk matches on (TELEMETRY_STATUS_NAME,TELEMETRY_STATUS_ANNOTATION,TELEMETRY_COLLECTOR_NAME) arrive in the CronJob env from two new helpers (tracebloc.telemetryStatusName,tracebloc.telemetryStateAnnotation) plus the existingtracebloc.telemetryCollectorName— the same helpers the status template and the DaemonSet render with, pinned bytests/telemetry_status_wiring_test.yaml(including underfullnameOverride). The image has nokubectl, and a barecurlagainst the API is exactly what the house style forbids, so helm is the only client used.Deployed ahead of the index (
current > latest)This is the state the ticket caught, and it deserves a plain statement: an edge running a chart version the repo does not serve (a dev chart installed from a local path) cannot be re-rendered by the tick, because there is nothing it can fetch —
helm upgradeneeds a chart, and the deployed one exists only inside the release. The verdict names it every tick (deployed chart X is not served by <repo> (newest there: Y): a same-version re-render is impossible, the Collector renders on the next published chart), and the status record says the same. The reconcile fixes the fleet case — an edge on the published chart whose Secret arrived after install, which until now loggedalready at latest; nothing to doforever.Type
Chart.yamlversionandappVersion1.9.116 → 1.9.117)Test plan
Everything CI runs for the chart tier, locally at CI severity (outputs kept):
make lint(bash -n on every script +shellcheck -S error) — green;shellcheck -S warning -xon both new gates — clean.make drift—drift: all 50 guards green(48 existing + the 2 new ones;auto-upgrade-inflight-vs-wedge.shunchanged and green) (includes the two new guards).make helm-lint helm-vocab— 5 lints green,chart-env-vocabulary: all 177 checks passed.make helm-templatewith kubeconform — aks/bm/eks/oc allInvalid: 0, Errors: 0.make helm-unittest—Test Suites: 42 passed, 42 total/Tests: 750 passed, 750 total(was 743; +7 here).make bats—bats scripts/tests/*.bats2067 ok, 0 not ok, rc=0.sh -n(alpine/helm:3.16.4).New checks
scripts/tests/auto-upgrade-telemetry-reconcile.sh(registered inmake drift) — drives the rendered script with a stubhelmon PATH, 23 cases: the full tick end to end (Secret arrived → reconcile pinned to$CURRENTwith all flags; Secret still absent / enabled / disabled-by-operator / incomplete-values / no record → no upgrade; contradictory record / unreadable manifest / failed dry-run / dry-run without record / names missing → no upgrade and the log says cannot tell; ahead-of-index → named, no upgrade; newer chart → normal upgrade, dry-run never consulted) and the extractedtelemetry_reconcile_verdictfunction directly for the rc 0/1/2 table. Fixtures are realhelm templaterenders of this chart, not typed YAML; the names come from the rendered CronJob's env.scripts/tests/auto-upgrade-telemetry-reconcile-mutations.sh(registered inmake drift) — the permanent mutation proof, each asserting the specific finding: (a) drop the DaemonSet-absent check → contradictory case reconciles, gate red; (b) accept askipped-no-tokendry-run → Secret-still-absent case reconciles, gate red; (c) unhook the reconcile from the at-latest branch → Secret-arrived case does not reconcile, gate red; (d) restore "this resolves itself once it does" in the status template →telemetry_collector_test.yamlreddens on "the no-token skip names the trigger that actually re-renders it, not a self-resolution". All four seen red, tree as shipped seen green first.telemetry_collector_test.yaml(viakubernetesProvider, which is what lets theskipped-no-tokenstate be reached offline — a kube-system Namespace and no Secret), 1 script-shape case inauto_upgrade_test.yaml, and the 2-case wiring suite.Deliberately not changed
telemetryCollector.enabledstays tri-state with no default; the collector is not defaulted on (option 4 of the internal ticket). The refusal-when-enabled-and-no-token path is untouched.auto-upgrade-inflight-vs-wedge.shgate still passes unchanged: it runs the script without the TELEMETRY_* env, which now takes the fail-closed2branch and logs, rather than erroring underset -u.manifest.sha256is unchanged.already at latest; nothing to dobecamealready at latest; nothing to upgrade(and… skipping→… skipping the upgrade) so the line is not contradicted by a reconcile that follows it; nothing in the repo asserted the old strings.Checklist
Chart.yamlversion + appVersion)shellcheck -S warning -x+bash -nclean on every shell touchedNote
Medium Risk
Changes production auto-upgrade behavior (same-version helm upgrades and server-side dry-runs) and telemetry operator messaging; heavily gated by new drift and helm-unittest checks.
Overview
Fixes telemetry Collector not appearing after the token Secret arrives when the fleet is already on the latest published chart. Collector state comes from template
lookup, which only runs onhelm upgrade, so hourly auto-upgrade previously did nothing on “already at latest” ticks even after jobs-manager wrote the Secret.When there is no newer chart to install, the auto-upgrade script now runs
telemetry_reconcile_verdict(): if the deployed manifest recordsskipped-no-token, has no Collector DaemonSet, the repo serves the current chart version, and a server-side dry-run of that version would resolveenabled, it performs a same-versionhelm upgrade(--reset-then-reuse-values --atomic, etc.). Tri-state behavior fails closed—ambiguous cases log and do not upgrade.Shared naming via new helpers
tracebloc.telemetryStatusNameandtracebloc.telemetryStateAnnotation, with CronJob env vars wired to the status ConfigMap writer. The telemetry statusreasontext no longer claims the skip “resolves itself”; it names the real trigger (next auto-upgrade tick with schedule/repo from values, or manualhelm upgradewhen auto-upgrade is off).Chart bumps to 1.9.118. CI/drift adds
auto-upgrade-telemetry-reconcile.sh(23 stub-helm cases) and mutation proofs; Helm unit workflow runs mutation (d) for the honesty unit test.Reviewed by Cursor Bugbot for commit 53ac19e. Bugbot is set up for automated code reviews on this repo. Configure here.