github.com/castai/kvisor@v1.7.1-0.20240516114728-b3572a2607b5/cmd/controller/kube/index.go (about)

     1  package kube
     2  
     3  import (
     4  	appsv1 "k8s.io/api/apps/v1"
     5  	corev1 "k8s.io/api/core/v1"
     6  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
     7  	"k8s.io/apimachinery/pkg/labels"
     8  	"k8s.io/apimachinery/pkg/types"
     9  )
    10  
    11  func NewIndex() *Index {
    12  	return &Index{
    13  		podsInfoByIP: make(map[string]IPInfo),
    14  		replicaSets:  make(map[types.UID]metav1.ObjectMeta),
    15  		jobs:         make(map[types.UID]metav1.ObjectMeta),
    16  		deployments:  make(map[types.UID]*appsv1.Deployment),
    17  		pods:         make(map[types.UID]*corev1.Pod),
    18  		nodesByName:  make(map[string]*corev1.Node),
    19  	}
    20  }
    21  
    22  type Index struct {
    23  	podsInfoByIP map[string]IPInfo
    24  	replicaSets  map[types.UID]metav1.ObjectMeta
    25  	jobs         map[types.UID]metav1.ObjectMeta
    26  	deployments  map[types.UID]*appsv1.Deployment
    27  	pods         map[types.UID]*corev1.Pod
    28  	nodesByName  map[string]*corev1.Node
    29  }
    30  
    31  func (i *Index) addFromPod(pod *corev1.Pod) {
    32  	i.pods[pod.UID] = pod
    33  	if !pod.Spec.HostNetwork {
    34  		ipInfo := IPInfo{
    35  			Pod:  pod,
    36  			Node: i.nodesByName[pod.Spec.NodeName],
    37  		}
    38  		owner := i.getPodOwner(pod)
    39  		if owner.UID != pod.UID {
    40  			ipInfo.Owner = &owner
    41  		}
    42  		i.podsInfoByIP[pod.Status.PodIP] = ipInfo
    43  	}
    44  }
    45  
    46  func (i *Index) addFromEndpoints(v *corev1.Endpoints) {
    47  	for _, subset := range v.Subsets {
    48  		for _, address := range subset.Addresses {
    49  			// Skip adding entries if target info exists. Will be added by pods.
    50  			if address.TargetRef != nil {
    51  				continue
    52  			}
    53  
    54  			i.podsInfoByIP[address.IP] = IPInfo{Endpoint: &IPEndpoint{
    55  				ID:        string(v.UID),
    56  				Name:      v.Name,
    57  				Namespace: v.Namespace,
    58  				Labels:    v.Labels,
    59  			}}
    60  		}
    61  	}
    62  }
    63  
    64  func (i *Index) addFromService(v *corev1.Service) {
    65  	ips := getServiceIPs(v)
    66  	if len(ips) == 0 {
    67  		return
    68  	}
    69  
    70  	for _, ip := range ips {
    71  		i.podsInfoByIP[ip] = IPInfo{Service: v}
    72  	}
    73  }
    74  
    75  func (i *Index) addFromNode(v *corev1.Node) {
    76  	i.nodesByName[v.Name] = v
    77  
    78  	for _, address := range v.Status.Addresses {
    79  		if address.Type == corev1.NodeInternalIP {
    80  			i.podsInfoByIP[address.Address] = IPInfo{Node: v}
    81  			return
    82  		}
    83  	}
    84  }
    85  
    86  func (i *Index) deleteFromPod(v *corev1.Pod) {
    87  	delete(i.pods, v.UID)
    88  
    89  	if !v.Spec.HostNetwork {
    90  		delete(i.podsInfoByIP, v.Status.PodIP)
    91  	}
    92  }
    93  
    94  func (i *Index) deleteFromEndpoints(v *corev1.Endpoints) {
    95  	for _, subset := range v.Subsets {
    96  		for _, address := range subset.Addresses {
    97  			if address.TargetRef != nil {
    98  				continue
    99  			}
   100  
   101  			delete(i.podsInfoByIP, address.IP)
   102  		}
   103  	}
   104  }
   105  
   106  func (i *Index) deleteFromService(v *corev1.Service) {
   107  	ips := getServiceIPs(v)
   108  	if len(ips) == 0 {
   109  		return
   110  	}
   111  
   112  	for _, ip := range ips {
   113  		delete(i.podsInfoByIP, ip)
   114  	}
   115  }
   116  
   117  func (i *Index) deleteByNode(v *corev1.Node) {
   118  	delete(i.nodesByName, v.Name)
   119  
   120  	for _, address := range v.Status.Addresses {
   121  		if address.Type == corev1.NodeInternalIP {
   122  			delete(i.podsInfoByIP, address.Address)
   123  		}
   124  	}
   125  }
   126  
   127  func (i *Index) getPodOwner(pod *corev1.Pod) metav1.OwnerReference {
   128  	if len(pod.OwnerReferences) == 0 {
   129  		return metav1.OwnerReference{
   130  			Kind: "Pod",
   131  			Name: pod.Name,
   132  			UID:  pod.UID,
   133  		}
   134  	}
   135  	owner := pod.OwnerReferences[0]
   136  	switch owner.Kind {
   137  	case "ReplicaSet":
   138  		if rs, found := i.replicaSets[owner.UID]; found {
   139  			owner = findOwner(owner, rs.OwnerReferences)
   140  			if owner.Kind != "Deployment" {
   141  				if dep, found := findDeploymentByPodSelector(i.deployments, pod); found {
   142  					return metav1.OwnerReference{
   143  						Kind: dep.Kind,
   144  						Name: dep.Name,
   145  						UID:  dep.UID,
   146  					}
   147  				}
   148  			}
   149  			return owner
   150  		}
   151  	case "Job":
   152  		if rs, found := i.jobs[owner.UID]; found {
   153  			return findOwner(owner, rs.OwnerReferences)
   154  		}
   155  	}
   156  	return owner
   157  }
   158  
   159  func findDeploymentByPodSelector(deployments map[types.UID]*appsv1.Deployment, pod *corev1.Pod) (*appsv1.Deployment, bool) {
   160  	for _, w := range deployments {
   161  		sel, err := metav1.LabelSelectorAsSelector(w.Spec.Selector)
   162  		if err != nil {
   163  			continue
   164  		}
   165  		if sel.Matches(labels.Set(pod.Labels)) {
   166  			return w, true
   167  		}
   168  	}
   169  	return nil, false
   170  }
   171  
   172  func findOwner(ref metav1.OwnerReference, refs []metav1.OwnerReference) metav1.OwnerReference {
   173  	if len(refs) > 0 {
   174  		return refs[0]
   175  	}
   176  	return ref
   177  }
   178  
   179  func getServiceIPs(svc *corev1.Service) []string {
   180  	switch svc.Spec.Type { //nolint:exhaustive
   181  	case corev1.ServiceTypeClusterIP, corev1.ServiceTypeNodePort:
   182  		if svc.Spec.ClusterIP == corev1.ClusterIPNone {
   183  			return nil
   184  		}
   185  		return []string{svc.Spec.ClusterIP}
   186  	case corev1.ServiceTypeLoadBalancer:
   187  		for _, ingress := range svc.Status.LoadBalancer.Ingress {
   188  			if ip := ingress.IP; ip != "" {
   189  				return []string{ip}
   190  			}
   191  		}
   192  	}
   193  	return svc.Spec.ExternalIPs
   194  }
   195  
   196  type IPEndpoint struct {
   197  	ID        string
   198  	Name      string
   199  	Namespace string
   200  	Labels    map[string]string
   201  }
   202  
   203  type IPInfo struct {
   204  	IP       string
   205  	Pod      *corev1.Pod
   206  	Service  *corev1.Service
   207  	Node     *corev1.Node
   208  	Endpoint *IPEndpoint
   209  	Owner    *metav1.OwnerReference
   210  }