Skip to content

Commit

Permalink
[TEP-0128]: Scheduled Runs
Browse files Browse the repository at this point in the history
This commit splits TEP-0083 (scheduled and polling runs) into two TEPs,
one for scheduled runs and one for polling runs, and adds an implementation plan
for scheduled runs.
  • Loading branch information
lbernick committed Dec 21, 2022
1 parent beadda1 commit 044f8b8
Show file tree
Hide file tree
Showing 5 changed files with 290 additions and 19 deletions.
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
---
status: proposed
title: Scheduled and Polling runs in Tekton
title: Polling runs in Tekton
creation-date: '2021-09-13'
last-updated: '2021-09-13'
authors:
- '@vdemeester'
- '@sm43'
---

# TEP-0083: Scheduled and Polling runs in Tekton
# TEP-0083: Polling runs in Tekton

<!-- toc -->
- [Summary](#summary)
Expand Down Expand Up @@ -53,9 +53,8 @@ updates.
[documentation style guide]: https://github.com/kubernetes/community/blob/master/contributors/guide/style-guide.md
-->

This TEP introduces an idea for a feature in triggers which allows user to
- Schedule a pipelinerun/taskrun at a certain time
- Setup a poll which looks for changes on a repository and triggers pipelinerun/taskrun.
This TEP introduces an idea for a feature in triggers which allows user to
setup a poll which looks for changes on a repository and triggers pipelinerun/taskrun.

## Motivation

Expand All @@ -68,19 +67,15 @@ demonstrate the interest in a TEP within the wider Tekton community.
[experience reports]: https://github.com/golang/go/wiki/ExperienceReports
-->

- To allow users to schedule a pipelinerun/taskrun at a certain time or at certain interval

Ex. I want to run a pipeline every day at 8 am. Currently, I can do this by setting up a cronjob, but having as a part of Trigger could be a good idea. So, Triggers can start a pipelinerun at the time mentioned by me.

- To allow users to use triggers without need to setup a webhook. Triggers could have a feature which allow user to setup a polling feature for a repository which would look for changes in repository and trigger a pipelinerun or taskrun.

This was briefly discussed on Issue [#1168](https://github.com/tektoncd/triggers/issues/1168) and [#480](https://github.com/tektoncd/triggers/issues/480).

This can be solved currently by a setting up a cronjob to check for changes but having as a part of triggers could enhance triggers.


Both of the feature could be use cases of conditional triggering where one is at certain time and other would at a certain time if an additional condition passes. They are
proposed together as the part implementation would be similar which would be discussed in design part in further iterations.
Both this feature and scheduled runs could be use cases of conditional triggering where one is at certain time
and other would run at a certain time if an additional condition passes.

### Goals

Expand All @@ -98,10 +93,6 @@ and make progress.

### Use Cases (optional)

(Scheduled Run)
- As a user, I want to run a pipeline everyday at a certain time. Currently, I can setup using a cronjob which would trigger the run but having this integrated with triggers would be nice. we would do without this feature would be : a cronjob + creating a PipelineRun or a cronjob and a http call to a trigger (to simulate a webhook event).

(Polling)
- As a user, I don't have permission to setup a webhook on a repository having a polling feature could be helpful to solve this issue. I can configure the polling feature to look for changes and trigger a pipeline.

- Due to restriction of company, users might not be able to expose eventlistener publicly so this could be an option which would look for changes at certain duration and trigger a Pipelinerun. [Reference.](https://github.com/tektoncd/triggers/issues/480#issuecomment-620605920)
Expand Down Expand Up @@ -316,7 +307,7 @@ It will be a quick reference for those looking for implementation of this TEP.
## References (optional)

- Polling a repository to detect changes and trigger a pipeline [#1168](https://github.com/tektoncd/triggers/issues/1168)
- Poll based change detection? [#480](https://github.com/tektoncd/triggers/issues/480)
- Poll based change detection? [#480](https://github.com/tektoncd/triggers/issues/480)


<!--
Expand Down
2 changes: 1 addition & 1 deletion teps/0095-common-repository-configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ Several projects and designs currently in-flight in the Tekton ecosystem
are related to or directly working with source repository-related information.
These include:

- [Scheduled and Polling Runs in Tekton](0083-scheduled-and-polling-runs-in-tekton.md)
- [Polling Runs in Tekton](0083-polling-runs-in-tekton.md)
- [Workflows](../working-groups.md#workflows)
- [Pipeline-as-Code](https://github.com/openshift-pipelines/pipelines-as-code)
- [Remote Resource Resolution](0060-remote-resource-resolution.md)
Expand Down
2 changes: 1 addition & 1 deletion teps/0098-workflows.md
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,6 @@ It will be a quick reference for those looking for implementation of this TEP.

- [TEP-0021: Results API](./0021-results-api.md)
- [TEP-0032: Tekton Notifications](./0032-tekton-notifications.md)
- [TEP-0083: Scheduled and polling runs](./0083-scheduled-and-polling-runs-in-tekton.md)
- [TEP-0083: Polling runs](./0083-polling-runs-in-tekton.md)
- [TEP-0095: Common repository configuration](./0095-common-repository-configuration.md)
- [TEP-0120: Canceling concurrent PipelineRuns](./0120-canceling-concurrent-pipelineruns.md)
279 changes: 279 additions & 0 deletions teps/0128-scheduled-runs.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,279 @@
---
status: implementable
title: Scheduled Runs
creation-date: '2022-12-20'
last-updated: '2022-12-20'
authors:
- '@vdemeester'
- '@sm43'
- '@lbernick'
collaborators: []
---

# TEP-0128: Scheduled Runs

<!-- toc -->
- [Summary](#summary)
- [Motivation](#motivation)
- [Goals](#goals)
- [Non-Goals](#non-goals)
- [Use Cases](#use-cases)
- [Proposal](#proposal)
- [Design Evaluation](#design-evaluation)
- [Reusability](#reusability)
- [Simplicity](#simplicity)
- [Flexibility](#flexibility)
- [Performance](#performance)
- [Security](#security)
- [Drawbacks](#drawbacks)
- [Alternatives](#alternatives)
- [Implementation Plan](#implementation-plan)
- [Implementation Pull Requests](#implementation-pull-requests)
- [References](#references)
<!-- /toc -->

## Summary

This TEP proposes allowing Task/Pipeline users to schedule runs on a recurring basis.

## Motivation

Currently, to get a run to occur on a regular basis, a user must write a cron job that either creates the run itself
(which duplicates much of triggers' functionality) or pings an EventListener.
If the EventListener is exposed outside of the cluster, the user must also sign the cron job event body and verify it in a custom interceptor
(although it's unlikely a user would choose to expose an ingress for an EventListener used only for cron jobs).

### Goals

- Can create new PipelineRuns, TaskRuns, or CustomRuns on a recurring basis without creating a webhook or writing a CronJob

### Non-Goals

- Polling a repository (or other external system) for changes; this is covered in [TEP-0083](./0083-polling-runs-in-tekton.md).

### Use Cases

- Release Pipeline: User would like to create releases of their project on a nightly basis.

## Proposal

Add a `schedule` field following Kubernetes CronJob syntax to the EventListener CRD, for example:

```yaml
kind: EventListener
spec:
schedule: "0 0 * * *"
triggers:
- bindings:
- name: project-name
value: wait-task
- name: triggers-uuid
value: $(context.eventID)
- name: datetime
value: $(context.datetime)
template:
ref: experimental-release-pipeline-template
```
```yaml
kind: EventListener
spec:
schedule: "0 0 * * *"
triggerGroups:
- triggerSelector:
labelSelector:
matchLabels:
type: nightly-release
```
An EventListener with a `schedule` would send an empty event body at the specified times.
This means that any bindings containing `$(body.foo)` or `$(header.bar)` would fail, as well as any interceptors
responsible for processing the event.
An EventListener with a `schedule` would still create a service for receiving events.

### Bindings

As part of future work for this proposal, we can add two new variable replacements in bindings:
- $(context.date): date when the run was created, in RFC3339 format
- $(context.datetime): timestamp when the run was created, in RFC3339 format

### CLI

As part of future work for this proposal, we can add a CLI command to manually trigger execution of an EventListener,
similar to the kubectl functionality `kubectl create job --from=cronjob/my-cronjob`, for example:

```sh
tkn eventlistener start <el_name>
```

## Design Evaluation

### Reusability

This feature is essentially syntactic sugar for a CronJob creating a Tekton resource.
It reuses EventListener functionality such as TriggerGroups and CloudEventSinks.
The schedule is a runtime concern, similar to other fields specified in EventListeners.

### Simplicity

The user experience with this proposal is much simpler with this proposal
(a single additional line of configuration) than without it.
For an example of what the user experience looks like without this proposal, see
the [nightly release CronJob](https://github.com/tektoncd/plumbing/blob/be9826a5e75722782799e8094c3441295b185fe9/tekton/cronjobs/bases/release/trigger-with-uuid.yaml)
used in the plumbing repo.

### Flexibility

- No new dependencies needed for this proposal
- We are not coupling projects together, but we are coupling event generation to resource creation to some extent.

### Conformance

- This proposal doesn't require the user to understand how the API is implemented,
or introduce new Kubernetes concepts into the API.
- The `schedule` field should not be required for Triggers conformance.

### Performance

Creating a CronJob to simply send an empty event body to an EventListener may not be very performant;
however, performance of creating scheduled runs is not as important as (for example) performance
of creating a run used for CI. Using CronJobs is a reasonable way to start, especially if it helps us avoid
reimplementing cron syntax.

### Security

EventListeners with ingresses exposed outside of the cluster are expected to use interceptors to validate event payloads.
EventListeners with `schedules` don't have a way of validating event payloads, as the event body is empty.
While there's less opportunity for attacks using malicious payloads, it's still possible to DOS an EventListener.
Therefore, we should advise users not to expose scheduled EventListener ingresses (there's no clear use case for doing so).
Alternatively, we could include a header for the event with a signature that can be verified by an interceptor.

In addition, this proposal would also mean the triggers controller has permissions to create, update, and delete CronJobs.

### Drawbacks

- We might want to avoid setting a precedent of building functionality into Triggers to trigger on many different types
of events. This proposal couples an event (a time occurring) with a Tekton resource creation, when we may prefer to keep
events and resource creation separate. However, cron jobs are an extremely common simple use case that likely makes sense
to address specifically.

- We might want to build this functionality into a higher level API like [Workflows](./0098-workflows.md) or a larger
feature like [polling runs](./0083-polling-runs-in-tekton.md). This proposal doesn't prevent that,
and CronTriggers could be leveraged to implement similar functionality in a higher level system.

- The use of the name "EventListener" for a CRD that doesn't need to "listen" for incoming events may be confusing.

## Alternatives

### Create a new CronTrigger CRD

Example:

```yaml
apiVersion: triggers.tekton.dev/v1alpha1
kind: CronTrigger
metadata:
name: nightly-release
spec:
schedule: "0 0 * * *"
bindings:
- name: project-name
value: wait-task
- name: triggers-uuid
value: $(context.eventID)
- name: datetime
value: $(context.datetime)
template:
ref: experimental-release-pipeline-template
serviceAccountName: default
cloudEventSink: http://eventlistener.free.beeceptor.com
```

CronTriggers don't support interceptors, and cannot be used in EventListeners.
The `schedule` field uses the same syntax as Kubernetes CronJobs.
`serviceAccountName` defaults to "default", and `cloudEventSink` is optional.

Bindings for CronTriggers are optional and don't support `$(body.foo)` or `$(header.foo)` syntax.
They support variable replacement for $(context.eventID), a UUID for the event, which is already supported in Triggers.

Pros:
- No need to worry about handling validation errors for interceptors, especially in referenced Triggers

Cons:
- Awkward syntax for creating many Triggers with the same schedule, unlike TriggerGroups
- Reuses many features from EventListener

### Add schedule to Trigger CRD

Example:

```yaml
kind: Trigger
spec:
schedule: "0 0 * * *"
bindings:
- name: project-name
value: wait-task
- name: triggers-uuid
value: $(context.eventID)
- name: datetime
value: $(context.datetime)
template:
ref: experimental-release-pipeline-template
```

Triggers with both a `schedule` and `interceptors` would result in a validation error.
Inline TriggerBindings using `$(body.foo)` and `$(header.foo)` syntax would also result in a validation error.

Unlike a Trigger without a `schedule`, a Trigger with a `schedule` can create resources without being used in an
EventListener, using the default serviceAccount. (We could also add a `serviceAccountName` field to the Trigger CRD,
which would override a `serviceAccountName` specified in any EventListeners.) If used in an EventListener, an incoming
event could trigger this Trigger at any time, using the `serviceAccountName` specified in the EventListener.

### Create a PingSource

This CRD would be extremely similar to the [Knative Eventing PingSource](https://knative.dev/docs/eventing/sources/ping-source),
without requiring installation of Knative Eventing.

For example:

```yaml
apiVersion: triggers.tekton.dev/v1alpha1
kind: PingSource
metadata:
name: nightly-release
spec:
schedule: "0 0 * * *"
sink:
ref:
name: my-eventlistener
```

This would send an empty event body to the EventListener, and we could later add support for a fixed
payload if desired.

Pros:
- Avoids coupling eventing with resource creation
- Adding support for fixed payloads allows Triggers that do process event bodies to be reused on a cron schedule

Cons
- Reimplements same functionality as Knative
- More verbose than proposed solution

## Implementation Plan

Create a CronJob which sends an empty event body to the EventListener service.

## Implementation Pull Requests

<!--
Once the TEP is ready to be marked as implemented, list down all the GitHub
merged pull requests.

Note: This section is exclusively for merged pull requests for this TEP.
It will be a quick reference for those looking for implementation of this TEP.
-->

## References

- [[feature proposal] Alternate ways of running triggers](https://github.com/tektoncd/triggers/issues/504)
3 changes: 2 additions & 1 deletion teps/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -253,7 +253,7 @@ This is the complete list of Tekton teps:
|[TEP-0080](0080-support-domainscoped-parameterresult-names.md) | Support domain-scoped parameter/result names | implemented | 2021-08-19 |
|[TEP-0081](0081-add-chains-subcommand-to-the-cli.md) | Add Chains sub-command to the CLI | implemented | 2022-04-27 |
|[TEP-0082](0082-workspace-hinting.md) | Workspace Hinting | proposed | 2021-10-26 |
|[TEP-0083](0083-scheduled-and-polling-runs-in-tekton.md) | Scheduled and Polling runs in Tekton | proposed | 2021-09-13 |
|[TEP-0083](0083-polling-runs-in-tekton.md) | Polling runs in Tekton | proposed | 2021-09-13 |
|[TEP-0084](0084-endtoend-provenance-collection.md) | end-to-end provenance collection | implementable | 2022-05-12 |
|[TEP-0085](0085-per-namespace-controller-configuration.md) | Per-Namespace Controller Configuration | proposed | 2021-10-14 |
|[TEP-0086](0086-changing-the-way-result-parameters-are-stored.md) | Changing the way result parameters are stored | proposed | 2022-06-09 |
Expand Down Expand Up @@ -294,3 +294,4 @@ This is the complete list of Tekton teps:
|[TEP-0124](0124-distributed-tracing-for-tasks-and-pipelines.md) | Distributed tracing for Tasks and Pipelines | implementable | 2022-10-16 |
|[TEP-0125](0125-add-credential-filter-to-entrypoint-logger.md) | Add credential filter to entrypoint logger | proposed | 2022-10-27 |
|[TEP-0127](0127-larger-results-via-sidecar-logs.md) | Larger Results via Sidecar Logs | implemented | 2022-12-15 |
|[TEP-0128](0128-scheduled-runs.md) | Scheduled Runs | implementable | 2022-12-20 |

0 comments on commit 044f8b8

Please sign in to comment.