Skip to content

Commit

Permalink
refactor(tools): install external binaries using temporary go module
Browse files Browse the repository at this point in the history
This avoids having a monolithic hack/tools/go.mod file and fixes problems with kustomize v4.5.7 failing to build w/ CAPI 1.5.x
  • Loading branch information
hrak committed Jul 11, 2024
1 parent 7bedbb6 commit 550b025
Show file tree
Hide file tree
Showing 7 changed files with 211 additions and 514 deletions.
165 changes: 145 additions & 20 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -16,26 +16,88 @@ export REPO_ROOT := $(shell git rev-parse --show-toplevel)

include $(REPO_ROOT)/common.mk

#
# Kubebuilder.
#
export KUBEBUILDER_ENVTEST_KUBERNETES_VERSION ?= 1.27.1
export KUBEBUILDER_CONTROLPLANE_START_TIMEOUT ?= 60s
export KUBEBUILDER_CONTROLPLANE_STOP_TIMEOUT ?=

# Directories
TOOLS_DIR := $(REPO_ROOT)/hack/tools
TOOLS_DIR_DEPS := $(TOOLS_DIR)/go.sum $(TOOLS_DIR)/go.mod $(TOOLS_DIR)/Makefile
TOOLS_BIN_DIR := $(TOOLS_DIR)/bin
BIN_DIR ?= bin
RELEASE_DIR ?= out
GO_INSTALL := ./hack/go_install.sh

GH_REPO ?= kubernetes-sigs/cluster-api-provider-cloudstack

# Helper function to get dependency version from go.mod
get_go_version = $(shell go list -m $1 | awk '{print $$2}')

# Binaries
CONTROLLER_GEN := $(TOOLS_BIN_DIR)/controller-gen
CONVERSION_GEN := $(TOOLS_BIN_DIR)/conversion-gen
GINKGO := $(TOOLS_BIN_DIR)/ginkgo
GOLANGCI_LINT := $(TOOLS_BIN_DIR)/golangci-lint
KUSTOMIZE := $(TOOLS_BIN_DIR)/kustomize
MOCKGEN := $(TOOLS_BIN_DIR)/mockgen
STATIC_CHECK := $(TOOLS_BIN_DIR)/staticcheck
KUSTOMIZE_VER := v4.5.7
KUSTOMIZE_BIN := kustomize
KUSTOMIZE := $(abspath $(TOOLS_BIN_DIR)/$(KUSTOMIZE_BIN)-$(KUSTOMIZE_VER))
KUSTOMIZE_PKG := sigs.k8s.io/kustomize/kustomize/v4

# This is a commit from CR main (22.05.2024).
# Intentionally using a commit from main to use a setup-envtest version
# that uses binaries from controller-tools, not GCS.
# CR PR: https://github.com/kubernetes-sigs/controller-runtime/pull/2811
SETUP_ENVTEST_VER := v0.0.0-20240522175850-2e9781e9fc60
SETUP_ENVTEST_BIN := setup-envtest
SETUP_ENVTEST := $(abspath $(TOOLS_BIN_DIR)/$(SETUP_ENVTEST_BIN)-$(SETUP_ENVTEST_VER))
SETUP_ENVTEST_PKG := sigs.k8s.io/controller-runtime/tools/setup-envtest

CONTROLLER_GEN_VER := v0.12.0
CONTROLLER_GEN_BIN := controller-gen
CONTROLLER_GEN := $(abspath $(TOOLS_BIN_DIR)/$(CONTROLLER_GEN_BIN)-$(CONTROLLER_GEN_VER))
CONTROLLER_GEN_PKG := sigs.k8s.io/controller-tools/cmd/controller-gen

GOTESTSUM_VER := v1.6.4
GOTESTSUM_BIN := gotestsum
GOTESTSUM := $(abspath $(TOOLS_BIN_DIR)/$(GOTESTSUM_BIN)-$(GOTESTSUM_VER))
GOTESTSUM_PKG := gotest.tools/gotestsum

CONVERSION_GEN_VER := v0.27.1
CONVERSION_GEN_BIN := conversion-gen
# We are intentionally using the binary without version suffix, to avoid the version
# in generated files.
CONVERSION_GEN := $(abspath $(TOOLS_BIN_DIR)/$(CONVERSION_GEN_BIN))
CONVERSION_GEN_PKG := k8s.io/code-generator/cmd/conversion-gen

ENVSUBST_BIN := envsubst
ENVSUBST_VER := $(call get_go_version,github.com/drone/envsubst/v2)
ENVSUBST := $(abspath $(TOOLS_BIN_DIR)/$(ENVSUBST_BIN)-$(ENVSUBST_VER))
ENVSUBST_PKG := github.com/drone/envsubst/v2/cmd/envsubst

GO_APIDIFF_VER := v0.6.0
GO_APIDIFF_BIN := go-apidiff
GO_APIDIFF := $(abspath $(TOOLS_BIN_DIR)/$(GO_APIDIFF_BIN)-$(GO_APIDIFF_VER))
GO_APIDIFF_PKG := github.com/joelanford/go-apidiff

GINKGO_BIN := ginkgo
GINGKO_VER := $(call get_go_version,github.com/onsi/ginkgo/v2)
GINKGO := $(abspath $(TOOLS_BIN_DIR)/$(GINKGO_BIN)-$(GINGKO_VER))
GINKGO_PKG := github.com/onsi/ginkgo/v2/ginkgo

GOLANGCI_LINT_BIN := golangci-lint
GOLANGCI_LINT_VER := v1.58.1
GOLANGCI_LINT := $(abspath $(TOOLS_BIN_DIR)/$(GOLANGCI_LINT_BIN)-$(GOLANGCI_LINT_VER))
GOLANGCI_LINT_PKG := github.com/golangci/golangci-lint/cmd/golangci-lint

MOCKGEN_BIN := mockgen
MOCKGEN_VER := v1.6.0
MOCKGEN := $(abspath $(TOOLS_BIN_DIR)/$(MOCKGEN_BIN)-$(MOCKGEN_VER))
MOCKGEN_PKG := github.com/golang/mock/mockgen

STATIC_CHECK_BIN := staticcheck
STATIC_CHECK_VER := v0.4.7
STATIC_CHECK := $(abspath $(TOOLS_BIN_DIR)/staticcheck)
STATIC_CHECK_PKG := honnef.co/go/tools/cmd/staticcheck

KUBECTL := $(TOOLS_BIN_DIR)/kubectl
API_SERVER := $(TOOLS_BIN_DIR)/kube-apiserver
ETCD := $(TOOLS_BIN_DIR)/etcd

# Release
STAGING_REGISTRY := gcr.io/k8s-staging-capi-cloudstack
Expand Down Expand Up @@ -81,7 +143,7 @@ all: build
## --------------------------------------

.PHONY: binaries
binaries: $(CONTROLLER_GEN) $(CONVERSION_GEN) $(GOLANGCI_LINT) $(STATIC_CHECK) $(GINKGO) $(MOCKGEN) $(KUSTOMIZE) managers # Builds and installs all binaries
binaries: $(CONTROLLER_GEN) $(CONVERSION_GEN) $(GOLANGCI_LINT) $(STATIC_CHECK) $(GINKGO) $(MOCKGEN) $(KUSTOMIZE) $(SETUP_ENVTEST) managers # Builds and installs all binaries

.PHONY: managers
managers:
Expand All @@ -91,11 +153,6 @@ managers:
manager-cloudstack-infrastructure: ## Build manager binary.
CGO_ENABLED=0 go build -ldflags "${LDFLAGS} -extldflags '-static'" -o $(BIN_DIR)/manager .

export K8S_VERSION=1.27.1
$(KUBECTL) $(API_SERVER) $(ETCD) &:
cd $(TOOLS_DIR) && curl --silent -L "https://go.kubebuilder.io/test-tools/${K8S_VERSION}/$(shell go env GOOS)/$(shell go env GOARCH)" --output - | \
tar -C ./ --strip-components=1 -zvxf -

##@ Linting
## --------------------------------------
## Linting
Expand Down Expand Up @@ -254,7 +311,8 @@ cluster-api/tilt-settings.json: hack/tilt-settings.json cluster-api
## Tests
## --------------------------------------

export KUBEBUILDER_ASSETS=$(TOOLS_BIN_DIR)
KUBEBUILDER_ASSETS ?= $(shell $(SETUP_ENVTEST) use --use-env -p path $(KUBEBUILDER_ENVTEST_KUBERNETES_VERSION))

DEEPCOPY_GEN_TARGETS_TEST=$(shell find test/fakes -type d -name "fakes" -exec echo {}\/zz_generated.deepcopy.go \;)
DEEPCOPY_GEN_INPUTS_TEST=$(shell find test/fakes/* -name "*zz_generated*" -prune -o -type f -print)
.PHONY: generate-deepcopy-test
Expand All @@ -269,22 +327,30 @@ config/.flag-test.mk: $(CONTROLLER_GEN) $(MANIFEST_GEN_INPUTS_TEST)
$(CONTROLLER_GEN) crd:crdVersions=v1 rbac:roleName=manager-role webhook paths="./test/fakes" output:crd:artifacts:config=test/fakes
@touch config/.flag-test.mk

.PHONY: setup-envtest
setup-envtest: $(SETUP_ENVTEST) ## Set up envtest (download kubebuilder assets)
@echo KUBEBUILDER_ASSETS=$(KUBEBUILDER_ASSETS)

.PHONY: test
test: ## Run tests.
test: generate-deepcopy-test generate-manifest-test generate-mocks lint $(GINKGO) $(KUBECTL) $(API_SERVER) $(ETCD)
test: generate-deepcopy-test generate-manifest-test generate-mocks lint setup-envtest $(GINKGO)
@./hack/testing_ginkgo_recover_statements.sh --add # Add ginkgo.GinkgoRecover() statements to controllers.
@# The following is a slightly funky way to make sure the ginkgo statements are removed regardless the test results.
@$(GINKGO) --label-filter="!integ" --cover -coverprofile cover.out --covermode=atomic -v ./api/... ./controllers/... ./pkg/...; EXIT_STATUS=$$?;\
KUBEBUILDER_ASSETS="$(KUBEBUILDER_ASSETS)" $(GINKGO) --label-filter="!integ" --cover -coverprofile cover.out --covermode=atomic -v ./api/... ./controllers/... ./pkg/...; EXIT_STATUS=$$?;\
./hack/testing_ginkgo_recover_statements.sh --remove; exit $$EXIT_STATUS

.PHONY: test-pkg
test-pkg: $(GINKGO) ## Run pkg tests.
@$(GINKGO) --label-filter="!integ" --cover -coverprofile cover.out --covermode=atomic -v ./pkg/...

CLUSTER_TEMPLATES_INPUT_FILES=$(shell find test/e2e/data/infrastructure-cloudstack/v1beta*/cluster-template* test/e2e/data/infrastructure-cloudstack/*/bases/* -type f)
CLUSTER_TEMPLATES_OUTPUT_FILES=$(shell find test/e2e/data/infrastructure-cloudstack -type d -name "cluster-template*" -exec echo {}.yaml \;)
.PHONY: e2e-cluster-templates
e2e-cluster-templates: $(CLUSTER_TEMPLATES_OUTPUT_FILES) ## Generate cluster template files for e2e testing.
cluster-template%yaml: $(KUSTOMIZE) $(CLUSTER_TEMPLATES_INPUT_FILES)
$(KUSTOMIZE) build --load-restrictor LoadRestrictionsNone $(basename $@) > $@

e2e-essentials: $(GINKGO) $(KUBECTL) e2e-cluster-templates create-kind-cluster ## Fulfill essential tasks for e2e testing.
e2e-essentials: $(GINKGO) setup-envtest e2e-cluster-templates create-kind-cluster ## Fulfill essential tasks for e2e testing.
IMG=$(IMG_LOCAL) make generate-manifests docker-build docker-push

JOB ?= .*
Expand Down Expand Up @@ -359,3 +425,62 @@ release-templates: ## Generate release templates
.PHONY: upload-staging-artifacts
upload-staging-artifacts: ## Upload release artifacts to the staging bucket
gsutil cp $(RELEASE_DIR)/* gs://$(STAGING_BUCKET)/components/$(RELEASE_ALIAS_TAG)/

##@ hack/tools:

.PHONY: $(CONTROLLER_GEN_BIN)
$(CONTROLLER_GEN_BIN): $(CONTROLLER_GEN) ## Build a local copy of controller-gen.

.PHONY: $(CONVERSION_GEN_BIN)
$(CONVERSION_GEN_BIN): $(CONVERSION_GEN) ## Build a local copy of conversion-gen.

.PHONY: $(ENVSUBST_BIN)
$(ENVSUBST_BIN): $(ENVSUBST) ## Build a local copy of envsubst.

.PHONY: $(KUSTOMIZE_BIN)
$(KUSTOMIZE_BIN): $(KUSTOMIZE) ## Build a local copy of kustomize.

.PHONY: $(SETUP_ENVTEST_BIN)
$(SETUP_ENVTEST_BIN): $(SETUP_ENVTEST) ## Build a local copy of setup-envtest.

.PHONY: $(GINKGO_BIN)
$(GINKGO_BIN): $(GINKGO) ## Build a local copy of ginkgo.

.PHONY: $(GOLANGCI_LINT_BIN)
$(GOLANGCI_LINT_BIN): $(GOLANGCI_LINT) ## Build a local copy of golangci-lint.

.PHONY: $(MOCKGEN_BIN)
$(MOCKGEN_BIN): $(MOCKGEN) ## Build a local copy of mockgen.

.PHONY: $(STATIC_CHECK_BIN)
$(STATIC_CHECK_BIN): $(STATIC_CHECK) ## Build a local copy of staticcheck.

$(CONTROLLER_GEN): # Build controller-gen from tools folder.
GOBIN=$(TOOLS_BIN_DIR) $(GO_INSTALL) $(CONTROLLER_GEN_PKG) $(CONTROLLER_GEN_BIN) $(CONTROLLER_GEN_VER)

## We are forcing a rebuilt of conversion-gen via PHONY so that we're always using an up-to-date version.
## We can't use a versioned name for the binary, because that would be reflected in generated files.
.PHONY: $(CONVERSION_GEN)
$(CONVERSION_GEN): # Build conversion-gen from tools folder.
GOBIN=$(TOOLS_BIN_DIR) $(GO_INSTALL) $(CONVERSION_GEN_PKG) $(CONVERSION_GEN_BIN) $(CONVERSION_GEN_VER)

$(ENVSUBST): # Build gotestsum from tools folder.
GOBIN=$(TOOLS_BIN_DIR) $(GO_INSTALL) $(ENVSUBST_PKG) $(ENVSUBST_BIN) $(ENVSUBST_VER)

$(KUSTOMIZE): # Build kustomize from tools folder.
CGO_ENABLED=0 GOBIN=$(TOOLS_BIN_DIR) $(GO_INSTALL) $(KUSTOMIZE_PKG) $(KUSTOMIZE_BIN) $(KUSTOMIZE_VER)

$(SETUP_ENVTEST): # Build setup-envtest from tools folder.
GOBIN=$(TOOLS_BIN_DIR) $(GO_INSTALL) $(SETUP_ENVTEST_PKG) $(SETUP_ENVTEST_BIN) $(SETUP_ENVTEST_VER)

$(GINKGO): # Build ginkgo from tools folder.
GOBIN=$(TOOLS_BIN_DIR) $(GO_INSTALL) $(GINKGO_PKG) $(GINKGO_BIN) $(GINGKO_VER)

$(GOLANGCI_LINT): # Build golangci-lint from tools folder.
GOBIN=$(TOOLS_BIN_DIR) $(GO_INSTALL) $(GOLANGCI_LINT_PKG) $(GOLANGCI_LINT_BIN) $(GOLANGCI_LINT_VER)

$(MOCKGEN): # Build mockgen from tools folder.
GOBIN=$(TOOLS_BIN_DIR) $(GO_INSTALL) $(MOCKGEN_PKG) $(MOCKGEN_BIN) $(MOCKGEN_VER)

$(STATIC_CHECK): # Build golangci-lint from tools folder.
GOBIN=$(TOOLS_BIN_DIR) $(GO_INSTALL) $(STATIC_CHECK_PKG) $(STATIC_CHECK_BIN) $(STATIC_CHECK_VER)
4 changes: 0 additions & 4 deletions common.mk
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ SHELL:=bash
MAKEFLAGS += --no-builtin-rules

TOOLS_DIR := $(REPO_ROOT)/hack/tools
TOOLS_DIR_DEPS := $(TOOLS_DIR)/go.sum $(TOOLS_DIR)/go.mod $(TOOLS_DIR)/Makefile
TOOLS_BIN_DIR := $(TOOLS_DIR)/bin
UID := $(shell id -u)
GID := $(shell id -g)
Expand All @@ -46,9 +45,6 @@ GOPROXY := https://proxy.golang.org
endif
export GOPROXY

$(TOOLS_BIN_DIR)/%: $(TOOLS_DIR_DEPS)
make -C $(TOOLS_DIR) $(subst $(TOOLS_DIR)/,,$@)

##@ Help
## --------------------------------------
## Help
Expand Down
45 changes: 45 additions & 0 deletions hack/go_install.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
#!/usr/bin/env bash
# Copyright 2021 The Kubernetes Authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

set -o errexit
set -o nounset
set -o pipefail

if [ -z "${1}" ]; then
echo "must provide module as first parameter"
exit 1
fi

if [ -z "${2}" ]; then
echo "must provide binary name as second parameter"
exit 1
fi

if [ -z "${3}" ]; then
echo "must provide version as third parameter"
exit 1
fi

if [ -z "${GOBIN}" ]; then
echo "GOBIN is not set. Must set GOBIN to install the bin in a specified directory."
exit 1
fi

rm -f "${GOBIN}/${2}"* || true

# install the golang module specified as the first argument
go install "${1}@${3}"
mv "${GOBIN}/${2}" "${GOBIN}/${2}-${3}"
ln -sf "${GOBIN}/${2}-${3}" "${GOBIN}/${2}"
45 changes: 0 additions & 45 deletions hack/tools/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,6 @@ ifeq ($(OS), windows)
MDBOOK_EXTRACT_COMMAND := unzip -d /tmp
endif

GOLANGCI_LINT_VERSION := v1.58.1
GOLANGCI_LINT_BIN := golangci-lint
GOLANGCI_LINT := $(abspath $(BIN_DIR)/$(GOLANGCI_LINT_BIN))
GOLANGCI_LINT_PKG := github.com/golangci/golangci-lint/cmd/golangci-lint

## --------------------------------------
## Tooling Binaries
## --------------------------------------
Expand All @@ -63,34 +58,6 @@ $(SHARE_DIR):
$(GTAR):
@$(GTAR) --version > /dev/null || (echo Install GNU Tar with brew install gnu-tar && exit -1)


CONTROLLER_GEN := $(BIN_DIR)/controller-gen
$(CONTROLLER_GEN): $(BIN_DIR) go.mod go.sum # Build controller-gen from tools folder.
go build -tags=tools -o $@ sigs.k8s.io/controller-tools/cmd/controller-gen

CONVERSION_GEN := $(BIN_DIR)/conversion-gen
$(CONVERSION_GEN): $(BIN_DIR) go.mod go.sum
go build -tags=tools -o $@ k8s.io/code-generator/cmd/conversion-gen

# A target for compatibility with the root Makefile.
$(BIN_DIR)/$(GOLANGCI_LINT_BIN): $(GOLANGCI_LINT)

$(GOLANGCI_LINT_BIN): $(GOLANGCI_LINT)
$(GOLANGCI_LINT): $(BIN_DIR) # Install golangci-lint in tools folder.
GOBIN=$(abspath $(BIN_DIR)) go install $(GOLANGCI_LINT_PKG)@$(GOLANGCI_LINT_VERSION)

STATIC_CHECK := $(BIN_DIR)/staticcheck
$(STATIC_CHECK): $(BIN_DIR) go.mod go.sum # Build staticcheck from tools folder.
go build -tags=tools -o $@ honnef.co/go/tools/cmd/staticcheck

GINKGO := $(BIN_DIR)/ginkgo
$(GINKGO): $(BIN_DIR) go.mod go.sum # Build staticcheck from tools folder.
go build -tags=tools -o $@ github.com/onsi/ginkgo/v2/ginkgo

ENVSUBST := $(BIN_DIR)/envsubst
$(ENVSUBST): $(BIN_DIR) go.mod go.sum # Build envsubst from tools folder.
go build -tags=tools -o $@ github.com/a8m/envsubst/cmd/envsubst

GH_SHARE := $(SHARE_DIR)/gh

$(GH_SHARE): $(SHARE_DIR)
Expand All @@ -105,14 +72,6 @@ GH: $(GTAR) $(GH_SHARE)/gh.tar.gz
chmod +x $@
touch -m $@

KIND := $(BIN_DIR)/kind
$(KIND): $(BIN_DIR) go.mod go.sum
go build -tags tools -o $@ sigs.k8s.io/kind

KUSTOMIZE := $(BIN_DIR)/kustomize
$(KUSTOMIZE): $(BIN_DIR) go.mod go.sum # Build kustomize from tools folder.
CGO_ENABLED=0 go build -tags=tools -o $@ sigs.k8s.io/kustomize/kustomize/v4

MDBOOK_SHARE := $(SHARE_DIR)/mdbook$(MDBOOK_ARCHIVE_EXT)
$(MDBOOK_SHARE): ../../versions.mk $(SHARE_DIR)
curl -sL -o $(MDBOOK_SHARE) "https://github.com/rust-lang/mdBook/releases/download/$(MDBOOK_VERSION)/mdBook-$(MDBOOK_VERSION)-x86_64-$(RUST_TARGET)$(MDBOOK_ARCHIVE_EXT)"
Expand All @@ -135,10 +94,6 @@ MDBOOK_TABULATE := $(BIN_DIR)/mdbook-tabulate
$(MDBOOK_TABULATE): $(BIN_DIR) go.mod go.sum
go build -tags=tools -o $(BIN_DIR)/mdbook-tabulate sigs.k8s.io/cluster-api/hack/tools/mdbook/tabulate

MOCKGEN := $(BIN_DIR)/mockgen
$(MOCKGEN): $(BIN_DIR) go.mod go.sum # Build mockgen from tools folder.
go build -tags=tools -o $@ github.com/golang/mock/mockgen

RELEASE_NOTES := $(BIN_DIR)/release-notes
$(RELEASE_NOTES): $(BIN_DIR) go.mod go.sum
go build -tags tools -o $@ sigs.k8s.io/cluster-api/hack/tools/release
Expand Down
Loading

0 comments on commit 550b025

Please sign in to comment.