Skip to content

Commit

Permalink
Add edge for resources generated by Kyverno (#349)
Browse files Browse the repository at this point in the history
Ref: https://issues.redhat.com/browse/ACM-15958

Signed-off-by: yiraeChristineKim <[email protected]>
  • Loading branch information
yiraeChristineKim authored Dec 20, 2024
1 parent b03c044 commit 68f2bab
Show file tree
Hide file tree
Showing 2 changed files with 159 additions and 3 deletions.
53 changes: 50 additions & 3 deletions pkg/transforms/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,53 @@ func CommonEdges(uid string, ns NodeStore) []Edge {

// deployer subscriber edges
ret = append(ret, edgesByDeployerSubscriber(nodeInfo, ns)...)

ret = edgesByKyverno(ret, currNode, ns)

return ret
}

// Function to create an edge linking any resource with a Kyverno Policy or ClusterPolicy that generates the resource.
func edgesByKyverno(ret []Edge, currNode Node, ns NodeStore) []Edge {
labels, ok := currNode.Properties["label"].(map[string]string)
if !ok {
return ret
}

if labels["app.kubernetes.io/managed-by"] != "kyverno" || labels["generate.kyverno.io/policy-name"] == "" {
return ret
}

// For resources created by kyverno
policyNamespace := labels["generate.kyverno.io/policy-namespace"]
policyName := labels["generate.kyverno.io/policy-name"]
// Kyverno Policy
policyKind := "Policy"

if policyNamespace == "" {
// Kyverno ClusterPolicy
policyKind = "ClusterPolicy"
policyNamespace = "_NONE"
}

policyNode, ok := ns.ByKindNamespaceName[policyKind][policyNamespace][policyName]
if !ok {
return ret
}

// Prevent from policy.policy.open-cluster-management.io
if policyNode.Properties["apigroup"] != "kyverno.io" {
return ret
}

ret = append(ret, Edge{
SourceKind: currNode.Properties["kind"].(string),
SourceUID: currNode.UID,
EdgeType: "generatedBy",
DestUID: policyNode.UID,
DestKind: policyNode.Properties["kind"].(string),
})

return ret
}

Expand Down Expand Up @@ -237,7 +284,8 @@ func edgesByDestinationName(
destKind string,
nodeInfo NodeInfo,
ns NodeStore,
seenDests []string) []Edge {
seenDests []string,
) []Edge {
ret := []Edge{}
for _, value := range seenDests {
// Checking against nodeInfo.UID - it gets updated every time edgesByDestinationName is called
Expand Down Expand Up @@ -309,7 +357,7 @@ func edgesByDestinationName(
nodeInfo.EdgeType, destKind, nodeInfo.NameSpace+"/"+name)
}
}
seenDests = append(seenDests, nodeInfo.UID) //add nodeInfo UID to processed/seen nodes
seenDests = append(seenDests, nodeInfo.UID) // add nodeInfo UID to processed/seen nodes

// If the destination node has property _ownerUID, create an edge between the pod and the destination's owner
// Call the edgesByOwner recursively to create the uses edge
Expand Down Expand Up @@ -419,7 +467,6 @@ func edgesByDeployerSubscriber(nodeInfo NodeInfo, ns NodeStore) []Edge {
}
ret = findSub(nodeInfo.UID)
return ret

}

// Build edges from the source node in nodeInfo to all applications/channels in the subscription's metadata.
Expand Down
109 changes: 109 additions & 0 deletions pkg/transforms/common_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import (
"github.com/stolostron/search-collector/pkg/config"
v1 "k8s.io/api/core/v1"
machineryV1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
)

var (
Expand Down Expand Up @@ -71,3 +72,111 @@ func TestCommonProperties(t *testing.T) {
t.Fail()
}
}

func TestKyvernoPolicyEdges(t *testing.T) {
configmap := &unstructured.Unstructured{Object: map[string]interface{}{
"apiVersion": "v1",
"kind": "ConfigMap",
"metadata": map[string]interface{}{
"name": "zk-kafka-address",
"uid": "18b016fe-1931-4e80-95d1-d51d3b936e24",
"namespace": "test2",
"labels": map[string]interface{}{
"app.kubernetes.io/managed-by": "kyverno",
"generate.kyverno.io/policy-name": "zk-kafka-address",
"generate.kyverno.io/policy-namespace": "",
"generate.kyverno.io/rule-name": "k-kafka-address",
"generate.kyverno.io/trigger-group": "",
"generate.kyverno.io/trigger-kind": "Namespace",
"generate.kyverno.io/trigger-namespace": "",
"generate.kyverno.io/trigger-uid": "12345",
"generate.kyverno.io/trigger-version": "v1",
"somekey": "somevalue",
},
},
}}

configmapTwo := &unstructured.Unstructured{Object: map[string]interface{}{
"apiVersion": "v1",
"kind": "ConfigMap",
"metadata": map[string]interface{}{
"name": "hello-cofigmap",
"uid": "777016fe-1931-4e80-95d1-d51d3b936e24",
"namespace": "test2",
"labels": map[string]interface{}{
"app.kubernetes.io/managed-by": "kyverno",
"generate.kyverno.io/policy-name": "kyverno-policy-test",
"generate.kyverno.io/policy-namespace": "test2",
"generate.kyverno.io/rule-name": "k-kafka-address",
"generate.kyverno.io/trigger-group": "",
"generate.kyverno.io/trigger-kind": "Namespace",
"generate.kyverno.io/trigger-namespace": "",
},
},
}}

kyvernoPolicy := &unstructured.Unstructured{
Object: map[string]interface{}{
"apiVersion": "kyverno.io/v1",
"kind": "Policy",
"metadata": map[string]interface{}{
"name": "kyverno-policy-test",
"namespace": "test2",
"uid": "777738fa-0591-44da-8a06-98ea7d74a7f7",
},
},
}

kyvernoClusterpolicy := &unstructured.Unstructured{
Object: map[string]interface{}{
"apiVersion": "kyverno.io/v1",
"kind": "ClusterPolicy",
"metadata": map[string]interface{}{
"name": "zk-kafka-address",
"uid": "8fc338fa-0591-44da-8a06-98ea7d74a7f7",
},
},
}

nodes := []Node{
KyvernoPolicyResourceBuilder(kyvernoPolicy).BuildNode(),
KyvernoPolicyResourceBuilder(kyvernoClusterpolicy).BuildNode(),
GenericResourceBuilder(configmap).BuildNode(),
GenericResourceBuilder(configmapTwo).BuildNode(),
}
nodeStore := BuildFakeNodeStore(nodes)

t.Log("Test Kyverno Cluster Policy")
edges := CommonEdges("local-cluster/18b016fe-1931-4e80-95d1-d51d3b936e24", nodeStore)
if len(edges) != 1 {
t.Fatalf("Expected 1 edge but got %d", len(edges))
}

edge := edges[0]
expectedEdge := Edge{
EdgeType: "generatedBy",
SourceUID: "local-cluster/18b016fe-1931-4e80-95d1-d51d3b936e24",
DestUID: "local-cluster/8fc338fa-0591-44da-8a06-98ea7d74a7f7",
SourceKind: "ConfigMap",
DestKind: "ClusterPolicy",
}

AssertDeepEqual("edge", edge, expectedEdge, t)

t.Log("Test Kyverno Policy")
edges = CommonEdges("local-cluster/777016fe-1931-4e80-95d1-d51d3b936e24", nodeStore)
if len(edges) != 1 {
t.Fatalf("Expected 1 edge but got %d", len(edges))
}

edge = edges[0]
expectedEdge = Edge{
EdgeType: "generatedBy",
SourceUID: "local-cluster/777016fe-1931-4e80-95d1-d51d3b936e24",
DestUID: "local-cluster/777738fa-0591-44da-8a06-98ea7d74a7f7",
SourceKind: "ConfigMap",
DestKind: "Policy",
}

AssertDeepEqual("edge", edge, expectedEdge, t)
}

0 comments on commit 68f2bab

Please sign in to comment.