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