k8s.io/kubernetes@v1.29.3/pkg/kubelet/stats/host_stats_provider.go (about) 1 /* 2 Copyright 2018 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 stats 18 19 import ( 20 "fmt" 21 "os" 22 "path/filepath" 23 24 cadvisorapiv2 "github.com/google/cadvisor/info/v2" 25 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 26 "k8s.io/apimachinery/pkg/types" 27 statsapi "k8s.io/kubelet/pkg/apis/stats/v1alpha1" 28 kubecontainer "k8s.io/kubernetes/pkg/kubelet/container" 29 "k8s.io/kubernetes/pkg/kubelet/kuberuntime" 30 "k8s.io/kubernetes/pkg/volume" 31 ) 32 33 // PodEtcHostsPathFunc is a function to fetch a etc hosts path by pod uid and whether etc host path is supported by the runtime 34 type PodEtcHostsPathFunc func(podUID types.UID) string 35 36 // metricsProviderByPath maps a path to its metrics provider 37 type metricsProviderByPath map[string]volume.MetricsProvider 38 39 // HostStatsProvider defines an interface for providing host stats associated with pod. 40 type HostStatsProvider interface { 41 // getPodLogStats gets stats associated with pod log usage 42 getPodLogStats(podNamespace, podName string, podUID types.UID, rootFsInfo *cadvisorapiv2.FsInfo) (*statsapi.FsStats, error) 43 // getPodContainerLogStats gets stats associated with container log usage 44 getPodContainerLogStats(podNamespace, podName string, podUID types.UID, containerName string, rootFsInfo *cadvisorapiv2.FsInfo) (*statsapi.FsStats, error) 45 // getPodEtcHostsStats gets stats associated with pod etc-hosts usage 46 getPodEtcHostsStats(podUID types.UID, rootFsInfo *cadvisorapiv2.FsInfo) (*statsapi.FsStats, error) 47 } 48 49 type hostStatsProvider struct { 50 // osInterface is the interface for syscalls. 51 osInterface kubecontainer.OSInterface 52 // podEtcHostsPathFunc fetches a pod etc hosts path by uid. 53 podEtcHostsPathFunc PodEtcHostsPathFunc 54 } 55 56 // NewHostStatsProvider returns a new HostStatsProvider type struct. 57 func NewHostStatsProvider(osInterface kubecontainer.OSInterface, podEtcHostsPathFunc PodEtcHostsPathFunc) HostStatsProvider { 58 return hostStatsProvider{ 59 osInterface: osInterface, 60 podEtcHostsPathFunc: podEtcHostsPathFunc, 61 } 62 } 63 64 func (h hostStatsProvider) getPodLogStats(podNamespace, podName string, podUID types.UID, rootFsInfo *cadvisorapiv2.FsInfo) (*statsapi.FsStats, error) { 65 metricsByPath, err := h.podLogMetrics(podNamespace, podName, podUID) 66 if err != nil { 67 return nil, err 68 } 69 return metricsByPathToFsStats(metricsByPath, rootFsInfo) 70 } 71 72 // getPodContainerLogStats gets stats for container 73 func (h hostStatsProvider) getPodContainerLogStats(podNamespace, podName string, podUID types.UID, containerName string, rootFsInfo *cadvisorapiv2.FsInfo) (*statsapi.FsStats, error) { 74 metricsByPath, err := h.podContainerLogMetrics(podNamespace, podName, podUID, containerName) 75 if err != nil { 76 return nil, err 77 } 78 return metricsByPathToFsStats(metricsByPath, rootFsInfo) 79 } 80 81 // getPodEtcHostsStats gets status for pod etc hosts usage 82 func (h hostStatsProvider) getPodEtcHostsStats(podUID types.UID, rootFsInfo *cadvisorapiv2.FsInfo) (*statsapi.FsStats, error) { 83 // Runtimes may not support etc hosts file (Windows with docker) 84 podEtcHostsPath := h.podEtcHostsPathFunc(podUID) 85 // Some pods have an explicit /etc/hosts mount and the Kubelet will not create an etc-hosts file for them 86 if _, err := os.Stat(podEtcHostsPath); os.IsNotExist(err) { 87 return nil, nil 88 } 89 90 metrics := volume.NewMetricsDu(podEtcHostsPath) 91 hostMetrics, err := metrics.GetMetrics() 92 if err != nil { 93 return nil, fmt.Errorf("failed to get stats %v", err) 94 } 95 result := rootFsInfoToFsStats(rootFsInfo) 96 usedBytes := uint64(hostMetrics.Used.Value()) 97 inodesUsed := uint64(hostMetrics.InodesUsed.Value()) 98 result.UsedBytes = addUsage(result.UsedBytes, &usedBytes) 99 result.InodesUsed = addUsage(result.InodesUsed, &inodesUsed) 100 result.Time = maxUpdateTime(&result.Time, &hostMetrics.Time) 101 return result, nil 102 } 103 104 func (h hostStatsProvider) podLogMetrics(podNamespace, podName string, podUID types.UID) (metricsProviderByPath, error) { 105 podLogsDirectoryPath := kuberuntime.BuildPodLogsDirectory(podNamespace, podName, podUID) 106 return h.fileMetricsByDir(podLogsDirectoryPath) 107 } 108 109 func (h hostStatsProvider) podContainerLogMetrics(podNamespace, podName string, podUID types.UID, containerName string) (metricsProviderByPath, error) { 110 podContainerLogsDirectoryPath := kuberuntime.BuildContainerLogsDirectory(podNamespace, podName, podUID, containerName) 111 return h.fileMetricsByDir(podContainerLogsDirectoryPath) 112 } 113 114 // fileMetricsByDir returns metrics by path for each file under specified directory 115 func (h hostStatsProvider) fileMetricsByDir(dirname string) (metricsProviderByPath, error) { 116 files, err := h.osInterface.ReadDir(dirname) 117 if err != nil { 118 return nil, err 119 } 120 results := metricsProviderByPath{} 121 for _, f := range files { 122 if f.IsDir() { 123 continue 124 } 125 // Only include *files* under pod log directory. 126 fpath := filepath.Join(dirname, f.Name()) 127 results[fpath] = volume.NewMetricsDu(fpath) 128 } 129 return results, nil 130 } 131 132 // metricsByPathToFsStats converts a metrics provider by path to fs stats 133 func metricsByPathToFsStats(metricsByPath metricsProviderByPath, rootFsInfo *cadvisorapiv2.FsInfo) (*statsapi.FsStats, error) { 134 result := rootFsInfoToFsStats(rootFsInfo) 135 for fpath, metrics := range metricsByPath { 136 hostMetrics, err := metrics.GetMetrics() 137 if err != nil { 138 return nil, fmt.Errorf("failed to get fsstats for %q: %v", fpath, err) 139 } 140 usedBytes := uint64(hostMetrics.Used.Value()) 141 inodesUsed := uint64(hostMetrics.InodesUsed.Value()) 142 result.UsedBytes = addUsage(result.UsedBytes, &usedBytes) 143 result.InodesUsed = addUsage(result.InodesUsed, &inodesUsed) 144 result.Time = maxUpdateTime(&result.Time, &hostMetrics.Time) 145 } 146 return result, nil 147 } 148 149 // rootFsInfoToFsStats is a utility to convert rootFsInfo into statsapi.FsStats 150 func rootFsInfoToFsStats(rootFsInfo *cadvisorapiv2.FsInfo) *statsapi.FsStats { 151 return &statsapi.FsStats{ 152 Time: metav1.NewTime(rootFsInfo.Timestamp), 153 AvailableBytes: &rootFsInfo.Available, 154 CapacityBytes: &rootFsInfo.Capacity, 155 InodesFree: rootFsInfo.InodesFree, 156 Inodes: rootFsInfo.Inodes, 157 } 158 }