Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ test: manifests generate fmt vet envtest ## Run tests.

# Utilize Kind or modify the e2e tests to load the image locally, enabling compatibility with other vendors.
.PHONY: test-e2e # Run the e2e tests against a Kind k8s instance that is spun up.
test-e2e:
test-e2e: operator-sdk
go test ./test/e2e/ -v -ginkgo.v -timeout 30m

GOLANGCI_LINT = $(shell pwd)/bin/golangci-lint
Expand Down
6 changes: 6 additions & 0 deletions docs/developer_guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,12 @@ To run e2e testing, make sure that you are logged in to a running kubernetes clu
make test-e2e
```

To run e2e testing using OLM (Operator Lifecycle Manager) bundle installation:

```sh
make test-e2e BUNDLE_IMG="your-registry/falcon-operator-bundle:version"
```

To run integration tests, run the following command:

```sh
Expand Down
47 changes: 47 additions & 0 deletions test/e2e/e2e_helpers.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package e2e

import (
"fmt"
"os"
"os/exec"
"path/filepath"
"strings"
)

// getOperatorSDKPath returns the path to operator-sdk executable, following the same logic as the Makefile
// It first checks LOCALBIN (./bin), then falls back to system PATH
func getOperatorSDKPath() (string, error) {
// Get current working directory to construct LOCALBIN path
pwd, err := os.Getwd()
if err != nil {
return "", fmt.Errorf("failed to get current directory: %w", err)
}

// Check LOCALBIN first (equivalent to $(LOCALBIN)/operator-sdk)
localBinPath := filepath.Join(pwd, "bin", "operator-sdk")
if _, err := os.Stat(localBinPath); err == nil {
return localBinPath, nil
}

// Fall back to system PATH (equivalent to $(shell which operator-sdk))
systemPath, err := exec.LookPath("operator-sdk")
if err != nil {
return "", fmt.Errorf("operator-sdk not found in LOCALBIN (%s) or system PATH: %w", localBinPath, err)
}

return systemPath, nil
}

// isOpenShift detects if the current cluster is OpenShift by checking for OpenShift-specific resources
func isOpenShift() bool {
// Check for OpenShift-specific API resources that indicate we're on OpenShift
// This is a common pattern used in operator development
cmd := exec.Command("kubectl", "api-resources", "--api-group=config.openshift.io")
output, err := cmd.Output()
if err != nil {
return false
}

// If we can find OpenShift config resources, we're on OpenShift
return len(output) > 0 && strings.Contains(string(output), "clusterversions")
}
115 changes: 96 additions & 19 deletions test/e2e/e2e_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,34 @@ var _ = Describe("falcon", Ordered, func() {
})

AfterAll(func() {
// Check if BUNDLE_IMG was used for installation and clean up accordingly
bundleImg := os.Getenv("BUNDLE_IMG")
if bundleImg != "" {
By("cleaning up OLM bundle installation")

// Get the proper operator-sdk executable path (following Makefile logic)
operatorSDKPath, err := getOperatorSDKPath()
if err == nil {
cmd := exec.Command(operatorSDKPath, "cleanup", "falcon-operator", "--namespace", namespace)
_, _ = utils.Run(cmd)

// Uninstall OLM only if not on OpenShift (OpenShift has built-in OLM)
if !isOpenShift() {
By("uninstalling OLM")
cmd = exec.Command(operatorSDKPath, "olm", "uninstall")
_, _ = utils.Run(cmd)
} else {
By("detected OpenShift - skipping OLM uninstall (managed by OpenShift)")
}
} else {
By("operator-sdk not found for cleanup, attempting manual cleanup")
}
} else {
By("cleaning up traditional deployment")
cmd := exec.Command("make", "undeploy")
_, _ = utils.Run(cmd)
}

By("removing manager namespace")
cmd := exec.Command("kubectl", "delete", "ns", namespace)
_, _ = utils.Run(cmd)
Expand All @@ -63,8 +91,12 @@ var _ = Describe("falcon", Ordered, func() {
By("removing metrics cluster role binding")
cmd = exec.Command("kubectl", "delete", "clusterrolebinding", metricsRoleBindingName)
_, _ = utils.Run(cmd)
cmd = exec.Command("make", "install")
_, _ = utils.Run(cmd)

// Only run make install for traditional deployment cleanup
if bundleImg == "" {
cmd = exec.Command("make", "install")
_, _ = utils.Run(cmd)
}
})

Context("Falcon Operator", func() {
Expand All @@ -79,28 +111,73 @@ var _ = Describe("falcon", Ordered, func() {
operatorImage = image
}

cmd := exec.Command("kind", "get", "clusters")
_, err = utils.Run(cmd)
if err == nil {
By("building the manager (Operator) image")
cmd := exec.Command("make", "docker-build", fmt.Sprintf("IMG=%s", operatorImage))
var outputMake []byte
var cmd *exec.Cmd

// Conditional installation: Use OLM bundle if BUNDLE_IMG is set, otherwise use traditional deployment
// This allows testing both installation methods:
// - OLM bundle: Set BUNDLE_IMG=<bundle-image-url> to test operator-sdk run bundle installation
// - Traditional: Leave BUNDLE_IMG unset to use make deploy with custom operator image
bundleImg := os.Getenv("BUNDLE_IMG")
if bundleImg != "" {
By("installing using OLM bundle: " + bundleImg)

// Get the proper operator-sdk executable path (following Makefile logic)
operatorSDKPath, err := getOperatorSDKPath()
if err != nil {
ExpectWithOffset(1, err).NotTo(HaveOccurred(), "operator-sdk is required when BUNDLE_IMG is set")
}

// Check if operator-sdk is available and working
cmd = exec.Command(operatorSDKPath, "version")
_, err = utils.Run(cmd)
ExpectWithOffset(1, err).NotTo(HaveOccurred())
if err != nil {
ExpectWithOffset(1, err).NotTo(HaveOccurred(), "operator-sdk is required when BUNDLE_IMG is set")
}

By("loading the the manager(Operator) image on Kind")
err = utils.LoadImageToKindClusterWithName(operatorImage)
// Install OLM if not already present (skip on OpenShift as it has OLM built-in)
if !isOpenShift() {
By("installing OLM")
cmd = exec.Command(operatorSDKPath, "olm", "install")
_, err = utils.Run(cmd)
if err != nil {
By("OLM may already be installed, continuing...")
}
} else {
By("detected OpenShift - skipping OLM installation (already built-in)")
}

// Run bundle installation
By("deploying operator via OLM bundle")
cmd = exec.Command(operatorSDKPath, "run", "bundle", bundleImg, "--namespace", namespace)
outputMake, err = utils.Run(cmd)
ExpectWithOffset(1, err).NotTo(HaveOccurred())
}
} else {
By("installing using traditional deployment method")

By("installing CRDs")
cmd = exec.Command("make", "install")
_, err = utils.Run(cmd)
ExpectWithOffset(1, err).NotTo(HaveOccurred())
cmd = exec.Command("kind", "get", "clusters")
_, err = utils.Run(cmd)
if err == nil {
By("building the manager (Operator) image")
cmd = exec.Command("make", "docker-build", fmt.Sprintf("IMG=%s", operatorImage))
_, err = utils.Run(cmd)
ExpectWithOffset(1, err).NotTo(HaveOccurred())

By("loading the the manager(Operator) image on Kind")
err = utils.LoadImageToKindClusterWithName(operatorImage)
ExpectWithOffset(1, err).NotTo(HaveOccurred())
}

By("installing CRDs")
cmd = exec.Command("make", "install")
_, err = utils.Run(cmd)
ExpectWithOffset(1, err).NotTo(HaveOccurred())

By("deploying the controller-manager")
cmd = exec.Command("make", "deploy", fmt.Sprintf("IMG=%s", operatorImage))
outputMake, err := utils.Run(cmd)
ExpectWithOffset(1, err).NotTo(HaveOccurred())
By("deploying the controller-manager")
cmd = exec.Command("make", "deploy", fmt.Sprintf("IMG=%s", operatorImage))
outputMake, err = utils.Run(cmd)
ExpectWithOffset(1, err).NotTo(HaveOccurred())
}

By("validating that manager Pod/container(s) are not restricted")
ExpectWithOffset(1, outputMake).NotTo(ContainSubstring("Warning: would violate PodSecurity"))
Expand Down