From 50756fbf88c6c09c6dd295040e7bf8b389f97717 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=98yvind=20Ingebrigtsen=20=C3=98vergaard?= Date: Tue, 25 Jan 2022 09:56:54 +0100 Subject: [PATCH] First draft e2e test matrix build + release stage - Docker build now only builds amd64 to work around limitations in multi arch image tooling (#179) - Run e2e tests in parallell via matrix build to speed up CI builds - Add make-release + script to create a release (untested and currently disabled) - Add push-container-image stage to push container image for master branch commit builds (untested and currently disabled) --- .semaphore/make-release.yml | 37 +++++++++++++ .semaphore/push-container-image.yml | 24 +++++++++ .semaphore/semaphore.yml | 80 +++++++++++++++++++---------- bin/docker_build | 58 +++++---------------- bin/make_release | 72 ++++++++++++++++++++++++++ 5 files changed, 199 insertions(+), 72 deletions(-) create mode 100644 .semaphore/make-release.yml create mode 100644 .semaphore/push-container-image.yml create mode 100755 bin/make_release diff --git a/.semaphore/make-release.yml b/.semaphore/make-release.yml new file mode 100644 index 00000000..bc954038 --- /dev/null +++ b/.semaphore/make-release.yml @@ -0,0 +1,37 @@ + +# Copyright 2022- The FIAAS Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +version: v1.0 +name: Release fiaas-deploy-daemon +agent: + machine: + type: e1-standard-2 + os_image: ubuntu1804 +blocks: + - name: Make release for fiaas-deploy-daemon + task: + secrets: + # TODO: gh release needs a github token + - name: docker + prologue: + commands: + - checkout + - docker login --username "${DOCKER_USERNAME}" --password-stdin <<< "${DOCKER_PASSWORD}" + - cache restore "${SEMAPHORE_PROJECT_NAME}-${SEMAPHORE_WORKFLOW_ID}-build" + jobs: + - name: Make a new release for a git tag + commands: + - bin/make_release "$SEMAPHORE_GIT_TAG_NAME" + diff --git a/.semaphore/push-container-image.yml b/.semaphore/push-container-image.yml new file mode 100644 index 00000000..1f743fbd --- /dev/null +++ b/.semaphore/push-container-image.yml @@ -0,0 +1,24 @@ +version: v1.0 +name: Push container image +agent: + machine: + type: e1-standard-2 + os_image: ubuntu1804 +blocks: + - name: Push development container image + task: + secrets: + - name: docker + prologue: + commands: + - docker login --username "${DOCKER_USERNAME}" --password-stdin <<< "${DOCKER_PASSWORD}" + - cache restore "${SEMAPHORE_PROJECT_NAME}-${SEMAPHORE_WORKFLOW_ID}-build" + jobs: + - name: 'docker push' + commands: + - VERSION="$(head -n1 build/version)" + - docker image load --input build/fiaas-deploy-daemon.tar + - docker image tag "fiaas/fiaas-deploy-daemon:$VERSION" fiaas/fiaas-deploy-daemon:latest + - docker push "fiaas/fiaas-deploy-daemon:$VERSION" + - docker push fiaas/fiaas-deploy-daemon:latest + diff --git a/.semaphore/semaphore.yml b/.semaphore/semaphore.yml index 1904d512..f9988dcd 100644 --- a/.semaphore/semaphore.yml +++ b/.semaphore/semaphore.yml @@ -13,47 +13,71 @@ # See the License for the specific language governing permissions and # limitations under the License. version: v1.0 -name: Fiaas-deploy-daemon docker build +name: fiaas-deploy-daemon CI build agent: machine: type: e1-standard-8 os_image: ubuntu1804 - blocks: - - name: "Test, build docker image and run e2e test" + - name: "Run unit tests, build container image" task: secrets: - name: docker - jobs: - - name: Docker build + prologue: commands: - # Check codestyle + run unit tests - checkout + - docker login --username "${DOCKER_USERNAME}" --password-stdin <<< "${DOCKER_PASSWORD}" + # qemu-user-static registers binfmt_misc handlers to be able to build multiarch images + # details: https://github.com/multiarch/qemu-user-static/blob/master/docs/developers_guide.md#technology-overview + # TODO: Can this be replaced with `apt-get install -y qemu-user-static` ? - sudo apt-get update - sudo apt-get install -y qemu-user - docker run --rm --privileged multiarch/qemu-user-static:4.2.0-7 --reset -p yes - - export PATH="$PATH:$HOME/.local/bin" - pip install --user .[ci] - - curl -Lo $HOME/.local/bin/kind https://kind.sigs.k8s.io/dl/v0.11.1/kind-linux-amd64 && chmod +x $HOME/.local/bin/kind + jobs: + - name: "Unit tests + docker build" + commands: - tox -e codestyle,test - # Build docker image - - docker login --username "${DOCKER_USERNAME}" --password-stdin <<< "${DOCKER_PASSWORD}" - ./bin/docker_build - # Run end-to-end/integration tests - - tox -e integration_test -- -n 2 --use-docker-for-e2e - # Store metadata for promotion jobs - - echo "$SEMAPHORE_JOB_ID" > semaphore_job_id - - echo "$SEMAPHORE_GIT_SHA" > semaphore_git_sha - - cache store $SEMAPHORE_PROJECT_NAME-$SEMAPHORE_WORKFLOW_ID-semaphore_job_id semaphore_job_id - - cache store $SEMAPHORE_PROJECT_NAME-$SEMAPHORE_WORKFLOW_ID-semaphore_git_sha semaphore_git_sha - - cache store $SEMAPHORE_PROJECT_NAME-$SEMAPHORE_WORKFLOW_ID-version version - - echo "done" -promotions: - - name: Promote latest - pipeline_file: latest.yml - auto_promote_on: - - result: passed - branch: - - master - - name: Promote stable - pipeline_file: stable.yml + # docker_build creates the following in ./build/ which is reused in later stages: + # - `fiaas-deploy-daemon.tar`: the fiaas-deploy-daemon container image + # - `version`: the version of the container image in the format `YYYYMMDDHHMMSS-$git_commit_ref` + - cache store "${SEMAPHORE_PROJECT_NAME}-${SEMAPHORE_WORKFLOW_ID}-build" build + - name: "Run end-to-end tests" + dependencies: ["Run unit tests, build container image"] + task: + prologue: + commands: + - checkout + - pip install --user .[ci] + - export PATH="$PATH:$HOME/.local/bin" + - curl -Lo $HOME/.local/bin/kind https://kind.sigs.k8s.io/dl/v0.11.1/kind-linux-amd64 && chmod +x $HOME/.local/bin/kind + - cache restore "${SEMAPHORE_PROJECT_NAME}-${SEMAPHORE_WORKFLOW_ID}-build" + jobs: + - name: "e2e test" + commands: + # import the image from 'Docker build' as fiaas/fiaas-deploy-daemon:latest as the e2e test expects + - docker image load build/fiaas-deploy-daemon.tar + - docker tag fiaas/fiaas-deploy-daemon:"$(< build/version)" fiaas/fiaas-deploy-daemon:latest + - tox -e integration_test -- -n 2 --use-docker-for-e2e --e2e-k8s-version "$K8S_VERSION" + matrix: + # e2e tests are run vs. these Kubernetes version + - env_var: K8S_VERSION + values: + - v1.15.12 + - v1.16.15 + - v1.18.19 + - v1.19.11 + - v1.20.7 + - v1.21.2 + - v1.22.4 +# TODO: Keep these commented while testing out to avoid accidental promotion +# promotions: +# - name: Push container image +# pipeline_file: push-container-image.yml +# auto_promote: +# when: "result = 'passed' and branch = 'master'" +# - name: Release fiaas-deploy-daemon +# pipeline_file: make-release.yml +# auto_promote: +# when: "result = 'passed' and tag =~ '^v\d+\.\d+\.\d+'" diff --git a/bin/docker_build b/bin/docker_build index a94ef3b4..a473df02 100755 --- a/bin/docker_build +++ b/bin/docker_build @@ -1,62 +1,32 @@ #!/usr/bin/env bash set -euo pipefail - -export DOCKER_CLI_EXPERIMENTAL=enabled +# Builds fiaas-deploy-daemon container image. +# Writes the container image to a tarball under $TARBALL +# Uses Python wheels from pip's wheel cache (if any) to speed up the container build +# Note: Keep this safe to run locally VERSION="$(date +%Y%m%d%H%M%S)-$(git rev-parse --short HEAD)" IMAGE="fiaas/fiaas-deploy-daemon" IMAGE_VERSION_TAG="${IMAGE}:$VERSION" -IMAGE_LATEST_TAG="${IMAGE}:latest" TARBALL=build/fiaas-deploy-daemon.tar -CACHE_DIR=${PIP_CACHE_DIR:-~/.cache/pip} +CACHE_DIR="$(python -m pip cache dir)" # `python -m` to ensure the correct pip is used + +# Always run in root of git repo +cd "$(git rev-parse --show-toplevel)" -if [[ "${CI:-false}" == "true" ]]; then - PLATFORMS=linux/arm,linux/arm64,linux/amd64 - if [[ "${SEMAPHORE_GIT_BRANCH}" == "master" && -z "${SEMAPHORE_GIT_PR_BRANCH:-}" ]]; then - OUTPUT=type=image,push=true - echo "$VERSION" > version - echo "Stored $VERSION in ./version" - else - OUTPUT=type=image,push=false - fi -else - PLATFORMS=linux/amd64 - OUTPUT=type=docker -fi -echo "Building ${OUTPUT} for ${PLATFORMS}" +mkdir -p build # Put cached wheels into the docker context so we can use it in our Dockerfile mkdir -p .wheel_cache -mkdir -p build mkdir -p "${CACHE_DIR}/wheels" find "${CACHE_DIR}/wheels" -name "*.whl" -execdir cp "{}" "${PWD}/.wheel_cache" \; -# Create a multi-arch buildx builder if needed -if docker buildx ls | grep docker-container | grep multi-arch &> /dev/null; then - echo "Using existing multi-arch builder" - docker buildx use multi-arch -else - echo "Creating new multi-arch builder" - docker buildx create --name multi-arch --driver docker-container --use --platform "${PLATFORMS}" -fi - -# Run multi-arch build and push it -docker buildx build --pull \ - --tag "${IMAGE_VERSION_TAG}" \ - --platform "${PLATFORMS}" \ - --output "${OUTPUT}" . - -# And again to load into docker if not already done -if [[ "${OUTPUT}" != "type=docker" ]]; then - docker buildx build \ - --tag "${IMAGE_LATEST_TAG}" \ - --output type=docker . -fi +# Build the image +docker build --tag "${IMAGE_VERSION_TAG}" . -# Once more to get the wheels -docker buildx build \ - --platform "${PLATFORMS}" \ - --output type=tar,dest="${TARBALL}" . +# Write docker image and version to build/ +docker image save "$IMAGE_VERSION_TAG" --output "${TARBALL}" +echo "$VERSION" > build/version # Grab the wheels out of the tarball and stuff them in the pip cache directory tar -v -C "${CACHE_DIR}/wheels" --wildcards -x "*/wheels/*.whl" -x "wheels/*.whl" -f "${TARBALL}" 2>/dev/null || true diff --git a/bin/make_release b/bin/make_release new file mode 100755 index 00000000..3ecf6f09 --- /dev/null +++ b/bin/make_release @@ -0,0 +1,72 @@ +#!/usr/bin/env bash +set -euo pipefail +# `make_release TAG` creates a Github release for git tag TAG + +cd "$(git rev-parse --show-toplevel)" + +# the first parameter should be the name of an annotated tag in the git repo +RELEASE="$1" +IMAGE=fiaas/fiaas-deploy-daemon +# the following files under build/ are artifacts expected to be created by the initial build stage +# the container image tarball +IMAGE_TARBALL=build/fiaas-deploy-daemon.tar +# contains the container image version as a single line +IMAGE_VERSION="$(< build/version)" +# contains the path to the helm chart tarball including version as a single line. +# the chart tarball should also be under build/ +HELM_CHART_TARBALL="$(< build/chart-tarball)" + +function publish_helm_chart() { + local release="$1" + local chart_tarball="$2" + + local helm_repo_dir + helm_repo_dir="$(mktemp -d)" + trap 'rm -rf $helm_repo_dir' RETURN + + git clone https://github.com/fiaas/helm "$helm_repo_dir" + mv "$chart_tarball" "$helm_repo_dir"/ + + pushd "$helm_repo_dir" + helm repo index . --url https://fiaas.github.io/helm/ + git add . + git commit -a -m "Release fiaas-deploy-daemon ${release}" + git push "https://${GITHUBKEY}@github.com/fiaas/helm" + popd + + echo "Published helm chart $chart_tarball" +} + +function tag_push_docker_image() { + local tarball="$1" + local version_tag="$2" + local release_tag="$3" + + docker image load --input "$tarball" + docker tag fiaas/fiaas-deploy-daemon:"${version_tag}" "$release_tag" + + docker push "$version_tag" + echo "Pushed image $version_tag" + docker push "$release_tag" + echo "Pushed image $release_tag" +} + +if [[ "${CI:-false}" != "true" ]]; then + echo "$0 is intended to run only in CI, run CI=true $0 to override" + exit 1 +fi + +if gh release view "$RELEASE" &> /dev/null; then + echo "The github release $RELEASE already exists, can't overwrite a existing release" + exit 2 +fi + +# get release notes from the content of the annotated release tag +git tag --list --format='%(contents)' "$RELEASE" > build/release-notes + +# publish artifacts +tag_push_docker_image "$IMAGE_TARBALL" "${IMAGE}:$IMAGE_VERSION" "${IMAGE}:$RELEASE" +publish_helm_chart "$RELEASE" "$HELM_CHART_TARBALL" + +# create the github release +gh release create --title "fiaas-deploy-daemon release $RELEASE" --notes-file build/release-notes