Skip to content

Commit

Permalink
Create Tekton task and Pipeline for Tekton bundles
Browse files Browse the repository at this point in the history
This adds `tkn-bundle` Tekton Task that simply finds all *.yaml or *.yml
files in the current `params.CONTEXT` directory and creates a Tekton
Bundle by pushing it to `params.IMAGE`. The result of the task are
`IMAGE_URL` image reference with digest (no tag) and `IMAGE_DIGEST`
containing the image digest.

Also adds `tekton-bundle-builder` builder pipeline that uses the
`tkn-bundle` task for the `build` step.

Tests are provided.

Ref. https://issues.redhat.com/browse/HACBS-1675
  • Loading branch information
zregvart committed Jan 27, 2023
1 parent 1bd4a57 commit 9eec08d
Show file tree
Hide file tree
Showing 16 changed files with 345 additions and 0 deletions.
7 changes: 7 additions & 0 deletions pipeline-bundle-list
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
quay.io/zregvart_redhat/pipeline-docker-build:2023-01-27-105259@sha256:7cbf6db4ec0e9869a12c32dab7e44b3d5d2e24ad30dcf73edb4a0fec812cea78
quay.io/zregvart_redhat/pipeline-hacbs-docker-build:2023-01-27-105259@sha256:bc651ab32e9d82e72ef48313f67ea3a4c554b693127edef2be71e6c286dfc627
quay.io/zregvart_redhat/pipeline-enterprise-contract:2023-01-27-105259@sha256:8ab81616d92fadc65cec43fef6bcdb23dfdd2ccb68efea1d1a1e263bf4833cd1
quay.io/zregvart_redhat/pipeline-fbc-builder:2023-01-27-105259@sha256:c44ea2b5c2db24e0536aea2248641b9566abe6859ef617735337195592eb9395
quay.io/zregvart_redhat/pipeline-java-builder:2023-01-27-105259@sha256:b1c99b671377215aa8b0bea5669127b8bc29db5f628bf3b92d3fbca5046fe680
quay.io/zregvart_redhat/pipeline-nodejs-builder:2023-01-27-105259@sha256:9a70882f8ab7dc796bf2aebf05c2f6874fb8a216f61e3f5f1b8e9daba1c6f60f
quay.io/zregvart_redhat/pipeline-tekton-bundle-builder:2023-01-27-105259@sha256:d1befd9a00e8d9bcd704e24acdf34643459f6cc472598469e3ab3c6b60626674
1 change: 1 addition & 0 deletions pipelines/kustomization.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ resources:
- nodejs-builder
- enterprise-contract.yaml
- fbc-builder
- tekton-bundle-builder
20 changes: 20 additions & 0 deletions pipelines/tekton-bundle-builder/kustomization.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ../template-build

patches:
# Use the template-build as a template replacing the Pipeline name and the
# `build-container` step's task reference
- patch: |-
- op: replace
path: /metadata/name
value: tekton-bundle-builder
- op: replace
path: /spec/tasks/4/taskRef
value:
name: tkn-bundle
version: "0.1"
target:
kind: Pipeline
name: template-build
22 changes: 22 additions & 0 deletions task-bundle-list
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
quay.io/zregvart_redhat/task-buildah:0.1@sha256:a3d239d08534b0a00232a19409f9840cfda9913f885d3e5bc46be7b085fe0924
quay.io/zregvart_redhat/task-clair-scan:0.1@sha256:1bdce0c26366d092d02b1049fc0a2d02ec0a8662b33851b426197baee3d6cfae
quay.io/zregvart_redhat/task-clamav-scan:0.1@sha256:7dd9db4ad055fa3537290fd982599907744f282ee06a2a87445ce1d3a10f160e
quay.io/zregvart_redhat/task-cleanup-build-directories:0.1@sha256:55862c6f2492ed771e0bbda4d408bf040beb5670659d41ae181f18194004866c
quay.io/zregvart_redhat/task-configure-build:0.1@sha256:6a6626fa72e1ec615e28f43665770a06be3b5b2db819772680f2054f7372a83f
quay.io/zregvart_redhat/task-deprecated-image-check:0.1@sha256:f0e0a4af62ba639767a8fcf76f86554247cb98ad86c10270b7629ab13fe63478
quay.io/zregvart_redhat/task-fbc-validation:0.1@sha256:89894035aa4221402ac31b006f198e31f191c495057bdded23547746e257ccf2
quay.io/zregvart_redhat/task-git-clone:0.1@sha256:01aaab92ba115b45460de5c09cf91b3acbd53cbb3d5b58a77d6ec5b97188c45e
quay.io/zregvart_redhat/task-init:0.1@sha256:34947be27fd8b83e2fd829e40da1f85504d85213f4ec6d94a40e25973b313650
quay.io/zregvart_redhat/task-prefetch-dependencies:0.1@sha256:58eee789cfe5e015164c5ce1988b9006e2dd40f13315986eb8ae0dd0bed51b7f
quay.io/zregvart_redhat/task-s2i-java:0.1@sha256:87df051e8d704637522b665d3f222b01fef624b50642fa3d59ce56c1464607c4
quay.io/zregvart_redhat/task-s2i-nodejs:0.1@sha256:34c9a798a2e8094b1fc02b13e36fd8f71a5d10fd300ec2ef0acc77dc126cc423
quay.io/zregvart_redhat/task-sanity-inspect-image:0.1@sha256:dee638b481dd4825685c5d05b1d007a08d36c119cc15b62e7ba7125ba19886b4
quay.io/zregvart_redhat/task-sanity-label-check:0.1@sha256:2f5fa96ec08d1623bc6404c67738e1764c6e5c1c5f79f0a3705d6ba6879f7b02
quay.io/zregvart_redhat/task-sast-go:0.1@sha256:3e5e11ac564b81159af4a5e32bcc48c300346c0725056bba3246aadf5fa07383
quay.io/zregvart_redhat/task-sast-java-sec-check:0.1@sha256:e302565b411f04d31ff4e112d28d16ba6fb9fe7fce4d0ce9dfcbeb5178e8dc93
quay.io/zregvart_redhat/task-sast-snyk-check:0.1@sha256:5ddb96aac456948eda3f87fd74554390ead6bff4cf6e2f6840957ea991dcf98b
quay.io/zregvart_redhat/task-sbom-json-check:0.1@sha256:ca7011f6bc3f11f638742bd455af64b7c1eeeb748710b196673e26a0cc0d94a2
quay.io/zregvart_redhat/task-summary:0.1@sha256:a1ffa3d26220ac3c9c491b813f0df0c4f19ae09e173f430cbbcd9e77cfaabe8f
quay.io/zregvart_redhat/task-tkn-bundle:0.1@sha256:b6b563492d27df10da2936b5e1bab793b5e5df8f0be56bcad9143acc9de988c2
quay.io/zregvart_redhat/task-update-infra-deployments:0.1@sha256:f96509ced66af8f04f85fa819602366aef09ba55cffbc4f4f1f1bed618f30daa
quay.io/zregvart_redhat/task-utils-task:0.1@sha256:e4a5795d3f39222ded6f9158b620a6d5f73073368cd3fa2b4db3491970a8ac88
1 change: 1 addition & 0 deletions task/tkn-bundle/0.1/.shellspec
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
--require spec_helper
26 changes: 26 additions & 0 deletions task/tkn-bundle/0.1/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# tkn-bundle - Tekton Task to push a Tekton Bundle to an image registry

Tekton Task to build and push Tekton Bundles (OCI images) which contain
definitions of Tekton objects, most commonly Task and Pipeline objects.

Task finds all `*.yaml` or `*.yml` files within `CONTEXT`, packages and pushes
them as a Tekton Bundle to the image repository, name and tag specified by the
`IMAGE` parameter.

## Input Parameters

The task supports the following input parameters.

| Name | Example | Description |
|---------|-------------------------|------------------------------------------|
| IMAGE | registry.io/my-task:tag | Reference of the image task will produce |
| CONTEXT | my-task/0.1 | Path to the directory to use as context |

## Results

The task emits the following results.

| Name | Example | Description |
|--------------|-----------------------------------|---------------------------------------------------|
| IMAGE_URL | registry.io/my-task@sha256-abc... | Image repository where the built image was pushed |
| IMAGE_DIGEST | abc... | Digest of the image just built |
37 changes: 37 additions & 0 deletions task/tkn-bundle/0.1/TESTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# Testing tkn-bundle Tekton Task

Make sure you have shellspec installed[1]. The test setup script will bring up a
kind[2] cluster and installs Tekton Pipeline. The source is provided via the
`source-pvc` PersistantVolumeClaim and prepopulated with the test?.y*ml files in
order to not necesate the need for source checkout.

For second and subsequent invocations the setup is quicker as it only applies
any changes to already started and setup cluster. To delete the cluster and
start afresh run: `kind delete cluster --name=test-tkn-bundle`.

To run the tests run `shellspec` from this directory.

## Example of a testing setup and session

```shell
$ pwd
.../build-definitions/task/tkn-bundle/0.1
$ shellspec
Running: /bin/sh [bash 5.2.15(1)-release]
namespace/tekton-pipelines created
clusterrole.rbac.authorization.k8s.io/tekton-pipelines-controller-cluster-access created
...
pod "setup-1674815473" deleted
deployment.apps/registry created
service/registry created
deployment.apps/registry condition met
deployment.apps/tekton-pipelines-controller condition met
deployment.apps/tekton-pipelines-webhook condition met
..

Finished in 119.59 seconds (user 7.37 seconds, sys 4.03 seconds)
2 examples, 0 failures
```

[1] https://shellspec.info/
[2] https://kind.sigs.k8s.io/
10 changes: 10 additions & 0 deletions task/tkn-bundle/0.1/spec/spec_helper.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#!/bin/env bash

set -o errexit
set -o pipefail
set -o nounset

spec_helper_configure() {
import 'support/task_run_subject'
import 'support/jq_matcher'
}
30 changes: 30 additions & 0 deletions task/tkn-bundle/0.1/spec/support/jq_matcher.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#!/bin/env bash

set -o errexit
set -o pipefail
set -o nounset

shellspec_syntax 'shellspec_matcher_jq'

shellspec_matcher_jq() {
shellspec_matcher__match() {
SHELLSPEC_EXPECT="$1"
[ "${SHELLSPEC_SUBJECT+x}" ] || return 1
echo "${SHELLSPEC_SUBJECT}" | jq --exit-status "${SHELLSPEC_EXPECT}" > /dev/null || return 1
return 0
}

# Message when the matcher fails with "should"
shellspec_matcher__failure_message() {
shellspec_putsn "expected: JSON $1 should evaluate with success against jq expression: $2"
}

# Message when the matcher fails with "should not"
shellspec_matcher__failure_message_when_negated() {
shellspec_putsn "expected: JSON $1 should not evaluate with success against jq expression: $2"
}

# checking for parameter count
shellspec_syntax_param count [ $# -eq 1 ] || return 0
shellspec_matcher_do_match "$@"
}
26 changes: 26 additions & 0 deletions task/tkn-bundle/0.1/spec/support/task_run_subject.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#!/bin/env bash

set -o errexit
set -o pipefail
set -o nounset

shellspec_syntax 'shellspec_subject_taskrun'

shellspec_subject_taskrun() {
# shellcheck disable=SC2034
SHELLSPEC_META='text'
shellspec_readfile_once SHELLSPEC_STDOUT "$SHELLSPEC_STDOUT_FILE"
if [ ${SHELLSPEC_STDOUT+x} ]; then
# shellcheck disable=SC2034
LINES=(${SHELLSPEC_STDOUT[@]})
TASK_RUN_NAME="${LINES[2]}" # "TaskRun(0) started:(1) tkn-bundle-run-ndjfb(2)
SHELLSPEC_SUBJECT="$(tkn tr describe "${TASK_RUN_NAME}" -o json)"
shellspec_chomp SHELLSPEC_SUBJECT
else
unset SHELLSPEC_SUBJECT ||:
fi

shellspec_off UNHANDLED_STDOUT

eval shellspec_syntax_dispatch modifier ${1+'"$@"'}
}
4 changes: 4 additions & 0 deletions task/tkn-bundle/0.1/spec/test1.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
name: test1
4 changes: 4 additions & 0 deletions task/tkn-bundle/0.1/spec/test2.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
name: test2
4 changes: 4 additions & 0 deletions task/tkn-bundle/0.1/spec/test3.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
name: test3
104 changes: 104 additions & 0 deletions task/tkn-bundle/0.1/spec/tkn-bundle_spec.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
#!/bin/env bash

set -o errexit
set -o pipefail
set -o nounset

eval "$(shellspec - -c) exit 1"

Describe "tkn-bundle task"
setup() {
# Create Kind cluster if it doesn't exist already
CLUSTER_NAME="test-tkn-bundle"
kind get clusters -q | grep -q "${CLUSTER_NAME}" || kind create cluster -q --name="${CLUSTER_NAME}"

# Install Tekton Pipeline, proceed with the rest of the test of the setup
kubectl apply -f https://storage.googleapis.com/tekton-releases/pipeline/previous/v0.42.0/release.yaml

# Create the test namespace
kubectl create namespace test --dry-run=client -o yaml | kubectl apply -f -
kubectl config set-context --current --namespace=test
while ! kubectl get serviceaccount default 2> /dev/null
do
sleep 1
done

# Create the tkn-bundle Task
kubectl apply -f tkn-bundle.yaml

# Copy the task's YAML file to the persistent volume mounted as source for
# running the task via a setup Pod

# Create the PersistentVolumeClaim
echo 'apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: source-pvc
spec:
storageClassName: standard
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Mi
' | kubectl apply -f -

# Image to run the setup pod with, taken from the Task definition
IMAGE="$(kubectl get task tkn-bundle -o=jsonpath='{.spec.steps[0].image}')"
# Semi-random name for the setup Pod
SETUP_POD="setup-$(date +%s)"
# Run the pod with the volume mounted at /source, the container is blocking
# until "/stop" file is created
kubectl run "${SETUP_POD}" \
--restart=Never \
--image="${IMAGE}" \
--override-type=json \
--overrides='[
{"op":"add","path":"/spec/containers/0/volumeMounts","value":[{"name":"source","mountPath":"/source"}]},
{"op":"add","path":"/spec/volumes","value":[{"name":"source","persistentVolumeClaim":{"claimName":"source-pvc"}}]}]' \
--command -- bash -c 'while [ ! -f /stop ]; do sleep 1; done'
# Wait for the Pod to be ready
kubectl wait --for=condition=Ready "pod/${SETUP_POD}" --timeout=3m
# Clean the volume before proceeding
kubectl exec "${SETUP_POD}" -- sh -c 'rm -rf /source/*'

# Copy the files over
kubectl cp spec/test1.yaml "${SETUP_POD}:/source/"
kubectl cp spec/test2.yml "${SETUP_POD}:/source/"
kubectl exec "${SETUP_POD}" -- mkdir -p /source/sub
kubectl cp spec/test3.yaml "${SETUP_POD}:/source/sub/"

# Trigger the termination and delete the Pod
kubectl exec "${SETUP_POD}" -- touch /stop
kubectl delete pod "${SETUP_POD}"

# Deploy an image registry and expose it via a Service
kubectl create deployment registry --image=docker.io/registry:2.8.1 --port=5000 --dry-run=client -o yaml | kubectl apply -f -
kubectl create service clusterip registry --tcp=5000:5000 --dry-run=client -o yaml | kubectl apply -f -
kubectl wait deployment registry --for=condition=Available --timeout=3m

# Finally wait for Tekton Pipeline to be available
kubectl -n tekton-pipelines wait deployment -l "app.kubernetes.io/part-of=tekton-pipelines" --for=condition=Available --timeout=3m
}
BeforeAll 'setup'

It 'creates Tekton bundles'
When call tkn task start tkn-bundle -p IMAGE=registry:5000/bundle:tag --use-param-defaults --timeout 1m --showlog -w name=source,claimName=source-pvc
The output should include 'Added Task: test1 to image'
The output should include 'Added Task: test2 to image'
The output should include 'Added Task: test3 to image'
The output should include 'Pushed Tekton Bundle to registry:5000/bundle'
The taskrun should jq '.status.taskResults[] | select(.name=="IMAGE_DIGEST").value | test("sha256:[a-z0-9]+")'
The taskrun should jq '.status.taskResults[] | select(.name=="IMAGE_URL").value | test("registry:5000/bundle@sha256:[a-z0-9]+")'
End

It 'creates Tekton bundles from specific context'
When call tkn task start tkn-bundle -p IMAGE=registry:5000/sub:tag -p CONTEXT=sub --timeout 1m --showlog -w name=source,claimName=source-pvc
The output should not include 'Added Task: test1 to image'
The output should not include 'Added Task: test2 to image'
The output should include 'Added Task: test3 to image'
The output should include 'Pushed Tekton Bundle to registry:5000/sub'
The taskrun should jq '.status.taskResults[] | select(.name=="IMAGE_DIGEST").value | test("sha256:[a-z0-9]+")'
The taskrun should jq '.status.taskResults[] | select(.name=="IMAGE_URL").value | test("registry:5000/sub@sha256:[a-z0-9]+")'
End
End
48 changes: 48 additions & 0 deletions task/tkn-bundle/0.1/tkn-bundle.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
labels:
app.kubernetes.io/version: "0.1"
annotations:
tekton.dev/pipelines.minVersion: "0.12.1"
tekton.dev/tags: "image-build, appstudio, hacbs"
name: tkn-bundle
spec:
description: |-
Creates and pushes a Tekton bundle containing the specified Tekton YAML files.
params:
- description: Reference of the image task will produce.
name: IMAGE
type: string
- default: .
description: Path to the directory to use as context.
name: CONTEXT
type: string
results:
- description: Digest of the image just built
name: IMAGE_DIGEST
- description: Image repository where the built image was pushed
name: IMAGE_URL
steps:
- image: quay.io/redhat-appstudio/appstudio-utils:4580b3ba3012095ff3981e50b6bbf753d4afd4c3
name: build
script: |
#!/bin/env bash
set -o errexit
set -o pipefail
set -o nounset
readarray FILES < <(find $(params.CONTEXT) \( -name '*.yaml' -o -name '*.yml' \))
[[ ${#FILES[@]} -eq 0 ]] \
&& echo 'No YAML files found in "$(params.CONTEXT)", aborting the build' \
&& exit 1
exec 3>&1;
OUT="$(tkn bundle push "$(params.IMAGE)" \
$(printf ' -f %s' "${FILES[@]}") \
|tee /proc/self/fd/3)"
echo "${OUT#*Pushed Tekton Bundle to }" > $(results.IMAGE_URL.path)
echo "${OUT#*Pushed Tekton Bundle to *@}" > $(results.IMAGE_DIGEST.path)
workingDir: $(workspaces.source.path)
workspaces:
- name: source
1 change: 1 addition & 0 deletions task/tkn-bundle/OWNERS
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
AppStudio/HACBS Team

0 comments on commit 9eec08d

Please sign in to comment.