forked from konflux-ci/release-service-catalog
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
chore(RELEASE-1039): add create-advisory internal task and pipeline (k…
…onflux-ci#710) This commit moves the create-advisory pipeline and task from the app-interface repo to the internal directory of this repo. It also adds tests and a README with it. Also resolves RELEASE-1097 Signed-off-by: Johnny Bieren <[email protected]>
- Loading branch information
1 parent
c18297b
commit fe8d948
Showing
10 changed files
with
469 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,16 @@ | ||
# create-advisory pipeline | ||
|
||
Tekton pipeline to execute the create-advisory task. The task clones the advisory repo, gets an ID for the advisory, | ||
generates an advisory, then pushes it if the generated advisory is valid. The pipeline returns a result with the | ||
advisory URL as well as a result to show the error message if one occurred. | ||
|
||
## Parameters | ||
|
||
| Name | Description | Optional | Default value | | ||
|----------------------|--------------------------------------------------------------------------------------------------------|----------|---------------| | ||
| advisory_json | String containing a JSON representation of the advisory data (e.g. '{"product_id":123,"type":"RHSA"}') | No | - | | ||
| application | Application being released | No | - | | ||
| origin | The origin workspace where the release CR comes from. This is used to determine the advisory path | No | - | | ||
| config_map_name | The name of the configMap that contains the signing key | No | - | | ||
| advisory_secret_name | The name of the secret that contains the advisory creation metadata | No | - | | ||
| errata_secret_name | The name of the secret that contains the errata service account metadata | 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,57 @@ | ||
--- | ||
apiVersion: tekton.dev/v1 | ||
kind: Pipeline | ||
metadata: | ||
name: create-advisory | ||
labels: | ||
app.kubernetes.io/version: "0.5.0" | ||
annotations: | ||
tekton.dev/pipelines.minVersion: "0.12.1" | ||
tekton.dev/tags: advisory | ||
spec: | ||
description: >- | ||
Pipeline to push an advisory yaml to a Git repository | ||
params: | ||
- name: advisory_json | ||
type: string | ||
description: | | ||
String containing a JSON representation of the advisory data (e.g. '{"product_id":123,"type":"RHSA"}') | ||
- name: application | ||
type: string | ||
description: Application being released | ||
- name: origin | ||
type: string | ||
description: | | ||
The origin workspace where the release CR comes from. | ||
This is used to determine the advisory path | ||
- name: config_map_name | ||
type: string | ||
description: The name of the configMap that contains the signing key | ||
- name: advisory_secret_name | ||
type: string | ||
description: The name of the secret that contains the advisory creation metadata | ||
- name: errata_secret_name | ||
type: string | ||
description: The name of the secret that contains the errata service account metadata | ||
tasks: | ||
- name: create-advisory-task | ||
taskRef: | ||
name: create-advisory-task | ||
params: | ||
- name: advisory_json | ||
value: $(params.advisory_json) | ||
- name: application | ||
value: $(params.application) | ||
- name: origin | ||
value: $(params.origin) | ||
- name: config_map_name | ||
value: $(params.config_map_name) | ||
- name: advisory_secret_name | ||
value: $(params.advisory_secret_name) | ||
- name: errata_secret_name | ||
value: $(params.errata_secret_name) | ||
results: | ||
- name: result | ||
value: $(tasks.create-advisory-task.results.result) | ||
- name: advisory_url | ||
value: $(tasks.create-advisory-task.results.advisory_url) |
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/create-advisory-task/create-advisory-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/create-advisory/create-advisory.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 @@ | ||
# create-advisory-task | ||
|
||
Pushes an advisory yaml to a Git repository. The task will always exit 0 even if something fails. This is because the task result | ||
will not be set if the task fails, and the task result should always be set and propagated back to the cluster that creates the | ||
internal request. The success/failure is handled in the task creating the internal request. | ||
|
||
## Parameters | ||
|
||
| Name | Description | Optional | Default value | | ||
|----------------------|--------------------------------------------------------------------------------------------------------|----------|---------------| | ||
| advisory_json | String containing a JSON representation of the advisory data (e.g. '{"product_id":123,"type":"RHSA"}') | No | - | | ||
| application | Application being released | No | - | | ||
| origin | The origin workspace where the release CR comes from. This is used to determine the advisory path | No | - | | ||
| config_map_name | The name of the configMap that contains the signing key | No | - | | ||
| advisory_secret_name | The name of the secret that contains the advisory creation metadata | No | - | | ||
| errata_secret_name | The name of the secret that contains the errata service account metadata | No | - | |
177 changes: 177 additions & 0 deletions
177
internal/tasks/create-advisory-task/create-advisory-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,177 @@ | ||
--- | ||
apiVersion: tekton.dev/v1 | ||
kind: Task | ||
metadata: | ||
name: create-advisory-task | ||
labels: | ||
app.kubernetes.io/version: "0.11.0" | ||
annotations: | ||
tekton.dev/pipelines.minVersion: "0.12.1" | ||
tekton.dev/tags: release | ||
spec: | ||
description: | | ||
Pushes an advisory yaml to a Git repository. | ||
The task will always exit 0 even if something fails. This is because the task result will not be | ||
set if the task fails, and the task result should always be set and propagated back to the cluster | ||
that creates the internal request. The success/failure is handled in the task creating the internal | ||
request. | ||
params: | ||
- name: advisory_json | ||
type: string | ||
description: | | ||
String containing a JSON representation of the advisory data (e.g. '{"product_id":123,"type":"RHSA"}'). | ||
- name: application | ||
type: string | ||
description: Application being released | ||
- name: origin | ||
type: string | ||
description: | | ||
The origin workspace where the release CR comes from. | ||
This is used to determine the advisory path | ||
- name: config_map_name | ||
type: string | ||
description: The name of the configMap that contains the signing key | ||
- name: advisory_secret_name | ||
type: string | ||
description: The name of the secret that contains the advisory creation metadata | ||
- name: errata_secret_name | ||
type: string | ||
description: The name of the secret that contains the errata service account metadata | ||
results: | ||
- name: result | ||
description: Success if the task succeeds, the error otherwise | ||
- name: advisory_url | ||
description: The advisory url if the task succeeds, empty string otherwise | ||
steps: | ||
- name: create-advisory | ||
image: quay.io/konflux-ci/release-service-utils:9089cafbf36bb889b4b73d8c2965613810f13736 | ||
env: | ||
- name: GITLAB_HOST | ||
valueFrom: | ||
secretKeyRef: | ||
name: $(params.advisory_secret_name) | ||
key: gitlab_host | ||
# This is a GitLab Project access token. Go to the settings/access_tokens page | ||
# of your repository to create one. It should have the Developer role with read | ||
# and write repository rights. | ||
- name: ACCESS_TOKEN | ||
valueFrom: | ||
secretKeyRef: | ||
name: $(params.advisory_secret_name) | ||
key: gitlab_access_token | ||
- name: GIT_AUTHOR_NAME | ||
valueFrom: | ||
secretKeyRef: | ||
name: $(params.advisory_secret_name) | ||
key: git_author_name | ||
- name: GIT_AUTHOR_EMAIL | ||
valueFrom: | ||
secretKeyRef: | ||
name: $(params.advisory_secret_name) | ||
key: git_author_email | ||
- name: GIT_REPO | ||
valueFrom: | ||
secretKeyRef: | ||
name: $(params.advisory_secret_name) | ||
key: git_repo | ||
- name: ERRATA_API | ||
valueFrom: | ||
secretKeyRef: | ||
name: $(params.errata_secret_name) | ||
key: errata_api | ||
- name: SERVICE_ACCOUNT_NAME | ||
valueFrom: | ||
secretKeyRef: | ||
name: $(params.errata_secret_name) | ||
key: name | ||
- name: SERVICE_ACCOUNT_KEYTAB | ||
valueFrom: | ||
secretKeyRef: | ||
name: $(params.errata_secret_name) | ||
key: base64_keytab | ||
- name: "ADVISORY_JSON" | ||
value: "$(params.advisory_json)" | ||
script: | | ||
#!/usr/bin/env bash | ||
set -eo pipefail | ||
exitfunc() { | ||
local err=$1 | ||
local line=$2 | ||
local command="$3" | ||
if [ "$err" -eq 0 ] ; then | ||
echo -n "Success" > "$(results.result.path)" | ||
else | ||
echo -n \ | ||
"$0: ERROR '$command' failed at line $line - exited with status $err" > "$(results.result.path)" | ||
fi | ||
echo -n "${ADVISORY_URL}" > "$(results.advisory_url.path)" | ||
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 | ||
REPO_BRANCH=main | ||
ADVISORY_URL="" | ||
# Switch to /tmp to avoid filesystem permission issues | ||
cd /tmp | ||
# loading git and gitlab functions | ||
# shellcheck source=/dev/null | ||
. /home/utils/gitlab-functions | ||
# shellcheck source=/dev/null | ||
. /home/utils/git-functions | ||
gitlab_init | ||
git_functions_init | ||
# This also cds into the git repo | ||
git_clone_and_checkout --repository "$GIT_REPO" --revision "$REPO_BRANCH" | ||
# Inject signing key into ADVISORY_JSON | ||
signingKey=$(kubectl get configmap "$(params.config_map_name)" -o jsonpath="{.data.SIG_KEY_NAME}") | ||
advisoryJsonWithKey=$(jq -c --arg key "$signingKey" \ | ||
'.content.images[] += {"signingKey": $key}' <<< "$ADVISORY_JSON") | ||
# write keytab to file | ||
echo -n "${SERVICE_ACCOUNT_KEYTAB}" | base64 --decode > /tmp/keytab | ||
# workaround kinit: Invalid UID in persistent keyring name while getting default ccache | ||
KRB5CCNAME=$(mktemp) | ||
export KRB5CCNAME | ||
# see https://stackoverflow.com/a/12308187 | ||
KRB5_CONFIG=$(mktemp) | ||
export KRB5_CONFIG | ||
export KRB5_TRACE=/dev/stderr | ||
sed '/\[libdefaults\]/a\ dns_canonicalize_hostname = false' /etc/krb5.conf > "${KRB5_CONFIG}" | ||
kinit "${SERVICE_ACCOUNT_NAME}" -k -t /tmp/keytab | ||
ID=$(curl --retry 3 --negotiate -u : "${ERRATA_API}/advisory/reserve_live_id" -XPOST | jq -r '.live_id') | ||
ADVISORY_NUM=$(printf "%04d" "$ID") | ||
# Use ISO 8601 format in UTC/Zulu time, e.g. 2024-03-06T17:27:38Z | ||
SHIP_DATE=$(date -u +"%Y-%m-%dT%H:%M:%SZ") | ||
YEAR=${SHIP_DATE%%-*} # derive the year from the ship date | ||
# group advisories by <origin workspace>/year | ||
ADVISORY_DIR="data/advisories/$(params.origin)/${YEAR}/${ADVISORY_NUM}" | ||
mkdir -p "${ADVISORY_DIR}" | ||
ADVISORY_FILEPATH="${ADVISORY_DIR}/advisory.yaml" | ||
ADVISORY_NAME="${YEAR}:${ADVISORY_NUM}" | ||
# Prepare variables for the advisory template | ||
DATA=$(jq -c '{"advisory":{"spec":.}}' <<< "$advisoryJsonWithKey") | ||
DATA=$(jq -c --arg advisory_name "$ADVISORY_NAME" --arg advisory_ship_date "$SHIP_DATE" \ | ||
'$ARGS.named + .' <<< "$DATA") | ||
# Create advisory file | ||
/home/utils/apply_template.py -o "$ADVISORY_FILEPATH" --data "$DATA" \ | ||
--template /home/templates/advisory.yaml.jinja | ||
# Ensure the created advisory file passes the advisory schema | ||
check-jsonschema --schemafile schema/advisory.json "$ADVISORY_FILEPATH" | ||
git add "${ADVISORY_FILEPATH}" | ||
git commit -m "[Konflux Release] new advisory for $(params.application)" | ||
echo "Pushing to ${REPO_BRANCH}..." | ||
git_push_with_retries --branch $REPO_BRANCH --retries 5 --url origin | ||
# Construct the advisory url to report back to the user as a result | ||
# Note: This currently only supports gitlab repos, which is all we expect for now | ||
ADVISORY_URL="${GIT_REPO//\.git/}/-/blob/${REPO_BRANCH}/${ADVISORY_FILEPATH}" |
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,66 @@ | ||
#!/usr/bin/env bash | ||
set -eux | ||
|
||
# mocks to be injected into task step scripts | ||
function git() { | ||
echo "Mock git called with: $*" | ||
|
||
if [[ "$*" == *"clone"* ]]; then | ||
gitRepo=$(echo "$*" | cut -f5 -d/ | cut -f1 -d.) | ||
mkdir -p "$gitRepo"/schema | ||
echo '{"$schema": "http://json-schema.org/draft-07/schema#","type": "object", "properties":{}}' > "$gitRepo"/schema/advisory.json | ||
elif [[ "$*" == *"failing-tenant"* ]]; then | ||
echo "Mocking failing git command" && false | ||
else | ||
# Mock the other git functions to pass | ||
: # no-op - do nothing | ||
fi | ||
} | ||
|
||
function glab() { | ||
echo "Mock glab called with: $*" | ||
|
||
if [[ "$*" != "auth login"* ]]; then | ||
echo Error: Unexpected call | ||
exit 1 | ||
fi | ||
} | ||
|
||
function kinit() { | ||
echo "kinit $*" | ||
} | ||
|
||
function curl() { | ||
echo Mock curl called with: $* >&2 | ||
|
||
if [[ "$*" == "--retry 3 --negotiate -u : https://errata/api/v1/advisory/reserve_live_id -XPOST" ]] ; then | ||
echo '{"live_id": 1234}' | ||
else | ||
echo Error: Unexpected call | ||
exit 1 | ||
fi | ||
} | ||
|
||
function date() { | ||
echo Mock date called with: $* >&2 | ||
|
||
case "$*" in | ||
*"+%Y-%m-%dT%H:%M:%SZ") | ||
echo "2024-12-12T00:00:00Z" | ||
;; | ||
"*") | ||
echo Error: Unexpected call | ||
exit 1 | ||
;; | ||
esac | ||
} | ||
|
||
function kubectl() { | ||
# The default SA doesn't have perms to get configmaps, so mock the `kubectl get configmap` call | ||
if [[ "$*" == "get configmap create-advisory-test-cm -o jsonpath={.data.SIG_KEY_NAME}" ]] | ||
then | ||
echo key1 | ||
else | ||
/usr/bin/kubectl $* | ||
fi | ||
} |
13 changes: 13 additions & 0 deletions
13
internal/tasks/create-advisory-task/tests/pre-apply-task-hook.sh
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,13 @@ | ||
#!/usr/bin/env bash | ||
|
||
TASK_PATH="$1" | ||
SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) | ||
|
||
# Add mocks to the beginning of task step script | ||
yq -i '.spec.steps[0].script = load_str("'$SCRIPT_DIR'/mocks.sh") + .spec.steps[0].script' "$TASK_PATH" | ||
|
||
kubectl delete secret create-advisory-secret --ignore-not-found | ||
kubectl create secret generic create-advisory-secret --from-literal=git_author_email=tester@tester --from-literal=git_author_name=tester --from-literal=gitlab_access_token=abc --from-literal=gitlab_host=myurl --from-literal=git_repo=https://gitlab.com/org/repo.git | ||
|
||
kubectl delete secret create-advisory-errata-secret --ignore-not-found | ||
kubectl create secret generic create-advisory-errata-secret --from-literal=errata_api=https://errata/api/v1 --from-literal=name=errata-tester --from-literal=base64_keytab=Zm9vCg== |
Oops, something went wrong.