Skip to content

Commit

Permalink
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[cel] CEL Custom Tasks CRD
Browse files Browse the repository at this point in the history
We introduced CEL Custom Tasks to experiment with using an expression
language with Tekton Pipelines.

Given feedback from the past several months of usage, we have identified
three main current challenges:
- CEL custom tasks do not take variables for the CEL environment.
As such, users cannot evaluate CEL expressions given specific variables
or in specific context. For example, as described in
tektoncd#716 and
tektoncd/community#403, a user needed to
declare runtime storage variables in the CEL environment.
- CEL custom tasks are not a CRD thus making them unreusable across
different Runs and PipelineRuns. Read more in
tektoncd/community#314 (review).
- CEL custom tasks take the CEL expressions through Parameters which is
misleading to some users. Read more in
tektoncd/community#314 (review).

To address the above challenges, this change introduces a CRD for CEL
Custom Tasks, which takes CEL expressions and CEL environment variables.
With this change:
- CEL custom tasks now take variables for the CEL environment
- CEL custom tasks are reusable across different Runs and PipelineRuns
- CEL custom tasks take expressions through its own field

Closes tektoncd/community#403
Closes tektoncd#716
jerop committed Aug 27, 2021

Verified

This commit was signed with the committer’s verified signature.
marcelstanley Marcel Moura
1 parent eddc3ed commit 56e04c1
Showing 3,055 changed files with 971,802 additions and 342 deletions.
The diff you're trying to view is too large. We only load the first 3000 changed files.
1 change: 1 addition & 0 deletions cel/.ko.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
defaultBaseImage: gcr.io/distroless/static:nonroot
354 changes: 244 additions & 110 deletions cel/README.md

Large diffs are not rendered by default.

20 changes: 18 additions & 2 deletions cel/cmd/controller/main.go
Original file line number Diff line number Diff line change
@@ -17,10 +17,26 @@ limitations under the License.
package main

import (
"github.com/tektoncd/experimental/cel/pkg/reconciler/cel"
"flag"
celrun "github.com/tektoncd/experimental/cel/pkg/reconciler/cel"
corev1 "k8s.io/api/core/v1"
"knative.dev/pkg/injection"
"knative.dev/pkg/injection/sharedmain"
"knative.dev/pkg/signals"
)

const (
// ControllerLogKey is the name of the logger for the controller cmd
ControllerLogKey = "cel-controller"
)

var (
namespace = flag.String("namespace", corev1.NamespaceAll, "Namespace to restrict informer to. Optional, defaults to all namespaces.")
)

func main() {
sharedmain.Main(cel.ControllerName, cel.NewController)
flag.Parse()
sharedmain.MainWithContext(injection.WithNamespaceScope(signals.NewContext(), *namespace), ControllerLogKey,
celrun.NewController(*namespace),
)
}
129 changes: 129 additions & 0 deletions cel/cmd/webhook/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
/*
Copyright 2021 The Tekton Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package main

import (
"context"
celv1alpha1 "github.com/tektoncd/experimental/cel/pkg/apis/cel/v1alpha1"
"os"

defaultconfig "github.com/tektoncd/pipeline/pkg/apis/config"
"github.com/tektoncd/pipeline/pkg/contexts"
"github.com/tektoncd/pipeline/pkg/system"
"k8s.io/apimachinery/pkg/runtime/schema"
"knative.dev/pkg/configmap"
"knative.dev/pkg/controller"
"knative.dev/pkg/injection"
"knative.dev/pkg/injection/sharedmain"
"knative.dev/pkg/logging"
"knative.dev/pkg/signals"
"knative.dev/pkg/webhook"
"knative.dev/pkg/webhook/certificates"
"knative.dev/pkg/webhook/resourcesemantics"
"knative.dev/pkg/webhook/resourcesemantics/defaulting"
"knative.dev/pkg/webhook/resourcesemantics/validation"
)

const (
// WebhookLogKey is the name of the logger for the webhook cmd.
// This name is also used to form lease names for the leader election of the webhook's controllers.
WebhookLogKey = "cel-webhook"
)

var types = map[schema.GroupVersionKind]resourcesemantics.GenericCRD{
celv1alpha1.SchemeGroupVersion.WithKind("Cel"): &celv1alpha1.Cel{},
}

func newDefaultingAdmissionController(ctx context.Context, cmw configmap.Watcher) *controller.Impl {
// Decorate contexts with the current state of the config.
store := defaultconfig.NewStore(logging.FromContext(ctx).Named("config-store"))
store.WatchConfigs(cmw)

return defaulting.NewAdmissionController(ctx,

// Name of the resource webhook.
"webhook.cel.custom.tekton.dev",

// The path on which to serve the webhook.
"/defaulting",

// The resources to validate and default.
types,

// A function that infuses the context passed to Validate/SetDefaults with custom metadata.
func(ctx context.Context) context.Context {
return contexts.WithUpgradeViaDefaulting(store.ToContext(ctx))
},

// Whether to disallow unknown fields.
true,
)
}

func newValidationAdmissionController(ctx context.Context, cmw configmap.Watcher) *controller.Impl {
// Decorate contexts with the current state of the config.
store := defaultconfig.NewStore(logging.FromContext(ctx).Named("config-store"))
store.WatchConfigs(cmw)
return validation.NewAdmissionController(ctx,

// Name of the resource webhook.
"validation.webhook.cel.custom.tekton.dev",

// The path on which to serve the webhook.
"/resource-validation",

// The resources to validate and default.
types,

// A function that infuses the context passed to Validate/SetDefaults with custom metadata.
func(ctx context.Context) context.Context {
return contexts.WithUpgradeViaDefaulting(store.ToContext(ctx))
},

// Whether to disallow unknown fields.
true,
)
}

func main() {
serviceName := os.Getenv("WEBHOOK_SERVICE_NAME")
if serviceName == "" {
serviceName = "cel-webhook"
}

secretName := os.Getenv("WEBHOOK_SECRET_NAME")
if secretName == "" {
secretName = "cel-webhook-certs" // #nosec
}

// Scope informers to the webhook's namespace instead of cluster-wide
ctx := injection.WithNamespaceScope(signals.NewContext(), system.GetNamespace())

// Set up a signal context with our webhook options
ctx = webhook.WithOptions(ctx, webhook.Options{
ServiceName: serviceName,
Port: 8443,
SecretName: secretName,
})

sharedmain.WebhookMainWithConfig(ctx, WebhookLogKey,
sharedmain.ParseAndGetConfigOrDie(),
certificates.NewController,
newDefaultingAdmissionController,
newValidationAdmissionController,
)
}
37 changes: 34 additions & 3 deletions cel/config/201-clusterrole.yaml
Original file line number Diff line number Diff line change
@@ -26,10 +26,10 @@ rules:
resources: ["runs"]
verbs: ["get", "list", "create", "update", "delete", "patch", "watch"]
- apiGroups: ["tekton.dev"]
resources: ["runs/finalizers"]
resources: ["runs/status", "runs/finalizers"]
verbs: ["get", "list", "create", "update", "delete", "patch", "watch"]
- apiGroups: ["tekton.dev"]
resources: ["runs/status"]
- apiGroups: ["custom.tekton.dev"]
resources: ["cels"]
verbs: ["get", "list", "create", "update", "delete", "patch", "watch"]

# Controller needs cluster access to leases for leader election.
@@ -41,3 +41,34 @@ rules:
- apiGroups: [""]
resources: ["events"]
verbs: ["get", "list", "create", "update", "delete", "patch", "watch"]

# The webhook needs to be able to list and update customresourcedefinitions,
# mainly to update the webhook certificates.
- apiGroups: ["apiextensions.k8s.io"]
resources: ["customresourcedefinitions", "customresourcedefinitions/status"]
verbs: ["get", "list", "update", "patch", "watch"]
- apiGroups: ["admissionregistration.k8s.io"]
# The webhook performs a reconciliation on these two resources and continuously
# updates configuration.
resources: ["mutatingwebhookconfigurations", "validatingwebhookconfigurations"]
# knative starts informers on these things, which is why we need get, list and watch.
verbs: ["list", "watch"]
- apiGroups: ["admissionregistration.k8s.io"]
resources: ["mutatingwebhookconfigurations"]
# This mutating webhook is responsible for applying defaults to tekton objects
# as they are received.
resourceNames: ["webhook.cel.custom.tekton.dev"]
# When there are changes to the configs or secrets, knative updates the mutatingwebhook config
# with the updated certificates or the refreshed set of rules.
verbs: ["get", "update"]
- apiGroups: ["admissionregistration.k8s.io"]
resources: ["validatingwebhookconfigurations"]
# validation.webhook.cel.custom.tekton.dev performs schema validation when you, for example, create cels.
resourceNames: ["validation.webhook.cel.custom.tekton.dev"]
# When there are changes to the configs or secrets, knative updates the validatingwebhook config
# with the updated certificates or the refreshed set of rules.
verbs: ["get", "update"]
- apiGroups: ["policy"]
resources: ["podsecuritypolicies"]
resourceNames: ["tekton-pipelines"]
verbs: ["use"]
51 changes: 51 additions & 0 deletions cel/config/300-cel.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# Copyright 2021 The Tekton Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
name: cels.custom.tekton.dev
labels:
app.kubernetes.io/instance: default
app.kubernetes.io/part-of: tekton-cel-run
spec:
group: custom.tekton.dev
preserveUnknownFields: false
validation:
openAPIV3Schema:
type: object
# One can use x-kubernetes-preserve-unknown-fields: true
# at the root of the schema (and inside any properties, additionalProperties)
# to get the traditional CRD behaviour that nothing is pruned, despite
# setting spec.preserveUnknownProperties: false.
#
# See https://kubernetes.io/blog/2019/06/20/crd-structural-schema/
# See issue: https://github.com/knative/serving/issues/912
x-kubernetes-preserve-unknown-fields: true
versions:
- name: v1alpha1
served: true
storage: true
names:
kind: Cel
plural: cels
categories:
- tekton
- tekton-pipelines
- tekton-cel-run
scope: Namespaced
# Opt into the status subresource so metadata.generation
# starts to increment
subresources:
status: {}
6 changes: 1 addition & 5 deletions cel/config/400-controller-service.yaml
Original file line number Diff line number Diff line change
@@ -19,13 +19,9 @@ metadata:
app.kubernetes.io/name: cel-controller
app.kubernetes.io/component: cel-controller
app.kubernetes.io/instance: default
app.kubernetes.io/version: devel
app.kubernetes.io/part-of: tekton-cel-run
# tekton.dev/release value replaced with inputs.params.versionTag in pipeline/tekton/publish.yaml
pipeline.tekton.dev/release: "devel"
# labels below are related to istio and should not be used for resource lookup
app: cel-controller
version: "devel"
version: devel
name: cel-controller
namespace: tekton-cel-run
spec:
6 changes: 2 additions & 4 deletions cel/config/500-controller.yaml
Original file line number Diff line number Diff line change
@@ -21,7 +21,6 @@ metadata:
app.kubernetes.io/name: cel-controller
app.kubernetes.io/component: cel-controller
app.kubernetes.io/instance: default
app.kubernetes.io/version: devel
app.kubernetes.io/part-of: tekton-cel-run
spec:
replicas: 1
@@ -30,7 +29,7 @@ spec:
app.kubernetes.io/name: cel-controller
app.kubernetes.io/component: cel-controller
app.kubernetes.io/instance: default
app.kubernetes.io/part-of: cel
app.kubernetes.io/part-of: tekton-cel-run
template:
metadata:
annotations:
@@ -39,8 +38,7 @@ spec:
app.kubernetes.io/name: cel-controller
app.kubernetes.io/component: cel-controller
app.kubernetes.io/instance: default
app.kubernetes.io/version: devel
app.kubernetes.io/part-of: cel
app.kubernetes.io/part-of: tekton-cel-run
app: cel-controller
spec:
serviceAccountName: cel-controller
63 changes: 63 additions & 0 deletions cel/config/500-webhook-configuration.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
# Copyright 2021 The Tekton Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

apiVersion: v1
kind: Secret
metadata:
name: cel-webhook-certs
namespace: tekton-cel-run
labels:
app.kubernetes.io/component: webhook
app.kubernetes.io/instance: default
app.kubernetes.io/part-of: tekton-cel-run
---
apiVersion: admissionregistration.k8s.io/v1beta1
kind: ValidatingWebhookConfiguration
metadata:
name: validation.webhook.cel.custom.tekton.dev
labels:
app.kubernetes.io/component: webhook
app.kubernetes.io/instance: default
app.kubernetes.io/part-of: tekton-cel-run
webhooks:
- admissionReviewVersions:
- v1beta1
clientConfig:
service:
name: cel-webhook
namespace: tekton-cel-run
failurePolicy: Fail
sideEffects: None
name: validation.webhook.cel.custom.tekton.dev

---
apiVersion: admissionregistration.k8s.io/v1beta1
kind: MutatingWebhookConfiguration
metadata:
name: webhook.cel.custom.tekton.dev
labels:
app.kubernetes.io/component: webhook
app.kubernetes.io/instance: default
app.kubernetes.io/part-of: tekton-cel-run
webhooks:
- admissionReviewVersions:
- v1beta1
clientConfig:
service:
name: cel-webhook
namespace: tekton-cel-run
failurePolicy: Fail
sideEffects: None
name: webhook.cel.custom.tekton.dev

107 changes: 107 additions & 0 deletions cel/config/500-webhook.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
# Copyright 2021 The Tekton Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

apiVersion: apps/v1
kind: Deployment
metadata:
name: cel-webhook
namespace: tekton-cel-run
labels:
app.kubernetes.io/name: cel-webhook
app.kubernetes.io/component: cel-webhook
app.kubernetes.io/instance: default
app.kubernetes.io/part-of: tekton-cel-run
spec:
replicas: 1
selector:
matchLabels:
app.kubernetes.io/name: cel-webhook
app.kubernetes.io/component: cel-webhook
app.kubernetes.io/instance: default
app.kubernetes.io/part-of: tekton-cel-run
template:
metadata:
annotations:
cluster-autoscaler.kubernetes.io/safe-to-evict: "false"
labels:
app.kubernetes.io/name: cel-webhook
app.kubernetes.io/component: cel-webhook
app.kubernetes.io/instance: default
app.kubernetes.io/part-of: tekton-cel-run
app: cel-webhook
spec:
serviceAccountName: cel-webhook
containers:
- name: cel-webhook
image: ko://github.com/tektoncd/experimental/cel/cmd/webhook
env:
- name: SYSTEM_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
# If you are changing these names, you will also need to update
# the webhook's Role in 200-role.yaml to include the new
# values in the "configmaps" "get" rule.
- name: CONFIG_LOGGING_NAME
value: config-logging
- name: CONFIG_OBSERVABILITY_NAME
value: config-observability
- name: CONFIG_LEADERELECTION_NAME
value: config-leader-election
- name: WEBHOOK_SERVICE_NAME
value: cel-webhook
- name: WEBHOOK_SECRET_NAME
value: cel-webhook-certs
- name: METRICS_DOMAIN
value: tekton.dev/pipeline
securityContext:
allowPrivilegeEscalation: false
runAsUser: 1001
ports:
- name: metrics
containerPort: 9090
- name: profiling
containerPort: 8008
- name: https-webhook
containerPort: 8443
---
apiVersion: v1
kind: Service
metadata:
labels:
app.kubernetes.io/name: cel-webhook
app.kubernetes.io/component: cel-webhook
app.kubernetes.io/instance: default
app.kubernetes.io/part-of: tekton-cel-run
app: cel-webhook
version: devel
name: cel-webhook
namespace: tekton-cel-run
spec:
ports:
# Define metrics and profiling for them to be accessible within service meshes.
- name: http-metrics
port: 9090
targetPort: 9090
- name: http-profiling
port: 8008
targetPort: 8008
- name: https-webhook
port: 443
targetPort: 8443
selector:
app.kubernetes.io/name: cel-webhook
app.kubernetes.io/component: cel-webhook
app.kubernetes.io/instance: default
app.kubernetes.io/part-of: tekton-cel-run
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
apiVersion: tekton.dev/v1alpha1
kind: Run
apiVersion: custom.tekton.dev/v1alpha1
kind: Cel
metadata:
generateName: celrun-is-red-
name: colors
spec:
ref:
apiVersion: cel.tekton.dev/v1alpha1
kind: CEL
params:
expressions:
- name: red
value: "{'blue': '0x000080', 'red': '0xFF0000'}['red']"
- name: blue
@@ -15,3 +12,13 @@ spec:
value: "{'blue': '0x000080', 'red': '0xFF0000'}['red'] == '0xFF0000'"
- name: is-blue
value: "{'blue': '0x000080', 'red': '0xFF0000'}['blue'] == '0xFF0000'"
---
apiVersion: tekton.dev/v1alpha1
kind: Run
metadata:
generateName: colors-
spec:
ref:
apiVersion: custom.tekton.dev/v1alpha1
kind: Cel
name: colors
19 changes: 13 additions & 6 deletions cel/examples/celrun-get-type.yaml
Original file line number Diff line number Diff line change
@@ -1,11 +1,18 @@
apiVersion: custom.tekton.dev/v1alpha1
kind: Cel
metadata:
name: get-type
spec:
expressions:
- name: expression
value: "type(1)"
---
apiVersion: tekton.dev/v1alpha1
kind: Run
metadata:
generateName: celrun-get-type-
generateName: get-type-
spec:
ref:
apiVersion: cel.tekton.dev/v1alpha1
kind: CEL
params:
- name: expression
value: "type(1)"
apiVersion: custom.tekton.dev/v1alpha1
kind: Cel
name: get-type
23 changes: 23 additions & 0 deletions cel/examples/celrun-sevs.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
apiVersion: custom.tekton.dev/v1alpha1
kind: Cel
metadata:
name: sevs
spec:
variables:
- name: job_priority
value: "high"
- name: alert_enable
value: "true"
expressions:
- name: job_severity
value: "job_priority in ['high', 'normal'] ? 'sev-1' : 'sev-2'"
---
apiVersion: tekton.dev/v1alpha1
kind: Run
metadata:
generateName: sevs-
spec:
ref:
apiVersion: custom.tekton.dev/v1alpha1
kind: Cel
name: sevs
48 changes: 26 additions & 22 deletions cel/examples/pipelinerun-celruns.yaml
Original file line number Diff line number Diff line change
@@ -1,30 +1,34 @@
apiVersion: custom.tekton.dev/v1alpha1
kind: Cel
metadata:
name: is-red
spec:
expressions:
- name: red
value: "{'blue': '0x000080', 'red': '0xFF0000'}['red'] == '0xFF0000'"
---
apiVersion: custom.tekton.dev/v1alpha1
kind: Cel
metadata:
name: get-type
spec:
expressions:
- name: type
value: "type(1)"
---
apiVersion: tekton.dev/v1beta1
kind: PipelineRun
metadata:
generateName: example-pr-
spec:
serviceAccountName: 'default'
pipelineSpec:
params:
- name: red
type: string
- name: type
type: string
tasks:
- name: is-red
taskRef:
apiVersion: cel.tekton.dev/v1alpha1
kind: CEL
params:
- name: red
value: "$(params.red)"
- name: get-type
taskRef:
apiVersion: cel.tekton.dev/v1alpha1
kind: CEL
params:
- name: type
value: "$(params.type)"
apiVersion: custom.tekton.dev/v1alpha1
kind: Cel
name: is-red
- name: echo-is-red
when:
- input: "$(tasks.is-red.results.red)"
@@ -35,6 +39,11 @@ spec:
- name: echo
image: ubuntu
script: echo ISRED!
- name: get-type
taskRef:
apiVersion: custom.tekton.dev/v1alpha1
kind: Cel
name: get-type
- name: echo-get-type
when:
- input: "$(tasks.get-type.results.type)"
@@ -45,8 +54,3 @@ spec:
- name: echo
image: ubuntu
script: echo ISINT!
params:
- name: red
value: "{'blue': '0x000080', 'red': '0xFF0000'}['red'] == '0xFF0000'"
- name: type
value: "type(1)"
20 changes: 12 additions & 8 deletions cel/go.mod
Original file line number Diff line number Diff line change
@@ -1,30 +1,34 @@
module github.com/tektoncd/experimental/cel

go 1.15
go 1.13

require (
github.com/ghodss/yaml v1.0.0
github.com/google/cel-go v0.7.0
github.com/google/go-cmp v0.5.4
github.com/tektoncd/pipeline v0.20.0
github.com/hashicorp/go-multierror v1.1.0
github.com/tektoncd/pipeline v0.20.1
go.opencensus.io v0.22.5
go.uber.org/zap v1.16.0
k8s.io/api v0.20.2
k8s.io/apimachinery v0.18.12
google.golang.org/genproto v0.0.0-20201211151036-40ec1c210f7a
k8s.io/api v0.18.12
k8s.io/apimachinery v0.19.0
k8s.io/client-go v11.0.1-0.20190805182717-6502b5e7b1b5+incompatible
knative.dev/pkg v0.0.0-20210114223020-f0ea5e6b9c4e
knative.dev/pkg v0.0.0-20210107022335-51c72e24c179
)

// Knative deps
// Knative deps (release-0.20)
replace (
contrib.go.opencensus.io/exporter/stackdriver => contrib.go.opencensus.io/exporter/stackdriver v0.12.9-0.20191108183826-59d068f8d8ff
contrib.go.opencensus.io/exporter/stackdriver => contrib.go.opencensus.io/exporter/stackdriver v0.13.4
github.com/Azure/azure-sdk-for-go => github.com/Azure/azure-sdk-for-go v38.2.0+incompatible
github.com/Azure/go-autorest => github.com/Azure/go-autorest v13.4.0+incompatible
)

// Pin k8s deps to v0.18.8
replace (
k8s.io/api => k8s.io/api v0.18.8
k8s.io/apiextensions-apiserver => k8s.io/apiextensions-apiserver v0.18.8
k8s.io/apimachinery => k8s.io/apimachinery v0.18.8
k8s.io/apiserver => k8s.io/apiserver v0.18.8
k8s.io/client-go => k8s.io/client-go v0.18.8
k8s.io/code-generator => k8s.io/code-generator v0.18.8
k8s.io/kube-openapi => k8s.io/kube-openapi v0.0.0-20200410145947-bcb3869e6f29
40 changes: 16 additions & 24 deletions cel/go.sum

Large diffs are not rendered by default.

15 changes: 15 additions & 0 deletions cel/hack/boilerplate/boilerplate.go.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/*
Copyright 2021 The Tekton Authors

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
8 changes: 8 additions & 0 deletions cel/hack/tools.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
//go:build tools
// +build tools

package tools

import (
_ "knative.dev/pkg/hack"
)
47 changes: 47 additions & 0 deletions cel/hack/update-codegen.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
#!/usr/bin/env bash

# Copyright 2021 The Tekton Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

set -o errexit
set -o nounset
set -o pipefail

export GO111MODULE=on

REPO_ROOT=$(dirname ${BASH_SOURCE})/..
CODEGEN_PKG=${CODEGEN_PKG:-$(cd ${REPO_ROOT}; ls -d -1 ./vendor/k8s.io/code-generator 2>/dev/null || echo ../code-generator)}

KNATIVE_CODEGEN_PKG=${KNATIVE_CODEGEN_PKG:-$(cd ${REPO_ROOT}; ls -d -1 ./vendor/knative.dev/pkg 2>/dev/null || echo ../pkg)}

# generate the code with:
# --output-base because this script should also be able to run inside the vendor dir of
# k8s.io/kubernetes. The output-base is needed for the generators to output into the vendor dir
# instead of the $GOPATH directly. For normal projects this can be dropped.
chmod +x ${CODEGEN_PKG}/generate-groups.sh
${CODEGEN_PKG}/generate-groups.sh "deepcopy,client,informer,lister" \
github.com/tektoncd/experimental/cel/pkg/client github.com/tektoncd/experimental/cel/pkg/apis \
"cel:v1alpha1" \
--go-header-file ${REPO_ROOT}/hack/boilerplate/boilerplate.go.txt

# Knative Injection

chmod +x ${KNATIVE_CODEGEN_PKG}/hack/generate-knative.sh
${KNATIVE_CODEGEN_PKG}/hack/generate-knative.sh "injection" \
github.com/tektoncd/experimental/cel/pkg/client github.com/tektoncd/experimental/cel/pkg/apis \
"cel:v1alpha1" \
--go-header-file ${REPO_ROOT}/hack/boilerplate/boilerplate.go.txt

# Make sure our dependencies are up-to-date
${REPO_ROOT}/hack/update-deps.sh
60 changes: 60 additions & 0 deletions cel/hack/update-deps.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
#!/usr/bin/env bash

# Copyright 2021 The Knative Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

readonly ROOT_DIR=$(dirname $0)/..
source $(git rev-parse --show-toplevel)/vendor/github.com/tektoncd/plumbing/scripts/library.sh

set -o errexit
set -o nounset
set -o pipefail

export GO111MODULE=on
export GOFLAGS=-mod=vendor

cd ${ROOT_DIR}

VERSION="release-0.18"

# The list of dependencies that we track at HEAD and periodically
# float forward in this repository.
FLOATING_DEPS=(
"knative.dev/pkg@${VERSION}"
"knative.dev/eventing@${VERSION}"
"knative.dev/test-infra@${VERSION}"
)

# Parse flags to determine any we should pass to dep.
GO_GET=0
while [[ $# -ne 0 ]]; do
parameter=$1
case ${parameter} in
--upgrade) GO_GET=1 ;;
*) abort "unknown option ${parameter}" ;;
esac
shift
done
readonly GO_GET

if (( GO_GET )); then
go get -d ${FLOATING_DEPS[@]}
fi

# Prune modules.
go mod tidy
go mod vendor

rm -rf $(find vendor/ -name 'OWNERS')
rm -rf $(find vendor/ -name '*_test.go')
22 changes: 22 additions & 0 deletions cel/pkg/apis/cel/controller.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/*
Copyright 2021 The Tekton Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package cel

const (
// ControllerName holds the name of the Cel controller
ControllerName = "Cel"
)
22 changes: 22 additions & 0 deletions cel/pkg/apis/cel/register.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/*
Copyright 2021 The Tekton Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package cel

const (
// GroupName is the Kubernetes resource group name for Cel types
GroupName = "custom.tekton.dev"
)
34 changes: 34 additions & 0 deletions cel/pkg/apis/cel/v1alpha1/cel_defaults.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/*
Copyright 2021 The Tekton Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package v1alpha1

import (
"context"

"knative.dev/pkg/apis"
)

var _ apis.Defaultable = (*Cel)(nil)

// SetDefaults set any defaults for the Cel
func (c *Cel) SetDefaults(ctx context.Context) {
c.Spec.SetDefaults(ctx)
}

// SetDefaults set any defaults for the Cel spec
func (cs *CelSpec) SetDefaults(ctx context.Context) {
}
96 changes: 96 additions & 0 deletions cel/pkg/apis/cel/v1alpha1/cel_types.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
/*
Copyright 2021 The Tekton Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package v1alpha1

import (
"github.com/tektoncd/pipeline/pkg/apis/pipeline/v1beta1"
"github.com/tektoncd/pipeline/pkg/apis/run/v1alpha1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

// +genclient
// +genclient:noStatus
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object

// Cel evaluates a CEL expression with given environment variables
// +k8s:openapi-gen=true
type Cel struct {
metav1.TypeMeta `json:",inline"`
// +optional
metav1.ObjectMeta `json:"metadata"`

// CelSpec holds the desired state of the Cel from the client
// +optional
Spec CelSpec `json:"spec"`
}

// CelSpec defines the desired state of the Cel
type CelSpec struct {
// Variables to be configured in the CEL environment before evaluation
// +optional
Variables []*v1beta1.Param `json:"variables,omitempty"`

// Expressions are a list of CEL expressions to be evaluated given the environment Variables
Expressions []*v1beta1.Param `json:"expressions"`
}

// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object

// CelList contains a list of Cels
type CelList struct {
metav1.TypeMeta `json:",inline"`
// +optional
metav1.ListMeta `json:"metadata,omitempty"`
Items []Cel `json:"items"`
}

// CelRunReason represents a reason for the Run "Succeeded" condition
type CelRunReason string

const (
// CelRunReasonFailedValidation indicates that the reason for failure status is that Cel failed validation
CelRunReasonFailedValidation CelRunReason = "RunValidationFailed"

// CelRunReasonSyntaxError indicates that the reason for failure status is that a Cel expression couldn't be parsed
CelRunReasonSyntaxError CelRunReason = "SyntaxError"

// CelRunReasonEvaluationError indicates that the reason for failure status is that a Cel expression couldn't be
// evaluated typically due to evaluation environment or executable program
CelRunReasonEvaluationError CelRunReason = "EvaluationError"

// CelRunReasonEvaluationSuccess indicates that the reason for the success status is that all Cel expressions were
// evaluated successfully and the evaluation results were produced
CelRunReasonEvaluationSuccess CelRunReason = "EvaluationSuccess"

// CelRunReasonCouldntGetCel indicates that the reason for the failure status is that the Run could not find the Cel
CelRunReasonCouldntGetCel CelRunReason = "CouldntGetCel"

// CelRunReasonInternalError indicates that the Cel failed due to an internal error in the reconciler
CelRunReasonInternalError CelRunReason = "InternalError"
)

func (t CelRunReason) String() string {
return string(t)
}

type CelStatus struct {
// CelSpec contains the exact spec used to instantiate the Run
CelSpec *CelSpec `json:"celSpec,omitempty"`

// CelResults contains the results from evaluating the Cel expressions given the environment Variables
CelResults []v1alpha1.RunResult `json:"celResults,omitempty"`
}
74 changes: 74 additions & 0 deletions cel/pkg/apis/cel/v1alpha1/cel_validation.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
/*
Copyright 2021 The Tekton Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package v1alpha1

import (
"context"
"fmt"
"github.com/tektoncd/pipeline/pkg/apis/validate"
"knative.dev/pkg/apis"
)

var _ apis.Validatable = (*Cel)(nil)

func (c *Cel) Validate(ctx context.Context) *apis.FieldError {
if err := validate.ObjectMetadata(c.GetObjectMeta()); err != nil {
return err.ViaField("metadata")
}
return c.Spec.Validate()
}

func (cs *CelSpec) Validate() *apis.FieldError {
if err := validateCel(cs); err != nil {
return err
}
return nil
}

func validateCel(cs *CelSpec) (errs *apis.FieldError) {
errs = errs.Also(validateExpressionsProvided(cs))
errs = errs.Also(validateExpressionsType(cs))
errs = errs.Also(validateVariablesType(cs))
return errs
}

func validateExpressionsProvided(cs *CelSpec) (errs *apis.FieldError) {
if len(cs.Expressions) == 0 {
errs = errs.Also(apis.ErrMissingField("expressions"))
}
return errs
}

func validateExpressionsType(cs *CelSpec) (errs *apis.FieldError) {
for _, expression := range cs.Expressions {
if expression.Value.StringVal == "" {
errs = errs.Also(apis.ErrInvalidValue(fmt.Sprintf("CEL expression %s must be a string", expression.Name),
"value").ViaFieldKey("expressions", expression.Name))
}
}
return errs
}

func validateVariablesType(cs *CelSpec) (errs *apis.FieldError) {
for _, variable := range cs.Variables {
if variable.Value.StringVal == "" {
errs = errs.Also(apis.ErrInvalidValue(fmt.Sprintf("CEL environment variable %s must be a string", variable.Name),
"value").ViaFieldKey("variables", variable.Name))
}
}
return errs
}
147 changes: 147 additions & 0 deletions cel/pkg/apis/cel/v1alpha1/cel_validation_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
/*
Copyright 2021 The Tekton Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package v1alpha1_test

import (
"context"
celv1alpha1 "github.com/tektoncd/experimental/cel/pkg/apis/cel/v1alpha1"
"github.com/tektoncd/pipeline/pkg/apis/pipeline/v1beta1"
"testing"

"github.com/google/go-cmp/cmp"
"github.com/google/go-cmp/cmp/cmpopts"
"github.com/tektoncd/pipeline/test/diff"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"knative.dev/pkg/apis"
)

func Test_Cel_Validate_Valid(t *testing.T) {
tests := []struct {
name string
cs *celv1alpha1.Cel
}{{
name: "expressions only",
cs: &celv1alpha1.Cel{
ObjectMeta: metav1.ObjectMeta{Name: "cel"},
Spec: celv1alpha1.CelSpec{
Expressions: []*v1beta1.Param{{
Name: "expr1",
Value: v1beta1.ArrayOrString{
StringVal: "foo",
},
}},
},
},
}, {
name: "expressions and variables",
cs: &celv1alpha1.Cel{
ObjectMeta: metav1.ObjectMeta{Name: "cel"},
Spec: celv1alpha1.CelSpec{
Expressions: []*v1beta1.Param{{
Name: "expr1",
Value: v1beta1.ArrayOrString{
StringVal: "foo",
},
}},
Variables: []*v1beta1.Param{{
Name: "var1",
Value: v1beta1.ArrayOrString{
StringVal: "bar",
},
}},
},
},
}}
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
err := tc.cs.Validate(context.Background())
if err != nil {
t.Errorf("Unexpected error for %s: %s", tc.name, err)
}
})
}
}

func Test_Cel_Validate_Invalid(t *testing.T) {
tests := []struct {
name string
cs *celv1alpha1.Cel
expectedError apis.FieldError
}{{
name: "no expressions",
cs: &celv1alpha1.Cel{
ObjectMeta: metav1.ObjectMeta{Name: "cel"},
Spec: celv1alpha1.CelSpec{},
},
expectedError: apis.FieldError{
Message: "missing field(s)",
Paths: []string{"expressions"},
},
}, {
name: "array expressions",
cs: &celv1alpha1.Cel{
ObjectMeta: metav1.ObjectMeta{Name: "cel"},
Spec: celv1alpha1.CelSpec{
Expressions: []*v1beta1.Param{{
Name: "expr1",
Value: v1beta1.ArrayOrString{
ArrayVal: []string{"foo", "bar"},
},
}},
},
},
expectedError: apis.FieldError{
Message: "invalid value: CEL expression expr1 must be a string",
Paths: []string{"expressions[expr1].value"},
},
}, {
name: "array variables",
cs: &celv1alpha1.Cel{
ObjectMeta: metav1.ObjectMeta{Name: "cel"},
Spec: celv1alpha1.CelSpec{
Expressions: []*v1beta1.Param{{
Name: "expr1",
Value: v1beta1.ArrayOrString{
StringVal: "foo",
},
}},
Variables: []*v1beta1.Param{{
Name: "var1",
Value: v1beta1.ArrayOrString{
ArrayVal: []string{"foo", "bar"},
},
}},
},
},
expectedError: apis.FieldError{
Message: "invalid value: CEL environment variable var1 must be a string",
Paths: []string{"variables[var1].value"},
},
}}
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
err := tc.cs.Validate(context.Background())
if err == nil {
t.Errorf("Expected an Error but did not get one for %s", tc.name)
} else {
if d := cmp.Diff(tc.expectedError.Error(), err.Error(), cmpopts.IgnoreUnexported(apis.FieldError{})); d != "" {
t.Errorf("Error is different from expected for %s. diff %s", tc.name, diff.PrintWantGot(d))
}
}
})
}
}
22 changes: 22 additions & 0 deletions cel/pkg/apis/cel/v1alpha1/doc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/*
Copyright 2021 The Tekton Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

// Package v1alpha1 contains API Schema definitions for the cel v1alpha1 API group
// +k8s:openapi-gen=true
// +k8s:deepcopy-gen=package,register
// +k8s:defaulter-gen=TypeMeta
// +groupName=custom.tekton.dev
package v1alpha1
54 changes: 54 additions & 0 deletions cel/pkg/apis/cel/v1alpha1/register.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/*
Copyright 2021 The Tekton Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package v1alpha1

import (
"github.com/tektoncd/experimental/cel/pkg/apis/cel"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
)

// SchemeGroupVersion is group version used to register these objects
var SchemeGroupVersion = schema.GroupVersion{Group: cel.GroupName, Version: "v1alpha1"}

// Kind takes an unqualified kind and returns back a Group qualified GroupKind
func Kind(kind string) schema.GroupKind {
return SchemeGroupVersion.WithKind(kind).GroupKind()
}

// Resource takes an unqualified resource and returns a Group qualified GroupResource
func Resource(resource string) schema.GroupResource {
return SchemeGroupVersion.WithResource(resource).GroupResource()
}

var (
schemeBuilder = runtime.NewSchemeBuilder(addKnownTypes)

// AddToScheme adds Build types to the scheme
AddToScheme = schemeBuilder.AddToScheme
)

// Adds the list of known types to Scheme
func addKnownTypes(scheme *runtime.Scheme) error {
scheme.AddKnownTypes(SchemeGroupVersion,
&Cel{},
&CelList{},
)
metav1.AddToGroupVersion(scheme, SchemeGroupVersion)
return nil
}
152 changes: 152 additions & 0 deletions cel/pkg/apis/cel/v1alpha1/zz_generated.deepcopy.go
97 changes: 97 additions & 0 deletions cel/pkg/client/clientset/versioned/clientset.go
20 changes: 20 additions & 0 deletions cel/pkg/client/clientset/versioned/doc.go
82 changes: 82 additions & 0 deletions cel/pkg/client/clientset/versioned/fake/clientset_generated.go
20 changes: 20 additions & 0 deletions cel/pkg/client/clientset/versioned/fake/doc.go
56 changes: 56 additions & 0 deletions cel/pkg/client/clientset/versioned/fake/register.go
20 changes: 20 additions & 0 deletions cel/pkg/client/clientset/versioned/scheme/doc.go
56 changes: 56 additions & 0 deletions cel/pkg/client/clientset/versioned/scheme/register.go
178 changes: 178 additions & 0 deletions cel/pkg/client/clientset/versioned/typed/cel/v1alpha1/cel.go
20 changes: 20 additions & 0 deletions cel/pkg/client/clientset/versioned/typed/cel/v1alpha1/doc.go
20 changes: 20 additions & 0 deletions cel/pkg/client/clientset/versioned/typed/cel/v1alpha1/fake/doc.go
130 changes: 130 additions & 0 deletions cel/pkg/client/clientset/versioned/typed/cel/v1alpha1/fake/fake_cel.go
46 changes: 46 additions & 0 deletions cel/pkg/client/informers/externalversions/cel/interface.go
90 changes: 90 additions & 0 deletions cel/pkg/client/informers/externalversions/cel/v1alpha1/cel.go
180 changes: 180 additions & 0 deletions cel/pkg/client/informers/externalversions/factory.go
62 changes: 62 additions & 0 deletions cel/pkg/client/informers/externalversions/generic.go
54 changes: 54 additions & 0 deletions cel/pkg/client/injection/client/client.go
54 changes: 54 additions & 0 deletions cel/pkg/client/injection/client/fake/fake.go
52 changes: 52 additions & 0 deletions cel/pkg/client/injection/informers/cel/v1alpha1/cel/cel.go
40 changes: 40 additions & 0 deletions cel/pkg/client/injection/informers/cel/v1alpha1/cel/fake/fake.go
Loading

0 comments on commit 56e04c1

Please sign in to comment.