Skip to content

Commit

Permalink
feat: Support Ingress & IngressClass relationships
Browse files Browse the repository at this point in the history
Signed-off-by: Justin Toh <tohjustin@hotmail.com>
  • Loading branch information
tohjustin committed Sep 29, 2021
1 parent 5f820a8 commit 533aa7d
Show file tree
Hide file tree
Showing 2 changed files with 159 additions and 0 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ List of supported relationships used for discovering dependent objects:
- Kubernetes
- [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/)
- [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/)
- [ServiceAccount References](https://kubernetes.io/docs/reference/kubernetes-api/authentication-resources/service-account-v1/)
Expand Down
158 changes: 158 additions & 0 deletions pkg/cmd/lineage/graph.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import (
"sort"

corev1 "k8s.io/api/core/v1"
extensionsv1beta1 "k8s.io/api/extensions/v1beta1"
networkingv1 "k8s.io/api/networking/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
unstructuredv1 "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime"
Expand Down Expand Up @@ -143,6 +145,13 @@ const (
RelationshipEventRegarding Relationship = "EventRegarding"
RelationshipEventRelated Relationship = "EventRelated"

// Kubernetes Ingress & IngressClass relationships.
RelationshipIngressClass Relationship = "IngressClass"
RelationshipIngressClassParameters Relationship = "IngressClassParameters"
RelationshipIngressResource Relationship = "IngressResource"
RelationshipIngressService Relationship = "IngressService"
RelationshipIngressTLSSecret Relationship = "IngressTLSSecret"

// Kubernetes Owner-Dependent relationships.
RelationshipControllerRef Relationship = "ControllerReference"
RelationshipOwnerRef Relationship = "OwnerReference"
Expand Down Expand Up @@ -259,6 +268,20 @@ func resolveDependents(objects []unstructuredv1.Unstructured, rootUID types.UID)
klog.V(4).Infof("Failed to get relationships for event named \"%s\" in namespace \"%s\": %s", node.Name, node.Namespace, err)
continue
}
// Populate dependents based on Ingress relationships
case (node.Group == "extensions" || node.Group == "networking.k8s.io") && node.Kind == "Ingress":
rmap, err = getIngressRelationships(node)
if err != nil {
klog.V(4).Infof("Failed to get relationships for ingress named \"%s\" in namespace \"%s\": %s", node.Name, node.Namespace, err)
continue
}
// Populate dependents based on IngressClass relationships
case node.Group == "networking.k8s.io" && node.Kind == "IngressClass":
rmap, err = getIngressClassRelationships(node)
if err != nil {
klog.V(4).Infof("Failed to get relationships for ingressclass named \"%s\": %s", node.Name, err)
continue
}
// Populate dependents based on PersistentVolume relationships
case node.Group == "" && node.Kind == "PersistentVolume":
rmap, err = getPersistentVolumeRelationships(node)
Expand Down Expand Up @@ -350,6 +373,141 @@ func getEventRelationships(n *Node) (*RelationshipMap, error) {
return &result, nil
}

// getIngressRelationships returns a map of relationships that this Ingress has
// with other objects, based on what was referenced in its manifest.
//nolint:funlen,gocognit
func getIngressRelationships(n *Node) (*RelationshipMap, error) {
var ref ObjectReference
ns := n.Namespace
result := newRelationshipMap()
switch n.Group {
case "extensions":
var ing extensionsv1beta1.Ingress
err := runtime.DefaultUnstructuredConverter.FromUnstructured(n.UnstructuredContent(), &ing)
if err != nil {
return nil, err
}

// RelationshipIngressClass
if ingc := ing.Spec.IngressClassName; ingc != nil && len(*ingc) > 0 {
ref = ObjectReference{Group: "networking.k8s.io", Kind: "IngressClass", Name: *ingc}
result.AddDependencyByKey(ref.Key(), RelationshipIngressClass)
}

// RelationshipIngressResource
// RelationshipIngressService
var backends []extensionsv1beta1.IngressBackend
if ing.Spec.Backend != nil {
backends = append(backends, *ing.Spec.Backend)
}
for _, rule := range ing.Spec.Rules {
if rule.HTTP != nil {
for _, path := range rule.HTTP.Paths {
backends = append(backends, path.Backend)
}
}
}
for _, b := range backends {
switch {
case b.Resource != nil:
group := ""
if b.Resource.APIGroup != nil {
group = *b.Resource.APIGroup
}
ref = ObjectReference{Group: group, Kind: b.Resource.Kind, Name: b.Resource.Name, Namespace: ns}
result.AddDependencyByKey(ref.Key(), RelationshipIngressResource)
case b.ServiceName != "":
ref = ObjectReference{Kind: "Service", Name: b.ServiceName, Namespace: ns}
result.AddDependencyByKey(ref.Key(), RelationshipIngressService)
}
}

// RelationshipIngressTLSSecret
for _, tls := range ing.Spec.TLS {
ref = ObjectReference{Kind: "Secret", Name: tls.SecretName, Namespace: ns}
result.AddDependencyByKey(ref.Key(), RelationshipIngressClass)
}
case "networking.k8s.io":
var ing networkingv1.Ingress
err := runtime.DefaultUnstructuredConverter.FromUnstructured(n.UnstructuredContent(), &ing)
if err != nil {
return nil, err
}

// RelationshipIngressClass
if ingc := ing.Spec.IngressClassName; ingc != nil && len(*ingc) > 0 {
ref = ObjectReference{Group: "networking.k8s.io", Kind: "IngressClass", Name: *ingc}
result.AddDependencyByKey(ref.Key(), RelationshipIngressClass)
}

// RelationshipIngressResource
// RelationshipIngressService
var backends []networkingv1.IngressBackend
if ing.Spec.DefaultBackend != nil {
backends = append(backends, *ing.Spec.DefaultBackend)
}
for _, rule := range ing.Spec.Rules {
if rule.HTTP != nil {
for _, path := range rule.HTTP.Paths {
backends = append(backends, path.Backend)
}
}
}
for _, b := range backends {
switch {
case b.Resource != nil:
group := ""
if b.Resource.APIGroup != nil {
group = *b.Resource.APIGroup
}
ref = ObjectReference{Group: group, Kind: b.Resource.Kind, Name: b.Resource.Name, Namespace: ns}
result.AddDependencyByKey(ref.Key(), RelationshipIngressResource)
case b.Service != nil:
ref = ObjectReference{Kind: "Service", Name: b.Service.Name, Namespace: ns}
result.AddDependencyByKey(ref.Key(), RelationshipIngressService)
}
}

// RelationshipIngressTLSSecret
for _, tls := range ing.Spec.TLS {
ref = ObjectReference{Kind: "Secret", Name: tls.SecretName, Namespace: ns}
result.AddDependencyByKey(ref.Key(), RelationshipIngressClass)
}
}

return &result, nil
}

// getIngressClassRelationships returns a map of relationships that this
// IngressClass has with other objects, based on what was referenced in its
// manifest.
func getIngressClassRelationships(n *Node) (*RelationshipMap, error) {
var ingc networkingv1.IngressClass
err := runtime.DefaultUnstructuredConverter.FromUnstructured(n.UnstructuredContent(), &ingc)
if err != nil {
return nil, err
}

var ref ObjectReference
result := newRelationshipMap()

// RelationshipIngressClassParameters
if p := ingc.Spec.Parameters; p != nil {
group := ""
if p.APIGroup != nil {
group = *p.APIGroup
}
ns := ""
if p.Namespace != nil {
ns = *p.Namespace
}
ref = ObjectReference{Group: group, Kind: p.Kind, Namespace: ns, Name: p.Name}
result.AddDependencyByKey(ref.Key(), RelationshipIngressClassParameters)
}

return &result, nil
}

// getPersistentVolumeRelationships returns a map of relationships that this
// PersistentVolume has with other objects, based on what was referenced in its
// manifest.
Expand Down

0 comments on commit 533aa7d

Please sign in to comment.