github.com/cilium/cilium@v1.16.2/operator/watchers/pod.go (about)

     1  // SPDX-License-Identifier: Apache-2.0
     2  // Copyright Authors of Cilium
     3  
     4  package watchers
     5  
     6  import (
     7  	"context"
     8  	"fmt"
     9  	"sync"
    10  
    11  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    12  	"k8s.io/apimachinery/pkg/fields"
    13  	"k8s.io/client-go/tools/cache"
    14  
    15  	operatorOption "github.com/cilium/cilium/operator/option"
    16  	k8sClient "github.com/cilium/cilium/pkg/k8s/client"
    17  	"github.com/cilium/cilium/pkg/k8s/informer"
    18  	slim_corev1 "github.com/cilium/cilium/pkg/k8s/slim/k8s/api/core/v1"
    19  	slim_metav1 "github.com/cilium/cilium/pkg/k8s/slim/k8s/apis/meta/v1"
    20  	k8sUtils "github.com/cilium/cilium/pkg/k8s/utils"
    21  )
    22  
    23  const PodNodeNameIndex = "pod-node"
    24  
    25  var (
    26  	// PodStore has a minimal copy of all pods running in the cluster.
    27  	// Warning: The pods stored in the cache are not intended to be used for Update
    28  	// operations in k8s as some of its fields are not populated.
    29  	PodStore cache.Store
    30  
    31  	// PodStoreSynced is closed once the PodStore is synced with k8s.
    32  	PodStoreSynced = make(chan struct{})
    33  
    34  	// UnmanagedPodStore has a minimal copy of the unmanaged pods running
    35  	// in the cluster.
    36  	// Warning: The pods stored in the cache are not intended to be used for Update
    37  	// operations in k8s as some of its fields are not populated.
    38  	UnmanagedPodStore cache.Store
    39  
    40  	// UnmanagedPodStoreSynced is closed once the UnmanagedKubeDNSPodStore is synced
    41  	// with k8s.
    42  	UnmanagedPodStoreSynced = make(chan struct{})
    43  )
    44  
    45  // podNodeNameIndexFunc indexes pods by node name
    46  func podNodeNameIndexFunc(obj interface{}) ([]string, error) {
    47  	pod := obj.(*slim_corev1.Pod)
    48  	if pod.Spec.NodeName != "" {
    49  		return []string{pod.Spec.NodeName}, nil
    50  	}
    51  	return []string{}, nil
    52  }
    53  
    54  func PodsInit(ctx context.Context, wg *sync.WaitGroup, clientset k8sClient.Clientset) {
    55  	var podInformer cache.Controller
    56  	PodStore = cache.NewIndexer(cache.DeletionHandlingMetaNamespaceKeyFunc, cache.Indexers{
    57  		PodNodeNameIndex: podNodeNameIndexFunc,
    58  	})
    59  	podInformer = informer.NewInformerWithStore(
    60  		k8sUtils.ListerWatcherWithFields(
    61  			k8sUtils.ListerWatcherFromTyped[*slim_corev1.PodList](clientset.Slim().CoreV1().Pods("")),
    62  			fields.Everything()),
    63  		&slim_corev1.Pod{},
    64  		0,
    65  		cache.ResourceEventHandlerFuncs{},
    66  		transformToPod,
    67  		PodStore,
    68  	)
    69  	wg.Add(1)
    70  	go func() {
    71  		defer wg.Done()
    72  		podInformer.Run(ctx.Done())
    73  	}()
    74  
    75  	cache.WaitForCacheSync(ctx.Done(), podInformer.HasSynced)
    76  }
    77  
    78  // transformToPod stores a minimal version of the pod as it is only intended
    79  // for it to check if a pod is running in the cluster or not. The stored pod
    80  // should not be used to update an existing pod in the kubernetes cluster.
    81  // If the given obj can't be cast into either Pod nor DeletedFinalStateUnknown,
    82  // an error is returned.
    83  func transformToPod(obj interface{}) (interface{}, error) {
    84  	switch concreteObj := obj.(type) {
    85  	case *slim_corev1.Pod:
    86  		p := &slim_corev1.Pod{
    87  			TypeMeta: concreteObj.TypeMeta,
    88  			ObjectMeta: slim_metav1.ObjectMeta{
    89  				Name:            concreteObj.Name,
    90  				Namespace:       concreteObj.Namespace,
    91  				ResourceVersion: concreteObj.ResourceVersion,
    92  			},
    93  			Spec: slim_corev1.PodSpec{
    94  				NodeName: concreteObj.Spec.NodeName,
    95  			},
    96  			Status: slim_corev1.PodStatus{
    97  				Phase: concreteObj.Status.Phase,
    98  			},
    99  		}
   100  		*concreteObj = slim_corev1.Pod{}
   101  		return p, nil
   102  	case cache.DeletedFinalStateUnknown:
   103  		pod, ok := concreteObj.Obj.(*slim_corev1.Pod)
   104  		if !ok {
   105  			return nil, fmt.Errorf("unknown object type %T", concreteObj.Obj)
   106  		}
   107  		dfsu := cache.DeletedFinalStateUnknown{
   108  			Key: concreteObj.Key,
   109  			Obj: &slim_corev1.Pod{
   110  				TypeMeta: pod.TypeMeta,
   111  				ObjectMeta: slim_metav1.ObjectMeta{
   112  					Name:            pod.Name,
   113  					Namespace:       pod.Namespace,
   114  					ResourceVersion: pod.ResourceVersion,
   115  				},
   116  				Spec: slim_corev1.PodSpec{
   117  					NodeName: pod.Spec.NodeName,
   118  				},
   119  				Status: slim_corev1.PodStatus{
   120  					Phase: pod.Status.Phase,
   121  				},
   122  			},
   123  		}
   124  		// Small GC optimization
   125  		*pod = slim_corev1.Pod{}
   126  		return dfsu, nil
   127  	default:
   128  		return nil, fmt.Errorf("unknown object type %T", concreteObj)
   129  	}
   130  }
   131  
   132  func UnmanagedPodsInit(ctx context.Context, wg *sync.WaitGroup, clientset k8sClient.Clientset) {
   133  	var unmanagedPodInformer cache.Controller
   134  	UnmanagedPodStore, unmanagedPodInformer = informer.NewInformer(
   135  		k8sUtils.ListerWatcherWithModifier(
   136  			k8sUtils.ListerWatcherFromTyped[*slim_corev1.PodList](clientset.Slim().CoreV1().Pods("")),
   137  			func(options *metav1.ListOptions) {
   138  				options.FieldSelector = "status.phase=Running"
   139  				options.LabelSelector = operatorOption.Config.PodRestartSelector
   140  			}),
   141  		&slim_corev1.Pod{},
   142  		0,
   143  		cache.ResourceEventHandlerFuncs{},
   144  		TransformToUnmanagedPod,
   145  	)
   146  	wg.Add(1)
   147  	go func() {
   148  		defer wg.Done()
   149  		unmanagedPodInformer.Run(ctx.Done())
   150  	}()
   151  
   152  	cache.WaitForCacheSync(ctx.Done(), unmanagedPodInformer.HasSynced)
   153  }
   154  
   155  func TransformToUnmanagedPod(obj interface{}) (interface{}, error) {
   156  	switch concreteObj := obj.(type) {
   157  	case *slim_corev1.Pod:
   158  		p := &slim_corev1.Pod{
   159  			TypeMeta: concreteObj.TypeMeta,
   160  			ObjectMeta: slim_metav1.ObjectMeta{
   161  				Name:            concreteObj.Name,
   162  				Namespace:       concreteObj.Namespace,
   163  				ResourceVersion: concreteObj.ResourceVersion,
   164  			},
   165  			Spec: slim_corev1.PodSpec{
   166  				HostNetwork: concreteObj.Spec.HostNetwork,
   167  			},
   168  			Status: slim_corev1.PodStatus{
   169  				StartTime: concreteObj.Status.StartTime,
   170  			},
   171  		}
   172  		*concreteObj = slim_corev1.Pod{}
   173  		return p, nil
   174  	case cache.DeletedFinalStateUnknown:
   175  		pod, ok := concreteObj.Obj.(*slim_corev1.Pod)
   176  		if !ok {
   177  			return nil, fmt.Errorf("unknown object type %T", concreteObj.Obj)
   178  		}
   179  		dfsu := cache.DeletedFinalStateUnknown{
   180  			Key: concreteObj.Key,
   181  			Obj: &slim_corev1.Pod{
   182  				TypeMeta: pod.TypeMeta,
   183  				ObjectMeta: slim_metav1.ObjectMeta{
   184  					Name:            pod.Name,
   185  					Namespace:       pod.Namespace,
   186  					ResourceVersion: pod.ResourceVersion,
   187  				},
   188  				Spec: slim_corev1.PodSpec{
   189  					HostNetwork: pod.Spec.HostNetwork,
   190  				},
   191  				Status: slim_corev1.PodStatus{
   192  					StartTime: pod.Status.StartTime,
   193  				},
   194  			},
   195  		}
   196  		// Small GC optimization
   197  		*pod = slim_corev1.Pod{}
   198  		return dfsu, nil
   199  	default:
   200  		return nil, fmt.Errorf("unknown object type %T", concreteObj)
   201  	}
   202  }