-
Notifications
You must be signed in to change notification settings - Fork 0
/
Makefile
782 lines (658 loc) · 30 KB
/
Makefile
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
.PHONY: help
help:
@echo "Usage: \n"
@sed -n 's/^## //p' ${MAKEFILE_LIST} | sort | column -t -s ':' | sed -e 's/^/ /'
# Export this first, incase we want to change it in the included makefiles.
export CGO_ENABLED=0
include scripts/dqlite/Makefile
#
# Makefile for juju-core.
#
PROJECT_DIR := $(shell dirname $(realpath $(firstword $(MAKEFILE_LIST))))
PROJECT := github.com/juju/juju
GOOS=$(shell go env GOOS)
GOARCH=$(shell go env GOARCH)
GOHOSTOS=$(shell go env GOHOSTOS)
GOHOSTARCH=$(shell go env GOHOSTARCH)
GO_MOD_VERSION=$(shell grep "^go" go.mod | awk '{print $$2}')
GO_INSTALLED_VERSION=$(shell go version | awk '{print $$3}' | sed -e /.*go/s///)
GO_INSTALL_PATH=$(if $(value GOBIN),$(value GOBIN),$(shell go env GOPATH)/bin)
# Build number passed in must be a monotonic int representing
# the build.
JUJU_BUILD_NUMBER ?=
# JUJU_VERSION is the JUJU version currently being represented in this
# repository.
JUJU_VERSION=$(shell go run -ldflags "-X $(PROJECT)/version.build=$(JUJU_BUILD_NUMBER)" scripts/version/main.go)
# BUILD_DIR is the directory relative to this project where we place build
# artifacts created by this Makefile.
BUILD_DIR ?= $(PROJECT_DIR)/_build
BIN_DIR ?= ${BUILD_DIR}/${GOOS}_${GOARCH}/bin
# JUJU_METADATA_SOURCE is the directory where we place simple streams archives
# for built juju binaries.
JUJU_METADATA_SOURCE ?= ${BUILD_DIR}/simplestreams
# JUJU_PUBLISH_STREAM defines the simplestreams stream that we will publish
# agents to (default "released").
JUJU_PUBLISH_STREAM ?= "released"
# TEST_PACKAGE_LIST is the path to a file that is a newline delimited list of
# packages to test. This file must be sorted.
TEST_PACKAGE_LIST ?=
# bin_platform_path calculates the bin directory path for build artifacts for
# the list of Go style platforms passed to this macro. For example
# linux/amd64 linux/arm64
bin_platform_paths = $(addprefix ${BUILD_DIR}/, $(addsuffix /bin, $(subst /,_,${1})))
# tool_platform_paths takes a juju binary to be built and the platform that it
# is to be built for and returns a list of paths for that binary to be output.
tool_platform_paths = $(addsuffix /${1},$(call bin_platform_paths,${2}))
# simplestream_paths takes a list of Go style platforms to calculate the
# paths to their respective simplestreams agent binary archives.
simplestream_paths = $(addprefix ${JUJU_METADATA_SOURCE}/, $(addprefix tools/${JUJU_PUBLISH_STREAM}/juju-${JUJU_VERSION}-, $(addsuffix .tgz,$(subst /,-,${1}))))
# CLIENT_PACKAGE_PLATFORMS defines a white space seperated list of platforms
# to build the Juju client binaries for. Platforms are defined as GO style
# OS_ARCH.
CLIENT_PACKAGE_PLATFORMS ?= $(GOOS)/$(GOARCH)
# AGENT_PACKAGE_PLATFORMS defines a white space seperated list of platforms
# to build the Juju agent binaries for. Platforms are defined as GO style
# OS_ARCH.
AGENT_PACKAGE_PLATFORMS ?= $(GOOS)/$(GOARCH)
# OCI_IMAGE_PLATFORMS defines a white space seperated list of platforms
# to build the Juju OCI images for. Platforms are defined as GO style
# OS_ARCH.
OCI_IMAGE_PLATFORMS ?= linux/$(GOARCH)
# Build tags passed to go install/build.
# Passing no-dqlite will disable building with dqlite.
# Example: BUILD_TAGS="minimal provider_kubernetes"
BUILD_TAGS ?=
# EXTRA_BUILD_TAGS is not passed in, but built up from context.
EXTRA_BUILD_TAGS =
ifeq (,$(findstring no-dqlite,$(BUILD_TAGS)))
EXTRA_BUILD_TAGS += libsqlite3
EXTRA_BUILD_TAGS += dqlite
endif
# TEST_BUILD_TAGS is the final list of build tags for tests only.
TEST_BUILD_TAGS=$(shell echo "$(BUILD_TAGS) $(EXTRA_BUILD_TAGS)" | awk '{$$1=$$1};1' | tr ' ' ',')
# FINAL_BUILD_TAGS is the final list of build tags.
FINAL_BUILD_TAGS=$(shell echo "$(BUILD_TAGS) $(EXTRA_BUILD_TAGS) notest" | awk '{$$1=$$1};1' | tr ' ' ',')
# GIT_COMMIT the current git commit of this repository
GIT_COMMIT ?= $(shell git -C $(PROJECT_DIR) rev-parse HEAD 2>/dev/null)
# Build flag passed to go -mod defaults to readonly to support go workspaces.
# CI should set this to vendor
JUJU_GOMOD_MODE ?= readonly
# If .git directory is missing, we are building out of an archive, otherwise report
# if the tree that is checked out is dirty (modified) or clean.
GIT_TREE_STATE = $(if $(shell git -C $(PROJECT_DIR) rev-parse --is-inside-work-tree 2>/dev/null | grep -e 'true'),$(if $(shell git -C $(PROJECT_DIR) status --porcelain),dirty,clean),archive)
# BUILD_AGENT_TARGETS is a list of make targets that get built, that fall under
# the category of Juju agents, that are not CGO. These targets are also the ones
# we are more then likely wanting to cross compile.
# NOTES:
# - We filter pebble here for only linux builds as that is only what it will
# compile for at the moment.
define BUILD_AGENT_TARGETS
$(call tool_platform_paths,jujuc,$(filter-out windows%,${AGENT_PACKAGE_PLATFORMS})) \
$(call tool_platform_paths,jujud,$(filter linux%,${AGENT_PACKAGE_PLATFORMS})) \
$(call tool_platform_paths,containeragent,$(filter-out windows%,${AGENT_PACKAGE_PLATFORMS})) \
$(call tool_platform_paths,pebble,$(filter linux%,${AGENT_PACKAGE_PLATFORMS}))
endef
# BUILD_CGO_AGENT_TARGETS is a list of make targets that get built, that fall
# under the category of Juju agents, that are CGO. These targets are also the
# ones we are more then likely wanting to cross compile.
define BUILD_CGO_AGENT_TARGETS
$(call tool_platform_paths,jujud-controller,$(filter linux%,${AGENT_PACKAGE_PLATFORMS}))
endef
define BUILD_CGO_BENCH_TARGETS
$(call tool_platform_paths,dqlite-bench,$(filter linux%,${AGENT_PACKAGE_PLATFORMS}))
endef
# BUILD_CLIENT_TARGETS is a list of make targets that get built that fall under
# the category of Juju clients. These targets are also less likely to be cross
# compiled
define BUILD_CLIENT_TARGETS
$(call tool_platform_paths,juju,${CLIENT_PACKAGE_PLATFORMS}) \
$(call tool_platform_paths,juju-metadata,${CLIENT_PACKAGE_PLATFORMS})
endef
# SIMPLESTREAMS_TARGETS is a list of make targets that get built when a
# user asks for simplestreams to be built. Because simplestreams are mainly
# mainly concerned with that of packaging juju agent binaries we work off of
# the Go style platforms.
define SIMPLESTREAMS_TARGETS
$(call simplestream_paths,${AGENT_PACKAGE_PLATFORMS})
endef
# INSTALL_TARGETS is a list of make targets that get installed when make
# install is run.
define INSTALL_TARGETS
juju \
jujuc \
jujud \
containeragent \
juju-metadata
endef
# Windows doesn't support the agent binaries
ifeq ($(GOOS), windows)
INSTALL_TARGETS = juju \
juju-metadata
endif
# We only add pebble to the list of install targets if we are building for linux
ifeq ($(GOOS), linux)
INSTALL_TARGETS += jujud-controller
INSTALL_TARGETS += pebble
endif
# Allow the tests to take longer on restricted platforms.
ifeq ($(shell echo "${GOARCH}" | sed -E 's/.*(arm|arm64|ppc64le|ppc64|s390x).*/golang/'), golang)
TEST_TIMEOUT ?= 5400s
else
TEST_TIMEOUT ?= 2700s
endif
TEST_TIMEOUT := $(TEST_TIMEOUT)
TEST_ARGS ?=
# Limit concurrency on s390x.
ifeq ($(shell echo "${GOARCH}" | sed -E 's/.*(s390x).*/golang/'), golang)
TEST_ARGS += -p 4
endif
# Enable coverage testing.
ifeq ($(COVERAGE_CHECK), 1)
TEST_ARGS += -coverprofile=coverage.txt -covermode=atomic
endif
ifeq ($(FUZZ_CHECK), 1)
TEST_ARGS += -fuzzminimizetime=30s
else
TEST_ARGS += -fuzzminimizetime=0
endif
# Enable verbose testing for reporting.
ifeq ($(VERBOSE_CHECK), 1)
CHECK_ARGS = -v
endif
define link_flags_version
-X $(PROJECT)/core/version.GitCommit=$(GIT_COMMIT) \
-X $(PROJECT)/core/version.GitTreeState=$(GIT_TREE_STATE) \
-X $(PROJECT)/core/version.build=$(JUJU_BUILD_NUMBER) \
-X $(PROJECT)/core/version.GoBuildTags=$(FINAL_BUILD_TAGS)
endef
# Compile with debug flags if requested.
ifeq ($(DEBUG_JUJU), 1)
COMPILE_FLAGS = -gcflags "all=-N -l"
LINK_FLAGS = "$(link_flags_version)"
CGO_LINK_FLAGS = "-linkmode 'external' -extldflags '-static' $(link_flags_version)"
else
LINK_FLAGS = "-s -w -extldflags '-static' $(link_flags_version)"
CGO_LINK_FLAGS = "-s -w -linkmode 'external' -extldflags '-static' $(link_flags_version)"
endif
define DEPENDENCIES
ca-certificates
bzip2
distro-info-data
git
zip
endef
# run_go_build is a canned command sequence for the steps required to build a
# juju package. It's expected that the make target using this sequence has a
# local variable defined for PACKAGE. An example of PACKAGE would be
# PACKAGE=github.com/juju/juju
#
# This canned command also allows building for architectures defined as
# ppc64el. Because of legacy Juju we use the arch ppc64el over the go defined
# arch of ppc64le. This canned command will do a last minute transformation of
# the string we build the "correct" go architecture. However the build result
# will still be placed at the expected location with names matching ppc64el.
define run_go_build
$(eval OS = $(word 1,$(subst _, ,$*)))
$(eval ARCH = $(word 2,$(subst _, ,$*)))
$(eval BBIN_DIR = ${BUILD_DIR}/${OS}_${ARCH}/bin)
$(eval BUILD_ARCH = $(subst ppc64el,ppc64le,${ARCH}))
@@mkdir -p ${BBIN_DIR}
@echo "Building ${PACKAGE} for ${OS}/${ARCH}"
@env GOOS=${OS} \
GOARCH=${BUILD_ARCH} \
go build \
-mod=$(JUJU_GOMOD_MODE) \
-tags=$(FINAL_BUILD_TAGS) \
-o ${BBIN_DIR} \
$(COMPILE_FLAGS) \
-ldflags $(LINK_FLAGS) \
-v ${PACKAGE}
endef
define run_cgo_build
$(eval OS = $(word 1,$(subst _, ,$*)))
$(eval ARCH = $(word 2,$(subst _, ,$*)))
$(eval BBIN_DIR = ${BUILD_DIR}/${OS}_${ARCH}/bin)
$(eval BUILD_ARCH = $(subst ppc64el,ppc64le,${ARCH}))
@@mkdir -p ${BBIN_DIR}
@echo "Building ${PACKAGE} for ${OS}/${ARCH}"
@env PATH="${MUSL_BIN_PATH}:${PATH}" \
CC="musl-gcc" \
CGO_CFLAGS="-I${DQLITE_EXTRACTED_DEPS_ARCHIVE_PATH}/include" \
CGO_LDFLAGS="-L${DQLITE_EXTRACTED_DEPS_ARCHIVE_PATH} -luv -ldqlite -lraft -llz4 -lsqlite3 -Wl,-z,stack-size=1048576" \
CGO_LDFLAGS_ALLOW="(-Wl,-wrap,pthread_create)|(-Wl,-z,now)" \
LD_LIBRARY_PATH="${DQLITE_EXTRACTED_DEPS_ARCHIVE_PATH}" \
CGO_ENABLED=1 \
GOOS=${OS} \
GOARCH=${BUILD_ARCH} \
go build \
-mod=$(JUJU_GOMOD_MODE) \
-tags=$(FINAL_BUILD_TAGS) \
-o ${BBIN_DIR} \
${COMPILE_FLAGS} \
-ldflags ${CGO_LINK_FLAGS} \
-v ${PACKAGE}
endef
define run_go_install
@echo "Installing ${PACKAGE}"
@go install \
-mod=$(JUJU_GOMOD_MODE) \
-tags=$(FINAL_BUILD_TAGS) \
$(COMPILE_FLAGS) \
-ldflags $(LINK_FLAGS) \
-v ${PACKAGE}
endef
define run_cgo_install
@echo "Installing ${PACKAGE}"
@env PATH="${MUSL_BIN_PATH}:${PATH}" \
CC="musl-gcc" \
CGO_CFLAGS="-I${DQLITE_EXTRACTED_DEPS_ARCHIVE_PATH}/include" \
CGO_LDFLAGS="-L${DQLITE_EXTRACTED_DEPS_ARCHIVE_PATH} -luv -ldqlite -lraft -llz4 -lsqlite3 -Wl,-z,stack-size=1048576" \
CGO_LDFLAGS_ALLOW="(-Wl,-wrap,pthread_create)|(-Wl,-z,now)" \
LD_LIBRARY_PATH="${DQLITE_EXTRACTED_DEPS_ARCHIVE_PATH}" \
CGO_ENABLED=1 \
GOOS=${GOOS} \
GOARCH=${GOARCH} \
go install \
-mod=$(JUJU_GOMOD_MODE) \
-tags=$(FINAL_BUILD_TAGS) \
${COMPILE_FLAGS} \
-ldflags ${CGO_LINK_FLAGS} \
-v ${PACKAGE}
endef
default: build
.PHONY: dqlite-bench
dqlite-bench: $(BUILD_CGO_BENCH_TARGETS)
.PHONY: juju
juju: PACKAGE = github.com/juju/juju/cmd/juju
juju:
## juju: Install juju without updating dependencies
${run_go_install}
.PHONY: jujuc
jujuc: PACKAGE = github.com/juju/juju/cmd/jujuc
jujuc:
## jujuc: Install jujuc without updating dependencies
${run_go_install}
.PHONY: jujud
jujud: PACKAGE = github.com/juju/juju/cmd/jujud
jujud:
## jujud: Install jujud without updating dependencies
${run_go_install}
mv $(GO_INSTALL_PATH)/jujud $(GO_INSTALL_PATH)/jujud-junk
.PHONY: jujud-controller
jujud-controller: PACKAGE = github.com/juju/juju/cmd/jujud-controller
jujud-controller: musl-install-if-missing dqlite-install-if-missing
## jujud: Install jujud without updating dependencies
${run_cgo_install}
mv $(GO_INSTALL_PATH)/jujud-controller $(GO_INSTALL_PATH)/jujud
.PHONY: dqlite-repl
dqlite-repl: PACKAGE = github.com/juju/juju/scripts/dqlite/cmd
dqlite-repl: musl-install-if-missing dqlite-install-if-missing
## jujud: Install jujud without updating dependencies
${run_cgo_install}
mv $(GO_INSTALL_PATH)/cmd $(GO_INSTALL_PATH)/dqlite-repl
.PHONY: containeragent
containeragent: PACKAGE = github.com/juju/juju/cmd/containeragent
containeragent:
## containeragent: Install containeragent without updating dependencies
${run_go_install}
.PHONY: juju-metadata
juju-metadata: PACKAGE = github.com/juju/juju/cmd/plugins/juju-metadata
juju-metadata:
## juju-metadata: Install juju-metadata without updating dependencies
${run_go_install}
.PHONY: pebble
pebble: PACKAGE = github.com/canonical/pebble/cmd/pebble
pebble:
## pebble: Install pebble without updating dependencies
${run_go_install}
.PHONY: phony_explicit
phony_explicit:
# phone_explicit: is a dummy target that can be added to pattern targets to phony make.
${BUILD_DIR}/%/bin/dqlite-bench: PACKAGE = github.com/juju/juju/scripts/dqlite-bench
${BUILD_DIR}/%/bin/dqlite-bench: phony_explicit musl-install-if-missing dqlite-install-if-missing
# build for dqlite-bench
$(run_cgo_build)
${BUILD_DIR}/%/bin/juju: PACKAGE = github.com/juju/juju/cmd/juju
${BUILD_DIR}/%/bin/juju: phony_explicit
# build for juju
$(run_go_build)
${BUILD_DIR}/%/bin/jujuc: PACKAGE = github.com/juju/juju/cmd/jujuc
${BUILD_DIR}/%/bin/jujuc: phony_explicit
# build for jujuc
$(run_go_build)
${BUILD_DIR}/%/bin/jujud: PACKAGE = github.com/juju/juju/cmd/jujud
${BUILD_DIR}/%/bin/jujud: phony_explicit
# build for jujud
$(run_go_build)
$(eval OS = $(word 1,$(subst _, ,$*)))
$(eval ARCH = $(word 2,$(subst _, ,$*)))
$(eval BBIN_DIR = ${BUILD_DIR}/${OS}_${ARCH}/bin)
mv ${BBIN_DIR}/jujud ${BBIN_DIR}/jujud-junk
${BUILD_DIR}/%/bin/jujud-controller: PACKAGE = github.com/juju/juju/cmd/jujud-controller
${BUILD_DIR}/%/bin/jujud-controller: phony_explicit musl-install-if-missing dqlite-install-if-missing
# build for jujud-controller
$(run_cgo_build)
$(eval OS = $(word 1,$(subst _, ,$*)))
$(eval ARCH = $(word 2,$(subst _, ,$*)))
$(eval BBIN_DIR = ${BUILD_DIR}/${OS}_${ARCH}/bin)
mv ${BBIN_DIR}/jujud-controller ${BBIN_DIR}/jujud
${BUILD_DIR}/%/bin/containeragent: PACKAGE = github.com/juju/juju/cmd/containeragent
${BUILD_DIR}/%/bin/containeragent: phony_explicit
# build for containeragent
$(run_go_build)
${BUILD_DIR}/%/bin/juju-metadata: PACKAGE = github.com/juju/juju/cmd/plugins/juju-metadata
${BUILD_DIR}/%/bin/juju-metadata: phony_explicit
# build for juju-metadata
$(run_go_build)
${BUILD_DIR}/%/bin/pebble: PACKAGE = github.com/canonical/pebble/cmd/pebble
${BUILD_DIR}/%/bin/pebble: phony_explicit
# build for pebble
$(run_go_build)
${JUJU_METADATA_SOURCE}/tools/${JUJU_PUBLISH_STREAM}/juju-${JUJU_VERSION}-%.tgz: phony_explicit juju $(BUILD_AGENT_TARGETS) $(BUILD_CGO_AGENT_TARGETS)
@echo "Packaging simplestream tools for juju ${JUJU_VERSION} on $*"
@mkdir -p ${JUJU_METADATA_SOURCE}/tools/${JUJU_PUBLISH_STREAM}
@tar czf "$@" -C $(call bin_platform_paths,$(subst -,/,$*)) jujud jujuc
.PHONY: simplestreams
simplestreams: juju juju-metadata ${SIMPLESTREAMS_TARGETS}
@juju metadata generate-agent-binaries -d ${JUJU_METADATA_SOURCE} --clean --prevent-fallback --stream ${JUJU_PUBLISH_STREAM} ;
@echo "\nRun export JUJU_METADATA_SOURCE=\"${JUJU_METADATA_SOURCE}\" if not defined in your env"
.PHONY: build
build: rebuild-schema go-build
## build: builds all the targets including rebuilding a new schema.
.PHONY: go-agent-build
go-agent-build: $(BUILD_AGENT_TARGETS) $(BUILD_CGO_AGENT_TARGETS)
.PHONY: go-agent-build-no-cgo
go-agent-build-no-cgo: $(BUILD_AGENT_TARGETS)
.PHONY: go-client-build
go-client-build: $(BUILD_CLIENT_TARGETS)
.PHONY: go-build
go-build: go-agent-build go-client-build
## go-build: builds all the targets without rebuilding a new schema.
.PHONY: release-build
release-build: go-agent-build
## release-build: Construct Juju binaries, without building schema
.PHONY: release-install
release-install: $(INSTALL_TARGETS)
## release-install: Install Juju binaries
.PHONY: pre-check
pre-check:
## pre-check: Verify go code via static analysis
@echo running pre-test checks
@INCLUDE_GOLINTERS=1 $(PROJECT_DIR)/scripts/verify.bash
.PHONY: check
check: pre-check run-tests
## check: Verify Juju code using static analysis and unit tests
.PHONY: test
test: run-tests
## test: Verify Juju code using unit tests
.PHONY: race-test
race-test:
## race-test: Verify Juju code using unit tests with the race detector enabled
+make run-tests TEST_ARGS="$(TEST_ARGS) -race"
.PHONY: run-tests run-go-tests go-test-alias
# Can't make the length of the TMP dir too long or it hits socket name length issues.
run-tests: musl-install-if-missing dqlite-install-if-missing
## run-tests: Run the unit tests
$(eval OS = $(shell go env GOOS))
$(eval ARCH = $(shell go env GOARCH))
$(eval BUILD_ARCH = $(subst ppc64el,ppc64le,${ARCH}))
$(eval TMP := $(shell mktemp -d $${TMPDIR:-/tmp}/jj-XXX))
$(eval TEST_PACKAGES := $(shell go list $(PROJECT)/... | sort | ([ -f "$(TEST_PACKAGE_LIST)" ] && comm -12 "$(TEST_PACKAGE_LIST)" - || cat) | grep -v $(PROJECT)$$ | grep -v $(PROJECT)/vendor/ | grep -v $(PROJECT)/generate/ | grep -v mocks))
@echo 'go test -mod=$(JUJU_GOMOD_MODE) -tags=$(TEST_BUILD_TAGS) $(TEST_ARGS) $(CHECK_ARGS) -test.timeout=$(TEST_TIMEOUT) $$TEST_PACKAGES -check.v'
@TMPDIR=$(TMP) \
PATH="${MUSL_BIN_PATH}:${PATH}" \
CC="musl-gcc" \
CGO_CFLAGS="-I${DQLITE_EXTRACTED_DEPS_ARCHIVE_PATH}/include" \
CGO_LDFLAGS="-L${DQLITE_EXTRACTED_DEPS_ARCHIVE_PATH} -luv -ldqlite -lraft -llz4 -lsqlite3 -Wl,-z,stack-size=1048576" \
CGO_LDFLAGS_ALLOW="(-Wl,-wrap,pthread_create)|(-Wl,-z,now)" \
LD_LIBRARY_PATH="${DQLITE_EXTRACTED_DEPS_ARCHIVE_PATH}" \
CGO_ENABLED=1 \
go test -v -mod=$(JUJU_GOMOD_MODE) -tags=$(TEST_BUILD_TAGS) $(TEST_ARGS) $(CHECK_ARGS) -ldflags ${CGO_LINK_FLAGS} -test.timeout=$(TEST_TIMEOUT) $(TEST_PACKAGES) -check.v
@rm -r $(TMP)
run-go-tests: musl-install-if-missing dqlite-install-if-missing
## run-go-tests: Run the unit tests
$(eval OS = $(shell go env GOOS))
$(eval ARCH = $(shell go env GOARCH))
$(eval BUILD_ARCH = $(subst ppc64el,ppc64le,${ARCH}))
$(eval TEST_PACKAGES ?= "./...")
$(eval TEST_FILTER ?= "")
@echo 'go test -mod=$(JUJU_GOMOD_MODE) -tags=$(TEST_BUILD_TAGS) $(TEST_ARGS) $(CHECK_ARGS) -test.timeout=$(TEST_TIMEOUT) $$TEST_PACKAGES -check.v -check.f $(TEST_FILTER)'
@PATH="${MUSL_BIN_PATH}:${PATH}" \
CC="musl-gcc" \
CGO_CFLAGS="-I${DQLITE_EXTRACTED_DEPS_ARCHIVE_PATH}/include" \
CGO_LDFLAGS="-L${DQLITE_EXTRACTED_DEPS_ARCHIVE_PATH} -luv -ldqlite -lraft -llz4 -lsqlite3 -Wl,-z,stack-size=1048576" \
CGO_LDFLAGS_ALLOW="(-Wl,-wrap,pthread_create)|(-Wl,-z,now)" \
LD_LIBRARY_PATH="${DQLITE_EXTRACTED_DEPS_ARCHIVE_PATH}" \
CGO_ENABLED=1 \
go test -v -mod=$(JUJU_GOMOD_MODE) -tags=$(TEST_BUILD_TAGS) $(TEST_ARGS) $(CHECK_ARGS) -ldflags ${CGO_LINK_FLAGS} -test.timeout=$(TEST_TIMEOUT) ${TEST_PACKAGES} -check.v -check.f $(TEST_FILTER)
go-test-alias: musl-install-if-missing dqlite-install-if-missing
## go-test-alias: Prints out an alias command for easy running of tests.
$(eval PPATH := "PATH")
@echo alias jt=\'PATH=\"${MUSL_BIN_PATH}:$$${PPATH}\" \
CC=\"musl-gcc\" \
CGO_CFLAGS=\"-I${DQLITE_EXTRACTED_DEPS_ARCHIVE_PATH}/include\" \
CGO_LDFLAGS=\"-L${DQLITE_EXTRACTED_DEPS_ARCHIVE_PATH} -luv -ldqlite -lraft -llz4 -lsqlite3 -Wl,-z,stack-size=1048576\" \
CGO_LDFLAGS_ALLOW=\""(-Wl,-wrap,pthread_create)|(-Wl,-z,now)"\" \
LD_LIBRARY_PATH=\"${DQLITE_EXTRACTED_DEPS_ARCHIVE_PATH}\" \
CGO_ENABLED=\"1\" \
go test -mod=\"$(JUJU_GOMOD_MODE)\" -tags=\"$(TEST_BUILD_TAGS)\" -ldflags \"${CGO_LINK_FLAGS}\"\'
.PHONY: install
install: rebuild-schema go-install
## install: Install Juju binaries with a rebuilt schema
.PHONY: go-install
go-install: $(INSTALL_TARGETS)
## go-install: Install Juju binaries
.PHONY: clean
clean:
## clean: Clean the cache and test caches
go clean -x --cache --testcache
go clean -x -r $(PROJECT)/...
.PHONY: vendor-dependencies
vendor-dependencies:
## vendor-dependencies: updates vendored dependencies
@go mod vendor
.PHONY: format
# Reformat source files.
format:
## format: Format the go source code
gofmt -w -l .
.PHONY: simplify
# Reformat and simplify source files.
simplify:
## simplify: Format and simplify the go source code
gofmt -w -l -s .
.PHONY: rebuild-schema
rebuild-schema:
## rebuild-schema: Rebuild the schema for clients with the latest facades
@echo "Generating facade schema..."
# GOOS and GOARCH environment variables are cleared in case the user is trying to cross architecture compilation.
ifdef SCHEMA_PATH
@env GOOS= GOARCH= CGO_ENABLED=1 go run -tags="libsqlite3" $(COMPILE_FLAGS) $(PROJECT)/generate/schemagen -admin-facades -facade-group=client "$(SCHEMA_PATH)/schema.json"
@env GOOS= GOARCH= CGO_ENABLED=1 go run -tags="libsqlite3" $(COMPILE_FLAGS) $(PROJECT)/generate/schemagen -admin-facades -facade-group=agent "$(SCHEMA_PATH)/agent-schema.json"
else
@env GOOS= GOARCH= CGO_ENABLED=1 go run -tags="libsqlite3" $(COMPILE_FLAGS) $(PROJECT)/generate/schemagen -admin-facades -facade-group=client \
./apiserver/facades/schema.json
@env GOOS= GOARCH= CGO_ENABLED=1 go run -tags="libsqlite3" $(COMPILE_FLAGS) $(PROJECT)/generate/schemagen -admin-facades -facade-group=agent \
./apiserver/facades/agent-schema.json
endif
.PHONY: rebuild-triggers
rebuild-triggers:
## rebuild-triggers: Rebuild the SQL trigger schema
@echo "Generating trigger schema..."
@env GOOS= GOARCH= CGO_ENABLED=1 go generate -tags="libsqlite3" $(COMPILE_FLAGS) -x ./domain/schema
.PHONY: install-snap-dependencies
# Install packages required to develop Juju and run tests. The stable
# PPA includes the required mongodb-server binaries.
install-snap-dependencies:
## install-snap-dependencies: Install the supported snap dependencies
ifeq ($(shell if [ "$(GO_INSTALLED_VERSION)" \> "$(GO_MOD_VERSION)" -o "$(GO_INSTALLED_VERSION)" = "$(GO_MOD_VERSION)" ]; then echo 1; fi),1)
@echo 'Using installed go-$(GO_MOD_VERSION)'
endif
ifeq ("$(GO_INSTALLED_VERSION)","")
@echo 'Installing go-$(GO_MOD_VERSION) snap'
@sudo snap install go --channel=$(GO_MOD_VERSION)/stable --classic
else
ifeq ($(shell if [ "$(GO_INSTALLED_VERSION)" \< "$(GO_MOD_VERSION)" ]; then echo 1; fi),1)
$(warning "warning: version of go too low: use 'snap refresh go --channel=$(GO_MOD_VERSION)'")
$(error "error Installed go version '$(GO_INSTALLED_VERSION)' less than required go version '$(GO_MOD_VERSION)'")
endif
endif
WAIT_FOR_DPKG=bash -c '. "${PROJECT_DIR}/make_functions.sh"; wait_for_dpkg "$$@"' wait_for_dpkg
JUJU_DB_VERSION=4.4
JUJU_DB_CHANNEL=${JUJU_DB_VERSION}/stable
.PHONY: install-mongo-dependencies
install-mongo-dependencies:
## install-mongo-dependencies: Install Mongo and its dependencies
@echo Installing ${JUJU_DB_CHANNEL} juju-db snap for mongodb
@sudo snap refresh juju-db --channel=${JUJU_DB_CHANNEL} 2> /dev/null; sudo snap install juju-db --channel=${JUJU_DB_CHANNEL} 2> /dev/null
@$(WAIT_FOR_DPKG)
@sudo apt-get --yes install $(strip $(DEPENDENCIES))
.PHONY: install-sqlite3-dependencies
install-sqlite3-dependencies:
## install-sqlite3-dependencies: Install libsqlite3-dev
@echo Installing libsqlite3-dev
@$(WAIT_FOR_DPKG)
@sudo apt-get update
@sudo apt-get --yes install libsqlite3-dev
.PHONY: install-dependencies
install-dependencies: install-snap-dependencies install-mongo-dependencies install-sqlite3-dependencies
## install-dependencies: Install all the dependencies
@echo "Installing dependencies"
.PHONY: install-etc
# Install bash_completion
install-etc:
## install-etc: Install auto-completion
@echo Installing bash completion
@sudo install -o root -g root -m 644 etc/bash_completion.d/juju /usr/share/bash-completion/completions
@sudo install -o root -g root -m 644 etc/bash_completion.d/juju-version /usr/share/bash-completion/completions
.PHONY: setup-lxd
setup-lxd:
## setup-lxd: Auto configure LXD
ifeq ($(shell ifconfig lxdbr0 2>&1 | grep -q "inet addr" && echo true),true)
@echo IPv4 networking is already setup for LXD.
@echo run "sudo scripts/setup-lxd.sh" to reconfigure IPv4 networking
else
@echo Setting up IPv4 networking for LXD
@sudo scripts/setup-lxd.sh || true
endif
GOCHECK_COUNT="$(shell go list -f '{{join .Deps "\n"}}' ${PROJECT}/... | grep -c "gopkg.in/check.v*")"
.PHONY: check-deps
check-deps:
## check-deps: Check dependencies are correct versions
@echo "$(GOCHECK_COUNT) instances of gocheck not in test code"
# CAAS related targets
export OCI_BUILDER ?= $(shell (which podman 2>&1 > /dev/null && echo podman) || echo docker )
DOCKER_USERNAME ?= docker.io/jujusolutions
DOCKER_BUILDX_CONTEXT ?= juju-make
DOCKER_STAGING_DIR ?= ${BUILD_DIR}/docker-staging
JUJUD_STAGING_DIR ?= ${DOCKER_STAGING_DIR}/jujud-operator
JUJUD_BIN_DIR ?= ${BIN_DIR}
OPERATOR_IMAGE_BUILD_SRC ?= true
# Import shell functions from make_functions.sh
# For the k8s operator.
BUILD_OPERATOR_IMAGE=bash -c '. "${PROJECT_DIR}/make_functions.sh"; build_push_operator_image "$$@"' build_push_operator_image
OPERATOR_IMAGE_PATH=bash -c '. "${PROJECT_DIR}/make_functions.sh"; operator_image_path "$$@"' operator_image_path
OPERATOR_IMAGE_RELEASE_PATH=bash -c '. "${PROJECT_DIR}/make_functions.sh"; operator_image_release_path "$$@"' operator_image_release_path
UPDATE_MICROK8S_OPERATOR=bash -c '. "${PROJECT_DIR}/make_functions.sh"; microk8s_operator_update "$$@"' microk8s_operator_update
SEED_REPOSITORY=bash -c '. "${PROJECT_DIR}/make_functions.sh"; seed_repository "$$@"' seed_repository
image_check_prereq=image-check-build
ifneq ($(OPERATOR_IMAGE_BUILD_SRC),true)
image_check_prereq=image-check-build-skip
endif
.PHONY: image-check
image-check: $(image_check_prereq)
.PHONY: image-check-build
image-check-build:
CLIENT_PACKAGE_PLATFORMS="$(OCI_IMAGE_PLATFORMS)" AGENT_PACKAGE_PLATFORMS="$(OCI_IMAGE_PLATFORMS)" make go-build
.PHONY: image-check-build-skip
image-check-build-skip:
@echo "skipping to build jujud bin, use existing one at ${JUJUD_BIN_DIR}/."
.PHONY: docker-builder
docker-builder:
## docker-builder: Makes sure that there is a buildx context for building the oci images
ifeq ($(OCI_BUILDER),docker)
-@docker buildx create --name ${DOCKER_BUILDX_CONTEXT}
endif
.PHONY: image-check
operator-image: image-check docker-builder
## operator-image: Build operator image via docker
${BUILD_OPERATOR_IMAGE} "$(OCI_IMAGE_PLATFORMS)" "$(PUSH_IMAGE)"
push_operator_image_prereq=push-operator-image-defined
ifeq ($(JUJU_BUILD_NUMBER),)
push_operator_image_prereq=push-operator-image-undefined
endif
.PHONY: push-operator-image-defined
push-operator-image-defined: PUSH_IMAGE=true
push-operator-image-defined: operator-image
.PHONY: push-operator-image-undefined
push-operator-image-undefined:
@echo "error Undefined JUJU_BUILD_NUMBER"
.PHONY: push-operator-image
push-operator-image: $(push_operator_image_prereq)
## push-operator-image: Push up the newly built operator image via docker
.PHONY: push-release-operator-image
push-release-operator-image: PUSH_IMAGE=true
push-release-operator-image: operator-image
## push-release-operator-image: Push up the newly built release operator image via docker
.PHONY: seed-repository
seed-repository:
## seed-repository: Copy required juju images from docker.io/jujusolutions
JUJU_DB_VERSION=$(JUJU_DB_VERSION) $(SEED_REPOSITORY)
.PHONY: host-install
host-install:
## host-install: installs juju for host os/architecture
+GOOS=$(GOHOSTOS) GOARCH=$(GOHOSTARCH) make juju
.PHONY: minikube-operator-update
minikube-operator-update: host-install operator-image
## minikube-operator-update: Inject the newly built operator image into minikube
$(OCI_BUILDER) save "$(shell ${OPERATOR_IMAGE_PATH})" | minikube image load --overwrite=true -
.PHONY: microk8s-operator-update
microk8s-operator-update: host-install operator-image
## microk8s-operator-update: Inject the newly built operator image into microk8s
@${UPDATE_MICROK8S_OPERATOR}
.PHONY: k3s-operator-update
k3s-operator-update: host-install operator-image
## k3s-operator-update: Inject the newly built operator image into k3s
$(OCI_BUILDER) save "$(shell ${OPERATOR_IMAGE_PATH})" | sudo k3s ctr images import -
.PHONY: check-k8s-model
check-k8s-model:
## check-k8s-model: Check if k8s model is present in show-model
@:$(if $(value JUJU_K8S_MODEL),, $(error Undefined JUJU_K8S_MODEL))
@juju show-model ${JUJU_K8S_MODEL} > /dev/null
.PHONY: local-operator-update
local-operator-update: check-k8s-model operator-image
## local-operator-update: Build then update local operator image
$(eval kubeworkers != juju status -m ${JUJU_K8S_MODEL} kubernetes-worker --format json | jq -c '.machines | keys' | tr -c '[:digit:]' ' ' 2>&1)
$(OCI_BUILDER) save "$(shell ${OPERATOR_IMAGE_PATH})" | gzip > ${DOCKER_STAGING_DIR}/jujud-operator-image.tar.gz
$(foreach wm,$(kubeworkers), juju scp -m ${JUJU_K8S_MODEL} ${DOCKER_STAGING_DIR}/jujud-operator-image.tar.gz $(wm):/tmp/jujud-operator-image.tar.gz ; )
$(foreach wm,$(kubeworkers), juju ssh -m ${JUJU_K8S_MODEL} $(wm) -- "zcat /tmp/jujud-operator-image.tar.gz | docker load" ; )
STATIC_ANALYSIS_JOB ?=
.PHONY: static-analysis
static-analysis: dqlite-install-if-missing
## static-analysis: Check the go code using static-analysis
@cd tests && CGO_ENABLED=1 \
CGO_LDFLAGS_ALLOW="(-Wl,-wrap,pthread_create)|(-Wl,-z,now)" \
./main.sh static_analysis ${STATIC_ANALYSIS_JOB}
.PHONY: docs
docs:
## docs: Displays make commands for docs
@echo "\n" \
"------------------------------------------------------------- \n" \
"* watch, build and serve the documentation: make docs-run \n" \
"* only build: make docs-html \n" \
"* only serve: make docs-serve \n" \
"* clean built doc files: make docs-clean-doc \n" \
"* clean full environment: make docs-clean \n" \
"* check links: make docs-linkcheck \n" \
"* check spelling: make docs-spelling \n" \
"* check spelling (without building again): make docs-spellcheck \n" \
"* check accessibility: make docs-pa11y \n" \
"* check style guide compliance: make docs-vale \n" \
"* check style guide compliance on target: make docs-vale TARGET=* \n" \
"* check metrics for documentation: make docs-allmetrics \n" \
"------------------------------------------------------------- \n"
.PHONY: docs-help
docs-help: docs
docs-%:
## Build the sphinx documentation
cd docs && $(MAKE) -f Makefile.sp sp-$* ALLFILES='*.md **/*.md'