...
1# See https://just.systems/man/en
2
3lint: action-lint action-dev-check md-lint sh-lint rs-fetch rs-clippy rs-check-fmt go-lint
4
5##
6## Go
7##
8
9export GO111MODULE := "on"
10
11go-fetch:
12 go mod download
13
14go-fmt *flags:
15 bin/fmt {{ flags }}
16
17go-lint *flags:
18 golangci-lint run {{ flags }}
19
20go-test:
21 LINKERD_TEST_PRETTY_DIFF=1 gotestsum -- -race -v -mod=readonly ./...
22
23##
24## Rust
25##
26
27# By default we compile in development mode mode because it's faster.
28rs-build-type := if env_var_or_default("RELEASE", "") == "" { "debug" } else { "release" }
29
30# Overriddes the default Rust toolchain version.
31rs-toolchain := ""
32
33rs-features := 'all'
34
35_cargo := "cargo" + if rs-toolchain != "" { " +" + rs-toolchain } else { "" }
36
37# Fetch Rust dependencies.
38rs-fetch:
39 {{ _cargo }} fetch --locked
40
41# Format Rust code.
42rs-fmt:
43 {{ _cargo }} fmt --all
44
45# Check that the Rust code is formatted correctly.
46rs-check-fmt:
47 {{ _cargo }} fmt --all -- --check
48
49# Lint Rust code.
50rs-clippy:
51 {{ _cargo }} clippy --frozen --workspace --all-targets --no-deps {{ _features }} {{ _fmt }}
52
53alias clippy := rs-clippy
54
55# Audit Rust dependencies.
56rs-audit-deps:
57 {{ _cargo }} deny {{ _features }} check
58
59# Generate Rust documentation.
60rs-doc *flags:
61 {{ _cargo }} doc --frozen \
62 {{ if rs-build-type == "release" { "--release" } else { "" } }} \
63 {{ _features }} \
64 {{ flags }}
65
66rs-test-build:
67 {{ _cargo-test }} --no-run --frozen \
68 --workspace --exclude=linkerd-policy-test \
69 {{ _features }}
70
71# Run Rust unit tests
72rs-test *flags:
73 {{ _cargo-test }} --frozen \
74 --workspace --exclude=linkerd-policy-test \
75 {{ if rs-build-type == "release" { "--release" } else { "" } }} \
76 {{ _features }} \
77 {{ flags }}
78
79# Check each crate independently to ensure its Cargo.toml is sufficient.
80rs-check-dirs:
81 #!/usr/bin/env bash
82 set -euo pipefail
83 while IFS= read -r toml ; do
84 {{ just_executable() }} \
85 rs-build-type='{{ rs-build-type }}' \
86 rs-features='{{ rs-features }}' \
87 rs-toolchain='{{ rs-toolchain }}' \
88 _rs-check-dir "${toml%/*}"
89 {{ just_executable() }} \
90 rs-build-type='{{ rs-build-type }}' \
91 rs-features='{{ rs-features }}' \
92 rs-toolchain='{{ rs-toolchain }}' \
93 _rs-check-dir "${toml%/*}" --tests
94 done < <(find . -mindepth 2 -name Cargo.toml | sort -r)
95
96_rs-check-dir dir *flags:
97 cd {{ dir }} \
98 && {{ _cargo }} check --frozen \
99 {{ if rs-build-type == "release" { "--release" } else { "" } }} \
100 {{ _features }} \
101 {{ flags }} \
102 {{ _fmt }}
103
104# If we're running in github actions and cargo-action-fmt is installed, then add
105# a command suffix that formats errors.
106_fmt := if env_var_or_default("GITHUB_ACTIONS", "") != "true" { "" } else {
107 ```
108 if command -v cargo-action-fmt >/dev/null 2>&1; then
109 echo "--message-format=json | cargo-action-fmt"
110 fi
111 ```
112}
113
114# Configures which features to enable when invoking cargo commands.
115_features := if rs-features == "all" {
116 "--all-features"
117 } else if rs-features != "" {
118 "--no-default-features --features=" + rs-features
119 } else { "" }
120
121# Use cargo-nextest if it is available. It may not be available when running
122# outside of the devcontainer.
123_cargo-test := _cargo + ```
124 if command -v cargo-nextest >/dev/null 2>&1 ; then
125 echo " nextest run"
126 else
127 echo " test"
128 fi
129 ```
130
131##
132## Policy integration tests
133##
134
135export POLICY_TEST_CONTEXT := env_var_or_default("POLICY_TEST_CONTEXT", "k3d-" + k3d-name)
136
137# Install linkerd in the test cluster and run the policy tests.
138policy-test: linkerd-install policy-test-deps-load policy-test-run && policy-test-cleanup linkerd-uninstall
139
140# Run the policy tests without installing linkerd.
141policy-test-run *flags:
142 cd policy-test && {{ _cargo-test }} {{ flags }}
143
144# Build the policy tests without running them.
145policy-test-build:
146 cd policy-test && {{ _cargo-test }} --no-run
147
148# Delete all test namespaces and remove linkerd from the cluster.
149policy-test-cleanup:
150 {{ _kubectl }} delete ns --selector='linkerd-policy-test'
151 @while [ $({{ _kubectl }} get ns --selector='linkerd-policy-test' -o json |jq '.items | length') != "0" ]; do sleep 1 ; done
152
153policy-test-deps-pull:
154 docker pull -q docker.io/bitnami/kubectl:latest
155 docker pull -q docker.io/curlimages/curl:latest
156 docker pull -q ghcr.io/olix0r/hokay:latest
157
158# Load all images into the test cluster.
159policy-test-deps-load: _k3d-init policy-test-deps-pull
160 for i in {1..3} ; do {{ _k3d-load }} \
161 bitnami/kubectl:latest \
162 curlimages/curl:latest \
163 ghcr.io/olix0r/hokay:latest && exit ; sleep 1 ; done
164
165##
166## Test cluster
167##
168
169# The name of the k3d cluster to use.
170k3d-name := "l5d-test"
171
172# The name of the docker network to use (i.e., for multicluster testing).
173k3d-network := "k3d-name"
174
175# The kubernetes version to use for the test cluster. e.g. 'v1.24', 'latest', etc
176k3d-k8s := "latest"
177
178k3d-agents := "0"
179k3d-servers := "1"
180
181_k3d-flags := "--no-lb --k3s-arg --disable='local-storage,traefik,servicelb,metrics-server@server:*'"
182
183_context := "--context=k3d-" + k3d-name
184_kubectl := "kubectl " + _context
185
186_k3d-load := "k3d image import --mode=direct --cluster=" + k3d-name
187
188# Run kubectl with the test cluster context.
189k *flags:
190 {{ _kubectl }} {{ flags }}
191
192# Creates a k3d cluster that can be used for testing.
193k3d-create: && _k3d-ready
194 k3d cluster create {{ k3d-name }} \
195 --image='+{{ k3d-k8s }}' \
196 --agents='{{ k3d-agents }}' \
197 --servers='{{ k3d-servers }}' \
198 --network='{{ k3d-network }}' \
199 {{ _k3d-flags }} \
200 --kubeconfig-update-default \
201 --kubeconfig-switch-context=false
202
203# Deletes the test cluster.
204k3d-delete:
205 k3d cluster delete {{ k3d-name }}
206
207# Print information the test cluster's detailed status.
208k3d-info:
209 k3d cluster list {{ k3d-name }} -o json | jq .
210
211# Set the default kubectl context to the test cluster.
212k3d-use:
213 k3d kubeconfig merge {{ k3d-name }} \
214 --kubeconfig-merge-default \
215 --kubeconfig-switch-context=true \
216 >/dev/null
217
218# Ensures the test cluster has been initialized.
219_k3d-init: && _k3d-ready
220 #!/usr/bin/env bash
221 set -euo pipefail
222 if ! k3d cluster list {{ k3d-name }} >/dev/null 2>/dev/null; then
223 {{ just_executable() }} \
224 k3d-k8s='{{ k3d-k8s }}' \
225 k3d-name='{{ k3d-name }}' \
226 k3d-network='{{ k3d-network }}' \
227 _k3d-flags='{{ _k3d-flags }}' \
228 k3d-create
229 fi
230 k3d kubeconfig merge {{ k3d-name }} \
231 --kubeconfig-merge-default \
232 --kubeconfig-switch-context=false \
233 >/dev/null
234
235_k3d-ready: _k3d-api-ready _k3d-dns-ready
236
237# Wait for the cluster's API server to be accessible
238_k3d-api-ready:
239 #!/usr/bin/env bash
240 set -euo pipefail
241 for i in {1..6} ; do
242 if {{ _kubectl }} cluster-info >/dev/null ; then exit 0 ; fi
243 sleep 10
244 done
245 exit 1
246
247# Wait for the cluster's DNS pods to be ready.
248_k3d-dns-ready:
249 while [ $({{ _kubectl }} get po -n kube-system -l k8s-app=kube-dns -o json |jq '.items | length') = "0" ]; do sleep 1 ; done
250 {{ _kubectl }} wait pod --for=condition=ready \
251 --namespace=kube-system --selector=k8s-app=kube-dns \
252 --timeout=1m
253
254##
255## Docker images
256##
257
258# If DOCKER_REGISTRY is not already set, use a bogus registry with a unique
259# name so that it's virtually impossible to accidentally use an incorrect image.
260export DOCKER_REGISTRY := env_var_or_default("DOCKER_REGISTRY", "test.l5d.io/" + _test-id )
261_test-id := `tr -dc 'a-z0-9' </dev/urandom | fold -w 5 | head -n 1`
262
263# The docker image tag.
264linkerd-tag := `bin/root-tag`
265
266docker-arch := ''
267
268_pause-load: _k3d-init
269 #!/usr/bin/env bash
270 set -euo pipefail
271 img="$(yq .gateway.pauseImage multicluster/charts/linkerd-multicluster/values.yaml)"
272 if [ -z "$(docker image ls -q "$img")" ]; then
273 docker pull -q "$img"
274 fi
275 k3d image import --mode=direct --cluster='{{ k3d-name }}' "$img"
276
277##
278## Linkerd CLI
279##
280
281# The Linkerd CLI binary.
282linkerd-exec := "bin/linkerd"
283_linkerd := linkerd-exec + " " + _context
284
285controller-image := DOCKER_REGISTRY + "/controller"
286proxy-image := DOCKER_REGISTRY + "/proxy"
287policy-controller-image := DOCKER_REGISTRY + "/policy-controller"
288
289# External dependencies
290#
291# We execute these commands lazily in case `yq` isn't present (so that other
292# just recipes can succeed).
293_proxy-init-image-cmd := "yq '.proxyInit.image | \"ghcr.io/linkerd/proxy-init:\" + .version' charts/linkerd-control-plane/values.yaml"
294_cni-plugin-image-cmd := "yq '.image | \"ghcr.io/linkerd/cni-plugin:\" + .version' charts/linkerd2-cni/values.yaml"
295_prometheus-image-cmd := "yq '.prometheus.image | .registry + \"/\" + .name + \":\" + .tag' viz/charts/linkerd-viz/values.yaml"
296
297linkerd *flags:
298 {{ _linkerd }} {{ flags }}
299
300# Install crds on the test cluster.
301linkerd-crds-install: _k3d-init
302 {{ _linkerd }} install --crds \
303 | {{ _kubectl }} apply -f -
304 {{ _kubectl }} wait crd --for condition=established \
305 --selector='linkerd.io/control-plane-ns' \
306 --timeout=1m
307
308# Install linkerd on the test cluster using test images.
309linkerd-install *args='': linkerd-load linkerd-crds-install && _linkerd-ready
310 {{ _linkerd }} install \
311 --set='imagePullPolicy=Never' \
312 --set='controllerImage={{ controller-image }}' \
313 --set='linkerdVersion={{ linkerd-tag }}' \
314 --set='policyController.image.name={{ policy-controller-image }}' \
315 --set='policyController.image.version={{ linkerd-tag }}' \
316 --set='policyController.loglevel=info\,linkerd=trace\,kubert=trace' \
317 --set='proxy.image.name={{ proxy-image }}' \
318 --set='proxy.image.version={{ linkerd-tag }}' \
319 --set='proxyInit.image.name=ghcr.io/linkerd/proxy-init' \
320 {{ args }} \
321 | {{ _kubectl }} apply -f -
322
323# Wait for all test namespaces to be removed before uninstalling linkerd from the cluster.
324linkerd-uninstall:
325 {{ _linkerd }} uninstall \
326 | {{ _kubectl }} delete -f -
327
328linkerd-load: _linkerd-images _k3d-init
329 for i in {1..3} ; do {{ _k3d-load }} \
330 '{{ controller-image }}:{{ linkerd-tag }}' \
331 '{{ policy-controller-image }}:{{ linkerd-tag }}' \
332 '{{ proxy-image }}:{{ linkerd-tag }}' \
333 $({{ _proxy-init-image-cmd }}) && exit ; sleep 1 ; done
334
335linkerd-load-cni:
336 docker pull -q $({{ _cni-plugin-image-cmd }})
337 {{ _k3d-load }} $({{ _cni-plugin-image-cmd }})
338
339linkerd-build: _policy-controller-build
340 TAG={{ linkerd-tag }} bin/docker-build-controller
341 TAG={{ linkerd-tag }} bin/docker-build-proxy
342
343_linkerd-images:
344 #!/usr/bin/env bash
345 set -xeuo pipefail
346 docker pull -q $({{ _proxy-init-image-cmd }})
347 for img in \
348 '{{ controller-image }}:{{ linkerd-tag }}' \
349 '{{ policy-controller-image }}:{{ linkerd-tag }}' \
350 '{{ proxy-image }}:{{ linkerd-tag }}'
351 do
352 if [ -z $(docker image ls -q "$img") ]; then
353 # Build images if any one of the images is missing.
354 exec {{ just_executable() }} \
355 controller-image='{{ controller-image }}' \
356 policy-controller-image='{{ policy-controller-image }}' \
357 linkerd-tag='{{ linkerd-tag }}' \
358 linkerd-build
359 fi
360 done
361
362# Build the policy controller docker image for testing (on amd64).
363_policy-controller-build:
364 docker buildx build . \
365 --file='policy-controller/Dockerfile' \
366 --platform={{ if docker-arch == '' { "amd64" } else { docker-arch} }} \
367 --build-arg='build_type={{ rs-build-type }}' \
368 --tag='{{ policy-controller-image }}:{{ linkerd-tag }}' \
369 --progress=plain \
370 --load
371
372_linkerd-ready:
373 if ! {{ _kubectl }} wait pod --for=condition=ready \
374 --namespace=linkerd --selector='linkerd.io/control-plane-component' \
375 --timeout=1m ; then \
376 {{ _kubectl }} describe pods --namespace=linkerd ; \
377 fi
378
379# Ensure that a linkerd control plane is installed
380_linkerd-init: && _linkerd-ready
381 #!/usr/bin/env bash
382 set -euo pipefail
383 if ! {{ _kubectl }} get ns linkerd >/dev/null 2>&1 ; then
384 {{ just_executable() }} \
385 k3d-name='{{ k3d-name }}' \
386 k3d-k8s='{{ k3d-k8s }}' \
387 k3d-agents='{{ k3d-agents }}' \
388 k3d-servers='{{ k3d-servers }}' \
389 k3d-network='{{ k3d-network }}' \
390 _k3d-flags='{{ _k3d-flags }}' \
391 linkerd-tag='{{ linkerd-tag }}' \
392 controller-image='{{ controller-image }}' \
393 proxy-image='{{ proxy-image }}' \
394 linkerd-exec='{{ linkerd-exec }}' \
395 linkerd-install
396 fi
397
398##
399## linkerd viz
400##
401
402linkerd-viz *flags: _k3d-init
403 {{ _linkerd }} viz {{ flags }}
404
405linkerd-viz-install: _linkerd-init linkerd-viz-load && _linkerd-viz-ready
406 {{ _linkerd }} viz install \
407 --set='defaultRegistry={{ DOCKER_REGISTRY }}' \
408 --set='linkerdVersion={{ linkerd-tag }}' \
409 --set='defaultImagePullPolicy=Never' \
410 | {{ _kubectl }} apply -f -
411
412# Wait for all test namespaces to be removed before uninstalling linkerd from the cluster.
413linkerd-viz-uninstall:
414 {{ _linkerd }} viz uninstall \
415 | {{ _kubectl }} delete -f -
416
417_linkerd-viz-images:
418 #!/usr/bin/env bash
419 set -euo pipefail
420 docker pull -q $({{ _prometheus-image-cmd }})
421 for img in \
422 '{{ DOCKER_REGISTRY }}/metrics-api:{{ linkerd-tag }}' \
423 '{{ DOCKER_REGISTRY }}/tap:{{ linkerd-tag }}' \
424 '{{ DOCKER_REGISTRY }}/web:{{ linkerd-tag }}'
425 do
426 if [ -z $(docker image ls -q "$img") ]; then
427 echo "Missing image: $img" >&2
428 exec {{ just_executable() }} \
429 linkerd-tag='{{ linkerd-tag }}' \
430 linkerd-viz-build
431 fi
432 done
433
434linkerd-viz-load: _linkerd-viz-images _k3d-init
435 for i in {1..3} ; do {{ _k3d-load }} \
436 {{ DOCKER_REGISTRY }}/metrics-api:{{ linkerd-tag }} \
437 {{ DOCKER_REGISTRY }}/tap:{{ linkerd-tag }} \
438 {{ DOCKER_REGISTRY }}/web:{{ linkerd-tag }} \
439 $({{ _prometheus-image-cmd }}) && exit ; sleep 1 ; done
440
441linkerd-viz-build:
442 TAG={{ linkerd-tag }} bin/docker-build-metrics-api
443 TAG={{ linkerd-tag }} bin/docker-build-tap
444 TAG={{ linkerd-tag }} bin/docker-build-web
445
446_linkerd-viz-ready:
447 {{ _kubectl }} wait pod --for=condition=ready \
448 --namespace=linkerd-viz --selector='linkerd.io/extension=viz' \
449 --timeout=1m
450
451# Ensure that a linkerd control plane is installed
452_linkerd-viz-uninit:
453 #!/usr/bin/env bash
454 set -euo pipefail
455 if {{ _kubectl }} get ns linkerd-viz >/dev/null 2>&1 ; then
456 {{ just_executable() }} \
457 k3d-name='{{ k3d-name }}' \
458 linkerd-exec='{{ linkerd-exec }}' \
459 linkerd-viz-uninstall
460 fi
461
462# TODO linkerd-jaeger-install
463
464##
465## linkerd multicluster
466##
467
468_mc-target-k3d-flags := "--k3s-arg --disable='local-storage,metrics-server@server:*' --k3s-arg '--cluster-cidr=10.23.0.0/24@server:*'"
469
470linkerd-mc-install: _linkerd-init
471 {{ _linkerd }} mc install --set='linkerdVersion={{ linkerd-tag }}' \
472 | {{ _kubectl }} apply -f -
473
474# Wait for all test namespaces to be removed before uninstalling linkerd-multicluster.
475linkerd-mc-uninstall:
476 {{ _linkerd }} mc uninstall \
477 | {{ _kubectl }} delete -f -
478
479mc-target-k3d-delete:
480 #!/usr/bin/env bash
481 set -euo pipefail
482 if k3d cluster list '{{ k3d-name }}-target' >/dev/null 2>/dev/null; then
483 {{ just_executable() }} \
484 k3d-name='{{ k3d-name }}-target' \
485 k3d-delete
486 fi
487
488_mc-load: _k3d-init linkerd-load
489
490_mc-target-load:
491 @{{ just_executable() }} \
492 k3d-name='{{ k3d-name }}-target' \
493 k3d-k8s='{{ k3d-k8s }}' \
494 k3d-agents='{{ k3d-agents }}' \
495 k3d-servers='{{ k3d-servers }}' \
496 k3d-network='{{ k3d-network }}' \
497 _k3d-flags='{{ _mc-target-k3d-flags }}' \
498 controller-image='{{ controller-image }}' \
499 proxy-image='{{ proxy-image }}' \
500 linkerd-exec='{{ linkerd-exec }}' \
501 linkerd-tag='{{ linkerd-tag }}' \
502 _pause-load \
503 _mc-load
504
505# Run the multicluster tests with cluster setup
506mc-test: mc-test-load mc-test-run
507
508mc-test-build:
509 go build --mod=readonly \
510 ./test/integration/multicluster/...
511
512mc-test-load: _mc-load _mc-target-load mc-flat-network-init
513
514k3d-source-server := "k3d-" + k3d-name + "-server-0"
515k3d-target-server := "k3d-" + k3d-name + "-target-server-0"
516
517_mc-route-output-fmt := "-o jsonpath='ip route add {.spec.podCIDR} via {.status.addresses[?(.type==\"InternalIP\")].address}'"
518_mc-print-source-route := _kubectl + " " + "get node " + k3d-source-server + " " + _mc-route-output-fmt
519_mc-print-target-route := "kubectl --context=k3d-" + k3d-name + "-target "+ "get node " + k3d-target-server + " " + _mc-route-output-fmt
520
521# Allow two k3d server nodes to participate in a flat network
522mc-flat-network-init:
523 @docker exec k3d-{{k3d-name}}-server-0 `{{_mc-print-target-route}}`
524 @docker exec k3d-{{k3d-name}}-target-server-0 `{{_mc-print-source-route}}`
525
526
527# Run the multicluster tests without any setup
528mc-test-run:
529 LINKERD_DOCKER_REGISTRY='{{ DOCKER_REGISTRY }}' \
530 go test -v -test.timeout=15m --failfast --mod=readonly \
531 ./test/integration/multicluster/... \
532 -integration-tests \
533 -linkerd='{{ justfile_directory() }}/bin/linkerd' \
534 -multicluster-source-context='k3d-{{ k3d-name }}' \
535 -multicluster-target-context='k3d-{{ k3d-name }}-target'
536
537##
538## GitHub Actions
539##
540
541# Format actionlint output for Github Actions if running in CI.
542_actionlint-fmt := if env_var_or_default("GITHUB_ACTIONS", "") != "true" { "" } else {
543 '{{range $err := .}}::error file={{$err.Filepath}},line={{$err.Line}},col={{$err.Column}}::{{$err.Message}}%0A```%0A{{replace $err.Snippet "\\n" "%0A"}}%0A```\n{{end}}'
544}
545
546# Lints all GitHub Actions workflows
547action-lint:
548 actionlint {{ if _actionlint-fmt != '' { "-format '" + _actionlint-fmt + "'" } else { "" } }} .github/workflows/*
549
550# Ensure all devcontainer versions are in sync
551action-dev-check:
552 just-dev check-action-images
553
554##
555## Other tools...
556##
557
558md-lint:
559 markdownlint-cli2 '**/*.md' '!**/node_modules' '!target'
560
561sh-lint:
562 bin/shellcheck-all
563
564##
565## Git
566##
567
568# Display the git history minus Dependabot updates
569history *paths='.':
570 @git log --oneline --graph --invert-grep --author="dependabot" -- {{ paths }}
571
572# Display the history of Dependabot changes
573history-dependabot *paths='.':
574 @git log --oneline --graph --author="dependabot" -- {{ paths }}
575
576# vim: set ft=make :
View as plain text