defaults_test.go 68 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878
  1. /*
  2. Copyright 2015 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 v1_test
  14. import (
  15. "encoding/json"
  16. "fmt"
  17. "reflect"
  18. "strings"
  19. "testing"
  20. v1 "k8s.io/api/core/v1"
  21. "k8s.io/apimachinery/pkg/api/resource"
  22. metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
  23. "k8s.io/apimachinery/pkg/runtime"
  24. "k8s.io/apimachinery/pkg/util/diff"
  25. "k8s.io/apimachinery/pkg/util/intstr"
  26. utilfeature "k8s.io/apiserver/pkg/util/feature"
  27. featuregatetesting "k8s.io/component-base/featuregate/testing"
  28. "k8s.io/kubernetes/pkg/api/legacyscheme"
  29. corev1 "k8s.io/kubernetes/pkg/apis/core/v1"
  30. "k8s.io/kubernetes/pkg/features"
  31. utilpointer "k8s.io/utils/pointer"
  32. // ensure types are installed
  33. _ "k8s.io/kubernetes/pkg/apis/core/install"
  34. )
  35. // TestWorkloadDefaults detects changes to defaults within PodTemplateSpec.
  36. // Defaulting changes within this type can cause spurious rollouts of workloads on API server update.
  37. func TestWorkloadDefaults(t *testing.T) {
  38. rc := &v1.ReplicationController{Spec: v1.ReplicationControllerSpec{Template: &v1.PodTemplateSpec{}}}
  39. template := rc.Spec.Template
  40. // New defaults under PodTemplateSpec are only acceptable if they would not be applied when reading data from a previous release.
  41. // Forbidden: adding a new field `MyField *bool` and defaulting it to a non-nil value
  42. // Forbidden: defaulting an existing field `MyField *bool` when it was previously not defaulted
  43. // Forbidden: changing an existing default value
  44. // Allowed: adding a new field `MyContainer *MyType` and defaulting a child of that type (e.g. `MyContainer.MyChildField`) if and only if MyContainer is non-nil
  45. expectedDefaults := map[string]string{
  46. ".Spec.Containers[0].Env[0].ValueFrom.FieldRef.APIVersion": `"v1"`,
  47. ".Spec.Containers[0].ImagePullPolicy": `"IfNotPresent"`,
  48. ".Spec.Containers[0].Lifecycle.PostStart.HTTPGet.Path": `"/"`,
  49. ".Spec.Containers[0].Lifecycle.PostStart.HTTPGet.Scheme": `"HTTP"`,
  50. ".Spec.Containers[0].Lifecycle.PreStop.HTTPGet.Path": `"/"`,
  51. ".Spec.Containers[0].Lifecycle.PreStop.HTTPGet.Scheme": `"HTTP"`,
  52. ".Spec.Containers[0].LivenessProbe.FailureThreshold": `3`,
  53. ".Spec.Containers[0].LivenessProbe.Handler.HTTPGet.Path": `"/"`,
  54. ".Spec.Containers[0].LivenessProbe.Handler.HTTPGet.Scheme": `"HTTP"`,
  55. ".Spec.Containers[0].LivenessProbe.PeriodSeconds": `10`,
  56. ".Spec.Containers[0].LivenessProbe.SuccessThreshold": `1`,
  57. ".Spec.Containers[0].LivenessProbe.TimeoutSeconds": `1`,
  58. ".Spec.Containers[0].Ports[0].Protocol": `"TCP"`,
  59. ".Spec.Containers[0].ReadinessProbe.FailureThreshold": `3`,
  60. ".Spec.Containers[0].ReadinessProbe.Handler.HTTPGet.Path": `"/"`,
  61. ".Spec.Containers[0].ReadinessProbe.Handler.HTTPGet.Scheme": `"HTTP"`,
  62. ".Spec.Containers[0].ReadinessProbe.PeriodSeconds": `10`,
  63. ".Spec.Containers[0].ReadinessProbe.SuccessThreshold": `1`,
  64. ".Spec.Containers[0].ReadinessProbe.TimeoutSeconds": `1`,
  65. ".Spec.Containers[0].StartupProbe.FailureThreshold": "3",
  66. ".Spec.Containers[0].StartupProbe.Handler.HTTPGet.Path": `"/"`,
  67. ".Spec.Containers[0].StartupProbe.Handler.HTTPGet.Scheme": `"HTTP"`,
  68. ".Spec.Containers[0].StartupProbe.PeriodSeconds": "10",
  69. ".Spec.Containers[0].StartupProbe.SuccessThreshold": "1",
  70. ".Spec.Containers[0].StartupProbe.TimeoutSeconds": "1",
  71. ".Spec.Containers[0].TerminationMessagePath": `"/dev/termination-log"`,
  72. ".Spec.Containers[0].TerminationMessagePolicy": `"File"`,
  73. ".Spec.DNSPolicy": `"ClusterFirst"`,
  74. ".Spec.EphemeralContainers[0].EphemeralContainerCommon.Env[0].ValueFrom.FieldRef.APIVersion": `"v1"`,
  75. ".Spec.EphemeralContainers[0].EphemeralContainerCommon.Lifecycle.PostStart.HTTPGet.Path": `"/"`,
  76. ".Spec.EphemeralContainers[0].EphemeralContainerCommon.Lifecycle.PostStart.HTTPGet.Scheme": `"HTTP"`,
  77. ".Spec.EphemeralContainers[0].EphemeralContainerCommon.Lifecycle.PreStop.HTTPGet.Path": `"/"`,
  78. ".Spec.EphemeralContainers[0].EphemeralContainerCommon.Lifecycle.PreStop.HTTPGet.Scheme": `"HTTP"`,
  79. ".Spec.EphemeralContainers[0].EphemeralContainerCommon.LivenessProbe.FailureThreshold": "3",
  80. ".Spec.EphemeralContainers[0].EphemeralContainerCommon.LivenessProbe.Handler.HTTPGet.Path": `"/"`,
  81. ".Spec.EphemeralContainers[0].EphemeralContainerCommon.LivenessProbe.Handler.HTTPGet.Scheme": `"HTTP"`,
  82. ".Spec.EphemeralContainers[0].EphemeralContainerCommon.LivenessProbe.PeriodSeconds": "10",
  83. ".Spec.EphemeralContainers[0].EphemeralContainerCommon.LivenessProbe.SuccessThreshold": "1",
  84. ".Spec.EphemeralContainers[0].EphemeralContainerCommon.LivenessProbe.TimeoutSeconds": "1",
  85. ".Spec.EphemeralContainers[0].EphemeralContainerCommon.Ports[0].Protocol": `"TCP"`,
  86. ".Spec.EphemeralContainers[0].EphemeralContainerCommon.ReadinessProbe.FailureThreshold": "3",
  87. ".Spec.EphemeralContainers[0].EphemeralContainerCommon.ReadinessProbe.Handler.HTTPGet.Path": `"/"`,
  88. ".Spec.EphemeralContainers[0].EphemeralContainerCommon.ReadinessProbe.Handler.HTTPGet.Scheme": `"HTTP"`,
  89. ".Spec.EphemeralContainers[0].EphemeralContainerCommon.ReadinessProbe.PeriodSeconds": "10",
  90. ".Spec.EphemeralContainers[0].EphemeralContainerCommon.ReadinessProbe.SuccessThreshold": "1",
  91. ".Spec.EphemeralContainers[0].EphemeralContainerCommon.ReadinessProbe.TimeoutSeconds": "1",
  92. ".Spec.EphemeralContainers[0].EphemeralContainerCommon.StartupProbe.FailureThreshold": "3",
  93. ".Spec.EphemeralContainers[0].EphemeralContainerCommon.StartupProbe.Handler.HTTPGet.Path": `"/"`,
  94. ".Spec.EphemeralContainers[0].EphemeralContainerCommon.StartupProbe.Handler.HTTPGet.Scheme": `"HTTP"`,
  95. ".Spec.EphemeralContainers[0].EphemeralContainerCommon.StartupProbe.PeriodSeconds": "10",
  96. ".Spec.EphemeralContainers[0].EphemeralContainerCommon.StartupProbe.SuccessThreshold": "1",
  97. ".Spec.EphemeralContainers[0].EphemeralContainerCommon.StartupProbe.TimeoutSeconds": "1",
  98. ".Spec.InitContainers[0].Env[0].ValueFrom.FieldRef.APIVersion": `"v1"`,
  99. ".Spec.InitContainers[0].ImagePullPolicy": `"IfNotPresent"`,
  100. ".Spec.InitContainers[0].Lifecycle.PostStart.HTTPGet.Path": `"/"`,
  101. ".Spec.InitContainers[0].Lifecycle.PostStart.HTTPGet.Scheme": `"HTTP"`,
  102. ".Spec.InitContainers[0].Lifecycle.PreStop.HTTPGet.Path": `"/"`,
  103. ".Spec.InitContainers[0].Lifecycle.PreStop.HTTPGet.Scheme": `"HTTP"`,
  104. ".Spec.InitContainers[0].LivenessProbe.FailureThreshold": `3`,
  105. ".Spec.InitContainers[0].LivenessProbe.Handler.HTTPGet.Path": `"/"`,
  106. ".Spec.InitContainers[0].LivenessProbe.Handler.HTTPGet.Scheme": `"HTTP"`,
  107. ".Spec.InitContainers[0].LivenessProbe.PeriodSeconds": `10`,
  108. ".Spec.InitContainers[0].LivenessProbe.SuccessThreshold": `1`,
  109. ".Spec.InitContainers[0].LivenessProbe.TimeoutSeconds": `1`,
  110. ".Spec.InitContainers[0].Ports[0].Protocol": `"TCP"`,
  111. ".Spec.InitContainers[0].ReadinessProbe.FailureThreshold": `3`,
  112. ".Spec.InitContainers[0].ReadinessProbe.Handler.HTTPGet.Path": `"/"`,
  113. ".Spec.InitContainers[0].ReadinessProbe.Handler.HTTPGet.Scheme": `"HTTP"`,
  114. ".Spec.InitContainers[0].ReadinessProbe.PeriodSeconds": `10`,
  115. ".Spec.InitContainers[0].ReadinessProbe.SuccessThreshold": `1`,
  116. ".Spec.InitContainers[0].ReadinessProbe.TimeoutSeconds": `1`,
  117. ".Spec.InitContainers[0].StartupProbe.FailureThreshold": "3",
  118. ".Spec.InitContainers[0].StartupProbe.Handler.HTTPGet.Path": `"/"`,
  119. ".Spec.InitContainers[0].StartupProbe.Handler.HTTPGet.Scheme": `"HTTP"`,
  120. ".Spec.InitContainers[0].StartupProbe.PeriodSeconds": "10",
  121. ".Spec.InitContainers[0].StartupProbe.SuccessThreshold": "1",
  122. ".Spec.InitContainers[0].StartupProbe.TimeoutSeconds": "1",
  123. ".Spec.InitContainers[0].TerminationMessagePath": `"/dev/termination-log"`,
  124. ".Spec.InitContainers[0].TerminationMessagePolicy": `"File"`,
  125. ".Spec.RestartPolicy": `"Always"`,
  126. ".Spec.SchedulerName": `"default-scheduler"`,
  127. ".Spec.SecurityContext": `{}`,
  128. ".Spec.TerminationGracePeriodSeconds": `30`,
  129. ".Spec.Volumes[0].VolumeSource.AzureDisk.CachingMode": `"ReadWrite"`,
  130. ".Spec.Volumes[0].VolumeSource.AzureDisk.FSType": `"ext4"`,
  131. ".Spec.Volumes[0].VolumeSource.AzureDisk.Kind": `"Shared"`,
  132. ".Spec.Volumes[0].VolumeSource.AzureDisk.ReadOnly": `false`,
  133. ".Spec.Volumes[0].VolumeSource.ConfigMap.DefaultMode": `420`,
  134. ".Spec.Volumes[0].VolumeSource.DownwardAPI.DefaultMode": `420`,
  135. ".Spec.Volumes[0].VolumeSource.DownwardAPI.Items[0].FieldRef.APIVersion": `"v1"`,
  136. ".Spec.Volumes[0].VolumeSource.EmptyDir": `{}`,
  137. ".Spec.Volumes[0].VolumeSource.HostPath.Type": `""`,
  138. ".Spec.Volumes[0].VolumeSource.ISCSI.ISCSIInterface": `"default"`,
  139. ".Spec.Volumes[0].VolumeSource.Projected.DefaultMode": `420`,
  140. ".Spec.Volumes[0].VolumeSource.Projected.Sources[0].DownwardAPI.Items[0].FieldRef.APIVersion": `"v1"`,
  141. ".Spec.Volumes[0].VolumeSource.Projected.Sources[0].ServiceAccountToken.ExpirationSeconds": `3600`,
  142. ".Spec.Volumes[0].VolumeSource.RBD.Keyring": `"/etc/ceph/keyring"`,
  143. ".Spec.Volumes[0].VolumeSource.RBD.RBDPool": `"rbd"`,
  144. ".Spec.Volumes[0].VolumeSource.RBD.RadosUser": `"admin"`,
  145. ".Spec.Volumes[0].VolumeSource.ScaleIO.FSType": `"xfs"`,
  146. ".Spec.Volumes[0].VolumeSource.ScaleIO.StorageMode": `"ThinProvisioned"`,
  147. ".Spec.Volumes[0].VolumeSource.Secret.DefaultMode": `420`,
  148. }
  149. defaults := detectDefaults(t, rc, reflect.ValueOf(template))
  150. if !reflect.DeepEqual(expectedDefaults, defaults) {
  151. t.Errorf("Defaults for PodTemplateSpec changed. This can cause spurious rollouts of workloads on API server upgrade.")
  152. t.Logf(diff.ObjectReflectDiff(expectedDefaults, defaults))
  153. }
  154. }
  155. // TestPodDefaults detects changes to defaults within PodSpec.
  156. // Defaulting changes within this type (*especially* within containers) can cause kubelets to restart containers on API server update.
  157. func TestPodDefaults(t *testing.T) {
  158. pod := &v1.Pod{}
  159. // New defaults under PodSpec are only acceptable if they would not be applied when reading data from a previous release.
  160. // Forbidden: adding a new field `MyField *bool` and defaulting it to a non-nil value
  161. // Forbidden: defaulting an existing field `MyField *bool` when it was previously not defaulted
  162. // Forbidden: changing an existing default value
  163. // Allowed: adding a new field `MyContainer *MyType` and defaulting a child of that type (e.g. `MyContainer.MyChildField`) if and only if MyContainer is non-nil
  164. expectedDefaults := map[string]string{
  165. ".Spec.Containers[0].Env[0].ValueFrom.FieldRef.APIVersion": `"v1"`,
  166. ".Spec.Containers[0].ImagePullPolicy": `"IfNotPresent"`,
  167. ".Spec.Containers[0].Lifecycle.PostStart.HTTPGet.Path": `"/"`,
  168. ".Spec.Containers[0].Lifecycle.PostStart.HTTPGet.Scheme": `"HTTP"`,
  169. ".Spec.Containers[0].Lifecycle.PreStop.HTTPGet.Path": `"/"`,
  170. ".Spec.Containers[0].Lifecycle.PreStop.HTTPGet.Scheme": `"HTTP"`,
  171. ".Spec.Containers[0].LivenessProbe.FailureThreshold": `3`,
  172. ".Spec.Containers[0].LivenessProbe.Handler.HTTPGet.Path": `"/"`,
  173. ".Spec.Containers[0].LivenessProbe.Handler.HTTPGet.Scheme": `"HTTP"`,
  174. ".Spec.Containers[0].LivenessProbe.PeriodSeconds": `10`,
  175. ".Spec.Containers[0].LivenessProbe.SuccessThreshold": `1`,
  176. ".Spec.Containers[0].LivenessProbe.TimeoutSeconds": `1`,
  177. ".Spec.Containers[0].Ports[0].Protocol": `"TCP"`,
  178. ".Spec.Containers[0].ReadinessProbe.FailureThreshold": `3`,
  179. ".Spec.Containers[0].ReadinessProbe.Handler.HTTPGet.Path": `"/"`,
  180. ".Spec.Containers[0].ReadinessProbe.Handler.HTTPGet.Scheme": `"HTTP"`,
  181. ".Spec.Containers[0].ReadinessProbe.PeriodSeconds": `10`,
  182. ".Spec.Containers[0].ReadinessProbe.SuccessThreshold": `1`,
  183. ".Spec.Containers[0].ReadinessProbe.TimeoutSeconds": `1`,
  184. ".Spec.Containers[0].Resources.Requests": `{"":"0"}`, // this gets defaulted from the limits field
  185. ".Spec.Containers[0].StartupProbe.FailureThreshold": "3",
  186. ".Spec.Containers[0].StartupProbe.Handler.HTTPGet.Path": `"/"`,
  187. ".Spec.Containers[0].StartupProbe.Handler.HTTPGet.Scheme": `"HTTP"`,
  188. ".Spec.Containers[0].StartupProbe.PeriodSeconds": "10",
  189. ".Spec.Containers[0].StartupProbe.SuccessThreshold": "1",
  190. ".Spec.Containers[0].StartupProbe.TimeoutSeconds": "1",
  191. ".Spec.Containers[0].TerminationMessagePath": `"/dev/termination-log"`,
  192. ".Spec.Containers[0].TerminationMessagePolicy": `"File"`,
  193. ".Spec.DNSPolicy": `"ClusterFirst"`,
  194. ".Spec.EnableServiceLinks": `true`,
  195. ".Spec.EphemeralContainers[0].EphemeralContainerCommon.Env[0].ValueFrom.FieldRef.APIVersion": `"v1"`,
  196. ".Spec.EphemeralContainers[0].EphemeralContainerCommon.Lifecycle.PostStart.HTTPGet.Path": `"/"`,
  197. ".Spec.EphemeralContainers[0].EphemeralContainerCommon.Lifecycle.PostStart.HTTPGet.Scheme": `"HTTP"`,
  198. ".Spec.EphemeralContainers[0].EphemeralContainerCommon.Lifecycle.PreStop.HTTPGet.Path": `"/"`,
  199. ".Spec.EphemeralContainers[0].EphemeralContainerCommon.Lifecycle.PreStop.HTTPGet.Scheme": `"HTTP"`,
  200. ".Spec.EphemeralContainers[0].EphemeralContainerCommon.LivenessProbe.FailureThreshold": "3",
  201. ".Spec.EphemeralContainers[0].EphemeralContainerCommon.LivenessProbe.Handler.HTTPGet.Path": `"/"`,
  202. ".Spec.EphemeralContainers[0].EphemeralContainerCommon.LivenessProbe.Handler.HTTPGet.Scheme": `"HTTP"`,
  203. ".Spec.EphemeralContainers[0].EphemeralContainerCommon.LivenessProbe.PeriodSeconds": "10",
  204. ".Spec.EphemeralContainers[0].EphemeralContainerCommon.LivenessProbe.SuccessThreshold": "1",
  205. ".Spec.EphemeralContainers[0].EphemeralContainerCommon.LivenessProbe.TimeoutSeconds": "1",
  206. ".Spec.EphemeralContainers[0].EphemeralContainerCommon.Ports[0].Protocol": `"TCP"`,
  207. ".Spec.EphemeralContainers[0].EphemeralContainerCommon.ReadinessProbe.FailureThreshold": "3",
  208. ".Spec.EphemeralContainers[0].EphemeralContainerCommon.ReadinessProbe.Handler.HTTPGet.Path": `"/"`,
  209. ".Spec.EphemeralContainers[0].EphemeralContainerCommon.ReadinessProbe.Handler.HTTPGet.Scheme": `"HTTP"`,
  210. ".Spec.EphemeralContainers[0].EphemeralContainerCommon.ReadinessProbe.PeriodSeconds": "10",
  211. ".Spec.EphemeralContainers[0].EphemeralContainerCommon.ReadinessProbe.SuccessThreshold": "1",
  212. ".Spec.EphemeralContainers[0].EphemeralContainerCommon.ReadinessProbe.TimeoutSeconds": "1",
  213. ".Spec.EphemeralContainers[0].EphemeralContainerCommon.StartupProbe.FailureThreshold": "3",
  214. ".Spec.EphemeralContainers[0].EphemeralContainerCommon.StartupProbe.Handler.HTTPGet.Path": `"/"`,
  215. ".Spec.EphemeralContainers[0].EphemeralContainerCommon.StartupProbe.Handler.HTTPGet.Scheme": `"HTTP"`,
  216. ".Spec.EphemeralContainers[0].EphemeralContainerCommon.StartupProbe.PeriodSeconds": "10",
  217. ".Spec.EphemeralContainers[0].EphemeralContainerCommon.StartupProbe.SuccessThreshold": "1",
  218. ".Spec.EphemeralContainers[0].EphemeralContainerCommon.StartupProbe.TimeoutSeconds": "1",
  219. ".Spec.InitContainers[0].Env[0].ValueFrom.FieldRef.APIVersion": `"v1"`,
  220. ".Spec.InitContainers[0].ImagePullPolicy": `"IfNotPresent"`,
  221. ".Spec.InitContainers[0].Lifecycle.PostStart.HTTPGet.Path": `"/"`,
  222. ".Spec.InitContainers[0].Lifecycle.PostStart.HTTPGet.Scheme": `"HTTP"`,
  223. ".Spec.InitContainers[0].Lifecycle.PreStop.HTTPGet.Path": `"/"`,
  224. ".Spec.InitContainers[0].Lifecycle.PreStop.HTTPGet.Scheme": `"HTTP"`,
  225. ".Spec.InitContainers[0].LivenessProbe.FailureThreshold": `3`,
  226. ".Spec.InitContainers[0].LivenessProbe.Handler.HTTPGet.Path": `"/"`,
  227. ".Spec.InitContainers[0].LivenessProbe.Handler.HTTPGet.Scheme": `"HTTP"`,
  228. ".Spec.InitContainers[0].LivenessProbe.PeriodSeconds": `10`,
  229. ".Spec.InitContainers[0].LivenessProbe.SuccessThreshold": `1`,
  230. ".Spec.InitContainers[0].LivenessProbe.TimeoutSeconds": `1`,
  231. ".Spec.InitContainers[0].Ports[0].Protocol": `"TCP"`,
  232. ".Spec.InitContainers[0].ReadinessProbe.FailureThreshold": `3`,
  233. ".Spec.InitContainers[0].ReadinessProbe.Handler.HTTPGet.Path": `"/"`,
  234. ".Spec.InitContainers[0].ReadinessProbe.Handler.HTTPGet.Scheme": `"HTTP"`,
  235. ".Spec.InitContainers[0].ReadinessProbe.PeriodSeconds": `10`,
  236. ".Spec.InitContainers[0].ReadinessProbe.SuccessThreshold": `1`,
  237. ".Spec.InitContainers[0].ReadinessProbe.TimeoutSeconds": `1`,
  238. ".Spec.InitContainers[0].Resources.Requests": `{"":"0"}`, // this gets defaulted from the limits field
  239. ".Spec.InitContainers[0].TerminationMessagePath": `"/dev/termination-log"`,
  240. ".Spec.InitContainers[0].TerminationMessagePolicy": `"File"`,
  241. ".Spec.InitContainers[0].StartupProbe.FailureThreshold": "3",
  242. ".Spec.InitContainers[0].StartupProbe.Handler.HTTPGet.Path": `"/"`,
  243. ".Spec.InitContainers[0].StartupProbe.Handler.HTTPGet.Scheme": `"HTTP"`,
  244. ".Spec.InitContainers[0].StartupProbe.PeriodSeconds": "10",
  245. ".Spec.InitContainers[0].StartupProbe.SuccessThreshold": "1",
  246. ".Spec.InitContainers[0].StartupProbe.TimeoutSeconds": "1",
  247. ".Spec.RestartPolicy": `"Always"`,
  248. ".Spec.SchedulerName": `"default-scheduler"`,
  249. ".Spec.SecurityContext": `{}`,
  250. ".Spec.TerminationGracePeriodSeconds": `30`,
  251. ".Spec.Volumes[0].VolumeSource.AzureDisk.CachingMode": `"ReadWrite"`,
  252. ".Spec.Volumes[0].VolumeSource.AzureDisk.FSType": `"ext4"`,
  253. ".Spec.Volumes[0].VolumeSource.AzureDisk.Kind": `"Shared"`,
  254. ".Spec.Volumes[0].VolumeSource.AzureDisk.ReadOnly": `false`,
  255. ".Spec.Volumes[0].VolumeSource.ConfigMap.DefaultMode": `420`,
  256. ".Spec.Volumes[0].VolumeSource.DownwardAPI.DefaultMode": `420`,
  257. ".Spec.Volumes[0].VolumeSource.DownwardAPI.Items[0].FieldRef.APIVersion": `"v1"`,
  258. ".Spec.Volumes[0].VolumeSource.EmptyDir": `{}`,
  259. ".Spec.Volumes[0].VolumeSource.HostPath.Type": `""`,
  260. ".Spec.Volumes[0].VolumeSource.ISCSI.ISCSIInterface": `"default"`,
  261. ".Spec.Volumes[0].VolumeSource.Projected.DefaultMode": `420`,
  262. ".Spec.Volumes[0].VolumeSource.Projected.Sources[0].DownwardAPI.Items[0].FieldRef.APIVersion": `"v1"`,
  263. ".Spec.Volumes[0].VolumeSource.Projected.Sources[0].ServiceAccountToken.ExpirationSeconds": `3600`,
  264. ".Spec.Volumes[0].VolumeSource.RBD.Keyring": `"/etc/ceph/keyring"`,
  265. ".Spec.Volumes[0].VolumeSource.RBD.RBDPool": `"rbd"`,
  266. ".Spec.Volumes[0].VolumeSource.RBD.RadosUser": `"admin"`,
  267. ".Spec.Volumes[0].VolumeSource.ScaleIO.FSType": `"xfs"`,
  268. ".Spec.Volumes[0].VolumeSource.ScaleIO.StorageMode": `"ThinProvisioned"`,
  269. ".Spec.Volumes[0].VolumeSource.Secret.DefaultMode": `420`,
  270. }
  271. defaults := detectDefaults(t, pod, reflect.ValueOf(pod))
  272. if !reflect.DeepEqual(expectedDefaults, defaults) {
  273. t.Errorf("Defaults for PodSpec changed. This can cause spurious restarts of containers on API server upgrade.")
  274. t.Logf(diff.ObjectReflectDiff(expectedDefaults, defaults))
  275. }
  276. }
  277. type testPath struct {
  278. path string
  279. value reflect.Value
  280. }
  281. func detectDefaults(t *testing.T, obj runtime.Object, v reflect.Value) map[string]string {
  282. defaults := map[string]string{}
  283. toVisit := []testPath{{path: "", value: v}}
  284. for len(toVisit) > 0 {
  285. visit := toVisit[0]
  286. toVisit = toVisit[1:]
  287. legacyscheme.Scheme.Default(obj)
  288. defaultedV := visit.value
  289. zeroV := reflect.Zero(visit.value.Type())
  290. switch {
  291. case visit.value.Kind() == reflect.Struct:
  292. for fi := 0; fi < visit.value.NumField(); fi++ {
  293. structField := visit.value.Type().Field(fi)
  294. valueField := visit.value.Field(fi)
  295. if valueField.CanSet() {
  296. toVisit = append(toVisit, testPath{path: visit.path + "." + structField.Name, value: valueField})
  297. }
  298. }
  299. case visit.value.Kind() == reflect.Slice:
  300. if !visit.value.IsNil() {
  301. // if we already have a value, we got defaulted
  302. marshaled, _ := json.Marshal(defaultedV.Interface())
  303. defaults[visit.path] = string(marshaled)
  304. } else if visit.value.Type().Elem().Kind() == reflect.Struct {
  305. if strings.HasPrefix(visit.path, ".ObjectMeta.ManagedFields[") {
  306. break
  307. }
  308. // if we don't already have a value, and contain structs, add an empty item so we can recurse
  309. item := reflect.New(visit.value.Type().Elem()).Elem()
  310. visit.value.Set(reflect.Append(visit.value, item))
  311. toVisit = append(toVisit, testPath{path: visit.path + "[0]", value: visit.value.Index(0)})
  312. } else if !isPrimitive(visit.value.Type().Elem().Kind()) {
  313. t.Logf("unhandled non-primitive slice type %s: %s", visit.path, visit.value.Type().Elem())
  314. }
  315. case visit.value.Kind() == reflect.Map:
  316. if !visit.value.IsNil() {
  317. // if we already have a value, we got defaulted
  318. marshaled, _ := json.Marshal(defaultedV.Interface())
  319. defaults[visit.path] = string(marshaled)
  320. } else if visit.value.Type().Key().Kind() == reflect.String && visit.value.Type().Elem().Kind() == reflect.Struct {
  321. if strings.HasPrefix(visit.path, ".ObjectMeta.ManagedFields[") {
  322. break
  323. }
  324. // if we don't already have a value, and contain structs, add an empty item so we can recurse
  325. item := reflect.New(visit.value.Type().Elem()).Elem()
  326. visit.value.Set(reflect.MakeMap(visit.value.Type()))
  327. visit.value.SetMapIndex(reflect.New(visit.value.Type().Key()).Elem(), item)
  328. toVisit = append(toVisit, testPath{path: visit.path + "[*]", value: item})
  329. } else if !isPrimitive(visit.value.Type().Elem().Kind()) {
  330. t.Logf("unhandled non-primitive map type %s: %s", visit.path, visit.value.Type().Elem())
  331. }
  332. case visit.value.Kind() == reflect.Ptr:
  333. if visit.value.IsNil() {
  334. if visit.value.Type().Elem().Kind() == reflect.Struct {
  335. visit.value.Set(reflect.New(visit.value.Type().Elem()))
  336. toVisit = append(toVisit, testPath{path: visit.path, value: visit.value.Elem()})
  337. } else if !isPrimitive(visit.value.Type().Elem().Kind()) {
  338. t.Errorf("unhandled non-primitive nil ptr: %s: %s", visit.path, visit.value.Type())
  339. }
  340. } else {
  341. if visit.path != "" {
  342. marshaled, _ := json.Marshal(defaultedV.Interface())
  343. defaults[visit.path] = string(marshaled)
  344. }
  345. toVisit = append(toVisit, testPath{path: visit.path, value: visit.value.Elem()})
  346. }
  347. case isPrimitive(visit.value.Kind()):
  348. if !reflect.DeepEqual(defaultedV.Interface(), zeroV.Interface()) {
  349. marshaled, _ := json.Marshal(defaultedV.Interface())
  350. defaults[visit.path] = string(marshaled)
  351. }
  352. default:
  353. t.Errorf("unhandled kind: %s: %s", visit.path, visit.value.Type())
  354. }
  355. }
  356. return defaults
  357. }
  358. func isPrimitive(k reflect.Kind) bool {
  359. switch k {
  360. case reflect.String, reflect.Bool, reflect.Int32, reflect.Int64, reflect.Int:
  361. return true
  362. default:
  363. return false
  364. }
  365. }
  366. func roundTrip(t *testing.T, obj runtime.Object) runtime.Object {
  367. codec := legacyscheme.Codecs.LegacyCodec(corev1.SchemeGroupVersion)
  368. data, err := runtime.Encode(codec, obj)
  369. if err != nil {
  370. t.Errorf("%v\n %#v", err, obj)
  371. return nil
  372. }
  373. obj2, err := runtime.Decode(codec, data)
  374. if err != nil {
  375. t.Errorf("%v\nData: %s\nSource: %#v", err, string(data), obj)
  376. return nil
  377. }
  378. obj3 := reflect.New(reflect.TypeOf(obj).Elem()).Interface().(runtime.Object)
  379. err = legacyscheme.Scheme.Convert(obj2, obj3, nil)
  380. if err != nil {
  381. t.Errorf("%v\nSource: %#v", err, obj2)
  382. return nil
  383. }
  384. return obj3
  385. }
  386. func TestSetDefaultReplicationController(t *testing.T) {
  387. tests := []struct {
  388. rc *v1.ReplicationController
  389. expectLabels bool
  390. expectSelector bool
  391. }{
  392. {
  393. rc: &v1.ReplicationController{
  394. Spec: v1.ReplicationControllerSpec{
  395. Template: &v1.PodTemplateSpec{
  396. ObjectMeta: metav1.ObjectMeta{
  397. Labels: map[string]string{
  398. "foo": "bar",
  399. },
  400. },
  401. },
  402. },
  403. },
  404. expectLabels: true,
  405. expectSelector: true,
  406. },
  407. {
  408. rc: &v1.ReplicationController{
  409. ObjectMeta: metav1.ObjectMeta{
  410. Labels: map[string]string{
  411. "bar": "foo",
  412. },
  413. },
  414. Spec: v1.ReplicationControllerSpec{
  415. Template: &v1.PodTemplateSpec{
  416. ObjectMeta: metav1.ObjectMeta{
  417. Labels: map[string]string{
  418. "foo": "bar",
  419. },
  420. },
  421. },
  422. },
  423. },
  424. expectLabels: false,
  425. expectSelector: true,
  426. },
  427. {
  428. rc: &v1.ReplicationController{
  429. ObjectMeta: metav1.ObjectMeta{
  430. Labels: map[string]string{
  431. "bar": "foo",
  432. },
  433. },
  434. Spec: v1.ReplicationControllerSpec{
  435. Selector: map[string]string{
  436. "some": "other",
  437. },
  438. Template: &v1.PodTemplateSpec{
  439. ObjectMeta: metav1.ObjectMeta{
  440. Labels: map[string]string{
  441. "foo": "bar",
  442. },
  443. },
  444. },
  445. },
  446. },
  447. expectLabels: false,
  448. expectSelector: false,
  449. },
  450. {
  451. rc: &v1.ReplicationController{
  452. Spec: v1.ReplicationControllerSpec{
  453. Selector: map[string]string{
  454. "some": "other",
  455. },
  456. Template: &v1.PodTemplateSpec{
  457. ObjectMeta: metav1.ObjectMeta{
  458. Labels: map[string]string{
  459. "foo": "bar",
  460. },
  461. },
  462. },
  463. },
  464. },
  465. expectLabels: true,
  466. expectSelector: false,
  467. },
  468. }
  469. for _, test := range tests {
  470. rc := test.rc
  471. obj2 := roundTrip(t, runtime.Object(rc))
  472. rc2, ok := obj2.(*v1.ReplicationController)
  473. if !ok {
  474. t.Errorf("unexpected object: %v", rc2)
  475. t.FailNow()
  476. }
  477. if test.expectSelector != reflect.DeepEqual(rc2.Spec.Selector, rc2.Spec.Template.Labels) {
  478. if test.expectSelector {
  479. t.Errorf("expected: %v, got: %v", rc2.Spec.Template.Labels, rc2.Spec.Selector)
  480. } else {
  481. t.Errorf("unexpected equality: %v", rc.Spec.Selector)
  482. }
  483. }
  484. if test.expectLabels != reflect.DeepEqual(rc2.Labels, rc2.Spec.Template.Labels) {
  485. if test.expectLabels {
  486. t.Errorf("expected: %v, got: %v", rc2.Spec.Template.Labels, rc2.Labels)
  487. } else {
  488. t.Errorf("unexpected equality: %v", rc.Labels)
  489. }
  490. }
  491. }
  492. }
  493. func TestSetDefaultReplicationControllerReplicas(t *testing.T) {
  494. tests := []struct {
  495. rc v1.ReplicationController
  496. expectReplicas int32
  497. }{
  498. {
  499. rc: v1.ReplicationController{
  500. Spec: v1.ReplicationControllerSpec{
  501. Template: &v1.PodTemplateSpec{
  502. ObjectMeta: metav1.ObjectMeta{
  503. Labels: map[string]string{
  504. "foo": "bar",
  505. },
  506. },
  507. },
  508. },
  509. },
  510. expectReplicas: 1,
  511. },
  512. {
  513. rc: v1.ReplicationController{
  514. Spec: v1.ReplicationControllerSpec{
  515. Replicas: utilpointer.Int32Ptr(0),
  516. Template: &v1.PodTemplateSpec{
  517. ObjectMeta: metav1.ObjectMeta{
  518. Labels: map[string]string{
  519. "foo": "bar",
  520. },
  521. },
  522. },
  523. },
  524. },
  525. expectReplicas: 0,
  526. },
  527. {
  528. rc: v1.ReplicationController{
  529. Spec: v1.ReplicationControllerSpec{
  530. Replicas: utilpointer.Int32Ptr(3),
  531. Template: &v1.PodTemplateSpec{
  532. ObjectMeta: metav1.ObjectMeta{
  533. Labels: map[string]string{
  534. "foo": "bar",
  535. },
  536. },
  537. },
  538. },
  539. },
  540. expectReplicas: 3,
  541. },
  542. }
  543. for _, test := range tests {
  544. rc := &test.rc
  545. obj2 := roundTrip(t, runtime.Object(rc))
  546. rc2, ok := obj2.(*v1.ReplicationController)
  547. if !ok {
  548. t.Errorf("unexpected object: %v", rc2)
  549. t.FailNow()
  550. }
  551. if rc2.Spec.Replicas == nil {
  552. t.Errorf("unexpected nil Replicas")
  553. } else if test.expectReplicas != *rc2.Spec.Replicas {
  554. t.Errorf("expected: %d replicas, got: %d", test.expectReplicas, *rc2.Spec.Replicas)
  555. }
  556. }
  557. }
  558. type InitContainerValidator func(got, expected *v1.Container) error
  559. func TestSetDefaultReplicationControllerInitContainers(t *testing.T) {
  560. assertEnvFieldRef := func(got, expected *v1.Container) error {
  561. if len(got.Env) != len(expected.Env) {
  562. return fmt.Errorf("different number of env: got <%v>, expected <%v>", len(got.Env), len(expected.Env))
  563. }
  564. for j := range got.Env {
  565. ge := &got.Env[j]
  566. ee := &expected.Env[j]
  567. if ge.Name != ee.Name {
  568. return fmt.Errorf("different name of env: got <%v>, expected <%v>", ge.Name, ee.Name)
  569. }
  570. if ge.ValueFrom.FieldRef.APIVersion != ee.ValueFrom.FieldRef.APIVersion {
  571. return fmt.Errorf("different api version of FieldRef <%v>: got <%v>, expected <%v>",
  572. ge.Name, ge.ValueFrom.FieldRef.APIVersion, ee.ValueFrom.FieldRef.APIVersion)
  573. }
  574. }
  575. return nil
  576. }
  577. assertImagePullPolicy := func(got, expected *v1.Container) error {
  578. if got.ImagePullPolicy != expected.ImagePullPolicy {
  579. return fmt.Errorf("different image pull policy: got <%v>, expected <%v>", got.ImagePullPolicy, expected.ImagePullPolicy)
  580. }
  581. return nil
  582. }
  583. assertContainerPort := func(got, expected *v1.Container) error {
  584. if len(got.Ports) != len(expected.Ports) {
  585. return fmt.Errorf("different number of ports: got <%v>, expected <%v>", len(got.Ports), len(expected.Ports))
  586. }
  587. for i := range got.Ports {
  588. gp := &got.Ports[i]
  589. ep := &expected.Ports[i]
  590. if gp.Name != ep.Name {
  591. return fmt.Errorf("different name of port: got <%v>, expected <%v>", gp.Name, ep.Name)
  592. }
  593. if gp.Protocol != ep.Protocol {
  594. return fmt.Errorf("different port protocol <%v>: got <%v>, expected <%v>", gp.Name, gp.Protocol, ep.Protocol)
  595. }
  596. }
  597. return nil
  598. }
  599. assertResource := func(got, expected *v1.Container) error {
  600. if len(got.Resources.Limits) != len(expected.Resources.Limits) {
  601. return fmt.Errorf("different number of resources.Limits: got <%v>, expected <%v>", len(got.Resources.Limits), (expected.Resources.Limits))
  602. }
  603. for k, v := range got.Resources.Limits {
  604. if ev, found := expected.Resources.Limits[v1.ResourceName(k)]; !found {
  605. return fmt.Errorf("failed to find resource <%v> in expected resources.Limits.", k)
  606. } else {
  607. if ev.Value() != v.Value() {
  608. return fmt.Errorf("different resource.Limits: got <%v>, expected <%v>.", v.Value(), ev.Value())
  609. }
  610. }
  611. }
  612. if len(got.Resources.Requests) != len(expected.Resources.Requests) {
  613. return fmt.Errorf("different number of resources.Requests: got <%v>, expected <%v>", len(got.Resources.Requests), (expected.Resources.Requests))
  614. }
  615. for k, v := range got.Resources.Requests {
  616. if ev, found := expected.Resources.Requests[v1.ResourceName(k)]; !found {
  617. return fmt.Errorf("failed to find resource <%v> in expected resources.Requests.", k)
  618. } else {
  619. if ev.Value() != v.Value() {
  620. return fmt.Errorf("different resource.Requests: got <%v>, expected <%v>.", v.Value(), ev.Value())
  621. }
  622. }
  623. }
  624. return nil
  625. }
  626. assertProb := func(got, expected *v1.Container) error {
  627. // Assert LivenessProbe
  628. if got.LivenessProbe.Handler.HTTPGet.Path != expected.LivenessProbe.Handler.HTTPGet.Path ||
  629. got.LivenessProbe.Handler.HTTPGet.Scheme != expected.LivenessProbe.Handler.HTTPGet.Scheme ||
  630. got.LivenessProbe.FailureThreshold != expected.LivenessProbe.FailureThreshold ||
  631. got.LivenessProbe.SuccessThreshold != expected.LivenessProbe.SuccessThreshold ||
  632. got.LivenessProbe.PeriodSeconds != expected.LivenessProbe.PeriodSeconds ||
  633. got.LivenessProbe.TimeoutSeconds != expected.LivenessProbe.TimeoutSeconds {
  634. return fmt.Errorf("different LivenessProbe: got <%v>, expected <%v>", got.LivenessProbe, expected.LivenessProbe)
  635. }
  636. // Assert ReadinessProbe
  637. if got.ReadinessProbe.Handler.HTTPGet.Path != expected.ReadinessProbe.Handler.HTTPGet.Path ||
  638. got.ReadinessProbe.Handler.HTTPGet.Scheme != expected.ReadinessProbe.Handler.HTTPGet.Scheme ||
  639. got.ReadinessProbe.FailureThreshold != expected.ReadinessProbe.FailureThreshold ||
  640. got.ReadinessProbe.SuccessThreshold != expected.ReadinessProbe.SuccessThreshold ||
  641. got.ReadinessProbe.PeriodSeconds != expected.ReadinessProbe.PeriodSeconds ||
  642. got.ReadinessProbe.TimeoutSeconds != expected.ReadinessProbe.TimeoutSeconds {
  643. return fmt.Errorf("different ReadinessProbe: got <%v>, expected <%v>", got.ReadinessProbe, expected.ReadinessProbe)
  644. }
  645. return nil
  646. }
  647. assertLifeCycle := func(got, expected *v1.Container) error {
  648. if got.Lifecycle.PostStart.HTTPGet.Path != expected.Lifecycle.PostStart.HTTPGet.Path ||
  649. got.Lifecycle.PostStart.HTTPGet.Scheme != expected.Lifecycle.PostStart.HTTPGet.Scheme {
  650. return fmt.Errorf("different LifeCycle: got <%v>, expected <%v>", got.Lifecycle, expected.Lifecycle)
  651. }
  652. return nil
  653. }
  654. cpu, _ := resource.ParseQuantity("100m")
  655. mem, _ := resource.ParseQuantity("100Mi")
  656. tests := []struct {
  657. name string
  658. rc v1.ReplicationController
  659. expected []v1.Container
  660. validators []InitContainerValidator
  661. }{
  662. {
  663. name: "imagePullIPolicy",
  664. rc: v1.ReplicationController{
  665. Spec: v1.ReplicationControllerSpec{
  666. Template: &v1.PodTemplateSpec{
  667. Spec: v1.PodSpec{
  668. InitContainers: []v1.Container{
  669. {
  670. Name: "install",
  671. Image: "busybox",
  672. },
  673. },
  674. },
  675. },
  676. },
  677. },
  678. expected: []v1.Container{
  679. {
  680. ImagePullPolicy: v1.PullAlways,
  681. },
  682. },
  683. validators: []InitContainerValidator{assertImagePullPolicy},
  684. },
  685. {
  686. name: "FieldRef",
  687. rc: v1.ReplicationController{
  688. Spec: v1.ReplicationControllerSpec{
  689. Template: &v1.PodTemplateSpec{
  690. Spec: v1.PodSpec{
  691. InitContainers: []v1.Container{
  692. {
  693. Name: "fun",
  694. Image: "alpine",
  695. Env: []v1.EnvVar{
  696. {
  697. Name: "MY_POD_IP",
  698. ValueFrom: &v1.EnvVarSource{
  699. FieldRef: &v1.ObjectFieldSelector{
  700. APIVersion: "",
  701. FieldPath: "status.podIP",
  702. },
  703. },
  704. },
  705. },
  706. },
  707. },
  708. },
  709. },
  710. },
  711. },
  712. expected: []v1.Container{
  713. {
  714. Env: []v1.EnvVar{
  715. {
  716. Name: "MY_POD_IP",
  717. ValueFrom: &v1.EnvVarSource{
  718. FieldRef: &v1.ObjectFieldSelector{
  719. APIVersion: "v1",
  720. FieldPath: "status.podIP",
  721. },
  722. },
  723. },
  724. },
  725. },
  726. },
  727. validators: []InitContainerValidator{assertEnvFieldRef},
  728. },
  729. {
  730. name: "ContainerPort",
  731. rc: v1.ReplicationController{
  732. Spec: v1.ReplicationControllerSpec{
  733. Template: &v1.PodTemplateSpec{
  734. Spec: v1.PodSpec{
  735. InitContainers: []v1.Container{
  736. {
  737. Name: "fun",
  738. Image: "alpine",
  739. Ports: []v1.ContainerPort{
  740. {
  741. Name: "default",
  742. },
  743. },
  744. },
  745. },
  746. },
  747. },
  748. },
  749. },
  750. expected: []v1.Container{
  751. {
  752. Ports: []v1.ContainerPort{
  753. {
  754. Name: "default",
  755. Protocol: v1.ProtocolTCP,
  756. },
  757. },
  758. },
  759. },
  760. validators: []InitContainerValidator{assertContainerPort},
  761. },
  762. {
  763. name: "Resources",
  764. rc: v1.ReplicationController{
  765. Spec: v1.ReplicationControllerSpec{
  766. Template: &v1.PodTemplateSpec{
  767. Spec: v1.PodSpec{
  768. InitContainers: []v1.Container{
  769. {
  770. Name: "fun",
  771. Image: "alpine",
  772. Resources: v1.ResourceRequirements{
  773. Limits: v1.ResourceList{
  774. v1.ResourceCPU: resource.MustParse("100m"),
  775. v1.ResourceMemory: resource.MustParse("100Mi"),
  776. },
  777. Requests: v1.ResourceList{
  778. v1.ResourceCPU: resource.MustParse("100m"),
  779. v1.ResourceMemory: resource.MustParse("100Mi"),
  780. },
  781. },
  782. },
  783. },
  784. },
  785. },
  786. },
  787. },
  788. expected: []v1.Container{
  789. {
  790. Resources: v1.ResourceRequirements{
  791. Limits: v1.ResourceList{
  792. v1.ResourceCPU: cpu,
  793. v1.ResourceMemory: mem,
  794. },
  795. Requests: v1.ResourceList{
  796. v1.ResourceCPU: cpu,
  797. v1.ResourceMemory: mem,
  798. },
  799. },
  800. },
  801. },
  802. validators: []InitContainerValidator{assertResource},
  803. },
  804. {
  805. name: "Probe",
  806. rc: v1.ReplicationController{
  807. Spec: v1.ReplicationControllerSpec{
  808. Template: &v1.PodTemplateSpec{
  809. Spec: v1.PodSpec{
  810. InitContainers: []v1.Container{
  811. {
  812. Name: "fun",
  813. Image: "alpine",
  814. LivenessProbe: &v1.Probe{
  815. Handler: v1.Handler{
  816. HTTPGet: &v1.HTTPGetAction{
  817. Host: "localhost",
  818. },
  819. },
  820. },
  821. ReadinessProbe: &v1.Probe{
  822. Handler: v1.Handler{
  823. HTTPGet: &v1.HTTPGetAction{
  824. Host: "localhost",
  825. },
  826. },
  827. },
  828. },
  829. },
  830. },
  831. },
  832. },
  833. },
  834. expected: []v1.Container{
  835. {
  836. LivenessProbe: &v1.Probe{
  837. Handler: v1.Handler{
  838. HTTPGet: &v1.HTTPGetAction{
  839. Path: "/",
  840. Scheme: v1.URISchemeHTTP,
  841. },
  842. },
  843. TimeoutSeconds: 1,
  844. PeriodSeconds: 10,
  845. SuccessThreshold: 1,
  846. FailureThreshold: 3,
  847. },
  848. ReadinessProbe: &v1.Probe{
  849. Handler: v1.Handler{
  850. HTTPGet: &v1.HTTPGetAction{
  851. Path: "/",
  852. Scheme: v1.URISchemeHTTP,
  853. },
  854. },
  855. TimeoutSeconds: 1,
  856. PeriodSeconds: 10,
  857. SuccessThreshold: 1,
  858. FailureThreshold: 3,
  859. },
  860. },
  861. },
  862. validators: []InitContainerValidator{assertProb},
  863. },
  864. {
  865. name: "LifeCycle",
  866. rc: v1.ReplicationController{
  867. Spec: v1.ReplicationControllerSpec{
  868. Template: &v1.PodTemplateSpec{
  869. Spec: v1.PodSpec{
  870. InitContainers: []v1.Container{
  871. {
  872. Name: "fun",
  873. Image: "alpine",
  874. Ports: []v1.ContainerPort{
  875. {
  876. Name: "default",
  877. },
  878. },
  879. Lifecycle: &v1.Lifecycle{
  880. PostStart: &v1.Handler{
  881. HTTPGet: &v1.HTTPGetAction{
  882. Host: "localhost",
  883. },
  884. },
  885. PreStop: &v1.Handler{
  886. HTTPGet: &v1.HTTPGetAction{
  887. Host: "localhost",
  888. },
  889. },
  890. },
  891. },
  892. },
  893. },
  894. },
  895. },
  896. },
  897. expected: []v1.Container{
  898. {
  899. Lifecycle: &v1.Lifecycle{
  900. PostStart: &v1.Handler{
  901. HTTPGet: &v1.HTTPGetAction{
  902. Path: "/",
  903. Scheme: v1.URISchemeHTTP,
  904. },
  905. },
  906. PreStop: &v1.Handler{
  907. HTTPGet: &v1.HTTPGetAction{
  908. Path: "/",
  909. Scheme: v1.URISchemeHTTP,
  910. },
  911. },
  912. },
  913. },
  914. },
  915. validators: []InitContainerValidator{assertLifeCycle},
  916. },
  917. }
  918. assertInitContainers := func(got, expected []v1.Container, validators []InitContainerValidator) error {
  919. if len(got) != len(expected) {
  920. return fmt.Errorf("different number of init container: got <%d>, expected <%d>",
  921. len(got), len(expected))
  922. }
  923. for i := range got {
  924. g := &got[i]
  925. e := &expected[i]
  926. for _, validator := range validators {
  927. if err := validator(g, e); err != nil {
  928. return err
  929. }
  930. }
  931. }
  932. return nil
  933. }
  934. for _, test := range tests {
  935. rc := &test.rc
  936. obj2 := roundTrip(t, runtime.Object(rc))
  937. rc2, ok := obj2.(*v1.ReplicationController)
  938. if !ok {
  939. t.Errorf("unexpected object: %v", rc2)
  940. t.FailNow()
  941. }
  942. if err := assertInitContainers(rc2.Spec.Template.Spec.InitContainers, test.expected, test.validators); err != nil {
  943. t.Errorf("test %v failed: %v", test.name, err)
  944. }
  945. }
  946. }
  947. func TestSetDefaultService(t *testing.T) {
  948. svc := &v1.Service{}
  949. obj2 := roundTrip(t, runtime.Object(svc))
  950. svc2 := obj2.(*v1.Service)
  951. if svc2.Spec.SessionAffinity != v1.ServiceAffinityNone {
  952. t.Errorf("Expected default session affinity type:%s, got: %s", v1.ServiceAffinityNone, svc2.Spec.SessionAffinity)
  953. }
  954. if svc2.Spec.SessionAffinityConfig != nil {
  955. t.Errorf("Expected empty session affinity config when session affinity type: %s, got: %v", v1.ServiceAffinityNone, svc2.Spec.SessionAffinityConfig)
  956. }
  957. if svc2.Spec.Type != v1.ServiceTypeClusterIP {
  958. t.Errorf("Expected default type:%s, got: %s", v1.ServiceTypeClusterIP, svc2.Spec.Type)
  959. }
  960. }
  961. func TestSetDefaultServiceIPFamily(t *testing.T) {
  962. svc := v1.Service{
  963. Spec: v1.ServiceSpec{
  964. SessionAffinity: v1.ServiceAffinityNone,
  965. Type: v1.ServiceTypeClusterIP,
  966. },
  967. }
  968. testCases := []struct {
  969. name string
  970. inSvcTweak func(s v1.Service) v1.Service
  971. outSvcTweak func(s v1.Service) v1.Service
  972. enableDualStack bool
  973. }{
  974. {
  975. name: "dualstack off. ipfamily not set",
  976. inSvcTweak: func(s v1.Service) v1.Service { return s },
  977. outSvcTweak: func(s v1.Service) v1.Service { return s },
  978. enableDualStack: false,
  979. },
  980. {
  981. name: "dualstack on. ipfamily not set, service is *not* ClusterIP-able",
  982. inSvcTweak: func(s v1.Service) v1.Service {
  983. s.Spec.Type = v1.ServiceTypeExternalName
  984. return s
  985. },
  986. outSvcTweak: func(s v1.Service) v1.Service { return s },
  987. enableDualStack: true,
  988. },
  989. {
  990. name: "dualstack off. ipfamily set",
  991. inSvcTweak: func(s v1.Service) v1.Service {
  992. ipv4Service := v1.IPv4Protocol
  993. s.Spec.IPFamily = &ipv4Service
  994. return s
  995. },
  996. outSvcTweak: func(s v1.Service) v1.Service {
  997. ipv4Service := v1.IPv4Protocol
  998. s.Spec.IPFamily = &ipv4Service
  999. return s
  1000. },
  1001. enableDualStack: false,
  1002. },
  1003. {
  1004. name: "dualstack off. ipfamily not set. clusterip set",
  1005. inSvcTweak: func(s v1.Service) v1.Service {
  1006. s.Spec.ClusterIP = "1.1.1.1"
  1007. return s
  1008. },
  1009. outSvcTweak: func(s v1.Service) v1.Service {
  1010. return s
  1011. },
  1012. enableDualStack: false,
  1013. },
  1014. {
  1015. name: "dualstack on. ipfamily not set (clusterIP is v4)",
  1016. inSvcTweak: func(s v1.Service) v1.Service {
  1017. s.Spec.ClusterIP = "1.1.1.1"
  1018. return s
  1019. },
  1020. outSvcTweak: func(s v1.Service) v1.Service {
  1021. ipv4Service := v1.IPv4Protocol
  1022. s.Spec.IPFamily = &ipv4Service
  1023. return s
  1024. },
  1025. enableDualStack: true,
  1026. },
  1027. {
  1028. name: "dualstack on. ipfamily not set (clusterIP is v6)",
  1029. inSvcTweak: func(s v1.Service) v1.Service {
  1030. s.Spec.ClusterIP = "fdd7:7713:8917:77ed:ffff:ffff:ffff:ffff"
  1031. return s
  1032. },
  1033. outSvcTweak: func(s v1.Service) v1.Service {
  1034. ipv6Service := v1.IPv6Protocol
  1035. s.Spec.IPFamily = &ipv6Service
  1036. return s
  1037. },
  1038. enableDualStack: true,
  1039. },
  1040. {
  1041. name: "dualstack on. ipfamily set (clusterIP is v4)",
  1042. inSvcTweak: func(s v1.Service) v1.Service {
  1043. ipv4Service := v1.IPv4Protocol
  1044. s.Spec.IPFamily = &ipv4Service
  1045. s.Spec.ClusterIP = "1.1.1.1"
  1046. return s
  1047. },
  1048. outSvcTweak: func(s v1.Service) v1.Service {
  1049. ipv4Service := v1.IPv4Protocol
  1050. s.Spec.IPFamily = &ipv4Service
  1051. return s
  1052. },
  1053. enableDualStack: true,
  1054. },
  1055. {
  1056. name: "dualstack on. ipfamily set (clusterIP is v6)",
  1057. inSvcTweak: func(s v1.Service) v1.Service {
  1058. ipv6Service := v1.IPv6Protocol
  1059. s.Spec.IPFamily = &ipv6Service
  1060. s.Spec.ClusterIP = "fdd7:7713:8917:77ed:ffff:ffff:ffff:ffff"
  1061. return s
  1062. },
  1063. outSvcTweak: func(s v1.Service) v1.Service {
  1064. ipv6Service := v1.IPv6Protocol
  1065. s.Spec.IPFamily = &ipv6Service
  1066. return s
  1067. },
  1068. enableDualStack: true,
  1069. },
  1070. }
  1071. for _, tc := range testCases {
  1072. t.Run(tc.name, func(t *testing.T) {
  1073. defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.IPv6DualStack, tc.enableDualStack)()
  1074. tweakedIn := tc.inSvcTweak(svc)
  1075. expectedSvc := tc.outSvcTweak(svc)
  1076. defaulted := roundTrip(t, runtime.Object(&tweakedIn))
  1077. defaultedSvc := defaulted.(*v1.Service)
  1078. if expectedSvc.Spec.IPFamily != nil {
  1079. if defaultedSvc.Spec.IPFamily == nil {
  1080. t.Fatalf("defaulted service ipfamily is nil while expected is not")
  1081. }
  1082. if *(expectedSvc.Spec.IPFamily) != *(defaultedSvc.Spec.IPFamily) {
  1083. t.Fatalf("defaulted service ipfamily %v does not match expected %v", defaultedSvc.Spec.IPFamily, expectedSvc.Spec.IPFamily)
  1084. }
  1085. }
  1086. if expectedSvc.Spec.IPFamily == nil && defaultedSvc.Spec.IPFamily != nil {
  1087. t.Fatalf("defaulted service ipfamily is not nil, while expected service ipfamily is")
  1088. }
  1089. })
  1090. }
  1091. }
  1092. func TestSetDefaultServiceSessionAffinityConfig(t *testing.T) {
  1093. testCases := map[string]v1.Service{
  1094. "SessionAffinityConfig is empty": {
  1095. Spec: v1.ServiceSpec{
  1096. SessionAffinity: v1.ServiceAffinityClientIP,
  1097. SessionAffinityConfig: nil,
  1098. },
  1099. },
  1100. "ClientIP is empty": {
  1101. Spec: v1.ServiceSpec{
  1102. SessionAffinity: v1.ServiceAffinityClientIP,
  1103. SessionAffinityConfig: &v1.SessionAffinityConfig{
  1104. ClientIP: nil,
  1105. },
  1106. },
  1107. },
  1108. "TimeoutSeconds is empty": {
  1109. Spec: v1.ServiceSpec{
  1110. SessionAffinity: v1.ServiceAffinityClientIP,
  1111. SessionAffinityConfig: &v1.SessionAffinityConfig{
  1112. ClientIP: &v1.ClientIPConfig{
  1113. TimeoutSeconds: nil,
  1114. },
  1115. },
  1116. },
  1117. },
  1118. }
  1119. for name, test := range testCases {
  1120. obj2 := roundTrip(t, runtime.Object(&test))
  1121. svc2 := obj2.(*v1.Service)
  1122. if svc2.Spec.SessionAffinityConfig == nil || svc2.Spec.SessionAffinityConfig.ClientIP == nil || svc2.Spec.SessionAffinityConfig.ClientIP.TimeoutSeconds == nil {
  1123. t.Fatalf("Case: %s, unexpected empty SessionAffinityConfig/ClientIP/TimeoutSeconds when session affinity type: %s, got: %v", name, v1.ServiceAffinityClientIP, svc2.Spec.SessionAffinityConfig)
  1124. }
  1125. if *svc2.Spec.SessionAffinityConfig.ClientIP.TimeoutSeconds != v1.DefaultClientIPServiceAffinitySeconds {
  1126. t.Errorf("Case: %s, default TimeoutSeconds should be %d when session affinity type: %s, got: %d", name, v1.DefaultClientIPServiceAffinitySeconds, v1.ServiceAffinityClientIP, *svc2.Spec.SessionAffinityConfig.ClientIP.TimeoutSeconds)
  1127. }
  1128. }
  1129. }
  1130. func TestSetDefaultSecretVolumeSource(t *testing.T) {
  1131. s := v1.PodSpec{}
  1132. s.Volumes = []v1.Volume{
  1133. {
  1134. VolumeSource: v1.VolumeSource{
  1135. Secret: &v1.SecretVolumeSource{},
  1136. },
  1137. },
  1138. }
  1139. pod := &v1.Pod{
  1140. Spec: s,
  1141. }
  1142. output := roundTrip(t, runtime.Object(pod))
  1143. pod2 := output.(*v1.Pod)
  1144. defaultMode := pod2.Spec.Volumes[0].VolumeSource.Secret.DefaultMode
  1145. expectedMode := v1.SecretVolumeSourceDefaultMode
  1146. if defaultMode == nil || *defaultMode != expectedMode {
  1147. t.Errorf("Expected secret DefaultMode %v, got %v", expectedMode, defaultMode)
  1148. }
  1149. }
  1150. func TestSetDefaultConfigMapVolumeSource(t *testing.T) {
  1151. s := v1.PodSpec{}
  1152. s.Volumes = []v1.Volume{
  1153. {
  1154. VolumeSource: v1.VolumeSource{
  1155. ConfigMap: &v1.ConfigMapVolumeSource{},
  1156. },
  1157. },
  1158. }
  1159. pod := &v1.Pod{
  1160. Spec: s,
  1161. }
  1162. output := roundTrip(t, runtime.Object(pod))
  1163. pod2 := output.(*v1.Pod)
  1164. defaultMode := pod2.Spec.Volumes[0].VolumeSource.ConfigMap.DefaultMode
  1165. expectedMode := v1.ConfigMapVolumeSourceDefaultMode
  1166. if defaultMode == nil || *defaultMode != expectedMode {
  1167. t.Errorf("Expected v1.ConfigMap DefaultMode %v, got %v", expectedMode, defaultMode)
  1168. }
  1169. }
  1170. func TestSetDefaultDownwardAPIVolumeSource(t *testing.T) {
  1171. s := v1.PodSpec{}
  1172. s.Volumes = []v1.Volume{
  1173. {
  1174. VolumeSource: v1.VolumeSource{
  1175. DownwardAPI: &v1.DownwardAPIVolumeSource{},
  1176. },
  1177. },
  1178. }
  1179. pod := &v1.Pod{
  1180. Spec: s,
  1181. }
  1182. output := roundTrip(t, runtime.Object(pod))
  1183. pod2 := output.(*v1.Pod)
  1184. defaultMode := pod2.Spec.Volumes[0].VolumeSource.DownwardAPI.DefaultMode
  1185. expectedMode := v1.DownwardAPIVolumeSourceDefaultMode
  1186. if defaultMode == nil || *defaultMode != expectedMode {
  1187. t.Errorf("Expected DownwardAPI DefaultMode %v, got %v", expectedMode, defaultMode)
  1188. }
  1189. }
  1190. func TestSetDefaultProjectedVolumeSource(t *testing.T) {
  1191. s := v1.PodSpec{}
  1192. s.Volumes = []v1.Volume{
  1193. {
  1194. VolumeSource: v1.VolumeSource{
  1195. Projected: &v1.ProjectedVolumeSource{},
  1196. },
  1197. },
  1198. }
  1199. pod := &v1.Pod{
  1200. Spec: s,
  1201. }
  1202. output := roundTrip(t, runtime.Object(pod))
  1203. pod2 := output.(*v1.Pod)
  1204. defaultMode := pod2.Spec.Volumes[0].VolumeSource.Projected.DefaultMode
  1205. expectedMode := v1.ProjectedVolumeSourceDefaultMode
  1206. if defaultMode == nil || *defaultMode != expectedMode {
  1207. t.Errorf("Expected v1.ProjectedVolumeSource DefaultMode %v, got %v", expectedMode, defaultMode)
  1208. }
  1209. }
  1210. func TestSetDefaultSecret(t *testing.T) {
  1211. s := &v1.Secret{}
  1212. obj2 := roundTrip(t, runtime.Object(s))
  1213. s2 := obj2.(*v1.Secret)
  1214. if s2.Type != v1.SecretTypeOpaque {
  1215. t.Errorf("Expected secret type %v, got %v", v1.SecretTypeOpaque, s2.Type)
  1216. }
  1217. }
  1218. func TestSetDefaultPersistentVolume(t *testing.T) {
  1219. fsMode := v1.PersistentVolumeFilesystem
  1220. blockMode := v1.PersistentVolumeBlock
  1221. tests := []struct {
  1222. name string
  1223. volumeMode *v1.PersistentVolumeMode
  1224. expectedVolumeMode v1.PersistentVolumeMode
  1225. }{
  1226. {
  1227. name: "volume mode nil",
  1228. volumeMode: nil,
  1229. expectedVolumeMode: v1.PersistentVolumeFilesystem,
  1230. },
  1231. {
  1232. name: "volume mode filesystem",
  1233. volumeMode: &fsMode,
  1234. expectedVolumeMode: v1.PersistentVolumeFilesystem,
  1235. },
  1236. {
  1237. name: "volume mode block",
  1238. volumeMode: &blockMode,
  1239. expectedVolumeMode: v1.PersistentVolumeBlock,
  1240. },
  1241. }
  1242. for _, test := range tests {
  1243. pv := &v1.PersistentVolume{
  1244. Spec: v1.PersistentVolumeSpec{
  1245. VolumeMode: test.volumeMode,
  1246. },
  1247. }
  1248. obj1 := roundTrip(t, runtime.Object(pv))
  1249. pv1 := obj1.(*v1.PersistentVolume)
  1250. if pv1.Status.Phase != v1.VolumePending {
  1251. t.Errorf("Expected claim phase %v, got %v", v1.ClaimPending, pv1.Status.Phase)
  1252. }
  1253. if pv1.Spec.PersistentVolumeReclaimPolicy != v1.PersistentVolumeReclaimRetain {
  1254. t.Errorf("Expected pv reclaim policy %v, got %v", v1.PersistentVolumeReclaimRetain, pv1.Spec.PersistentVolumeReclaimPolicy)
  1255. }
  1256. if *pv1.Spec.VolumeMode != test.expectedVolumeMode {
  1257. t.Errorf("Test %s failed, Expected VolumeMode: %v, but got %v", test.name, test.volumeMode, *pv1.Spec.VolumeMode)
  1258. }
  1259. }
  1260. }
  1261. func TestSetDefaultPersistentVolumeClaim(t *testing.T) {
  1262. fsMode := v1.PersistentVolumeFilesystem
  1263. blockMode := v1.PersistentVolumeBlock
  1264. tests := []struct {
  1265. name string
  1266. volumeMode *v1.PersistentVolumeMode
  1267. expectedVolumeMode v1.PersistentVolumeMode
  1268. }{
  1269. {
  1270. name: "volume mode nil",
  1271. volumeMode: nil,
  1272. expectedVolumeMode: v1.PersistentVolumeFilesystem,
  1273. },
  1274. {
  1275. name: "volume mode filesystem",
  1276. volumeMode: &fsMode,
  1277. expectedVolumeMode: v1.PersistentVolumeFilesystem,
  1278. },
  1279. {
  1280. name: "volume mode block",
  1281. volumeMode: &blockMode,
  1282. expectedVolumeMode: v1.PersistentVolumeBlock,
  1283. },
  1284. }
  1285. for _, test := range tests {
  1286. pvc := &v1.PersistentVolumeClaim{
  1287. Spec: v1.PersistentVolumeClaimSpec{
  1288. VolumeMode: test.volumeMode,
  1289. },
  1290. }
  1291. obj1 := roundTrip(t, runtime.Object(pvc))
  1292. pvc1 := obj1.(*v1.PersistentVolumeClaim)
  1293. if pvc1.Status.Phase != v1.ClaimPending {
  1294. t.Errorf("Expected claim phase %v, got %v", v1.ClaimPending, pvc1.Status.Phase)
  1295. }
  1296. if *pvc1.Spec.VolumeMode != test.expectedVolumeMode {
  1297. t.Errorf("Test %s failed, Expected VolumeMode: %v, but got %v", test.name, test.volumeMode, *pvc1.Spec.VolumeMode)
  1298. }
  1299. }
  1300. }
  1301. func TestSetDefaultEndpointsProtocol(t *testing.T) {
  1302. in := &v1.Endpoints{Subsets: []v1.EndpointSubset{
  1303. {Ports: []v1.EndpointPort{{}, {Protocol: "UDP"}, {}}},
  1304. }}
  1305. obj := roundTrip(t, runtime.Object(in))
  1306. out := obj.(*v1.Endpoints)
  1307. for i := range out.Subsets {
  1308. for j := range out.Subsets[i].Ports {
  1309. if in.Subsets[i].Ports[j].Protocol == "" {
  1310. if out.Subsets[i].Ports[j].Protocol != v1.ProtocolTCP {
  1311. t.Errorf("Expected protocol %s, got %s", v1.ProtocolTCP, out.Subsets[i].Ports[j].Protocol)
  1312. }
  1313. } else {
  1314. if out.Subsets[i].Ports[j].Protocol != in.Subsets[i].Ports[j].Protocol {
  1315. t.Errorf("Expected protocol %s, got %s", in.Subsets[i].Ports[j].Protocol, out.Subsets[i].Ports[j].Protocol)
  1316. }
  1317. }
  1318. }
  1319. }
  1320. }
  1321. func TestSetDefaultServiceTargetPort(t *testing.T) {
  1322. in := &v1.Service{Spec: v1.ServiceSpec{Ports: []v1.ServicePort{{Port: 1234}}}}
  1323. obj := roundTrip(t, runtime.Object(in))
  1324. out := obj.(*v1.Service)
  1325. if out.Spec.Ports[0].TargetPort != intstr.FromInt(1234) {
  1326. t.Errorf("Expected TargetPort to be defaulted, got %v", out.Spec.Ports[0].TargetPort)
  1327. }
  1328. in = &v1.Service{Spec: v1.ServiceSpec{Ports: []v1.ServicePort{{Port: 1234, TargetPort: intstr.FromInt(5678)}}}}
  1329. obj = roundTrip(t, runtime.Object(in))
  1330. out = obj.(*v1.Service)
  1331. if out.Spec.Ports[0].TargetPort != intstr.FromInt(5678) {
  1332. t.Errorf("Expected TargetPort to be unchanged, got %v", out.Spec.Ports[0].TargetPort)
  1333. }
  1334. }
  1335. func TestSetDefaultServicePort(t *testing.T) {
  1336. // Unchanged if set.
  1337. in := &v1.Service{Spec: v1.ServiceSpec{
  1338. Ports: []v1.ServicePort{
  1339. {Protocol: "UDP", Port: 9376, TargetPort: intstr.FromString("p")},
  1340. {Protocol: "UDP", Port: 8675, TargetPort: intstr.FromInt(309)},
  1341. },
  1342. }}
  1343. out := roundTrip(t, runtime.Object(in)).(*v1.Service)
  1344. if out.Spec.Ports[0].Protocol != v1.ProtocolUDP {
  1345. t.Errorf("Expected protocol %s, got %s", v1.ProtocolUDP, out.Spec.Ports[0].Protocol)
  1346. }
  1347. if out.Spec.Ports[0].TargetPort != intstr.FromString("p") {
  1348. t.Errorf("Expected port %v, got %v", in.Spec.Ports[0].Port, out.Spec.Ports[0].TargetPort)
  1349. }
  1350. if out.Spec.Ports[1].Protocol != v1.ProtocolUDP {
  1351. t.Errorf("Expected protocol %s, got %s", v1.ProtocolUDP, out.Spec.Ports[1].Protocol)
  1352. }
  1353. if out.Spec.Ports[1].TargetPort != intstr.FromInt(309) {
  1354. t.Errorf("Expected port %v, got %v", in.Spec.Ports[1].Port, out.Spec.Ports[1].TargetPort)
  1355. }
  1356. // Defaulted.
  1357. in = &v1.Service{Spec: v1.ServiceSpec{
  1358. Ports: []v1.ServicePort{
  1359. {Protocol: "", Port: 9376, TargetPort: intstr.FromString("")},
  1360. {Protocol: "", Port: 8675, TargetPort: intstr.FromInt(0)},
  1361. },
  1362. }}
  1363. out = roundTrip(t, runtime.Object(in)).(*v1.Service)
  1364. if out.Spec.Ports[0].Protocol != v1.ProtocolTCP {
  1365. t.Errorf("Expected protocol %s, got %s", v1.ProtocolTCP, out.Spec.Ports[0].Protocol)
  1366. }
  1367. if out.Spec.Ports[0].TargetPort != intstr.FromInt(int(in.Spec.Ports[0].Port)) {
  1368. t.Errorf("Expected port %v, got %v", in.Spec.Ports[0].Port, out.Spec.Ports[0].TargetPort)
  1369. }
  1370. if out.Spec.Ports[1].Protocol != v1.ProtocolTCP {
  1371. t.Errorf("Expected protocol %s, got %s", v1.ProtocolTCP, out.Spec.Ports[1].Protocol)
  1372. }
  1373. if out.Spec.Ports[1].TargetPort != intstr.FromInt(int(in.Spec.Ports[1].Port)) {
  1374. t.Errorf("Expected port %v, got %v", in.Spec.Ports[1].Port, out.Spec.Ports[1].TargetPort)
  1375. }
  1376. }
  1377. func TestSetDefaultServiceExternalTraffic(t *testing.T) {
  1378. in := &v1.Service{}
  1379. obj := roundTrip(t, runtime.Object(in))
  1380. out := obj.(*v1.Service)
  1381. if out.Spec.ExternalTrafficPolicy != "" {
  1382. t.Errorf("Expected ExternalTrafficPolicy to be empty, got %v", out.Spec.ExternalTrafficPolicy)
  1383. }
  1384. in = &v1.Service{Spec: v1.ServiceSpec{Type: v1.ServiceTypeNodePort}}
  1385. obj = roundTrip(t, runtime.Object(in))
  1386. out = obj.(*v1.Service)
  1387. if out.Spec.ExternalTrafficPolicy != v1.ServiceExternalTrafficPolicyTypeCluster {
  1388. t.Errorf("Expected ExternalTrafficPolicy to be %v, got %v", v1.ServiceExternalTrafficPolicyTypeCluster, out.Spec.ExternalTrafficPolicy)
  1389. }
  1390. in = &v1.Service{Spec: v1.ServiceSpec{Type: v1.ServiceTypeLoadBalancer}}
  1391. obj = roundTrip(t, runtime.Object(in))
  1392. out = obj.(*v1.Service)
  1393. if out.Spec.ExternalTrafficPolicy != v1.ServiceExternalTrafficPolicyTypeCluster {
  1394. t.Errorf("Expected ExternalTrafficPolicy to be %v, got %v", v1.ServiceExternalTrafficPolicyTypeCluster, out.Spec.ExternalTrafficPolicy)
  1395. }
  1396. }
  1397. func TestSetDefaultNamespace(t *testing.T) {
  1398. s := &v1.Namespace{}
  1399. obj2 := roundTrip(t, runtime.Object(s))
  1400. s2 := obj2.(*v1.Namespace)
  1401. if s2.Status.Phase != v1.NamespaceActive {
  1402. t.Errorf("Expected phase %v, got %v", v1.NamespaceActive, s2.Status.Phase)
  1403. }
  1404. }
  1405. func TestSetDefaultPodSpecHostNetwork(t *testing.T) {
  1406. portNum := int32(8080)
  1407. s := v1.PodSpec{}
  1408. s.HostNetwork = true
  1409. s.Containers = []v1.Container{
  1410. {
  1411. Ports: []v1.ContainerPort{
  1412. {
  1413. ContainerPort: portNum,
  1414. },
  1415. },
  1416. },
  1417. }
  1418. s.InitContainers = []v1.Container{
  1419. {
  1420. Ports: []v1.ContainerPort{
  1421. {
  1422. ContainerPort: portNum,
  1423. },
  1424. },
  1425. },
  1426. }
  1427. pod := &v1.Pod{
  1428. Spec: s,
  1429. }
  1430. obj2 := roundTrip(t, runtime.Object(pod))
  1431. pod2 := obj2.(*v1.Pod)
  1432. s2 := pod2.Spec
  1433. hostPortNum := s2.Containers[0].Ports[0].HostPort
  1434. if hostPortNum != portNum {
  1435. t.Errorf("Expected container port to be defaulted, was made %d instead of %d", hostPortNum, portNum)
  1436. }
  1437. hostPortNum = s2.InitContainers[0].Ports[0].HostPort
  1438. if hostPortNum != portNum {
  1439. t.Errorf("Expected container port to be defaulted, was made %d instead of %d", hostPortNum, portNum)
  1440. }
  1441. }
  1442. func TestSetDefaultNodeStatusAllocatable(t *testing.T) {
  1443. capacity := v1.ResourceList{
  1444. v1.ResourceCPU: resource.MustParse("1000m"),
  1445. v1.ResourceMemory: resource.MustParse("10G"),
  1446. }
  1447. allocatable := v1.ResourceList{
  1448. v1.ResourceCPU: resource.MustParse("500m"),
  1449. v1.ResourceMemory: resource.MustParse("5G"),
  1450. }
  1451. tests := []struct {
  1452. capacity v1.ResourceList
  1453. allocatable v1.ResourceList
  1454. expectedAllocatable v1.ResourceList
  1455. }{{ // Everything set, no defaulting.
  1456. capacity: capacity,
  1457. allocatable: allocatable,
  1458. expectedAllocatable: allocatable,
  1459. }, { // Allocatable set, no defaulting.
  1460. capacity: nil,
  1461. allocatable: allocatable,
  1462. expectedAllocatable: allocatable,
  1463. }, { // Capacity set, allocatable defaults to capacity.
  1464. capacity: capacity,
  1465. allocatable: nil,
  1466. expectedAllocatable: capacity,
  1467. }, { // Nothing set, allocatable "defaults" to capacity.
  1468. capacity: nil,
  1469. allocatable: nil,
  1470. expectedAllocatable: nil,
  1471. }}
  1472. copyResourceList := func(rl v1.ResourceList) v1.ResourceList {
  1473. if rl == nil {
  1474. return nil
  1475. }
  1476. copy := make(v1.ResourceList, len(rl))
  1477. for k, v := range rl {
  1478. copy[k] = v.DeepCopy()
  1479. }
  1480. return copy
  1481. }
  1482. resourceListsEqual := func(a v1.ResourceList, b v1.ResourceList) bool {
  1483. if len(a) != len(b) {
  1484. return false
  1485. }
  1486. for k, v := range a {
  1487. vb, found := b[k]
  1488. if !found {
  1489. return false
  1490. }
  1491. if v.Cmp(vb) != 0 {
  1492. return false
  1493. }
  1494. }
  1495. return true
  1496. }
  1497. for i, testcase := range tests {
  1498. node := v1.Node{
  1499. Status: v1.NodeStatus{
  1500. Capacity: copyResourceList(testcase.capacity),
  1501. Allocatable: copyResourceList(testcase.allocatable),
  1502. },
  1503. }
  1504. node2 := roundTrip(t, runtime.Object(&node)).(*v1.Node)
  1505. actual := node2.Status.Allocatable
  1506. expected := testcase.expectedAllocatable
  1507. if !resourceListsEqual(expected, actual) {
  1508. t.Errorf("[%d] Expected v1.NodeStatus.Allocatable: %+v; Got: %+v", i, expected, actual)
  1509. }
  1510. }
  1511. }
  1512. func TestSetDefaultObjectFieldSelectorAPIVersion(t *testing.T) {
  1513. s := v1.PodSpec{
  1514. Containers: []v1.Container{
  1515. {
  1516. Env: []v1.EnvVar{
  1517. {
  1518. ValueFrom: &v1.EnvVarSource{
  1519. FieldRef: &v1.ObjectFieldSelector{},
  1520. },
  1521. },
  1522. },
  1523. },
  1524. },
  1525. }
  1526. pod := &v1.Pod{
  1527. Spec: s,
  1528. }
  1529. obj2 := roundTrip(t, runtime.Object(pod))
  1530. pod2 := obj2.(*v1.Pod)
  1531. s2 := pod2.Spec
  1532. apiVersion := s2.Containers[0].Env[0].ValueFrom.FieldRef.APIVersion
  1533. if apiVersion != "v1" {
  1534. t.Errorf("Expected default APIVersion v1, got: %v", apiVersion)
  1535. }
  1536. }
  1537. func TestSetMinimumScalePod(t *testing.T) {
  1538. // verify we default if limits are specified (and that request=0 is preserved)
  1539. s := v1.PodSpec{}
  1540. s.Containers = []v1.Container{
  1541. {
  1542. Resources: v1.ResourceRequirements{
  1543. Requests: v1.ResourceList{
  1544. v1.ResourceMemory: resource.MustParse("1n"),
  1545. },
  1546. Limits: v1.ResourceList{
  1547. v1.ResourceCPU: resource.MustParse("2n"),
  1548. },
  1549. },
  1550. },
  1551. }
  1552. s.InitContainers = []v1.Container{
  1553. {
  1554. Resources: v1.ResourceRequirements{
  1555. Requests: v1.ResourceList{
  1556. v1.ResourceMemory: resource.MustParse("1n"),
  1557. },
  1558. Limits: v1.ResourceList{
  1559. v1.ResourceCPU: resource.MustParse("2n"),
  1560. },
  1561. },
  1562. },
  1563. }
  1564. pod := &v1.Pod{
  1565. Spec: s,
  1566. }
  1567. corev1.SetObjectDefaults_Pod(pod)
  1568. if expect := resource.MustParse("1m"); expect.Cmp(pod.Spec.Containers[0].Resources.Requests[v1.ResourceMemory]) != 0 {
  1569. t.Errorf("did not round resources: %#v", pod.Spec.Containers[0].Resources)
  1570. }
  1571. if expect := resource.MustParse("1m"); expect.Cmp(pod.Spec.InitContainers[0].Resources.Requests[v1.ResourceMemory]) != 0 {
  1572. t.Errorf("did not round resources: %#v", pod.Spec.InitContainers[0].Resources)
  1573. }
  1574. }
  1575. func TestSetDefaultRequestsPod(t *testing.T) {
  1576. // verify we default if limits are specified (and that request=0 is preserved)
  1577. s := v1.PodSpec{}
  1578. s.Containers = []v1.Container{
  1579. {
  1580. Resources: v1.ResourceRequirements{
  1581. Requests: v1.ResourceList{
  1582. v1.ResourceMemory: resource.MustParse("0"),
  1583. },
  1584. Limits: v1.ResourceList{
  1585. v1.ResourceCPU: resource.MustParse("100m"),
  1586. v1.ResourceMemory: resource.MustParse("1Gi"),
  1587. },
  1588. },
  1589. },
  1590. }
  1591. s.InitContainers = []v1.Container{
  1592. {
  1593. Resources: v1.ResourceRequirements{
  1594. Requests: v1.ResourceList{
  1595. v1.ResourceMemory: resource.MustParse("0"),
  1596. },
  1597. Limits: v1.ResourceList{
  1598. v1.ResourceCPU: resource.MustParse("100m"),
  1599. v1.ResourceMemory: resource.MustParse("1Gi"),
  1600. },
  1601. },
  1602. },
  1603. }
  1604. pod := &v1.Pod{
  1605. Spec: s,
  1606. }
  1607. output := roundTrip(t, runtime.Object(pod))
  1608. pod2 := output.(*v1.Pod)
  1609. defaultRequest := pod2.Spec.Containers[0].Resources.Requests
  1610. if requestValue := defaultRequest[v1.ResourceCPU]; requestValue.String() != "100m" {
  1611. t.Errorf("Expected request cpu: %s, got: %s", "100m", requestValue.String())
  1612. }
  1613. if requestValue := defaultRequest[v1.ResourceMemory]; requestValue.String() != "0" {
  1614. t.Errorf("Expected request memory: %s, got: %s", "0", requestValue.String())
  1615. }
  1616. defaultRequest = pod2.Spec.InitContainers[0].Resources.Requests
  1617. if requestValue := defaultRequest[v1.ResourceCPU]; requestValue.String() != "100m" {
  1618. t.Errorf("Expected request cpu: %s, got: %s", "100m", requestValue.String())
  1619. }
  1620. if requestValue := defaultRequest[v1.ResourceMemory]; requestValue.String() != "0" {
  1621. t.Errorf("Expected request memory: %s, got: %s", "0", requestValue.String())
  1622. }
  1623. // verify we do nothing if no limits are specified
  1624. s = v1.PodSpec{}
  1625. s.Containers = []v1.Container{{}}
  1626. s.InitContainers = []v1.Container{{}}
  1627. pod = &v1.Pod{
  1628. Spec: s,
  1629. }
  1630. output = roundTrip(t, runtime.Object(pod))
  1631. pod2 = output.(*v1.Pod)
  1632. defaultRequest = pod2.Spec.Containers[0].Resources.Requests
  1633. if requestValue := defaultRequest[v1.ResourceCPU]; requestValue.String() != "0" {
  1634. t.Errorf("Expected 0 request value, got: %s", requestValue.String())
  1635. }
  1636. defaultRequest = pod2.Spec.InitContainers[0].Resources.Requests
  1637. if requestValue := defaultRequest[v1.ResourceCPU]; requestValue.String() != "0" {
  1638. t.Errorf("Expected 0 request value, got: %s", requestValue.String())
  1639. }
  1640. }
  1641. func TestDefaultRequestIsNotSetForReplicationController(t *testing.T) {
  1642. s := v1.PodSpec{}
  1643. s.Containers = []v1.Container{
  1644. {
  1645. Resources: v1.ResourceRequirements{
  1646. Limits: v1.ResourceList{
  1647. v1.ResourceCPU: resource.MustParse("100m"),
  1648. },
  1649. },
  1650. },
  1651. }
  1652. rc := &v1.ReplicationController{
  1653. Spec: v1.ReplicationControllerSpec{
  1654. Replicas: utilpointer.Int32Ptr(3),
  1655. Template: &v1.PodTemplateSpec{
  1656. ObjectMeta: metav1.ObjectMeta{
  1657. Labels: map[string]string{
  1658. "foo": "bar",
  1659. },
  1660. },
  1661. Spec: s,
  1662. },
  1663. },
  1664. }
  1665. output := roundTrip(t, runtime.Object(rc))
  1666. rc2 := output.(*v1.ReplicationController)
  1667. defaultRequest := rc2.Spec.Template.Spec.Containers[0].Resources.Requests
  1668. requestValue := defaultRequest[v1.ResourceCPU]
  1669. if requestValue.String() != "0" {
  1670. t.Errorf("Expected 0 request value, got: %s", requestValue.String())
  1671. }
  1672. }
  1673. func TestSetDefaultLimitRangeItem(t *testing.T) {
  1674. limitRange := &v1.LimitRange{
  1675. ObjectMeta: metav1.ObjectMeta{
  1676. Name: "test-defaults",
  1677. },
  1678. Spec: v1.LimitRangeSpec{
  1679. Limits: []v1.LimitRangeItem{{
  1680. Type: v1.LimitTypeContainer,
  1681. Max: v1.ResourceList{
  1682. v1.ResourceCPU: resource.MustParse("100m"),
  1683. },
  1684. Min: v1.ResourceList{
  1685. v1.ResourceMemory: resource.MustParse("100Mi"),
  1686. },
  1687. Default: v1.ResourceList{},
  1688. DefaultRequest: v1.ResourceList{},
  1689. }},
  1690. },
  1691. }
  1692. output := roundTrip(t, runtime.Object(limitRange))
  1693. limitRange2 := output.(*v1.LimitRange)
  1694. defaultLimit := limitRange2.Spec.Limits[0].Default
  1695. defaultRequest := limitRange2.Spec.Limits[0].DefaultRequest
  1696. // verify that default cpu was set to the max
  1697. defaultValue := defaultLimit[v1.ResourceCPU]
  1698. if defaultValue.String() != "100m" {
  1699. t.Errorf("Expected default cpu: %s, got: %s", "100m", defaultValue.String())
  1700. }
  1701. // verify that default request was set to the limit
  1702. requestValue := defaultRequest[v1.ResourceCPU]
  1703. if requestValue.String() != "100m" {
  1704. t.Errorf("Expected request cpu: %s, got: %s", "100m", requestValue.String())
  1705. }
  1706. // verify that if a min is provided, it will be the default if no limit is specified
  1707. requestMinValue := defaultRequest[v1.ResourceMemory]
  1708. if requestMinValue.String() != "100Mi" {
  1709. t.Errorf("Expected request memory: %s, got: %s", "100Mi", requestMinValue.String())
  1710. }
  1711. }
  1712. func TestSetDefaultProbe(t *testing.T) {
  1713. originalProbe := v1.Probe{}
  1714. expectedProbe := v1.Probe{
  1715. InitialDelaySeconds: 0,
  1716. TimeoutSeconds: 1,
  1717. PeriodSeconds: 10,
  1718. SuccessThreshold: 1,
  1719. FailureThreshold: 3,
  1720. }
  1721. pod := &v1.Pod{
  1722. Spec: v1.PodSpec{
  1723. Containers: []v1.Container{{LivenessProbe: &originalProbe}},
  1724. },
  1725. }
  1726. output := roundTrip(t, runtime.Object(pod)).(*v1.Pod)
  1727. actualProbe := *output.Spec.Containers[0].LivenessProbe
  1728. if actualProbe != expectedProbe {
  1729. t.Errorf("Expected probe: %+v\ngot: %+v\n", expectedProbe, actualProbe)
  1730. }
  1731. }
  1732. func TestSetDefaultSchedulerName(t *testing.T) {
  1733. pod := &v1.Pod{}
  1734. output := roundTrip(t, runtime.Object(pod)).(*v1.Pod)
  1735. if output.Spec.SchedulerName != v1.DefaultSchedulerName {
  1736. t.Errorf("Expected scheduler name: %+v\ngot: %+v\n", v1.DefaultSchedulerName, output.Spec.SchedulerName)
  1737. }
  1738. }
  1739. func TestSetDefaultHostPathVolumeSource(t *testing.T) {
  1740. s := v1.PodSpec{}
  1741. s.Volumes = []v1.Volume{
  1742. {
  1743. VolumeSource: v1.VolumeSource{
  1744. HostPath: &v1.HostPathVolumeSource{Path: "foo"},
  1745. },
  1746. },
  1747. }
  1748. pod := &v1.Pod{
  1749. Spec: s,
  1750. }
  1751. output := roundTrip(t, runtime.Object(pod))
  1752. pod2 := output.(*v1.Pod)
  1753. defaultType := pod2.Spec.Volumes[0].VolumeSource.HostPath.Type
  1754. expectedType := v1.HostPathUnset
  1755. if defaultType == nil || *defaultType != expectedType {
  1756. t.Errorf("Expected v1.HostPathVolumeSource default type %v, got %v", expectedType, defaultType)
  1757. }
  1758. }
  1759. func TestSetDefaultEnableServiceLinks(t *testing.T) {
  1760. pod := &v1.Pod{}
  1761. output := roundTrip(t, runtime.Object(pod)).(*v1.Pod)
  1762. if output.Spec.EnableServiceLinks == nil || *output.Spec.EnableServiceLinks != v1.DefaultEnableServiceLinks {
  1763. t.Errorf("Expected enableServiceLinks value: %+v\ngot: %+v\n", v1.DefaultEnableServiceLinks, *output.Spec.EnableServiceLinks)
  1764. }
  1765. }