ci(validate-oc-ampere): add e2e cluster validation workflow - #1797
Conversation
oc-ampere had zero live e2e coverage (only offline flate/kubeconform schema checks) despite being a real production Flux Operator cluster. Ports the same top-level-resource loop (Mechanism 1) and fail-closed per-app loop (Mechanism 2) already merged for kubenuc/k8s-vms-daniele (#1790-#1795), extended with a new fourth resolution tier: a dirname()-based fallback that parses the root apps/kustomization.yaml for apps with no per-app deploy.yaml of their own. 2 of 4 real apps deploy for real: flux-operator (real-path fallback; verified via `helm template` with empty values that its chart installs only a Deployment/RBAC/CRDs with no hooks and stays idle until a FluxInstance CR exists — flux-instance.yaml itself stays skip-listed in this job, which bootstraps Flux via plain `flux install` instead) and ngx-webhook (new tier-4 resolver; no credentials, no outbound calls, NodePort-only). system-upgrade-controller and teleport-agent are excluded for the same live-external-side-effect reasons as k3s-rabbit's. Production oc-ampere's compute is genuinely ARM64 (terraform/oci/k8s-armchair, VM.Standard.A1.Flex); this e2e run validates manifest/reconciliation correctness on the (undocumented, presumed x86_64) self-hosted runner, not ARM64 image availability — stated plainly in the workflow's header comment. The comment-only touch to apps/ngx-webhook/manifests/deploy.yml exercises the tier-4 resolver on this workflow's first real CI run. Signed-off-by: Daniele De Lorenzi <2905124+dark-vex@users.noreply.github.com>
… PR's own CI run An independent Codex review of this PR (before merge) found that DEPLOY_APPS is derived purely from `git diff` against main, and this PR's only touched app path was ngx-webhook/ — so flux-operator, despite not being in EXCLUDED_APPS and despite the workflow's own header comment claiming both apps "deploy for real," never actually entered the deploy loop on this PR's own CI run. The workflow's design was correct (a future PR touching flux-operator/ would exercise it), but this PR's verification run would have proven nothing about it. Add the same kind of comment-only touch already used for ngx-webhook, this time under apps/flux-operator/, so DEPLOY_APPS contains both apps and this PR's real CI run actually exercises flux-operator's real-path deploy — the first time anywhere in this repo. Also add a missing -f existence check to the tier-4 resolver (flagged in the same review): it previously only checked for a '/' in the matched apps/kustomization.yaml entry, not that the entry actually resolves to a real file, before computing dirname() — a future directory-style entry with a '/' in its name would have been misclassified as a file path rather than failing at the resolver boundary. Signed-off-by: Daniele De Lorenzi <2905124+dark-vex@users.noreply.github.com>
Independent Codex reviewRan an independent Codex review (via the local Codex CLI, not the cloud Real bug found and fixed ( Minor fix: tier-4 resolver now also checks the matched Confirmed correct, no action needed:
Not independently re-verified by Codex (its sandbox couldn't reach Noted but not changed (pre-existing convention shared with |
Preventive fix for the same bug that failed the companion validate-k3s-rabbit.yml workflow's real CI run: "Check resource deployment status" calls `flux get helmreleases -A` with no `|| true`, and flux's CLI exits non-zero when it finds zero matching objects. This PR's own run passed because flux-operator's real HelmRelease happens to exist, but any future oc-ampere PR touching only excluded apps (system-upgrade-controller, teleport-agent) would deploy zero HelmReleases and hit this every time. Add `|| true` to both `flux get` calls, consistent with the "Check for failed reconciliations" step just below it. Signed-off-by: Daniele De Lorenzi <2905124+dark-vex@users.noreply.github.com>
ci(validate-oc-ampere): add e2e cluster validation workflow
flux-operator landed on k3s-rabbit via separate PRs (#1799, #1804, #1805) while the e2e workflow PR (#1796) was still rebasing on top of them, so it never appeared in that PR's own diff and no live CI run has exercised the tier-3 real-deploy path for it here — unlike oc-ampere, where an identical comment-only touch (PR #1797, commit 66d5dfd) already forced that coverage. A comment-only touch on flux-operator's HelmRelease forces it into this PR's own DEPLOY_APPS so this run finally exercises that path. Also corrects several comments/docs that assumed k3s-rabbit deploys zero real apps by design, stale since flux-operator's addition. Safety re-verified independently this session via a fresh live `helm template` render of chart v0.57.0: zero Helm hooks, no FluxInstance object; the Deployment just starts the operator controller, which idles until a FluxInstance CR exists. k3s-rabbit's root kustomization.yaml has no flux-instance.yaml entry, so that CR is never created during an e2e run — same as oc-ampere. Signed-off-by: Daniele De Lorenzi <2905124+dark-vex@users.noreply.github.com>
Summary
validate-oc-ampere.yml, giving oc-ampere its first live e2e coverage (real k3s + realflux install+ real reconcile-to-Ready), matching the mechanism already merged for kubenuc/k8s-vms-daniele (ci(kubenuc,k8s-vms): derive top-level cluster resources instead of hand-enumerating #1790-ci(validate-flux-render): work around flate's concurrent-dispatch livelock #1795) and companion PR ci(validate-k3s-rabbit): add e2e cluster validation workflow #1796 for k3s-rabbit.dirname()-based fallback that parses the rootapps/kustomization.yamlfor apps with no per-appdeploy.yamlof their own — needed here forngx-webhook.flux-operator(real-path fallback) andngx-webhook(new tier-4 resolver, no credentials/outbound calls, NodePort-only).system-upgrade-controllerandteleport-agentare excluded for the same live-external-side-effect reasons as k3s-rabbit's.flux-operatorpre-FluxInstancerisk, resolved: rendered the pinned chart (helm template ... --version 0.57.0 --values '{}') — it installs only a Deployment/RBAC/CRDs/NetworkPolicy/Service, no Helm hooks. The Deployment's only arg is--log-level=info; RBAC includes a broadget/list/watchrule (used for its FluxReport cross-cluster status aggregation) and apatch/reconcilerule scoped tokustomize.toolkit.fluxcd.io/helm.toolkit.fluxcd.io(used by its optional Web UI/MCP-server manual-reconcile-trigger feature — nothing in this workflow calls those endpoints). Nothing fires automatically at pod startup absent aFluxInstanceCR.flux-instance.yamlitself stays skip-listed in this job (which bootstraps Flux via plainflux installinstead) — documented in-workflow why that must never change.terraform/oci/k8s-armchair,VM.Standard.A1.Flex); this run validates manifest/reconciliation correctness on the (undocumented, presumed x86_64) self-hosted runner, not ARM64 image availability. Named images:nginxinc/nginx-unprivileged:1.31-alpine,ghcr.io/controlplaneio-fluxcd/flux-operator:v0.57.0.clusters/oc-ampere/apps/ngx-webhook/manifests/deploy.ymlexercises the tier-4 resolver on this workflow's first real run.Test plan
clusters/oc-ampere/kustomization.yaml(resolves tosystem-upgrade-controller.yamlonly;flux-instance.yaml/cluster-vars.yamlcorrectly skipped)apps/kustomization.yamlwithAPP=ngx-webhook(resolves viadirname()tongx-webhook/manifests)EXCLUDED_APPSmembership verified for both excluded apps;flux-operator/ngx-webhookconfirmed not excludedflux-operatorchart rendered locally, no hooks, idle-until-FluxInstanceconfirmed (see summary)chartsKustomization's wait timeout (first time this repo exercises that volume),flux-operatorandngx-webhookboth reach Ready,system-upgrade-controller/teleport-agentcorrectly skipped🤖 Generated with Claude Code