1
2
3
4
19
20 package cm
21
22 import (
23 "reflect"
24 "strconv"
25 "testing"
26 "time"
27
28 v1 "k8s.io/api/core/v1"
29 "k8s.io/apimachinery/pkg/api/resource"
30 utilfeature "k8s.io/apiserver/pkg/util/feature"
31 featuregatetesting "k8s.io/component-base/featuregate/testing"
32 pkgfeatures "k8s.io/kubernetes/pkg/features"
33 )
34
35
36
37 func getResourceList(cpu, memory string) v1.ResourceList {
38 res := v1.ResourceList{}
39 if cpu != "" {
40 res[v1.ResourceCPU] = resource.MustParse(cpu)
41 }
42 if memory != "" {
43 res[v1.ResourceMemory] = resource.MustParse(memory)
44 }
45 return res
46 }
47
48
49 func getResourceRequirements(requests, limits v1.ResourceList) v1.ResourceRequirements {
50 res := v1.ResourceRequirements{}
51 res.Requests = requests
52 res.Limits = limits
53 return res
54 }
55
56 func TestResourceConfigForPod(t *testing.T) {
57 defaultQuotaPeriod := uint64(100 * time.Millisecond / time.Microsecond)
58 tunedQuotaPeriod := uint64(5 * time.Millisecond / time.Microsecond)
59
60 minShares := uint64(MinShares)
61 burstableShares := MilliCPUToShares(100)
62 memoryQuantity := resource.MustParse("200Mi")
63 burstableMemory := memoryQuantity.Value()
64 burstablePartialShares := MilliCPUToShares(200)
65 burstableQuota := MilliCPUToQuota(200, int64(defaultQuotaPeriod))
66 guaranteedShares := MilliCPUToShares(100)
67 guaranteedQuota := MilliCPUToQuota(100, int64(defaultQuotaPeriod))
68 guaranteedTunedQuota := MilliCPUToQuota(100, int64(tunedQuotaPeriod))
69 memoryQuantity = resource.MustParse("100Mi")
70 cpuNoLimit := int64(-1)
71 guaranteedMemory := memoryQuantity.Value()
72 testCases := map[string]struct {
73 pod *v1.Pod
74 expected *ResourceConfig
75 enforceCPULimits bool
76 quotaPeriod uint64
77 }{
78 "besteffort": {
79 pod: &v1.Pod{
80 Spec: v1.PodSpec{
81 Containers: []v1.Container{
82 {
83 Resources: getResourceRequirements(getResourceList("", ""), getResourceList("", "")),
84 },
85 },
86 },
87 },
88 enforceCPULimits: true,
89 quotaPeriod: defaultQuotaPeriod,
90 expected: &ResourceConfig{CPUShares: &minShares},
91 },
92 "burstable-no-limits": {
93 pod: &v1.Pod{
94 Spec: v1.PodSpec{
95 Containers: []v1.Container{
96 {
97 Resources: getResourceRequirements(getResourceList("100m", "100Mi"), getResourceList("", "")),
98 },
99 },
100 },
101 },
102 enforceCPULimits: true,
103 quotaPeriod: defaultQuotaPeriod,
104 expected: &ResourceConfig{CPUShares: &burstableShares},
105 },
106 "burstable-with-limits": {
107 pod: &v1.Pod{
108 Spec: v1.PodSpec{
109 Containers: []v1.Container{
110 {
111 Resources: getResourceRequirements(getResourceList("100m", "100Mi"), getResourceList("200m", "200Mi")),
112 },
113 },
114 },
115 },
116 enforceCPULimits: true,
117 quotaPeriod: defaultQuotaPeriod,
118 expected: &ResourceConfig{CPUShares: &burstableShares, CPUQuota: &burstableQuota, CPUPeriod: &defaultQuotaPeriod, Memory: &burstableMemory},
119 },
120 "burstable-with-limits-no-cpu-enforcement": {
121 pod: &v1.Pod{
122 Spec: v1.PodSpec{
123 Containers: []v1.Container{
124 {
125 Resources: getResourceRequirements(getResourceList("100m", "100Mi"), getResourceList("200m", "200Mi")),
126 },
127 },
128 },
129 },
130 enforceCPULimits: false,
131 quotaPeriod: defaultQuotaPeriod,
132 expected: &ResourceConfig{CPUShares: &burstableShares, CPUQuota: &cpuNoLimit, CPUPeriod: &defaultQuotaPeriod, Memory: &burstableMemory},
133 },
134 "burstable-partial-limits": {
135 pod: &v1.Pod{
136 Spec: v1.PodSpec{
137 Containers: []v1.Container{
138 {
139 Resources: getResourceRequirements(getResourceList("100m", "100Mi"), getResourceList("200m", "200Mi")),
140 },
141 {
142 Resources: getResourceRequirements(getResourceList("100m", "100Mi"), getResourceList("", "")),
143 },
144 },
145 },
146 },
147 enforceCPULimits: true,
148 quotaPeriod: defaultQuotaPeriod,
149 expected: &ResourceConfig{CPUShares: &burstablePartialShares},
150 },
151 "burstable-with-limits-with-tuned-quota": {
152 pod: &v1.Pod{
153 Spec: v1.PodSpec{
154 Containers: []v1.Container{
155 {
156 Resources: getResourceRequirements(getResourceList("100m", "100Mi"), getResourceList("200m", "200Mi")),
157 },
158 },
159 },
160 },
161 enforceCPULimits: true,
162 quotaPeriod: tunedQuotaPeriod,
163 expected: &ResourceConfig{CPUShares: &burstableShares, CPUQuota: &burstableQuota, CPUPeriod: &tunedQuotaPeriod, Memory: &burstableMemory},
164 },
165 "burstable-with-limits-no-cpu-enforcement-with-tuned-quota": {
166 pod: &v1.Pod{
167 Spec: v1.PodSpec{
168 Containers: []v1.Container{
169 {
170 Resources: getResourceRequirements(getResourceList("100m", "100Mi"), getResourceList("200m", "200Mi")),
171 },
172 },
173 },
174 },
175 enforceCPULimits: false,
176 quotaPeriod: tunedQuotaPeriod,
177 expected: &ResourceConfig{CPUShares: &burstableShares, CPUQuota: &cpuNoLimit, CPUPeriod: &tunedQuotaPeriod, Memory: &burstableMemory},
178 },
179 "burstable-partial-limits-with-tuned-quota": {
180 pod: &v1.Pod{
181 Spec: v1.PodSpec{
182 Containers: []v1.Container{
183 {
184 Resources: getResourceRequirements(getResourceList("100m", "100Mi"), getResourceList("200m", "200Mi")),
185 },
186 {
187 Resources: getResourceRequirements(getResourceList("100m", "100Mi"), getResourceList("", "")),
188 },
189 },
190 },
191 },
192 enforceCPULimits: true,
193 quotaPeriod: tunedQuotaPeriod,
194 expected: &ResourceConfig{CPUShares: &burstablePartialShares},
195 },
196 "guaranteed": {
197 pod: &v1.Pod{
198 Spec: v1.PodSpec{
199 Containers: []v1.Container{
200 {
201 Resources: getResourceRequirements(getResourceList("100m", "100Mi"), getResourceList("100m", "100Mi")),
202 },
203 },
204 },
205 },
206 enforceCPULimits: true,
207 quotaPeriod: defaultQuotaPeriod,
208 expected: &ResourceConfig{CPUShares: &guaranteedShares, CPUQuota: &guaranteedQuota, CPUPeriod: &defaultQuotaPeriod, Memory: &guaranteedMemory},
209 },
210 "guaranteed-no-cpu-enforcement": {
211 pod: &v1.Pod{
212 Spec: v1.PodSpec{
213 Containers: []v1.Container{
214 {
215 Resources: getResourceRequirements(getResourceList("100m", "100Mi"), getResourceList("100m", "100Mi")),
216 },
217 },
218 },
219 },
220 enforceCPULimits: false,
221 quotaPeriod: defaultQuotaPeriod,
222 expected: &ResourceConfig{CPUShares: &guaranteedShares, CPUQuota: &cpuNoLimit, CPUPeriod: &defaultQuotaPeriod, Memory: &guaranteedMemory},
223 },
224 "guaranteed-with-tuned-quota": {
225 pod: &v1.Pod{
226 Spec: v1.PodSpec{
227 Containers: []v1.Container{
228 {
229 Resources: getResourceRequirements(getResourceList("100m", "100Mi"), getResourceList("100m", "100Mi")),
230 },
231 },
232 },
233 },
234 enforceCPULimits: true,
235 quotaPeriod: tunedQuotaPeriod,
236 expected: &ResourceConfig{CPUShares: &guaranteedShares, CPUQuota: &guaranteedTunedQuota, CPUPeriod: &tunedQuotaPeriod, Memory: &guaranteedMemory},
237 },
238 "guaranteed-no-cpu-enforcement-with-tuned-quota": {
239 pod: &v1.Pod{
240 Spec: v1.PodSpec{
241 Containers: []v1.Container{
242 {
243 Resources: getResourceRequirements(getResourceList("100m", "100Mi"), getResourceList("100m", "100Mi")),
244 },
245 },
246 },
247 },
248 enforceCPULimits: false,
249 quotaPeriod: tunedQuotaPeriod,
250 expected: &ResourceConfig{CPUShares: &guaranteedShares, CPUQuota: &cpuNoLimit, CPUPeriod: &tunedQuotaPeriod, Memory: &guaranteedMemory},
251 },
252 "burstable-partial-limits-with-init-containers": {
253 pod: &v1.Pod{
254 Spec: v1.PodSpec{
255 Containers: []v1.Container{
256 {
257 Resources: getResourceRequirements(getResourceList("100m", "100m"), getResourceList("100m", "100Mi")),
258 },
259 {
260 Resources: getResourceRequirements(getResourceList("100m", "100m"), getResourceList("", "")),
261 },
262 },
263 InitContainers: []v1.Container{
264 {
265 Resources: getResourceRequirements(getResourceList("100m", "100m"), getResourceList("100m", "100Mi")),
266 },
267 {
268 Resources: getResourceRequirements(getResourceList("100m", "100m"), getResourceList("", "")),
269 },
270 },
271 },
272 },
273 enforceCPULimits: true,
274 quotaPeriod: tunedQuotaPeriod,
275 expected: &ResourceConfig{CPUShares: &burstablePartialShares},
276 },
277 }
278
279 for testName, testCase := range testCases {
280
281 actual := ResourceConfigForPod(testCase.pod, testCase.enforceCPULimits, testCase.quotaPeriod, false)
282
283 if !reflect.DeepEqual(actual.CPUPeriod, testCase.expected.CPUPeriod) {
284 t.Errorf("unexpected result, test: %v, cpu period not as expected. Expected: %v, Actual:%v", testName, *testCase.expected.CPUPeriod, *actual.CPUPeriod)
285 }
286 if !reflect.DeepEqual(actual.CPUQuota, testCase.expected.CPUQuota) {
287 t.Errorf("unexpected result, test: %v, cpu quota not as expected. Expected: %v, Actual:%v", testName, *testCase.expected.CPUQuota, *actual.CPUQuota)
288 }
289 if !reflect.DeepEqual(actual.CPUShares, testCase.expected.CPUShares) {
290 t.Errorf("unexpected result, test: %v, cpu shares not as expected. Expected: %v, Actual:%v", testName, *testCase.expected.CPUShares, &actual.CPUShares)
291 }
292 if !reflect.DeepEqual(actual.Memory, testCase.expected.Memory) {
293 t.Errorf("unexpected result, test: %v, memory not as expected. Expected: %v, Actual:%v", testName, *testCase.expected.Memory, *actual.Memory)
294 }
295 }
296 }
297
298 func TestResourceConfigForPodWithCustomCPUCFSQuotaPeriod(t *testing.T) {
299 defaultQuotaPeriod := uint64(100 * time.Millisecond / time.Microsecond)
300 tunedQuotaPeriod := uint64(5 * time.Millisecond / time.Microsecond)
301 tunedQuota := int64(1 * time.Millisecond / time.Microsecond)
302
303 defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, pkgfeatures.CPUCFSQuotaPeriod, true)()
304
305 minShares := uint64(MinShares)
306 burstableShares := MilliCPUToShares(100)
307 memoryQuantity := resource.MustParse("200Mi")
308 burstableMemory := memoryQuantity.Value()
309 burstablePartialShares := MilliCPUToShares(200)
310 burstableQuota := MilliCPUToQuota(200, int64(defaultQuotaPeriod))
311 guaranteedShares := MilliCPUToShares(100)
312 guaranteedQuota := MilliCPUToQuota(100, int64(defaultQuotaPeriod))
313 guaranteedTunedQuota := MilliCPUToQuota(100, int64(tunedQuotaPeriod))
314 memoryQuantity = resource.MustParse("100Mi")
315 cpuNoLimit := int64(-1)
316 guaranteedMemory := memoryQuantity.Value()
317 testCases := map[string]struct {
318 pod *v1.Pod
319 expected *ResourceConfig
320 enforceCPULimits bool
321 quotaPeriod uint64
322 }{
323 "besteffort": {
324 pod: &v1.Pod{
325 Spec: v1.PodSpec{
326 Containers: []v1.Container{
327 {
328 Resources: getResourceRequirements(getResourceList("", ""), getResourceList("", "")),
329 },
330 },
331 },
332 },
333 enforceCPULimits: true,
334 quotaPeriod: defaultQuotaPeriod,
335 expected: &ResourceConfig{CPUShares: &minShares},
336 },
337 "burstable-no-limits": {
338 pod: &v1.Pod{
339 Spec: v1.PodSpec{
340 Containers: []v1.Container{
341 {
342 Resources: getResourceRequirements(getResourceList("100m", "100Mi"), getResourceList("", "")),
343 },
344 },
345 },
346 },
347 enforceCPULimits: true,
348 quotaPeriod: defaultQuotaPeriod,
349 expected: &ResourceConfig{CPUShares: &burstableShares},
350 },
351 "burstable-with-limits": {
352 pod: &v1.Pod{
353 Spec: v1.PodSpec{
354 Containers: []v1.Container{
355 {
356 Resources: getResourceRequirements(getResourceList("100m", "100Mi"), getResourceList("200m", "200Mi")),
357 },
358 },
359 },
360 },
361 enforceCPULimits: true,
362 quotaPeriod: defaultQuotaPeriod,
363 expected: &ResourceConfig{CPUShares: &burstableShares, CPUQuota: &burstableQuota, CPUPeriod: &defaultQuotaPeriod, Memory: &burstableMemory},
364 },
365 "burstable-with-limits-no-cpu-enforcement": {
366 pod: &v1.Pod{
367 Spec: v1.PodSpec{
368 Containers: []v1.Container{
369 {
370 Resources: getResourceRequirements(getResourceList("100m", "100Mi"), getResourceList("200m", "200Mi")),
371 },
372 },
373 },
374 },
375 enforceCPULimits: false,
376 quotaPeriod: defaultQuotaPeriod,
377 expected: &ResourceConfig{CPUShares: &burstableShares, CPUQuota: &cpuNoLimit, CPUPeriod: &defaultQuotaPeriod, Memory: &burstableMemory},
378 },
379 "burstable-partial-limits": {
380 pod: &v1.Pod{
381 Spec: v1.PodSpec{
382 Containers: []v1.Container{
383 {
384 Resources: getResourceRequirements(getResourceList("100m", "100Mi"), getResourceList("200m", "200Mi")),
385 },
386 {
387 Resources: getResourceRequirements(getResourceList("100m", "100Mi"), getResourceList("", "")),
388 },
389 },
390 },
391 },
392 enforceCPULimits: true,
393 quotaPeriod: defaultQuotaPeriod,
394 expected: &ResourceConfig{CPUShares: &burstablePartialShares},
395 },
396 "burstable-with-limits-with-tuned-quota": {
397 pod: &v1.Pod{
398 Spec: v1.PodSpec{
399 Containers: []v1.Container{
400 {
401 Resources: getResourceRequirements(getResourceList("100m", "100Mi"), getResourceList("200m", "200Mi")),
402 },
403 },
404 },
405 },
406 enforceCPULimits: true,
407 quotaPeriod: tunedQuotaPeriod,
408 expected: &ResourceConfig{CPUShares: &burstableShares, CPUQuota: &tunedQuota, CPUPeriod: &tunedQuotaPeriod, Memory: &burstableMemory},
409 },
410 "burstable-with-limits-no-cpu-enforcement-with-tuned-quota": {
411 pod: &v1.Pod{
412 Spec: v1.PodSpec{
413 Containers: []v1.Container{
414 {
415 Resources: getResourceRequirements(getResourceList("100m", "100Mi"), getResourceList("200m", "200Mi")),
416 },
417 },
418 },
419 },
420 enforceCPULimits: false,
421 quotaPeriod: tunedQuotaPeriod,
422 expected: &ResourceConfig{CPUShares: &burstableShares, CPUQuota: &cpuNoLimit, CPUPeriod: &tunedQuotaPeriod, Memory: &burstableMemory},
423 },
424 "burstable-partial-limits-with-tuned-quota": {
425 pod: &v1.Pod{
426 Spec: v1.PodSpec{
427 Containers: []v1.Container{
428 {
429 Resources: getResourceRequirements(getResourceList("100m", "100Mi"), getResourceList("200m", "200Mi")),
430 },
431 {
432 Resources: getResourceRequirements(getResourceList("100m", "100Mi"), getResourceList("", "")),
433 },
434 },
435 },
436 },
437 enforceCPULimits: true,
438 quotaPeriod: tunedQuotaPeriod,
439 expected: &ResourceConfig{CPUShares: &burstablePartialShares},
440 },
441 "guaranteed": {
442 pod: &v1.Pod{
443 Spec: v1.PodSpec{
444 Containers: []v1.Container{
445 {
446 Resources: getResourceRequirements(getResourceList("100m", "100Mi"), getResourceList("100m", "100Mi")),
447 },
448 },
449 },
450 },
451 enforceCPULimits: true,
452 quotaPeriod: defaultQuotaPeriod,
453 expected: &ResourceConfig{CPUShares: &guaranteedShares, CPUQuota: &guaranteedQuota, CPUPeriod: &defaultQuotaPeriod, Memory: &guaranteedMemory},
454 },
455 "guaranteed-no-cpu-enforcement": {
456 pod: &v1.Pod{
457 Spec: v1.PodSpec{
458 Containers: []v1.Container{
459 {
460 Resources: getResourceRequirements(getResourceList("100m", "100Mi"), getResourceList("100m", "100Mi")),
461 },
462 },
463 },
464 },
465 enforceCPULimits: false,
466 quotaPeriod: defaultQuotaPeriod,
467 expected: &ResourceConfig{CPUShares: &guaranteedShares, CPUQuota: &cpuNoLimit, CPUPeriod: &defaultQuotaPeriod, Memory: &guaranteedMemory},
468 },
469 "guaranteed-with-tuned-quota": {
470 pod: &v1.Pod{
471 Spec: v1.PodSpec{
472 Containers: []v1.Container{
473 {
474 Resources: getResourceRequirements(getResourceList("100m", "100Mi"), getResourceList("100m", "100Mi")),
475 },
476 },
477 },
478 },
479 enforceCPULimits: true,
480 quotaPeriod: tunedQuotaPeriod,
481 expected: &ResourceConfig{CPUShares: &guaranteedShares, CPUQuota: &guaranteedTunedQuota, CPUPeriod: &tunedQuotaPeriod, Memory: &guaranteedMemory},
482 },
483 "guaranteed-no-cpu-enforcement-with-tuned-quota": {
484 pod: &v1.Pod{
485 Spec: v1.PodSpec{
486 Containers: []v1.Container{
487 {
488 Resources: getResourceRequirements(getResourceList("100m", "100Mi"), getResourceList("100m", "100Mi")),
489 },
490 },
491 },
492 },
493 enforceCPULimits: false,
494 quotaPeriod: tunedQuotaPeriod,
495 expected: &ResourceConfig{CPUShares: &guaranteedShares, CPUQuota: &cpuNoLimit, CPUPeriod: &tunedQuotaPeriod, Memory: &guaranteedMemory},
496 },
497 }
498
499 for testName, testCase := range testCases {
500
501 actual := ResourceConfigForPod(testCase.pod, testCase.enforceCPULimits, testCase.quotaPeriod, false)
502
503 if !reflect.DeepEqual(actual.CPUPeriod, testCase.expected.CPUPeriod) {
504 t.Errorf("unexpected result, test: %v, cpu period not as expected", testName)
505 }
506 if !reflect.DeepEqual(actual.CPUQuota, testCase.expected.CPUQuota) {
507 t.Errorf("unexpected result, test: %v, cpu quota not as expected", testName)
508 }
509 if !reflect.DeepEqual(actual.CPUShares, testCase.expected.CPUShares) {
510 t.Errorf("unexpected result, test: %v, cpu shares not as expected", testName)
511 }
512 if !reflect.DeepEqual(actual.Memory, testCase.expected.Memory) {
513 t.Errorf("unexpected result, test: %v, memory not as expected", testName)
514 }
515 }
516 }
517
518 func TestMilliCPUToQuota(t *testing.T) {
519 testCases := []struct {
520 input int64
521 quota int64
522 period uint64
523 }{
524 {
525 input: int64(0),
526 quota: int64(0),
527 period: uint64(0),
528 },
529 {
530 input: int64(5),
531 quota: int64(1000),
532 period: uint64(100000),
533 },
534 {
535 input: int64(9),
536 quota: int64(1000),
537 period: uint64(100000),
538 },
539 {
540 input: int64(10),
541 quota: int64(1000),
542 period: uint64(100000),
543 },
544 {
545 input: int64(200),
546 quota: int64(20000),
547 period: uint64(100000),
548 },
549 {
550 input: int64(500),
551 quota: int64(50000),
552 period: uint64(100000),
553 },
554 {
555 input: int64(1000),
556 quota: int64(100000),
557 period: uint64(100000),
558 },
559 {
560 input: int64(1500),
561 quota: int64(150000),
562 period: uint64(100000),
563 },
564 }
565 for _, testCase := range testCases {
566 quota := MilliCPUToQuota(testCase.input, int64(testCase.period))
567 if quota != testCase.quota {
568 t.Errorf("Input %v and %v, expected quota %v, but got quota %v", testCase.input, testCase.period, testCase.quota, quota)
569 }
570 }
571 }
572
573 func TestHugePageLimits(t *testing.T) {
574 Mi := int64(1024 * 1024)
575 type inputStruct struct {
576 key string
577 input string
578 }
579
580 testCases := []struct {
581 name string
582 inputs []inputStruct
583 expected map[int64]int64
584 }{
585 {
586 name: "no valid hugepages",
587 inputs: []inputStruct{
588 {
589 key: "2Mi",
590 input: "128",
591 },
592 },
593 expected: map[int64]int64{},
594 },
595 {
596 name: "2Mi only",
597 inputs: []inputStruct{
598 {
599 key: v1.ResourceHugePagesPrefix + "2Mi",
600 input: "128",
601 },
602 },
603 expected: map[int64]int64{2 * Mi: 128},
604 },
605 {
606 name: "2Mi and 4Mi",
607 inputs: []inputStruct{
608 {
609 key: v1.ResourceHugePagesPrefix + "2Mi",
610 input: "128",
611 },
612 {
613 key: v1.ResourceHugePagesPrefix + strconv.FormatInt(2*Mi, 10),
614 input: "256",
615 },
616 {
617 key: v1.ResourceHugePagesPrefix + "4Mi",
618 input: "512",
619 },
620 {
621 key: "4Mi",
622 input: "1024",
623 },
624 },
625 expected: map[int64]int64{2 * Mi: 384, 4 * Mi: 512},
626 },
627 }
628
629 for _, testcase := range testCases {
630 t.Run(testcase.name, func(t *testing.T) {
631 resourceList := v1.ResourceList{}
632
633 for _, input := range testcase.inputs {
634 value, err := resource.ParseQuantity(input.input)
635 if err != nil {
636 t.Fatalf("error in parsing hugepages, value: %s", input.input)
637 } else {
638 resourceList[v1.ResourceName(input.key)] = value
639 }
640 }
641
642 resultValue := HugePageLimits(resourceList)
643
644 if !reflect.DeepEqual(testcase.expected, resultValue) {
645 t.Errorf("unexpected result for HugePageLimits(), expected: %v, actual: %v", testcase.expected, resultValue)
646 }
647
648
649 p := v1.Pod{
650 Spec: v1.PodSpec{
651 Containers: []v1.Container{
652 {
653 Resources: v1.ResourceRequirements{
654 Requests: resourceList,
655 },
656 },
657 },
658 },
659 }
660 resultValuePod := ResourceConfigForPod(&p, false, 0, false)
661 if !reflect.DeepEqual(testcase.expected, resultValuePod.HugePageLimit) {
662 t.Errorf("unexpected result for ResourceConfigForPod(), expected: %v, actual: %v", testcase.expected, resultValuePod)
663 }
664 })
665 }
666 }
667
668 func TestResourceConfigForPodWithEnforceMemoryQoS(t *testing.T) {
669 defaultQuotaPeriod := uint64(100 * time.Millisecond / time.Microsecond)
670 tunedQuotaPeriod := uint64(5 * time.Millisecond / time.Microsecond)
671
672 minShares := uint64(MinShares)
673 burstableShares := MilliCPUToShares(100)
674 memoryQuantity := resource.MustParse("200Mi")
675 burstableMemory := memoryQuantity.Value()
676 burstablePartialShares := MilliCPUToShares(200)
677 burstableQuota := MilliCPUToQuota(200, int64(defaultQuotaPeriod))
678 guaranteedShares := MilliCPUToShares(100)
679 guaranteedQuota := MilliCPUToQuota(100, int64(defaultQuotaPeriod))
680 guaranteedTunedQuota := MilliCPUToQuota(100, int64(tunedQuotaPeriod))
681 memoryQuantity = resource.MustParse("100Mi")
682 cpuNoLimit := int64(-1)
683 guaranteedMemory := memoryQuantity.Value()
684 testCases := map[string]struct {
685 pod *v1.Pod
686 expected *ResourceConfig
687 enforceCPULimits bool
688 quotaPeriod uint64
689 }{
690 "besteffort": {
691 pod: &v1.Pod{
692 Spec: v1.PodSpec{
693 Containers: []v1.Container{
694 {
695 Resources: getResourceRequirements(getResourceList("", ""), getResourceList("", "")),
696 },
697 },
698 },
699 },
700 enforceCPULimits: true,
701 quotaPeriod: defaultQuotaPeriod,
702 expected: &ResourceConfig{CPUShares: &minShares},
703 },
704 "burstable-no-limits": {
705 pod: &v1.Pod{
706 Spec: v1.PodSpec{
707 Containers: []v1.Container{
708 {
709 Resources: getResourceRequirements(getResourceList("100m", "100Mi"), getResourceList("", "")),
710 },
711 },
712 },
713 },
714 enforceCPULimits: true,
715 quotaPeriod: defaultQuotaPeriod,
716 expected: &ResourceConfig{CPUShares: &burstableShares, Unified: map[string]string{"memory.min": "104857600"}},
717 },
718 "burstable-with-limits": {
719 pod: &v1.Pod{
720 Spec: v1.PodSpec{
721 Containers: []v1.Container{
722 {
723 Resources: getResourceRequirements(getResourceList("100m", "100Mi"), getResourceList("200m", "200Mi")),
724 },
725 },
726 },
727 },
728 enforceCPULimits: true,
729 quotaPeriod: defaultQuotaPeriod,
730 expected: &ResourceConfig{CPUShares: &burstableShares, CPUQuota: &burstableQuota, CPUPeriod: &defaultQuotaPeriod, Memory: &burstableMemory, Unified: map[string]string{"memory.min": "104857600"}},
731 },
732 "burstable-with-limits-no-cpu-enforcement": {
733 pod: &v1.Pod{
734 Spec: v1.PodSpec{
735 Containers: []v1.Container{
736 {
737 Resources: getResourceRequirements(getResourceList("100m", "100Mi"), getResourceList("200m", "200Mi")),
738 },
739 },
740 },
741 },
742 enforceCPULimits: false,
743 quotaPeriod: defaultQuotaPeriod,
744 expected: &ResourceConfig{CPUShares: &burstableShares, CPUQuota: &cpuNoLimit, CPUPeriod: &defaultQuotaPeriod, Memory: &burstableMemory, Unified: map[string]string{"memory.min": "104857600"}},
745 },
746 "burstable-partial-limits": {
747 pod: &v1.Pod{
748 Spec: v1.PodSpec{
749 Containers: []v1.Container{
750 {
751 Resources: getResourceRequirements(getResourceList("100m", "100Mi"), getResourceList("200m", "200Mi")),
752 },
753 {
754 Resources: getResourceRequirements(getResourceList("100m", "100Mi"), getResourceList("", "")),
755 },
756 },
757 },
758 },
759 enforceCPULimits: true,
760 quotaPeriod: defaultQuotaPeriod,
761 expected: &ResourceConfig{CPUShares: &burstablePartialShares, Unified: map[string]string{"memory.min": "209715200"}},
762 },
763 "burstable-with-limits-with-tuned-quota": {
764 pod: &v1.Pod{
765 Spec: v1.PodSpec{
766 Containers: []v1.Container{
767 {
768 Resources: getResourceRequirements(getResourceList("100m", "100Mi"), getResourceList("200m", "200Mi")),
769 },
770 },
771 },
772 },
773 enforceCPULimits: true,
774 quotaPeriod: tunedQuotaPeriod,
775 expected: &ResourceConfig{CPUShares: &burstableShares, CPUQuota: &burstableQuota, CPUPeriod: &tunedQuotaPeriod, Memory: &burstableMemory, Unified: map[string]string{"memory.min": "104857600"}},
776 },
777 "burstable-with-limits-no-cpu-enforcement-with-tuned-quota": {
778 pod: &v1.Pod{
779 Spec: v1.PodSpec{
780 Containers: []v1.Container{
781 {
782 Resources: getResourceRequirements(getResourceList("100m", "100Mi"), getResourceList("200m", "200Mi")),
783 },
784 },
785 },
786 },
787 enforceCPULimits: false,
788 quotaPeriod: tunedQuotaPeriod,
789 expected: &ResourceConfig{CPUShares: &burstableShares, CPUQuota: &cpuNoLimit, CPUPeriod: &tunedQuotaPeriod, Memory: &burstableMemory, Unified: map[string]string{"memory.min": "104857600"}},
790 },
791 "burstable-partial-limits-with-tuned-quota": {
792 pod: &v1.Pod{
793 Spec: v1.PodSpec{
794 Containers: []v1.Container{
795 {
796 Resources: getResourceRequirements(getResourceList("100m", "100Mi"), getResourceList("200m", "200Mi")),
797 },
798 {
799 Resources: getResourceRequirements(getResourceList("100m", "100Mi"), getResourceList("", "")),
800 },
801 },
802 },
803 },
804 enforceCPULimits: true,
805 quotaPeriod: tunedQuotaPeriod,
806 expected: &ResourceConfig{CPUShares: &burstablePartialShares, Unified: map[string]string{"memory.min": "209715200"}},
807 },
808 "guaranteed": {
809 pod: &v1.Pod{
810 Spec: v1.PodSpec{
811 Containers: []v1.Container{
812 {
813 Resources: getResourceRequirements(getResourceList("100m", "100Mi"), getResourceList("100m", "100Mi")),
814 },
815 },
816 },
817 },
818 enforceCPULimits: true,
819 quotaPeriod: defaultQuotaPeriod,
820 expected: &ResourceConfig{CPUShares: &guaranteedShares, CPUQuota: &guaranteedQuota, CPUPeriod: &defaultQuotaPeriod, Memory: &guaranteedMemory, Unified: map[string]string{"memory.min": "104857600"}},
821 },
822 "guaranteed-no-cpu-enforcement": {
823 pod: &v1.Pod{
824 Spec: v1.PodSpec{
825 Containers: []v1.Container{
826 {
827 Resources: getResourceRequirements(getResourceList("100m", "100Mi"), getResourceList("100m", "100Mi")),
828 },
829 },
830 },
831 },
832 enforceCPULimits: false,
833 quotaPeriod: defaultQuotaPeriod,
834 expected: &ResourceConfig{CPUShares: &guaranteedShares, CPUQuota: &cpuNoLimit, CPUPeriod: &defaultQuotaPeriod, Memory: &guaranteedMemory, Unified: map[string]string{"memory.min": "104857600"}},
835 },
836 "guaranteed-with-tuned-quota": {
837 pod: &v1.Pod{
838 Spec: v1.PodSpec{
839 Containers: []v1.Container{
840 {
841 Resources: getResourceRequirements(getResourceList("100m", "100Mi"), getResourceList("100m", "100Mi")),
842 },
843 },
844 },
845 },
846 enforceCPULimits: true,
847 quotaPeriod: tunedQuotaPeriod,
848 expected: &ResourceConfig{CPUShares: &guaranteedShares, CPUQuota: &guaranteedTunedQuota, CPUPeriod: &tunedQuotaPeriod, Memory: &guaranteedMemory, Unified: map[string]string{"memory.min": "104857600"}},
849 },
850 "guaranteed-no-cpu-enforcement-with-tuned-quota": {
851 pod: &v1.Pod{
852 Spec: v1.PodSpec{
853 Containers: []v1.Container{
854 {
855 Resources: getResourceRequirements(getResourceList("100m", "100Mi"), getResourceList("100m", "100Mi")),
856 },
857 },
858 },
859 },
860 enforceCPULimits: false,
861 quotaPeriod: tunedQuotaPeriod,
862 expected: &ResourceConfig{CPUShares: &guaranteedShares, CPUQuota: &cpuNoLimit, CPUPeriod: &tunedQuotaPeriod, Memory: &guaranteedMemory, Unified: map[string]string{"memory.min": "104857600"}},
863 },
864 }
865
866 for testName, testCase := range testCases {
867
868 actual := ResourceConfigForPod(testCase.pod, testCase.enforceCPULimits, testCase.quotaPeriod, true)
869
870 if !reflect.DeepEqual(actual.Unified, testCase.expected.Unified) {
871 t.Errorf("unexpected result, test: %v, unified not as expected", testName)
872 }
873 }
874 }
875
View as plain text