k8s.io/kubernetes@v1.31.0-alpha.0.0.20240520171757-56147500dadc/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 // 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 }