diff --git a/stepactions/README.md b/stepactions/README.md new file mode 100644 index 000000000..6fad02621 --- /dev/null +++ b/stepactions/README.md @@ -0,0 +1,13 @@ +# reduce-snapshot-action + +StepAction that reduces a snapshot to a single component based on the component that the snapshot was built for. + +## Parameters + +| Name | Description | Optional | Default value | +|-----------------------|---------------------------------------------|----------|---------------| +| IMAGES | String representation of Snapshot | No | - | +| SINGLE_COMPONENT | Single component enabled | No | - | +| CR_TO_QUERY | Custom Resource to query for built Snapshot | No | - | +| CR_TO_QUERY_NAMESPACE | Namespace where Custom Resource is found | Yes | "" | +| SNAPSHOT_PATH | The location to placed the reduced Snapshot | No | - | diff --git a/stepactions/reduce-snapshot/reduce-snapshot.yaml b/stepactions/reduce-snapshot/reduce-snapshot.yaml new file mode 100644 index 000000000..8c53173e6 --- /dev/null +++ b/stepactions/reduce-snapshot/reduce-snapshot.yaml @@ -0,0 +1,88 @@ +--- +apiVersion: tekton.dev/v1beta1 +kind: StepAction +metadata: + name: reduce-snapshot-action +spec: + image: quay.io/konflux-ci/appstudio-utils:ab6b0b8e40e440158e7288c73aff1cf83a2cc8a9@sha256:24179f0efd06c65d16868c2d7eb82573cce8e43533de6cea14fec3b7446e0b14 + params: + - name: IMAGES + type: string + - name: SINGLE_COMPONENT + type: string + - name: CR_TO_QUERY + type: string + - name: CR_TO_QUERY_NAMESPACE + type: string + default: "" + - name: SNAPSHOT_PATH + type: string + env: + - name: SNAPSHOT + value: $(params.IMAGES) + - name: SINGLE_COMPONENT + value: $(params.SINGLE_COMPONENT) + - name: CR_TO_QUERY + value: $(params.CR_TO_QUERY) + - name: CR_TO_QUERY_NAMESPACE + value: $(params.CR_TO_QUERY_NAMESPACE) + - name: SNAPSHOT_PATH + value: $(params.SNAPSHOT_PATH) + results: + - name: snapshotCreationComponent + description: Name of C + script: | + #!/usr/bin/env bash + set -eux + + echo "Single Component mode? ${SINGLE_COMPONENT}" + if [ "${SINGLE_COMPONENT}" == "true" ]; then + + CR_NAMESPACE_ARG="" + if [ ! -z "${CR_TO_QUERY_NAMESPACE}" ]; then + CR_NAMESPACE_ARG="-n ${CR_TO_QUERY_NAMESPACE}" + fi + SNAPSHOT_CREATION_TYPE=$(oc get "$CR_TO_QUERY" ${CR_NAMESPACE_ARG} -ojson \ + | jq -rec '.metadata.labels."test.appstudio.openshift.io/type" // ""') + SNAPSHOT_CREATION_COMPONENT=$(oc get "$CR_TO_QUERY" ${CR_NAMESPACE_ARG} -ojson \ + | jq -rec '.metadata.labels."appstudio.openshift.io/component" // ""') + + echo "SNAPSHOT_CREATION_TYPE: ${SNAPSHOT_CREATION_TYPE}" + echo "SNAPSHOT_CREATION_COMPONENT: ${SNAPSHOT_CREATION_COMPONENT}" + if [ "${SNAPSHOT_CREATION_TYPE}" == "component" ] && [ "${SNAPSHOT_CREATION_COMPONENT}" != "" ]; then + echo "Single Component mode is ${SINGLE_COMPONENT} and Snapshot type is component" + # verify if in json form + set +e + echo "${SNAPSHOT}" | jq -e > /dev/null 2>&1 + CHECK_JSON=$? + set -e + if [ "${CHECK_JSON}" != "0" ]; then + # try to load as file first + set +e + cat "${SNAPSHOT}" | jq -e > /dev/null 2>&1 + CHECK_JSON_FILE=$? + set -e + if [ "${CHECK_JSON_FILE}" != "0" ]; then + echo "Cannot load snapshot from json string or file" + exit 1 + fi + SNAPSHOT=$(cat "${SNAPSHOT}") + fi + REDUCED_SNAPSHOT=$(echo "${SNAPSHOT}" | jq --arg component "${SNAPSHOT_CREATION_COMPONENT}" \ + 'del(.components[] | select(.name != $component))') + + ## make sure we still have 1 component + COMPONENT_COUNT=$(echo "$REDUCED_SNAPSHOT" | jq -r '[ .components[] ] | length') + echo "COMPONENT_COUNT: ${COMPONENT_COUNT}" + if [ "${COMPONENT_COUNT}" != "1" ] ; then + echo "Error: Reduced Snapshot has ${COMPONENT_COUNT} components. It should contain 1" + echo " Verify that the Snapshot contains the built component: ${SNAPSHOT_CREATION_COMPONENT}" + exit 1 + fi + + echo "Reducing Snapshot to:" + echo "$REDUCED_SNAPSHOT" | jq . + SNAPSHOT=$(echo "$REDUCED_SNAPSHOT" | tr -d ' ' | tr -d '\n') + echo "$SNAPSHOT" > "${SNAPSHOT_PATH}" + fi + fi diff --git a/tasks/reduce-snapshot/README.md b/tasks/reduce-snapshot/README.md new file mode 100644 index 000000000..14636361f --- /dev/null +++ b/tasks/reduce-snapshot/README.md @@ -0,0 +1,15 @@ +# reduce-snapshot + +Tekton task to reduce a snapshot to a single component based on the component that the snapshot was built for. + +It uses the `reduce-snapshot-action` StepAction to perform the reduction. + +## Parameters + +| Name | Description | Optional | Default value | +|-----------------------|---------------------------------------------|----------|---------------| +| IMAGES | String representation of Snapshot | No | - | +| SINGLE_COMPONENT | Single component enabled | No | - | +| CR_TO_QUERY | Custom Resource to query for built Snapshot | No | - | +| CR_TO_QUERY_NAMESPACE | Namespace where Custom Resource is found | No | - | +| SNAPSHOT_PATH | The location to placed the reduced Snapshot | No | - | diff --git a/tasks/reduce-snapshot/reduce-snapshot.yaml b/tasks/reduce-snapshot/reduce-snapshot.yaml new file mode 100644 index 000000000..f2f1e4fdb --- /dev/null +++ b/tasks/reduce-snapshot/reduce-snapshot.yaml @@ -0,0 +1,49 @@ +--- +apiVersion: tekton.dev/v1 +kind: Task +metadata: + name: reduce-snapshot + 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 reduce snapshot + params: + - name: IMAGES + type: string + - name: SINGLE_COMPONENT + type: string + - name: CR_TO_QUERY + type: string + - name: CR_TO_QUERY_NAMESPACE + type: string + - name: SNAPSHOT_PATH + type: string + workspaces: + - name: data + description: Workspace to save the CR jsons to + steps: + - name: reduce + params: + - name: IMAGES + value: $(params.IMAGES) + - name: SINGLE_COMPONENT + value: $(params.SINGLE_COMPONENT) + - name: CR_TO_QUERY + value: $(params.CR_TO_QUERY) + - name: CR_TO_QUERY_NAMESPACE + value: $(params.CR_TO_QUERY_NAMESPACE) + - name: SNAPSHOT_PATH + value: $(params.SNAPSHOT_PATH) + ref: + resolver: git + params: + - name: url + value: https://github.com/konflux-ci/release-service-catalog + - name: revision + value: main + - name: pathInRepo + value: stepactions/reduce-snapshot/reduce-snapshot.yaml diff --git a/tasks/reduce-snapshot/tests/pre-apply-task-hook.sh b/tasks/reduce-snapshot/tests/pre-apply-task-hook.sh new file mode 100755 index 000000000..8c91e3e4e --- /dev/null +++ b/tasks/reduce-snapshot/tests/pre-apply-task-hook.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env bash + +# Install the CRDs so we can create/get them +.github/scripts/install_crds.sh + +# Add RBAC so that the SA executing the tests can retrieve CRs +kubectl apply -f .github/resources/crd_rbac.yaml + +# enable 'enable-step-actions' feature flag (already enabled in staging and production) +kubectl get cm/feature-flags -n tekton-pipelines -oyaml | \ + sed 's/\(enable-step-actions: .*$\)/enable-step-actions: "true"/' | \ + kubectl replace -f - + +# install dependent stepaction +kubectl apply -f stepactions/reduce-snapshot/reduce-snapshot.yaml + +# ensure local stepaction is used +TASK_PATH="$1" +yq -i 'del(.spec.steps[0].ref)' "$TASK_PATH" +yq -i '.spec.steps[0].ref.name = "reduce-snapshot-action"' "$TASK_PATH" diff --git a/tasks/reduce-snapshot/tests/test-reduce-snapshot-disabled-single-component-mode.yaml b/tasks/reduce-snapshot/tests/test-reduce-snapshot-disabled-single-component-mode.yaml new file mode 100644 index 000000000..6e87e9885 --- /dev/null +++ b/tasks/reduce-snapshot/tests/test-reduce-snapshot-disabled-single-component-mode.yaml @@ -0,0 +1,91 @@ +--- +apiVersion: tekton.dev/v1 +kind: Pipeline +metadata: + name: test-reduce-snapshot-disabled-single-component-mode +spec: + description: | + Run the reduce snapshot task with single component mode being false + workspaces: + - name: tests-workspace + tasks: + - name: setup + taskSpec: + steps: + - name: create-crs + image: quay.io/konflux-ci/release-service-utils:e633d51cd41d73e4b3310face21bb980af7a662f + script: | + #!/usr/bin/env bash + set -eux + + cat > snapshot << EOF + apiVersion: appstudio.redhat.com/v1alpha1 + kind: Snapshot + metadata: + name: snapshot-sample + namespace: default + spec: + application: foo + components: + - name: scott + containerImage: newimage + - name: tom + containerImage: newimage2 + EOF + kubectl apply -f snapshot + + kubectl get snapshot/snapshot-sample -ojson | jq .spec | tee $(workspaces.data.path)/snapshot.json + workspaces: + - name: data + workspace: tests-workspace + - name: run-task + taskRef: + name: reduce-snapshot + params: + - name: IMAGES + value: $(workspaces.data.path)/snapshot.json + - name: SINGLE_COMPONENT + value: false + - name: CR_TO_QUERY + value: snapshot/snapshot-sample + - name: CR_TO_QUERY_NAMESPACE + value: default + - name: SNAPSHOT_PATH + value: $(workspaces.data.path)/snapshot.json + runAfter: + - setup + workspaces: + - name: data + workspace: tests-workspace + - name: check-result + workspaces: + - name: data + workspace: tests-workspace + runAfter: + - run-task + taskSpec: + workspaces: + - name: data + steps: + - name: check-result + image: quay.io/konflux-ci/release-service-utils:e633d51cd41d73e4b3310face21bb980af7a662f + script: | + #!/usr/bin/env bash + set -eux + + cat "$(workspaces.data.path)/snapshot.json" + if [ "$(jq '.components | length' < "$(workspaces.data.path)/snapshot.json")" -ne 2 ]; then + echo "ERROR: Resulting snapshot does not contain 2 components" + exit 1 + fi + finally: + - name: cleanup + taskSpec: + steps: + - name: delete-crs + image: quay.io/konflux-ci/release-service-utils:e633d51cd41d73e4b3310face21bb980af7a662f + script: | + #!/usr/bin/env sh + set -eux + + kubectl delete snapshot snapshot-sample diff --git a/tasks/reduce-snapshot/tests/test-reduce-snapshot-missing-resource.yaml b/tasks/reduce-snapshot/tests/test-reduce-snapshot-missing-resource.yaml new file mode 100644 index 000000000..d925107ea --- /dev/null +++ b/tasks/reduce-snapshot/tests/test-reduce-snapshot-missing-resource.yaml @@ -0,0 +1,94 @@ +--- +apiVersion: tekton.dev/v1 +kind: Pipeline +metadata: + name: test-reduce-snapshot-missing-resources +spec: + description: | + Run the reduce task to reduce to a single component but CR to query is missing + workspaces: + - name: tests-workspace + tasks: + - name: setup + taskSpec: + steps: + - name: create-crs + image: quay.io/konflux-ci/release-service-utils:e633d51cd41d73e4b3310face21bb980af7a662f + script: | + #!/usr/bin/env bash + set -eux + + cat > snapshot << EOF + apiVersion: appstudio.redhat.com/v1alpha1 + kind: Snapshot + metadata: + name: snapshot-sample + namespace: default + labels: + test.appstudio.openshift.io/type: component + appstudio.openshift.io/component: tom + spec: + application: foo + components: + - name: scott + containerImage: newimage + - name: tom + containerImage: newimage2 + EOF + kubectl apply -f snapshot + + kubectl get snapshot/snapshot-sample -ojson | jq .spec | tee $(workspaces.data.path)/snapshot.json + workspaces: + - name: data + workspace: tests-workspace + - name: run-task + taskRef: + name: reduce-snapshot + params: + - name: IMAGES + value: $(workspaces.data.path)/snapshot.json + - name: SINGLE_COMPONENT + value: true + - name: CR_TO_QUERY + value: snapshot/snapshot-unknown + - name: CR_TO_QUERY_NAMESPACE + value: default + - name: SNAPSHOT_PATH + value: $(workspaces.data.path)/snapshot.json + runAfter: + - setup + workspaces: + - name: data + workspace: tests-workspace + - name: check-result + workspaces: + - name: data + workspace: tests-workspace + runAfter: + - run-task + taskSpec: + workspaces: + - name: data + steps: + - name: check-result + image: quay.io/konflux-ci/release-service-utils:e633d51cd41d73e4b3310face21bb980af7a662f + script: | + #!/usr/bin/env bash + set -eux + + cat "$(workspaces.data.path)/snapshot.json" + if [ "$(jq '.components | length' < "$(workspaces.data.path)/snapshot.json")" -ne 2 ]; then + echo "ERROR: Resulting snapshot does not contain 2 components" + exit 1 + fi + finally: + - name: cleanup + taskSpec: + steps: + - name: delete-crs + image: quay.io/konflux-ci/release-service-utils:e633d51cd41d73e4b3310face21bb980af7a662f + script: | + #!/usr/bin/env sh + set -eux + + kubectl delete snapshot snapshot-sample diff --git a/tasks/reduce-snapshot/tests/test-reduce-snapshot-no-labels.yaml b/tasks/reduce-snapshot/tests/test-reduce-snapshot-no-labels.yaml new file mode 100644 index 000000000..a5e58f1e3 --- /dev/null +++ b/tasks/reduce-snapshot/tests/test-reduce-snapshot-no-labels.yaml @@ -0,0 +1,91 @@ +--- +apiVersion: tekton.dev/v1 +kind: Pipeline +metadata: + name: test-reduce-snapshot-no-labels +spec: + description: | + Run the reduce snapshot task with missing labels + workspaces: + - name: tests-workspace + tasks: + - name: setup + taskSpec: + steps: + - name: create-crs + image: quay.io/konflux-ci/release-service-utils:e633d51cd41d73e4b3310face21bb980af7a662f + script: | + #!/usr/bin/env bash + set -eux + + cat > snapshot << EOF + apiVersion: appstudio.redhat.com/v1alpha1 + kind: Snapshot + metadata: + name: snapshot-sample + namespace: default + spec: + application: foo + components: + - name: scott + containerImage: newimage + - name: tom + containerImage: newimage2 + EOF + kubectl apply -f snapshot + + kubectl get snapshot/snapshot-sample -ojson | jq .spec | tee $(workspaces.data.path)/snapshot.json + workspaces: + - name: data + workspace: tests-workspace + - name: run-task + taskRef: + name: reduce-snapshot + params: + - name: IMAGES + value: $(workspaces.data.path)/snapshot.json + - name: SINGLE_COMPONENT + value: true + - name: CR_TO_QUERY + value: snapshot/snapshot-sample + - name: CR_TO_QUERY_NAMESPACE + value: default + - name: SNAPSHOT_PATH + value: $(workspaces.data.path)/snapshot.json + runAfter: + - setup + workspaces: + - name: data + workspace: tests-workspace + - name: check-result + workspaces: + - name: data + workspace: tests-workspace + runAfter: + - run-task + taskSpec: + workspaces: + - name: data + steps: + - name: check-result + image: quay.io/konflux-ci/release-service-utils:e633d51cd41d73e4b3310face21bb980af7a662f + script: | + #!/usr/bin/env bash + set -eux + + cat "$(workspaces.data.path)/snapshot.json" + if [ "$(jq '.components | length' < "$(workspaces.data.path)/snapshot.json")" -ne 2 ]; then + echo "ERROR: Resulting snapshot does not contain 2 components" + exit 1 + fi + finally: + - name: cleanup + taskSpec: + steps: + - name: delete-crs + image: quay.io/konflux-ci/release-service-utils:e633d51cd41d73e4b3310face21bb980af7a662f + script: | + #!/usr/bin/env sh + set -eux + + kubectl delete snapshot snapshot-sample diff --git a/tasks/reduce-snapshot/tests/test-reduce-snapshot-wrong-component.yaml b/tasks/reduce-snapshot/tests/test-reduce-snapshot-wrong-component.yaml new file mode 100644 index 000000000..c7b8ececc --- /dev/null +++ b/tasks/reduce-snapshot/tests/test-reduce-snapshot-wrong-component.yaml @@ -0,0 +1,96 @@ +--- +apiVersion: tekton.dev/v1 +kind: Pipeline +metadata: + name: test-reduce-snapshot-wrong-component + annotations: + test/assert-task-failure: "run-task" +spec: + description: | + Run the reduce task with a snapshot mentioning a component that does not exist + workspaces: + - name: tests-workspace + tasks: + - name: setup + taskSpec: + steps: + - name: create-crs + image: quay.io/konflux-ci/release-service-utils:e633d51cd41d73e4b3310face21bb980af7a662f + script: | + #!/usr/bin/env bash + set -eux + + cat > snapshot << EOF + apiVersion: appstudio.redhat.com/v1alpha1 + kind: Snapshot + metadata: + name: snapshot-sample + namespace: default + labels: + test.appstudio.openshift.io/type: component + appstudio.openshift.io/component: scoobydoo + spec: + application: foo + components: + - name: scott + containerImage: newimage + - name: tom + containerImage: newimage2 + EOF + kubectl apply -f snapshot + + kubectl get snapshot/snapshot-sample -ojson | jq .spec | tee $(workspaces.data.path)/snapshot.json + workspaces: + - name: data + workspace: tests-workspace + - name: run-task + taskRef: + name: reduce-snapshot + params: + - name: IMAGES + value: $(workspaces.data.path)/snapshot.json + - name: SINGLE_COMPONENT + value: true + - name: CR_TO_QUERY + value: snapshot/snapshot-sample + - name: CR_TO_QUERY_NAMESPACE + value: default + - name: SNAPSHOT_PATH + value: $(workspaces.data.path)/snapshot.json + runAfter: + - setup + workspaces: + - name: data + workspace: tests-workspace + - name: check-result + workspaces: + - name: data + workspace: tests-workspace + runAfter: + - run-task + taskSpec: + workspaces: + - name: data + steps: + - name: check-result + image: quay.io/konflux-ci/release-service-utils:e633d51cd41d73e4b3310face21bb980af7a662f + script: | + #!/usr/bin/env bash + set -eux + + cat "$(workspaces.data.path)/snapshot.json" + if [ "$(jq '.components | length' < "$(workspaces.data.path)/snapshot.json")" -ne 2 ]; then + echo "ERROR: Resulting snapshot does not contain 2 components" + exit 1 + fi + finally: + - name: cleanup + taskSpec: + steps: + - name: delete-crs + image: quay.io/konflux-ci/release-service-utils:e633d51cd41d73e4b3310face21bb980af7a662f + script: | + #!/usr/bin/env sh + set -eux + + kubectl delete snapshot snapshot-sample diff --git a/tasks/reduce-snapshot/tests/test-reduce-snapshot.yaml b/tasks/reduce-snapshot/tests/test-reduce-snapshot.yaml new file mode 100644 index 000000000..1bc4cdc1a --- /dev/null +++ b/tasks/reduce-snapshot/tests/test-reduce-snapshot.yaml @@ -0,0 +1,98 @@ +--- +apiVersion: tekton.dev/v1 +kind: Pipeline +metadata: + name: test-reduce-snapshot +spec: + description: | + Run the reduce task to reduce to a single component + workspaces: + - name: tests-workspace + tasks: + - name: setup + taskSpec: + steps: + - name: create-crs + image: quay.io/konflux-ci/release-service-utils:e633d51cd41d73e4b3310face21bb980af7a662f + script: | + #!/usr/bin/env bash + set -eux + + cat > snapshot << EOF + apiVersion: appstudio.redhat.com/v1alpha1 + kind: Snapshot + metadata: + name: snapshot-sample + namespace: default + labels: + test.appstudio.openshift.io/type: component + appstudio.openshift.io/component: tom + spec: + application: foo + components: + - name: scott + containerImage: newimage + - name: tom + containerImage: newimage2 + EOF + kubectl apply -f snapshot + + kubectl get snapshot/snapshot-sample -ojson | jq .spec | tee $(workspaces.data.path)/snapshot.json + workspaces: + - name: data + workspace: tests-workspace + - name: run-task + taskRef: + name: reduce-snapshot + params: + - name: IMAGES + value: $(workspaces.data.path)/snapshot.json + - name: SINGLE_COMPONENT + value: true + - name: CR_TO_QUERY + value: snapshot/snapshot-sample + - name: CR_TO_QUERY_NAMESPACE + value: default + - name: SNAPSHOT_PATH + value: $(workspaces.data.path)/snapshot.json + runAfter: + - setup + workspaces: + - name: data + workspace: tests-workspace + - name: check-result + workspaces: + - name: data + workspace: tests-workspace + runAfter: + - run-task + taskSpec: + workspaces: + - name: data + steps: + - name: check-result + image: quay.io/konflux-ci/release-service-utils:e633d51cd41d73e4b3310face21bb980af7a662f + script: | + #!/usr/bin/env bash + set -eux + + cat "$(workspaces.data.path)/snapshot.json" + if [ "$(jq '.components | length' < "$(workspaces.data.path)/snapshot.json")" -ne 1 ]; then + echo "ERROR: Resulting snapshot does not contain 1 component" + exit 1 + fi + if [ "$(jq -cr '.components[0].name' < "$(workspaces.data.path)/snapshot.json")" != "tom" ]; then + echo "ERROR: Resulting snapshot does not contain the 'tom' component" + exit 1 + fi + finally: + - name: cleanup + taskSpec: + steps: + - name: delete-crs + image: quay.io/konflux-ci/release-service-utils:e633d51cd41d73e4b3310face21bb980af7a662f + script: | + #!/usr/bin/env sh + set -eux + + kubectl delete snapshot snapshot-sample