diff --git a/task/bentoml/0.2/Dockerfile b/task/bentoml/0.2/Dockerfile new file mode 100644 index 0000000000..dc61d89035 --- /dev/null +++ b/task/bentoml/0.2/Dockerfile @@ -0,0 +1,10 @@ +FROM ubuntu:19.10 + +ENV PATH /usr/bin:$PATH + +RUN apt-get update +RUN apt-get update && apt-get install --no-install-recommends --yes python3 python3-pip python3-dev python-dev gcc g++ build-essential + +RUN pip3 install numpy Cython setuptools + +RUN pip3 --no-cache-dir install bentoml diff --git a/task/bentoml/0.2/README.md b/task/bentoml/0.2/README.md new file mode 100644 index 0000000000..e9b1ef63d4 --- /dev/null +++ b/task/bentoml/0.2/README.md @@ -0,0 +1,29 @@ +# BentoML + +This task allows operations on [BentoML](https://github.com/bentoml/BentoML) services. + +## Why BentoML Task? + +BentoML now supports the ability to retrieve artifact bundles via its cli. This will allow for in integration with CI, so models can be safely packaged into containers and deployed without any manual effort. The build context is auto-generated by BentoML and can be easily connected to CI/CD pipelines. This task offers a new pattern for data scientists. + +## Parameters + +* **YATAISERVICE**: Optional address of YataiService to connect to for command. + + _default_: ""` + +* **ARGS**: The arguments to pass to `bentoml` CLI. This parameter is required to run this task. + +### Examples + +Run `bentoml --help` for BentoML usage. Using the [Tekton CLI](https://github.com/tektoncd/cli/blob/main/docs/cmd/tkn_task_start.md) (`tkn`): + +Use bentoml to retrieve a full ML build environment in the cwd: + +```shell +tkn task start bentoml -p ARGS="retrieve ServiceName:20200616152703_9E2AD7","YATAISERVICE=10.10.10.1:50051 --target_dir=/workspace/storage" +``` + +## Platforms + +The Task can be run on `linux/amd64` platform. diff --git a/task/bentoml/0.2/bentoml.yaml b/task/bentoml/0.2/bentoml.yaml new file mode 100644 index 0000000000..5221db84f1 --- /dev/null +++ b/task/bentoml/0.2/bentoml.yaml @@ -0,0 +1,42 @@ +--- +apiVersion: tekton.dev/v1 +kind: Task +metadata: + name: bentoml + labels: + app.kubernetes.io/version: "0.2" + annotations: + tekton.dev/categories: Automation, Integration & Delivery + tekton.dev/pipelines.minVersion: "0.50.0" + tekton.dev/tags: cli + tekton.dev/platforms: "linux/amd64" +spec: + description: >- + This task allows operations on BentoML services + + BentoML now supports the ability to retrieve artifact bundles via its + cli. This will allow for in integration with CI, so models can be safely + packaged into containers and deployed without any manual effort. The + build context is auto-generated by BentoML and can be easily connected to + CI/CD pipelines. This task offers a new pattern for data scientists. + + params: + - name: ARGS + type: array + description: BentoML CLI arguments to run + - name: YATAISERVICE + type: string + description: BentoML CLI arguments to run + default: "" + steps: + - name: bento + image: docker.io/iancoffey/bentoml-python3@sha256:ac99d45853efa4750bd4e5f6bc4ab9a7d7aedce57e7930bbb6ef643f9892915d #tag: latest + command: ["bentoml"] + args: ["$(inputs.params.ARGS)"] + env: + - name: "BENTOML__YATAI_SERVICE__URL" + value: "$(inputs.params.YATAISERVICE)" + workspaces: + - name: bentoml + description: The folder where bentoml will write state to + mountPath: /workspace/bentoml diff --git a/task/bentoml/0.2/tests/run.yaml b/task/bentoml/0.2/tests/run.yaml new file mode 100644 index 0000000000..3a7a85fa66 --- /dev/null +++ b/task/bentoml/0.2/tests/run.yaml @@ -0,0 +1,14 @@ +--- +apiVersion: tekton.dev/v1 +kind: TaskRun +metadata: + name: bentoml-list-run +spec: + params: + - name: ARGS + value: ["list"] + taskRef: + name: bentoml + workspaces: + - name: bentoml + emptyDir: {} diff --git a/task/generate-build-id/0.2/README.md b/task/generate-build-id/0.2/README.md new file mode 100644 index 0000000000..ad4dab1a17 --- /dev/null +++ b/task/generate-build-id/0.2/README.md @@ -0,0 +1,128 @@ +# `buildid` + +Given a base version, this task generates a unique build id by appending the base-version to the current timestamp. + +## Install the Task + +``` +kubectl apply -f https://raw.githubusercontent.com/tektoncd/catalog/main/task/generate-build-id/0.2/generate-build-id.yaml +``` + +## Parameters + +* **base-version**: The base version to use in the generated build id. _default_: `["1.0"]` + +## Platforms + +The Task can be run on `linux/amd64`, `linux/s390x`, `linux/arm64` and `linux/ppc64le` platforms. + +## Platforms + +The Task can be run on `linux/amd64` platform. + +## Usage + +### Include the task inside a taskrun +In this example, we will demonstrate how to use the task to generate the build id by including it in a taskrun definition called `taskrun.yaml`: + +``` +apiVersion: tekton.dev/v1 +kind: TaskRun +metadata: + name: generate-build-id-run +spec: + params: + - name: base-version + value: "2.3.1" + taskRef: + name: generate-build-id +``` + +As can be seen from the example, the default `base-version` is being overridden by providing a new `base-version` value of `2.3.1` as input param to the task. + +The taskrun definition is then applied by installing it in Kubernetes cluster as `kubectl apply -f taskrun.yaml`. +Logs from the executed task are then retrieved using `tkn taskrun logs generate-build-id-run`: + +``` +#\> tkn taskrun logs generate-build-id-run +[get-timestamp] Current Timestamp: 20200617-180133 +[get-timestamp] 20200617-180133 + +[get-buildid] 2.3.1-20200617-180133 + +``` + +### Use the generated build id in another task in a pipeline definition +In this example, we will demonstrate how the generated build id can be used by another task by including them inside a pipeline definition. + +In the following example two tasks are included in a pipeline definition called `pipeline.yaml` + +``` +apiVersion: tekton.dev/v1 +kind: Pipeline +metadata: + name: pipeline-demo-generated-build-id +spec: + params: + - name: service-version + type: string + default: "3.1.1" + tasks: + - name: get-build-id + taskRef: + name: generate-build-id + params: + - name: base-version + value: $(params.service-version) + - name: build-api + taskRef: + name: build-service-api + params: + - name: build-id + value: "$(tasks.get-build-id.results.build-id)" +``` +As can be seen from the example the first task generates the build id while the second task consumes the generated build id. +In the task to generate the build id, we override the default value of `base-version` using the value of the `service-version` pipeline parameter that has currently been set to a default value of 3.1.1. +In the task to build the service api, we then pass the generated build from the first task as its input param called `build-id`. +For the sake of completeness, here is what the task to build the service api (`build-service-api.yaml`) looks like: + +``` +apiVersion: tekton.dev/v1 +kind: Task +metadata: + name: build-service-api +spec: + params: + - name: build-id + description: ID of the current build + type: string + steps: + - name: display-buildid + image: bash:latest + script: | + #!/usr/bin/env bash + echo "Provided Build ID: $(inputs.params.build-id)" +``` + +As can be seen above, this task accepts a build id as its input and displays it in its one and only step. + +The task to build the service api and pipeline are then installed using `kubectl apply -f build-service-api.yaml` and `kubectl apply -f pipeline.yaml`. +Once installed the pipeline is started using `tkn pipeline start pipeline-demo-generated-build-id`. +Logs from the executed pipeline demonstrate that the first task generated a build id while the second task consumed it: + +``` +#\> tkn pipeline start pipeline-demo-generated-build-id +? Value for param `service-version` of type `string`? (Default is `3.1.1`) 3.1.1 +Pipelinerun started: pipeline-demo-generated-build-id-run-g7tgw + +In order to track the pipelinerun progress run: +tkn pipelinerun logs pipeline-demo-generated-build-id-run-g7tgw -f -n default + +#\> tkn pipelinerun logs pipeline-demo-generated-build-id-run-g7tgw +[get-build-id : get-timestamp] Current Timestamp: 20200617-181338 +[get-build-id : get-timestamp] 20200617-181338 + +[get-build-id : get-buildid] 3.1.1-20200617-181338 + +[build-api : display-buildid] Provided Build ID: 3.1.1-20200617-181338 +``` diff --git a/task/generate-build-id/0.2/generate-build-id.yaml b/task/generate-build-id/0.2/generate-build-id.yaml new file mode 100644 index 0000000000..4ca3b56133 --- /dev/null +++ b/task/generate-build-id/0.2/generate-build-id.yaml @@ -0,0 +1,42 @@ +apiVersion: tekton.dev/v1 +kind: Task +metadata: + name: generate-build-id + labels: + app.kubernetes.io/version: "0.2" + annotations: + tekton.dev/pipelines.minVersion: "0.50.0" + tekton.dev/categories: Build Tools + tekton.dev/tags: build-tool + tekton.dev/displayName: "buildid" + tekton.dev/platforms: "linux/amd64,linux/s390x,linux/ppc64le,linux/arm64" +spec: + description: >- + Given a base version, this task generates a unique build id by appending + the base-version to the current timestamp. + + params: + - name: base-version + description: Base product version + type: string + default: "1.0" + results: + - name: timestamp + description: Current timestamp + - name: build-id + description: ID of the current build + steps: + - name: get-timestamp + image: docker.io/library/bash:5.0.18@sha256:879f94a9da53dc064779e7a68339aecd60a9028ff884cacaa47ae752ca690404 #tag: 5.0.18 + script: | + #!/usr/bin/env bash + ts=`date "+%Y%m%d-%H%M%S"` + echo "Current Timestamp: ${ts}" + echo ${ts} | tr -d "\n" | tee $(results.timestamp.path) + - name: get-buildid + image: docker.io/library/bash:5.0.18@sha256:879f94a9da53dc064779e7a68339aecd60a9028ff884cacaa47ae752ca690404 #tag: 5.0.18 + script: | + #!/usr/bin/env bash + ts=`cat $(results.timestamp.path)` + buildId=$(inputs.params.base-version)-${ts} + echo ${buildId} | tr -d "\n" | tee $(results.build-id.path) diff --git a/task/generate-build-id/0.2/samples/build-service-api.yaml b/task/generate-build-id/0.2/samples/build-service-api.yaml new file mode 100644 index 0000000000..edbb573736 --- /dev/null +++ b/task/generate-build-id/0.2/samples/build-service-api.yaml @@ -0,0 +1,15 @@ +apiVersion: tekton.dev/v1 +kind: Task +metadata: + name: build-service-api +spec: + params: + - name: build-id + description: ID of the current build + type: string + steps: + - name: display-buildid + image: bash:latest + script: | + #!/usr/bin/env bash + echo "Provided Build ID: $(inputs.params.build-id)" \ No newline at end of file diff --git a/task/generate-build-id/0.2/samples/pipeline.yaml b/task/generate-build-id/0.2/samples/pipeline.yaml new file mode 100644 index 0000000000..32f59846de --- /dev/null +++ b/task/generate-build-id/0.2/samples/pipeline.yaml @@ -0,0 +1,22 @@ +apiVersion: tekton.dev/v1 +kind: Pipeline +metadata: + name: pipeline-demo-generated-build-id +spec: + params: + - name: service-version + type: string + default: "3.1.1" + tasks: + - name: get-build-id + taskRef: + name: generate-build-id + params: + - name: base-version + value: $(params.service-version) + - name: build-api + taskRef: + name: build-service-api + params: + - name: build-id + value: "$(tasks.get-build-id.results.build-id)" \ No newline at end of file diff --git a/task/generate-build-id/0.2/samples/taskrun.yaml b/task/generate-build-id/0.2/samples/taskrun.yaml new file mode 100644 index 0000000000..0a9907d461 --- /dev/null +++ b/task/generate-build-id/0.2/samples/taskrun.yaml @@ -0,0 +1,10 @@ +apiVersion: tekton.dev/v1 +kind: TaskRun +metadata: + name: generate-build-id-run +spec: + params: + - name: base-version + value: "2.3.1" + taskRef: + name: generate-build-id \ No newline at end of file diff --git a/task/generate-build-id/0.2/tests/run.yaml b/task/generate-build-id/0.2/tests/run.yaml new file mode 100644 index 0000000000..13d4da0337 --- /dev/null +++ b/task/generate-build-id/0.2/tests/run.yaml @@ -0,0 +1,10 @@ +apiVersion: tekton.dev/v1 +kind: TaskRun +metadata: + name: generate-build-id-run +spec: + params: + - name: base-version + value: "1.0.0" + taskRef: + name: generate-build-id \ No newline at end of file diff --git a/task/goreleaser/0.3/README.md b/task/goreleaser/0.3/README.md new file mode 100644 index 0000000000..360fb469c7 --- /dev/null +++ b/task/goreleaser/0.3/README.md @@ -0,0 +1,112 @@ +# GoReleaser + +[GoReleaser](https://github.com/goreleaser/goreleaser) builds Go binaries for several platforms, creates a GitHub release and then pushes a Homebrew formula to a tap repository. + +## Installing the Task + +```bash +kubectl apply -f https://raw.githubusercontent.com/tektoncd/catalog/main/task/goreleaser/0.3/goreleaser.yaml +``` + +## Parameters + +- **package**: Base package to build and release. (Required) +- **github-token-secret**: Name of the secret holding the github-token. (_Default_: `bot-token-github`) +- **github-token-secret-key**: Name of the secret key holding the github-token. (_Default_: `bot-token`) +- **flags**: Flags to pass to `goreleaser release`. (_Default_: `--timeout=30m`) +- **image**: The image name for goreleaser (_Default_: `docker.io/goreleaser/goreleaser@sha256:0e87d0e33840a556d3b9c10a7f71a3a69bcd9c29b86a180cbbf7d7ad1f3fa280`) + +## Workspaces + +- **source**: The workspace containing the Go source code which needs to be released. The default `mountPath` is `/workspace/src/$(params.package)` + +## Platforms + +The Task can be run on `linux/amd64` platform. + +## Usage + +1. Create the GitHub token by following the steps from [here](https://docs.github.com/en/free-pro-team@latest/github/authenticating-to-github/creating-a-personal-access-token) + +2. Create the Secret + +```bash +kubectl create secret generic bot-token-github --from-literal=bot-token=${github_token} +``` + +3. Create the Pipeline and PipelineRun + +```yaml +apiVersion: tekton.dev/v1 +kind: Pipeline +metadata: + name: gorelease-pipeline +spec: + workspaces: + - name: shared-workspace + params: + - name: url + description: git url to clone + - name: revision + description: revision branch to checkout + - name: package + description: package to release + default: github.com/tektoncd/cli + - name: github-token-secret + description: name of the secret holding the github-token + default: bot-token-github + - name: github-token-secret-key + description: name of the key for the secret holding the github-token + default: bot-token + tasks: + - name: fetch-repository + taskRef: + name: git-clone + workspaces: + - name: output + workspace: shared-workspace + params: + - name: url + value: $(params.url) + - name: revision + value: $(params.revision) + - name: deleteExisting + value: "true" + - name: release + runAfter: + - fetch-repository + taskRef: + name: goreleaser + params: + - name: package + value: $(params.package) + - name: github-token-secret + value: $(params.github-token-secret) + - name: github-token-secret-key + value: $(params.github-token-secret-key) + workspaces: + - name: source + workspace: shared-workspace +--- +apiVersion: tekton.dev/v1 +kind: PipelineRun +metadata: + generateName: gorelease-pipeline-run +spec: + pipelineRef: + name: gorelease-pipeline + workspaces: + - name: shared-workspace + volumeClaimTemplate: + spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 500Mi + params: + - name: revision + value: "v1.1.1" + - name: url + value: https://github.com/tektoncd/cli +``` diff --git a/task/goreleaser/0.3/goreleaser.yaml b/task/goreleaser/0.3/goreleaser.yaml new file mode 100644 index 0000000000..21565ecb4a --- /dev/null +++ b/task/goreleaser/0.3/goreleaser.yaml @@ -0,0 +1,59 @@ +apiVersion: tekton.dev/v1 +kind: Task +metadata: + name: goreleaser + labels: + app.kubernetes.io/version: "0.3" + annotations: + tekton.dev/pipelines.minVersion: "0.50.0" + tekton.dev/categories: Automation, Publishing + tekton.dev/tags: golang, release-automation, package + tekton.dev/displayName: "GoReleaser" + tekton.dev/platforms: "linux/amd64" +spec: + description: >- + GoReleaser builds Go binaries for several platforms. + + It creates a GitHub release and then pushes a Homebrew formula to a tap repository. + workspaces: + - name: source + mountPath: /workspace/src/$(params.package) + description: >- + The workspace containing the Go source code + which needs to be released. + params: + - name: package + description: base package to build in + - name: github-token-secret + description: name of the secret holding the github-token + default: bot-token-github + - name: github-token-secret-key + description: name of the secret key holding the github-token + default: bot-token + - name: flags + description: flags to pass to `goreleaser release` + default: --timeout=30m + - name: image + description: container image location for goreleaser + default: docker.io/goreleaser/goreleaser@sha256:2a949686d9886ac7c10582a6c29116fd29d3077d02755e87e111870d63607725 + steps: + - name: pull + image: $(params.image) + workingDir: $(workspaces.source.path) + script: | + git config --global --add safe.directory $(workspaces.source.path) + git status; git fetch -p --all + - name: release + image: $(params.image) + workingDir: $(workspaces.source.path) + script: | + git config --global --add safe.directory $(workspaces.source.path) + goreleaser release $(params.flags) + env: + - name: GOPATH + value: /workspace + - name: GITHUB_TOKEN + valueFrom: + secretKeyRef: + name: $(params.github-token-secret) + key: $(params.github-token-secret-key) diff --git a/task/goreleaser/0.3/samples/run.yaml b/task/goreleaser/0.3/samples/run.yaml new file mode 100644 index 0000000000..42a74f3c4a --- /dev/null +++ b/task/goreleaser/0.3/samples/run.yaml @@ -0,0 +1,72 @@ +apiVersion: tekton.dev/v1 +kind: Pipeline +metadata: + name: gorelease-pipeline +spec: + workspaces: + - name: shared-workspace + params: + - name: url + description: git url to clone + - name: revision + description: revision branch to checkout + - name: package + description: package to release + default: github.com/tektoncd/cli + - name: github-token-secret + description: name of the secret holding the github-token + default: bot-token-github + - name: github-token-secret-key + description: name of the key for the secret holding the github-token + default: bot-token + tasks: + - name: fetch-repository + taskRef: + name: git-clone + workspaces: + - name: output + workspace: shared-workspace + params: + - name: url + value: $(params.url) + - name: revision + value: $(params.revision) + - name: deleteExisting + value: "true" + - name: release + runAfter: + - fetch-repository + taskRef: + name: goreleaser + params: + - name: package + value: $(params.package) + - name: github-token-secret + value: $(params.github-token-secret) + - name: github-token-secret-key + value: $(params.github-token-secret-key) + workspaces: + - name: source + workspace: shared-workspace +--- +apiVersion: tekton.dev/v1 +kind: PipelineRun +metadata: + generateName: gorelease-pipeline-run +spec: + pipelineRef: + name: gorelease-pipeline + workspaces: + - name: shared-workspace + volumeClaimTemplate: + spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 500Mi + params: + - name: revision + value: "v1.1.1" + - name: url + value: https://github.com/tektoncd/cli diff --git a/task/gradle/0.5/README.md b/task/gradle/0.5/README.md new file mode 100644 index 0000000000..1adf3a9d5f --- /dev/null +++ b/task/gradle/0.5/README.md @@ -0,0 +1,70 @@ +# Gradle + +This Task can be used to run a Gradle build on a gradle project. +If the project contains a gradle wrapper, the wrapper will be invoked instead of the gradle executable provided by the image. + +## Install the Task + +```bash +kubectl apply -f https://raw.githubusercontent.com/tektoncd/catalog/main/task/gradle/0.5/gradle.yaml +``` + +## Parameters + +- **GRADLE_IMAGE**: The base image for gradle (_default_: `gradle:7.6-jdk8`) +- **PROJECT_DIR**: The project directory containing `build.gradle` (_default_: `.`) +- **TASKS**: The gradle tasks to run (_default_: `build`) + +## Workspaces + +- **source**: `PersistentVolumeClaim`-type so that the volume can be shared among `git-clone` and `gradle` task + +```yaml +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: gradle-source-pvc +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 500Mi +``` + +- **gradle-config**: A volume containing the gradle.properties to be used during the gradle run. Is `optional`. + +```yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: gradle-config +data: + gradle.properties: |- + artifactory_contextUrl=https://jfrog.com/artifactory +``` +## Platforms + +The Task can be run on `linux/amd64`, `linux/s390x` and `linux/ppc64le` platforms. + +## Usage + +```yaml +apiVersion: tekton.dev/v1 +kind: TaskRun +metadata: + name: run-gradle-build +spec: + taskRef: + name: gradle + workspaces: + - name: source + persistentVolumeClaim: + claimName: my-source + - name: gradle-config + configmap: + name: gradle-config + params: + - name: PROJECT_DIR + value: my-workspace +``` diff --git a/task/gradle/0.5/gradle.yaml b/task/gradle/0.5/gradle.yaml new file mode 100644 index 0000000000..11c23fbfcd --- /dev/null +++ b/task/gradle/0.5/gradle.yaml @@ -0,0 +1,71 @@ +apiVersion: tekton.dev/v1 +kind: Task +metadata: + name: gradle + labels: + app.kubernetes.io/version: "0.5" + annotations: + tekton.dev/pipelines.minVersion: "0.50.0" + tekton.dev/displayName: Gradle + tekton.dev/categories: Build Tools + tekton.dev/tags: build-tool + tekton.dev/platforms: "linux/amd64,linux/s390x,linux/ppc64le" +spec: + description: >- + This Task can be used to run a Gradle build. + + workspaces: + - name: source + description: The workspace consisting of the gradle project. + - name: gradle-config + description: The workspace consisting of the custom gradle properties provided by the user. + optional: true + params: + - name: GRADLE_IMAGE + description: Gradle base image. + type: string + default: docker.io/library/gradle:7.6-jdk8@sha256:ebda657f66e04cfa9f152896b4fa70bea4b80561a836adddca3ed85d622f8898 + - name: PROJECT_DIR + description: The directory containing build.gradle + type: string + default: "." + - name: TASKS + description: 'The gradle tasks to run (default: build)' + type: array + default: + - build + steps: + - name: gradle-tasks + image: $(params.GRADLE_IMAGE) + env: + - name: GRADLE_USER_HOME + value: "/home/gradle" + workingDir: $(workspaces.source.path)/$(params.PROJECT_DIR) + args: + - "$(params.TASKS)" + script: | + #!/usr/bin/env bash + + if [[ "$(workspaces.gradle-config.bound)" == "true" ]]; then + echo "gradle-config workspace is bound" + if [[ -f $(workspaces.gradle-config.path)/gradle.properties ]]; then + echo "copying gradle.properties to /home/gradle" + cp "$(workspaces.gradle-config.path)/gradle.properties" /home/gradle + fi + fi + + if [[ -f gradlew ]]; then + cmd="./gradlew $*" + else + cmd="gradle $*" + fi + + echo "Running gradle task with command below" + echo "$cmd" + eval "$cmd" + volumeMounts: + - mountPath: /home/gradle + name: empty-dir + volumes: + - name: empty-dir + emptyDir: {} diff --git a/task/gradle/0.5/tests/pre-apply-task-hook.sh b/task/gradle/0.5/tests/pre-apply-task-hook.sh new file mode 100644 index 0000000000..64f2208fb8 --- /dev/null +++ b/task/gradle/0.5/tests/pre-apply-task-hook.sh @@ -0,0 +1,4 @@ +#!/bin/bash + +# Add git-clone +add_task git-clone latest diff --git a/task/gradle/0.5/tests/resources.yaml b/task/gradle/0.5/tests/resources.yaml new file mode 100644 index 0000000000..4f9f34710c --- /dev/null +++ b/task/gradle/0.5/tests/resources.yaml @@ -0,0 +1,19 @@ +--- +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: gradle-source-pvc +spec: + resources: + requests: + storage: 500Mi + accessModes: + - ReadWriteOnce +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: gradle-config +data: + gradle.properties: |- + artifactory_contextUrl=https://jfrog.com/artifactory diff --git a/task/gradle/0.5/tests/run.yaml b/task/gradle/0.5/tests/run.yaml new file mode 100644 index 0000000000..b81427f136 --- /dev/null +++ b/task/gradle/0.5/tests/run.yaml @@ -0,0 +1,85 @@ +--- +apiVersion: tekton.dev/v1 +kind: Pipeline +metadata: + name: gradle-test-pipeline +spec: + workspaces: + - name: shared-workspace + - name: gradle-config + tasks: + - name: fetch-code + taskRef: + name: git-clone + workspaces: + - name: output + workspace: shared-workspace + params: + - name: url + value: https://github.com/crshnburn/simple-gradle + - name: subdirectory + value: "" + - name: deleteExisting + value: "true" + - name: gradle-run + taskRef: + name: gradle + runAfter: + - fetch-code + params: + - name: TASKS + value: + - build + workspaces: + - name: source + workspace: shared-workspace + - name: gradle-config + workspace: gradle-config + - name: fetch-wrapper-code + taskRef: + name: git-clone + runAfter: + - gradle-run + workspaces: + - name: output + workspace: shared-workspace + params: + - name: url + value: https://github.com/BastiaanN/simple-gradle-wrapper + - name: subdirectory + value: "wrapper-test" + - name: deleteExisting + value: "true" + - name: gradle-wrapper-run + taskRef: + name: gradle + runAfter: + - fetch-wrapper-code + params: + - name: TASKS + value: + - build + - name: PROJECT_DIR + value: "wrapper-test" + - name: GRADLE_IMAGE + value: docker.io/library/eclipse-temurin:17-ubi9-minimal@sha256:19c66566a0a802df5674301b223683ffbcf56cf18488a37a21d53e3d09df57d1 + workspaces: + - name: source + workspace: shared-workspace + - name: gradle-config + workspace: gradle-config +--- +apiVersion: tekton.dev/v1 +kind: PipelineRun +metadata: + name: gradle-test-pipeline-rune +spec: + pipelineRef: + name: gradle-test-pipeline + workspaces: + - name: shared-workspace + persistentVolumeClaim: + claimName: gradle-source-pvc + - name: gradle-config + configMap: + name: gradle-config diff --git a/task/jenkins/0.2/README.md b/task/jenkins/0.2/README.md new file mode 100644 index 0000000000..714fbd4fa3 --- /dev/null +++ b/task/jenkins/0.2/README.md @@ -0,0 +1,117 @@ +# Jenkins Task + +The following task can be used to interact with Jenkins using the Jenkins REST API. + +More details on Remote Access API can be found [here](https://www.jenkins.io/doc/book/using/remote-access-api/) + +## Install the Task + +```bash +kubectl apply -f https://raw.githubusercontent.com/tektoncd/catalog/main/task/jenkins/0.2/jenkins.yaml +``` + +## Parameters + +- **JENKINS_HOST_URL**: The URL on which Jenkins is running (**Required**) +- **JENKINS_SECRETS**: The name of the secret containing the username and API token for authenticating the Jenkins (_Default_: jenkins-credentials) (**Required**) +- **ARGS**: Extra arguments to add to the control script. (**Required**) + +The arguments are : + +1. `start`: Start a new Jenkins job. + +``` +start [--file-to-upload FILE_TO_UPLOAD] [--wait-started] [--wait-finished] job [job_parameters [job_parameters ...]] +positional arguments: + job - The job name + job_parameters - Optional: The parameters to add i.e: key=value + +optional arguments: + --file-to-upload FILE_TO_UPLOAD + The path of the file to upload to job. + --wait-started Wether to wait for the job to be started. + --wait-finished Wether to wait for the job to be finished. +``` + +`log`: Get log of a jenkins build. + +``` +log [-h] [--output-file OUTPUT_FILE] job [build_number] + +positional arguments: + job - The job name + build_number - The build number, use 'lastBuild' to get the latest build + +optional arguments: + --output-file OUTPUT_FILE + The location where to save logs on the filesystem. (i.e: a workspace location) +``` + +## Results + +- **build_number**: This will output the current jenkins build_number of the job. + +## Workspaces + +- **source**: In case any file needs to be provided or saved by the Jenkins Job. (_Default_: `emptyDir: {}`) + +## Secrets + +Secrets containing `username`,`API token` that are used in the task for making the REST API request. + +```yaml +apiVersion: v1 +kind: Secret +metadata: + name: jenkins-credentials +type: Opaque +stringData: + username: username + apitoken: api-token +``` + +## Platforms + +The Task can be run on `linux/amd64` platform. + +## Usage + +1. Start a job without parameters + + ```yaml + apiVersion: tekton.dev/v1 + kind: TaskRun + metadata: + name: jenkins-job-run + spec: + taskRef: + name: jenkins + params: + - name: JENKINS_HOST_URL + value: "http://localhost:8080" + - name: ARGS + value: ["start", "job"] + workspaces: + - name: source + emptyDir: {} + ``` + +1. Start job with the parameters `param=value` and wait that it finishes. + + ```yaml + apiVersion: tekton.dev/v1 + kind: TaskRun + metadata: + name: jenkins-job-run + spec: + taskRef: + name: jenkins + params: + - name: JENKINS_HOST_URL + value: "http://localhost:8080" + - name: ARGS + value: ["start", "--wait-finished", "test", "param=value"] + workspaces: + - name: source + emptyDir: {} + ``` diff --git a/task/jenkins/0.2/jenkins.yaml b/task/jenkins/0.2/jenkins.yaml new file mode 100644 index 0000000000..d9ef1680b8 --- /dev/null +++ b/task/jenkins/0.2/jenkins.yaml @@ -0,0 +1,246 @@ +apiVersion: tekton.dev/v1 +kind: Task +metadata: + name: jenkins + labels: + app.kubernetes.io/version: "0.2" + annotations: + tekton.dev/pipelines.minVersion: "0.50.0" + tekton.dev/categories: Automation + tekton.dev/tags: jenkins, build + tekton.dev/displayName: "jenkins operation" + tekton.dev/platforms: "linux/amd64" +spec: + description: >- + The following task can be used to interact with the the Jenkins REST API. + workspaces: + - name: source + description: >- + The workspace which can be used to mount files which can be + send via the API to the Jenkins job. + results: + - name: build_number + params: + - name: JENKINS_HOST_URL + type: string + description: Server URL on which Jenkins is running + - name: JENKINS_SECRETS + type: string + description: Jenkins secret containing credentials + default: jenkins-credentials + - name: ARGS + type: array + description: The argument to send to the control script, see README of this task for details. + default: ["--help"] + steps: + - name: jenkins-control + image: registry.access.redhat.com/ubi8:8.2@sha256:d748c21a55796827da82c61f162b505c59451cba24f1874e5185f21275b6bddc + workingDir: $(workspaces.source.path) + args: + - $(params.ARGS) + env: + - name: BUILD_ID_RESULTS_PATH + value: $(results.build_number.path) + - name: USERNAME + valueFrom: + secretKeyRef: + name: $(params.JENKINS_SECRETS) + key: username + - name: API_TOKEN + valueFrom: + secretKeyRef: + name: $(params.JENKINS_SECRETS) + key: apitoken + script: | + #!/usr/libexec/platform-python + import argparse + import base64 + import http.cookiejar + import json + import os + import sys + import time + import urllib.request + + COOKIE_JAR = http.cookiejar.CookieJar() + + JENKINS_URL = """$(params.JENKINS_HOST_URL)""" + USERNAME = os.getenv("USERNAME") + PASSWORD = os.getenv("API_TOKEN") + + BUILD_ID_RESULTS_PATH = os.getenv("BUILD_ID_RESULTS_PATH") + + + def parse_args(args): + parser = argparse.ArgumentParser( + description='Tekton jenkins task control CLI', ) + + actions = parser.add_subparsers(title="Actions") + + start = actions.add_parser("start", help="Start a Jenkins Job") + start.add_argument("--file-to-upload", + type=str, + help="The path of the file to upload to job.") + start.add_argument("--wait-started", + action='store_true', + default=False, + help="Wether to wait for the job to be started.") + start.add_argument("--wait-finished", + action='store_true', + default=False, + help="Wether to wait for the job to be finished.") + start.add_argument("job", type=str) + start.add_argument("job_parameters", nargs="*") + + log = actions.add_parser("log", help="Get log of a JOB") + log.add_argument("--output-file", + type=str, + help="The location where to save logs on the filesystem.") + + log.add_argument("job", type=str) + log.add_argument("build_number", nargs="?") + + if len(args) == 0: + parser.print_help() + sys.exit(1) + + args = parser.parse_args(args) + args.action = sys.argv[1] + return args + + + def build_parameters(parameters): + data = {} + for params in parameters: + if "=" in params: + key_value = params.split("=") + data[key_value[0]] = key_value[1] + if data: + data = urllib.parse.urlencode(data).encode("utf-8") + return data + + + def get_crumb(headers, cookiejar): + url = f"{JENKINS_URL}/crumbIssuer/api/xml?xpath=concat(//crumbRequestField,%22:%22,//crumb)" + opener = urllib.request.build_opener( + urllib.request.HTTPCookieProcessor(cookiejar)) + opener.addheaders = headers + return opener.open(url) + + + def build_req(url, data=None, debug=False, file_to_upload=None): + base64string = base64.b64encode(f"{USERNAME}:{PASSWORD}".encode("utf-8")) + headers = [("Authorization", f"Basic {base64string.decode('utf-8')}")] + + crumb = get_crumb(headers, COOKIE_JAR).read().decode().replace( + "Jenkins-Crumb:", "") + headers.append(("Jenkins-Crumb", crumb)) + + # TODO(chmou):This doesn't seem to work or i can't make it to work :\ + if file_to_upload: + headers.append(("Content-Type", "multipart/form-data")) + headers.append(("Content-Length", os.stat(file_to_upload).st_size)) + request = urllib.request.Request(url, open(file_to_upload, "rb")) + else: + request = urllib.request.Request(url, data=data) + + opener = urllib.request.build_opener( + urllib.request.HTTPCookieProcessor(COOKIE_JAR)) + opener.addheaders = headers + if debug: + print(f"Requesting {url} with data={repr(data)}") + return (opener, request) + + + def get_job_info(job, build_number='lastBuild'): + url = f"{JENKINS_URL}/job/{job}/{build_number}/api/json?depth=0" + opener, request = build_req(url) + return json.loads(opener.open(request).read()) + + + def wait_for_build_started(job_name, _info_current): + try: + _info = get_job_info(job_name) + except urllib.error.HTTPError as err: + if not hasattr(err, "code") or err.code != 404: + raise + _info = {'id': 0} + + max_loop = 100 + current = 0 + print(f"Waiting for job '{job_name}' to start.") + while _info_current['id'] == _info['id']: + try: + _info = get_job_info(job_name) + except urllib.error.HTTPError as err: + if not hasattr(err, "code") or err.code != 404: + raise + if current >= max_loop: + raise Exception( + f"It took to long to wait for the job '{job_name}' to start") + current += 1 + time.sleep(5) + print(f"Job '{job_name}' has started with build number: {_info['id']}") + return _info + + + def wait_for_build_completed(job_name, build_number): + job_info = get_job_info(job_name, build_number) + max_loop = 100 + current = 0 + print(f"Waiting for job '{job_name}' to be completed") + while True: + if 'building' in job_name and job_info['building']: + job_info = get_job_info(job_name) + if current >= max_loop: + raise Exception( + f"It took to long to wait for the job '{job_name}' to complete" + ) + current += 1 + time.sleep(5) + continue + break + print(f"Job '{job_name}' has completed: {job_info['url']}") + return job_info + + + def main(): + args = parse_args(sys.argv[1:]) + data = {} + if args.action == "log": + query_type = f"{args.build_number}/consoleText" + elif args.action == "start": + if args.job_parameters: + data = build_parameters(args.job_parameters) + query_type = "buildWithParameters" + else: + query_type = "build" + + url = f"{JENKINS_URL}/job/{args.job}/{query_type}" + + # We catch the error in case the job has never been started yet. + try: + _info_current = get_job_info(args.job) + except urllib.error.HTTPError: + _info_current = {'id': 0} + opener, request = build_req(url, data=data, debug=True) + with opener.open(request) as handle: + output = handle.read().decode("utf-8") + if output: + print(output) + if 'output_file' in args: + open(args.output_file, 'w').write(output) + + if args.action == "start": + print(f"Job {args.job} has started.") + if args.wait_started or args.wait_finished: + _info_current = wait_for_build_started(args.job, _info_current) + if args.wait_finished: + wait_for_build_completed(args.job, _info_current['id']) + + if BUILD_ID_RESULTS_PATH and _info_current['id'] != 0: + open(BUILD_ID_RESULTS_PATH, 'w').write(_info_current['id']) + + + if __name__ == '__main__': + main() diff --git a/task/jenkins/0.2/samples/run.yaml b/task/jenkins/0.2/samples/run.yaml new file mode 100644 index 0000000000..33d4ffef49 --- /dev/null +++ b/task/jenkins/0.2/samples/run.yaml @@ -0,0 +1,20 @@ +apiVersion: tekton.dev/v1 +kind: TaskRun +metadata: + name: jenkins-run +spec: + taskRef: + name: jenkins + params: + - name: JENKINS_HOST_URL + value: http://localhost:8080 + - name: JENKINS_SECRETS + value: jenkins-credentials + - name: ARGS + value: + - start + - test + - id=123 + workspaces: + - name: source + emptyDir: {} diff --git a/task/jenkins/0.2/samples/secrets.yaml b/task/jenkins/0.2/samples/secrets.yaml new file mode 100644 index 0000000000..9e5b212cc8 --- /dev/null +++ b/task/jenkins/0.2/samples/secrets.yaml @@ -0,0 +1,8 @@ +apiVersion: v1 +kind: Secret +metadata: + name: jenkins-credentials +type: Opaque +stringData: + username: username + apitoken: api-token diff --git a/task/jenkins/0.2/tests/pre-apply-task-hook.sh b/task/jenkins/0.2/tests/pre-apply-task-hook.sh new file mode 100755 index 0000000000..a8534e9080 --- /dev/null +++ b/task/jenkins/0.2/tests/pre-apply-task-hook.sh @@ -0,0 +1,98 @@ +#!/bin/bash +# This will create a Jenkins deployment, a jenkins service, grab the password, +# gets a 'crumb' and generate a secret out of it for our task to run against to. + +cat </dev/null)" + [[ -n "${apitoken}" ]] && break + sleep 5 + lock=$((lock+1)) + if [[ "${lock}" == 60 ]];then + echo "Error waiting for jenkins to generate a password" + exit 1 + fi +done +set -e + + +# We need to execute the script on the pods, since it's too painful with direct exec the commands +cat </tmp/script.sh +#!/bin/bash +set +x +cookiejar=\$(mktemp) +apitoken=\$(cat /var/jenkins_home/secrets/initialAdminPassword) +while [[ -z "\${crumb}" ]];do + crumb=\$(curl --fail -s -u "admin:\${apitoken}" --cookie-jar "\${cookiejar}" 'jenkins:8080/crumbIssuer/api/xml?xpath=concat(//crumbRequestField,%22:%22,//crumb)') + sleep 2 +done +set -e +cat </tmp/job.xml + + + + + false + + + + + Word + + Bird it is! + false + + + + + + + echo "Hello \\\${Word}" + + + + + + +XXMLOF +curl -f -s -X POST -H "\${crumb}" --cookie "\${cookiejar}" -u "admin:${apitoken}" -X POST -H "Content-Type:application/xml" -d @/tmp/job.xml "jenkins:8080/createItem?name=test" +echo \${crumb}|sed 's/Jenkins-Crumb://' +EOF +tar cf - /tmp/script.sh|kubectl -n "${tns}" exec -i deployment/jenkins -- tar xf - -C / +crumb=$(kubectl -n "${tns}" exec -i deployment/jenkins -- /bin/bash /tmp/script.sh) + +kubectl delete secret jenkins-credentials 2>/dev/null || true +kubectl create secret generic -n "${tns}" jenkins-credentials --from-literal=apitoken="${apitoken}" --from-literal=username="admin" diff --git a/task/jenkins/0.2/tests/run.yaml b/task/jenkins/0.2/tests/run.yaml new file mode 100644 index 0000000000..2765539f83 --- /dev/null +++ b/task/jenkins/0.2/tests/run.yaml @@ -0,0 +1,61 @@ +apiVersion: tekton.dev/v1 +kind: PipelineRun +metadata: + name: jenkins-run +spec: + pipelineSpec: + results: + - name: build_number + description: The run build number + value: $(tasks.start.results.build_number) + workspaces: + - name: source + tasks: + - name: start + taskRef: + name: jenkins + workspaces: + - name: source + workspace: source + params: + - name: JENKINS_HOST_URL + value: http://jenkins:8080 + - name: ARGS + value: ["start", "--wait-finished", "test", "Word=World"] + - name: log + runAfter: + - start + taskRef: + name: jenkins + workspaces: + - name: source + workspace: source + params: + - name: JENKINS_HOST_URL + value: http://jenkins:8080 + - name: ARGS + value: ["log", "test", "$(tasks.start.results.build_number)", "--output-file=$(workspaces.source.path)/output.log"] + - name: check + runAfter: + - log + taskSpec: + workspaces: + - name: source + steps: + - name: check-it-baby + image: registry.access.redhat.com/ubi8/ubi-minimal:8.2 + script: | + ls $(workspaces.source.path) + grep "Hello World" $(workspaces.source.path)/output.log + workspaces: + - name: source + workspace: source + workspaces: + - name: source + volumeClaimTemplate: + spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 1Mi diff --git a/task/npm/0.2/README.md b/task/npm/0.2/README.md new file mode 100644 index 0000000000..b77dc508be --- /dev/null +++ b/task/npm/0.2/README.md @@ -0,0 +1,35 @@ +# NPM CLI + +This task can be used to run `npm` goals on a source code with the default environment as `CI=true` and has some pre-defined scripts in `package.json` file. + +## Install the Task + +```bash +kubectl apply -f https://raw.githubusercontent.com/tektoncd/catalog/main/task/npm/0.2/npm.yaml +``` + +## Parameters + +- **PATH_CONTEXT**: The path where `package.json` of the project is defined. (_Default: `"."`_) + +- **ARGS**: The npm goals you want to run. (_Default: `version`_) + +- **IMAGE**: The node image you want to use. (_Default: docker.io/library/node:12-alpine@sha256:12048cdfd75d944df35f3144132d9bdeee78015fbd6df765edad1be46599b110_) + +## Workspaces + +- **source**: The place which consists of the project. + +## Platforms + +The Task can be run on `linux/amd64`, `linux/s390x`, and `linux/ppc64le` platforms. + +## Usage + +1. Apply the [`git-clone`](https://raw.githubusercontent.com/tektoncd/catalog/main/task/git-clone/0.2/git-clone.yaml) task which will help to clone the repository. + +2. Apply the sample [run.yaml](https://raw.githubusercontent.com/tektoncd/catalog/main/task/npm/0.2/tests/run.yaml) which will clone the [tektoncd/hub](https://github.com/tektoncd/hub) repo and perform few npm goals:- + - install dependencies using `npm clean-install` + - perform `eslint` check on the source code using `npm run lint`. + - run unit tests using `npm run test` + - run build tests using `npm run build` diff --git a/task/npm/0.2/npm.yaml b/task/npm/0.2/npm.yaml new file mode 100644 index 0000000000..4b5b47eb15 --- /dev/null +++ b/task/npm/0.2/npm.yaml @@ -0,0 +1,44 @@ +apiVersion: tekton.dev/v1 +kind: Task +metadata: + name: npm + labels: + app.kubernetes.io/version: "0.2" + annotations: + tekton.dev/pipelines.minVersion: "0.50.0" + tekton.dev/categories: Build Tools + tekton.dev/tags: build-tool + tekton.dev/platforms: "linux/amd64,linux/s390x,linux/ppc64le" +spec: + description: >- + This task can be used to run npm goals on a project. + + This task can be used to run npm goals on a project + where package.json is present and has some pre-defined + npm scripts. + workspaces: + - name: source + params: + - name: PATH_CONTEXT + type: string + default: "." + description: The path where package.json of the project is defined. + - name: ARGS + type: array + default: ["version"] + description: The npm goals you want to run. + - name: IMAGE + type: string + default: "docker.io/library/node:12-alpine@sha256:dfbebf17bfb014e1e7068e76325a117bccf8679c68aec6a28514184a209c8bae" + description: The node image you want to use. + steps: + - name: npm-run + image: $(params.IMAGE) + command: + - "npm" + args: + - $(params.ARGS) + workingDir: $(workspaces.source.path)/$(params.PATH_CONTEXT) + env: + - name: CI + value: "true" diff --git a/task/npm/0.2/tests/pre-apply-task-hook.sh b/task/npm/0.2/tests/pre-apply-task-hook.sh new file mode 100644 index 0000000000..64f2208fb8 --- /dev/null +++ b/task/npm/0.2/tests/pre-apply-task-hook.sh @@ -0,0 +1,4 @@ +#!/bin/bash + +# Add git-clone +add_task git-clone latest diff --git a/task/npm/0.2/tests/run.yaml b/task/npm/0.2/tests/run.yaml new file mode 100644 index 0000000000..60d56f6708 --- /dev/null +++ b/task/npm/0.2/tests/run.yaml @@ -0,0 +1,59 @@ +apiVersion: tekton.dev/v1 +kind: PipelineRun +metadata: + name: npm-run +spec: + workspaces: + - name: shared-workspace + volumeClaimTemplate: + spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 10Gi + pipelineSpec: + workspaces: + - name: shared-workspace + tasks: + - name: fetch-repository + taskRef: + name: git-clone + workspaces: + - name: output + workspace: shared-workspace + params: + - name: url + value: https://github.com/vinamra28/sonartest + - name: subdirectory + value: "" + - name: deleteExisting + value: "true" + - name: install-dependencies + taskRef: + name: npm + workspaces: + - name: source + workspace: shared-workspace + params: + - name: PATH_CONTEXT + value: "app" + - name: ARGS + value: + - clean-install + runAfter: + - fetch-repository + - name: run-test + taskRef: + name: npm + workspaces: + - name: source + workspace: shared-workspace + params: + - name: PATH_CONTEXT + value: "app" + - name: ARGS + value: + - test + runAfter: + - install-dependencies diff --git a/task/tekton-operator-install/0.2/README.md b/task/tekton-operator-install/0.2/README.md new file mode 100644 index 0000000000..d323efcc98 --- /dev/null +++ b/task/tekton-operator-install/0.2/README.md @@ -0,0 +1,70 @@ +# Install Tekton & Components + +This task can be used to install Tekton pipelines and also it's components using [Tekton Operator](https://github.com/tektoncd/operator) on a new cluster. + +## Install the Task + +```shell +kubectl apply --filename https://raw.githubusercontent.com/tektoncd/catalog/main/task/tekton-operator-install/0.2/tekton-operator-install.yaml +``` + +## Parameters + +- **OPERATOR_VERSION**: Tekton Operator release version to be used for installing tekton components. (_Default_ : "latest") +- **INSTALL_TRIGGERS**: If [Triggers](https://github.com/tektoncd/triggers) needs to be installed. (_Default_ : "false") +- **INSTALL_DASHBOARD**: If [Tekton Dashboard](https://github.com/tektoncd/dashboard) needs to be installed. (_Default_ : "false") +- **INSTALL_EXTENSION_WEBHOOKS**: If [Tekton Extension Webhooks](https://github.com/tektoncd/experimental/tree/main/webhooks-extension) needs to be installed. (_Default_ : "false") + +### Note: The last three parameters accepts value "true"/"false". Default being "false" means we don't want to install that component. + +## Workspaces + +- **kubeconfig**: The workspace consisting of the `kubeconfig` file of the new cluster on which tekton pipelines & components needs to be installed. + +## Sample Usage + +1. Create the `ConfigMap` + +```shell +kubectl create configmap kubeconfig --from-file="path/to/kubeconfig" +``` + +2. Create a TaskRun in case you want to install Triggers + +```yaml +apiVersion: tekton.dev/v1 +kind: TaskRun +metadata: + name: operator-run +spec: + taskRef: + name: tekton-operator-install + params: + - name: INSTALL_TRIGGERS + value: "true" + workspaces: + - name: kubeconfig + configMap: + name: kubeconfig +``` + +3. Create a TaskRun in case you want to install Triggers as well as Dashboard + +```yaml +apiVersion: tekton.dev/v1 +kind: TaskRun +metadata: + name: operator-run +spec: + taskRef: + name: tekton-operator-install + params: + - name: INSTALL_TRIGGERS + value: "true" + - name: INSTALL_DASHBOARD + value: "true" + workspaces: + - name: kubeconfig + configMap: + name: kubeconfig +``` diff --git a/task/tekton-operator-install/0.2/tekton-operator-install.yaml b/task/tekton-operator-install/0.2/tekton-operator-install.yaml new file mode 100644 index 0000000000..59db0b3884 --- /dev/null +++ b/task/tekton-operator-install/0.2/tekton-operator-install.yaml @@ -0,0 +1,218 @@ +apiVersion: tekton.dev/v1 +kind: Task +metadata: + name: tekton-operator-install + labels: + app.kubernetes.io/version: "0.2" + annotations: + tekton.dev/pipelines.minVersion: "0.50.0" + tekton.dev/categories: Automation + tekton.dev/tags: operator, tekton, deploy + tekton.dev/displayName: "Tekton Operator Install" +spec: + description: >- + This task can be used to install Tekton pipelines and also it's + components using Tekton Operator on a new cluster. + workspaces: + - name: kubeconfig + description: >- + The workspace consisting of kubeconfig file so that operator + can install tekton components on fresh cluster + params: + - name: OPERATOR_VERSION + type: string + description: Tekton operator version to be installed + default: "latest" + - name: INSTALL_TRIGGERS + type: string + description: If triggers needs to be installed + default: "false" + - name: INSTALL_DASHBOARD + type: string + description: If Tekton dashboard to be installed + default: "false" + - name: INSTALL_EXTENSION_WEBHOOKS + type: string + description: If Tekton Extension Webhooks needs to be installed + default: "false" + steps: + - name: install-operator + image: docker.io/lachlanevenson/k8s-kubectl@sha256:3a5e22a406a109f4f26ec06b5f1f6a66ae0cd0e185bc28499eb7b7a3bbf1fe09 + workingDir: $(workspaces.kubeconfig.path) + script: | + #!/bin/sh + set -u -o pipefail + + [[ -f ./kubeconfig ]] && \ + export KUBECONFIG=./kubeconfig || \ + (echo "please provide kubeconfig file" && exit 1) + + # check whether CR is installed or not + checkCodeStatus() { + local crd_name=${1} + local cr_name=${2} + kubectl get "${crd_name}" "${cr_name}" \ + -o jsonpath='{range .status.conditions[0]}{.code}{"\n"}{end}' + } + + # check the version of the installed CR + checkVersionStatus() { + local crd_name=${1} + local cr_name=${2} + kubectl get "${crd_name}" "${cr_name}" \ + -o jsonpath='{range .status.conditions[0]}{.version}{"\n"}{end}' + } + + show_failure() { + echo "failed to install $1 $2" + exit 1 + } + + main(){ + kubectl apply -f https://storage.googleapis.com/tekton-releases/operator/$(params.OPERATOR_VERSION)/release.notags.yaml + local maxloop=30 # 5 minutes max + + # check operator and pipeline correctly installed or not + # display the version of pipeline + local count=0 + while true; do + # hard timeout condition + [[ ${count} == ${maxloop} ]] && show_failure "tektonpipelines" "cluster" + + local codeStatus=$(checkCodeStatus "tektonpipelines" "cluster") + [[ "$codeStatus" == "installed" ]] && \ + checkVersionStatus "tektonpipelines" "cluster" && break + sleep 10 + count=$((count+1)) + done + echo "successfully installed operator version $(params.OPERATOR_VERSION)" + } + + main "$@" + + - name: install-addon + image: docker.io/lachlanevenson/k8s-kubectl@sha256:3a5e22a406a109f4f26ec06b5f1f6a66ae0cd0e185bc28499eb7b7a3bbf1fe09 + workingDir: $(workspaces.kubeconfig.path) + script: | + #!/bin/sh + set -u -o pipefail + + [[ -f ./kubeconfig ]] && \ + export KUBECONFIG=./kubeconfig || \ + (echo "please provide kubeconfig file" && exit 1) + + # create TektonAddon CR manifest and apply that directly + createCustomResource() { + cr_name=${1} + cat </dev/null)" + [[ -n "${apitoken}" ]] && break + sleep 5 + lock=$((lock+1)) + if [[ "${lock}" == 60 ]];then + echo "Error waiting for jenkins to generate a password" + exit 1 + fi +done +set -e + + +# We need to execute the script on the pods, since it's too painful with direct exec the commands +cat </tmp/script.sh +#!/bin/bash +set -x +cookiejar=\$(mktemp) +apitoken=\$(cat /var/jenkins_home/secrets/initialAdminPassword) +while [[ -z "\${crumb}" ]];do + crumb=\$(curl --fail -s -u "admin:${apitoken}" --cookie-jar "\${cookiejar}" 'jenkins:8080/crumbIssuer/api/xml?xpath=concat(//crumbRequestField,%22:%22,//crumb)') + sleep 2 +done +set -e +curl -f -s -X POST -H "\${crumb}" --cookie "\${cookiejar}" -u "admin:${apitoken}" -X POST -H "Content-Type:application/xml" -d "" "jenkins:8080/createItem?name=test" +echo \${crumb}|sed 's/Jenkins-Crumb://' +EOF +tar cf - /tmp/script.sh|kubectl -n "${tns}" exec -i deployment/jenkins -- tar xf - -C / +crumb=$(kubectl -n "${tns}" exec -i deployment/jenkins -- /bin/bash /tmp/script.sh) + +kubectl create secret generic -n "${tns}" jenkins-credentials --from-literal=apitoken="${apitoken}" --from-literal=username="admin" --from-literal=crumb="${crumb}" diff --git a/task/trigger-jenkins-job/0.2/tests/run.yaml b/task/trigger-jenkins-job/0.2/tests/run.yaml new file mode 100644 index 0000000000..bc357b8bf8 --- /dev/null +++ b/task/trigger-jenkins-job/0.2/tests/run.yaml @@ -0,0 +1,29 @@ +apiVersion: tekton.dev/v1 +kind: PipelineRun +metadata: + name: trigger-jenkins-job-run +spec: + pipelineSpec: + workspaces: + - name: source + tasks: + - name: trigger-jenkins-job-test + taskRef: + name: trigger-jenkins-job + workspaces: + - name: source + workspace: source + params: + - name: JENKINS_HOST_URL + value: http://jenkins:8080 + - name: JOB_NAME + value: "test" + workspaces: + - name: source + volumeClaimTemplate: + spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 1Mi diff --git a/task/trigger-jenkins-job/0.2/trigger-jenkins-job.yaml b/task/trigger-jenkins-job/0.2/trigger-jenkins-job.yaml new file mode 100644 index 0000000000..de6ac8b608 --- /dev/null +++ b/task/trigger-jenkins-job/0.2/trigger-jenkins-job.yaml @@ -0,0 +1,120 @@ +apiVersion: tekton.dev/v1 +kind: Task +metadata: + name: trigger-jenkins-job + labels: + app.kubernetes.io/version: "0.2" + annotations: + tekton.dev/pipelines.minVersion: "0.50.0" + tekton.dev/categories: Automation, Continuous Integration + tekton.dev/tags: jenkins, build + tekton.dev/displayName: "trigger jenkins job" +spec: + description: >- + The following task can be used to trigger a Jenkins job using + CURL request from a Tekton Task. + workspaces: + - name: source + description: >- + The workspace which can be used to mount files which can be + send via CURL request to Jenkins job. + params: + - name: JENKINS_HOST_URL + type: string + description: Server URL on which Jenkins is running + - name: JOB_NAME + type: string + description: Jenkins Job which needs to be triggered + - name: JENKINS_SECRETS + type: string + description: Jenkins secret containing credentials + default: jenkins-credentials + - name: JOB_PARAMS + type: array + description: Extra arguments to append as a part of CURL request + default: [""] + steps: + - name: trigger-pipeline + image: registry.access.redhat.com/ubi8/ubi:8.2@sha256:d748c21a55796827da82c61f162b505c59451cba24f1874e5185f21275b6bddc + workingDir: $(workspaces.source.path) + args: + - $(params.JOB_PARAMS) + script: | + #!/usr/libexec/platform-python + import base64 + import http.cookiejar + import os + import sys + import urllib.request + + JENKINS_URL = """$(params.JENKINS_HOST_URL)""" + JOB_NAME = """$(params.JOB_NAME)""" + USERNAME = os.getenv("USERNAME") + APITOKEN = os.getenv("API_TOKEN") + + def build_args(args): + data = {} + filename = "" + for params in args: + if "@" in params: + filename += params.split("=")[1][1:] + elif "=" in params: + key_value = params.split("=") + data[key_value[0]] = key_value[1] + if data: + data = urllib.parse.urlencode(data).encode("utf-8") + return (data, filename) + + + def get_crumb(headers, cookiejar): + url = f"{JENKINS_URL}/crumbIssuer/api/xml?xpath=concat(//crumbRequestField,%22:%22,//crumb)" + opener = urllib.request.build_opener(urllib.request.HTTPCookieProcessor(cookiejar)) + opener.addheaders = headers + return opener.open(url) + + + def main(): + data, filename = build_args(sys.argv[1:]) + + if data: + query_type = "buildWithParameters" + else: + query_type = "build" + job_url = f"{JENKINS_URL}/job/{JOB_NAME}/{query_type}" + + jarhead = http.cookiejar.CookieJar() + base64string = base64.b64encode(f"{USERNAME}:{APITOKEN}".encode("utf-8")) + headers = [("Authorization", f"Basic {base64string.decode('utf-8')}")] + + crumb = get_crumb(headers, jarhead).read().decode().replace("Jenkins-Crumb:", "") + headers.append(("Jenkins-Crumb", crumb)) + + request = urllib.request.Request(job_url, data=data) + if filename: + headers.append(("Content-Type", "multipart/form-data")) + headers.append(("Content-Length", os.stat(filename).st_size)) + request = urllib.request.Request(job_url, open(filename, "rb")) + + opener = urllib.request.build_opener(urllib.request.HTTPCookieProcessor(jarhead)) + opener.addheaders = headers + with opener.open(request) as handle: + print(f"Job has started, status: {handle.status}") + handle.read().decode("utf-8") + main() + + env: + - name: USERNAME + valueFrom: + secretKeyRef: + name: $(params.JENKINS_SECRETS) + key: username + - name: API_TOKEN + valueFrom: + secretKeyRef: + name: $(params.JENKINS_SECRETS) + key: apitoken + - name: JENKINS_CRUMB + valueFrom: + secretKeyRef: + name: $(params.JENKINS_SECRETS) + key: crumb