airshipctl/Makefile
Ruslan Aliev 3e44c42989 Introduce KRM based k8s applier
The KRM based k8s applier solves multiple design problems
which were introduced in previous airshipctl generation,
making apply code and process more clear, reliable and
readable. In particular:
 * k8s applier now is a KRM function and it allows the
   end user to choose or implement desired backend for
   k8s apply operations;
 * the related amount of code was reduced by three times,
   multiple unused and unnecessary structs/interfaces/design
   patterns were removed or rewrited in more clean and efficient
   way;
 * removed cli-utils dependency from airshipctl;
 * fixed several bugs and code issues, such as incorrect printing
   of tables, duplicated unit tests, improper generation and applying
   inventory config map, etc;
 * cli-utils version used in KRM function was bumped to 0.26.0;
 * phases with duplicated k8s resources were removed or fixed;
 * unit test coverage increased to 83.1%;
 * KRM function logs were integrated with klog library which allows
   to observe logs directly from cli-utils and other dependent libs.

Change-Id: Ief509f1d6abefd53caf7fcffc4e36b0319815373
Signed-off-by: Ruslan Aliev <raliev@mirantis.com>
Closes: #646
2021-10-27 08:14:22 +00:00

400 lines
13 KiB
Makefile

SHELL := /bin/bash
GIT_VERSION ?= v0.1.0
GIT_COMMIT ?= $(shell git rev-parse HEAD)
BUILD_DATE ?= $(shell date -u +'%Y-%m-%dT%H:%M:%SZ')
GIT_MODULE ?= opendev.org/airship/airshipctl/pkg/version
LDFLAGS += -X ${GIT_MODULE}.gitVersion=${GIT_VERSION}
LDFLAGS += -X ${GIT_MODULE}.gitCommit=${GIT_COMMIT}
LDFLAGS += -X ${GIT_MODULE}.buildDate=${BUILD_DATE}
GO_FLAGS := -ldflags '-extldflags "-static"' -tags=netgo -trimpath
GO_FLAGS += -ldflags '$(LDFLAGS)'
# Get the currently used golang install path (in GOPATH/bin, unless GOBIN is set)
ifeq (,$(shell go env GOBIN 2> /dev/null))
GOBIN = $(shell go env GOPATH 2> /dev/null)/bin
else
GOBIN = $(shell go env GOBIN 2> /dev/null)
endif
# Produce CRDs that work back to Kubernetes 1.16
CRD_OPTIONS ?= crd:crdVersions=v1
TOOLBINDIR := tools/bin
# linting
LINTER := $(TOOLBINDIR)/golangci-lint
LINTER_CONFIG := .golangci.yaml
# docker
DOCKER_MAKE_TARGET := build
DOCKER_CMD_FLAGS :=
# docker image options
DOCKER_REGISTRY ?= quay.io
DOCKER_FORCE_CLEAN ?= true
DOCKER_IMAGE_NAME ?= airshipctl
DOCKER_IMAGE_PREFIX ?= airshipit
DOCKER_IMAGE_TAG ?= latest
DOCKER_IMAGE ?= $(DOCKER_REGISTRY)/$(DOCKER_IMAGE_PREFIX)/$(DOCKER_IMAGE_NAME):$(DOCKER_IMAGE_TAG)
DOCKER_TARGET_STAGE ?= release
PUBLISH ?= false
# use this variable for image labels added in internal build process
COMMIT ?= $(shell git rev-parse HEAD)
LABEL ?= org.airshipit.build=community
LABEL += --label "org.opencontainers.image.revision=$(COMMIT)"
LABEL += --label "org.opencontainers.image.created=$(shell date --rfc-3339=seconds --utc)"
LABEL += --label "org.opencontainers.image.title=$(DOCKER_IMAGE_NAME)"
# go options
PKG ?= ./...
TESTS ?= .
TEST_FLAGS ?=
COVER_FLAGS ?=
COVER_PROFILE ?= cover.out
COVER_EXCLUDE ?= (zz_generated|errors)
# proxy options
PROXY ?= http://proxy.foo.com:8000
NO_PROXY ?= localhost,127.0.0.1,.svc.cluster.local
USE_PROXY ?= false
# docker build flags
DOCKER_CMD_FLAGS += --network=host
DOCKER_CMD_FLAGS += --force-rm=$(DOCKER_FORCE_CLEAN)
ifeq ($(USE_PROXY), true)
DOCKER_CMD_FLAGS += --build-arg http_proxy=$(PROXY)
DOCKER_CMD_FLAGS += --build-arg https_proxy=$(PROXY)
DOCKER_CMD_FLAGS += --build-arg HTTP_PROXY=$(PROXY)
DOCKER_CMD_FLAGS += --build-arg HTTPS_PROXY=$(PROXY)
DOCKER_CMD_FLAGS += --build-arg no_proxy=$(NO_PROXY)
DOCKER_CMD_FLAGS += --build-arg NO_PROXY=$(NO_PROXY)
endif
ifneq ($(strip $(GOPROXY)),)
DOCKER_CMD_FLAGS += --build-arg GOPROXY=$(strip $(GOPROXY))
endif
# Godoc server options
GD_PORT ?= 8080
# Documentation location
DOCS_DIR ?= docs
# document validation options
UNAME != uname
export KIND_URL ?= https://kind.sigs.k8s.io/dl/v0.8.1/kind-$(UNAME)-amd64
KUBECTL_VERSION ?= v1.18.6
export KUBECTL_URL ?= https://storage.googleapis.com/kubernetes-release/release/${KUBECTL_VERSION}/bin/linux/amd64/kubectl
.PHONY: depend
depend:
@go mod download
.PHONY: build
.PHONY: install
install: depend
install:
@CGO_ENABLED=0 go install .
# Core of build logic
BIN_DIR := bin
BIN_SRC_DIR := krm-functions
BINS := airshipctl $(subst $(BIN_SRC_DIR)/,,$(wildcard $(BIN_SRC_DIR)/*))
IMGS := $(BINS)
# This section sets the settings for different subcomponents
# airshipctl is a special case - we need to override it manually:
# its makefile target for image is 'docker-image' - others have
# docker-image-<name of component> targets
airshipctl_IMG_TGT_NAME:=docker-image
# its main.go is in the root of repo - others have main.go in
# $(BIN_SRC_DIR)/<name of component>/main.go
airshipctl_FROM_PATH:=.
# and its Dockerfile is also in the root of repo - others have Dockerfile in
# $(BIN_SRC_DIR)/<name of component>/Dockerfile
docker-image_DOCKERFILE:=Dockerfile
# kubeval-validator, toolbox and toolbox-virsh don't depend on
# airshipctl repo. Their Dockerfiles don't
# need to be called from the root of the repo.
applier_IS_INDEPENDED:=true
kubeval-validator_IS_INDEPENDED:=true
clusterctl_IS_INDEPENDED:=true
clusterctl-v0.3_IS_INDEPENDED:=true
toolbox-virsh_IS_INDEPENDED:=true
# in addition toolbox-virsh docker image needs toolbox docker image to be built first
docker-image-clusterctl-v0.3_DEPENDENCY:=docker-image-clusterctl
docker-image-toolbox-virsh_DEPENDENCY:=docker-image-toolbox
# The template that generates targets for creating binaries per component:
# Targets will be generated only for components that depend on airshipctl repo (part of that go module)
# Note: expressions with ?= won't be executed if the values of that variable was already set to it.
# Using that syntax it's possible to build values overrides for components.
# Note 2: $$ is needed to instruct make-engine that variable should be used after template rendering.
# When template is rendered all $ will be rendered in the template and $$ will be converted to $, e.g.
# if we call map_binary_defaults_tmpl for airshipctl $1 will be converted to 'airshipctl' and we'll get
# ifneq ($(airshipctl_IS_INDEPENDED),true)
# airshipctl_FROM_PATH?=$(BIN_SRC_DIR)/airshipctl/main.go
# ...
# since we defining airshipctl_FROM_PATH above, and ?= is used in the 2nd line
# airshipctl_FROM_PATH will stay the same as it was defined above.
define map_binary_defaults_tmpl
ifneq ($$($1_IS_INDEPENDED),true)
$1_FROM_PATH?=$$(BIN_SRC_DIR)/$1/main.go
$$(warning Adding dynamic target $$(BIN_DIR)/$1)
$$(BIN_DIR)/$1: $$($1_FROM_PATH) depend
@CGO_ENABLED=0 go build -o $$@ $$(GO_FLAGS) $$<
$$(warning Adding dynamic target $1)
.PHONY: $1
$1: $$(BIN_DIR)/$1
build: $1
endif
endef
map_binary_defaults = $(eval $(call map_binary_defaults_tmpl,$1))
# Go through all components and generate binary targets for each of them
$(foreach bin,$(BINS),$(call map_binary_defaults,$(bin)))
.PHONY: images
.PHONY: images-publish
# The template that generates targets for creating images per components
# There is a special logic to handle per-components overrides
# 2 targets will be generated per component: docker-image-<component name> (possible to override)
# and docker-image-<component name>-publish
define map_image_defaults_tmpl
$1_IMG_TGT_NAME?=docker-image-$1
$$($1_IMG_TGT_NAME)_IMG_TITLE?=$1
$$($1_IMG_TGT_NAME)_IMG_TAG?=$$(DOCKER_IMAGE_TAG)
$$($1_IMG_TGT_NAME)_DOCKERTGT?=$$(DOCKER_TARGET_STAGE)
$$($1_IMG_TGT_NAME)_DOCKERFILE?=$$(BIN_SRC_DIR)/$1/Dockerfile
$$($1_IMG_TGT_NAME)_MAKETGT?=$$(BIN_DIR)/$1
ifeq ($$($1_IS_INDEPENDED),true)
$$($1_IMG_TGT_NAME)_DOCKERROOT?=$$(BIN_SRC_DIR)/$1
else
$$($1_IMG_TGT_NAME)_DOCKERROOT?=.
endif
ifneq ($1,airshipctl)
ifneq ($$(origin DOCKER_BASE_PLUGINS_GO_IMAGE), undefined)
$$($1_IMG_TGT_NAME)_BASE_GO_IMAGE?=$$(DOCKER_BASE_PLUGINS_GO_IMAGE)
endif
endif
$$($1_IMG_TGT_NAME)_BASE_GO_IMAGE?=$$(DOCKER_BASE_GO_IMAGE)
ifneq ($$(strip $$($$($1_IMG_TGT_NAME)_BASE_GO_IMAGE)),)
$$($1_IMG_TGT_NAME)_BUILD_ARG += GO_IMAGE=$$($$($1_IMG_TGT_NAME)_BASE_GO_IMAGE)
endif
ifneq ($1,airshipctl)
ifneq ($$(origin DOCKER_BASE_PLUGINS_BUILD_IMAGE), undefined)
$$($1_IMG_TGT_NAME)_BASE_BUILD_IMAGE?=$$(DOCKER_BASE_PLUGINS_BUILD_IMAGE)
endif
endif
$$($1_IMG_TGT_NAME)_BASE_BUILD_IMAGE?=$$(DOCKER_BASE_BUILD_IMAGE)
ifneq ($$(strip $$($$($1_IMG_TGT_NAME)_BASE_BUILD_IMAGE)),)
$$($1_IMG_TGT_NAME)_BUILD_ARG += BUILD_IMAGE=$$($$($1_IMG_TGT_NAME)_BASE_BUILD_IMAGE)
endif
ifneq ($1,airshipctl)
ifneq ($$(origin DOCKER_BASE_PLUGINS_RELEASE_IMAGE), undefined)
$$($1_IMG_TGT_NAME)_BASE_RELEASE_IMAGE?=$$(DOCKER_BASE_PLUGINS_RELEASE_IMAGE)
endif
endif
$$($1_IMG_TGT_NAME)_BASE_RELEASE_IMAGE?=$$(DOCKER_BASE_RELEASE_IMAGE)
ifneq ($$(strip $$($$($1_IMG_TGT_NAME)_BASE_RELEASE_IMAGE)),)
$$($1_IMG_TGT_NAME)_BUILD_ARG += RELEASE_IMAGE=$$($$($1_IMG_TGT_NAME)_BASE_RELEASE_IMAGE)
endif
ifeq ($1,clusterctl-v0.3)
$$($1_IMG_TGT_NAME)_IMG_TAG=v0.3
$$($1_IMG_TGT_NAME)_IMG_TITLE=clusterctl
endif
$$(warning Adding dynamic target $$($1_IMG_TGT_NAME))
.PHONY: $$($1_IMG_TGT_NAME)
$$($1_IMG_TGT_NAME): $$($$($1_IMG_TGT_NAME)_DEPENDENCY)
docker build $$($$($1_IMG_TGT_NAME)_DOCKERROOT) $$(DOCKER_CMD_FLAGS)\
--file $$($$($1_IMG_TGT_NAME)_DOCKERFILE) \
--label $$(LABEL) \
--label "org.opencontainers.image.revision=$$(COMMIT)" \
--label "org.opencontainers.image.created=$$(shell date --rfc-3339=seconds --utc)" \
--label "org.opencontainers.image.title=$$($$($1_IMG_TGT_NAME)_IMG_TITLE)" \
--target $$($$($1_IMG_TGT_NAME)_DOCKERTGT) \
$$(addprefix --build-arg ,$$($$($1_IMG_TGT_NAME)_BUILD_ARG)) \
--build-arg MAKE_TARGET=$$($$($1_IMG_TGT_NAME)_MAKETGT) \
--tag $$(DOCKER_REGISTRY)/$$(DOCKER_IMAGE_PREFIX)/$$($$($1_IMG_TGT_NAME)_IMG_TITLE):$$($$($1_IMG_TGT_NAME)_IMG_TAG) \
$$(foreach tag,$$(DOCKER_IMAGE_EXTRA_TAGS),--tag $$(DOCKER_REGISTRY)/$$(DOCKER_IMAGE_PREFIX)/$1:$$(tag) )
ifeq ($$(PUBLISH), true)
@docker push $$(DOCKER_REGISTRY)/$$(DOCKER_IMAGE_PREFIX)/$$($$($1_IMG_TGT_NAME)_IMG_TITLE):$$($$($1_IMG_TGT_NAME)_IMG_TAG)
endif
images: $$($1_IMG_TGT_NAME)
$$(warning Adding dynamic target $$($1_IMG_TGT_NAME)-publish)
.PHONY: $$($1_IMG_TGT_NAME)-publish
$$($1_IMG_TGT_NAME)-publish: $$($1_IMG_TGT_NAME)
@docker push $$(DOCKER_REGISTRY)/$$(DOCKER_IMAGE_PREFIX)/$1:$$(DOCKER_IMAGE_TAG)
images-publish: $$($1_IMG_TGT_NAME)-publish
endef
map_image_defaults = $(eval $(call map_image_defaults_tmpl,$1))
# go through components and render the template
$(foreach img,$(IMGS),$(call map_image_defaults,$(img)))
.PHONY: test
test: lint
test: cover
test: check-copyright
.PHONY: unit-tests
unit-tests: TESTFLAGS += -race -v
unit-tests:
@echo "Performing unit test step..."
@go test -run $(TESTS) $(PKG) $(TESTFLAGS) $(COVER_FLAGS)
@echo "All unit tests passed"
.PHONY: cover
cover: COVER_FLAGS = -covermode=atomic -coverprofile=fullcover.out
cover: unit-tests
@grep -vE "$(COVER_EXCLUDE)" fullcover.out > $(COVER_PROFILE)
@./tools/coverage_check $(COVER_PROFILE)
.PHONY: fmt
fmt: lint
.PHONY: lint
lint: tidy
lint: $(LINTER)
@echo "Performing linting step..."
@./tools/whitespace_linter
@./$(LINTER) run --config $(LINTER_CONFIG)
@echo "Linting completed successfully"
.PHONY: tidy
tidy:
@echo "Checking that go.mod is up to date..."
@./tools/gomod_check
@echo "go.mod is up to date"
.PHONY: golint
golint:
@./tools/golint
.PHONY: print-docker-image-tag
print-docker-image-tag:
@echo "$(DOCKER_IMAGE)"
.PHONY: docker-image-test-suite
docker-image-test-suite: docker-image_MAKETGT = "cover update-golden generate check-git-diff"
docker-image-test-suite: docker-image_DOCKERTGT = builder
docker-image-test-suite: docker-image
.PHONY: docker-image-unit-tests
docker-image-unit-tests: docker-image_MAKETGT = cover
docker-image-unit-tests: docker-image_DOCKERTGT = builder
docker-image-unit-tests: docker-image
.PHONY: docker-image-lint
docker-image-lint: docker-image_MAKETGT = "lint check-copyright"
docker-image-lint: docker-image_DOCKERTGT = builder
docker-image-lint: docker-image
.PHONY: docker-image-golint
docker-image-golint: docker-image_MAKETGT = golint
docker-image-golint: docker-image_DOCKERTGT = builder
docker-image-golint: docker-image
.PHONY: clean
clean:
@rm -fr $(BIN_DIR)
@rm -fr $(COVER_PROFILE)
.PHONY: docs
docs:
tox
.PHONY: godoc
godoc:
@go install golang.org/x/tools/cmd/godoc
@echo "Follow this link to package documentation: http://localhost:${GD_PORT}/pkg/opendev.org/airship/airshipctl/"
@godoc -http=":${GD_PORT}"
.PHONY: cli-docs
cli-docs:
@echo "Generating CLI documentation..."
@go run $(DOCS_DIR)/tools/generate_cli_docs.go
@echo "CLI documentation generated"
.PHONY: releasenotes
releasenotes:
@echo "TODO"
$(TOOLBINDIR):
mkdir -p $(TOOLBINDIR)
$(LINTER): $(TOOLBINDIR)
./tools/install_linter
.PHONY: update-golden
update-golden: delete-golden
update-golden: TESTFLAGS += -update
update-golden: PKG = opendev.org/airship/airshipctl/cmd/...
update-golden: unit-tests
update-golden: cli-docs
# The delete-golden target is a utility for update-golden
.PHONY: delete-golden
delete-golden:
@find . -type f -name "*.golden" -delete
# Used by gates after unit-tests and update-golden targets to ensure no files are deleted.
.PHONY: check-git-diff
check-git-diff:
@./tools/git_diff_check
# add-copyright is a utility to add copyright header to missing files
.PHONY: add-copyright
add-copyright:
@./tools/add_license.sh
# check-copyright is a utility to check if copyright header is present on all files
.PHONY: check-copyright
check-copyright:
@./tools/check_copyright
# Validate YAMLs for all sites
.PHONY: validate-docs
validate-docs:
@./tools/validate_docs
# Generate code
generate: controller-gen
$(CONTROLLER_GEN) object:headerFile="tools/license_go.txt" paths="./..."
# find or download controller-gen
# download controller-gen if necessary
controller-gen:
ifeq (, $(shell which controller-gen))
@{ \
set -e ;\
CONTROLLER_GEN_TMP_DIR=$$(mktemp -d) ;\
cd $$CONTROLLER_GEN_TMP_DIR ;\
go mod init tmp ;\
go get sigs.k8s.io/controller-tools/cmd/controller-gen@v0.6.1 ;\
rm -rf $$CONTROLLER_GEN_TMP_DIR ;\
}
CONTROLLER_GEN=$(GOBIN)/controller-gen
else
CONTROLLER_GEN=$(shell which controller-gen)
endif
# Generate manifests e.g. CRD, RBAC etc.
manifests: controller-gen
$(CONTROLLER_GEN) $(CRD_OPTIONS) rbac:roleName=manager-role webhook paths="./..." output:crd:artifacts:config=manifests/function/airshipctl-schemas