Skip to content

Commit

Permalink
app-sre artifacts for image building and saas deployments
Browse files Browse the repository at this point in the history
adding scripts for image building and installation template generation with AppSREs [qontract-reconcile](https://github.com/app-sre/qontract-reconcile)

running `make app-sre-saas-template` generates the operator installation manifests with `hypershift install --render` and wraps them
into an [Openshift template](https://docs.openshift.com/container-platform/4.9/openshift_images/using-templates.html).
a fresh build of current hypershift sources is used for the installation manifest generation.
the resulting template is placed under `hack/app-sre/saas_template.yaml` and offers parameters for the actual
container image to use on template instantiation.

the hack/app-sre/build_push.sh script is used in AppSREs CI. it will
* build the image with `make docker-build`
* verify that the template is up to date in regards to the current hypershift build
* tag the image and push it to quay.io/app-sre/hypershift-operator:${7-char-commit_sha}

the CI build in AppSREs build enviroment will fail if the `install --render` output does not align with
the template stored under `hack/app-sre/saas_template.yaml`. it is the responsibility of the author of
a change to call `make app-sre-saas-template` and commit changes to the resulting `saas_template.yaml`
along with the changes to hypershift itself.

Signed-off-by: Gerd Oberlechner <goberlec@redhat.com>
  • Loading branch information
geoberle committed Jan 25, 2022
1 parent 036ac65 commit 2769c3a
Show file tree
Hide file tree
Showing 6 changed files with 24,853 additions and 0 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ tools/bin
.kube
/kubeconfig
.dockerignore
.docker

# ignore util binaries
/contrib/cleanzones/cleanzones

4 changes: 4 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,10 @@ cluster-api-provider-agent: $(CONTROLLER_GEN)
api-docs: $(GENAPIDOCS)
hack/gen-api-docs.sh $(GENAPIDOCS) $(DIR)

.PHONY: app-sre-saas-template
app-sre-saas-template: hypershift
hack/app-sre/generate-saas-template.sh bin/hypershift

# Run tests
.PHONY: test
test: build
Expand Down
115 changes: 115 additions & 0 deletions hack/app-sre/build_push.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
#!/bin/bash

# AppSRE team CD

set -exv

DIR=$(realpath $(dirname "${BASH_SOURCE[0]}"))
GIT_HASH=`git rev-parse --short=7 HEAD`
IMG_BASE="quay.io/app-sre/hypershift-operator"
IMG="${IMG_BASE}:${GIT_HASH}"
IMG_LATEST="${IMG_BASE}:latest"

### Accommodate docker or podman
#
# The docker/podman creds cache needs to be in a location unique to this
# invocation; otherwise it could collide across jenkins jobs. We'll use
# a .docker folder relative to pwd (the repo root).
CONTAINER_ENGINE_CONFIG_DIR=.docker
mkdir -p ${CONTAINER_ENGINE_CONFIG_DIR}
# But docker and podman use different options to configure it :eyeroll:
# ==> Podman uses --authfile=PATH *after* the `login` subcommand; but
# also accepts REGISTRY_AUTH_FILE from the env. See
# https://www.mankier.com/1/podman-login#Options---authfile=path
export REGISTRY_AUTH_FILE=${CONTAINER_ENGINE_CONFIG_DIR}/config.json
# ==> Docker uses --config=PATH *before* (any) subcommand; so we'll glue
# that to the CONTAINER_ENGINE variable itself. (NOTE: I tried half a
# dozen other ways to do this. This was the least ugly one that actually
# works.)
CONTAINER_ENGINE=$(command -v podman 2>/dev/null || echo docker --config=${CONTAINER_ENGINE_CONFIG_DIR})

# Make sure we can log into quay; otherwise we won't be able to push
${CONTAINER_ENGINE} login -u="${QUAY_USER}" -p="${QUAY_TOKEN}" quay.io

## image_exits_in_repo IMAGE_URI
#
# Checks whether IMAGE_URI -- e.g. quay.io/app-sre/osd-metrics-exporter:abcd123
# -- exists in the remote repository.
# If so, returns success.
# If the image does not exist, but the query was otherwise successful, returns
# failure.
# If the query fails for any reason, prints an error and *exits* nonzero.
image_exists_in_repo() {
local image_uri=$1
local output
local rc

local skopeo_stderr=$(mktemp)

output=$(skopeo inspect docker://${image_uri} 2>$skopeo_stderr)
rc=$?
# So we can delete the temp file right away...
stderr=$(cat $skopeo_stderr)
rm -f $skopeo_stderr
if [[ $rc -eq 0 ]]; then
# The image exists. Sanity check the output.
local digest=$(echo $output | jq -r .Digest)
if [[ -z "$digest" ]]; then
echo "Unexpected error: skopeo inspect succeeded, but output contained no .Digest"
echo "Here's the output:"
echo "$output"
echo "...and stderr:"
echo "$stderr"
exit 1
fi
echo "Image ${image_uri} exists with digest $digest."
return 0
elif [[ "$stderr" == *"manifest unknown"* ]]; then
# We were able to talk to the repository, but the tag doesn't exist.
# This is the normal "green field" case.
echo "Image ${image_uri} does not exist in the repository."
return 1
elif [[ "$stderr" == *"was deleted or has expired"* ]]; then
# This should be rare, but accounts for cases where we had to
# manually delete an image.
echo "Image ${image_uri} was deleted from the repository."
echo "Proceeding as if it never existed."
return 1
else
# Any other error. For example:
# - "unauthorized: access to the requested resource is not
# authorized". This happens not just on auth errors, but if we
# reference a repository that doesn't exist.
# - "no such host".
# - Network or other infrastructure failures.
# In all these cases, we want to bail, because we don't know whether
# the image exists (and we'd likely fail to push it anyway).
echo "Error querying the repository for ${image_uri}:"
echo "stdout: $output"
echo "stderr: $stderr"
exit 1
fi
}

if image_exists_in_repo "${IMG}"; then
echo "Skipping image build/push for ${IMG}"
exit 0
fi

# build the image
make RUNTIME="$CONTAINER_ENGINE" IMG="$IMG" docker-build

# verify if saas-template is up to date
$DIR/generate-saas-template.sh "${CONTAINER_ENGINE} run --rm --entrypoint /usr/bin/hypershift ${IMG}"
if [[ `git status --porcelain` ]]; then
echo "hack/app-sre/saas_template.yaml is not uptodate"
echo "make sure to run 'make app-sre-saas-template' and commit the changes"
exit 1
fi

# push the image
${CONTAINER_ENGINE} push ${IMG}

# tag and push latest
${CONTAINER_ENGINE} tag ${IMG} ${IMG_LATEST}
${CONTAINER_ENGINE} push ${IMG_LATEST}
40 changes: 40 additions & 0 deletions hack/app-sre/generate-saas-template.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
#!/usr/bin/env python

import sys
import yaml

usage="""
Usage: provide a list of yaml manifests on stdin and expect the template on stdout
"""

template = {
"apiVersion": "v1",
"kind": "Template",
"metadata": {
"name": "hypershift-saas-template"
},
"parameters": [
{
"name": "REGISTRY_IMG",
"value": "quay.io/app-sre/hypershift-operator",
},
{
"name": "IMAGE_TAG",
"value": "latest",
}
],
"objects": []
}

# read objects
template["objects"] = list(yaml.load_all(sys.stdin, Loader=yaml.SafeLoader))

for obj in template["objects"]:
# patch image
if obj and obj["kind"] in "Deployment":
for container in obj["spec"]["template"]["spec"]["containers"]:
if container["image"] == "quay.io/app-sre/hypershift-operator:latest":
container["image"] = '${REGISTRY_IMG}:${IMAGE_TAG}'

# write output
yaml.dump(template, sys.stdout, default_flow_style=False)
23 changes: 23 additions & 0 deletions hack/app-sre/generate-saas-template.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#!/bin/bash

HYPERSHIFT_BIN=$1
CONTAINER_ENGINE=$(command -v podman 2>/dev/null || echo docker)

DIR=$(realpath $(dirname "${BASH_SOURCE[0]}"))
TMP_DIR=$DIR/tmp
mkdir -p $TMP_DIR

# generate hypershift operator manifests
${HYPERSHIFT_BIN} install --render \
--hypershift-image=quay.io/app-sre/hypershift-operator:latest \
--namespace=hypershift \
--oidc-storage-provider-s3-bucket-name="bucket" > $TMP_DIR/manifests.yaml

# process manifests into a template
cat $TMP_DIR/manifests.yaml | $CONTAINER_ENGINE run --rm -i \
--entrypoint "/bin/bash" -v $DIR:/workdir:z \
registry.access.redhat.com/ubi8/python-39 \
-c "pip3.9 --disable-pip-version-check install -q pyyaml && /workdir/generate-saas-template.py" \
> $DIR/saas_template.yaml

rm -rf $TMP_DIR
Loading

0 comments on commit 2769c3a

Please sign in to comment.