Skip to content

Commit 8b79878

Browse files
authored
Merge pull request #1602 from shlomitk1/namespace-restriction-from-selector
✨Restrict namespace for list/watch based on field selectors
2 parents 865d56a + 568672a commit 8b79878

File tree

1 file changed

+38
-12
lines changed

1 file changed

+38
-12
lines changed

pkg/cache/internal/informers_map.go

Lines changed: 38 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -274,17 +274,19 @@ func createStructuredListWatch(gvk schema.GroupVersionKind, ip *specificInformer
274274
ListFunc: func(opts metav1.ListOptions) (runtime.Object, error) {
275275
ip.selectors[gvk].ApplyToList(&opts)
276276
res := listObj.DeepCopyObject()
277-
isNamespaceScoped := ip.namespace != "" && mapping.Scope.Name() != meta.RESTScopeNameRoot
278-
err := client.Get().NamespaceIfScoped(ip.namespace, isNamespaceScoped).Resource(mapping.Resource.Resource).VersionedParams(&opts, ip.paramCodec).Do(ctx).Into(res)
277+
namespace := restrictNamespaceBySelector(ip.namespace, ip.selectors[gvk])
278+
isNamespaceScoped := namespace != "" && mapping.Scope.Name() != meta.RESTScopeNameRoot
279+
err := client.Get().NamespaceIfScoped(namespace, isNamespaceScoped).Resource(mapping.Resource.Resource).VersionedParams(&opts, ip.paramCodec).Do(ctx).Into(res)
279280
return res, err
280281
},
281282
// Setup the watch function
282283
WatchFunc: func(opts metav1.ListOptions) (watch.Interface, error) {
283284
ip.selectors[gvk].ApplyToList(&opts)
284285
// Watch needs to be set to true separately
285286
opts.Watch = true
286-
isNamespaceScoped := ip.namespace != "" && mapping.Scope.Name() != meta.RESTScopeNameRoot
287-
return client.Get().NamespaceIfScoped(ip.namespace, isNamespaceScoped).Resource(mapping.Resource.Resource).VersionedParams(&opts, ip.paramCodec).Watch(ctx)
287+
namespace := restrictNamespaceBySelector(ip.namespace, ip.selectors[gvk])
288+
isNamespaceScoped := namespace != "" && mapping.Scope.Name() != meta.RESTScopeNameRoot
289+
return client.Get().NamespaceIfScoped(namespace, isNamespaceScoped).Resource(mapping.Resource.Resource).VersionedParams(&opts, ip.paramCodec).Watch(ctx)
288290
},
289291
}, nil
290292
}
@@ -313,8 +315,9 @@ func createUnstructuredListWatch(gvk schema.GroupVersionKind, ip *specificInform
313315
return &cache.ListWatch{
314316
ListFunc: func(opts metav1.ListOptions) (runtime.Object, error) {
315317
ip.selectors[gvk].ApplyToList(&opts)
316-
if ip.namespace != "" && mapping.Scope.Name() != meta.RESTScopeNameRoot {
317-
return dynamicClient.Resource(mapping.Resource).Namespace(ip.namespace).List(ctx, opts)
318+
namespace := restrictNamespaceBySelector(ip.namespace, ip.selectors[gvk])
319+
if namespace != "" && mapping.Scope.Name() != meta.RESTScopeNameRoot {
320+
return dynamicClient.Resource(mapping.Resource).Namespace(namespace).List(ctx, opts)
318321
}
319322
return dynamicClient.Resource(mapping.Resource).List(ctx, opts)
320323
},
@@ -323,8 +326,9 @@ func createUnstructuredListWatch(gvk schema.GroupVersionKind, ip *specificInform
323326
ip.selectors[gvk].ApplyToList(&opts)
324327
// Watch needs to be set to true separately
325328
opts.Watch = true
326-
if ip.namespace != "" && mapping.Scope.Name() != meta.RESTScopeNameRoot {
327-
return dynamicClient.Resource(mapping.Resource).Namespace(ip.namespace).Watch(ctx, opts)
329+
namespace := restrictNamespaceBySelector(ip.namespace, ip.selectors[gvk])
330+
if namespace != "" && mapping.Scope.Name() != meta.RESTScopeNameRoot {
331+
return dynamicClient.Resource(mapping.Resource).Namespace(namespace).Watch(ctx, opts)
328332
}
329333
return dynamicClient.Resource(mapping.Resource).Watch(ctx, opts)
330334
},
@@ -358,8 +362,9 @@ func createMetadataListWatch(gvk schema.GroupVersionKind, ip *specificInformersM
358362
return &cache.ListWatch{
359363
ListFunc: func(opts metav1.ListOptions) (runtime.Object, error) {
360364
ip.selectors[gvk].ApplyToList(&opts)
361-
if ip.namespace != "" && mapping.Scope.Name() != meta.RESTScopeNameRoot {
362-
return client.Resource(mapping.Resource).Namespace(ip.namespace).List(ctx, opts)
365+
namespace := restrictNamespaceBySelector(ip.namespace, ip.selectors[gvk])
366+
if namespace != "" && mapping.Scope.Name() != meta.RESTScopeNameRoot {
367+
return client.Resource(mapping.Resource).Namespace(namespace).List(ctx, opts)
363368
}
364369
return client.Resource(mapping.Resource).List(ctx, opts)
365370
},
@@ -368,8 +373,9 @@ func createMetadataListWatch(gvk schema.GroupVersionKind, ip *specificInformersM
368373
ip.selectors[gvk].ApplyToList(&opts)
369374
// Watch needs to be set to true separately
370375
opts.Watch = true
371-
if ip.namespace != "" && mapping.Scope.Name() != meta.RESTScopeNameRoot {
372-
return client.Resource(mapping.Resource).Namespace(ip.namespace).Watch(ctx, opts)
376+
namespace := restrictNamespaceBySelector(ip.namespace, ip.selectors[gvk])
377+
if namespace != "" && mapping.Scope.Name() != meta.RESTScopeNameRoot {
378+
return client.Resource(mapping.Resource).Namespace(namespace).Watch(ctx, opts)
373379
}
374380
return client.Resource(mapping.Resource).Watch(ctx, opts)
375381
},
@@ -386,3 +392,23 @@ func resyncPeriod(resync time.Duration) func() time.Duration {
386392
return time.Duration(float64(resync.Nanoseconds()) * factor)
387393
}
388394
}
395+
396+
// restrictNamespaceBySelector returns either a global restriction for all ListWatches
397+
// if not default/empty, or the namespace that a ListWatch for the specific resource
398+
// is restricted to, based on a specified field selector for metadata.namespace field.
399+
func restrictNamespaceBySelector(namespaceOpt string, s Selector) string {
400+
if namespaceOpt != "" {
401+
// namespace is already restricted
402+
return namespaceOpt
403+
}
404+
fieldSelector := s.Field
405+
if fieldSelector == nil || fieldSelector.Empty() {
406+
return ""
407+
}
408+
// check whether a selector includes the namespace field
409+
value, found := fieldSelector.RequiresExactMatch("metadata.namespace")
410+
if found {
411+
return value
412+
}
413+
return ""
414+
}

0 commit comments

Comments
 (0)