From b9e5eb55b36d881a9d29f42209163a66fbfba932 Mon Sep 17 00:00:00 2001 From: Jeremias Weber Date: Fri, 21 Apr 2023 15:33:00 +0200 Subject: [PATCH 1/4] #74 Fix CVEs --- CHANGELOG.md | 5 +++++ Dockerfile | 14 +++++++------- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 583d4a6..aa59f08 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,11 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] +### Changed +- [#20] Upgrade Base Image to 3.17.3-2 + +### Security +- [#20] Fixed CVE-2023-27536, CVE-2023-27536 and some others ## [v1.23.2-4] - 2023-03-31 ### Added diff --git a/Dockerfile b/Dockerfile index c99537a..820ed24 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM registry.cloudogu.com/official/base:3.15.3-1 as builder +FROM registry.cloudogu.com/official/base:3.17.3-2 as builder LABEL maintainer="hello@cloudogu.com" # dockerfile is based on https://github.com/dockerfile/nginx and https://github.com/bellycard/docker-loadbalancer @@ -19,11 +19,10 @@ RUN set -x -o errexit \ && echo "${NGINX_TAR_SHA256} *nginx-${NGINX_VERSION}.tar.gz" | sha256sum -c - \ && tar -zxvf nginx-${NGINX_VERSION}.tar.gz \ && cd /build/nginx-${NGINX_VERSION} \ - && /build.sh \ - && rm -rf /var/cache/apk/* /build + && /build.sh -FROM registry.cloudogu.com/official/base:3.15.3-1 +FROM registry.cloudogu.com/official/base:3.17.3-2 LABEL maintainer="hello@cloudogu.com" \ NAME="official/nginx" \ VERSION="1.23.2-4" @@ -44,7 +43,7 @@ RUN set -x -o errexit \ && apk update \ && apk upgrade \ # install required packages - && apk --update add openssl pcre zlib \ + && apk --update add --no-cache openssl pcre zlib curl \ # add nginx user && adduser nginx -D \ # install ces-confd @@ -59,11 +58,13 @@ RUN set -x -o errexit \ && curl -Lsk https://github.com/cloudogu/ces-about/releases/download/v${CES_ABOUT_VERSION}/ces-about-v${CES_ABOUT_VERSION}.tar.gz -o ces-about-v${CES_ABOUT_VERSION}.tar.gz \ && echo "${CES_ABOUT_TAR_SHA256} *ces-about-v${CES_ABOUT_VERSION}.tar.gz" | sha256sum -c - \ && tar -xzvf ces-about-v${CES_ABOUT_VERSION}.tar.gz -C /var/www/html \ + && rm -rf ces-about-v${CES_ABOUT_VERSION}.tar.gz \ && sed -i 's@base href=".*"@base href="/info/"@' /var/www/html/info/index.html \ # install warp menu && curl -Lsk https://github.com/cloudogu/warp-menu/releases/download/v${WARP_MENU_VERSION}/warp-v${WARP_MENU_VERSION}.zip -o /tmp/warp.zip \ && echo "${WARP_MENU_TAR_SHA256} */tmp/warp.zip" | sha256sum -c - \ && unzip /tmp/warp.zip -d /var/www/html \ + && rm -rf /tmp/warp.zip \ # install custom error pages && curl -Lsk https://github.com/cloudogu/ces-theme/archive/${CES_THEME_VERSION}.zip -o /tmp/theme.zip \ && echo "${CES_THEME_TAR_SHA256} */tmp/theme.zip" | sha256sum -c - \ @@ -74,8 +75,7 @@ RUN set -x -o errexit \ # redirect logs && ln -sf /dev/stdout /var/log/nginx/access.log \ && ln -sf /dev/stderr /var/log/nginx/error.log \ - # cleanup apk cache - && rm -rf /var/cache/apk/* + && apk del curl # copy files COPY --from=builder /usr/sbin/nginx /usr/sbin/nginx From bde1c05c06d41238600fadc18ec90c3c1dc928f9 Mon Sep 17 00:00:00 2001 From: Jeremias Weber Date: Fri, 21 Apr 2023 15:36:38 +0200 Subject: [PATCH 2/4] #74 Update build-libs --- Jenkinsfile | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Jenkinsfile b/Jenkinsfile index bc6837d..ea9e73a 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -1,5 +1,5 @@ #!groovy -@Library(['github.com/cloudogu/dogu-build-lib@v1.10.0', 'github.com/cloudogu/ces-build-lib@1.60.1']) _ +@Library(['github.com/cloudogu/dogu-build-lib@v2.0.0', 'github.com/cloudogu/ces-build-lib@1.64.1']) _ import com.cloudogu.ces.dogubuildlib.* import com.cloudogu.ces.cesbuildlib.* @@ -36,6 +36,11 @@ node('vagrant') { lintDockerfile() } + stage('Check Markdown Links') { + Markdown markdown = new Markdown(this, "3.11.0") + markdown.check() + } + stage('Shellcheck'){ shellCheck('./resources/startup.sh ./nginx-build/build.sh') } From c07dfaff19209cef977232ea2ff8c48b1c643452 Mon Sep 17 00:00:00 2001 From: Jeremias Weber Date: Fri, 21 Apr 2023 15:37:06 +0200 Subject: [PATCH 3/4] #74 Update makefiles --- Makefile | 2 +- build/make/bats.mk | 64 +++++++ build/make/bats/Dockerfile | 7 + build/make/bats/customBatsEntrypoint.sh | 6 + build/make/bower.mk | 6 +- build/make/build.mk | 34 ++-- build/make/clean.mk | 7 +- build/make/dependencies-glide.mk | 24 --- build/make/dependencies-godep.mk | 10 -- build/make/dependencies-gomod.mk | 4 +- build/make/deploy-debian.mk | 21 +-- build/make/digital-signature.mk | 11 +- build/make/info.mk | 8 - build/make/k8s-controller.mk | 96 +++++++++++ build/make/k8s-dogu.mk | 44 +++++ build/make/k8s-dogu.tpl | 9 + build/make/k8s.mk | 119 +++++++++++++ build/make/mockery.yaml | 4 + build/make/mocks.mk | 27 +++ build/make/package-debian.mk | 6 +- build/make/package-tar.mk | 4 +- build/make/release.mk | 9 +- build/make/release.sh | 156 ++++------------- build/make/release_functions.sh | 220 ++++++++++++++++++++++++ build/make/self-update.mk | 4 +- build/make/static-analysis.mk | 66 +++++-- build/make/test-common.mk | 8 +- build/make/test-integration.mk | 19 +- build/make/test-unit.mk | 8 +- build/make/variables.mk | 47 ++++- build/make/yarn.mk | 6 +- 31 files changed, 818 insertions(+), 238 deletions(-) create mode 100644 build/make/bats.mk create mode 100644 build/make/bats/Dockerfile create mode 100755 build/make/bats/customBatsEntrypoint.sh delete mode 100644 build/make/dependencies-glide.mk delete mode 100644 build/make/dependencies-godep.mk delete mode 100644 build/make/info.mk create mode 100644 build/make/k8s-controller.mk create mode 100644 build/make/k8s-dogu.mk create mode 100644 build/make/k8s-dogu.tpl create mode 100644 build/make/k8s.mk create mode 100644 build/make/mockery.yaml create mode 100644 build/make/mocks.mk create mode 100755 build/make/release_functions.sh diff --git a/Makefile b/Makefile index b5203ce..c8ba249 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -MAKEFILES_VERSION=4.2.0 +MAKEFILES_VERSION=7.5.0 .DEFAULT_GOAL:=dogu-release diff --git a/build/make/bats.mk b/build/make/bats.mk new file mode 100644 index 0000000..ce1319c --- /dev/null +++ b/build/make/bats.mk @@ -0,0 +1,64 @@ +WORKSPACE=/workspace +BATS_LIBRARY_DIR=$(TARGET_DIR)/bats_libs +TESTS_DIR=$(WORKDIR)/batsTests +BASH_TEST_REPORT_DIR=$(TARGET_DIR)/shell_test_reports +BASH_TEST_REPORTS=$(BASH_TEST_REPORT_DIR)/TestReport-*.xml +BATS_ASSERT=$(BATS_LIBRARY_DIR)/bats-assert +BATS_MOCK=$(BATS_LIBRARY_DIR)/bats-mock +BATS_SUPPORT=$(BATS_LIBRARY_DIR)/bats-support +BATS_FILE=$(BATS_LIBRARY_DIR)/bats-file +BATS_BASE_IMAGE?=bats/bats +BATS_CUSTOM_IMAGE?=cloudogu/bats +BATS_TAG?=1.2.1 +BATS_DIR=build/make/bats +BATS_WORKDIR="${WORKDIR}"/"${BATS_DIR}" + +.PHONY unit-test-shell: +unit-test-shell: unit-test-shell-$(ENVIRONMENT) + +$(BATS_ASSERT): + @git clone --depth 1 https://github.com/bats-core/bats-assert $@ + +$(BATS_MOCK): + @git clone --depth 1 https://github.com/grayhemp/bats-mock $@ + +$(BATS_SUPPORT): + @git clone --depth 1 https://github.com/bats-core/bats-support $@ + +$(BATS_FILE): + @git clone --depth 1 https://github.com/bats-core/bats-file $@ + +$(BASH_SRC): + BASH_SRC:=$(shell find "${WORKDIR}" -type f -name "*.sh") + +${BASH_TEST_REPORT_DIR}: $(TARGET_DIR) + @mkdir -p $(BASH_TEST_REPORT_DIR) + +unit-test-shell-ci: $(BASH_SRC) $(BASH_TEST_REPORT_DIR) $(BATS_ASSERT) $(BATS_MOCK) $(BATS_SUPPORT) $(BATS_FILE) + @echo "Test shell units on CI server" + @make unit-test-shell-generic + +unit-test-shell-local: $(BASH_SRC) $(PASSWD) $(ETCGROUP) $(HOME_DIR) buildTestImage $(BASH_TEST_REPORT_DIR) $(BATS_ASSERT) $(BATS_MOCK) $(BATS_SUPPORT) $(BATS_FILE) + @echo "Test shell units locally (in Docker)" + @docker run --rm \ + -v $(HOME_DIR):/home/$(USER) \ + -v $(WORKDIR):$(WORKSPACE) \ + -w $(WORKSPACE) \ + --entrypoint="" \ + $(BATS_CUSTOM_IMAGE):$(BATS_TAG) \ + "${BATS_DIR}"/customBatsEntrypoint.sh make unit-test-shell-generic-no-junit + +unit-test-shell-generic: + @bats --formatter junit --output ${BASH_TEST_REPORT_DIR} ${TESTS_DIR} + +unit-test-shell-generic-no-junit: + @bats ${TESTS_DIR} + +.PHONY buildTestImage: +buildTestImage: + @echo "Build shell test container" + @cd $(BATS_WORKDIR) && docker build \ + --build-arg=BATS_BASE_IMAGE=${BATS_BASE_IMAGE} \ + --build-arg=BATS_TAG=${BATS_TAG} \ + -t ${BATS_CUSTOM_IMAGE}:${BATS_TAG} \ + . \ No newline at end of file diff --git a/build/make/bats/Dockerfile b/build/make/bats/Dockerfile new file mode 100644 index 0000000..f75afe1 --- /dev/null +++ b/build/make/bats/Dockerfile @@ -0,0 +1,7 @@ +ARG BATS_BASE_IMAGE +ARG BATS_TAG + +FROM ${BATS_BASE_IMAGE}:${BATS_TAG} + +# Make bash more findable by scripts and tests +RUN apk add make git bash \ No newline at end of file diff --git a/build/make/bats/customBatsEntrypoint.sh b/build/make/bats/customBatsEntrypoint.sh new file mode 100755 index 0000000..58856fe --- /dev/null +++ b/build/make/bats/customBatsEntrypoint.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash +set -o errexit +set -o nounset +set -o pipefail + +"$@" \ No newline at end of file diff --git a/build/make/bower.mk b/build/make/bower.mk index 1289b70..a2c76a9 100644 --- a/build/make/bower.mk +++ b/build/make/bower.mk @@ -1,7 +1,9 @@ +##@ Bower dependency management + BOWER_JSON=$(WORKDIR)/bower.json .PHONY: bower-install -bower-install: $(BOWER_TARGET) +bower-install: $(BOWER_TARGET) ## Execute yarn run bower (in Docker) ifeq ($(ENVIRONMENT), ci) @@ -19,7 +21,7 @@ $(BOWER_TARGET): $(BOWER_JSON) $(PASSWD) $(YARN_TARGET) -v $(PASSWD):/etc/passwd:ro \ -v $(WORKDIR):$(WORKDIR) \ -w $(WORKDIR) \ - node:8 \ + node:$(NODE_VERSION) \ yarn run bower @touch $@ diff --git a/build/make/build.mk b/build/make/build.mk index a024856..b102149 100644 --- a/build/make/build.mk +++ b/build/make/build.mk @@ -1,16 +1,20 @@ +##@ Compiling go software + ADDITIONAL_LDFLAGS?=-extldflags -static LDFLAGS?=-ldflags "$(ADDITIONAL_LDFLAGS) -X main.Version=$(VERSION) -X main.CommitID=$(COMMIT_ID)" -GOIMAGE?=cloudogu/golang -GOTAG?=1.10.2-2 +GOIMAGE?=golang +GOTAG?=1.14.13 GOOS?=linux GOARCH?=amd64 PRE_COMPILE?= GO_ENV_VARS?= +CUSTOM_GO_MOUNT?=-v /tmp:/tmp +GO_BUILD_FLAGS?=-mod=vendor -a -tags netgo $(LDFLAGS) -installsuffix cgo -o $(BINARY) .PHONY: compile -compile: $(BINARY) +compile: $(BINARY) ## Compile the go program via Docker -compile-ci: +compile-ci: ## Compile the go program without Docker @echo "Compiling (CI)..." make compile-generic @@ -18,7 +22,7 @@ compile-generic: @echo "Compiling..." # here is go called without mod capabilities because of error "go: error loading module requirements" # see https://github.com/golang/go/issues/30868#issuecomment-474199640 - @$(GO_ENV_VARS) go build -a -tags netgo $(LDFLAGS) -installsuffix cgo -o $(BINARY) + @$(GO_ENV_VARS) go build $(GO_BUILD_FLAGS) ifeq ($(ENVIRONMENT), ci) @@ -29,17 +33,19 @@ $(BINARY): $(SRC) vendor $(PRE_COMPILE) else -$(BINARY): $(SRC) vendor $(PASSWD) $(HOME_DIR) $(PRE_COMPILE) +$(BINARY): $(SRC) vendor $(PASSWD) $(ETCGROUP) $(HOME_DIR) $(PRE_COMPILE) @echo "Building locally (in Docker)" @docker run --rm \ - -e GOOS=$(GOOS) \ - -e GOARCH=$(GOARCH) \ - -u "$(UID_NR):$(GID_NR)" \ - -v $(PASSWD):/etc/passwd:ro \ - -v $(HOME_DIR):/home/$(USER) \ - -v $(WORKDIR):/go/src/github.com/cloudogu/$(ARTIFACT_ID) \ - -w /go/src/github.com/cloudogu/$(ARTIFACT_ID) \ - $(GOIMAGE):$(GOTAG) \ + -e GOOS=$(GOOS) \ + -e GOARCH=$(GOARCH) \ + -u "$(UID_NR):$(GID_NR)" \ + -v $(PASSWD):/etc/passwd:ro \ + -v $(ETCGROUP):/etc/group:ro \ + -v $(HOME_DIR):/home/$(USER) \ + -v $(WORKDIR):/go/src/github.com/cloudogu/$(ARTIFACT_ID) \ + $(CUSTOM_GO_MOUNT) \ + -w /go/src/github.com/cloudogu/$(ARTIFACT_ID) \ + $(GOIMAGE):$(GOTAG) \ make compile-generic endif diff --git a/build/make/clean.mk b/build/make/clean.mk index 4f11678..119387f 100644 --- a/build/make/clean.mk +++ b/build/make/clean.mk @@ -1,10 +1,13 @@ +##@ Cleaning + .PHONY: clean -clean: $(ADDITIONAL_CLEAN) +clean: $(ADDITIONAL_CLEAN) ## Remove target and tmp directories rm -rf ${TARGET_DIR} rm -rf ${TMP_DIR} + rm -rf ${UTILITY_BIN_PATH} .PHONY: dist-clean -dist-clean: clean +dist-clean: clean ## Remove all generated directories rm -rf node_modules rm -rf public/vendor rm -rf vendor diff --git a/build/make/dependencies-glide.mk b/build/make/dependencies-glide.mk deleted file mode 100644 index 87eb43f..0000000 --- a/build/make/dependencies-glide.mk +++ /dev/null @@ -1,24 +0,0 @@ -GLIDE=$(GOPATH)/bin/glide -GLIDEFLAGS= -GLIDEHOME=$(GLIDE_HOME) - -ifeq ($(ENVIRONMENT), ci) - GLIDEFLAGS+=--no-color - GLIDEHOME=$(WORKDIR)/.glide_home - GLIDEFLAGS+= --home $(GLIDEHOME) -endif - -.PHONY: update-dependencies -update-dependencies: $(GLIDE) - -.PHONY: dependencies -dependencies: vendor - -vendor: $(GLIDE) glide.yaml glide.lock - @echo "Installing dependencies using Glide..." - $(GLIDE) $(GLIDEFLAGS) install -v - -$(GLIDE): - @echo "installing glide" - @curl https://glide.sh/get | sh - diff --git a/build/make/dependencies-godep.mk b/build/make/dependencies-godep.mk deleted file mode 100644 index 455a69d..0000000 --- a/build/make/dependencies-godep.mk +++ /dev/null @@ -1,10 +0,0 @@ -GODEP=$(GOPATH)/bin/dep - -$(GODEP): - @curl https://raw.githubusercontent.com/golang/dep/master/install.sh | sh - -vendor: $(GODEP) Gopkg.toml Gopkg.lock - @echo "Installing dependencies using go dep..." - @dep ensure - -dependencies: vendor diff --git a/build/make/dependencies-gomod.mk b/build/make/dependencies-gomod.mk index 1a71d6d..3b3b989 100644 --- a/build/make/dependencies-gomod.mk +++ b/build/make/dependencies-gomod.mk @@ -1,5 +1,7 @@ +##@ Go mod dependency management + .PHONY: dependencies -dependencies: vendor +dependencies: vendor ## Install dependencies using go mod vendor: go.mod go.sum @echo "Installing dependencies using go modules..." diff --git a/build/make/deploy-debian.mk b/build/make/deploy-debian.mk index 8427cd9..89b0fbe 100644 --- a/build/make/deploy-debian.mk +++ b/build/make/deploy-debian.mk @@ -1,3 +1,5 @@ +##@ Debian package deployment + # This Makefile holds all targets for deploying and undeploying # Uses the variable APT_REPO to determine which apt repos should be used to deploy @@ -21,11 +23,8 @@ ifeq ($(APT_REPO), ces-premium) @echo "... add package to ces-premium repository" @$(APTLY) -X POST "${APT_API_BASE_URL}/repos/ces-premium/file/$$(basename ${DEBIAN_PACKAGE})" else - @echo "... add package to ces and xenial repositories" - # heads up: For migration to a new repo structure we use two repos, new (ces) and old (xenial) - # '?noRemove=1': aptly removes the file on success. This leads to an error on the second package add. Keep it this round - @$(APTLY) -X POST "${APT_API_BASE_URL}/repos/ces/file/$$(basename ${DEBIAN_PACKAGE})?noRemove=1" - @$(APTLY) -X POST "${APT_API_BASE_URL}/repos/xenial/file/$$(basename ${DEBIAN_PACKAGE})" + @echo "\n... add package to ces repository" + @$(APTLY) -X POST "${APT_API_BASE_URL}/repos/ces/file/$$(basename ${DEBIAN_PACKAGE})" endif define aptly_publish @@ -34,17 +33,16 @@ endef .PHONY: publish publish: - @echo "... publish packages" + @echo "\n... publish packages" ifeq ($(APT_REPO), ces-premium) @$(call aptly_publish,ces-premium,bionic) else - @$(call aptly_publish,xenial,xenial) - @$(call aptly_publish,ces,xenial) + @$(call aptly_publish,ces,focal) @$(call aptly_publish,ces,bionic) endif .PHONY: deploy -deploy: add-package-to-repo publish +deploy: add-package-to-repo publish ## Deploy package to apt repository define aptly_undeploy PREF=$$(${APTLY} "${APT_API_BASE_URL}/repos/$(1)/packages?q=${ARTIFACT_ID}%20(${VERSION})"); \ @@ -56,13 +54,12 @@ remove-package-from-repo: ifeq ($(APT_REPO), ces-premium) @$(call aptly_undeploy,ces-premium) else - @$(call aptly_undeploy,xenial) @$(call aptly_undeploy,ces) endif .PHONY: undeploy -undeploy: deploy-check remove-package-from-repo publish +undeploy: deploy-check remove-package-from-repo publish ## Undeploy package from apt repository .PHONE: lint-deb-package -lint-deb-package: debian +lint-deb-package: debian ## Lint debian package @lintian -i $(DEBIAN_PACKAGE) diff --git a/build/make/digital-signature.mk b/build/make/digital-signature.mk index dd005fd..c0eba35 100644 --- a/build/make/digital-signature.mk +++ b/build/make/digital-signature.mk @@ -1,7 +1,9 @@ +##@ Digital signatures + CHECKSUM=$(TARGET_DIR)/$(ARTIFACT_ID).sha256sum .PHONY: checksum -checksum: $(CHECKSUM) +checksum: $(CHECKSUM) ## Generate checksums # we have to depend on target dir, because we want to rebuild the checksum # if one of the artefacts was changed $(CHECKSUM): $(TARGET_DIR) @@ -11,7 +13,12 @@ $(CHECKSUM): $(TARGET_DIR) SIGNATURE=$(CHECKSUM).asc .PHONY: signature -signature: $(SIGNATURE) +signature: $(SIGNATURE) ## Generate signature $(SIGNATURE): $(CHECKSUM) @echo "Generating Signature" @gpg --batch --yes --detach-sign --armor -o $@ $< + +.PHONY: signature-ci +signature-ci: $(CHECKSUM) + @echo "Generating Signature" + @gpg2 --batch --pinentry-mode loopback --passphrase="${passphrase}" --yes --detach-sign --armor -o ${SIGNATURE} $< diff --git a/build/make/info.mk b/build/make/info.mk deleted file mode 100644 index e402a37..0000000 --- a/build/make/info.mk +++ /dev/null @@ -1,8 +0,0 @@ -.PHONY: info -info: - @echo "dumping build information ..." - @echo "Version : $(VERSION)" - @echo "Commit-ID : $(COMMIT_ID)" - @echo "Environment: $(ENVIRONMENT)" - @echo "Branch : $(BRANCH)" - @echo "Packages : $(PACKAGES)" diff --git a/build/make/k8s-controller.mk b/build/make/k8s-controller.mk new file mode 100644 index 0000000..5735f00 --- /dev/null +++ b/build/make/k8s-controller.mk @@ -0,0 +1,96 @@ +# This script can be used to build and deploy kubernetes controllers. It is required to implement the controller +# specific targets `manifests` and `generate`: +# +# Examples: +# +#.PHONY: manifests +#manifests: controller-gen ## Generate WebhookConfiguration, ClusterRole and CustomResourceDefinition objects. +# @echo "Generate manifests..." +# @$(CONTROLLER_GEN) rbac:roleName=manager-role crd webhook paths="./..." output:crd:artifacts:config=config/crd/bases +# +#.PHONY: generate +#generate: controller-gen ## Generate code containing DeepCopy, DeepCopyInto, and DeepCopyObject method implementations. +# @echo "Auto-generate deepcopy functions..." +# @$(CONTROLLER_GEN) object:headerFile="hack/boilerplate.go.txt" paths="./..." + +# This script requires the k8s.mk script +include $(WORKDIR)/build/make/k8s.mk + +## Variables + +# Setting SHELL to bash allows bash commands to be executed by recipes. +# This is a requirement for 'setup-envtest.sh' in the test target. +# Options are set to exit when a recipe line exits non-zero or a piped command fails. +SHELL = /usr/bin/env bash -o pipefail +.SHELLFLAGS = -ec + +# make sure to create a statically linked binary otherwise it may quit with +# "exec user process caused: no such file or directory" +GO_BUILD_FLAGS=-mod=vendor -a -tags netgo,osusergo $(LDFLAGS) -o $(BINARY) + +# remove DWARF symbol table and strip other symbols to shave ~13 MB from binary +ADDITIONAL_LDFLAGS=-extldflags -static -w -s + +# ENVTEST_K8S_VERSION refers to the version of kubebuilder assets to be downloaded by envtest binary. +ENVTEST_K8S_VERSION = 1.23 +K8S_INTEGRATION_TEST_DIR=${TARGET_DIR}/k8s-integration-test + +##@ K8s - EcoSystem + +.PHONY: build +build: image-import k8s-apply ## Builds a new version of the dogu and deploys it into the K8s-EcoSystem. + +##@ Release + +.PHONY: controller-release +controller-release: ## Interactively starts the release workflow. + @echo "Starting git flow release..." + @build/make/release.sh controller-tool + +##@ K8s - Development + +.PHONY: build-controller +build-controller: ${SRC} compile ## Builds the controller Go binary. + +# Allows to perform tasks before locally running the controller +K8S_RUN_PRE_TARGETS ?= +.PHONY: run +run: manifests generate $(K8S_RUN_PRE_TARGETS) ## Run a controller from your host. + go run -ldflags "-X main.Version=$(VERSION)" ./main.go + +##@ K8s - Integration test with envtest + +$(K8S_INTEGRATION_TEST_DIR): + @mkdir -p $@ + +.PHONY: k8s-integration-test +k8s-integration-test: $(K8S_INTEGRATION_TEST_DIR) manifests generate envtest ## Run k8s integration tests. + @echo "Running K8s integration tests..." + @KUBEBUILDER_ASSETS="$(shell $(ENVTEST) use $(ENVTEST_K8S_VERSION) -p path)" go test -tags=k8s_integration ./... -coverprofile ${K8S_INTEGRATION_TEST_DIR}/report-k8s-integration.out + +##@ K8s - Controller Resource + +# The pre generation script creates a K8s resource yaml containing generated manager yaml. +.PHONY: k8s-create-temporary-resource + k8s-create-temporary-resource: $(K8S_RESOURCE_TEMP_FOLDER) manifests kustomize + @echo "Generating temporary k8s resources $(K8S_RESOURCE_TEMP_YAML)..." + cd $(WORKDIR)/config/manager && $(KUSTOMIZE) edit set image controller=$(IMAGE) + $(KUSTOMIZE) build config/default > $(K8S_RESOURCE_TEMP_YAML) + @echo "Done." + +##@ K8s - Download Kubernetes Utility Tools + +CONTROLLER_GEN = $(UTILITY_BIN_PATH)/controller-gen +.PHONY: controller-gen +controller-gen: ## Download controller-gen locally if necessary. + $(call go-get-tool,$(CONTROLLER_GEN),sigs.k8s.io/controller-tools/cmd/controller-gen@v0.11.3) + +KUSTOMIZE = $(UTILITY_BIN_PATH)/kustomize +.PHONY: kustomize +kustomize: ## Download kustomize locally if necessary. + $(call go-get-tool,$(KUSTOMIZE),sigs.k8s.io/kustomize/kustomize/v4@v4.5.7) + +ENVTEST = $(UTILITY_BIN_PATH)/setup-envtest +.PHONY: envtest +envtest: ## Download envtest-setup locally if necessary. + $(call go-get-tool,$(ENVTEST),sigs.k8s.io/controller-runtime/tools/setup-envtest@latest) \ No newline at end of file diff --git a/build/make/k8s-dogu.mk b/build/make/k8s-dogu.mk new file mode 100644 index 0000000..ff0973b --- /dev/null +++ b/build/make/k8s-dogu.mk @@ -0,0 +1,44 @@ +# Variables +# Path to the dogu json of the dogu +DOGU_JSON_FILE=$(WORKDIR)/dogu.json +DOGU_JSON_DEV_FILE=${TARGET_DIR}/dogu.json +# Name of the dogu is extracted from the dogu.json +ARTIFACT_ID=$(shell $(BINARY_YQ) -e ".Name" $(DOGU_JSON_FILE) | sed "s|.*/||g") +# Namespace of the dogu is extracted from the dogu.json +ARTIFACT_NAMESPACE=$(shell $(BINARY_YQ) -e ".Name" $(DOGU_JSON_FILE) | sed "s|/.*||g") +# Namespace of the dogu is extracted from the dogu.json +VERSION=$(shell $(BINARY_YQ) -e ".Version" $(DOGU_JSON_FILE)) +# Image of the dogu is extracted from the dogu.json +IMAGE=$(shell $(BINARY_YQ) -e ".Image" $(DOGU_JSON_FILE)):$(VERSION) +IMAGE_DEV_WITHOUT_TAG=$(shell $(BINARY_YQ) -e ".Image" $(DOGU_JSON_FILE) | sed "s|registry\.cloudogu\.com\(.\+\)|${K3CES_REGISTRY_URL_PREFIX}\1|g") +IMAGE_DEV=${IMAGE_DEV_WITHOUT_TAG}:${VERSION} + +include $(WORKDIR)/build/make/k8s.mk + +##@ K8s - EcoSystem + +.PHONY: build +build: image-import install-dogu-descriptor k8s-apply ## Builds a new version of the dogu and deploys it into the K8s-EcoSystem. + +##@ K8s - Dogu - Resource + +# The additional k8s yaml files +K8S_RESOURCE_PRODUCTIVE_FOLDER ?= $(WORKDIR)/k8s +K8S_RESOURCE_PRODUCTIVE_YAML ?= $(K8S_RESOURCE_PRODUCTIVE_FOLDER)/$(ARTIFACT_ID).yaml +K8S_RESOURCE_DOGU_CR_TEMPLATE_YAML ?= $(WORKDIR)/build/make/k8s-dogu.tpl +# The pre generation script creates a k8s resource yaml containing the dogu crd and the content from the k8s folder. +.PHONY: k8s-create-temporary-resource + k8s-create-temporary-resource: ${BINARY_YQ} $(K8S_RESOURCE_TEMP_FOLDER) + @echo "Generating temporary K8s resources $(K8S_RESOURCE_TEMP_YAML)..." + @rm -f $(K8S_RESOURCE_TEMP_YAML) + @sed "s|NAMESPACE|$(ARTIFACT_NAMESPACE)|g" $(K8S_RESOURCE_DOGU_CR_TEMPLATE_YAML) | sed "s|NAME|$(ARTIFACT_ID)|g" | sed "s|VERSION|$(VERSION)|g" >> $(K8S_RESOURCE_TEMP_YAML) + @echo "Done." + +##@ K8s - Dogu + +.PHONY: install-dogu-descriptor +install-dogu-descriptor: ${BINARY_YQ} $(TARGET_DIR) ## Installs a configmap with current dogu.json into the cluster. + @echo "Generate configmap from dogu.json..." + @$(BINARY_YQ) ".Image=\"${IMAGE_DEV_WITHOUT_TAG}\"" ${DOGU_JSON_FILE} > ${DOGU_JSON_DEV_FILE} + @kubectl create configmap "$(ARTIFACT_ID)-descriptor" --from-file=$(DOGU_JSON_DEV_FILE) --dry-run=client -o yaml | kubectl apply -f - --namespace=${NAMESPACE} + @echo "Done." diff --git a/build/make/k8s-dogu.tpl b/build/make/k8s-dogu.tpl new file mode 100644 index 0000000..44cd9cf --- /dev/null +++ b/build/make/k8s-dogu.tpl @@ -0,0 +1,9 @@ +apiVersion: k8s.cloudogu.com/v1 +kind: Dogu +metadata: + name: NAME + labels: + dogu: NAME +spec: + name: NAMESPACE/NAME + version: VERSION \ No newline at end of file diff --git a/build/make/k8s.mk b/build/make/k8s.mk new file mode 100644 index 0000000..8e0fa4a --- /dev/null +++ b/build/make/k8s.mk @@ -0,0 +1,119 @@ +# This file is optional and can be used to set personal information without committing them to the repository. +MY_ENV_FILE ?= $(WORKDIR)/.env +ifneq (,$(wildcard $(MY_ENV_FILE))) + include .env +endif + +## Variables + +BINARY_YQ = $(UTILITY_BIN_PATH)/yq + +# The productive tag of the image +IMAGE ?= + +K3S_CLUSTER_FQDN?=k3ces.local +K3S_LOCAL_REGISTRY_PORT?=30099 +K3CES_REGISTRY_URL_PREFIX="${K3S_CLUSTER_FQDN}:${K3S_LOCAL_REGISTRY_PORT}" + +# Variables for the temporary yaml files. These are used as template to generate a development resource containing +# the current namespace and the dev image. +K8S_RESOURCE_TEMP_FOLDER ?= $(TARGET_DIR)/make/k8s +K8S_RESOURCE_TEMP_YAML ?= $(K8S_RESOURCE_TEMP_FOLDER)/$(ARTIFACT_ID)_$(VERSION).yaml + +##@ K8s - Variables + +.PHONY: check-all-vars +check-all-vars: check-k8s-image-env-var check-k8s-artifact-id check-etc-hosts check-insecure-cluster-registry check-k8s-namespace-env-var ## Conduct a sanity check against selected build artefacts or local environment + +.PHONY: check-k8s-namespace-env-var +check-k8s-namespace-env-var: + @$(call check_defined, NAMESPACE, k8s namespace) + +.PHONY: check-k8s-image-env-var +check-k8s-image-env-var: + @$(call check_defined, IMAGE, docker image tag) + +.PHONY: check-k8s-artifact-id +check-k8s-artifact-id: + @$(call check_defined, ARTIFACT_ID, app/dogu name) + +.PHONY: check-etc-hosts +check-etc-hosts: + @grep -E "^.+\s+${K3S_CLUSTER_FQDN}\$$" /etc/hosts > /dev/null || \ + (echo "Missing /etc/hosts entry for ${K3S_CLUSTER_FQDN}" && exit 1) + +.PHONY: check-insecure-cluster-registry +check-insecure-cluster-registry: + @grep "${K3CES_REGISTRY_URL_PREFIX}" /etc/docker/daemon.json > /dev/null || \ + (echo "Missing /etc/docker/daemon.json for ${K3CES_REGISTRY_URL_PREFIX}" && exit 1) + +##@ K8s - Resources + +${K8S_RESOURCE_TEMP_FOLDER}: + @mkdir -p $@ + +.PHONY: k8s-delete +k8s-delete: k8s-generate $(K8S_POST_GENERATE_TARGETS) ## Deletes all dogu related resources from the K8s cluster. + @echo "Delete old dogu resources..." + @kubectl delete -f $(K8S_RESOURCE_TEMP_YAML) --wait=false --ignore-not-found=true --namespace=${NAMESPACE} + +# The additional targets executed after the generate target, executed before each apply and delete. The generate target +# produces a temporary yaml. This yaml is accessible via K8S_RESOURCE_TEMP_YAML an can be changed before the apply/delete. +K8S_POST_GENERATE_TARGETS ?= +# The additional targets executed before the generate target, executed before each apply and delete. +K8S_PRE_GENERATE_TARGETS ?= k8s-create-temporary-resource + +.PHONY: k8s-generate +k8s-generate: ${BINARY_YQ} $(K8S_RESOURCE_TEMP_FOLDER) $(K8S_PRE_GENERATE_TARGETS) ## Generates the final resource yaml. + @echo "Applying general transformations..." + @sed -i "s/'{{ .Namespace }}'/$(NAMESPACE)/" $(K8S_RESOURCE_TEMP_YAML) + @$(BINARY_YQ) -i e "(select(.kind == \"Deployment\").spec.template.spec.containers[]|select(.image == \"*$(ARTIFACT_ID)*\").image)=\"$(IMAGE_DEV)\"" $(K8S_RESOURCE_TEMP_YAML) + @echo "Done." + +.PHONY: k8s-apply +k8s-apply: k8s-generate $(K8S_POST_GENERATE_TARGETS) ## Applies all generated K8s resources to the current cluster and namespace. + @echo "Apply generated K8s resources..." + @kubectl apply -f $(K8S_RESOURCE_TEMP_YAML) --namespace=${NAMESPACE} + +##@ K8s - Docker + +.PHONY: docker-build +docker-build: check-k8s-image-env-var ## Builds the docker image of the K8s app. + @echo "Building docker image..." + DOCKER_BUILDKIT=1 docker build . -t $(IMAGE) + +.PHONY: docker-dev-tag +docker-dev-tag: check-k8s-image-dev-var docker-build ## Tags a Docker image for local K3ces deployment. + @echo "Tagging image with dev tag..." + DOCKER_BUILDKIT=1 docker tag ${IMAGE} ${IMAGE_DEV} + +.PHONY: check-k8s-image-dev-var +check-k8s-image-dev-var: +ifeq (${IMAGE_DEV},) + @echo "Missing make variable IMAGE_DEV detected. It should look like \$${K3CES_REGISTRY_URL_PREFIX}/docker-image:tag" + @exit 19 +endif + +.PHONY: image-import +image-import: check-all-vars check-k8s-artifact-id docker-dev-tag ## Imports the currently available image into the cluster-local registry. + @echo "Import ${IMAGE_DEV} into K8s cluster ${K3S_CLUSTER_FQDN}..." + @docker push ${IMAGE_DEV} + @echo "Done." + +## Functions + +# Check that given variables are set and all have non-empty values, +# die with an error otherwise. +# +# Params: +# 1. Variable name(s) to test. +# 2. (optional) Error message to print. +check_defined = \ + $(strip $(foreach 1,$1, \ + $(call __check_defined,$1,$(strip $(value 2))))) +__check_defined = \ + $(if $(value $1),, \ + $(error Undefined $1$(if $2, ($2)))) + +${BINARY_YQ}: $(UTILITY_BIN_PATH) ## Download controller-gen locally if necessary. + $(call go-get-tool,$(BINARY_YQ),github.com/mikefarah/yq/v4@v4.25.1) \ No newline at end of file diff --git a/build/make/mockery.yaml b/build/make/mockery.yaml new file mode 100644 index 0000000..67b4339 --- /dev/null +++ b/build/make/mockery.yaml @@ -0,0 +1,4 @@ +inpackage: True +testonly: True +with-expecter: True +keeptree: False \ No newline at end of file diff --git a/build/make/mocks.mk b/build/make/mocks.mk new file mode 100644 index 0000000..9e61b46 --- /dev/null +++ b/build/make/mocks.mk @@ -0,0 +1,27 @@ +##@ Mocking + +MOCKERY_BIN=${UTILITY_BIN_PATH}/mockery +MOCKERY_VERSION=v2.20.0 +MOCKERY_YAML=${WORKDIR}/.mockery.yaml + +${MOCKERY_BIN}: ${UTILITY_BIN_PATH} + $(call go-get-tool,$(MOCKERY_BIN),github.com/vektra/mockery/v2@$(MOCKERY_VERSION)) + +${MOCKERY_YAML}: + @cp ${WORKDIR}/build/make/mockery.yaml ${WORKDIR}/.mockery.yaml + +.PHONY: mocks +mocks: ${MOCKERY_BIN} ${MOCKERY_YAML} ## This target is used to generate mocks for all interfaces in a project. + @for dir in ${WORKDIR}/*/ ;\ + do \ + # removes trailing '/' \ + dir=$${dir%*/} ;\ + # removes everything before the last '/' \ + dir=$${dir##*/} ;\ + if ! echo '${MOCKERY_IGNORED}' | egrep -q "\b$${dir}\b" ;\ + then \ + echo "Creating mocks for $${dir}" ;\ + ${MOCKERY_BIN} --all --dir $${dir} ;\ + fi ;\ + done ; + @echo "Mocks successfully created." diff --git a/build/make/package-debian.mk b/build/make/package-debian.mk index 168e8e2..ad55ea1 100644 --- a/build/make/package-debian.mk +++ b/build/make/package-debian.mk @@ -1,3 +1,5 @@ +##@ Debian packaging + # This Makefile holds all targets for building a debian package # For deployment of the deb package include the deploy-debian.mk! @@ -8,10 +10,10 @@ CONFFILES_FILE_TMP="$(DEBIAN_CONTENT_DIR)/conffiles_" DEBSRC:=$(shell find "${WORKDIR}/deb" -type f) .PHONY: package -package: debian-with-binary +package: debian-with-binary ## Build binary and package into .deb file .PHONY: debian -debian: $(DEBIAN_PACKAGE) +debian: $(DEBIAN_PACKAGE) ## Create .deb package without building the binary before .PHONY: debian-with-binary debian-with-binary: $(BINARY) $(DEBIAN_PACKAGE) diff --git a/build/make/package-tar.mk b/build/make/package-tar.mk index 307212f..9b842a3 100644 --- a/build/make/package-tar.mk +++ b/build/make/package-tar.mk @@ -1,7 +1,9 @@ +##@ Tar packaging + TAR_PACKAGE:=$(ARTIFACT_ID)-$(VERSION).tar.gz .PHONY: package -package: $(TAR_PACKAGE) +package: $(TAR_PACKAGE) ## Build binary and create tar package from it $(TAR_PACKAGE): $(BINARY) # Check owner and group id diff --git a/build/make/release.mk b/build/make/release.mk index d8a5892..11dde9a 100644 --- a/build/make/release.mk +++ b/build/make/release.mk @@ -1,6 +1,11 @@ +##@ Releases + # This makefile holds the dogu-release target for starting a new dogu release .PHONY: dogu-release -dogu-release: - build/make/release.sh +dogu-release: ## Start a dogu release + build/make/release.sh dogu +.PHONY: go-release +go-release: ## Start a go tool release + build/make/release.sh go-tool \ No newline at end of file diff --git a/build/make/release.sh b/build/make/release.sh index 2d64cdd..4fd4569 100755 --- a/build/make/release.sh +++ b/build/make/release.sh @@ -3,132 +3,52 @@ set -o errexit set -o nounset set -o pipefail -wait_for_ok(){ - printf "\n" - OK=false - while [[ ${OK} != "ok" ]] ; do - read -r -p "${1} (type 'ok'): " OK - done -} - -ask_yes_or_no(){ - local ANSWER="" - - while [ "${ANSWER}" != "y" ] && [ "${ANSWER}" != "n" ]; do - read -r -p "${1} (type 'y/n'): " ANSWER - done - - echo "${ANSWER}" -} - -# dogu.json will always exist. So get current dogu version from dogu.json. -CURRENT_DOGU_VERSION=$(jq ".Version" --raw-output dogu.json) - -# Enter the target version -read -r -p "Current Version is v${CURRENT_DOGU_VERSION}. Please provide the new version: v" NEW_RELEASE_VERSION - -# Validate that release version does not start with vv -if [[ ${NEW_RELEASE_VERSION} = v* ]]; then - echo "WARNING: The new release version (v${NEW_RELEASE_VERSION}) starts with 'vv'." - echo "You must not enter the v when defining the new version." - ANSWER=$(ask_yes_or_no "Should the first v be removed?") - if [ "${ANSWER}" == "y" ]; then - NEW_RELEASE_VERSION="${NEW_RELEASE_VERSION:1}" - echo "Release version now is: ${NEW_RELEASE_VERSION}" +# Extension points in release.sh: +# +# A custom release argument file will be sourced if found. The custom release arg file may implement one or more bash +# functions which either release.sh or release_functions.sh define. If such a custom release function is found the +# release script must define the argument list which the custom release function will receive during the release. + +sourceCustomReleaseArgs() { + RELEASE_ARGS_FILE="${1}" + + if [[ -f "${RELEASE_ARGS_FILE}" ]]; then + echo "Using custom release args file ${RELEASE_ARGS_FILE}" + + sourceCustomReleaseExitCode=0 + # shellcheck disable=SC1090 + source "${RELEASE_ARGS_FILE}" || sourceCustomReleaseExitCode=$? + if [[ ${sourceCustomReleaseExitCode} -ne 0 ]]; then + echo "Error while sourcing custom release arg file ${sourceCustomReleaseExitCode}. Exiting." + exit 9 + fi fi -fi; - -# Do gitflow -git flow init -df -git checkout master -git pull origin master -git checkout develop -git pull origin develop -git flow release start v"${NEW_RELEASE_VERSION}" - -# Update version in dogu.json -jq ".Version = \"${NEW_RELEASE_VERSION}\"" dogu.json > dogu2.json && mv dogu2.json dogu.json -# Update version in Dockerfile -sed -i "s/\(^[ ]*VERSION=\"\)\([^\"]*\)\(.*$\)/\1${NEW_RELEASE_VERSION}\3/" Dockerfile -# Update version in Makefile -if [ -f "Makefile" ]; then - sed -i "s/\(^VERSION=\)\(.*\)$/\1${NEW_RELEASE_VERSION}/" Makefile -fi -# Update version in package.json -if [ -f "package.json" ]; then - jq ".version = \"${NEW_RELEASE_VERSION}\"" package.json > package2.json && mv package2.json package.json -fi -# Update version in pom.xml -if [ -f "pom.xml" ]; then - echo "Updating version in pom.xml..." - mvn versions:set -DgenerateBackupPoms=false -DnewVersion="${NEW_RELEASE_VERSION}" -fi - - -# Commit changes to version -wait_for_ok "Please make sure that all versions have been updated correctly now (e.g. via \"git diff\")." -git add Dockerfile -git add dogu.json -if [ -f "Makefile" ]; then - git add Makefile -fi -if [ -f "package.json" ]; then - git add package.json -fi -if [ -f "pom.xml" ]; then - git add pom.xml -fi -git commit -m "Bump version" +} -# Changelog update -CURRENT_DATE=$(date --rfc-3339=date) -NEW_CHANGELOG_TITLE="## [v${NEW_RELEASE_VERSION}] - ${CURRENT_DATE}" -# Check if "Unreleased" tag exists -while ! grep --silent "## \[Unreleased\]" CHANGELOG.md; do - echo "" - echo -e "\e[31mYour CHANGELOG.md does not contain a \"## [Unreleased]\" line!\e[0m" - echo "Please add one to make it comply to https://keepachangelog.com/en/1.0.0/" - wait_for_ok "Please insert a \"## [Unreleased]\" line into CHANGELOG.md now." -done +PROJECT_DIR="$(pwd)" +RELEASE_ARGS_FILE="${PROJECT_DIR}/release_args.sh" -# Add new title line to changelog -sed -i "s|## \[Unreleased\]|## \[Unreleased\]\n\n${NEW_CHANGELOG_TITLE}|g" CHANGELOG.md +sourceCustomReleaseArgs "${RELEASE_ARGS_FILE}" -# Wait for user to validate changelog changes -wait_for_ok "Please make sure your CHANGELOG.md looks as desired." +source "$(pwd)/build/make/release_functions.sh" -# Check if new version tag still exists -while ! grep --silent "## \[v${NEW_RELEASE_VERSION}\] - ${CURRENT_DATE}" CHANGELOG.md; do - echo "" - echo -e "\e[31mYour CHANGELOG.md does not contain \"${NEW_CHANGELOG_TITLE}\"!\e[0m" - wait_for_ok "Please update your CHANGELOG.md now." -done +TYPE="${1}" -git add CHANGELOG.md -git commit -m "Update changelog" +echo "=====Starting Release process=====" -if ! git diff --exit-code > /dev/null; then - echo "There are still uncommitted changes:" - echo "" - echo "# # # # # # # # # #" - echo "" - git --no-pager diff - echo "" - echo "# # # # # # # # # #" +if [ "${TYPE}" == "dogu" ];then + CURRENT_TOOL_VERSION=$(get_current_version_by_dogu_json) +else + CURRENT_TOOL_VERSION=$(get_current_version_by_makefile) fi -echo "All changes compared to develop branch:" -echo "" -echo "# # # # # # # # # #" -echo "" -git --no-pager diff develop -echo "" -echo "# # # # # # # # # #" +NEW_RELEASE_VERSION="$(read_new_version)" -# Push changes and delete release branch -wait_for_ok "Dogu upgrade from version v${CURRENT_DOGU_VERSION} to version v${NEW_RELEASE_VERSION} finished. Should the changes be pushed?" -git push origin release/v"${NEW_RELEASE_VERSION}" +validate_new_version "${NEW_RELEASE_VERSION}" +start_git_flow_release "${NEW_RELEASE_VERSION}" +update_versions "${NEW_RELEASE_VERSION}" +update_changelog "${NEW_RELEASE_VERSION}" +show_diff +finish_release_and_push "${CURRENT_TOOL_VERSION}" "${NEW_RELEASE_VERSION}" -echo "Switching back to develop and deleting branch release/v${NEW_RELEASE_VERSION}..." -git checkout develop -git branch -D release/v"${NEW_RELEASE_VERSION}" +echo "=====Finished Release process=====" diff --git a/build/make/release_functions.sh b/build/make/release_functions.sh new file mode 100755 index 0000000..528806b --- /dev/null +++ b/build/make/release_functions.sh @@ -0,0 +1,220 @@ +#!/bin/bash +set -o errexit +set -o nounset +set -o pipefail + +wait_for_ok(){ + printf "\n" + OK=false + while [[ ${OK} != "ok" ]] ; do + read -r -p "${1} (type 'ok'): " OK + done +} + +ask_yes_or_no(){ + local ANSWER="" + + while [ "${ANSWER}" != "y" ] && [ "${ANSWER}" != "n" ]; do + read -r -p "${1} (type 'y/n'): " ANSWER + done + + echo "${ANSWER}" +} + +get_current_version_by_makefile(){ + grep '^VERSION=[0-9[:alpha:].-]*$' Makefile | sed s/VERSION=//g +} + +get_current_version_by_dogu_json(){ + jq ".Version" --raw-output dogu.json +} + +read_new_version(){ + local NEW_RELEASE_VERSION + read -r -p "Current Version is v${CURRENT_TOOL_VERSION}. Please provide the new version: v" NEW_RELEASE_VERSION + echo "${NEW_RELEASE_VERSION}" +} + +validate_new_version(){ + local NEW_RELEASE_VERSION="${1}" + # Validate that release version does not start with vv + if [[ ${NEW_RELEASE_VERSION} = v* ]]; then + echo "WARNING: The new release version (v${NEW_RELEASE_VERSION}) starts with 'vv'." + echo "You must not enter the v when defining the new version." + ANSWER=$(ask_yes_or_no "Should the first v be removed?") + if [ "${ANSWER}" == "y" ]; then + NEW_RELEASE_VERSION="${NEW_RELEASE_VERSION:1}" + echo "Release version now is: ${NEW_RELEASE_VERSION}" + fi + fi; +} + +start_git_flow_release(){ + local NEW_RELEASE_VERSION="${1}" + # Do gitflow + git flow init --defaults --force + + mainBranchExists="$(git show-ref refs/remotes/origin/main || echo "")" + if [ -n "$mainBranchExists" ]; then + echo 'Using "main" branch for production releases' + git flow config set master main + git checkout main + git pull origin main + else + echo 'Using "master" branch for production releases' + git checkout master + git pull origin master + fi + + git checkout develop + git pull origin develop + git flow release start v"${NEW_RELEASE_VERSION}" +} + +# update_versions updates files with the new release version and interactively asks the user for verification. If okay +# the updated files will be staged to git and finally committed. +# +# extension points: +# - update_versions_modify_files - update a file with the new version number +# - update_versions_stage_modified_files - stage a modified file to prepare the file for the up-coming commit +update_versions(){ + local NEW_RELEASE_VERSION="${1}" + + if [[ $(type -t update_versions_modify_files) == function ]]; then + preSkriptExitCode=0 + update_versions_modify_files "${NEW_RELEASE_VERSION}" || preSkriptExitCode=$? + if [[ ${preSkriptExitCode} -ne 0 ]]; then + echo "ERROR: custom update_versions_modify_files() exited with exit code ${preSkriptExitCode}" + exit 1 + fi + fi + + # Update version in dogu.json + if [ -f "dogu.json" ]; then + echo "Updating version in dogu.json..." + jq ".Version = \"${NEW_RELEASE_VERSION}\"" dogu.json > dogu2.json && mv dogu2.json dogu.json + fi + + # Update version in Dockerfile + if [ -f "Dockerfile" ]; then + echo "Updating version in Dockerfile..." + sed -i "s/\(^[ ]*VERSION=\"\)\([^\"]*\)\(.*$\)/\1${NEW_RELEASE_VERSION}\3/" Dockerfile + fi + + # Update version in Makefile + if [ -f "Makefile" ]; then + echo "Updating version in Makefile..." + sed -i "s/\(^VERSION=\)\(.*\)$/\1${NEW_RELEASE_VERSION}/" Makefile + fi + + # Update version in package.json + if [ -f "package.json" ]; then + echo "Updating version in package.json..." + jq ".version = \"${NEW_RELEASE_VERSION}\"" package.json > package2.json && mv package2.json package.json + fi + + # Update version in pom.xml + if [ -f "pom.xml" ]; then + echo "Updating version in pom.xml..." + mvn versions:set -DgenerateBackupPoms=false -DnewVersion="${NEW_RELEASE_VERSION}" + fi + + wait_for_ok "Please make sure that all versions have been updated correctly now (e.g. via \"git diff\")." + + ### The `git add` command has to be after the okay. Otherwise user-made changes to versions would not be added. + + if [[ $(type -t update_versions_stage_modified_files) == function ]]; then + preSkriptExitCode=0 + update_versions_stage_modified_files "${NEW_RELEASE_VERSION}" || preSkriptExitCode=$? + if [[ ${preSkriptExitCode} -ne 0 ]]; then + echo "ERROR: custom update_versions_stage_modified_files exited with exit code ${preSkriptExitCode}" + exit 1 + fi + fi + + if [ -f "dogu.json" ]; then + git add dogu.json + fi + + if [ -f "Dockerfile" ]; then + git add Dockerfile + fi + + if [ -f "Makefile" ]; then + git add Makefile + fi + + if [ -f "package.json" ]; then + git add package.json + fi + + if [ -f "pom.xml" ]; then + git add pom.xml + fi + + git commit -m "Bump version" +} + +update_changelog(){ + local NEW_RELEASE_VERSION="${1}" + + # Changelog update + CURRENT_DATE=$(date --rfc-3339=date) + NEW_CHANGELOG_TITLE="## [v${NEW_RELEASE_VERSION}] - ${CURRENT_DATE}" + # Check if "Unreleased" tag exists + while ! grep --silent "## \[Unreleased\]" CHANGELOG.md; do + echo "" + echo -e "\e[31mYour CHANGELOG.md does not contain a \"## [Unreleased]\" line!\e[0m" + echo "Please add one to make it comply to https://keepachangelog.com/en/1.0.0/" + wait_for_ok "Please insert a \"## [Unreleased]\" line into CHANGELOG.md now." + done + + # Add new title line to changelog + sed -i "s|## \[Unreleased\]|## \[Unreleased\]\n\n${NEW_CHANGELOG_TITLE}|g" CHANGELOG.md + + # Wait for user to validate changelog changes + wait_for_ok "Please make sure your CHANGELOG.md looks as desired." + + # Check if new version tag still exists + while ! grep --silent "## \[v${NEW_RELEASE_VERSION}\] - ${CURRENT_DATE}" CHANGELOG.md; do + echo "" + echo -e "\e[31mYour CHANGELOG.md does not contain \"${NEW_CHANGELOG_TITLE}\"!\e[0m" + wait_for_ok "Please update your CHANGELOG.md now." + done + + git add CHANGELOG.md + git commit -m "Update changelog" +} + +show_diff(){ + if ! git diff --exit-code > /dev/null; then + echo "There are still uncommitted changes:" + echo "" + echo "# # # # # # # # # #" + echo "" + git --no-pager diff + echo "" + echo "# # # # # # # # # #" + fi + + echo "All changes compared to develop branch:" + echo "" + echo "# # # # # # # # # #" + echo "" + git --no-pager diff develop + echo "" + echo "# # # # # # # # # #" +} + +finish_release_and_push(){ + local CURRENT_VERSION="${1}" + local NEW_RELEASE_VERSION="${2}" + + # Push changes and delete release branch + wait_for_ok "Upgrade from version v${CURRENT_VERSION} to version v${NEW_RELEASE_VERSION} finished. Should the changes be pushed?" + git push origin release/v"${NEW_RELEASE_VERSION}" + + echo "Switching back to develop and deleting branch release/v${NEW_RELEASE_VERSION}..." + git checkout develop + git branch -D release/v"${NEW_RELEASE_VERSION}" +} diff --git a/build/make/self-update.mk b/build/make/self-update.mk index 8eaa807..175f8a6 100644 --- a/build/make/self-update.mk +++ b/build/make/self-update.mk @@ -1,5 +1,7 @@ +##@ Makefile management + .PHONY: update-makefiles -update-makefiles: do-update-makefiles +update-makefiles: do-update-makefiles ## Update Makefiles to MAKEFILES_VERSION .PHONY: do-update-makefiles do-update-makefiles: $(TMP_DIR) download-and-extract remove-old-files copy-new-files diff --git a/build/make/static-analysis.mk b/build/make/static-analysis.mk index f64bd78..70e6468 100644 --- a/build/make/static-analysis.mk +++ b/build/make/static-analysis.mk @@ -1,36 +1,66 @@ +##@ Static analysis + STATIC_ANALYSIS_DIR=$(TARGET_DIR)/static-analysis +GOIMAGE?=golang +GOTAG?=1.18 +CUSTOM_GO_MOUNT?=-v /tmp:/tmp -LINT=$(GOPATH)/bin/golangci-lint +REVIEW_DOG=$(TMP_DIR)/bin/reviewdog +LINT=$(TMP_DIR)/bin/golangci-lint +LINT_VERSION?=v1.49.0 # ignore tests and mocks -LINTFLAGS=--tests=false --skip-files="^.*_mock.go$$" --skip-files="^.*/mock.*.go$$" +LINTFLAGS=--tests=false --skip-files="^.*_mock.go$$" --skip-files="^.*/mock.*.go$$" --timeout 10m --issues-exit-code 0 +ADDITIONAL_LINTER=-E bodyclose -E containedctx -E contextcheck -E decorder -E dupl -E errname -E forcetypeassert -E funlen -E unparam .PHONY: static-analysis -static-analysis: $(GOPATH)/bin/reviewdog static-analysis-$(ENVIRONMENT) +static-analysis: static-analysis-$(ENVIRONMENT) ## Start a static analysis of the code .PHONY: static-analysis-ci -static-analysis-ci: $(STATIC_ANALYSIS_DIR)/static-analysis-cs.log $(STATIC_ANALYSIS_DIR)/static-analysis.log - @if [ X"$(CI_PULL_REQUEST)" != X"" -a X"$(CI_PULL_REQUEST)" != X"null" ] ; then cat $< | CI_COMMIT=$(COMMIT_ID) reviewdog -f=checkstyle -reporter="github-pr-review"; fi +static-analysis-ci: + @make $(STATIC_ANALYSIS_DIR)/static-analysis-cs.log $(STATIC_ANALYSIS_DIR)/static-analysis.log static-analysis-ci-report-pr + +static-analysis-ci-report-pr: $(REVIEW_DOG) + @if [ X"$(CI_PULL_REQUEST)" != X"" -a X"$(CI_PULL_REQUEST)" != X"null" ] ; then \ + cat $(STATIC_ANALYSIS_DIR)/static-analysis-cs.log | CI_COMMIT=$(COMMIT_ID) $(REVIEW_DOG) -f=checkstyle -reporter="github-pr-review"; \ + fi .PHONY: static-analysis-local -static-analysis-local: $(STATIC_ANALYSIS_DIR)/static-analysis-cs.log $(STATIC_ANALYSIS_DIR)/static-analysis.log +static-analysis-local: $(PASSWD) $(ETCGROUP) $(HOME_DIR) + @docker run --rm \ + -e GOOS=$(GOOS) \ + -e GOARCH=$(GOARCH) \ + -u "$(UID_NR):$(GID_NR)" \ + -v $(PASSWD):/etc/passwd:ro \ + -v $(ETCGROUP):/etc/group:ro \ + -v $(HOME_DIR):/home/$(USER) \ + -v $(WORKDIR):/go/src/github.com/cloudogu/$(ARTIFACT_ID) \ + $(CUSTOM_GO_MOUNT) \ + -w /go/src/github.com/cloudogu/$(ARTIFACT_ID) \ + $(GOIMAGE):$(GOTAG) \ + make $(STATIC_ANALYSIS_DIR)/static-analysis-cs.log $(STATIC_ANALYSIS_DIR)/static-analysis.log static-analysis-ci-report-local + +$(STATIC_ANALYSIS_DIR)/static-analysis.log: $(STATIC_ANALYSIS_DIR) @echo "" - @echo "differences to develop branch:" + @echo "complete static analysis:" @echo "" - @cat $< | $(GOPATH)/bin/reviewdog -f checkstyle -diff "git diff develop" + @$(LINT) $(LINTFLAGS) run ./... $(ADDITIONAL_LINTER) > $@ -$(LINT): - @${GO_CALL} get -u github.com/golangci/golangci-lint/cmd/golangci-lint +$(STATIC_ANALYSIS_DIR)/static-analysis-cs.log: $(STATIC_ANALYSIS_DIR) + @echo "run static analysis with export to checkstyle format" + @$(LINT) $(LINTFLAGS) run --out-format=checkstyle ./... $(ADDITIONAL_LINTER) > $@ -$(STATIC_ANALYSIS_DIR)/static-analysis.log: $(LINT) +$(STATIC_ANALYSIS_DIR): $(LINT) @mkdir -p $(STATIC_ANALYSIS_DIR) + +static-analysis-ci-report-local: $(STATIC_ANALYSIS_DIR)/static-analysis-cs.log $(REVIEW_DOG) @echo "" - @echo "complete static analysis:" + @echo "differences to develop branch:" @echo "" - @$(LINT) $(LINTFLAGS) run ./... | tee $@ + @cat $(STATIC_ANALYSIS_DIR)/static-analysis-cs.log | $(REVIEW_DOG) -f checkstyle -diff "git diff develop" -$(STATIC_ANALYSIS_DIR)/static-analysis-cs.log: $(LINT) - @mkdir -p $(STATIC_ANALYSIS_DIR) - @$(LINT) $(LINTFLAGS) run --out-format=checkstyle ./... > $@ | true +$(LINT): $(TMP_DIR) + @echo "Download golangci-lint $(LINT_VERSION)..." + @curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(TMP_DIR)/bin $(LINT_VERSION) -$(GOPATH)/bin/reviewdog: - @${GO_CALL} get -u github.com/haya14busa/reviewdog/cmd/reviewdog +$(REVIEW_DOG): $(TMP_DIR) + @curl -sfL https://raw.githubusercontent.com/reviewdog/reviewdog/master/install.sh| sh -s -- -b $(TMP_DIR)/bin diff --git a/build/make/test-common.mk b/build/make/test-common.mk index 53ab656..6eaa0da 100644 --- a/build/make/test-common.mk +++ b/build/make/test-common.mk @@ -1,2 +1,6 @@ -$(GOPATH)/bin/go-junit-report: - @$(GO_CALL) get -u github.com/jstemmer/go-junit-report +GO_JUNIT_REPORT=$(UTILITY_BIN_PATH)/go-junit-report +GO_JUNIT_REPORT_VERSION=v1.0.0 + +$(GO_JUNIT_REPORT): $(UTILITY_BIN_PATH) + @echo "Download go-junit-report..." + @$(call go-get-tool,$@,github.com/jstemmer/go-junit-report@$(GO_JUNIT_REPORT_VERSION)) diff --git a/build/make/test-integration.mk b/build/make/test-integration.mk index 2bf53c2..9a3103c 100644 --- a/build/make/test-integration.mk +++ b/build/make/test-integration.mk @@ -1,12 +1,15 @@ +##@ Integration testing + INTEGRATION_TEST_DIR=$(TARGET_DIR)/integration-tests XUNIT_INTEGRATION_XML=$(INTEGRATION_TEST_DIR)/integration-tests.xml INTEGRATION_TEST_LOG=$(INTEGRATION_TEST_DIR)/integration-tests.log INTEGRATION_TEST_REPORT=$(INTEGRATION_TEST_DIR)/coverage.out PRE_INTEGRATIONTESTS?=start-local-docker-compose POST_INTEGRATIONTESTS?=stop-local-docker-compose +INTEGRATION_TEST_NAME_PATTERN?=.* .PHONY: integration-test -integration-test: $(XUNIT_INTEGRATION_XML) +integration-test: $(XUNIT_INTEGRATION_XML) ## Start integration tests .PHONY: start-local-docker-compose start-local-docker-compose: @@ -27,22 +30,16 @@ else echo "Found CI environment. Nothing to be done" endif -$(XUNIT_INTEGRATION_XML): $(SRC) $(GOPATH)/bin/go-junit-report +$(XUNIT_INTEGRATION_XML): $(SRC) $(GO_JUNIT_REPORT) ifneq ($(strip $(PRE_INTEGRATIONTESTS)),) @make $(PRE_INTEGRATIONTESTS) endif @mkdir -p $(INTEGRATION_TEST_DIR) - @echo 'mode: set' > ${INTEGRATION_TEST_REPORT} + @echo 'mode: set' > $(INTEGRATION_TEST_REPORT) @rm -f $(INTEGRATION_TEST_LOG) || true - @for PKG in $(PACKAGES_FOR_INTEGRATION_TEST) ; do \ - ${GO_CALL} test -tags=${GO_BUILD_TAG_INTEGRATION_TEST} -v $$PKG -coverprofile=${INTEGRATION_TEST_REPORT}.tmp 2>&1 | tee $(INTEGRATION_TEST_LOG).tmp ; \ - cat ${INTEGRATION_TEST_REPORT}.tmp | tail +2 >> ${INTEGRATION_TEST_REPORT} ; \ - rm -f ${INTEGRATION_TEST_REPORT}.tmp ; \ - cat $(INTEGRATION_TEST_LOG).tmp >> $(INTEGRATION_TEST_LOG) ; \ - rm -f $(INTEGRATION_TEST_LOG).tmp ; \ - done - @cat $(INTEGRATION_TEST_LOG) | go-junit-report > $@ + @$(GO_CALL) test ./... -v -tags=${GO_BUILD_TAG_INTEGRATION_TEST} -coverpkg=./... -coverprofile=${INTEGRATION_TEST_REPORT} -run ${INTEGRATION_TEST_NAME_PATTERN} 2>&1 | tee $(INTEGRATION_TEST_LOG) + @cat $(INTEGRATION_TEST_LOG) | $(GO_JUNIT_REPORT) > $@ @if grep '^FAIL' $(INTEGRATION_TEST_LOG); then \ exit 1; \ fi diff --git a/build/make/test-unit.mk b/build/make/test-unit.mk index 8b696ee..6838b1c 100644 --- a/build/make/test-unit.mk +++ b/build/make/test-unit.mk @@ -1,3 +1,5 @@ +##@ Unit testing + UNIT_TEST_DIR=$(TARGET_DIR)/unit-tests XUNIT_XML=$(UNIT_TEST_DIR)/unit-tests.xml UNIT_TEST_LOG=$(UNIT_TEST_DIR)/unit-tests.log @@ -7,9 +9,9 @@ PRE_UNITTESTS?= POST_UNITTESTS?= .PHONY: unit-test -unit-test: $(XUNIT_XML) +unit-test: $(XUNIT_XML) ## Start unit tests -$(XUNIT_XML): $(SRC) $(GOPATH)/bin/go-junit-report +$(XUNIT_XML): $(SRC) $(GO_JUNIT_REPORT) ifneq ($(strip $(PRE_UNITTESTS)),) @make $(PRE_UNITTESTS) endif @@ -24,7 +26,7 @@ endif cat $(UNIT_TEST_LOG).tmp >> $(UNIT_TEST_LOG) ; \ rm -f $(UNIT_TEST_LOG).tmp ; \ done - @cat $(UNIT_TEST_LOG) | go-junit-report > $@ + @cat $(UNIT_TEST_LOG) | $(GO_JUNIT_REPORT) > $@ @if grep '^FAIL' $(UNIT_TEST_LOG); then \ exit 1; \ fi diff --git a/build/make/variables.mk b/build/make/variables.mk index f78e267..639a8b1 100644 --- a/build/make/variables.mk +++ b/build/make/variables.mk @@ -15,10 +15,11 @@ GO_ENVIRONMENT?= # GO_CALL accomodates the go CLI command as well as necessary environment variables which are optional. GO_CALL=${GO_ENVIRONMENT} go PACKAGES=$(shell ${GO_CALL} list ./... | grep -v /vendor/) -PACKAGES_FOR_INTEGRATION_TEST?=${PACKAGES} GO_BUILD_TAG_INTEGRATION_TEST?=integration +GOMODULES=on +UTILITY_BIN_PATH?=${WORKDIR}/.bin -SRC:=$(shell find "${WORKDIR}" -type f -name "*.go" -not -path "./vendor/*") +SRC:=$(shell find "${WORKDIR}" -type f -name "*.go" -not -path "*/vendor/*") # debian stuff DEBIAN_BUILD_DIR=$(BUILD_DIR)/deb @@ -35,11 +36,13 @@ endif YARN_TARGET=$(WORKDIR)/node_modules BOWER_TARGET?=$(WORKDIR)/public/vendor +NODE_VERSION?=8 UID_NR:=$(shell id -u) GID_NR:=$(shell id -g) HOME_DIR=$(TMP_DIR)/home PASSWD=$(TMP_DIR)/passwd +ETCGROUP=$(TMP_DIR)/group $(TMP_DIR): @mkdir -p $(TMP_DIR) @@ -52,3 +55,43 @@ $(TARGET_DIR): $(PASSWD): $(TMP_DIR) @echo "$(USER):x:$(UID_NR):$(GID_NR):$(USER):/home/$(USER):/bin/bash" > $(PASSWD) + +$(ETCGROUP): $(TMP_DIR) + @echo "root:x:0:" > $(ETCGROUP) + @echo "$(USER):x:$(GID_NR):" >> $(ETCGROUP) + +$(UTILITY_BIN_PATH): + @mkdir -p $@ + +# Subdirectories of workdir where no mocks should be generated. +# Multiple directories can be separated by space, comma or whatever is not a word to regex. +MOCKERY_IGNORED=vendor,build,docs + +##@ General + +.PHONY: help +help: ## Display this help. + @awk 'BEGIN {FS = ":.*##"; printf "\nUsage:\n make \033[36m\033[0m\n"} /^[a-zA-Z_0-9-]+:.*?##/ { printf " \033[36m%-15s\033[0m %s\n", $$1, $$2 } /^##@/ { printf "\n\033[1m%s\033[0m\n", substr($$0, 5) } ' $(MAKEFILE_LIST) + +.PHONY: info +info: ## Print build information + @echo "dumping build information ..." + @echo "Version : $(VERSION)" + @echo "Commit-ID : $(COMMIT_ID)" + @echo "Environment: $(ENVIRONMENT)" + @echo "Branch : $(BRANCH)" + @echo "Packages : $(PACKAGES)" + + +# go-get-tool will 'go get' any package $2 and install it to $1. +define go-get-tool + @[ -f $(1) ] || { \ + set -e ;\ + TMP_DIR=$$(mktemp -d) ;\ + cd $$TMP_DIR ;\ + go mod init tmp ;\ + echo "Downloading $(2)" ;\ + GOBIN=$(UTILITY_BIN_PATH) go install $(2) ;\ + rm -rf $$TMP_DIR ;\ + } +endef diff --git a/build/make/yarn.mk b/build/make/yarn.mk index 2af3112..12792b4 100644 --- a/build/make/yarn.mk +++ b/build/make/yarn.mk @@ -1,7 +1,9 @@ +##@ Yarn dependency management + YARN_LOCK=$(WORKDIR)/yarn.lock .PHONY: yarn-install -yarn-install: $(YARN_TARGET) +yarn-install: $(YARN_TARGET) ## Execute yarn install ifeq ($(ENVIRONMENT), ci) @@ -18,7 +20,7 @@ $(YARN_TARGET): $(YARN_LOCK) $(PASSWD) -v $(PASSWD):/etc/passwd:ro \ -v $(WORKDIR):$(WORKDIR) \ -w $(WORKDIR) \ - node:8 \ + node:$(NODE_VERSION) \ yarn install @touch $@ From d2b1f9e96a155c7727a04c680b21771f1dc55333 Mon Sep 17 00:00:00 2001 From: Jeremias Weber Date: Fri, 21 Apr 2023 17:00:07 +0200 Subject: [PATCH 4/4] #74 Improve multistage --- Dockerfile | 100 +++++++++++++++++++++++++++-------------------------- 1 file changed, 51 insertions(+), 49 deletions(-) diff --git a/Dockerfile b/Dockerfile index 820ed24..89d2e3c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -3,8 +3,18 @@ LABEL maintainer="hello@cloudogu.com" # dockerfile is based on https://github.com/dockerfile/nginx and https://github.com/bellycard/docker-loadbalancer -ENV NGINX_VERSION 1.23.2 -ENV NGINX_TAR_SHA256="a80cc272d3d72aaee70aa8b517b4862a635c0256790434dbfc4d618a999b0b46" +ENV NGINX_VERSION=1.23.2 \ + NGINX_TAR_SHA256="a80cc272d3d72aaee70aa8b517b4862a635c0256790434dbfc4d618a999b0b46" \ + CES_CONFD_VERSION=0.8.0 \ + CES_CONFD_TAR_SHA256="365a4033e80af6953d5b6513296a828dfd772a6640533bb51dd9abd34a1e53e8" \ + WARP_MENU_VERSION=1.7.2 \ + WARP_MENU_TAR_SHA256="0f89f3a4bcd24779b792bab34e77c60e27b9142c402e168013711f3094045726" \ + CES_ABOUT_VERSION=0.2.2 \ + CES_ABOUT_TAR_SHA256="9926649be62d8d4667b2e7e6d1e3a00ebec1c4bbc5b80a0e830f7be21219d496" \ + CES_THEME_VERSION=0.7.0 \ + CES_THEME_TAR_SHA256="d3c8ba654cdaccff8fa3202f3958ac0c61156fb25a288d6008354fae75227941" + +WORKDIR /build COPY nginx-build / RUN set -x -o errexit \ @@ -13,29 +23,50 @@ RUN set -x -o errexit \ && apk update \ && apk upgrade \ && apk --update add openssl-dev pcre-dev zlib-dev wget build-base \ - && mkdir /build \ - && cd /build \ - && wget http://nginx.org/download/nginx-${NGINX_VERSION}.tar.gz \ - && echo "${NGINX_TAR_SHA256} *nginx-${NGINX_VERSION}.tar.gz" | sha256sum -c - \ - && tar -zxvf nginx-${NGINX_VERSION}.tar.gz \ + && wget --progress=bar:force:noscroll http://nginx.org/download/nginx-${NGINX_VERSION}.tar.gz -O /tmp/nginx-${NGINX_VERSION}.tar.gz \ + && echo "${NGINX_TAR_SHA256} */tmp/nginx-${NGINX_VERSION}.tar.gz" | sha256sum -c - \ + && tar -zxvf /tmp/nginx-${NGINX_VERSION}.tar.gz -C /build \ && cd /build/nginx-${NGINX_VERSION} \ && /build.sh +# install ces-confd +RUN wget --progress=bar:force:noscroll -O "/tmp/ces-confd-${CES_CONFD_VERSION}.tar.gz" https://github.com/cloudogu/ces-confd/releases/download/v${CES_CONFD_VERSION}/ces-confd-${CES_CONFD_VERSION}.tar.gz \ + && echo "${CES_CONFD_TAR_SHA256} */tmp/ces-confd-${CES_CONFD_VERSION}.tar.gz" | sha256sum -c - \ + && mkdir -p /build/usr/bin \ + && tar -xzvf /tmp/ces-confd-${CES_CONFD_VERSION}.tar.gz -C /build/usr/bin \ + && chmod +x /build/usr/bin/ces-confd \ + && mkdir -p /build/var/log/nginx \ + && mkdir -p /build/var/www/html \ + && mkdir -p /build/var/www/customhtml + +# install ces-about page +RUN wget --progress=bar:force:noscroll -O /tmp/ces-about-v${CES_ABOUT_VERSION}.tar.gz https://github.com/cloudogu/ces-about/releases/download/v${CES_ABOUT_VERSION}/ces-about-v${CES_ABOUT_VERSION}.tar.gz \ + && echo "${CES_ABOUT_TAR_SHA256} */tmp/ces-about-v${CES_ABOUT_VERSION}.tar.gz" | sha256sum -c - \ + && tar -xzvf /tmp/ces-about-v${CES_ABOUT_VERSION}.tar.gz -C /build/var/www/html \ + && sed -i 's@base href=".*"@base href="/info/"@' /build/var/www/html/info/index.html + +# install warp menu +RUN wget --progress=bar:force:noscroll -O /tmp/warp.zip https://github.com/cloudogu/warp-menu/releases/download/v${WARP_MENU_VERSION}/warp-v${WARP_MENU_VERSION}.zip \ + && echo "${WARP_MENU_TAR_SHA256} */tmp/warp.zip" | sha256sum -c - \ + && unzip /tmp/warp.zip -d /build/var/www/html + +# install custom error pages +RUN wget --progress=bar:force:noscroll -O /tmp/theme.zip https://github.com/cloudogu/ces-theme/archive/v${CES_THEME_VERSION}.zip \ + && echo "${CES_THEME_TAR_SHA256} */tmp/theme.zip" | sha256sum -c - \ + && unzip /tmp/theme.zip -d /tmp/theme \ + && cp -r /tmp/theme/ces-theme-${CES_THEME_VERSION}/dist/errors /build/var/www/html + +# redirect logs +RUN ln -sf /dev/stdout /var/log/nginx/access.log \ + && ln -sf /dev/stderr /var/log/nginx/error.log + FROM registry.cloudogu.com/official/base:3.17.3-2 LABEL maintainer="hello@cloudogu.com" \ NAME="official/nginx" \ VERSION="1.23.2-4" -ENV CES_CONFD_VERSION=0.8.0 \ - CES_CONFD_TAR_SHA256="365a4033e80af6953d5b6513296a828dfd772a6640533bb51dd9abd34a1e53e8" \ - WARP_MENU_VERSION=1.7.2 \ - WARP_MENU_TAR_SHA256="0f89f3a4bcd24779b792bab34e77c60e27b9142c402e168013711f3094045726" \ - CES_ABOUT_VERSION=0.2.2 \ - CES_ABOUT_TAR_SHA256="9926649be62d8d4667b2e7e6d1e3a00ebec1c4bbc5b80a0e830f7be21219d496" \ - CES_THEME_VERSION=v0.7.0 \ - CES_THEME_TAR_SHA256="d3c8ba654cdaccff8fa3202f3958ac0c61156fb25a288d6008354fae75227941" \ - CES_MAINTENANCE_MODE=false +ENV CES_MAINTENANCE_MODE=false RUN set -x -o errexit \ && set -o nounset \ @@ -43,43 +74,14 @@ RUN set -x -o errexit \ && apk update \ && apk upgrade \ # install required packages - && apk --update add --no-cache openssl pcre zlib curl \ + && apk --update add --no-cache openssl pcre zlib \ # add nginx user - && adduser nginx -D \ - # install ces-confd - && curl -Lsk https://github.com/cloudogu/ces-confd/releases/download/v${CES_CONFD_VERSION}/ces-confd-${CES_CONFD_VERSION}.tar.gz -o "ces-confd-${CES_CONFD_VERSION}.tar.gz" \ - && echo "${CES_CONFD_TAR_SHA256} *ces-confd-${CES_CONFD_VERSION}.tar.gz" | sha256sum -c - \ - && tar -xzvf ces-confd-${CES_CONFD_VERSION}.tar.gz -O > /usr/bin/ces-confd \ - && chmod +x /usr/bin/ces-confd \ - && mkdir -p /var/log/nginx \ - && mkdir -p /var/www/html \ - && mkdir -p /var/www/customhtml \ - # install ces-about page - && curl -Lsk https://github.com/cloudogu/ces-about/releases/download/v${CES_ABOUT_VERSION}/ces-about-v${CES_ABOUT_VERSION}.tar.gz -o ces-about-v${CES_ABOUT_VERSION}.tar.gz \ - && echo "${CES_ABOUT_TAR_SHA256} *ces-about-v${CES_ABOUT_VERSION}.tar.gz" | sha256sum -c - \ - && tar -xzvf ces-about-v${CES_ABOUT_VERSION}.tar.gz -C /var/www/html \ - && rm -rf ces-about-v${CES_ABOUT_VERSION}.tar.gz \ - && sed -i 's@base href=".*"@base href="/info/"@' /var/www/html/info/index.html \ - # install warp menu - && curl -Lsk https://github.com/cloudogu/warp-menu/releases/download/v${WARP_MENU_VERSION}/warp-v${WARP_MENU_VERSION}.zip -o /tmp/warp.zip \ - && echo "${WARP_MENU_TAR_SHA256} */tmp/warp.zip" | sha256sum -c - \ - && unzip /tmp/warp.zip -d /var/www/html \ - && rm -rf /tmp/warp.zip \ - # install custom error pages - && curl -Lsk https://github.com/cloudogu/ces-theme/archive/${CES_THEME_VERSION}.zip -o /tmp/theme.zip \ - && echo "${CES_THEME_TAR_SHA256} */tmp/theme.zip" | sha256sum -c - \ - && mkdir /var/www/html/errors \ - && unzip /tmp/theme.zip -d /tmp/theme \ - && mv /tmp/theme/ces-theme-*/dist/errors/* /var/www/html/errors \ - && rm -rf /tmp/theme.zip /tmp/theme \ - # redirect logs - && ln -sf /dev/stdout /var/log/nginx/access.log \ - && ln -sf /dev/stderr /var/log/nginx/error.log \ - && apk del curl + && adduser nginx -D # copy files -COPY --from=builder /usr/sbin/nginx /usr/sbin/nginx COPY resources / +COPY --from=builder /usr/sbin/nginx /usr/sbin/nginx +COPY --from=builder /build / # Volumes are used to avoid writing to containers writable layer https://docs.docker.com/storage/ # Compared to the bind mounted volumes we declare in the dogu.json,