From 3bc4a0edf166eb1c8842d00dc70ddcfdde6d2bec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20W=C3=B6hrl?= Date: Wed, 17 Apr 2024 09:59:17 +0200 Subject: [PATCH] fix: grand children --- pkg/cache/cluster.go | 24 +++++++++++------- pkg/cache/cluster_test.go | 52 ++++++++++++++++++++++++++++++++++++--- 2 files changed, 64 insertions(+), 12 deletions(-) diff --git a/pkg/cache/cluster.go b/pkg/cache/cluster.go index ea64a9af7..98b617991 100644 --- a/pkg/cache/cluster.go +++ b/pkg/cache/cluster.go @@ -976,6 +976,20 @@ func (c *clusterCache) FindResources(namespace string, predicates ...func(r *Res return result } +func (c *clusterCache) addChildResourcesRecursivly(nsNodes map[kube.ResourceKey]*Resource, key kube.ResourceKey) map[kube.ResourceKey]*Resource { + nsNodeReturned := nsNodes + childRefs := c.childrenByParent[key] + childResources := map[kube.ResourceKey]*Resource{} + for _, childRef := range childRefs { + if c.resources[childRef] != nil { + childResources[childRef] = c.resources[childRef] + nsNodeReturned = c.addChildResourcesRecursivly(nsNodeReturned, childRef) + } + } + // Merge the maps into a different copy to avoid updating the original nsIndex map + return mergeResourceMaps(nsNodeReturned, childResources) +} + // IterateHierarchy iterates resource tree starting from the specified top level resource and executes callback for each resource in the tree func (c *clusterCache) IterateHierarchy(key kube.ResourceKey, action func(resource *Resource, namespaceResources map[kube.ResourceKey]*Resource) bool) { c.lock.RLock() @@ -983,15 +997,7 @@ func (c *clusterCache) IterateHierarchy(key kube.ResourceKey, action func(resour if res, ok := c.resources[key]; ok { nsNodes := c.nsIndex[key.Namespace] if key.Namespace == "" && c.showClusterResourceChildren { - childRefs := c.childrenByParent[key] - childResources := map[kube.ResourceKey]*Resource{} - for _, childRef := range childRefs { - if c.resources[childRef] != nil { - childResources[childRef] = c.resources[childRef] - } - } - // Merge the maps into a different copy to avoid updating the original nsIndex map - nsNodes = mergeResourceMaps(nsNodes, childResources) + nsNodes = c.addChildResourcesRecursivly(nsNodes, key) } if !action(res, nsNodes) { return diff --git a/pkg/cache/cluster_test.go b/pkg/cache/cluster_test.go index 30e30619c..6164f7636 100644 --- a/pkg/cache/cluster_test.go +++ b/pkg/cache/cluster_test.go @@ -283,7 +283,7 @@ func TestEnsureSyncedSingleNamespace(t *testing.T) { } func TestGetChildren(t *testing.T) { - cluster := newCluster(t, testPod(), testRS(), testDeploy(), testClusterRole(), testSA()) + cluster := newCluster(t, testPod(), testRS(), testDeploy(), testClusterRole(), testSA(), testSADeployment()) err := cluster.EnsureSynced() require.NoError(t, err) cluster.showClusterResourceChildren = true @@ -327,13 +327,35 @@ func TestGetChildren(t *testing.T) { unstructuredClusterRole := mustToUnstructured(testClusterRole()) unstructuredSA := mustToUnstructured(testSA()) + unstructuredSADeployment := mustToUnstructured(testSADeployment()) cluster.childrenByParent = map[kube.ResourceKey][]kube.ResourceKey{ kube.GetResourceKey(unstructuredClusterRole): { kube.GetResourceKey(unstructuredSA), }, + kube.GetResourceKey(unstructuredSA): { + kube.GetResourceKey(unstructuredSADeployment), + }, } - crChildren := getChildren(cluster, mustToUnstructured(testClusterRole())) + + saChildren := getChildren(cluster, mustToUnstructured(testSA())) assert.Equal(t, []*Resource{{ + Ref: corev1.ObjectReference{ + Kind: "Deployment", + Namespace: "default", + Name: "helm-guestbook-sa", + APIVersion: "apps/v1", + UID: "6", + }, + ResourceVersion: "234", + OwnerRefs: []metav1.OwnerReference{{APIVersion: "v1", Kind: "ServiceAccount", Name: "helm-guestbook-sa", UID: "4"}}, + CreationTimestamp: &metav1.Time{ + Time: testCreationTime.Local(), + }, + }}, saChildren) + + + crChildren := getChildren(cluster, mustToUnstructured(testClusterRole())) + assert.Equal(t, append([]*Resource{{ Ref: corev1.ObjectReference{ Kind: "ServiceAccount", Namespace: "default", @@ -346,7 +368,7 @@ func TestGetChildren(t *testing.T) { CreationTimestamp: &metav1.Time{ Time: testCreationTime.Local(), }, - }}, crChildren) + }}, saChildren...), crChildren) } func TestUpdateChildrenByParentMap(t *testing.T) { @@ -1250,6 +1272,30 @@ func TestMergeResourceMaps(t *testing.T) { assert.Equal(t, expectedVal, mapA[testKey]) } +func testSADeployment() *appsv1.Deployment { + return &appsv1.Deployment{ + TypeMeta: metav1.TypeMeta{ + APIVersion: "apps/v1", + Kind: "Deployment", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "helm-guestbook-sa", + Namespace: "default", + UID: "6", + ResourceVersion: "234", + CreationTimestamp: metav1.NewTime(testCreationTime), + OwnerReferences: []metav1.OwnerReference{ + { + APIVersion: "v1", + UID: "4", + Kind: "ServiceAccount", + Name: "helm-guestbook-sa", + }, + }, + }, + } +} + func testSA() *corev1.ServiceAccount { return &corev1.ServiceAccount{ TypeMeta: metav1.TypeMeta{