From c835c3f7192d59ec3aa6bf9d75f2f05a8b4433fd Mon Sep 17 00:00:00 2001 From: Alice Frosi Date: Tue, 20 Oct 2026 08:41:19 +0000 Subject: [PATCH 1/7] e2e: enable upgrade test on EKS with pull secret support Add EKS to the upgrade test provider gate and read E2E_IMAGE_PULL_SECRET to set imagePullSecrets on helm install/upgrade, allowing the test to pull from private registries. Assisted-by: AI Signed-off-by: Alice Frosi (cherry picked from commit 001d6989642e3e4753bce4810464bd07ab62efd4) --- test/e2e/upgrade_test.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/test/e2e/upgrade_test.go b/test/e2e/upgrade_test.go index 90172488..b78910bd 100644 --- a/test/e2e/upgrade_test.go +++ b/test/e2e/upgrade_test.go @@ -36,7 +36,7 @@ var operatorCRDNames = []string{ // helm upgrade with the current image and verifies the operator still // works. func TestOperatorUpgrade(t *testing.T) { - e2eutil.Providers(t, "bink") + e2eutil.Providers(t, "bink", "eks") releaseTag := os.Getenv("E2E_OPERATOR_RELEASE_TAG") if releaseTag == "" { @@ -206,6 +206,9 @@ func helmImageArgs(t *testing.T, img string, extraArgs []string) []string { "--set-string", "image.tag=" + tag, "--set-string", "image.pullPolicy=Always", } + if secret := os.Getenv("E2E_IMAGE_PULL_SECRET"); secret != "" { + args = append(args, "--set", "imagePullSecrets[0].name="+secret) + } if len(extraArgs) > 0 { j, err := json.Marshal(extraArgs) if err != nil { From 1b6643037d65e3f3c43e9826f9f5c3ab954116a7 Mon Sep 17 00:00:00 2001 From: Alice Frosi Date: Tue, 20 Oct 2026 08:41:24 +0000 Subject: [PATCH 2/7] e2e: pass upgrade test vars to e2e-eks target Forward RELEASED_OPERATOR_TAG, RELEASED_OPERATOR_IMG, and EKS_IMAGE_PULL_SECRET to the e2e-eks make target so the upgrade test can run against EKS clusters. Assisted-by: AI Signed-off-by: Alice Frosi (cherry picked from commit 6cac27d9a9cd1c77fe4e53cee43b5404f7b29402) --- Makefile | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Makefile b/Makefile index 09bf7638..d3c4e1fc 100644 --- a/Makefile +++ b/Makefile @@ -129,6 +129,7 @@ EKS_NODE_IMAGE_UPDATE2_REF ?= EKS_REGISTRY_HOST ?= EKS_REGISTRY_USER ?= EKS_REGISTRY_PASSWORD ?= +EKS_IMAGE_PULL_SECRET ?= .PHONY: e2e-eks e2e-eks: ## Run e2e tests against EKS. V=1 for verbose. RUN= to filter. @@ -145,6 +146,9 @@ e2e-eks: ## Run e2e tests against EKS. V=1 for verbose. RUN= to filter. E2E_REGISTRY_HOST="$(EKS_REGISTRY_HOST)" \ E2E_REGISTRY_USER="$(EKS_REGISTRY_USER)" \ E2E_REGISTRY_PASSWORD="$(EKS_REGISTRY_PASSWORD)" \ + $(if $(RELEASED_OPERATOR_TAG),E2E_OPERATOR_RELEASE_TAG=$(RELEASED_OPERATOR_TAG)) \ + $(if $(RELEASED_OPERATOR_IMG),E2E_OPERATOR_RELEASED_IMG=$(RELEASED_OPERATOR_IMG)) \ + $(if $(EKS_IMAGE_PULL_SECRET),E2E_IMAGE_PULL_SECRET=$(EKS_IMAGE_PULL_SECRET)) \ ARTIFACTS="$(ARTIFACTS)" \ go test -timeout 30m -count=1 -parallel 2 $(if $(V),-v) $(if $(RUN),-run '$(RUN)') . From 36f48fe358e242ea46f6c7230a05d1a3e56783b9 Mon Sep 17 00:00:00 2001 From: Alice Frosi Date: Tue, 20 Oct 2026 10:54:39 +0000 Subject: [PATCH 3/7] helm: set nameOverride to fix OCI chart naming The Konflux build pipeline packages the chart as bootc-operator-chart, causing the Helm fullname template to produce bootc-operator-bootc-operator-chart instead of bootc-operator. Setting nameOverride ensures consistent resource names regardless of the OCI artifact name. Assisted-by: AI Signed-off-by: Alice Frosi (cherry picked from commit bbd939a1a6c5876ccf420ac199bed329fc51f8a8) --- chart/bootc-operator/values.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/chart/bootc-operator/values.yaml b/chart/bootc-operator/values.yaml index 9aaacc54..383c3705 100644 --- a/chart/bootc-operator/values.yaml +++ b/chart/bootc-operator/values.yaml @@ -1,3 +1,5 @@ +nameOverride: bootc-operator + crds: install: true From c6b21b2e369ed5eeb08edcaed4add9e37a60c703 Mon Sep 17 00:00:00 2001 From: Alice Frosi Date: Tue, 20 Oct 2026 11:53:29 +0000 Subject: [PATCH 4/7] e2e: use helm upgrade --install for operator restore The upgrade test cleanup uses helm upgrade to restore the operator after the test. If the test fails during uninstall (e.g. CRD deletion timeout), the Helm release no longer exists and a plain helm upgrade fails, leaving the operator down for subsequent tests. Adding --install allows the cleanup to recover from a fully uninstalled state, preventing cascading failures. Assisted-by: AI Signed-off-by: Alice Frosi (cherry picked from commit e5747f1dcf9591a53a3c1f88ba0e0bdee8aaf04b) --- test/e2e/upgrade_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/e2e/upgrade_test.go b/test/e2e/upgrade_test.go index b78910bd..50bf90de 100644 --- a/test/e2e/upgrade_test.go +++ b/test/e2e/upgrade_test.go @@ -190,7 +190,7 @@ func helmInstallOperator(t *testing.T, chartPath, img string, extraArgs []string func helmUpgradeOperator(t *testing.T, chartPath, img string, extraArgs []string) { t.Helper() args := []string{ - "upgrade", helmReleaseName, chartPath, + "upgrade", "--install", helmReleaseName, chartPath, "--namespace", testutil.OperatorNamespaceName, } args = append(args, helmImageArgs(t, img, extraArgs)...) From 34c0ed38691160d3809944a0df8efa2db898d38d Mon Sep 17 00:00:00 2001 From: Alice Frosi Date: Tue, 20 Oct 2026 13:59:13 +0000 Subject: [PATCH 5/7] e2e: build helm chart dependencies before install in upgrade test Run helm dependency build before helm install so the CRDs subchart is available. Update uninstallOperator comment to reflect that CRDs are removed together with the main release. Assisted-by: AI Signed-off-by: Alice Frosi (cherry picked from commit ac037fe83113c4d3cfb1c2793e8150f56eb38096) --- test/e2e/upgrade_test.go | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/test/e2e/upgrade_test.go b/test/e2e/upgrade_test.go index 50bf90de..80fea605 100644 --- a/test/e2e/upgrade_test.go +++ b/test/e2e/upgrade_test.go @@ -126,10 +126,10 @@ func TestOperatorUpgrade(t *testing.T) { Should(poolAllUpdated(1, env.NodeImageUpdateDigest())) } -// uninstallOperator removes the operator via Helm uninstall, then -// deletes CRDs (which Helm does not manage on uninstall). Custom -// resources are deleted first while the operator is still running so -// it can handle finalizer removal. +// uninstallOperator removes the operator. Custom resources are deleted +// first while the operator is still running so it can handle finalizer +// removal. CRDs are bundled as a subchart dependency so they are +// removed together with the main release. func uninstallOperator( t *testing.T, g Gomega, @@ -152,7 +152,7 @@ func uninstallOperator( }).WithTimeout(2*time.Minute).Should(Succeed(), "expected all custom resources to be deleted") - t.Logf("Uninstalling Helm release...") + t.Logf("Uninstalling Helm releases...") helmRun(t, "uninstall", helmReleaseName, "--namespace", testutil.OperatorNamespaceName) @@ -177,6 +177,7 @@ func uninstallOperator( // helmInstallOperator installs the operator via helm install. func helmInstallOperator(t *testing.T, chartPath, img string, extraArgs []string) { t.Helper() + helmRun(t, "dependency", "build", chartPath) args := []string{ "install", helmReleaseName, chartPath, "--namespace", testutil.OperatorNamespaceName, From 3c96cd29e5c0053467d1c489821871e659ec30b4 Mon Sep 17 00:00:00 2001 From: Alice Frosi Date: Tue, 20 Oct 2026 14:50:02 +0000 Subject: [PATCH 6/7] e2e: use imageMatchesDigest in upgrade test On EKS, bootc status reports the platform-specific content digest in ImageDigest and the manifest-list digest in the Image pullspec. The direct ImageDigest check fails when these differ. Use the imageMatchesDigest helper which accepts both, matching what the controller does via InfoMatchesDigest. Assisted-by: AI Signed-off-by: Alice Frosi (cherry picked from commit d259ae5344b256d3128faf7046ab6bbda4eecc41) --- test/e2e/upgrade_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/e2e/upgrade_test.go b/test/e2e/upgrade_test.go index 80fea605..77c94a4d 100644 --- a/test/e2e/upgrade_test.go +++ b/test/e2e/upgrade_test.go @@ -117,7 +117,7 @@ func TestOperatorUpgrade(t *testing.T) { t.Logf("Patched pool to update image %s", updateRef) testutil.WaitForNodeIdle(t, g, ctx, env.Client, nodeName, 5*time.Minute, - HaveField("Booted", HaveField("ImageDigest", env.NodeImageUpdateDigest())), + HaveField("Booted", imageMatchesDigest(env.NodeImageUpdateDigest())), ) t.Logf("Node %q completed update with upgraded operator", nodeName) From 607fc745882688ea798169222abb96d3b44f5da1 Mon Sep 17 00:00:00 2001 From: Alice Frosi Date: Thu, 22 Oct 2026 09:07:03 +0000 Subject: [PATCH 7/7] e2e: uninstall standalone CRDs release in upgrade test On EKS CI, the Konflux pipeline publishes the operator and CRDs as separate OCI Helm charts. The deploy script (test_deploy.py) installs them as two independent releases: bootc-operator-crds and bootc-operator (with crds.install=false). The upgrade test only ran helm uninstall on the main release, leaving the CRDs behind and timing out waiting for them to be deleted. Check whether a standalone CRDs release exists before uninstalling. On bink (where CRDs are bundled as a subchart in a single release) the check returns false and the extra uninstall is skipped. Assisted-by: AI Signed-off-by: Alice Frosi (cherry picked from commit f998392526102f7031f1bc20b5bf933931ff31f6) --- test/e2e/upgrade_test.go | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/test/e2e/upgrade_test.go b/test/e2e/upgrade_test.go index 77c94a4d..da7ff675 100644 --- a/test/e2e/upgrade_test.go +++ b/test/e2e/upgrade_test.go @@ -153,8 +153,15 @@ func uninstallOperator( "expected all custom resources to be deleted") t.Logf("Uninstalling Helm releases...") + crdsRelease := helmReleaseName + "-crds" + hasCRDsRelease := helmReleaseExists(t, crdsRelease) helmRun(t, "uninstall", helmReleaseName, "--namespace", testutil.OperatorNamespaceName) + if hasCRDsRelease { + t.Logf("Uninstalling standalone CRDs release...") + helmRun(t, "uninstall", crdsRelease, + "--namespace", testutil.OperatorNamespaceName) + } g.Eventually(func(g Gomega) { var d appsv1.Deployment @@ -220,6 +227,28 @@ func helmImageArgs(t *testing.T, img string, extraArgs []string) []string { return args } +// helmReleaseExists returns true if the named Helm release exists in +// the operator namespace. Any error other than "release: not found" +// fails the test. +func helmReleaseExists(t *testing.T, name string) bool { + t.Helper() + args := []string{"status", name, + "--namespace", testutil.OperatorNamespaceName} + if kc := os.Getenv("KUBECONFIG"); kc != "" { + args = append([]string{"--kubeconfig", kc}, args...) + } + cmd := exec.Command("helm", args...) + out, err := cmd.CombinedOutput() + if err == nil { + return true + } + if strings.Contains(string(out), "release: not found") { + return false + } + t.Fatalf("helm status %s failed: %v\n%s", name, err, out) + return false +} + // helmRun executes a helm command, adding --kubeconfig if set. func helmRun(t *testing.T, args ...string) { t.Helper()