agent-platform release v3.20.0
Added
- Self-management through the bundled Flux, on by default (roadmap#4348, PRD Q5/Q5b): where the chart brings the engine, the engine also holds the chart.
gitops.self.enabled (auto | true | false, default auto = follows components.flux.enabled; true with the engine off fails the render) renders the release’s own OCIRepository + HelmRelease (templates/self/release.yaml, both named after the release, in the release namespace, run as agent-platform-flux — gitops.serviceAccountName overrides it — chartRef to the OCIRepository, releaseName/targetNamespace the release’s, install/upgrade.disableWait, values from Secret agent-platform-values key values.yaml with optional: false). The OCIRepository follows <gitops.self.repository>/agent-platform (default oci://gsoci.azurecr.io/charts/giantswarm; gitops.self.insecure for a plain-HTTP lab registry) at >=<installed version> <next major>.0.0, derived from the running chart at render time (gitops.self.versionRange overrides; an offline helm template derives it from the placeholder Chart.yaml version), on gitops.self.interval (default 10m). The bundled helm-controller adopts the CLI-installed release with one extra revision and rolls the chart forward inside its major without a helm upgrade. Measured on kind: install --wait 87 s, adoption in the second the release went deployed, a pushed version applied 47 s after the push with the new chart default in effect and the user’s values intact, a rewritten values Secret applied within 20 s, uninstall --wait with the self HelmRelease present in under a minute, the upgrade from an engine-on 3.18.0 into this version adopted with the bracket held. - The install-time bracket: the self
HelmRelease is rendered suspend: true on helm install and whenever it does not exist yet (a guarded lookup — the upgrade of an engine-on installation into this version), never on a controller-driven upgrade; the post-install/post-upgrade hook <release>-self-values (weight 0) writes the user-supplied values of the revision in flight (helm get values, never the merged tree) into Secret agent-platform-values, labelled reconcile.fluxcd.io/watch=Enabled, by server-side apply, and — only while the HelmRelease is suspended — starts the detached Job <release>-self-resume, which polls helm status and resumes the HelmRelease once the release is deployed (or failed); still pending after 300 s it exits 1 without resuming. Neither is a chart object Helm’s kstatus --wait would wait on. helm template renders suspend: true. - The Helm CLI is day-0 only — a
ValidatingAdmissionPolicy (templates/self/policy.yaml: <release>-self-managed-<namespace> + a binding of the same name scoped to the release namespace, failurePolicy: Fail) on the CREATE of Secrets of type helm.sh/release.v1 labelled name=<release>: admitted for system:serviceaccount:<namespace>:agent-platform-flux (the identity the bundled helm-controller impersonates) or while the namespace carries agent-platform.giantswarm.io/helm-cli=allow. helm upgrade and helm rollback fail in about a second with the reason in Helm’s own error output (the message names Secret agent-platform-values and the hand-back) and write no revision; UPDATE/DELETE pass, so does helm uninstall. Needs Kubernetes ≥ 1.30: the render refuses an older cluster while self-management is on. A render guard also refuses the annotation together with self-management on (two writers on one release). The guard-Job alternative (a pre-upgrade hook reading the pending storage Secret’s managedFields manager) stays documented in UPGRADE.md as the fallback should the policy ever be ruled out. - The hand-back / escape hatch:
kubectl annotate namespace <ns> agent-platform.giantswarm.io/helm-cli=allow, then helm upgrade … --set gitops.self.enabled=false --force-conflicts (once; helm-controller co-owns the fields) hands the release back to the CLI without an uninstall — the new pre-upgrade hooks suspend the self HelmRelease before Helm deletes it, so helm-controller drops its finalizer; the value stays in the values file (README “Self-management”). - Teardown extended (
templates/hooks/self.yaml, rendered whenever the engine is on): weight -6 <release>-self-stop-resumer (one plain kubectl delete of the resumer Job, --ignore-not-found) and weight -5 <release>-self-suspend (suspends the self HelmRelease if present, removes the hook-written values Secret by its labels) at pre-delete — and at pre-upgrade too while self-management is off (the hand-back and lab renders). They run as the new namespaced identity <release>-self (ServiceAccount + Role + RoleBinding, templates/self/rbac.yaml, regular objects: the detached resumer runs after a hook-managed account is gone), as do the values hook and the resumer. gitops.hooks.helmImage (docker.io/alpine/k8s:1.36.4 — kubectl, helm, jq, a shell; Renovate-tracked like gitops.hooks.image) runs the hooks that need helm or have to tolerate a missing object; templates/hooks/_job.tpl takes script, image and serviceAccountName. - Lab shape:
gitops.self.enabled: false renders none of it (no self objects, no values hook, no policy) but the -6/-5 hooks and their identity; tests/test-values.yaml sets it — the ATS installs an unreleased chart, which a self HelmRelease would replace with the published one — and tests/ats/test_smoke.py asserts the lab shape on the cluster. make verify-self (tests/verify-self.py, in CI with Helm 3.17.3) asserts the three shapes, the guards and the knobs; make verify-engine renders its engine-on shape with self-management off. No installation needs to act: the fleet (engine off) renders byte-identically; an engine-on CLI installation becomes self-managed on its next helm upgrade — see UPGRADE.md.