1
16
17 package validation
18
19 import (
20 "strings"
21 "testing"
22
23 "k8s.io/apimachinery/pkg/api/resource"
24 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
25 utilfeature "k8s.io/apiserver/pkg/util/feature"
26 featuregatetesting "k8s.io/component-base/featuregate/testing"
27 "k8s.io/kubernetes/pkg/apis/autoscaling"
28 api "k8s.io/kubernetes/pkg/apis/core"
29 "k8s.io/kubernetes/pkg/features"
30 utilpointer "k8s.io/utils/pointer"
31 )
32
33 func TestValidateScale(t *testing.T) {
34 successCases := []autoscaling.Scale{{
35 ObjectMeta: metav1.ObjectMeta{
36 Name: "frontend",
37 Namespace: metav1.NamespaceDefault,
38 },
39 Spec: autoscaling.ScaleSpec{
40 Replicas: 1,
41 },
42 }, {
43 ObjectMeta: metav1.ObjectMeta{
44 Name: "frontend",
45 Namespace: metav1.NamespaceDefault,
46 },
47 Spec: autoscaling.ScaleSpec{
48 Replicas: 10,
49 },
50 }, {
51 ObjectMeta: metav1.ObjectMeta{
52 Name: "frontend",
53 Namespace: metav1.NamespaceDefault,
54 },
55 Spec: autoscaling.ScaleSpec{
56 Replicas: 0,
57 },
58 }}
59
60 for _, successCase := range successCases {
61 if errs := ValidateScale(&successCase); len(errs) != 0 {
62 t.Errorf("expected success: %v", errs)
63 }
64 }
65
66 errorCases := []struct {
67 scale autoscaling.Scale
68 msg string
69 }{{
70 scale: autoscaling.Scale{
71 ObjectMeta: metav1.ObjectMeta{
72 Name: "frontend",
73 Namespace: metav1.NamespaceDefault,
74 },
75 Spec: autoscaling.ScaleSpec{
76 Replicas: -1,
77 },
78 },
79 msg: "must be greater than or equal to 0",
80 }}
81
82 for _, c := range errorCases {
83 if errs := ValidateScale(&c.scale); len(errs) == 0 {
84 t.Errorf("expected failure for %s", c.msg)
85 } else if !strings.Contains(errs[0].Error(), c.msg) {
86 t.Errorf("unexpected error: %v, expected: %s", errs[0], c.msg)
87 }
88 }
89 }
90
91 func TestValidateBehavior(t *testing.T) {
92 maxPolicy := autoscaling.MaxPolicySelect
93 minPolicy := autoscaling.MinPolicySelect
94 disabledPolicy := autoscaling.DisabledPolicySelect
95 incorrectPolicy := autoscaling.ScalingPolicySelect("incorrect")
96 simplePoliciesList := []autoscaling.HPAScalingPolicy{{
97 Type: autoscaling.PercentScalingPolicy,
98 Value: 10,
99 PeriodSeconds: 1,
100 }, {
101 Type: autoscaling.PodsScalingPolicy,
102 Value: 1,
103 PeriodSeconds: 1800,
104 }}
105 successCases := []autoscaling.HorizontalPodAutoscalerBehavior{{
106 ScaleUp: nil,
107 ScaleDown: nil,
108 }, {
109 ScaleUp: &autoscaling.HPAScalingRules{
110 StabilizationWindowSeconds: utilpointer.Int32(3600),
111 SelectPolicy: &minPolicy,
112 Policies: simplePoliciesList,
113 },
114 ScaleDown: &autoscaling.HPAScalingRules{
115 StabilizationWindowSeconds: utilpointer.Int32(0),
116 SelectPolicy: &disabledPolicy,
117 Policies: simplePoliciesList,
118 },
119 }, {
120 ScaleUp: &autoscaling.HPAScalingRules{
121 StabilizationWindowSeconds: utilpointer.Int32(120),
122 SelectPolicy: &maxPolicy,
123 Policies: []autoscaling.HPAScalingPolicy{{
124 Type: autoscaling.PodsScalingPolicy,
125 Value: 1,
126 PeriodSeconds: 2,
127 }, {
128 Type: autoscaling.PercentScalingPolicy,
129 Value: 3,
130 PeriodSeconds: 4,
131 }, {
132 Type: autoscaling.PodsScalingPolicy,
133 Value: 5,
134 PeriodSeconds: 6,
135 }, {
136 Type: autoscaling.PercentScalingPolicy,
137 Value: 7,
138 PeriodSeconds: 8,
139 }},
140 },
141 ScaleDown: &autoscaling.HPAScalingRules{
142 StabilizationWindowSeconds: utilpointer.Int32(120),
143 SelectPolicy: &maxPolicy,
144 Policies: []autoscaling.HPAScalingPolicy{{
145 Type: autoscaling.PodsScalingPolicy,
146 Value: 1,
147 PeriodSeconds: 2,
148 }, {
149 Type: autoscaling.PercentScalingPolicy,
150 Value: 3,
151 PeriodSeconds: 4,
152 }, {
153 Type: autoscaling.PodsScalingPolicy,
154 Value: 5,
155 PeriodSeconds: 6,
156 }, {
157 Type: autoscaling.PercentScalingPolicy,
158 Value: 7,
159 PeriodSeconds: 8,
160 }},
161 },
162 }}
163 for _, behavior := range successCases {
164 hpa := prepareHPAWithBehavior(behavior)
165 if errs := ValidateHorizontalPodAutoscaler(&hpa); len(errs) != 0 {
166 t.Errorf("expected success: %v", errs)
167 }
168 }
169 errorCases := []struct {
170 behavior autoscaling.HorizontalPodAutoscalerBehavior
171 msg string
172 }{{
173 behavior: autoscaling.HorizontalPodAutoscalerBehavior{
174 ScaleUp: &autoscaling.HPAScalingRules{
175 SelectPolicy: &minPolicy,
176 },
177 },
178 msg: "spec.behavior.scaleUp.policies: Required value: must specify at least one Policy",
179 }, {
180 behavior: autoscaling.HorizontalPodAutoscalerBehavior{
181 ScaleUp: &autoscaling.HPAScalingRules{
182 StabilizationWindowSeconds: utilpointer.Int32(3601),
183 SelectPolicy: &minPolicy,
184 Policies: simplePoliciesList,
185 },
186 },
187 msg: "spec.behavior.scaleUp.stabilizationWindowSeconds: Invalid value: 3601: must be less than or equal to 3600",
188 }, {
189 behavior: autoscaling.HorizontalPodAutoscalerBehavior{
190 ScaleUp: &autoscaling.HPAScalingRules{
191 Policies: []autoscaling.HPAScalingPolicy{{
192 Type: autoscaling.PodsScalingPolicy,
193 Value: 7,
194 PeriodSeconds: 1801,
195 }},
196 },
197 },
198 msg: "spec.behavior.scaleUp.policies[0].periodSeconds: Invalid value: 1801: must be less than or equal to 1800",
199 }, {
200 behavior: autoscaling.HorizontalPodAutoscalerBehavior{
201 ScaleUp: &autoscaling.HPAScalingRules{
202 SelectPolicy: &incorrectPolicy,
203 Policies: []autoscaling.HPAScalingPolicy{{
204 Type: autoscaling.PodsScalingPolicy,
205 Value: 7,
206 PeriodSeconds: 8,
207 }},
208 },
209 },
210 msg: `spec.behavior.scaleUp.selectPolicy: Unsupported value: "incorrect": supported values: "Disabled", "Max", "Min"`,
211 }, {
212 behavior: autoscaling.HorizontalPodAutoscalerBehavior{
213 ScaleUp: &autoscaling.HPAScalingRules{
214 Policies: []autoscaling.HPAScalingPolicy{{
215 Type: autoscaling.HPAScalingPolicyType("hm"),
216 Value: 7,
217 PeriodSeconds: 8,
218 }},
219 },
220 },
221 msg: `spec.behavior.scaleUp.policies[0].type: Unsupported value: "hm": supported values: "Percent", "Pods"`,
222 }, {
223 behavior: autoscaling.HorizontalPodAutoscalerBehavior{
224 ScaleUp: &autoscaling.HPAScalingRules{
225 Policies: []autoscaling.HPAScalingPolicy{{
226 Type: autoscaling.PodsScalingPolicy,
227 Value: 8,
228 }},
229 },
230 },
231 msg: "spec.behavior.scaleUp.policies[0].periodSeconds: Invalid value: 0: must be greater than zero",
232 }, {
233 behavior: autoscaling.HorizontalPodAutoscalerBehavior{
234 ScaleUp: &autoscaling.HPAScalingRules{
235 Policies: []autoscaling.HPAScalingPolicy{{
236 Type: autoscaling.PodsScalingPolicy,
237 PeriodSeconds: 8,
238 }},
239 },
240 },
241 msg: "spec.behavior.scaleUp.policies[0].value: Invalid value: 0: must be greater than zero",
242 }, {
243 behavior: autoscaling.HorizontalPodAutoscalerBehavior{
244 ScaleUp: &autoscaling.HPAScalingRules{
245 Policies: []autoscaling.HPAScalingPolicy{{
246 Type: autoscaling.PodsScalingPolicy,
247 PeriodSeconds: -1,
248 Value: 1,
249 }},
250 },
251 },
252 msg: "spec.behavior.scaleUp.policies[0].periodSeconds: Invalid value: -1: must be greater than zero",
253 }, {
254 behavior: autoscaling.HorizontalPodAutoscalerBehavior{
255 ScaleUp: &autoscaling.HPAScalingRules{
256 Policies: []autoscaling.HPAScalingPolicy{{
257 Type: autoscaling.PodsScalingPolicy,
258 PeriodSeconds: 1,
259 Value: -1,
260 }},
261 },
262 },
263 msg: "spec.behavior.scaleUp.policies[0].value: Invalid value: -1: must be greater than zero",
264 }, {
265 behavior: autoscaling.HorizontalPodAutoscalerBehavior{
266 ScaleDown: &autoscaling.HPAScalingRules{
267 SelectPolicy: &minPolicy,
268 },
269 },
270 msg: "spec.behavior.scaleDown.policies: Required value: must specify at least one Policy",
271 }, {
272 behavior: autoscaling.HorizontalPodAutoscalerBehavior{
273 ScaleDown: &autoscaling.HPAScalingRules{
274 StabilizationWindowSeconds: utilpointer.Int32(3601),
275 SelectPolicy: &minPolicy,
276 Policies: simplePoliciesList,
277 },
278 },
279 msg: "spec.behavior.scaleDown.stabilizationWindowSeconds: Invalid value: 3601: must be less than or equal to 3600",
280 }, {
281 behavior: autoscaling.HorizontalPodAutoscalerBehavior{
282 ScaleDown: &autoscaling.HPAScalingRules{
283 Policies: []autoscaling.HPAScalingPolicy{{
284 Type: autoscaling.PercentScalingPolicy,
285 Value: 7,
286 PeriodSeconds: 1801,
287 }},
288 },
289 },
290 msg: "spec.behavior.scaleDown.policies[0].periodSeconds: Invalid value: 1801: must be less than or equal to 1800",
291 }, {
292 behavior: autoscaling.HorizontalPodAutoscalerBehavior{
293 ScaleDown: &autoscaling.HPAScalingRules{
294 SelectPolicy: &incorrectPolicy,
295 Policies: []autoscaling.HPAScalingPolicy{{
296 Type: autoscaling.PodsScalingPolicy,
297 Value: 7,
298 PeriodSeconds: 8,
299 }},
300 },
301 },
302 msg: `spec.behavior.scaleDown.selectPolicy: Unsupported value: "incorrect": supported values: "Disabled", "Max", "Min"`,
303 }, {
304 behavior: autoscaling.HorizontalPodAutoscalerBehavior{
305 ScaleDown: &autoscaling.HPAScalingRules{
306 Policies: []autoscaling.HPAScalingPolicy{{
307 Type: autoscaling.HPAScalingPolicyType("hm"),
308 Value: 7,
309 PeriodSeconds: 8,
310 }},
311 },
312 },
313 msg: `spec.behavior.scaleDown.policies[0].type: Unsupported value: "hm": supported values: "Percent", "Pods"`,
314 }, {
315 behavior: autoscaling.HorizontalPodAutoscalerBehavior{
316 ScaleDown: &autoscaling.HPAScalingRules{
317 Policies: []autoscaling.HPAScalingPolicy{{
318 Type: autoscaling.PodsScalingPolicy,
319 Value: 8,
320 }},
321 },
322 },
323 msg: "spec.behavior.scaleDown.policies[0].periodSeconds: Invalid value: 0: must be greater than zero",
324 }, {
325 behavior: autoscaling.HorizontalPodAutoscalerBehavior{
326 ScaleDown: &autoscaling.HPAScalingRules{
327 Policies: []autoscaling.HPAScalingPolicy{{
328 Type: autoscaling.PodsScalingPolicy,
329 PeriodSeconds: 8,
330 }},
331 },
332 },
333 msg: "spec.behavior.scaleDown.policies[0].value: Invalid value: 0: must be greater than zero",
334 }, {
335 behavior: autoscaling.HorizontalPodAutoscalerBehavior{
336 ScaleDown: &autoscaling.HPAScalingRules{
337 Policies: []autoscaling.HPAScalingPolicy{{
338 Type: autoscaling.PodsScalingPolicy,
339 PeriodSeconds: -1,
340 Value: 1,
341 }},
342 },
343 },
344 msg: "spec.behavior.scaleDown.policies[0].periodSeconds: Invalid value: -1: must be greater than zero",
345 }, {
346 behavior: autoscaling.HorizontalPodAutoscalerBehavior{
347 ScaleDown: &autoscaling.HPAScalingRules{
348 Policies: []autoscaling.HPAScalingPolicy{{
349 Type: autoscaling.PodsScalingPolicy,
350 PeriodSeconds: 1,
351 Value: -1,
352 }},
353 },
354 },
355 msg: "spec.behavior.scaleDown.policies[0].value: Invalid value: -1: must be greater than zero",
356 }}
357 for _, c := range errorCases {
358 hpa := prepareHPAWithBehavior(c.behavior)
359 if errs := ValidateHorizontalPodAutoscaler(&hpa); len(errs) == 0 {
360 t.Errorf("expected failure for %s", c.msg)
361 } else if !strings.Contains(errs[0].Error(), c.msg) {
362 t.Errorf("unexpected error: %v, expected: %s", errs[0], c.msg)
363 }
364 }
365 }
366
367 func prepareHPAWithBehavior(b autoscaling.HorizontalPodAutoscalerBehavior) autoscaling.HorizontalPodAutoscaler {
368 return autoscaling.HorizontalPodAutoscaler{
369 ObjectMeta: metav1.ObjectMeta{
370 Name: "myautoscaler",
371 Namespace: metav1.NamespaceDefault,
372 },
373 Spec: autoscaling.HorizontalPodAutoscalerSpec{
374 ScaleTargetRef: autoscaling.CrossVersionObjectReference{
375 Kind: "ReplicationController",
376 Name: "myrc",
377 },
378 MinReplicas: utilpointer.Int32(1),
379 MaxReplicas: 5,
380 Metrics: []autoscaling.MetricSpec{{
381 Type: autoscaling.ResourceMetricSourceType,
382 Resource: &autoscaling.ResourceMetricSource{
383 Name: api.ResourceCPU,
384 Target: autoscaling.MetricTarget{
385 Type: autoscaling.UtilizationMetricType,
386 AverageUtilization: utilpointer.Int32(70),
387 },
388 },
389 }},
390 Behavior: &b,
391 },
392 }
393 }
394
395 func TestValidateHorizontalPodAutoscaler(t *testing.T) {
396 metricLabelSelector, err := metav1.ParseToLabelSelector("label=value")
397 if err != nil {
398 t.Errorf("unable to parse label selector: %v", err)
399 }
400
401 successCases := []autoscaling.HorizontalPodAutoscaler{{
402 ObjectMeta: metav1.ObjectMeta{
403 Name: "myautoscaler",
404 Namespace: metav1.NamespaceDefault,
405 },
406 Spec: autoscaling.HorizontalPodAutoscalerSpec{
407 ScaleTargetRef: autoscaling.CrossVersionObjectReference{
408 Kind: "ReplicationController",
409 Name: "myrc",
410 },
411 MinReplicas: utilpointer.Int32(1),
412 MaxReplicas: 5,
413 Metrics: []autoscaling.MetricSpec{{
414 Type: autoscaling.ResourceMetricSourceType,
415 Resource: &autoscaling.ResourceMetricSource{
416 Name: api.ResourceCPU,
417 Target: autoscaling.MetricTarget{
418 Type: autoscaling.UtilizationMetricType,
419 AverageUtilization: utilpointer.Int32(70),
420 },
421 },
422 }},
423 },
424 }, {
425 ObjectMeta: metav1.ObjectMeta{
426 Name: "myautoscaler",
427 Namespace: metav1.NamespaceDefault,
428 },
429 Spec: autoscaling.HorizontalPodAutoscalerSpec{
430 ScaleTargetRef: autoscaling.CrossVersionObjectReference{
431 Kind: "ReplicationController",
432 Name: "myrc",
433 },
434 MinReplicas: utilpointer.Int32(1),
435 MaxReplicas: 5,
436 },
437 }, {
438 ObjectMeta: metav1.ObjectMeta{
439 Name: "myautoscaler",
440 Namespace: metav1.NamespaceDefault,
441 },
442 Spec: autoscaling.HorizontalPodAutoscalerSpec{
443 ScaleTargetRef: autoscaling.CrossVersionObjectReference{
444 Kind: "ReplicationController",
445 Name: "myrc",
446 },
447 MinReplicas: utilpointer.Int32(1),
448 MaxReplicas: 5,
449 Metrics: []autoscaling.MetricSpec{{
450 Type: autoscaling.ResourceMetricSourceType,
451 Resource: &autoscaling.ResourceMetricSource{
452 Name: api.ResourceCPU,
453 Target: autoscaling.MetricTarget{
454 Type: autoscaling.AverageValueMetricType,
455 AverageValue: resource.NewMilliQuantity(300, resource.DecimalSI),
456 },
457 },
458 }},
459 },
460 }, {
461 ObjectMeta: metav1.ObjectMeta{
462 Name: "myautoscaler",
463 Namespace: metav1.NamespaceDefault,
464 },
465 Spec: autoscaling.HorizontalPodAutoscalerSpec{
466 ScaleTargetRef: autoscaling.CrossVersionObjectReference{
467 Kind: "ReplicationController",
468 Name: "myrc",
469 },
470 MinReplicas: utilpointer.Int32(1),
471 MaxReplicas: 5,
472 Metrics: []autoscaling.MetricSpec{{
473 Type: autoscaling.PodsMetricSourceType,
474 Pods: &autoscaling.PodsMetricSource{
475 Metric: autoscaling.MetricIdentifier{
476 Name: "somemetric",
477 },
478 Target: autoscaling.MetricTarget{
479 Type: autoscaling.AverageValueMetricType,
480 AverageValue: resource.NewMilliQuantity(300, resource.DecimalSI),
481 },
482 },
483 }},
484 },
485 }, {
486 ObjectMeta: metav1.ObjectMeta{
487 Name: "myautoscaler",
488 Namespace: metav1.NamespaceDefault,
489 },
490 Spec: autoscaling.HorizontalPodAutoscalerSpec{
491 ScaleTargetRef: autoscaling.CrossVersionObjectReference{
492 Kind: "ReplicationController",
493 Name: "myrc",
494 },
495 MinReplicas: utilpointer.Int32(1),
496 MaxReplicas: 5,
497 Metrics: []autoscaling.MetricSpec{{
498 Type: autoscaling.ContainerResourceMetricSourceType,
499 ContainerResource: &autoscaling.ContainerResourceMetricSource{
500 Name: api.ResourceCPU,
501 Container: "test-container",
502 Target: autoscaling.MetricTarget{
503 Type: autoscaling.UtilizationMetricType,
504 AverageUtilization: utilpointer.Int32(70),
505 },
506 },
507 }},
508 },
509 }, {
510 ObjectMeta: metav1.ObjectMeta{
511 Name: "myautoscaler",
512 Namespace: metav1.NamespaceDefault,
513 },
514 Spec: autoscaling.HorizontalPodAutoscalerSpec{
515 ScaleTargetRef: autoscaling.CrossVersionObjectReference{
516 Kind: "ReplicationController",
517 Name: "myrc",
518 },
519 MinReplicas: utilpointer.Int32(1),
520 MaxReplicas: 5,
521 Metrics: []autoscaling.MetricSpec{{
522 Type: autoscaling.ContainerResourceMetricSourceType,
523 ContainerResource: &autoscaling.ContainerResourceMetricSource{
524 Name: api.ResourceCPU,
525 Container: "test-container",
526 Target: autoscaling.MetricTarget{
527 Type: autoscaling.AverageValueMetricType,
528 AverageValue: resource.NewMilliQuantity(300, resource.DecimalSI),
529 },
530 },
531 }},
532 },
533 }, {
534 ObjectMeta: metav1.ObjectMeta{
535 Name: "myautoscaler",
536 Namespace: metav1.NamespaceDefault,
537 },
538 Spec: autoscaling.HorizontalPodAutoscalerSpec{
539 ScaleTargetRef: autoscaling.CrossVersionObjectReference{
540 Kind: "ReplicationController",
541 Name: "myrc",
542 },
543 MinReplicas: utilpointer.Int32(1),
544 MaxReplicas: 5,
545 Metrics: []autoscaling.MetricSpec{{
546 Type: autoscaling.ObjectMetricSourceType,
547 Object: &autoscaling.ObjectMetricSource{
548 DescribedObject: autoscaling.CrossVersionObjectReference{
549 Kind: "ReplicationController",
550 Name: "myrc",
551 },
552 Metric: autoscaling.MetricIdentifier{
553 Name: "somemetric",
554 },
555 Target: autoscaling.MetricTarget{
556 Type: autoscaling.ValueMetricType,
557 Value: resource.NewMilliQuantity(300, resource.DecimalSI),
558 },
559 },
560 }},
561 },
562 }, {
563 ObjectMeta: metav1.ObjectMeta{
564 Name: "myautoscaler",
565 Namespace: metav1.NamespaceDefault,
566 },
567 Spec: autoscaling.HorizontalPodAutoscalerSpec{
568 ScaleTargetRef: autoscaling.CrossVersionObjectReference{
569 Kind: "ReplicationController",
570 Name: "myrc",
571 },
572 MinReplicas: utilpointer.Int32(1),
573 MaxReplicas: 5,
574 Metrics: []autoscaling.MetricSpec{{
575 Type: autoscaling.ExternalMetricSourceType,
576 External: &autoscaling.ExternalMetricSource{
577 Metric: autoscaling.MetricIdentifier{
578 Name: "somemetric",
579 Selector: metricLabelSelector,
580 },
581 Target: autoscaling.MetricTarget{
582 Type: autoscaling.ValueMetricType,
583 Value: resource.NewMilliQuantity(300, resource.DecimalSI),
584 },
585 },
586 }},
587 },
588 }, {
589 ObjectMeta: metav1.ObjectMeta{
590 Name: "myautoscaler",
591 Namespace: metav1.NamespaceDefault,
592 },
593 Spec: autoscaling.HorizontalPodAutoscalerSpec{
594 ScaleTargetRef: autoscaling.CrossVersionObjectReference{
595 Kind: "ReplicationController",
596 Name: "myrc",
597 },
598 MinReplicas: utilpointer.Int32(1),
599 MaxReplicas: 5,
600 Metrics: []autoscaling.MetricSpec{{
601 Type: autoscaling.ExternalMetricSourceType,
602 External: &autoscaling.ExternalMetricSource{
603 Metric: autoscaling.MetricIdentifier{
604 Name: "somemetric",
605 Selector: metricLabelSelector,
606 },
607 Target: autoscaling.MetricTarget{
608 Type: autoscaling.AverageValueMetricType,
609 AverageValue: resource.NewMilliQuantity(300, resource.DecimalSI),
610 },
611 },
612 }},
613 },
614 }}
615 for _, successCase := range successCases {
616 if errs := ValidateHorizontalPodAutoscaler(&successCase); len(errs) != 0 {
617 t.Errorf("expected success: %v", errs)
618 }
619 }
620
621 errorCases := []struct {
622 horizontalPodAutoscaler autoscaling.HorizontalPodAutoscaler
623 msg string
624 }{{
625 horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{
626 ObjectMeta: metav1.ObjectMeta{Name: "myautoscaler", Namespace: metav1.NamespaceDefault},
627 Spec: autoscaling.HorizontalPodAutoscalerSpec{
628 ScaleTargetRef: autoscaling.CrossVersionObjectReference{Name: "myrc"},
629 MinReplicas: utilpointer.Int32(1),
630 MaxReplicas: 5,
631 Metrics: []autoscaling.MetricSpec{{
632 Type: autoscaling.ResourceMetricSourceType,
633 Resource: &autoscaling.ResourceMetricSource{
634 Name: api.ResourceCPU,
635 Target: autoscaling.MetricTarget{
636 Type: autoscaling.UtilizationMetricType,
637 AverageUtilization: utilpointer.Int32(70),
638 },
639 },
640 }},
641 },
642 },
643 msg: "scaleTargetRef.kind: Required",
644 }, {
645 horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{
646 ObjectMeta: metav1.ObjectMeta{Name: "myautoscaler", Namespace: metav1.NamespaceDefault},
647 Spec: autoscaling.HorizontalPodAutoscalerSpec{
648 ScaleTargetRef: autoscaling.CrossVersionObjectReference{Name: "myrc"},
649 MinReplicas: utilpointer.Int32(1),
650 MaxReplicas: 5,
651 Metrics: []autoscaling.MetricSpec{{
652 Type: autoscaling.ContainerResourceMetricSourceType,
653 ContainerResource: &autoscaling.ContainerResourceMetricSource{
654 Name: api.ResourceCPU,
655 Container: "test-application",
656 Target: autoscaling.MetricTarget{
657 Type: autoscaling.UtilizationMetricType,
658 AverageUtilization: utilpointer.Int32(70),
659 },
660 },
661 }},
662 },
663 },
664 msg: "scaleTargetRef.kind: Required",
665 }, {
666 horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{
667 ObjectMeta: metav1.ObjectMeta{Name: "myautoscaler", Namespace: metav1.NamespaceDefault},
668 Spec: autoscaling.HorizontalPodAutoscalerSpec{
669 ScaleTargetRef: autoscaling.CrossVersionObjectReference{Kind: "..", Name: "myrc"},
670 MinReplicas: utilpointer.Int32(1),
671 MaxReplicas: 5,
672 Metrics: []autoscaling.MetricSpec{{
673 Type: autoscaling.ResourceMetricSourceType,
674 Resource: &autoscaling.ResourceMetricSource{
675 Name: api.ResourceCPU,
676 Target: autoscaling.MetricTarget{
677 Type: autoscaling.UtilizationMetricType,
678 AverageUtilization: utilpointer.Int32(70),
679 },
680 },
681 }},
682 },
683 },
684 msg: "scaleTargetRef.kind: Invalid",
685 }, {
686 horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{
687 ObjectMeta: metav1.ObjectMeta{Name: "myautoscaler", Namespace: metav1.NamespaceDefault},
688 Spec: autoscaling.HorizontalPodAutoscalerSpec{
689 ScaleTargetRef: autoscaling.CrossVersionObjectReference{Kind: "..", Name: "myrc"},
690 MinReplicas: utilpointer.Int32(1),
691 MaxReplicas: 5,
692 Metrics: []autoscaling.MetricSpec{{
693 Type: autoscaling.ContainerResourceMetricSourceType,
694 ContainerResource: &autoscaling.ContainerResourceMetricSource{
695 Name: api.ResourceCPU,
696 Container: "test-application",
697 Target: autoscaling.MetricTarget{
698 Type: autoscaling.UtilizationMetricType,
699 AverageUtilization: utilpointer.Int32(70),
700 },
701 },
702 }},
703 },
704 },
705 msg: "scaleTargetRef.kind: Invalid",
706 }, {
707 horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{
708 ObjectMeta: metav1.ObjectMeta{Name: "myautoscaler", Namespace: metav1.NamespaceDefault},
709 Spec: autoscaling.HorizontalPodAutoscalerSpec{
710 ScaleTargetRef: autoscaling.CrossVersionObjectReference{Kind: "ReplicationController"},
711 MinReplicas: utilpointer.Int32(1),
712 MaxReplicas: 5,
713 Metrics: []autoscaling.MetricSpec{{
714 Type: autoscaling.ResourceMetricSourceType,
715 Resource: &autoscaling.ResourceMetricSource{
716 Name: api.ResourceCPU,
717 Target: autoscaling.MetricTarget{
718 Type: autoscaling.UtilizationMetricType,
719 AverageUtilization: utilpointer.Int32(70),
720 },
721 },
722 }},
723 },
724 },
725 msg: "scaleTargetRef.name: Required",
726 }, {
727 horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{
728 ObjectMeta: metav1.ObjectMeta{Name: "myautoscaler", Namespace: metav1.NamespaceDefault},
729 Spec: autoscaling.HorizontalPodAutoscalerSpec{
730 ScaleTargetRef: autoscaling.CrossVersionObjectReference{Kind: "ReplicationController"},
731 MinReplicas: utilpointer.Int32(1),
732 MaxReplicas: 5,
733 Metrics: []autoscaling.MetricSpec{{
734 Type: autoscaling.ContainerResourceMetricSourceType,
735 ContainerResource: &autoscaling.ContainerResourceMetricSource{
736 Name: api.ResourceCPU,
737 Container: "test-application",
738 Target: autoscaling.MetricTarget{
739 Type: autoscaling.UtilizationMetricType,
740 AverageUtilization: utilpointer.Int32(70),
741 },
742 },
743 }},
744 },
745 },
746 msg: "scaleTargetRef.name: Required",
747 }, {
748 horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{
749 ObjectMeta: metav1.ObjectMeta{Name: "myautoscaler", Namespace: metav1.NamespaceDefault},
750 Spec: autoscaling.HorizontalPodAutoscalerSpec{
751 ScaleTargetRef: autoscaling.CrossVersionObjectReference{Kind: "ReplicationController", Name: ".."},
752 MinReplicas: utilpointer.Int32(1),
753 MaxReplicas: 5,
754 Metrics: []autoscaling.MetricSpec{{
755 Type: autoscaling.ResourceMetricSourceType,
756 Resource: &autoscaling.ResourceMetricSource{
757 Name: api.ResourceCPU,
758 Target: autoscaling.MetricTarget{
759 Type: autoscaling.UtilizationMetricType,
760 AverageUtilization: utilpointer.Int32(70),
761 },
762 },
763 }},
764 },
765 },
766 msg: "scaleTargetRef.name: Invalid",
767 }, {
768 horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{
769 ObjectMeta: metav1.ObjectMeta{Name: "myautoscaler", Namespace: metav1.NamespaceDefault},
770 Spec: autoscaling.HorizontalPodAutoscalerSpec{
771 ScaleTargetRef: autoscaling.CrossVersionObjectReference{Kind: "ReplicationController", Name: ".."},
772 MinReplicas: utilpointer.Int32(1),
773 MaxReplicas: 5,
774 Metrics: []autoscaling.MetricSpec{{
775 Type: autoscaling.ContainerResourceMetricSourceType,
776 ContainerResource: &autoscaling.ContainerResourceMetricSource{
777 Name: api.ResourceCPU,
778 Container: "test-application",
779 Target: autoscaling.MetricTarget{
780 Type: autoscaling.UtilizationMetricType,
781 AverageUtilization: utilpointer.Int32(70),
782 },
783 },
784 }},
785 },
786 },
787 msg: "scaleTargetRef.name: Invalid",
788 }, {
789 horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{
790 ObjectMeta: metav1.ObjectMeta{
791 Name: "myautoscaler",
792 Namespace: metav1.NamespaceDefault,
793 },
794 Spec: autoscaling.HorizontalPodAutoscalerSpec{
795 ScaleTargetRef: autoscaling.CrossVersionObjectReference{},
796 MinReplicas: utilpointer.Int32(-1),
797 MaxReplicas: 5,
798 },
799 },
800 msg: "must be greater than or equal to 1",
801 }, {
802 horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{
803 ObjectMeta: metav1.ObjectMeta{
804 Name: "myautoscaler",
805 Namespace: metav1.NamespaceDefault,
806 },
807 Spec: autoscaling.HorizontalPodAutoscalerSpec{
808 ScaleTargetRef: autoscaling.CrossVersionObjectReference{},
809 MinReplicas: utilpointer.Int32(7),
810 MaxReplicas: 5,
811 },
812 },
813 msg: "must be greater than or equal to `minReplicas`",
814 }, {
815 horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{
816 ObjectMeta: metav1.ObjectMeta{
817 Name: "myautoscaler",
818 Namespace: metav1.NamespaceDefault,
819 },
820 Spec: autoscaling.HorizontalPodAutoscalerSpec{
821 ScaleTargetRef: autoscaling.CrossVersionObjectReference{Name: "myrc", Kind: "ReplicationController"},
822 MinReplicas: utilpointer.Int32(1),
823 MaxReplicas: 5,
824 Metrics: []autoscaling.MetricSpec{{
825 Type: autoscaling.ResourceMetricSourceType,
826 Resource: &autoscaling.ResourceMetricSource{
827 Name: api.ResourceCPU,
828 Target: autoscaling.MetricTarget{
829 Type: autoscaling.UtilizationMetricType,
830 AverageUtilization: utilpointer.Int32(70),
831 AverageValue: resource.NewMilliQuantity(300, resource.DecimalSI),
832 },
833 },
834 }},
835 },
836 },
837 msg: "may not set both a target raw value and a target utilization",
838 }, {
839 horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{
840 ObjectMeta: metav1.ObjectMeta{
841 Name: "myautoscaler",
842 Namespace: metav1.NamespaceDefault,
843 },
844 Spec: autoscaling.HorizontalPodAutoscalerSpec{
845 ScaleTargetRef: autoscaling.CrossVersionObjectReference{Name: "myrc", Kind: "ReplicationController"},
846 MinReplicas: utilpointer.Int32(1),
847 MaxReplicas: 5,
848 Metrics: []autoscaling.MetricSpec{{
849 Type: autoscaling.ContainerResourceMetricSourceType,
850 ContainerResource: &autoscaling.ContainerResourceMetricSource{
851 Name: api.ResourceCPU,
852 Container: "test-application",
853 Target: autoscaling.MetricTarget{
854 Type: autoscaling.UtilizationMetricType,
855 AverageUtilization: utilpointer.Int32(70),
856 AverageValue: resource.NewMilliQuantity(300, resource.DecimalSI),
857 },
858 },
859 }},
860 },
861 },
862 msg: "may not set both a target raw value and a target utilization",
863 }, {
864 horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{
865 ObjectMeta: metav1.ObjectMeta{Name: "myautoscaler", Namespace: metav1.NamespaceDefault},
866 Spec: autoscaling.HorizontalPodAutoscalerSpec{
867 ScaleTargetRef: autoscaling.CrossVersionObjectReference{Name: "myrc", Kind: "ReplicationController"},
868 MinReplicas: utilpointer.Int32(1),
869 MaxReplicas: 5,
870 Metrics: []autoscaling.MetricSpec{{
871 Type: autoscaling.ResourceMetricSourceType,
872 Resource: &autoscaling.ResourceMetricSource{
873 Target: autoscaling.MetricTarget{
874 Type: autoscaling.UtilizationMetricType,
875 AverageUtilization: utilpointer.Int32(70),
876 },
877 },
878 }},
879 },
880 },
881 msg: "must specify a resource name",
882 }, {
883 horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{
884 ObjectMeta: metav1.ObjectMeta{Name: "myautoscaler", Namespace: metav1.NamespaceDefault},
885 Spec: autoscaling.HorizontalPodAutoscalerSpec{
886 ScaleTargetRef: autoscaling.CrossVersionObjectReference{Name: "myrc", Kind: "ReplicationController"},
887 MinReplicas: utilpointer.Int32(1),
888 MaxReplicas: 5,
889 Metrics: []autoscaling.MetricSpec{{
890 Type: autoscaling.ContainerResourceMetricSourceType,
891 ContainerResource: &autoscaling.ContainerResourceMetricSource{
892 Container: "test-application",
893 Target: autoscaling.MetricTarget{
894 Type: autoscaling.UtilizationMetricType,
895 AverageUtilization: utilpointer.Int32(70),
896 },
897 },
898 }},
899 },
900 },
901 msg: "must specify a resource name",
902 }, {
903 horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{
904 ObjectMeta: metav1.ObjectMeta{Name: "myautoscaler", Namespace: metav1.NamespaceDefault},
905 Spec: autoscaling.HorizontalPodAutoscalerSpec{
906 ScaleTargetRef: autoscaling.CrossVersionObjectReference{Name: "myrc", Kind: "ReplicationController"},
907 MinReplicas: utilpointer.Int32(1),
908 MaxReplicas: 5,
909 Metrics: []autoscaling.MetricSpec{{
910 Type: autoscaling.ContainerResourceMetricSourceType,
911 ContainerResource: &autoscaling.ContainerResourceMetricSource{
912 Name: "InvalidResource",
913 Container: "test-application",
914 Target: autoscaling.MetricTarget{
915 Type: autoscaling.UtilizationMetricType,
916 AverageUtilization: utilpointer.Int32(70),
917 },
918 },
919 }},
920 },
921 },
922 msg: "Invalid value: InvalidResource: must be a standard resource type or fully qualified",
923 }, {
924 horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{
925 ObjectMeta: metav1.ObjectMeta{Name: "myautoscaler", Namespace: metav1.NamespaceDefault},
926 Spec: autoscaling.HorizontalPodAutoscalerSpec{
927 ScaleTargetRef: autoscaling.CrossVersionObjectReference{Name: "myrc", Kind: "ReplicationController"},
928 MinReplicas: utilpointer.Int32(1),
929 MaxReplicas: 5,
930 Metrics: []autoscaling.MetricSpec{{
931 Type: autoscaling.ResourceMetricSourceType,
932 Resource: &autoscaling.ResourceMetricSource{
933 Name: api.ResourceCPU,
934 Target: autoscaling.MetricTarget{
935 Type: autoscaling.UtilizationMetricType,
936 AverageUtilization: utilpointer.Int32(-10),
937 },
938 },
939 }},
940 },
941 },
942 msg: "must be greater than 0",
943 }, {
944 horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{
945 ObjectMeta: metav1.ObjectMeta{Name: "myautoscaler", Namespace: metav1.NamespaceDefault},
946 Spec: autoscaling.HorizontalPodAutoscalerSpec{
947 ScaleTargetRef: autoscaling.CrossVersionObjectReference{Name: "myrc", Kind: "ReplicationController"},
948 MinReplicas: utilpointer.Int32(1),
949 MaxReplicas: 5,
950 Metrics: []autoscaling.MetricSpec{{
951 Type: autoscaling.ContainerResourceMetricSourceType,
952 ContainerResource: &autoscaling.ContainerResourceMetricSource{
953 Name: api.ResourceCPU,
954 Container: "test-application",
955 Target: autoscaling.MetricTarget{
956 Type: autoscaling.UtilizationMetricType,
957 AverageUtilization: utilpointer.Int32(-10),
958 },
959 },
960 }},
961 },
962 },
963 msg: "must be greater than 0",
964 }, {
965 horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{
966 ObjectMeta: metav1.ObjectMeta{Name: "myautoscaler", Namespace: metav1.NamespaceDefault},
967 Spec: autoscaling.HorizontalPodAutoscalerSpec{
968 ScaleTargetRef: autoscaling.CrossVersionObjectReference{Name: "myrc", Kind: "ReplicationController"},
969 MinReplicas: utilpointer.Int32(1),
970 MaxReplicas: 5,
971 Metrics: []autoscaling.MetricSpec{{
972 Type: autoscaling.ContainerResourceMetricSourceType,
973 ContainerResource: &autoscaling.ContainerResourceMetricSource{
974 Name: api.ResourceCPU,
975 Target: autoscaling.MetricTarget{
976 Type: autoscaling.UtilizationMetricType,
977 AverageUtilization: utilpointer.Int32(-10),
978 },
979 },
980 }},
981 },
982 },
983 msg: "must specify a container",
984 }, {
985 horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{
986 ObjectMeta: metav1.ObjectMeta{Name: "myautoscaler", Namespace: metav1.NamespaceDefault},
987 Spec: autoscaling.HorizontalPodAutoscalerSpec{
988 ScaleTargetRef: autoscaling.CrossVersionObjectReference{Name: "myrc", Kind: "ReplicationController"},
989 MinReplicas: utilpointer.Int32(1),
990 MaxReplicas: 5,
991 Metrics: []autoscaling.MetricSpec{{
992 Type: autoscaling.ContainerResourceMetricSourceType,
993 ContainerResource: &autoscaling.ContainerResourceMetricSource{
994 Name: api.ResourceCPU,
995 Container: "---***",
996 Target: autoscaling.MetricTarget{
997 Type: autoscaling.UtilizationMetricType,
998 AverageUtilization: utilpointer.Int32(-10),
999 },
1000 },
1001 }},
1002 },
1003 },
1004 msg: "Invalid value: \"---***\"",
1005 }, {
1006 horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{
1007 ObjectMeta: metav1.ObjectMeta{Name: "myautoscaler", Namespace: metav1.NamespaceDefault},
1008 Spec: autoscaling.HorizontalPodAutoscalerSpec{
1009 ScaleTargetRef: autoscaling.CrossVersionObjectReference{Name: "myrc", Kind: "ReplicationController"},
1010 MinReplicas: utilpointer.Int32(1),
1011 MaxReplicas: 5,
1012 Metrics: []autoscaling.MetricSpec{{
1013 Type: autoscaling.ResourceMetricSourceType,
1014 Resource: &autoscaling.ResourceMetricSource{
1015 Name: api.ResourceCPU,
1016 Target: autoscaling.MetricTarget{
1017 Type: autoscaling.ValueMetricType,
1018 },
1019 },
1020 }},
1021 },
1022 },
1023 msg: "must set either a target raw value or a target utilization",
1024 }, {
1025 horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{
1026 ObjectMeta: metav1.ObjectMeta{Name: "myautoscaler", Namespace: metav1.NamespaceDefault},
1027 Spec: autoscaling.HorizontalPodAutoscalerSpec{
1028 ScaleTargetRef: autoscaling.CrossVersionObjectReference{Name: "myrc", Kind: "ReplicationController"},
1029 MinReplicas: utilpointer.Int32(1),
1030 MaxReplicas: 5,
1031 Metrics: []autoscaling.MetricSpec{{
1032 Type: autoscaling.ContainerResourceMetricSourceType,
1033 ContainerResource: &autoscaling.ContainerResourceMetricSource{
1034 Name: api.ResourceCPU,
1035 Container: "test-application",
1036 Target: autoscaling.MetricTarget{
1037 Type: autoscaling.ValueMetricType,
1038 },
1039 },
1040 }},
1041 },
1042 },
1043 msg: "must set either a target raw value or a target utilization",
1044 }, {
1045 horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{
1046 ObjectMeta: metav1.ObjectMeta{Name: "myautoscaler", Namespace: metav1.NamespaceDefault},
1047 Spec: autoscaling.HorizontalPodAutoscalerSpec{
1048 ScaleTargetRef: autoscaling.CrossVersionObjectReference{Name: "myrc", Kind: "ReplicationController"},
1049 MinReplicas: utilpointer.Int32(1),
1050 MaxReplicas: 5,
1051 Metrics: []autoscaling.MetricSpec{{
1052 Type: autoscaling.PodsMetricSourceType,
1053 Pods: &autoscaling.PodsMetricSource{
1054 Metric: autoscaling.MetricIdentifier{},
1055 Target: autoscaling.MetricTarget{
1056 Type: autoscaling.ValueMetricType,
1057 AverageValue: resource.NewMilliQuantity(100, resource.DecimalSI),
1058 },
1059 },
1060 }},
1061 },
1062 },
1063 msg: "must specify a metric name",
1064 }, {
1065 horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{
1066 ObjectMeta: metav1.ObjectMeta{Name: "myautoscaler", Namespace: metav1.NamespaceDefault},
1067 Spec: autoscaling.HorizontalPodAutoscalerSpec{
1068 ScaleTargetRef: autoscaling.CrossVersionObjectReference{Name: "myrc", Kind: "ReplicationController"},
1069 MinReplicas: utilpointer.Int32(1),
1070 MaxReplicas: 5,
1071 Metrics: []autoscaling.MetricSpec{{
1072 Type: autoscaling.PodsMetricSourceType,
1073 Pods: &autoscaling.PodsMetricSource{
1074 Metric: autoscaling.MetricIdentifier{
1075 Name: "somemetric",
1076 },
1077 Target: autoscaling.MetricTarget{
1078 Type: autoscaling.ValueMetricType,
1079 },
1080 },
1081 }},
1082 },
1083 },
1084 msg: "must specify a positive target averageValue",
1085 }, {
1086 horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{
1087 ObjectMeta: metav1.ObjectMeta{Name: "myautoscaler", Namespace: metav1.NamespaceDefault},
1088 Spec: autoscaling.HorizontalPodAutoscalerSpec{
1089 ScaleTargetRef: autoscaling.CrossVersionObjectReference{Name: "myrc", Kind: "ReplicationController"},
1090 MinReplicas: utilpointer.Int32(1),
1091 MaxReplicas: 5,
1092 Metrics: []autoscaling.MetricSpec{{
1093 Type: autoscaling.ObjectMetricSourceType,
1094 Object: &autoscaling.ObjectMetricSource{
1095 DescribedObject: autoscaling.CrossVersionObjectReference{
1096 Kind: "ReplicationController",
1097 Name: "myrc",
1098 },
1099 Metric: autoscaling.MetricIdentifier{
1100 Name: "somemetric",
1101 },
1102 Target: autoscaling.MetricTarget{
1103 Type: autoscaling.ValueMetricType,
1104 },
1105 },
1106 }},
1107 },
1108 },
1109 msg: "must set either a target value or averageValue",
1110 }, {
1111 horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{
1112 ObjectMeta: metav1.ObjectMeta{Name: "myautoscaler", Namespace: metav1.NamespaceDefault},
1113 Spec: autoscaling.HorizontalPodAutoscalerSpec{
1114 ScaleTargetRef: autoscaling.CrossVersionObjectReference{Name: "myrc", Kind: "ReplicationController"},
1115 MinReplicas: utilpointer.Int32(1),
1116 MaxReplicas: 5,
1117 Metrics: []autoscaling.MetricSpec{{
1118 Type: autoscaling.ObjectMetricSourceType,
1119 Object: &autoscaling.ObjectMetricSource{
1120 DescribedObject: autoscaling.CrossVersionObjectReference{
1121 Name: "myrc",
1122 },
1123 Metric: autoscaling.MetricIdentifier{
1124 Name: "somemetric",
1125 },
1126 Target: autoscaling.MetricTarget{
1127 Type: autoscaling.ValueMetricType,
1128 Value: resource.NewMilliQuantity(100, resource.DecimalSI),
1129 },
1130 },
1131 }},
1132 },
1133 },
1134 msg: "object.describedObject.kind: Required",
1135 }, {
1136 horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{
1137 ObjectMeta: metav1.ObjectMeta{Name: "myautoscaler", Namespace: metav1.NamespaceDefault},
1138 Spec: autoscaling.HorizontalPodAutoscalerSpec{
1139 ScaleTargetRef: autoscaling.CrossVersionObjectReference{Name: "myrc", Kind: "ReplicationController"},
1140 MinReplicas: utilpointer.Int32(1),
1141 MaxReplicas: 5,
1142 Metrics: []autoscaling.MetricSpec{{
1143 Type: autoscaling.ObjectMetricSourceType,
1144 Object: &autoscaling.ObjectMetricSource{
1145 DescribedObject: autoscaling.CrossVersionObjectReference{
1146 Kind: "ReplicationController",
1147 Name: "myrc",
1148 },
1149 Target: autoscaling.MetricTarget{
1150 Type: autoscaling.ValueMetricType,
1151 Value: resource.NewMilliQuantity(100, resource.DecimalSI),
1152 },
1153 },
1154 }},
1155 },
1156 },
1157 msg: "must specify a metric name",
1158 }, {
1159 horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{
1160 ObjectMeta: metav1.ObjectMeta{Name: "myautoscaler", Namespace: metav1.NamespaceDefault},
1161 Spec: autoscaling.HorizontalPodAutoscalerSpec{
1162 ScaleTargetRef: autoscaling.CrossVersionObjectReference{Name: "myrc", Kind: "ReplicationController"},
1163 MinReplicas: utilpointer.Int32(1),
1164 MaxReplicas: 5,
1165 Metrics: []autoscaling.MetricSpec{{
1166 Type: autoscaling.ExternalMetricSourceType,
1167 External: &autoscaling.ExternalMetricSource{
1168 Metric: autoscaling.MetricIdentifier{
1169 Selector: metricLabelSelector,
1170 },
1171 Target: autoscaling.MetricTarget{
1172 Type: autoscaling.ValueMetricType,
1173 Value: resource.NewMilliQuantity(300, resource.DecimalSI),
1174 },
1175 },
1176 }},
1177 },
1178 },
1179 msg: "must specify a metric name",
1180 }, {
1181 horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{
1182 ObjectMeta: metav1.ObjectMeta{Name: "myautoscaler", Namespace: metav1.NamespaceDefault},
1183 Spec: autoscaling.HorizontalPodAutoscalerSpec{
1184 ScaleTargetRef: autoscaling.CrossVersionObjectReference{Name: "myrc", Kind: "ReplicationController"},
1185 MinReplicas: utilpointer.Int32(1),
1186 MaxReplicas: 5,
1187 Metrics: []autoscaling.MetricSpec{{
1188 Type: autoscaling.ExternalMetricSourceType,
1189 External: &autoscaling.ExternalMetricSource{
1190 Metric: autoscaling.MetricIdentifier{
1191 Name: "foo/../",
1192 Selector: metricLabelSelector,
1193 },
1194 Target: autoscaling.MetricTarget{
1195 Type: autoscaling.ValueMetricType,
1196 Value: resource.NewMilliQuantity(300, resource.DecimalSI),
1197 },
1198 },
1199 }},
1200 },
1201 },
1202 msg: "'/'",
1203 },
1204
1205 {
1206 horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{
1207 ObjectMeta: metav1.ObjectMeta{Name: "myautoscaler", Namespace: metav1.NamespaceDefault},
1208 Spec: autoscaling.HorizontalPodAutoscalerSpec{
1209 ScaleTargetRef: autoscaling.CrossVersionObjectReference{Name: "myrc", Kind: "ReplicationController"},
1210 MinReplicas: utilpointer.Int32(1),
1211 MaxReplicas: 5,
1212 Metrics: []autoscaling.MetricSpec{{
1213 Type: autoscaling.ExternalMetricSourceType,
1214 External: &autoscaling.ExternalMetricSource{
1215 Metric: autoscaling.MetricIdentifier{
1216 Name: "somemetric",
1217 Selector: metricLabelSelector,
1218 },
1219 Target: autoscaling.MetricTarget{
1220 Type: autoscaling.ValueMetricType,
1221 },
1222 },
1223 }},
1224 },
1225 },
1226 msg: "must set either a target value for metric or a per-pod target",
1227 }, {
1228 horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{
1229 ObjectMeta: metav1.ObjectMeta{Name: "myautoscaler", Namespace: metav1.NamespaceDefault},
1230 Spec: autoscaling.HorizontalPodAutoscalerSpec{
1231 ScaleTargetRef: autoscaling.CrossVersionObjectReference{Name: "myrc", Kind: "ReplicationController"},
1232 MinReplicas: utilpointer.Int32(1),
1233 MaxReplicas: 5,
1234 Metrics: []autoscaling.MetricSpec{{
1235 Type: autoscaling.ExternalMetricSourceType,
1236 External: &autoscaling.ExternalMetricSource{
1237 Metric: autoscaling.MetricIdentifier{
1238 Name: "somemetric",
1239 Selector: metricLabelSelector,
1240 },
1241 Target: autoscaling.MetricTarget{
1242 Type: autoscaling.ValueMetricType,
1243 Value: resource.NewMilliQuantity(-300, resource.DecimalSI),
1244 },
1245 },
1246 }},
1247 },
1248 },
1249 msg: "must be positive",
1250 }, {
1251 horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{
1252 ObjectMeta: metav1.ObjectMeta{Name: "myautoscaler", Namespace: metav1.NamespaceDefault},
1253 Spec: autoscaling.HorizontalPodAutoscalerSpec{
1254 ScaleTargetRef: autoscaling.CrossVersionObjectReference{Name: "myrc", Kind: "ReplicationController"},
1255 MinReplicas: utilpointer.Int32(1),
1256 MaxReplicas: 5,
1257 Metrics: []autoscaling.MetricSpec{{
1258 Type: autoscaling.ExternalMetricSourceType,
1259 External: &autoscaling.ExternalMetricSource{
1260 Metric: autoscaling.MetricIdentifier{
1261 Name: "somemetric",
1262 Selector: metricLabelSelector,
1263 },
1264 Target: autoscaling.MetricTarget{
1265 Type: autoscaling.ValueMetricType,
1266 AverageValue: resource.NewMilliQuantity(-300, resource.DecimalSI),
1267 },
1268 },
1269 }},
1270 },
1271 },
1272 msg: "must be positive",
1273 }, {
1274 horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{
1275 ObjectMeta: metav1.ObjectMeta{Name: "myautoscaler", Namespace: metav1.NamespaceDefault},
1276 Spec: autoscaling.HorizontalPodAutoscalerSpec{
1277 ScaleTargetRef: autoscaling.CrossVersionObjectReference{Name: "myrc", Kind: "ReplicationController"},
1278 MinReplicas: utilpointer.Int32(1),
1279 MaxReplicas: 5,
1280 Metrics: []autoscaling.MetricSpec{{
1281 Type: autoscaling.ExternalMetricSourceType,
1282 External: &autoscaling.ExternalMetricSource{
1283 Metric: autoscaling.MetricIdentifier{
1284 Name: "somemetric",
1285 Selector: metricLabelSelector,
1286 },
1287 Target: autoscaling.MetricTarget{
1288 Type: autoscaling.ValueMetricType,
1289 Value: resource.NewMilliQuantity(300, resource.DecimalSI),
1290 AverageValue: resource.NewMilliQuantity(300, resource.DecimalSI),
1291 },
1292 },
1293 }},
1294 },
1295 },
1296 msg: "may not set both a target value for metric and a per-pod target",
1297 }, {
1298 horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{
1299 ObjectMeta: metav1.ObjectMeta{Name: "myautoscaler", Namespace: metav1.NamespaceDefault},
1300 Spec: autoscaling.HorizontalPodAutoscalerSpec{
1301 ScaleTargetRef: autoscaling.CrossVersionObjectReference{Name: "myrc", Kind: "ReplicationController"},
1302 MinReplicas: utilpointer.Int32(1),
1303 MaxReplicas: 5,
1304 Metrics: []autoscaling.MetricSpec{{
1305 Type: autoscaling.ExternalMetricSourceType,
1306 External: &autoscaling.ExternalMetricSource{
1307 Metric: autoscaling.MetricIdentifier{
1308 Name: "somemetric",
1309 Selector: metricLabelSelector,
1310 },
1311 Target: autoscaling.MetricTarget{
1312 Type: "boogity",
1313 Value: resource.NewMilliQuantity(300, resource.DecimalSI),
1314 },
1315 },
1316 }},
1317 },
1318 },
1319 msg: "must be either Utilization, Value, or AverageValue",
1320 }, {
1321 horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{
1322 ObjectMeta: metav1.ObjectMeta{Name: "myautoscaler", Namespace: metav1.NamespaceDefault},
1323 Spec: autoscaling.HorizontalPodAutoscalerSpec{
1324 ScaleTargetRef: autoscaling.CrossVersionObjectReference{Name: "myrc", Kind: "ReplicationController"},
1325 MinReplicas: utilpointer.Int32(1),
1326 MaxReplicas: 5,
1327 Metrics: []autoscaling.MetricSpec{{
1328 Type: autoscaling.ExternalMetricSourceType,
1329 External: &autoscaling.ExternalMetricSource{
1330 Metric: autoscaling.MetricIdentifier{
1331 Name: "somemetric",
1332 Selector: metricLabelSelector,
1333 },
1334 Target: autoscaling.MetricTarget{
1335 Value: resource.NewMilliQuantity(300, resource.DecimalSI),
1336 },
1337 },
1338 }},
1339 },
1340 },
1341 msg: "must specify a metric target type",
1342 }, {
1343 horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{
1344 ObjectMeta: metav1.ObjectMeta{Name: "myautoscaler", Namespace: metav1.NamespaceDefault},
1345 Spec: autoscaling.HorizontalPodAutoscalerSpec{
1346 ScaleTargetRef: autoscaling.CrossVersionObjectReference{Name: "myrc", Kind: "ReplicationController"},
1347 MinReplicas: utilpointer.Int32(1),
1348 MaxReplicas: 5,
1349 Metrics: []autoscaling.MetricSpec{{
1350 Type: autoscaling.ExternalMetricSourceType,
1351 External: &autoscaling.ExternalMetricSource{
1352 Metric: autoscaling.MetricIdentifier{
1353 Name: "somemetric",
1354 Selector: metricLabelSelector,
1355 },
1356 },
1357 }},
1358 },
1359 },
1360 msg: "must specify a metric target",
1361 }, {
1362 horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{
1363 ObjectMeta: metav1.ObjectMeta{Name: "myautoscaler", Namespace: metav1.NamespaceDefault},
1364 Spec: autoscaling.HorizontalPodAutoscalerSpec{
1365 ScaleTargetRef: autoscaling.CrossVersionObjectReference{Name: "myrc", Kind: "ReplicationController"},
1366 MinReplicas: utilpointer.Int32(1),
1367 MaxReplicas: 5,
1368 Metrics: []autoscaling.MetricSpec{
1369 {},
1370 },
1371 },
1372 },
1373 msg: "must specify a metric source type",
1374 }, {
1375 horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{
1376 ObjectMeta: metav1.ObjectMeta{Name: "myautoscaler", Namespace: metav1.NamespaceDefault},
1377 Spec: autoscaling.HorizontalPodAutoscalerSpec{
1378 ScaleTargetRef: autoscaling.CrossVersionObjectReference{Name: "myrc", Kind: "ReplicationController"},
1379 MinReplicas: utilpointer.Int32(1),
1380 MaxReplicas: 5,
1381 Metrics: []autoscaling.MetricSpec{{
1382 Type: autoscaling.MetricSourceType("InvalidType"),
1383 }},
1384 },
1385 },
1386 msg: "type: Unsupported value",
1387 }, {
1388 horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{
1389 ObjectMeta: metav1.ObjectMeta{Name: "myautoscaler", Namespace: metav1.NamespaceDefault},
1390 Spec: autoscaling.HorizontalPodAutoscalerSpec{
1391 ScaleTargetRef: autoscaling.CrossVersionObjectReference{Name: "myrc", Kind: "ReplicationController"},
1392 MinReplicas: utilpointer.Int32(1),
1393 MaxReplicas: 5,
1394 Metrics: []autoscaling.MetricSpec{{
1395 Type: autoscaling.ResourceMetricSourceType,
1396 Resource: &autoscaling.ResourceMetricSource{
1397 Name: api.ResourceCPU,
1398 Target: autoscaling.MetricTarget{
1399 Type: autoscaling.AverageValueMetricType,
1400 AverageValue: resource.NewMilliQuantity(100, resource.DecimalSI),
1401 },
1402 },
1403 Pods: &autoscaling.PodsMetricSource{
1404 Metric: autoscaling.MetricIdentifier{
1405 Name: "somemetric",
1406 },
1407 Target: autoscaling.MetricTarget{
1408 Type: autoscaling.AverageValueMetricType,
1409 AverageValue: resource.NewMilliQuantity(100, resource.DecimalSI),
1410 },
1411 },
1412 }},
1413 },
1414 },
1415 msg: "must populate the given metric source only",
1416 },
1417 }
1418
1419 for _, c := range errorCases {
1420 errs := ValidateHorizontalPodAutoscaler(&c.horizontalPodAutoscaler)
1421 if len(errs) == 0 {
1422 t.Errorf("expected failure for %q", c.msg)
1423 } else if !strings.Contains(errs[0].Error(), c.msg) {
1424 t.Errorf("unexpected error: %q, expected: %q", errs[0], c.msg)
1425 }
1426 }
1427
1428 sourceTypes := map[autoscaling.MetricSourceType]autoscaling.MetricSpec{
1429 autoscaling.ResourceMetricSourceType: {
1430 Resource: &autoscaling.ResourceMetricSource{
1431 Name: api.ResourceCPU,
1432 Target: autoscaling.MetricTarget{
1433 Type: autoscaling.AverageValueMetricType,
1434 AverageValue: resource.NewMilliQuantity(100, resource.DecimalSI),
1435 },
1436 },
1437 },
1438 autoscaling.ContainerResourceMetricSourceType: {
1439 ContainerResource: &autoscaling.ContainerResourceMetricSource{
1440 Name: api.ResourceCPU,
1441 Container: "test-application",
1442 Target: autoscaling.MetricTarget{
1443 Type: autoscaling.AverageValueMetricType,
1444 AverageValue: resource.NewMilliQuantity(100, resource.DecimalSI),
1445 },
1446 },
1447 },
1448 autoscaling.PodsMetricSourceType: {
1449 Pods: &autoscaling.PodsMetricSource{
1450 Metric: autoscaling.MetricIdentifier{
1451 Name: "somemetric",
1452 },
1453 Target: autoscaling.MetricTarget{
1454 Type: autoscaling.AverageValueMetricType,
1455 AverageValue: resource.NewMilliQuantity(100, resource.DecimalSI),
1456 },
1457 },
1458 },
1459 autoscaling.ObjectMetricSourceType: {
1460 Object: &autoscaling.ObjectMetricSource{
1461 DescribedObject: autoscaling.CrossVersionObjectReference{
1462 Kind: "ReplicationController",
1463 Name: "myrc",
1464 },
1465 Metric: autoscaling.MetricIdentifier{
1466 Name: "somemetric",
1467 },
1468 Target: autoscaling.MetricTarget{
1469 Type: autoscaling.ValueMetricType,
1470 Value: resource.NewMilliQuantity(100, resource.DecimalSI),
1471 },
1472 },
1473 },
1474 }
1475
1476 for correctType, spec := range sourceTypes {
1477 for incorrectType := range sourceTypes {
1478 if correctType == incorrectType {
1479 continue
1480 }
1481
1482 spec.Type = incorrectType
1483
1484 errs := ValidateHorizontalPodAutoscaler(&autoscaling.HorizontalPodAutoscaler{
1485 ObjectMeta: metav1.ObjectMeta{Name: "myautoscaler", Namespace: metav1.NamespaceDefault},
1486 Spec: autoscaling.HorizontalPodAutoscalerSpec{
1487 ScaleTargetRef: autoscaling.CrossVersionObjectReference{Name: "myrc", Kind: "ReplicationController"},
1488 MinReplicas: utilpointer.Int32(1),
1489 MaxReplicas: 5, Metrics: []autoscaling.MetricSpec{spec},
1490 },
1491 })
1492
1493 expectedMsg := "must populate information for the given metric source"
1494
1495 if len(errs) == 0 {
1496 t.Errorf("expected failure with type of %v and spec for %v", incorrectType, correctType)
1497 } else if !strings.Contains(errs[0].Error(), expectedMsg) {
1498 t.Errorf("unexpected error: %q, expected %q", errs[0], expectedMsg)
1499 }
1500 }
1501 }
1502 }
1503
1504 func prepareMinReplicasCases(t *testing.T, minReplicas int32) []autoscaling.HorizontalPodAutoscaler {
1505 metricLabelSelector, err := metav1.ParseToLabelSelector("label=value")
1506 if err != nil {
1507 t.Errorf("unable to parse label selector: %v", err)
1508 }
1509 minReplicasCases := []autoscaling.HorizontalPodAutoscaler{{
1510 ObjectMeta: metav1.ObjectMeta{
1511 Name: "myautoscaler",
1512 Namespace: metav1.NamespaceDefault,
1513 ResourceVersion: "theversion",
1514 },
1515 Spec: autoscaling.HorizontalPodAutoscalerSpec{
1516 ScaleTargetRef: autoscaling.CrossVersionObjectReference{
1517 Kind: "ReplicationController",
1518 Name: "myrc",
1519 },
1520 MinReplicas: utilpointer.Int32(minReplicas),
1521 MaxReplicas: 5,
1522 Metrics: []autoscaling.MetricSpec{{
1523 Type: autoscaling.ObjectMetricSourceType,
1524 Object: &autoscaling.ObjectMetricSource{
1525 DescribedObject: autoscaling.CrossVersionObjectReference{
1526 Kind: "ReplicationController",
1527 Name: "myrc",
1528 },
1529 Metric: autoscaling.MetricIdentifier{
1530 Name: "somemetric",
1531 },
1532 Target: autoscaling.MetricTarget{
1533 Type: autoscaling.ValueMetricType,
1534 Value: resource.NewMilliQuantity(300, resource.DecimalSI),
1535 },
1536 },
1537 }},
1538 },
1539 }, {
1540 ObjectMeta: metav1.ObjectMeta{
1541 Name: "myautoscaler",
1542 Namespace: metav1.NamespaceDefault,
1543 ResourceVersion: "theversion",
1544 },
1545 Spec: autoscaling.HorizontalPodAutoscalerSpec{
1546 ScaleTargetRef: autoscaling.CrossVersionObjectReference{
1547 Kind: "ReplicationController",
1548 Name: "myrc",
1549 },
1550 MinReplicas: utilpointer.Int32(minReplicas),
1551 MaxReplicas: 5,
1552 Metrics: []autoscaling.MetricSpec{{
1553 Type: autoscaling.ExternalMetricSourceType,
1554 External: &autoscaling.ExternalMetricSource{
1555 Metric: autoscaling.MetricIdentifier{
1556 Name: "somemetric",
1557 Selector: metricLabelSelector,
1558 },
1559 Target: autoscaling.MetricTarget{
1560 Type: autoscaling.AverageValueMetricType,
1561 AverageValue: resource.NewMilliQuantity(300, resource.DecimalSI),
1562 },
1563 },
1564 }},
1565 },
1566 }}
1567 return minReplicasCases
1568 }
1569
1570 func TestValidateHorizontalPodAutoscalerScaleToZeroEnabled(t *testing.T) {
1571
1572 defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.HPAScaleToZero, true)()
1573
1574 zeroMinReplicasCases := prepareMinReplicasCases(t, 0)
1575 for _, successCase := range zeroMinReplicasCases {
1576 if errs := ValidateHorizontalPodAutoscaler(&successCase); len(errs) != 0 {
1577 t.Errorf("expected success: %v", errs)
1578 }
1579 }
1580 }
1581
1582 func TestValidateHorizontalPodAutoscalerScaleToZeroDisabled(t *testing.T) {
1583
1584 defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.HPAScaleToZero, false)()
1585
1586 zeroMinReplicasCases := prepareMinReplicasCases(t, 0)
1587 errorMsg := "must be greater than or equal to 1"
1588
1589 for _, errorCase := range zeroMinReplicasCases {
1590 errs := ValidateHorizontalPodAutoscaler(&errorCase)
1591 if len(errs) == 0 {
1592 t.Errorf("expected failure for %q", errorMsg)
1593 } else if !strings.Contains(errs[0].Error(), errorMsg) {
1594 t.Errorf("unexpected error: %q, expected: %q", errs[0], errorMsg)
1595 }
1596 }
1597
1598 nonZeroMinReplicasCases := prepareMinReplicasCases(t, 1)
1599
1600 for _, successCase := range nonZeroMinReplicasCases {
1601 successCase.Spec.MinReplicas = utilpointer.Int32(1)
1602 if errs := ValidateHorizontalPodAutoscaler(&successCase); len(errs) != 0 {
1603 t.Errorf("expected success: %v", errs)
1604 }
1605 }
1606 }
1607
1608 func TestValidateHorizontalPodAutoscalerUpdateScaleToZeroEnabled(t *testing.T) {
1609
1610 defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.HPAScaleToZero, true)()
1611
1612 zeroMinReplicasCases := prepareMinReplicasCases(t, 0)
1613 nonZeroMinReplicasCases := prepareMinReplicasCases(t, 1)
1614
1615 for i, zeroCase := range zeroMinReplicasCases {
1616 nonZeroCase := nonZeroMinReplicasCases[i]
1617
1618 if errs := ValidateHorizontalPodAutoscalerUpdate(&nonZeroCase, &zeroCase); len(errs) != 0 {
1619 t.Errorf("expected success: %v", errs)
1620 }
1621
1622 if errs := ValidateHorizontalPodAutoscalerUpdate(&zeroCase, &nonZeroCase); len(errs) != 0 {
1623 t.Errorf("expected success: %v", errs)
1624 }
1625 }
1626 }
1627
1628 func TestValidateHorizontalPodAutoscalerScaleToZeroUpdateDisabled(t *testing.T) {
1629
1630 defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.HPAScaleToZero, false)()
1631
1632 zeroMinReplicasCases := prepareMinReplicasCases(t, 0)
1633 nonZeroMinReplicasCases := prepareMinReplicasCases(t, 1)
1634 errorMsg := "must be greater than or equal to 1"
1635
1636 for i, zeroCase := range zeroMinReplicasCases {
1637 nonZeroCase := nonZeroMinReplicasCases[i]
1638 errs := ValidateHorizontalPodAutoscalerUpdate(&zeroCase, &nonZeroCase)
1639
1640 if len(errs) == 0 {
1641 t.Errorf("expected failure for %q", errorMsg)
1642 } else if !strings.Contains(errs[0].Error(), errorMsg) {
1643 t.Errorf("unexpected error: %q, expected: %q", errs[0], errorMsg)
1644 }
1645
1646 if errs := ValidateHorizontalPodAutoscalerUpdate(&zeroCase, &zeroCase); len(errs) != 0 {
1647 t.Errorf("expected success: %v", errs)
1648 }
1649
1650 if errs := ValidateHorizontalPodAutoscalerUpdate(&nonZeroCase, &zeroCase); len(errs) != 0 {
1651 t.Errorf("expected success: %v", errs)
1652 }
1653 }
1654 }
1655
View as plain text