Part III: EDP Tekton Interceptor

Sergiy Kulanov
EPAM Delivery Platform
5 min readFeb 6, 2023

This is the third article in the series of publications describing our migration path to Tekton for the EPAM Delivery Platform (EDP). Check the first part to understand the requirements and baseline architecture better. The second part describes Gerrit and Tekton integrations. This article covers the topic of the EDP Tekton Interceptor, the component we’ve introduced to enrich the events payload from the version control systems (VCSs) to enable conditional execution and extend pipeline logic. What are the benefits of a Tekton Interceptor?

Tekton Interceptor

Tekton Interceptor is a component in the Tekton Pipelines project, an open-source Kubernetes-native framework for creating CI/CD pipelines. The interceptor allows modification and extension of pipeline tasks’ execution behavior. It provides a way to extend the functionality of a pipeline task without modifying its code, e.g., by adding logging, error handling, or conditional execution. Tekton Triggers ships with the following coreInterceptors to help you get started:

Read the official documentation to find out the capabilities of the above components. To better understand the way interceptors work, review the following Kubernetes deployment diagram:

  • VCS (GitHub) has a webhook pointing Ingress URL.
  • Ingress routes traffic to EventListener Pod.
  • EventListener Pod uses Core-Interceptors to process the payload.
EventListener and Core-Interceptors are deployed in the tekton-pipelines namespace.

Logically, the interceptor is defined in the scope of EventListener (see image below). One can mix (chain) interceptors to filter events and modify payload.

Tekton Triggers components.

The EDP Interceptor

The EDP Interceptor is written in Go and enriches the original VCS payload with EDP metadata, e.g., framework, language, build tool, etc. The metadata is stored in the Kubernetes cluster in the format defined by codebases.v2.edp.epam.com Custom Resource Definition (CRD). The following code describes Custom Resource (CR) with the demo-go name, a Go application stored in Gerrit VCS. It has an EDP approach for artifacts versioning and tagging, and supports helm chart deployment:

apiVersion: v2.edp.epam.com/v1
kind: Codebase
metadata:
name: demo-go
spec:
buildTool: Go
ciTool: Jenkins
commitMessagePattern: >-
^\[EPMDEDP-\d+\]:\s(feat|fix|docs|style|refactor|test|chore)+!?:\s[A-Z][a-z]*.*
defaultBranch: master
deploymentScript: helm-chart
emptyProject: false
framework: other
gitServer: gerrit
jenkinsSlave: go
jiraIssueMetadataPayload: '{"components":"EDP_COMPONENT","fixVersions":"EDP_SEM_VERSION-EDP_COMPONENT"}'
jiraServer: jira-corp
jobProvisioning: custom-gerrit
lang: go
repository:
url: https://github.com/epam/edp-codebase-operator.git
strategy: clone
ticketNamePattern: EPMDEDP-\d+
type: application
versioning:
startFrom: 2.6.0-SNAPSHOT
type: edp

Based on the VCS events payload, we perform validation, routing, filtering, and modifications. The EDP CI system operates with two types of pipelines: CodeReview (Pull request event) and Build (Merged event). For details, please refer to Part 1: Tekton adoption.

This is how the event from GitHub is processed: the GitHub interceptor validates the payload, the Cel interceptor selects the proper flow (routing or pipeline), the edp interceptor extracts metadata for the related git repository from the codebase custom resource and puts it spec into the payload. The next in the chain is the cel interceptor which transforms metadata for pipeline consumption. See the definition of the described schema below:

apiVersion: triggers.tekton.dev/v1beta1
kind: EventListener
metadata:
name: github-listener
spec:
triggers:


# Build Pipeline logic
- name: github-listener-build
interceptors:

# Ensure that this payload comes from our GitHub repo
- ref:
name: "github"
params:
- name: "secretRef"
value:
secretName: existingSecret
secretKey: secretString
- name: "eventTypes"
value: ["pull_request"]

# Go further if action is 'closed'
- ref:
name: "cel"
params:
- name: "filter"
value: "body.action in ['closed']"

# Grab EDP codebase spec with EDP Interceptor, which is deployed
# in the same namespace as EventListener
- ref:
name: "edp"
kind: NamespacedInterceptor

# Truncate codebase 'type' field to 3 chars.
# Might be: application (app), library (lib), autotest (aut)
# Later, this value is used for routing stuff, for example
# Pipline name - gerrit-maven-java8-lib-build-default
- ref:
name: "cel"
params:
- name: "overlays"
value:
- key: cbtype_short
expression: "extensions.spec.type.truncate(3)"

bindings:
- ref: github-binding-build
template:
ref: github-build-template


# CodeReview Pipeline logic
- name: github-listener-review
interceptors:
- ref:
name: "github"
params:
- name: "secretRef"
value:
secretName: existingSecret
secretKey: secretString
- name: "eventTypes"
value: ["pull_request"]
- ref:
name: "cel"
params:
- name: "filter"
value: "body.action in ['opened', 'synchronize', 'edited']"
- ref:
name: "edp"
kind: NamespacedInterceptor
- ref:
name: "cel"
params:
- name: "overlays"
value:
- key: cbtype_short
expression: "extensions.spec.type.truncate(3)"
bindings:
- ref: github-binding-review
template:
ref: github-review-template

The conceptual view for the described event routing approach:

Conceptual view for events routing with EDP Interceptor.

The TriggerBinding processes the data from the EDP interceptor and passes it to PipelineRun as variables using TriggerTemplate. Check the TriggerBinding below, it contains the body section from the original VCS payload and the extensions — populated by the EDP Interceptor:

apiVersion: triggers.tekton.dev/v1beta1
kind: TriggerBinding
metadata:
name: github-binding-review
labels:
spec:
params:
- name: gitrevision
value: $(body.pull_request.head.ref)
- name: gitrepositoryurl
value: $(body.repository.ssh_url)
- name: gitrepositoryname
value: $(body.repository.name)
- name: gitfullrepositoryname
value: $(body.repository.full_name)
- name: gitsha
value: $(body.pull_request.head.sha)
- name: buildtool
value: "$(extensions.spec.buildTool)"
- name: framework
value: "$(extensions.spec.framework)"
# Truncated cbtype type name to reduce string length
- name: cbtype
value: "$(extensions.cbtype_short)"
- name: commitMessagePattern
value: "$(extensions.spec.commitMessagePattern)"
- name: codebase
value: "$(extensions.codebase)"
- name: codebasebranch
value: "$(extensions.codebasebranch)"

Based on the extracted values, we run the business logic in our pipelines, for example:

Further steps

While working with Tekton, we’ve faced several challenges. Most of them are already addressed with the latest releases (see CHANGELOG.md). We also plan to share more details in our next publications. Get familiar with the list of our published and future articles on Tekton integration:

Follow us to stay informed :wink:

--

--

Sergiy Kulanov
EPAM Delivery Platform

Systems Architect at EPAM, Ukraine. OpenSource contributor. DevOps, Build, CI Engineer. Current Role: Architect on EPAM Delivery Platform