OpenShift Pipelines (Tekton) - Triggers Basics
Let’s Explore Tekton Triggers
Recap from the Intro: A fully configured Tekton Trigger is composed of five components:
-
A TriggerTemplate defines the Pipeline and/or Task resources, and the parameters which are passed to them
-
A TriggerBinding links values from a webhook payload to parameters that are passed to a TriggerTemplate
-
A Trigger is a custom resource that combines Interceptors, TriggerBindings, and TriggerTemplates into a unit
-
An EventListener receives the webhook payload and passes it to one or more Triggers. The EventListener is the only component in Tekton that is a long running process. It runs as a Pod in the Namespace that it was created in.
-
An Interceptor is used to perform validation or value-add activities on a webhook payload before it is passed to the TriggerTemplate for the execution of pipelines and or tasks
Create a basic webhook trigger:
-
Take a look at the file named
first-trigger.yaml
apiVersion: triggers.tekton.dev/v1beta1 kind: TriggerTemplate metadata: name: my-app-trigger-template annotations: triggers.tekton.dev/old-escape-quotes: 'true' spec: params: - name: app-name description: The application name default: my-app - name: run-it description: Should I run the new container image? resourcetemplates: - apiVersion: tekton.dev/v1beta1 kind: PipelineRun metadata: generateName: my-app-pipeline-run- labels: app-name: my-app spec: serviceAccountName: pipeline pipelineRef: name: build-container-run-pod params: - name: app-name value: $(tt.params.app-name) - name: run-it value: $(tt.params.run-it) --- apiVersion: triggers.tekton.dev/v1beta1 kind: TriggerBinding metadata: name: my-app-trigger-binding spec: params: - name: app-name value: "$(body.name)" - name: run-it value: "$(body.run-it)" --- apiVersion: triggers.tekton.dev/v1beta1 kind: Trigger metadata: name: my-app-trigger spec: interceptors: [] bindings: - ref: my-app-trigger-binding template: ref: my-app-trigger-template --- apiVersion: triggers.tekton.dev/v1beta1 kind: EventListener metadata: name: my-app-trigger-listener spec: serviceAccountName: pipeline triggers: - triggerRef: my-app-trigger
This file contains four objects:
-
A TriggerTemplate named
my-app-trigger-template
-
A TriggerBinding named
my-app-trigger-binding
-
A Trigger named
my-app-trigger
-
An EventListener named
my-app-trigger-listener
-
-
Add these objects to your OpenShift project:
oc apply -f ~/tekton-tutorial/basics/first-trigger.yaml -n my-app
-
Note that you now have another Pod running:
oc get pod --field-selector=status.phase==Running -n my-app
NAME READY STATUS RESTARTS AGE el-my-app-trigger-listener-6bf78d7884-mkzgj 1/1 Running 0 7m41s
This is the EventListener. There is also a Service that was created for it.
-
Take a look at the Service that was created:
Get the Service name, it will be the
generatedName
of the EventListeneroc get el my-app-trigger-listener -o=jsonpath='{.status.configuration.generatedName}' -n my-app
Let’s nest that in another command to look at the Service:
oc get service $(oc get el my-app-trigger-listener -o=jsonpath='{.status.configuration.generatedName}') -n my-app
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE el-my-app-trigger-listener ClusterIP 10.217.4.225 <none> 8080/TCP,9000/TCP 14m
-
Load the Service name into an environment variable. We’ll be using it a few times:
SVC_NAME=$(oc get el my-app-trigger-listener -o=jsonpath='{.status.configuration.generatedName}')
-
Create a Route to expose the EventListener so that it can receive external webhook requests:
oc create route edge ${SVC_NAME}-route --service=${SVC_NAME}
-
Take a look at the Route that was created:
oc get route ${SVC_NAME}-route -n my-app
NAME HOST/PORT PATH SERVICES PORT TERMINATION WILDCARD el-my-app-trigger-listener-route el-my-app-trigger-listener-route-my-app.apps-crc.testing el-my-app-trigger-listener http-listener edge None
Note: This is a TLS route with edge termination.
Invoke The Trigger
Let’s Pull that Trigger and see what happens! Then, as before, we’ll pause to talk about it.
First, if you want something to look at:
-
Open the OpenShift web console and login:
If you are using Code Ready Containers:
crc console --credentials crc console
-
Navigate to the
my-app
project -
Expand the
Pipelines
menu on the left-hand nav bar: -
Click on
Pipelines
in the sub-menu: -
Keep this window open where you can see it.
Now, invoke the trigger:
-
Load the EventListener URL into an environment variable.
HOOK_URL=https://$(oc get route ${SVC_NAME}-route -o=jsonpath='{.spec.host}')
-
Invoke the Trigger with
curl
curl --insecure --location --request POST ${HOOK_URL} --header 'Content-Type: application/json' --data-raw '{"name":"run-my-app","run-it":"yes-please"}'
Note: We’ve likely got a self-signed cert on the cluster, so we used the
--insecure
flag… I really hate that.If you have the gear for your own home lab, I show you how to set up secure trust with your cluster.
-
Watch the OpenShift web console window that you have open:
You should see the Pipeline start a run.
Pretty neat, right?
We just invoked a PipelineRun with an external webhook.
Albeit, insecurely… Note that there was no validation that the webhook was from a legitimate source, or that the payload was valid.
That’s what Interceptors are for. We’ll talk about them when we set up some real code here in a bit.
Examine the Trigger Objects
As before, let’s dive into each of the objects that we created:
TriggerTemplate
apiVersion: triggers.tekton.dev/v1beta1
kind: TriggerTemplate
metadata:
name: my-app-trigger-template
annotations:
triggers.tekton.dev/old-escape-quotes: 'true'
spec:
params:
- name: app-name
description: The application name
default: my-app
- name: run-it
description: Should I run the new container image?
resourcetemplates:
- apiVersion: tekton.dev/v1beta1
kind: PipelineRun
metadata:
generateName: my-app-pipeline-run-
labels:
app-name: my-app
spec:
serviceAccountName: pipeline
pipelineRef:
name: build-container-run-pod
params:
- name: app-name
value: $(tt.params.app-name)
- name: run-it
value: $(tt.params.run-it)
Our TriggerTemplate spec:
has two elements:
-
params:
These are the parameters that are passed into the template from a webhook payload. The params are mapped from the webhook payload to theTriggerTemplate
params by aTriggerBinding
We’ll talk about theTriggerBinding
here shortly. -
`resourcetemplates: This is a list of TaskRun and/or PipelineRun objects.
The objects are defined exactly like the TaskRun or PipelineRun objects that we created in a previous exercise.
Note: the reference to the TriggerTemplate params that map to the input params for the
resourcetemplate
objects -$(tt.params.run-it)
TriggerBinding
apiVersion: triggers.tekton.dev/v1beta1
kind: TriggerBinding
metadata:
name: my-app-trigger-binding
spec:
params:
- name: app-name
value: "$(body.name)"
- name: run-it
value: "$(body.run-it)"
Our TriggerBinding spec:
just has one element. The parameters to be mapped.
The value:
of each of the parameters in our example, is being extracted from the payload of the webhook. The webhook is assumed to be JSON, and the payload is mapped to the parameter body
.
Trigger
apiVersion: triggers.tekton.dev/v1beta1
kind: Trigger
metadata:
name: my-app-trigger
spec:
interceptors: []
bindings:
- ref: my-app-trigger-binding
template:
ref: my-app-trigger-template
Our Trigger spec:
has three elements:
-
interceptors:
This would be a list of one or more interceptors that pre-process the webhook payload before releasing it to the TriggerTemplate.We’ll illustrate Interceptors in the next exercise.
-
bindings:
This is a list of one or more TriggerBindings to map data from the webhook to params that the TriggerTemplate can use. -
template:
This is a reference to the TriggerTemplate that defines the actions triggered by a webhook received by the EventListener.
EventListener
apiVersion: triggers.tekton.dev/v1beta1
kind: EventListener
metadata:
name: my-app-trigger-listener
spec:
serviceAccountName: pipeline
triggers:
- triggerRef: my-app-trigger
Our EventListener spec:
has two elements:
-
serviceAccountName:
The namespace scoped service account that we want the Tasks or Pipelines to run as. Note:pipeline
is the default service account, but I included it here just to be explicit. -
triggers:
A list of triggers that the EventListener will invoke. Note: This can be a list of bothtriggerRef:
to externally defined Trigger objects, or inline definedtrigger:
objects. See the docs for more info.
Now Let’s Write Some Code and Build an App
Go to the next section, where we will set up Gitea as our SCM, write some code (generate it actually…), and create a real webhook!
OpenShift Pipelines (Tekton) - Triggers with a cup of Gitea - Cluster Setup