1
16
17 package v1_test
18
19 import (
20 "encoding/json"
21 "fmt"
22 "reflect"
23 "strings"
24 "testing"
25
26 "github.com/google/go-cmp/cmp"
27 v1 "k8s.io/api/core/v1"
28 "k8s.io/apimachinery/pkg/api/resource"
29 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
30 "k8s.io/apimachinery/pkg/runtime"
31 "k8s.io/apimachinery/pkg/util/intstr"
32 utilfeature "k8s.io/apiserver/pkg/util/feature"
33 featuregatetesting "k8s.io/component-base/featuregate/testing"
34 "k8s.io/kubernetes/pkg/api/legacyscheme"
35 corev1 "k8s.io/kubernetes/pkg/apis/core/v1"
36 "k8s.io/kubernetes/pkg/features"
37 utilpointer "k8s.io/utils/pointer"
38
39
40 _ "k8s.io/kubernetes/pkg/apis/core/install"
41 )
42
43
44
45 func TestWorkloadDefaults(t *testing.T) {
46 t.Run("enabled_features", func(t *testing.T) { testWorkloadDefaults(t, true) })
47 t.Run("disabled_features", func(t *testing.T) { testWorkloadDefaults(t, false) })
48 }
49 func testWorkloadDefaults(t *testing.T, featuresEnabled bool) {
50 allFeatures := utilfeature.DefaultFeatureGate.DeepCopy().GetAll()
51 for feature, featureSpec := range allFeatures {
52 if !featureSpec.LockToDefault {
53 defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, feature, featuresEnabled)()
54 }
55 }
56
57
58
59
60
61 expectedDefaults := map[string]string{
62 ".Spec.Containers[0].Env[0].ValueFrom.FieldRef.APIVersion": `"v1"`,
63 ".Spec.Containers[0].ImagePullPolicy": `"IfNotPresent"`,
64 ".Spec.Containers[0].Lifecycle.PostStart.HTTPGet.Path": `"/"`,
65 ".Spec.Containers[0].Lifecycle.PostStart.HTTPGet.Scheme": `"HTTP"`,
66 ".Spec.Containers[0].Lifecycle.PreStop.HTTPGet.Path": `"/"`,
67 ".Spec.Containers[0].Lifecycle.PreStop.HTTPGet.Scheme": `"HTTP"`,
68 ".Spec.Containers[0].LivenessProbe.FailureThreshold": `3`,
69 ".Spec.Containers[0].LivenessProbe.ProbeHandler.HTTPGet.Path": `"/"`,
70 ".Spec.Containers[0].LivenessProbe.ProbeHandler.HTTPGet.Scheme": `"HTTP"`,
71 ".Spec.Containers[0].LivenessProbe.PeriodSeconds": `10`,
72 ".Spec.Containers[0].LivenessProbe.SuccessThreshold": `1`,
73 ".Spec.Containers[0].LivenessProbe.TimeoutSeconds": `1`,
74 ".Spec.Containers[0].Ports[0].Protocol": `"TCP"`,
75 ".Spec.Containers[0].ReadinessProbe.FailureThreshold": `3`,
76 ".Spec.Containers[0].ReadinessProbe.ProbeHandler.HTTPGet.Path": `"/"`,
77 ".Spec.Containers[0].ReadinessProbe.ProbeHandler.HTTPGet.Scheme": `"HTTP"`,
78 ".Spec.Containers[0].ReadinessProbe.PeriodSeconds": `10`,
79 ".Spec.Containers[0].ReadinessProbe.SuccessThreshold": `1`,
80 ".Spec.Containers[0].ReadinessProbe.TimeoutSeconds": `1`,
81 ".Spec.Containers[0].StartupProbe.FailureThreshold": "3",
82 ".Spec.Containers[0].StartupProbe.ProbeHandler.HTTPGet.Path": `"/"`,
83 ".Spec.Containers[0].StartupProbe.ProbeHandler.HTTPGet.Scheme": `"HTTP"`,
84 ".Spec.Containers[0].StartupProbe.PeriodSeconds": "10",
85 ".Spec.Containers[0].StartupProbe.SuccessThreshold": "1",
86 ".Spec.Containers[0].StartupProbe.TimeoutSeconds": "1",
87 ".Spec.Containers[0].TerminationMessagePath": `"/dev/termination-log"`,
88 ".Spec.Containers[0].TerminationMessagePolicy": `"File"`,
89 ".Spec.Containers[0].LivenessProbe.ProbeHandler.GRPC.Service": `""`,
90 ".Spec.Containers[0].ReadinessProbe.ProbeHandler.GRPC.Service": `""`,
91 ".Spec.Containers[0].StartupProbe.ProbeHandler.GRPC.Service": `""`,
92 ".Spec.DNSPolicy": `"ClusterFirst"`,
93 ".Spec.EphemeralContainers[0].EphemeralContainerCommon.LivenessProbe.ProbeHandler.HTTPGet.Path": `"/"`,
94 ".Spec.EphemeralContainers[0].EphemeralContainerCommon.LivenessProbe.ProbeHandler.HTTPGet.Scheme": `"HTTP"`,
95 ".Spec.EphemeralContainers[0].EphemeralContainerCommon.ReadinessProbe.ProbeHandler.HTTPGet.Path": `"/"`,
96 ".Spec.EphemeralContainers[0].EphemeralContainerCommon.ReadinessProbe.ProbeHandler.HTTPGet.Scheme": `"HTTP"`,
97 ".Spec.EphemeralContainers[0].EphemeralContainerCommon.StartupProbe.ProbeHandler.HTTPGet.Path": `"/"`,
98 ".Spec.EphemeralContainers[0].EphemeralContainerCommon.StartupProbe.ProbeHandler.HTTPGet.Scheme": `"HTTP"`,
99 ".Spec.InitContainers[0].LivenessProbe.ProbeHandler.HTTPGet.Path": `"/"`,
100 ".Spec.InitContainers[0].LivenessProbe.ProbeHandler.HTTPGet.Scheme": `"HTTP"`,
101 ".Spec.InitContainers[0].ReadinessProbe.ProbeHandler.HTTPGet.Path": `"/"`,
102 ".Spec.InitContainers[0].ReadinessProbe.ProbeHandler.HTTPGet.Scheme": `"HTTP"`,
103 ".Spec.InitContainers[0].StartupProbe.ProbeHandler.HTTPGet.Path": `"/"`,
104 ".Spec.InitContainers[0].StartupProbe.ProbeHandler.HTTPGet.Scheme": `"HTTP"`,
105 ".Spec.EphemeralContainers[0].EphemeralContainerCommon.Env[0].ValueFrom.FieldRef.APIVersion": `"v1"`,
106 ".Spec.EphemeralContainers[0].EphemeralContainerCommon.ImagePullPolicy": `"IfNotPresent"`,
107 ".Spec.EphemeralContainers[0].EphemeralContainerCommon.Lifecycle.PostStart.HTTPGet.Path": `"/"`,
108 ".Spec.EphemeralContainers[0].EphemeralContainerCommon.Lifecycle.PostStart.HTTPGet.Scheme": `"HTTP"`,
109 ".Spec.EphemeralContainers[0].EphemeralContainerCommon.Lifecycle.PreStop.HTTPGet.Path": `"/"`,
110 ".Spec.EphemeralContainers[0].EphemeralContainerCommon.Lifecycle.PreStop.HTTPGet.Scheme": `"HTTP"`,
111 ".Spec.EphemeralContainers[0].EphemeralContainerCommon.LivenessProbe.FailureThreshold": "3",
112 ".Spec.EphemeralContainers[0].EphemeralContainerCommon.LivenessProbe.ProbeHandler.GRPC.Service": `""`,
113 ".Spec.EphemeralContainers[0].EphemeralContainerCommon.LivenessProbe.PeriodSeconds": "10",
114 ".Spec.EphemeralContainers[0].EphemeralContainerCommon.LivenessProbe.SuccessThreshold": "1",
115 ".Spec.EphemeralContainers[0].EphemeralContainerCommon.LivenessProbe.TimeoutSeconds": "1",
116 ".Spec.EphemeralContainers[0].EphemeralContainerCommon.Ports[0].Protocol": `"TCP"`,
117 ".Spec.EphemeralContainers[0].EphemeralContainerCommon.ReadinessProbe.FailureThreshold": "3",
118 ".Spec.EphemeralContainers[0].EphemeralContainerCommon.ReadinessProbe.ProbeHandler.GRPC.Service": `""`,
119 ".Spec.EphemeralContainers[0].EphemeralContainerCommon.ReadinessProbe.PeriodSeconds": "10",
120 ".Spec.EphemeralContainers[0].EphemeralContainerCommon.ReadinessProbe.SuccessThreshold": "1",
121 ".Spec.EphemeralContainers[0].EphemeralContainerCommon.ReadinessProbe.TimeoutSeconds": "1",
122 ".Spec.EphemeralContainers[0].EphemeralContainerCommon.StartupProbe.FailureThreshold": "3",
123 ".Spec.EphemeralContainers[0].EphemeralContainerCommon.StartupProbe.ProbeHandler.GRPC.Service": `""`,
124 ".Spec.EphemeralContainers[0].EphemeralContainerCommon.StartupProbe.PeriodSeconds": "10",
125 ".Spec.EphemeralContainers[0].EphemeralContainerCommon.StartupProbe.SuccessThreshold": "1",
126 ".Spec.EphemeralContainers[0].EphemeralContainerCommon.StartupProbe.TimeoutSeconds": "1",
127 ".Spec.EphemeralContainers[0].EphemeralContainerCommon.TerminationMessagePath": `"/dev/termination-log"`,
128 ".Spec.EphemeralContainers[0].EphemeralContainerCommon.TerminationMessagePolicy": `"File"`,
129 ".Spec.InitContainers[0].Env[0].ValueFrom.FieldRef.APIVersion": `"v1"`,
130 ".Spec.InitContainers[0].ImagePullPolicy": `"IfNotPresent"`,
131 ".Spec.InitContainers[0].Lifecycle.PostStart.HTTPGet.Path": `"/"`,
132 ".Spec.InitContainers[0].Lifecycle.PostStart.HTTPGet.Scheme": `"HTTP"`,
133 ".Spec.InitContainers[0].Lifecycle.PreStop.HTTPGet.Path": `"/"`,
134 ".Spec.InitContainers[0].Lifecycle.PreStop.HTTPGet.Scheme": `"HTTP"`,
135 ".Spec.InitContainers[0].LivenessProbe.FailureThreshold": `3`,
136 ".Spec.InitContainers[0].LivenessProbe.ProbeHandler.GRPC.Service": `""`,
137 ".Spec.InitContainers[0].LivenessProbe.PeriodSeconds": `10`,
138 ".Spec.InitContainers[0].LivenessProbe.SuccessThreshold": `1`,
139 ".Spec.InitContainers[0].LivenessProbe.TimeoutSeconds": `1`,
140 ".Spec.InitContainers[0].Ports[0].Protocol": `"TCP"`,
141 ".Spec.InitContainers[0].ReadinessProbe.FailureThreshold": `3`,
142 ".Spec.InitContainers[0].ReadinessProbe.ProbeHandler.GRPC.Service": `""`,
143 ".Spec.InitContainers[0].ReadinessProbe.PeriodSeconds": `10`,
144 ".Spec.InitContainers[0].ReadinessProbe.SuccessThreshold": `1`,
145 ".Spec.InitContainers[0].ReadinessProbe.TimeoutSeconds": `1`,
146 ".Spec.InitContainers[0].StartupProbe.FailureThreshold": "3",
147 ".Spec.InitContainers[0].StartupProbe.ProbeHandler.GRPC.Service": `""`,
148 ".Spec.InitContainers[0].StartupProbe.PeriodSeconds": "10",
149 ".Spec.InitContainers[0].StartupProbe.SuccessThreshold": "1",
150 ".Spec.InitContainers[0].StartupProbe.TimeoutSeconds": "1",
151 ".Spec.InitContainers[0].TerminationMessagePath": `"/dev/termination-log"`,
152 ".Spec.InitContainers[0].TerminationMessagePolicy": `"File"`,
153 ".Spec.RestartPolicy": `"Always"`,
154 ".Spec.SchedulerName": `"default-scheduler"`,
155 ".Spec.SecurityContext": `{}`,
156 ".Spec.TerminationGracePeriodSeconds": `30`,
157 ".Spec.Volumes[0].VolumeSource.AzureDisk.CachingMode": `"ReadWrite"`,
158 ".Spec.Volumes[0].VolumeSource.AzureDisk.FSType": `"ext4"`,
159 ".Spec.Volumes[0].VolumeSource.AzureDisk.Kind": `"Shared"`,
160 ".Spec.Volumes[0].VolumeSource.AzureDisk.ReadOnly": `false`,
161 ".Spec.Volumes[0].VolumeSource.ConfigMap.DefaultMode": `420`,
162 ".Spec.Volumes[0].VolumeSource.DownwardAPI.DefaultMode": `420`,
163 ".Spec.Volumes[0].VolumeSource.DownwardAPI.Items[0].FieldRef.APIVersion": `"v1"`,
164 ".Spec.Volumes[0].VolumeSource.EmptyDir": `{}`,
165 ".Spec.Volumes[0].VolumeSource.Ephemeral.VolumeClaimTemplate.Spec.VolumeMode": `"Filesystem"`,
166 ".Spec.Volumes[0].VolumeSource.HostPath.Type": `""`,
167 ".Spec.Volumes[0].VolumeSource.ISCSI.ISCSIInterface": `"default"`,
168 ".Spec.Volumes[0].VolumeSource.Projected.DefaultMode": `420`,
169 ".Spec.Volumes[0].VolumeSource.Projected.Sources[0].DownwardAPI.Items[0].FieldRef.APIVersion": `"v1"`,
170 ".Spec.Volumes[0].VolumeSource.Projected.Sources[0].ServiceAccountToken.ExpirationSeconds": `3600`,
171 ".Spec.Volumes[0].VolumeSource.RBD.Keyring": `"/etc/ceph/keyring"`,
172 ".Spec.Volumes[0].VolumeSource.RBD.RBDPool": `"rbd"`,
173 ".Spec.Volumes[0].VolumeSource.RBD.RadosUser": `"admin"`,
174 ".Spec.Volumes[0].VolumeSource.ScaleIO.FSType": `"xfs"`,
175 ".Spec.Volumes[0].VolumeSource.ScaleIO.StorageMode": `"ThinProvisioned"`,
176 ".Spec.Volumes[0].VolumeSource.Secret.DefaultMode": `420`,
177 }
178 t.Run("empty PodTemplateSpec", func(t *testing.T) {
179 rc := &v1.ReplicationController{Spec: v1.ReplicationControllerSpec{Template: &v1.PodTemplateSpec{}}}
180 template := rc.Spec.Template
181 defaults := detectDefaults(t, rc, reflect.ValueOf(template))
182 if !reflect.DeepEqual(expectedDefaults, defaults) {
183 t.Errorf("Defaults for PodTemplateSpec changed. This can cause spurious rollouts of workloads on API server upgrade.")
184 t.Logf(cmp.Diff(expectedDefaults, defaults))
185 }
186 })
187 t.Run("hostnet PodTemplateSpec with ports", func(t *testing.T) {
188 rc := &v1.ReplicationController{
189 Spec: v1.ReplicationControllerSpec{
190 Template: &v1.PodTemplateSpec{
191 Spec: v1.PodSpec{
192 HostNetwork: true,
193 Containers: []v1.Container{{
194 Ports: []v1.ContainerPort{{
195 ContainerPort: 12345,
196 Protocol: v1.ProtocolTCP,
197 }},
198 }},
199 },
200 },
201 },
202 }
203 template := rc.Spec.Template
204 defaults := detectDefaults(t, rc, reflect.ValueOf(template))
205 expected := func() map[string]string {
206
207 m := map[string]string{
208 ".Spec.HostNetwork": "true",
209 ".Spec.Containers[0].Ports[0].ContainerPort": "12345",
210 }
211 if utilfeature.DefaultFeatureGate.Enabled(features.DefaultHostNetworkHostPortsInPodTemplates) {
212 m[".Spec.Containers"] = `[{"name":"","ports":[{"hostPort":12345,"containerPort":12345,"protocol":"TCP"}],"resources":{},"terminationMessagePath":"/dev/termination-log","terminationMessagePolicy":"File","imagePullPolicy":"IfNotPresent"}]`
213 m[".Spec.Containers[0].Ports"] = `[{"hostPort":12345,"containerPort":12345,"protocol":"TCP"}]`
214 m[".Spec.Containers[0].Ports[0].HostPort"] = "12345"
215 } else {
216 m[".Spec.Containers"] = `[{"name":"","ports":[{"containerPort":12345,"protocol":"TCP"}],"resources":{},"terminationMessagePath":"/dev/termination-log","terminationMessagePolicy":"File","imagePullPolicy":"IfNotPresent"}]`
217 m[".Spec.Containers[0].Ports"] = `[{"containerPort":12345,"protocol":"TCP"}]`
218 }
219 for k, v := range expectedDefaults {
220 if _, found := m[k]; !found {
221 m[k] = v
222 }
223 }
224 return m
225 }()
226 if !reflect.DeepEqual(expected, defaults) {
227 t.Errorf("Defaults for PodTemplateSpec changed. This can cause spurious rollouts of workloads on API server upgrade.")
228 t.Logf(cmp.Diff(expected, defaults))
229 }
230 })
231 }
232
233
234
235 func TestPodDefaults(t *testing.T) {
236 t.Run("enabled_features", func(t *testing.T) { testPodDefaults(t, true) })
237 t.Run("disabled_features", func(t *testing.T) { testPodDefaults(t, false) })
238 }
239 func testPodDefaults(t *testing.T, featuresEnabled bool) {
240 features := utilfeature.DefaultFeatureGate.DeepCopy().GetAll()
241 for feature, featureSpec := range features {
242 if !featureSpec.LockToDefault {
243 defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, feature, featuresEnabled)()
244 }
245 }
246 pod := &v1.Pod{}
247
248
249
250
251
252 expectedDefaults := map[string]string{
253 ".Spec.Containers[0].Env[0].ValueFrom.FieldRef.APIVersion": `"v1"`,
254 ".Spec.Containers[0].ImagePullPolicy": `"IfNotPresent"`,
255 ".Spec.Containers[0].Lifecycle.PostStart.HTTPGet.Path": `"/"`,
256 ".Spec.Containers[0].Lifecycle.PostStart.HTTPGet.Scheme": `"HTTP"`,
257 ".Spec.Containers[0].Lifecycle.PreStop.HTTPGet.Path": `"/"`,
258 ".Spec.Containers[0].Lifecycle.PreStop.HTTPGet.Scheme": `"HTTP"`,
259 ".Spec.Containers[0].LivenessProbe.FailureThreshold": `3`,
260 ".Spec.Containers[0].LivenessProbe.ProbeHandler.HTTPGet.Path": `"/"`,
261 ".Spec.Containers[0].LivenessProbe.ProbeHandler.HTTPGet.Scheme": `"HTTP"`,
262 ".Spec.Containers[0].LivenessProbe.PeriodSeconds": `10`,
263 ".Spec.Containers[0].LivenessProbe.SuccessThreshold": `1`,
264 ".Spec.Containers[0].LivenessProbe.TimeoutSeconds": `1`,
265 ".Spec.Containers[0].Ports[0].Protocol": `"TCP"`,
266 ".Spec.Containers[0].ReadinessProbe.FailureThreshold": `3`,
267 ".Spec.Containers[0].ReadinessProbe.ProbeHandler.HTTPGet.Path": `"/"`,
268 ".Spec.Containers[0].ReadinessProbe.ProbeHandler.HTTPGet.Scheme": `"HTTP"`,
269 ".Spec.Containers[0].ReadinessProbe.PeriodSeconds": `10`,
270 ".Spec.Containers[0].ReadinessProbe.SuccessThreshold": `1`,
271 ".Spec.Containers[0].ReadinessProbe.TimeoutSeconds": `1`,
272 ".Spec.Containers[0].Resources.Requests": `{"":"0"}`,
273 ".Spec.Containers[0].StartupProbe.FailureThreshold": "3",
274 ".Spec.Containers[0].StartupProbe.ProbeHandler.HTTPGet.Path": `"/"`,
275 ".Spec.Containers[0].StartupProbe.ProbeHandler.HTTPGet.Scheme": `"HTTP"`,
276 ".Spec.Containers[0].StartupProbe.PeriodSeconds": "10",
277 ".Spec.Containers[0].StartupProbe.SuccessThreshold": "1",
278 ".Spec.Containers[0].StartupProbe.TimeoutSeconds": "1",
279 ".Spec.Containers[0].TerminationMessagePath": `"/dev/termination-log"`,
280 ".Spec.Containers[0].TerminationMessagePolicy": `"File"`,
281 ".Spec.Containers[0].LivenessProbe.ProbeHandler.GRPC.Service": `""`,
282 ".Spec.Containers[0].ReadinessProbe.ProbeHandler.GRPC.Service": `""`,
283 ".Spec.Containers[0].StartupProbe.ProbeHandler.GRPC.Service": `""`,
284 ".Spec.DNSPolicy": `"ClusterFirst"`,
285 ".Spec.EnableServiceLinks": `true`,
286 ".Spec.EphemeralContainers[0].EphemeralContainerCommon.Env[0].ValueFrom.FieldRef.APIVersion": `"v1"`,
287 ".Spec.EphemeralContainers[0].EphemeralContainerCommon.ImagePullPolicy": `"IfNotPresent"`,
288 ".Spec.EphemeralContainers[0].EphemeralContainerCommon.Lifecycle.PostStart.HTTPGet.Path": `"/"`,
289 ".Spec.EphemeralContainers[0].EphemeralContainerCommon.Lifecycle.PostStart.HTTPGet.Scheme": `"HTTP"`,
290 ".Spec.EphemeralContainers[0].EphemeralContainerCommon.Lifecycle.PreStop.HTTPGet.Path": `"/"`,
291 ".Spec.EphemeralContainers[0].EphemeralContainerCommon.Lifecycle.PreStop.HTTPGet.Scheme": `"HTTP"`,
292 ".Spec.EphemeralContainers[0].EphemeralContainerCommon.LivenessProbe.FailureThreshold": "3",
293 ".Spec.EphemeralContainers[0].EphemeralContainerCommon.LivenessProbe.PeriodSeconds": "10",
294 ".Spec.EphemeralContainers[0].EphemeralContainerCommon.LivenessProbe.SuccessThreshold": "1",
295 ".Spec.EphemeralContainers[0].EphemeralContainerCommon.LivenessProbe.TimeoutSeconds": "1",
296 ".Spec.EphemeralContainers[0].EphemeralContainerCommon.Ports[0].Protocol": `"TCP"`,
297 ".Spec.EphemeralContainers[0].EphemeralContainerCommon.ReadinessProbe.FailureThreshold": "3",
298 ".Spec.EphemeralContainers[0].EphemeralContainerCommon.ReadinessProbe.PeriodSeconds": "10",
299 ".Spec.EphemeralContainers[0].EphemeralContainerCommon.ReadinessProbe.SuccessThreshold": "1",
300 ".Spec.EphemeralContainers[0].EphemeralContainerCommon.ReadinessProbe.TimeoutSeconds": "1",
301 ".Spec.EphemeralContainers[0].EphemeralContainerCommon.StartupProbe.FailureThreshold": "3",
302 ".Spec.EphemeralContainers[0].EphemeralContainerCommon.StartupProbe.PeriodSeconds": "10",
303 ".Spec.EphemeralContainers[0].EphemeralContainerCommon.StartupProbe.SuccessThreshold": "1",
304 ".Spec.EphemeralContainers[0].EphemeralContainerCommon.StartupProbe.TimeoutSeconds": "1",
305 ".Spec.EphemeralContainers[0].EphemeralContainerCommon.TerminationMessagePath": `"/dev/termination-log"`,
306 ".Spec.EphemeralContainers[0].EphemeralContainerCommon.TerminationMessagePolicy": `"File"`,
307 ".Spec.InitContainers[0].Env[0].ValueFrom.FieldRef.APIVersion": `"v1"`,
308 ".Spec.InitContainers[0].ImagePullPolicy": `"IfNotPresent"`,
309 ".Spec.InitContainers[0].Lifecycle.PostStart.HTTPGet.Path": `"/"`,
310 ".Spec.InitContainers[0].Lifecycle.PostStart.HTTPGet.Scheme": `"HTTP"`,
311 ".Spec.InitContainers[0].Lifecycle.PreStop.HTTPGet.Path": `"/"`,
312 ".Spec.InitContainers[0].Lifecycle.PreStop.HTTPGet.Scheme": `"HTTP"`,
313 ".Spec.InitContainers[0].LivenessProbe.FailureThreshold": `3`,
314 ".Spec.InitContainers[0].LivenessProbe.PeriodSeconds": `10`,
315 ".Spec.InitContainers[0].LivenessProbe.SuccessThreshold": `1`,
316 ".Spec.InitContainers[0].LivenessProbe.TimeoutSeconds": `1`,
317 ".Spec.InitContainers[0].Ports[0].Protocol": `"TCP"`,
318 ".Spec.InitContainers[0].ReadinessProbe.FailureThreshold": `3`,
319 ".Spec.InitContainers[0].ReadinessProbe.PeriodSeconds": `10`,
320 ".Spec.InitContainers[0].ReadinessProbe.SuccessThreshold": `1`,
321 ".Spec.InitContainers[0].ReadinessProbe.TimeoutSeconds": `1`,
322 ".Spec.InitContainers[0].Resources.Requests": `{"":"0"}`,
323 ".Spec.InitContainers[0].TerminationMessagePath": `"/dev/termination-log"`,
324 ".Spec.InitContainers[0].TerminationMessagePolicy": `"File"`,
325 ".Spec.InitContainers[0].StartupProbe.FailureThreshold": "3",
326 ".Spec.InitContainers[0].StartupProbe.PeriodSeconds": "10",
327 ".Spec.InitContainers[0].StartupProbe.SuccessThreshold": "1",
328 ".Spec.InitContainers[0].StartupProbe.TimeoutSeconds": "1",
329 ".Spec.EphemeralContainers[0].EphemeralContainerCommon.LivenessProbe.ProbeHandler.GRPC.Service": `""`,
330 ".Spec.EphemeralContainers[0].EphemeralContainerCommon.LivenessProbe.ProbeHandler.HTTPGet.Path": `"/"`,
331 ".Spec.EphemeralContainers[0].EphemeralContainerCommon.LivenessProbe.ProbeHandler.HTTPGet.Scheme": `"HTTP"`,
332 ".Spec.EphemeralContainers[0].EphemeralContainerCommon.ReadinessProbe.ProbeHandler.GRPC.Service": `""`,
333 ".Spec.EphemeralContainers[0].EphemeralContainerCommon.ReadinessProbe.ProbeHandler.HTTPGet.Path": `"/"`,
334 ".Spec.EphemeralContainers[0].EphemeralContainerCommon.ReadinessProbe.ProbeHandler.HTTPGet.Scheme": `"HTTP"`,
335 ".Spec.EphemeralContainers[0].EphemeralContainerCommon.StartupProbe.ProbeHandler.GRPC.Service": `""`,
336 ".Spec.EphemeralContainers[0].EphemeralContainerCommon.StartupProbe.ProbeHandler.HTTPGet.Path": `"/"`,
337 ".Spec.EphemeralContainers[0].EphemeralContainerCommon.StartupProbe.ProbeHandler.HTTPGet.Scheme": `"HTTP"`,
338 ".Spec.InitContainers[0].LivenessProbe.ProbeHandler.GRPC.Service": `""`,
339 ".Spec.InitContainers[0].LivenessProbe.ProbeHandler.HTTPGet.Path": `"/"`,
340 ".Spec.InitContainers[0].LivenessProbe.ProbeHandler.HTTPGet.Scheme": `"HTTP"`,
341 ".Spec.InitContainers[0].ReadinessProbe.ProbeHandler.GRPC.Service": `""`,
342 ".Spec.InitContainers[0].ReadinessProbe.ProbeHandler.HTTPGet.Path": `"/"`,
343 ".Spec.InitContainers[0].ReadinessProbe.ProbeHandler.HTTPGet.Scheme": `"HTTP"`,
344 ".Spec.InitContainers[0].StartupProbe.ProbeHandler.GRPC.Service": `""`,
345 ".Spec.InitContainers[0].StartupProbe.ProbeHandler.HTTPGet.Path": `"/"`,
346 ".Spec.InitContainers[0].StartupProbe.ProbeHandler.HTTPGet.Scheme": `"HTTP"`,
347 ".Spec.RestartPolicy": `"Always"`,
348 ".Spec.SchedulerName": `"default-scheduler"`,
349 ".Spec.SecurityContext": `{}`,
350 ".Spec.TerminationGracePeriodSeconds": `30`,
351 ".Spec.Volumes[0].VolumeSource.AzureDisk.CachingMode": `"ReadWrite"`,
352 ".Spec.Volumes[0].VolumeSource.AzureDisk.FSType": `"ext4"`,
353 ".Spec.Volumes[0].VolumeSource.AzureDisk.Kind": `"Shared"`,
354 ".Spec.Volumes[0].VolumeSource.AzureDisk.ReadOnly": `false`,
355 ".Spec.Volumes[0].VolumeSource.ConfigMap.DefaultMode": `420`,
356 ".Spec.Volumes[0].VolumeSource.DownwardAPI.DefaultMode": `420`,
357 ".Spec.Volumes[0].VolumeSource.DownwardAPI.Items[0].FieldRef.APIVersion": `"v1"`,
358 ".Spec.Volumes[0].VolumeSource.EmptyDir": `{}`,
359 ".Spec.Volumes[0].VolumeSource.Ephemeral.VolumeClaimTemplate.Spec.VolumeMode": `"Filesystem"`,
360 ".Spec.Volumes[0].VolumeSource.HostPath.Type": `""`,
361 ".Spec.Volumes[0].VolumeSource.ISCSI.ISCSIInterface": `"default"`,
362 ".Spec.Volumes[0].VolumeSource.Projected.DefaultMode": `420`,
363 ".Spec.Volumes[0].VolumeSource.Projected.Sources[0].DownwardAPI.Items[0].FieldRef.APIVersion": `"v1"`,
364 ".Spec.Volumes[0].VolumeSource.Projected.Sources[0].ServiceAccountToken.ExpirationSeconds": `3600`,
365 ".Spec.Volumes[0].VolumeSource.RBD.Keyring": `"/etc/ceph/keyring"`,
366 ".Spec.Volumes[0].VolumeSource.RBD.RBDPool": `"rbd"`,
367 ".Spec.Volumes[0].VolumeSource.RBD.RadosUser": `"admin"`,
368 ".Spec.Volumes[0].VolumeSource.ScaleIO.FSType": `"xfs"`,
369 ".Spec.Volumes[0].VolumeSource.ScaleIO.StorageMode": `"ThinProvisioned"`,
370 ".Spec.Volumes[0].VolumeSource.Secret.DefaultMode": `420`,
371 }
372 defaults := detectDefaults(t, pod, reflect.ValueOf(pod))
373 if !reflect.DeepEqual(expectedDefaults, defaults) {
374 t.Errorf("Defaults for PodSpec changed. This can cause spurious restarts of containers on API server upgrade.")
375 t.Logf(cmp.Diff(expectedDefaults, defaults))
376 }
377 }
378
379 func TestPodHostNetworkDefaults(t *testing.T) {
380 cases := []struct {
381 name string
382 gate bool
383 hostNet bool
384 expectPodDefault bool
385 expectPodSpecDefault bool
386 }{{
387 name: "gate disabled, hostNetwork=false",
388 gate: false,
389 hostNet: false,
390 expectPodDefault: false,
391 expectPodSpecDefault: false,
392 }, {
393 name: "gate disabled, hostNetwork=true",
394 gate: false,
395 hostNet: true,
396 expectPodDefault: true,
397 expectPodSpecDefault: false,
398 }, {
399 name: "gate enabled, hostNetwork=false",
400 gate: true,
401 hostNet: false,
402 expectPodDefault: false,
403 expectPodSpecDefault: false,
404 }, {
405 name: "gate enabled, hostNetwork=true",
406 gate: true,
407 hostNet: true,
408 expectPodDefault: true,
409 expectPodSpecDefault: true,
410 }}
411
412 for _, tc := range cases {
413 t.Run(tc.name, func(t *testing.T) {
414 defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.DefaultHostNetworkHostPortsInPodTemplates, tc.gate)()
415
416 const portNum = 12345
417 spec := v1.PodSpec{
418 HostNetwork: tc.hostNet,
419 Containers: []v1.Container{{
420 Ports: []v1.ContainerPort{{
421 ContainerPort: portNum,
422 Protocol: v1.ProtocolTCP,
423
424 }},
425 }},
426 }
427
428
429 p := v1.Pod{Spec: *spec.DeepCopy()}
430 corev1.SetDefaults_Pod(&p)
431 if got := p.Spec.Containers[0].Ports[0].HostPort; tc.expectPodDefault && got == 0 {
432 t.Errorf("expected Pod HostPort to be defaulted, got %v", got)
433 }
434 if got := p.Spec.Containers[0].Ports[0].HostPort; !tc.expectPodDefault && got != 0 {
435 t.Errorf("expected Pod HostPort to be 0, got %v", got)
436 }
437
438
439 s := spec.DeepCopy()
440 corev1.SetDefaults_PodSpec(s)
441 if got := s.Containers[0].Ports[0].HostPort; tc.expectPodSpecDefault && got == 0 {
442 t.Errorf("expected PodSpec HostPort to be defaulted, got %v", got)
443 }
444 if got := s.Containers[0].Ports[0].HostPort; !tc.expectPodSpecDefault && got != 0 {
445 t.Errorf("expected PodSpec HostPort to be 0, got %v", got)
446 }
447 })
448 }
449 }
450
451 type testPath struct {
452 path string
453 value reflect.Value
454 }
455
456 func detectDefaults(t *testing.T, obj runtime.Object, v reflect.Value) map[string]string {
457 defaults := map[string]string{}
458 toVisit := []testPath{{path: "", value: v}}
459
460 for len(toVisit) > 0 {
461 visit := toVisit[0]
462 toVisit = toVisit[1:]
463
464 legacyscheme.Scheme.Default(obj)
465 defaultedV := visit.value
466 zeroV := reflect.Zero(visit.value.Type())
467
468 switch {
469 case visit.value.Kind() == reflect.Struct:
470 for fi := 0; fi < visit.value.NumField(); fi++ {
471 structField := visit.value.Type().Field(fi)
472 valueField := visit.value.Field(fi)
473 if valueField.CanSet() {
474 toVisit = append(toVisit, testPath{path: visit.path + "." + structField.Name, value: valueField})
475 }
476 }
477
478 case visit.value.Kind() == reflect.Slice:
479 if !visit.value.IsNil() {
480
481
482
483 marshaled, _ := json.Marshal(defaultedV.Interface())
484 defaults[visit.path] = string(marshaled)
485 toVisit = append(toVisit, testPath{path: visit.path + "[0]", value: visit.value.Index(0)})
486 } else if visit.value.Type().Elem().Kind() == reflect.Struct {
487 if strings.HasPrefix(visit.path, ".ObjectMeta.ManagedFields[") {
488 break
489 }
490
491 item := reflect.New(visit.value.Type().Elem()).Elem()
492 visit.value.Set(reflect.Append(visit.value, item))
493 toVisit = append(toVisit, testPath{path: visit.path + "[0]", value: visit.value.Index(0)})
494 } else if !isPrimitive(visit.value.Type().Elem().Kind()) {
495 t.Logf("unhandled non-primitive slice type %s: %s", visit.path, visit.value.Type().Elem())
496 }
497
498 case visit.value.Kind() == reflect.Map:
499 if !visit.value.IsNil() {
500
501 marshaled, _ := json.Marshal(defaultedV.Interface())
502 defaults[visit.path] = string(marshaled)
503 } else if visit.value.Type().Key().Kind() == reflect.String && visit.value.Type().Elem().Kind() == reflect.Struct {
504 if strings.HasPrefix(visit.path, ".ObjectMeta.ManagedFields[") {
505 break
506 }
507
508 item := reflect.New(visit.value.Type().Elem()).Elem()
509 visit.value.Set(reflect.MakeMap(visit.value.Type()))
510 visit.value.SetMapIndex(reflect.New(visit.value.Type().Key()).Elem(), item)
511 toVisit = append(toVisit, testPath{path: visit.path + "[*]", value: item})
512 } else if !isPrimitive(visit.value.Type().Elem().Kind()) {
513 t.Logf("unhandled non-primitive map type %s: %s", visit.path, visit.value.Type().Elem())
514 }
515
516 case visit.value.Kind() == reflect.Pointer:
517 if visit.value.IsNil() {
518 if visit.value.Type().Elem().Kind() == reflect.Struct {
519 visit.value.Set(reflect.New(visit.value.Type().Elem()))
520 toVisit = append(toVisit, testPath{path: visit.path, value: visit.value.Elem()})
521 } else if !isPrimitive(visit.value.Type().Elem().Kind()) {
522 t.Errorf("unhandled non-primitive nil ptr: %s: %s", visit.path, visit.value.Type())
523 }
524 } else {
525 if visit.path != "" {
526 marshaled, _ := json.Marshal(defaultedV.Interface())
527 defaults[visit.path] = string(marshaled)
528 }
529 toVisit = append(toVisit, testPath{path: visit.path, value: visit.value.Elem()})
530 }
531
532 case isPrimitive(visit.value.Kind()):
533 if !reflect.DeepEqual(defaultedV.Interface(), zeroV.Interface()) {
534 marshaled, _ := json.Marshal(defaultedV.Interface())
535 defaults[visit.path] = string(marshaled)
536 }
537
538 default:
539 t.Errorf("unhandled kind: %s: %s", visit.path, visit.value.Type())
540 }
541
542 }
543 return defaults
544 }
545
546 func isPrimitive(k reflect.Kind) bool {
547 switch k {
548 case reflect.String, reflect.Bool, reflect.Int32, reflect.Int64, reflect.Int:
549 return true
550 default:
551 return false
552 }
553 }
554
555 func roundTrip(t *testing.T, obj runtime.Object) runtime.Object {
556 codec := legacyscheme.Codecs.LegacyCodec(corev1.SchemeGroupVersion)
557 data, err := runtime.Encode(codec, obj)
558 if err != nil {
559 t.Errorf("%v\n %#v", err, obj)
560 return nil
561 }
562 obj2, err := runtime.Decode(codec, data)
563 if err != nil {
564 t.Errorf("%v\nData: %s\nSource: %#v", err, string(data), obj)
565 return nil
566 }
567 obj3 := reflect.New(reflect.TypeOf(obj).Elem()).Interface().(runtime.Object)
568 err = legacyscheme.Scheme.Convert(obj2, obj3, nil)
569 if err != nil {
570 t.Errorf("%v\nSource: %#v", err, obj2)
571 return nil
572 }
573 return obj3
574 }
575
576 func TestSetDefaultReplicationController(t *testing.T) {
577 tests := []struct {
578 rc *v1.ReplicationController
579 expectLabels bool
580 expectSelector bool
581 }{
582 {
583 rc: &v1.ReplicationController{
584 Spec: v1.ReplicationControllerSpec{
585 Template: &v1.PodTemplateSpec{
586 ObjectMeta: metav1.ObjectMeta{
587 Labels: map[string]string{
588 "foo": "bar",
589 },
590 },
591 },
592 },
593 },
594 expectLabels: true,
595 expectSelector: true,
596 },
597 {
598 rc: &v1.ReplicationController{
599 ObjectMeta: metav1.ObjectMeta{
600 Labels: map[string]string{
601 "bar": "foo",
602 },
603 },
604 Spec: v1.ReplicationControllerSpec{
605 Template: &v1.PodTemplateSpec{
606 ObjectMeta: metav1.ObjectMeta{
607 Labels: map[string]string{
608 "foo": "bar",
609 },
610 },
611 },
612 },
613 },
614 expectLabels: false,
615 expectSelector: true,
616 },
617 {
618 rc: &v1.ReplicationController{
619 ObjectMeta: metav1.ObjectMeta{
620 Labels: map[string]string{
621 "bar": "foo",
622 },
623 },
624 Spec: v1.ReplicationControllerSpec{
625 Selector: map[string]string{
626 "some": "other",
627 },
628 Template: &v1.PodTemplateSpec{
629 ObjectMeta: metav1.ObjectMeta{
630 Labels: map[string]string{
631 "foo": "bar",
632 },
633 },
634 },
635 },
636 },
637 expectLabels: false,
638 expectSelector: false,
639 },
640 {
641 rc: &v1.ReplicationController{
642 Spec: v1.ReplicationControllerSpec{
643 Selector: map[string]string{
644 "some": "other",
645 },
646 Template: &v1.PodTemplateSpec{
647 ObjectMeta: metav1.ObjectMeta{
648 Labels: map[string]string{
649 "foo": "bar",
650 },
651 },
652 },
653 },
654 },
655 expectLabels: true,
656 expectSelector: false,
657 },
658 }
659
660 for _, test := range tests {
661 rc := test.rc
662 obj2 := roundTrip(t, runtime.Object(rc))
663 rc2, ok := obj2.(*v1.ReplicationController)
664 if !ok {
665 t.Errorf("unexpected object: %v", rc2)
666 t.FailNow()
667 }
668 if test.expectSelector != reflect.DeepEqual(rc2.Spec.Selector, rc2.Spec.Template.Labels) {
669 if test.expectSelector {
670 t.Errorf("expected: %v, got: %v", rc2.Spec.Template.Labels, rc2.Spec.Selector)
671 } else {
672 t.Errorf("unexpected equality: %v", rc.Spec.Selector)
673 }
674 }
675 if test.expectLabels != reflect.DeepEqual(rc2.Labels, rc2.Spec.Template.Labels) {
676 if test.expectLabels {
677 t.Errorf("expected: %v, got: %v", rc2.Spec.Template.Labels, rc2.Labels)
678 } else {
679 t.Errorf("unexpected equality: %v", rc.Labels)
680 }
681 }
682 }
683 }
684
685 func TestSetDefaultReplicationControllerReplicas(t *testing.T) {
686 tests := []struct {
687 rc v1.ReplicationController
688 expectReplicas int32
689 }{
690 {
691 rc: v1.ReplicationController{
692 Spec: v1.ReplicationControllerSpec{
693 Template: &v1.PodTemplateSpec{
694 ObjectMeta: metav1.ObjectMeta{
695 Labels: map[string]string{
696 "foo": "bar",
697 },
698 },
699 },
700 },
701 },
702 expectReplicas: 1,
703 },
704 {
705 rc: v1.ReplicationController{
706 Spec: v1.ReplicationControllerSpec{
707 Replicas: utilpointer.Int32(0),
708 Template: &v1.PodTemplateSpec{
709 ObjectMeta: metav1.ObjectMeta{
710 Labels: map[string]string{
711 "foo": "bar",
712 },
713 },
714 },
715 },
716 },
717 expectReplicas: 0,
718 },
719 {
720 rc: v1.ReplicationController{
721 Spec: v1.ReplicationControllerSpec{
722 Replicas: utilpointer.Int32(3),
723 Template: &v1.PodTemplateSpec{
724 ObjectMeta: metav1.ObjectMeta{
725 Labels: map[string]string{
726 "foo": "bar",
727 },
728 },
729 },
730 },
731 },
732 expectReplicas: 3,
733 },
734 }
735
736 for _, test := range tests {
737 rc := &test.rc
738 obj2 := roundTrip(t, runtime.Object(rc))
739 rc2, ok := obj2.(*v1.ReplicationController)
740 if !ok {
741 t.Errorf("unexpected object: %v", rc2)
742 t.FailNow()
743 }
744 if rc2.Spec.Replicas == nil {
745 t.Errorf("unexpected nil Replicas")
746 } else if test.expectReplicas != *rc2.Spec.Replicas {
747 t.Errorf("expected: %d replicas, got: %d", test.expectReplicas, *rc2.Spec.Replicas)
748 }
749 }
750 }
751
752 type InitContainerValidator func(got, expected *v1.Container) error
753
754 func TestSetDefaultReplicationControllerInitContainers(t *testing.T) {
755 assertEnvFieldRef := func(got, expected *v1.Container) error {
756 if len(got.Env) != len(expected.Env) {
757 return fmt.Errorf("different number of env: got <%v>, expected <%v>", len(got.Env), len(expected.Env))
758 }
759
760 for j := range got.Env {
761 ge := &got.Env[j]
762 ee := &expected.Env[j]
763
764 if ge.Name != ee.Name {
765 return fmt.Errorf("different name of env: got <%v>, expected <%v>", ge.Name, ee.Name)
766 }
767
768 if ge.ValueFrom.FieldRef.APIVersion != ee.ValueFrom.FieldRef.APIVersion {
769 return fmt.Errorf("different api version of FieldRef <%v>: got <%v>, expected <%v>",
770 ge.Name, ge.ValueFrom.FieldRef.APIVersion, ee.ValueFrom.FieldRef.APIVersion)
771 }
772 }
773 return nil
774 }
775
776 assertImagePullPolicy := func(got, expected *v1.Container) error {
777 if got.ImagePullPolicy != expected.ImagePullPolicy {
778 return fmt.Errorf("different image pull policy: got <%v>, expected <%v>", got.ImagePullPolicy, expected.ImagePullPolicy)
779 }
780 return nil
781 }
782
783 assertContainerPort := func(got, expected *v1.Container) error {
784 if len(got.Ports) != len(expected.Ports) {
785 return fmt.Errorf("different number of ports: got <%v>, expected <%v>", len(got.Ports), len(expected.Ports))
786 }
787
788 for i := range got.Ports {
789 gp := &got.Ports[i]
790 ep := &expected.Ports[i]
791
792 if gp.Name != ep.Name {
793 return fmt.Errorf("different name of port: got <%v>, expected <%v>", gp.Name, ep.Name)
794 }
795
796 if gp.Protocol != ep.Protocol {
797 return fmt.Errorf("different port protocol <%v>: got <%v>, expected <%v>", gp.Name, gp.Protocol, ep.Protocol)
798 }
799 }
800
801 return nil
802 }
803
804 assertResource := func(got, expected *v1.Container) error {
805 if len(got.Resources.Limits) != len(expected.Resources.Limits) {
806 return fmt.Errorf("different number of resources.Limits: got <%v>, expected <%v>", len(got.Resources.Limits), (expected.Resources.Limits))
807 }
808
809 for k, v := range got.Resources.Limits {
810 if ev, found := expected.Resources.Limits[v1.ResourceName(k)]; !found {
811 return fmt.Errorf("failed to find resource <%v> in expected resources.Limits.", k)
812 } else {
813 if ev.Value() != v.Value() {
814 return fmt.Errorf("different resource.Limits: got <%v>, expected <%v>.", v.Value(), ev.Value())
815 }
816 }
817 }
818
819 if len(got.Resources.Requests) != len(expected.Resources.Requests) {
820 return fmt.Errorf("different number of resources.Requests: got <%v>, expected <%v>", len(got.Resources.Requests), (expected.Resources.Requests))
821 }
822
823 for k, v := range got.Resources.Requests {
824 if ev, found := expected.Resources.Requests[v1.ResourceName(k)]; !found {
825 return fmt.Errorf("failed to find resource <%v> in expected resources.Requests.", k)
826 } else {
827 if ev.Value() != v.Value() {
828 return fmt.Errorf("different resource.Requests: got <%v>, expected <%v>.", v.Value(), ev.Value())
829 }
830 }
831 }
832
833 return nil
834 }
835
836 assertProb := func(got, expected *v1.Container) error {
837
838 if got.LivenessProbe.ProbeHandler.HTTPGet.Path != expected.LivenessProbe.ProbeHandler.HTTPGet.Path ||
839 got.LivenessProbe.ProbeHandler.HTTPGet.Scheme != expected.LivenessProbe.ProbeHandler.HTTPGet.Scheme ||
840 got.LivenessProbe.FailureThreshold != expected.LivenessProbe.FailureThreshold ||
841 got.LivenessProbe.SuccessThreshold != expected.LivenessProbe.SuccessThreshold ||
842 got.LivenessProbe.PeriodSeconds != expected.LivenessProbe.PeriodSeconds ||
843 got.LivenessProbe.TimeoutSeconds != expected.LivenessProbe.TimeoutSeconds {
844 return fmt.Errorf("different LivenessProbe: got <%v>, expected <%v>", got.LivenessProbe, expected.LivenessProbe)
845 }
846
847
848 if got.ReadinessProbe.ProbeHandler.HTTPGet.Path != expected.ReadinessProbe.ProbeHandler.HTTPGet.Path ||
849 got.ReadinessProbe.ProbeHandler.HTTPGet.Scheme != expected.ReadinessProbe.ProbeHandler.HTTPGet.Scheme ||
850 got.ReadinessProbe.FailureThreshold != expected.ReadinessProbe.FailureThreshold ||
851 got.ReadinessProbe.SuccessThreshold != expected.ReadinessProbe.SuccessThreshold ||
852 got.ReadinessProbe.PeriodSeconds != expected.ReadinessProbe.PeriodSeconds ||
853 got.ReadinessProbe.TimeoutSeconds != expected.ReadinessProbe.TimeoutSeconds {
854 return fmt.Errorf("different ReadinessProbe: got <%v>, expected <%v>", got.ReadinessProbe, expected.ReadinessProbe)
855 }
856
857 return nil
858 }
859
860 assertLifeCycle := func(got, expected *v1.Container) error {
861 if got.Lifecycle.PostStart.HTTPGet.Path != expected.Lifecycle.PostStart.HTTPGet.Path ||
862 got.Lifecycle.PostStart.HTTPGet.Scheme != expected.Lifecycle.PostStart.HTTPGet.Scheme {
863 return fmt.Errorf("different LifeCycle: got <%v>, expected <%v>", got.Lifecycle, expected.Lifecycle)
864 }
865
866 return nil
867 }
868
869 cpu, _ := resource.ParseQuantity("100m")
870 mem, _ := resource.ParseQuantity("100Mi")
871
872 tests := []struct {
873 name string
874 rc v1.ReplicationController
875 expected []v1.Container
876 validators []InitContainerValidator
877 }{
878 {
879 name: "imagePullIPolicy",
880 rc: v1.ReplicationController{
881 Spec: v1.ReplicationControllerSpec{
882 Template: &v1.PodTemplateSpec{
883 Spec: v1.PodSpec{
884 InitContainers: []v1.Container{
885 {
886 Name: "install",
887 Image: "busybox",
888 },
889 },
890 },
891 },
892 },
893 },
894 expected: []v1.Container{
895 {
896 ImagePullPolicy: v1.PullAlways,
897 },
898 },
899 validators: []InitContainerValidator{assertImagePullPolicy},
900 },
901 {
902 name: "FieldRef",
903 rc: v1.ReplicationController{
904 Spec: v1.ReplicationControllerSpec{
905 Template: &v1.PodTemplateSpec{
906 Spec: v1.PodSpec{
907 InitContainers: []v1.Container{
908 {
909 Name: "fun",
910 Image: "alpine",
911 Env: []v1.EnvVar{
912 {
913 Name: "MY_POD_IP",
914 ValueFrom: &v1.EnvVarSource{
915 FieldRef: &v1.ObjectFieldSelector{
916 APIVersion: "",
917 FieldPath: "status.podIP",
918 },
919 },
920 },
921 },
922 },
923 },
924 },
925 },
926 },
927 },
928 expected: []v1.Container{
929 {
930 Env: []v1.EnvVar{
931 {
932 Name: "MY_POD_IP",
933 ValueFrom: &v1.EnvVarSource{
934 FieldRef: &v1.ObjectFieldSelector{
935 APIVersion: "v1",
936 FieldPath: "status.podIP",
937 },
938 },
939 },
940 },
941 },
942 },
943 validators: []InitContainerValidator{assertEnvFieldRef},
944 },
945 {
946 name: "ContainerPort",
947 rc: v1.ReplicationController{
948 Spec: v1.ReplicationControllerSpec{
949 Template: &v1.PodTemplateSpec{
950 Spec: v1.PodSpec{
951 InitContainers: []v1.Container{
952 {
953 Name: "fun",
954 Image: "alpine",
955 Ports: []v1.ContainerPort{
956 {
957 Name: "default",
958 },
959 },
960 },
961 },
962 },
963 },
964 },
965 },
966 expected: []v1.Container{
967 {
968 Ports: []v1.ContainerPort{
969 {
970 Name: "default",
971 Protocol: v1.ProtocolTCP,
972 },
973 },
974 },
975 },
976 validators: []InitContainerValidator{assertContainerPort},
977 },
978 {
979 name: "Resources",
980 rc: v1.ReplicationController{
981 Spec: v1.ReplicationControllerSpec{
982 Template: &v1.PodTemplateSpec{
983 Spec: v1.PodSpec{
984 InitContainers: []v1.Container{
985 {
986 Name: "fun",
987 Image: "alpine",
988 Resources: v1.ResourceRequirements{
989 Limits: v1.ResourceList{
990 v1.ResourceCPU: resource.MustParse("100m"),
991 v1.ResourceMemory: resource.MustParse("100Mi"),
992 },
993 Requests: v1.ResourceList{
994 v1.ResourceCPU: resource.MustParse("100m"),
995 v1.ResourceMemory: resource.MustParse("100Mi"),
996 },
997 },
998 },
999 },
1000 },
1001 },
1002 },
1003 },
1004 expected: []v1.Container{
1005 {
1006 Resources: v1.ResourceRequirements{
1007 Limits: v1.ResourceList{
1008 v1.ResourceCPU: cpu,
1009 v1.ResourceMemory: mem,
1010 },
1011 Requests: v1.ResourceList{
1012 v1.ResourceCPU: cpu,
1013 v1.ResourceMemory: mem,
1014 },
1015 },
1016 },
1017 },
1018 validators: []InitContainerValidator{assertResource},
1019 },
1020 {
1021 name: "Probe",
1022 rc: v1.ReplicationController{
1023 Spec: v1.ReplicationControllerSpec{
1024 Template: &v1.PodTemplateSpec{
1025 Spec: v1.PodSpec{
1026 InitContainers: []v1.Container{
1027 {
1028 Name: "fun",
1029 Image: "alpine",
1030 LivenessProbe: &v1.Probe{
1031 ProbeHandler: v1.ProbeHandler{
1032 HTTPGet: &v1.HTTPGetAction{
1033 Host: "localhost",
1034 },
1035 },
1036 },
1037 ReadinessProbe: &v1.Probe{
1038 ProbeHandler: v1.ProbeHandler{
1039 HTTPGet: &v1.HTTPGetAction{
1040 Host: "localhost",
1041 },
1042 },
1043 },
1044 },
1045 },
1046 },
1047 },
1048 },
1049 },
1050 expected: []v1.Container{
1051 {
1052 LivenessProbe: &v1.Probe{
1053 ProbeHandler: v1.ProbeHandler{
1054 HTTPGet: &v1.HTTPGetAction{
1055 Path: "/",
1056 Scheme: v1.URISchemeHTTP,
1057 },
1058 },
1059 TimeoutSeconds: 1,
1060 PeriodSeconds: 10,
1061 SuccessThreshold: 1,
1062 FailureThreshold: 3,
1063 },
1064 ReadinessProbe: &v1.Probe{
1065 ProbeHandler: v1.ProbeHandler{
1066 HTTPGet: &v1.HTTPGetAction{
1067 Path: "/",
1068 Scheme: v1.URISchemeHTTP,
1069 },
1070 },
1071 TimeoutSeconds: 1,
1072 PeriodSeconds: 10,
1073 SuccessThreshold: 1,
1074 FailureThreshold: 3,
1075 },
1076 },
1077 },
1078 validators: []InitContainerValidator{assertProb},
1079 },
1080 {
1081 name: "LifeCycle",
1082 rc: v1.ReplicationController{
1083 Spec: v1.ReplicationControllerSpec{
1084 Template: &v1.PodTemplateSpec{
1085 Spec: v1.PodSpec{
1086 InitContainers: []v1.Container{
1087 {
1088 Name: "fun",
1089 Image: "alpine",
1090 Ports: []v1.ContainerPort{
1091 {
1092 Name: "default",
1093 },
1094 },
1095 Lifecycle: &v1.Lifecycle{
1096 PostStart: &v1.LifecycleHandler{
1097 HTTPGet: &v1.HTTPGetAction{
1098 Host: "localhost",
1099 },
1100 },
1101 PreStop: &v1.LifecycleHandler{
1102 HTTPGet: &v1.HTTPGetAction{
1103 Host: "localhost",
1104 },
1105 },
1106 },
1107 },
1108 },
1109 },
1110 },
1111 },
1112 },
1113 expected: []v1.Container{
1114 {
1115 Lifecycle: &v1.Lifecycle{
1116 PostStart: &v1.LifecycleHandler{
1117 HTTPGet: &v1.HTTPGetAction{
1118 Path: "/",
1119 Scheme: v1.URISchemeHTTP,
1120 },
1121 },
1122 PreStop: &v1.LifecycleHandler{
1123 HTTPGet: &v1.HTTPGetAction{
1124 Path: "/",
1125 Scheme: v1.URISchemeHTTP,
1126 },
1127 },
1128 },
1129 },
1130 },
1131 validators: []InitContainerValidator{assertLifeCycle},
1132 },
1133 }
1134
1135 assertInitContainers := func(got, expected []v1.Container, validators []InitContainerValidator) error {
1136 if len(got) != len(expected) {
1137 return fmt.Errorf("different number of init container: got <%d>, expected <%d>",
1138 len(got), len(expected))
1139 }
1140
1141 for i := range got {
1142 g := &got[i]
1143 e := &expected[i]
1144
1145 for _, validator := range validators {
1146 if err := validator(g, e); err != nil {
1147 return err
1148 }
1149 }
1150 }
1151
1152 return nil
1153 }
1154
1155 for _, test := range tests {
1156 rc := &test.rc
1157 obj2 := roundTrip(t, runtime.Object(rc))
1158 rc2, ok := obj2.(*v1.ReplicationController)
1159 if !ok {
1160 t.Errorf("unexpected object: %v", rc2)
1161 t.FailNow()
1162 }
1163
1164 if err := assertInitContainers(rc2.Spec.Template.Spec.InitContainers, test.expected, test.validators); err != nil {
1165 t.Errorf("test %v failed: %v", test.name, err)
1166 }
1167 }
1168 }
1169
1170 func TestSetDefaultService(t *testing.T) {
1171 svc := &v1.Service{}
1172 obj2 := roundTrip(t, runtime.Object(svc))
1173 svc2 := obj2.(*v1.Service)
1174 if svc2.Spec.SessionAffinity != v1.ServiceAffinityNone {
1175 t.Errorf("Expected default session affinity type:%s, got: %s", v1.ServiceAffinityNone, svc2.Spec.SessionAffinity)
1176 }
1177 if svc2.Spec.SessionAffinityConfig != nil {
1178 t.Errorf("Expected empty session affinity config when session affinity type: %s, got: %v", v1.ServiceAffinityNone, svc2.Spec.SessionAffinityConfig)
1179 }
1180 if svc2.Spec.Type != v1.ServiceTypeClusterIP {
1181 t.Errorf("Expected default type:%s, got: %s", v1.ServiceTypeClusterIP, svc2.Spec.Type)
1182 }
1183 }
1184
1185 func TestSetDefaultServiceSessionAffinityConfig(t *testing.T) {
1186 testCases := map[string]v1.Service{
1187 "SessionAffinityConfig is empty": {
1188 Spec: v1.ServiceSpec{
1189 SessionAffinity: v1.ServiceAffinityClientIP,
1190 SessionAffinityConfig: nil,
1191 },
1192 },
1193 "ClientIP is empty": {
1194 Spec: v1.ServiceSpec{
1195 SessionAffinity: v1.ServiceAffinityClientIP,
1196 SessionAffinityConfig: &v1.SessionAffinityConfig{
1197 ClientIP: nil,
1198 },
1199 },
1200 },
1201 "TimeoutSeconds is empty": {
1202 Spec: v1.ServiceSpec{
1203 SessionAffinity: v1.ServiceAffinityClientIP,
1204 SessionAffinityConfig: &v1.SessionAffinityConfig{
1205 ClientIP: &v1.ClientIPConfig{
1206 TimeoutSeconds: nil,
1207 },
1208 },
1209 },
1210 },
1211 }
1212 for name, test := range testCases {
1213 obj2 := roundTrip(t, runtime.Object(&test))
1214 svc2 := obj2.(*v1.Service)
1215 if svc2.Spec.SessionAffinityConfig == nil || svc2.Spec.SessionAffinityConfig.ClientIP == nil || svc2.Spec.SessionAffinityConfig.ClientIP.TimeoutSeconds == nil {
1216 t.Fatalf("Case: %s, unexpected empty SessionAffinityConfig/ClientIP/TimeoutSeconds when session affinity type: %s, got: %v", name, v1.ServiceAffinityClientIP, svc2.Spec.SessionAffinityConfig)
1217 }
1218 if *svc2.Spec.SessionAffinityConfig.ClientIP.TimeoutSeconds != v1.DefaultClientIPServiceAffinitySeconds {
1219 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)
1220 }
1221 }
1222 }
1223
1224 func TestSetDefaultServiceLoadbalancerIPMode(t *testing.T) {
1225 modeVIP := v1.LoadBalancerIPModeVIP
1226 modeProxy := v1.LoadBalancerIPModeProxy
1227 testCases := []struct {
1228 name string
1229 ipModeEnabled bool
1230 svc *v1.Service
1231 expectedIPMode []*v1.LoadBalancerIPMode
1232 }{
1233 {
1234 name: "Set IP but not set IPMode with LoadbalancerIPMode disabled",
1235 ipModeEnabled: false,
1236 svc: &v1.Service{
1237 Spec: v1.ServiceSpec{Type: v1.ServiceTypeLoadBalancer},
1238 Status: v1.ServiceStatus{
1239 LoadBalancer: v1.LoadBalancerStatus{
1240 Ingress: []v1.LoadBalancerIngress{{
1241 IP: "1.2.3.4",
1242 }},
1243 },
1244 }},
1245 expectedIPMode: []*v1.LoadBalancerIPMode{nil},
1246 }, {
1247 name: "Set IP but bot set IPMode with LoadbalancerIPMode enabled",
1248 ipModeEnabled: true,
1249 svc: &v1.Service{
1250 Spec: v1.ServiceSpec{Type: v1.ServiceTypeLoadBalancer},
1251 Status: v1.ServiceStatus{
1252 LoadBalancer: v1.LoadBalancerStatus{
1253 Ingress: []v1.LoadBalancerIngress{{
1254 IP: "1.2.3.4",
1255 }},
1256 },
1257 }},
1258 expectedIPMode: []*v1.LoadBalancerIPMode{&modeVIP},
1259 }, {
1260 name: "Both IP and IPMode are set with LoadbalancerIPMode enabled",
1261 ipModeEnabled: true,
1262 svc: &v1.Service{
1263 Spec: v1.ServiceSpec{Type: v1.ServiceTypeLoadBalancer},
1264 Status: v1.ServiceStatus{
1265 LoadBalancer: v1.LoadBalancerStatus{
1266 Ingress: []v1.LoadBalancerIngress{{
1267 IP: "1.2.3.4",
1268 IPMode: &modeProxy,
1269 }},
1270 },
1271 }},
1272 expectedIPMode: []*v1.LoadBalancerIPMode{&modeProxy},
1273 },
1274 }
1275
1276 for _, tc := range testCases {
1277 t.Run(tc.name, func(t *testing.T) {
1278 defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.LoadBalancerIPMode, tc.ipModeEnabled)()
1279 obj := roundTrip(t, runtime.Object(tc.svc))
1280 svc := obj.(*v1.Service)
1281 for i, s := range svc.Status.LoadBalancer.Ingress {
1282 got := s.IPMode
1283 expected := tc.expectedIPMode[i]
1284 if !reflect.DeepEqual(got, expected) {
1285 t.Errorf("Expected IPMode %v, got %v", tc.expectedIPMode[i], s.IPMode)
1286 }
1287 }
1288 })
1289 }
1290 }
1291
1292 func TestSetDefaultSecretVolumeSource(t *testing.T) {
1293 s := v1.PodSpec{}
1294 s.Volumes = []v1.Volume{
1295 {
1296 VolumeSource: v1.VolumeSource{
1297 Secret: &v1.SecretVolumeSource{},
1298 },
1299 },
1300 }
1301 pod := &v1.Pod{
1302 Spec: s,
1303 }
1304 output := roundTrip(t, runtime.Object(pod))
1305 pod2 := output.(*v1.Pod)
1306 defaultMode := pod2.Spec.Volumes[0].VolumeSource.Secret.DefaultMode
1307 expectedMode := v1.SecretVolumeSourceDefaultMode
1308
1309 if defaultMode == nil || *defaultMode != expectedMode {
1310 t.Errorf("Expected secret DefaultMode %v, got %v", expectedMode, defaultMode)
1311 }
1312 }
1313
1314 func TestSetDefaultConfigMapVolumeSource(t *testing.T) {
1315 s := v1.PodSpec{}
1316 s.Volumes = []v1.Volume{
1317 {
1318 VolumeSource: v1.VolumeSource{
1319 ConfigMap: &v1.ConfigMapVolumeSource{},
1320 },
1321 },
1322 }
1323 pod := &v1.Pod{
1324 Spec: s,
1325 }
1326 output := roundTrip(t, runtime.Object(pod))
1327 pod2 := output.(*v1.Pod)
1328 defaultMode := pod2.Spec.Volumes[0].VolumeSource.ConfigMap.DefaultMode
1329 expectedMode := v1.ConfigMapVolumeSourceDefaultMode
1330
1331 if defaultMode == nil || *defaultMode != expectedMode {
1332 t.Errorf("Expected v1.ConfigMap DefaultMode %v, got %v", expectedMode, defaultMode)
1333 }
1334 }
1335
1336 func TestSetDefaultDownwardAPIVolumeSource(t *testing.T) {
1337 s := v1.PodSpec{}
1338 s.Volumes = []v1.Volume{
1339 {
1340 VolumeSource: v1.VolumeSource{
1341 DownwardAPI: &v1.DownwardAPIVolumeSource{},
1342 },
1343 },
1344 }
1345 pod := &v1.Pod{
1346 Spec: s,
1347 }
1348 output := roundTrip(t, runtime.Object(pod))
1349 pod2 := output.(*v1.Pod)
1350 defaultMode := pod2.Spec.Volumes[0].VolumeSource.DownwardAPI.DefaultMode
1351 expectedMode := v1.DownwardAPIVolumeSourceDefaultMode
1352
1353 if defaultMode == nil || *defaultMode != expectedMode {
1354 t.Errorf("Expected DownwardAPI DefaultMode %v, got %v", expectedMode, defaultMode)
1355 }
1356 }
1357
1358 func TestSetDefaultProjectedVolumeSource(t *testing.T) {
1359 s := v1.PodSpec{}
1360 s.Volumes = []v1.Volume{
1361 {
1362 VolumeSource: v1.VolumeSource{
1363 Projected: &v1.ProjectedVolumeSource{},
1364 },
1365 },
1366 }
1367 pod := &v1.Pod{
1368 Spec: s,
1369 }
1370 output := roundTrip(t, runtime.Object(pod))
1371 pod2 := output.(*v1.Pod)
1372 defaultMode := pod2.Spec.Volumes[0].VolumeSource.Projected.DefaultMode
1373 expectedMode := v1.ProjectedVolumeSourceDefaultMode
1374
1375 if defaultMode == nil || *defaultMode != expectedMode {
1376 t.Errorf("Expected v1.ProjectedVolumeSource DefaultMode %v, got %v", expectedMode, defaultMode)
1377 }
1378 }
1379
1380 func TestSetDefaultSecret(t *testing.T) {
1381 s := &v1.Secret{}
1382 obj2 := roundTrip(t, runtime.Object(s))
1383 s2 := obj2.(*v1.Secret)
1384
1385 if s2.Type != v1.SecretTypeOpaque {
1386 t.Errorf("Expected secret type %v, got %v", v1.SecretTypeOpaque, s2.Type)
1387 }
1388 }
1389
1390 func TestSetDefaultPersistentVolume(t *testing.T) {
1391 fsMode := v1.PersistentVolumeFilesystem
1392 blockMode := v1.PersistentVolumeBlock
1393
1394 tests := []struct {
1395 name string
1396 volumeMode *v1.PersistentVolumeMode
1397 expectedVolumeMode v1.PersistentVolumeMode
1398 }{
1399 {
1400 name: "volume mode nil",
1401 volumeMode: nil,
1402 expectedVolumeMode: v1.PersistentVolumeFilesystem,
1403 },
1404 {
1405 name: "volume mode filesystem",
1406 volumeMode: &fsMode,
1407 expectedVolumeMode: v1.PersistentVolumeFilesystem,
1408 },
1409 {
1410 name: "volume mode block",
1411 volumeMode: &blockMode,
1412 expectedVolumeMode: v1.PersistentVolumeBlock,
1413 },
1414 }
1415
1416 for _, test := range tests {
1417 pv := &v1.PersistentVolume{
1418 Spec: v1.PersistentVolumeSpec{
1419 VolumeMode: test.volumeMode,
1420 },
1421 }
1422 obj1 := roundTrip(t, runtime.Object(pv))
1423 pv1 := obj1.(*v1.PersistentVolume)
1424 if pv1.Status.Phase != v1.VolumePending {
1425 t.Errorf("Expected claim phase %v, got %v", v1.ClaimPending, pv1.Status.Phase)
1426 }
1427 if pv1.Spec.PersistentVolumeReclaimPolicy != v1.PersistentVolumeReclaimRetain {
1428 t.Errorf("Expected pv reclaim policy %v, got %v", v1.PersistentVolumeReclaimRetain, pv1.Spec.PersistentVolumeReclaimPolicy)
1429 }
1430 if *pv1.Spec.VolumeMode != test.expectedVolumeMode {
1431 t.Errorf("Test %s failed, Expected VolumeMode: %v, but got %v", test.name, test.volumeMode, *pv1.Spec.VolumeMode)
1432 }
1433 }
1434 }
1435
1436 func TestSetDefaultPersistentVolumeClaim(t *testing.T) {
1437 fsMode := v1.PersistentVolumeFilesystem
1438 blockMode := v1.PersistentVolumeBlock
1439
1440 tests := []struct {
1441 name string
1442 volumeMode *v1.PersistentVolumeMode
1443 expectedVolumeMode v1.PersistentVolumeMode
1444 }{
1445 {
1446 name: "volume mode nil",
1447 volumeMode: nil,
1448 expectedVolumeMode: v1.PersistentVolumeFilesystem,
1449 },
1450 {
1451 name: "volume mode filesystem",
1452 volumeMode: &fsMode,
1453 expectedVolumeMode: v1.PersistentVolumeFilesystem,
1454 },
1455 {
1456 name: "volume mode block",
1457 volumeMode: &blockMode,
1458 expectedVolumeMode: v1.PersistentVolumeBlock,
1459 },
1460 }
1461
1462 for _, test := range tests {
1463 pvc := &v1.PersistentVolumeClaim{
1464 Spec: v1.PersistentVolumeClaimSpec{
1465 VolumeMode: test.volumeMode,
1466 },
1467 }
1468 obj1 := roundTrip(t, runtime.Object(pvc))
1469 pvc1 := obj1.(*v1.PersistentVolumeClaim)
1470 if pvc1.Status.Phase != v1.ClaimPending {
1471 t.Errorf("Expected claim phase %v, got %v", v1.ClaimPending, pvc1.Status.Phase)
1472 }
1473 if *pvc1.Spec.VolumeMode != test.expectedVolumeMode {
1474 t.Errorf("Test %s failed, Expected VolumeMode: %v, but got %v", test.name, test.volumeMode, *pvc1.Spec.VolumeMode)
1475 }
1476 }
1477 }
1478
1479 func TestSetDefaultEphemeral(t *testing.T) {
1480 fsMode := v1.PersistentVolumeFilesystem
1481 blockMode := v1.PersistentVolumeBlock
1482
1483 tests := []struct {
1484 name string
1485 volumeMode *v1.PersistentVolumeMode
1486 expectedVolumeMode v1.PersistentVolumeMode
1487 }{
1488 {
1489 name: "volume mode nil",
1490 volumeMode: nil,
1491 expectedVolumeMode: v1.PersistentVolumeFilesystem,
1492 },
1493 {
1494 name: "volume mode filesystem",
1495 volumeMode: &fsMode,
1496 expectedVolumeMode: v1.PersistentVolumeFilesystem,
1497 },
1498 {
1499 name: "volume mode block",
1500 volumeMode: &blockMode,
1501 expectedVolumeMode: v1.PersistentVolumeBlock,
1502 },
1503 }
1504
1505 for _, test := range tests {
1506 pod := &v1.Pod{
1507 Spec: v1.PodSpec{
1508 Volumes: []v1.Volume{
1509 {
1510 VolumeSource: v1.VolumeSource{
1511 Ephemeral: &v1.EphemeralVolumeSource{
1512 VolumeClaimTemplate: &v1.PersistentVolumeClaimTemplate{
1513 Spec: v1.PersistentVolumeClaimSpec{
1514 VolumeMode: test.volumeMode,
1515 },
1516 },
1517 },
1518 },
1519 },
1520 },
1521 },
1522 }
1523 obj1 := roundTrip(t, runtime.Object(pod))
1524 pod1 := obj1.(*v1.Pod)
1525 if *pod1.Spec.Volumes[0].VolumeSource.Ephemeral.VolumeClaimTemplate.Spec.VolumeMode != test.expectedVolumeMode {
1526 t.Errorf("Test %s failed, Expected VolumeMode: %v, but got %v", test.name, test.volumeMode, *pod1.Spec.Volumes[0].VolumeSource.Ephemeral.VolumeClaimTemplate.Spec.VolumeMode)
1527 }
1528 }
1529 }
1530
1531 func TestSetDefaultEndpointsProtocol(t *testing.T) {
1532 in := &v1.Endpoints{Subsets: []v1.EndpointSubset{
1533 {Ports: []v1.EndpointPort{{}, {Protocol: "UDP"}, {}}},
1534 }}
1535 obj := roundTrip(t, runtime.Object(in))
1536 out := obj.(*v1.Endpoints)
1537
1538 for i := range out.Subsets {
1539 for j := range out.Subsets[i].Ports {
1540 if in.Subsets[i].Ports[j].Protocol == "" {
1541 if out.Subsets[i].Ports[j].Protocol != v1.ProtocolTCP {
1542 t.Errorf("Expected protocol %s, got %s", v1.ProtocolTCP, out.Subsets[i].Ports[j].Protocol)
1543 }
1544 } else {
1545 if out.Subsets[i].Ports[j].Protocol != in.Subsets[i].Ports[j].Protocol {
1546 t.Errorf("Expected protocol %s, got %s", in.Subsets[i].Ports[j].Protocol, out.Subsets[i].Ports[j].Protocol)
1547 }
1548 }
1549 }
1550 }
1551 }
1552
1553 func TestSetDefaultServiceTargetPort(t *testing.T) {
1554 in := &v1.Service{Spec: v1.ServiceSpec{Ports: []v1.ServicePort{{Port: 1234}}}}
1555 obj := roundTrip(t, runtime.Object(in))
1556 out := obj.(*v1.Service)
1557 if out.Spec.Ports[0].TargetPort != intstr.FromInt32(1234) {
1558 t.Errorf("Expected TargetPort to be defaulted, got %v", out.Spec.Ports[0].TargetPort)
1559 }
1560
1561 in = &v1.Service{Spec: v1.ServiceSpec{Ports: []v1.ServicePort{{Port: 1234, TargetPort: intstr.FromInt32(5678)}}}}
1562 obj = roundTrip(t, runtime.Object(in))
1563 out = obj.(*v1.Service)
1564 if out.Spec.Ports[0].TargetPort != intstr.FromInt32(5678) {
1565 t.Errorf("Expected TargetPort to be unchanged, got %v", out.Spec.Ports[0].TargetPort)
1566 }
1567 }
1568
1569 func TestSetDefaultServicePort(t *testing.T) {
1570
1571 in := &v1.Service{Spec: v1.ServiceSpec{
1572 Ports: []v1.ServicePort{
1573 {Protocol: "UDP", Port: 9376, TargetPort: intstr.FromString("p")},
1574 {Protocol: "UDP", Port: 8675, TargetPort: intstr.FromInt32(309)},
1575 },
1576 }}
1577 out := roundTrip(t, runtime.Object(in)).(*v1.Service)
1578 if out.Spec.Ports[0].Protocol != v1.ProtocolUDP {
1579 t.Errorf("Expected protocol %s, got %s", v1.ProtocolUDP, out.Spec.Ports[0].Protocol)
1580 }
1581 if out.Spec.Ports[0].TargetPort != intstr.FromString("p") {
1582 t.Errorf("Expected port %v, got %v", in.Spec.Ports[0].Port, out.Spec.Ports[0].TargetPort)
1583 }
1584 if out.Spec.Ports[1].Protocol != v1.ProtocolUDP {
1585 t.Errorf("Expected protocol %s, got %s", v1.ProtocolUDP, out.Spec.Ports[1].Protocol)
1586 }
1587 if out.Spec.Ports[1].TargetPort != intstr.FromInt32(309) {
1588 t.Errorf("Expected port %v, got %v", in.Spec.Ports[1].Port, out.Spec.Ports[1].TargetPort)
1589 }
1590
1591
1592 in = &v1.Service{Spec: v1.ServiceSpec{
1593 Ports: []v1.ServicePort{
1594 {Protocol: "", Port: 9376, TargetPort: intstr.FromString("")},
1595 {Protocol: "", Port: 8675, TargetPort: intstr.FromInt32(0)},
1596 },
1597 }}
1598 out = roundTrip(t, runtime.Object(in)).(*v1.Service)
1599 if out.Spec.Ports[0].Protocol != v1.ProtocolTCP {
1600 t.Errorf("Expected protocol %s, got %s", v1.ProtocolTCP, out.Spec.Ports[0].Protocol)
1601 }
1602 if out.Spec.Ports[0].TargetPort != intstr.FromInt32(in.Spec.Ports[0].Port) {
1603 t.Errorf("Expected port %v, got %v", in.Spec.Ports[0].Port, out.Spec.Ports[0].TargetPort)
1604 }
1605 if out.Spec.Ports[1].Protocol != v1.ProtocolTCP {
1606 t.Errorf("Expected protocol %s, got %s", v1.ProtocolTCP, out.Spec.Ports[1].Protocol)
1607 }
1608 if out.Spec.Ports[1].TargetPort != intstr.FromInt32(in.Spec.Ports[1].Port) {
1609 t.Errorf("Expected port %v, got %v", in.Spec.Ports[1].Port, out.Spec.Ports[1].TargetPort)
1610 }
1611 }
1612
1613 func TestSetDefaultServiceExternalTraffic(t *testing.T) {
1614 in := &v1.Service{}
1615 obj := roundTrip(t, runtime.Object(in))
1616 out := obj.(*v1.Service)
1617 if out.Spec.ExternalTrafficPolicy != "" {
1618 t.Errorf("Expected ExternalTrafficPolicy to be empty, got %v", out.Spec.ExternalTrafficPolicy)
1619 }
1620
1621 in = &v1.Service{Spec: v1.ServiceSpec{Type: v1.ServiceTypeNodePort}}
1622 obj = roundTrip(t, runtime.Object(in))
1623 out = obj.(*v1.Service)
1624 if out.Spec.ExternalTrafficPolicy != v1.ServiceExternalTrafficPolicyCluster {
1625 t.Errorf("Expected ExternalTrafficPolicy to be %v, got %v", v1.ServiceExternalTrafficPolicyCluster, out.Spec.ExternalTrafficPolicy)
1626 }
1627
1628 in = &v1.Service{Spec: v1.ServiceSpec{Type: v1.ServiceTypeLoadBalancer}}
1629 obj = roundTrip(t, runtime.Object(in))
1630 out = obj.(*v1.Service)
1631 if out.Spec.ExternalTrafficPolicy != v1.ServiceExternalTrafficPolicyCluster {
1632 t.Errorf("Expected ExternalTrafficPolicy to be %v, got %v", v1.ServiceExternalTrafficPolicyCluster, out.Spec.ExternalTrafficPolicy)
1633 }
1634
1635 in = &v1.Service{Spec: v1.ServiceSpec{Type: v1.ServiceTypeClusterIP, ExternalIPs: []string{"1.2.3.4"}}}
1636 obj = roundTrip(t, runtime.Object(in))
1637 out = obj.(*v1.Service)
1638 if out.Spec.ExternalTrafficPolicy != v1.ServiceExternalTrafficPolicyCluster {
1639 t.Errorf("Expected ExternalTrafficPolicy to be %v, got %v", v1.ServiceExternalTrafficPolicyCluster, out.Spec.ExternalTrafficPolicy)
1640 }
1641
1642 in = &v1.Service{Spec: v1.ServiceSpec{Type: v1.ServiceTypeClusterIP}}
1643 obj = roundTrip(t, runtime.Object(in))
1644 out = obj.(*v1.Service)
1645 if out.Spec.ExternalTrafficPolicy != "" {
1646 t.Errorf("Expected ExternalTrafficPolicy to be empty, got %v", out.Spec.ExternalTrafficPolicy)
1647 }
1648
1649 in = &v1.Service{Spec: v1.ServiceSpec{Type: v1.ServiceTypeExternalName}}
1650 obj = roundTrip(t, runtime.Object(in))
1651 out = obj.(*v1.Service)
1652 if out.Spec.ExternalTrafficPolicy != "" {
1653 t.Errorf("Expected ExternalTrafficPolicy to be empty, got %v", out.Spec.ExternalTrafficPolicy)
1654 }
1655 }
1656
1657 func TestSetDefaultNamespace(t *testing.T) {
1658 s := &v1.Namespace{}
1659 obj2 := roundTrip(t, runtime.Object(s))
1660 s2 := obj2.(*v1.Namespace)
1661
1662 if s2.Status.Phase != v1.NamespaceActive {
1663 t.Errorf("Expected phase %v, got %v", v1.NamespaceActive, s2.Status.Phase)
1664 }
1665 }
1666
1667 func TestSetDefaultNamespaceLabels(t *testing.T) {
1668 theNs := "default-ns-labels-are-great"
1669 s := &v1.Namespace{
1670 ObjectMeta: metav1.ObjectMeta{
1671 Name: theNs,
1672 },
1673 }
1674 obj2 := roundTrip(t, runtime.Object(s))
1675 s2 := obj2.(*v1.Namespace)
1676
1677 if s2.ObjectMeta.Labels[v1.LabelMetadataName] != theNs {
1678 t.Errorf("Expected default namespace label value of %v, but got %v", theNs, s2.ObjectMeta.Labels[v1.LabelMetadataName])
1679 }
1680 }
1681
1682 func TestSetDefaultPodSpecHostNetwork(t *testing.T) {
1683 portNum := int32(8080)
1684 s := v1.PodSpec{}
1685 s.HostNetwork = true
1686 s.Containers = []v1.Container{
1687 {
1688 Ports: []v1.ContainerPort{
1689 {
1690 ContainerPort: portNum,
1691 },
1692 },
1693 },
1694 }
1695 s.InitContainers = []v1.Container{
1696 {
1697 Ports: []v1.ContainerPort{
1698 {
1699 ContainerPort: portNum,
1700 },
1701 },
1702 },
1703 }
1704 pod := &v1.Pod{
1705 Spec: s,
1706 }
1707 obj2 := roundTrip(t, runtime.Object(pod))
1708 pod2 := obj2.(*v1.Pod)
1709 s2 := pod2.Spec
1710
1711 hostPortNum := s2.Containers[0].Ports[0].HostPort
1712 if hostPortNum != portNum {
1713 t.Errorf("Expected container port to be defaulted, was made %d instead of %d", hostPortNum, portNum)
1714 }
1715
1716 hostPortNum = s2.InitContainers[0].Ports[0].HostPort
1717 if hostPortNum != portNum {
1718 t.Errorf("Expected container port to be defaulted, was made %d instead of %d", hostPortNum, portNum)
1719 }
1720 }
1721
1722 func TestSetDefaultNodeStatusAllocatable(t *testing.T) {
1723 capacity := v1.ResourceList{
1724 v1.ResourceCPU: resource.MustParse("1000m"),
1725 v1.ResourceMemory: resource.MustParse("10G"),
1726 }
1727 allocatable := v1.ResourceList{
1728 v1.ResourceCPU: resource.MustParse("500m"),
1729 v1.ResourceMemory: resource.MustParse("5G"),
1730 }
1731 tests := []struct {
1732 capacity v1.ResourceList
1733 allocatable v1.ResourceList
1734 expectedAllocatable v1.ResourceList
1735 }{{
1736 capacity: capacity,
1737 allocatable: allocatable,
1738 expectedAllocatable: allocatable,
1739 }, {
1740 capacity: nil,
1741 allocatable: allocatable,
1742 expectedAllocatable: allocatable,
1743 }, {
1744 capacity: capacity,
1745 allocatable: nil,
1746 expectedAllocatable: capacity,
1747 }, {
1748 capacity: nil,
1749 allocatable: nil,
1750 expectedAllocatable: nil,
1751 }}
1752
1753 copyResourceList := func(rl v1.ResourceList) v1.ResourceList {
1754 if rl == nil {
1755 return nil
1756 }
1757 copy := make(v1.ResourceList, len(rl))
1758 for k, v := range rl {
1759 copy[k] = v.DeepCopy()
1760 }
1761 return copy
1762 }
1763
1764 resourceListsEqual := func(a v1.ResourceList, b v1.ResourceList) bool {
1765 if len(a) != len(b) {
1766 return false
1767 }
1768 for k, v := range a {
1769 vb, found := b[k]
1770 if !found {
1771 return false
1772 }
1773 if v.Cmp(vb) != 0 {
1774 return false
1775 }
1776 }
1777 return true
1778 }
1779
1780 for i, testcase := range tests {
1781 node := v1.Node{
1782 Status: v1.NodeStatus{
1783 Capacity: copyResourceList(testcase.capacity),
1784 Allocatable: copyResourceList(testcase.allocatable),
1785 },
1786 }
1787 node2 := roundTrip(t, runtime.Object(&node)).(*v1.Node)
1788 actual := node2.Status.Allocatable
1789 expected := testcase.expectedAllocatable
1790 if !resourceListsEqual(expected, actual) {
1791 t.Errorf("[%d] Expected v1.NodeStatus.Allocatable: %+v; Got: %+v", i, expected, actual)
1792 }
1793 }
1794 }
1795
1796 func TestSetDefaultObjectFieldSelectorAPIVersion(t *testing.T) {
1797 s := v1.PodSpec{
1798 Containers: []v1.Container{
1799 {
1800 Env: []v1.EnvVar{
1801 {
1802 ValueFrom: &v1.EnvVarSource{
1803 FieldRef: &v1.ObjectFieldSelector{},
1804 },
1805 },
1806 },
1807 },
1808 },
1809 }
1810 pod := &v1.Pod{
1811 Spec: s,
1812 }
1813 obj2 := roundTrip(t, runtime.Object(pod))
1814 pod2 := obj2.(*v1.Pod)
1815 s2 := pod2.Spec
1816
1817 apiVersion := s2.Containers[0].Env[0].ValueFrom.FieldRef.APIVersion
1818 if apiVersion != "v1" {
1819 t.Errorf("Expected default APIVersion v1, got: %v", apiVersion)
1820 }
1821 }
1822
1823 func TestSetMinimumScalePod(t *testing.T) {
1824
1825 s := v1.PodSpec{}
1826 s.Containers = []v1.Container{
1827 {
1828 Resources: v1.ResourceRequirements{
1829 Requests: v1.ResourceList{
1830 v1.ResourceMemory: resource.MustParse("1n"),
1831 },
1832 Limits: v1.ResourceList{
1833 v1.ResourceCPU: resource.MustParse("2n"),
1834 },
1835 },
1836 },
1837 }
1838 s.InitContainers = []v1.Container{
1839 {
1840 Resources: v1.ResourceRequirements{
1841 Requests: v1.ResourceList{
1842 v1.ResourceMemory: resource.MustParse("1n"),
1843 },
1844 Limits: v1.ResourceList{
1845 v1.ResourceCPU: resource.MustParse("2n"),
1846 },
1847 },
1848 },
1849 }
1850 pod := &v1.Pod{
1851 Spec: s,
1852 }
1853 corev1.SetObjectDefaults_Pod(pod)
1854
1855 if expect := resource.MustParse("1m"); expect.Cmp(pod.Spec.Containers[0].Resources.Requests[v1.ResourceMemory]) != 0 {
1856 t.Errorf("did not round resources: %#v", pod.Spec.Containers[0].Resources)
1857 }
1858 if expect := resource.MustParse("1m"); expect.Cmp(pod.Spec.InitContainers[0].Resources.Requests[v1.ResourceMemory]) != 0 {
1859 t.Errorf("did not round resources: %#v", pod.Spec.InitContainers[0].Resources)
1860 }
1861 }
1862
1863 func TestSetDefaultRequestsPod(t *testing.T) {
1864
1865 s := v1.PodSpec{}
1866 s.Containers = []v1.Container{
1867 {
1868 Resources: v1.ResourceRequirements{
1869 Requests: v1.ResourceList{
1870 v1.ResourceMemory: resource.MustParse("0"),
1871 },
1872 Limits: v1.ResourceList{
1873 v1.ResourceCPU: resource.MustParse("100m"),
1874 v1.ResourceMemory: resource.MustParse("1Gi"),
1875 },
1876 },
1877 },
1878 }
1879 s.InitContainers = []v1.Container{
1880 {
1881 Resources: v1.ResourceRequirements{
1882 Requests: v1.ResourceList{
1883 v1.ResourceMemory: resource.MustParse("0"),
1884 },
1885 Limits: v1.ResourceList{
1886 v1.ResourceCPU: resource.MustParse("100m"),
1887 v1.ResourceMemory: resource.MustParse("1Gi"),
1888 },
1889 },
1890 },
1891 }
1892 pod := &v1.Pod{
1893 Spec: s,
1894 }
1895 output := roundTrip(t, runtime.Object(pod))
1896 pod2 := output.(*v1.Pod)
1897 defaultRequest := pod2.Spec.Containers[0].Resources.Requests
1898 if requestValue := defaultRequest[v1.ResourceCPU]; requestValue.String() != "100m" {
1899 t.Errorf("Expected request cpu: %s, got: %s", "100m", requestValue.String())
1900 }
1901 if requestValue := defaultRequest[v1.ResourceMemory]; requestValue.String() != "0" {
1902 t.Errorf("Expected request memory: %s, got: %s", "0", requestValue.String())
1903 }
1904 defaultRequest = pod2.Spec.InitContainers[0].Resources.Requests
1905 if requestValue := defaultRequest[v1.ResourceCPU]; requestValue.String() != "100m" {
1906 t.Errorf("Expected request cpu: %s, got: %s", "100m", requestValue.String())
1907 }
1908 if requestValue := defaultRequest[v1.ResourceMemory]; requestValue.String() != "0" {
1909 t.Errorf("Expected request memory: %s, got: %s", "0", requestValue.String())
1910 }
1911
1912
1913 s = v1.PodSpec{}
1914 s.Containers = []v1.Container{{}}
1915 s.InitContainers = []v1.Container{{}}
1916 pod = &v1.Pod{
1917 Spec: s,
1918 }
1919 output = roundTrip(t, runtime.Object(pod))
1920 pod2 = output.(*v1.Pod)
1921 defaultRequest = pod2.Spec.Containers[0].Resources.Requests
1922 if requestValue := defaultRequest[v1.ResourceCPU]; requestValue.String() != "0" {
1923 t.Errorf("Expected 0 request value, got: %s", requestValue.String())
1924 }
1925 defaultRequest = pod2.Spec.InitContainers[0].Resources.Requests
1926 if requestValue := defaultRequest[v1.ResourceCPU]; requestValue.String() != "0" {
1927 t.Errorf("Expected 0 request value, got: %s", requestValue.String())
1928 }
1929 }
1930
1931 func TestDefaultRequestIsNotSetForReplicationController(t *testing.T) {
1932 s := v1.PodSpec{}
1933 s.Containers = []v1.Container{
1934 {
1935 Resources: v1.ResourceRequirements{
1936 Limits: v1.ResourceList{
1937 v1.ResourceCPU: resource.MustParse("100m"),
1938 },
1939 },
1940 },
1941 }
1942 rc := &v1.ReplicationController{
1943 Spec: v1.ReplicationControllerSpec{
1944 Replicas: utilpointer.Int32(3),
1945 Template: &v1.PodTemplateSpec{
1946 ObjectMeta: metav1.ObjectMeta{
1947 Labels: map[string]string{
1948 "foo": "bar",
1949 },
1950 },
1951 Spec: s,
1952 },
1953 },
1954 }
1955 output := roundTrip(t, runtime.Object(rc))
1956 rc2 := output.(*v1.ReplicationController)
1957 defaultRequest := rc2.Spec.Template.Spec.Containers[0].Resources.Requests
1958 requestValue := defaultRequest[v1.ResourceCPU]
1959 if requestValue.String() != "0" {
1960 t.Errorf("Expected 0 request value, got: %s", requestValue.String())
1961 }
1962 }
1963
1964 func TestSetDefaultLimitRangeItem(t *testing.T) {
1965 limitRange := &v1.LimitRange{
1966 ObjectMeta: metav1.ObjectMeta{
1967 Name: "test-defaults",
1968 },
1969 Spec: v1.LimitRangeSpec{
1970 Limits: []v1.LimitRangeItem{{
1971 Type: v1.LimitTypeContainer,
1972 Max: v1.ResourceList{
1973 v1.ResourceCPU: resource.MustParse("100m"),
1974 },
1975 Min: v1.ResourceList{
1976 v1.ResourceMemory: resource.MustParse("100Mi"),
1977 },
1978 Default: v1.ResourceList{},
1979 DefaultRequest: v1.ResourceList{},
1980 }},
1981 },
1982 }
1983
1984 output := roundTrip(t, runtime.Object(limitRange))
1985 limitRange2 := output.(*v1.LimitRange)
1986 defaultLimit := limitRange2.Spec.Limits[0].Default
1987 defaultRequest := limitRange2.Spec.Limits[0].DefaultRequest
1988
1989
1990 defaultValue := defaultLimit[v1.ResourceCPU]
1991 if defaultValue.String() != "100m" {
1992 t.Errorf("Expected default cpu: %s, got: %s", "100m", defaultValue.String())
1993 }
1994
1995 requestValue := defaultRequest[v1.ResourceCPU]
1996 if requestValue.String() != "100m" {
1997 t.Errorf("Expected request cpu: %s, got: %s", "100m", requestValue.String())
1998 }
1999
2000 requestMinValue := defaultRequest[v1.ResourceMemory]
2001 if requestMinValue.String() != "100Mi" {
2002 t.Errorf("Expected request memory: %s, got: %s", "100Mi", requestMinValue.String())
2003 }
2004 }
2005
2006 func TestSetDefaultProbe(t *testing.T) {
2007 originalProbe := v1.Probe{}
2008 expectedProbe := v1.Probe{
2009 InitialDelaySeconds: 0,
2010 TimeoutSeconds: 1,
2011 PeriodSeconds: 10,
2012 SuccessThreshold: 1,
2013 FailureThreshold: 3,
2014 }
2015
2016 pod := &v1.Pod{
2017 Spec: v1.PodSpec{
2018 Containers: []v1.Container{{LivenessProbe: &originalProbe}},
2019 },
2020 }
2021
2022 output := roundTrip(t, runtime.Object(pod)).(*v1.Pod)
2023 actualProbe := *output.Spec.Containers[0].LivenessProbe
2024 if actualProbe != expectedProbe {
2025 t.Errorf("Expected probe: %+v\ngot: %+v\n", expectedProbe, actualProbe)
2026 }
2027 }
2028
2029 func TestSetDefaultSchedulerName(t *testing.T) {
2030 pod := &v1.Pod{}
2031
2032 output := roundTrip(t, runtime.Object(pod)).(*v1.Pod)
2033 if output.Spec.SchedulerName != v1.DefaultSchedulerName {
2034 t.Errorf("Expected scheduler name: %+v\ngot: %+v\n", v1.DefaultSchedulerName, output.Spec.SchedulerName)
2035 }
2036 }
2037
2038 func TestSetDefaultHostPathVolumeSource(t *testing.T) {
2039 s := v1.PodSpec{}
2040 s.Volumes = []v1.Volume{
2041 {
2042 VolumeSource: v1.VolumeSource{
2043 HostPath: &v1.HostPathVolumeSource{Path: "foo"},
2044 },
2045 },
2046 }
2047 pod := &v1.Pod{
2048 Spec: s,
2049 }
2050 output := roundTrip(t, runtime.Object(pod))
2051 pod2 := output.(*v1.Pod)
2052 defaultType := pod2.Spec.Volumes[0].VolumeSource.HostPath.Type
2053 expectedType := v1.HostPathUnset
2054
2055 if defaultType == nil || *defaultType != expectedType {
2056 t.Errorf("Expected v1.HostPathVolumeSource default type %v, got %v", expectedType, defaultType)
2057 }
2058 }
2059
2060 func TestSetDefaultEnableServiceLinks(t *testing.T) {
2061 pod := &v1.Pod{}
2062 output := roundTrip(t, runtime.Object(pod)).(*v1.Pod)
2063 if output.Spec.EnableServiceLinks == nil || *output.Spec.EnableServiceLinks != v1.DefaultEnableServiceLinks {
2064 t.Errorf("Expected enableServiceLinks value: %+v\ngot: %+v\n", v1.DefaultEnableServiceLinks, *output.Spec.EnableServiceLinks)
2065 }
2066 }
2067
2068 func TestSetDefaultServiceInternalTrafficPolicy(t *testing.T) {
2069 cluster := v1.ServiceInternalTrafficPolicyCluster
2070 local := v1.ServiceInternalTrafficPolicyLocal
2071 testCases := []struct {
2072 name string
2073 expectedInternalTrafficPolicy *v1.ServiceInternalTrafficPolicy
2074 svc v1.Service
2075 }{
2076 {
2077 name: "must set default internalTrafficPolicy",
2078 expectedInternalTrafficPolicy: &cluster,
2079 svc: v1.Service{},
2080 },
2081 {
2082 name: "must not set default internalTrafficPolicy when it's cluster",
2083 expectedInternalTrafficPolicy: &cluster,
2084 svc: v1.Service{
2085 Spec: v1.ServiceSpec{
2086 InternalTrafficPolicy: &cluster,
2087 },
2088 },
2089 },
2090 {
2091 name: "must not set default internalTrafficPolicy when type is ExternalName",
2092 expectedInternalTrafficPolicy: nil,
2093 svc: v1.Service{
2094 Spec: v1.ServiceSpec{
2095 Type: v1.ServiceTypeExternalName,
2096 },
2097 },
2098 },
2099 {
2100 name: "must not set default internalTrafficPolicy when it's local",
2101 expectedInternalTrafficPolicy: &local,
2102 svc: v1.Service{
2103 Spec: v1.ServiceSpec{
2104 InternalTrafficPolicy: &local,
2105 },
2106 },
2107 },
2108 }
2109 for _, test := range testCases {
2110 t.Run(test.name, func(t *testing.T) {
2111 obj := roundTrip(t, runtime.Object(&test.svc))
2112 svc := obj.(*v1.Service)
2113
2114 if !reflect.DeepEqual(svc.Spec.InternalTrafficPolicy, test.expectedInternalTrafficPolicy) {
2115 t.Errorf("expected .spec.internalTrafficPolicy: %v got %v", test.expectedInternalTrafficPolicy, svc.Spec.InternalTrafficPolicy)
2116 }
2117 })
2118 }
2119 }
2120
2121 func TestSetDefaultResizePolicy(t *testing.T) {
2122
2123 defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.InPlacePodVerticalScaling, true)()
2124
2125 for desc, tc := range map[string]struct {
2126 testContainer v1.Container
2127 expectedResizePolicy []v1.ContainerResizePolicy
2128 }{
2129 "CPU and memory limits are specified": {
2130 testContainer: v1.Container{
2131 Resources: v1.ResourceRequirements{
2132 Limits: v1.ResourceList{
2133 v1.ResourceCPU: resource.MustParse("100m"),
2134 v1.ResourceMemory: resource.MustParse("200Mi"),
2135 },
2136 },
2137 },
2138 expectedResizePolicy: []v1.ContainerResizePolicy{
2139 {
2140 ResourceName: v1.ResourceCPU,
2141 RestartPolicy: v1.NotRequired,
2142 },
2143 {
2144 ResourceName: v1.ResourceMemory,
2145 RestartPolicy: v1.NotRequired,
2146 },
2147 },
2148 },
2149 "CPU requests are specified": {
2150 testContainer: v1.Container{
2151 Resources: v1.ResourceRequirements{
2152 Requests: v1.ResourceList{
2153 v1.ResourceCPU: resource.MustParse("100m"),
2154 },
2155 },
2156 },
2157 expectedResizePolicy: []v1.ContainerResizePolicy{
2158 {
2159 ResourceName: v1.ResourceCPU,
2160 RestartPolicy: v1.NotRequired,
2161 },
2162 },
2163 },
2164 "Memory limits are specified": {
2165 testContainer: v1.Container{
2166 Resources: v1.ResourceRequirements{
2167 Limits: v1.ResourceList{
2168 v1.ResourceMemory: resource.MustParse("200Mi"),
2169 },
2170 },
2171 },
2172 expectedResizePolicy: []v1.ContainerResizePolicy{
2173 {
2174 ResourceName: v1.ResourceMemory,
2175 RestartPolicy: v1.NotRequired,
2176 },
2177 },
2178 },
2179 "No resources are specified": {
2180 testContainer: v1.Container{Name: "besteffort"},
2181 expectedResizePolicy: nil,
2182 },
2183 "CPU and memory limits are specified with restartContainer resize policy for memory": {
2184 testContainer: v1.Container{
2185 Resources: v1.ResourceRequirements{
2186 Limits: v1.ResourceList{
2187 v1.ResourceCPU: resource.MustParse("100m"),
2188 v1.ResourceMemory: resource.MustParse("200Mi"),
2189 },
2190 },
2191 ResizePolicy: []v1.ContainerResizePolicy{
2192 {
2193 ResourceName: v1.ResourceMemory,
2194 RestartPolicy: v1.RestartContainer,
2195 },
2196 },
2197 },
2198 expectedResizePolicy: []v1.ContainerResizePolicy{
2199 {
2200 ResourceName: v1.ResourceMemory,
2201 RestartPolicy: v1.RestartContainer,
2202 },
2203 {
2204 ResourceName: v1.ResourceCPU,
2205 RestartPolicy: v1.NotRequired,
2206 },
2207 },
2208 },
2209 "CPU requests and memory limits are specified with restartContainer resize policy for CPU": {
2210 testContainer: v1.Container{
2211 Resources: v1.ResourceRequirements{
2212 Limits: v1.ResourceList{
2213 v1.ResourceMemory: resource.MustParse("200Mi"),
2214 },
2215 Requests: v1.ResourceList{
2216 v1.ResourceCPU: resource.MustParse("100m"),
2217 },
2218 },
2219 ResizePolicy: []v1.ContainerResizePolicy{
2220 {
2221 ResourceName: v1.ResourceCPU,
2222 RestartPolicy: v1.RestartContainer,
2223 },
2224 },
2225 },
2226 expectedResizePolicy: []v1.ContainerResizePolicy{
2227 {
2228 ResourceName: v1.ResourceCPU,
2229 RestartPolicy: v1.RestartContainer,
2230 },
2231 {
2232 ResourceName: v1.ResourceMemory,
2233 RestartPolicy: v1.NotRequired,
2234 },
2235 },
2236 },
2237 "CPU and memory requests are specified with restartContainer resize policy for both": {
2238 testContainer: v1.Container{
2239 Resources: v1.ResourceRequirements{
2240 Requests: v1.ResourceList{
2241 v1.ResourceCPU: resource.MustParse("100m"),
2242 v1.ResourceMemory: resource.MustParse("200Mi"),
2243 },
2244 },
2245 ResizePolicy: []v1.ContainerResizePolicy{
2246 {
2247 ResourceName: v1.ResourceCPU,
2248 RestartPolicy: v1.RestartContainer,
2249 },
2250 {
2251 ResourceName: v1.ResourceMemory,
2252 RestartPolicy: v1.RestartContainer,
2253 },
2254 },
2255 },
2256 expectedResizePolicy: []v1.ContainerResizePolicy{
2257 {
2258 ResourceName: v1.ResourceCPU,
2259 RestartPolicy: v1.RestartContainer,
2260 },
2261 {
2262 ResourceName: v1.ResourceMemory,
2263 RestartPolicy: v1.RestartContainer,
2264 },
2265 },
2266 },
2267 "Ephemeral storage limits are specified": {
2268 testContainer: v1.Container{
2269 Resources: v1.ResourceRequirements{
2270 Limits: v1.ResourceList{
2271 v1.ResourceEphemeralStorage: resource.MustParse("500Mi"),
2272 },
2273 },
2274 },
2275 expectedResizePolicy: nil,
2276 },
2277 "Ephemeral storage requests and CPU limits are specified": {
2278 testContainer: v1.Container{
2279 Resources: v1.ResourceRequirements{
2280 Limits: v1.ResourceList{
2281 v1.ResourceCPU: resource.MustParse("100m"),
2282 },
2283 Requests: v1.ResourceList{
2284 v1.ResourceEphemeralStorage: resource.MustParse("500Mi"),
2285 },
2286 },
2287 },
2288 expectedResizePolicy: []v1.ContainerResizePolicy{
2289 {
2290 ResourceName: v1.ResourceCPU,
2291 RestartPolicy: v1.NotRequired,
2292 },
2293 },
2294 },
2295 "Ephemeral storage requests and limits, memory requests with restartContainer policy are specified": {
2296 testContainer: v1.Container{
2297 Resources: v1.ResourceRequirements{
2298 Limits: v1.ResourceList{
2299 v1.ResourceEphemeralStorage: resource.MustParse("500Mi"),
2300 },
2301 Requests: v1.ResourceList{
2302 v1.ResourceEphemeralStorage: resource.MustParse("500Mi"),
2303 v1.ResourceMemory: resource.MustParse("200Mi"),
2304 },
2305 },
2306 ResizePolicy: []v1.ContainerResizePolicy{
2307 {
2308 ResourceName: v1.ResourceMemory,
2309 RestartPolicy: v1.RestartContainer,
2310 },
2311 },
2312 },
2313 expectedResizePolicy: []v1.ContainerResizePolicy{
2314 {
2315 ResourceName: v1.ResourceMemory,
2316 RestartPolicy: v1.RestartContainer,
2317 },
2318 },
2319 },
2320 } {
2321 t.Run(desc, func(t *testing.T) {
2322 testPod := v1.Pod{}
2323 testPod.Spec.Containers = append(testPod.Spec.Containers, tc.testContainer)
2324 output := roundTrip(t, runtime.Object(&testPod))
2325 pod2 := output.(*v1.Pod)
2326 if !cmp.Equal(pod2.Spec.Containers[0].ResizePolicy, tc.expectedResizePolicy) {
2327 t.Errorf("expected resize policy %+v, but got %+v", tc.expectedResizePolicy, pod2.Spec.Containers[0].ResizePolicy)
2328 }
2329 })
2330 }
2331 }
2332
View as plain text