1
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
34 type PodEtcHostsPathFunc func(podUID types.UID) string
35
36
37 type metricsProviderByPath map[string]volume.MetricsProvider
38
39
40 type HostStatsProvider interface {
41
42 getPodLogStats(podNamespace, podName string, podUID types.UID, rootFsInfo *cadvisorapiv2.FsInfo) (*statsapi.FsStats, error)
43
44 getPodContainerLogStats(podNamespace, podName string, podUID types.UID, containerName string, rootFsInfo *cadvisorapiv2.FsInfo) (*statsapi.FsStats, error)
45
46 getPodEtcHostsStats(podUID types.UID, rootFsInfo *cadvisorapiv2.FsInfo) (*statsapi.FsStats, error)
47 }
48
49 type hostStatsProvider struct {
50
51 osInterface kubecontainer.OSInterface
52
53 podEtcHostsPathFunc PodEtcHostsPathFunc
54
55 podLogsDirectory string
56 }
57
58
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
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
85 func (h hostStatsProvider) getPodEtcHostsStats(podUID types.UID, rootFsInfo *cadvisorapiv2.FsInfo) (*statsapi.FsStats, error) {
86
87 podEtcHostsPath := h.podEtcHostsPathFunc(podUID)
88
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
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
129 fpath := filepath.Join(dirname, f.Name())
130 results[fpath] = volume.NewMetricsDu(fpath)
131 }
132 return results, nil
133 }
134
135
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
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 }
162
View as plain text