validation_test.go 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005
  1. /*
  2. Copyright 2016 The Kubernetes Authors.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. package validation
  14. import (
  15. "strings"
  16. "testing"
  17. "k8s.io/apimachinery/pkg/api/resource"
  18. metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
  19. "k8s.io/kubernetes/pkg/apis/autoscaling"
  20. api "k8s.io/kubernetes/pkg/apis/core"
  21. utilpointer "k8s.io/utils/pointer"
  22. )
  23. func TestValidateScale(t *testing.T) {
  24. successCases := []autoscaling.Scale{
  25. {
  26. ObjectMeta: metav1.ObjectMeta{
  27. Name: "frontend",
  28. Namespace: metav1.NamespaceDefault,
  29. },
  30. Spec: autoscaling.ScaleSpec{
  31. Replicas: 1,
  32. },
  33. },
  34. {
  35. ObjectMeta: metav1.ObjectMeta{
  36. Name: "frontend",
  37. Namespace: metav1.NamespaceDefault,
  38. },
  39. Spec: autoscaling.ScaleSpec{
  40. Replicas: 10,
  41. },
  42. },
  43. {
  44. ObjectMeta: metav1.ObjectMeta{
  45. Name: "frontend",
  46. Namespace: metav1.NamespaceDefault,
  47. },
  48. Spec: autoscaling.ScaleSpec{
  49. Replicas: 0,
  50. },
  51. },
  52. }
  53. for _, successCase := range successCases {
  54. if errs := ValidateScale(&successCase); len(errs) != 0 {
  55. t.Errorf("expected success: %v", errs)
  56. }
  57. }
  58. errorCases := []struct {
  59. scale autoscaling.Scale
  60. msg string
  61. }{
  62. {
  63. scale: autoscaling.Scale{
  64. ObjectMeta: metav1.ObjectMeta{
  65. Name: "frontend",
  66. Namespace: metav1.NamespaceDefault,
  67. },
  68. Spec: autoscaling.ScaleSpec{
  69. Replicas: -1,
  70. },
  71. },
  72. msg: "must be greater than or equal to 0",
  73. },
  74. }
  75. for _, c := range errorCases {
  76. if errs := ValidateScale(&c.scale); len(errs) == 0 {
  77. t.Errorf("expected failure for %s", c.msg)
  78. } else if !strings.Contains(errs[0].Error(), c.msg) {
  79. t.Errorf("unexpected error: %v, expected: %s", errs[0], c.msg)
  80. }
  81. }
  82. }
  83. func TestValidateHorizontalPodAutoscaler(t *testing.T) {
  84. metricLabelSelector, err := metav1.ParseToLabelSelector("label=value")
  85. if err != nil {
  86. t.Errorf("unable to parse label selector: %v", err)
  87. }
  88. successCases := []autoscaling.HorizontalPodAutoscaler{
  89. {
  90. ObjectMeta: metav1.ObjectMeta{
  91. Name: "myautoscaler",
  92. Namespace: metav1.NamespaceDefault,
  93. },
  94. Spec: autoscaling.HorizontalPodAutoscalerSpec{
  95. ScaleTargetRef: autoscaling.CrossVersionObjectReference{
  96. Kind: "ReplicationController",
  97. Name: "myrc",
  98. },
  99. MinReplicas: utilpointer.Int32Ptr(1),
  100. MaxReplicas: 5,
  101. Metrics: []autoscaling.MetricSpec{
  102. {
  103. Type: autoscaling.ResourceMetricSourceType,
  104. Resource: &autoscaling.ResourceMetricSource{
  105. Name: api.ResourceCPU,
  106. Target: autoscaling.MetricTarget{
  107. Type: autoscaling.UtilizationMetricType,
  108. AverageUtilization: utilpointer.Int32Ptr(70),
  109. },
  110. },
  111. },
  112. },
  113. },
  114. },
  115. {
  116. ObjectMeta: metav1.ObjectMeta{
  117. Name: "myautoscaler",
  118. Namespace: metav1.NamespaceDefault,
  119. },
  120. Spec: autoscaling.HorizontalPodAutoscalerSpec{
  121. ScaleTargetRef: autoscaling.CrossVersionObjectReference{
  122. Kind: "ReplicationController",
  123. Name: "myrc",
  124. },
  125. MinReplicas: utilpointer.Int32Ptr(1),
  126. MaxReplicas: 5,
  127. },
  128. },
  129. {
  130. ObjectMeta: metav1.ObjectMeta{
  131. Name: "myautoscaler",
  132. Namespace: metav1.NamespaceDefault,
  133. },
  134. Spec: autoscaling.HorizontalPodAutoscalerSpec{
  135. ScaleTargetRef: autoscaling.CrossVersionObjectReference{
  136. Kind: "ReplicationController",
  137. Name: "myrc",
  138. },
  139. MinReplicas: utilpointer.Int32Ptr(1),
  140. MaxReplicas: 5,
  141. Metrics: []autoscaling.MetricSpec{
  142. {
  143. Type: autoscaling.ResourceMetricSourceType,
  144. Resource: &autoscaling.ResourceMetricSource{
  145. Name: api.ResourceCPU,
  146. Target: autoscaling.MetricTarget{
  147. Type: autoscaling.AverageValueMetricType,
  148. AverageValue: resource.NewMilliQuantity(300, resource.DecimalSI),
  149. },
  150. },
  151. },
  152. },
  153. },
  154. },
  155. {
  156. ObjectMeta: metav1.ObjectMeta{
  157. Name: "myautoscaler",
  158. Namespace: metav1.NamespaceDefault,
  159. },
  160. Spec: autoscaling.HorizontalPodAutoscalerSpec{
  161. ScaleTargetRef: autoscaling.CrossVersionObjectReference{
  162. Kind: "ReplicationController",
  163. Name: "myrc",
  164. },
  165. MinReplicas: utilpointer.Int32Ptr(1),
  166. MaxReplicas: 5,
  167. Metrics: []autoscaling.MetricSpec{
  168. {
  169. Type: autoscaling.PodsMetricSourceType,
  170. Pods: &autoscaling.PodsMetricSource{
  171. Metric: autoscaling.MetricIdentifier{
  172. Name: "somemetric",
  173. },
  174. Target: autoscaling.MetricTarget{
  175. Type: autoscaling.AverageValueMetricType,
  176. AverageValue: resource.NewMilliQuantity(300, resource.DecimalSI),
  177. },
  178. },
  179. },
  180. },
  181. },
  182. },
  183. {
  184. ObjectMeta: metav1.ObjectMeta{
  185. Name: "myautoscaler",
  186. Namespace: metav1.NamespaceDefault,
  187. },
  188. Spec: autoscaling.HorizontalPodAutoscalerSpec{
  189. ScaleTargetRef: autoscaling.CrossVersionObjectReference{
  190. Kind: "ReplicationController",
  191. Name: "myrc",
  192. },
  193. MinReplicas: utilpointer.Int32Ptr(1),
  194. MaxReplicas: 5,
  195. Metrics: []autoscaling.MetricSpec{
  196. {
  197. Type: autoscaling.ObjectMetricSourceType,
  198. Object: &autoscaling.ObjectMetricSource{
  199. DescribedObject: autoscaling.CrossVersionObjectReference{
  200. Kind: "ReplicationController",
  201. Name: "myrc",
  202. },
  203. Metric: autoscaling.MetricIdentifier{
  204. Name: "somemetric",
  205. },
  206. Target: autoscaling.MetricTarget{
  207. Type: autoscaling.ValueMetricType,
  208. Value: resource.NewMilliQuantity(300, resource.DecimalSI),
  209. },
  210. },
  211. },
  212. },
  213. },
  214. },
  215. {
  216. ObjectMeta: metav1.ObjectMeta{
  217. Name: "myautoscaler",
  218. Namespace: metav1.NamespaceDefault,
  219. },
  220. Spec: autoscaling.HorizontalPodAutoscalerSpec{
  221. ScaleTargetRef: autoscaling.CrossVersionObjectReference{
  222. Kind: "ReplicationController",
  223. Name: "myrc",
  224. },
  225. MinReplicas: utilpointer.Int32Ptr(1),
  226. MaxReplicas: 5,
  227. Metrics: []autoscaling.MetricSpec{
  228. {
  229. Type: autoscaling.ExternalMetricSourceType,
  230. External: &autoscaling.ExternalMetricSource{
  231. Metric: autoscaling.MetricIdentifier{
  232. Name: "somemetric",
  233. Selector: metricLabelSelector,
  234. },
  235. Target: autoscaling.MetricTarget{
  236. Type: autoscaling.ValueMetricType,
  237. Value: resource.NewMilliQuantity(300, resource.DecimalSI),
  238. },
  239. },
  240. },
  241. },
  242. },
  243. },
  244. {
  245. ObjectMeta: metav1.ObjectMeta{
  246. Name: "myautoscaler",
  247. Namespace: metav1.NamespaceDefault,
  248. },
  249. Spec: autoscaling.HorizontalPodAutoscalerSpec{
  250. ScaleTargetRef: autoscaling.CrossVersionObjectReference{
  251. Kind: "ReplicationController",
  252. Name: "myrc",
  253. },
  254. MinReplicas: utilpointer.Int32Ptr(1),
  255. MaxReplicas: 5,
  256. Metrics: []autoscaling.MetricSpec{
  257. {
  258. Type: autoscaling.ExternalMetricSourceType,
  259. External: &autoscaling.ExternalMetricSource{
  260. Metric: autoscaling.MetricIdentifier{
  261. Name: "somemetric",
  262. Selector: metricLabelSelector,
  263. },
  264. Target: autoscaling.MetricTarget{
  265. Type: autoscaling.AverageValueMetricType,
  266. AverageValue: resource.NewMilliQuantity(300, resource.DecimalSI),
  267. },
  268. },
  269. },
  270. },
  271. },
  272. },
  273. }
  274. for _, successCase := range successCases {
  275. if errs := ValidateHorizontalPodAutoscaler(&successCase); len(errs) != 0 {
  276. t.Errorf("expected success: %v", errs)
  277. }
  278. }
  279. errorCases := []struct {
  280. horizontalPodAutoscaler autoscaling.HorizontalPodAutoscaler
  281. msg string
  282. }{
  283. {
  284. horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{
  285. ObjectMeta: metav1.ObjectMeta{Name: "myautoscaler", Namespace: metav1.NamespaceDefault},
  286. Spec: autoscaling.HorizontalPodAutoscalerSpec{
  287. ScaleTargetRef: autoscaling.CrossVersionObjectReference{Name: "myrc"},
  288. MinReplicas: utilpointer.Int32Ptr(1),
  289. MaxReplicas: 5,
  290. Metrics: []autoscaling.MetricSpec{
  291. {
  292. Type: autoscaling.ResourceMetricSourceType,
  293. Resource: &autoscaling.ResourceMetricSource{
  294. Name: api.ResourceCPU,
  295. Target: autoscaling.MetricTarget{
  296. Type: autoscaling.UtilizationMetricType,
  297. AverageUtilization: utilpointer.Int32Ptr(70),
  298. },
  299. },
  300. },
  301. },
  302. },
  303. },
  304. msg: "scaleTargetRef.kind: Required",
  305. },
  306. {
  307. horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{
  308. ObjectMeta: metav1.ObjectMeta{Name: "myautoscaler", Namespace: metav1.NamespaceDefault},
  309. Spec: autoscaling.HorizontalPodAutoscalerSpec{
  310. ScaleTargetRef: autoscaling.CrossVersionObjectReference{Kind: "..", Name: "myrc"},
  311. MinReplicas: utilpointer.Int32Ptr(1),
  312. MaxReplicas: 5,
  313. Metrics: []autoscaling.MetricSpec{
  314. {
  315. Type: autoscaling.ResourceMetricSourceType,
  316. Resource: &autoscaling.ResourceMetricSource{
  317. Name: api.ResourceCPU,
  318. Target: autoscaling.MetricTarget{
  319. Type: autoscaling.UtilizationMetricType,
  320. AverageUtilization: utilpointer.Int32Ptr(70),
  321. },
  322. },
  323. },
  324. },
  325. },
  326. },
  327. msg: "scaleTargetRef.kind: Invalid",
  328. },
  329. {
  330. horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{
  331. ObjectMeta: metav1.ObjectMeta{Name: "myautoscaler", Namespace: metav1.NamespaceDefault},
  332. Spec: autoscaling.HorizontalPodAutoscalerSpec{
  333. ScaleTargetRef: autoscaling.CrossVersionObjectReference{Kind: "ReplicationController"},
  334. MinReplicas: utilpointer.Int32Ptr(1),
  335. MaxReplicas: 5,
  336. Metrics: []autoscaling.MetricSpec{
  337. {
  338. Type: autoscaling.ResourceMetricSourceType,
  339. Resource: &autoscaling.ResourceMetricSource{
  340. Name: api.ResourceCPU,
  341. Target: autoscaling.MetricTarget{
  342. Type: autoscaling.UtilizationMetricType,
  343. AverageUtilization: utilpointer.Int32Ptr(70),
  344. },
  345. },
  346. },
  347. },
  348. },
  349. },
  350. msg: "scaleTargetRef.name: Required",
  351. },
  352. {
  353. horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{
  354. ObjectMeta: metav1.ObjectMeta{Name: "myautoscaler", Namespace: metav1.NamespaceDefault},
  355. Spec: autoscaling.HorizontalPodAutoscalerSpec{
  356. ScaleTargetRef: autoscaling.CrossVersionObjectReference{Kind: "ReplicationController", Name: ".."},
  357. MinReplicas: utilpointer.Int32Ptr(1),
  358. MaxReplicas: 5,
  359. Metrics: []autoscaling.MetricSpec{
  360. {
  361. Type: autoscaling.ResourceMetricSourceType,
  362. Resource: &autoscaling.ResourceMetricSource{
  363. Name: api.ResourceCPU,
  364. Target: autoscaling.MetricTarget{
  365. Type: autoscaling.UtilizationMetricType,
  366. AverageUtilization: utilpointer.Int32Ptr(70),
  367. },
  368. },
  369. },
  370. },
  371. },
  372. },
  373. msg: "scaleTargetRef.name: Invalid",
  374. },
  375. {
  376. horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{
  377. ObjectMeta: metav1.ObjectMeta{
  378. Name: "myautoscaler",
  379. Namespace: metav1.NamespaceDefault,
  380. },
  381. Spec: autoscaling.HorizontalPodAutoscalerSpec{
  382. ScaleTargetRef: autoscaling.CrossVersionObjectReference{},
  383. MinReplicas: utilpointer.Int32Ptr(-1),
  384. MaxReplicas: 5,
  385. },
  386. },
  387. msg: "must be greater than 0",
  388. },
  389. {
  390. horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{
  391. ObjectMeta: metav1.ObjectMeta{
  392. Name: "myautoscaler",
  393. Namespace: metav1.NamespaceDefault,
  394. },
  395. Spec: autoscaling.HorizontalPodAutoscalerSpec{
  396. ScaleTargetRef: autoscaling.CrossVersionObjectReference{},
  397. MinReplicas: utilpointer.Int32Ptr(7),
  398. MaxReplicas: 5,
  399. },
  400. },
  401. msg: "must be greater than or equal to `minReplicas`",
  402. },
  403. {
  404. horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{
  405. ObjectMeta: metav1.ObjectMeta{
  406. Name: "myautoscaler",
  407. Namespace: metav1.NamespaceDefault,
  408. },
  409. Spec: autoscaling.HorizontalPodAutoscalerSpec{
  410. ScaleTargetRef: autoscaling.CrossVersionObjectReference{Name: "myrc", Kind: "ReplicationController"},
  411. MinReplicas: utilpointer.Int32Ptr(1),
  412. MaxReplicas: 5,
  413. Metrics: []autoscaling.MetricSpec{
  414. {
  415. Type: autoscaling.ResourceMetricSourceType,
  416. Resource: &autoscaling.ResourceMetricSource{
  417. Name: api.ResourceCPU,
  418. Target: autoscaling.MetricTarget{
  419. Type: autoscaling.UtilizationMetricType,
  420. AverageUtilization: utilpointer.Int32Ptr(70),
  421. AverageValue: resource.NewMilliQuantity(300, resource.DecimalSI),
  422. },
  423. },
  424. },
  425. },
  426. },
  427. },
  428. msg: "may not set both a target raw value and a target utilization",
  429. },
  430. {
  431. horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{
  432. ObjectMeta: metav1.ObjectMeta{Name: "myautoscaler", Namespace: metav1.NamespaceDefault},
  433. Spec: autoscaling.HorizontalPodAutoscalerSpec{
  434. ScaleTargetRef: autoscaling.CrossVersionObjectReference{Name: "myrc", Kind: "ReplicationController"},
  435. MinReplicas: utilpointer.Int32Ptr(1),
  436. MaxReplicas: 5,
  437. Metrics: []autoscaling.MetricSpec{
  438. {
  439. Type: autoscaling.ResourceMetricSourceType,
  440. Resource: &autoscaling.ResourceMetricSource{
  441. Target: autoscaling.MetricTarget{
  442. Type: autoscaling.UtilizationMetricType,
  443. AverageUtilization: utilpointer.Int32Ptr(70),
  444. },
  445. },
  446. },
  447. },
  448. },
  449. },
  450. msg: "must specify a resource name",
  451. },
  452. {
  453. horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{
  454. ObjectMeta: metav1.ObjectMeta{Name: "myautoscaler", Namespace: metav1.NamespaceDefault},
  455. Spec: autoscaling.HorizontalPodAutoscalerSpec{
  456. ScaleTargetRef: autoscaling.CrossVersionObjectReference{Name: "myrc", Kind: "ReplicationController"},
  457. MinReplicas: utilpointer.Int32Ptr(1),
  458. MaxReplicas: 5,
  459. Metrics: []autoscaling.MetricSpec{
  460. {
  461. Type: autoscaling.ResourceMetricSourceType,
  462. Resource: &autoscaling.ResourceMetricSource{
  463. Name: api.ResourceCPU,
  464. Target: autoscaling.MetricTarget{
  465. Type: autoscaling.UtilizationMetricType,
  466. AverageUtilization: utilpointer.Int32Ptr(-10),
  467. },
  468. },
  469. },
  470. },
  471. },
  472. },
  473. msg: "must be greater than 0",
  474. },
  475. {
  476. horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{
  477. ObjectMeta: metav1.ObjectMeta{Name: "myautoscaler", Namespace: metav1.NamespaceDefault},
  478. Spec: autoscaling.HorizontalPodAutoscalerSpec{
  479. ScaleTargetRef: autoscaling.CrossVersionObjectReference{Name: "myrc", Kind: "ReplicationController"},
  480. MinReplicas: utilpointer.Int32Ptr(1),
  481. MaxReplicas: 5,
  482. Metrics: []autoscaling.MetricSpec{
  483. {
  484. Type: autoscaling.ResourceMetricSourceType,
  485. Resource: &autoscaling.ResourceMetricSource{
  486. Name: api.ResourceCPU,
  487. Target: autoscaling.MetricTarget{
  488. Type: autoscaling.ValueMetricType,
  489. },
  490. },
  491. },
  492. },
  493. },
  494. },
  495. msg: "must set either a target raw value or a target utilization",
  496. },
  497. {
  498. horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{
  499. ObjectMeta: metav1.ObjectMeta{Name: "myautoscaler", Namespace: metav1.NamespaceDefault},
  500. Spec: autoscaling.HorizontalPodAutoscalerSpec{
  501. ScaleTargetRef: autoscaling.CrossVersionObjectReference{Name: "myrc", Kind: "ReplicationController"},
  502. MinReplicas: utilpointer.Int32Ptr(1),
  503. MaxReplicas: 5,
  504. Metrics: []autoscaling.MetricSpec{
  505. {
  506. Type: autoscaling.PodsMetricSourceType,
  507. Pods: &autoscaling.PodsMetricSource{
  508. Metric: autoscaling.MetricIdentifier{},
  509. Target: autoscaling.MetricTarget{
  510. Type: autoscaling.ValueMetricType,
  511. AverageValue: resource.NewMilliQuantity(100, resource.DecimalSI),
  512. },
  513. },
  514. },
  515. },
  516. },
  517. },
  518. msg: "must specify a metric name",
  519. },
  520. {
  521. horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{
  522. ObjectMeta: metav1.ObjectMeta{Name: "myautoscaler", Namespace: metav1.NamespaceDefault},
  523. Spec: autoscaling.HorizontalPodAutoscalerSpec{
  524. ScaleTargetRef: autoscaling.CrossVersionObjectReference{Name: "myrc", Kind: "ReplicationController"},
  525. MinReplicas: utilpointer.Int32Ptr(1),
  526. MaxReplicas: 5,
  527. Metrics: []autoscaling.MetricSpec{
  528. {
  529. Type: autoscaling.PodsMetricSourceType,
  530. Pods: &autoscaling.PodsMetricSource{
  531. Metric: autoscaling.MetricIdentifier{
  532. Name: "somemetric",
  533. },
  534. Target: autoscaling.MetricTarget{
  535. Type: autoscaling.ValueMetricType,
  536. },
  537. },
  538. },
  539. },
  540. },
  541. },
  542. msg: "must specify a positive target averageValue",
  543. },
  544. {
  545. horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{
  546. ObjectMeta: metav1.ObjectMeta{Name: "myautoscaler", Namespace: metav1.NamespaceDefault},
  547. Spec: autoscaling.HorizontalPodAutoscalerSpec{
  548. ScaleTargetRef: autoscaling.CrossVersionObjectReference{Name: "myrc", Kind: "ReplicationController"},
  549. MinReplicas: utilpointer.Int32Ptr(1),
  550. MaxReplicas: 5,
  551. Metrics: []autoscaling.MetricSpec{
  552. {
  553. Type: autoscaling.ObjectMetricSourceType,
  554. Object: &autoscaling.ObjectMetricSource{
  555. DescribedObject: autoscaling.CrossVersionObjectReference{
  556. Kind: "ReplicationController",
  557. Name: "myrc",
  558. },
  559. Metric: autoscaling.MetricIdentifier{
  560. Name: "somemetric",
  561. },
  562. Target: autoscaling.MetricTarget{
  563. Type: autoscaling.ValueMetricType,
  564. },
  565. },
  566. },
  567. },
  568. },
  569. },
  570. msg: "must set either a target value or averageValue",
  571. },
  572. {
  573. horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{
  574. ObjectMeta: metav1.ObjectMeta{Name: "myautoscaler", Namespace: metav1.NamespaceDefault},
  575. Spec: autoscaling.HorizontalPodAutoscalerSpec{
  576. ScaleTargetRef: autoscaling.CrossVersionObjectReference{Name: "myrc", Kind: "ReplicationController"},
  577. MinReplicas: utilpointer.Int32Ptr(1),
  578. MaxReplicas: 5,
  579. Metrics: []autoscaling.MetricSpec{
  580. {
  581. Type: autoscaling.ObjectMetricSourceType,
  582. Object: &autoscaling.ObjectMetricSource{
  583. DescribedObject: autoscaling.CrossVersionObjectReference{
  584. Name: "myrc",
  585. },
  586. Metric: autoscaling.MetricIdentifier{
  587. Name: "somemetric",
  588. },
  589. Target: autoscaling.MetricTarget{
  590. Type: autoscaling.ValueMetricType,
  591. Value: resource.NewMilliQuantity(100, resource.DecimalSI),
  592. },
  593. },
  594. },
  595. },
  596. },
  597. },
  598. msg: "object.describedObject.kind: Required",
  599. },
  600. {
  601. horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{
  602. ObjectMeta: metav1.ObjectMeta{Name: "myautoscaler", Namespace: metav1.NamespaceDefault},
  603. Spec: autoscaling.HorizontalPodAutoscalerSpec{
  604. ScaleTargetRef: autoscaling.CrossVersionObjectReference{Name: "myrc", Kind: "ReplicationController"},
  605. MinReplicas: utilpointer.Int32Ptr(1),
  606. MaxReplicas: 5,
  607. Metrics: []autoscaling.MetricSpec{
  608. {
  609. Type: autoscaling.ObjectMetricSourceType,
  610. Object: &autoscaling.ObjectMetricSource{
  611. DescribedObject: autoscaling.CrossVersionObjectReference{
  612. Kind: "ReplicationController",
  613. Name: "myrc",
  614. },
  615. Target: autoscaling.MetricTarget{
  616. Type: autoscaling.ValueMetricType,
  617. Value: resource.NewMilliQuantity(100, resource.DecimalSI),
  618. },
  619. },
  620. },
  621. },
  622. },
  623. },
  624. msg: "must specify a metric name",
  625. },
  626. {
  627. horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{
  628. ObjectMeta: metav1.ObjectMeta{Name: "myautoscaler", Namespace: metav1.NamespaceDefault},
  629. Spec: autoscaling.HorizontalPodAutoscalerSpec{
  630. ScaleTargetRef: autoscaling.CrossVersionObjectReference{Name: "myrc", Kind: "ReplicationController"},
  631. MinReplicas: utilpointer.Int32Ptr(1),
  632. MaxReplicas: 5,
  633. Metrics: []autoscaling.MetricSpec{
  634. {
  635. Type: autoscaling.ExternalMetricSourceType,
  636. External: &autoscaling.ExternalMetricSource{
  637. Metric: autoscaling.MetricIdentifier{
  638. Selector: metricLabelSelector,
  639. },
  640. Target: autoscaling.MetricTarget{
  641. Type: autoscaling.ValueMetricType,
  642. Value: resource.NewMilliQuantity(300, resource.DecimalSI),
  643. },
  644. },
  645. },
  646. },
  647. },
  648. },
  649. msg: "must specify a metric name",
  650. },
  651. {
  652. horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{
  653. ObjectMeta: metav1.ObjectMeta{Name: "myautoscaler", Namespace: metav1.NamespaceDefault},
  654. Spec: autoscaling.HorizontalPodAutoscalerSpec{
  655. ScaleTargetRef: autoscaling.CrossVersionObjectReference{Name: "myrc", Kind: "ReplicationController"},
  656. MinReplicas: utilpointer.Int32Ptr(1),
  657. MaxReplicas: 5,
  658. Metrics: []autoscaling.MetricSpec{
  659. {
  660. Type: autoscaling.ExternalMetricSourceType,
  661. External: &autoscaling.ExternalMetricSource{
  662. Metric: autoscaling.MetricIdentifier{
  663. Name: "foo/../",
  664. Selector: metricLabelSelector,
  665. },
  666. Target: autoscaling.MetricTarget{
  667. Type: autoscaling.ValueMetricType,
  668. Value: resource.NewMilliQuantity(300, resource.DecimalSI),
  669. },
  670. },
  671. },
  672. },
  673. },
  674. },
  675. msg: "'/'",
  676. },
  677. {
  678. horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{
  679. ObjectMeta: metav1.ObjectMeta{Name: "myautoscaler", Namespace: metav1.NamespaceDefault},
  680. Spec: autoscaling.HorizontalPodAutoscalerSpec{
  681. ScaleTargetRef: autoscaling.CrossVersionObjectReference{Name: "myrc", Kind: "ReplicationController"},
  682. MinReplicas: utilpointer.Int32Ptr(1),
  683. MaxReplicas: 5,
  684. Metrics: []autoscaling.MetricSpec{
  685. {
  686. Type: autoscaling.ExternalMetricSourceType,
  687. External: &autoscaling.ExternalMetricSource{
  688. Metric: autoscaling.MetricIdentifier{
  689. Name: "somemetric",
  690. Selector: metricLabelSelector,
  691. },
  692. Target: autoscaling.MetricTarget{
  693. Type: autoscaling.ValueMetricType,
  694. },
  695. },
  696. },
  697. },
  698. },
  699. },
  700. msg: "must set either a target value for metric or a per-pod target",
  701. },
  702. {
  703. horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{
  704. ObjectMeta: metav1.ObjectMeta{Name: "myautoscaler", Namespace: metav1.NamespaceDefault},
  705. Spec: autoscaling.HorizontalPodAutoscalerSpec{
  706. ScaleTargetRef: autoscaling.CrossVersionObjectReference{Name: "myrc", Kind: "ReplicationController"},
  707. MinReplicas: utilpointer.Int32Ptr(1),
  708. MaxReplicas: 5,
  709. Metrics: []autoscaling.MetricSpec{
  710. {
  711. Type: autoscaling.ExternalMetricSourceType,
  712. External: &autoscaling.ExternalMetricSource{
  713. Metric: autoscaling.MetricIdentifier{
  714. Name: "somemetric",
  715. Selector: metricLabelSelector,
  716. },
  717. Target: autoscaling.MetricTarget{
  718. Type: autoscaling.ValueMetricType,
  719. Value: resource.NewMilliQuantity(-300, resource.DecimalSI),
  720. },
  721. },
  722. },
  723. },
  724. },
  725. },
  726. msg: "must be positive",
  727. },
  728. {
  729. horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{
  730. ObjectMeta: metav1.ObjectMeta{Name: "myautoscaler", Namespace: metav1.NamespaceDefault},
  731. Spec: autoscaling.HorizontalPodAutoscalerSpec{
  732. ScaleTargetRef: autoscaling.CrossVersionObjectReference{Name: "myrc", Kind: "ReplicationController"},
  733. MinReplicas: utilpointer.Int32Ptr(1),
  734. MaxReplicas: 5,
  735. Metrics: []autoscaling.MetricSpec{
  736. {
  737. Type: autoscaling.ExternalMetricSourceType,
  738. External: &autoscaling.ExternalMetricSource{
  739. Metric: autoscaling.MetricIdentifier{
  740. Name: "somemetric",
  741. Selector: metricLabelSelector,
  742. },
  743. Target: autoscaling.MetricTarget{
  744. Type: autoscaling.ValueMetricType,
  745. AverageValue: resource.NewMilliQuantity(-300, resource.DecimalSI),
  746. },
  747. },
  748. },
  749. },
  750. },
  751. },
  752. msg: "must be positive",
  753. },
  754. {
  755. horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{
  756. ObjectMeta: metav1.ObjectMeta{Name: "myautoscaler", Namespace: metav1.NamespaceDefault},
  757. Spec: autoscaling.HorizontalPodAutoscalerSpec{
  758. ScaleTargetRef: autoscaling.CrossVersionObjectReference{Name: "myrc", Kind: "ReplicationController"},
  759. MinReplicas: utilpointer.Int32Ptr(1),
  760. MaxReplicas: 5,
  761. Metrics: []autoscaling.MetricSpec{
  762. {
  763. Type: autoscaling.ExternalMetricSourceType,
  764. External: &autoscaling.ExternalMetricSource{
  765. Metric: autoscaling.MetricIdentifier{
  766. Name: "somemetric",
  767. Selector: metricLabelSelector,
  768. },
  769. Target: autoscaling.MetricTarget{
  770. Type: autoscaling.ValueMetricType,
  771. Value: resource.NewMilliQuantity(300, resource.DecimalSI),
  772. AverageValue: resource.NewMilliQuantity(300, resource.DecimalSI),
  773. },
  774. },
  775. },
  776. },
  777. },
  778. },
  779. msg: "may not set both a target value for metric and a per-pod target",
  780. },
  781. {
  782. horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{
  783. ObjectMeta: metav1.ObjectMeta{Name: "myautoscaler", Namespace: metav1.NamespaceDefault},
  784. Spec: autoscaling.HorizontalPodAutoscalerSpec{
  785. ScaleTargetRef: autoscaling.CrossVersionObjectReference{Name: "myrc", Kind: "ReplicationController"},
  786. MinReplicas: utilpointer.Int32Ptr(1),
  787. MaxReplicas: 5,
  788. Metrics: []autoscaling.MetricSpec{
  789. {
  790. Type: autoscaling.ExternalMetricSourceType,
  791. External: &autoscaling.ExternalMetricSource{
  792. Metric: autoscaling.MetricIdentifier{
  793. Name: "somemetric",
  794. Selector: metricLabelSelector,
  795. },
  796. Target: autoscaling.MetricTarget{
  797. Type: "boogity",
  798. Value: resource.NewMilliQuantity(300, resource.DecimalSI),
  799. },
  800. },
  801. },
  802. },
  803. },
  804. },
  805. msg: "must be either Utilization, Value, or AverageValue",
  806. },
  807. {
  808. horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{
  809. ObjectMeta: metav1.ObjectMeta{Name: "myautoscaler", Namespace: metav1.NamespaceDefault},
  810. Spec: autoscaling.HorizontalPodAutoscalerSpec{
  811. ScaleTargetRef: autoscaling.CrossVersionObjectReference{Name: "myrc", Kind: "ReplicationController"},
  812. MinReplicas: utilpointer.Int32Ptr(1),
  813. MaxReplicas: 5,
  814. Metrics: []autoscaling.MetricSpec{
  815. {
  816. Type: autoscaling.ExternalMetricSourceType,
  817. External: &autoscaling.ExternalMetricSource{
  818. Metric: autoscaling.MetricIdentifier{
  819. Name: "somemetric",
  820. Selector: metricLabelSelector,
  821. },
  822. Target: autoscaling.MetricTarget{
  823. Value: resource.NewMilliQuantity(300, resource.DecimalSI),
  824. },
  825. },
  826. },
  827. },
  828. },
  829. },
  830. msg: "must specify a metric target type",
  831. },
  832. {
  833. horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{
  834. ObjectMeta: metav1.ObjectMeta{Name: "myautoscaler", Namespace: metav1.NamespaceDefault},
  835. Spec: autoscaling.HorizontalPodAutoscalerSpec{
  836. ScaleTargetRef: autoscaling.CrossVersionObjectReference{Name: "myrc", Kind: "ReplicationController"},
  837. MinReplicas: utilpointer.Int32Ptr(1),
  838. MaxReplicas: 5,
  839. Metrics: []autoscaling.MetricSpec{
  840. {
  841. Type: autoscaling.ExternalMetricSourceType,
  842. External: &autoscaling.ExternalMetricSource{
  843. Metric: autoscaling.MetricIdentifier{
  844. Name: "somemetric",
  845. Selector: metricLabelSelector,
  846. },
  847. },
  848. },
  849. },
  850. },
  851. },
  852. msg: "must specify a metric target",
  853. },
  854. {
  855. horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{
  856. ObjectMeta: metav1.ObjectMeta{Name: "myautoscaler", Namespace: metav1.NamespaceDefault},
  857. Spec: autoscaling.HorizontalPodAutoscalerSpec{
  858. ScaleTargetRef: autoscaling.CrossVersionObjectReference{Name: "myrc", Kind: "ReplicationController"},
  859. MinReplicas: utilpointer.Int32Ptr(1),
  860. MaxReplicas: 5,
  861. Metrics: []autoscaling.MetricSpec{
  862. {},
  863. },
  864. },
  865. },
  866. msg: "must specify a metric source type",
  867. },
  868. {
  869. horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{
  870. ObjectMeta: metav1.ObjectMeta{Name: "myautoscaler", Namespace: metav1.NamespaceDefault},
  871. Spec: autoscaling.HorizontalPodAutoscalerSpec{
  872. ScaleTargetRef: autoscaling.CrossVersionObjectReference{Name: "myrc", Kind: "ReplicationController"},
  873. MinReplicas: utilpointer.Int32Ptr(1),
  874. MaxReplicas: 5,
  875. Metrics: []autoscaling.MetricSpec{
  876. {
  877. Type: autoscaling.MetricSourceType("InvalidType"),
  878. },
  879. },
  880. },
  881. },
  882. msg: "type: Unsupported value",
  883. },
  884. {
  885. horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{
  886. ObjectMeta: metav1.ObjectMeta{Name: "myautoscaler", Namespace: metav1.NamespaceDefault},
  887. Spec: autoscaling.HorizontalPodAutoscalerSpec{
  888. ScaleTargetRef: autoscaling.CrossVersionObjectReference{Name: "myrc", Kind: "ReplicationController"},
  889. MinReplicas: utilpointer.Int32Ptr(1),
  890. MaxReplicas: 5,
  891. Metrics: []autoscaling.MetricSpec{
  892. {
  893. Type: autoscaling.ResourceMetricSourceType,
  894. Resource: &autoscaling.ResourceMetricSource{
  895. Name: api.ResourceCPU,
  896. Target: autoscaling.MetricTarget{
  897. Type: autoscaling.AverageValueMetricType,
  898. AverageValue: resource.NewMilliQuantity(100, resource.DecimalSI),
  899. },
  900. },
  901. Pods: &autoscaling.PodsMetricSource{
  902. Metric: autoscaling.MetricIdentifier{
  903. Name: "somemetric",
  904. },
  905. Target: autoscaling.MetricTarget{
  906. Type: autoscaling.AverageValueMetricType,
  907. AverageValue: resource.NewMilliQuantity(100, resource.DecimalSI),
  908. },
  909. },
  910. },
  911. },
  912. },
  913. },
  914. msg: "must populate the given metric source only",
  915. },
  916. }
  917. for _, c := range errorCases {
  918. errs := ValidateHorizontalPodAutoscaler(&c.horizontalPodAutoscaler)
  919. if len(errs) == 0 {
  920. t.Errorf("expected failure for %q", c.msg)
  921. } else if !strings.Contains(errs[0].Error(), c.msg) {
  922. t.Errorf("unexpected error: %q, expected: %q", errs[0], c.msg)
  923. }
  924. }
  925. sourceTypes := map[autoscaling.MetricSourceType]autoscaling.MetricSpec{
  926. autoscaling.ResourceMetricSourceType: {
  927. Resource: &autoscaling.ResourceMetricSource{
  928. Name: api.ResourceCPU,
  929. Target: autoscaling.MetricTarget{
  930. Type: autoscaling.AverageValueMetricType,
  931. AverageValue: resource.NewMilliQuantity(100, resource.DecimalSI),
  932. },
  933. },
  934. },
  935. autoscaling.PodsMetricSourceType: {
  936. Pods: &autoscaling.PodsMetricSource{
  937. Metric: autoscaling.MetricIdentifier{
  938. Name: "somemetric",
  939. },
  940. Target: autoscaling.MetricTarget{
  941. Type: autoscaling.AverageValueMetricType,
  942. AverageValue: resource.NewMilliQuantity(100, resource.DecimalSI),
  943. },
  944. },
  945. },
  946. autoscaling.ObjectMetricSourceType: {
  947. Object: &autoscaling.ObjectMetricSource{
  948. DescribedObject: autoscaling.CrossVersionObjectReference{
  949. Kind: "ReplicationController",
  950. Name: "myrc",
  951. },
  952. Metric: autoscaling.MetricIdentifier{
  953. Name: "somemetric",
  954. },
  955. Target: autoscaling.MetricTarget{
  956. Type: autoscaling.ValueMetricType,
  957. Value: resource.NewMilliQuantity(100, resource.DecimalSI),
  958. },
  959. },
  960. },
  961. }
  962. for correctType, spec := range sourceTypes {
  963. for incorrectType := range sourceTypes {
  964. if correctType == incorrectType {
  965. continue
  966. }
  967. spec.Type = incorrectType
  968. errs := ValidateHorizontalPodAutoscaler(&autoscaling.HorizontalPodAutoscaler{
  969. ObjectMeta: metav1.ObjectMeta{Name: "myautoscaler", Namespace: metav1.NamespaceDefault},
  970. Spec: autoscaling.HorizontalPodAutoscalerSpec{
  971. ScaleTargetRef: autoscaling.CrossVersionObjectReference{Name: "myrc", Kind: "ReplicationController"},
  972. MinReplicas: utilpointer.Int32Ptr(1),
  973. MaxReplicas: 5, Metrics: []autoscaling.MetricSpec{spec},
  974. },
  975. })
  976. expectedMsg := "must populate information for the given metric source"
  977. if len(errs) == 0 {
  978. t.Errorf("expected failure with type of %v and spec for %v", incorrectType, correctType)
  979. } else if !strings.Contains(errs[0].Error(), expectedMsg) {
  980. t.Errorf("unexpected error: %q, expected %q", errs[0], expectedMsg)
  981. }
  982. }
  983. }
  984. }