From 88403dec75c0207f7b469a63d21defee4aba046e Mon Sep 17 00:00:00 2001 From: Tomas Hozza Date: Wed, 20 Jul 2022 12:11:50 +0200 Subject: [PATCH] koji.sh: support testing of upload to the cloud Extend the `koji.sh` test case to allow also testing the upload to cloud, in addition to the testing that it supports currently (building of multiple images in one Koji compose request). The script now reuses some common functions used by the `api.sh` test case. Once the Koji compose succeeds, the script verifies that the image is present in the appropriate cloud environment using a CLI tool. No additional testing of the image is done, it is not booted. --- test/cases/api/azure.sh | 9 ++- test/cases/api/common/aws.sh | 7 ++ test/cases/api/gcp.sh | 10 ++- test/cases/koji.sh | 151 ++++++++++++++++++++++++++++++++++- 4 files changed, 168 insertions(+), 9 deletions(-) diff --git a/test/cases/api/azure.sh b/test/cases/api/azure.sh index 76be691b8..263cc253d 100644 --- a/test/cases/api/azure.sh +++ b/test/cases/api/azure.sh @@ -109,11 +109,16 @@ function checkUploadStatusOptions() { test "$IMAGE_NAME" = "$AZURE_IMAGE_NAME" } -# Verify image in Azure -function verify() { +# Log into Azure +function cloud_login() { set +x $AZURE_CMD login --service-principal --username "${V2_AZURE_CLIENT_ID}" --password "${V2_AZURE_CLIENT_SECRET}" --tenant "${AZURE_TENANT_ID}" set -x +} + +# Verify image in Azure +function verify() { + cloud_login # verify that the image exists and tag it $AZURE_CMD image show --resource-group "${AZURE_RESOURCE_GROUP}" --name "${AZURE_IMAGE_NAME}" diff --git a/test/cases/api/common/aws.sh b/test/cases/api/common/aws.sh index 14c315e54..7037056b3 100644 --- a/test/cases/api/common/aws.sh +++ b/test/cases/api/common/aws.sh @@ -31,3 +31,10 @@ function installClient() { fi $GOVC_CMD version } + +# Log into AWS +# AWS does not need explicit login, but define this function for the sake of +# consistency to allow calling scripts to not care about cloud differences +function cloud_login() { + true +} diff --git a/test/cases/api/gcp.sh b/test/cases/api/gcp.sh index 267b8159c..d88877c8a 100644 --- a/test/cases/api/gcp.sh +++ b/test/cases/api/gcp.sh @@ -101,14 +101,18 @@ function checkUploadStatusOptions() { test "$PROJECT_ID" = "$GCP_PROJECT" } - -# Verify image in Compute Engine on GCP -function verify() { +# Log into GCP +function cloud_login() { # Authenticate $GCP_CMD auth activate-service-account --key-file "$GOOGLE_APPLICATION_CREDENTIALS" # Extract and set the default project to be used for commands GCP_PROJECT=$(jq -r '.project_id' "$GOOGLE_APPLICATION_CREDENTIALS") $GCP_CMD config set project "$GCP_PROJECT" +} + +# Verify image in Compute Engine on GCP +function verify() { + cloud_login # Add "gitlab-ci-test" label to the image $GCP_CMD compute images add-labels "$GCP_IMAGE_NAME" --labels=gitlab-ci-test=true diff --git a/test/cases/koji.sh b/test/cases/koji.sh index 887fe73c4..1c3fa1049 100755 --- a/test/cases/koji.sh +++ b/test/cases/koji.sh @@ -16,6 +16,89 @@ if [ "${NIGHTLY:=false}" == "true" ]; then exit 0 fi +# +# Cloud provider / target names +# + +CLOUD_PROVIDER_AWS="aws" +CLOUD_PROVIDER_GCP="gcp" +CLOUD_PROVIDER_AZURE="azure" + +# +# Test types +# +# Tests Koji compose via cloudapi +TEST_TYPE_CLOUDAPI="cloudapi" +# Tests Koji compose via cloudapi with upload to a cloud target +TEST_TYPE_CLOUD_UPLOAD="cloud-upload" + +# test Koji compose via cloudapi without upload to cloud by default +TEST_TYPE="${1:-$TEST_TYPE_CLOUDAPI}" + +# +# Cloud upload - check environment and prepare it +# +if [[ "$TEST_TYPE" == "$TEST_TYPE_CLOUD_UPLOAD" ]]; then + if [[ $# -ne 3 ]]; then + echo "Usage: $0 cloud-upload TARGET IMAGE_TYPE" + exit 1 + fi + + CLOUD_PROVIDER="${2}" + IMAGE_TYPE="${3}" + + greenprint "Using Cloud Provider / Target ${CLOUD_PROVIDER} for Image Type ${IMAGE_TYPE}" + + # Load a correct test runner. + # Each one must define following methods: + # - checkEnv + # - cleanup + # - installClient + case $CLOUD_PROVIDER in + "$CLOUD_PROVIDER_AWS") + source /usr/libexec/tests/osbuild-composer/api/aws.sh + ;; + "$CLOUD_PROVIDER_GCP") + source /usr/libexec/tests/osbuild-composer/api/gcp.sh + ;; + "$CLOUD_PROVIDER_AZURE") + source /usr/libexec/tests/osbuild-composer/api/azure.sh + ;; + *) + echo "Unknown cloud provider: ${CLOUD_PROVIDER}" + exit 1 + esac + + # Verify that this script is running in the right environment. + checkEnv + + # Container image used for cloud provider CLI tools + export CONTAINER_IMAGE_CLOUD_TOOLS="quay.io/osbuild/cloud-tools:latest" + + if which podman 2>/dev/null >&2; then + export CONTAINER_RUNTIME=podman + elif which docker 2>/dev/null >&2; then + export CONTAINER_RUNTIME=docker + else + echo No container runtime found, install podman or docker. + exit 1 + fi + + WORKDIR=$(mktemp -d) + export WORKDIR + function cleanups() { + greenprint "Script execution stopped or finished - Cleaning up" + set +eu + cleanup + sudo rm -rf "$WORKDIR" + set -eu + } + trap cleanups EXIT + + # install appropriate cloud environment client tool + installClient +fi + # Provision the software under test. /usr/libexec/osbuild-composer-test/provision.sh @@ -51,13 +134,73 @@ koji --server=http://localhost:8080/kojihub --user kojiadmin --password kojipass # Always build the latest RHEL - that suits the koji API usecase the most. if [[ "$DISTRO_CODE" == rhel-8* ]]; then - DISTRO_CODE=rhel-87 + DISTRO_CODE=rhel-87 elif [[ "$DISTRO_CODE" == rhel-9* ]]; then - DISTRO_CODE=rhel-91 + DISTRO_CODE=rhel-91 fi -greenprint "Pushing compose to Koji (/api/image-builder-comoser/v2/" -sudo /usr/libexec/osbuild-composer-test/koji-compose.py "$DISTRO_CODE" "${ARCH}" +case ${TEST_TYPE} in + "$TEST_TYPE_CLOUDAPI") + greenprint "Pushing compose to Koji (/api/image-builder-comoser/v2/)" + COMPOSE_ID="$(sudo /usr/libexec/osbuild-composer-test/koji-compose.py "${DISTRO_CODE}" "${ARCH}")" + ;; + "$TEST_TYPE_CLOUD_UPLOAD") + greenprint "Pushing compose to Koji (/api/image-builder-comoser/v2/) with cloud upload target" + COMPOSE_ID="$(sudo -E /usr/libexec/osbuild-composer-test/koji-compose.py "${DISTRO_CODE}" "${ARCH}" "${CLOUD_PROVIDER}" "${IMAGE_TYPE}")" + ;; + *) + echo "Unknown test type: ${TEST_TYPE}" + exit 1 +esac + +if [[ "$TEST_TYPE" == "$TEST_TYPE_CLOUD_UPLOAD" ]]; then + greenprint "Verify that image was uploaded to the cloud provider" + + COMPOSE_STATUS=$(curl \ + --silent \ + --show-error \ + --cacert /etc/osbuild-composer/ca-crt.pem \ + --key /etc/osbuild-composer/client-key.pem \ + --cert /etc/osbuild-composer/client-crt.pem \ + "https://localhost/api/image-builder-composer/v2/composes/${COMPOSE_ID}") + UPLOAD_OPTIONS=$(echo "${COMPOSE_STATUS}" | jq -r '.image_status.upload_status.options') + + # Authenticate with the appropriate cloud + cloud_login + + case $CLOUD_PROVIDER in + "$CLOUD_PROVIDER_AWS") + AMI_IMAGE_ID=$(echo "${UPLOAD_OPTIONS}" | jq -r '.ami') + $AWS_CMD ec2 describe-images \ + --owners self \ + --filters Name=image-id,Values="${AMI_IMAGE_ID}" \ + > "${WORKDIR}/ami.json" + # extract the snapshot ID for the purpose of cleanup + AWS_SNAPSHOT_ID=$(jq -r '.Images[].BlockDeviceMappings[].Ebs.SnapshotId' "$WORKDIR/ami.json") + export AWS_SNAPSHOT_ID + if [[ $(jq '.Images | length' "${WORKDIR}/ami.json") -ne 1 ]]; then + echo "${AMI_IMAGE_ID} image not found in AWS" + exit 1 + fi + ;; + "$CLOUD_PROVIDER_GCP") + GCP_IMAGE_NAME=$(echo "${UPLOAD_OPTIONS}" | jq -r '.image_name') + # The command exits with non-zero value if the image does not exist + $GCP_CMD compute images describe "${GCP_IMAGE_NAME}" + ;; + "$CLOUD_PROVIDER_AZURE") + AZURE_IMAGE_NAME=$(echo "${UPLOAD_OPTIONS}" | jq -r '.image_name') + # The command exits with non-zero value if the image does not exist + $AZURE_CMD image show --resource-group "${AZURE_RESOURCE_GROUP}" --name "${AZURE_IMAGE_NAME}" + ;; + *) + echo "Unknown cloud provider: ${CLOUD_PROVIDER}" + exit 1 + esac + + # if we got here, the image must have been found + greenprint "Image was SUCCESSFULLY found in the respective cloud provider environment!" +fi greenprint "Show Koji task" koji --server=http://localhost:8080/kojihub taskinfo 1