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

     1  /*
     2  Copyright 2016 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  package kubelet
    18  
    19  import (
    20  	"context"
    21  	"fmt"
    22  	"net"
    23  	"os"
    24  	"path/filepath"
    25  
    26  	cadvisorapiv1 "github.com/google/cadvisor/info/v1"
    27  	cadvisorv2 "github.com/google/cadvisor/info/v2"
    28  	"k8s.io/klog/v2"
    29  	"k8s.io/mount-utils"
    30  	utilpath "k8s.io/utils/path"
    31  	utilstrings "k8s.io/utils/strings"
    32  
    33  	v1 "k8s.io/api/core/v1"
    34  	"k8s.io/apimachinery/pkg/types"
    35  	"k8s.io/kubernetes/pkg/kubelet/cm"
    36  	"k8s.io/kubernetes/pkg/kubelet/config"
    37  	kubecontainer "k8s.io/kubernetes/pkg/kubelet/container"
    38  	kubelettypes "k8s.io/kubernetes/pkg/kubelet/types"
    39  	utilnode "k8s.io/kubernetes/pkg/util/node"
    40  	"k8s.io/kubernetes/pkg/volume/csi"
    41  )
    42  
    43  // getRootDir returns the full path to the directory under which kubelet can
    44  // store data.  These functions are useful to pass interfaces to other modules
    45  // that may need to know where to write data without getting a whole kubelet
    46  // instance.
    47  func (kl *Kubelet) getRootDir() string {
    48  	return kl.rootDirectory
    49  }
    50  
    51  // getPodsDir returns the full path to the directory under which pod
    52  // directories are created.
    53  func (kl *Kubelet) getPodsDir() string {
    54  	return filepath.Join(kl.getRootDir(), config.DefaultKubeletPodsDirName)
    55  }
    56  
    57  // getPluginsDir returns the full path to the directory under which plugin
    58  // directories are created.  Plugins can use these directories for data that
    59  // they need to persist.  Plugins should create subdirectories under this named
    60  // after their own names.
    61  func (kl *Kubelet) getPluginsDir() string {
    62  	return filepath.Join(kl.getRootDir(), config.DefaultKubeletPluginsDirName)
    63  }
    64  
    65  // getPluginsRegistrationDir returns the full path to the directory under which
    66  // plugins socket should be placed to be registered.
    67  // More information is available about plugin registration in the pluginwatcher
    68  // module
    69  func (kl *Kubelet) getPluginsRegistrationDir() string {
    70  	return filepath.Join(kl.getRootDir(), config.DefaultKubeletPluginsRegistrationDirName)
    71  }
    72  
    73  // getPluginDir returns a data directory name for a given plugin name.
    74  // Plugins can use these directories to store data that they need to persist.
    75  // For per-pod plugin data, see getPodPluginDir.
    76  func (kl *Kubelet) getPluginDir(pluginName string) string {
    77  	return filepath.Join(kl.getPluginsDir(), pluginName)
    78  }
    79  
    80  // getCheckpointsDir returns a data directory name for checkpoints.
    81  // Checkpoints can be stored in this directory for further use.
    82  func (kl *Kubelet) getCheckpointsDir() string {
    83  	return filepath.Join(kl.getRootDir(), config.DefaultKubeletCheckpointsDirName)
    84  }
    85  
    86  // getVolumeDevicePluginsDir returns the full path to the directory under which plugin
    87  // directories are created.  Plugins can use these directories for data that
    88  // they need to persist.  Plugins should create subdirectories under this named
    89  // after their own names.
    90  func (kl *Kubelet) getVolumeDevicePluginsDir() string {
    91  	return filepath.Join(kl.getRootDir(), config.DefaultKubeletPluginsDirName)
    92  }
    93  
    94  // getVolumeDevicePluginDir returns a data directory name for a given plugin name.
    95  // Plugins can use these directories to store data that they need to persist.
    96  // For per-pod plugin data, see getVolumeDevicePluginsDir.
    97  func (kl *Kubelet) getVolumeDevicePluginDir(pluginName string) string {
    98  	return filepath.Join(kl.getVolumeDevicePluginsDir(), pluginName, config.DefaultKubeletVolumeDevicesDirName)
    99  }
   100  
   101  // GetPodDir returns the full path to the per-pod data directory for the
   102  // specified pod. This directory may not exist if the pod does not exist.
   103  func (kl *Kubelet) GetPodDir(podUID types.UID) string {
   104  	return kl.getPodDir(podUID)
   105  }
   106  
   107  // ListPodsFromDisk gets a list of pods that have data directories.
   108  func (kl *Kubelet) ListPodsFromDisk() ([]types.UID, error) {
   109  	return kl.listPodsFromDisk()
   110  }
   111  
   112  // getPodDir returns the full path to the per-pod directory for the pod with
   113  // the given UID.
   114  func (kl *Kubelet) getPodDir(podUID types.UID) string {
   115  	return filepath.Join(kl.getPodsDir(), string(podUID))
   116  }
   117  
   118  // getPodVolumesSubpathsDir returns the full path to the per-pod subpaths directory under
   119  // which subpath volumes are created for the specified pod.  This directory may not
   120  // exist if the pod does not exist or subpaths are not specified.
   121  func (kl *Kubelet) getPodVolumeSubpathsDir(podUID types.UID) string {
   122  	return filepath.Join(kl.getPodDir(podUID), config.DefaultKubeletVolumeSubpathsDirName)
   123  }
   124  
   125  // getPodVolumesDir returns the full path to the per-pod data directory under
   126  // which volumes are created for the specified pod.  This directory may not
   127  // exist if the pod does not exist.
   128  func (kl *Kubelet) getPodVolumesDir(podUID types.UID) string {
   129  	return filepath.Join(kl.getPodDir(podUID), config.DefaultKubeletVolumesDirName)
   130  }
   131  
   132  // getPodVolumeDir returns the full path to the directory which represents the
   133  // named volume under the named plugin for specified pod.  This directory may not
   134  // exist if the pod does not exist.
   135  func (kl *Kubelet) getPodVolumeDir(podUID types.UID, pluginName string, volumeName string) string {
   136  	return filepath.Join(kl.getPodVolumesDir(podUID), pluginName, volumeName)
   137  }
   138  
   139  // getPodVolumeDevicesDir returns the full path to the per-pod data directory under
   140  // which volumes are created for the specified pod. This directory may not
   141  // exist if the pod does not exist.
   142  func (kl *Kubelet) getPodVolumeDevicesDir(podUID types.UID) string {
   143  	return filepath.Join(kl.getPodDir(podUID), config.DefaultKubeletVolumeDevicesDirName)
   144  }
   145  
   146  // getPodVolumeDeviceDir returns the full path to the directory which represents the
   147  // named plugin for specified pod. This directory may not exist if the pod does not exist.
   148  func (kl *Kubelet) getPodVolumeDeviceDir(podUID types.UID, pluginName string) string {
   149  	return filepath.Join(kl.getPodVolumeDevicesDir(podUID), pluginName)
   150  }
   151  
   152  // getPodPluginsDir returns the full path to the per-pod data directory under
   153  // which plugins may store data for the specified pod.  This directory may not
   154  // exist if the pod does not exist.
   155  func (kl *Kubelet) getPodPluginsDir(podUID types.UID) string {
   156  	return filepath.Join(kl.getPodDir(podUID), config.DefaultKubeletPluginsDirName)
   157  }
   158  
   159  // getPodPluginDir returns a data directory name for a given plugin name for a
   160  // given pod UID.  Plugins can use these directories to store data that they
   161  // need to persist.  For non-per-pod plugin data, see getPluginDir.
   162  func (kl *Kubelet) getPodPluginDir(podUID types.UID, pluginName string) string {
   163  	return filepath.Join(kl.getPodPluginsDir(podUID), pluginName)
   164  }
   165  
   166  // getPodContainerDir returns the full path to the per-pod data directory under
   167  // which container data is held for the specified pod.  This directory may not
   168  // exist if the pod or container does not exist.
   169  func (kl *Kubelet) getPodContainerDir(podUID types.UID, ctrName string) string {
   170  	return filepath.Join(kl.getPodDir(podUID), config.DefaultKubeletContainersDirName, ctrName)
   171  }
   172  
   173  // getPodResourcesSocket returns the full path to the directory containing the pod resources socket
   174  func (kl *Kubelet) getPodResourcesDir() string {
   175  	return filepath.Join(kl.getRootDir(), config.DefaultKubeletPodResourcesDirName)
   176  }
   177  
   178  // GetPods returns all pods bound to the kubelet and their spec, and the mirror
   179  // pods.
   180  func (kl *Kubelet) GetPods() []*v1.Pod {
   181  	pods := kl.podManager.GetPods()
   182  	// a kubelet running without apiserver requires an additional
   183  	// update of the static pod status. See #57106
   184  	for i, p := range pods {
   185  		if kubelettypes.IsStaticPod(p) {
   186  			if status, ok := kl.statusManager.GetPodStatus(p.UID); ok {
   187  				klog.V(2).InfoS("Pod status updated", "pod", klog.KObj(p), "status", status.Phase)
   188  				// do not mutate the cache
   189  				p = p.DeepCopy()
   190  				p.Status = status
   191  				pods[i] = p
   192  			}
   193  		}
   194  	}
   195  	return pods
   196  }
   197  
   198  // GetRunningPods returns all pods running on kubelet from looking at the
   199  // container runtime cache. This function converts kubecontainer.Pod to
   200  // v1.Pod, so only the fields that exist in both kubecontainer.Pod and
   201  // v1.Pod are considered meaningful.
   202  func (kl *Kubelet) GetRunningPods(ctx context.Context) ([]*v1.Pod, error) {
   203  	pods, err := kl.runtimeCache.GetPods(ctx)
   204  	if err != nil {
   205  		return nil, err
   206  	}
   207  
   208  	apiPods := make([]*v1.Pod, 0, len(pods))
   209  	for _, pod := range pods {
   210  		apiPods = append(apiPods, pod.ToAPIPod())
   211  	}
   212  	return apiPods, nil
   213  }
   214  
   215  // GetPodByFullName gets the pod with the given 'full' name, which
   216  // incorporates the namespace as well as whether the pod was found.
   217  func (kl *Kubelet) GetPodByFullName(podFullName string) (*v1.Pod, bool) {
   218  	return kl.podManager.GetPodByFullName(podFullName)
   219  }
   220  
   221  // GetPodByName provides the first pod that matches namespace and name, as well
   222  // as whether the pod was found.
   223  func (kl *Kubelet) GetPodByName(namespace, name string) (*v1.Pod, bool) {
   224  	return kl.podManager.GetPodByName(namespace, name)
   225  }
   226  
   227  // GetPodByCgroupfs provides the pod that maps to the specified cgroup, as well
   228  // as whether the pod was found.
   229  func (kl *Kubelet) GetPodByCgroupfs(cgroupfs string) (*v1.Pod, bool) {
   230  	pcm := kl.containerManager.NewPodContainerManager()
   231  	if result, podUID := pcm.IsPodCgroup(cgroupfs); result {
   232  		return kl.podManager.GetPodByUID(podUID)
   233  	}
   234  	return nil, false
   235  }
   236  
   237  // GetHostname Returns the hostname as the kubelet sees it.
   238  func (kl *Kubelet) GetHostname() string {
   239  	return kl.hostname
   240  }
   241  
   242  // getRuntime returns the current Runtime implementation in use by the kubelet.
   243  func (kl *Kubelet) getRuntime() kubecontainer.Runtime {
   244  	return kl.containerRuntime
   245  }
   246  
   247  // GetNode returns the node info for the configured node name of this Kubelet.
   248  func (kl *Kubelet) GetNode() (*v1.Node, error) {
   249  	if kl.kubeClient == nil {
   250  		return kl.initialNode(context.TODO())
   251  	}
   252  	return kl.nodeLister.Get(string(kl.nodeName))
   253  }
   254  
   255  // getNodeAnyWay() must return a *v1.Node which is required by RunGeneralPredicates().
   256  // The *v1.Node is obtained as follows:
   257  // Return kubelet's nodeInfo for this node, except on error or if in standalone mode,
   258  // in which case return a manufactured nodeInfo representing a node with no pods,
   259  // zero capacity, and the default labels.
   260  func (kl *Kubelet) getNodeAnyWay() (*v1.Node, error) {
   261  	if kl.kubeClient != nil {
   262  		if n, err := kl.nodeLister.Get(string(kl.nodeName)); err == nil {
   263  			return n, nil
   264  		}
   265  	}
   266  	return kl.initialNode(context.TODO())
   267  }
   268  
   269  // GetNodeConfig returns the container manager node config.
   270  func (kl *Kubelet) GetNodeConfig() cm.NodeConfig {
   271  	return kl.containerManager.GetNodeConfig()
   272  }
   273  
   274  // GetPodCgroupRoot returns the listeral cgroupfs value for the cgroup containing all pods
   275  func (kl *Kubelet) GetPodCgroupRoot() string {
   276  	return kl.containerManager.GetPodCgroupRoot()
   277  }
   278  
   279  // GetHostIPs returns host IPs or nil in case of error.
   280  func (kl *Kubelet) GetHostIPs() ([]net.IP, error) {
   281  	node, err := kl.GetNode()
   282  	if err != nil {
   283  		return nil, fmt.Errorf("cannot get node: %v", err)
   284  	}
   285  	return utilnode.GetNodeHostIPs(node)
   286  }
   287  
   288  // getHostIPsAnyWay attempts to return the host IPs from kubelet's nodeInfo, or
   289  // the initialNode.
   290  func (kl *Kubelet) getHostIPsAnyWay() ([]net.IP, error) {
   291  	node, err := kl.getNodeAnyWay()
   292  	if err != nil {
   293  		return nil, err
   294  	}
   295  	return utilnode.GetNodeHostIPs(node)
   296  }
   297  
   298  // GetExtraSupplementalGroupsForPod returns a list of the extra
   299  // supplemental groups for the Pod. These extra supplemental groups come
   300  // from annotations on persistent volumes that the pod depends on.
   301  func (kl *Kubelet) GetExtraSupplementalGroupsForPod(pod *v1.Pod) []int64 {
   302  	return kl.volumeManager.GetExtraSupplementalGroupsForPod(pod)
   303  }
   304  
   305  // getPodVolumePathListFromDisk returns a list of the volume paths by reading the
   306  // volume directories for the given pod from the disk.
   307  func (kl *Kubelet) getPodVolumePathListFromDisk(podUID types.UID) ([]string, error) {
   308  	volumes := []string{}
   309  	podVolDir := kl.getPodVolumesDir(podUID)
   310  
   311  	if pathExists, pathErr := mount.PathExists(podVolDir); pathErr != nil {
   312  		return volumes, fmt.Errorf("error checking if path %q exists: %v", podVolDir, pathErr)
   313  	} else if !pathExists {
   314  		klog.V(6).InfoS("Path does not exist", "path", podVolDir)
   315  		return volumes, nil
   316  	}
   317  
   318  	volumePluginDirs, err := os.ReadDir(podVolDir)
   319  	if err != nil {
   320  		klog.ErrorS(err, "Could not read directory", "path", podVolDir)
   321  		return volumes, err
   322  	}
   323  	for _, volumePluginDir := range volumePluginDirs {
   324  		volumePluginName := volumePluginDir.Name()
   325  		volumePluginPath := filepath.Join(podVolDir, volumePluginName)
   326  		volumeDirs, err := utilpath.ReadDirNoStat(volumePluginPath)
   327  		if err != nil {
   328  			return volumes, fmt.Errorf("could not read directory %s: %v", volumePluginPath, err)
   329  		}
   330  		unescapePluginName := utilstrings.UnescapeQualifiedName(volumePluginName)
   331  
   332  		if unescapePluginName != csi.CSIPluginName {
   333  			for _, volumeDir := range volumeDirs {
   334  				volumes = append(volumes, filepath.Join(volumePluginPath, volumeDir))
   335  			}
   336  		} else {
   337  			// For CSI volumes, the mounted volume path has an extra sub path "/mount", so also add it
   338  			// to the list if the mounted path exists.
   339  			for _, volumeDir := range volumeDirs {
   340  				path := filepath.Join(volumePluginPath, volumeDir)
   341  				csimountpath := csi.GetCSIMounterPath(path)
   342  				if pathExists, _ := mount.PathExists(csimountpath); pathExists {
   343  					volumes = append(volumes, csimountpath)
   344  				}
   345  			}
   346  		}
   347  	}
   348  	return volumes, nil
   349  }
   350  
   351  func (kl *Kubelet) getMountedVolumePathListFromDisk(podUID types.UID) ([]string, error) {
   352  	mountedVolumes := []string{}
   353  	volumePaths, err := kl.getPodVolumePathListFromDisk(podUID)
   354  	if err != nil {
   355  		return mountedVolumes, err
   356  	}
   357  	// Only use IsLikelyNotMountPoint to check might not cover all cases. For CSI volumes that
   358  	// either: 1) don't mount or 2) bind mount in the rootfs, the mount check will not work as expected.
   359  	// We plan to remove this mountpoint check as a condition before deleting pods since it is
   360  	// not reliable and the condition might be different for different types of volumes. But it requires
   361  	// a reliable way to clean up unused volume dir to avoid problems during pod deletion. See discussion in issue #74650
   362  	for _, volumePath := range volumePaths {
   363  		isNotMount, err := kl.mounter.IsLikelyNotMountPoint(volumePath)
   364  		if err != nil {
   365  			return mountedVolumes, fmt.Errorf("fail to check mount point %q: %v", volumePath, err)
   366  		}
   367  		if !isNotMount {
   368  			mountedVolumes = append(mountedVolumes, volumePath)
   369  		}
   370  	}
   371  	return mountedVolumes, nil
   372  }
   373  
   374  // getPodVolumeSubpathListFromDisk returns a list of the volume-subpath paths by reading the
   375  // subpath directories for the given pod from the disk.
   376  func (kl *Kubelet) getPodVolumeSubpathListFromDisk(podUID types.UID) ([]string, error) {
   377  	volumes := []string{}
   378  	podSubpathsDir := kl.getPodVolumeSubpathsDir(podUID)
   379  
   380  	if pathExists, pathErr := mount.PathExists(podSubpathsDir); pathErr != nil {
   381  		return nil, fmt.Errorf("error checking if path %q exists: %v", podSubpathsDir, pathErr)
   382  	} else if !pathExists {
   383  		return volumes, nil
   384  	}
   385  
   386  	// Explicitly walks /<volume>/<container name>/<subPathIndex>
   387  	volumePluginDirs, err := os.ReadDir(podSubpathsDir)
   388  	if err != nil {
   389  		klog.ErrorS(err, "Could not read directory", "path", podSubpathsDir)
   390  		return volumes, err
   391  	}
   392  	for _, volumePluginDir := range volumePluginDirs {
   393  		volumePluginName := volumePluginDir.Name()
   394  		volumePluginPath := filepath.Join(podSubpathsDir, volumePluginName)
   395  		containerDirs, err := os.ReadDir(volumePluginPath)
   396  		if err != nil {
   397  			return volumes, fmt.Errorf("could not read directory %s: %v", volumePluginPath, err)
   398  		}
   399  		for _, containerDir := range containerDirs {
   400  			containerName := containerDir.Name()
   401  			containerPath := filepath.Join(volumePluginPath, containerName)
   402  			// Switch to ReadDirNoStat at the subPathIndex level to prevent issues with stat'ing
   403  			// mount points that may not be responsive
   404  			subPaths, err := utilpath.ReadDirNoStat(containerPath)
   405  			if err != nil {
   406  				return volumes, fmt.Errorf("could not read directory %s: %v", containerPath, err)
   407  			}
   408  			for _, subPathDir := range subPaths {
   409  				volumes = append(volumes, filepath.Join(containerPath, subPathDir))
   410  			}
   411  		}
   412  	}
   413  	return volumes, nil
   414  }
   415  
   416  // GetRequestedContainersInfo returns container info.
   417  func (kl *Kubelet) GetRequestedContainersInfo(containerName string, options cadvisorv2.RequestOptions) (map[string]*cadvisorapiv1.ContainerInfo, error) {
   418  	return kl.cadvisor.GetRequestedContainersInfo(containerName, options)
   419  }
   420  
   421  // GetVersionInfo returns information about the version of cAdvisor in use.
   422  func (kl *Kubelet) GetVersionInfo() (*cadvisorapiv1.VersionInfo, error) {
   423  	return kl.cadvisor.VersionInfo()
   424  }
   425  
   426  // GetCachedMachineInfo assumes that the machine info can't change without a reboot
   427  func (kl *Kubelet) GetCachedMachineInfo() (*cadvisorapiv1.MachineInfo, error) {
   428  	kl.machineInfoLock.RLock()
   429  	defer kl.machineInfoLock.RUnlock()
   430  	return kl.machineInfo, nil
   431  }
   432  
   433  func (kl *Kubelet) setCachedMachineInfo(info *cadvisorapiv1.MachineInfo) {
   434  	kl.machineInfoLock.Lock()
   435  	defer kl.machineInfoLock.Unlock()
   436  	kl.machineInfo = info
   437  }