1
16
17 package collectors
18
19 import (
20 "context"
21
22 "k8s.io/apimachinery/pkg/util/sets"
23 "k8s.io/component-base/metrics"
24 stats "k8s.io/kubelet/pkg/apis/stats/v1alpha1"
25 kubeletmetrics "k8s.io/kubernetes/pkg/kubelet/metrics"
26 serverstats "k8s.io/kubernetes/pkg/kubelet/server/stats"
27 )
28
29 var (
30 volumeStatsCapacityBytesDesc = metrics.NewDesc(
31 metrics.BuildFQName("", kubeletmetrics.KubeletSubsystem, kubeletmetrics.VolumeStatsCapacityBytesKey),
32 "Capacity in bytes of the volume",
33 []string{"namespace", "persistentvolumeclaim"}, nil,
34 metrics.ALPHA, "",
35 )
36 volumeStatsAvailableBytesDesc = metrics.NewDesc(
37 metrics.BuildFQName("", kubeletmetrics.KubeletSubsystem, kubeletmetrics.VolumeStatsAvailableBytesKey),
38 "Number of available bytes in the volume",
39 []string{"namespace", "persistentvolumeclaim"}, nil,
40 metrics.ALPHA, "",
41 )
42 volumeStatsUsedBytesDesc = metrics.NewDesc(
43 metrics.BuildFQName("", kubeletmetrics.KubeletSubsystem, kubeletmetrics.VolumeStatsUsedBytesKey),
44 "Number of used bytes in the volume",
45 []string{"namespace", "persistentvolumeclaim"}, nil,
46 metrics.ALPHA, "",
47 )
48 volumeStatsInodesDesc = metrics.NewDesc(
49 metrics.BuildFQName("", kubeletmetrics.KubeletSubsystem, kubeletmetrics.VolumeStatsInodesKey),
50 "Maximum number of inodes in the volume",
51 []string{"namespace", "persistentvolumeclaim"}, nil,
52 metrics.ALPHA, "",
53 )
54 volumeStatsInodesFreeDesc = metrics.NewDesc(
55 metrics.BuildFQName("", kubeletmetrics.KubeletSubsystem, kubeletmetrics.VolumeStatsInodesFreeKey),
56 "Number of free inodes in the volume",
57 []string{"namespace", "persistentvolumeclaim"}, nil,
58 metrics.ALPHA, "",
59 )
60 volumeStatsInodesUsedDesc = metrics.NewDesc(
61 metrics.BuildFQName("", kubeletmetrics.KubeletSubsystem, kubeletmetrics.VolumeStatsInodesUsedKey),
62 "Number of used inodes in the volume",
63 []string{"namespace", "persistentvolumeclaim"}, nil,
64 metrics.ALPHA, "",
65 )
66
67 volumeStatsHealthAbnormalDesc = metrics.NewDesc(
68 metrics.BuildFQName("", kubeletmetrics.KubeletSubsystem, kubeletmetrics.VolumeStatsHealthStatusAbnormalKey),
69 "Abnormal volume health status. The count is either 1 or 0. 1 indicates the volume is unhealthy, 0 indicates volume is healthy",
70 []string{"namespace", "persistentvolumeclaim"}, nil,
71 metrics.ALPHA, "")
72 )
73
74 type volumeStatsCollector struct {
75 metrics.BaseStableCollector
76
77 statsProvider serverstats.Provider
78 }
79
80
81 var _ metrics.StableCollector = &volumeStatsCollector{}
82
83
84 func NewVolumeStatsCollector(statsProvider serverstats.Provider) metrics.StableCollector {
85 return &volumeStatsCollector{statsProvider: statsProvider}
86 }
87
88
89 func (collector *volumeStatsCollector) DescribeWithStability(ch chan<- *metrics.Desc) {
90 ch <- volumeStatsCapacityBytesDesc
91 ch <- volumeStatsAvailableBytesDesc
92 ch <- volumeStatsUsedBytesDesc
93 ch <- volumeStatsInodesDesc
94 ch <- volumeStatsInodesFreeDesc
95 ch <- volumeStatsInodesUsedDesc
96 ch <- volumeStatsHealthAbnormalDesc
97 }
98
99
100 func (collector *volumeStatsCollector) CollectWithStability(ch chan<- metrics.Metric) {
101 ctx := context.Background()
102 podStats, err := collector.statsProvider.ListPodStats(ctx)
103 if err != nil {
104 return
105 }
106 addGauge := func(desc *metrics.Desc, pvcRef *stats.PVCReference, v float64, lv ...string) {
107 lv = append([]string{pvcRef.Namespace, pvcRef.Name}, lv...)
108 ch <- metrics.NewLazyConstMetric(desc, metrics.GaugeValue, v, lv...)
109 }
110 allPVCs := sets.String{}
111 for _, podStat := range podStats {
112 if podStat.VolumeStats == nil {
113 continue
114 }
115 for _, volumeStat := range podStat.VolumeStats {
116 pvcRef := volumeStat.PVCRef
117 if pvcRef == nil {
118
119 continue
120 }
121 pvcUniqStr := pvcRef.Namespace + "/" + pvcRef.Name
122 if allPVCs.Has(pvcUniqStr) {
123
124 continue
125 }
126 addGauge(volumeStatsCapacityBytesDesc, pvcRef, float64(*volumeStat.CapacityBytes))
127 addGauge(volumeStatsAvailableBytesDesc, pvcRef, float64(*volumeStat.AvailableBytes))
128 addGauge(volumeStatsUsedBytesDesc, pvcRef, float64(*volumeStat.UsedBytes))
129 addGauge(volumeStatsInodesDesc, pvcRef, float64(*volumeStat.Inodes))
130 addGauge(volumeStatsInodesFreeDesc, pvcRef, float64(*volumeStat.InodesFree))
131 addGauge(volumeStatsInodesUsedDesc, pvcRef, float64(*volumeStat.InodesUsed))
132 if volumeStat.VolumeHealthStats != nil {
133 addGauge(volumeStatsHealthAbnormalDesc, pvcRef, convertBoolToFloat64(volumeStat.VolumeHealthStats.Abnormal))
134 }
135 allPVCs.Insert(pvcUniqStr)
136 }
137 }
138 }
139
140 func convertBoolToFloat64(boolVal bool) float64 {
141 if boolVal {
142 return 1
143 }
144
145 return 0
146 }
147
View as plain text