...

Text file src/github.com/emissary-ingress/emissary/v3/build-aux/builder.mk

Documentation: github.com/emissary-ingress/emissary/v3/build-aux

     1BUILDER_HOME := $(dir $(abspath $(lastword $(MAKEFILE_LIST))))
     2
     3LCNAME := $(shell echo $(NAME) | tr '[:upper:]' '[:lower:]')
     4BUILDER_NAME ?= $(LCNAME)
     5
     6include $(OSS_HOME)/build-aux/prelude.mk
     7include $(OSS_HOME)/build-aux/colors.mk
     8
     9docker.tag.local = $(BUILDER_NAME).local/$(*F)
    10docker.tag.remote = $(if $(DEV_REGISTRY),,$(error $(REGISTRY_ERR)))$(DEV_REGISTRY)/$(*F):$(patsubst v%,%,$(VERSION))
    11include $(OSS_HOME)/build-aux/docker.mk
    12
    13include $(OSS_HOME)/build-aux/teleproxy.mk
    14
    15MODULES :=
    16
    17module = $(eval MODULES += $(1))$(eval SOURCE_$(1)=$(abspath $(2)))
    18
    19BUILDER = BUILDER_NAME=$(BUILDER_NAME) $(abspath $(BUILDER_HOME)/builder.sh)
    20
    21AWS_S3_BUCKET ?= datawire-static-files
    22
    23# the image used for running the Ingress v1 tests with KIND.
    24# the current, official image does not support Ingress v1, so we must build our own image with k8s 1.18.
    25# build this image with:
    26# 1. checkout the Kuberentes sources in a directory like "~/sources/kubernetes"
    27# 2. kind build node-image --kube-root ~/sources/kubernetes
    28# 3. docker tag kindest/node:latest docker.io/datawire/kindest-node:latest
    29# 4. docker push docker.io/datawire/kindest-node:latest
    30# This will not be necessary once the KIND images are built for a Kubernetes 1.18 and support Ingress v1beta1 improvements.
    31KIND_IMAGE ?= kindest/node:v1.18.0
    32#KIND_IMAGE ?= docker.io/datawire/kindest-node:latest
    33KIND_KUBECONFIG = /tmp/kind-kubeconfig
    34
    35# The ingress conformance tests directory
    36# build this image with:
    37# 1. checkout https://github.com/kubernetes-sigs/ingress-controller-conformance
    38# 2. cd ingress-controller-conformance && make image
    39# 3. docker tag ingress-controller-conformance:latest docker.io/datawire/ingress-controller-conformance:latest
    40# 4. docker push docker.io/datawire/ingress-controller-conformance:latest
    41INGRESS_TEST_IMAGE ?= docker.io/datawire/ingress-controller-conformance:latest
    42
    43# local ports for the Ingress conformance tests
    44INGRESS_TEST_LOCAL_PLAIN_PORT = 8000
    45INGRESS_TEST_LOCAL_TLS_PORT = 8443
    46INGRESS_TEST_LOCAL_ADMIN_PORT = 8877
    47
    48# directory with the manifests for loading Ambassador for running the Ingress Conformance tests
    49# NOTE: these manifests can be slightly different to the regular ones asd they include
    50INGRESS_TEST_MANIF_DIR = $(BUILDER_HOME)/../manifests/emissary/
    51INGRESS_TEST_MANIFS = emissary-crds.yaml emissary-emissaryns.yaml
    52
    53# DOCKER_BUILDKIT is _required_ by our Dockerfile, since we use Dockerfile extensions for the
    54# Go build cache. See https://github.com/moby/buildkit/blob/master/frontend/dockerfile/docs/syntax.md.
    55export DOCKER_BUILDKIT := 1
    56
    57all: help
    58.PHONY: all
    59
    60.NOTPARALLEL:
    61
    62# the name of the Docker network
    63# note: use your local k3d/microk8s/kind network for running tests
    64DOCKER_NETWORK ?= $(BUILDER_NAME)
    65
    66# local host IP address (and not 127.0.0.1)
    67ifneq ($(shell which ipconfig 2>/dev/null),)
    68  # macOS
    69  HOST_IP := $(shell ipconfig getifaddr $$(route get 1.1.1.1 | awk '/interface:/ {print $$2}'))
    70else ifneq ($(shell which ip 2>/dev/null),)
    71  # modern (iproute2) GNU/Linux
    72  #HOST_IP := $(shell ip --json route get to 1.1.1.1 | jq -r '.[0].prefsrc')
    73  HOST_IP := $(shell ip route get to 1.1.1.1 | sed -n '1s/.*src \([0-9.]\+\).*/\1/p')
    74else
    75  $(error I do not know how to get the host IP on this system; it has neither 'ipconfig' (macOS) nor 'ip' (modern GNU/Linux))
    76  # ...and I (lukeshu) couldn't figure out a good way to do it on old (net-tools) GNU/Linux.
    77endif
    78
    79GO_ERR     = $(RED)ERROR: please update to go 1.13 or newer$(END)
    80DOCKER_ERR = $(RED)ERROR: please update to a version of docker built with Go 1.13 or newer$(END)
    81
    82preflight:
    83	@printf "$(CYN)==> $(GRN)Preflight checks$(END)\n"
    84
    85	@echo "Checking that 'go' is installed and is 1.13 or later"
    86	@$(if $(call _prelude.go.VERSION.HAVE,1.13),,printf '%s\n' $(call quote.shell,$(GO_ERR)))
    87
    88	@echo "Checking that 'docker' is installed and supports the 'slice' function for '--format'"
    89	@$(if $(and $(shell which docker 2>/dev/null),\
    90	            $(call _prelude.go.VERSION.ge,$(patsubst go%,%,$(lastword $(shell go version $$(which docker)))),1.13)),\
    91	      ,\
    92	      printf '%s\n' $(call quote.shell,$(DOCKER_ERR)))
    93.PHONY: preflight
    94
    95preflight-cluster: $(tools/kubectl)
    96	@test -n "$(DEV_KUBECONFIG)" || (printf "$${KUBECONFIG_ERR}\n"; exit 1)
    97	@if [ "$(DEV_KUBECONFIG)" == '-skip-for-release-' ]; then \
    98		printf "$(CYN)==> $(RED)Skipping test cluster checks$(END)\n" ;\
    99	else \
   100		printf "$(CYN)==> $(GRN)Checking for test cluster$(END)\n" ;\
   101		success=; \
   102		for i in {1..5}; do \
   103			$(tools/kubectl) --kubeconfig $(DEV_KUBECONFIG) -n default get service kubernetes > /dev/null && success=true && break || sleep 15 ; \
   104		done; \
   105		if [ ! "$${success}" ] ; then { printf "$$KUBECTL_ERR\n" ; exit 1; } ; fi; \
   106	fi
   107.PHONY: preflight-cluster
   108
   109python/ambassador.version: $(tools/write-ifchanged) FORCE
   110	set -e -o pipefail; { \
   111	  echo $(patsubst v%,%,$(VERSION)); \
   112	  git rev-parse HEAD; \
   113	} | $(tools/write-ifchanged) $@
   114clean: python/ambassador.version.rm
   115
   116# Give Make a hint about which pattern rules to apply.  Honestly, I'm
   117# not sure why Make isn't figuring it out on its own, but it isn't.
   118_images = base-envoy $(LCNAME) kat-client kat-server
   119$(foreach i,$(_images), docker/$i.docker.tag.local  ): docker/%.docker.tag.local : docker/%.docker
   120$(foreach i,$(_images), docker/$i.docker.tag.remote ): docker/%.docker.tag.remote: docker/%.docker
   121
   122docker/.base-envoy.docker.stamp: FORCE
   123	@set -e; { \
   124	  if docker image inspect $(ENVOY_DOCKER_TAG) --format='{{ .Id }}' >$@ 2>/dev/null; then \
   125	    printf "${CYN}==> ${GRN}Base Envoy image is already pulled${END}\n"; \
   126	  else \
   127	    printf "${CYN}==> ${GRN}Pulling base Envoy image${END}\n"; \
   128	    TIMEFORMAT="     (docker pull took %1R seconds)"; \
   129	    time docker pull $(ENVOY_DOCKER_TAG); \
   130	    unset TIMEFORMAT; \
   131	  fi; \
   132	  echo $(ENVOY_DOCKER_TAG) >$@; \
   133	}
   134clobber: docker/base-envoy.docker.clean
   135
   136docker/.$(LCNAME).docker.stamp: %/.$(LCNAME).docker.stamp: %/base.docker.tag.local %/base-envoy.docker.tag.local %/base-pip.docker.tag.local python/ambassador.version $(BUILDER_HOME)/Dockerfile $(OSS_HOME)/build-aux/py-version.txt $(tools/dsum) vendor FORCE
   137	@printf "${CYN}==> ${GRN}Building image ${BLU}$(LCNAME)${END}\n"
   138	@printf "    ${BLU}base=$$(sed -n 2p $*/base.docker.tag.local)${END}\n"
   139	@printf "    ${BLU}envoy=$$(cat $*/base-envoy.docker)${END}\n"
   140	@printf "    ${BLU}builderbase=$$(sed -n 2p $*/base-pip.docker.tag.local)${END}\n"
   141	{ $(tools/dsum) '$(LCNAME) build' 3s \
   142	  docker build -f ${BUILDER_HOME}/Dockerfile . \
   143			--platform="$(BUILD_ARCH)" \
   144	    --build-arg=base="$$(sed -n 2p $*/base.docker.tag.local)" \
   145	    --build-arg=envoy="$$(cat $*/base-envoy.docker)" \
   146	    --build-arg=builderbase="$$(sed -n 2p $*/base-pip.docker.tag.local)" \
   147	    --build-arg=py_version="$$(cat build-aux/py-version.txt)" \
   148	    --iidfile=$@; }
   149clean: docker/$(LCNAME).docker.clean
   150
   151REPO=$(BUILDER_NAME)
   152
   153images: docker/$(LCNAME).docker.tag.local
   154images: docker/kat-client.docker.tag.local
   155images: docker/kat-server.docker.tag.local
   156.PHONY: images
   157
   158REGISTRY_ERR  = $(RED)
   159REGISTRY_ERR += $(NL)ERROR: please set the DEV_REGISTRY make/env variable to the docker registry
   160REGISTRY_ERR += $(NL)       you would like to use for development
   161REGISTRY_ERR += $(END)
   162
   163push: docker/$(LCNAME).docker.push.remote
   164push: docker/kat-client.docker.push.remote
   165push: docker/kat-server.docker.push.remote
   166.PHONY: push
   167
   168# `make push-dev` is meant to be run by CI.
   169push-dev: docker/$(LCNAME).docker.tag.local
   170	@[[ '$(VERSION)' == *-* ]] || (echo "$(RED)$@: VERSION=$(VERSION) is not a pre-release version$(END)" >&2; exit 1)
   171
   172	@printf '$(CYN)==> $(GRN)pushing $(BLU)%s$(GRN) as $(BLU)$(GRN)...$(END)\n' '$(LCNAME)' '$(DEV_REGISTRY)/$(LCNAME):$(patsubst v%,%,$(VERSION))'
   173	docker tag $$(cat docker/$(LCNAME).docker) '$(DEV_REGISTRY)/$(LCNAME):$(patsubst v%,%,$(VERSION))'
   174	docker push '$(DEV_REGISTRY)/$(LCNAME):$(patsubst v%,%,$(VERSION))'
   175.PHONY: push-dev
   176
   177export KUBECONFIG_ERR=$(RED)ERROR: please set the $(BLU)DEV_KUBECONFIG$(RED) make/env variable to the cluster\n       you would like to use for development. Note this cluster must have access\n       to $(BLU)DEV_REGISTRY$(RED) (currently $(BLD)$(DEV_REGISTRY)$(END)$(RED))$(END)
   178export KUBECTL_ERR=$(RED)ERROR: preflight kubectl check failed$(END)
   179
   180test-ready: push preflight-cluster
   181.PHONY: test-ready
   182
   183PYTEST_ARGS ?=
   184export PYTEST_ARGS
   185
   186pytest: push-pytest-images
   187pytest: $(tools/kubestatus)
   188pytest: $(tools/kubectl)
   189pytest: $(OSS_HOME)/venv
   190pytest: docker/base-envoy.docker.tag.local
   191pytest: proxy
   192	@printf "$(CYN)==> $(GRN)Running $(BLU)py$(GRN) tests$(END)\n"
   193	@echo "AMBASSADOR_DOCKER_IMAGE=$$AMBASSADOR_DOCKER_IMAGE"
   194	@echo "DEV_KUBECONFIG=$$DEV_KUBECONFIG"
   195	@echo "PYTEST_ARGS=$$PYTEST_ARGS"
   196	set -e; { \
   197	  . $(OSS_HOME)/venv/bin/activate; \
   198	  export SOURCE_ROOT=$(CURDIR); \
   199	  export ENVOY_DOCKER_TAG=$$(cat docker/base-envoy.docker); \
   200	  export KUBESTATUS_PATH=$(CURDIR)/tools/bin/kubestatus; \
   201	  pytest --tb=short -rP $(PYTEST_ARGS); \
   202	}
   203.PHONY: pytest
   204
   205pytest-unit: $(OSS_HOME)/venv
   206pytest-unit: docker/base-envoy.docker.tag.local
   207	@printf "$(CYN)==> $(GRN)Running $(BLU)py$(GRN) unit tests$(END)\n"
   208	set -e; { \
   209	  . $(OSS_HOME)/venv/bin/activate; \
   210	  export SOURCE_ROOT=$(CURDIR); \
   211	  export ENVOY_DOCKER_TAG=$$(cat docker/base-envoy.docker); \
   212	  pytest --tb=short -rP $(PYTEST_ARGS) python/tests/unit; \
   213	}
   214.PHONY: pytest-unit
   215
   216pytest-integration: push-pytest-images
   217	@printf "$(CYN)==> $(GRN)Running $(BLU)py$(GRN) integration tests$(END)\n"
   218	$(MAKE) pytest PYTEST_ARGS="$$PYTEST_ARGS python/tests/integration"
   219.PHONY: pytest-integration
   220
   221pytest-kat-envoy3: push-pytest-images # doing this all at once is too much for CI...
   222	$(MAKE) pytest PYTEST_ARGS="$$PYTEST_ARGS python/tests/kat"
   223# ... so we have a separate rule to run things split up
   224build-aux/.pytest-kat.txt.stamp: $(OSS_HOME)/venv push-pytest-images $(tools/kubectl) FORCE
   225	. venv/bin/activate && set -o pipefail && pytest --collect-only python/tests/kat 2>&1 | sed -En 's/.*<Function (.*)>/\1/p' | cut -d. -f1 | sort -u > $@
   226build-aux/pytest-kat.txt: build-aux/%: build-aux/.%.stamp $(tools/copy-ifchanged)
   227	$(tools/copy-ifchanged) $< $@
   228clean: build-aux/.pytest-kat.txt.stamp.rm build-aux/pytest-kat.txt.rm
   229pytest-kat-envoy3-%: build-aux/pytest-kat.txt $(tools/py-split-tests)
   230	$(MAKE) pytest PYTEST_ARGS="$$PYTEST_ARGS -k '$$($(tools/py-split-tests) $(subst -of-, ,$*) <build-aux/pytest-kat.txt)' python/tests/kat"
   231
   232$(OSS_HOME)/venv: python/requirements.txt python/requirements-dev.txt
   233	rm -rf $@
   234	python3 -m venv $@
   235	$@/bin/pip3 install -r python/requirements.txt
   236	$@/bin/pip3 install -r python/requirements-dev.txt
   237	$@/bin/pip3 install -e $(OSS_HOME)/python
   238clobber: venv.rm-r
   239
   240GOTEST_ARGS ?= -race -count=1 -timeout 30m
   241GOTEST_ARGS += -parallel=150 # The ./pkg/envoy-control-plane/cache/v{2,3}/ tests require high parallelism to reliably work
   242GOTEST_PKGS ?= ./...
   243gotest: $(OSS_HOME)/venv $(tools/kubectl)
   244	@printf "$(CYN)==> $(GRN)Running $(BLU)go$(GRN) tests$(END)\n"
   245	{ . $(OSS_HOME)/venv/bin/activate && \
   246	  export PATH=$(tools.bindir):$${PATH} && \
   247	  export EDGE_STACK=$(GOTEST_AES_ENABLED) && \
   248	  go test $(GOTEST_ARGS) $(GOTEST_PKGS); }
   249.PHONY: gotest
   250
   251# Ingress v1 conformance tests, using KIND and the Ingress Conformance Tests suite.
   252ingresstest: $(tools/kubectl) | docker/$(LCNAME).docker.push.remote
   253	@printf "$(CYN)==> $(GRN)Running $(BLU)Ingress v1$(GRN) tests$(END)\n"
   254	@[ -n "$(INGRESS_TEST_IMAGE)" ] || { printf "$(RED)ERROR: no INGRESS_TEST_IMAGE defined$(END)\n"; exit 1; }
   255	@[ -n "$(INGRESS_TEST_MANIF_DIR)" ] || { printf "$(RED)ERROR: no INGRESS_TEST_MANIF_DIR defined$(END)\n"; exit 1; }
   256	@[ -d "$(INGRESS_TEST_MANIF_DIR)" ] || { printf "$(RED)ERROR: $(INGRESS_TEST_MANIF_DIR) does not seem a valid directory$(END)\n"; exit 1; }
   257	@[ -n "$(HOST_IP)" ] || { printf "$(RED)ERROR: no IP obtained for host$(END)\n"; ip addr ; exit 1; }
   258
   259	@printf "$(CYN)==> $(GRN)Creating/recreating KIND cluster with image $(KIND_IMAGE)$(END)\n"
   260	@for i in {1..5} ; do \
   261		kind delete cluster 2>/dev/null || true ; \
   262		kind create cluster --image $(KIND_IMAGE) && break || sleep 10 ; \
   263	done
   264
   265	@printf "$(CYN)==> $(GRN)Saving KUBECONFIG at $(KIND_KUBECONFIG)$(END)\n"
   266	@kind get kubeconfig > $(KIND_KUBECONFIG)
   267	@sleep 10
   268
   269	@APISERVER_IP=`docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' kind-control-plane` ; \
   270		[ -n "$$APISERVER_IP" ] || { printf "$(RED)ERROR: no IP obtained for API server$(END)\n"; docker ps ; docker inspect kind-control-plane ; exit 1; } ; \
   271		printf "$(CYN)==> $(GRN)API server at $$APISERVER_IP. Fixing server in $(KIND_KUBECONFIG).$(END)\n" ; \
   272		sed -i -e "s|server: .*|server: https://$$APISERVER_IP:6443|g" $(KIND_KUBECONFIG)
   273
   274	@printf "$(CYN)==> $(GRN)Showing some cluster info:$(END)\n"
   275	@$(tools/kubectl) --kubeconfig=$(KIND_KUBECONFIG) cluster-info || { printf "$(RED)ERROR: kubernetes cluster not ready $(END)\n"; exit 1 ; }
   276	@$(tools/kubectl) --kubeconfig=$(KIND_KUBECONFIG) version || { printf "$(RED)ERROR: kubernetes cluster not ready $(END)\n"; exit 1 ; }
   277
   278	@printf "$(CYN)==> $(GRN)Loading Ambassador (from the Ingress conformance tests) with image=$$(sed -n 2p docker/$(LCNAME).docker.push.remote)$(END)\n"
   279	@for f in $(INGRESS_TEST_MANIFS) ; do \
   280		printf "$(CYN)==> $(GRN)... $$f $(END)\n" ; \
   281		cat $(INGRESS_TEST_MANIF_DIR)/$$f | sed -e "s|image:.*ambassador\:.*|image: $$(sed -n 2p docker/$(LCNAME).docker.push.remote)|g" | tee /dev/tty | $(tools/kubectl) apply -f - ; \
   282	done
   283
   284	@printf "$(CYN)==> $(GRN)Waiting for Ambassador to be ready$(END)\n"
   285	@$(tools/kubectl) --kubeconfig=$(KIND_KUBECONFIG) wait --for=condition=available --timeout=180s deployment/ambassador || { \
   286		printf "$(RED)ERROR: Ambassador was not ready after 3 mins $(END)\n"; \
   287		$(tools/kubectl) --kubeconfig=$(KIND_KUBECONFIG) get services --all-namespaces ; \
   288		exit 1 ; }
   289
   290	@printf "$(CYN)==> $(GRN)Exposing Ambassador service$(END)\n"
   291	@$(tools/kubectl) --kubeconfig=$(KIND_KUBECONFIG) expose deployment ambassador --type=LoadBalancer --name=ambassador
   292
   293	@printf "$(CYN)==> $(GRN)Starting the tests container (in the background)$(END)\n"
   294	@docker stop -t 3 ingress-tests 2>/dev/null || true && docker rm ingress-tests 2>/dev/null || true
   295	@docker run -d --rm --name ingress-tests -e KUBECONFIG=/opt/.kube/config --mount type=bind,source=$(KIND_KUBECONFIG),target=/opt/.kube/config \
   296		--entrypoint "/bin/sleep" $(INGRESS_TEST_IMAGE) 600
   297
   298	@printf "$(CYN)==> $(GRN)Loading the Ingress conformance tests manifests$(END)\n"
   299	@docker exec -ti ingress-tests \
   300		/opt/ingress-controller-conformance apply --api-version=networking.k8s.io/v1beta1 --ingress-controller=getambassador.io/ingress-controller --ingress-class=ambassador
   301	@sleep 10
   302
   303	@printf "$(CYN)==> $(GRN)Forwarding traffic to Ambassador service$(END)\n"
   304	@$(tools/kubectl) --kubeconfig=$(KIND_KUBECONFIG) port-forward --address=$(HOST_IP) svc/ambassador \
   305		$(INGRESS_TEST_LOCAL_PLAIN_PORT):8080 $(INGRESS_TEST_LOCAL_TLS_PORT):8443 $(INGRESS_TEST_LOCAL_ADMIN_PORT):8877 &
   306	@sleep 10
   307
   308	@for url in "http://$(HOST_IP):$(INGRESS_TEST_LOCAL_PLAIN_PORT)" "https://$(HOST_IP):$(INGRESS_TEST_LOCAL_TLS_PORT)" "http://$(HOST_IP):$(INGRESS_TEST_LOCAL_ADMIN_PORT)/ambassador/v0/check_ready" ; do \
   309		printf "$(CYN)==> $(GRN)Waiting until $$url is ready...$(END)\n" ; \
   310		until curl --silent -k "$$url" ; do printf "$(CYN)==> $(GRN)... still waiting.$(END)\n" ; sleep 2 ; done ; \
   311		printf "$(CYN)==> $(GRN)... $$url seems to be ready.$(END)\n" ; \
   312	done
   313	@sleep 30
   314
   315	@printf "$(CYN)==> $(GRN)Running the Ingress conformance tests against $(HOST_IP)$(END)\n"
   316	@docker exec -ti ingress-tests \
   317		/opt/ingress-controller-conformance verify \
   318			--api-version=networking.k8s.io/v1beta1 \
   319			--use-insecure-host=$(HOST_IP):$(INGRESS_TEST_LOCAL_PLAIN_PORT) \
   320			--use-secure-host=$(HOST_IP):$(INGRESS_TEST_LOCAL_TLS_PORT)
   321
   322	@printf "$(CYN)==> $(GRN)Cleaning up...$(END)\n"
   323	-@pkill $(tools/kubectl) -9
   324	@docker stop -t 3 ingress-tests 2>/dev/null || true && docker rm ingress-tests 2>/dev/null || true
   325
   326	@if [ -n "$(CLEANUP)" ] ; then \
   327		printf "$(CYN)==> $(GRN)We are done. Destroying the cluster now.$(END)\n"; kind delete cluster || true; \
   328	else \
   329		printf "$(CYN)==> $(GRN)We are done. You should destroy the cluster with 'kind delete cluster'.$(END)\n"; \
   330	fi
   331
   332test: ingresstest gotest pytest
   333.PHONY: test
   334
   335AMB_IMAGE_RC=$(RELEASE_REGISTRY)/$(REPO):$(patsubst v%,%,$(VERSION))
   336AMB_IMAGE_RELEASE=$(RELEASE_REGISTRY)/$(REPO):$(patsubst v%,%,$(VERSION))
   337
   338export RELEASE_REGISTRY_ERR=$(RED)ERROR: please set the RELEASE_REGISTRY make/env variable to the docker registry\n       you would like to use for release$(END)
   339
   340release/promote-oss/.main: $(tools/docker-promote)
   341	@[[ '$(PROMOTE_FROM_VERSION)' =~ ^v[0-9]+\.[0-9]+\.[0-9]+(-.*)?$$ ]] || (echo >&2 'Must set PROMOTE_FROM_VERSION to a vSEMVER value'; exit 1)
   342	@[[ '$(PROMOTE_TO_VERSION)'   =~ ^v[0-9]+\.[0-9]+\.[0-9]+(-.*)?$$ ]] || (echo >&2 'Must set PROMOTE_TO_VERSION to a vSEMVER value' ; exit 1)
   343	@[[ -n '$(PROMOTE_FROM_REPO)'                                     ]] || (echo >&2 'Must set PROMOTE_FROM_REPO' ; exit 1)
   344	@[[ -n '$(PROMOTE_TO_REPO)'                                       ]] || (echo >&2 'Must set PROMOTE_TO_REPO' ; exit 1)
   345	@case '$(PROMOTE_CHANNEL)' in \
   346	  ''|wip|early|test|hotfix) true;; \
   347	  *) echo >&2 'Unknown PROMOTE_CHANNEL $(PROMOTE_CHANNEL)'; exit 1;; \
   348	esac
   349
   350	@printf "$(CYN)==> $(GRN)Promoting $(BLU)%s$(GRN) to $(BLU)%s$(GRN) (channel='$(BLU)%s$(GRN)')$(END)\n" '$(PROMOTE_FROM_VERSION)' '$(PROMOTE_TO_VERSION)' '$(PROMOTE_CHANNEL)'
   351
   352	@printf '  pushing $(CYN)$(PROMOTE_TO_REPO):$(patsubst v%,%,$(PROMOTE_FROM_VERSION))$(END)...\n'
   353	$(tools/docker-promote) $(PROMOTE_FROM_REPO):$(patsubst v%,%,$(PROMOTE_FROM_VERSION)) $(PROMOTE_TO_REPO):$(patsubst v%,%,$(PROMOTE_TO_VERSION))
   354	docker push $(PROMOTE_TO_REPO):$(patsubst v%,%,$(PROMOTE_TO_VERSION))
   355
   356ifneq ($(IS_PRIVATE),)
   357	@echo '$@: not pushing to S3 because this is a private repo'
   358else
   359	@printf '  pushing $(CYN)https://s3.amazonaws.com/$(AWS_S3_BUCKET)/emissary-ingress/$(PROMOTE_CHANNEL)stable.txt$(END)...\n'
   360	printf '%s' "$(patsubst v%,%,$(PROMOTE_TO_VERSION))" | aws s3 cp - s3://$(AWS_S3_BUCKET)/emissary-ingress/$(PROMOTE_CHANNEL)stable.txt
   361
   362	@printf '  pushing $(CYN)s3://scout-datawire-io/emissary-ingress/$(PROMOTE_CHANNEL)app.json$(END)...\n'
   363	printf '{"application":"emissary","latest_version":"%s","notices":[]}' "$(patsubst v%,%,$(PROMOTE_TO_VERSION))" | aws s3 cp - s3://scout-datawire-io/emissary-ingress/$(PROMOTE_CHANNEL)app.json
   364
   365	{ $(MAKE) \
   366	  push-manifests \
   367	  publish-docs-yaml; }
   368endif
   369.PHONY: release/promote-oss/.main
   370
   371release/promote-oss/to-rc: $(tools/devversion)
   372	@test -n "$(RELEASE_REGISTRY)" || (printf "$${RELEASE_REGISTRY_ERR}\n"; exit 1)
   373	@[[ "$(VERSION)" =~ ^v[0-9]+\.[0-9]+\.[0-9]+(-rc\.[0-9]+|-dev)$$ ]] || (printf '$(RED)ERROR: VERSION=%s does not look like an RC or dev tag\n' "$(VERSION)"; exit 1)
   374	@set -e; { \
   375	  dev_version=$$($(tools/devversion)); \
   376	  printf "$(CYN)==> $(GRN)found version $(BLU)$$dev_version$(GRN).$(END)\n"; \
   377	  $(MAKE) release/promote-oss/.main \
   378	    PROMOTE_FROM_VERSION="$$dev_version" \
   379	    PROMOTE_TO_VERSION='$(VERSION)' \
   380	    PROMOTE_FROM_REPO='$(DEV_REGISTRY)/$(REPO)' \
   381	    PROMOTE_TO_REPO='$(RELEASE_REGISTRY)/$(REPO)' \
   382	    PROMOTE_CHANNEL='test'; \
   383	}
   384.PHONY: release/promote-oss/to-rc
   385
   386# To be run from a checkout at the tag you are promoting _from_.
   387# This is normally run from CI by creating the GA tag.
   388release/promote-oss/to-ga: $(tools/devversion)
   389	@test -n "$(RELEASE_REGISTRY)" || (printf "$${RELEASE_REGISTRY_ERR}\n"; exit 1)
   390	@[[ "$(VERSION)" =~ ^v[0-9]+\.[0-9]+\.[0-9]+(-ea)?$$ ]] || (printf '$(RED)ERROR: VERSION=%s does not look like a GA tag\n' "$(VERSION)"; exit 1)
   391	@set -e; { \
   392	  dev_version=$$($(tools/devversion)); \
   393	  printf "$(CYN)==> $(GRN)found version $(BLU)$$dev_version$(GRN).$(END)\n"; \
   394	  $(MAKE) release/promote-oss/.main \
   395	    PROMOTE_FROM_VERSION="$$dev_version" \
   396	    PROMOTE_TO_VERSION='$(VERSION)' \
   397	    PROMOTE_FROM_REPO='$(DEV_REGISTRY)/$(REPO)' \
   398	    PROMOTE_TO_REPO='$(RELEASE_REGISTRY)/$(REPO)' \
   399	    PROMOTE_CHANNEL=''; \
   400	}
   401.PHONY: release/promote-oss/to-ga
   402
   403# `make release/ga-check` is meant to be run by a human maintainer to
   404# check that CI did all the right things.
   405release/ga-check:
   406	{ $(OSS_HOME)/releng/release-ga-check \
   407	  --ga-version=$(patsubst v%,%,$(VERSION)) \
   408	  --chart-version=$(patsubst v%,%,$(CHART_VERSION)) \
   409	  --source-registry=$(RELEASE_REGISTRY) \
   410	  --image-name=$(LCNAME); }
   411
   412AMBASSADOR_DOCKER_IMAGE = $(shell sed -n 2p docker/$(LCNAME).docker.push.remote 2>/dev/null)
   413export AMBASSADOR_DOCKER_IMAGE
   414
   415_user-vars  = BUILDER_NAME
   416_user-vars += DEV_KUBECONFIG
   417_user-vars += DEV_REGISTRY
   418_user-vars += RELEASE_REGISTRY
   419_user-vars += AMBASSADOR_DOCKER_IMAGE
   420env:
   421	@printf '$(BLD)%s$(END)=$(BLU)%s$(END)\n' $(foreach v,$(_user-vars), $v $(call quote.shell,$(call quote.shell,$($v))) )
   422.PHONY: env
   423
   424export:
   425	@printf 'export %s=%s\n' $(foreach v,$(_user-vars), $v $(call quote.shell,$(call quote.shell,$($v))) )
   426.PHONY: export
   427
   428help:
   429	@printf '%s\n' $(call quote.shell,$(_help.intro))
   430.PHONY: help
   431
   432targets:
   433	@printf '%s\n' $(call quote.shell,$(HELP_TARGETS))
   434.PHONY: help
   435
   436define HELP_TARGETS
   437$(BLD)Targets:$(END)
   438
   439$(_help.targets)
   440
   441$(BLD)Codebases:$(END)
   442  $(foreach MODULE,$(MODULES),$(NL)  $(BLD)$(SOURCE_$(MODULE)) ==> $(BLU)$(MODULE)$(END))
   443
   444endef
   445
   446# Style note: _help.intro
   447# - is wrapped to 72 columns (after stripping the ANSI color codes)
   448# - has sentences separated with 2 spaces
   449# - uses bold blue ("$(BLU)") when introducing a new variable
   450# - uses bold ("$(BLD)") for variables that have already been introduced
   451# - uses bold ("$(BLD)") when you would use `backticks` in markdown
   452define _help.intro
   453This Makefile builds Ambassador using a standard build environment
   454inside a Docker container.  The $(BLD)$(REPO)$(END), $(BLD)kat-server$(END), and $(BLD)kat-client$(END)
   455images are created from this container after the build stage is
   456finished.
   457
   458The build works by maintaining a running build container in the
   459background.  It gets source code into that container via $(BLD)rsync$(END).  The
   460$(BLD)/home/dw$(END) directory in this container is a Docker volume, which allows
   461files (e.g. the Go build cache and $(BLD)pip$(END) downloads) to be cached across
   462builds.
   463
   464This arrangement also permits building multiple codebases.  This is
   465useful for producing builds with extended functionality.  Each external
   466codebase is synced into the container at the $(BLD)/buildroot/<name>$(END) path.
   467
   468You can control the name of the container and the images it builds by
   469setting $(BLU)$$BUILDER_NAME$(END), which defaults to $(BLD)$(LCNAME)$(END).  Note well that if
   470you want to make multiple clones of this repo and build in more than one
   471of them at the same time, you $(BLD)must$(END) set $(BLD)$$BUILDER_NAME$(END) so that each clone
   472has its own builder!  If you do not do this, your builds will collide
   473with confusing results.
   474
   475The build system doesn't try to magically handle all dependencies.  In
   476general, if you change something that is not pure source code, you will
   477likely need to do a $(BLD)$(MAKE) clean$(END) in order to see the effect.  For example,
   478Python code only gets set up once, so if you change $(BLD)setup.py$(END), then you
   479will need to do a clean build to see the effects.  Assuming you didn't
   480$(BLD)$(MAKE) clobber$(END), this shouldn't take long due to the cache in the Docker
   481volume.
   482
   483All targets that deploy to a cluster by way of $(BLU)$$DEV_REGISTRY$(END) can be made
   484to have the cluster use an imagePullSecret to pull from $(BLD)$$DEV_REGISTRY$(END),
   485by setting $(BLU)$$DEV_USE_IMAGEPULLSECRET$(END) to a non-empty value.  The
   486imagePullSecret will be constructed from $(BLD)$$DEV_REGISTRY$(END),
   487$(BLU)$$DOCKER_BUILD_USERNAME$(END), and $(BLU)$$DOCKER_BUILD_PASSWORD$(END).
   488
   489Use $(BLD)$(MAKE) $(BLU)targets$(END) for help about available $(BLD)make$(END) targets.
   490endef
   491
   492define _help.targets
   493  $(BLD)$(MAKE) $(BLU)help$(END)         -- displays the main help message.
   494
   495  $(BLD)$(MAKE) $(BLU)targets$(END)      -- displays this message.
   496
   497  $(BLD)$(MAKE) $(BLU)env$(END)          -- display the value of important env vars.
   498
   499  $(BLD)$(MAKE) $(BLU)export$(END)       -- display important env vars in shell syntax, for use with $(BLD)eval$(END).
   500
   501  $(BLD)$(MAKE) $(BLU)preflight$(END)    -- checks dependencies of this makefile.
   502
   503  $(BLD)$(MAKE) $(BLU)version$(END)      -- display source code version.
   504
   505  $(BLD)$(MAKE) $(BLU)images$(END)       -- creates images from the build container.
   506
   507  $(BLD)$(MAKE) $(BLU)push$(END)         -- pushes images to $(BLD)$$DEV_REGISTRY$(END). ($(DEV_REGISTRY))
   508
   509  $(BLD)$(MAKE) $(BLU)test$(END)         -- runs Go and Python tests inside the build container.
   510
   511    The tests require a Kubernetes cluster and a Docker registry in order to
   512    function. These must be supplied via the $(BLD)$(MAKE)$(END)/$(BLD)env$(END) variables $(BLD)$$DEV_KUBECONFIG$(END)
   513    and $(BLD)$$DEV_REGISTRY$(END).
   514
   515  $(BLD)$(MAKE) $(BLU)gotest$(END)       -- runs just the Go tests inside the build container.
   516
   517    Use $(BLD)$$GOTEST_PKGS$(END) to control which packages are passed to $(BLD)gotest$(END). ($(GOTEST_PKGS))
   518    Use $(BLD)$$GOTEST_ARGS$(END) to supply additional non-package arguments. ($(GOTEST_ARGS))
   519    Example: $(BLD)$(MAKE) gotest GOTEST_PKGS=./cmd/entrypoint GOTEST_ARGS=-v$(END)  # run entrypoint tests verbosely
   520
   521  $(BLD)$(MAKE) $(BLU)pytest$(END)       -- runs just the Python tests inside the build container.
   522
   523    Use $(BLD)$$PYTEST_ARGS$(END) to pass args to $(BLD)pytest$(END). ($(PYTEST_ARGS))
   524
   525    Example: $(BLD)$(MAKE) pytest PYTEST_ARGS="-k Lua"$(END)  # run only the Lua test, with a real Envoy
   526
   527  $(BLD)$(MAKE) $(BLU)release/promote-oss/to-ga$(END) -- promote a release candidate to general availability
   528
   529    The current commit must be tagged for this to work, and your tree must be clean.
   530    Additionally, the tag must be of the form 'vX.Y.Z'. You must also have previously
   531    built and promoted the RC that will become GA, using $(BLD)release/bits$(END).
   532
   533  $(BLD)$(MAKE) $(BLU)clean$(END)     -- kills the build container.
   534
   535  $(BLD)$(MAKE) $(BLU)clobber$(END)   -- kills the build container and the cache volume.
   536
   537  $(BLD)$(MAKE) $(BLU)generate$(END)  -- update generated files that get checked in to Git.
   538
   539    1. Use $(BLD)$$ENVOY_COMMIT$(END) to update the vendored gRPC protobuf files ('api/envoy').
   540    2. Run 'protoc' to generate things from the protobuf files (both those from
   541       Envoy, and those from 'api/kat').
   542    3. Use $(BLD)$$ENVOY_GO_CONTROL_PLANE_COMMIT$(END) to update the vendored+patched copy of
   543       envoyproxy/go-control-plane ('pkg/envoy-control-plane/').
   544    4. Use the Go CRD definitions in 'pkg/api/getambassador.io/' to generate YAML
   545       (and a few 'zz_generated.*.go' files).
   546
   547  $(BLD)$(MAKE) $(BLU)generate-fast$(END) -- like $(BLD)make generate$(END), but skips the slow Envoy stuff.
   548
   549  $(BLD)$(MAKE) $(BLU)go-mod-tidy$(END) -- 'go mod tidy', but plays nice with 'make generate'
   550
   551  $(BLD)$(MAKE) $(BLU)guess-envoy-go-control-plane-commit$(END) -- Make a suggestion for setting ENVOY_GO_CONTROL_PLANE_COMMIT= in generate.mk
   552
   553  $(BLD)$(MAKE) $(BLU)lint$(END)        -- runs golangci-lint.
   554
   555  $(BLD)$(MAKE) $(BLU)format$(END)      -- runs golangci-lint with --fix.
   556
   557endef

View as plain text