...

Source file src/k8s.io/kubernetes/pkg/kubelet/kubelet_getters.go

Documentation: k8s.io/kubernetes/pkg/kubelet

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

View as plain text