...

Source file src/k8s.io/kubernetes/pkg/apis/core/v1/defaults_test.go

Documentation: k8s.io/kubernetes/pkg/apis/core/v1

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

View as plain text