From 349149019876f5486aa5e9fb01ef6d1eb512e070 Mon Sep 17 00:00:00 2001 From: Jawed khelil Date: Mon, 1 Jul 2024 13:23:34 +0200 Subject: [PATCH] Support multinamespace informer filtering --- cmd/controller/main.go | 19 +- docs/config.md | 18 +- pkg/reconciler/filter.go | 80 ++++++++ pkg/reconciler/filter_test.go | 173 ++++++++++++++++++ pkg/reconciler/pipelinerun/controller.go | 131 ++++++------- .../pipelinerun/pipelinerun_test.go | 3 +- pkg/reconciler/taskrun/controller.go | 109 ++++++----- pkg/reconciler/taskrun/taskrun_test.go | 4 +- 8 files changed, 415 insertions(+), 122 deletions(-) create mode 100644 pkg/reconciler/filter.go create mode 100644 pkg/reconciler/filter_test.go diff --git a/cmd/controller/main.go b/cmd/controller/main.go index a95618a1c1..4058d8343c 100644 --- a/cmd/controller/main.go +++ b/cmd/controller/main.go @@ -15,6 +15,7 @@ package main import ( "flag" + "strings" "github.com/tektoncd/chains/pkg/reconciler/pipelinerun" "github.com/tektoncd/chains/pkg/reconciler/taskrun" @@ -24,6 +25,7 @@ import ( "knative.dev/pkg/controller" "knative.dev/pkg/injection" "knative.dev/pkg/injection/sharedmain" + "knative.dev/pkg/logging" "knative.dev/pkg/signals" // Run with all of the upstream providers. @@ -41,11 +43,21 @@ import ( func main() { flag.IntVar(&controller.DefaultThreadsPerController, "threads-per-controller", controller.DefaultThreadsPerController, "Threads (goroutines) to create per controller") - namespace := flag.String("namespace", "", "Namespace to restrict informer to. Optional, defaults to all namespaces.") + namespaceList := flag.String("namespace", "", "Comma-separated list of namespaces to restrict informer to. Optional, if empty defaults to all namespaces.") // This also calls flag.Parse(). cfg := injection.ParseAndGetRESTConfigOrDie() + ctx := signals.NewContext() + logger := logging.FromContext(ctx) + + var namespaces []string + if *namespaceList != "" { + // Remove any whitespace from the namespaces string and split it + namespaces = strings.Split(strings.ReplaceAll(*namespaceList, " ", ""), ",") + logger.Infof("controller is scoped to the following namespaces: %s\n", namespaces) + } + if cfg.QPS == 0 { cfg.QPS = 2 * rest.DefaultQPS } @@ -57,8 +69,5 @@ func main() { cfg.QPS = 2 * cfg.QPS cfg.Burst = 2 * cfg.Burst - flag.Parse() - ctx := injection.WithNamespaceScope(signals.NewContext(), *namespace) - - sharedmain.MainWithConfig(ctx, "watcher", cfg, taskrun.NewController, pipelinerun.NewController) + sharedmain.MainWithConfig(ctx, "watcher", cfg, taskrun.NewNamespacesScopedController(namespaces), pipelinerun.NewNamespacesScopedController(namespaces)) } diff --git a/docs/config.md b/docs/config.md index 5005208961..ba056f3307 100644 --- a/docs/config.md +++ b/docs/config.md @@ -4,9 +4,7 @@ linkTitle: "Chains Configuration" weight: 20 --- --> - # Chains Configuration - `Chains` works by observing `TaskRun` and `PipelineRun` executions, capturing relevant information, and storing it in a cryptographically-signed format. `TaskRuns` and `PipelineRuns` can indicate inputs and outputs which are then captured and surfaced in the `Chains` payload formats, where relevant. @@ -158,4 +156,18 @@ chains.tekton.dev/transparency-upload: "true" > the path specified by `signers.kms.auth.token-dir`. > [!IMPORTANT] -> To project the latest token values without needing to recreate the pod, avoid using `subPath` in volume mount. \ No newline at end of file +> To project the latest token values without needing to recreate the pod, avoid using `subPath` in volume mount. + +## Namespaces Restrictions in Chains Controller +This feature allows you to specify a list of namespaces for the controller to monitor, providing granular control over its operation. If no namespaces are specified, the controller defaults to monitoring all namespaces. + +### Usage +To restrict the Chains Controller to specific namespaces, pass a comma-separated list of namespaces as an argument to the controller using the --namespace flag. The controller will then limit its watch to the specified namespaces, filtering the PipelineRun and TaskRun objects accordingly. + +### Argument Description +--namespace: A comma-separated list of namespaces that the controller should monitor. If this argument is not provided or is left empty, the controller will watch all namespaces by default. + +### Example +To restrict the controller to the dev and test namespaces, you would start the controller with the following argument: +--namespace=dev,test +In this example, the controller will only monitor resources within the dev and test namespaces. diff --git a/pkg/reconciler/filter.go b/pkg/reconciler/filter.go new file mode 100644 index 0000000000..a1863a4670 --- /dev/null +++ b/pkg/reconciler/filter.go @@ -0,0 +1,80 @@ +/* +Copyright 2024 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 reconciler + +import ( + v1 "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1" + "knative.dev/pkg/controller" +) + +// PipelineRunInformerFilterFunc returns a filter function +// for PipelineRuns ensuring PipelineRuns are filtered by list of namespaces membership +func PipelineRunInformerFilterFunc(namespaces []string) func(obj interface{}) bool { + return func(obj interface{}) bool { + // Namespace filter + if len(namespaces) == 0 { + return true + } + if pr, ok := obj.(*v1.PipelineRun); ok { + for _, ns := range namespaces { + if pr.Namespace == ns { + return true + } + } + } + return false + } +} + +// TaskRunInformerFilterFunc returns a filter function +// for TaskRuns ensuring TaskRuns are filtered by list of namespaces membership +func TaskRunInformerFilterFunc(namespaces []string) func(obj interface{}) bool { + return func(obj interface{}) bool { + // Namespace filter + if len(namespaces) == 0 { + return true + } + if tr, ok := obj.(*v1.TaskRun); ok { + for _, ns := range namespaces { + if tr.Namespace == ns { + return true + } + } + } + return false + } +} + +// TaskRunInformerFilterFuncWithOwnership returns a filter function +// for TaskRuns ensuring Ownership by a PipelineRun and filtered by list of namespaces membership and +func TaskRunInformerFilterFuncWithOwnership(namespaces []string) func(obj interface{}) bool { + return func(obj interface{}) bool { + // Ownership filter + if !controller.FilterController(&v1.PipelineRun{})(obj) { + return false + } + // Namespace filter + if len(namespaces) == 0 { + return true + } + if tr, ok := obj.(*v1.TaskRun); ok { + for _, ns := range namespaces { + if tr.Namespace == ns { + return true + } + } + } + return false + } +} diff --git a/pkg/reconciler/filter_test.go b/pkg/reconciler/filter_test.go new file mode 100644 index 0000000000..ed1dcc6e27 --- /dev/null +++ b/pkg/reconciler/filter_test.go @@ -0,0 +1,173 @@ +/* +Copyright 2024 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 reconciler + +import ( + "testing" + + v1 "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// TestPipelineRunInformerFilterFunc tests the PipelineRunInformerFilterFunc +func TestPipelineRunInformerFilterFunc(t *testing.T) { + tests := []struct { + name string + namespaces []string + obj interface{} + expected bool + }{ + { + name: "Empty namespaces, should match", + namespaces: []string{}, + obj: &v1.PipelineRun{ObjectMeta: metav1.ObjectMeta{Namespace: "default"}}, + expected: true, + }, + { + name: "Matching namespace", + namespaces: []string{"default", "test"}, + obj: &v1.PipelineRun{ObjectMeta: metav1.ObjectMeta{Namespace: "default"}}, + expected: true, + }, + { + name: "Non-matching namespace", + namespaces: []string{"test"}, + obj: &v1.PipelineRun{ObjectMeta: metav1.ObjectMeta{Namespace: "default"}}, + expected: false, + }, + { + name: "Non PipelineRun object", + namespaces: []string{"default"}, + obj: &v1.TaskRun{ObjectMeta: metav1.ObjectMeta{Namespace: "default"}}, + expected: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + filterFunc := PipelineRunInformerFilterFunc(tt.namespaces) + result := filterFunc(tt.obj) + if result != tt.expected { + t.Errorf("Reconciler.PipelineRunInformerFilterFunc() result = %v, wanted %v", result, tt.expected) + } + }) + } +} + +// TestTaskRunInformerFilterFunc tests the TaskRunInformerFilterFunc +func TestTaskRunInformerFilterFunc(t *testing.T) { + tests := []struct { + name string + namespaces []string + obj interface{} + expected bool + }{ + { + name: "Matching namespace", + namespaces: []string{"default", "test"}, + obj: &v1.TaskRun{ObjectMeta: metav1.ObjectMeta{Namespace: "default"}}, + expected: true, + }, + { + name: "Empty namespaces, should match", + namespaces: []string{}, + obj: &v1.TaskRun{ObjectMeta: metav1.ObjectMeta{Namespace: "default"}}, + expected: true, + }, + { + name: "Non-matching namespace", + namespaces: []string{"test"}, + obj: &v1.TaskRun{ObjectMeta: metav1.ObjectMeta{Namespace: "default"}}, + expected: false, + }, + { + name: "Non TaskRun object", + namespaces: []string{"default"}, + obj: &v1.PipelineRun{ObjectMeta: metav1.ObjectMeta{Namespace: "default"}}, + expected: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + filterFunc := TaskRunInformerFilterFunc(tt.namespaces) + result := filterFunc(tt.obj) + if result != tt.expected { + t.Errorf("Reconciler.TaskRunInformerFilterFunc() result = %v, wanted %v", result, tt.expected) + } + }) + } +} + +// TestTaskRunInformerFilterFuncWithOwnership tests the TaskRunInformerFilterFuncWithOwnership +func TestTaskRunInformerFilterFuncWithOwnership(t *testing.T) { + boolValue := true + tests := []struct { + name string + namespaces []string + obj interface{} + expected bool + }{ + { + name: "Empty namespaces and ownership, should match", + namespaces: []string{}, + obj: &v1.TaskRun{ObjectMeta: metav1.ObjectMeta{ + Namespace: "default", + OwnerReferences: []metav1.OwnerReference{ + {APIVersion: "tekton.dev/v1", Kind: "PipelineRun", Controller: &boolValue}, + }, + }}, + expected: true, + }, + { + name: "Matching namespace and ownership", + namespaces: []string{"default", "test"}, + obj: &v1.TaskRun{ObjectMeta: metav1.ObjectMeta{ + Namespace: "default", + OwnerReferences: []metav1.OwnerReference{ + {APIVersion: "tekton.dev/v1", Kind: "PipelineRun", Controller: &boolValue}, + }, + }}, + expected: true, + }, + { + name: "Non-matching namespace and ownership", + namespaces: []string{"test"}, + obj: &v1.TaskRun{ObjectMeta: metav1.ObjectMeta{ + Namespace: "default", + OwnerReferences: []metav1.OwnerReference{ + {APIVersion: "tekton.dev/v1", Kind: "PipelineRun", Controller: &boolValue}, + }, + }}, + expected: false, + }, + { + name: "No ownership", + namespaces: []string{"default"}, + obj: &v1.TaskRun{ObjectMeta: metav1.ObjectMeta{Namespace: "default"}}, + expected: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + filterFunc := TaskRunInformerFilterFuncWithOwnership(tt.namespaces) + result := filterFunc(tt.obj) + if result != tt.expected { + t.Errorf("Reconciler.TaskRunInformerFilterFuncWithOwnership() result = %v, wanted %v", result, tt.expected) + } + }) + } +} diff --git a/pkg/reconciler/pipelinerun/controller.go b/pkg/reconciler/pipelinerun/controller.go index 8a7baab9e5..f081d6c87d 100644 --- a/pkg/reconciler/pipelinerun/controller.go +++ b/pkg/reconciler/pipelinerun/controller.go @@ -20,7 +20,7 @@ import ( "github.com/tektoncd/chains/pkg/chains/storage" "github.com/tektoncd/chains/pkg/config" "github.com/tektoncd/chains/pkg/pipelinerunmetrics" - v1 "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1" + "github.com/tektoncd/chains/pkg/reconciler" pipelineclient "github.com/tektoncd/pipeline/pkg/client/injection/client" pipelineruninformer "github.com/tektoncd/pipeline/pkg/client/injection/informers/pipeline/v1/pipelinerun" taskruninformer "github.com/tektoncd/pipeline/pkg/client/injection/informers/pipeline/v1/taskrun" @@ -34,75 +34,82 @@ import ( _ "github.com/tektoncd/chains/pkg/chains/formats/all" ) -func NewController(ctx context.Context, cmw configmap.Watcher) *controller.Impl { - logger := logging.FromContext(ctx) - pipelineRunInformer := pipelineruninformer.Get(ctx) - taskRunInformer := taskruninformer.Get(ctx) - - kubeClient := kubeclient.Get(ctx) - pipelineClient := pipelineclient.Get(ctx) - - psSigner := &chains.ObjectSigner{ - SecretPath: SecretPath, - Pipelineclientset: pipelineClient, - Recorder: pipelinerunmetrics.Get(ctx), - } - - c := &Reconciler{ - PipelineRunSigner: psSigner, - Pipelineclientset: pipelineClient, - TaskRunLister: taskRunInformer.Lister(), - } - - impl := pipelinerunreconciler.NewImpl(ctx, c, func(impl *controller.Impl) controller.Options { - watcherStop := make(chan bool) - - cfgStore := config.NewConfigStore(logger, func(name string, value interface{}) { - select { - case watcherStop <- true: - logger.Info("sent close event to WatchBackends()...") - default: - logger.Info("could not send close event to WatchBackends()...") - } - - // get updated config - cfg := *value.(*config.Config) +// NewNamespacesScopedController returns a new controller implementation where informer is filtered +// given a list of namespaces +func NewNamespacesScopedController(namespaces []string) func(ctx context.Context, cmw configmap.Watcher) *controller.Impl { + return func(ctx context.Context, cmw configmap.Watcher) *controller.Impl { + logger := logging.FromContext(ctx) + pipelineRunInformer := pipelineruninformer.Get(ctx) + taskRunInformer := taskruninformer.Get(ctx) + + kubeClient := kubeclient.Get(ctx) + pipelineClient := pipelineclient.Get(ctx) + + psSigner := &chains.ObjectSigner{ + SecretPath: SecretPath, + Pipelineclientset: pipelineClient, + Recorder: pipelinerunmetrics.Get(ctx), + } - // get all backends for storing provenance - backends, err := storage.InitializeBackends(ctx, pipelineClient, kubeClient, cfg) - if err != nil { - logger.Error(err) - } - psSigner.Backends = backends + c := &Reconciler{ + PipelineRunSigner: psSigner, + Pipelineclientset: pipelineClient, + TaskRunLister: taskRunInformer.Lister(), + } - if err := storage.WatchBackends(ctx, watcherStop, psSigner.Backends, cfg); err != nil { - logger.Error(err) + impl := pipelinerunreconciler.NewImpl(ctx, c, func(_ *controller.Impl) controller.Options { + watcherStop := make(chan bool) + + cfgStore := config.NewConfigStore(logger, func(_ string, value interface{}) { + select { + case watcherStop <- true: + logger.Info("sent close event to WatchBackends()...") + default: + logger.Info("could not send close event to WatchBackends()...") + } + + // get updated config + cfg := *value.(*config.Config) + + // get all backends for storing provenance + backends, err := storage.InitializeBackends(ctx, pipelineClient, kubeClient, cfg) + if err != nil { + logger.Error(err) + } + psSigner.Backends = backends + + if err := storage.WatchBackends(ctx, watcherStop, psSigner.Backends, cfg); err != nil { + logger.Error(err) + } + }) + + // setup watches for the config names provided by client + cfgStore.WatchConfigs(cmw) + + return controller.Options{ + // The chains reconciler shouldn't mutate the pipelinerun's status. + SkipStatusUpdates: true, + ConfigStore: cfgStore, + FinalizerName: "chains.tekton.dev/pipelinerun", // TODO: unique name required? } }) - // setup watches for the config names provided by client - cfgStore.WatchConfigs(cmw) + c.Tracker = impl.Tracker - return controller.Options{ - // The chains reconciler shouldn't mutate the pipelinerun's status. - SkipStatusUpdates: true, - ConfigStore: cfgStore, - FinalizerName: "chains.tekton.dev/pipelinerun", // TODO: unique name required? + if _, err := pipelineRunInformer.Informer().AddEventHandler(cache.FilteringResourceEventHandler{ + FilterFunc: reconciler.PipelineRunInformerFilterFunc(namespaces), + Handler: controller.HandleAll(impl.Enqueue), + }); err != nil { + logger.Errorf("adding event handler for pipelinerun controller's pipelinerun informer encountered error: %v", err) } - }) - c.Tracker = impl.Tracker - - if _, err := pipelineRunInformer.Informer().AddEventHandler(controller.HandleAll(impl.Enqueue)); err != nil { - logger.Errorf("adding event handler for pipelinerun controller's pipelinerun informer encountered error: %w", err) - } + if _, err := taskRunInformer.Informer().AddEventHandler(cache.FilteringResourceEventHandler{ + FilterFunc: reconciler.TaskRunInformerFilterFuncWithOwnership(namespaces), + Handler: controller.HandleAll(impl.EnqueueControllerOf), + }); err != nil { + logger.Errorf("adding event handler for pipelinerun controller's taskrun informer encountered error: %v", err) + } - if _, err := taskRunInformer.Informer().AddEventHandler(cache.FilteringResourceEventHandler{ - FilterFunc: controller.FilterController(&v1.PipelineRun{}), - Handler: controller.HandleAll(impl.EnqueueControllerOf), - }); err != nil { - logger.Errorf("adding event handler for pipelinerun controller's taskrun informer encountered error: %w", err) + return impl } - - return impl } diff --git a/pkg/reconciler/pipelinerun/pipelinerun_test.go b/pkg/reconciler/pipelinerun/pipelinerun_test.go index 2d7cf60a05..6c1d3b01dc 100644 --- a/pkg/reconciler/pipelinerun/pipelinerun_test.go +++ b/pkg/reconciler/pipelinerun/pipelinerun_test.go @@ -78,7 +78,8 @@ func TestReconciler_Reconcile(t *testing.T) { Name: config.ChainsConfig, }, }) - ctl := NewController(ctx, configMapWatcher) + namespacedScopedController := NewNamespacesScopedController(nil) + ctl := namespacedScopedController(ctx, configMapWatcher) if la, ok := ctl.Reconciler.(pkgreconciler.LeaderAware); ok { if err := la.Promote(pkgreconciler.UniversalBucket(), func(pkgreconciler.Bucket, types.NamespacedName) {}); err != nil { diff --git a/pkg/reconciler/taskrun/controller.go b/pkg/reconciler/taskrun/controller.go index 0f6596203f..d6aa481c63 100644 --- a/pkg/reconciler/taskrun/controller.go +++ b/pkg/reconciler/taskrun/controller.go @@ -19,10 +19,12 @@ import ( "github.com/tektoncd/chains/pkg/chains" "github.com/tektoncd/chains/pkg/chains/storage" "github.com/tektoncd/chains/pkg/config" + "github.com/tektoncd/chains/pkg/reconciler" "github.com/tektoncd/chains/pkg/taskrunmetrics" pipelineclient "github.com/tektoncd/pipeline/pkg/client/injection/client" taskruninformer "github.com/tektoncd/pipeline/pkg/client/injection/informers/pipeline/v1/taskrun" taskrunreconciler "github.com/tektoncd/pipeline/pkg/client/injection/reconciler/pipeline/v1/taskrun" + "k8s.io/client-go/tools/cache" kubeclient "knative.dev/pkg/client/injection/kube/client" "knative.dev/pkg/configmap" "knative.dev/pkg/controller" @@ -31,63 +33,70 @@ import ( _ "github.com/tektoncd/chains/pkg/chains/formats/all" ) -func NewController(ctx context.Context, cmw configmap.Watcher) *controller.Impl { - logger := logging.FromContext(ctx) - taskRunInformer := taskruninformer.Get(ctx) +// NewNamespacesScopedController returns a new controller implementation where informer is filtered +// given a list of namespaces +func NewNamespacesScopedController(namespaces []string) func(ctx context.Context, cmw configmap.Watcher) *controller.Impl { + return func(ctx context.Context, cmw configmap.Watcher) *controller.Impl { + logger := logging.FromContext(ctx) + taskRunInformer := taskruninformer.Get(ctx) - kubeClient := kubeclient.Get(ctx) - pipelineClient := pipelineclient.Get(ctx) + kubeClient := kubeclient.Get(ctx) + pipelineClient := pipelineclient.Get(ctx) - tsSigner := &chains.ObjectSigner{ - SecretPath: SecretPath, - Pipelineclientset: pipelineClient, - Recorder: taskrunmetrics.Get(ctx), - } - - c := &Reconciler{ - TaskRunSigner: tsSigner, - Pipelineclientset: pipelineClient, - } - impl := taskrunreconciler.NewImpl(ctx, c, func(impl *controller.Impl) controller.Options { - watcherStop := make(chan bool) - - cfgStore := config.NewConfigStore(logger, func(name string, value interface{}) { - select { - case watcherStop <- true: - logger.Info("sent close event to WatchBackends()...") - default: - logger.Info("could not send close event to WatchBackends()...") - } - - // get updated config - cfg := *value.(*config.Config) - - // get all backends for storing provenance - backends, err := storage.InitializeBackends(ctx, pipelineClient, kubeClient, cfg) - if err != nil { - logger.Error(err) - } - tsSigner.Backends = backends + tsSigner := &chains.ObjectSigner{ + SecretPath: SecretPath, + Pipelineclientset: pipelineClient, + Recorder: taskrunmetrics.Get(ctx), + } - if err := storage.WatchBackends(ctx, watcherStop, tsSigner.Backends, cfg); err != nil { - logger.Error(err) + c := &Reconciler{ + TaskRunSigner: tsSigner, + Pipelineclientset: pipelineClient, + } + impl := taskrunreconciler.NewImpl(ctx, c, func(_ *controller.Impl) controller.Options { + watcherStop := make(chan bool) + + cfgStore := config.NewConfigStore(logger, func(_ string, value interface{}) { + select { + case watcherStop <- true: + logger.Info("sent close event to WatchBackends()...") + default: + logger.Info("could not send close event to WatchBackends()...") + } + + // get updated config + cfg := *value.(*config.Config) + + // get all backends for storing provenance + backends, err := storage.InitializeBackends(ctx, pipelineClient, kubeClient, cfg) + if err != nil { + logger.Error(err) + } + tsSigner.Backends = backends + + if err := storage.WatchBackends(ctx, watcherStop, tsSigner.Backends, cfg); err != nil { + logger.Error(err) + } + }) + + // setup watches for the config names provided by client + cfgStore.WatchConfigs(cmw) + + return controller.Options{ + // The chains reconciler shouldn't mutate the taskrun's status. + SkipStatusUpdates: true, + ConfigStore: cfgStore, + FinalizerName: "chains.tekton.dev", } }) - // setup watches for the config names provided by client - cfgStore.WatchConfigs(cmw) - - return controller.Options{ - // The chains reconciler shouldn't mutate the taskrun's status. - SkipStatusUpdates: true, - ConfigStore: cfgStore, - FinalizerName: "chains.tekton.dev", + if _, err := taskRunInformer.Informer().AddEventHandler(cache.FilteringResourceEventHandler{ + FilterFunc: reconciler.TaskRunInformerFilterFunc(namespaces), + Handler: controller.HandleAll(impl.Enqueue), + }); err != nil { + logger.Errorf("adding event handler for taskrun controller's taskrun informer encountered error: %v", err) } - }) - if _, err := taskRunInformer.Informer().AddEventHandler(controller.HandleAll(impl.Enqueue)); err != nil { - logger.Errorf("adding event handler for taskrun controller's taskrun informer encountered error: %w", err) + return impl } - - return impl } diff --git a/pkg/reconciler/taskrun/taskrun_test.go b/pkg/reconciler/taskrun/taskrun_test.go index 20ba45023f..29c35d6053 100644 --- a/pkg/reconciler/taskrun/taskrun_test.go +++ b/pkg/reconciler/taskrun/taskrun_test.go @@ -75,7 +75,9 @@ func TestReconciler_Reconcile(t *testing.T) { Name: config.ChainsConfig, }, }) - ctl := NewController(ctx, configMapWatcher) + + namespacedScopedController := NewNamespacesScopedController(nil) + ctl := namespacedScopedController(ctx, configMapWatcher) if la, ok := ctl.Reconciler.(pkgreconciler.LeaderAware); ok { if err := la.Promote(pkgreconciler.UniversalBucket(), func(pkgreconciler.Bucket, types.NamespacedName) {}); err != nil {