From 1674b68b62bab2697781697d98073fe31345d8da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christoph=20St=C3=A4bler?= Date: Fri, 10 Apr 2026 12:00:57 +0200 Subject: [PATCH 1/5] Run e2e tests as matrix for builder & deployer combintation --- .github/workflows/test-e2e.yml | 9 +++++- test/e2e/func_middleware_update_test.go | 8 ++---- test/utils/func.go | 37 +++++++++++++++++-------- 3 files changed, 36 insertions(+), 18 deletions(-) diff --git a/.github/workflows/test-e2e.yml b/.github/workflows/test-e2e.yml index 965eac2..ed173c7 100644 --- a/.github/workflows/test-e2e.yml +++ b/.github/workflows/test-e2e.yml @@ -11,8 +11,13 @@ concurrency: jobs: test-e2e: - name: E2E Tests + name: E2E Tests (${{ matrix.builder }}/${{ matrix.deployer }}) runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + builder: [pack, s2i] + deployer: [knative, raw, keda] steps: - name: Clone the code uses: actions/checkout@v4 @@ -50,4 +55,6 @@ jobs: env: REGISTRY_INSECURE: true REGISTRY: kind-registry:5000 + DEFAULT_BUILDER: ${{ matrix.builder }} + DEFAULT_DEPLOYER: ${{ matrix.deployer }} run: make test-e2e diff --git a/test/e2e/func_middleware_update_test.go b/test/e2e/func_middleware_update_test.go index 9b96af7..6e2d68f 100644 --- a/test/e2e/func_middleware_update_test.go +++ b/test/e2e/func_middleware_update_test.go @@ -76,11 +76,9 @@ var _ = Describe("Middleware Update", func() { DeferCleanup(os.RemoveAll, repoDir) // Deploy function using the same OLD func CLI version - out, err := utils.RunFuncWithVersion(oldFuncVersion, "deploy", - "--namespace", functionNamespace, - "--path", repoDir, - "--registry", utils.Registry(), - fmt.Sprintf("--registry-insecure=%t", utils.IsRegistryInsecure())) + out, err := utils.RunFuncDeploy(repoDir, + utils.WithNamespace(functionNamespace), + utils.WithDeployCliVersion(oldFuncVersion)) Expect(err).NotTo(HaveOccurred()) _, _ = fmt.Fprint(GinkgoWriter, out) diff --git a/test/utils/func.go b/test/utils/func.go index d592b85..f720fdf 100644 --- a/test/utils/func.go +++ b/test/utils/func.go @@ -33,12 +33,27 @@ func RunFunc(command string, args ...string) (string, error) { return Run(cmd) } +// RunFuncWithVersion executes the func CLI with a specific version +// It downloads and caches the version if not already present +func RunFuncWithVersion(version string, command string, args ...string) (string, error) { + funcBinary, err := ensureFuncVersion(version) + if err != nil { + return "", err + } + + allArgs := append([]string{command}, args...) + cmd := exec.Command(funcBinary, allArgs...) + return Run(cmd) +} + // RunFuncDeploy runs func deploy func RunFuncDeploy(functionDir string, optFns ...FuncDeployOption) (string, error) { opts := &FuncDeployOptions{ // defaults Registry: Registry(), RegistryInsecure: IsRegistryInsecure(), + Builder: os.Getenv("DEFAULT_BUILDER"), + Deployer: os.Getenv("DEFAULT_DEPLOYER"), } for _, optFn := range optFns { @@ -63,20 +78,11 @@ func RunFuncDeploy(functionDir string, optFns ...FuncDeployOption) (string, erro args = append(args, "--deployer", opts.Deployer) } - return RunFunc("deploy", args...) -} - -// RunFuncWithVersion executes the func CLI with a specific version -// It downloads and caches the version if not already present -func RunFuncWithVersion(version string, command string, args ...string) (string, error) { - funcBinary, err := ensureFuncVersion(version) - if err != nil { - return "", err + if opts.CliVersion != "" { + return RunFuncWithVersion(opts.CliVersion, "deploy", args...) } - allArgs := append([]string{command}, args...) - cmd := exec.Command(funcBinary, allArgs...) - return Run(cmd) + return RunFunc("deploy", args...) } type FuncDeployOptions struct { @@ -85,6 +91,7 @@ type FuncDeployOptions struct { Namespace string Builder string Deployer string + CliVersion string } type FuncDeployOption func(*FuncDeployOptions) @@ -107,6 +114,12 @@ func WithDeployer(deployer string) FuncDeployOption { } } +func WithDeployCliVersion(version string) FuncDeployOption { + return func(opts *FuncDeployOptions) { + opts.CliVersion = version + } +} + // ensureFuncVersion ensures the specified func version is available and returns its path func ensureFuncVersion(version string) (string, error) { projectDir, err := GetProjectDir() From 49b258baa4c361cc18eb6c5f92228d64c3753de6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christoph=20St=C3=A4bler?= Date: Fri, 10 Apr 2026 13:58:10 +0200 Subject: [PATCH 2/5] Add missing permissions for PAC pipeline --- config/rbac/role.yaml | 1 + internal/controller/function_controller.go | 19 ++++++++++++++++++- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/config/rbac/role.yaml b/config/rbac/role.yaml index 98b5b6d..55cf981 100644 --- a/config/rbac/role.yaml +++ b/config/rbac/role.yaml @@ -24,6 +24,7 @@ rules: - apps resources: - deployments + - replicasets verbs: - create - delete diff --git a/internal/controller/function_controller.go b/internal/controller/function_controller.go index 7ce331a..90df4ed 100644 --- a/internal/controller/function_controller.go +++ b/internal/controller/function_controller.go @@ -61,7 +61,7 @@ type FunctionReconciler struct { // +kubebuilder:rbac:groups=functions.dev,resources=functions/status,verbs=get;update;patch // +kubebuilder:rbac:groups=functions.dev,resources=functions/finalizers,verbs=update // +kubebuilder:rbac:groups="",resources=pods;pods/attach;secrets;services;persistentvolumeclaims,verbs=get;list;watch;create;update;patch;delete -// +kubebuilder:rbac:groups="apps",resources=deployments,verbs=get;list;watch;create;update;patch;delete +// +kubebuilder:rbac:groups="apps",resources=deployments;replicasets,verbs=get;list;watch;create;update;patch;delete // +kubebuilder:rbac:groups="serving.knative.dev",resources=services;routes,verbs=get;list;watch;create;update;patch;delete // +kubebuilder:rbac:groups="eventing.knative.dev",resources=triggers,verbs=get;list;watch;create;update;patch;delete // +kubebuilder:rbac:groups=tekton.dev,resources=pipelines;pipelineruns,verbs=get;list;watch;create;update;patch;delete @@ -249,6 +249,7 @@ func (r *FunctionReconciler) setupPipelineRBAC(ctx context.Context, function *v1 func (r *FunctionReconciler) ensureDeployFunctionRole(ctx context.Context, namespace string) error { logger := log.FromContext(ctx) + // TODO: only add the rules which are needed for the functions deployer expectedRole := &rbacv1.Role{ ObjectMeta: metav1.ObjectMeta{ Name: deployFunctionRoleName, @@ -259,6 +260,22 @@ func (r *FunctionReconciler) ensureDeployFunctionRole(ctx context.Context, names APIGroups: []string{"serving.knative.dev"}, Resources: []string{"services", "routes"}, Verbs: []string{"create", "delete", "get", "list", "patch", "update", "watch"}, + }, { + APIGroups: []string{"eventing.knative.dev"}, + Resources: []string{"triggers"}, + Verbs: []string{"create", "delete", "get", "list", "patch", "update", "watch"}, + }, { + APIGroups: []string{"apps"}, + Resources: []string{"deployments", "replicasets"}, + Verbs: []string{"create", "delete", "get", "list", "patch", "update", "watch"}, + }, { + APIGroups: []string{""}, + Resources: []string{"services", "pods"}, + Verbs: []string{"create", "delete", "get", "list", "patch", "update", "watch"}, + }, { + APIGroups: []string{"http.keda.sh"}, + Resources: []string{"httpscaledobjects"}, + Verbs: []string{"create", "delete", "get", "list", "patch", "update", "watch"}, }, }, } From 589cae075aeb412fac8fb3545e538adbe359885d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christoph=20St=C3=A4bler?= Date: Fri, 10 Apr 2026 20:15:40 +0200 Subject: [PATCH 3/5] Catch more operator logs in e2e tests --- test/e2e/bundle_test.go | 2 +- test/e2e/e2e_test.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/e2e/bundle_test.go b/test/e2e/bundle_test.go index c29fbaa..39cd347 100644 --- a/test/e2e/bundle_test.go +++ b/test/e2e/bundle_test.go @@ -62,7 +62,7 @@ var _ = Describe("Bundle", Label("bundle"), Ordered, func() { By("Collecting logs from deployed operators") for _, testNs := range testNamespaces { By("Logs from operator in namespace " + testNs.Name) - cmd := exec.Command("kubectl", "logs", "-l", "control-plane=controller-manager", "--namespace", testNs.Name) + cmd := exec.Command("kubectl", "logs", "-l", "control-plane=controller-manager", "--namespace", testNs.Name, "-t", "-1") controllerLogs, err := utils.Run(cmd) if err == nil { _, _ = fmt.Fprintf(GinkgoWriter, "Controller logs:\n %s", controllerLogs) diff --git a/test/e2e/e2e_test.go b/test/e2e/e2e_test.go index 1426607..45d7d27 100644 --- a/test/e2e/e2e_test.go +++ b/test/e2e/e2e_test.go @@ -236,7 +236,7 @@ func logFailedTestDetails(functionName, functionNamespace string) { } By("Fetching controller manager pod logs") - cmd := exec.Command("kubectl", "logs", "-l", "control-plane=controller-manager", "-n", namespace) + cmd := exec.Command("kubectl", "logs", "-l", "control-plane=controller-manager", "-n", namespace, "-t", "20") controllerLogs, err := utils.Run(cmd) if err == nil { _, _ = fmt.Fprintf(GinkgoWriter, "Controller logs:\n %s", controllerLogs) From bc4ddcdf9aaf13f93268a9f1a3b12f07b132b576 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christoph=20St=C3=A4bler?= Date: Fri, 10 Apr 2026 20:16:01 +0200 Subject: [PATCH 4/5] Export all operator logs on e2e test failure --- .github/workflows/test-e2e.yml | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/.github/workflows/test-e2e.yml b/.github/workflows/test-e2e.yml index ed173c7..ae380c6 100644 --- a/.github/workflows/test-e2e.yml +++ b/.github/workflows/test-e2e.yml @@ -58,3 +58,18 @@ jobs: DEFAULT_BUILDER: ${{ matrix.builder }} DEFAULT_DEPLOYER: ${{ matrix.deployer }} run: make test-e2e + + - name: Collect Kubernetes artifacts + if: failure() + run: | + mkdir -p /tmp/k8s-artifacts + kubectl logs -n func-operator-system -l control-plane=controller-manager --tail=-1 --all-containers --prefix --timestamps > /tmp/k8s-artifacts/func-operator.log + kubectl get functions -A -o yaml > /tmp/functions.yaml + + - name: Upload Kubernetes artifacts + if: failure() + uses: actions/upload-artifact@v4 + with: + name: func-operator-logs-${{ matrix.builder }}-${{ matrix.deployer }} + path: /tmp/k8s-artifacts/ + retention-days: 7 From b7d72f83b3edbcb8f27a3d2d7f5f63c553a3d6d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christoph=20St=C3=A4bler?= Date: Fri, 10 Apr 2026 20:19:05 +0200 Subject: [PATCH 5/5] Fix linter --- test/e2e/bundle_test.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/test/e2e/bundle_test.go b/test/e2e/bundle_test.go index 39cd347..bc74396 100644 --- a/test/e2e/bundle_test.go +++ b/test/e2e/bundle_test.go @@ -62,7 +62,11 @@ var _ = Describe("Bundle", Label("bundle"), Ordered, func() { By("Collecting logs from deployed operators") for _, testNs := range testNamespaces { By("Logs from operator in namespace " + testNs.Name) - cmd := exec.Command("kubectl", "logs", "-l", "control-plane=controller-manager", "--namespace", testNs.Name, "-t", "-1") + cmd := exec.Command( + "kubectl", "logs", + "-l", "control-plane=controller-manager", + "--namespace", testNs.Name, + "-t", "-1") controllerLogs, err := utils.Run(cmd) if err == nil { _, _ = fmt.Fprintf(GinkgoWriter, "Controller logs:\n %s", controllerLogs)