k8s.io/kubernetes@v1.31.0-alpha.0.0.20240520171757-56147500dadc/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 // podLogsDirectory is the root directory path for pod logs. 55 podLogsDirectory string 56 } 57 58 // NewHostStatsProvider returns a new HostStatsProvider type struct. 59 func NewHostStatsProvider(osInterface kubecontainer.OSInterface, podEtcHostsPathFunc PodEtcHostsPathFunc, podLogsDirectory string) HostStatsProvider { 60 return hostStatsProvider{ 61 osInterface: osInterface, 62 podEtcHostsPathFunc: podEtcHostsPathFunc, 63 podLogsDirectory: podLogsDirectory, 64 } 65 } 66 67 func (h hostStatsProvider) getPodLogStats(podNamespace, podName string, podUID types.UID, rootFsInfo *cadvisorapiv2.FsInfo) (*statsapi.FsStats, error) { 68 metricsByPath, err := h.podLogMetrics(podNamespace, podName, podUID) 69 if err != nil { 70 return nil, err 71 } 72 return metricsByPathToFsStats(metricsByPath, rootFsInfo) 73 } 74 75 // getPodContainerLogStats gets stats for container 76 func (h hostStatsProvider) getPodContainerLogStats(podNamespace, podName string, podUID types.UID, containerName string, rootFsInfo *cadvisorapiv2.FsInfo) (*statsapi.FsStats, error) { 77 metricsByPath, err := h.podContainerLogMetrics(podNamespace, podName, podUID, containerName) 78 if err != nil { 79 return nil, err 80 } 81 return metricsByPathToFsStats(metricsByPath, rootFsInfo) 82 } 83 84 // getPodEtcHostsStats gets status for pod etc hosts usage 85 func (h hostStatsProvider) getPodEtcHostsStats(podUID types.UID, rootFsInfo *cadvisorapiv2.FsInfo) (*statsapi.FsStats, error) { 86 // Runtimes may not support etc hosts file (Windows with docker) 87 podEtcHostsPath := h.podEtcHostsPathFunc(podUID) 88 // Some pods have an explicit /etc/hosts mount and the Kubelet will not create an etc-hosts file for them 89 if _, err := os.Stat(podEtcHostsPath); os.IsNotExist(err) { 90 return nil, nil 91 } 92 93 metrics := volume.NewMetricsDu(podEtcHostsPath) 94 hostMetrics, err := metrics.GetMetrics() 95 if err != nil { 96 return nil, fmt.Errorf("failed to get stats %v", err) 97 } 98 result := rootFsInfoToFsStats(rootFsInfo) 99 usedBytes := uint64(hostMetrics.Used.Value()) 100 inodesUsed := uint64(hostMetrics.InodesUsed.Value()) 101 result.UsedBytes = addUsage(result.UsedBytes, &usedBytes) 102 result.InodesUsed = addUsage(result.InodesUsed, &inodesUsed) 103 result.Time = maxUpdateTime(&result.Time, &hostMetrics.Time) 104 return result, nil 105 } 106 107 func (h hostStatsProvider) podLogMetrics(podNamespace, podName string, podUID types.UID) (metricsProviderByPath, error) { 108 podLogsDirectoryPath := kuberuntime.BuildPodLogsDirectory(h.podLogsDirectory, podNamespace, podName, podUID) 109 return h.fileMetricsByDir(podLogsDirectoryPath) 110 } 111 112 func (h hostStatsProvider) podContainerLogMetrics(podNamespace, podName string, podUID types.UID, containerName string) (metricsProviderByPath, error) { 113 podContainerLogsDirectoryPath := kuberuntime.BuildContainerLogsDirectory(h.podLogsDirectory, podNamespace, podName, podUID, containerName) 114 return h.fileMetricsByDir(podContainerLogsDirectoryPath) 115 } 116 117 // fileMetricsByDir returns metrics by path for each file under specified directory 118 func (h hostStatsProvider) fileMetricsByDir(dirname string) (metricsProviderByPath, error) { 119 files, err := h.osInterface.ReadDir(dirname) 120 if err != nil { 121 return nil, err 122 } 123 results := metricsProviderByPath{} 124 for _, f := range files { 125 if f.IsDir() { 126 continue 127 } 128 // Only include *files* under pod log directory. 129 fpath := filepath.Join(dirname, f.Name()) 130 results[fpath] = volume.NewMetricsDu(fpath) 131 } 132 return results, nil 133 } 134 135 // metricsByPathToFsStats converts a metrics provider by path to fs stats 136 func metricsByPathToFsStats(metricsByPath metricsProviderByPath, rootFsInfo *cadvisorapiv2.FsInfo) (*statsapi.FsStats, error) { 137 result := rootFsInfoToFsStats(rootFsInfo) 138 for fpath, metrics := range metricsByPath { 139 hostMetrics, err := metrics.GetMetrics() 140 if err != nil { 141 return nil, fmt.Errorf("failed to get fsstats for %q: %v", fpath, err) 142 } 143 usedBytes := uint64(hostMetrics.Used.Value()) 144 inodesUsed := uint64(hostMetrics.InodesUsed.Value()) 145 result.UsedBytes = addUsage(result.UsedBytes, &usedBytes) 146 result.InodesUsed = addUsage(result.InodesUsed, &inodesUsed) 147 result.Time = maxUpdateTime(&result.Time, &hostMetrics.Time) 148 } 149 return result, nil 150 } 151 152 // rootFsInfoToFsStats is a utility to convert rootFsInfo into statsapi.FsStats 153 func rootFsInfoToFsStats(rootFsInfo *cadvisorapiv2.FsInfo) *statsapi.FsStats { 154 return &statsapi.FsStats{ 155 Time: metav1.NewTime(rootFsInfo.Timestamp), 156 AvailableBytes: &rootFsInfo.Available, 157 CapacityBytes: &rootFsInfo.Capacity, 158 InodesFree: rootFsInfo.InodesFree, 159 Inodes: rootFsInfo.Inodes, 160 } 161 }