Makefile 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255
  1. # Image URL to use all building/pushing image targets
  2. IMG ?= controller:latest
  3. # Get the currently used golang install path (in GOPATH/bin, unless GOBIN is set)
  4. ifeq (,$(shell go env GOBIN))
  5. GOBIN=$(shell go env GOPATH)/bin
  6. else
  7. GOBIN=$(shell go env GOBIN)
  8. endif
  9. # CONTAINER_TOOL defines the container tool to be used for building images.
  10. # Be aware that the target commands are only tested with Docker which is
  11. # scaffolded by default. However, you might want to replace it to use other
  12. # tools. (i.e. podman)
  13. CONTAINER_TOOL ?= docker
  14. # Setting SHELL to bash allows bash commands to be executed by recipes.
  15. # Options are set to exit when a recipe line exits non-zero or a piped command fails.
  16. SHELL = /usr/bin/env bash -o pipefail
  17. .SHELLFLAGS = -ec
  18. .PHONY: all
  19. all: build
  20. ##@ General
  21. # The help target prints out all targets with their descriptions organized
  22. # beneath their categories. The categories are represented by '##@' and the
  23. # target descriptions by '##'. The awk command is responsible for reading the
  24. # entire set of makefiles included in this invocation, looking for lines of the
  25. # file as xyz: ## something, and then pretty-format the target and help. Then,
  26. # if there's a line with ##@ something, that gets pretty-printed as a category.
  27. # More info on the usage of ANSI control characters for terminal formatting:
  28. # https://en.wikipedia.org/wiki/ANSI_escape_code#SGR_parameters
  29. # More info on the awk command:
  30. # http://linuxcommand.org/lc3_adv_awk.php
  31. .PHONY: help
  32. help: ## Display this help.
  33. @awk 'BEGIN {FS = ":.*##"; printf "\nUsage:\n make \033[36m<target>\033[0m\n"} /^[a-zA-Z_0-9-]+:.*?##/ { printf " \033[36m%-15s\033[0m %s\n", $$1, $$2 } /^##@/ { printf "\n\033[1m%s\033[0m\n", substr($$0, 5) } ' $(MAKEFILE_LIST)
  34. ##@ Development
  35. .PHONY: manifests
  36. manifests: controller-gen ## Generate WebhookConfiguration, ClusterRole and CustomResourceDefinition objects.
  37. "$(CONTROLLER_GEN)" rbac:roleName=manager-role crd webhook paths="./..." output:crd:artifacts:config=config/crd/bases
  38. .PHONY: generate
  39. generate: controller-gen ## Generate code containing DeepCopy, DeepCopyInto, and DeepCopyObject method implementations.
  40. "$(CONTROLLER_GEN)" object:headerFile="hack/boilerplate.go.txt" paths="./..."
  41. .PHONY: fmt
  42. fmt: ## Run go fmt against code.
  43. go fmt ./...
  44. .PHONY: vet
  45. vet: ## Run go vet against code.
  46. go vet ./...
  47. .PHONY: test
  48. test: manifests generate fmt vet setup-envtest ## Run tests.
  49. KUBEBUILDER_ASSETS="$(shell "$(ENVTEST)" use $(ENVTEST_K8S_VERSION) --bin-dir "$(LOCALBIN)" -p path)" go test $$(go list ./... | grep -v /e2e) -coverprofile cover.out
  50. # TODO(user): To use a different vendor for e2e tests, modify the setup under 'tests/e2e'.
  51. # The default setup assumes Kind is pre-installed and builds/loads the Manager Docker image locally.
  52. # CertManager is installed by default; skip with:
  53. # - CERT_MANAGER_INSTALL_SKIP=true
  54. KIND_CLUSTER ?= loco-operator-test-e2e
  55. .PHONY: setup-test-e2e
  56. setup-test-e2e: ## Set up a Kind cluster for e2e tests if it does not exist
  57. @command -v $(KIND) >/dev/null 2>&1 || { \
  58. echo "Kind is not installed. Please install Kind manually."; \
  59. exit 1; \
  60. }
  61. @case "$$($(KIND) get clusters)" in \
  62. *"$(KIND_CLUSTER)"*) \
  63. echo "Kind cluster '$(KIND_CLUSTER)' already exists. Skipping creation." ;; \
  64. *) \
  65. echo "Creating Kind cluster '$(KIND_CLUSTER)'..."; \
  66. $(KIND) create cluster --name $(KIND_CLUSTER) ;; \
  67. esac
  68. .PHONY: test-e2e
  69. test-e2e: setup-test-e2e manifests generate fmt vet ## Run the e2e tests. Expected an isolated environment using Kind.
  70. KIND=$(KIND) KIND_CLUSTER=$(KIND_CLUSTER) go test -tags=e2e ./test/e2e/ -v -ginkgo.v
  71. $(MAKE) cleanup-test-e2e
  72. .PHONY: cleanup-test-e2e
  73. cleanup-test-e2e: ## Tear down the Kind cluster used for e2e tests
  74. @$(KIND) delete cluster --name $(KIND_CLUSTER)
  75. .PHONY: lint
  76. lint: golangci-lint ## Run golangci-lint linter
  77. "$(GOLANGCI_LINT)" run
  78. .PHONY: lint-fix
  79. lint-fix: golangci-lint ## Run golangci-lint linter and perform fixes
  80. "$(GOLANGCI_LINT)" run --fix
  81. .PHONY: lint-config
  82. lint-config: golangci-lint ## Verify golangci-lint linter configuration
  83. "$(GOLANGCI_LINT)" config verify
  84. ##@ Build
  85. .PHONY: build
  86. build: manifests generate fmt vet ## Build manager binary.
  87. go build -o bin/manager cmd/main.go
  88. .PHONY: run
  89. run: manifests generate fmt vet ## Run a controller from your host.
  90. go run ./cmd/main.go
  91. # If you wish to build the manager image targeting other platforms you can use the --platform flag.
  92. # (i.e. docker build --platform linux/arm64). However, you must enable docker buildKit for it.
  93. # More info: https://docs.docker.com/develop/develop-images/build_enhancements/
  94. .PHONY: docker-build
  95. docker-build: ## Build docker image with the manager.
  96. $(CONTAINER_TOOL) build -t ${IMG} .
  97. .PHONY: docker-push
  98. docker-push: ## Push docker image with the manager.
  99. $(CONTAINER_TOOL) push ${IMG}
  100. # PLATFORMS defines the target platforms for the manager image be built to provide support to multiple
  101. # architectures. (i.e. make docker-buildx IMG=myregistry/mypoperator:0.0.1). To use this option you need to:
  102. # - be able to use docker buildx. More info: https://docs.docker.com/build/buildx/
  103. # - have enabled BuildKit. More info: https://docs.docker.com/develop/develop-images/build_enhancements/
  104. # - be able to push the image to your registry (i.e. if you do not set a valid value via IMG=<myregistry/image:<tag>> then the export will fail)
  105. # To adequately provide solutions that are compatible with multiple platforms, you should consider using this option.
  106. PLATFORMS ?= linux/arm64,linux/amd64,linux/s390x,linux/ppc64le
  107. .PHONY: docker-buildx
  108. docker-buildx: ## Build and push docker image for the manager for cross-platform support
  109. # copy existing Dockerfile and insert --platform=${BUILDPLATFORM} into Dockerfile.cross, and preserve the original Dockerfile
  110. sed -e '1 s/\(^FROM\)/FROM --platform=\$$\{BUILDPLATFORM\}/; t' -e ' 1,// s//FROM --platform=\$$\{BUILDPLATFORM\}/' Dockerfile > Dockerfile.cross
  111. - $(CONTAINER_TOOL) buildx create --name loco-operator-builder
  112. $(CONTAINER_TOOL) buildx use loco-operator-builder
  113. - $(CONTAINER_TOOL) buildx build --push --platform=$(PLATFORMS) --tag ${IMG} -f Dockerfile.cross .
  114. - $(CONTAINER_TOOL) buildx rm loco-operator-builder
  115. rm Dockerfile.cross
  116. .PHONY: build-installer
  117. build-installer: manifests generate kustomize ## Generate a consolidated YAML with CRDs and deployment.
  118. mkdir -p dist
  119. cd config/manager && "$(KUSTOMIZE)" edit set image controller=${IMG}
  120. "$(KUSTOMIZE)" build config/default > dist/install.yaml
  121. ##@ Deployment
  122. ifndef ignore-not-found
  123. ignore-not-found = false
  124. endif
  125. .PHONY: install
  126. install: manifests kustomize ## Install CRDs into the K8s cluster specified in ~/.kube/config.
  127. @out="$$( "$(KUSTOMIZE)" build config/crd 2>/dev/null || true )"; \
  128. if [ -n "$$out" ]; then echo "$$out" | "$(KUBECTL)" apply -f -; else echo "No CRDs to install; skipping."; fi
  129. .PHONY: uninstall
  130. uninstall: manifests kustomize ## Uninstall CRDs from the K8s cluster specified in ~/.kube/config. Call with ignore-not-found=true to ignore resource not found errors during deletion.
  131. @out="$$( "$(KUSTOMIZE)" build config/crd 2>/dev/null || true )"; \
  132. if [ -n "$$out" ]; then echo "$$out" | "$(KUBECTL)" delete --ignore-not-found=$(ignore-not-found) -f -; else echo "No CRDs to delete; skipping."; fi
  133. .PHONY: deploy
  134. deploy: manifests kustomize ## Deploy controller to the K8s cluster specified in ~/.kube/config.
  135. cd config/manager && "$(KUSTOMIZE)" edit set image controller=${IMG}
  136. "$(KUSTOMIZE)" build config/default | "$(KUBECTL)" apply -f -
  137. .PHONY: undeploy
  138. undeploy: kustomize ## Undeploy controller from the K8s cluster specified in ~/.kube/config. Call with ignore-not-found=true to ignore resource not found errors during deletion.
  139. "$(KUSTOMIZE)" build config/default | "$(KUBECTL)" delete --ignore-not-found=$(ignore-not-found) -f -
  140. ##@ Dependencies
  141. ## Location to install dependencies to
  142. LOCALBIN ?= $(shell pwd)/bin
  143. $(LOCALBIN):
  144. mkdir -p "$(LOCALBIN)"
  145. ## Tool Binaries
  146. KUBECTL ?= kubectl
  147. KIND ?= kind
  148. KUSTOMIZE ?= $(LOCALBIN)/kustomize
  149. CONTROLLER_GEN ?= $(LOCALBIN)/controller-gen
  150. ENVTEST ?= $(LOCALBIN)/setup-envtest
  151. GOLANGCI_LINT = $(LOCALBIN)/golangci-lint
  152. ## Tool Versions
  153. KUSTOMIZE_VERSION ?= v5.8.1
  154. CONTROLLER_TOOLS_VERSION ?= v0.20.1
  155. #ENVTEST_VERSION is the version of controller-runtime release branch to fetch the envtest setup script (i.e. release-0.20)
  156. ENVTEST_VERSION ?= $(shell v='$(call gomodver,sigs.k8s.io/controller-runtime)'; \
  157. [ -n "$$v" ] || { echo "Set ENVTEST_VERSION manually (controller-runtime replace has no tag)" >&2; exit 1; }; \
  158. printf '%s\n' "$$v" | sed -E 's/^v?([0-9]+)\.([0-9]+).*/release-\1.\2/')
  159. #ENVTEST_K8S_VERSION is the version of Kubernetes to use for setting up ENVTEST binaries (i.e. 1.31)
  160. ENVTEST_K8S_VERSION ?= $(shell v='$(call gomodver,k8s.io/api)'; \
  161. [ -n "$$v" ] || { echo "Set ENVTEST_K8S_VERSION manually (k8s.io/api replace has no tag)" >&2; exit 1; }; \
  162. printf '%s\n' "$$v" | sed -E 's/^v?[0-9]+\.([0-9]+).*/1.\1/')
  163. GOLANGCI_LINT_VERSION ?= v2.8.0
  164. .PHONY: kustomize
  165. kustomize: $(KUSTOMIZE) ## Download kustomize locally if necessary.
  166. $(KUSTOMIZE): $(LOCALBIN)
  167. $(call go-install-tool,$(KUSTOMIZE),sigs.k8s.io/kustomize/kustomize/v5,$(KUSTOMIZE_VERSION))
  168. .PHONY: controller-gen
  169. controller-gen: $(CONTROLLER_GEN) ## Download controller-gen locally if necessary.
  170. $(CONTROLLER_GEN): $(LOCALBIN)
  171. $(call go-install-tool,$(CONTROLLER_GEN),sigs.k8s.io/controller-tools/cmd/controller-gen,$(CONTROLLER_TOOLS_VERSION))
  172. .PHONY: setup-envtest
  173. setup-envtest: envtest ## Download the binaries required for ENVTEST in the local bin directory.
  174. @echo "Setting up envtest binaries for Kubernetes version $(ENVTEST_K8S_VERSION)..."
  175. @"$(ENVTEST)" use $(ENVTEST_K8S_VERSION) --bin-dir "$(LOCALBIN)" -p path || { \
  176. echo "Error: Failed to set up envtest binaries for version $(ENVTEST_K8S_VERSION)."; \
  177. exit 1; \
  178. }
  179. .PHONY: envtest
  180. envtest: $(ENVTEST) ## Download setup-envtest locally if necessary.
  181. $(ENVTEST): $(LOCALBIN)
  182. $(call go-install-tool,$(ENVTEST),sigs.k8s.io/controller-runtime/tools/setup-envtest,$(ENVTEST_VERSION))
  183. .PHONY: golangci-lint
  184. golangci-lint: $(GOLANGCI_LINT) ## Download golangci-lint locally if necessary.
  185. $(GOLANGCI_LINT): $(LOCALBIN)
  186. $(call go-install-tool,$(GOLANGCI_LINT),github.com/golangci/golangci-lint/v2/cmd/golangci-lint,$(GOLANGCI_LINT_VERSION))
  187. @test -f .custom-gcl.yml && { \
  188. echo "Building custom golangci-lint with plugins..." && \
  189. $(GOLANGCI_LINT) custom --destination $(LOCALBIN) --name golangci-lint-custom && \
  190. mv -f $(LOCALBIN)/golangci-lint-custom $(GOLANGCI_LINT); \
  191. } || true
  192. # go-install-tool will 'go install' any package with custom target and name of binary, if it doesn't exist
  193. # $1 - target path with name of binary
  194. # $2 - package url which can be installed
  195. # $3 - specific version of package
  196. define go-install-tool
  197. @[ -f "$(1)-$(3)" ] && [ "$$(readlink -- "$(1)" 2>/dev/null)" = "$(1)-$(3)" ] || { \
  198. set -e; \
  199. package=$(2)@$(3) ;\
  200. echo "Downloading $${package}" ;\
  201. rm -f "$(1)" ;\
  202. GOBIN="$(LOCALBIN)" go install $${package} ;\
  203. mv "$(LOCALBIN)/$$(basename "$(1)")" "$(1)-$(3)" ;\
  204. } ;\
  205. ln -sf "$$(realpath "$(1)-$(3)")" "$(1)"
  206. endef
  207. define gomodver
  208. $(shell go list -m -f '{{if .Replace}}{{.Replace.Version}}{{else}}{{.Version}}{{end}}' $(1) 2>/dev/null)
  209. endef