k8s.io/kubernetes@v1.29.3/pkg/kubelet/metrics/collectors/volume_stats.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 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 // Check if volumeStatsCollector implements necessary interface 81 var _ metrics.StableCollector = &volumeStatsCollector{} 82 83 // NewVolumeStatsCollector creates a volume stats metrics.StableCollector. 84 func NewVolumeStatsCollector(statsProvider serverstats.Provider) metrics.StableCollector { 85 return &volumeStatsCollector{statsProvider: statsProvider} 86 } 87 88 // DescribeWithStability implements the metrics.StableCollector interface. 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 // CollectWithStability implements the metrics.StableCollector interface. 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 // ignore if no PVC reference 119 continue 120 } 121 pvcUniqStr := pvcRef.Namespace + "/" + pvcRef.Name 122 if allPVCs.Has(pvcUniqStr) { 123 // ignore if already collected 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 }