Skip to content

Commit

Permalink
Add EventListener Selector For TriggerCRD
Browse files Browse the repository at this point in the history
EventListener have NamespaceSelector field which gives us namespaces
from where EventListener fetches Trigger object to process events.
  • Loading branch information
khrm authored and tekton-robot committed Nov 20, 2020
1 parent 713da5a commit 7702dc4
Show file tree
Hide file tree
Showing 30 changed files with 912 additions and 401 deletions.
5 changes: 5 additions & 0 deletions cmd/eventlistenersink/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,11 @@ func main() {

factory := externalversions.NewSharedInformerFactoryWithOptions(sinkClients.TriggersClient,
30*time.Second, externalversions.WithNamespace(sinkArgs.ElNamespace))
if sinkArgs.IsMultiNS {
factory = externalversions.NewSharedInformerFactory(sinkClients.TriggersClient,
30*time.Second)
}

go func(ctx context.Context) {
factory.Start(ctx.Done())
<-ctx.Done()
Expand Down
14 changes: 4 additions & 10 deletions cmd/triggerrun/cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ func trigger(triggerFile, httpPath, action, kubeconfig string, writer io.Writer)
}
case "create":
{
err := r.CreateResources("", resources, tri.Name, eventID, eventLog)
err := r.CreateResources(tri.Namespace, "", resources, tri.Name, eventID, eventLog)
if err != nil {
return fmt.Errorf("fail to create resources: %w", err)
}
Expand Down Expand Up @@ -193,15 +193,9 @@ func processTriggerSpec(kubeClient kubernetes.Interface, client triggersclientse
return nil, errors.New("trigger is not defined")
}

//convert trigger to eventListener
el, err := triggersv1.ToEventListenerTrigger(tri.Spec)
if err != nil {
return nil, fmt.Errorf("fail to convert Trigger to EvenetListener: %w", err)
}

log := eventLog.With(zap.String(triggersv1.TriggerLabelKey, el.Name))
log := eventLog.With(zap.String(triggersv1.TriggerLabelKey, r.EventListenerName))

finalPayload, header, iresp, err := r.ExecuteInterceptors(&el, request, body, log, eventID)
finalPayload, header, iresp, err := r.ExecuteInterceptors(*tri, request, body, log, eventID)
if err != nil {
log.Error(err)
return nil, err
Expand All @@ -216,7 +210,7 @@ func processTriggerSpec(kubeClient kubernetes.Interface, client triggersclientse
tri.Namespace = "default"
}

rt, err := template.ResolveTrigger(el,
rt, err := template.ResolveTrigger(*tri,
func(name string) (*triggersv1.TriggerBinding, error) {
return client.TriggersV1alpha1().TriggerBindings(tri.Namespace).Get(context.Background(), name, metav1.GetOptions{})
},
Expand Down
26 changes: 26 additions & 0 deletions docs/eventlisteners.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ using [Event Interceptors](#Interceptors).
- [PodTemplate](#podtemplate)
- [Resources](#resources)
- [Logging](#logging)
- [NamespaceSelector](#namespaceSelector)
- [Labels](#labels)
- [Annotations](#annotations)
- [Interceptors](#interceptors)
Expand Down Expand Up @@ -68,6 +69,8 @@ the following fields:
for your EventListener pod
- [`resources`](#resources) - Specifies the Kubernetes Resource information
for your EventListener pod
- [`namespaceSelector`](#namespaceSelector) - Specifies the namespaces where
EventListener can fetch triggers from and create Tekton resources.

[kubernetes-overview]:
https://kubernetes.io/docs/concepts/overview/working-with-objects/kubernetes-objects/#required-fields
Expand Down Expand Up @@ -294,6 +297,29 @@ To access logs for the EventListener sink, you can query for pods with the
kubectl get pods --selector eventlistener=my-eventlistener
```

### NamespaceSelector
The `namespaceSelector` field is optional.
This field determines the namespaces where EventListener can search for triggers and
create Tekton resources. If this field isn't provided, EventListener will only serve Triggers from its
own namespace.

Snippet below will function in foo and bar namespaces.
```yaml
namespaceSelector:
matchNames:
- foo
- bar
```

If EventListener is required to listen to serve the whole cluster, then below snippet
can be used where we only provide single argument for `matchNames` as `*`.
```yaml
namespaceSelector:
matchNames:
- *
```


## Labels

By default, EventListeners will attach the following labels automatically to all
Expand Down
10 changes: 10 additions & 0 deletions examples/selectors/00_ns.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
---
apiVersion: v1
kind: Namespace
metadata:
name: foo
---
apiVersion: v1
kind: Namespace
metadata:
name: bar
74 changes: 74 additions & 0 deletions examples/selectors/01_rbac.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: el-sel-clusterrole
rules:
# Permissions for every EventListener deployment to function
- apiGroups: ["triggers.tekton.dev"]
resources: ["eventlisteners", "clustertriggerbindings", "triggerbindings", "triggertemplates", "triggers"]
verbs: ["get", "list", "watch"]
- apiGroups: [""]
resources: ["configmaps", "secrets"]
verbs: ["get", "list", "watch"]
- apiGroups: [""]
resources: ["serviceaccounts"]
verbs: ["impersonate"]
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: foo-el-sa
namespace: foo
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: el-sel-clusterrolebinding
subjects:
- kind: ServiceAccount
name: foo-el-sa
namespace: foo
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: el-sel-clusterrole
---
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: triggercr-role
namespace: bar
rules:
- apiGroups: ["tekton.dev"]
resources: ["pipelineruns", "pipelineresources", "taskruns"]
verbs: ["create"]
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: bar-trigger-sa
namespace: bar
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: triggercr-rolebinding
namespace: bar
subjects:
- kind: ServiceAccount
name: bar-trigger-sa
namespace: bar
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: triggercr-role
---
apiVersion: v1
kind: Secret
metadata:
name: github-secret
namespace: bar
type: Opaque
stringData:
secretToken: "1234567"
11 changes: 11 additions & 0 deletions examples/selectors/02_eventlistener-sel.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
apiVersion: triggers.tekton.dev/v1alpha1
kind: EventListener
metadata:
name: listener-sel
namespace: foo
spec:
serviceAccountName: foo-el-sa
namespaceSelector:
matchNames:
- foo
- bar
77 changes: 77 additions & 0 deletions examples/selectors/03_trigger.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
---
apiVersion: triggers.tekton.dev/v1alpha1
kind: Trigger
metadata:
name: trigger
namespace: bar
spec:
serviceAccountName: bar-trigger-sa
interceptors:
- github:
secretRef:
secretName: github-secret
secretKey: secretToken
eventTypes:
- pull_request
bindings:
- ref: pipeline-binding
template:
ref: pipeline-template
---
apiVersion: triggers.tekton.dev/v1alpha1
kind: TriggerBinding
metadata:
name: pipeline-binding
namespace: bar
spec:
params:
- name: gitrevision
value: $(body.head_commit.id)
- name: gitrepositoryurl
value: $(body.repository.url)
- name: contenttype
value: $(header.Content-Type)
---
apiVersion: triggers.tekton.dev/v1alpha1
kind: TriggerTemplate
metadata:
name: pipeline-template
namespace: bar
spec:
params:
- name: gitrevision
description: The git revision
default: master
- name: gitrepositoryurl
description: The git repository url
- name: message
description: The message to print
default: This is the default message
- name: contenttype
description: The Content-Type of the event
resourcetemplates:
- apiVersion: tekton.dev/v1beta1
kind: PipelineRun
metadata:
generateName: simple-pipeline-run-
spec:
pipelineRef:
name: simple-pipeline
podTemplate:
securityContext:
runAsNonRoot: true
runAsUser: 1001
params:
- name: message
value: $(tt.params.message)
- name: contenttype
value: $(tt.params.contenttype)
resources:
- name: git-source
resourceSpec:
type: git
params:
- name: revision
value: $(tt.params.gitrevision)
- name: url
value: $(tt.params.gitrepositoryurl)
46 changes: 46 additions & 0 deletions examples/selectors/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
## Namespace Selector EventListener

Creates an EventListener that serve triggers in multiple namespaces.

### Try it out locally:

1. To create the namespace selector trigger and all related resources, run:

```bash
kubectl apply -f examples/selectors/
```

2. Port forward:

```bash
kubectl config set-context --current --namespace=bar
kubectl apply -f examples/example-pipeline.yaml
```

**Note**: Instead of port forwarding, you can set the
[`serviceType`](https://github.com/tektoncd/triggers/blob/master/docs/eventlisteners.md#serviceType)
to `LoadBalancer` to expose the EventListener with a public IP.

3. Create sample pipelinerun in namespace bar:
```bash
kubectl port-forward \
-n foo $(kubectl get pod -n foo -o=name \
-l eventlistener=listener-sel) 8080
```

3. Test by sending the sample payload.

```bash
curl -k -v \
-H 'X-GitHub-Event: pull_request' \
-H 'X-Hub-Signature: sha1=8d7c4d33686fd908394208a07d997b8f5bd70aa6' \
-H 'Content-Type: application/json' \
-d '{"head_commit":{"id":"28911bbb5a3e2ea034daf1f6be0a822d50e31e73"},"action": "opened", "pull_request":{"head":{"sha": "28911bbb5a3e2ea034daf1f6be0a822d50e31e73"}},"repository":{"clone_url": "https://github.com/tektoncd/triggers.git", "url":"https://github.com/tektoncd/triggers.git"}}' http://localhost:8080 ```
The response status code should be `201 Created`
4. You should see a new Pipelinerun that got created:
```bash
tkn pr -n bar list
```
9 changes: 9 additions & 0 deletions pkg/apis/triggers/v1alpha1/event_listener_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ type EventListenerSpec struct {
ServiceType corev1.ServiceType `json:"serviceType,omitempty"`
Replicas *int32 `json:"replicas,omitempty"`
PodTemplate PodTemplate `json:"podTemplate,omitempty"`
NamespaceSelector NamespaceSelector `json:"namespaceSelector,omitempty"`
Resources Resources `json:"resources,omitempty"`
}

Expand Down Expand Up @@ -151,6 +152,14 @@ type EventListenerConfig struct {
GeneratedResourceName string `json:"generatedName"`
}

// NamespaceSelector is a selector for selecting either all namespaces or a
// list of namespaces.
// +k8s:openapi-gen=true
type NamespaceSelector struct {
// List of namespace names.
MatchNames []string `json:"matchNames,omitempty"`
}

// The conditions that are internally resolved by the EventListener reconciler
const (
// ServiceExists is the ConditionType set on the EventListener, which
Expand Down
3 changes: 0 additions & 3 deletions pkg/apis/triggers/v1alpha1/event_listener_validation.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,6 @@ func (s *EventListenerSpec) validate(ctx context.Context) (errs *apis.FieldError
errs = errs.Also(apis.ErrInvalidValue(*s.Replicas, "spec.replicas"))
}
}
if len(s.Triggers) == 0 {
errs = errs.Also(apis.ErrMissingField("spec.triggers"))
}
for i, trigger := range s.Triggers {
errs = errs.Also(trigger.validate(ctx).ViaField(fmt.Sprintf("spec.triggers[%d]", i)))
}
Expand Down
22 changes: 0 additions & 22 deletions pkg/apis/triggers/v1alpha1/event_listener_validation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -215,28 +215,6 @@ func TestEventListenerValidate_error(t *testing.T) {
name string
el *v1alpha1.EventListener
}{{
name: "no triggers",
el: &v1alpha1.EventListener{
ObjectMeta: metav1.ObjectMeta{
Name: "n",
Namespace: "namespace",
},
Spec: v1alpha1.EventListenerSpec{
Triggers: []v1alpha1.EventListenerTrigger{{}},
},
},
}, {
name: "EventListener with no Trigger ref or Template",
el: &v1alpha1.EventListener{
ObjectMeta: metav1.ObjectMeta{
Name: "n",
Namespace: "namespace",
},
Spec: v1alpha1.EventListenerSpec{
Triggers: nil,
},
},
}, {
name: "Valid EventListener with empty TriggerTemplate name",
el: bldr.EventListener("name", "namespace",
bldr.EventListenerSpec(
Expand Down
Loading

0 comments on commit 7702dc4

Please sign in to comment.