sigs.k8s.io/cluster-api-provider-azure@v1.17.0/Makefile (about)

     1  # Copyright 2018 The Kubernetes Authors.
     2  #
     3  # Licensed under the Apache License, Version 2.0 (the "License");
     4  # you may not use this file except in compliance with the License.
     5  # You may obtain a copy of the License at
     6  #
     7  #     http://www.apache.org/licenses/LICENSE-2.0
     8  #
     9  # Unless required by applicable law or agreed to in writing, software
    10  # distributed under the License is distributed on an "AS IS" BASIS,
    11  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  # See the License for the specific language governing permissions and
    13  # limitations under the License.
    14  
    15  # If you update this file, please follow
    16  # https://suva.sh/en/writings/well-documented-makefiles
    17  
    18  # Ensure Make is run with bash shell as some syntax below is bash-specific
    19  SHELL:=/usr/bin/env bash
    20  
    21  .DEFAULT_GOAL:=help
    22  
    23  GOPATH  := $(shell go env GOPATH)
    24  GOARCH  := $(shell go env GOARCH)
    25  GOOS    := $(shell go env GOOS)
    26  GOPROXY := $(shell go env GOPROXY)
    27  ifeq ($(GOPROXY),)
    28  GOPROXY := https://proxy.golang.org
    29  endif
    30  export GOPROXY
    31  
    32  # Active module mode, as we use go modules to manage dependencies
    33  export GO111MODULE=on
    34  
    35  # Kubebuilder.
    36  export KUBEBUILDER_ENVTEST_KUBERNETES_VERSION ?= 1.31.0
    37  export KUBEBUILDER_CONTROLPLANE_START_TIMEOUT ?= 60s
    38  export KUBEBUILDER_CONTROLPLANE_STOP_TIMEOUT ?= 60s
    39  
    40  # This option is for running docker manifest command
    41  export DOCKER_CLI_EXPERIMENTAL := enabled
    42  
    43  # curl retries
    44  CURL_RETRIES=3
    45  
    46  # Directories.
    47  ROOT_DIR := $(shell dirname $(realpath $(firstword $(MAKEFILE_LIST))))
    48  TOOLS_DIR := hack/tools
    49  TOOLS_BIN_DIR := $(abspath $(TOOLS_DIR)/bin)
    50  TEMPLATES_DIR := $(ROOT_DIR)/templates
    51  BIN_DIR := $(abspath $(ROOT_DIR)/bin)
    52  EXP_DIR := exp
    53  GO_INSTALL = ./scripts/go_install.sh
    54  E2E_DATA_DIR ?= $(ROOT_DIR)/test/e2e/data
    55  KUBETEST_CONF_PATH ?= $(abspath $(E2E_DATA_DIR)/kubetest/conformance.yaml)
    56  KUBETEST_WINDOWS_CONFIG ?= upstream-windows.yaml
    57  KUBETEST_WINDOWS_CONF_PATH ?= $(abspath $(E2E_DATA_DIR)/kubetest/$(KUBETEST_WINDOWS_CONFIG))
    58  KUBETEST_REPO_LIST_PATH ?= $(abspath $(E2E_DATA_DIR)/kubetest/)
    59  AZURE_TEMPLATES := $(E2E_DATA_DIR)/infrastructure-azure
    60  ADDONS_DIR := templates/addons
    61  CONVERSION_VERIFIER := $(TOOLS_BIN_DIR)/conversion-verifier
    62  
    63  # use the project local tool binaries first
    64  export PATH := $(TOOLS_BIN_DIR):$(PATH)
    65  
    66  # set --output-base used for conversion-gen which needs to be different for in GOPATH and outside GOPATH dev
    67  ifneq ($(abspath $(ROOT_DIR)),$(GOPATH)/src/sigs.k8s.io/cluster-api-provider-azure)
    68    OUTPUT_BASE := --output-base=$(ROOT_DIR)
    69  endif
    70  
    71  # Binaries.
    72  CONTROLLER_GEN_VER := v0.15.0
    73  CONTROLLER_GEN_BIN := controller-gen
    74  CONTROLLER_GEN := $(TOOLS_BIN_DIR)/$(CONTROLLER_GEN_BIN)-$(CONTROLLER_GEN_VER)
    75  
    76  CONVERSION_GEN_VER := v0.30.0
    77  CONVERSION_GEN_BIN := conversion-gen
    78  CONVERSION_GEN := $(TOOLS_BIN_DIR)/$(CONVERSION_GEN_BIN)-$(CONVERSION_GEN_VER)
    79  
    80  ENVSUBST_VER := $(shell go list -m -f '{{.Version}}' github.com/drone/envsubst/v2)
    81  ENVSUBST_BIN := envsubst
    82  ENVSUBST := $(TOOLS_BIN_DIR)/$(ENVSUBST_BIN)-$(ENVSUBST_VER)
    83  
    84  GOLANGCI_LINT_VER := v1.55.2
    85  GOLANGCI_LINT_BIN := golangci-lint
    86  GOLANGCI_LINT := $(TOOLS_BIN_DIR)/$(GOLANGCI_LINT_BIN)-$(GOLANGCI_LINT_VER)
    87  
    88  KUSTOMIZE_VER := v5.4.1
    89  KUSTOMIZE_BIN := kustomize
    90  KUSTOMIZE := $(TOOLS_BIN_DIR)/$(KUSTOMIZE_BIN)-$(KUSTOMIZE_VER)
    91  
    92  AZWI_VER := v1.2.2
    93  AZWI_BIN := azwi
    94  AZWI := $(TOOLS_BIN_DIR)/$(AZWI_BIN)-$(AZWI_VER)
    95  
    96  MOCKGEN_VER := v0.4.0
    97  MOCKGEN_BIN := mockgen
    98  MOCKGEN := $(TOOLS_BIN_DIR)/$(MOCKGEN_BIN)-$(MOCKGEN_VER)
    99  
   100  RELEASE_NOTES_VER := v0.16.6-0.20240222112346-71feb57b59a4
   101  RELEASE_NOTES_BIN := release-notes
   102  RELEASE_NOTES := $(TOOLS_BIN_DIR)/$(RELEASE_NOTES_BIN)-$(RELEASE_NOTES_VER)
   103  
   104  KPROMO_VER := v4.0.5
   105  KPROMO_BIN := kpromo
   106  KPROMO := $(TOOLS_BIN_DIR)/$(KPROMO_BIN)-$(KPROMO_VER)
   107  
   108  GO_APIDIFF_VER := v0.8.2
   109  GO_APIDIFF_BIN := go-apidiff
   110  GO_APIDIFF := $(TOOLS_BIN_DIR)/$(GO_APIDIFF_BIN)
   111  
   112  GINKGO_VER := $(shell go list -m -f '{{.Version}}' github.com/onsi/ginkgo/v2)
   113  GINKGO_BIN := ginkgo
   114  GINKGO := $(TOOLS_BIN_DIR)/$(GINKGO_BIN)-$(GINKGO_VER)
   115  
   116  KUBECTL_VER := v1.28.4
   117  KUBECTL_BIN := kubectl
   118  KUBECTL := $(TOOLS_BIN_DIR)/$(KUBECTL_BIN)-$(KUBECTL_VER)
   119  
   120  HELM_VER := v3.14.4
   121  HELM_BIN := helm
   122  HELM := $(TOOLS_BIN_DIR)/$(HELM_BIN)-$(HELM_VER)
   123  
   124  YQ_VER := v4.35.2
   125  YQ_BIN := yq
   126  YQ :=  $(TOOLS_BIN_DIR)/$(YQ_BIN)-$(YQ_VER)
   127  
   128  KIND_VER := $(shell go list -m -f '{{.Version}}' sigs.k8s.io/kind)
   129  KIND_BIN := kind
   130  KIND :=  $(TOOLS_BIN_DIR)/$(KIND_BIN)-$(KIND_VER)
   131  
   132  CODESPELL_VER := 2.2.6
   133  CODESPELL_BIN := codespell
   134  CODESPELL_DIST_DIR := codespell_dist
   135  CODESPELL := $(TOOLS_BIN_DIR)/$(CODESPELL_DIST_DIR)/$(CODESPELL_BIN)
   136  
   137  # This is a commit from CR main (22.05.2024).
   138  # Intentionally using a commit from main to use a setup-envtest version
   139  # that uses binaries from controller-tools, not GCS.
   140  # CR PR: https://github.com/kubernetes-sigs/controller-runtime/pull/2811
   141  SETUP_ENVTEST_VER := v0.0.0-20240522175850-2e9781e9fc60
   142  SETUP_ENVTEST_BIN := setup-envtest
   143  SETUP_ENVTEST := $(abspath $(TOOLS_BIN_DIR)/$(SETUP_ENVTEST_BIN)-$(SETUP_ENVTEST_VER))
   144  SETUP_ENVTEST_PKG := sigs.k8s.io/controller-runtime/tools/setup-envtest
   145  
   146  KUBEBUILDER_ASSETS ?= $(shell $(SETUP_ENVTEST) use --use-env -p path $(KUBEBUILDER_ENVTEST_KUBERNETES_VERSION))
   147  
   148  # Define Docker related variables. Releases should modify and double check these vars.
   149  ifeq (,$(shell command -v gcloud))
   150      REGISTRY ?= gcr.io/$(shell gcloud config get-value project)
   151  else
   152      REGISTRY ?= localhost:5000
   153  endif
   154  STAGING_REGISTRY := gcr.io/k8s-staging-cluster-api-azure
   155  PROD_REGISTRY := registry.k8s.io/cluster-api-azure
   156  IMAGE_NAME ?= cluster-api-azure-controller
   157  CONTROLLER_IMG ?= $(REGISTRY)/$(IMAGE_NAME)
   158  TAG ?= dev
   159  ARCH ?= $(GOARCH)
   160  ALL_ARCH = amd64 arm arm64 ppc64le s390x
   161  
   162  # Allow overriding manifest generation destination directory
   163  MANIFEST_ROOT ?= config
   164  CRD_ROOT ?= $(MANIFEST_ROOT)/crd/bases
   165  WEBHOOK_ROOT ?= $(MANIFEST_ROOT)/webhook
   166  RBAC_ROOT ?= $(MANIFEST_ROOT)/rbac
   167  ASO_CRDS_PATH := $(MANIFEST_ROOT)/aso/crds.yaml
   168  ASO_VERSION := v2.8.0
   169  ASO_CRDS := resourcegroups.resources.azure.com natgateways.network.azure.com managedclusters.containerservice.azure.com managedclustersagentpools.containerservice.azure.com bastionhosts.network.azure.com virtualnetworks.network.azure.com virtualnetworkssubnets.network.azure.com privateendpoints.network.azure.com fleetsmembers.containerservice.azure.com extensions.kubernetesconfiguration.azure.com
   170  
   171  # Allow overriding the imagePullPolicy
   172  PULL_POLICY ?= Always
   173  
   174  # Allow overriding the e2e configurations
   175  GINKGO_FOCUS ?= \[REQUIRED\]
   176  GINKGO_SKIP ?=
   177  GINKGO_NODES ?= 3
   178  GINKGO_NOCOLOR ?= false
   179  GINKGO_ARGS ?=
   180  ARTIFACTS ?= $(ROOT_DIR)/_artifacts
   181  E2E_CONF_FILE ?= $(ROOT_DIR)/test/e2e/config/azure-dev.yaml
   182  E2E_CONF_FILE_ENVSUBST := $(ROOT_DIR)/test/e2e/config/azure-dev-envsubst.yaml
   183  SKIP_CLEANUP ?= false
   184  AZWI_SKIP_CLEANUP ?= false
   185  SKIP_LOG_COLLECTION ?= false
   186  # @sonasingh46: Skip creating mgmt cluster for ci as workload identity needs kind cluster
   187  # to be created with extra mounts for key pairs which is not yet supported
   188  # by existing e2e framework. A mgmt cluster(kind) is created as part of e2e suite
   189  # that meets workload identity pre-requisites.
   190  SKIP_CREATE_MGMT_CLUSTER ?= true
   191  WIN_REPO_URL ?=
   192  
   193  # Build time versioning details.
   194  LDFLAGS := $(shell hack/version.sh)
   195  
   196  CLUSTER_TEMPLATE ?= cluster-template.yaml
   197  
   198  export KIND_CLUSTER_NAME ?= capz
   199  export RANDOM_SUFFIX := $(shell /bin/bash -c "echo $$RANDOM")
   200  export AZWI_RESOURCE_GROUP ?= capz-wi-$(RANDOM_SUFFIX)
   201  export CI_RG ?= $(AZWI_RESOURCE_GROUP)
   202  export USER_IDENTITY ?= $(addsuffix $(RANDOM_SUFFIX),$(CI_RG))
   203  export AZURE_IDENTITY_ID_FILEPATH ?= $(ROOT_DIR)/azure_identity_id
   204  
   205  ## --------------------------------------
   206  ## Binaries
   207  ## --------------------------------------
   208  
   209  ##@ Binaries:
   210  
   211  .PHONY: binaries
   212  binaries: manager ## Builds all binaries.
   213  
   214  .PHONY: manager
   215  manager: ## Build manager binary.
   216  	go build -ldflags "$(LDFLAGS)" -o $(BIN_DIR)/manager .
   217  
   218  ## --------------------------------------
   219  ## Cleanup / Verification
   220  ## --------------------------------------
   221  
   222  ##@ Cleanup / Verification:
   223  
   224  .PHONY: clean
   225  clean: ## Remove bin and kubeconfigs.
   226  	$(MAKE) clean-bin
   227  	$(MAKE) clean-temporary
   228  
   229  .PHONY: clean-bin
   230  clean-bin: ## Remove all generated binaries.
   231  	rm -rf bin
   232  	rm -rf hack/tools/bin
   233  
   234  .PHONY: clean-temporary
   235  clean-temporary: ## Remove all temporary files and folders.
   236  	rm -f minikube.kubeconfig
   237  	rm -f kubeconfig
   238  	rm -f *.kubeconfig
   239  
   240  .PHONY: clean-release
   241  clean-release: clean-release-git ## Remove the release folder.
   242  	rm -rf $(RELEASE_DIR)
   243  
   244  .PHONY: clean-release-git
   245  clean-release-git: ## Restores the git files usually modified during a release
   246  	git restore ./*manager_image_patch.yaml ./*manager_pull_policy.yaml
   247  
   248  APIDIFF_OLD_COMMIT ?= $(shell git rev-parse origin/main)
   249  
   250  .PHONY: apidiff
   251  apidiff: $(GO_APIDIFF) ## Check for API differences.
   252  	$(GO_APIDIFF) $(APIDIFF_OLD_COMMIT)
   253  
   254  .PHONY: format-tiltfile
   255  format-tiltfile: ## Format the Tiltfile.
   256  	./hack/verify-starlark.sh fix
   257  
   258  .PHONY: verify
   259  verify: verify-boilerplate verify-modules verify-gen verify-shellcheck verify-conversions verify-tiltfile verify-codespell ## Run "verify-boilerplate", "verify-modules", "verify-gen", "verify-shellcheck", "verify-conversions", "verify-tiltfile" "verify-codespell" rules.
   260  
   261  .PHONY: verify-boilerplate
   262  verify-boilerplate: ## Verify boilerplate header.
   263  	./hack/verify-boilerplate.sh
   264  
   265  .PHONY: verify-modules
   266  verify-modules: modules ## Verify go.sum go.mod are the latest.
   267  	@if !(git diff --quiet HEAD -- go.sum go.mod $(TOOLS_DIR)/go.sum $(TOOLS_DIR)/go.mod); then \
   268  		echo "go module files are out of date"; exit 1; \
   269  	fi
   270  
   271  .PHONY: verify-gen
   272  verify-gen: generate ## Verify generated files are the latest.
   273  	@if !(git diff --quiet HEAD); then \
   274  		git diff; echo "generated files are out of date, run make generate"; exit 1; \
   275  	fi
   276  
   277  .PHONY: verify-shellcheck
   278  verify-shellcheck: ## Verify shell files are passing lint.
   279  	./hack/verify-shellcheck.sh
   280  
   281  .PHONY: verify-conversions
   282  verify-conversions: $(CONVERSION_VERIFIER)  ## Verifies expected API conversion are in place.
   283  	$(CONVERSION_VERIFIER)
   284  
   285  .PHONY: verify-tiltfile
   286  verify-tiltfile: ## Verify Tiltfile format.
   287  	./hack/verify-starlark.sh
   288  
   289  .PHONY: verify-codespell
   290  verify-codespell: codespell ## Verify codespell.
   291  	@$(CODESPELL) $(ROOT_DIR) --ignore-words=$(ROOT_DIR)/.codespellignore --skip="*.git,*_artifacts,*.sum,$(ROOT_DIR)/docs/book/bookout,$(ROOT_DIR)/hack/tools/bin/codespell_dist"
   292  
   293  ## --------------------------------------
   294  ## Development
   295  ## --------------------------------------
   296  
   297  ##@ Development:
   298  
   299  .PHONY: install-tools # populate hack/tools/bin
   300  install-tools: $(ENVSUBST) $(KUSTOMIZE) $(KUBECTL) $(HELM) $(GINKGO) $(KIND) $(AZWI)
   301  
   302  .PHONY: create-management-cluster
   303  create-management-cluster: $(KUSTOMIZE) $(ENVSUBST) $(KUBECTL) $(KIND) ## Create a management cluster.
   304  	# Create kind management cluster.
   305  	$(MAKE) kind-create
   306  
   307  	# Install cert manager and wait for availability
   308  	./hack/install-cert-manager.sh
   309  
   310  	# Create customized cloud provider configs
   311  	AZURE_CLIENT_ID_USER_ASSIGNED_IDENTITY="$${AZURE_CLIENT_ID_USER_ASSIGNED_IDENTITY:-$$(cat $(AZURE_IDENTITY_ID_FILEPATH))}" \
   312  	./hack/create-custom-cloud-provider-config.sh
   313  
   314  	# Deploy CAPI
   315  	timeout --foreground 300 bash -c "until curl --retry $(CURL_RETRIES) -sSL https://github.com/kubernetes-sigs/cluster-api/releases/download/v1.8.3/cluster-api-components.yaml | $(ENVSUBST) | $(KUBECTL) apply -f -; do sleep 5; done"
   316  
   317  	# Deploy CAAPH
   318  	timeout --foreground 300 bash -c "until curl --retry $(CURL_RETRIES) -sSL https://github.com/kubernetes-sigs/cluster-api-addon-provider-helm/releases/download/v0.2.5/addon-components.yaml | $(ENVSUBST) | $(KUBECTL) apply -f -; do sleep 5; done"
   319  
   320  	# Deploy CAPZ
   321  	$(KIND) load docker-image $(CONTROLLER_IMG)-$(ARCH):$(TAG) --name=$(KIND_CLUSTER_NAME)
   322  	timeout --foreground 300 bash -c "until $(KUSTOMIZE) build config/default | $(ENVSUBST) | $(KUBECTL) apply -f - --server-side=true; do sleep 5; done"
   323  
   324  	# Wait for CAPI deployments
   325  	$(KUBECTL) wait --for=condition=Available --timeout=5m -n capi-system deployment -l cluster.x-k8s.io/provider=cluster-api
   326  	$(KUBECTL) wait --for=condition=Available --timeout=5m -n capi-kubeadm-bootstrap-system deployment -l cluster.x-k8s.io/provider=bootstrap-kubeadm
   327  	$(KUBECTL) wait --for=condition=Available --timeout=5m -n capi-kubeadm-control-plane-system deployment -l cluster.x-k8s.io/provider=control-plane-kubeadm
   328  
   329  	# Wait for CAAPH deployment
   330  	$(KUBECTL) wait --for=condition=Available --timeout=5m -n caaph-system deployment -l cluster.x-k8s.io/provider=helm
   331  
   332  	# Wait for the ClusterResourceSet CRD resource to be "installed" onto the mgmt cluster before installing CRS addons
   333  	timeout --foreground 300 bash -c "until $(KUBECTL) get clusterresourcesets -A; do sleep 3; done"
   334  
   335  	# install Windows Calico cluster resource set
   336  	timeout --foreground 300 bash -c "until $(KUBECTL) create configmap calico-windows-addon -n default --from-file="$(ADDONS_DIR)/windows/calico" --dry-run=client -o yaml | kubectl apply -f -; do sleep 5; done"
   337  	timeout --foreground 300 bash -c "until $(KUBECTL) apply -f templates/addons/windows/calico-resource-set.yaml; do sleep 5; done"
   338  
   339  	# Wait for CAPZ deployments
   340  	$(KUBECTL) wait --for=condition=Available --timeout=5m -n capz-system deployment --all
   341  
   342  	# required sleep for when creating management and workload cluster simultaneously
   343  	# Wait for the core CRD resources to be "installed" onto the mgmt cluster before returning control
   344  	timeout --foreground 300 bash -c "until $(KUBECTL) get clusters -A; do sleep 3; done"
   345  	timeout --foreground 300 bash -c "until $(KUBECTL) get azureclusters -A; do sleep 3; done"
   346  	timeout --foreground 300 bash -c "until $(KUBECTL) get kubeadmcontrolplanes -A; do sleep 3; done"
   347  	@echo 'Set kubectl context to the kind management cluster by running "$(KUBECTL) config set-context kind-$(KIND_CLUSTER_NAME)"'
   348  
   349  .PHONY: create-workload-cluster
   350  create-workload-cluster: $(ENVSUBST) $(KUBECTL) ## Create a workload cluster.
   351  	# Create workload Cluster.
   352  	@if [ -z "${AZURE_CLIENT_ID_USER_ASSIGNED_IDENTITY}" ]; then \
   353  		export AZURE_CLIENT_ID_USER_ASSIGNED_IDENTITY=$(shell cat $(AZURE_IDENTITY_ID_FILEPATH)); \
   354  	fi; \
   355  	if [ -f "$(TEMPLATES_DIR)/$(CLUSTER_TEMPLATE)" ]; then \
   356  		timeout --foreground 300 bash -c "until $(ENVSUBST) < $(TEMPLATES_DIR)/$(CLUSTER_TEMPLATE) | $(KUBECTL) apply -f -; do sleep 5; done"; \
   357  	elif [ -f "$(CLUSTER_TEMPLATE)" ]; then \
   358  		timeout --foreground 300 bash -c "until $(ENVSUBST) < "$(CLUSTER_TEMPLATE)" | $(KUBECTL) apply -f -; do sleep 5; done"; \
   359  	else \
   360  		timeout --foreground 300 bash -c "until curl --retry "$(CURL_RETRIES)" "$(CLUSTER_TEMPLATE)" | "$(ENVSUBST)" | $(KUBECTL) apply -f -; do sleep 5; done"; \
   361  	fi
   362  
   363  	# Wait for the kubeconfig to become available.
   364  	timeout --foreground 1800 bash -c "while ! $(KUBECTL) get secrets -n default | grep $(CLUSTER_NAME)-kubeconfig; do sleep 1; done"
   365  	# Get kubeconfig and store it locally.
   366  	$(KUBECTL) get secret/$(CLUSTER_NAME)-kubeconfig -n default -o json | jq -r .data.value | base64 --decode > ./kubeconfig
   367  	$(KUBECTL) -n default wait --for=condition=Ready --timeout=10m cluster "$(CLUSTER_NAME)"
   368  
   369  	@echo 'run "$(KUBECTL) --kubeconfig=./kubeconfig ..." to work with the new target cluster'
   370  
   371  .PHONY: create-cluster
   372  create-cluster: ## Create a workload development Kubernetes cluster on Azure in a kind management cluster.
   373  	EXP_CLUSTER_RESOURCE_SET=true \
   374  	EXP_MACHINE_POOL=true \
   375  	EXP_EDGEZONE=true \
   376  	EXP_ASO_API=true \
   377  	$(MAKE) create-management-cluster \
   378  	create-workload-cluster
   379  
   380  .PHONY: delete-workload-cluster
   381  delete-workload-cluster: $(KUBECTL) ## Deletes the example workload Kubernetes cluster.
   382  	@echo 'Your Azure resources will now be deleted, this can take up to 20 minutes'
   383  	$(KUBECTL) delete cluster $(CLUSTER_NAME)
   384  
   385  ## --------------------------------------
   386  ## Docker
   387  ## --------------------------------------
   388  
   389  ##@ Docker:
   390  
   391  .PHONY: acr-login
   392  acr-login: ## Login to Azure Container Registry.
   393  	./hack/ensure-acr-login.sh
   394  
   395  .PHONY: docker-pull-prerequisites
   396  docker-pull-prerequisites: ## Pull prerequisites for building controller-manager.
   397  	docker pull docker/dockerfile:1.4
   398  	docker pull docker.io/library/golang:1.22
   399  	docker pull gcr.io/distroless/static:latest
   400  
   401  .PHONY: docker-build
   402  docker-build: docker-pull-prerequisites ## Build the docker image for controller-manager.
   403  	DOCKER_BUILDKIT=1 docker build --build-arg goproxy=$(GOPROXY) --build-arg ARCH=$(ARCH) --build-arg ldflags="$(LDFLAGS)" . -t $(CONTROLLER_IMG)-$(ARCH):$(TAG)
   404  	$(MAKE) set-manifest-image MANIFEST_IMG=$(CONTROLLER_IMG)-$(ARCH) MANIFEST_TAG=$(TAG) TARGET_RESOURCE="./config/capz/manager_image_patch.yaml"
   405  	$(MAKE) set-manifest-pull-policy TARGET_RESOURCE="./config/capz/manager_pull_policy.yaml"
   406  
   407  .PHONY: docker-push
   408  docker-push: ## Push the docker image
   409  	docker push $(CONTROLLER_IMG)-$(ARCH):$(TAG)
   410  
   411  ## --------------------------------------
   412  ## Docker — All ARCH
   413  ## --------------------------------------
   414  
   415  ##@ Docker - All Arch:
   416  
   417  .PHONY: docker-build-all
   418  docker-build-all: $(addprefix docker-build-,$(ALL_ARCH)) ## Build all the architecture docker images.
   419  
   420  docker-build-%:
   421  	$(MAKE) ARCH=$* docker-build
   422  
   423  .PHONY: docker-push-all
   424  docker-push-all: $(addprefix docker-push-,$(ALL_ARCH)) ## Push all the architecture docker images.
   425  	$(MAKE) docker-push-manifest
   426  
   427  docker-push-%:
   428  	$(MAKE) ARCH=$* docker-push
   429  
   430  .PHONY: docker-push-manifest
   431  docker-push-manifest: ## Push the fat manifest docker image.
   432  	## Minimum docker version 18.06.0 is required for creating and pushing manifest images.
   433  	docker manifest create --amend $(CONTROLLER_IMG):$(TAG) $(shell echo $(ALL_ARCH) | sed -e "s~[^ ]*~$(CONTROLLER_IMG)\-&:$(TAG)~g")
   434  	@for arch in $(ALL_ARCH); do docker manifest annotate --arch $${arch} ${CONTROLLER_IMG}:${TAG} ${CONTROLLER_IMG}-$${arch}:${TAG}; done
   435  	docker manifest push --purge ${CONTROLLER_IMG}:${TAG}
   436  	MANIFEST_IMG=$(CONTROLLER_IMG) MANIFEST_TAG=$(TAG) $(MAKE) set-manifest-image
   437  	$(MAKE) set-manifest-pull-policy
   438  
   439  .PHONY: set-manifest-image
   440  set-manifest-image: ## Update kustomize image patch file for default resource.
   441  	$(info Updating kustomize image patch file for default resource)
   442  	sed -i'' -e 's@image: .*@image: '"${MANIFEST_IMG}:$(MANIFEST_TAG)"'@' ./config/capz/manager_image_patch.yaml
   443  
   444  .PHONY: set-manifest-pull-policy
   445  set-manifest-pull-policy: ## Update kustomize pull policy file for default resource.
   446  	$(info Updating kustomize pull policy file for default resource)
   447  	sed -i'' -e 's@imagePullPolicy: .*@imagePullPolicy: '"$(PULL_POLICY)"'@' ./config/capz/manager_pull_policy.yaml
   448  
   449  ## --------------------------------------
   450  ## Generate
   451  ## --------------------------------------
   452  
   453  ##@ Generate:
   454  
   455  .PHONY: generate
   456  generate: ## Generate go related targets, manifests, flavors, e2e-templates and addons.
   457  	$(MAKE) generate-go
   458  	$(MAKE) generate-manifests
   459  	$(MAKE) generate-flavors
   460  	$(MAKE) generate-e2e-templates
   461  	$(MAKE) generate-addons
   462  	$(MAKE) generate-aso-crds
   463  
   464  .PHONY: generate-go
   465  generate-go: $(CONTROLLER_GEN) $(MOCKGEN) $(CONVERSION_GEN) ## Runs Go related generate targets.
   466  	$(CONTROLLER_GEN) \
   467  		paths=./api/... \
   468  		paths=./$(EXP_DIR)/api/... \
   469  		object:headerFile=./hack/boilerplate/boilerplate.generatego.txt
   470  	go generate ./...
   471  
   472  .PHONY: generate-manifests
   473  generate-manifests: $(CONTROLLER_GEN) ## Generate manifests e.g. CRD, RBAC etc.
   474  	$(CONTROLLER_GEN) \
   475  		paths=./api/... \
   476  		paths=./$(EXP_DIR)/api/... \
   477  		crd:crdVersions=v1 \
   478  		rbac:roleName=base-manager-role \
   479  		output:crd:dir=$(CRD_ROOT) \
   480  		output:webhook:dir=$(WEBHOOK_ROOT) \
   481  		webhook
   482  	$(CONTROLLER_GEN) \
   483  		paths=./ \
   484  		paths=./controllers/... \
   485  		paths=./$(EXP_DIR)/controllers/... \
   486  		output:rbac:dir=$(RBAC_ROOT) \
   487  		rbac:roleName=base-manager-role
   488  
   489  .PHONY: generate-flavors ## Generate template flavors.
   490  generate-flavors: $(KUSTOMIZE) generate-addons
   491  	./hack/gen-flavors.sh
   492  
   493  .PHONY: generate-e2e-templates
   494  generate-e2e-templates: $(KUSTOMIZE) ## Generate Azure infrastructure templates for the v1beta1 CAPI test suite.
   495  	$(KUSTOMIZE) build $(AZURE_TEMPLATES)/v1beta1/cluster-template --load-restrictor LoadRestrictionsNone > $(AZURE_TEMPLATES)/v1beta1/cluster-template.yaml
   496  	$(KUSTOMIZE) build $(AZURE_TEMPLATES)/v1beta1/cluster-template-md-remediation --load-restrictor LoadRestrictionsNone > $(AZURE_TEMPLATES)/v1beta1/cluster-template-md-remediation.yaml
   497  	$(KUSTOMIZE) build $(AZURE_TEMPLATES)/v1beta1/cluster-template-kcp-remediation --load-restrictor LoadRestrictionsNone > $(AZURE_TEMPLATES)/v1beta1/cluster-template-kcp-remediation.yaml
   498  	$(KUSTOMIZE) build $(AZURE_TEMPLATES)/v1beta1/cluster-template-machine-pool --load-restrictor LoadRestrictionsNone > $(AZURE_TEMPLATES)/v1beta1/cluster-template-machine-pool.yaml
   499  	$(KUSTOMIZE) build $(AZURE_TEMPLATES)/v1beta1/cluster-template-node-drain --load-restrictor LoadRestrictionsNone > $(AZURE_TEMPLATES)/v1beta1/cluster-template-node-drain.yaml
   500  	$(KUSTOMIZE) build $(AZURE_TEMPLATES)/v1beta1/cluster-template-upgrades --load-restrictor LoadRestrictionsNone > $(AZURE_TEMPLATES)/v1beta1/cluster-template-upgrades.yaml
   501  	$(KUSTOMIZE) build $(AZURE_TEMPLATES)/v1beta1/cluster-template-kcp-scale-in --load-restrictor LoadRestrictionsNone > $(AZURE_TEMPLATES)/v1beta1/cluster-template-kcp-scale-in.yaml
   502  
   503  .PHONY: generate-addons
   504  generate-addons: fetch-calico-manifests ## Generate metric-server, calico, calico-ipv6, azure cni v1 addons.
   505  	$(KUSTOMIZE) build $(ADDONS_DIR)/metrics-server > $(ADDONS_DIR)/metrics-server/metrics-server.yaml
   506  	$(KUSTOMIZE) build $(ADDONS_DIR)/calico > $(ADDONS_DIR)/calico.yaml
   507  	$(KUSTOMIZE) build $(ADDONS_DIR)/calico-ipv6 > $(ADDONS_DIR)/calico-ipv6.yaml
   508  	$(KUSTOMIZE) build $(ADDONS_DIR)/calico-dual-stack > $(ADDONS_DIR)/calico-dual-stack.yaml
   509  	$(KUSTOMIZE) build $(ADDONS_DIR)/azure-cni-v1 > $(ADDONS_DIR)/azure-cni-v1.yaml
   510  
   511  .PHONY: generate-aso-crds
   512  # The yq command filters the list of all ASO CRDs to just the ones specified by ASO_CRDS.
   513  # The sed command changes '$$' to '$$$$' so once the CRDs get run through
   514  # envsubst, '$$$$' changes back to '$$' so ASO will not detect a diff and try to
   515  # update the CRDs for which we don't give it permission.
   516  generate-aso-crds: $(YQ)
   517  	curl -fSsL "https://github.com/Azure/azure-service-operator/releases/download/$(ASO_VERSION)/azureserviceoperator_customresourcedefinitions_$(ASO_VERSION).yaml" | \
   518  		$(YQ) e '. | select($(foreach name,$(ASO_CRDS),.metadata.name == "$(name)" or )false)' - | \
   519  		sed 's/\$$\$$/$$$$$$$$/g' \
   520  		> $(ASO_CRDS_PATH)
   521  
   522  # When updating this, make sure to also update the Windows image version in templates/addons/windows/calico.
   523  export CALICO_VERSION := v3.26.1
   524  # Where all downloaded Calico manifests are unpacked and stored.
   525  CALICO_RELEASES := $(ARTIFACTS)/calico
   526  # Path to manifests directory in a Calico release archive.
   527  CALICO_RELEASE_MANIFESTS_DIR := release-$(CALICO_VERSION)/manifests
   528  # Path where Calico manifests are stored which should be used for addons generation.
   529  CALICO_MANIFESTS_DIR := $(ARTIFACTS)/calico/$(CALICO_RELEASE_MANIFESTS_DIR)
   530  
   531  .PHONY: get-calico-version
   532  get-calico-version: ## Print the Calico version used for CNI in the repo.
   533  	@echo $(CALICO_VERSION)
   534  
   535  .PHONY: fetch-calico-manifests
   536  fetch-calico-manifests: $(CALICO_MANIFESTS_DIR) ## Get Calico release manifests and unzip them.
   537  	cp $(CALICO_MANIFESTS_DIR)/calico-vxlan.yaml $(ADDONS_DIR)/calico
   538  	cp $(CALICO_MANIFESTS_DIR)/calico-policy-only.yaml $(ADDONS_DIR)/calico-ipv6
   539  
   540  $(CALICO_MANIFESTS_DIR):
   541  	mkdir -p $(ARTIFACTS)/calico
   542  	@echo "Fetching Calico release manifests from release artifacts, this might take a minute..."
   543  	wget -qO- https://github.com/projectcalico/calico/releases/download/$(CALICO_VERSION)/release-$(CALICO_VERSION).tgz | tar xz --directory $(CALICO_RELEASES) $(CALICO_RELEASE_MANIFESTS_DIR)
   544  
   545  .PHONY: modules
   546  modules: ## Runs go mod tidy to ensure proper vendoring.
   547  	go mod tidy
   548  	pushd $(TOOLS_DIR) && go mod tidy; popd
   549  
   550  ## --------------------------------------
   551  ## Help
   552  ## --------------------------------------
   553  
   554  ##@ Help:
   555  
   556  help: ## Display this help.
   557  	@awk 'BEGIN {FS = ":.*##"; printf "\nUsage:\n  make \033[36m<target>\033[0m\n"} /^[0-9a-zA-Z_-]+:.*?##/ { printf "  \033[36m%-25s\033[0m %s\n", $$1, $$2 } /^##@/ { printf "\n\033[1m%s\033[0m\n", substr($$0, 5) } ' $(MAKEFILE_LIST)
   558  
   559  ## --------------------------------------
   560  ## Linting
   561  ## --------------------------------------
   562  
   563  ##@ Linting:
   564  
   565  .PHONY: lint
   566  lint: $(GOLANGCI_LINT) lint-latest ## Lint codebase.
   567  	$(GOLANGCI_LINT) run -v --timeout=8m0s --print-resources-usage $(GOLANGCI_LINT_EXTRA_ARGS)
   568  
   569  .PHONY: lint-fix
   570  lint-fix: $(GOLANGCI_LINT) ## Lint the codebase and run auto-fixers if supported by the linter.
   571  	GOLANGCI_LINT_EXTRA_ARGS=--fix $(MAKE) lint
   572  
   573  lint-full: $(GOLANGCI_LINT) ## Run slower linters to detect possible issues.
   574  	$(GOLANGCI_LINT) run -v --fast=false
   575  
   576  .PHONY: lint-latest
   577  lint-latest:
   578  	./hack/lint-latest.sh
   579  
   580  ## --------------------------------------
   581  ## Release
   582  ## --------------------------------------
   583  
   584  ##@ Release:
   585  
   586  RELEASE_TAG ?= $(shell git describe --abbrev=0 2>/dev/null)
   587  # if the release tag contains a hyphen, treat it as a pre-release
   588  ifneq (,$(findstring -,$(RELEASE_TAG)))
   589      PRE_RELEASE=true
   590  endif
   591  FULL_VERSION := $(RELEASE_TAG:v%=%)
   592  MAJOR_VERSION := $(shell echo $(FULL_VERSION) | sed -E 's/^([0-9]+)\.([0-9]+)\.([0-9]+)$$/\1/')
   593  MINOR_VERSION := $(shell echo $(FULL_VERSION) | sed -E 's/^([0-9]+)\.([0-9]+)\.([0-9]+)$$/\2/')
   594  PATCH_VERSION := $(shell echo $(FULL_VERSION) | sed -E 's/^([0-9]+)\.([0-9]+)\.([0-9]+)$$/\3/')
   595  # if the release tag is a .0 version, use the main branch
   596  ifeq ($(PATCH_VERSION),0)
   597  	RELEASE_BRANCH ?= main
   598  else
   599  	RELEASE_BRANCH ?= release-$(MAJOR_VERSION).$(MINOR_VERSION)
   600  endif
   601  # the previous release tag, e.g., v0.3.9, excluding pre-release tags
   602  PREVIOUS_TAG ?= $(shell git tag --merged $(GIT_REMOTE_NAME)/$(RELEASE_BRANCH) -l | grep -E "^v[0-9]+\.[0-9]+\.[0-9]+$$" | sort -V | tail -n 1 2>/dev/null)
   603  START_SHA ?= $(shell git rev-list -n 1 $(PREVIOUS_TAG) 2>/dev/null)
   604  END_SHA ?= $(shell git rev-parse $(GIT_REMOTE_NAME)/$(RELEASE_BRANCH) 2>/dev/null)
   605  RELEASE_DIR ?= out
   606  RELEASE_NOTES_DIR := CHANGELOG
   607  GIT_REPO_NAME ?= cluster-api-provider-azure
   608  GIT_ORG_NAME ?= kubernetes-sigs
   609  GIT_REMOTE_NAME ?= upstream
   610  USER_FORK ?= $(shell git config --get remote.origin.url | cut -d/ -f4)
   611  IMAGE_REVIEWERS ?= $(shell ./hack/get-project-maintainers.sh)
   612  
   613  $(RELEASE_DIR):
   614  	mkdir -p $(RELEASE_DIR)/
   615  
   616  $(RELEASE_NOTES_DIR):
   617  	mkdir -p $(RELEASE_NOTES_DIR)/
   618  
   619  .PHONY: release
   620  release: clean-release  ## Builds and push container images using the latest git tag for the commit.
   621  	@if [ -z "${RELEASE_TAG}" ]; then echo "RELEASE_TAG is not set"; exit 1; fi
   622  	@if ! [ -z "$$(git status --porcelain)" ]; then echo "Your local git repository contains uncommitted changes, use git clean before proceeding."; exit 1; fi
   623  	git checkout "${RELEASE_TAG}"
   624  	# Set the manifest image to the production bucket.
   625  	$(MAKE) set-manifest-image MANIFEST_IMG=$(PROD_REGISTRY)/$(IMAGE_NAME) MANIFEST_TAG=$(RELEASE_TAG)
   626  	$(MAKE) set-manifest-pull-policy PULL_POLICY=IfNotPresent
   627  	$(MAKE) release-manifests
   628  	$(MAKE) release-templates
   629  	$(MAKE) release-metadata
   630  
   631  .PHONY: release-manifests
   632  release-manifests: $(KUSTOMIZE) $(RELEASE_DIR) ## Builds the manifests to publish with a release.
   633  	$(KUSTOMIZE) build config/default > $(RELEASE_DIR)/infrastructure-components.yaml
   634  
   635  .PHONY: release-templates
   636  release-templates: $(RELEASE_DIR)
   637  	cp templates/cluster-template* $(RELEASE_DIR)/
   638  
   639  .PHONY: release-metadata
   640  release-metadata: $(RELEASE_DIR)
   641  	cp metadata.yaml $(RELEASE_DIR)/metadata.yaml
   642  
   643  .PHONY: release-binary
   644  release-binary: $(RELEASE_DIR) ## Compile and build release binaries.
   645  	docker run \
   646  		--rm \
   647  		-e CGO_ENABLED=0 \
   648  		-e GOOS=$(GOOS) \
   649  		-e GOARCH=$(GOARCH) \
   650  		-v "$$(pwd):/workspace" \
   651  		-w /workspace \
   652  		golang:1.22 \
   653  		go build -a -ldflags '$(LDFLAGS) -extldflags "-static"' \
   654  		-o $(RELEASE_DIR)/$(notdir $(RELEASE_BINARY))-$(GOOS)-$(GOARCH) $(RELEASE_BINARY)
   655  
   656  .PHONY: release-staging
   657  release-staging: ## Builds and push container images to the staging bucket.
   658  	REGISTRY=$(STAGING_REGISTRY) $(MAKE) docker-build-all docker-push-all release-alias-tag
   659  
   660  RELEASE_ALIAS_TAG=$(PULL_BASE_REF)
   661  
   662  .PHONY: release-alias-tag
   663  release-alias-tag: ## Adds the tag to the last build tag.
   664  	gcloud container images add-tag $(CONTROLLER_IMG):$(TAG) $(CONTROLLER_IMG):$(RELEASE_ALIAS_TAG)
   665  
   666  .PHONY: release-notes
   667  release-notes: $(RELEASE_NOTES) $(RELEASE_NOTES_DIR) ## Generate/update release notes.
   668  	@echo "generating release notes from $(PREVIOUS_TAG) to $(RELEASE_TAG) with start sha $(START_SHA) and end sha $(END_SHA)"
   669  	@if [ -n "${PRE_RELEASE}" ]; then echo ":rotating_light: This is a RELEASE CANDIDATE. Use it only for testing purposes. If you find any bugs, file an [issue](https://github.com/kubernetes-sigs/cluster-api-provider-azure/issues/new)." > $(RELEASE_NOTES_DIR)/release-notes-$(RELEASE_TAG).md; \
   670  	else $(RELEASE_NOTES) --org $(GIT_ORG_NAME) --repo $(GIT_REPO_NAME) --branch $(RELEASE_BRANCH) --repo-path $(ROOT_DIR) --start-sha $(START_SHA) --end-sha $(END_SHA) --markdown-links true --output $(RELEASE_NOTES_DIR)/$(RELEASE_TAG).md --list-v2; \
   671  	sed 's/\[SIG Cluster Lifecycle\]//g' $(RELEASE_NOTES_DIR)/$(RELEASE_TAG).md > $(RELEASE_NOTES_DIR)/tmp-release-notes.md; \
   672  	cp $(RELEASE_NOTES_DIR)/tmp-release-notes.md $(RELEASE_NOTES_DIR)/$(RELEASE_TAG).md; \
   673  	rm -f $(RELEASE_NOTES_DIR)/tmp-release-notes.md; \
   674  	fi
   675  
   676  .PHONY: promote-images
   677  promote-images: $(KPROMO) ## Promote images.
   678  	$(KPROMO) pr --project cluster-api-azure --tag $(RELEASE_TAG) --reviewers "$(IMAGE_REVIEWERS)" --fork $(USER_FORK)
   679  
   680  ## --------------------------------------
   681  ## Testing
   682  ## --------------------------------------
   683  
   684  ##@ Testing:
   685  .PHONY: test
   686  test: generate lint go-test-race ## Run "generate", "lint" and "go-test-race" rules.
   687  
   688  .PHONY: go-test-race
   689  go-test-race: TEST_ARGS+= -race
   690  go-test-race: go-test ## Run go tests with the race detector enabled.
   691  
   692  .PHONY: go-test
   693  go-test: $(SETUP_ENVTEST) ## Run go tests.
   694  	KUBEBUILDER_ASSETS="$(KUBEBUILDER_ASSETS)" go test ./... $(TEST_ARGS)
   695  
   696  .PHONY: test-cover
   697  test-cover: TEST_ARGS+= -coverprofile coverage.out
   698  test-cover: test ## Run tests with code coverage and generate reports.
   699  	go tool cover -func=coverage.out -o coverage.txt
   700  	./hack/codecov-ignore.sh
   701  	go tool cover -html=coverage.out -o coverage.html
   702  
   703  .PHONY: kind-create-bootstrap
   704  kind-create-bootstrap: $(KUBECTL) ## Create capz kind bootstrap cluster.
   705  	KIND_CLUSTER_NAME=capz-e2e ./scripts/kind-with-registry.sh
   706  
   707  .PHONY: cleanup-workload-identity
   708  cleanup-workload-identity: ## Cleanup CI workload-identity infra
   709  	@if ! [ "$(AZWI_SKIP_CLEANUP)" == "true" ]; then \
   710  		./scripts/cleanup-workload-identity.sh \
   711  	fi
   712  
   713  ## --------------------------------------
   714  ## Security Scanning
   715  ## --------------------------------------
   716  
   717  .PHONY: verify-container-images
   718  verify-container-images: ## Verify container images
   719  	./hack/verify-container-images.sh
   720  
   721  ## --------------------------------------
   722  ## Tilt / Kind
   723  ## --------------------------------------
   724  
   725  ##@ Tilt / Kind:
   726  
   727  .PHONY: kind-create
   728  kind-create: $(KUBECTL) ## Create capz kind cluster if needed.
   729  	./scripts/kind-with-registry.sh
   730  
   731  .PHONY: aks-create
   732  aks-create: $(KUBECTL) ## Create aks cluster as mgmt cluster.
   733  	./scripts/aks-as-mgmt.sh
   734  
   735  .PHONY: tilt-up
   736  tilt-up: install-tools ## Start tilt and build kind cluster if needed.
   737  	@if [ -z "${AZURE_CLIENT_ID_USER_ASSIGNED_IDENTITY}" ]; then \
   738  		export AZURE_CLIENT_ID_USER_ASSIGNED_IDENTITY=$(shell cat $(AZURE_IDENTITY_ID_FILEPATH)); \
   739  	fi; \
   740  	CLUSTER_TOPOLOGY=true EXP_ASO_API=true EXP_CLUSTER_RESOURCE_SET=true EXP_MACHINE_POOL=true EXP_KUBEADM_BOOTSTRAP_FORMAT_IGNITION=true EXP_EDGEZONE=true tilt up
   741  
   742  .PHONY: delete-cluster
   743  delete-cluster: delete-workload-cluster  ## Deletes the example kind cluster "capz".
   744  	$(KIND) delete cluster --name=capz
   745  
   746  .PHONY: kind-reset
   747  kind-reset: $(KIND) ## Destroys the "capz" and "capz-e2e" kind clusters.
   748  	$(KIND) delete cluster --name=$(KIND_CLUSTER_NAME) || true
   749  	$(KIND) delete cluster --name=capz-e2e || true
   750  
   751  ## --------------------------------------
   752  ## Tooling Binaries
   753  ## --------------------------------------
   754  
   755  ##@ Tooling Binaries:
   756  
   757  conversion-verifier: $(CONVERSION_VERIFIER) go.mod go.sum ## Build a local copy of CAPI's conversion verifier.
   758  controller-gen: $(CONTROLLER_GEN) ## Build a local copy of controller-gen.
   759  conversion-gen: $(CONVERSION_GEN) ## Build a local copy of conversion-gen.
   760  envsubst: $(ENVSUBST) ## Build a local copy of envsubst.
   761  golangci-lint: $(GOLANGCI_LINT) ## Build a local copy of golang ci-lint.
   762  kustomize: $(KUSTOMIZE) ## Build a local copy of kustomize.
   763  mockgen: $(MOCKGEN) ## Build a local copy of mockgen.
   764  kpromo: $(KPROMO) ## Build a local copy of kpromo.
   765  release-notes: $(RELEASE_NOTES) ## Build a local copy of release notes.
   766  goapi-diff: $(GO_APIDIFF) ## Build a local copy of go api-diff.
   767  ginkgo: $(GINKGO) ## Build a local copy of ginkgo.
   768  kubectl: $(KUBECTL) ## Build a local copy of kubectl.
   769  helm: $(HELM) ## Build a local copy of helm.
   770  yq: $(YQ) ## Build a local copy of yq.
   771  kind: $(KIND) ## Build a local copy of kind.
   772  setup-envtest: $(SETUP_ENVTEST) ## Build a local copy of setup-envtest.
   773  codespell : $(CODESPELL) ## Build a local copy of codespell.
   774  azwi: $(AZWI) ## Build a local copy of azwi.
   775  
   776  $(CONVERSION_VERIFIER): go.mod
   777  	cd $(TOOLS_DIR); go build -tags=tools -o $@ sigs.k8s.io/cluster-api/hack/tools/conversion-verifier
   778  
   779  $(CONTROLLER_GEN): ## Build controller-gen from tools folder.
   780  	GOBIN=$(TOOLS_BIN_DIR) $(GO_INSTALL) sigs.k8s.io/controller-tools/cmd/controller-gen $(CONTROLLER_GEN_BIN) $(CONTROLLER_GEN_VER)
   781  
   782  $(CONVERSION_GEN): ## Build conversion-gen from tools folder.
   783  	GOBIN=$(TOOLS_BIN_DIR) $(GO_INSTALL) k8s.io/code-generator/cmd/conversion-gen $(CONVERSION_GEN_BIN) $(CONVERSION_GEN_VER)
   784  
   785  $(ENVSUBST): ## Build envsubst from tools folder.
   786  	GOBIN=$(TOOLS_BIN_DIR) $(GO_INSTALL) github.com/drone/envsubst/v2/cmd/envsubst $(ENVSUBST_BIN) $(ENVSUBST_VER)
   787  
   788  $(GOLANGCI_LINT): ## Build golangci-lint from tools folder.
   789  	GOBIN=$(TOOLS_BIN_DIR) $(GO_INSTALL) github.com/golangci/golangci-lint/cmd/golangci-lint $(GOLANGCI_LINT_BIN) $(GOLANGCI_LINT_VER)
   790  
   791  $(KUSTOMIZE): ## Build kustomize from tools folder.
   792  	GOBIN=$(TOOLS_BIN_DIR) $(GO_INSTALL) sigs.k8s.io/kustomize/kustomize/v5 $(KUSTOMIZE_BIN) $(KUSTOMIZE_VER)
   793  
   794  $(MOCKGEN): ## Build mockgen from tools folder.
   795  	GOBIN=$(TOOLS_BIN_DIR) $(GO_INSTALL) go.uber.org/mock/mockgen $(MOCKGEN_BIN) $(MOCKGEN_VER)
   796  
   797  $(KPROMO): ## Build kpromo from tools folder.
   798  	GOBIN=$(TOOLS_BIN_DIR) $(GO_INSTALL) sigs.k8s.io/promo-tools/v4/cmd/kpromo $(KPROMO_BIN) $(KPROMO_VER)
   799  
   800  $(RELEASE_NOTES): ## Build release notes from tools folder.
   801  	GOBIN=$(TOOLS_BIN_DIR) $(GO_INSTALL) k8s.io/release/cmd/release-notes $(RELEASE_NOTES_BIN) $(RELEASE_NOTES_VER)
   802  
   803  $(GO_APIDIFF): ## Build go-apidiff from tools folder.
   804  	GOBIN=$(TOOLS_BIN_DIR) $(GO_INSTALL) github.com/joelanford/go-apidiff $(GO_APIDIFF_BIN) $(GO_APIDIFF_VER)
   805  
   806  $(GINKGO): ## Build ginkgo from tools folder.
   807  	GOBIN=$(TOOLS_BIN_DIR) $(GO_INSTALL) github.com/onsi/ginkgo/v2/ginkgo $(GINKGO_BIN) $(GINKGO_VER)
   808  
   809  $(KUBECTL): ## Build kubectl from tools folder.
   810  	mkdir -p $(TOOLS_BIN_DIR)
   811  	rm -f "$(TOOLS_BIN_DIR)/$(KUBECTL_BIN)*"
   812  	curl --retry $(CURL_RETRIES) -fsL https://dl.k8s.io/release/$(KUBECTL_VER)/bin/$(GOOS)/$(GOARCH)/kubectl -o $(KUBECTL)
   813  	ln -sf $(KUBECTL) $(TOOLS_BIN_DIR)/$(KUBECTL_BIN)
   814  	chmod +x $(KUBECTL) $(TOOLS_BIN_DIR)/$(KUBECTL_BIN)
   815  
   816  $(HELM): ## Put helm into tools folder.
   817  	mkdir -p $(TOOLS_BIN_DIR)
   818  	rm -f "$(TOOLS_BIN_DIR)/$(HELM_BIN)*"
   819  	curl --retry $(CURL_RETRIES) -fsSL -o $(TOOLS_BIN_DIR)/get_helm.sh https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3
   820  	chmod 700 $(TOOLS_BIN_DIR)/get_helm.sh
   821  	USE_SUDO=false HELM_INSTALL_DIR=$(TOOLS_BIN_DIR) DESIRED_VERSION=$(HELM_VER) BINARY_NAME=$(HELM_BIN)-$(HELM_VER) $(TOOLS_BIN_DIR)/get_helm.sh
   822  	ln -sf $(HELM) $(TOOLS_BIN_DIR)/$(HELM_BIN)
   823  	rm -f $(TOOLS_BIN_DIR)/get_helm.sh
   824  
   825  $(AZWI): ## Put azwi into tools folder.
   826  	mkdir -p $(TOOLS_BIN_DIR)
   827  	rm -f "$(TOOLS_BIN_DIR)/$(AZWI_BIN)*"
   828  	curl --retry $(CURL_RETRIES) -fsSL -o $(TOOLS_BIN_DIR)/azwi.tar.gz https://github.com/Azure/azure-workload-identity/releases/download/$(AZWI_VER)/azwi-$(AZWI_VER)-$(GOOS)-$(GOARCH).tar.gz
   829  	tar -xf "$(TOOLS_BIN_DIR)/azwi.tar.gz" -C $(TOOLS_BIN_DIR) $(AZWI_BIN)
   830  	mv "$(TOOLS_BIN_DIR)/$(AZWI_BIN)" $(AZWI)
   831  	ln -sf $(AZWI) $(TOOLS_BIN_DIR)/$(AZWI_BIN)
   832  	chmod +x $(AZWI) $(TOOLS_BIN_DIR)/$(AZWI_BIN)
   833  	rm -f $(TOOLS_BIN_DIR)/azwi.tar.gz
   834  
   835  $(KIND): ## Build kind into tools folder.
   836  	GOBIN=$(TOOLS_BIN_DIR) $(GO_INSTALL) sigs.k8s.io/kind $(KIND_BIN) $(KIND_VER)
   837  
   838  .PHONY: $(ENVSUBST_BIN)
   839  $(ENVSUBST_BIN): $(ENVSUBST)
   840  
   841  .PHONY: $(KUBECTL_BIN)
   842  $(KUBECTL_BIN): $(KUBECTL)
   843  
   844  .PHONY: $(HELM_BIN)
   845  $(HELM_BIN): $(HELM)
   846  
   847  .PHONY: $(GO_APIDIFF_BIN)
   848  $(GO_APIDIFF_BIN): $(GO_APIDIFF)
   849  
   850  $(YQ): ## Build yq from tools folder.
   851  	GOBIN=$(TOOLS_BIN_DIR) $(GO_INSTALL) github.com/mikefarah/yq/v4 $(YQ_BIN) $(YQ_VER)
   852  
   853  .PHONY: $(YQ_BIN)
   854  $(YQ_BIN): $(YQ) ## Building yq from the tools folder.
   855  
   856  .PHONY: $(KIND_BIN)
   857  $(KIND_BIN): $(KIND)
   858  
   859  .PHONY: $(SETUP_ENVTEST_BIN)
   860  $(SETUP_ENVTEST_BIN): $(SETUP_ENVTEST) ## Build a local copy of setup-envtest.
   861  
   862  $(SETUP_ENVTEST): # Build setup-envtest from tools folder.
   863  	GOBIN=$(TOOLS_BIN_DIR) $(GO_INSTALL) $(SETUP_ENVTEST_PKG) $(SETUP_ENVTEST_BIN) $(SETUP_ENVTEST_VER)
   864  
   865  $(CODESPELL): ## Build codespell from tools folder.
   866  	@which $(CODESPELL) >/dev/null || ( \
   867          mkdir -p $(TOOLS_BIN_DIR); \
   868          pip install --target=$(TOOLS_BIN_DIR)/$(CODESPELL_DIST_DIR) $(CODESPELL_BIN)==$(CODESPELL_VER); \
   869  		mv $(TOOLS_BIN_DIR)/$(CODESPELL_DIST_DIR)/bin/$(CODESPELL_BIN) $(TOOLS_BIN_DIR)/$(CODESPELL_DIST_DIR); \
   870  		rm -r $(TOOLS_BIN_DIR)/$(CODESPELL_DIST_DIR)/bin; \
   871      )
   872  
   873  include conformance.mk
   874  include e2e.mk