diff --git a/.github/workflows/e2e.yaml b/.github/workflows/e2e.yaml new file mode 100644 index 000000000..ab880ed26 --- /dev/null +++ b/.github/workflows/e2e.yaml @@ -0,0 +1,20 @@ +name: e2e + +on: + workflow_dispatch: + pull_request: + push: + branches: + - main + +jobs: + e2e-kind: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v1 + - uses: actions/setup-go@v3 + with: + go-version-file: "go.mod" + - name: Run e2e tests + run: | + make e2e diff --git a/Makefile b/Makefile index 2f361a625..15215f9ee 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,15 @@ - +########################### +# Configuration Variables # +########################### # Image URL to use all building/pushing image targets -IMG ?= controller:latest +export IMAGE_REPO ?= quay.io/operator-framework/operator-controller +export IMAGE_TAG ?= devel +export GO_BUILD_TAGS ?= upstream +IMG?=$(IMAGE_REPO):$(IMAGE_TAG) + +OPERATOR_CONTROLLER_NAMESPACE ?= operator-controller-system +KIND_CLUSTER_NAME ?= operator-controller + # ENVTEST_K8S_VERSION refers to the version of kubebuilder assets to be downloaded by envtest binary. ENVTEST_K8S_VERSION = 1.25.0 @@ -16,6 +25,9 @@ endif SHELL = /usr/bin/env bash -o pipefail .SHELLFLAGS = -ec +# Disable -j flag for make +.NOTPARALLEL: + .PHONY: all all: build @@ -54,10 +66,28 @@ fmt: ## Run go fmt against code. vet: ## Run go vet against code. go vet ./... -.PHONY: test -test: manifests generate fmt vet envtest ## Run tests. +.PHONY: test test-e2e e2e kind-load kind-cluster kind-cluster-cleanup +test: manifests generate fmt vet envtest test-e2e ## Run all tests. KUBEBUILDER_ASSETS="$(shell $(ENVTEST) use $(ENVTEST_K8S_VERSION) --bin-dir $(LOCALBIN) -p path)" go test ./... -coverprofile cover.out +FOCUS := $(if $(TEST),-v -focus "$(TEST)") +E2E_FLAGS ?= "" +test-e2e: ginkgo ## Run the e2e tests + $(GINKGO) --tags $(GO_BUILD_TAGS) $(E2E_FLAGS) -trace -progress $(FOCUS) test/e2e + +e2e: KIND_CLUSTER_NAME=operator-controller-e2e +e2e: run test-e2e kind-cluster-cleanup ## Run e2e test suite on local kind cluster + +kind-load: kind ## Loads the currently constructed image onto the cluster + $(KIND) load docker-image $(IMG) --name $(KIND_CLUSTER_NAME) + +kind-cluster: kind kind-cluster-cleanup ## Standup a kind cluster + $(KIND) create cluster --name ${KIND_CLUSTER_NAME} + $(KIND) export kubeconfig --name ${KIND_CLUSTER_NAME} + +kind-cluster-cleanup: kind ## Delete the kind cluster + $(KIND) delete cluster --name ${KIND_CLUSTER_NAME} + ##@ Build .PHONY: build @@ -65,14 +95,17 @@ build: manifests generate fmt vet ## Build manager binary. go build -o bin/manager main.go .PHONY: run -run: manifests generate fmt vet ## Run a controller from your host. - go run ./main.go +run: docker-build kind-cluster kind-load install deploy wait ## Build the operator-controller then deploy it into a new kind cluster. + +.PHONY: wait +wait: + kubectl wait --for=condition=Available --namespace=$(OPERATOR_CONTROLLER_NAMESPACE) deployment/operator-controller-controller-manager --timeout=60s # If you wish built the manager image targeting other platforms you can use the --platform flag. # (i.e. docker build --platform linux/arm64 ). However, you must enable docker buildKit for it. # More info: https://docs.docker.com/develop/develop-images/build_enhancements/ .PHONY: docker-build -docker-build: test ## Build docker image with the manager. +docker-build: generate ## Build docker image with the operator-controller. docker build -t ${IMG} . .PHONY: docker-push @@ -129,12 +162,24 @@ $(LOCALBIN): ## Tool Binaries KUSTOMIZE ?= $(LOCALBIN)/kustomize CONTROLLER_GEN ?= $(LOCALBIN)/controller-gen +KIND ?= $(LOCALBIN)/kind +GINKGO ?= $(LOCALBIN)/ginkgo ENVTEST ?= $(LOCALBIN)/setup-envtest ## Tool Versions KUSTOMIZE_VERSION ?= v4.5.7 CONTROLLER_TOOLS_VERSION ?= v0.10.0 +.PHONY: kind +kind: $(KIND) ## Download kind locally if necessary. +$(KIND): $(LOCALBIN) + test -s $(LOCALBIN)/kind || GOBIN=$(LOCALBIN) go install sigs.k8s.io/kind@v0.15.0 + +.PHONY: ginkgo +ginkgo: $(GINKGO) ## Download ginkgo locally if necessary. +$(GINKGO): $(LOCALBIN) + test -s $(LOCALBIN)/ginkgo || GOBIN=$(LOCALBIN) go install github.com/onsi/ginkgo/v2/ginkgo@v2.1.4 + KUSTOMIZE_INSTALL_SCRIPT ?= "https://raw.githubusercontent.com/kubernetes-sigs/kustomize/master/hack/install_kustomize.sh" .PHONY: kustomize kustomize: $(KUSTOMIZE) ## Download kustomize locally if necessary. If wrong version is installed, it will be removed before downloading. diff --git a/config/manager/kustomization.yaml b/config/manager/kustomization.yaml index 5c5f0b84c..754433c31 100644 --- a/config/manager/kustomization.yaml +++ b/config/manager/kustomization.yaml @@ -1,2 +1,8 @@ resources: - manager.yaml +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +images: +- name: controller + newName: quay.io/operator-framework/operator-controller + newTag: devel diff --git a/config/manager/manager.yaml b/config/manager/manager.yaml index ff064e5d3..42a435060 100644 --- a/config/manager/manager.yaml +++ b/config/manager/manager.yaml @@ -71,6 +71,7 @@ spec: args: - --leader-elect image: controller:latest + imagePullPolicy: IfNotPresent name: manager securityContext: allowPrivilegeEscalation: false diff --git a/test/e2e/e2e_suite_test.go b/test/e2e/e2e_suite_test.go new file mode 100644 index 000000000..428c0b25f --- /dev/null +++ b/test/e2e/e2e_suite_test.go @@ -0,0 +1,38 @@ +package e2e + +import ( + "testing" + "time" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/client-go/rest" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + + operatorv1alpha1 "github.com/operator-framework/operator-controller/api/v1alpha1" +) + +var ( + cfg *rest.Config + c client.Client +) + +func TestE2E(t *testing.T) { + RegisterFailHandler(Fail) + SetDefaultEventuallyTimeout(1 * time.Minute) + SetDefaultEventuallyPollingInterval(1 * time.Second) + RunSpecs(t, "E2E Suite") +} + +var _ = BeforeSuite(func() { + cfg = ctrl.GetConfigOrDie() + + scheme := runtime.NewScheme() + err := operatorv1alpha1.AddToScheme(scheme) + Expect(err).To(Not(HaveOccurred())) + + c, err = client.New(cfg, client.Options{Scheme: scheme}) + Expect(err).To(Not(HaveOccurred())) +}) diff --git a/test/e2e/reconcile_test.go b/test/e2e/reconcile_test.go new file mode 100644 index 000000000..d2b993d55 --- /dev/null +++ b/test/e2e/reconcile_test.go @@ -0,0 +1,46 @@ +package e2e + +import ( + "context" + "fmt" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/util/rand" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + operatorv1alpha1 "github.com/operator-framework/operator-controller/api/v1alpha1" +) + +var _ = Describe("Operator Install", func() { + When("a valid Operator CR specifying a package", func() { + var ( + operator *operatorv1alpha1.Operator + ctx context.Context + err error + ) + BeforeEach(func() { + ctx = context.Background() + + operator = &operatorv1alpha1.Operator{ + ObjectMeta: metav1.ObjectMeta{ + Name: fmt.Sprintf("operator-%s", rand.String(8)), + }, + Spec: operatorv1alpha1.OperatorSpec{ + PackageName: "my-cool-package", + }, + } + err = c.Create(ctx, operator) + Expect(err).To(Not(HaveOccurred())) + }) + AfterEach(func() { + By("deleting the testing Operator resource") + err = c.Delete(ctx, operator) + Expect(err).To(Not(HaveOccurred())) + }) + PIt("installs the specified package", func() { + // Pending until we actually have some code to test + // Expect that a CRD and Deployment were successfully installed by rukpak + }) + }) +})