-
Notifications
You must be signed in to change notification settings - Fork 356
Expand file tree
/
Copy pathbuild_funcs.sh
More file actions
executable file
·401 lines (350 loc) · 15 KB
/
build_funcs.sh
File metadata and controls
executable file
·401 lines (350 loc) · 15 KB
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
#!/usr/bin/env bash
# Helpful debug info while script runs.
PS4='\033[1m[$0:${LINENO}] $\033[0m '
BINARY=sonobuoy
TARGET=sonobuoy
GOTARGET=github.com/vmware-tanzu/"$TARGET"
GOPATH=$(go env GOPATH)
REGISTRY=sonobuoy
LINUX_ARCH=(amd64 arm64 ppc64le s390x)
# Currently only under a single arch, can iterate over these and still assume arch value.
WIN_ARCH=amd64
WINVERSIONS=("ltsc2022")
# Not used for pushing images, just for local building on other GOOS. Defaults to
# grabbing from the local go env but can be set manually to avoid that requirement.
HOST_GOOS=$(go env GOOS)
HOST_GOARCH=$(go env GOARCH)
# --tags allows detecting non-annotated tags as well as annotated ones
GIT_VERSION=${VERSION:-"$(git describe --always --dirty --tags)"}
# PRE_DEFINED_VERSION is used when building binary and tagging image. Fallback to GIT_VERSION if not set.
# This is useful when automate creating documents. Otherwise the version in the doc will be git shas.
PRE_DEFINED_VERSION=${PRE_DEFINED_VERSION:-$GIT_VERSION}
IMAGE_VERSION=$(git describe --always --dirty --tags)
IMAGE_TAG=$(echo "$IMAGE_VERSION" | cut -d. -f1,2)
IMAGE_BRANCH=$(git rev-parse --abbrev-ref HEAD | sed 's/\///g')
GIT_REF_LONG=$(git rev-parse --verify HEAD)
BUILDMNT=/go/src/$GOTARGET
GO_VERSION=$(go env GOVERSION | sed 's/go//')
BUILD_IMAGE="golang:${GO_VERSION}"
AMD_IMAGE=gcr.io/distroless/static:nonroot
ARM_IMAGE=gcr.io/distroless/static:nonroot-arm64
PPC64LE_IMAGE=gcr.io/distroless/static:nonroot-ppc64le
S390X_IMAGE=gcr.io/distroless/static:nonroot-s390x
WIN_AMD64_BASEIMAGE=mcr.microsoft.com/windows/nanoserver
TEST_IMAGE=testimage:v0.1
LINT_IMAGE=golangci/golangci-lint:v1.64.8
KIND_CLUSTER=kind
SCRIPT_DIR="$( cd -- "$( dirname -- "${BASH_SOURCE[0]:-$0}"; )" &> /dev/null && pwd 2> /dev/null; )"
unit_local() {
go test ${VERBOSE:+-v} -timeout 60s -coverprofile=coverage.txt -covermode=atomic $GOTARGET/cmd/... $GOTARGET/pkg/...
}
unit() {
docker run --rm -v "$(pwd)":$BUILDMNT -w $BUILDMNT $BUILD_IMAGE /bin/sh -c \
"go test ${VERBOSE:+-v} -timeout 60s -coverprofile=coverage.txt -covermode=atomic $GOTARGET/cmd/... $GOTARGET/pkg/..."
}
stress() {
docker run --rm -v "$(pwd)":$BUILDMNT -w $BUILDMNT $BUILD_IMAGE /bin/sh -c \
"go test ${VERBOSE:+-v} -timeout 60s -coverprofile=coverage.txt -covermode=atomic $GOTARGET/test/stress/..."
}
integration() {
# Download linux kubectl and move into default path for tests
curl --output ./kubectl https://storage.googleapis.com/kubernetes-release/release/v1.26.1/bin/linux/amd64/kubectl
chmod +x ./kubectl
docker run --rm \
-v "$(pwd)":$BUILDMNT \
-v /tmp/artifacts:/tmp/artifacts \
-v "${HOME}"/.kube/config:/root/.kube/kubeconfig \
--env KUBECONFIG=/root/.kube/kubeconfig \
-w "$BUILDMNT" \
--env ARTIFACTS_DIR=/tmp/artifacts \
--env SONOBUOY_CLI="$SONOBUOY_CLI" \
--env KUBECTL_CLI="$KUBECTL_CLI" \
--network host \
"$BUILD_IMAGE" \
go test ${VERBOSE:+-v} -tags=integration "$GOTARGET"/test/integration/...
}
local_integration(){
# Build linx binary and move into default path for tests
build_binary_GOOS_GOARCH linux amd64
cp ./build/linux/amd64/sonobuoy ./sonobuoy
# Download linux kubectl and move into default path for tests
curl --output ./kubectl https://storage.googleapis.com/kubernetes-release/release/v1.26.1/bin/linux/amd64/kubectl
chmod +x ./kubectl
integration
}
lint() {
docker run --rm -v "$(pwd)":$BUILDMNT -w $BUILDMNT $LINT_IMAGE /bin/sh -c \
"golangci-lint run --out-format=github-actions --timeout=5m0s -v"
}
vet() {
docker run --rm -v "$(pwd)":$BUILDMNT -w $BUILDMNT $BUILD_IMAGE /bin/sh -c \
"CGO_ENABLED=0 go vet ${VERBOSE:+-v} -timeout 60s $GOTARGET/cmd/... $GOTARGET/pkg/..."
}
# Builds a container given the dockerfile and image name (not registry).
# Dockerfiles typically generated via another method.
build_container_dockerfile_arch() {
docker build \
-t "$REGISTRY/$TARGET:$2-$IMAGE_VERSION" \
-t "$REGISTRY/$TARGET:$2-$IMAGE_TAG" \
-t "$REGISTRY/$TARGET:$2-$IMAGE_BRANCH" \
-f "$1" \
.
}
buildx_container_windows_version(){
mkdir -p "build/windows/$WIN_ARCH/$VERSION"
docker buildx build --pull \
--output=type=docker,dest=build/windows/$WIN_ARCH/$VERSION/sonobuoy-img-win-$WIN_ARCH-$VERSION-$GITHUB_RUN_ID.tar \
--platform windows/amd64 \
-t $REGISTRY/$TARGET:win-$WIN_ARCH-$VERSION-$IMAGE_VERSION \
--build-arg VERSION=$1 \
-f build/windows/$WIN_ARCH/Dockerfile \
.
}
# Generates a dockerfile given the os and arch (the 2 and only arguments).
gen_dockerfile_for_os_arch(){
dockerfile="build/$1/$2/Dockerfile"
if [ "$1" = "linux" ]; then
if [ "$2" = "amd64" ]; then
sed -e "s|BASEIMAGE|$AMD_IMAGE|g" \
-e 's|CMD1||g' \
-e 's|BINARY|build/linux/amd64/sonobuoy|g' Dockerfile > "$dockerfile"
elif [ "$2" = "arm64" ]; then
sed -e "s|BASEIMAGE|$ARM_IMAGE|g" \
-e 's|CMD1||g' \
-e 's|BINARY|build/linux/arm64/sonobuoy|g' Dockerfile > "$dockerfile"
elif [ "$2" = "ppc64le" ]; then
sed -e "s|BASEIMAGE|$PPC64LE_IMAGE|g" \
-e 's|CMD1||g' \
-e 's|BINARY|build/linux/ppc64le/sonobuoy|g' Dockerfile > "$dockerfile"
elif [ "$2" = "s390x" ]; then
sed -e "s|BASEIMAGE|$S390X_IMAGE|g" \
-e 's|CMD1||g' \
-e 's|BINARY|build/linux/s390x/sonobuoy|g' Dockerfile > "$dockerfile"
else
echo "Linux ARCH unknown"
fi
elif [ "$1" = "windows" ]; then
if [ "$2" = "amd64" ]; then
# Onlhy doing one arch so this could be hardcoded, likewise we could handle the
# base image differently. Wanted something here for parity with linux in case we expand it though.
sed -e 's|BINARY|build/windows/amd64/sonobuoy.exe|g' DockerfileWindows > "$dockerfile"
else
echo "Windows ARCH unknown"
fi
else
echo "OS unknown"
fi
}
# Builds the image given just the os, arch, and image name.
build_container_os_arch_version(){
dockerfile="build/$1/$2/Dockerfile"
gen_dockerfile_for_os_arch "$1" "$2"
if [ "$1" = "windows" ]; then
buildx_container_windows_version $3
else
build_container_dockerfile_arch "$dockerfile" $2
fi
}
# Builds all linux images. Assumes binaries are available.
linux_containers() {
for arch in "${LINUX_ARCH[@]}"; do
build_container_os_arch_version linux "$arch"
done
}
# Builds the windows images. Assumes binary is available.
windows_containers() {
for VERSION in "${WINVERSIONS[@]}"; do
build_container_os_arch_version windows "$WIN_ARCH" "$VERSION"
done
}
# Builds a binary for a specific goos/goarch.
build_binary_GOOS_GOARCH() {
LDFLAGS="-s -w -X $GOTARGET/pkg/buildinfo.Version=$PRE_DEFINED_VERSION -X $GOTARGET/pkg/buildinfo.GitSHA=$GIT_REF_LONG"
args=(${VERBOSE:+-v} -ldflags "${LDFLAGS}" "$GOTARGET")
if [ "$VERBOSE" ]; then args+=("-v"); fi;
echo Building "$1"/"$2"
mkdir -p build/"$1"/"$2"
if [ "$1" = "windows" ]; then
BINARY="sonobuoy.exe"
else
BINARY="sonobuoy"
fi
# Avoid quoting nightmare by not running in /bin/sh
docker run --rm -v "$(pwd)":"$BUILDMNT" -w "$BUILDMNT" \
-e CGO_ENABLED=0 -e GOOS="$1" -e GOARCH="$2" "$BUILD_IMAGE" \
go build -buildvcs=false -o build/"$1"/"$2"/"$BINARY" "${args[@]}" "$GOTARGET"
}
# Builds all linux and windows binaries.
build_binaries() {
for arch in "${LINUX_ARCH[@]}"; do
build_binary_GOOS_GOARCH linux "$arch"
done
for arch in "${WIN_ARCH[@]}"; do
build_binary_GOOS_GOARCH windows "$arch"
done
}
# Builds sonobuoy using the local goos/goarch.
native() {
LDFLAGS="-s -w -X $GOTARGET/pkg/buildinfo.Version=$PRE_DEFINED_VERSION -X $GOTARGET/pkg/buildinfo.GitSHA=$GIT_REF_LONG"
args=(-ldflags "${LDFLAGS}" "$GOTARGET")
CGO_ENABLED=0 GOOS="$HOST_GOOS" GOARCH="$HOST_GOARCH" go build -buildvcs=false -o sonobuoy "${args[@]}"
mkdir -p ./build/$HOST_GOOS/$HOST_GOARCH
cp ./sonobuoy ./build/$HOST_GOOS/$HOST_GOARCH/sonobuoy
}
# Pushes sonobuoy images. Usually by branch/ref but by tag/latest if it is a new tag.
push_images() {
for arch in "${LINUX_ARCH[@]}"; do
docker push "$REGISTRY/$TARGET:$arch-$IMAGE_BRANCH"
docker push "$REGISTRY/$TARGET:$arch-$IMAGE_VERSION"
done
export REGISTRY_AUTH_FILE=$(pwd)/auth.json
skopeo login --username $DOCKERHUB_USER --password $DOCKERHUB_TOKEN registry.hub.docker.com/$REGISTRY
for VERSION in "${WINVERSIONS[@]}"; do
skopeo --debug copy docker-archive://$(pwd)/build/windows/$WIN_ARCH/$VERSION/sonobuoy-img-win-$WIN_ARCH-$VERSION-$GITHUB_RUN_ID.tar "docker://registry.hub.docker.com/$REGISTRY/$TARGET:win-$WIN_ARCH-$VERSION-$IMAGE_BRANCH"
skopeo --debug copy docker-archive://$(pwd)/build/windows/$WIN_ARCH/$VERSION/sonobuoy-img-win-$WIN_ARCH-$VERSION-$GITHUB_RUN_ID.tar "docker://registry.hub.docker.com/$REGISTRY/$TARGET:win-$WIN_ARCH-$VERSION-$IMAGE_VERSION"
done
}
# Generates the multi-os manifest for sonobuoy. First argument
# is the tag for the manifest, 2nd is the image tags. 2nd value
# defaults to IMAGE_VERSION since that should always be pushed.
gen_manifest_with_tag() {
imgTag="${2:-$IMAGE_VERSION}"
for arch in "${LINUX_ARCH[@]}"; do
docker manifest create \
"$REGISTRY/$TARGET:$1" \
--amend "$REGISTRY/$TARGET:$arch-$imgTag"
done
for VERSION in "${WINVERSIONS[@]}"; do
full_version=$(docker manifest inspect ${WIN_AMD64_BASEIMAGE}:${VERSION} | jq '.manifests[0].platform."os.version"' -r)
docker manifest create \
"$REGISTRY/$TARGET:$1" \
--amend "$REGISTRY/$TARGET:win-$WIN_ARCH-$VERSION-$imgTag"
docker manifest annotate "$REGISTRY/$TARGET:$1" \
"$REGISTRY/$TARGET:win-$WIN_ARCH-$VERSION-$imgTag" \
--os-version="${full_version}"
done
}
# Pushes the multi-os manifest for sonobuoy; must be generated first.
push_manifest_with_tag() {
gen_manifest_with_tag "$1"
docker manifest push "$REGISTRY/$TARGET:$1"
}
# Pushes all images and the manifest.
# Assumes you have the images built or loaded already. Not
# added as dependency due to having both Linux/Windows
# prereqs which can't be done on the same machine.
gen_manifest_and_push_all() {
push_images
if git describe --tags --exact-match >/dev/null 2>&1 ; then
push_manifest_with_tag "$IMAGE_VERSION"
push_manifest_with_tag "$IMAGE_BRANCH"
push_manifest_with_tag "$IMAGE_TAG"
push_manifest_with_tag latest
else
push_manifest_with_tag "$IMAGE_VERSION"
push_manifest_with_tag "$IMAGE_BRANCH"
fi
}
# Removes a given image from docker. Image name (not registry) should be the first
# and only argument.
remove_image() {
docker rmi -f "$(docker images "$REGISTRY/$1" -a -q)" || true
}
# Removes temp files, built images, etc so the next build and repo are
# in a pristine state.
clean() {
# Best effort for clean; don't exit if failure.
set +e
rm -f "$TARGET"
rm -rf build
remove_image "$TARGET"
set -e
}
# kind_images will build the kind-node image. Generally building the base image is not necessary
# and we can use the upstream kindest/base image.
kind_images() {
K8S_PATH="$GOPATH/src/github.com/kubernetes/kubernetes"
KIND_K8S_TAG="$(cd "$K8S_PATH" && git describe)"
kind build node-image --kube-root="$K8S_PATH" --image "$REGISTRY/kind-node:$KIND_K8S_TAG"
}
# push_kind_images will push the same image kind_images just built our registry.
push_kind_images() {
K8S_PATH="$GOPATH"/src/github.com/kubernetes/kubernetes
KIND_K8S_TAG="$(cd "$K8S_PATH" && git describe)"
docker push "$REGISTRY/kind-node:$KIND_K8S_TAG"
}
# check_kind_env will show you what will be built/tagged before doing so with kind_images
check_kind_env() {
if [ -z "$K8S_PATH" ] ; then
echo K8S_PATH is undefined
exit 1
fi
if [ -z "$KIND_K8S_TAG" ] ; then
echo KIND_K8S_TAG is undefined
exit 1
fi
echo --kube-root="$K8S_PATH" tagging as --image "$REGISTRY/kind-node:$KIND_K8S_TAG"
}
# Creates the kind cluster if it does not already exist.
setup_kind_cluster(){
if ! kind get clusters | grep -q "^$KIND_CLUSTER$"; then
kind create cluster --name "$KIND_CLUSTER" --config kind-config.yaml
# Although the cluster has been created, not all the pods in kube-system are created/available
sleep 20
fi
}
# Builds the test image for integration tests.
build_test_image(){
(
cd test/integration/testImage
./build.sh
)
}
# Saves the images which we persist in CI and use for testing/publishing.
save_images_to_tar(){
# Save linux images to tar; for loading into test cluster and into build by os/arch for artifacts.
docker save -o build/testimage-$GITHUB_RUN_ID.tar sonobuoy/testimage
for arch in "${LINUX_ARCH[@]}"; do
docker save -o build/linux/$arch/sonobuoy-img-linux-$arch-$GITHUB_RUN_ID.tar "$REGISTRY/$TARGET:$arch-$IMAGE_VERSION" "$REGISTRY/$TARGET:$arch-$IMAGE_BRANCH"
done
}
# Loads sonobuoy image and the testing image into the kind cluster.
load_test_images_into_cluster(){
# Retag in case we are in a fork; ignore error on our own registry though.
docker tag $REGISTRY/$TARGET:amd64-$IMAGE_VERSION sonobuoy/$TARGET:$IMAGE_VERSION || true
# Tests will look for the sonobuoy images by default, so hard-code those.
kind load docker-image --name $KIND_CLUSTER sonobuoy/$TARGET:$IMAGE_VERSION
kind load docker-image --name $KIND_CLUSTER sonobuoy/$TEST_IMAGE
}
# update_local updates all the goldenfiles throughout our tests. Some of those are integration
# tests so this will also build sonobuoy locally. A kind cluster won't be necessary.
update_local() {
set -x
if [ ! -f "./kubectl" ]; then
# Download linux kubectl and move into default path for tests
curl --output ./kubectl https://storage.googleapis.com/kubernetes-release/release/v1.26.1/bin/linux/amd64/kubectl
chmod +x ./kubectl
fi
# Redirect output so we can avoid clutter where go is telling us where -update
# is not defined. Just printing out the packages at the end.
go test $GOTARGET/cmd/... $GOTARGET/pkg/... -update > tmp_update.out
cat tmp_update.out | grep github | grep -v ok
cat tmp_update.out | grep github | grep ok
rm tmp_update.out
# Ensure you build using the intended script so buildinfo gets set.
native
# Integration tests take longer and need kind (usually). Just run the test we need.
go test $GOTARGET/test/integration -update -v -tags integration -run 'Golden'
set +x
}
update_cli_docs() {
output="$SCRIPT_DIR/../site/content/docs/main/cli"
echo "Using sonobuoy at ./sonobuoy to generate docs and place them at ${output}"
echo "Building sonobuoy for local machine to gen cli docs..."
native
echo "Removing old cli docs from main..."
rm -rf "${output}"
mkdir -p "${output}"
echo "Generating new docs..."
./sonobuoy gen cli "${output}"
}