Skip to content

Commit 2c0bd8f

Browse files
committed
feat: ignore namespace key when getting cluster-scoped resources
1 parent fe4a67a commit 2c0bd8f

File tree

3 files changed

+78
-15
lines changed

3 files changed

+78
-15
lines changed

pkg/cache/cache_test.go

Lines changed: 66 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ import (
3535
"sigs.k8s.io/controller-runtime/pkg/client"
3636
)
3737

38+
const testNodeOne = "test-node-1"
3839
const testNamespaceOne = "test-namespace-1"
3940
const testNamespaceTwo = "test-namespace-2"
4041
const testNamespaceThree = "test-namespace-3"
@@ -98,6 +99,8 @@ func CacheTest(createCacheFunc func(config *rest.Config, opts cache.Options) (ca
9899
By("creating three pods")
99100
cl, err := client.New(cfg, client.Options{})
100101
Expect(err).NotTo(HaveOccurred())
102+
err = ensureNode(testNodeOne, cl)
103+
Expect(err).NotTo(HaveOccurred())
101104
err = ensureNamespace(testNamespaceOne, cl)
102105
Expect(err).NotTo(HaveOccurred())
103106
err = ensureNamespace(testNamespaceTwo, cl)
@@ -413,17 +416,33 @@ func CacheTest(createCacheFunc func(config *rest.Config, opts cache.Options) (ca
413416
Expect(out.Items).Should(HaveLen(1))
414417
Expect(out.Items[0].GetNamespace()).To(Equal(testNamespaceOne))
415418

416-
By("listing all namespaces - should still be able to get a cluster-scoped resource")
417-
namespaceList := &unstructured.UnstructuredList{}
418-
namespaceList.SetGroupVersionKind(schema.GroupVersionKind{
419+
By("listing all nodes - should still be able to list a cluster-scoped resource")
420+
nodeList := &unstructured.UnstructuredList{}
421+
nodeList.SetGroupVersionKind(schema.GroupVersionKind{
419422
Group: "",
420423
Version: "v1",
421-
Kind: "NamespaceList",
424+
Kind: "NodeList",
422425
})
423-
Expect(namespacedCache.List(context.Background(), namespaceList)).To(Succeed())
426+
Expect(namespacedCache.List(context.Background(), nodeList)).To(Succeed())
427+
428+
By("verifying the node list is not empty")
429+
Expect(nodeList.Items).NotTo(BeEmpty())
430+
431+
By("getting a node - should still be able to get a cluster-scoped resource")
432+
node := &unstructured.Unstructured{}
433+
node.SetGroupVersionKind(schema.GroupVersionKind{
434+
Group: "",
435+
Version: "v1",
436+
Kind: "Node",
437+
})
438+
439+
By("verifying that getting the node works with an empty namespace")
440+
key1 := client.ObjectKey{Namespace: "", Name: testNodeOne}
441+
Expect(namespacedCache.Get(context.Background(), key1, node)).To(Succeed())
424442

425-
By("verifying the namespace list is not empty")
426-
Expect(namespaceList.Items).NotTo(BeEmpty())
443+
By("verifying that the namespace is ignored when getting a cluster-scoped resource")
444+
key2 := client.ObjectKey{Namespace: "random", Name: testNodeOne}
445+
Expect(namespacedCache.Get(context.Background(), key2, node)).To(Succeed())
427446
})
428447

429448
It("should deep copy the object unless told otherwise", func() {
@@ -607,17 +626,33 @@ func CacheTest(createCacheFunc func(config *rest.Config, opts cache.Options) (ca
607626
Expect(out.Items).Should(HaveLen(1))
608627
Expect(out.Items[0].GetNamespace()).To(Equal(testNamespaceOne))
609628

610-
By("listing all namespaces - should still be able to get a cluster-scoped resource")
611-
namespaceList := &kmetav1.PartialObjectMetadataList{}
612-
namespaceList.SetGroupVersionKind(schema.GroupVersionKind{
629+
By("listing all nodes - should still be able to list a cluster-scoped resource")
630+
nodeList := &kmetav1.PartialObjectMetadataList{}
631+
nodeList.SetGroupVersionKind(schema.GroupVersionKind{
613632
Group: "",
614633
Version: "v1",
615-
Kind: "NamespaceList",
634+
Kind: "NodeList",
616635
})
617-
Expect(namespacedCache.List(context.Background(), namespaceList)).To(Succeed())
636+
Expect(namespacedCache.List(context.Background(), nodeList)).To(Succeed())
637+
638+
By("verifying the node list is not empty")
639+
Expect(nodeList.Items).NotTo(BeEmpty())
640+
641+
By("getting a node - should still be able to get a cluster-scoped resource")
642+
node := &kmetav1.PartialObjectMetadata{}
643+
node.SetGroupVersionKind(schema.GroupVersionKind{
644+
Group: "",
645+
Version: "v1",
646+
Kind: "Node",
647+
})
648+
649+
By("verifying that getting the node works with an empty namespace")
650+
key1 := client.ObjectKey{Namespace: "", Name: testNodeOne}
651+
Expect(namespacedCache.Get(context.Background(), key1, node)).To(Succeed())
618652

619-
By("verifying the namespace list is not empty")
620-
Expect(namespaceList.Items).NotTo(BeEmpty())
653+
By("verifying that the namespace is ignored when getting a cluster-scoped resource")
654+
key2 := client.ObjectKey{Namespace: "random", Name: testNodeOne}
655+
Expect(namespacedCache.Get(context.Background(), key2, node)).To(Succeed())
621656
})
622657

623658
It("should deep copy the object unless told otherwise", func() {
@@ -1079,6 +1114,23 @@ func ensureNamespace(namespace string, client client.Client) error {
10791114
return err
10801115
}
10811116

1117+
func ensureNode(name string, client client.Client) error {
1118+
node := kcorev1.Node{
1119+
ObjectMeta: kmetav1.ObjectMeta{
1120+
Name: name,
1121+
},
1122+
TypeMeta: kmetav1.TypeMeta{
1123+
Kind: "Node",
1124+
APIVersion: "v1",
1125+
},
1126+
}
1127+
err := client.Create(context.TODO(), &node)
1128+
if errors.IsAlreadyExists(err) {
1129+
return nil
1130+
}
1131+
return err
1132+
}
1133+
10821134
//nolint:interfacer
10831135
func isKubeService(svc kmetav1.Object) bool {
10841136
// grumble grumble linters grumble grumble

pkg/cache/internal/cache_reader.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import (
2929
"k8s.io/apimachinery/pkg/runtime/schema"
3030
"k8s.io/apimachinery/pkg/selection"
3131
"k8s.io/client-go/tools/cache"
32+
3233
"sigs.k8s.io/controller-runtime/pkg/client"
3334
)
3435

@@ -42,10 +43,16 @@ type CacheReader struct {
4243

4344
// groupVersionKind is the group-version-kind of the resource.
4445
groupVersionKind schema.GroupVersionKind
46+
47+
// scopeName is the scope of the resource (namespaced or cluster-scoped).
48+
scopeName apimeta.RESTScopeName
4549
}
4650

4751
// Get checks the indexer for the object and writes a copy of it if found
4852
func (c *CacheReader) Get(_ context.Context, key client.ObjectKey, out client.Object) error {
53+
if c.scopeName == apimeta.RESTScopeNameRoot {
54+
key.Namespace = ""
55+
}
4956
storeKey := objectKeyToStoreKey(key)
5057

5158
// Lookup the object from the indexer cache

pkg/cache/internal/informers_map.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -212,9 +212,13 @@ func (ip *specificInformersMap) addInformerToMap(gvk schema.GroupVersionKind, ob
212212
ni := cache.NewSharedIndexInformer(lw, obj, resyncPeriod(ip.resync)(), cache.Indexers{
213213
cache.NamespaceIndex: cache.MetaNamespaceIndexFunc,
214214
})
215+
rm, err := ip.mapper.RESTMapping(gvk.GroupKind(), gvk.Version)
216+
if err != nil {
217+
return nil, false, err
218+
}
215219
i := &MapEntry{
216220
Informer: ni,
217-
Reader: CacheReader{indexer: ni.GetIndexer(), groupVersionKind: gvk},
221+
Reader: CacheReader{indexer: ni.GetIndexer(), groupVersionKind: gvk, scopeName: rm.Scope.Name()},
218222
}
219223
ip.informersByGVK[gvk] = i
220224

0 commit comments

Comments
 (0)