kabanero-io / events-operator

This repo will be archived soon.
Apache License 2.0
9 stars 3 forks source link

events-operator

Build Status

Table of Contents

Introduction

The events operator allows users to define a Kubernetes centric event mediation flow. Through custom resource definitions, users can quickly construct mediation logic to receive, transform, and route JSON data structure. The transformation logic is based on Common Expression Language (CEL).

The use cases for event mediator include:

Functional Specification

The main components of events infrastructure are:

Like other Kubernetes resources, the event mediators, mediations, and connections may be changed dynamically.

Event Mediators

An event mediator contains a list of mediations. As an example:

apiVersion: events.kabanero.io/v1alpha1
kind: EventMediator
metadata:
  name: webhook
spec:
  createListener: true
  createRoute: true
  mediations:
    - mediation:
        name: webhook
        sendTo: [ "dest"  ]
        body:
          - = : 'sendEvent(dest, message)'

When the attribute createListener is true, a https listener is created to receive JSON data as input. In addition, a Service with the same name as the mediator's name is created so that the listener is accessible. An OpenShift service serving self-signed TLS certificate is automatically created to secure the communications. No authentication/authorization is currently implemented.

The URL to send a JSON message to the mediation within the mediator is https://<mediatorname>/<mediation name>. For example: https://webhook/webhook. The <mediation name> in the URL addresses the specific mediation within the mediator.

When both attributes createListener and createRoute are set to true, a new Route with the same name as the mediator is created to allow external access to the mediator. The external host name for the Route is installation specific. The default URL to send a message to the mediation is https:<external name>/<mediation name>. For example: https://webhook-default.apps.mycompany.com/webhook.

Event Mediations

Each event mediation within a mediator defines one path for message processing. Its general form looks like :

  mediations:
    - mediation:
        name: <mediation name>
        variables:
            - name: <variable-name-1>
              value: <variable-value-1>
            - name: <variable-name-2>
              value: <variable-value-2>
            ...
        sendTo: [ "destination 1", "destination 2", ...  ]
        body:
           <body>

The attributes are:

Two additional implicitly pre-defined variables are also available for a mediation:

The body of a mediation is an array of JSON objects, where each object may contain one or multiples of:

For examples:

apiVersion: events.kabanero.io/v1alpha1
kind: EventMediator
metadata:
  name: example
spec:
  createListener: true
  createRoute: true
  mediations:
    - mediation:
        name: mediation1
        sendTo: [ "dest1", "dest2", "dest3"  ]
        body:
          - =: 'attrValue = "" '
          - if: "has(body.attr)"
            =: "attrValue = body.attr"
          - switch:
              - if : ' attrValue == "value1" '
                =: "sendEvent(dest1, body, header)"
              - if : 'attrValue == "value2" '
                =: "sendEvent(dest2, body, header)"
              - default:
                =: "sendEvent(dest3, body, header)"

More formally,

Below are examples of assignments. Note that variable name is optional.

=: 'attrValue = 1"
=: " sendEvent(dest, body, header)

The first variation of an if statement:

 - if : ' attrvalue == "value1" '
   =: "sendEvent(dest1, message)"

And second variation of an if statement with a body:

- if : ' attrvalue == "value1" '
  body:
    - =: "attr = "value1""
    - =: "sendEvent(dest1, body, header)"

An example of switch statement:

- switch:
  - if : ' attrvalue == "value1" '
    =: "sendEvent(dest1, body, header)"
  - if : 'attrValue == "value2" '
    =: "sendEvent(dest2, body, header)"
  - default:
    =: "sendEvent(dest3, body, header)"

Built-in functions

Additional bult-in functions are provided to falicitate event processing and routing. These are in addition to stanard functions in the Common Expression Language.

sendEvent

The sendEvent function sends an event to a destination.

Input:

Output: empty string if OK, otherwise, error message

Example:

  - =: 'sendEvent(tekton-listener, body, header)'

eventListenerURL("deploy-kustomize-listener")

The eventListenerURL function returns the URL for an event listener.

Input:

Output: the internal URL of the event listener if found. Otherwise, an error message.

Example:

  - =: 'url = eventListenerURL("deploy-kustomize-listener")'

Event Connections

Event connections map the destinations of mediations to real endpoints. Currently only https endpoints are supported.

Given the mediator with mediation named webhook below:

apiVersion: events.kabanero.io/v1alpha1
kind: EventMediator
metadata:
  name: webhook
spec:
  createListener: true
  createRoute: true
  mediations:
    - mediation:
        name: webhook
        sendTo: [ "dest"  ]
        body:
          - = : 'sendEvent(dest, body, header)'

The connection specification may look like:

apiVersion: events.kabanero.io/v1alpha1
kind: EventConnections
metadata:
  name: example1
spec:
  connections:
    - from:
        mediator:
            name: webhook
            mediation: webhook
            destination: dest
      to:
        - https:
            - url: https://mediator1/mediation1
              insecure: true
            - urlExpression: cel_expression
              insecure: true

The from attribute specifies:

The to attribute currently only supports https endpoints. The url may be any REST endpoint. If pointing to another mediator, the other mediator's createListener attribute must be set to true, and the URL to use is: https://<service-name>/<mediation name>, where <service-name> is the name of the mediator.

The urlExpression is used to enable dynamically generated destinations. It is an Common Expression Language expression evaluated within the scope of the mediation.

Webhook Processing

The mediator framework provides additional function to facilitate the processing of webhook messages. Currently only github webhook messages are supported. For example:

apiVersion: events.kabanero.io/v1alpha1
kind: EventMediator
metadata:
  name: webhook
spec:
  createListener: true
  createRoute: true
  repositories:
    - github:
        secret: your-github-secret
        webhookSecret: my-webhook-secret
  mediations:
    - mediation:
        name: appsody
        selector:
          - urlPattern: webhook
          - repositoryType:
            file: .type1.yaml
            newVariable: message.body.webhooks-type1
        sendTo: [ "dest"  ]
        variables:
          - name: message.body.webhooks-tekton-service-account
            value: kabanero-pipeline
          body:
              - = : 'sendEvent(dest, body, header)'
    - mediation:
        name: gitops
        selector:
          - urlPattern: webhook
          - repositoryType:
            name: message.body.webhooks-type2
            file: .type2.yaml
        sendTo: [ "dest"  ]
        body:
          - = : 'sendEvent(dest, body, header)'

The repositories attribute defines repository related configuration. For github repository,

The selector defines which mediation to call based on the specified criteria:

The varibles section creates new variables.

In addition, the mediation automatically adds additional predefined variables to the body of the incoming message after the creation of the repository variables. Though these variables are meant to be used for Tekton event listeners, they are generic enough to be used by other downstream listeners as well.

When processing an incoming webhook message, the flow is as follows:

Kabanero Integration

This section contains a tutorial on how the event mediator is integrated with Kabanero. The integration point is to use the event mediator as a organizational webhook to drive Tekton pipelines installed with Kabanero.

Basic Architecture

Webhook Mediator

As shown above, the webhook mediator may be used with a github organizational webhook. Once defined, all webhook events within the organization are sent to the the same webhook mediator.
The mediator does the following for appsody projects:

  1. Determine that the type of the repository is appsody.
  2. Find the best matching Tekton event listener based on the semantic version of the project.
  3. Generate parameters required for the Tekton listener and Tekton trigger bindings.
  4. Forward the request to the listener.

For example, the steps to process the pull request for project2 involves:

  1. Webhook mediator receives a pull request webhook event.
  2. Webhook mediator determines the type of the repository is appsody, and the requested stack version 0.3.
  3. Webhook mediator locates the Tekton event listener that best matches the stack, which is listener for stack version 0.3.3.
  4. Webhook mediator add the Tekton related parameters to the message body.
  5. Webhook mediator forwards the webhook message with the added parameters to the Tekton listener.

Note that for our example, there is no match for project1 , while the match for project3 is for version 1.0.2.

Install Kabanero

Follow the instructions here: https://kabanero.io/docs/ref/general/installation/installing-kabanero-foundation.html

Change to kabanero project

Change to the project where kabanero is installed. The default is kabanero. For example,

oc project kabanero

Create Kabanero CRD with events-operator enabled

Edit and apply the following yaml to use the default stacks and events based pipeline:

apiVersion: kabanero.io/v1alpha2
  kind: Kabanero
  metadata:
    name: kabanero
  spec:
    version: "0.9.1"
    stacks:
      repositories:
      - name: central
        https:
          url: https://github.com/kabanero-io/collections/releases/download/0.9.0/kabanero-index.yaml
      pipelines:
      - id: default
        sha256: caf603b69095ec3d128f1c2fa964a2964509854e306fb3c5add8addc8f7f7b71
        https:
          url: https://github.com/kabanero-io/kabanero-pipelines/releases/download/0.9.1/kabanero-events-pipelines.tar.gz

Create Github related secrets

API Token

The mediator needs an API token to access github to read configuration files such as .appsody-config.yaml. You may use an existing secret already configured for Tekton pipelines, or you may configure a new secret.

If you need to create a new secret, edit and apply the following secret:

apiVersion: v1
kind: Secret
metadata:
  name: my-github-secret
  namespace: kabanero
  annotations:
    tekton.dev/git-0: https://github.com
type: kubernetes.io/basic-auth
stringData:
  username: <user name>
  password: <API token>

Note:

Image registry secret

If you have not yet configured a secret for your Tekton pipeline to access your image registry, edit and apply the following secret:

apiVersion: v1
kind: Secret
metadata:
  name: my-docker-secret
  annotations:
    tekton.dev/docker-0: https://index.docker.io
type: kubernetes.io/basic-auth
stringData:
  username: <user>
  password: <password>

Note:

Update Pipeline Service Account

Associate the secrets you created with your Tekton pipeline service account. This enables them to be used when running the pipelines. The default service account is kabanero-pipeline.

oc edit serviceaccount kabanero-pipeline

At the bottom, add the following entries

secrets:
- name: my-github-secret
- name: my-docker-secret

Save the file when done.

Webhook Secret

The webhook secret is the secret you configure on Github, and embedded in each webhook message received from github. It enables the mediator to verify that the message is indeed from github.

Edit and apply the following secret. Change <my-webhook-secret> to a string of your choosing. You'll provide the same string when configuring the webhook secret on Github.

apiVersion: v1
kind: Secret
metadata:
  name: my-webhook-secret
stringData:
  secretToken: <my-webhook-secret>

Create Webhook Event Mediator

To create a webhook mediator, edit and apply the following yaml file:

apiVersion: events.kabanero.io/v1alpha1
kind: EventMediator
metadata:
  name: webhook
spec:
  createListener: true
  createRoute: true
  repositories:
    - github:
        secret: my-github-secret
        webhookSecret: my-webhook-secret
  mediations:
    - name: webhook
      selector:
        repositoryType:
          newVariable: body.webhooks-appsody-config
          file: .appsody-config.yaml
      variables:
        - name: body.webhooks-tekton-target-namespace
          value: kabanero
        - name: body.webhooks-tekton-service-account
          value: kabanero-pipeline
        - name: body.webhooks-tekton-docker-registry
          value: <my-docker-registry>
        - name: body.webhooks-tekton-ssl-verify
          value: "false"
        - name: body.webhooks-tekton-insecure-skip-tls-verify
          value: "true"
        - name: body.webhooks-tekton-local-deploy
          value: "true"
        - name: body.webhooks-tekton-monitor-dashboard-url
          value: <tekton-dashboard>
      sendTo: [ "dest"  ]
      body:
        - = : "sendEvent(dest, body, header)"

Note:

use oc get route webhook to find the external hostname of the route that was created. Use this host when creating a webhook.

Create Event Connections

Apply the following yaml:

apiVersion: events.kabanero.io/v1alpha1
kind: EventConnections
metadata:
  name: connections
spec:
  connections:
    - from:
        mediator:
            name: webhook
            mediation: webhook
            destination: dest
      to:
        - https:
            - urlExpression:  body["webhooks-kabanero-tekton-listener"]
              insecure: true

Note that body["webhooks-kabanero-tekton-listner"] is a variable generated by the mediator. Its value is the Tekton event listener that best matches the incoming stack version using semantic versioning.

Configure webhook on your source repository

To create an organization webhook, follow the instructions here for Configuring webhooks for organization events in your enterprise account.

Note:

If you are not working within an enterprise, you may also create per-repository webhook.

Test webhook

Make a change to an Appsody project on github, within the organization that you configured the webhook.

Kabanero Web hook Processing Flow for Appsody Projects

Let's illustrate the flow with a sample appsody project whose .appsody-config.yaml looks like:

project-name: test1
stack: docker.io/kabanero/nodejs:0.3

The name of this project is test1, and the name of the stack is docker.io/kabanero/nodejs. The version of the stack is 0.3. It may be built with any Kabanero build pipeline that is semantically matched to version 0.3.

The association between a stack and its corresponding build pipelines is specified in the Kabanero CRD. In the following example, pipeline release 0.3.0-rc1 is used to build appsody stacks in release 0.3.0-rc1. And the pipelines in release 1.0.0.-rc is used to build the stacks in release 1.0.0-rc1.

apiVersion: kabanero.io/v1alpha2
kind: Kabanero
metadata:
  name: kabanero
  namespace: kabanero
  resourceVersion: "244275"
  selfLink: /apis/kabanero.io/v1alpha2/namespaces/kabanero/kabaneros/kabanero
  uid: b217411a-480b-41e4-b01b-8e2aabec165d
spec:
  events:
    enable: true
  stacks:
    repositories:
    - gitRelease: {}
      name: central
      https:
        url: https://github.com/kabanero-io/kabanero-stack-hub/releases/download/0.3.0-rc.1/kabanero-stack-hub-index.yaml
      pipelines:
      - gitRelease: {}
        https:
          url: https://github.com/kabanero-io/kabanero-pipelines/releases/download/0.3.0-rc.1/default-kabanero-pipelines.tar.gz
        id: default
        sha256: 12345678eef31fea470abc860909b407f0af54016acb79b723c04c711350d344
    - gitRelease: {}
      name: central
      https:
        url: https://github.com/kabanero-io/kabanero-stack-hub/releases/download/1.0.0-rc.1/kabanero-stack-hub-index.yaml
      pipelines:
      - gitRelease: {}
        https:
          url: https://github.com/kabanero-io/kabanero-pipelines/releases/download/1.0.0-rc.1/default-kabanero-pipelines.tar.gz
        id: default
        sha256: 87654321eef31fea470abc860909b407f0af54016acb79b723c04c711350d344
  version: 0.7.0

After the kabanero CRD is applied, the Stack CRD is created to track the pipeline resources associated with the stack release. For example,

apiVersion: kabanero.io/v1alpha2
kind: Stack
metadata:
  name: nodejs
  namespace: kabanero
  ...
spec:
  name: nodejs
  versions:
  - images:
    - id: Node.js
      image: docker.io/kabanero/nodejs
    pipelines:
    - gitRelease: {}
      https:
        url: https://github.com/kabanero-io/kabanero-pipelines/releases/download/0.3.0/default-kabanero-pipelines.tar.gz
      id: default
      sha256: 876543221af21540f0d0dac8caf0a2d805e8d90f174cb912a31831f700d049bb1
    version: 0.3.3
  - images:
    - id: Node.js
      image: docker.io/kabanero/nodejs
    pipelines:
    - gitRelease: {}
      https:
        url: https://github.com/kabanero-io/kabanero-pipelines/releases/download/1.0.0/default-kabanero-pipelines.tar.gz
      id: default
      sha256: 12345678af21540f0d0dac8caf0a2d805e8d90f174cb912a31831f700d049bb1
    version: 1.0.0
status:
  summary: '[ 0.3.3: active ] [ 1.0.0: active ]'
  versions:
  - images:
    - id: Node.js
      image: docker.io/kabanero/nodejs
    pipelines:
    - activeAssets:
      - assetDigest: ...
        version: v1alpha1
        status: active
        group: tekton.dev
        kind: EventListener
        namespace: kabanero
        assetName: listener-12345678
      - assetDigest: 12345678601fbb577ce2fdf3557261ef5c3915bb15d5ea5f9423191e2366bb0b
        assetName: build-push-pl-12345678
        group: tekton.dev
        kind: Pipeline
        namespace: kabanero
        status: active
        version: v1alpha1a
    status: active
    version: 0.3.3
  - images:
    - id: Node.js
      image: docker.io/kabanero/nodejs
    pipelines:
    - activeAssets:
      - assetDigest: ...
        version: v1alpha1
        status: active
        group: tekton.dev
        kind: EventListener
        namespace: kabanero
        assetName: listener-87654321
      - assetDigest: 87654321601fbb577ce2fdf3557261ef5c3915bb15d5ea5f9423191e2366bb0b
        assetName: build-push-pl-87654321
        group: tekton.dev
        kind: Pipeline
        namespace: kabanero
        status: active
        version: v1alpha1a
    status: active
    version: 1.0.0
...

Note that:

When a new webhook message is received, the event mediator uses the selector in the mediator to find a matching mediation. It verifies the url pattern of the webhook request, the github secret, and reads .appsody-config.yaml. This allows it to associate the webhook event with the mediation appsody.

The event mediator applies additional logic for appsody projects. First, it finds the best matching active stack by matching its .spec.images[i].name to the stack name as defined in appsody-config.yaml. It uses .spec.images[i].version to find the best semantically matched version. It uses .status to ensure that the version is active. It creates the variable message.body.webhooks-kabanero-tekton-listener to be listener-12345678.

It also creates all the default variables and user defined variables to be passed downstream to the Tekton event listener.

When sending the message downstream, the URL as defined in the EventConnection is: body["webhooks-kabanero-tekton-listener"]. This resolves to: https://listener-12345678

The Tekton event listener is configured to trigger the correct pipeline based on input parameters. For the example below, there is a separate pipeline called depending on whether it is a push or pull request. In addition, a separate monitor task is created when the event mediator decides.

apiVersion: tekton.dev/v1alpha1
kind: EventListener
metadata:
  name: listener-12345678
  namespace: kabanero
spec:
  serviceAccountName: tekton-webhooks-extension-eventlistener
  triggers:
  - bindings:
    name: kabanero-push-event
    template:
      apiversion: v1alpha1
      name: build-deploy-pl-template-12345678
    - apiversion: v1alpha1
      name: build-deploy-pl-push-binding-12345678
    - interceptor:
      - cel:
          filter: 'body["webhooks-event-type"] == "push" '
  - bindings:
    name: kabanero-pullrequest-event
    - apiversion: v1alpha1
      name: build-deploy-pl-pullrequest-binding-12345678
    template:
      apiversion: v1alpha1
      name: build-deploy-pl-template-12345678
    interceptors:
      - cel:
          filter: 'body["webhooks-event-type"] == "pull_request" '
  - bindings:
    name: kabanero-monitor-task-event
    - apiversion: v1alpha1
      name: monitor-task-github-binding-12345678
    template:
     apiversion: v1alpha1
     name: monitor-task-template-12345678
     interceptors:
      - cel:
          filter: 'body["webhooks-tekton-monitor"] '

Tech Preview

You may configure event mediator to use the tech preview gitops pipeline to deploys your application. To use the tech preview, these additional steps are required:

Gitops Repository

Configure your gitops repository per instructions in the Kabanero pipelines section.

Webhook Mediator

Edit and apply the following webhook mediator, instead of using the default webhook mediator:

apiVersion: events.kabanero.io/v1alpha1
kind: EventMediator
metadata:
  name: webhook
spec:
  createListener: true
  createRoute: true
  repositories:
    - github:
        secret: my-github-secret
        webhookSecret: my-webhook-secret
  mediations:
    - name: webhook
      selector:
        repositoryType:
          newVariable: body.webhooks-appsody-config
          file: .appsody-config.yaml
      variables:
        - name: body.webhooks-tekton-target-namespace
          value: kabanero
        - name: body.webhooks-tekton-service-account
          value: kabanero-pipeline
        - name: body.webhooks-tekton-docker-registry
          value: <my-docker-registry>
        - name: body.webhooks-tekton-ssl-verify
          value: "false"
        - name: body.webhooks-tekton-insecure-skip-tls-verify
          value: "true"
        - name: body.webhooks-tekton-local-deploy
          value: "false"
        - name: body.webhooks-tekton-monitor-dashboard-url
          value: <tekton-dashboard>
      sendTo: [ "dest"  ]
      body:
        - = : "sendEvent(dest, body, header)"
    - name: gitops
      selector:
        repositoryType:
          newVariable: body.webhooks-gitops
          file: environments/kustomization.yaml
      variables:
        - name: body.webhooks-tekton-target-namespace
          value: kabanero
        - name: body.webhooks-tekton-service-account
          value: kabanero-pipeline
        - name: body.webhooks-tekton-docker-registry
          value: <my-docker-registry>
        - name: body.webhooks-tekton-ssl-verify
          value: "false"
        - name: body.webhooks-tekton-insecure-skip-tls-verify
          value: "true"
        - name: body.webhooks-tekton-local-deploy
          value: "false"
        - name: body.webhooks-tekton-monitor-dashboard-url
          value: <tekton-dashboard>
      sendTo: [ "dest"  ]
      body:
        - = : "sendEvent(dest, body, header)"

Note:

EventConnections

Create and apply the following EventConnections, instead of using the default:

apiVersion: events.kabanero.io/v1alpha1
kind: EventConnections
metadata:
  name: connections
spec:
  connections:
    - from: 
        mediator:
            name: webhook
            mediation: webhook
            destination: dest
      to:
        - https:
            - urlExpression:  body["webhooks-kabanero-tekton-listener"]
              insecure: true
    - from: 
        mediator:
            name: webhook
            mediation: gitops
            destination: dest
      to:
        - https:
            - urlExpression:  eventListenerURL("deploy-kustomize-listener")
              insecure: true

Note that:

Using the Gitops Pipeline

Migrating from Tekton Webhooks Extension

If you are already using the Tekton Webhooks extension, and you would like to continue to use your existing pipelines with Kabanero Events, you can do so by creating a passthrough mediation. The passthrough mediation will pass any events it receives to the configured EventListener.

The steps to use an existing pipeline with the webhook mediator is as follows:

  1. Apply the monitor-task-binding.yaml and event-trigger-binding.yaml TriggerBindings.
  2. Create an internal EventListener to route traffic to the existing pipelines. See below for an example EventListener. Note that the EventListener should be applied in same namespace as the webhook extension (i.e. tekton-pipelines).
  3. Create a webhook mediator that passes events through to the EventListener.
  4. Remove the existing webhook configuration created by Tekton Webhooks extension from your project on Github
  5. Configure a webhook at either the organization level or the project level in Github to call the webhook mediator.

Setting up the EventListener

A few TriggerBindings need to be applied to be able to use your existing Tekton triggers created by the Tekton webhooks extension. Run the following two commands to create these resources:

cat <<'EOF' | kubectl apply -n tekton-pipelines -f -
apiVersion: triggers.tekton.dev/v1alpha1
kind: TriggerBinding
metadata:
  name: kabanero-events-webhook-trigger-binding
spec:
  params:
  - name: webhooks-tekton-release-name
    value: "$(body.webhooks-tekton-release-name)"
  - name: webhooks-tekton-target-namespace
    value: "$(body.webhooks-tekton-target-namespace)"
  - name: webhooks-tekton-service-account
    value: "$(body.webhooks-tekton-service-account)"
  - name: webhooks-tekton-git-server
    value: "$(body.webhooks-tekton-git-server)"
  - name: webhooks-tekton-git-org
    value: "$(body.webhooks-tekton-git-org)"
  - name: webhooks-tekton-git-repo
    value: "$(body.webhooks-tekton-git-repo)"
  - name: webhooks-tekton-pull-task
    value: "$(body.webhooks-tekton-pull-task)"
  - name: webhooks-tekton-ssl-verify
    value: "$(body.webhooks-tekton-ssl-verify)"
  - name: webhooks-tekton-insecure-skip-tls-verify
    value: "$(body.webhooks-tekton-insecure-skip-tls-verify)"
  - name: webhooks-tekton-docker-registry
    value: "$(body.webhooks-tekton-docker-registry)"
EOF
cat <<'EOF' | kubectl apply -n tekton-pipelines -f -
apiVersion: triggers.tekton.dev/v1alpha1
kind: TriggerBinding
metadata:
  name: kabanero-events-monitor-task-binding
spec:
  params:
  - name: commentsuccess
    value: $(body.commentsuccess)
  - name: commentfailure
    value: $(body.commentfailure)
  - name: commenttimeout
    value: $(body.commenttimeout)
  - name: commentmissing
    value: $(body.commentmissing)
  - name: gitsecretname
    value: $(body.gitsecretname)
  - name: gitsecretkeyname
    value: $(body.gitsecretkeyname)
  - name: dashboardurl
    value: $(body.dashboardurl)
  - name: insecure-skip-tls-verify
    value: $(body.webhooks-tekton-insecure-skip-tls-verify)
  - name: provider
    value: $(body.provider)
  - name: apiurl
    value: $(body.apiurl)
EOF

The internal EventListener that the mediator will forward events to can now be created. The example EventListener configuration demonstrates how to set up an EventListener that processes GitHub push and pull_request events for two stacks: java-openliberty and nodejs-express. Push and pull requests events that are handled will cause the appropriate build-push pipeline to be executed.

apiVersion: triggers.tekton.dev/v1alpha1
kind: EventListener
metadata:
  name: kabanero-event-listener
  namespace: tekton-pipelines
spec:
  serviceAccountName: tekton-webhooks-extension-eventlistener
  triggers:
  - name: kabanero-ol-push-event
    interceptors:
    - cel:
        filter: 'body["webhooks-appsody-config"]["stack"].contains("java-openliberty:") && body["webhooks-tekton-event-type"] == "push" && body["webhooks-tekton-git-branch"] == "master"'
    template:
      apiVersion: v1alpha1
      name: java-openliberty-build-push-pl-template
    bindings:
    - apiversion: v1alpha1
      kind: TriggerBinding
      name: java-openliberty-build-push-pl-push-binding
    - apiversion: v1alpha1
      kind: TriggerBinding
      name: kabanero-events-webhook-trigger-binding
  - name: kabanero-ol-pullrequest-event
    interceptors:
    - cel:
        filter: 'body["webhooks-appsody-config"]["stack"].contains("java-openliberty:") && body["webhooks-tekton-event-type"] == "pull_request" && body["webhooks-tekton-git-branch"] != "master" && (body["action"] == "opened" || body["action"] == "synchronize")'
    template:
      apiVersion: v1alpha1
      name: java-openliberty-build-push-pl-template
    bindings:
    - apiversion: v1alpha1
      kind: TriggerBinding
      name: java-openliberty-build-push-pl-pullrequest-binding
    - apiversion: v1alpha1
      kind: TriggerBinding
      name: kabanero-events-webhook-trigger-binding
  - name: kabanero-nodejs-express-push-event
    interceptors:
    - cel:
        filter: 'body["webhooks-appsody-config"]["stack"].contains("nodejs-express:") && body["webhooks-tekton-event-type"] == "push" && body["webhooks-tekton-git-branch"] == "master"'
    template:
      apiVersion: v1alpha1
      name: nodejs-express-build-push-pl-template
    bindings:
    - apiversion: v1alpha1
      kind: TriggerBinding
      name: nodejs-express-build-push-pl-push-binding
    - apiversion: v1alpha1
      kind: TriggerBinding
      name: kabanero-events-webhook-trigger-binding
  - name: kabanero-nodejs-express-pullrequest-event
    interceptors:
    - cel:
        filter: 'body["webhooks-appsody-config"]["stack"].contains("nodejs-express:") && body["webhooks-tekton-event-type"] == "pull_request" && body["webhooks-tekton-git-branch"] != "master" && (body["action"] == "opened" || body["action"] == "synchronize")'
    template:
      apiVersion: v1alpha1
      name: nodejs-express-build-push-pl-template
    bindings:
    - apiversion: v1alpha1
      kind: TriggerBinding
      name: nodejs-express-build-push-pl-pullrequest-binding
    - apiversion: v1alpha1
      kind: TriggerBinding
      name: kabanero-events-webhook-trigger-binding
  - name: kabanero-monitor-task-event
    interceptors:
    - cel:
        filter: 'body["webhooks-tekton-event-type"] == "pull_request" && body["webhooks-tekton-git-branch"] != "master" && (body["action"] == "opened" || body["action"] == "synchronize")'
    template:
      apiversion: v1alpha1
      name: monitor-task-template
    bindings:
    - apiversion: v1alpha1
      kind: TriggerBinding
      name: monitor-task-github-binding
    - apiversion: v1alpha1
      kind: TriggerBinding
      name: kabanero-events-monitor-task-binding

The example EventListener can be modified for whichever pipelines you would like to execute based on the stack and event that is handled. The TriggerTemplates and TriggerBindings needed can be determined by inspecting your current Webhooks extension EventListener:

$ oc get el <the-eventlistener-being-migrated> -o yaml | less
...

Note that any TriggerBindings prefixed with wext- do not need to be added since you already applied the replacement TriggerBindings above.

Once you are finished creating the replacement EventListener, it should be applied to the tekton-pipelines namespaces like so:

$ oc apply -f kabanero-event-listener.yaml -n tekton-pipelines

Setting up the Passthrough Event Mediation

To setup a passthrough event mediation, first set up the connections to route from the mediation to the EventListener created in the previous step:

apiVersion: events.kabanero.io/v1alpha1
kind: EventConnections
metadata:
  name: example-connections
spec:
  connections:
    - from: 
        mediator:
            name: example-webhook-mediator
            mediation: example-webhook
            destination: dest
      to:
        - https:
            - url: "http://el-<name-of-the-event-listener-created-above>.tekton-pipelines.svc.cluster.local:8080"
              insecure: true

The passthrough webhook mediation should then look like:

apiVersion: events.kabanero.io/v1alpha1
kind: EventMediator
metadata:
  name: example-webhook-mediator
spec:
  createListener: true
  createRoute: true
  repositories:
    - github:
        secret: ghe-https-secret
        webhookSecret: ghe-webhook-secret
  mediations:
    - name: example-webhook
      selector:
        repositoryType:
          newVariable: body.webhooks-appsody-config
          file: .appsody-config.yaml
      variables:
        - name: body.webhooks-tekton-target-namespace
          value: kabanero
        - name: body.webhooks-tekton-service-account
          value: kabanero-pipeline
        # body.webhooks-tekton-docker-registry is docker registry you want; e.g. `docker.io/<your-dockerhub-user-name>`
        - name: body.webhooks-tekton-docker-registry
          value: <your-docker-registry>
        - name: body.webhooks-tekton-ssl-verify
          value: "false"
        - name: body.webhooks-tekton-insecure-skip-tls-verify
          value: "true"
        - name: body.webhooks-tekton-local-deploy
          value: "false"
        - name: body.webhooks-tekton-monitor-dashboard-url
          value: "https://tekton-dashboard-tekton-pipelines.apps.<your-domain>/#/pipelineruns"
        # Additional values needed by the webhooks extension TriggerBindings
        - name: body.webhooks-tekton-release-name
          valueExpression: 'body["webhooks-tekton-git-repo"]'
        - name: body.webhooks-tekton-pull-task
          value: monitor-task
        # Values needed by the monitor task.
        - name: body.commentsuccess
          value: Success
        - name: body.commentfailure
          value: Failed
        - name: body.commenttimeout
          value: Unknown
        - name: body.commentmissing
          value: Missing
        - name: body.gitsecretname
          valueExpression: 'body["webhooks-tekton-github-secret-name"]'
        - name: body.gitsecretkeyname
          valueExpression: 'body["webhooks-tekton-github-secret-key-name"]'
        - name: body.dashboardurl
          value: tekton-dashboard-tekton-pipelines.apps.<your-domain>
        - name: body.provider
          value: github
        - name: body.apiurl
          value: https://<github-url>/api/v3/
      sendTo: [ "dest"  ]
      body:
        - = : "sendEvent(dest, body, header)"

Set the values to the variables as needed, particularly those whose values enclosed within <>. These values can be determined by looking at the wext- trigger binding that the Webhooks extension created for your EventListener. Afterwards, apply both the connections and webhook mediation YAML to the kabanero namespace.

Configuring the Webhook

The webhook that calls the webhook mediator can be configured at the project level or at the organization level. The Tekton webhooks extension only supported project-level webhooks, but Kabanero events also supports webhooks at the organization level. An organization-level webhook is suggested to save users from having to configure a webhook for each repository.

The webhook should be created with the following information: