k8s.io/kubernetes@v1.29.3/pkg/kubelet/pod/pod_manager.go (about)

     1  /*
     2  Copyright 2015 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  //go:generate mockgen -destination=testing/mock_manager.go -package=testing -build_flags=-mod=mod . Manager
    18  package pod
    19  
    20  import (
    21  	"sync"
    22  
    23  	v1 "k8s.io/api/core/v1"
    24  	"k8s.io/apimachinery/pkg/types"
    25  	kubecontainer "k8s.io/kubernetes/pkg/kubelet/container"
    26  	"k8s.io/kubernetes/pkg/kubelet/metrics"
    27  	kubetypes "k8s.io/kubernetes/pkg/kubelet/types"
    28  )
    29  
    30  // Manager stores and manages access to pods, maintaining the mappings
    31  // between static pods and mirror pods.
    32  //
    33  // The kubelet discovers pod updates from 3 sources: file, http, and
    34  // apiserver. Pods from non-apiserver sources are called static pods, and API
    35  // server is not aware of the existence of static pods. In order to monitor
    36  // the status of such pods, the kubelet creates a mirror pod for each static
    37  // pod via the API server.
    38  //
    39  // A mirror pod has the same pod full name (name and namespace) as its static
    40  // counterpart (albeit different metadata such as UID, etc). By leveraging the
    41  // fact that the kubelet reports the pod status using the pod full name, the
    42  // status of the mirror pod always reflects the actual status of the static
    43  // pod. When a static pod gets deleted, the associated orphaned mirror pod
    44  // will also be removed.
    45  type Manager interface {
    46  	// GetPodByFullName returns the (non-mirror) pod that matches full name, as well as
    47  	// whether the pod was found.
    48  	GetPodByFullName(podFullName string) (*v1.Pod, bool)
    49  	// GetPodByName provides the (non-mirror) pod that matches namespace and
    50  	// name, as well as whether the pod was found.
    51  	GetPodByName(namespace, name string) (*v1.Pod, bool)
    52  	// GetPodByUID provides the (non-mirror) pod that matches pod UID, as well as
    53  	// whether the pod is found.
    54  	GetPodByUID(types.UID) (*v1.Pod, bool)
    55  	// GetPodByMirrorPod returns the static pod for the given mirror pod and
    56  	// whether it was known to the pod manager.
    57  	GetPodByMirrorPod(*v1.Pod) (*v1.Pod, bool)
    58  	// GetMirrorPodByPod returns the mirror pod for the given static pod and
    59  	// whether it was known to the pod manager.
    60  	GetMirrorPodByPod(*v1.Pod) (*v1.Pod, bool)
    61  	// GetPodAndMirrorPod returns the complement for a pod - if a pod was provided
    62  	// and a mirror pod can be found, return it. If a mirror pod is provided and
    63  	// the pod can be found, return it and true for wasMirror.
    64  	GetPodAndMirrorPod(*v1.Pod) (pod, mirrorPod *v1.Pod, wasMirror bool)
    65  
    66  	// GetPods returns the regular pods bound to the kubelet and their spec.
    67  	GetPods() []*v1.Pod
    68  
    69  	// GetPodsAndMirrorPods returns the set of pods, the set of mirror pods, and
    70  	// the pod fullnames of any orphaned mirror pods.
    71  	GetPodsAndMirrorPods() (allPods []*v1.Pod, allMirrorPods []*v1.Pod, orphanedMirrorPodFullnames []string)
    72  
    73  	// SetPods replaces the internal pods with the new pods.
    74  	// It is currently only used for testing.
    75  	SetPods(pods []*v1.Pod)
    76  	// AddPod adds the given pod to the manager.
    77  	AddPod(pod *v1.Pod)
    78  	// UpdatePod updates the given pod in the manager.
    79  	UpdatePod(pod *v1.Pod)
    80  	// RemovePod deletes the given pod from the manager.  For mirror pods,
    81  	// this means deleting the mappings related to mirror pods.  For non-
    82  	// mirror pods, this means deleting from indexes for all non-mirror pods.
    83  	RemovePod(pod *v1.Pod)
    84  
    85  	// TranslatePodUID returns the actual UID of a pod. If the UID belongs to
    86  	// a mirror pod, returns the UID of its static pod. Otherwise, returns the
    87  	// original UID.
    88  	//
    89  	// All public-facing functions should perform this translation for UIDs
    90  	// because user may provide a mirror pod UID, which is not recognized by
    91  	// internal Kubelet functions.
    92  	TranslatePodUID(uid types.UID) kubetypes.ResolvedPodUID
    93  	// GetUIDTranslations returns the mappings of static pod UIDs to mirror pod
    94  	// UIDs and mirror pod UIDs to static pod UIDs.
    95  	GetUIDTranslations() (podToMirror map[kubetypes.ResolvedPodUID]kubetypes.MirrorPodUID, mirrorToPod map[kubetypes.MirrorPodUID]kubetypes.ResolvedPodUID)
    96  }
    97  
    98  // basicManager is a functional Manager.
    99  //
   100  // All fields in basicManager are read-only and are updated calling SetPods,
   101  // AddPod, UpdatePod, or RemovePod.
   102  type basicManager struct {
   103  	// Protects all internal maps.
   104  	lock sync.RWMutex
   105  
   106  	// Regular pods indexed by UID.
   107  	podByUID map[kubetypes.ResolvedPodUID]*v1.Pod
   108  	// Mirror pods indexed by UID.
   109  	mirrorPodByUID map[kubetypes.MirrorPodUID]*v1.Pod
   110  
   111  	// Pods indexed by full name for easy access.
   112  	podByFullName       map[string]*v1.Pod
   113  	mirrorPodByFullName map[string]*v1.Pod
   114  
   115  	// Mirror pod UID to pod UID map.
   116  	translationByUID map[kubetypes.MirrorPodUID]kubetypes.ResolvedPodUID
   117  }
   118  
   119  // NewBasicPodManager returns a functional Manager.
   120  func NewBasicPodManager() Manager {
   121  	pm := &basicManager{}
   122  	pm.SetPods(nil)
   123  	return pm
   124  }
   125  
   126  // Set the internal pods based on the new pods.
   127  func (pm *basicManager) SetPods(newPods []*v1.Pod) {
   128  	pm.lock.Lock()
   129  	defer pm.lock.Unlock()
   130  
   131  	pm.podByUID = make(map[kubetypes.ResolvedPodUID]*v1.Pod)
   132  	pm.podByFullName = make(map[string]*v1.Pod)
   133  	pm.mirrorPodByUID = make(map[kubetypes.MirrorPodUID]*v1.Pod)
   134  	pm.mirrorPodByFullName = make(map[string]*v1.Pod)
   135  	pm.translationByUID = make(map[kubetypes.MirrorPodUID]kubetypes.ResolvedPodUID)
   136  
   137  	pm.updatePodsInternal(newPods...)
   138  }
   139  
   140  func (pm *basicManager) AddPod(pod *v1.Pod) {
   141  	pm.UpdatePod(pod)
   142  }
   143  
   144  func (pm *basicManager) UpdatePod(pod *v1.Pod) {
   145  	pm.lock.Lock()
   146  	defer pm.lock.Unlock()
   147  	pm.updatePodsInternal(pod)
   148  }
   149  
   150  // updateMetrics updates the metrics surfaced by the pod manager.
   151  // oldPod or newPod may be nil to signify creation or deletion.
   152  func updateMetrics(oldPod, newPod *v1.Pod) {
   153  	var numEC int
   154  	if oldPod != nil {
   155  		numEC -= len(oldPod.Spec.EphemeralContainers)
   156  	}
   157  	if newPod != nil {
   158  		numEC += len(newPod.Spec.EphemeralContainers)
   159  	}
   160  	if numEC != 0 {
   161  		metrics.ManagedEphemeralContainers.Add(float64(numEC))
   162  	}
   163  }
   164  
   165  // updatePodsInternal replaces the given pods in the current state of the
   166  // manager, updating the various indices. The caller is assumed to hold the
   167  // lock.
   168  func (pm *basicManager) updatePodsInternal(pods ...*v1.Pod) {
   169  	for _, pod := range pods {
   170  		podFullName := kubecontainer.GetPodFullName(pod)
   171  		// This logic relies on a static pod and its mirror to have the same name.
   172  		// It is safe to type convert here due to the IsMirrorPod guard.
   173  		if kubetypes.IsMirrorPod(pod) {
   174  			mirrorPodUID := kubetypes.MirrorPodUID(pod.UID)
   175  			pm.mirrorPodByUID[mirrorPodUID] = pod
   176  			pm.mirrorPodByFullName[podFullName] = pod
   177  			if p, ok := pm.podByFullName[podFullName]; ok {
   178  				pm.translationByUID[mirrorPodUID] = kubetypes.ResolvedPodUID(p.UID)
   179  			}
   180  		} else {
   181  			resolvedPodUID := kubetypes.ResolvedPodUID(pod.UID)
   182  			updateMetrics(pm.podByUID[resolvedPodUID], pod)
   183  			pm.podByUID[resolvedPodUID] = pod
   184  			pm.podByFullName[podFullName] = pod
   185  			if mirror, ok := pm.mirrorPodByFullName[podFullName]; ok {
   186  				pm.translationByUID[kubetypes.MirrorPodUID(mirror.UID)] = resolvedPodUID
   187  			}
   188  		}
   189  	}
   190  }
   191  
   192  func (pm *basicManager) RemovePod(pod *v1.Pod) {
   193  	updateMetrics(pod, nil)
   194  	pm.lock.Lock()
   195  	defer pm.lock.Unlock()
   196  	podFullName := kubecontainer.GetPodFullName(pod)
   197  	// It is safe to type convert here due to the IsMirrorPod guard.
   198  	if kubetypes.IsMirrorPod(pod) {
   199  		mirrorPodUID := kubetypes.MirrorPodUID(pod.UID)
   200  		delete(pm.mirrorPodByUID, mirrorPodUID)
   201  		delete(pm.mirrorPodByFullName, podFullName)
   202  		delete(pm.translationByUID, mirrorPodUID)
   203  	} else {
   204  		delete(pm.podByUID, kubetypes.ResolvedPodUID(pod.UID))
   205  		delete(pm.podByFullName, podFullName)
   206  	}
   207  }
   208  
   209  func (pm *basicManager) GetPods() []*v1.Pod {
   210  	pm.lock.RLock()
   211  	defer pm.lock.RUnlock()
   212  	return podsMapToPods(pm.podByUID)
   213  }
   214  
   215  func (pm *basicManager) GetPodsAndMirrorPods() (allPods []*v1.Pod, allMirrorPods []*v1.Pod, orphanedMirrorPodFullnames []string) {
   216  	pm.lock.RLock()
   217  	defer pm.lock.RUnlock()
   218  	allPods = podsMapToPods(pm.podByUID)
   219  	allMirrorPods = mirrorPodsMapToMirrorPods(pm.mirrorPodByUID)
   220  
   221  	for podFullName := range pm.mirrorPodByFullName {
   222  		if _, ok := pm.podByFullName[podFullName]; !ok {
   223  			orphanedMirrorPodFullnames = append(orphanedMirrorPodFullnames, podFullName)
   224  		}
   225  	}
   226  	return allPods, allMirrorPods, orphanedMirrorPodFullnames
   227  }
   228  
   229  func (pm *basicManager) GetPodByUID(uid types.UID) (*v1.Pod, bool) {
   230  	pm.lock.RLock()
   231  	defer pm.lock.RUnlock()
   232  	pod, ok := pm.podByUID[kubetypes.ResolvedPodUID(uid)] // Safe conversion, map only holds non-mirrors.
   233  	return pod, ok
   234  }
   235  
   236  func (pm *basicManager) GetPodByName(namespace, name string) (*v1.Pod, bool) {
   237  	podFullName := kubecontainer.BuildPodFullName(name, namespace)
   238  	return pm.GetPodByFullName(podFullName)
   239  }
   240  
   241  func (pm *basicManager) GetPodByFullName(podFullName string) (*v1.Pod, bool) {
   242  	pm.lock.RLock()
   243  	defer pm.lock.RUnlock()
   244  	pod, ok := pm.podByFullName[podFullName]
   245  	return pod, ok
   246  }
   247  
   248  func (pm *basicManager) TranslatePodUID(uid types.UID) kubetypes.ResolvedPodUID {
   249  	// It is safe to type convert to a resolved UID because type conversion is idempotent.
   250  	if uid == "" {
   251  		return kubetypes.ResolvedPodUID(uid)
   252  	}
   253  
   254  	pm.lock.RLock()
   255  	defer pm.lock.RUnlock()
   256  	if translated, ok := pm.translationByUID[kubetypes.MirrorPodUID(uid)]; ok {
   257  		return translated
   258  	}
   259  	return kubetypes.ResolvedPodUID(uid)
   260  }
   261  
   262  func (pm *basicManager) GetUIDTranslations() (podToMirror map[kubetypes.ResolvedPodUID]kubetypes.MirrorPodUID,
   263  	mirrorToPod map[kubetypes.MirrorPodUID]kubetypes.ResolvedPodUID) {
   264  	pm.lock.RLock()
   265  	defer pm.lock.RUnlock()
   266  
   267  	podToMirror = make(map[kubetypes.ResolvedPodUID]kubetypes.MirrorPodUID, len(pm.translationByUID))
   268  	mirrorToPod = make(map[kubetypes.MirrorPodUID]kubetypes.ResolvedPodUID, len(pm.translationByUID))
   269  	// Insert empty translation mapping for all static pods.
   270  	for uid, pod := range pm.podByUID {
   271  		if !kubetypes.IsStaticPod(pod) {
   272  			continue
   273  		}
   274  		podToMirror[uid] = ""
   275  	}
   276  	// Fill in translations. Notice that if there is no mirror pod for a
   277  	// static pod, its uid will be translated into empty string "". This
   278  	// is WAI, from the caller side we can know that the static pod doesn't
   279  	// have a corresponding mirror pod instead of using static pod uid directly.
   280  	for k, v := range pm.translationByUID {
   281  		mirrorToPod[k] = v
   282  		podToMirror[v] = k
   283  	}
   284  	return podToMirror, mirrorToPod
   285  }
   286  
   287  // IsMirrorPodOf returns true if pod and mirrorPod are associated with each other.
   288  func IsMirrorPodOf(mirrorPod, pod *v1.Pod) bool {
   289  	// Check name and namespace first.
   290  	if pod.Name != mirrorPod.Name || pod.Namespace != mirrorPod.Namespace {
   291  		return false
   292  	}
   293  	hash, ok := getHashFromMirrorPod(mirrorPod)
   294  	if !ok {
   295  		return false
   296  	}
   297  	return hash == getPodHash(pod)
   298  }
   299  
   300  func podsMapToPods(UIDMap map[kubetypes.ResolvedPodUID]*v1.Pod) []*v1.Pod {
   301  	pods := make([]*v1.Pod, 0, len(UIDMap))
   302  	for _, pod := range UIDMap {
   303  		pods = append(pods, pod)
   304  	}
   305  	return pods
   306  }
   307  
   308  func mirrorPodsMapToMirrorPods(UIDMap map[kubetypes.MirrorPodUID]*v1.Pod) []*v1.Pod {
   309  	pods := make([]*v1.Pod, 0, len(UIDMap))
   310  	for _, pod := range UIDMap {
   311  		pods = append(pods, pod)
   312  	}
   313  	return pods
   314  }
   315  
   316  func (pm *basicManager) GetMirrorPodByPod(pod *v1.Pod) (*v1.Pod, bool) {
   317  	pm.lock.RLock()
   318  	defer pm.lock.RUnlock()
   319  	mirrorPod, ok := pm.mirrorPodByFullName[kubecontainer.GetPodFullName(pod)]
   320  	return mirrorPod, ok
   321  }
   322  
   323  func (pm *basicManager) GetPodByMirrorPod(mirrorPod *v1.Pod) (*v1.Pod, bool) {
   324  	pm.lock.RLock()
   325  	defer pm.lock.RUnlock()
   326  	pod, ok := pm.podByFullName[kubecontainer.GetPodFullName(mirrorPod)]
   327  	return pod, ok
   328  }
   329  
   330  func (pm *basicManager) GetPodAndMirrorPod(aPod *v1.Pod) (pod, mirrorPod *v1.Pod, wasMirror bool) {
   331  	pm.lock.RLock()
   332  	defer pm.lock.RUnlock()
   333  
   334  	fullName := kubecontainer.GetPodFullName(aPod)
   335  	if kubetypes.IsMirrorPod(aPod) {
   336  		return pm.podByFullName[fullName], aPod, true
   337  	}
   338  	return aPod, pm.mirrorPodByFullName[fullName], false
   339  
   340  }