1
16
17 package collectors
18
19 import (
20 "context"
21 "strings"
22 "testing"
23
24 "github.com/golang/mock/gomock"
25 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
26 "k8s.io/component-base/metrics/testutil"
27 statsapi "k8s.io/kubelet/pkg/apis/stats/v1alpha1"
28 statstest "k8s.io/kubernetes/pkg/kubelet/server/stats/testing"
29 )
30
31 func newUint64Pointer(i uint64) *uint64 {
32 return &i
33 }
34
35 func TestVolumeStatsCollector(t *testing.T) {
36 ctx := context.Background()
37
38
39 const metadata = `
40 # HELP kubelet_volume_stats_available_bytes [ALPHA] Number of available bytes in the volume
41 # TYPE kubelet_volume_stats_available_bytes gauge
42 # HELP kubelet_volume_stats_capacity_bytes [ALPHA] Capacity in bytes of the volume
43 # TYPE kubelet_volume_stats_capacity_bytes gauge
44 # HELP kubelet_volume_stats_inodes [ALPHA] Maximum number of inodes in the volume
45 # TYPE kubelet_volume_stats_inodes gauge
46 # HELP kubelet_volume_stats_inodes_free [ALPHA] Number of free inodes in the volume
47 # TYPE kubelet_volume_stats_inodes_free gauge
48 # HELP kubelet_volume_stats_inodes_used [ALPHA] Number of used inodes in the volume
49 # TYPE kubelet_volume_stats_inodes_used gauge
50 # HELP kubelet_volume_stats_used_bytes [ALPHA] Number of used bytes in the volume
51 # TYPE kubelet_volume_stats_used_bytes gauge
52 # HELP kubelet_volume_stats_health_status_abnormal [ALPHA] Abnormal volume health status. The count is either 1 or 0. 1 indicates the volume is unhealthy, 0 indicates volume is healthy
53 # TYPE kubelet_volume_stats_health_status_abnormal gauge
54 `
55
56 var (
57 podStats = []statsapi.PodStats{
58 {
59 PodRef: statsapi.PodReference{Name: "test-pod", Namespace: "test-namespace", UID: "UID_test-pod"},
60 StartTime: metav1.Now(),
61 VolumeStats: []statsapi.VolumeStats{
62 {
63 FsStats: statsapi.FsStats{
64 Time: metav1.Now(),
65 AvailableBytes: newUint64Pointer(5.663154176e+09),
66 CapacityBytes: newUint64Pointer(1.0434699264e+10),
67 UsedBytes: newUint64Pointer(4.21789696e+09),
68 InodesFree: newUint64Pointer(655344),
69 Inodes: newUint64Pointer(655360),
70 InodesUsed: newUint64Pointer(16),
71 },
72 Name: "test",
73 PVCRef: nil,
74 },
75 {
76 FsStats: statsapi.FsStats{
77 Time: metav1.Now(),
78 AvailableBytes: newUint64Pointer(5.663154176e+09),
79 CapacityBytes: newUint64Pointer(1.0434699264e+10),
80 UsedBytes: newUint64Pointer(4.21789696e+09),
81 InodesFree: newUint64Pointer(655344),
82 Inodes: newUint64Pointer(655360),
83 InodesUsed: newUint64Pointer(16),
84 },
85 Name: "test",
86 PVCRef: &statsapi.PVCReference{
87 Name: "testpvc",
88 Namespace: "testns",
89 },
90 VolumeHealthStats: &statsapi.VolumeHealthStats{
91 Abnormal: true,
92 },
93 },
94 },
95 },
96 {
97
98 PodRef: statsapi.PodReference{Name: "test-pod-2", Namespace: "test-namespace", UID: "UID_test-pod"},
99 StartTime: metav1.Now(),
100 VolumeStats: []statsapi.VolumeStats{
101 {
102 FsStats: statsapi.FsStats{
103 Time: metav1.Now(),
104 AvailableBytes: newUint64Pointer(5.663154176e+09),
105 CapacityBytes: newUint64Pointer(1.0434699264e+10),
106 UsedBytes: newUint64Pointer(4.21789696e+09),
107 InodesFree: newUint64Pointer(655344),
108 Inodes: newUint64Pointer(655360),
109 InodesUsed: newUint64Pointer(16),
110 },
111 Name: "test",
112 PVCRef: &statsapi.PVCReference{
113 Name: "testpvc",
114 Namespace: "testns",
115 },
116 VolumeHealthStats: &statsapi.VolumeHealthStats{
117 Abnormal: true,
118 },
119 },
120 },
121 },
122 }
123
124 want = metadata + `
125 kubelet_volume_stats_available_bytes{namespace="testns",persistentvolumeclaim="testpvc"} 5.663154176e+09
126 kubelet_volume_stats_capacity_bytes{namespace="testns",persistentvolumeclaim="testpvc"} 1.0434699264e+10
127 kubelet_volume_stats_inodes{namespace="testns",persistentvolumeclaim="testpvc"} 655360
128 kubelet_volume_stats_inodes_free{namespace="testns",persistentvolumeclaim="testpvc"} 655344
129 kubelet_volume_stats_inodes_used{namespace="testns",persistentvolumeclaim="testpvc"} 16
130 kubelet_volume_stats_used_bytes{namespace="testns",persistentvolumeclaim="testpvc"} 4.21789696e+09
131 kubelet_volume_stats_health_status_abnormal{namespace="testns",persistentvolumeclaim="testpvc"} 1
132 `
133
134 metrics = []string{
135 "kubelet_volume_stats_available_bytes",
136 "kubelet_volume_stats_capacity_bytes",
137 "kubelet_volume_stats_inodes",
138 "kubelet_volume_stats_inodes_free",
139 "kubelet_volume_stats_inodes_used",
140 "kubelet_volume_stats_used_bytes",
141 "kubelet_volume_stats_health_status_abnormal",
142 }
143 )
144
145 mockCtrl := gomock.NewController(t)
146 defer mockCtrl.Finish()
147 mockStatsProvider := statstest.NewMockProvider(mockCtrl)
148
149 mockStatsProvider.EXPECT().ListPodStats(ctx).Return(podStats, nil).AnyTimes()
150 mockStatsProvider.EXPECT().ListPodStatsAndUpdateCPUNanoCoreUsage(ctx).Return(podStats, nil).AnyTimes()
151 if err := testutil.CustomCollectAndCompare(&volumeStatsCollector{statsProvider: mockStatsProvider}, strings.NewReader(want), metrics...); err != nil {
152 t.Errorf("unexpected collecting result:\n%s", err)
153 }
154 }
155
156 func TestVolumeStatsCollectorWithNullVolumeStatus(t *testing.T) {
157 ctx := context.Background()
158
159
160 const metadata = `
161 # HELP kubelet_volume_stats_available_bytes [ALPHA] Number of available bytes in the volume
162 # TYPE kubelet_volume_stats_available_bytes gauge
163 # HELP kubelet_volume_stats_capacity_bytes [ALPHA] Capacity in bytes of the volume
164 # TYPE kubelet_volume_stats_capacity_bytes gauge
165 # HELP kubelet_volume_stats_inodes [ALPHA] Maximum number of inodes in the volume
166 # TYPE kubelet_volume_stats_inodes gauge
167 # HELP kubelet_volume_stats_inodes_free [ALPHA] Number of free inodes in the volume
168 # TYPE kubelet_volume_stats_inodes_free gauge
169 # HELP kubelet_volume_stats_inodes_used [ALPHA] Number of used inodes in the volume
170 # TYPE kubelet_volume_stats_inodes_used gauge
171 # HELP kubelet_volume_stats_used_bytes [ALPHA] Number of used bytes in the volume
172 # TYPE kubelet_volume_stats_used_bytes gauge
173 `
174
175 var (
176 podStats = []statsapi.PodStats{
177 {
178 PodRef: statsapi.PodReference{Name: "test-pod", Namespace: "test-namespace", UID: "UID_test-pod"},
179 StartTime: metav1.Now(),
180 VolumeStats: []statsapi.VolumeStats{
181 {
182 FsStats: statsapi.FsStats{
183 Time: metav1.Now(),
184 AvailableBytes: newUint64Pointer(5.663154176e+09),
185 CapacityBytes: newUint64Pointer(1.0434699264e+10),
186 UsedBytes: newUint64Pointer(4.21789696e+09),
187 InodesFree: newUint64Pointer(655344),
188 Inodes: newUint64Pointer(655360),
189 InodesUsed: newUint64Pointer(16),
190 },
191 Name: "test",
192 PVCRef: nil,
193 },
194 {
195 FsStats: statsapi.FsStats{
196 Time: metav1.Now(),
197 AvailableBytes: newUint64Pointer(5.663154176e+09),
198 CapacityBytes: newUint64Pointer(1.0434699264e+10),
199 UsedBytes: newUint64Pointer(4.21789696e+09),
200 InodesFree: newUint64Pointer(655344),
201 Inodes: newUint64Pointer(655360),
202 InodesUsed: newUint64Pointer(16),
203 },
204 Name: "test",
205 PVCRef: &statsapi.PVCReference{
206 Name: "testpvc",
207 Namespace: "testns",
208 },
209 },
210 },
211 },
212 }
213
214 want = metadata + `
215 kubelet_volume_stats_available_bytes{namespace="testns",persistentvolumeclaim="testpvc"} 5.663154176e+09
216 kubelet_volume_stats_capacity_bytes{namespace="testns",persistentvolumeclaim="testpvc"} 1.0434699264e+10
217 kubelet_volume_stats_inodes{namespace="testns",persistentvolumeclaim="testpvc"} 655360
218 kubelet_volume_stats_inodes_free{namespace="testns",persistentvolumeclaim="testpvc"} 655344
219 kubelet_volume_stats_inodes_used{namespace="testns",persistentvolumeclaim="testpvc"} 16
220 kubelet_volume_stats_used_bytes{namespace="testns",persistentvolumeclaim="testpvc"} 4.21789696e+09
221 `
222
223 metrics = []string{
224 "kubelet_volume_stats_available_bytes",
225 "kubelet_volume_stats_capacity_bytes",
226 "kubelet_volume_stats_inodes",
227 "kubelet_volume_stats_inodes_free",
228 "kubelet_volume_stats_inodes_used",
229 "kubelet_volume_stats_used_bytes",
230 }
231 )
232
233 mockCtrl := gomock.NewController(t)
234 defer mockCtrl.Finish()
235 mockStatsProvider := statstest.NewMockProvider(mockCtrl)
236
237 mockStatsProvider.EXPECT().ListPodStats(ctx).Return(podStats, nil).AnyTimes()
238 mockStatsProvider.EXPECT().ListPodStatsAndUpdateCPUNanoCoreUsage(ctx).Return(podStats, nil).AnyTimes()
239 if err := testutil.CustomCollectAndCompare(&volumeStatsCollector{statsProvider: mockStatsProvider}, strings.NewReader(want), metrics...); err != nil {
240 t.Errorf("unexpected collecting result:\n%s", err)
241 }
242 }
243
View as plain text