Skip to content

Commit 9ddd976

Browse files
committed
Option to restrict informer cache to a namespace
A namespace option can be passed from the manager to the cache which restricts the ListWatch for all informers to the desired namespace. This way a manager can be run with a Role instead of a ClusterRole.
1 parent 419794c commit 9ddd976

File tree

4 files changed

+41
-5
lines changed

4 files changed

+41
-5
lines changed

pkg/cache/cache.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,10 @@ type Options struct {
7979

8080
// Resync is the resync period. Defaults to defaultResyncTime.
8181
Resync *time.Duration
82+
83+
// Namespace restricts the cache's ListWatch to the desired namespace
84+
// Default watches all namespaces
85+
Namespace string
8286
}
8387

8488
var defaultResyncTime = 10 * time.Hour
@@ -89,7 +93,7 @@ func New(config *rest.Config, opts Options) (Cache, error) {
8993
if err != nil {
9094
return nil, err
9195
}
92-
im := internal.NewInformersMap(config, opts.Scheme, opts.Mapper, *opts.Resync)
96+
im := internal.NewInformersMap(config, opts.Scheme, opts.Mapper, *opts.Resync, opts.Namespace)
9397
return &informerCache{InformersMap: im}, nil
9498
}
9599

pkg/cache/cache_test.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,28 @@ var _ = Describe("Informer Cache", func() {
188188
Expect(actual.Namespace).To(Equal(testNamespaceOne))
189189
})
190190

191+
It("should be able to restrict cache to a namespace", func() {
192+
By("creating a namespaced cache")
193+
namespacedCache, err := cache.New(cfg, cache.Options{Namespace: testNamespaceOne})
194+
Expect(err).NotTo(HaveOccurred())
195+
196+
By("running the cache and waiting for it to sync")
197+
go func() {
198+
defer GinkgoRecover()
199+
Expect(namespacedCache.Start(stop)).To(Succeed())
200+
}()
201+
Expect(namespacedCache.WaitForCacheSync(stop)).NotTo(BeFalse())
202+
203+
By("listing pods in all namespaces")
204+
out := kcorev1.PodList{}
205+
Expect(namespacedCache.List(context.Background(), nil, &out)).To(Succeed())
206+
207+
By("verifying the returned pod is from the watched namespace")
208+
Expect(out.Items).NotTo(BeEmpty())
209+
Expect(out.Items).Should(HaveLen(1))
210+
Expect(out.Items[0].Namespace).To(Equal(testNamespaceOne))
211+
})
212+
191213
It("should deep copy the object unless told otherwise", func() {
192214
By("retrieving a specific pod from the cache")
193215
out := &kcorev1.Pod{}

pkg/cache/internal/informers_map.go

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,8 @@ import (
3636
func NewInformersMap(config *rest.Config,
3737
scheme *runtime.Scheme,
3838
mapper meta.RESTMapper,
39-
resync time.Duration) *InformersMap {
39+
resync time.Duration,
40+
namespace string) *InformersMap {
4041
ip := &InformersMap{
4142
config: config,
4243
Scheme: scheme,
@@ -45,6 +46,7 @@ func NewInformersMap(config *rest.Config,
4546
codecs: serializer.NewCodecFactory(scheme),
4647
paramCodec: runtime.NewParameterCodec(scheme),
4748
resync: resync,
49+
namespace: namespace,
4850
}
4951
return ip
5052
}
@@ -90,6 +92,10 @@ type InformersMap struct {
9092

9193
// start is true if the informers have been started
9294
started bool
95+
96+
// namespace is the namespace that all ListWatches are restricted to
97+
// default means all namespaces
98+
namespace string
9399
}
94100

95101
// Start calls Run on each of the informers and sets started to true. Blocks on the stop channel.
@@ -217,14 +223,14 @@ func (ip *InformersMap) newListWatch(gvk schema.GroupVersionKind) (*cache.ListWa
217223
return &cache.ListWatch{
218224
ListFunc: func(opts metav1.ListOptions) (runtime.Object, error) {
219225
res := listObj.DeepCopyObject()
220-
err := client.Get().Resource(mapping.Resource.Resource).VersionedParams(&opts, ip.paramCodec).Do().Into(res)
226+
err := client.Get().NamespaceIfScoped(ip.namespace, ip.namespace != "").Resource(mapping.Resource.Resource).VersionedParams(&opts, ip.paramCodec).Do().Into(res)
221227
return res, err
222228
},
223229
// Setup the watch function
224230
WatchFunc: func(opts metav1.ListOptions) (watch.Interface, error) {
225231
// Watch needs to be set to true separately
226232
opts.Watch = true
227-
return client.Get().Resource(mapping.Resource.Resource).VersionedParams(&opts, ip.paramCodec).Watch()
233+
return client.Get().NamespaceIfScoped(ip.namespace, ip.namespace != "").Resource(mapping.Resource.Resource).VersionedParams(&opts, ip.paramCodec).Watch()
228234
},
229235
}, nil
230236
}

pkg/manager/manager.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,10 @@ type Options struct {
9797
// will use for holding the leader lock.
9898
LeaderElectionID string
9999

100+
// Namespace if specified restricts the manager's cache to watch the desired namespace
101+
// Defaults to all namespaces
102+
Namespace string
103+
100104
// Dependency injection for testing
101105
newCache func(config *rest.Config, opts cache.Options) (cache.Cache, error)
102106
newClient func(config *rest.Config, options client.Options) (client.Client, error)
@@ -143,7 +147,7 @@ func New(config *rest.Config, options Options) (Manager, error) {
143147
}
144148

145149
// Create the cache for the cached read client and registering informers
146-
cache, err := options.newCache(config, cache.Options{Scheme: options.Scheme, Mapper: mapper, Resync: options.SyncPeriod})
150+
cache, err := options.newCache(config, cache.Options{Scheme: options.Scheme, Mapper: mapper, Resync: options.SyncPeriod, Namespace: options.Namespace})
147151
if err != nil {
148152
return nil, err
149153
}

0 commit comments

Comments
 (0)