From f280b812cf925ec9cf1f8e29038bc26cfa78ff4e Mon Sep 17 00:00:00 2001 From: Khurram Baig Date: Mon, 28 Sep 2020 12:59:39 +0530 Subject: [PATCH] Add EventListener Selector for TriggerCRD EventListener have NamespaceSelector field which gives us namespaces from where EventListener fetches Trigger object to process events. --- cmd/triggerrun/cmd/root.go | 14 +- .../triggers/v1alpha1/event_listener_types.go | 12 + .../v1alpha1/zz_generated.deepcopy.go | 22 ++ pkg/interceptors/bitbucket/bitbucket.go | 18 +- pkg/interceptors/bitbucket/bitbucket_test.go | 8 +- pkg/interceptors/cel/cel.go | 18 +- pkg/interceptors/github/github.go | 18 +- pkg/interceptors/github/github_test.go | 8 +- pkg/interceptors/gitlab/gitlab.go | 18 +- pkg/interceptors/gitlab/gitlab_test.go | 8 +- pkg/interceptors/webhook/webhook.go | 18 +- pkg/sink/sink.go | 113 ++++--- pkg/sink/sink_test.go | 308 ++++++++++++++++-- pkg/template/resource.go | 10 +- pkg/template/resource_test.go | 224 +++++++------ test/builder/eventlistener.go | 14 + test/builder/eventlistener_test.go | 44 +++ 17 files changed, 644 insertions(+), 231 deletions(-) diff --git a/cmd/triggerrun/cmd/root.go b/cmd/triggerrun/cmd/root.go index e81004030b..d6687564b6 100644 --- a/cmd/triggerrun/cmd/root.go +++ b/cmd/triggerrun/cmd/root.go @@ -125,7 +125,7 @@ func trigger(triggerFile, httpPath, action string, writer io.Writer) error { } 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) } @@ -191,15 +191,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, err := r.ExecuteInterceptors(&el, request, body, log) + finalPayload, header, err := r.ExecuteInterceptors(*tri, request, body, log) if err != nil { log.Error(err) return nil, err @@ -209,7 +203,7 @@ func processTriggerSpec(kubeClient kubernetes.Interface, client triggersclientse tri.Namespace = "default" } - rt, err := template.ResolveTrigger(el, + rt, err := template.ResolveTrigger(*tri, client.TriggersV1alpha1().TriggerBindings(tri.Namespace).Get, client.TriggersV1alpha1().ClusterTriggerBindings().Get, client.TriggersV1alpha1().TriggerTemplates(tri.Namespace).Get) diff --git a/pkg/apis/triggers/v1alpha1/event_listener_types.go b/pkg/apis/triggers/v1alpha1/event_listener_types.go index e819bacb93..50b95559ef 100644 --- a/pkg/apis/triggers/v1alpha1/event_listener_types.go +++ b/pkg/apis/triggers/v1alpha1/event_listener_types.go @@ -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"` } @@ -152,6 +153,17 @@ 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 { + // Boolean describing whether all namespaces are selected in contrast to a + // list restricting them. + Any bool `json:"any,omitempty"` + // 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 diff --git a/pkg/apis/triggers/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/triggers/v1alpha1/zz_generated.deepcopy.go index 50d9d288c4..d4abc04579 100644 --- a/pkg/apis/triggers/v1alpha1/zz_generated.deepcopy.go +++ b/pkg/apis/triggers/v1alpha1/zz_generated.deepcopy.go @@ -243,6 +243,7 @@ func (in *EventListenerSpec) DeepCopyInto(out *EventListenerSpec) { **out = **in } in.PodTemplate.DeepCopyInto(&out.PodTemplate) + in.NamespaceSelector.DeepCopyInto(&out.NamespaceSelector) in.Resources.DeepCopyInto(&out.Resources) return } @@ -388,6 +389,27 @@ func (in *KubernetesResource) DeepCopy() *KubernetesResource { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NamespaceSelector) DeepCopyInto(out *NamespaceSelector) { + *out = *in + if in.MatchNames != nil { + in, out := &in.MatchNames, &out.MatchNames + *out = make([]string, len(*in)) + copy(*out, *in) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NamespaceSelector. +func (in *NamespaceSelector) DeepCopy() *NamespaceSelector { + if in == nil { + return nil + } + out := new(NamespaceSelector) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *Param) DeepCopyInto(out *Param) { *out = *in diff --git a/pkg/interceptors/bitbucket/bitbucket.go b/pkg/interceptors/bitbucket/bitbucket.go index b44f399c69..2db7d954bd 100644 --- a/pkg/interceptors/bitbucket/bitbucket.go +++ b/pkg/interceptors/bitbucket/bitbucket.go @@ -31,18 +31,18 @@ import ( ) type Interceptor struct { - KubeClientSet kubernetes.Interface - Logger *zap.SugaredLogger - Bitbucket *triggersv1.BitbucketInterceptor - EventListenerNamespace string + KubeClientSet kubernetes.Interface + Logger *zap.SugaredLogger + Bitbucket *triggersv1.BitbucketInterceptor + TriggerNamespace string } func NewInterceptor(bh *triggersv1.BitbucketInterceptor, k kubernetes.Interface, ns string, l *zap.SugaredLogger) interceptors.Interceptor { return &Interceptor{ - Logger: l, - Bitbucket: bh, - KubeClientSet: k, - EventListenerNamespace: ns, + Logger: l, + Bitbucket: bh, + KubeClientSet: k, + TriggerNamespace: ns, } } @@ -64,7 +64,7 @@ func (w *Interceptor) ExecuteTrigger(request *http.Request) (*http.Response, err if header == "" { return nil, errors.New("no X-Hub-Signature header set") } - secretToken, err := interceptors.GetSecretToken(request, w.KubeClientSet, w.Bitbucket.SecretRef, w.EventListenerNamespace) + secretToken, err := interceptors.GetSecretToken(request, w.KubeClientSet, w.Bitbucket.SecretRef, w.TriggerNamespace) if err != nil { return nil, err } diff --git a/pkg/interceptors/bitbucket/bitbucket_test.go b/pkg/interceptors/bitbucket/bitbucket_test.go index 727f111414..4122f1f2ea 100644 --- a/pkg/interceptors/bitbucket/bitbucket_test.go +++ b/pkg/interceptors/bitbucket/bitbucket_test.go @@ -240,10 +240,10 @@ func TestInterceptor_ExecuteTrigger_Signature(t *testing.T) { } } w := &Interceptor{ - KubeClientSet: kubeClient, - Bitbucket: tt.Bitbucket, - Logger: logger, - EventListenerNamespace: metav1.NamespaceDefault, + KubeClientSet: kubeClient, + Bitbucket: tt.Bitbucket, + Logger: logger, + TriggerNamespace: metav1.NamespaceDefault, } resp, err := w.ExecuteTrigger(request) if err != nil { diff --git a/pkg/interceptors/cel/cel.go b/pkg/interceptors/cel/cel.go index b8ad0dfe30..edc5b46525 100644 --- a/pkg/interceptors/cel/cel.go +++ b/pkg/interceptors/cel/cel.go @@ -45,10 +45,10 @@ import ( // against the incoming body and headers to match, if the expression returns // a true value, then the interception is "successful". type Interceptor struct { - KubeClientSet kubernetes.Interface - Logger *zap.SugaredLogger - CEL *triggersv1.CELInterceptor - EventListenerNamespace string + KubeClientSet kubernetes.Interface + Logger *zap.SugaredLogger + CEL *triggersv1.CELInterceptor + TriggerNamespace string } var ( @@ -60,16 +60,16 @@ var ( // NewInterceptor creates a prepopulated Interceptor. func NewInterceptor(cel *triggersv1.CELInterceptor, k kubernetes.Interface, ns string, l *zap.SugaredLogger) interceptors.Interceptor { return &Interceptor{ - Logger: l, - CEL: cel, - KubeClientSet: k, - EventListenerNamespace: ns, + Logger: l, + CEL: cel, + KubeClientSet: k, + TriggerNamespace: ns, } } // ExecuteTrigger is an implementation of the Interceptor interface. func (w *Interceptor) ExecuteTrigger(request *http.Request) (*http.Response, error) { - env, err := makeCelEnv(request, w.EventListenerNamespace, w.KubeClientSet) + env, err := makeCelEnv(request, w.TriggerNamespace, w.KubeClientSet) if err != nil { return nil, fmt.Errorf("error creating cel environment: %w", err) } diff --git a/pkg/interceptors/github/github.go b/pkg/interceptors/github/github.go index 0921c368d9..8e9d509d4c 100644 --- a/pkg/interceptors/github/github.go +++ b/pkg/interceptors/github/github.go @@ -31,18 +31,18 @@ import ( ) type Interceptor struct { - KubeClientSet kubernetes.Interface - Logger *zap.SugaredLogger - GitHub *triggersv1.GitHubInterceptor - EventListenerNamespace string + KubeClientSet kubernetes.Interface + Logger *zap.SugaredLogger + GitHub *triggersv1.GitHubInterceptor + TriggerNamespace string } func NewInterceptor(gh *triggersv1.GitHubInterceptor, k kubernetes.Interface, ns string, l *zap.SugaredLogger) interceptors.Interceptor { return &Interceptor{ - Logger: l, - GitHub: gh, - KubeClientSet: k, - EventListenerNamespace: ns, + Logger: l, + GitHub: gh, + KubeClientSet: k, + TriggerNamespace: ns, } } @@ -64,7 +64,7 @@ func (w *Interceptor) ExecuteTrigger(request *http.Request) (*http.Response, err if header == "" { return nil, errors.New("no X-Hub-Signature header set") } - secretToken, err := interceptors.GetSecretToken(request, w.KubeClientSet, w.GitHub.SecretRef, w.EventListenerNamespace) + secretToken, err := interceptors.GetSecretToken(request, w.KubeClientSet, w.GitHub.SecretRef, w.TriggerNamespace) if err != nil { return nil, err } diff --git a/pkg/interceptors/github/github_test.go b/pkg/interceptors/github/github_test.go index 62932e8a9f..0e10e929dd 100644 --- a/pkg/interceptors/github/github_test.go +++ b/pkg/interceptors/github/github_test.go @@ -240,10 +240,10 @@ func TestInterceptor_ExecuteTrigger_Signature(t *testing.T) { } } w := &Interceptor{ - KubeClientSet: kubeClient, - GitHub: tt.GitHub, - Logger: logger, - EventListenerNamespace: metav1.NamespaceDefault, + KubeClientSet: kubeClient, + GitHub: tt.GitHub, + Logger: logger, + TriggerNamespace: metav1.NamespaceDefault, } resp, err := w.ExecuteTrigger(request) if err != nil { diff --git a/pkg/interceptors/gitlab/gitlab.go b/pkg/interceptors/gitlab/gitlab.go index f349e7b489..ae5c832c19 100644 --- a/pkg/interceptors/gitlab/gitlab.go +++ b/pkg/interceptors/gitlab/gitlab.go @@ -31,18 +31,18 @@ import ( ) type Interceptor struct { - KubeClientSet kubernetes.Interface - Logger *zap.SugaredLogger - GitLab *triggersv1.GitLabInterceptor - EventListenerNamespace string + KubeClientSet kubernetes.Interface + Logger *zap.SugaredLogger + GitLab *triggersv1.GitLabInterceptor + TriggerNamespace string } func NewInterceptor(gl *triggersv1.GitLabInterceptor, k kubernetes.Interface, ns string, l *zap.SugaredLogger) interceptors.Interceptor { return &Interceptor{ - Logger: l, - GitLab: gl, - KubeClientSet: k, - EventListenerNamespace: ns, + Logger: l, + GitLab: gl, + KubeClientSet: k, + TriggerNamespace: ns, } } @@ -54,7 +54,7 @@ func (w *Interceptor) ExecuteTrigger(request *http.Request) (*http.Response, err return nil, errors.New("no X-GitLab-Token header set") } - secretToken, err := interceptors.GetSecretToken(request, w.KubeClientSet, w.GitLab.SecretRef, w.EventListenerNamespace) + secretToken, err := interceptors.GetSecretToken(request, w.KubeClientSet, w.GitLab.SecretRef, w.TriggerNamespace) if err != nil { return nil, err } diff --git a/pkg/interceptors/gitlab/gitlab_test.go b/pkg/interceptors/gitlab/gitlab_test.go index 286eed9efb..ba00a40a81 100644 --- a/pkg/interceptors/gitlab/gitlab_test.go +++ b/pkg/interceptors/gitlab/gitlab_test.go @@ -223,10 +223,10 @@ func TestInterceptor_ExecuteTrigger(t *testing.T) { } } w := &Interceptor{ - KubeClientSet: kubeClient, - GitLab: tt.GitLab, - Logger: logger, - EventListenerNamespace: metav1.NamespaceDefault, + KubeClientSet: kubeClient, + GitLab: tt.GitLab, + Logger: logger, + TriggerNamespace: metav1.NamespaceDefault, } resp, err := w.ExecuteTrigger(request) if err != nil { diff --git a/pkg/interceptors/webhook/webhook.go b/pkg/interceptors/webhook/webhook.go index c29e41aa73..fc85191a5b 100644 --- a/pkg/interceptors/webhook/webhook.go +++ b/pkg/interceptors/webhook/webhook.go @@ -41,10 +41,10 @@ const ( ) type Interceptor struct { - HTTPClient *http.Client - EventListenerNamespace string - Logger *zap.SugaredLogger - Webhook *triggersv1.WebhookInterceptor + HTTPClient *http.Client + TriggerNamespace string + Logger *zap.SugaredLogger + Webhook *triggersv1.WebhookInterceptor } func NewInterceptor(wh *triggersv1.WebhookInterceptor, c *http.Client, ns string, l *zap.SugaredLogger) interceptors.Interceptor { @@ -53,15 +53,15 @@ func NewInterceptor(wh *triggersv1.WebhookInterceptor, c *http.Client, ns string Timeout: interceptorTimeout, } return &Interceptor{ - HTTPClient: timeoutClient, - EventListenerNamespace: ns, - Logger: l, - Webhook: wh, + HTTPClient: timeoutClient, + TriggerNamespace: ns, + Logger: l, + Webhook: wh, } } func (w *Interceptor) ExecuteTrigger(request *http.Request) (*http.Response, error) { - u, err := getURI(w.Webhook.ObjectRef, w.EventListenerNamespace) // TODO: Cache this result or do this on initialization + u, err := getURI(w.Webhook.ObjectRef, w.TriggerNamespace) // TODO: Cache this result or do this on initialization if err != nil { return nil, err } diff --git a/pkg/sink/sink.go b/pkg/sink/sink.go index 8b287a47b7..54f651473c 100644 --- a/pkg/sink/sink.go +++ b/pkg/sink/sink.go @@ -42,7 +42,7 @@ import ( "k8s.io/client-go/kubernetes" ) -// Sink defines the sink resource for processing incoming events for the +// Sink defines the sink resourcsifor processing incoming events for the // EventListener. type Sink struct { KubeClientSet kubernetes.Interface @@ -70,8 +70,8 @@ type Response struct { func (r Sink) HandleEvent(response http.ResponseWriter, request *http.Request) { el, err := r.TriggersClient.TriggersV1alpha1().EventListeners(r.EventListenerNamespace).Get(r.EventListenerName, metav1.GetOptions{}) if err != nil { - r.Logger.Fatalf("Error getting EventListener %s in Namespace %s: %s", r.EventListenerName, r.EventListenerNamespace, err) response.WriteHeader(http.StatusInternalServerError) + r.Logger.Errorf("Error getting EventListener %s in Namespace %s: %s", r.EventListenerName, r.EventListenerNamespace, err) return } event, err := ioutil.ReadAll(request.Body) @@ -85,13 +85,38 @@ func (r Sink) HandleEvent(response http.ResponseWriter, request *http.Request) { eventLog := r.Logger.With(zap.String(triggersv1.EventIDLabelKey, eventID)) eventLog.Debugf("EventListener: %s in Namespace: %s handling event (EventID: %s) with payload: %s and header: %v", r.EventListenerName, r.EventListenerNamespace, eventID, string(event), request.Header) - + var trItems []triggersv1.Trigger + if el.Spec.NamespaceSelector.Any { + trList, err := r.TriggersClient.TriggersV1alpha1().Triggers("").List(metav1.ListOptions{}) + if err != nil { + r.Logger.Errorf("Error getting Triggers: %s", err) + response.WriteHeader(http.StatusInternalServerError) + return + } + trItems = trList.Items + } else if len(el.Spec.NamespaceSelector.MatchNames) != 0 { + for _, v := range el.Spec.NamespaceSelector.MatchNames { + trList, err := r.TriggersClient.TriggersV1alpha1().Triggers(v).List(metav1.ListOptions{}) + if err != nil { + r.Logger.Errorf("Error getting Triggers: %s", err) + response.WriteHeader(http.StatusInternalServerError) + return + } + trItems = append(trItems, trList.Items...) + } + } + triggers, err := r.merge(el.Spec.Triggers, trItems) + if err != nil { + r.Logger.Errorf("Error merging Triggers: %s", err) + response.WriteHeader(http.StatusInternalServerError) + return + } result := make(chan int, 10) // Execute each Trigger - for _, t := range el.Spec.Triggers { - go func(t triggersv1.EventListenerTrigger) { + for _, t := range triggers { + go func(t triggersv1.Trigger) { localRequest := request.Clone(request.Context()) - if err := r.processTrigger(&t, localRequest, event, eventID, eventLog); err != nil { + if err := r.processTrigger(t, localRequest, event, eventID, eventLog); err != nil { if kerrors.IsUnauthorized(err) { result <- http.StatusUnauthorized return @@ -110,7 +135,7 @@ func (r Sink) HandleEvent(response http.ResponseWriter, request *http.Request) { //The eventlistener waits until all the trigger executions (up-to the creation of the resources) and //only when at least one of the execution completed successfully, it returns response code 201(Created) otherwise it returns 202 (Accepted). code := http.StatusAccepted - for i := 0; i < len(el.Spec.Triggers); i++ { + for i := 0; i < len(triggers); i++ { thiscode := <-result // current take - if someone is doing unauthorized stuff, we abort immediately; // unauthorized should be the final status code vs. the less than comparison @@ -136,25 +161,37 @@ func (r Sink) HandleEvent(response http.ResponseWriter, request *http.Request) { } } -func (r Sink) processTrigger(t *triggersv1.EventListenerTrigger, request *http.Request, event []byte, eventID string, eventLog *zap.SugaredLogger) error { - if t == nil { - return errors.New("EventListenerTrigger not defined") - } - - if t.Template == nil && t.TriggerRef != "" { - trigger, err := r.TriggersClient.TriggersV1alpha1().Triggers(r.EventListenerNamespace).Get(t.TriggerRef, metav1.GetOptions{}) - if err != nil { - r.Logger.Fatalf("Error getting Trigger %s in Namespace %s: %s", t.TriggerRef, r.EventListenerNamespace, err) - return err - } - trig, err := triggersv1.ToEventListenerTrigger(trigger.Spec) - if err != nil { - r.Logger.Fatalf("Error changing Trigger to EventListenerTrigger: %s", err) - return err +func (r Sink) merge(et []triggersv1.EventListenerTrigger, trItems []triggersv1.Trigger) ([]triggersv1.Trigger, error) { + triggers := trItems + for _, t := range et { + switch { + case t.Template == nil && t.TriggerRef != "": + trig, err := r.TriggersClient.TriggersV1alpha1().Triggers(r.EventListenerNamespace).Get(t.TriggerRef, metav1.GetOptions{}) + if err != nil { + r.Logger.Errorf("Error getting Trigger %s in Namespace %s: %s", t.TriggerRef, r.EventListenerNamespace, err) + return nil, fmt.Errorf("Error getting Trigger %s in Namespace %s: %s", t.TriggerRef, r.EventListenerNamespace, err) + } + triggers = append(triggers, *trig) + case t.Template != nil: + triggers = append(triggers, triggersv1.Trigger{ + ObjectMeta: metav1.ObjectMeta{ + Name: t.Name, + Namespace: r.EventListenerNamespace}, + Spec: triggersv1.TriggerSpec{ + ServiceAccountName: t.ServiceAccountName, + Bindings: t.Bindings, + Template: *t.Template, + Interceptors: t.Interceptors, + }, + }) + default: + return nil, errors.New("EventListenerTrigger not defined") } - t = &trig } + return triggers, nil +} +func (r Sink) processTrigger(t triggersv1.Trigger, request *http.Request, event []byte, eventID string, eventLog *zap.SugaredLogger) error { log := eventLog.With(zap.String(triggersv1.TriggerLabelKey, t.Name)) finalPayload, header, err := r.ExecuteInterceptors(t, request, event, log) @@ -163,10 +200,10 @@ func (r Sink) processTrigger(t *triggersv1.EventListenerTrigger, request *http.R return err } - rt, err := template.ResolveTrigger(*t, - r.TriggersClient.TriggersV1alpha1().TriggerBindings(r.EventListenerNamespace).Get, + rt, err := template.ResolveTrigger(t, + r.TriggersClient.TriggersV1alpha1().TriggerBindings(t.Namespace).Get, r.TriggersClient.TriggersV1alpha1().ClusterTriggerBindings().Get, - r.TriggersClient.TriggersV1alpha1().TriggerTemplates(r.EventListenerNamespace).Get) + r.TriggersClient.TriggersV1alpha1().TriggerTemplates(t.Namespace).Get) if err != nil { log.Error(err) return err @@ -180,15 +217,15 @@ func (r Sink) processTrigger(t *triggersv1.EventListenerTrigger, request *http.R log.Infof("ResolvedParams : %+v", params) resources := template.ResolveResources(rt.TriggerTemplate, params) - if err := r.CreateResources(t.ServiceAccountName, resources, t.Name, eventID, log); err != nil { + if err := r.CreateResources(t.Namespace, t.Spec.ServiceAccountName, resources, t.Name, eventID, log); err != nil { log.Error(err) return err } return nil } -func (r Sink) ExecuteInterceptors(t *triggersv1.EventListenerTrigger, in *http.Request, event []byte, log *zap.SugaredLogger) ([]byte, http.Header, error) { - if len(t.Interceptors) == 0 { +func (r Sink) ExecuteInterceptors(t triggersv1.Trigger, in *http.Request, event []byte, log *zap.SugaredLogger) ([]byte, http.Header, error) { + if len(t.Spec.Interceptors) == 0 { return event, in.Header, nil } @@ -205,19 +242,19 @@ func (r Sink) ExecuteInterceptors(t *triggersv1.EventListenerTrigger, in *http.R request = interceptors.WithCache(request) var resp *http.Response - for _, i := range t.Interceptors { + for _, i := range t.Spec.Interceptors { var interceptor interceptors.Interceptor switch { case i.Webhook != nil: - interceptor = webhook.NewInterceptor(i.Webhook, r.HTTPClient, r.EventListenerNamespace, log) + interceptor = webhook.NewInterceptor(i.Webhook, r.HTTPClient, t.Namespace, log) case i.GitHub != nil: - interceptor = github.NewInterceptor(i.GitHub, r.KubeClientSet, r.EventListenerNamespace, log) + interceptor = github.NewInterceptor(i.GitHub, r.KubeClientSet, t.Namespace, log) case i.GitLab != nil: - interceptor = gitlab.NewInterceptor(i.GitLab, r.KubeClientSet, r.EventListenerNamespace, log) + interceptor = gitlab.NewInterceptor(i.GitLab, r.KubeClientSet, t.Namespace, log) case i.CEL != nil: - interceptor = cel.NewInterceptor(i.CEL, r.KubeClientSet, r.EventListenerNamespace, log) + interceptor = cel.NewInterceptor(i.CEL, r.KubeClientSet, t.Namespace, log) case i.Bitbucket != nil: - interceptor = bitbucket.NewInterceptor(i.Bitbucket, r.KubeClientSet, r.EventListenerNamespace, log) + interceptor = bitbucket.NewInterceptor(i.Bitbucket, r.KubeClientSet, t.Namespace, log) default: return nil, nil, fmt.Errorf("unknown interceptor type: %v", i) } @@ -244,7 +281,7 @@ func (r Sink) ExecuteInterceptors(t *triggersv1.EventListenerTrigger, in *http.R return payload, resp.Header, nil } -func (r Sink) CreateResources(sa string, res []json.RawMessage, triggerName, eventID string, log *zap.SugaredLogger) error { +func (r Sink) CreateResources(triggerNS, sa string, res []json.RawMessage, triggerName, eventID string, log *zap.SugaredLogger) error { discoveryClient := r.DiscoveryClient dynamicClient := r.DynamicClient var err error @@ -254,7 +291,7 @@ func (r Sink) CreateResources(sa string, res []json.RawMessage, triggerName, eve // However, we also have a ServiceAccountName reference with each EventListenerTrigger to allow // for more fine grained authorization control around the resources we create below. - discoveryClient, dynamicClient, err = r.Auth.OverrideAuthentication(sa, r.EventListenerNamespace, log, r.DiscoveryClient, r.DynamicClient) + discoveryClient, dynamicClient, err = r.Auth.OverrideAuthentication(sa, triggerNS, log, r.DiscoveryClient, r.DynamicClient) if err != nil { log.Errorf("problem cloning rest config: %#v", err) return err @@ -262,7 +299,7 @@ func (r Sink) CreateResources(sa string, res []json.RawMessage, triggerName, eve } for _, rr := range res { - if err := resources.Create(r.Logger, rr, triggerName, eventID, r.EventListenerName, r.EventListenerNamespace, discoveryClient, dynamicClient); err != nil { + if err := resources.Create(r.Logger, rr, triggerName, eventID, r.EventListenerName, triggerNS, discoveryClient, dynamicClient); err != nil { log.Errorf("problem creating obj: %#v", err) return err } diff --git a/pkg/sink/sink_test.go b/pkg/sink/sink_test.go index 619d837411..eab3f94b76 100644 --- a/pkg/sink/sink_test.go +++ b/pkg/sink/sink_test.go @@ -257,6 +257,224 @@ func TestHandleEvent(t *testing.T) { } } +func TestHandleEventNSSelectorMatchNames(t *testing.T) { + eventBody := json.RawMessage(`{"head_commit": {"id": "testrevision"}, "repository": {"url": "testurl"}, "foo": "bar\t\r\nbaz昨"}`) + + triggerNS := "bar" + + pipelineResource := pipelinev1alpha1.PipelineResource{ + TypeMeta: metav1.TypeMeta{ + APIVersion: "tekton.dev/v1alpha1", + Kind: "PipelineResource", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "$(tt.params.name)", + Namespace: triggerNS, + Labels: map[string]string{ + "app": "$(tt.params.foo)", + "type": "$(tt.params.type)", + }, + }, + Spec: pipelinev1alpha1.PipelineResourceSpec{ + Type: pipelinev1alpha1.PipelineResourceTypeGit, + Params: []pipelinev1alpha1.ResourceParam{ + {Name: "url", Value: "$(tt.params.url)"}, + {Name: "revision", Value: "$(tt.params.revision)"}, + }, + }, + } + pipelineResourceBytes, err := json.Marshal(pipelineResource) + if err != nil { + t.Fatalf("Error unmarshalling pipelineResource: %s", err) + } + + tt := bldr.TriggerTemplate("my-triggertemplate", triggerNS, + bldr.TriggerTemplateSpec( + bldr.TriggerTemplateParam("name", "", ""), + bldr.TriggerTemplateParam("url", "", ""), + bldr.TriggerTemplateParam("revision", "", ""), + bldr.TriggerTemplateParam("foo", "", ""), + bldr.TriggerTemplateParam("type", "", ""), + bldr.TriggerResourceTemplate(runtime.RawExtension{Raw: pipelineResourceBytes}), + )) + // Create TriggerBinding + tbs := []*triggersv1.TriggerBinding{bldr.TriggerBinding("my-triggerbinding", triggerNS, + bldr.TriggerBindingSpec( + bldr.TriggerBindingParam("name", "my-pipelineresource"), + bldr.TriggerBindingParam("url", "$(body.repository.url)"), + bldr.TriggerBindingParam("revision", "$(body.head_commit.id)"), + bldr.TriggerBindingParam("foo", "$(body.foo)"), + bldr.TriggerBindingParam("type", "$(header.Content-Type)"), + ))} + // Add TriggerBinding to Trigger + triggers := []*triggersv1.Trigger{bldr.Trigger("my-trigger", triggerNS, bldr.TriggerSpec( + bldr.TriggerSpecBinding("my-triggerbinding", "", "my-triggerbinding", "v1alpha1"), + bldr.TriggerSpecTemplate("my-triggertemplate", "v1alpha1"), + ))} + // Add TriggerRef to EventListener + el := bldr.EventListener("my-eventlistener", namespace, bldr.EventListenerSpec(bldr.EventListenerNamespaceSelectorMatchNames([]string{triggerNS}))) + + resources := test.Resources{ + TriggerBindings: tbs, + TriggerTemplates: []*triggersv1.TriggerTemplate{tt}, + EventListeners: []*triggersv1.EventListener{el}, + Triggers: triggers, + } + + sink, dynamicClient := getSinkAssets(t, resources, el.Name, DefaultAuthOverride{}) + + ts := httptest.NewServer(http.HandlerFunc(sink.HandleEvent)) + defer ts.Close() + + resp, err := http.Post(ts.URL, "application/json", bytes.NewReader(eventBody)) + if err != nil { + t.Fatalf("Error creating Post request: %s", err) + } + + checkSinkResponse(t, resp, el.Name) + // Check right resources were created. + var wantPrs []pipelinev1alpha1.PipelineResource + wantResource := pipelinev1alpha1.PipelineResource{ + TypeMeta: metav1.TypeMeta{ + APIVersion: "tekton.dev/v1alpha1", + Kind: "PipelineResource", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "my-pipelineresource", + Namespace: triggerNS, + Labels: map[string]string{ + "app": "bar\t\r\nbaz昨", + "type": "application/json", + resourceLabel: "my-eventlistener", + triggerLabel: "my-trigger", + eventIDLabel: eventID, + }, + }, + Spec: pipelinev1alpha1.PipelineResourceSpec{ + Type: pipelinev1alpha1.PipelineResourceTypeGit, + Params: []pipelinev1alpha1.ResourceParam{ + {Name: "url", Value: "testurl"}, + {Name: "revision", Value: "testrevision"}, + }, + }, + } + wantPrs = append(wantPrs, wantResource) + // Sort actions (we do not know what order they executed in) + gotPrs := getCreatedPipelineResources(t, dynamicClient.Actions()) + if diff := cmp.Diff(wantPrs, gotPrs, cmpopts.SortSlices(comparePR)); diff != "" { + t.Errorf("Created resources mismatch (-want + got): %s", diff) + } +} + +func TestHandleEventNSSelectorAny(t *testing.T) { + eventBody := json.RawMessage(`{"head_commit": {"id": "testrevision"}, "repository": {"url": "testurl"}, "foo": "bar\t\r\nbaz昨"}`) + + triggerNS := "bar" + + pipelineResource := pipelinev1alpha1.PipelineResource{ + TypeMeta: metav1.TypeMeta{ + APIVersion: "tekton.dev/v1alpha1", + Kind: "PipelineResource", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "$(tt.params.name)", + Namespace: triggerNS, + Labels: map[string]string{ + "app": "$(tt.params.foo)", + "type": "$(tt.params.type)", + }, + }, + Spec: pipelinev1alpha1.PipelineResourceSpec{ + Type: pipelinev1alpha1.PipelineResourceTypeGit, + Params: []pipelinev1alpha1.ResourceParam{ + {Name: "url", Value: "$(tt.params.url)"}, + {Name: "revision", Value: "$(tt.params.revision)"}, + }, + }, + } + pipelineResourceBytes, err := json.Marshal(pipelineResource) + if err != nil { + t.Fatalf("Error unmarshalling pipelineResource: %s", err) + } + + tt := bldr.TriggerTemplate("my-triggertemplate", triggerNS, + bldr.TriggerTemplateSpec( + bldr.TriggerTemplateParam("name", "", ""), + bldr.TriggerTemplateParam("url", "", ""), + bldr.TriggerTemplateParam("revision", "", ""), + bldr.TriggerTemplateParam("foo", "", ""), + bldr.TriggerTemplateParam("type", "", ""), + bldr.TriggerResourceTemplate(runtime.RawExtension{Raw: pipelineResourceBytes}), + )) + // Create TriggerBinding + tbs := []*triggersv1.TriggerBinding{bldr.TriggerBinding("my-triggerbinding", triggerNS, + bldr.TriggerBindingSpec( + bldr.TriggerBindingParam("name", "my-pipelineresource"), + bldr.TriggerBindingParam("url", "$(body.repository.url)"), + bldr.TriggerBindingParam("revision", "$(body.head_commit.id)"), + bldr.TriggerBindingParam("foo", "$(body.foo)"), + bldr.TriggerBindingParam("type", "$(header.Content-Type)"), + ))} + // Add TriggerBinding to Trigger + triggers := []*triggersv1.Trigger{bldr.Trigger("my-trigger", triggerNS, bldr.TriggerSpec( + bldr.TriggerSpecBinding("my-triggerbinding", "", "my-triggerbinding", "v1alpha1"), + bldr.TriggerSpecTemplate("my-triggertemplate", "v1alpha1"), + ))} + // Add TriggerRef to EventListener + el := bldr.EventListener("my-eventlistener", namespace, bldr.EventListenerSpec(bldr.EventListenerNamespaceSelectorAny())) + + resources := test.Resources{ + TriggerBindings: tbs, + TriggerTemplates: []*triggersv1.TriggerTemplate{tt}, + EventListeners: []*triggersv1.EventListener{el}, + Triggers: triggers, + } + + sink, dynamicClient := getSinkAssets(t, resources, el.Name, DefaultAuthOverride{}) + + ts := httptest.NewServer(http.HandlerFunc(sink.HandleEvent)) + defer ts.Close() + + resp, err := http.Post(ts.URL, "application/json", bytes.NewReader(eventBody)) + if err != nil { + t.Fatalf("Error creating Post request: %s", err) + } + + checkSinkResponse(t, resp, el.Name) + // Check right resources were created. + var wantPrs []pipelinev1alpha1.PipelineResource + wantResource := pipelinev1alpha1.PipelineResource{ + TypeMeta: metav1.TypeMeta{ + APIVersion: "tekton.dev/v1alpha1", + Kind: "PipelineResource", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "my-pipelineresource", + Namespace: triggerNS, + Labels: map[string]string{ + "app": "bar\t\r\nbaz昨", + "type": "application/json", + resourceLabel: "my-eventlistener", + triggerLabel: "my-trigger", + eventIDLabel: eventID, + }, + }, + Spec: pipelinev1alpha1.PipelineResourceSpec{ + Type: pipelinev1alpha1.PipelineResourceTypeGit, + Params: []pipelinev1alpha1.ResourceParam{ + {Name: "url", Value: "testurl"}, + {Name: "revision", Value: "testrevision"}, + }, + }, + } + wantPrs = append(wantPrs, wantResource) + // Sort actions (we do not know what order they executed in) + gotPrs := getCreatedPipelineResources(t, dynamicClient.Actions()) + if diff := cmp.Diff(wantPrs, gotPrs, cmpopts.SortSlices(comparePR)); diff != "" { + t.Errorf("Created resources mismatch (-want + got): %s", diff) + } +} + func TestHandleEventTriggerRef(t *testing.T) { eventBody := json.RawMessage(`{"head_commit": {"id": "testrevision"}, "repository": {"url": "testurl"}, "foo": "bar\t\r\nbaz昨"}`) @@ -344,7 +562,7 @@ func TestHandleEventTriggerRef(t *testing.T) { "app": "bar\t\r\nbaz昨", "type": "application/json", resourceLabel: "my-eventlistener", - triggerLabel: el.Spec.Triggers[0].Name, + triggerLabel: "my-trigger", eventIDLabel: eventID, }, }, @@ -364,6 +582,55 @@ func TestHandleEventTriggerRef(t *testing.T) { } } +func TestHandleEventTriggerRefNotFound(t *testing.T) { + eventBody := json.RawMessage(`{"head_commit": {"id": "testrevision"}, "repository": {"url": "testurl"}, "foo": "bar\t\r\nbaz昨"}`) + triggers := []*triggersv1.Trigger{} + // Add TriggerRef to EventListener + el := bldr.EventListener("my-eventlistener", namespace, bldr.EventListenerSpec(bldr.EventListenerTriggerRef("my-trigger"))) + + resources := test.Resources{ + TriggerBindings: []*triggersv1.TriggerBinding{}, + TriggerTemplates: []*triggersv1.TriggerTemplate{}, + EventListeners: []*triggersv1.EventListener{el}, + Triggers: triggers, + } + + sink, _ := getSinkAssets(t, resources, el.Name, DefaultAuthOverride{}) + + ts := httptest.NewServer(http.HandlerFunc(sink.HandleEvent)) + defer ts.Close() + + resp, err := http.Post(ts.URL, "application/json", bytes.NewReader(eventBody)) + if err != nil { + t.Fatalf("Error creating Post request: %s", err) + } + if resp.StatusCode != http.StatusInternalServerError { + t.Fatalf("Status Code Mismatch : (want: %d got: %d", resp.StatusCode, http.StatusInternalServerError) + } +} + +func TestHandleEventELNotFound(t *testing.T) { + eventBody := json.RawMessage(`{"head_commit": {"id": "testrevision"}, "repository": {"url": "testurl"}, "foo": "bar\t\r\nbaz昨"}`) + resources := test.Resources{ + TriggerBindings: []*triggersv1.TriggerBinding{}, + TriggerTemplates: []*triggersv1.TriggerTemplate{}, + EventListeners: []*triggersv1.EventListener{}, + Triggers: []*triggersv1.Trigger{}, + } + + sink, _ := getSinkAssets(t, resources, "my-eventlistener", DefaultAuthOverride{}) + + ts := httptest.NewServer(http.HandlerFunc(sink.HandleEvent)) + defer ts.Close() + resp, err := http.Post(ts.URL, "application/json", bytes.NewReader(eventBody)) + if err != nil { + t.Fatalf("Error creating Post request: %s", err) + } + if resp.StatusCode != http.StatusInternalServerError { + t.Fatalf("Status Code Mismatch : (want: %d got: %d", resp.StatusCode, http.StatusInternalServerError) + } +} + func TestHandleEventWithInterceptors(t *testing.T) { eventBody := json.RawMessage(`{"head_commit": {"id": "testrevision"}, "repository": {"url": "testurl"}, "foo": "bar\t\r\nbaz昨"}`) @@ -783,8 +1050,9 @@ func TestExecuteInterceptor(t *testing.T) { }, }, } - trigger := &triggersv1.EventListenerTrigger{ - Interceptors: []*triggersv1.EventInterceptor{a, a}, + trigger := triggersv1.Trigger{ + Spec: triggersv1.TriggerSpec{ + Interceptors: []*triggersv1.EventInterceptor{a, a}}, } for _, method := range []string{ @@ -857,24 +1125,26 @@ func TestExecuteInterceptor_error(t *testing.T) { Logger: logger.Sugar(), } - trigger := &triggersv1.EventListenerTrigger{ - Interceptors: []*triggersv1.EventInterceptor{ - // Error interceptor needs to come first. - { - Webhook: &triggersv1.WebhookInterceptor{ - ObjectRef: &corev1.ObjectReference{ - APIVersion: "v1", - Kind: "Service", - Name: errHost, + trigger := triggersv1.Trigger{ + Spec: triggersv1.TriggerSpec{ + Interceptors: []*triggersv1.EventInterceptor{ + // Error interceptor needs to come first. + { + Webhook: &triggersv1.WebhookInterceptor{ + ObjectRef: &corev1.ObjectReference{ + APIVersion: "v1", + Kind: "Service", + Name: errHost, + }, }, }, - }, - { - Webhook: &triggersv1.WebhookInterceptor{ - ObjectRef: &corev1.ObjectReference{ - APIVersion: "v1", - Kind: "Service", - Name: "foo", + { + Webhook: &triggersv1.WebhookInterceptor{ + ObjectRef: &corev1.ObjectReference{ + APIVersion: "v1", + Kind: "Service", + Name: "foo", + }, }, }, }, diff --git a/pkg/template/resource.go b/pkg/template/resource.go index 026ce655e6..7a014a7650 100644 --- a/pkg/template/resource.go +++ b/pkg/template/resource.go @@ -45,10 +45,10 @@ type getClusterTriggerBinding func(name string, options metav1.GetOptions) (*tri // ResolveTrigger takes in a trigger containing object refs to bindings and // templates and resolves them to their underlying values. -func ResolveTrigger(trigger triggersv1.EventListenerTrigger, getTB getTriggerBinding, getCTB getClusterTriggerBinding, getTT getTriggerTemplate) (ResolvedTrigger, error) { - tb := make([]*triggersv1.TriggerBinding, 0, len(trigger.Bindings)) - ctb := make([]*triggersv1.ClusterTriggerBinding, 0, len(trigger.Bindings)) - for _, b := range trigger.Bindings { +func ResolveTrigger(trigger triggersv1.Trigger, getTB getTriggerBinding, getCTB getClusterTriggerBinding, getTT getTriggerTemplate) (ResolvedTrigger, error) { + tb := make([]*triggersv1.TriggerBinding, 0, len(trigger.Spec.Bindings)) + ctb := make([]*triggersv1.ClusterTriggerBinding, 0, len(trigger.Spec.Bindings)) + for _, b := range trigger.Spec.Bindings { if b.Spec != nil { tb = append(tb, &triggersv1.TriggerBinding{ ObjectMeta: metav1.ObjectMeta{ @@ -74,7 +74,7 @@ func ResolveTrigger(trigger triggersv1.EventListenerTrigger, getTB getTriggerBin } } - ttName := trigger.Template.Name + ttName := trigger.Spec.Template.Name tt, err := getTT(ttName, metav1.GetOptions{}) if err != nil { return ResolvedTrigger{}, fmt.Errorf("error getting TriggerTemplate %s: %w", ttName, err) diff --git a/pkg/template/resource_test.go b/pkg/template/resource_test.go index 836ea9f96c..a1282ee6ae 100644 --- a/pkg/template/resource_test.go +++ b/pkg/template/resource_test.go @@ -317,19 +317,21 @@ var ( func Test_ResolveTrigger(t *testing.T) { tests := []struct { name string - trigger triggersv1.EventListenerTrigger + trigger triggersv1.Trigger want ResolvedTrigger }{ { name: "1 binding", - trigger: triggersv1.EventListenerTrigger{ - Bindings: []*triggersv1.EventListenerBinding{{ - Ref: "my-triggerbinding", - Kind: triggersv1.NamespacedTriggerBindingKind, - }}, - Template: &triggersv1.EventListenerTemplate{ - Name: "my-triggertemplate", - APIVersion: "v1alpha1", + trigger: triggersv1.Trigger{ + Spec: triggersv1.TriggerSpec{ + Bindings: []*triggersv1.EventListenerBinding{{ + Ref: "my-triggerbinding", + Kind: triggersv1.NamespacedTriggerBindingKind, + }}, + Template: triggersv1.EventListenerTemplate{ + Name: "my-triggertemplate", + APIVersion: "v1alpha1", + }, }, }, want: ResolvedTrigger{ @@ -340,14 +342,16 @@ func Test_ResolveTrigger(t *testing.T) { }, { name: "1 clustertype binding", - trigger: triggersv1.EventListenerTrigger{ - Bindings: []*triggersv1.EventListenerBinding{{ - Ref: "my-clustertriggerbinding", - Kind: triggersv1.ClusterTriggerBindingKind, - }}, - Template: &triggersv1.EventListenerTemplate{ - Name: "my-triggertemplate", - APIVersion: "v1alpha1", + trigger: triggersv1.Trigger{ + Spec: triggersv1.TriggerSpec{ + Bindings: []*triggersv1.EventListenerBinding{{ + Ref: "my-clustertriggerbinding", + Kind: triggersv1.ClusterTriggerBindingKind, + }}, + Template: triggersv1.EventListenerTemplate{ + Name: "my-triggertemplate", + APIVersion: "v1alpha1", + }, }, }, want: ResolvedTrigger{ @@ -358,19 +362,21 @@ func Test_ResolveTrigger(t *testing.T) { }, { name: "1 embed binding", - trigger: triggersv1.EventListenerTrigger{ - Bindings: []*triggersv1.EventListenerBinding{{ - Name: "my-embed-binding", - Spec: &triggersv1.TriggerBindingSpec{ - Params: []triggersv1.Param{{ - Name: "key", - Value: "value", - }}, + trigger: triggersv1.Trigger{ + Spec: triggersv1.TriggerSpec{ + Bindings: []*triggersv1.EventListenerBinding{{ + Name: "my-embed-binding", + Spec: &triggersv1.TriggerBindingSpec{ + Params: []triggersv1.Param{{ + Name: "key", + Value: "value", + }}, + }, + }}, + Template: triggersv1.EventListenerTemplate{ + Name: "my-triggertemplate", + APIVersion: "v1alpha1", }, - }}, - Template: &triggersv1.EventListenerTemplate{ - Name: "my-triggertemplate", - APIVersion: "v1alpha1", }, }, want: ResolvedTrigger{ @@ -391,47 +397,51 @@ func Test_ResolveTrigger(t *testing.T) { }, { name: "no binding", - trigger: triggersv1.EventListenerTrigger{ - Template: &triggersv1.EventListenerTemplate{ - Name: "my-triggertemplate", - APIVersion: "v1alpha1", + trigger: triggersv1.Trigger{ + Spec: triggersv1.TriggerSpec{ + Template: triggersv1.EventListenerTemplate{ + Name: "my-triggertemplate", + APIVersion: "v1alpha1", + }, }, }, want: ResolvedTrigger{TriggerBindings: []*triggersv1.TriggerBinding{}, ClusterTriggerBindings: []*triggersv1.ClusterTriggerBinding{}, TriggerTemplate: &tt}, }, { name: "multiple bindings", - trigger: triggersv1.EventListenerTrigger{ - Bindings: []*triggersv1.EventListenerBinding{ - { - Name: "my-triggerbinding", - Kind: triggersv1.NamespacedTriggerBindingKind, - Ref: "my-triggerbinding", - APIVersion: "v1alpha1", - }, - { - Name: "tb-params", - Kind: triggersv1.NamespacedTriggerBindingKind, - Ref: "tb-params", - APIVersion: "v1alpha1", - }, - { - Name: "my-clustertriggerbinding", - Kind: triggersv1.ClusterTriggerBindingKind, - Ref: "my-clustertriggerbinding", - APIVersion: "v1alpha1", + trigger: triggersv1.Trigger{ + Spec: triggersv1.TriggerSpec{ + Bindings: []*triggersv1.EventListenerBinding{ + { + Name: "my-triggerbinding", + Kind: triggersv1.NamespacedTriggerBindingKind, + Ref: "my-triggerbinding", + APIVersion: "v1alpha1", + }, + { + Name: "tb-params", + Kind: triggersv1.NamespacedTriggerBindingKind, + Ref: "tb-params", + APIVersion: "v1alpha1", + }, + { + Name: "my-clustertriggerbinding", + Kind: triggersv1.ClusterTriggerBindingKind, + Ref: "my-clustertriggerbinding", + APIVersion: "v1alpha1", + }, + { + Name: "ctb-params", + Kind: triggersv1.ClusterTriggerBindingKind, + Ref: "ctb-params", + APIVersion: "v1alpha1", + }, }, - { - Name: "ctb-params", - Kind: triggersv1.ClusterTriggerBindingKind, - Ref: "ctb-params", + Template: triggersv1.EventListenerTemplate{ + Name: "my-triggertemplate", APIVersion: "v1alpha1", }, }, - Template: &triggersv1.EventListenerTemplate{ - Name: "my-triggertemplate", - APIVersion: "v1alpha1", - }, }, want: ResolvedTrigger{ TriggerBindings: []*triggersv1.TriggerBinding{ @@ -447,15 +457,17 @@ func Test_ResolveTrigger(t *testing.T) { }, { name: "missing kind implies namespacedTriggerBinding", - trigger: triggersv1.EventListenerTrigger{ - Bindings: []*triggersv1.EventListenerBinding{{ - Name: "my-triggerbinding", - APIVersion: "v1alpha1", - Ref: "my-triggerbinding", - }}, - Template: &triggersv1.EventListenerTemplate{ - Name: "my-triggertemplate", - APIVersion: "v1alpha1", + trigger: triggersv1.Trigger{ + Spec: triggersv1.TriggerSpec{ + Bindings: []*triggersv1.EventListenerBinding{{ + Name: "my-triggerbinding", + APIVersion: "v1alpha1", + Ref: "my-triggerbinding", + }}, + Template: triggersv1.EventListenerTemplate{ + Name: "my-triggertemplate", + APIVersion: "v1alpha1", + }, }, }, want: ResolvedTrigger{ @@ -481,21 +493,23 @@ func Test_ResolveTrigger(t *testing.T) { func Test_ResolveTrigger_error(t *testing.T) { tests := []struct { name string - trigger triggersv1.EventListenerTrigger + trigger triggersv1.Trigger getTB getTriggerBinding getTT getTriggerTemplate getCTB getClusterTriggerBinding }{ { name: "error triggerbinding", - trigger: triggersv1.EventListenerTrigger{ - Bindings: []*triggersv1.EventListenerBinding{{ - Ref: "invalid-tb-name", - Kind: triggersv1.NamespacedTriggerBindingKind, - }}, - Template: &triggersv1.EventListenerTemplate{ - Name: "my-triggertemplate", - APIVersion: "v1alpha1", + trigger: triggersv1.Trigger{ + Spec: triggersv1.TriggerSpec{ + Bindings: []*triggersv1.EventListenerBinding{{ + Ref: "invalid-tb-name", + Kind: triggersv1.NamespacedTriggerBindingKind, + }}, + Template: triggersv1.EventListenerTemplate{ + Name: "my-triggertemplate", + APIVersion: "v1alpha1", + }, }, }, getTB: getTB, @@ -504,14 +518,16 @@ func Test_ResolveTrigger_error(t *testing.T) { }, { name: "error clustertriggerbinding", - trigger: triggersv1.EventListenerTrigger{ - Bindings: []*triggersv1.EventListenerBinding{{ - Ref: "invalid-ctb-name", - Kind: triggersv1.ClusterTriggerBindingKind, - }}, - Template: &triggersv1.EventListenerTemplate{ - Name: "my-triggertemplate", - APIVersion: "v1alpha1", + trigger: triggersv1.Trigger{ + Spec: triggersv1.TriggerSpec{ + Bindings: []*triggersv1.EventListenerBinding{{ + Ref: "invalid-ctb-name", + Kind: triggersv1.ClusterTriggerBindingKind, + }}, + Template: triggersv1.EventListenerTemplate{ + Name: "my-triggertemplate", + APIVersion: "v1alpha1", + }, }, }, getTB: getTB, @@ -520,14 +536,16 @@ func Test_ResolveTrigger_error(t *testing.T) { }, { name: "error triggertemplate", - trigger: triggersv1.EventListenerTrigger{ - Bindings: []*triggersv1.EventListenerBinding{{ - Ref: "my-triggerbinding", - Kind: triggersv1.NamespacedTriggerBindingKind, - }}, - Template: &triggersv1.EventListenerTemplate{ - Name: "invalid-tt-name", - APIVersion: "v1alpha1", + trigger: triggersv1.Trigger{ + Spec: triggersv1.TriggerSpec{ + Bindings: []*triggersv1.EventListenerBinding{{ + Ref: "my-triggerbinding", + Kind: triggersv1.NamespacedTriggerBindingKind, + }}, + Template: triggersv1.EventListenerTemplate{ + Name: "invalid-tt-name", + APIVersion: "v1alpha1", + }, }, }, getTB: getTB, @@ -536,14 +554,16 @@ func Test_ResolveTrigger_error(t *testing.T) { }, { name: "error triggerbinding and triggertemplate", - trigger: triggersv1.EventListenerTrigger{ - Bindings: []*triggersv1.EventListenerBinding{{ - Ref: "invalid-tb-name", - Kind: triggersv1.NamespacedTriggerBindingKind, - }}, - Template: &triggersv1.EventListenerTemplate{ - Name: "invalid-tt-name", - APIVersion: "v1alpha1", + trigger: triggersv1.Trigger{ + Spec: triggersv1.TriggerSpec{ + Bindings: []*triggersv1.EventListenerBinding{{ + Ref: "invalid-tb-name", + Kind: triggersv1.NamespacedTriggerBindingKind, + }}, + Template: triggersv1.EventListenerTemplate{ + Name: "invalid-tt-name", + APIVersion: "v1alpha1", + }, }, }, getTB: getTB, diff --git a/test/builder/eventlistener.go b/test/builder/eventlistener.go index 6e37bc5403..c93c8f4897 100644 --- a/test/builder/eventlistener.go +++ b/test/builder/eventlistener.go @@ -321,6 +321,20 @@ func EventListenerCELOverlay(key, expression string) EventInterceptorOp { } } +// EventListenerNamespaceSelectorAny sets the specified selector for the EventListener. +func EventListenerNamespaceSelectorAny() EventListenerSpecOp { + return func(spec *v1alpha1.EventListenerSpec) { + spec.NamespaceSelector.Any = true + } +} + +// EventListenerNamespaceSelectorMatchNames sets the specified selector for the EventListener. +func EventListenerNamespaceSelectorMatchNames(ns []string) EventListenerSpecOp { + return func(spec *v1alpha1.EventListenerSpec) { + spec.NamespaceSelector.MatchNames = ns + } +} + // EventListenerResources set specified resources to the EventListener. func EventListenerResources(ops ...EventListenerResourceOp) EventListenerSpecOp { return func(spec *v1alpha1.EventListenerSpec) { diff --git a/test/builder/eventlistener_test.go b/test/builder/eventlistener_test.go index d3babadca0..3d6e935ba2 100644 --- a/test/builder/eventlistener_test.go +++ b/test/builder/eventlistener_test.go @@ -202,6 +202,50 @@ func TestEventListenerBuilder(t *testing.T) { EventListenerSpec( EventListenerServiceAccount("serviceAccount"), EventListenerTriggerRef("my-trigger"))), + }, { + name: "EventListener with Any NamespaceSelector", + normal: &v1alpha1.EventListener{ + ObjectMeta: metav1.ObjectMeta{ + Name: "name", + Namespace: "namespace", + }, + Spec: v1alpha1.EventListenerSpec{ + ServiceAccountName: "serviceAccount", + Triggers: []v1alpha1.EventListenerTrigger{{ + TriggerRef: "my-trigger", + }}, + NamespaceSelector: v1alpha1.NamespaceSelector{ + Any: true, + }, + }, + }, + builder: EventListener("name", "namespace", + EventListenerSpec( + EventListenerNamespaceSelectorAny(), + EventListenerServiceAccount("serviceAccount"), + EventListenerTriggerRef("my-trigger"))), + }, { + name: "EventListener with Matchnames NamespaceSelector", + normal: &v1alpha1.EventListener{ + ObjectMeta: metav1.ObjectMeta{ + Name: "name", + Namespace: "namespace", + }, + Spec: v1alpha1.EventListenerSpec{ + ServiceAccountName: "serviceAccount", + Triggers: []v1alpha1.EventListenerTrigger{{ + TriggerRef: "my-trigger", + }}, + NamespaceSelector: v1alpha1.NamespaceSelector{ + MatchNames: []string{"foo", "bar"}, + }, + }, + }, + builder: EventListener("name", "namespace", + EventListenerSpec( + EventListenerNamespaceSelectorMatchNames([]string{"foo", "bar"}), + EventListenerServiceAccount("serviceAccount"), + EventListenerTriggerRef("my-trigger"))), }, { name: "One Trigger with one Binding", normal: &v1alpha1.EventListener{