-
Notifications
You must be signed in to change notification settings - Fork 52
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(RELEASE-1350): internal push-artifacts
- new clone of push-disk-images pipeline and task called `push-artifacts` - can now skip components with no CGW data Signed-off-by: Scott Hebert <[email protected]>
- Loading branch information
Showing
23 changed files
with
1,332 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
# push-disk-images | ||
|
||
Tekton Pipeline to push artifacts to CDN and/or Dev Portal | ||
|
||
## Parameters | ||
|
||
| Name | Description | Optional | Default value | | ||
|----------------|-------------------------------------------------------------------|----------|----------------------------------------------------------| | ||
| snapshot_json | String containing a JSON representation of the snapshot spec | No | - | | ||
| exodusGwSecret | Env specific secret containing the Exodus Gateway configs | No | - | | ||
| exodusGwEnv | Environment to use in the Exodus Gateway. Options are [live, pre] | No | - | | ||
| pulpSecret | Env specific secret containing the rhsm-pulp credentials | No | - | | ||
| udcacheSecret | Env specific secret containing the udcache credentials | No | - | | ||
| cgwHostname | The hostname of the content-gateway to publish the metadata to | Yes | https://developers.redhat.com/content-gateway/rest/admin | | ||
| cgwSecret | Env specific secret containing the content gateway credentials | No | - | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
--- | ||
apiVersion: tekton.dev/v1 | ||
kind: Pipeline | ||
metadata: | ||
name: push-disk-images | ||
labels: | ||
app.kubernetes.io/version: "0.0.1" | ||
annotations: | ||
tekton.dev/pipelines.minVersion: "0.12.1" | ||
tekton.dev/tags: release | ||
spec: | ||
description: >- | ||
Pipeline to push artifacts to CDN and/or Dev Portal | ||
params: | ||
- name: snapshot_json | ||
type: string | ||
description: String containing a JSON representation of the snapshot spec | ||
- name: exodusGwSecret | ||
type: string | ||
description: Env specific secret containing the Exodus Gateway configs | ||
- name: exodusGwEnv | ||
type: string | ||
description: Environment to use in the Exodus Gateway. Options are [live, pre] | ||
- name: pulpSecret | ||
type: string | ||
description: Env specific secret containing the rhsm-pulp credentials | ||
- name: udcacheSecret | ||
type: string | ||
description: Env specific secret containing the udcache credentials | ||
- name: cgwHostname | ||
type: string | ||
description: The hostname of the content-gateway to publish the metadata to | ||
default: https://developers.redhat.com/content-gateway/rest/admin | ||
- name: cgwSecret | ||
type: string | ||
description: Env specific secret containing the content gateway credentials | ||
tasks: | ||
- name: push-artifacts-task | ||
timeout: "24h00m0s" | ||
taskRef: | ||
name: push-artifacts-task | ||
params: | ||
- name: snapshot_json | ||
value: $(params.snapshot_json) | ||
- name: exodusGwSecret | ||
value: $(params.exodusGwSecret) | ||
- name: exodusGwEnv | ||
value: $(params.exodusGwEnv) | ||
- name: pulpSecret | ||
value: $(params.pulpSecret) | ||
- name: udcacheSecret | ||
value: $(params.udcacheSecret) | ||
- name: cgwHostname | ||
value: $(params.cgwHostname) | ||
- name: cgwSecret | ||
value: $(params.cgwSecret) | ||
results: | ||
- name: result | ||
value: $(tasks.push-artifacts-task.results.result) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
../tasks/push-artifacts-task/push-artifacts-task.yaml |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
../pipelines/push-artifacts/push-artifacts.yaml |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
# push-artifacts-task | ||
|
||
Tekton task to push artifacts to CDN and optionally Dev Portal with optional signing | ||
|
||
## Parameters | ||
|
||
| Name | Description | Optional | Default value | | ||
|-----------------|-------------------------------------------------------------------|----------|----------------------------------------------------------| | ||
| snapshot_json | String containing a JSON representation of the snapshot spec | No | - | | ||
| concurrentLimit | The maximum number of images to be pulled at once | Yes | 3 | | ||
| exodusGwSecret | Env specific secret containing the Exodus Gateway configs | No | - | | ||
| exodusGwEnv | Environment to use in the Exodus Gateway. Options are [live, pre] | No | - | | ||
| pulpSecret | Env specific secret containing the rhsm-pulp credentials | No | - | | ||
| udcacheSecret | Env specific secret containing the udcache credentials | No | - | | ||
| cgwHostname | The hostname of the content-gateway to publish the metadata to | Yes | https://developers.redhat.com/content-gateway/rest/admin | | ||
| cgwSecret | Env specific secret containing the content gateway credentials | No | - | |
293 changes: 293 additions & 0 deletions
293
internal/tasks/push-artifacts-task/push-artifacts-task.yaml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,293 @@ | ||
--- | ||
apiVersion: tekton.dev/v1 | ||
kind: Task | ||
metadata: | ||
name: push-artifacts-task | ||
labels: | ||
app.kubernetes.io/version: "0.0.1" | ||
annotations: | ||
tekton.dev/pipelines.minVersion: "0.12.1" | ||
tekton.dev/tags: release | ||
spec: | ||
description: >- | ||
Tekton task to push artifacts | ||
params: | ||
- name: snapshot_json | ||
type: string | ||
description: String containing a JSON representation of the snapshot spec | ||
- name: concurrentLimit | ||
type: string | ||
description: The maximum number of images to be pulled at once | ||
default: 3 | ||
- name: exodusGwSecret | ||
type: string | ||
description: Env specific secret containing the Exodus Gateway configs | ||
- name: exodusGwEnv | ||
type: string | ||
description: Environment to use in the Exodus Gateway. Options are [live, pre] | ||
- name: pulpSecret | ||
type: string | ||
description: Env specific secret containing the rhsm-pulp credentials | ||
- name: udcacheSecret | ||
type: string | ||
description: Env specific secret containing the udcache credentials | ||
- name: cgwHostname | ||
type: string | ||
description: Env specific hostname for content gateway | ||
- name: cgwSecret | ||
type: string | ||
description: Env specific secret containing the content gateway credentials | ||
results: | ||
- name: result | ||
description: Success if the task succeeds, the error otherwise | ||
steps: | ||
- name: pull-and-push-images | ||
image: quay.io/konflux-ci/release-service-utils:6556e8a6b031c1aad4f0472703fd121a6e1cd45d | ||
env: | ||
- name: EXODUS_CERT | ||
valueFrom: | ||
secretKeyRef: | ||
name: $(params.exodusGwSecret) | ||
key: cert | ||
- name: EXODUS_KEY | ||
valueFrom: | ||
secretKeyRef: | ||
name: $(params.exodusGwSecret) | ||
key: key | ||
- name: EXODUS_URL | ||
valueFrom: | ||
secretKeyRef: | ||
name: $(params.exodusGwSecret) | ||
key: url | ||
- name: PULP_URL | ||
valueFrom: | ||
secretKeyRef: | ||
name: $(params.pulpSecret) | ||
key: pulp_url | ||
- name: PULP_CERT | ||
valueFrom: | ||
secretKeyRef: | ||
name: $(params.pulpSecret) | ||
key: konflux-release-rhsm-pulp.crt | ||
- name: PULP_KEY | ||
valueFrom: | ||
secretKeyRef: | ||
name: $(params.pulpSecret) | ||
key: konflux-release-rhsm-pulp.key | ||
- name: UDC_URL | ||
valueFrom: | ||
secretKeyRef: | ||
name: $(params.udcacheSecret) | ||
key: url | ||
- name: UDC_CERT | ||
valueFrom: | ||
secretKeyRef: | ||
name: $(params.udcacheSecret) | ||
key: cert | ||
- name: UDC_KEY | ||
valueFrom: | ||
secretKeyRef: | ||
name: $(params.udcacheSecret) | ||
key: key | ||
- name: DOCKER_CONFIG_JSON | ||
valueFrom: | ||
secretKeyRef: | ||
name: redhat-workloads-token | ||
key: .dockerconfigjson | ||
- name: "SNAPSHOT_JSON" | ||
value: "$(params.snapshot_json)" | ||
- name: CGW_USERNAME | ||
valueFrom: | ||
secretKeyRef: | ||
name: $(params.cgwSecret) | ||
key: username | ||
- name: CGW_PASSWORD | ||
valueFrom: | ||
secretKeyRef: | ||
name: $(params.cgwSecret) | ||
key: token | ||
script: | | ||
#!/usr/bin/env bash | ||
set -ex | ||
STDERR_FILE=/tmp/stderr.txt | ||
exitfunc() { | ||
local err=$1 | ||
local line=$2 | ||
local command="$3" | ||
if [ "$err" -eq 0 ] ; then | ||
echo -n "Success" > "$(results.result.path)" | ||
else | ||
echo "$0: ERROR '$command' failed at line $line - exited with status $err" \ | ||
> "$(results.result.path)" | ||
if [ -f "$STDERR_FILE" ] ; then | ||
tail -n 20 "$STDERR_FILE" >> "$(results.result.path)" | ||
fi | ||
fi | ||
exit 0 # exit the script cleanly as there is no point in proceeding past an error or exit call | ||
} | ||
# due to set -e, this catches all EXIT and ERR calls and the task should never fail with nonzero exit code | ||
trap 'exitfunc $? $LINENO "$BASH_COMMAND"' EXIT | ||
# Setup required variables | ||
export EXODUS_GW_CERT=/tmp/exodus.crt | ||
export EXODUS_GW_KEY=/tmp/exodus.key | ||
export PULP_CERT_FILE=/tmp/pulp.crt | ||
export PULP_KEY_FILE=/tmp/pulp.key | ||
export UDCACHE_CERT=/tmp/udc.crt | ||
export UDCACHE_KEY=/tmp/udc.key | ||
EXODUS_GW_ENV=$(params.exodusGwEnv) | ||
export EXODUS_GW_ENV | ||
export EXODUS_GW_URL="$EXODUS_URL" | ||
export EXODUS_PULP_HOOK_ENABLED=True | ||
export EXODUS_GW_TIMEOUT=7200 | ||
mkdir -p ~/.docker | ||
set +x | ||
echo "$EXODUS_CERT" > "$EXODUS_GW_CERT" | ||
echo "$EXODUS_KEY" > "$EXODUS_GW_KEY" | ||
echo "$PULP_CERT" > "$PULP_CERT_FILE" | ||
echo "$PULP_KEY" > "$PULP_KEY_FILE" | ||
echo "$UDC_CERT" > "$UDCACHE_CERT" | ||
echo "$UDC_KEY" > "$UDCACHE_KEY" | ||
# Quotes are added to the secret so it applies in k8s nicely. But now we have to remove them | ||
echo "$DOCKER_CONFIG_JSON" | sed -r 's/(^|\})[^{}]+(\{|$)/\1\2/g' > ~/.docker/config.json | ||
set -x | ||
DISK_IMAGE_DIR="$(mktemp -d)" | ||
export DISK_IMAGE_DIR | ||
process_component() { # Expected argument is [component json] | ||
COMPONENT=$1 | ||
PULLSPEC=$(jq -er '.containerImage' <<< "${COMPONENT}") | ||
DESTINATION="${DISK_IMAGE_DIR}/$(jq -er '.staged.destination' <<< "${COMPONENT}")/FILES" \ | ||
|| (echo "Missing staged.destination value for component. This should be an existing pulp repo. \ | ||
Failing" && exit 1) | ||
mkdir -p "${DESTINATION}" | ||
DOWNLOAD_DIR=$(mktemp -d) | ||
cd "$DOWNLOAD_DIR" | ||
# oras has very limited support for selecting the right auth entry, | ||
# so create a custom auth file with just one entry | ||
AUTH_FILE=$(mktemp) | ||
select-oci-auth "${PULLSPEC}" > "$AUTH_FILE" | ||
oras pull --registry-config "$AUTH_FILE" "$PULLSPEC" | ||
NUM_MAPPED_FILES=$(jq '.staged.files | length' <<< "${COMPONENT}") | ||
for ((i = 0; i < NUM_MAPPED_FILES; i++)) ; do | ||
FILE=$(jq -c --arg i "$i" '.staged.files[$i|tonumber]' <<< "$COMPONENT") | ||
SOURCE=$(jq -er '.source' <<< "$FILE") | ||
FILENAME=$(jq -er '.filename' <<< "$FILE") | ||
# The .qcow2 images are not zipped | ||
if [ -f "${SOURCE}.gz" ] ; then | ||
gzip -d "${SOURCE}.gz" | ||
fi | ||
DESTINATION_FILE="${DESTINATION}/${FILENAME}" | ||
# Albeit a rare one, this is a race condition since this is run in parallel. | ||
# The race condition is if two files have the same $DESTINATION_FILE and both | ||
# if checks are run before either mv is run a few lines below. | ||
if [ -f "${DESTINATION_FILE}" ] ; then | ||
echo -n "Multiple files use the same destination value: $DESTINATION" >&2 | ||
echo " and filename value: $FILENAME. Failing..." >&2 | ||
exit 1 | ||
fi | ||
mv "$SOURCE" "${DESTINATION_FILE}" || echo "didn't find mapped file: ${SOURCE}" | ||
done | ||
} | ||
process_component_for_developer_portal() { # Expected argument are [component json], [content_directory] | ||
COMPONENT=$1 | ||
contentGatewayConfig="$(jq -c '.contentGateway // {}' <<< "${COMPONENT}")" | ||
contentGatewayConfigSize="$(jq '. | length' <<< "${contentGatewayConfig}")" | ||
if [ "${contentGatewayConfigSize}" == "0" ]; then | ||
echo "Configuration is not defined for Developer Portal publishing...skipping component" | ||
return | ||
fi | ||
productName="$(jq -er '.productName' <<< "${contentGatewayConfig}")" \ | ||
|| (echo "Missing contentGateway.productName value for component. This should be an existing product \ | ||
in the Developer Portal. Failing" && exit 1) | ||
productCode="$(jq -er '.productCode' <<< "${contentGatewayConfig}")" \ | ||
|| (echo "Missing contentGateway.productCode value for component. This should be an existing product \ | ||
in the Developer Portal. Failing" && exit 1) | ||
productVersionName="$(jq -er '.productVersionName' <<< "${contentGatewayConfig}")" \ | ||
|| (echo "Missing contentGateway.productVersionName value for component. This should be an existing \ | ||
product in the Developer Portal. Failing" && exit 1) | ||
filePrefix="$(jq -er '.filePrefix' <<< "${contentGatewayConfig}")" \ | ||
|| (echo "Missing contentGateway.filePrefix value for component. This should be the prefix for files to \ | ||
upload to the Developer Portal. Failing" && exit 1) | ||
developer_portal_wrapper --debug --product-name "${productName}" \ | ||
--product-code "${productCode}" \ | ||
--product-version-name "${productVersionName}" \ | ||
--cgw-hostname "$(params.cgwHostname)" \ | ||
--content-directory "$2" \ | ||
--file-prefix "${filePrefix}" | ||
} | ||
RUNNING_JOBS="\j" # Bash parameter for number of jobs currently running | ||
NUM_COMPONENTS=$(jq '.components | length' <<< "$SNAPSHOT_JSON") | ||
# use the 1st component's version | ||
VERSION=$(jq -cr '.components[0].staged.version // ""' <<< "$SNAPSHOT_JSON") | ||
if [ "${VERSION}" == "" ] ; then | ||
echo "Error: version not specified in .components[0].staged.version. Needed to publish to customer portal" | ||
exit 1 | ||
fi | ||
# Process each component in parallel | ||
for ((i = 0; i < NUM_COMPONENTS; i++)) ; do | ||
COMPONENT=$(jq -c --arg i "$i" '.components[$i|tonumber]' <<< "$SNAPSHOT_JSON") | ||
# Limit batch size to concurrent limit | ||
while (( ${RUNNING_JOBS@P} >= $(params.concurrentLimit) )); do | ||
wait -n | ||
done | ||
process_component "$COMPONENT" 2> "$STDERR_FILE" & | ||
done | ||
# Wait for remaining processes to finish | ||
while (( ${RUNNING_JOBS@P} > 0 )); do | ||
wait -n | ||
done | ||
# Change to the subdir with the images | ||
cd "${DISK_IMAGE_DIR}" | ||
STAGED_JSON='{"header":{"version": "0.2"},"payload":{"files":[]}}' | ||
# Add the files to the payload | ||
# shell check wants us to find ./* but that adds `./` to the paths which breaks the script | ||
# shellcheck disable=SC2035 | ||
while IFS= read -r -d '' file ; do | ||
STAGED_JSON=$(jq --arg filename "$(basename "$file")" --arg path "$file" \ | ||
--arg version "$VERSION" \ | ||
'.payload.files[.payload.files | length] = | ||
{"filename": $filename, "relative_path": $path, "version": $version}' <<< "$STAGED_JSON") | ||
done < <(find * -type f -print0) | ||
echo "$STAGED_JSON" | yq -P -I 4 > staged.yaml | ||
pulp_push_wrapper --debug --source "${DISK_IMAGE_DIR}" --pulp-url "$PULP_URL" \ | ||
--pulp-cert $PULP_CERT_FILE --pulp-key $PULP_KEY_FILE --udcache-url "$UDC_URL" \ | ||
2> "$STDERR_FILE" | ||
relative_paths=$(echo "$STAGED_JSON" | jq -erc .payload.files[].relative_path) | ||
component_destinations=() | ||
for path in $relative_paths: | ||
do | ||
parent_dir=$(dirname "$path") | ||
component_destinations+=("${DISK_IMAGE_DIR}/$parent_dir") | ||
done | ||
## Process Files for Developer Portal / CGW | ||
## | ||
NUM_COMPONENTS=$(jq '.components | length' <<< "$SNAPSHOT_JSON") | ||
for ((i = 0; i < NUM_COMPONENTS; i++)) ; do | ||
COMPONENT=$(jq -c --arg i "$i" '.components[$i|tonumber]' <<< "$SNAPSHOT_JSON") | ||
process_component_for_developer_portal "$COMPONENT" "${component_destinations[$i]}" 2> "$STDERR_FILE" | ||
done |
Oops, something went wrong.