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 }