k8s.io/kubernetes@v1.31.0-alpha.0.0.20240520171757-56147500dadc/pkg/apis/core/v1/defaults_test.go (about)

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