1
2
3
4
19
20 package stats
21
22 import (
23 "context"
24 "testing"
25 "time"
26
27 "github.com/golang/mock/gomock"
28 fuzz "github.com/google/gofuzz"
29 "github.com/stretchr/testify/assert"
30
31 v1 "k8s.io/api/core/v1"
32 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
33 statsapi "k8s.io/kubelet/pkg/apis/stats/v1alpha1"
34 "k8s.io/kubernetes/pkg/kubelet/cm"
35 statstest "k8s.io/kubernetes/pkg/kubelet/server/stats/testing"
36 )
37
38 var (
39 imageFsStats = getFsStats()
40 rootFsStats = getFsStats()
41 node = &v1.Node{ObjectMeta: metav1.ObjectMeta{Name: "test-node"}}
42 nodeConfig = cm.NodeConfig{
43 RuntimeCgroupsName: "/runtime",
44 SystemCgroupsName: "/misc",
45 KubeletCgroupsName: "/kubelet",
46 }
47 cgroupRoot = "/kubepods"
48 rlimitStats = getRlimitStats()
49 )
50
51 func TestSummaryProviderGetStatsNoSplitFileSystem(t *testing.T) {
52 ctx := context.Background()
53 assert := assert.New(t)
54
55 podStats := []statsapi.PodStats{
56 {
57 PodRef: statsapi.PodReference{Name: "test-pod", Namespace: "test-namespace", UID: "UID_test-pod"},
58 StartTime: metav1.NewTime(time.Now()),
59 Containers: []statsapi.ContainerStats{*getContainerStats()},
60 Network: getNetworkStats(),
61 VolumeStats: []statsapi.VolumeStats{*getVolumeStats()},
62 },
63 }
64 cgroupStatsMap := map[string]struct {
65 cs *statsapi.ContainerStats
66 ns *statsapi.NetworkStats
67 }{
68 "/": {cs: getContainerStats(), ns: getNetworkStats()},
69 "/runtime": {cs: getContainerStats(), ns: getNetworkStats()},
70 "/misc": {cs: getContainerStats(), ns: getNetworkStats()},
71 "/kubelet": {cs: getContainerStats(), ns: getNetworkStats()},
72 "/pods": {cs: getContainerStats(), ns: getNetworkStats()},
73 }
74
75 mockCtrl := gomock.NewController(t)
76 defer mockCtrl.Finish()
77 mockStatsProvider := statstest.NewMockProvider(mockCtrl)
78
79 mockStatsProvider.EXPECT().GetNode().Return(node, nil)
80 mockStatsProvider.EXPECT().GetNodeConfig().Return(nodeConfig)
81 mockStatsProvider.EXPECT().GetPodCgroupRoot().Return(cgroupRoot)
82 mockStatsProvider.EXPECT().ListPodStats(ctx).Return(podStats, nil).AnyTimes()
83 mockStatsProvider.EXPECT().ListPodStatsAndUpdateCPUNanoCoreUsage(ctx).Return(podStats, nil)
84 mockStatsProvider.EXPECT().ImageFsStats(ctx).Return(imageFsStats, imageFsStats, nil)
85 mockStatsProvider.EXPECT().RootFsStats().Return(rootFsStats, nil)
86 mockStatsProvider.EXPECT().RlimitStats().Return(rlimitStats, nil)
87 mockStatsProvider.EXPECT().GetCgroupStats("/", true).Return(cgroupStatsMap["/"].cs, cgroupStatsMap["/"].ns, nil)
88 mockStatsProvider.EXPECT().GetCgroupStats("/runtime", false).Return(cgroupStatsMap["/runtime"].cs, cgroupStatsMap["/runtime"].ns, nil)
89 mockStatsProvider.EXPECT().GetCgroupStats("/misc", false).Return(cgroupStatsMap["/misc"].cs, cgroupStatsMap["/misc"].ns, nil)
90 mockStatsProvider.EXPECT().GetCgroupStats("/kubelet", false).Return(cgroupStatsMap["/kubelet"].cs, cgroupStatsMap["/kubelet"].ns, nil)
91 mockStatsProvider.EXPECT().GetCgroupStats("/kubepods", true).Return(cgroupStatsMap["/pods"].cs, cgroupStatsMap["/pods"].ns, nil)
92
93 kubeletCreationTime := metav1.Now()
94 systemBootTime := metav1.Now()
95 provider := summaryProviderImpl{kubeletCreationTime: kubeletCreationTime, systemBootTime: systemBootTime, provider: mockStatsProvider}
96 summary, err := provider.Get(ctx, true)
97 assert.NoError(err)
98
99 assert.Equal(summary.Node.NodeName, "test-node")
100 assert.Equal(summary.Node.StartTime, systemBootTime)
101 assert.Equal(summary.Node.CPU, cgroupStatsMap["/"].cs.CPU)
102 assert.Equal(summary.Node.Memory, cgroupStatsMap["/"].cs.Memory)
103 assert.Equal(summary.Node.Swap, cgroupStatsMap["/"].cs.Swap)
104 assert.Equal(summary.Node.Network, cgroupStatsMap["/"].ns)
105 assert.Equal(summary.Node.Fs, rootFsStats)
106 assert.Equal(summary.Node.Runtime, &statsapi.RuntimeStats{ContainerFs: imageFsStats, ImageFs: imageFsStats})
107
108 assert.Equal(len(summary.Node.SystemContainers), 4)
109 assert.Contains(summary.Node.SystemContainers, statsapi.ContainerStats{
110 Name: "kubelet",
111 StartTime: kubeletCreationTime,
112 CPU: cgroupStatsMap["/kubelet"].cs.CPU,
113 Memory: cgroupStatsMap["/kubelet"].cs.Memory,
114 Accelerators: cgroupStatsMap["/kubelet"].cs.Accelerators,
115 UserDefinedMetrics: cgroupStatsMap["/kubelet"].cs.UserDefinedMetrics,
116 Swap: cgroupStatsMap["/kubelet"].cs.Swap,
117 })
118 assert.Contains(summary.Node.SystemContainers, statsapi.ContainerStats{
119 Name: "misc",
120 StartTime: cgroupStatsMap["/misc"].cs.StartTime,
121 CPU: cgroupStatsMap["/misc"].cs.CPU,
122 Memory: cgroupStatsMap["/misc"].cs.Memory,
123 Accelerators: cgroupStatsMap["/misc"].cs.Accelerators,
124 UserDefinedMetrics: cgroupStatsMap["/misc"].cs.UserDefinedMetrics,
125 Swap: cgroupStatsMap["/misc"].cs.Swap,
126 })
127 assert.Contains(summary.Node.SystemContainers, statsapi.ContainerStats{
128 Name: "runtime",
129 StartTime: cgroupStatsMap["/runtime"].cs.StartTime,
130 CPU: cgroupStatsMap["/runtime"].cs.CPU,
131 Memory: cgroupStatsMap["/runtime"].cs.Memory,
132 Accelerators: cgroupStatsMap["/runtime"].cs.Accelerators,
133 UserDefinedMetrics: cgroupStatsMap["/runtime"].cs.UserDefinedMetrics,
134 Swap: cgroupStatsMap["/runtime"].cs.Swap,
135 })
136 assert.Contains(summary.Node.SystemContainers, statsapi.ContainerStats{
137 Name: "pods",
138 StartTime: cgroupStatsMap["/pods"].cs.StartTime,
139 CPU: cgroupStatsMap["/pods"].cs.CPU,
140 Memory: cgroupStatsMap["/pods"].cs.Memory,
141 Accelerators: cgroupStatsMap["/pods"].cs.Accelerators,
142 UserDefinedMetrics: cgroupStatsMap["/pods"].cs.UserDefinedMetrics,
143 Swap: cgroupStatsMap["/pods"].cs.Swap,
144 })
145 assert.Equal(summary.Pods, podStats)
146 }
147
148 func TestSummaryProviderGetStatsSplitImageFs(t *testing.T) {
149 ctx := context.Background()
150 assert := assert.New(t)
151
152 podStats := []statsapi.PodStats{
153 {
154 PodRef: statsapi.PodReference{Name: "test-pod", Namespace: "test-namespace", UID: "UID_test-pod"},
155 StartTime: metav1.NewTime(time.Now()),
156 Containers: []statsapi.ContainerStats{*getContainerStats()},
157 Network: getNetworkStats(),
158 VolumeStats: []statsapi.VolumeStats{*getVolumeStats()},
159 },
160 }
161 cgroupStatsMap := map[string]struct {
162 cs *statsapi.ContainerStats
163 ns *statsapi.NetworkStats
164 }{
165 "/": {cs: getContainerStats(), ns: getNetworkStats()},
166 "/runtime": {cs: getContainerStats(), ns: getNetworkStats()},
167 "/misc": {cs: getContainerStats(), ns: getNetworkStats()},
168 "/kubelet": {cs: getContainerStats(), ns: getNetworkStats()},
169 "/pods": {cs: getContainerStats(), ns: getNetworkStats()},
170 }
171
172 mockCtrl := gomock.NewController(t)
173 defer mockCtrl.Finish()
174 mockStatsProvider := statstest.NewMockProvider(mockCtrl)
175
176 mockStatsProvider.EXPECT().GetNode().Return(node, nil)
177 mockStatsProvider.EXPECT().GetNodeConfig().Return(nodeConfig)
178 mockStatsProvider.EXPECT().GetPodCgroupRoot().Return(cgroupRoot)
179 mockStatsProvider.EXPECT().ListPodStats(ctx).Return(podStats, nil).AnyTimes()
180 mockStatsProvider.EXPECT().ListPodStatsAndUpdateCPUNanoCoreUsage(ctx).Return(podStats, nil)
181 mockStatsProvider.EXPECT().RootFsStats().Return(rootFsStats, nil)
182 mockStatsProvider.EXPECT().RlimitStats().Return(rlimitStats, nil)
183 mockStatsProvider.EXPECT().GetCgroupStats("/", true).Return(cgroupStatsMap["/"].cs, cgroupStatsMap["/"].ns, nil)
184 mockStatsProvider.EXPECT().GetCgroupStats("/runtime", false).Return(cgroupStatsMap["/runtime"].cs, cgroupStatsMap["/runtime"].ns, nil)
185 mockStatsProvider.EXPECT().GetCgroupStats("/misc", false).Return(cgroupStatsMap["/misc"].cs, cgroupStatsMap["/misc"].ns, nil)
186 mockStatsProvider.EXPECT().GetCgroupStats("/kubelet", false).Return(cgroupStatsMap["/kubelet"].cs, cgroupStatsMap["/kubelet"].ns, nil)
187 mockStatsProvider.EXPECT().GetCgroupStats("/kubepods", true).Return(cgroupStatsMap["/pods"].cs, cgroupStatsMap["/pods"].ns, nil)
188
189 mockStatsProvider.EXPECT().ImageFsStats(ctx).Return(imageFsStats, rootFsStats, nil)
190
191 kubeletCreationTime := metav1.Now()
192 systemBootTime := metav1.Now()
193 provider := summaryProviderImpl{kubeletCreationTime: kubeletCreationTime, systemBootTime: systemBootTime, provider: mockStatsProvider}
194 summary, err := provider.Get(ctx, true)
195 assert.NoError(err)
196
197 assert.Equal(summary.Node.NodeName, "test-node")
198 assert.Equal(summary.Node.StartTime, systemBootTime)
199 assert.Equal(summary.Node.CPU, cgroupStatsMap["/"].cs.CPU)
200 assert.Equal(summary.Node.Memory, cgroupStatsMap["/"].cs.Memory)
201 assert.Equal(summary.Node.Swap, cgroupStatsMap["/"].cs.Swap)
202 assert.Equal(summary.Node.Network, cgroupStatsMap["/"].ns)
203 assert.Equal(summary.Node.Fs, rootFsStats)
204
205 assert.Equal(summary.Node.Runtime, &statsapi.RuntimeStats{ContainerFs: rootFsStats, ImageFs: imageFsStats})
206
207 assert.Equal(len(summary.Node.SystemContainers), 4)
208 assert.Contains(summary.Node.SystemContainers, statsapi.ContainerStats{
209 Name: "kubelet",
210 StartTime: kubeletCreationTime,
211 CPU: cgroupStatsMap["/kubelet"].cs.CPU,
212 Memory: cgroupStatsMap["/kubelet"].cs.Memory,
213 Accelerators: cgroupStatsMap["/kubelet"].cs.Accelerators,
214 UserDefinedMetrics: cgroupStatsMap["/kubelet"].cs.UserDefinedMetrics,
215 Swap: cgroupStatsMap["/kubelet"].cs.Swap,
216 })
217 assert.Contains(summary.Node.SystemContainers, statsapi.ContainerStats{
218 Name: "misc",
219 StartTime: cgroupStatsMap["/misc"].cs.StartTime,
220 CPU: cgroupStatsMap["/misc"].cs.CPU,
221 Memory: cgroupStatsMap["/misc"].cs.Memory,
222 Accelerators: cgroupStatsMap["/misc"].cs.Accelerators,
223 UserDefinedMetrics: cgroupStatsMap["/misc"].cs.UserDefinedMetrics,
224 Swap: cgroupStatsMap["/misc"].cs.Swap,
225 })
226 assert.Contains(summary.Node.SystemContainers, statsapi.ContainerStats{
227 Name: "runtime",
228 StartTime: cgroupStatsMap["/runtime"].cs.StartTime,
229 CPU: cgroupStatsMap["/runtime"].cs.CPU,
230 Memory: cgroupStatsMap["/runtime"].cs.Memory,
231 Accelerators: cgroupStatsMap["/runtime"].cs.Accelerators,
232 UserDefinedMetrics: cgroupStatsMap["/runtime"].cs.UserDefinedMetrics,
233 Swap: cgroupStatsMap["/runtime"].cs.Swap,
234 })
235 assert.Contains(summary.Node.SystemContainers, statsapi.ContainerStats{
236 Name: "pods",
237 StartTime: cgroupStatsMap["/pods"].cs.StartTime,
238 CPU: cgroupStatsMap["/pods"].cs.CPU,
239 Memory: cgroupStatsMap["/pods"].cs.Memory,
240 Accelerators: cgroupStatsMap["/pods"].cs.Accelerators,
241 UserDefinedMetrics: cgroupStatsMap["/pods"].cs.UserDefinedMetrics,
242 Swap: cgroupStatsMap["/pods"].cs.Swap,
243 })
244 assert.Equal(summary.Pods, podStats)
245 }
246
247 func TestSummaryProviderGetCPUAndMemoryStats(t *testing.T) {
248 ctx := context.Background()
249 assert := assert.New(t)
250
251 podStats := []statsapi.PodStats{
252 {
253 PodRef: statsapi.PodReference{Name: "test-pod", Namespace: "test-namespace", UID: "UID_test-pod"},
254 StartTime: metav1.NewTime(time.Now()),
255 Containers: []statsapi.ContainerStats{*getContainerStats()},
256 },
257 }
258 cgroupStatsMap := map[string]struct {
259 cs *statsapi.ContainerStats
260 }{
261 "/": {cs: getVolumeCPUAndMemoryStats()},
262 "/runtime": {cs: getVolumeCPUAndMemoryStats()},
263 "/misc": {cs: getVolumeCPUAndMemoryStats()},
264 "/kubelet": {cs: getVolumeCPUAndMemoryStats()},
265 "/pods": {cs: getVolumeCPUAndMemoryStats()},
266 }
267
268 mockCtrl := gomock.NewController(t)
269 defer mockCtrl.Finish()
270 mockStatsProvider := statstest.NewMockProvider(mockCtrl)
271
272 mockStatsProvider.EXPECT().GetNode().Return(node, nil)
273 mockStatsProvider.EXPECT().GetNodeConfig().Return(nodeConfig)
274 mockStatsProvider.EXPECT().GetPodCgroupRoot().Return(cgroupRoot)
275 mockStatsProvider.EXPECT().ListPodCPUAndMemoryStats(ctx).Return(podStats, nil)
276 mockStatsProvider.EXPECT().GetCgroupCPUAndMemoryStats("/", false).Return(cgroupStatsMap["/"].cs, nil)
277 mockStatsProvider.EXPECT().GetCgroupCPUAndMemoryStats("/runtime", false).Return(cgroupStatsMap["/runtime"].cs, nil)
278 mockStatsProvider.EXPECT().GetCgroupCPUAndMemoryStats("/misc", false).Return(cgroupStatsMap["/misc"].cs, nil)
279 mockStatsProvider.EXPECT().GetCgroupCPUAndMemoryStats("/kubelet", false).Return(cgroupStatsMap["/kubelet"].cs, nil)
280 mockStatsProvider.EXPECT().GetCgroupCPUAndMemoryStats("/kubepods", false).Return(cgroupStatsMap["/pods"].cs, nil)
281
282 provider := NewSummaryProvider(mockStatsProvider)
283 summary, err := provider.GetCPUAndMemoryStats(ctx)
284 assert.NoError(err)
285
286 assert.Equal(summary.Node.NodeName, "test-node")
287 assert.Equal(summary.Node.StartTime, cgroupStatsMap["/"].cs.StartTime)
288 assert.Equal(summary.Node.CPU, cgroupStatsMap["/"].cs.CPU)
289 assert.Equal(summary.Node.Memory, cgroupStatsMap["/"].cs.Memory)
290 assert.Nil(summary.Node.Network)
291 assert.Nil(summary.Node.Fs)
292 assert.Nil(summary.Node.Runtime)
293
294 assert.Equal(len(summary.Node.SystemContainers), 4)
295 assert.Contains(summary.Node.SystemContainers, statsapi.ContainerStats{
296 Name: "kubelet",
297 StartTime: cgroupStatsMap["/kubelet"].cs.StartTime,
298 CPU: cgroupStatsMap["/kubelet"].cs.CPU,
299 Memory: cgroupStatsMap["/kubelet"].cs.Memory,
300 })
301 assert.Contains(summary.Node.SystemContainers, statsapi.ContainerStats{
302 Name: "misc",
303 StartTime: cgroupStatsMap["/misc"].cs.StartTime,
304 CPU: cgroupStatsMap["/misc"].cs.CPU,
305 Memory: cgroupStatsMap["/misc"].cs.Memory,
306 })
307 assert.Contains(summary.Node.SystemContainers, statsapi.ContainerStats{
308 Name: "runtime",
309 StartTime: cgroupStatsMap["/runtime"].cs.StartTime,
310 CPU: cgroupStatsMap["/runtime"].cs.CPU,
311 Memory: cgroupStatsMap["/runtime"].cs.Memory,
312 })
313 assert.Contains(summary.Node.SystemContainers, statsapi.ContainerStats{
314 Name: "pods",
315 StartTime: cgroupStatsMap["/pods"].cs.StartTime,
316 CPU: cgroupStatsMap["/pods"].cs.CPU,
317 Memory: cgroupStatsMap["/pods"].cs.Memory,
318 })
319 assert.Equal(summary.Pods, podStats)
320 }
321
322 func getFsStats() *statsapi.FsStats {
323 f := fuzz.New().NilChance(0)
324 v := &statsapi.FsStats{}
325 f.Fuzz(v)
326 return v
327 }
328
329 func getContainerStats() *statsapi.ContainerStats {
330 f := fuzz.New().NilChance(0)
331 v := &statsapi.ContainerStats{}
332 f.Fuzz(v)
333 return v
334 }
335 func getVolumeCPUAndMemoryStats() *statsapi.ContainerStats {
336 f := fuzz.New().NilChance(0)
337 v := &statsapi.ContainerStats{}
338 f.Fuzz(&v.Name)
339 f.Fuzz(&v.StartTime)
340 f.Fuzz(v.CPU)
341 f.Fuzz(v.Memory)
342 return v
343 }
344
345 func getVolumeStats() *statsapi.VolumeStats {
346 f := fuzz.New().NilChance(0)
347 v := &statsapi.VolumeStats{}
348 f.Fuzz(v)
349 return v
350 }
351
352 func getNetworkStats() *statsapi.NetworkStats {
353 f := fuzz.New().NilChance(0)
354 v := &statsapi.NetworkStats{}
355 f.Fuzz(v)
356 return v
357 }
358
359 func getRlimitStats() *statsapi.RlimitStats {
360 f := fuzz.New().NilChance(0)
361 v := &statsapi.RlimitStats{}
362 f.Fuzz(v)
363 return v
364 }
365
View as plain text