From 568672ac0ec61d8f1498fb6f996e5edda55c42af Mon Sep 17 00:00:00 2001 From: "SHLOMITK@il.ibm.com" Date: Wed, 21 Jul 2021 14:27:54 +0300 Subject: [PATCH] obtain namespace for list/watch from field selectors Signed-off-by: SHLOMITK@il.ibm.com --- pkg/cache/internal/informers_map.go | 50 ++++++++++++++++++++++------- 1 file changed, 38 insertions(+), 12 deletions(-) diff --git a/pkg/cache/internal/informers_map.go b/pkg/cache/internal/informers_map.go index bef54d302e..007a28e727 100644 --- a/pkg/cache/internal/informers_map.go +++ b/pkg/cache/internal/informers_map.go @@ -274,8 +274,9 @@ func createStructuredListWatch(gvk schema.GroupVersionKind, ip *specificInformer ListFunc: func(opts metav1.ListOptions) (runtime.Object, error) { ip.selectors[gvk].ApplyToList(&opts) res := listObj.DeepCopyObject() - isNamespaceScoped := ip.namespace != "" && mapping.Scope.Name() != meta.RESTScopeNameRoot - err := client.Get().NamespaceIfScoped(ip.namespace, isNamespaceScoped).Resource(mapping.Resource.Resource).VersionedParams(&opts, ip.paramCodec).Do(ctx).Into(res) + namespace := restrictNamespaceBySelector(ip.namespace, ip.selectors[gvk]) + isNamespaceScoped := namespace != "" && mapping.Scope.Name() != meta.RESTScopeNameRoot + err := client.Get().NamespaceIfScoped(namespace, isNamespaceScoped).Resource(mapping.Resource.Resource).VersionedParams(&opts, ip.paramCodec).Do(ctx).Into(res) return res, err }, // Setup the watch function @@ -283,8 +284,9 @@ func createStructuredListWatch(gvk schema.GroupVersionKind, ip *specificInformer ip.selectors[gvk].ApplyToList(&opts) // Watch needs to be set to true separately opts.Watch = true - isNamespaceScoped := ip.namespace != "" && mapping.Scope.Name() != meta.RESTScopeNameRoot - return client.Get().NamespaceIfScoped(ip.namespace, isNamespaceScoped).Resource(mapping.Resource.Resource).VersionedParams(&opts, ip.paramCodec).Watch(ctx) + namespace := restrictNamespaceBySelector(ip.namespace, ip.selectors[gvk]) + isNamespaceScoped := namespace != "" && mapping.Scope.Name() != meta.RESTScopeNameRoot + return client.Get().NamespaceIfScoped(namespace, isNamespaceScoped).Resource(mapping.Resource.Resource).VersionedParams(&opts, ip.paramCodec).Watch(ctx) }, }, nil } @@ -313,8 +315,9 @@ func createUnstructuredListWatch(gvk schema.GroupVersionKind, ip *specificInform return &cache.ListWatch{ ListFunc: func(opts metav1.ListOptions) (runtime.Object, error) { ip.selectors[gvk].ApplyToList(&opts) - if ip.namespace != "" && mapping.Scope.Name() != meta.RESTScopeNameRoot { - return dynamicClient.Resource(mapping.Resource).Namespace(ip.namespace).List(ctx, opts) + namespace := restrictNamespaceBySelector(ip.namespace, ip.selectors[gvk]) + if namespace != "" && mapping.Scope.Name() != meta.RESTScopeNameRoot { + return dynamicClient.Resource(mapping.Resource).Namespace(namespace).List(ctx, opts) } return dynamicClient.Resource(mapping.Resource).List(ctx, opts) }, @@ -323,8 +326,9 @@ func createUnstructuredListWatch(gvk schema.GroupVersionKind, ip *specificInform ip.selectors[gvk].ApplyToList(&opts) // Watch needs to be set to true separately opts.Watch = true - if ip.namespace != "" && mapping.Scope.Name() != meta.RESTScopeNameRoot { - return dynamicClient.Resource(mapping.Resource).Namespace(ip.namespace).Watch(ctx, opts) + namespace := restrictNamespaceBySelector(ip.namespace, ip.selectors[gvk]) + if namespace != "" && mapping.Scope.Name() != meta.RESTScopeNameRoot { + return dynamicClient.Resource(mapping.Resource).Namespace(namespace).Watch(ctx, opts) } return dynamicClient.Resource(mapping.Resource).Watch(ctx, opts) }, @@ -358,8 +362,9 @@ func createMetadataListWatch(gvk schema.GroupVersionKind, ip *specificInformersM return &cache.ListWatch{ ListFunc: func(opts metav1.ListOptions) (runtime.Object, error) { ip.selectors[gvk].ApplyToList(&opts) - if ip.namespace != "" && mapping.Scope.Name() != meta.RESTScopeNameRoot { - return client.Resource(mapping.Resource).Namespace(ip.namespace).List(ctx, opts) + namespace := restrictNamespaceBySelector(ip.namespace, ip.selectors[gvk]) + if namespace != "" && mapping.Scope.Name() != meta.RESTScopeNameRoot { + return client.Resource(mapping.Resource).Namespace(namespace).List(ctx, opts) } return client.Resource(mapping.Resource).List(ctx, opts) }, @@ -368,8 +373,9 @@ func createMetadataListWatch(gvk schema.GroupVersionKind, ip *specificInformersM ip.selectors[gvk].ApplyToList(&opts) // Watch needs to be set to true separately opts.Watch = true - if ip.namespace != "" && mapping.Scope.Name() != meta.RESTScopeNameRoot { - return client.Resource(mapping.Resource).Namespace(ip.namespace).Watch(ctx, opts) + namespace := restrictNamespaceBySelector(ip.namespace, ip.selectors[gvk]) + if namespace != "" && mapping.Scope.Name() != meta.RESTScopeNameRoot { + return client.Resource(mapping.Resource).Namespace(namespace).Watch(ctx, opts) } return client.Resource(mapping.Resource).Watch(ctx, opts) }, @@ -386,3 +392,23 @@ func resyncPeriod(resync time.Duration) func() time.Duration { return time.Duration(float64(resync.Nanoseconds()) * factor) } } + +// restrictNamespaceBySelector returns either a global restriction for all ListWatches +// if not default/empty, or the namespace that a ListWatch for the specific resource +// is restricted to, based on a specified field selector for metadata.namespace field. +func restrictNamespaceBySelector(namespaceOpt string, s Selector) string { + if namespaceOpt != "" { + // namespace is already restricted + return namespaceOpt + } + fieldSelector := s.Field + if fieldSelector == nil || fieldSelector.Empty() { + return "" + } + // check whether a selector includes the namespace field + value, found := fieldSelector.RequiresExactMatch("metadata.namespace") + if found { + return value + } + return "" +}