diff --git a/.github/common-actions/e2e-test-cli/action.yaml b/.github/common-actions/e2e-test-cli/action.yaml index c137a09..8ceb401 100644 --- a/.github/common-actions/e2e-test-cli/action.yaml +++ b/.github/common-actions/e2e-test-cli/action.yaml @@ -26,7 +26,7 @@ runs: working-directory: /tmp/operator-builder-test run: | if [[ "${{ inputs.test-deploy }}" == "true" ]]; then - COMMAND=`find ${PWD}/bin ! -name kustomize ! -name controller-gen ! -name operator-builder ! -name kube-apiserver ! -name etcd ! -name kubectl ! -name setup-envtest -type f` + COMMAND=`find ${PWD}/bin ! -name "*kustomize*" ! -name "*controller-gen*" ! -name operator-builder ! -name kube-apiserver ! -name etcd ! -name kubectl ! -name "*setup-envtest*" -type f` echo $COMMAND MANIFEST=`find ${PWD}/config/samples ! -name kustomization.yaml -name "*.yaml" | head -1` echo $MANIFEST diff --git a/.github/common-actions/e2e-test/action.yaml b/.github/common-actions/e2e-test/action.yaml index f58a388..ecf8203 100644 --- a/.github/common-actions/e2e-test/action.yaml +++ b/.github/common-actions/e2e-test/action.yaml @@ -42,7 +42,7 @@ runs: working-directory: /tmp/operator-builder-test run: | make controller-gen && make kustomize - chmod +x bin/controller-gen && chmod +x bin/kustomize + chmod +x bin/* make install - name: Build Container diff --git a/internal/plugins/workload/v1/scaffolds/init.go b/internal/plugins/workload/v1/scaffolds/init.go index 8c8f39c..6ff37cf 100644 --- a/internal/plugins/workload/v1/scaffolds/init.go +++ b/internal/plugins/workload/v1/scaffolds/init.go @@ -12,21 +12,16 @@ import ( "sigs.k8s.io/kubebuilder/v3/pkg/config" "sigs.k8s.io/kubebuilder/v3/pkg/machinery" "sigs.k8s.io/kubebuilder/v3/pkg/plugins" - kustomizecommonv1 "sigs.k8s.io/kubebuilder/v3/pkg/plugins/common/kustomize/v1" "github.com/nukleros/operator-builder/internal/plugins/workload/v1/scaffolds/templates" "github.com/nukleros/operator-builder/internal/plugins/workload/v1/scaffolds/templates/cli" "github.com/nukleros/operator-builder/internal/plugins/workload/v1/scaffolds/templates/config/manifests" "github.com/nukleros/operator-builder/internal/plugins/workload/v1/scaffolds/templates/config/scorecard" "github.com/nukleros/operator-builder/internal/plugins/workload/v1/scaffolds/templates/test/e2e" + "github.com/nukleros/operator-builder/internal/utils" "github.com/nukleros/operator-builder/internal/workload/v1/kinds" ) -const ( - operatorSDKVersion = "v1.28.0" - controllerToolsVersion = "v0.14.0" -) - var _ plugins.Scaffolder = &initScaffolder{} type initScaffolder struct { @@ -100,12 +95,16 @@ func (s *initScaffolder) Scaffold() error { ControllerImg: s.controllerImg, }, &templates.Makefile{ - RootCmdName: s.cliRootCommandName, - ControllerImg: s.controllerImg, - EnableOLM: s.enableOlm, - KustomizeVersion: kustomizecommonv1.KustomizeVersion, - ControllerToolsVersion: controllerToolsVersion, - OperatorSDKVersion: operatorSDKVersion, + RootCmdName: s.cliRootCommandName, + ControllerImg: s.controllerImg, + EnableOLM: s.enableOlm, + KustomizeVersion: utils.KustomizeVersion, + ControllerToolsVersion: utils.ControllerToolsVersion, + OperatorSDKVersion: utils.OperatorSDKVersion, + ControllerRuntimeVersion: utils.ControllerRuntimeVersion, + EnvtestVersion: utils.EnvtestVersion, + EnvtestK8SVersion: utils.EnvtestK8SVersion, + GolangCILintVersion: utils.GolangCILintVersion, }, &e2e.Test{}, ); err != nil { diff --git a/internal/plugins/workload/v1/scaffolds/templates/gomod.go b/internal/plugins/workload/v1/scaffolds/templates/gomod.go index 3f0c678..aaf5aad 100644 --- a/internal/plugins/workload/v1/scaffolds/templates/gomod.go +++ b/internal/plugins/workload/v1/scaffolds/templates/gomod.go @@ -38,9 +38,11 @@ func goModDependencyMap() map[string]string { "k8s.io/api": "v0.29.4", "k8s.io/apimachinery": "v0.29.4", "k8s.io/client-go": "v0.29.4", - "sigs.k8s.io/controller-runtime": "v0.17.3", "sigs.k8s.io/kubebuilder/v3": "v3.7.0", "sigs.k8s.io/yaml": "v1.4.0", + + // externally versioned packages via the utils package + "sigs.k8s.io/controller-runtime": utils.ControllerRuntimeVersion, } } diff --git a/internal/plugins/workload/v1/scaffolds/templates/makefile.go b/internal/plugins/workload/v1/scaffolds/templates/makefile.go index e7685b1..b01cda9 100644 --- a/internal/plugins/workload/v1/scaffolds/templates/makefile.go +++ b/internal/plugins/workload/v1/scaffolds/templates/makefile.go @@ -26,9 +26,13 @@ type Makefile struct { ControllerImg string EnableOLM bool - ControllerToolsVersion string - KustomizeVersion string - OperatorSDKVersion string + ControllerToolsVersion string + KustomizeVersion string + OperatorSDKVersion string + ControllerRuntimeVersion string + EnvtestVersion string + EnvtestK8SVersion string + GolangCILintVersion string } func (f *Makefile) SetTemplateDefaults() error { @@ -41,6 +45,20 @@ func (f *Makefile) SetTemplateDefaults() error { f.IfExistsAction = machinery.OverwriteFile + //nolint:godox + // TODO: Current workaround for setup-envtest compatibility + // Due to past instances where controller-runtime maintainers released + // versions without corresponding branches, directly relying on branches + // poses a risk of breaking the Kubebuilder chain. Such practices may + // change over time, potentially leading to compatibility issues. This + // approach, although not ideal, remains the best solution for ensuring + // compatibility with controller-runtime releases as of now. For more + // details on the quest for a more robust solution, refer to the issue + // raised in the controller-runtime repository: https://github.com/kubernetes-sigs/controller-runtime/issues/2744 + if f.EnvtestVersion == "" { + f.EnvtestVersion = "latest" + } + return nil } @@ -54,10 +72,12 @@ const makeHelp = `help: ## Display this help. const makefileTemplate = ` # Image URL to use all building/pushing image targets IMG ?= "{{ .ControllerImg }}" + # Produce CRDs that work back to Kubernetes 1.11 (no version conversion) CRD_OPTIONS ?= "crd:crdVersions=v1" + # ENVTEST_K8S_VERSION refers to the version of kubebuilder assets to be downloaded by envtest binary. -ENVTEST_K8S_VERSION = 1.26.1 +ENVTEST_K8S_VERSION = 1.30.0 # Get the currently used golang install path (in GOPATH/bin, unless GOBIN is set) ifeq (,$(shell go env GOBIN)) @@ -66,6 +86,12 @@ else GOBIN=$(shell go env GOBIN) endif +# CONTAINER_TOOL defines the container tool to be used for building images. +# Be aware that the target commands are only tested with Docker which is +# scaffolded by default. However, you might want to replace it to use other +# tools. (i.e. podman) +CONTAINER_TOOL ?= docker + # Setting SHELL to bash allows bash commands to be executed by recipes. # Options are set to exit when a recipe line exits non-zero or a piped command fails. SHELL = /usr/bin/env bash -o pipefail @@ -109,12 +135,20 @@ vet: ## Run go vet against code. .PHONY: test test: manifests generate fmt vet envtest ## Run tests. - KUBEBUILDER_ASSETS="$(shell $(ENVTEST) use $(ENVTEST_K8S_VERSION) --bin-dir $(LOCALBIN) -p path)" go test ./... -coverprofile cover.out + KUBEBUILDER_ASSETS="$(shell $(ENVTEST) use $(ENVTEST_K8S_VERSION) --bin-dir $(LOCALBIN) -p path)" go test $$(go list ./... | grep -v /e2e) -coverprofile cover.out .PHONY: test-e2e test-e2e: ## Run E2E tests against a running Kubernetes cluster. go test {{ .Repo }}/test/e2e -tags=e2e_test -count=1 +.PHONY: lint +lint: golangci-lint ## Run golangci-lint linter + $(GOLANGCI_LINT) run + +.PHONY: lint-fix +lint-fix: golangci-lint ## Run golangci-lint linter and perform fixes + $(GOLANGCI_LINT) run --fix + ##@ Build .PHONY: build @@ -130,11 +164,11 @@ run: manifests generate fmt vet ## Run a controller from your host. # 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 -t $(IMG) . + $(CONTAINER_TOOL) build -t $(IMG) . .PHONY: docker-push docker-push: ## Push docker image with the manager. - docker push $(IMG) + $(CONTAINER_TOOL) push $(IMG) # PLATFORMS defines the target platforms for the manager image be build to provide support to multiple # architectures. (i.e. make docker-buildx IMG=myregistry/mypoperator:0.0.1). To use this option you need to: @@ -147,12 +181,18 @@ PLATFORMS ?= linux/arm64,linux/amd64,linux/s390x,linux/ppc64le docker-buildx: test ## Build and push docker image for the manager for cross-platform support # copy existing Dockerfile and insert --platform=${BUILDPLATFORM} into Dockerfile.cross, and preserve the original Dockerfile sed -e '1 s/\(^FROM\)/FROM --platform=\$$\{BUILDPLATFORM\}/; t' -e ' 1,// s//FROM --platform=\$$\{BUILDPLATFORM\}/' Dockerfile > Dockerfile.cross - - docker buildx create --name project-v3-builder - docker buildx use project-v3-builder - - docker buildx build --push --platform=$(PLATFORMS) --tag ${IMG} -f Dockerfile.cross . - - docker buildx rm project-v3-builder + - $(CONTAINER_TOOL) buildx create --name {{ .ProjectName }}-builder + $(CONTAINER_TOOL) buildx use {{ .ProjectName }}-builder + - $(CONTAINER_TOOL) buildx build --push --platform=$(PLATFORMS) --tag ${IMG} -f Dockerfile.cross . + - $(CONTAINER_TOOL) buildx rm {{ .ProjectName }}-builder rm Dockerfile.cross +.PHONY: build-installer +build-installer: manifests generate kustomize ## Generate a consolidated YAML with CRDs and deployment. + mkdir -p dist + cd config/manager && $(KUSTOMIZE) edit set image controller=${IMG} + $(KUSTOMIZE) build config/default > dist/install.yaml + ##@ Deployment ifndef ignore-not-found @@ -176,7 +216,7 @@ deploy: manifests kustomize ## Deploy controller to the K8s cluster specified in undeploy: ## Undeploy controller from the K8s cluster specified in ~/.kube/config. Call with ignore-not-found=true to ignore resource not found errors during deletion. $(KUSTOMIZE) build config/default | kubectl delete --ignore-not-found=$(ignore-not-found) -f - -##@ Build Dependencies +##@ Dependencies ## Location to install dependencies to LOCALBIN ?= $(shell pwd)/bin @@ -184,34 +224,51 @@ $(LOCALBIN): mkdir -p $(LOCALBIN) ## Tool Binaries -KUSTOMIZE ?= $(LOCALBIN)/kustomize -CONTROLLER_GEN ?= $(LOCALBIN)/controller-gen -ENVTEST ?= $(LOCALBIN)/setup-envtest +KUBECTL ?= kubectl +KUSTOMIZE ?= $(LOCALBIN)/kustomize-$(KUSTOMIZE_VERSION) +CONTROLLER_GEN ?= $(LOCALBIN)/controller-gen-$(CONTROLLER_TOOLS_VERSION) +ENVTEST ?= $(LOCALBIN)/setup-envtest-$(ENVTEST_VERSION) +GOLANGCI_LINT = $(LOCALBIN)/golangci-lint-$(GOLANGCI_LINT_VERSION) ## Tool Versions KUSTOMIZE_VERSION ?= {{ .KustomizeVersion }} CONTROLLER_TOOLS_VERSION ?= {{ .ControllerToolsVersion }} +ENVTEST_VERSION ?= {{ .EnvtestVersion }} +GOLANGCI_LINT_VERSION ?= v1.57.2 -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. +kustomize: $(KUSTOMIZE) ## Download kustomize locally if necessary. $(KUSTOMIZE): $(LOCALBIN) - @if test -x $(LOCALBIN)/kustomize && ! $(LOCALBIN)/kustomize version | grep -q $(KUSTOMIZE_VERSION); then \ - echo "$(LOCALBIN)/kustomize version is not expected $(KUSTOMIZE_VERSION). Removing it before installing."; \ - rm -rf $(LOCALBIN)/kustomize; \ - fi - test -s $(LOCALBIN)/kustomize || { curl -Ss $(KUSTOMIZE_INSTALL_SCRIPT) --output install_kustomize.sh && bash install_kustomize.sh $(subst v,,$(KUSTOMIZE_VERSION)) $(LOCALBIN); rm install_kustomize.sh; } + $(call go-install-tool,$(KUSTOMIZE),sigs.k8s.io/kustomize/kustomize/v5,$(KUSTOMIZE_VERSION)) .PHONY: controller-gen -controller-gen: $(CONTROLLER_GEN) ## Download controller-gen locally if necessary. If wrong version is installed, it will be overwritten. +controller-gen: $(CONTROLLER_GEN) ## Download controller-gen locally if necessary. $(CONTROLLER_GEN): $(LOCALBIN) - test -s $(LOCALBIN)/controller-gen && $(LOCALBIN)/controller-gen --version | grep -q $(CONTROLLER_TOOLS_VERSION) || \ - GOBIN=$(LOCALBIN) go install sigs.k8s.io/controller-tools/cmd/controller-gen@$(CONTROLLER_TOOLS_VERSION) + $(call go-install-tool,$(CONTROLLER_GEN),sigs.k8s.io/controller-tools/cmd/controller-gen,$(CONTROLLER_TOOLS_VERSION)) .PHONY: envtest -envtest: $(ENVTEST) ## Download envtest-setup locally if necessary. +envtest: $(ENVTEST) ## Download setup-envtest locally if necessary. $(ENVTEST): $(LOCALBIN) - test -s $(LOCALBIN)/setup-envtest || GOBIN=$(LOCALBIN) go install sigs.k8s.io/controller-runtime/tools/setup-envtest@latest + $(call go-install-tool,$(ENVTEST),sigs.k8s.io/controller-runtime/tools/setup-envtest,$(ENVTEST_VERSION)) + +.PHONY: golangci-lint +golangci-lint: $(GOLANGCI_LINT) ## Download golangci-lint locally if necessary. +$(GOLANGCI_LINT): $(LOCALBIN) + $(call go-install-tool,$(GOLANGCI_LINT),github.com/golangci/golangci-lint/cmd/golangci-lint,${GOLANGCI_LINT_VERSION}) + +# go-install-tool will 'go install' any package with custom target and name of binary, if it doesn't exist +# $1 - target path with name of binary (ideally with version) +# $2 - package url which can be installed +# $3 - specific version of package +define go-install-tool +@[ -f $(1) ] || { \ +set -e; \ +package=$(2)@$(3) ;\ +echo "Downloading $${package}" ;\ +GOBIN=$(LOCALBIN) go install $${package} ;\ +mv "$$(echo "$(1)" | sed "s/-$(3)$$//")" $(1) ;\ +} +endef {{ if .EnableOLM -}} ##@ Operator Lifecycle Manager diff --git a/internal/utils/version.go b/internal/utils/version.go index 6dc6cc9..384df81 100644 --- a/internal/utils/version.go +++ b/internal/utils/version.go @@ -10,4 +10,13 @@ const ( // specifies the preferred version. GeneratedGoVersionPreferred = "1.22" + + // makefile and go.mod versions. + ControllerToolsVersion = "v0.15.0" + ControllerRuntimeVersion = "v0.17.3" + KustomizeVersion = "v5.4.1" + GolangCILintVersion = "v1.57.2" + EnvtestVersion = "release-0.17" + EnvtestK8SVersion = "1.30.0" + OperatorSDKVersion = "v1.28.0" )