From 3cc024ca33d0e1f3276e87267856ca1b8a2d741f Mon Sep 17 00:00:00 2001 From: Justin Toh Date: Fri, 1 Oct 2021 00:18:47 +0800 Subject: [PATCH] feat: Support MutatingWebhookConfiguration & ValidatingWebhookConfiguration relationships Signed-off-by: Justin Toh --- README.md | 1 + pkg/cmd/lineage/graph.go | 66 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 67 insertions(+) diff --git a/README.md b/README.md index 967bab3..6c5e5cd 100644 --- a/README.md +++ b/README.md @@ -35,6 +35,7 @@ List of supported relationships used for discovering dependent objects: - [Controller References](https://github.com/kubernetes/community/blob/master/contributors/design-proposals/api-machinery/controller-ref.md) & [Owner References](https://kubernetes.io/docs/concepts/overview/working-with-objects/owners-dependents/) - [Event References](https://kubernetes.io/docs/reference/kubernetes-api/cluster-resources/event-v1/) - [Ingress References](https://kubernetes.io/docs/reference/kubernetes-api/service-resources/ingress-v1/) & [IngressClass Reference](https://kubernetes.io/docs/reference/kubernetes-api/service-resources/ingress-class-v1/) + - [MutatingWebhookConfiguration References](https://kubernetes.io/docs/reference/kubernetes-api/extend-resources/mutating-webhook-configuration-v1/) & [ValidatingWebhookConfiguration References](https://kubernetes.io/docs/reference/kubernetes-api/extend-resources/validating-webhook-configuration-v1/) - [PersistentVolume References](https://kubernetes.io/docs/reference/kubernetes-api/config-and-storage-resources/persistent-volume-v1/) & [PersistentVolumeClaim References](https://kubernetes.io/docs/reference/kubernetes-api/config-and-storage-resources/persistent-volume-claim-v1/) - [Pod References](https://kubernetes.io/docs/reference/kubernetes-api/workload-resources/pod-v1/) - [Service References](https://kubernetes.io/docs/reference/kubernetes-api/service-resources/service-v1/) diff --git a/pkg/cmd/lineage/graph.go b/pkg/cmd/lineage/graph.go index 6ddfe47..0447298 100644 --- a/pkg/cmd/lineage/graph.go +++ b/pkg/cmd/lineage/graph.go @@ -4,6 +4,7 @@ import ( "fmt" "sort" + admissionregistrationv1 "k8s.io/api/admissionregistration/v1" corev1 "k8s.io/api/core/v1" extensionsv1beta1 "k8s.io/api/extensions/v1beta1" networkingv1 "k8s.io/api/networking/v1" @@ -195,6 +196,9 @@ const ( RelationshipIngressService Relationship = "IngressService" RelationshipIngressTLSSecret Relationship = "IngressTLSSecret" + // Kubernetes MutatingWebhookConfiguration & ValidatingWebhookConfiguration relationships. + RelationshipWebhookConfigurationService Relationship = "WebhookConfigurationService" + // Kubernetes Owner-Dependent relationships. RelationshipControllerRef Relationship = "ControllerReference" RelationshipOwnerRef Relationship = "OwnerReference" @@ -372,6 +376,20 @@ func resolveDependents(objects []unstructuredv1.Unstructured, rootUID types.UID) klog.V(4).Infof("Failed to get relationships for serviceaccount named \"%s\" in namespace \"%s\": %s", node.Name, node.Namespace, err) continue } + // Populate dependents based on MutatingWebhookConfiguration relationships + case node.Group == "admissionregistration.k8s.io" && node.Kind == "MutatingWebhookConfiguration": + rmap, err = getMutatingWebhookConfigurationRelationships(node) + if err != nil { + klog.V(4).Infof("Failed to get relationships for mutatingwebhookconfiguration named \"%s\": %s", node.Name, err) + continue + } + // Populate dependents based on ValidatingWebhookConfiguration relationships + case node.Group == "admissionregistration.k8s.io" && node.Kind == "ValidatingWebhookConfiguration": + rmap, err = getValidatingWebhookConfigurationRelationships(node) + if err != nil { + klog.V(4).Infof("Failed to get relationships for validatingwebhookconfiguration named \"%s\": %s", node.Name, err) + continue + } // Populate dependents based on Event relationships // TODO: It's possible to have events to be in a different namespace from the // its referenced object, so update the resource fetching logic to @@ -594,6 +612,30 @@ func getIngressClassRelationships(n *Node) (*RelationshipMap, error) { return &result, nil } +// getMutatingWebhookConfigurationRelationships returns a map of relationships +// that this MutatingWebhookConfiguration has with other objects, based on what +// was referenced in its manifest. +func getMutatingWebhookConfigurationRelationships(n *Node) (*RelationshipMap, error) { + var mwc admissionregistrationv1.MutatingWebhookConfiguration + err := runtime.DefaultUnstructuredConverter.FromUnstructured(n.UnstructuredContent(), &mwc) + if err != nil { + return nil, err + } + + var ref ObjectReference + result := newRelationshipMap() + + // RelationshipWebhookConfigurationService + for _, wh := range mwc.Webhooks { + if svc := wh.ClientConfig.Service; svc != nil { + ref = ObjectReference{Kind: "Service", Namespace: svc.Namespace, Name: svc.Name} + result.AddDependencyByKey(ref.Key(), RelationshipWebhookConfigurationService) + } + } + + return &result, nil +} + // getPersistentVolumeRelationships returns a map of relationships that this // PersistentVolume has with other objects, based on what was referenced in its // manifest. @@ -789,3 +831,27 @@ func getServiceAccountRelationships(n *Node) (*RelationshipMap, error) { return &result, nil } + +// getValidatingWebhookConfigurationRelationships returns a map of relationships +// that this ValidatingWebhookConfiguration has with other objects, based on +// what was referenced in its manifest. +func getValidatingWebhookConfigurationRelationships(n *Node) (*RelationshipMap, error) { + var vwc admissionregistrationv1.ValidatingWebhookConfiguration + err := runtime.DefaultUnstructuredConverter.FromUnstructured(n.UnstructuredContent(), &vwc) + if err != nil { + return nil, err + } + + var ref ObjectReference + result := newRelationshipMap() + + // RelationshipWebhookConfigurationService + for _, wh := range vwc.Webhooks { + if svc := wh.ClientConfig.Service; svc != nil { + ref = ObjectReference{Kind: "Service", Namespace: svc.Namespace, Name: svc.Name} + result.AddDependencyByKey(ref.Key(), RelationshipWebhookConfigurationService) + } + } + + return &result, nil +}