diff --git a/pkg/api/pod/testing/make.go b/pkg/api/pod/testing/make.go new file mode 100644 index 00000000000..51d45bc3bc3 --- /dev/null +++ b/pkg/api/pod/testing/make.go @@ -0,0 +1,293 @@ +/* +Copyright 2024 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package testing + +import ( + v1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/resource" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + api "k8s.io/kubernetes/pkg/apis/core" + "k8s.io/utils/ptr" +) + +// Tweak is a function that modifies a Pod. +type Tweak func(*api.Pod) +type TweakContainer func(*api.Container) + +// MakePod helps construct Pod objects (which pass API validation) more +// legibly and tersely than a Go struct definition. By default this produces +// a Pod with a single container, ctr. The caller can pass any number of tweak +// functions to further modify the result. +func MakePod(name string, tweaks ...Tweak) *api.Pod { + // NOTE: Any field that would be populated by defaulting needs to be + // present and valid here. + pod := &api.Pod{ + ObjectMeta: metav1.ObjectMeta{ + Name: name, + Namespace: metav1.NamespaceDefault, + }, + Spec: api.PodSpec{ + Containers: []api.Container{MakeContainer("ctr")}, + DNSPolicy: api.DNSClusterFirst, + RestartPolicy: api.RestartPolicyAlways, + TerminationGracePeriodSeconds: ptr.To[int64](v1.DefaultTerminationGracePeriodSeconds), + }, + } + + for _, tweak := range tweaks { + tweak(pod) + } + + return pod +} + +func MakePodSpec(policy api.RestartPolicy, tweaks ...Tweak) api.PodSpec { + return MakePod("", append([]Tweak{SetRestartPolicy(policy)}, tweaks...)...).Spec +} + +func SetNamespace(ns string) Tweak { + return func(pod *api.Pod) { + pod.Namespace = ns + } +} + +func SetResourceVersion(rv string) Tweak { + return func(pod *api.Pod) { + pod.ResourceVersion = rv + } +} + +func SetContainers(containers ...api.Container) Tweak { + return func(pod *api.Pod) { + pod.Spec.Containers = containers + } +} + +func SetInitContainers(containers ...api.Container) Tweak { + return func(pod *api.Pod) { + pod.Spec.InitContainers = containers + } +} + +func SetEphemeralContainers(containers ...api.EphemeralContainer) Tweak { + return func(pod *api.Pod) { + pod.Spec.EphemeralContainers = containers + } +} + +func SetVolumes(volumes ...api.Volume) Tweak { + return func(pod *api.Pod) { + pod.Spec.Volumes = volumes + } +} + +func MakeEmptyVolume(name string) api.Volume { + return api.Volume{Name: name, VolumeSource: api.VolumeSource{EmptyDir: &api.EmptyDirVolumeSource{}}} +} + +func SetNodeSelector(nodeSelector map[string]string) Tweak { + return func(pod *api.Pod) { + pod.Spec.NodeSelector = nodeSelector + } +} + +func SetNodeName(name string) Tweak { + return func(pod *api.Pod) { + pod.Spec.NodeName = name + } +} + +func SetActiveDeadlineSeconds(deadline int64) Tweak { + return func(pod *api.Pod) { + pod.Spec.ActiveDeadlineSeconds = &deadline + } +} + +func SetServiceAccountName(name string) Tweak { + return func(pod *api.Pod) { + pod.Spec.ServiceAccountName = name + } +} + +func SetSecurityContext(ctx *api.PodSecurityContext) Tweak { + return func(pod *api.Pod) { + pod.Spec.SecurityContext = ctx + } +} + +func SetAffinity(affinity *api.Affinity) Tweak { + return func(pod *api.Pod) { + pod.Spec.Affinity = affinity + } +} + +func SetHostAliases(hostAliases ...api.HostAlias) Tweak { + return func(pod *api.Pod) { + pod.Spec.HostAliases = hostAliases + } +} + +func SetPriorityClassName(name string) Tweak { + return func(pod *api.Pod) { + pod.Spec.PriorityClassName = name + } +} + +func SetRuntimeClassName(name string) Tweak { + return func(pod *api.Pod) { + pod.Spec.RuntimeClassName = &name + } +} + +func SetOverhead(overhead api.ResourceList) Tweak { + return func(pod *api.Pod) { + pod.Spec.Overhead = overhead + } +} + +func SetDNSPolicy(policy api.DNSPolicy) Tweak { + return func(pod *api.Pod) { + pod.Spec.DNSPolicy = policy + } +} + +func SetRestartPolicy(policy api.RestartPolicy) Tweak { + return func(pod *api.Pod) { + pod.Spec.RestartPolicy = policy + } +} + +func SetTolerations(tolerations ...api.Toleration) Tweak { + return func(pod *api.Pod) { + pod.Spec.Tolerations = tolerations + } +} + +func SetAnnotations(annos map[string]string) Tweak { + return func(pod *api.Pod) { + pod.Annotations = annos + } +} + +func SetLabels(annos map[string]string) Tweak { + return func(pod *api.Pod) { + pod.Labels = annos + } +} + +func SetSchedulingGates(gates ...api.PodSchedulingGate) Tweak { + return func(pod *api.Pod) { + pod.Spec.SchedulingGates = gates + } +} + +func SetTerminationGracePeriodSeconds(grace int64) Tweak { + return func(pod *api.Pod) { + pod.Spec.TerminationGracePeriodSeconds = &grace + } +} + +func SetOS(name api.OSName) Tweak { + return func(pod *api.Pod) { + pod.Spec.OS = &api.PodOS{Name: name} + } +} + +func SetStatus(status api.PodStatus) Tweak { + return func(pod *api.Pod) { + pod.Status = status + } +} + +func SetResourceClaims(claims ...api.PodResourceClaim) Tweak { + return func(pod *api.Pod) { + pod.Spec.ResourceClaims = claims + } +} + +func SetTopologySpreadConstraints(tsc ...api.TopologySpreadConstraint) Tweak { + return func(pod *api.Pod) { + pod.Spec.TopologySpreadConstraints = tsc + } +} + +func SetObjectMeta(objectMeta metav1.ObjectMeta) Tweak { + return func(pod *api.Pod) { + pod.ObjectMeta = objectMeta + } +} + +func MakeContainer(name string, tweaks ...TweakContainer) api.Container { + cnr := api.Container{ + Name: name, Image: "image", ImagePullPolicy: "IfNotPresent", + TerminationMessagePolicy: "File", + TerminationMessagePath: v1.TerminationMessagePathDefault, + } + + for _, tweak := range tweaks { + tweak(&cnr) + } + + return cnr +} + +func SetContainerImage(image string) TweakContainer { + return func(cnr *api.Container) { + cnr.Image = image + } +} + +func MakeResourceRequirements(requests, limits map[string]string) api.ResourceRequirements { + rr := api.ResourceRequirements{Requests: api.ResourceList{}, Limits: api.ResourceList{}} + for k, v := range requests { + rr.Requests[api.ResourceName(k)] = resource.MustParse(v) + } + for k, v := range limits { + rr.Limits[api.ResourceName(k)] = resource.MustParse(v) + } + return rr +} + +func SetContainerResources(rr api.ResourceRequirements) TweakContainer { + return func(cnr *api.Container) { + cnr.Resources = rr + } +} + +func SetContainerPorts(ports ...api.ContainerPort) TweakContainer { + return func(cnr *api.Container) { + cnr.Ports = ports + } +} + +func SetContainerResizePolicy(policies ...api.ContainerResizePolicy) TweakContainer { + return func(cnr *api.Container) { + cnr.ResizePolicy = policies + } +} + +func SetContainerSecurityContext(ctx api.SecurityContext) TweakContainer { + return func(cnr *api.Container) { + cnr.SecurityContext = &ctx + } +} + +func SetContainerRestartPolicy(policy api.ContainerRestartPolicy) TweakContainer { + return func(cnr *api.Container) { + cnr.RestartPolicy = &policy + } +} diff --git a/pkg/apis/apps/validation/validation_test.go b/pkg/apis/apps/validation/validation_test.go index c2bc0b12143..5483b58066a 100644 --- a/pkg/apis/apps/validation/validation_test.go +++ b/pkg/apis/apps/validation/validation_test.go @@ -34,6 +34,7 @@ import ( utilfeature "k8s.io/apiserver/pkg/util/feature" featuregatetesting "k8s.io/component-base/featuregate/testing" "k8s.io/kubernetes/pkg/api/pod" + podtest "k8s.io/kubernetes/pkg/api/pod/testing" "k8s.io/kubernetes/pkg/apis/apps" api "k8s.io/kubernetes/pkg/apis/core" corevalidation "k8s.io/kubernetes/pkg/apis/core/validation" @@ -1503,29 +1504,15 @@ func TestValidateDaemonSetUpdate(t *testing.T) { validSelector2 := map[string]string{"c": "d"} invalidSelector := map[string]string{"NoUppercaseOrSpecialCharsLike=Equals": "b"} - validPodSpecAbc := api.PodSpec{ - RestartPolicy: api.RestartPolicyAlways, - DNSPolicy: api.DNSClusterFirst, - Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: api.TerminationMessageReadFile}}, - } - validPodSpecDef := api.PodSpec{ - RestartPolicy: api.RestartPolicyAlways, - DNSPolicy: api.DNSClusterFirst, - Containers: []api.Container{{Name: "def", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: api.TerminationMessageReadFile}}, - } - validPodSpecNodeSelector := api.PodSpec{ - NodeSelector: validSelector, - NodeName: "xyz", - RestartPolicy: api.RestartPolicyAlways, - DNSPolicy: api.DNSClusterFirst, - Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: api.TerminationMessageReadFile}}, - } - validPodSpecVolume := api.PodSpec{ - Volumes: []api.Volume{{Name: "gcepd", VolumeSource: api.VolumeSource{GCEPersistentDisk: &api.GCEPersistentDiskVolumeSource{PDName: "my-PD", FSType: "ext4", Partition: 1, ReadOnly: false}}}}, - RestartPolicy: api.RestartPolicyAlways, - DNSPolicy: api.DNSClusterFirst, - Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: api.TerminationMessageReadFile}}, - } + validPodSpecAbc := podtest.MakePodSpec(api.RestartPolicyAlways, + podtest.SetContainers(podtest.MakeContainer("abc"))) + validPodSpecDef := podtest.MakePodSpec(api.RestartPolicyAlways, + podtest.SetContainers(podtest.MakeContainer("def"))) + validPodSpecNodeSelector := podtest.MakePodSpec(api.RestartPolicyAlways, + podtest.SetNodeSelector(validSelector), + podtest.SetNodeName("xyz")) + validPodSpecVolume := podtest.MakePodSpec(api.RestartPolicyAlways, + podtest.SetVolumes(api.Volume{Name: "gcepd", VolumeSource: api.VolumeSource{GCEPersistentDisk: &api.GCEPersistentDiskVolumeSource{PDName: "my-PD", FSType: "ext4", Partition: 1, ReadOnly: false}}})) validPodTemplateAbc := api.PodTemplate{ Template: api.PodTemplateSpec{ @@ -1570,11 +1557,8 @@ func TestValidateDaemonSetUpdate(t *testing.T) { } invalidPodTemplate := api.PodTemplate{ Template: api.PodTemplateSpec{ - Spec: api.PodSpec{ - // no containers specified - RestartPolicy: api.RestartPolicyAlways, - DNSPolicy: api.DNSClusterFirst, - }, + // no containers specified + Spec: podtest.MakePodSpec(api.RestartPolicyAlways, podtest.SetContainers()), ObjectMeta: metav1.ObjectMeta{ Labels: validSelector, }, @@ -1992,11 +1976,7 @@ func TestValidateDaemonSet(t *testing.T) { ObjectMeta: metav1.ObjectMeta{ Labels: validSelector, }, - Spec: api.PodSpec{ - RestartPolicy: api.RestartPolicyAlways, - DNSPolicy: api.DNSClusterFirst, - Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: api.TerminationMessageReadFile}}, - }, + Spec: podtest.MakePodSpec(api.RestartPolicyAlways), }, } validHostNetPodTemplate := api.PodTemplate{ @@ -2004,35 +1984,22 @@ func TestValidateDaemonSet(t *testing.T) { ObjectMeta: metav1.ObjectMeta{ Labels: validSelector, }, - Spec: api.PodSpec{ - SecurityContext: &api.PodSecurityContext{ + Spec: podtest.MakePodSpec(api.RestartPolicyAlways, + podtest.SetSecurityContext(&api.PodSecurityContext{ HostNetwork: true, - }, - RestartPolicy: api.RestartPolicyAlways, - DNSPolicy: api.DNSClusterFirst, - Containers: []api.Container{{ - Name: "abc", - Image: "image", - ImagePullPolicy: "IfNotPresent", - TerminationMessagePolicy: api.TerminationMessageReadFile, - Ports: []api.ContainerPort{{ + }), + podtest.SetContainers(podtest.MakeContainer("abc", + podtest.SetContainerPorts(api.ContainerPort{ ContainerPort: 12345, Protocol: api.ProtocolTCP, - }}, - }}, - }, + }))), + ), }, } invalidSelector := map[string]string{"NoUppercaseOrSpecialCharsLike=Equals": "b"} invalidPodTemplate := api.PodTemplate{ Template: api.PodTemplateSpec{ - Spec: api.PodSpec{ - RestartPolicy: api.RestartPolicyAlways, - DNSPolicy: api.DNSClusterFirst, - }, - ObjectMeta: metav1.ObjectMeta{ - Labels: invalidSelector, - }, + Spec: podtest.MakePodSpec(api.RestartPolicyAlways, podtest.SetLabels(invalidSelector)), }, } successCases := []apps.DaemonSet{{ @@ -2157,14 +2124,7 @@ func TestValidateDaemonSet(t *testing.T) { Spec: apps.DaemonSetSpec{ Selector: &metav1.LabelSelector{MatchLabels: validSelector}, Template: api.PodTemplateSpec{ - Spec: api.PodSpec{ - RestartPolicy: api.RestartPolicyOnFailure, - DNSPolicy: api.DNSClusterFirst, - Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: api.TerminationMessageReadFile}}, - }, - ObjectMeta: metav1.ObjectMeta{ - Labels: validSelector, - }, + Spec: podtest.MakePodSpec(api.RestartPolicyOnFailure, podtest.SetLabels(validSelector)), }, }, }, @@ -2176,14 +2136,7 @@ func TestValidateDaemonSet(t *testing.T) { Spec: apps.DaemonSetSpec{ Selector: &metav1.LabelSelector{MatchLabels: validSelector}, Template: api.PodTemplateSpec{ - Spec: api.PodSpec{ - RestartPolicy: api.RestartPolicyNever, - DNSPolicy: api.DNSClusterFirst, - Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: api.TerminationMessageReadFile}}, - }, - ObjectMeta: metav1.ObjectMeta{ - Labels: validSelector, - }, + Spec: podtest.MakePodSpec(api.RestartPolicyNever, podtest.SetLabels(validSelector)), }, }, }, @@ -2195,12 +2148,8 @@ func TestValidateDaemonSet(t *testing.T) { ObjectMeta: metav1.ObjectMeta{ Labels: validSelector, }, - Spec: api.PodSpec{ - RestartPolicy: api.RestartPolicyAlways, - DNSPolicy: api.DNSClusterFirst, - Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: api.TerminationMessageReadFile}}, - EphemeralContainers: []api.EphemeralContainer{{EphemeralContainerCommon: api.EphemeralContainerCommon{Name: "debug", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}}, - }, + Spec: podtest.MakePodSpec(api.RestartPolicyAlways, + podtest.SetEphemeralContainers(api.EphemeralContainer{EphemeralContainerCommon: api.EphemeralContainerCommon{Name: "debug", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}})), }, UpdateStrategy: apps.DaemonSetUpdateStrategy{ Type: apps.OnDeleteDaemonSetStrategyType, @@ -2258,16 +2207,7 @@ func validDeployment(tweaks ...func(d *apps.Deployment)) *apps.Deployment { "name": "abc", }, }, - Spec: api.PodSpec{ - RestartPolicy: api.RestartPolicyAlways, - DNSPolicy: api.DNSDefault, - Containers: []api.Container{{ - Name: "nginx", - Image: "image", - ImagePullPolicy: api.PullNever, - TerminationMessagePolicy: api.TerminationMessageReadFile, - }}, - }, + Spec: podtest.MakePodSpec(api.RestartPolicyAlways), }, RollbackTo: &apps.RollbackConfig{ Revision: 1, @@ -2598,11 +2538,7 @@ func TestValidateDeploymentUpdate(t *testing.T) { ObjectMeta: metav1.ObjectMeta{ Labels: validLabels, }, - Spec: api.PodSpec{ - RestartPolicy: api.RestartPolicyAlways, - DNSPolicy: api.DNSClusterFirst, - Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: api.TerminationMessageReadFile}}, - }, + Spec: podtest.MakePodSpec(api.RestartPolicyAlways), }, } readWriteVolumePodTemplate := api.PodTemplate{ @@ -2610,22 +2546,16 @@ func TestValidateDeploymentUpdate(t *testing.T) { ObjectMeta: metav1.ObjectMeta{ Labels: validLabels, }, - Spec: api.PodSpec{ - RestartPolicy: api.RestartPolicyAlways, - DNSPolicy: api.DNSClusterFirst, - Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: api.TerminationMessageReadFile}}, - Volumes: []api.Volume{{Name: "gcepd", VolumeSource: api.VolumeSource{GCEPersistentDisk: &api.GCEPersistentDiskVolumeSource{PDName: "my-PD", FSType: "ext4", Partition: 1, ReadOnly: false}}}}, - }, + Spec: podtest.MakePodSpec(api.RestartPolicyAlways, + podtest.SetVolumes(api.Volume{Name: "gcepd", VolumeSource: api.VolumeSource{GCEPersistentDisk: &api.GCEPersistentDiskVolumeSource{PDName: "my-PD", FSType: "ext4", Partition: 1, ReadOnly: false}}}), + ), }, } invalidLabels := map[string]string{"NoUppercaseOrSpecialCharsLike=Equals": "b"} invalidPodTemplate := api.PodTemplate{ Template: api.PodTemplateSpec{ - Spec: api.PodSpec{ - // no containers specified - RestartPolicy: api.RestartPolicyAlways, - DNSPolicy: api.DNSClusterFirst, - }, + // no containers specified + Spec: podtest.MakePodSpec(api.RestartPolicyAlways, podtest.SetContainers()), ObjectMeta: metav1.ObjectMeta{ Labels: invalidLabels, }, @@ -2922,11 +2852,7 @@ func TestValidateReplicaSetStatusUpdate(t *testing.T) { ObjectMeta: metav1.ObjectMeta{ Labels: validLabels, }, - Spec: api.PodSpec{ - RestartPolicy: api.RestartPolicyAlways, - DNSPolicy: api.DNSClusterFirst, - Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: api.TerminationMessageReadFile}}, - }, + Spec: podtest.MakePodSpec(api.RestartPolicyAlways), }, } type rcUpdateTest struct { @@ -3004,11 +2930,7 @@ func TestValidateReplicaSetUpdate(t *testing.T) { ObjectMeta: metav1.ObjectMeta{ Labels: validLabels, }, - Spec: api.PodSpec{ - RestartPolicy: api.RestartPolicyAlways, - DNSPolicy: api.DNSClusterFirst, - Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: api.TerminationMessageReadFile}}, - }, + Spec: podtest.MakePodSpec(api.RestartPolicyAlways), }, } readWriteVolumePodTemplate := api.PodTemplate{ @@ -3016,21 +2938,15 @@ func TestValidateReplicaSetUpdate(t *testing.T) { ObjectMeta: metav1.ObjectMeta{ Labels: validLabels, }, - Spec: api.PodSpec{ - RestartPolicy: api.RestartPolicyAlways, - DNSPolicy: api.DNSClusterFirst, - Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: api.TerminationMessageReadFile}}, - Volumes: []api.Volume{{Name: "gcepd", VolumeSource: api.VolumeSource{GCEPersistentDisk: &api.GCEPersistentDiskVolumeSource{PDName: "my-PD", FSType: "ext4", Partition: 1, ReadOnly: false}}}}, - }, + Spec: podtest.MakePodSpec(api.RestartPolicyAlways, + podtest.SetVolumes(api.Volume{Name: "gcepd", VolumeSource: api.VolumeSource{GCEPersistentDisk: &api.GCEPersistentDiskVolumeSource{PDName: "my-PD", FSType: "ext4", Partition: 1, ReadOnly: false}}}), + ), }, } invalidLabels := map[string]string{"NoUppercaseOrSpecialCharsLike=Equals": "b"} invalidPodTemplate := api.PodTemplate{ Template: api.PodTemplateSpec{ - Spec: api.PodSpec{ - RestartPolicy: api.RestartPolicyAlways, - DNSPolicy: api.DNSClusterFirst, - }, + Spec: podtest.MakePodSpec(api.RestartPolicyAlways, podtest.SetContainers()), ObjectMeta: metav1.ObjectMeta{ Labels: invalidLabels, }, @@ -3180,11 +3096,7 @@ func TestValidateReplicaSet(t *testing.T) { ObjectMeta: metav1.ObjectMeta{ Labels: validLabels, }, - Spec: api.PodSpec{ - RestartPolicy: api.RestartPolicyAlways, - DNSPolicy: api.DNSClusterFirst, - Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: api.TerminationMessageReadFile}}, - }, + Spec: podtest.MakePodSpec(api.RestartPolicyAlways), }, } validHostNetPodTemplate := api.PodTemplate{ @@ -3192,23 +3104,15 @@ func TestValidateReplicaSet(t *testing.T) { ObjectMeta: metav1.ObjectMeta{ Labels: validLabels, }, - Spec: api.PodSpec{ - SecurityContext: &api.PodSecurityContext{ + Spec: podtest.MakePodSpec(api.RestartPolicyAlways, + podtest.SetSecurityContext(&api.PodSecurityContext{ HostNetwork: true, - }, - RestartPolicy: api.RestartPolicyAlways, - DNSPolicy: api.DNSClusterFirst, - Containers: []api.Container{{ - Name: "abc", - Image: "image", - ImagePullPolicy: "IfNotPresent", - TerminationMessagePolicy: api.TerminationMessageReadFile, - Ports: []api.ContainerPort{{ - ContainerPort: 12345, - Protocol: api.ProtocolTCP, - }}, - }}, - }, + }), + podtest.SetContainers(podtest.MakeContainer("abc", podtest.SetContainerPorts(api.ContainerPort{ + ContainerPort: 12345, + Protocol: api.ProtocolTCP, + }))), + ), }, } readWriteVolumePodTemplate := api.PodTemplate{ @@ -3216,21 +3120,15 @@ func TestValidateReplicaSet(t *testing.T) { ObjectMeta: metav1.ObjectMeta{ Labels: validLabels, }, - Spec: api.PodSpec{ - Volumes: []api.Volume{{Name: "gcepd", VolumeSource: api.VolumeSource{GCEPersistentDisk: &api.GCEPersistentDiskVolumeSource{PDName: "my-PD", FSType: "ext4", Partition: 1, ReadOnly: false}}}}, - RestartPolicy: api.RestartPolicyAlways, - DNSPolicy: api.DNSClusterFirst, - Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: api.TerminationMessageReadFile}}, - }, + Spec: podtest.MakePodSpec(api.RestartPolicyAlways, + podtest.SetVolumes(api.Volume{Name: "gcepd", VolumeSource: api.VolumeSource{GCEPersistentDisk: &api.GCEPersistentDiskVolumeSource{PDName: "my-PD", FSType: "ext4", Partition: 1, ReadOnly: false}}}), + ), }, } invalidLabels := map[string]string{"NoUppercaseOrSpecialCharsLike=Equals": "b"} invalidPodTemplate := api.PodTemplate{ Template: api.PodTemplateSpec{ - Spec: api.PodSpec{ - RestartPolicy: api.RestartPolicyAlways, - DNSPolicy: api.DNSClusterFirst, - }, + Spec: podtest.MakePodSpec(api.RestartPolicyAlways), ObjectMeta: metav1.ObjectMeta{ Labels: invalidLabels, }, @@ -3364,11 +3262,7 @@ func TestValidateReplicaSet(t *testing.T) { Spec: apps.ReplicaSetSpec{ Selector: &metav1.LabelSelector{MatchLabels: validLabels}, Template: api.PodTemplateSpec{ - Spec: api.PodSpec{ - RestartPolicy: api.RestartPolicyOnFailure, - DNSPolicy: api.DNSClusterFirst, - Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: api.TerminationMessageReadFile}}, - }, + Spec: podtest.MakePodSpec(api.RestartPolicyOnFailure), ObjectMeta: metav1.ObjectMeta{ Labels: validLabels, }, @@ -3383,11 +3277,7 @@ func TestValidateReplicaSet(t *testing.T) { Spec: apps.ReplicaSetSpec{ Selector: &metav1.LabelSelector{MatchLabels: validLabels}, Template: api.PodTemplateSpec{ - Spec: api.PodSpec{ - RestartPolicy: api.RestartPolicyNever, - DNSPolicy: api.DNSClusterFirst, - Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: api.TerminationMessageReadFile}}, - }, + Spec: podtest.MakePodSpec(api.RestartPolicyNever), ObjectMeta: metav1.ObjectMeta{ Labels: validLabels, }, diff --git a/pkg/apis/batch/validation/validation_test.go b/pkg/apis/batch/validation/validation_test.go index 9a4166c3861..c2fa713c928 100644 --- a/pkg/apis/batch/validation/validation_test.go +++ b/pkg/apis/batch/validation/validation_test.go @@ -30,6 +30,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/util/validation/field" + podtest "k8s.io/kubernetes/pkg/api/pod/testing" "k8s.io/kubernetes/pkg/apis/batch" api "k8s.io/kubernetes/pkg/apis/core" corevalidation "k8s.io/kubernetes/pkg/apis/core/validation" @@ -61,11 +62,7 @@ func getValidPodTemplateSpecForManual(selector *metav1.LabelSelector) api.PodTem ObjectMeta: metav1.ObjectMeta{ Labels: selector.MatchLabels, }, - Spec: api.PodSpec{ - RestartPolicy: api.RestartPolicyOnFailure, - DNSPolicy: api.DNSClusterFirst, - Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: api.TerminationMessageReadFile}}, - }, + Spec: podtest.MakePodSpec(api.RestartPolicyOnFailure), } } @@ -80,12 +77,8 @@ func getValidPodTemplateSpecForGenerated(selector *metav1.LabelSelector) api.Pod ObjectMeta: metav1.ObjectMeta{ Labels: selector.MatchLabels, }, - Spec: api.PodSpec{ - RestartPolicy: api.RestartPolicyOnFailure, - DNSPolicy: api.DNSClusterFirst, - Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: api.TerminationMessageReadFile}}, - InitContainers: []api.Container{{Name: "def", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: api.TerminationMessageReadFile}}, - }, + Spec: podtest.MakePodSpec(api.RestartPolicyOnFailure, + podtest.SetInitContainers(podtest.MakeContainer("def"))), } } @@ -165,7 +158,7 @@ func TestValidateJob(t *testing.T) { }, { Action: batch.PodFailurePolicyActionCount, OnExitCodes: &batch.PodFailurePolicyOnExitCodesRequirement{ - ContainerName: pointer.String("abc"), + ContainerName: pointer.String("ctr"), Operator: batch.PodFailurePolicyOnExitCodesOpIn, Values: []int32{1, 2, 3}, }, @@ -395,12 +388,7 @@ func TestValidateJob(t *testing.T) { ObjectMeta: metav1.ObjectMeta{ Labels: map[string]string{batch.LegacyControllerUidLabel: "1a2b3c", batch.LegacyJobNameLabel: "myjob"}, }, - Spec: api.PodSpec{ - RestartPolicy: api.RestartPolicyOnFailure, - DNSPolicy: api.DNSClusterFirst, - Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: api.TerminationMessageReadFile}}, - InitContainers: []api.Container{{Name: "def", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: api.TerminationMessageReadFile}}, - }, + Spec: podtest.MakePodSpec(api.RestartPolicyOnFailure), }, }, }, @@ -819,7 +807,7 @@ func TestValidateJob(t *testing.T) { Rules: []batch.PodFailurePolicyRule{{ Action: batch.PodFailurePolicyActionFailJob, OnExitCodes: &batch.PodFailurePolicyOnExitCodesRequirement{ - ContainerName: pointer.String("abc"), + ContainerName: pointer.String("ctr"), Operator: batch.PodFailurePolicyOnExitCodesOpIn, Values: []int32{1, 2, 3}, }, @@ -862,7 +850,7 @@ func TestValidateJob(t *testing.T) { Rules: []batch.PodFailurePolicyRule{{ Action: batch.PodFailurePolicyActionIgnore, OnExitCodes: &batch.PodFailurePolicyOnExitCodesRequirement{ - ContainerName: pointer.String("abc"), + ContainerName: pointer.String("ctr"), Operator: batch.PodFailurePolicyOnExitCodesOpIn, Values: []int32{1, 2, 3}, }, @@ -889,7 +877,7 @@ func TestValidateJob(t *testing.T) { Rules: []batch.PodFailurePolicyRule{{ Action: "UnknownAction", OnExitCodes: &batch.PodFailurePolicyOnExitCodesRequirement{ - ContainerName: pointer.String("abc"), + ContainerName: pointer.String("ctr"), Operator: batch.PodFailurePolicyOnExitCodesOpIn, Values: []int32{1, 2, 3}, }, @@ -1033,11 +1021,7 @@ func TestValidateJob(t *testing.T) { ObjectMeta: metav1.ObjectMeta{ Labels: validGeneratedSelector.MatchLabels, }, - Spec: api.PodSpec{ - RestartPolicy: api.RestartPolicyOnFailure, - DNSPolicy: api.DNSClusterFirst, - Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: api.TerminationMessageReadFile}}, - }, + Spec: podtest.MakePodSpec(api.RestartPolicyOnFailure), }, PodFailurePolicy: &batch.PodFailurePolicy{ Rules: []batch.PodFailurePolicyRule{}, @@ -1251,11 +1235,7 @@ func TestValidateJob(t *testing.T) { ObjectMeta: metav1.ObjectMeta{ Labels: map[string]string{"y": "z"}, }, - Spec: api.PodSpec{ - RestartPolicy: api.RestartPolicyOnFailure, - DNSPolicy: api.DNSClusterFirst, - Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: api.TerminationMessageReadFile}}, - }, + Spec: podtest.MakePodSpec(api.RestartPolicyOnFailure), }, }, }, @@ -1275,11 +1255,7 @@ func TestValidateJob(t *testing.T) { ObjectMeta: metav1.ObjectMeta{ Labels: map[string]string{"controller-uid": "4d5e6f"}, }, - Spec: api.PodSpec{ - RestartPolicy: api.RestartPolicyOnFailure, - DNSPolicy: api.DNSClusterFirst, - Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: api.TerminationMessageReadFile}}, - }, + Spec: podtest.MakePodSpec(api.RestartPolicyOnFailure), }, }, }, @@ -1299,11 +1275,7 @@ func TestValidateJob(t *testing.T) { ObjectMeta: metav1.ObjectMeta{ Labels: validManualSelector.MatchLabels, }, - Spec: api.PodSpec{ - RestartPolicy: api.RestartPolicyAlways, - DNSPolicy: api.DNSClusterFirst, - Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: api.TerminationMessageReadFile}}, - }, + Spec: podtest.MakePodSpec(api.RestartPolicyAlways), }, }, }, @@ -1323,11 +1295,7 @@ func TestValidateJob(t *testing.T) { ObjectMeta: metav1.ObjectMeta{ Labels: validManualSelector.MatchLabels, }, - Spec: api.PodSpec{ - RestartPolicy: "Invalid", - DNSPolicy: api.DNSClusterFirst, - Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: api.TerminationMessageReadFile}}, - }, + Spec: podtest.MakePodSpec("Invalid"), }, }, }, @@ -1395,12 +1363,7 @@ func TestValidateJob(t *testing.T) { ObjectMeta: metav1.ObjectMeta{ Labels: map[string]string{batch.LegacyJobNameLabel: "myjob"}, }, - Spec: api.PodSpec{ - RestartPolicy: api.RestartPolicyOnFailure, - DNSPolicy: api.DNSClusterFirst, - Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: api.TerminationMessageReadFile}}, - InitContainers: []api.Container{{Name: "def", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: api.TerminationMessageReadFile}}, - }, + Spec: podtest.MakePodSpec(api.RestartPolicyOnFailure), }, }, }, @@ -1420,12 +1383,7 @@ func TestValidateJob(t *testing.T) { ObjectMeta: metav1.ObjectMeta{ Labels: map[string]string{batch.LegacyJobNameLabel: "myjob"}, }, - Spec: api.PodSpec{ - RestartPolicy: api.RestartPolicyOnFailure, - DNSPolicy: api.DNSClusterFirst, - Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: api.TerminationMessageReadFile}}, - InitContainers: []api.Container{{Name: "def", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: api.TerminationMessageReadFile}}, - }, + Spec: podtest.MakePodSpec(api.RestartPolicyOnFailure), }, }, }, @@ -1462,12 +1420,7 @@ func TestValidateJob(t *testing.T) { ObjectMeta: metav1.ObjectMeta{ Labels: map[string]string{batch.JobNameLabel: "myjob", batch.LegacyControllerUidLabel: "1a2b3c", batch.LegacyJobNameLabel: "myjob"}, }, - Spec: api.PodSpec{ - RestartPolicy: api.RestartPolicyOnFailure, - DNSPolicy: api.DNSClusterFirst, - Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: api.TerminationMessageReadFile}}, - InitContainers: []api.Container{{Name: "def", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: api.TerminationMessageReadFile}}, - }, + Spec: podtest.MakePodSpec(api.RestartPolicyOnFailure), }, }, }, @@ -2882,11 +2835,7 @@ func TestValidateCronJob(t *testing.T) { JobTemplate: batch.JobTemplateSpec{ Spec: batch.JobSpec{ Template: api.PodTemplateSpec{ - Spec: api.PodSpec{ - RestartPolicy: api.RestartPolicyAlways, - DNSPolicy: api.DNSClusterFirst, - Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: api.TerminationMessageReadFile}}, - }, + Spec: podtest.MakePodSpec(api.RestartPolicyAlways), }, }, }, @@ -2904,11 +2853,7 @@ func TestValidateCronJob(t *testing.T) { JobTemplate: batch.JobTemplateSpec{ Spec: batch.JobSpec{ Template: api.PodTemplateSpec{ - Spec: api.PodSpec{ - RestartPolicy: "Invalid", - DNSPolicy: api.DNSClusterFirst, - Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: api.TerminationMessageReadFile}}, - }, + Spec: podtest.MakePodSpec("Invalid"), }, }, }, diff --git a/pkg/apis/core/validation/validation.go b/pkg/apis/core/validation/validation.go index af00ae14737..7eadbe664d6 100644 --- a/pkg/apis/core/validation/validation.go +++ b/pkg/apis/core/validation/validation.go @@ -3039,7 +3039,7 @@ func validatePodResourceClaim(podMeta *metav1.ObjectMeta, claim core.PodResource return allErrs } -func validateLivenessProbe(probe *core.Probe, gracePeriod int64, fldPath *field.Path) field.ErrorList { +func validateLivenessProbe(probe *core.Probe, gracePeriod *int64, fldPath *field.Path) field.ErrorList { allErrs := field.ErrorList{} if probe == nil { @@ -3052,7 +3052,7 @@ func validateLivenessProbe(probe *core.Probe, gracePeriod int64, fldPath *field. return allErrs } -func validateReadinessProbe(probe *core.Probe, gracePeriod int64, fldPath *field.Path) field.ErrorList { +func validateReadinessProbe(probe *core.Probe, gracePeriod *int64, fldPath *field.Path) field.ErrorList { allErrs := field.ErrorList{} if probe == nil { @@ -3065,7 +3065,7 @@ func validateReadinessProbe(probe *core.Probe, gracePeriod int64, fldPath *field return allErrs } -func validateStartupProbe(probe *core.Probe, gracePeriod int64, fldPath *field.Path) field.ErrorList { +func validateStartupProbe(probe *core.Probe, gracePeriod *int64, fldPath *field.Path) field.ErrorList { allErrs := field.ErrorList{} if probe == nil { @@ -3078,7 +3078,7 @@ func validateStartupProbe(probe *core.Probe, gracePeriod int64, fldPath *field.P return allErrs } -func validateProbe(probe *core.Probe, gracePeriod int64, fldPath *field.Path) field.ErrorList { +func validateProbe(probe *core.Probe, gracePeriod *int64, fldPath *field.Path) field.ErrorList { allErrs := field.ErrorList{} if probe == nil { @@ -3140,10 +3140,10 @@ func handlerFromLifecycle(lh *core.LifecycleHandler) commonHandler { } } -func validateSleepAction(sleep *core.SleepAction, gracePeriod int64, fldPath *field.Path) field.ErrorList { +func validateSleepAction(sleep *core.SleepAction, gracePeriod *int64, fldPath *field.Path) field.ErrorList { allErrors := field.ErrorList{} - if sleep.Seconds <= 0 || sleep.Seconds > gracePeriod { - invalidStr := fmt.Sprintf("must be greater than 0 and less than terminationGracePeriodSeconds (%d)", gracePeriod) + if gracePeriod != nil && sleep.Seconds <= 0 || sleep.Seconds > *gracePeriod { + invalidStr := fmt.Sprintf("must be greater than 0 and less than terminationGracePeriodSeconds (%d)", *gracePeriod) allErrors = append(allErrors, field.Invalid(fldPath, sleep.Seconds, invalidStr)) } return allErrors @@ -3257,7 +3257,7 @@ func validateTCPSocketAction(tcp *core.TCPSocketAction, fldPath *field.Path) fie func validateGRPCAction(grpc *core.GRPCAction, fldPath *field.Path) field.ErrorList { return ValidatePortNumOrName(intstr.FromInt32(grpc.Port), fldPath.Child("port")) } -func validateHandler(handler commonHandler, gracePeriod int64, fldPath *field.Path) field.ErrorList { +func validateHandler(handler commonHandler, gracePeriod *int64, fldPath *field.Path) field.ErrorList { numHandlers := 0 allErrors := field.ErrorList{} if handler.Exec != nil { @@ -3306,7 +3306,7 @@ func validateHandler(handler commonHandler, gracePeriod int64, fldPath *field.Pa return allErrors } -func validateLifecycle(lifecycle *core.Lifecycle, gracePeriod int64, fldPath *field.Path) field.ErrorList { +func validateLifecycle(lifecycle *core.Lifecycle, gracePeriod *int64, fldPath *field.Path) field.ErrorList { allErrs := field.ErrorList{} if lifecycle.PostStart != nil { allErrs = append(allErrs, validateHandler(handlerFromLifecycle(lifecycle.PostStart), gracePeriod, fldPath.Child("postStart"))...) @@ -3457,7 +3457,7 @@ func validateFieldAllowList(value interface{}, allowedFields map[string]bool, er } // validateInitContainers is called by pod spec and template validation to validate the list of init containers -func validateInitContainers(containers []core.Container, regularContainers []core.Container, volumes map[string]core.VolumeSource, podClaimNames sets.Set[string], gracePeriod int64, fldPath *field.Path, opts PodValidationOptions, podRestartPolicy *core.RestartPolicy, hostUsers bool) field.ErrorList { +func validateInitContainers(containers []core.Container, regularContainers []core.Container, volumes map[string]core.VolumeSource, podClaimNames sets.Set[string], gracePeriod *int64, fldPath *field.Path, opts PodValidationOptions, podRestartPolicy *core.RestartPolicy, hostUsers bool) field.ErrorList { var allErrs field.ErrorList allNames := sets.Set[string]{} @@ -3595,7 +3595,7 @@ func validateHostUsers(spec *core.PodSpec, fldPath *field.Path) field.ErrorList } // validateContainers is called by pod spec and template validation to validate the list of regular containers. -func validateContainers(containers []core.Container, volumes map[string]core.VolumeSource, podClaimNames sets.Set[string], gracePeriod int64, fldPath *field.Path, opts PodValidationOptions, podRestartPolicy *core.RestartPolicy, hostUsers bool) field.ErrorList { +func validateContainers(containers []core.Container, volumes map[string]core.VolumeSource, podClaimNames sets.Set[string], gracePeriod *int64, fldPath *field.Path, opts PodValidationOptions, podRestartPolicy *core.RestartPolicy, hostUsers bool) field.ErrorList { allErrs := field.ErrorList{} if len(containers) == 0 { @@ -4145,11 +4145,10 @@ func validateHostIPs(pod *core.Pod) field.ErrorList { func ValidatePodSpec(spec *core.PodSpec, podMeta *metav1.ObjectMeta, fldPath *field.Path, opts PodValidationOptions) field.ErrorList { allErrs := field.ErrorList{} - var gracePeriod int64 - if spec.TerminationGracePeriodSeconds != nil { - // this could happen in tests - gracePeriod = *spec.TerminationGracePeriodSeconds + if spec.TerminationGracePeriodSeconds == nil { + allErrs = append(allErrs, field.Required(fldPath.Child("terminationGracePeriodSeconds"), "")) } + gracePeriod := spec.TerminationGracePeriodSeconds // The default for hostUsers is true, so a spec with no SecurityContext or no HostUsers field will be true. // If the default ever changes, this condition will need to be changed. diff --git a/pkg/apis/core/validation/validation_test.go b/pkg/apis/core/validation/validation_test.go index 27f996fca95..855582aee1b 100644 --- a/pkg/apis/core/validation/validation_test.go +++ b/pkg/apis/core/validation/validation_test.go @@ -42,6 +42,7 @@ import ( "k8s.io/component-base/featuregate" featuregatetesting "k8s.io/component-base/featuregate/testing" kubeletapis "k8s.io/kubelet/pkg/apis" + podtest "k8s.io/kubernetes/pkg/api/pod/testing" "k8s.io/kubernetes/pkg/apis/core" "k8s.io/kubernetes/pkg/capabilities" "k8s.io/kubernetes/pkg/features" @@ -54,7 +55,6 @@ const ( dnsSubdomainLabelErrMsg = "a lowercase RFC 1123 subdomain" envVarNameErrMsg = "a valid environment variable name must consist of" relaxedEnvVarNameFmtErrMsg string = "a valid environment variable name must consist only of printable ASCII characters other than '='" - defaultGracePeriod = int64(30) noUserNamespace = false ) @@ -64,6 +64,7 @@ var ( containerRestartPolicyNever = core.ContainerRestartPolicy("Never") containerRestartPolicyInvalid = core.ContainerRestartPolicy("invalid") containerRestartPolicyEmpty = core.ContainerRestartPolicy("") + defaultGracePeriod = ptr.To[int64](30) ) type topologyPair struct { @@ -5406,126 +5407,82 @@ func TestHugePagesIsolation(t *testing.T) { expectError bool }{ "Valid: request hugepages-2Mi": { - pod: &core.Pod{ - ObjectMeta: metav1.ObjectMeta{Name: "123", Namespace: "ns"}, - Spec: core.PodSpec{ - Containers: []core.Container{{ - Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File", - Resources: core.ResourceRequirements{ - Requests: core.ResourceList{ - core.ResourceName(core.ResourceCPU): resource.MustParse("10"), - core.ResourceName(core.ResourceMemory): resource.MustParse("10G"), - core.ResourceName("hugepages-2Mi"): resource.MustParse("1Gi"), - }, - Limits: core.ResourceList{ - core.ResourceName(core.ResourceCPU): resource.MustParse("10"), - core.ResourceName(core.ResourceMemory): resource.MustParse("10G"), - core.ResourceName("hugepages-2Mi"): resource.MustParse("1Gi"), - }, + pod: podtest.MakePod("123", + podtest.SetContainers(podtest.MakeContainer("ctr", podtest.SetContainerResources( + podtest.MakeResourceRequirements( + map[string]string{ + string(core.ResourceCPU): "10", + string(core.ResourceMemory): "10G", + "hugepages-2Mi": "1Gi", }, - }}, - RestartPolicy: core.RestartPolicyAlways, - DNSPolicy: core.DNSClusterFirst, - }, - }, + map[string]string{ + string(core.ResourceCPU): "10", + string(core.ResourceMemory): "10G", + "hugepages-2Mi": "1Gi", + }))))), }, "Valid: request more than one hugepages size": { - pod: &core.Pod{ - ObjectMeta: metav1.ObjectMeta{Name: "hugepages-shared", Namespace: "ns"}, - Spec: core.PodSpec{ - Containers: []core.Container{{ - Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File", - Resources: core.ResourceRequirements{ - Requests: core.ResourceList{ - core.ResourceName(core.ResourceCPU): resource.MustParse("10"), - core.ResourceName(core.ResourceMemory): resource.MustParse("10G"), - core.ResourceName("hugepages-2Mi"): resource.MustParse("1Gi"), - core.ResourceName("hugepages-1Gi"): resource.MustParse("2Gi"), - }, - Limits: core.ResourceList{ - core.ResourceName(core.ResourceCPU): resource.MustParse("10"), - core.ResourceName(core.ResourceMemory): resource.MustParse("10G"), - core.ResourceName("hugepages-2Mi"): resource.MustParse("1Gi"), - core.ResourceName("hugepages-1Gi"): resource.MustParse("2Gi"), - }, + pod: podtest.MakePod("hugepages-shared", + podtest.SetContainers(podtest.MakeContainer("ctr", podtest.SetContainerResources( + podtest.MakeResourceRequirements( + map[string]string{ + string(core.ResourceCPU): "10", + string(core.ResourceMemory): "10G", + "hugepages-2Mi": "1Gi", + "hugepages-1Gi": "2Gi", }, - }}, - RestartPolicy: core.RestartPolicyAlways, - DNSPolicy: core.DNSClusterFirst, - }, - }, + map[string]string{ + string(core.ResourceCPU): "10", + string(core.ResourceMemory): "10G", + "hugepages-2Mi": "1Gi", + "hugepages-1Gi": "2Gi", + }))))), expectError: false, }, "Valid: request hugepages-1Gi, limit hugepages-2Mi and hugepages-1Gi": { - pod: &core.Pod{ - ObjectMeta: metav1.ObjectMeta{Name: "hugepages-multiple", Namespace: "ns"}, - Spec: core.PodSpec{ - Containers: []core.Container{{ - Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File", - Resources: core.ResourceRequirements{ - Requests: core.ResourceList{ - core.ResourceName(core.ResourceCPU): resource.MustParse("10"), - core.ResourceName(core.ResourceMemory): resource.MustParse("10G"), - core.ResourceName("hugepages-2Mi"): resource.MustParse("1Gi"), - core.ResourceName("hugepages-1Gi"): resource.MustParse("2Gi"), - }, - Limits: core.ResourceList{ - core.ResourceName(core.ResourceCPU): resource.MustParse("10"), - core.ResourceName(core.ResourceMemory): resource.MustParse("10G"), - core.ResourceName("hugepages-2Mi"): resource.MustParse("1Gi"), - core.ResourceName("hugepages-1Gi"): resource.MustParse("2Gi"), - }, + pod: podtest.MakePod("hugepages-multiple", + podtest.SetContainers(podtest.MakeContainer("ctr", podtest.SetContainerResources( + podtest.MakeResourceRequirements( + map[string]string{ + string(core.ResourceCPU): "10", + string(core.ResourceMemory): "10G", + "hugepages-2Mi": "1Gi", + "hugepages-1Gi": "2Gi", }, - }}, - RestartPolicy: core.RestartPolicyAlways, - DNSPolicy: core.DNSClusterFirst, - }, - }, + map[string]string{ + string(core.ResourceCPU): "10", + string(core.ResourceMemory): "10G", + "hugepages-2Mi": "1Gi", + "hugepages-1Gi": "2Gi", + }))))), }, "Invalid: not requesting cpu and memory": { - pod: &core.Pod{ - ObjectMeta: metav1.ObjectMeta{Name: "hugepages-requireCpuOrMemory", Namespace: "ns"}, - Spec: core.PodSpec{ - Containers: []core.Container{{ - Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File", - Resources: core.ResourceRequirements{ - Requests: core.ResourceList{ - core.ResourceName("hugepages-2Mi"): resource.MustParse("1Gi"), - }, - Limits: core.ResourceList{ - core.ResourceName("hugepages-2Mi"): resource.MustParse("1Gi"), - }, + pod: podtest.MakePod("hugepages-requireCpuOrMemory", + podtest.SetContainers(podtest.MakeContainer("ctr", podtest.SetContainerResources( + podtest.MakeResourceRequirements( + map[string]string{ + "hugepages-2Mi": "1Gi", }, - }}, - RestartPolicy: core.RestartPolicyAlways, - DNSPolicy: core.DNSClusterFirst, - }, - }, + map[string]string{ + "hugepages-2Mi": "1Gi", + }))))), expectError: true, }, "Invalid: request 1Gi hugepages-2Mi but limit 2Gi": { - pod: &core.Pod{ - ObjectMeta: metav1.ObjectMeta{Name: "hugepages-shared", Namespace: "ns"}, - Spec: core.PodSpec{ - Containers: []core.Container{{ - Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File", - Resources: core.ResourceRequirements{ - Requests: core.ResourceList{ - core.ResourceName(core.ResourceCPU): resource.MustParse("10"), - core.ResourceName(core.ResourceMemory): resource.MustParse("10G"), - core.ResourceName("hugepages-2Mi"): resource.MustParse("1Gi"), + pod: podtest.MakePod("hugepages-shared", + podtest.SetContainers(podtest.MakeContainer("ctr", + podtest.SetContainerResources( + podtest.MakeResourceRequirements( + map[string]string{ + string(core.ResourceCPU): "10", + string(core.ResourceMemory): "10G", + "hugepages-2Mi": "1Gi", }, - Limits: core.ResourceList{ - core.ResourceName(core.ResourceCPU): resource.MustParse("10"), - core.ResourceName(core.ResourceMemory): resource.MustParse("10G"), - core.ResourceName("hugepages-2Mi"): resource.MustParse("2Gi"), - }, - }, - }}, - RestartPolicy: core.RestartPolicyAlways, - DNSPolicy: core.DNSClusterFirst, - }, - }, + map[string]string{ + string(core.ResourceCPU): "10", + string(core.ResourceMemory): "10G", + "hugepages-2Mi": "2Gi", + }))))), expectError: true, }, } @@ -9940,7 +9897,6 @@ func TestValidatePodConditions(t *testing.T) { } func TestValidatePodSpec(t *testing.T) { - activeDeadlineSeconds := int64(30) activeDeadlineSecondsMax := int64(math.MaxInt32) minUserID := int64(0) @@ -9951,173 +9907,126 @@ func TestValidatePodSpec(t *testing.T) { badfsGroupChangePolicy1 := core.PodFSGroupChangePolicy("invalid") badfsGroupChangePolicy2 := core.PodFSGroupChangePolicy("") - successCases := map[string]core.PodSpec{ - "populate basic fields, leave defaults for most": { - Volumes: []core.Volume{{Name: "vol", VolumeSource: core.VolumeSource{EmptyDir: &core.EmptyDirVolumeSource{}}}}, - Containers: []core.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, - RestartPolicy: core.RestartPolicyAlways, - DNSPolicy: core.DNSClusterFirst, - }, - "populate all fields": { - Volumes: []core.Volume{ - {Name: "vol", VolumeSource: core.VolumeSource{EmptyDir: &core.EmptyDirVolumeSource{}}}, - }, - Containers: []core.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, - InitContainers: []core.Container{{Name: "ictr", Image: "iimage", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, - RestartPolicy: core.RestartPolicyAlways, - NodeSelector: map[string]string{ + successCases := map[string]core.Pod{ + "populate basic fields, leave defaults for most": *podtest.MakePod(""), + "populate all fields": *podtest.MakePod("", + podtest.SetInitContainers(podtest.MakeContainer("ictr")), + podtest.SetVolumes(podtest.MakeEmptyVolume(("vol"))), + podtest.SetNodeSelector(map[string]string{ "key": "value", - }, - NodeName: "foobar", - DNSPolicy: core.DNSClusterFirst, - ActiveDeadlineSeconds: &activeDeadlineSeconds, - ServiceAccountName: "acct", - }, - "populate all fields with larger active deadline": { - Volumes: []core.Volume{ - {Name: "vol", VolumeSource: core.VolumeSource{EmptyDir: &core.EmptyDirVolumeSource{}}}, - }, - Containers: []core.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, - InitContainers: []core.Container{{Name: "ictr", Image: "iimage", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, - RestartPolicy: core.RestartPolicyAlways, - NodeSelector: map[string]string{ - "key": "value", - }, - NodeName: "foobar", - DNSPolicy: core.DNSClusterFirst, - ActiveDeadlineSeconds: &activeDeadlineSecondsMax, - ServiceAccountName: "acct", - }, - "populate HostNetwork": { - Containers: []core.Container{ - {Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File", - Ports: []core.ContainerPort{ - {HostPort: 8080, ContainerPort: 8080, Protocol: "TCP"}}, - }, - }, - SecurityContext: &core.PodSecurityContext{ - HostNetwork: true, - }, - RestartPolicy: core.RestartPolicyAlways, - DNSPolicy: core.DNSClusterFirst, - }, - "populate RunAsUser SupplementalGroups FSGroup with minID 0": { - Containers: []core.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, - SecurityContext: &core.PodSecurityContext{ + }), + podtest.SetNodeName("foobar"), + podtest.SetActiveDeadlineSeconds(activeDeadlineSecondsMax), + podtest.SetServiceAccountName("acct"), + ), + "populate HostNetwork": *podtest.MakePod("", + podtest.SetContainers(podtest.MakeContainer("ctr", + podtest.SetContainerPorts(core.ContainerPort{HostPort: 8080, ContainerPort: 8080, Protocol: "TCP"}))), + podtest.SetSecurityContext(&core.PodSecurityContext{HostNetwork: true}), + ), + "populate RunAsUser SupplementalGroups FSGroup with minID 0": *podtest.MakePod("", + podtest.SetSecurityContext(&core.PodSecurityContext{ SupplementalGroups: []int64{minGroupID}, RunAsUser: &minUserID, FSGroup: &minGroupID, - }, - RestartPolicy: core.RestartPolicyAlways, - DNSPolicy: core.DNSClusterFirst, - }, - "populate RunAsUser SupplementalGroups FSGroup with maxID 2147483647": { - Containers: []core.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, - SecurityContext: &core.PodSecurityContext{ + }), + ), + "populate RunAsUser SupplementalGroups FSGroup with maxID 2147483647": *podtest.MakePod("", + podtest.SetSecurityContext(&core.PodSecurityContext{ SupplementalGroups: []int64{maxGroupID}, RunAsUser: &maxUserID, FSGroup: &maxGroupID, - }, - RestartPolicy: core.RestartPolicyAlways, - DNSPolicy: core.DNSClusterFirst, - }, - "populate HostIPC": { - SecurityContext: &core.PodSecurityContext{ + }), + ), + "populate HostIPC": *podtest.MakePod("", + podtest.SetSecurityContext(&core.PodSecurityContext{ HostIPC: true, - }, - Volumes: []core.Volume{{Name: "vol", VolumeSource: core.VolumeSource{EmptyDir: &core.EmptyDirVolumeSource{}}}}, - Containers: []core.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, - RestartPolicy: core.RestartPolicyAlways, - DNSPolicy: core.DNSClusterFirst, - }, - "populate HostPID": { - SecurityContext: &core.PodSecurityContext{ + }), + ), + "populate HostPID": *podtest.MakePod("", + podtest.SetSecurityContext(&core.PodSecurityContext{ HostPID: true, - }, - Volumes: []core.Volume{{Name: "vol", VolumeSource: core.VolumeSource{EmptyDir: &core.EmptyDirVolumeSource{}}}}, - Containers: []core.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, - RestartPolicy: core.RestartPolicyAlways, - DNSPolicy: core.DNSClusterFirst, - }, - "populate Affinity": { - Volumes: []core.Volume{{Name: "vol", VolumeSource: core.VolumeSource{EmptyDir: &core.EmptyDirVolumeSource{}}}}, - Containers: []core.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, - RestartPolicy: core.RestartPolicyAlways, - DNSPolicy: core.DNSClusterFirst, - }, - "populate HostAliases": { - HostAliases: []core.HostAlias{{IP: "12.34.56.78", Hostnames: []string{"host1", "host2"}}}, - Volumes: []core.Volume{{Name: "vol", VolumeSource: core.VolumeSource{EmptyDir: &core.EmptyDirVolumeSource{}}}}, - Containers: []core.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, - RestartPolicy: core.RestartPolicyAlways, - DNSPolicy: core.DNSClusterFirst, - }, - "populate HostAliases with `foo.bar` hostnames": { - HostAliases: []core.HostAlias{{IP: "12.34.56.78", Hostnames: []string{"host1.foo", "host2.bar"}}}, - Volumes: []core.Volume{{Name: "vol", VolumeSource: core.VolumeSource{EmptyDir: &core.EmptyDirVolumeSource{}}}}, - Containers: []core.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, - RestartPolicy: core.RestartPolicyAlways, - DNSPolicy: core.DNSClusterFirst, - }, - "populate HostAliases with HostNetwork": { - HostAliases: []core.HostAlias{{IP: "12.34.56.78", Hostnames: []string{"host1.foo", "host2.bar"}}}, - Containers: []core.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, - SecurityContext: &core.PodSecurityContext{ + }), + ), + "populate Affinity": *podtest.MakePod("", + podtest.SetAffinity(&core.Affinity{ + NodeAffinity: &core.NodeAffinity{ + RequiredDuringSchedulingIgnoredDuringExecution: &core.NodeSelector{ + NodeSelectorTerms: []core.NodeSelectorTerm{{ + MatchExpressions: []core.NodeSelectorRequirement{{ + Key: "key2", + Operator: core.NodeSelectorOpIn, + Values: []string{"value1", "value2"}, + }}, + MatchFields: []core.NodeSelectorRequirement{{ + Key: "metadata.name", + Operator: core.NodeSelectorOpIn, + Values: []string{"host1"}, + }}, + }}, + }, + PreferredDuringSchedulingIgnoredDuringExecution: []core.PreferredSchedulingTerm{{ + Weight: 10, + Preference: core.NodeSelectorTerm{ + MatchExpressions: []core.NodeSelectorRequirement{{ + Key: "foo", + Operator: core.NodeSelectorOpIn, + Values: []string{"bar"}, + }}, + }, + }}, + }, + }), + ), + "populate HostAliases": *podtest.MakePod("", + podtest.SetHostAliases(core.HostAlias{IP: "12.34.56.78", Hostnames: []string{"host1", "host2"}}), + ), + "populate HostAliases with `foo.bar` hostnames": *podtest.MakePod("", + podtest.SetHostAliases(core.HostAlias{IP: "12.34.56.78", Hostnames: []string{"host1.foo", "host2.bar"}}), + ), + "populate HostAliases with HostNetwork": *podtest.MakePod("", + podtest.SetHostAliases(core.HostAlias{IP: "12.34.56.78", Hostnames: []string{"host1.foo", "host2.bar"}}), + podtest.SetSecurityContext(&core.PodSecurityContext{ HostNetwork: true, - }, - RestartPolicy: core.RestartPolicyAlways, - DNSPolicy: core.DNSClusterFirst, - }, - "populate PriorityClassName": { - Volumes: []core.Volume{{Name: "vol", VolumeSource: core.VolumeSource{EmptyDir: &core.EmptyDirVolumeSource{}}}}, - Containers: []core.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, - RestartPolicy: core.RestartPolicyAlways, - DNSPolicy: core.DNSClusterFirst, - PriorityClassName: "valid-name", - }, - "populate ShareProcessNamespace": { - Volumes: []core.Volume{{Name: "vol", VolumeSource: core.VolumeSource{EmptyDir: &core.EmptyDirVolumeSource{}}}}, - Containers: []core.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, - RestartPolicy: core.RestartPolicyAlways, - DNSPolicy: core.DNSClusterFirst, - SecurityContext: &core.PodSecurityContext{ + }), + ), + "populate PriorityClassName": *podtest.MakePod("", + podtest.SetPriorityClassName("valid-name"), + ), + "populate ShareProcessNamespace": *podtest.MakePod("", + podtest.SetSecurityContext(&core.PodSecurityContext{ ShareProcessNamespace: &[]bool{true}[0], - }, - }, - "populate RuntimeClassName": { - Containers: []core.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, - RestartPolicy: core.RestartPolicyAlways, - DNSPolicy: core.DNSClusterFirst, - RuntimeClassName: utilpointer.String("valid-sandbox"), - }, - "populate Overhead": { - Containers: []core.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, - RestartPolicy: core.RestartPolicyAlways, - DNSPolicy: core.DNSClusterFirst, - RuntimeClassName: utilpointer.String("valid-sandbox"), - Overhead: core.ResourceList{}, - }, - "populate DNSPolicy": { - Containers: []core.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, - SecurityContext: &core.PodSecurityContext{ + }), + ), + "populate RuntimeClassName": *podtest.MakePod("", + podtest.SetRuntimeClassName("valid-sandbox"), + ), + "populate Overhead": *podtest.MakePod("", + podtest.SetOverhead(core.ResourceList{}), + ), + "populate FSGroupChangePolicy": *podtest.MakePod("", + podtest.SetSecurityContext(&core.PodSecurityContext{ FSGroupChangePolicy: &goodfsGroupChangePolicy, - }, - RestartPolicy: core.RestartPolicyAlways, - DNSPolicy: core.DNSClusterFirst, - }, + }), + ), + "resources resize policy for containers": *podtest.MakePod("", + podtest.SetContainers(podtest.MakeContainer("ctr", podtest.SetContainerResizePolicy( + core.ContainerResizePolicy{ResourceName: "cpu", RestartPolicy: "NotRequired"}), + )), + ), } for k, v := range successCases { t.Run(k, func(t *testing.T) { opts := PodValidationOptions{ ResourceIsPod: true, } - if errs := ValidatePodSpec(&v, nil, field.NewPath("field"), opts); len(errs) != 0 { + if errs := ValidatePodSpec(&v.Spec, nil, field.NewPath("field"), opts); len(errs) != 0 { t.Errorf("expected success: %v", errs) } }) } - activeDeadlineSeconds = int64(0) + activeDeadlineSecondsZero := int64(0) activeDeadlineSecondsTooLarge := int64(math.MaxInt32 + 1) minUserID = int64(-1) @@ -10125,254 +10034,118 @@ func TestValidatePodSpec(t *testing.T) { minGroupID = int64(-1) maxGroupID = int64(2147483648) - failureCases := map[string]core.PodSpec{ - "bad volume": { - Volumes: []core.Volume{{}}, - RestartPolicy: core.RestartPolicyAlways, - DNSPolicy: core.DNSClusterFirst, - Containers: []core.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, - }, - "no containers": { - RestartPolicy: core.RestartPolicyAlways, - DNSPolicy: core.DNSClusterFirst, - }, - "bad container": { - Containers: []core.Container{{}}, - RestartPolicy: core.RestartPolicyAlways, - DNSPolicy: core.DNSClusterFirst, - }, - "bad init container": { - Containers: []core.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, - InitContainers: []core.Container{{}}, - RestartPolicy: core.RestartPolicyAlways, - DNSPolicy: core.DNSClusterFirst, - }, - "bad DNS policy": { - DNSPolicy: core.DNSPolicy("invalid"), - RestartPolicy: core.RestartPolicyAlways, - Containers: []core.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, - }, - "bad service account name": { - Containers: []core.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, - RestartPolicy: core.RestartPolicyAlways, - DNSPolicy: core.DNSClusterFirst, - ServiceAccountName: "invalidName", - }, - "bad restart policy": { - RestartPolicy: "UnknowPolicy", - DNSPolicy: core.DNSClusterFirst, - Containers: []core.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, - }, - "with hostNetwork hostPort unspecified": { - Containers: []core.Container{ - {Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", Ports: []core.ContainerPort{ - {HostPort: 0, ContainerPort: 2600, Protocol: "TCP"}}, - }, - }, - SecurityContext: &core.PodSecurityContext{ + failureCases := map[string]core.Pod{ + "bad volume": *podtest.MakePod("", podtest.SetVolumes(core.Volume{})), + "no containers": *podtest.MakePod("", podtest.SetContainers()), + "bad container": *podtest.MakePod("", podtest.SetContainers(core.Container{})), + "bad init container": *podtest.MakePod("", podtest.SetInitContainers(core.Container{})), + "bad DNS policy": *podtest.MakePod("", podtest.SetDNSPolicy(core.DNSPolicy("invalid"))), + "bad service account name": *podtest.MakePod("", podtest.SetServiceAccountName("invalidName")), + "bad restart policy": *podtest.MakePod("", podtest.SetRestartPolicy("UnknowPolicy")), + "with hostNetwork hostPort unspecified": *podtest.MakePod("", + podtest.SetContainers(podtest.MakeContainer("ctr", + podtest.SetContainerPorts(core.ContainerPort{HostPort: 0, ContainerPort: 2600, Protocol: "TCP"}))), + podtest.SetSecurityContext(&core.PodSecurityContext{ HostNetwork: true, - }, - RestartPolicy: core.RestartPolicyAlways, - DNSPolicy: core.DNSClusterFirst, - }, - "with hostNetwork hostPort not equal to containerPort": { - Containers: []core.Container{ - {Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", Ports: []core.ContainerPort{ - {HostPort: 8080, ContainerPort: 2600, Protocol: "TCP"}}, - }, - }, - SecurityContext: &core.PodSecurityContext{ + }), + ), + "with hostNetwork hostPort not equal to containerPort": *podtest.MakePod("", + podtest.SetContainers(podtest.MakeContainer("ctr", + podtest.SetContainerPorts(core.ContainerPort{HostPort: 8080, ContainerPort: 2600, Protocol: "TCP"}))), + podtest.SetSecurityContext(&core.PodSecurityContext{ HostNetwork: true, - }, - RestartPolicy: core.RestartPolicyAlways, - DNSPolicy: core.DNSClusterFirst, - }, - "with hostAliases with invalid IP": { - SecurityContext: &core.PodSecurityContext{ + }), + ), + "with hostAliases with invalid IP": *podtest.MakePod("", + podtest.SetSecurityContext(&core.PodSecurityContext{ HostNetwork: false, - }, - HostAliases: []core.HostAlias{{IP: "999.999.999.999", Hostnames: []string{"host1", "host2"}}}, - }, - "with hostAliases with invalid hostname": { - SecurityContext: &core.PodSecurityContext{ + }), + podtest.SetHostAliases(core.HostAlias{IP: "999.999.999.999", Hostnames: []string{"host1", "host2"}}), + ), + "with hostAliases with invalid hostname": *podtest.MakePod("", + podtest.SetSecurityContext(&core.PodSecurityContext{ HostNetwork: false, - }, - HostAliases: []core.HostAlias{{IP: "12.34.56.78", Hostnames: []string{"@#$^#@#$"}}}, - }, - "bad supplementalGroups large than math.MaxInt32": { - Containers: []core.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, - SecurityContext: &core.PodSecurityContext{ + }), + podtest.SetHostAliases(core.HostAlias{IP: "12.34.56.78", Hostnames: []string{"@#$^#@#$"}}), + ), + "bad supplementalGroups large than math.MaxInt32": *podtest.MakePod("", + podtest.SetSecurityContext(&core.PodSecurityContext{ SupplementalGroups: []int64{maxGroupID, 1234}, - }, - RestartPolicy: core.RestartPolicyAlways, - DNSPolicy: core.DNSClusterFirst, - }, - "bad supplementalGroups less than 0": { - Containers: []core.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, - SecurityContext: &core.PodSecurityContext{ + }), + ), + "bad supplementalGroups less than 0": *podtest.MakePod("", + podtest.SetSecurityContext(&core.PodSecurityContext{ SupplementalGroups: []int64{minGroupID, 1234}, - }, - RestartPolicy: core.RestartPolicyAlways, - DNSPolicy: core.DNSClusterFirst, - }, - "bad runAsUser large than math.MaxInt32": { - Containers: []core.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, - SecurityContext: &core.PodSecurityContext{ + }), + ), + "bad runAsUser large than math.MaxInt32": *podtest.MakePod("", + podtest.SetSecurityContext(&core.PodSecurityContext{ RunAsUser: &maxUserID, - }, - RestartPolicy: core.RestartPolicyAlways, - DNSPolicy: core.DNSClusterFirst, - }, - "bad runAsUser less than 0": { - Containers: []core.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, - SecurityContext: &core.PodSecurityContext{ + }), + ), + "bad runAsUser less than 0": *podtest.MakePod("", + podtest.SetSecurityContext(&core.PodSecurityContext{ RunAsUser: &minUserID, - }, - RestartPolicy: core.RestartPolicyAlways, - DNSPolicy: core.DNSClusterFirst, - }, - "bad fsGroup large than math.MaxInt32": { - Containers: []core.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, - SecurityContext: &core.PodSecurityContext{ + }), + ), + "bad fsGroup large than math.MaxInt32": *podtest.MakePod("", + podtest.SetSecurityContext(&core.PodSecurityContext{ FSGroup: &maxGroupID, - }, - RestartPolicy: core.RestartPolicyAlways, - DNSPolicy: core.DNSClusterFirst, - }, - "bad fsGroup less than 0": { - Containers: []core.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, - SecurityContext: &core.PodSecurityContext{ + }), + ), + "bad fsGroup less than 0": *podtest.MakePod("", + podtest.SetSecurityContext(&core.PodSecurityContext{ FSGroup: &minGroupID, - }, - RestartPolicy: core.RestartPolicyAlways, - DNSPolicy: core.DNSClusterFirst, - }, - "bad-active-deadline-seconds": { - Volumes: []core.Volume{ - {Name: "vol", VolumeSource: core.VolumeSource{EmptyDir: &core.EmptyDirVolumeSource{}}}, - }, - Containers: []core.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, - RestartPolicy: core.RestartPolicyAlways, - NodeSelector: map[string]string{ - "key": "value", - }, - NodeName: "foobar", - DNSPolicy: core.DNSClusterFirst, - ActiveDeadlineSeconds: &activeDeadlineSeconds, - }, - "active-deadline-seconds-too-large": { - Volumes: []core.Volume{ - {Name: "vol", VolumeSource: core.VolumeSource{EmptyDir: &core.EmptyDirVolumeSource{}}}, - }, - Containers: []core.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, - RestartPolicy: core.RestartPolicyAlways, - NodeSelector: map[string]string{ - "key": "value", - }, - NodeName: "foobar", - DNSPolicy: core.DNSClusterFirst, - ActiveDeadlineSeconds: &activeDeadlineSecondsTooLarge, - }, - "bad nodeName": { - NodeName: "node name", - Volumes: []core.Volume{{Name: "vol", VolumeSource: core.VolumeSource{EmptyDir: &core.EmptyDirVolumeSource{}}}}, - Containers: []core.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, - RestartPolicy: core.RestartPolicyAlways, - DNSPolicy: core.DNSClusterFirst, - }, - "bad PriorityClassName": { - Volumes: []core.Volume{{Name: "vol", VolumeSource: core.VolumeSource{EmptyDir: &core.EmptyDirVolumeSource{}}}}, - Containers: []core.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, - RestartPolicy: core.RestartPolicyAlways, - DNSPolicy: core.DNSClusterFirst, - PriorityClassName: "InvalidName", - }, - "ShareProcessNamespace and HostPID both set": { - Volumes: []core.Volume{{Name: "vol", VolumeSource: core.VolumeSource{EmptyDir: &core.EmptyDirVolumeSource{}}}}, - Containers: []core.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, - RestartPolicy: core.RestartPolicyAlways, - DNSPolicy: core.DNSClusterFirst, - SecurityContext: &core.PodSecurityContext{ + }), + ), + "bad-active-deadline-seconds": *podtest.MakePod("", + podtest.SetActiveDeadlineSeconds(activeDeadlineSecondsZero), + ), + "active-deadline-seconds-too-large": *podtest.MakePod("", + podtest.SetActiveDeadlineSeconds(activeDeadlineSecondsTooLarge), + ), + "bad nodeName": *podtest.MakePod("", + podtest.SetNodeName("node name"), + ), + "bad PriorityClassName": *podtest.MakePod("", + podtest.SetPriorityClassName("InvalidName"), + ), + "ShareProcessNamespace and HostPID both set": *podtest.MakePod("", + podtest.SetSecurityContext(&core.PodSecurityContext{ HostPID: true, ShareProcessNamespace: &[]bool{true}[0], - }, - }, - "bad RuntimeClassName": { - Containers: []core.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, - RestartPolicy: core.RestartPolicyAlways, - DNSPolicy: core.DNSClusterFirst, - RuntimeClassName: utilpointer.String("invalid/sandbox"), - }, - "bad empty fsGroupchangepolicy": { - Containers: []core.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, - SecurityContext: &core.PodSecurityContext{ + }), + ), + "bad RuntimeClassName": *podtest.MakePod("", + podtest.SetRuntimeClassName("invalid/sandbox"), + ), + "bad empty fsGroupchangepolicy": *podtest.MakePod("", + podtest.SetSecurityContext(&core.PodSecurityContext{ FSGroupChangePolicy: &badfsGroupChangePolicy2, - }, - RestartPolicy: core.RestartPolicyAlways, - DNSPolicy: core.DNSClusterFirst, - }, - "bad invalid fsgroupchangepolicy": { - Containers: []core.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, - SecurityContext: &core.PodSecurityContext{ + }), + ), + "bad invalid fsgroupchangepolicy": *podtest.MakePod("", + podtest.SetSecurityContext(&core.PodSecurityContext{ FSGroupChangePolicy: &badfsGroupChangePolicy1, - }, - RestartPolicy: core.RestartPolicyAlways, - DNSPolicy: core.DNSClusterFirst, - }, - "disallowed resources resize policy for init containers": { - InitContainers: []core.Container{{ - Name: "initctr", - Image: "initimage", - ResizePolicy: []core.ContainerResizePolicy{ - {ResourceName: "cpu", RestartPolicy: "NotRequired"}, - }, - ImagePullPolicy: "IfNotPresent", - TerminationMessagePolicy: "File", - }}, - Containers: []core.Container{{ - Name: "ctr", - Image: "image", - ResizePolicy: []core.ContainerResizePolicy{ - {ResourceName: "cpu", RestartPolicy: "NotRequired"}, - }, - ImagePullPolicy: "IfNotPresent", - TerminationMessagePolicy: "File", - }}, - RestartPolicy: core.RestartPolicyAlways, - DNSPolicy: core.DNSClusterFirst, - }, + }), + ), + "disallowed resources resize policy for init containers": *podtest.MakePod("", + podtest.SetInitContainers(podtest.MakeContainer("initctr", podtest.SetContainerResizePolicy( + core.ContainerResizePolicy{ResourceName: "cpu", RestartPolicy: "NotRequired"}, + ))), + ), } for k, v := range failureCases { opts := PodValidationOptions{ ResourceIsPod: true, } - if errs := ValidatePodSpec(&v, nil, field.NewPath("field"), opts); len(errs) == 0 { + if errs := ValidatePodSpec(&v.Spec, nil, field.NewPath("field"), opts); len(errs) == 0 { t.Errorf("expected failure for %q", k) } } } -func extendPodSpecwithTolerations(in core.PodSpec, tolerations []core.Toleration) core.PodSpec { - var out core.PodSpec - out.Containers = in.Containers - out.RestartPolicy = in.RestartPolicy - out.DNSPolicy = in.DNSPolicy - out.Tolerations = tolerations - return out -} - func TestValidatePod(t *testing.T) { - validPodSpec := func(affinity *core.Affinity) core.PodSpec { - spec := core.PodSpec{ - Containers: []core.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, - RestartPolicy: core.RestartPolicyAlways, - DNSPolicy: core.DNSClusterFirst, - } - if affinity != nil { - spec.Affinity = affinity - } - return spec - } validPVCSpec := core.PersistentVolumeClaimSpec{ AccessModes: []core.PersistentVolumeAccessMode{ core.ReadWriteOnce, @@ -10390,36 +10163,18 @@ func TestValidatePod(t *testing.T) { longVolName := strings.Repeat("b", 60) successCases := map[string]core.Pod{ - "basic fields": { - ObjectMeta: metav1.ObjectMeta{Name: "123", Namespace: "ns"}, - Spec: core.PodSpec{ - Volumes: []core.Volume{{Name: "vol", VolumeSource: core.VolumeSource{EmptyDir: &core.EmptyDirVolumeSource{}}}}, - Containers: []core.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, - RestartPolicy: core.RestartPolicyAlways, - DNSPolicy: core.DNSClusterFirst, - }, - }, - "just about everything": { - ObjectMeta: metav1.ObjectMeta{Name: "abc.123.do-re-mi", Namespace: "ns"}, - Spec: core.PodSpec{ - Volumes: []core.Volume{ - {Name: "vol", VolumeSource: core.VolumeSource{EmptyDir: &core.EmptyDirVolumeSource{}}}, - }, - Containers: []core.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, - RestartPolicy: core.RestartPolicyAlways, - DNSPolicy: core.DNSClusterFirst, - NodeSelector: map[string]string{ - "key": "value", - }, - NodeName: "foobar", - }, - }, - "serialized node affinity requirements": { - ObjectMeta: metav1.ObjectMeta{ - Name: "123", - Namespace: "ns", - }, - Spec: validPodSpec( + "basic fields": *podtest.MakePod("123"), + "just about everything": *podtest.MakePod("abc.123.do-re-mi", + podtest.SetInitContainers(podtest.MakeContainer("ictr")), + podtest.SetVolumes(podtest.MakeEmptyVolume(("vol"))), + podtest.SetNodeSelector(map[string]string{ + "key": "value", + }), + podtest.SetNodeName("foobar"), + podtest.SetServiceAccountName("acct"), + ), + "serialized node affinity requirements": *podtest.MakePod("123", + podtest.SetAffinity( // TODO: Uncomment and move this block and move inside NodeAffinity once // RequiredDuringSchedulingRequiredDuringExecution is implemented // RequiredDuringSchedulingRequiredDuringExecution: &core.NodeSelector{ @@ -10461,15 +10216,10 @@ func TestValidatePod(t *testing.T) { }, }}, }, - }, - ), - }, - "serialized node affinity requirements, II": { - ObjectMeta: metav1.ObjectMeta{ - Name: "123", - Namespace: "ns", - }, - Spec: validPodSpec( + }), + ), + "serialized node affinity requirements, II": *podtest.MakePod("123", + podtest.SetAffinity( // TODO: Uncomment and move this block and move inside NodeAffinity once // RequiredDuringSchedulingRequiredDuringExecution is implemented // RequiredDuringSchedulingRequiredDuringExecution: &core.NodeSelector{ @@ -10500,11 +10250,9 @@ func TestValidatePod(t *testing.T) { }, }, ), - }, - "serialized pod affinity in affinity requirements in annotations": { - ObjectMeta: metav1.ObjectMeta{ - Name: "123", - Namespace: "ns", + ), + "serialized pod affinity in affinity requirements in annotations": *podtest.MakePod("123", + podtest.SetAffinity( // TODO: Uncomment and move this block into Annotations map once // RequiredDuringSchedulingRequiredDuringExecution is implemented // "requiredDuringSchedulingRequiredDuringExecution": [{ @@ -10518,48 +10266,45 @@ func TestValidatePod(t *testing.T) { // "namespaces":["ns"], // "topologyKey": "zone" // }] - }, - Spec: validPodSpec(&core.Affinity{ - PodAffinity: &core.PodAffinity{ - RequiredDuringSchedulingIgnoredDuringExecution: []core.PodAffinityTerm{{ - LabelSelector: &metav1.LabelSelector{ - MatchExpressions: []metav1.LabelSelectorRequirement{{ - Key: "key2", - Operator: metav1.LabelSelectorOpIn, - Values: []string{"value1", "value2"}, - }}, - }, - TopologyKey: "zone", - Namespaces: []string{"ns"}, - NamespaceSelector: &metav1.LabelSelector{ - MatchExpressions: []metav1.LabelSelectorRequirement{{ - Key: "key", - Operator: metav1.LabelSelectorOpIn, - Values: []string{"value1", "value2"}, - }}, - }, - }}, - PreferredDuringSchedulingIgnoredDuringExecution: []core.WeightedPodAffinityTerm{{ - Weight: 10, - PodAffinityTerm: core.PodAffinityTerm{ + &core.Affinity{ + PodAffinity: &core.PodAffinity{ + RequiredDuringSchedulingIgnoredDuringExecution: []core.PodAffinityTerm{{ LabelSelector: &metav1.LabelSelector{ MatchExpressions: []metav1.LabelSelectorRequirement{{ Key: "key2", - Operator: metav1.LabelSelectorOpNotIn, + Operator: metav1.LabelSelectorOpIn, Values: []string{"value1", "value2"}, }}, }, + TopologyKey: "zone", Namespaces: []string{"ns"}, - TopologyKey: "region", - }, - }}, - }, - }), - }, - "serialized pod anti affinity with different Label Operators in affinity requirements in annotations": { - ObjectMeta: metav1.ObjectMeta{ - Name: "123", - Namespace: "ns", + NamespaceSelector: &metav1.LabelSelector{ + MatchExpressions: []metav1.LabelSelectorRequirement{{ + Key: "key", + Operator: metav1.LabelSelectorOpIn, + Values: []string{"value1", "value2"}, + }}, + }, + }}, + PreferredDuringSchedulingIgnoredDuringExecution: []core.WeightedPodAffinityTerm{{ + Weight: 10, + PodAffinityTerm: core.PodAffinityTerm{ + LabelSelector: &metav1.LabelSelector{ + MatchExpressions: []metav1.LabelSelectorRequirement{{ + Key: "key2", + Operator: metav1.LabelSelectorOpNotIn, + Values: []string{"value1", "value2"}, + }}, + }, + Namespaces: []string{"ns"}, + TopologyKey: "region", + }, + }}, + }, + }), + ), + "serialized pod anti affinity with different Label Operators in affinity requirements in annotations": *podtest.MakePod("123", + podtest.SetAffinity( // TODO: Uncomment and move this block into Annotations map once // RequiredDuringSchedulingRequiredDuringExecution is implemented // "requiredDuringSchedulingRequiredDuringExecution": [{ @@ -10573,604 +10318,371 @@ func TestValidatePod(t *testing.T) { // "namespaces":["ns"], // "topologyKey": "zone" // }] - }, - Spec: validPodSpec(&core.Affinity{ - PodAntiAffinity: &core.PodAntiAffinity{ - RequiredDuringSchedulingIgnoredDuringExecution: []core.PodAffinityTerm{{ - LabelSelector: &metav1.LabelSelector{ - MatchExpressions: []metav1.LabelSelectorRequirement{{ - Key: "key2", - Operator: metav1.LabelSelectorOpExists, - }}, - }, - TopologyKey: "zone", - Namespaces: []string{"ns"}, - }}, - PreferredDuringSchedulingIgnoredDuringExecution: []core.WeightedPodAffinityTerm{{ - Weight: 10, - PodAffinityTerm: core.PodAffinityTerm{ + &core.Affinity{ + PodAntiAffinity: &core.PodAntiAffinity{ + RequiredDuringSchedulingIgnoredDuringExecution: []core.PodAffinityTerm{{ LabelSelector: &metav1.LabelSelector{ MatchExpressions: []metav1.LabelSelectorRequirement{{ Key: "key2", - Operator: metav1.LabelSelectorOpDoesNotExist, + Operator: metav1.LabelSelectorOpExists, }}, }, + TopologyKey: "zone", Namespaces: []string{"ns"}, - TopologyKey: "region", - }, - }}, - }, - }), - }, - "populate forgiveness tolerations with exists operator in annotations.": { - ObjectMeta: metav1.ObjectMeta{ - Name: "123", - Namespace: "ns", - }, - Spec: extendPodSpecwithTolerations(validPodSpec(nil), []core.Toleration{{Key: "foo", Operator: "Exists", Value: "", Effect: "NoExecute", TolerationSeconds: &[]int64{60}[0]}}), - }, - "populate forgiveness tolerations with equal operator in annotations.": { - ObjectMeta: metav1.ObjectMeta{ - Name: "123", - Namespace: "ns", - }, - Spec: extendPodSpecwithTolerations(validPodSpec(nil), []core.Toleration{{Key: "foo", Operator: "Equal", Value: "bar", Effect: "NoExecute", TolerationSeconds: &[]int64{60}[0]}}), - }, - "populate tolerations equal operator in annotations.": { - ObjectMeta: metav1.ObjectMeta{ - Name: "123", - Namespace: "ns", - }, - Spec: extendPodSpecwithTolerations(validPodSpec(nil), []core.Toleration{{Key: "foo", Operator: "Equal", Value: "bar", Effect: "NoSchedule"}}), - }, - "populate tolerations exists operator in annotations.": { - ObjectMeta: metav1.ObjectMeta{ - Name: "123", - Namespace: "ns", - }, - Spec: validPodSpec(nil), - }, - "empty key with Exists operator is OK for toleration, empty toleration key means match all taint keys.": { - ObjectMeta: metav1.ObjectMeta{ - Name: "123", - Namespace: "ns", - }, - Spec: extendPodSpecwithTolerations(validPodSpec(nil), []core.Toleration{{Operator: "Exists", Effect: "NoSchedule"}}), - }, - "empty operator is OK for toleration, defaults to Equal.": { - ObjectMeta: metav1.ObjectMeta{ - Name: "123", - Namespace: "ns", - }, - Spec: extendPodSpecwithTolerations(validPodSpec(nil), []core.Toleration{{Key: "foo", Value: "bar", Effect: "NoSchedule"}}), - }, - "empty effect is OK for toleration, empty toleration effect means match all taint effects.": { - ObjectMeta: metav1.ObjectMeta{ - Name: "123", - Namespace: "ns", - }, - Spec: extendPodSpecwithTolerations(validPodSpec(nil), []core.Toleration{{Key: "foo", Operator: "Equal", Value: "bar"}}), - }, - "negative tolerationSeconds is OK for toleration.": { - ObjectMeta: metav1.ObjectMeta{ - Name: "pod-forgiveness-invalid", - Namespace: "ns", - }, - Spec: extendPodSpecwithTolerations(validPodSpec(nil), []core.Toleration{{Key: "node.kubernetes.io/not-ready", Operator: "Exists", Effect: "NoExecute", TolerationSeconds: &[]int64{-2}[0]}}), - }, - "runtime default seccomp profile": { - ObjectMeta: metav1.ObjectMeta{ - Name: "123", - Namespace: "ns", - Annotations: map[string]string{ - core.SeccompPodAnnotationKey: core.SeccompProfileRuntimeDefault, - }, - }, - Spec: validPodSpec(nil), - }, - "docker default seccomp profile": { - ObjectMeta: metav1.ObjectMeta{ - Name: "123", - Namespace: "ns", - Annotations: map[string]string{ - core.SeccompPodAnnotationKey: core.DeprecatedSeccompProfileDockerDefault, - }, - }, - Spec: validPodSpec(nil), - }, - "unconfined seccomp profile": { - ObjectMeta: metav1.ObjectMeta{ - Name: "123", - Namespace: "ns", - Annotations: map[string]string{ - core.SeccompPodAnnotationKey: "unconfined", - }, - }, - Spec: validPodSpec(nil), - }, - "localhost seccomp profile": { - ObjectMeta: metav1.ObjectMeta{ - Name: "123", - Namespace: "ns", - Annotations: map[string]string{ - core.SeccompPodAnnotationKey: "localhost/foo", - }, - }, - Spec: validPodSpec(nil), - }, - "localhost seccomp profile for a container": { - ObjectMeta: metav1.ObjectMeta{ - Name: "123", - Namespace: "ns", - Annotations: map[string]string{ - core.SeccompContainerAnnotationKeyPrefix + "foo": "localhost/foo", - }, - }, - Spec: validPodSpec(nil), - }, - "runtime default seccomp profile for a pod": { - ObjectMeta: metav1.ObjectMeta{ - Name: "123", - Namespace: "ns", - }, - Spec: core.PodSpec{ - Containers: []core.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, - RestartPolicy: core.RestartPolicyAlways, - DNSPolicy: core.DNSDefault, - SecurityContext: &core.PodSecurityContext{ - SeccompProfile: &core.SeccompProfile{ - Type: core.SeccompProfileTypeRuntimeDefault, + }}, + PreferredDuringSchedulingIgnoredDuringExecution: []core.WeightedPodAffinityTerm{{ + Weight: 10, + PodAffinityTerm: core.PodAffinityTerm{ + LabelSelector: &metav1.LabelSelector{ + MatchExpressions: []metav1.LabelSelectorRequirement{{ + Key: "key2", + Operator: metav1.LabelSelectorOpDoesNotExist, + }}, + }, + Namespaces: []string{"ns"}, + TopologyKey: "region", + }, + }}, }, + }), + ), + "populate forgiveness tolerations with exists operator in annotations.": *podtest.MakePod("123", + podtest.SetTolerations(core.Toleration{Key: "foo", Operator: "Exists", Value: "", Effect: "NoExecute", TolerationSeconds: &[]int64{60}[0]}), + ), + "populate forgiveness tolerations with equal operator in annotations.": *podtest.MakePod("123", + podtest.SetTolerations(core.Toleration{Key: "foo", Operator: "Equal", Value: "bar", Effect: "NoExecute", TolerationSeconds: &[]int64{60}[0]}), + ), + "populate tolerations equal operator in annotations.": *podtest.MakePod("123", + podtest.SetTolerations(core.Toleration{Key: "foo", Operator: "Equal", Value: "bar", Effect: "NoSchedule"}), + ), + "populate tolerations exists operator in annotations.": *podtest.MakePod("123", + podtest.SetVolumes(podtest.MakeEmptyVolume("vol")), + ), + "empty key with Exists operator is OK for toleration, empty toleration key means match all taint keys.": *podtest.MakePod("123", + podtest.SetTolerations(core.Toleration{Operator: "Exists", Effect: "NoSchedule"}), + ), + "empty operator is OK for toleration, defaults to Equal.": *podtest.MakePod("123", + podtest.SetTolerations(core.Toleration{Key: "foo", Value: "bar", Effect: "NoSchedule"}), + ), + "empty effect is OK for toleration, empty toleration effect means match all taint effects.": *podtest.MakePod("123", + podtest.SetTolerations(core.Toleration{Key: "foo", Operator: "Equal", Value: "bar"}), + ), + "negative tolerationSeconds is OK for toleration.": *podtest.MakePod("123", + podtest.SetTolerations( + core.Toleration{Key: "node.kubernetes.io/not-ready", Operator: "Exists", Effect: "NoExecute", TolerationSeconds: &[]int64{-2}[0]}), + ), + "runtime default seccomp profile": *podtest.MakePod("123", + podtest.SetAnnotations(map[string]string{ + core.SeccompPodAnnotationKey: core.SeccompProfileRuntimeDefault, + }, + ), + ), + "docker default seccomp profile": *podtest.MakePod("123", + podtest.SetAnnotations(map[string]string{ + core.SeccompPodAnnotationKey: "unconfined", + }, + ), + ), + "localhost seccomp profile": *podtest.MakePod("123", + podtest.SetAnnotations(map[string]string{ + core.SeccompPodAnnotationKey: "localhost/foo", + }, + ), + ), + "localhost seccomp profile for a container": *podtest.MakePod("123", + podtest.SetAnnotations(map[string]string{ + core.SeccompContainerAnnotationKeyPrefix + "foo": "localhost/foo", + }, + ), + ), + "runtime default seccomp profile for a pod": *podtest.MakePod("123", + podtest.SetSecurityContext(&core.PodSecurityContext{ + SeccompProfile: &core.SeccompProfile{ + Type: core.SeccompProfileTypeRuntimeDefault, }, }, - }, - "runtime default seccomp profile for a container": { - ObjectMeta: metav1.ObjectMeta{ - Name: "123", - Namespace: "ns", - }, - Spec: core.PodSpec{ - Containers: []core.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File", - SecurityContext: &core.SecurityContext{ - SeccompProfile: &core.SeccompProfile{ - Type: core.SeccompProfileTypeRuntimeDefault, - }, - }, - }}, - RestartPolicy: core.RestartPolicyAlways, - DNSPolicy: core.DNSDefault, - }, - }, - "unconfined seccomp profile for a pod": { - ObjectMeta: metav1.ObjectMeta{ - Name: "123", - Namespace: "ns", - }, - Spec: core.PodSpec{ - Containers: []core.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, - RestartPolicy: core.RestartPolicyAlways, - DNSPolicy: core.DNSDefault, - SecurityContext: &core.PodSecurityContext{ + ), + ), + "runtime default seccomp profile for a container": *podtest.MakePod("123", + podtest.SetContainers(podtest.MakeContainer("ctr", + podtest.SetContainerSecurityContext(core.SecurityContext{ SeccompProfile: &core.SeccompProfile{ Type: core.SeccompProfileTypeUnconfined, }, + }), + )), + ), + "unconfined seccomp profile for a pod": *podtest.MakePod("123", + podtest.SetSecurityContext(&core.PodSecurityContext{ + SeccompProfile: &core.SeccompProfile{ + Type: core.SeccompProfileTypeRuntimeDefault, }, - }, - }, - "unconfined seccomp profile for a container": { - ObjectMeta: metav1.ObjectMeta{ - Name: "123", - Namespace: "ns", - }, - Spec: core.PodSpec{ - Containers: []core.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File", - SecurityContext: &core.SecurityContext{ - SeccompProfile: &core.SeccompProfile{ - Type: core.SeccompProfileTypeUnconfined, - }, + }), + ), + "unconfined seccomp profile for a container": *podtest.MakePod("123", + podtest.SetContainers(podtest.MakeContainer("ctr", + podtest.SetContainerSecurityContext(core.SecurityContext{ + SeccompProfile: &core.SeccompProfile{ + Type: core.SeccompProfileTypeUnconfined, }, - }}, - RestartPolicy: core.RestartPolicyAlways, - DNSPolicy: core.DNSDefault, - }, - }, - "localhost seccomp profile for a pod": { - ObjectMeta: metav1.ObjectMeta{ - Name: "123", - Namespace: "ns", - }, - Spec: core.PodSpec{ - Containers: []core.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, - RestartPolicy: core.RestartPolicyAlways, - DNSPolicy: core.DNSDefault, - SecurityContext: &core.PodSecurityContext{ + }), + )), + ), + "localhost seccomp profile for a pod": *podtest.MakePod("123", + podtest.SetSecurityContext(&core.PodSecurityContext{ + SeccompProfile: &core.SeccompProfile{ + Type: core.SeccompProfileTypeLocalhost, + LocalhostProfile: utilpointer.String("filename.json"), + }, + }), + ), + "localhost seccomp profile for a container, II": *podtest.MakePod("123", + podtest.SetContainers(podtest.MakeContainer("ctr", + podtest.SetContainerSecurityContext(core.SecurityContext{ SeccompProfile: &core.SeccompProfile{ Type: core.SeccompProfileTypeLocalhost, LocalhostProfile: utilpointer.String("filename.json"), }, + }), + )), + ), + "default AppArmor annotation for a container": *podtest.MakePod("123", + podtest.SetAnnotations(map[string]string{ + v1.DeprecatedAppArmorBetaContainerAnnotationKeyPrefix + "ctr": v1.DeprecatedAppArmorBetaProfileRuntimeDefault, + }), + ), + "default AppArmor annotation for an init container": *podtest.MakePod("123", + podtest.SetInitContainers(podtest.MakeContainer("init-ctr")), + podtest.SetAnnotations(map[string]string{ + v1.DeprecatedAppArmorBetaContainerAnnotationKeyPrefix + "init-ctr": v1.DeprecatedAppArmorBetaProfileRuntimeDefault, + }), + ), + "localhost AppArmor annotation for a container": *podtest.MakePod("123", + podtest.SetAnnotations(map[string]string{ + v1.DeprecatedAppArmorBetaContainerAnnotationKeyPrefix + "ctr": v1.DeprecatedAppArmorBetaProfileNamePrefix + "foo", + }), + ), + "runtime default AppArmor profile for a pod": *podtest.MakePod("123", + podtest.SetSecurityContext(&core.PodSecurityContext{ + AppArmorProfile: &core.AppArmorProfile{ + Type: core.AppArmorProfileTypeRuntimeDefault, }, - }, - }, - "localhost seccomp profile for a container, II": { - ObjectMeta: metav1.ObjectMeta{ - Name: "123", - Namespace: "ns", - }, - Spec: core.PodSpec{ - Containers: []core.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File", - SecurityContext: &core.SecurityContext{ - SeccompProfile: &core.SeccompProfile{ - Type: core.SeccompProfileTypeLocalhost, - LocalhostProfile: utilpointer.String("filename.json"), - }, - }, - }}, - RestartPolicy: core.RestartPolicyAlways, - DNSPolicy: core.DNSDefault, - }, - }, - "default AppArmor annotation for a container": { - ObjectMeta: metav1.ObjectMeta{ - Name: "123", - Namespace: "ns", - Annotations: map[string]string{ - v1.DeprecatedAppArmorBetaContainerAnnotationKeyPrefix + "ctr": v1.DeprecatedAppArmorBetaProfileRuntimeDefault, - }, - }, - Spec: validPodSpec(nil), - }, - "default AppArmor annotation for an init container": { - ObjectMeta: metav1.ObjectMeta{ - Name: "123", - Namespace: "ns", - Annotations: map[string]string{ - v1.DeprecatedAppArmorBetaContainerAnnotationKeyPrefix + "init-ctr": v1.DeprecatedAppArmorBetaProfileRuntimeDefault, - }, - }, - Spec: core.PodSpec{ - InitContainers: []core.Container{{Name: "init-ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, - Containers: []core.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, - RestartPolicy: core.RestartPolicyAlways, - DNSPolicy: core.DNSClusterFirst, - }, - }, - "localhost AppArmor annotation for a container": { - ObjectMeta: metav1.ObjectMeta{ - Name: "123", - Namespace: "ns", - Annotations: map[string]string{ - v1.DeprecatedAppArmorBetaContainerAnnotationKeyPrefix + "ctr": v1.DeprecatedAppArmorBetaProfileNamePrefix + "foo", - }, - }, - Spec: validPodSpec(nil), - }, - "runtime default AppArmor profile for a pod": { - ObjectMeta: metav1.ObjectMeta{ - Name: "123", - Namespace: "ns", - }, - Spec: core.PodSpec{ - Containers: []core.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, - RestartPolicy: core.RestartPolicyAlways, - DNSPolicy: core.DNSDefault, - SecurityContext: &core.PodSecurityContext{ + }), + ), + "runtime default AppArmor profile for a container": *podtest.MakePod("123", + podtest.SetContainers(podtest.MakeContainer("ctr", + podtest.SetContainerSecurityContext(core.SecurityContext{ AppArmorProfile: &core.AppArmorProfile{ Type: core.AppArmorProfileTypeRuntimeDefault, }, + }), + )), + ), + "unconfined AppArmor profile for a pod": *podtest.MakePod("123", + podtest.SetSecurityContext(&core.PodSecurityContext{ + AppArmorProfile: &core.AppArmorProfile{ + Type: core.AppArmorProfileTypeUnconfined, }, - }, - }, - "runtime default AppArmor profile for a container": { - ObjectMeta: metav1.ObjectMeta{ - Name: "123", - Namespace: "ns", - }, - Spec: core.PodSpec{ - Containers: []core.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File", - SecurityContext: &core.SecurityContext{ - AppArmorProfile: &core.AppArmorProfile{ - Type: core.AppArmorProfileTypeRuntimeDefault, - }, - }, - }}, - RestartPolicy: core.RestartPolicyAlways, - DNSPolicy: core.DNSDefault, - }, - }, - "unconfined AppArmor profile for a pod": { - ObjectMeta: metav1.ObjectMeta{ - Name: "123", - Namespace: "ns", - }, - Spec: core.PodSpec{ - Containers: []core.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, - RestartPolicy: core.RestartPolicyAlways, - DNSPolicy: core.DNSDefault, - SecurityContext: &core.PodSecurityContext{ + }), + ), + "unconfined AppArmor profile for a container": *podtest.MakePod("123", + podtest.SetContainers(podtest.MakeContainer("ctr", + podtest.SetContainerSecurityContext(core.SecurityContext{ AppArmorProfile: &core.AppArmorProfile{ Type: core.AppArmorProfileTypeUnconfined, }, + }), + )), + ), + "localhost AppArmor profile for a pod": *podtest.MakePod("123", + podtest.SetSecurityContext(&core.PodSecurityContext{ + AppArmorProfile: &core.AppArmorProfile{ + Type: core.AppArmorProfileTypeLocalhost, + LocalhostProfile: ptr.To("example-org/application-foo"), }, - }, - }, - "unconfined AppArmor profile for a container": { - ObjectMeta: metav1.ObjectMeta{ - Name: "123", - Namespace: "ns", - }, - Spec: core.PodSpec{ - Containers: []core.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File", - SecurityContext: &core.SecurityContext{ - AppArmorProfile: &core.AppArmorProfile{ - Type: core.AppArmorProfileTypeUnconfined, - }, - }, - }}, - RestartPolicy: core.RestartPolicyAlways, - DNSPolicy: core.DNSDefault, - }, - }, - "localhost AppArmor profile for a pod": { - ObjectMeta: metav1.ObjectMeta{ - Name: "123", - Namespace: "ns", - }, - Spec: core.PodSpec{ - Containers: []core.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, - RestartPolicy: core.RestartPolicyAlways, - DNSPolicy: core.DNSDefault, - SecurityContext: &core.PodSecurityContext{ + }), + ), + "localhost AppArmor profile for a container field": *podtest.MakePod("123", + podtest.SetContainers(podtest.MakeContainer("ctr", + podtest.SetContainerSecurityContext(core.SecurityContext{ AppArmorProfile: &core.AppArmorProfile{ Type: core.AppArmorProfileTypeLocalhost, LocalhostProfile: ptr.To("example-org/application-foo"), }, - }, - }, - }, - "localhost AppArmor profile for a container field": { - ObjectMeta: metav1.ObjectMeta{ - Name: "123", - Namespace: "ns", - }, - Spec: core.PodSpec{ - Containers: []core.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File", - SecurityContext: &core.SecurityContext{ - AppArmorProfile: &core.AppArmorProfile{ - Type: core.AppArmorProfileTypeLocalhost, - LocalhostProfile: ptr.To("example-org/application-foo"), - }, - }, - }}, - RestartPolicy: core.RestartPolicyAlways, - DNSPolicy: core.DNSDefault, - }, - }, - "matching AppArmor fields and annotations": { - ObjectMeta: metav1.ObjectMeta{ - Name: "123", - Namespace: "ns", - Annotations: map[string]string{ - core.DeprecatedAppArmorAnnotationKeyPrefix + "ctr": core.DeprecatedAppArmorAnnotationValueLocalhostPrefix + "foo", - }, - }, - Spec: core.PodSpec{ - Containers: []core.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File", - SecurityContext: &core.SecurityContext{ - AppArmorProfile: &core.AppArmorProfile{ - Type: core.AppArmorProfileTypeLocalhost, - LocalhostProfile: ptr.To("foo"), - }, - }, - }}, - RestartPolicy: core.RestartPolicyAlways, - DNSPolicy: core.DNSDefault, - }, - }, - "matching AppArmor pod field and annotations": { - ObjectMeta: metav1.ObjectMeta{ - Name: "123", - Namespace: "ns", - Annotations: map[string]string{ - core.DeprecatedAppArmorAnnotationKeyPrefix + "ctr": core.DeprecatedAppArmorAnnotationValueLocalhostPrefix + "foo", - }, - }, - Spec: core.PodSpec{ - SecurityContext: &core.PodSecurityContext{ + }), + )), + ), + "matching AppArmor fields and annotations": *podtest.MakePod("123", + podtest.SetAnnotations(map[string]string{ + core.DeprecatedAppArmorAnnotationKeyPrefix + "ctr": core.DeprecatedAppArmorAnnotationValueLocalhostPrefix + "foo", + }), + podtest.SetContainers(podtest.MakeContainer("ctr", + podtest.SetContainerSecurityContext(core.SecurityContext{ AppArmorProfile: &core.AppArmorProfile{ Type: core.AppArmorProfileTypeLocalhost, LocalhostProfile: ptr.To("foo"), }, + }), + )), + ), + "matching AppArmor pod field and annotations": *podtest.MakePod("123", + podtest.SetAnnotations(map[string]string{ + core.DeprecatedAppArmorAnnotationKeyPrefix + "ctr": core.DeprecatedAppArmorAnnotationValueLocalhostPrefix + "foo", + }), + podtest.SetSecurityContext(&core.PodSecurityContext{ + AppArmorProfile: &core.AppArmorProfile{ + Type: core.AppArmorProfileTypeLocalhost, + LocalhostProfile: ptr.To("foo"), }, - Containers: []core.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, - RestartPolicy: core.RestartPolicyAlways, - DNSPolicy: core.DNSDefault, - }, - }, - "syntactically valid sysctls": { - ObjectMeta: metav1.ObjectMeta{ - Name: "123", - Namespace: "ns", - }, - Spec: core.PodSpec{ - Containers: []core.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, - RestartPolicy: core.RestartPolicyAlways, - DNSPolicy: core.DNSClusterFirst, - SecurityContext: &core.PodSecurityContext{ - Sysctls: []core.Sysctl{{ - Name: "kernel.shmmni", - Value: "32768", - }, { - Name: "kernel.shmmax", - Value: "1000000000", - }, { - Name: "knet.ipv4.route.min_pmtu", - Value: "1000", - }}, - }, - }, - }, - "valid extended resources for init container": { - ObjectMeta: metav1.ObjectMeta{Name: "valid-extended", Namespace: "ns"}, - Spec: core.PodSpec{ - InitContainers: []core.Container{{ - Name: "valid-extended", - Image: "image", - ImagePullPolicy: "IfNotPresent", - Resources: core.ResourceRequirements{ - Requests: core.ResourceList{ - core.ResourceName("example.com/a"): resource.MustParse("10"), - }, - Limits: core.ResourceList{ - core.ResourceName("example.com/a"): resource.MustParse("10"), - }, - }, - TerminationMessagePolicy: "File", + }), + ), + "syntactically valid sysctls": *podtest.MakePod("123", + podtest.SetSecurityContext(&core.PodSecurityContext{ + Sysctls: []core.Sysctl{{ + Name: "kernel.shmmni", + Value: "32768", + }, { + Name: "kernel.shmmax", + Value: "1000000000", + }, { + Name: "knet.ipv4.route.min_pmtu", + Value: "1000", }}, - Containers: []core.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, - RestartPolicy: core.RestartPolicyAlways, - DNSPolicy: core.DNSClusterFirst, - }, - }, - "valid extended resources for regular container": { - ObjectMeta: metav1.ObjectMeta{Name: "valid-extended", Namespace: "ns"}, - Spec: core.PodSpec{ - InitContainers: []core.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, - Containers: []core.Container{{ - Name: "valid-extended", - Image: "image", - ImagePullPolicy: "IfNotPresent", - Resources: core.ResourceRequirements{ - Requests: core.ResourceList{ - core.ResourceName("example.com/a"): resource.MustParse("10"), + }), + ), + "valid extended resources for init container": *podtest.MakePod("valid-extended", + podtest.SetInitContainers(podtest.MakeContainer("valid-extended", + podtest.SetContainerResources( + podtest.MakeResourceRequirements( + map[string]string{ + "example.com/a": "10", }, - Limits: core.ResourceList{ - core.ResourceName("example.com/a"): resource.MustParse("10"), + map[string]string{ + "example.com/a": "10", }, - }, - TerminationMessagePolicy: "File", - }}, - RestartPolicy: core.RestartPolicyAlways, - DNSPolicy: core.DNSClusterFirst, - }, - }, - "valid serviceaccount token projected volume with serviceaccount name specified": { - ObjectMeta: metav1.ObjectMeta{Name: "valid-extended", Namespace: "ns"}, - Spec: core.PodSpec{ - ServiceAccountName: "some-service-account", - Containers: []core.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, - RestartPolicy: core.RestartPolicyAlways, - DNSPolicy: core.DNSClusterFirst, - Volumes: []core.Volume{{ - Name: "projected-volume", - VolumeSource: core.VolumeSource{ - Projected: &core.ProjectedVolumeSource{ - Sources: []core.VolumeProjection{{ - ServiceAccountToken: &core.ServiceAccountTokenProjection{ - Audience: "foo-audience", - ExpirationSeconds: 6000, - Path: "foo-path", - }, - }}, + ))), + ), + ), + "valid extended resources for regular container": *podtest.MakePod("valid-extended", + podtest.SetContainers(podtest.MakeContainer("valid-extended", + podtest.SetContainerResources( + podtest.MakeResourceRequirements( + map[string]string{ + "example.com/a": "10", }, - }, - }}, - }, - }, - "valid ClusterTrustBundlePEM projected volume referring to a CTB by name": { - ObjectMeta: metav1.ObjectMeta{Name: "valid-extended", Namespace: "ns"}, - Spec: core.PodSpec{ - ServiceAccountName: "some-service-account", - Containers: []core.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, - RestartPolicy: core.RestartPolicyAlways, - DNSPolicy: core.DNSClusterFirst, - Volumes: []core.Volume{ - { - Name: "projected-volume", - VolumeSource: core.VolumeSource{ - Projected: &core.ProjectedVolumeSource{ - Sources: []core.VolumeProjection{ - { - ClusterTrustBundle: &core.ClusterTrustBundleProjection{ - Path: "foo-path", - Name: utilpointer.String("foo"), - }, - }, - }, + map[string]string{ + "example.com/a": "10", + }, + ))), + ), + ), + "valid serviceaccount token projected volume with serviceaccount name specified": *podtest.MakePod("valid-extended", + podtest.SetServiceAccountName("some-service-account"), + podtest.SetVolumes(core.Volume{ + Name: "projected-volume", + VolumeSource: core.VolumeSource{ + Projected: &core.ProjectedVolumeSource{ + Sources: []core.VolumeProjection{{ + ServiceAccountToken: &core.ServiceAccountTokenProjection{ + Audience: "foo-audience", + ExpirationSeconds: 6000, + Path: "foo-path", }, - }, + }}, }, }, - }, - }, - "valid ClusterTrustBundlePEM projected volume referring to a CTB by signer name": { - ObjectMeta: metav1.ObjectMeta{Name: "valid-extended", Namespace: "ns"}, - Spec: core.PodSpec{ - ServiceAccountName: "some-service-account", - Containers: []core.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, - RestartPolicy: core.RestartPolicyAlways, - DNSPolicy: core.DNSClusterFirst, - Volumes: []core.Volume{ - { - Name: "projected-volume", - VolumeSource: core.VolumeSource{ - Projected: &core.ProjectedVolumeSource{ - Sources: []core.VolumeProjection{ - { - ClusterTrustBundle: &core.ClusterTrustBundleProjection{ - Path: "foo-path", - SignerName: utilpointer.String("example.com/foo"), - LabelSelector: &metav1.LabelSelector{ - MatchLabels: map[string]string{ - "version": "live", - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - "ephemeral volume + PVC, no conflict between them": { - ObjectMeta: metav1.ObjectMeta{Name: "123", Namespace: "ns"}, - Spec: core.PodSpec{ - Volumes: []core.Volume{ - {Name: "pvc", VolumeSource: core.VolumeSource{PersistentVolumeClaim: &core.PersistentVolumeClaimVolumeSource{ClaimName: "my-pvc"}}}, - {Name: "ephemeral", VolumeSource: core.VolumeSource{Ephemeral: &core.EphemeralVolumeSource{VolumeClaimTemplate: &validPVCTemplate}}}, - }, - Containers: []core.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, - RestartPolicy: core.RestartPolicyAlways, - DNSPolicy: core.DNSClusterFirst, - }, - }, - "negative pod-deletion-cost": { - ObjectMeta: metav1.ObjectMeta{Name: "123", Namespace: "ns", Annotations: map[string]string{core.PodDeletionCost: "-100"}}, - Spec: core.PodSpec{ - Containers: []core.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, - RestartPolicy: core.RestartPolicyAlways, - DNSPolicy: core.DNSClusterFirst, - }, - }, - "positive pod-deletion-cost": { - ObjectMeta: metav1.ObjectMeta{Name: "123", Namespace: "ns", Annotations: map[string]string{core.PodDeletionCost: "100"}}, - Spec: core.PodSpec{ - Containers: []core.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, - RestartPolicy: core.RestartPolicyAlways, - DNSPolicy: core.DNSClusterFirst, - }, - }, - "MatchLabelKeys/MismatchLabelKeys in required PodAffinity": { - ObjectMeta: metav1.ObjectMeta{Name: "123", Namespace: "ns"}, - Spec: core.PodSpec{ - Containers: []core.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, - RestartPolicy: core.RestartPolicyAlways, - DNSPolicy: core.DNSClusterFirst, - Affinity: &core.Affinity{ - PodAffinity: &core.PodAffinity{ - RequiredDuringSchedulingIgnoredDuringExecution: []core.PodAffinityTerm{ + }), + ), + "valid ClusterTrustBundlePEM projected volume referring to a CTB by name": *podtest.MakePod("valid-extended", + podtest.SetVolumes(core.Volume{ + Name: "projected-volume", + VolumeSource: core.VolumeSource{ + Projected: &core.ProjectedVolumeSource{ + Sources: []core.VolumeProjection{ { + ClusterTrustBundle: &core.ClusterTrustBundleProjection{ + Path: "foo-path", + Name: utilpointer.String("foo"), + }, + }, + }, + }, + }, + }), + ), + "valid ClusterTrustBundlePEM projected volume referring to a CTB by signer name": *podtest.MakePod("valid-extended", + podtest.SetVolumes(core.Volume{ + Name: "projected-volume", + VolumeSource: core.VolumeSource{ + Projected: &core.ProjectedVolumeSource{ + Sources: []core.VolumeProjection{ + { + ClusterTrustBundle: &core.ClusterTrustBundleProjection{ + Path: "foo-path", + SignerName: utilpointer.String("example.com/foo"), + LabelSelector: &metav1.LabelSelector{ + MatchLabels: map[string]string{ + "version": "live", + }, + }, + }, + }, + }, + }, + }, + }), + ), + "ephemeral volume + PVC, no conflict between them": *podtest.MakePod("valid-extended", + podtest.SetVolumes( + core.Volume{Name: "pvc", VolumeSource: core.VolumeSource{PersistentVolumeClaim: &core.PersistentVolumeClaimVolumeSource{ClaimName: "my-pvc"}}}, + core.Volume{Name: "ephemeral", VolumeSource: core.VolumeSource{Ephemeral: &core.EphemeralVolumeSource{VolumeClaimTemplate: &validPVCTemplate}}}, + ), + ), + "negative pod-deletion-cost": *podtest.MakePod("123", + podtest.SetAnnotations(map[string]string{core.PodDeletionCost: "-100"}), + ), + "positive pod-deletion-cost": *podtest.MakePod("123", + podtest.SetAnnotations(map[string]string{core.PodDeletionCost: "100"}), + ), + "MatchLabelKeys/MismatchLabelKeys in required PodAffinity": *podtest.MakePod("123", + podtest.SetAffinity(&core.Affinity{ + PodAffinity: &core.PodAffinity{ + RequiredDuringSchedulingIgnoredDuringExecution: []core.PodAffinityTerm{ + { + LabelSelector: &metav1.LabelSelector{ + MatchExpressions: []metav1.LabelSelectorRequirement{ + { + Key: "key", + Operator: metav1.LabelSelectorOpNotIn, + Values: []string{"value1", "value2"}, + }, + { + Key: "key2", + Operator: metav1.LabelSelectorOpIn, + Values: []string{"value1"}, + }, + { + Key: "key3", + Operator: metav1.LabelSelectorOpNotIn, + Values: []string{"value1"}, + }, + }, + }, + TopologyKey: "k8s.io/zone", + MatchLabelKeys: []string{"key2"}, + MismatchLabelKeys: []string{"key3"}, + }, + }, + }, + }), + ), + "MatchLabelKeys/MismatchLabelKeys in preferred PodAffinity": *podtest.MakePod("123", + podtest.SetAffinity(&core.Affinity{ + PodAffinity: &core.PodAffinity{ + PreferredDuringSchedulingIgnoredDuringExecution: []core.WeightedPodAffinityTerm{ + { + Weight: 10, + PodAffinityTerm: core.PodAffinityTerm{ LabelSelector: &metav1.LabelSelector{ MatchExpressions: []metav1.LabelSelectorRequirement{ { @@ -11197,59 +10709,47 @@ func TestValidatePod(t *testing.T) { }, }, }, - }, - }, - "MatchLabelKeys/MismatchLabelKeys in preferred PodAffinity": { - ObjectMeta: metav1.ObjectMeta{Name: "123", Namespace: "ns"}, - Spec: core.PodSpec{ - Containers: []core.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, - RestartPolicy: core.RestartPolicyAlways, - DNSPolicy: core.DNSClusterFirst, - Affinity: &core.Affinity{ - PodAffinity: &core.PodAffinity{ - PreferredDuringSchedulingIgnoredDuringExecution: []core.WeightedPodAffinityTerm{ - { - Weight: 10, - PodAffinityTerm: core.PodAffinityTerm{ - LabelSelector: &metav1.LabelSelector{ - MatchExpressions: []metav1.LabelSelectorRequirement{ - { - Key: "key", - Operator: metav1.LabelSelectorOpNotIn, - Values: []string{"value1", "value2"}, - }, - { - Key: "key2", - Operator: metav1.LabelSelectorOpIn, - Values: []string{"value1"}, - }, - { - Key: "key3", - Operator: metav1.LabelSelectorOpNotIn, - Values: []string{"value1"}, - }, - }, + }), + ), + "MatchLabelKeys/MismatchLabelKeys in required PodAntiAffinity": *podtest.MakePod("123", + podtest.SetAffinity(&core.Affinity{ + PodAntiAffinity: &core.PodAntiAffinity{ + RequiredDuringSchedulingIgnoredDuringExecution: []core.PodAffinityTerm{ + { + LabelSelector: &metav1.LabelSelector{ + MatchExpressions: []metav1.LabelSelectorRequirement{ + { + Key: "key", + Operator: metav1.LabelSelectorOpNotIn, + Values: []string{"value1", "value2"}, + }, + { + Key: "key2", + Operator: metav1.LabelSelectorOpIn, + Values: []string{"value1"}, + }, + { + Key: "key3", + Operator: metav1.LabelSelectorOpNotIn, + Values: []string{"value1"}, }, - TopologyKey: "k8s.io/zone", - MatchLabelKeys: []string{"key2"}, - MismatchLabelKeys: []string{"key3"}, }, }, + TopologyKey: "k8s.io/zone", + MatchLabelKeys: []string{"key2"}, + MismatchLabelKeys: []string{"key3"}, }, }, }, - }, - }, - "MatchLabelKeys/MismatchLabelKeys in required PodAntiAffinity": { - ObjectMeta: metav1.ObjectMeta{Name: "123", Namespace: "ns"}, - Spec: core.PodSpec{ - Containers: []core.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, - RestartPolicy: core.RestartPolicyAlways, - DNSPolicy: core.DNSClusterFirst, - Affinity: &core.Affinity{ - PodAntiAffinity: &core.PodAntiAffinity{ - RequiredDuringSchedulingIgnoredDuringExecution: []core.PodAffinityTerm{ - { + }), + ), + "MatchLabelKeys/MismatchLabelKeys in preferred PodAntiAffinity": *podtest.MakePod("123", + podtest.SetAffinity(&core.Affinity{ + PodAntiAffinity: &core.PodAntiAffinity{ + PreferredDuringSchedulingIgnoredDuringExecution: []core.WeightedPodAffinityTerm{ + { + Weight: 10, + PodAffinityTerm: core.PodAffinityTerm{ LabelSelector: &metav1.LabelSelector{ MatchExpressions: []metav1.LabelSelectorRequirement{ { @@ -11276,89 +10776,42 @@ func TestValidatePod(t *testing.T) { }, }, }, - }, - }, - "MatchLabelKeys/MismatchLabelKeys in preferred PodAntiAffinity": { - ObjectMeta: metav1.ObjectMeta{Name: "123", Namespace: "ns"}, - Spec: core.PodSpec{ - Containers: []core.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, - RestartPolicy: core.RestartPolicyAlways, - DNSPolicy: core.DNSClusterFirst, - Affinity: &core.Affinity{ - PodAntiAffinity: &core.PodAntiAffinity{ - PreferredDuringSchedulingIgnoredDuringExecution: []core.WeightedPodAffinityTerm{ - { - Weight: 10, - PodAffinityTerm: core.PodAffinityTerm{ - LabelSelector: &metav1.LabelSelector{ - MatchExpressions: []metav1.LabelSelectorRequirement{ - { - Key: "key", - Operator: metav1.LabelSelectorOpNotIn, - Values: []string{"value1", "value2"}, - }, - { - Key: "key2", - Operator: metav1.LabelSelectorOpIn, - Values: []string{"value1"}, - }, - { - Key: "key3", - Operator: metav1.LabelSelectorOpNotIn, - Values: []string{"value1"}, - }, - }, + }), + ), + "LabelSelector can have the same key as MismatchLabelKeys": *podtest.MakePod("123", + podtest.SetAffinity(&core.Affinity{ + // Note: On the contrary, in case of matchLabelKeys, keys in matchLabelKeys are not allowed to be specified in labelSelector by users. + PodAffinity: &core.PodAffinity{ + RequiredDuringSchedulingIgnoredDuringExecution: []core.PodAffinityTerm{ + { + LabelSelector: &metav1.LabelSelector{ + MatchExpressions: []metav1.LabelSelectorRequirement{ + { + Key: "key", + Operator: metav1.LabelSelectorOpNotIn, + Values: []string{"value1", "value2"}, + }, + { + // This is the same key as in MismatchLabelKeys + // but it's allowed. + Key: "key2", + Operator: metav1.LabelSelectorOpIn, + Values: []string{"value1"}, + }, + { + Key: "key2", + Operator: metav1.LabelSelectorOpNotIn, + Values: []string{"value1"}, }, - TopologyKey: "k8s.io/zone", - MatchLabelKeys: []string{"key2"}, - MismatchLabelKeys: []string{"key3"}, }, }, + TopologyKey: "k8s.io/zone", + MismatchLabelKeys: []string{"key2"}, }, }, }, - }, - }, - "LabelSelector can have the same key as MismatchLabelKeys": { - // Note: On the contrary, in case of matchLabelKeys, keys in matchLabelKeys are not allowed to be specified in labelSelector by users. - ObjectMeta: metav1.ObjectMeta{Name: "123", Namespace: "ns"}, - Spec: core.PodSpec{ - Containers: []core.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, - RestartPolicy: core.RestartPolicyAlways, - DNSPolicy: core.DNSClusterFirst, - Affinity: &core.Affinity{ - PodAffinity: &core.PodAffinity{ - RequiredDuringSchedulingIgnoredDuringExecution: []core.PodAffinityTerm{ - { - LabelSelector: &metav1.LabelSelector{ - MatchExpressions: []metav1.LabelSelectorRequirement{ - { - Key: "key", - Operator: metav1.LabelSelectorOpNotIn, - Values: []string{"value1", "value2"}, - }, - { - // This is the same key as in MismatchLabelKeys - // but it's allowed. - Key: "key2", - Operator: metav1.LabelSelectorOpIn, - Values: []string{"value1"}, - }, - { - Key: "key2", - Operator: metav1.LabelSelectorOpNotIn, - Values: []string{"value1"}, - }, - }, - }, - TopologyKey: "k8s.io/zone", - MismatchLabelKeys: []string{"key2"}, - }, - }, - }, - }, - }, - }, + }), + ), } for k, v := range successCases { @@ -11375,82 +10828,40 @@ func TestValidatePod(t *testing.T) { }{ "bad name": { expectedError: "metadata.name", - spec: core.Pod{ - ObjectMeta: metav1.ObjectMeta{Name: "", Namespace: "ns"}, - Spec: core.PodSpec{ - RestartPolicy: core.RestartPolicyAlways, - DNSPolicy: core.DNSClusterFirst, - Containers: []core.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, - }, - }, + spec: *podtest.MakePod(""), }, "image whitespace": { expectedError: "spec.containers[0].image", - spec: core.Pod{ - ObjectMeta: metav1.ObjectMeta{Name: "abc", Namespace: "ns"}, - Spec: core.PodSpec{ - RestartPolicy: core.RestartPolicyAlways, - DNSPolicy: core.DNSClusterFirst, - Containers: []core.Container{{Name: "ctr", Image: " ", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, - }, - }, + spec: *podtest.MakePod("123", + podtest.SetContainers(podtest.MakeContainer("ctr", podtest.SetContainerImage(" "))), + ), }, "image leading and trailing whitespace": { expectedError: "spec.containers[0].image", - spec: core.Pod{ - ObjectMeta: metav1.ObjectMeta{Name: "abc", Namespace: "ns"}, - Spec: core.PodSpec{ - RestartPolicy: core.RestartPolicyAlways, - DNSPolicy: core.DNSClusterFirst, - Containers: []core.Container{{Name: "ctr", Image: " something ", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, - }, - }, + spec: *podtest.MakePod("123", + podtest.SetContainers(podtest.MakeContainer("ctr", podtest.SetContainerImage(" something "))), + ), }, "bad namespace": { expectedError: "metadata.namespace", - spec: core.Pod{ - ObjectMeta: metav1.ObjectMeta{Name: "abc", Namespace: ""}, - Spec: core.PodSpec{ - RestartPolicy: core.RestartPolicyAlways, - DNSPolicy: core.DNSClusterFirst, - Containers: []core.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, - }, - }, + spec: *podtest.MakePod("123", podtest.SetNamespace("")), }, "bad spec": { expectedError: "spec.containers[0].name", - spec: core.Pod{ - ObjectMeta: metav1.ObjectMeta{Name: "abc", Namespace: "ns"}, - Spec: core.PodSpec{ - Containers: []core.Container{{}}, - }, - }, + spec: *podtest.MakePod("123", podtest.SetContainers(core.Container{})), }, "bad label": { expectedError: "NoUppercaseOrSpecialCharsLike=Equals", - spec: core.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "abc", - Namespace: "ns", - Labels: map[string]string{ - "NoUppercaseOrSpecialCharsLike=Equals": "bar", - }, - }, - Spec: core.PodSpec{ - RestartPolicy: core.RestartPolicyAlways, - DNSPolicy: core.DNSClusterFirst, - Containers: []core.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, - }, - }, + spec: *podtest.MakePod("123", + podtest.SetLabels(map[string]string{ + "NoUppercaseOrSpecialCharsLike=Equals": "bar", + }), + ), }, "invalid node selector requirement in node affinity, operator can't be null": { expectedError: "spec.affinity.nodeAffinity.requiredDuringSchedulingIgnoredDuringExecution.nodeSelectorTerms[0].matchExpressions[0].operator", - spec: core.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "123", - Namespace: "ns", - }, - Spec: validPodSpec(&core.Affinity{ + spec: *podtest.MakePod("123", + podtest.SetAffinity(&core.Affinity{ NodeAffinity: &core.NodeAffinity{ RequiredDuringSchedulingIgnoredDuringExecution: &core.NodeSelector{ NodeSelectorTerms: []core.NodeSelectorTerm{{ @@ -11458,19 +10869,14 @@ func TestValidatePod(t *testing.T) { Key: "key1", }}, }}, - }, - }, + }}, }), - }, + ), }, "invalid node selector requirement in node affinity, key is invalid": { expectedError: "spec.affinity.nodeAffinity.requiredDuringSchedulingIgnoredDuringExecution.nodeSelectorTerms[0].matchExpressions[0].key", - spec: core.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "123", - Namespace: "ns", - }, - Spec: validPodSpec(&core.Affinity{ + spec: *podtest.MakePod("123", + podtest.SetAffinity(&core.Affinity{ NodeAffinity: &core.NodeAffinity{ RequiredDuringSchedulingIgnoredDuringExecution: &core.NodeSelector{ NodeSelectorTerms: []core.NodeSelectorTerm{{ @@ -11482,16 +10888,12 @@ func TestValidatePod(t *testing.T) { }, }, }), - }, + ), }, "invalid node field selector requirement in node affinity, more values for field selector": { expectedError: "spec.affinity.nodeAffinity.requiredDuringSchedulingIgnoredDuringExecution.nodeSelectorTerms[0].matchFields[0].values", - spec: core.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "123", - Namespace: "ns", - }, - Spec: validPodSpec(&core.Affinity{ + spec: *podtest.MakePod("123", + podtest.SetAffinity(&core.Affinity{ NodeAffinity: &core.NodeAffinity{ RequiredDuringSchedulingIgnoredDuringExecution: &core.NodeSelector{ NodeSelectorTerms: []core.NodeSelectorTerm{{ @@ -11501,19 +10903,14 @@ func TestValidatePod(t *testing.T) { Values: []string{"host1", "host2"}, }}, }}, - }, - }, + }}, }), - }, + ), }, "invalid node field selector requirement in node affinity, invalid operator": { expectedError: "spec.affinity.nodeAffinity.requiredDuringSchedulingIgnoredDuringExecution.nodeSelectorTerms[0].matchFields[0].operator", - spec: core.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "123", - Namespace: "ns", - }, - Spec: validPodSpec(&core.Affinity{ + spec: *podtest.MakePod("123", + podtest.SetAffinity(&core.Affinity{ NodeAffinity: &core.NodeAffinity{ RequiredDuringSchedulingIgnoredDuringExecution: &core.NodeSelector{ NodeSelectorTerms: []core.NodeSelectorTerm{{ @@ -11525,16 +10922,12 @@ func TestValidatePod(t *testing.T) { }, }, }), - }, + ), }, "invalid node field selector requirement in node affinity, invalid key": { expectedError: "spec.affinity.nodeAffinity.requiredDuringSchedulingIgnoredDuringExecution.nodeSelectorTerms[0].matchFields[0].key", - spec: core.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "123", - Namespace: "ns", - }, - Spec: validPodSpec(&core.Affinity{ + spec: *podtest.MakePod("123", + podtest.SetAffinity(&core.Affinity{ NodeAffinity: &core.NodeAffinity{ RequiredDuringSchedulingIgnoredDuringExecution: &core.NodeSelector{ NodeSelectorTerms: []core.NodeSelectorTerm{{ @@ -11547,16 +10940,12 @@ func TestValidatePod(t *testing.T) { }, }, }), - }, + ), }, "invalid preferredSchedulingTerm in node affinity, weight should be in range 1-100": { expectedError: "must be in the range 1-100", - spec: core.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "123", - Namespace: "ns", - }, - Spec: validPodSpec(&core.Affinity{ + spec: *podtest.MakePod("123", + podtest.SetAffinity(&core.Affinity{ NodeAffinity: &core.NodeAffinity{ PreferredDuringSchedulingIgnoredDuringExecution: []core.PreferredSchedulingTerm{{ Weight: 199, @@ -11570,32 +10959,24 @@ func TestValidatePod(t *testing.T) { }}, }, }), - }, + ), }, "invalid requiredDuringSchedulingIgnoredDuringExecution node selector, nodeSelectorTerms must have at least one term": { expectedError: "spec.affinity.nodeAffinity.requiredDuringSchedulingIgnoredDuringExecution.nodeSelectorTerms", - spec: core.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "123", - Namespace: "ns", - }, - Spec: validPodSpec(&core.Affinity{ + spec: *podtest.MakePod("123", + podtest.SetAffinity(&core.Affinity{ NodeAffinity: &core.NodeAffinity{ RequiredDuringSchedulingIgnoredDuringExecution: &core.NodeSelector{ NodeSelectorTerms: []core.NodeSelectorTerm{}, }, }, }), - }, + ), }, "invalid weight in preferredDuringSchedulingIgnoredDuringExecution in pod affinity annotations, weight should be in range 1-100": { expectedError: "must be in the range 1-100", - spec: core.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "123", - Namespace: "ns", - }, - Spec: validPodSpec(&core.Affinity{ + spec: *podtest.MakePod("123", + podtest.SetAffinity(&core.Affinity{ PodAffinity: &core.PodAffinity{ PreferredDuringSchedulingIgnoredDuringExecution: []core.WeightedPodAffinityTerm{{ Weight: 109, @@ -11613,16 +10994,12 @@ func TestValidatePod(t *testing.T) { }}, }, }), - }, + ), }, "invalid labelSelector in preferredDuringSchedulingIgnoredDuringExecution in podaffinity annotations, values should be empty if the operator is Exists": { expectedError: "spec.affinity.podAntiAffinity.preferredDuringSchedulingIgnoredDuringExecution[0].podAffinityTerm.labelSelector.matchExpressions[0].values", - spec: core.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "123", - Namespace: "ns", - }, - Spec: validPodSpec(&core.Affinity{ + spec: *podtest.MakePod("123", + podtest.SetAffinity(&core.Affinity{ PodAntiAffinity: &core.PodAntiAffinity{ PreferredDuringSchedulingIgnoredDuringExecution: []core.WeightedPodAffinityTerm{{ Weight: 10, @@ -11640,16 +11017,12 @@ func TestValidatePod(t *testing.T) { }}, }, }), - }, + ), }, "invalid namespaceSelector in preferredDuringSchedulingIgnoredDuringExecution in podaffinity, In operator must include Values": { expectedError: "spec.affinity.podAntiAffinity.preferredDuringSchedulingIgnoredDuringExecution[0].podAffinityTerm.namespaceSelector.matchExpressions[0].values", - spec: core.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "123", - Namespace: "ns", - }, - Spec: validPodSpec(&core.Affinity{ + spec: *podtest.MakePod("123", + podtest.SetAffinity(&core.Affinity{ PodAntiAffinity: &core.PodAntiAffinity{ PreferredDuringSchedulingIgnoredDuringExecution: []core.WeightedPodAffinityTerm{{ Weight: 10, @@ -11666,16 +11039,12 @@ func TestValidatePod(t *testing.T) { }}, }, }), - }, + ), }, "invalid namespaceSelector in preferredDuringSchedulingIgnoredDuringExecution in podaffinity, Exists operator can not have values": { expectedError: "spec.affinity.podAntiAffinity.preferredDuringSchedulingIgnoredDuringExecution[0].podAffinityTerm.namespaceSelector.matchExpressions[0].values", - spec: core.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "123", - Namespace: "ns", - }, - Spec: validPodSpec(&core.Affinity{ + spec: *podtest.MakePod("123", + podtest.SetAffinity(&core.Affinity{ PodAntiAffinity: &core.PodAntiAffinity{ PreferredDuringSchedulingIgnoredDuringExecution: []core.WeightedPodAffinityTerm{{ Weight: 10, @@ -11693,16 +11062,12 @@ func TestValidatePod(t *testing.T) { }}, }, }), - }, + ), }, "invalid name space in preferredDuringSchedulingIgnoredDuringExecution in podaffinity annotations, namespace should be valid": { expectedError: "spec.affinity.podAffinity.preferredDuringSchedulingIgnoredDuringExecution[0].podAffinityTerm.namespace", - spec: core.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "123", - Namespace: "ns", - }, - Spec: validPodSpec(&core.Affinity{ + spec: *podtest.MakePod("123", + podtest.SetAffinity(&core.Affinity{ PodAffinity: &core.PodAffinity{ PreferredDuringSchedulingIgnoredDuringExecution: []core.WeightedPodAffinityTerm{{ Weight: 10, @@ -11719,16 +11084,12 @@ func TestValidatePod(t *testing.T) { }}, }, }), - }, + ), }, "invalid hard pod affinity, empty topologyKey is not allowed for hard pod affinity": { expectedError: "can not be empty", - spec: core.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "123", - Namespace: "ns", - }, - Spec: validPodSpec(&core.Affinity{ + spec: *podtest.MakePod("123", + podtest.SetAffinity(&core.Affinity{ PodAffinity: &core.PodAffinity{ RequiredDuringSchedulingIgnoredDuringExecution: []core.PodAffinityTerm{{ LabelSelector: &metav1.LabelSelector{ @@ -11742,16 +11103,12 @@ func TestValidatePod(t *testing.T) { }}, }, }), - }, + ), }, "invalid hard pod anti-affinity, empty topologyKey is not allowed for hard pod anti-affinity": { expectedError: "can not be empty", - spec: core.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "123", - Namespace: "ns", - }, - Spec: validPodSpec(&core.Affinity{ + spec: *podtest.MakePod("123", + podtest.SetAffinity(&core.Affinity{ PodAntiAffinity: &core.PodAntiAffinity{ RequiredDuringSchedulingIgnoredDuringExecution: []core.PodAffinityTerm{{ LabelSelector: &metav1.LabelSelector{ @@ -11765,16 +11122,12 @@ func TestValidatePod(t *testing.T) { }}, }, }), - }, + ), }, "invalid soft pod affinity, empty topologyKey is not allowed for soft pod affinity": { expectedError: "can not be empty", - spec: core.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "123", - Namespace: "ns", - }, - Spec: validPodSpec(&core.Affinity{ + spec: *podtest.MakePod("123", + podtest.SetAffinity(&core.Affinity{ PodAffinity: &core.PodAffinity{ PreferredDuringSchedulingIgnoredDuringExecution: []core.WeightedPodAffinityTerm{{ Weight: 10, @@ -11791,16 +11144,12 @@ func TestValidatePod(t *testing.T) { }}, }, }), - }, + ), }, "invalid soft pod anti-affinity, empty topologyKey is not allowed for soft pod anti-affinity": { expectedError: "can not be empty", - spec: core.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "123", - Namespace: "ns", - }, - Spec: validPodSpec(&core.Affinity{ + spec: *podtest.MakePod("123", + podtest.SetAffinity(&core.Affinity{ PodAntiAffinity: &core.PodAntiAffinity{ PreferredDuringSchedulingIgnoredDuringExecution: []core.WeightedPodAffinityTerm{{ Weight: 10, @@ -11817,16 +11166,12 @@ func TestValidatePod(t *testing.T) { }}, }, }), - }, + ), }, "invalid soft pod affinity, key in MatchLabelKeys isn't correctly defined": { expectedError: "prefix part must be non-empty", - spec: core.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "123", - Namespace: "ns", - }, - Spec: validPodSpec(&core.Affinity{ + spec: *podtest.MakePod("123", + podtest.SetAffinity(&core.Affinity{ PodAffinity: &core.PodAffinity{ PreferredDuringSchedulingIgnoredDuringExecution: []core.WeightedPodAffinityTerm{ { @@ -11848,16 +11193,12 @@ func TestValidatePod(t *testing.T) { }, }, }), - }, + ), }, "invalid hard pod affinity, key in MatchLabelKeys isn't correctly defined": { expectedError: "prefix part must be non-empty", - spec: core.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "123", - Namespace: "ns", - }, - Spec: validPodSpec(&core.Affinity{ + spec: *podtest.MakePod("123", + podtest.SetAffinity(&core.Affinity{ PodAffinity: &core.PodAffinity{ RequiredDuringSchedulingIgnoredDuringExecution: []core.PodAffinityTerm{ { @@ -11876,16 +11217,12 @@ func TestValidatePod(t *testing.T) { }, }, }), - }, + ), }, "invalid soft pod anti-affinity, key in MatchLabelKeys isn't correctly defined": { expectedError: "prefix part must be non-empty", - spec: core.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "123", - Namespace: "ns", - }, - Spec: validPodSpec(&core.Affinity{ + spec: *podtest.MakePod("123", + podtest.SetAffinity(&core.Affinity{ PodAntiAffinity: &core.PodAntiAffinity{ PreferredDuringSchedulingIgnoredDuringExecution: []core.WeightedPodAffinityTerm{ { @@ -11907,16 +11244,12 @@ func TestValidatePod(t *testing.T) { }, }, }), - }, + ), }, "invalid hard pod anti-affinity, key in MatchLabelKeys isn't correctly defined": { expectedError: "prefix part must be non-empty", - spec: core.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "123", - Namespace: "ns", - }, - Spec: validPodSpec(&core.Affinity{ + spec: *podtest.MakePod("123", + podtest.SetAffinity(&core.Affinity{ PodAntiAffinity: &core.PodAntiAffinity{ RequiredDuringSchedulingIgnoredDuringExecution: []core.PodAffinityTerm{ { @@ -11935,16 +11268,12 @@ func TestValidatePod(t *testing.T) { }, }, }), - }, + ), }, "invalid soft pod affinity, key in MismatchLabelKeys isn't correctly defined": { expectedError: "prefix part must be non-empty", - spec: core.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "123", - Namespace: "ns", - }, - Spec: validPodSpec(&core.Affinity{ + spec: *podtest.MakePod("123", + podtest.SetAffinity(&core.Affinity{ PodAffinity: &core.PodAffinity{ PreferredDuringSchedulingIgnoredDuringExecution: []core.WeightedPodAffinityTerm{ { @@ -11966,16 +11295,12 @@ func TestValidatePod(t *testing.T) { }, }, }), - }, + ), }, "invalid hard pod affinity, key in MismatchLabelKeys isn't correctly defined": { expectedError: "prefix part must be non-empty", - spec: core.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "123", - Namespace: "ns", - }, - Spec: validPodSpec(&core.Affinity{ + spec: *podtest.MakePod("123", + podtest.SetAffinity(&core.Affinity{ PodAffinity: &core.PodAffinity{ RequiredDuringSchedulingIgnoredDuringExecution: []core.PodAffinityTerm{ { @@ -11994,16 +11319,12 @@ func TestValidatePod(t *testing.T) { }, }, }), - }, + ), }, "invalid soft pod anti-affinity, key in MismatchLabelKeys isn't correctly defined": { expectedError: "prefix part must be non-empty", - spec: core.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "123", - Namespace: "ns", - }, - Spec: validPodSpec(&core.Affinity{ + spec: *podtest.MakePod("123", + podtest.SetAffinity(&core.Affinity{ PodAntiAffinity: &core.PodAntiAffinity{ PreferredDuringSchedulingIgnoredDuringExecution: []core.WeightedPodAffinityTerm{ { @@ -12025,16 +11346,12 @@ func TestValidatePod(t *testing.T) { }, }, }), - }, + ), }, "invalid hard pod anti-affinity, key in MismatchLabelKeys isn't correctly defined": { expectedError: "prefix part must be non-empty", - spec: core.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "123", - Namespace: "ns", - }, - Spec: validPodSpec(&core.Affinity{ + spec: *podtest.MakePod("123", + podtest.SetAffinity(&core.Affinity{ PodAntiAffinity: &core.PodAntiAffinity{ RequiredDuringSchedulingIgnoredDuringExecution: []core.PodAffinityTerm{ { @@ -12053,17 +11370,12 @@ func TestValidatePod(t *testing.T) { }, }, }), - }, + ), }, "invalid soft pod affinity, key exists in both matchLabelKeys and labelSelector": { expectedError: "exists in both matchLabelKeys and labelSelector", - spec: core.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "123", - Namespace: "ns", - Labels: map[string]string{"key": "value1"}, - }, - Spec: validPodSpec(&core.Affinity{ + spec: *podtest.MakePod("123", + podtest.SetAffinity(&core.Affinity{ PodAffinity: &core.PodAffinity{ PreferredDuringSchedulingIgnoredDuringExecution: []core.WeightedPodAffinityTerm{ { @@ -12091,17 +11403,13 @@ func TestValidatePod(t *testing.T) { }, }, }), - }, + ), }, "invalid hard pod affinity, key exists in both matchLabelKeys and labelSelector": { expectedError: "exists in both matchLabelKeys and labelSelector", - spec: core.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "123", - Namespace: "ns", - Labels: map[string]string{"key": "value1"}, - }, - Spec: validPodSpec(&core.Affinity{ + spec: *podtest.MakePod("123", + podtest.SetLabels(map[string]string{"key": "value1"}), + podtest.SetAffinity(&core.Affinity{ PodAffinity: &core.PodAffinity{ RequiredDuringSchedulingIgnoredDuringExecution: []core.PodAffinityTerm{ { @@ -12126,17 +11434,13 @@ func TestValidatePod(t *testing.T) { }, }, }), - }, + ), }, "invalid soft pod anti-affinity, key exists in both matchLabelKeys and labelSelector": { expectedError: "exists in both matchLabelKeys and labelSelector", - spec: core.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "123", - Namespace: "ns", - Labels: map[string]string{"key": "value1"}, - }, - Spec: validPodSpec(&core.Affinity{ + spec: *podtest.MakePod("123", + podtest.SetLabels(map[string]string{"key": "value1"}), + podtest.SetAffinity(&core.Affinity{ PodAntiAffinity: &core.PodAntiAffinity{ PreferredDuringSchedulingIgnoredDuringExecution: []core.WeightedPodAffinityTerm{ { @@ -12164,17 +11468,13 @@ func TestValidatePod(t *testing.T) { }, }, }), - }, + ), }, "invalid hard pod anti-affinity, key exists in both matchLabelKeys and labelSelector": { expectedError: "exists in both matchLabelKeys and labelSelector", - spec: core.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "123", - Namespace: "ns", - Labels: map[string]string{"key": "value1"}, - }, - Spec: validPodSpec(&core.Affinity{ + spec: *podtest.MakePod("123", + podtest.SetLabels(map[string]string{"key": "value1"}), + podtest.SetAffinity(&core.Affinity{ PodAntiAffinity: &core.PodAntiAffinity{ RequiredDuringSchedulingIgnoredDuringExecution: []core.PodAffinityTerm{ { @@ -12199,16 +11499,12 @@ func TestValidatePod(t *testing.T) { }, }, }), - }, + ), }, "invalid soft pod affinity, key exists in both MatchLabelKeys and MismatchLabelKeys": { expectedError: "exists in both matchLabelKeys and mismatchLabelKeys", - spec: core.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "123", - Namespace: "ns", - }, - Spec: validPodSpec(&core.Affinity{ + spec: *podtest.MakePod("123", + podtest.SetAffinity(&core.Affinity{ PodAffinity: &core.PodAffinity{ PreferredDuringSchedulingIgnoredDuringExecution: []core.WeightedPodAffinityTerm{ { @@ -12231,16 +11527,12 @@ func TestValidatePod(t *testing.T) { }, }, }), - }, + ), }, "invalid hard pod affinity, key exists in both MatchLabelKeys and MismatchLabelKeys": { expectedError: "exists in both matchLabelKeys and mismatchLabelKeys", - spec: core.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "123", - Namespace: "ns", - }, - Spec: validPodSpec(&core.Affinity{ + spec: *podtest.MakePod("123", + podtest.SetAffinity(&core.Affinity{ PodAffinity: &core.PodAffinity{ RequiredDuringSchedulingIgnoredDuringExecution: []core.PodAffinityTerm{ { @@ -12260,16 +11552,12 @@ func TestValidatePod(t *testing.T) { }, }, }), - }, + ), }, "invalid soft pod anti-affinity, key exists in both MatchLabelKeys and MismatchLabelKeys": { expectedError: "exists in both matchLabelKeys and mismatchLabelKeys", - spec: core.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "123", - Namespace: "ns", - }, - Spec: validPodSpec(&core.Affinity{ + spec: *podtest.MakePod("123", + podtest.SetAffinity(&core.Affinity{ PodAntiAffinity: &core.PodAntiAffinity{ PreferredDuringSchedulingIgnoredDuringExecution: []core.WeightedPodAffinityTerm{ { @@ -12292,16 +11580,12 @@ func TestValidatePod(t *testing.T) { }, }, }), - }, + ), }, "invalid hard pod anti-affinity, key exists in both MatchLabelKeys and MismatchLabelKeys": { expectedError: "exists in both matchLabelKeys and mismatchLabelKeys", - spec: core.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "123", - Namespace: "ns", - }, - Spec: validPodSpec(&core.Affinity{ + spec: *podtest.MakePod("123", + podtest.SetAffinity(&core.Affinity{ PodAntiAffinity: &core.PodAntiAffinity{ RequiredDuringSchedulingIgnoredDuringExecution: []core.PodAffinityTerm{ { @@ -12321,742 +11605,469 @@ func TestValidatePod(t *testing.T) { }, }, }), - }, + ), }, "invalid toleration key": { expectedError: "spec.tolerations[0].key", - spec: core.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "123", - Namespace: "ns", - }, - Spec: extendPodSpecwithTolerations(validPodSpec(nil), []core.Toleration{{Key: "nospecialchars^=@", Operator: "Equal", Value: "bar", Effect: "NoSchedule"}}), - }, + spec: *podtest.MakePod("123", + podtest.SetTolerations(core.Toleration{Key: "nospecialchars^=@", Operator: "Equal", Value: "bar", Effect: "NoSchedule"}), + ), }, "invalid toleration operator": { expectedError: "spec.tolerations[0].operator", - spec: core.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "123", - Namespace: "ns", - }, - Spec: extendPodSpecwithTolerations(validPodSpec(nil), []core.Toleration{{Key: "foo", Operator: "In", Value: "bar", Effect: "NoSchedule"}}), - }, + spec: *podtest.MakePod("123", + podtest.SetTolerations(core.Toleration{Key: "foo", Operator: "In", Value: "bar", Effect: "NoSchedule"}), + ), }, "value must be empty when `operator` is 'Exists'": { expectedError: "spec.tolerations[0].operator", - spec: core.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "123", - Namespace: "ns", - }, - Spec: extendPodSpecwithTolerations(validPodSpec(nil), []core.Toleration{{Key: "foo", Operator: "Exists", Value: "bar", Effect: "NoSchedule"}}), - }, + spec: *podtest.MakePod("123", + podtest.SetTolerations(core.Toleration{Key: "foo", Operator: "Exists", Value: "bar", Effect: "NoSchedule"}), + ), }, - "operator must be 'Exists' when `key` is empty": { expectedError: "spec.tolerations[0].operator", - spec: core.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "123", - Namespace: "ns", - }, - Spec: extendPodSpecwithTolerations(validPodSpec(nil), []core.Toleration{{Operator: "Equal", Value: "bar", Effect: "NoSchedule"}}), - }, + spec: *podtest.MakePod("123", + podtest.SetTolerations(core.Toleration{Operator: "Equal", Value: "bar", Effect: "NoSchedule"}), + ), }, "effect must be 'NoExecute' when `TolerationSeconds` is set": { expectedError: "spec.tolerations[0].effect", - spec: core.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "pod-forgiveness-invalid", - Namespace: "ns", - }, - Spec: extendPodSpecwithTolerations(validPodSpec(nil), []core.Toleration{{Key: "node.kubernetes.io/not-ready", Operator: "Exists", Effect: "NoSchedule", TolerationSeconds: &[]int64{20}[0]}}), - }, + spec: *podtest.MakePod("pod-forgiveness-invalid", + podtest.SetTolerations(core.Toleration{Key: "node.kubernetes.io/not-ready", Operator: "Exists", Effect: "NoSchedule", TolerationSeconds: &[]int64{20}[0]}), + ), }, "must be a valid pod seccomp profile": { expectedError: "must be a valid seccomp profile", - spec: core.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "123", - Namespace: "ns", - Annotations: map[string]string{ - core.SeccompPodAnnotationKey: "foo", - }, - }, - Spec: validPodSpec(nil), - }, + spec: *podtest.MakePod("123", + podtest.SetAnnotations(map[string]string{ + core.SeccompPodAnnotationKey: "foo", + }), + ), }, "must be a valid container seccomp profile": { expectedError: "must be a valid seccomp profile", - spec: core.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "123", - Namespace: "ns", - Annotations: map[string]string{ - core.SeccompContainerAnnotationKeyPrefix + "foo": "foo", - }, - }, - Spec: validPodSpec(nil), - }, + spec: *podtest.MakePod("123", + podtest.SetAnnotations(map[string]string{ + core.SeccompContainerAnnotationKeyPrefix + "foo": "foo", + }), + ), }, "must be a non-empty container name in seccomp annotation": { expectedError: "name part must be non-empty", - spec: core.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "123", - Namespace: "ns", - Annotations: map[string]string{ - core.SeccompContainerAnnotationKeyPrefix: "foo", - }, - }, - Spec: validPodSpec(nil), - }, + spec: *podtest.MakePod("123", + podtest.SetAnnotations(map[string]string{ + core.SeccompContainerAnnotationKeyPrefix: "foo", + }), + ), }, "must be a non-empty container profile in seccomp annotation": { expectedError: "must be a valid seccomp profile", - spec: core.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "123", - Namespace: "ns", - Annotations: map[string]string{ - core.SeccompContainerAnnotationKeyPrefix + "foo": "", - }, - }, - Spec: validPodSpec(nil), - }, + spec: *podtest.MakePod("123", + podtest.SetAnnotations(map[string]string{ + core.SeccompContainerAnnotationKeyPrefix + "foo": "", + }), + ), }, "must match seccomp profile type and pod annotation": { expectedError: "seccomp type in annotation and field must match", - spec: core.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "123", - Namespace: "ns", - Annotations: map[string]string{ - core.SeccompPodAnnotationKey: "unconfined", + spec: *podtest.MakePod("123", + podtest.SetAnnotations(map[string]string{ + core.SeccompPodAnnotationKey: "unconfined", + }), + podtest.SetSecurityContext(&core.PodSecurityContext{ + SeccompProfile: &core.SeccompProfile{ + Type: core.SeccompProfileTypeRuntimeDefault, }, - }, - Spec: core.PodSpec{ - SecurityContext: &core.PodSecurityContext{ - SeccompProfile: &core.SeccompProfile{ - Type: core.SeccompProfileTypeRuntimeDefault, - }, - }, - Containers: []core.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, - RestartPolicy: core.RestartPolicyAlways, - DNSPolicy: core.DNSClusterFirst, - }, - }, + }), + ), }, "must match seccomp profile type and container annotation": { expectedError: "seccomp type in annotation and field must match", - spec: core.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "123", - Namespace: "ns", - Annotations: map[string]string{ - core.SeccompContainerAnnotationKeyPrefix + "ctr": "unconfined", - }, - }, - Spec: core.PodSpec{ - Containers: []core.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File", - SecurityContext: &core.SecurityContext{ - SeccompProfile: &core.SeccompProfile{ - Type: core.SeccompProfileTypeRuntimeDefault, - }, - }}}, - RestartPolicy: core.RestartPolicyAlways, - DNSPolicy: core.DNSClusterFirst, - }, - }, + spec: *podtest.MakePod("123", + podtest.SetContainers(podtest.MakeContainer("ctr", + podtest.SetContainerSecurityContext(core.SecurityContext{ + SeccompProfile: &core.SeccompProfile{ + Type: core.SeccompProfileTypeRuntimeDefault, + }, + }), + )), + podtest.SetAnnotations(map[string]string{ + core.SeccompContainerAnnotationKeyPrefix + "ctr": "unconfined", + }), + ), }, "must be a relative path in a node-local seccomp profile annotation": { expectedError: "must be a relative path", - spec: core.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "123", - Namespace: "ns", - Annotations: map[string]string{ - core.SeccompPodAnnotationKey: "localhost//foo", - }, - }, - Spec: validPodSpec(nil), - }, + spec: *podtest.MakePod("123", + podtest.SetAnnotations(map[string]string{ + core.SeccompPodAnnotationKey: "localhost//foo", + }), + ), }, "must not start with '../'": { expectedError: "must not contain '..'", - spec: core.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "123", - Namespace: "ns", - Annotations: map[string]string{ - core.SeccompPodAnnotationKey: "localhost/../foo", - }, - }, - Spec: validPodSpec(nil), - }, + spec: *podtest.MakePod("123", + podtest.SetAnnotations(map[string]string{ + core.SeccompPodAnnotationKey: "localhost/../foo", + }), + ), }, "AppArmor profile must apply to a container": { expectedError: "metadata.annotations[container.apparmor.security.beta.kubernetes.io/fake-ctr]", - spec: core.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "123", - Namespace: "ns", - Annotations: map[string]string{ - v1.DeprecatedAppArmorBetaContainerAnnotationKeyPrefix + "ctr": v1.DeprecatedAppArmorBetaProfileRuntimeDefault, - v1.DeprecatedAppArmorBetaContainerAnnotationKeyPrefix + "init-ctr": v1.DeprecatedAppArmorBetaProfileRuntimeDefault, - v1.DeprecatedAppArmorBetaContainerAnnotationKeyPrefix + "fake-ctr": v1.DeprecatedAppArmorBetaProfileRuntimeDefault, - }, - }, - Spec: core.PodSpec{ - InitContainers: []core.Container{{Name: "init-ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, - Containers: []core.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, - RestartPolicy: core.RestartPolicyAlways, - DNSPolicy: core.DNSClusterFirst, - }, - }, + spec: *podtest.MakePod("123", + podtest.SetInitContainers(podtest.MakeContainer("init-ctr")), + podtest.SetAnnotations(map[string]string{ + v1.DeprecatedAppArmorBetaContainerAnnotationKeyPrefix + "ctr": v1.DeprecatedAppArmorBetaProfileRuntimeDefault, + v1.DeprecatedAppArmorBetaContainerAnnotationKeyPrefix + "init-ctr": v1.DeprecatedAppArmorBetaProfileRuntimeDefault, + v1.DeprecatedAppArmorBetaContainerAnnotationKeyPrefix + "fake-ctr": v1.DeprecatedAppArmorBetaProfileRuntimeDefault, + }), + ), }, "AppArmor profile format must be valid": { expectedError: "invalid AppArmor profile name", - spec: core.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "123", - Namespace: "ns", - Annotations: map[string]string{ - v1.DeprecatedAppArmorBetaContainerAnnotationKeyPrefix + "ctr": "bad-name", - }, - }, - Spec: validPodSpec(nil), - }, + spec: *podtest.MakePod("123", + podtest.SetAnnotations(map[string]string{ + v1.DeprecatedAppArmorBetaContainerAnnotationKeyPrefix + "ctr": "bad-name", + }), + ), }, "only default AppArmor profile may start with runtime/": { expectedError: "invalid AppArmor profile name", - spec: core.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "123", - Namespace: "ns", - Annotations: map[string]string{ - v1.DeprecatedAppArmorBetaContainerAnnotationKeyPrefix + "ctr": "runtime/foo", - }, - }, - Spec: validPodSpec(nil), - }, + spec: *podtest.MakePod("123", + podtest.SetAnnotations(map[string]string{ + v1.DeprecatedAppArmorBetaContainerAnnotationKeyPrefix + "ctr": "runtime/foo", + }), + ), }, "unsupported pod AppArmor profile type": { expectedError: `Unsupported value: "test"`, - spec: core.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "123", - Namespace: "ns", - }, - Spec: core.PodSpec{ - Containers: []core.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, - RestartPolicy: core.RestartPolicyAlways, - DNSPolicy: core.DNSDefault, - SecurityContext: &core.PodSecurityContext{ - AppArmorProfile: &core.AppArmorProfile{ - Type: "test", - }, + spec: *podtest.MakePod("123", + podtest.SetSecurityContext(&core.PodSecurityContext{ + AppArmorProfile: &core.AppArmorProfile{ + Type: "test", }, - }, - }, + }), + ), }, "unsupported container AppArmor profile type": { expectedError: `Unsupported value: "test"`, - spec: core.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "123", - Namespace: "ns", - }, - Spec: core.PodSpec{ - Containers: []core.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File", - SecurityContext: &core.SecurityContext{ - AppArmorProfile: &core.AppArmorProfile{ - Type: "test", - }, + spec: *podtest.MakePod("123", + podtest.SetContainers(podtest.MakeContainer("ctr", + podtest.SetContainerSecurityContext(core.SecurityContext{ + AppArmorProfile: &core.AppArmorProfile{ + Type: "test", }, - }}, - RestartPolicy: core.RestartPolicyAlways, - DNSPolicy: core.DNSDefault, - }, - }, + }), + )), + ), }, "missing pod AppArmor profile type": { expectedError: "Required value: type is required when appArmorProfile is set", - spec: core.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "123", - Namespace: "ns", - }, - Spec: core.PodSpec{ - Containers: []core.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, - RestartPolicy: core.RestartPolicyAlways, - DNSPolicy: core.DNSDefault, - SecurityContext: &core.PodSecurityContext{ - AppArmorProfile: &core.AppArmorProfile{ - Type: "", - }, + spec: *podtest.MakePod("123", + podtest.SetSecurityContext(&core.PodSecurityContext{ + AppArmorProfile: &core.AppArmorProfile{ + Type: "", }, - }, - }, + }), + ), }, "missing AppArmor localhost profile": { expectedError: "Required value: must be set when AppArmor type is Localhost", - spec: core.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "123", - Namespace: "ns", - }, - Spec: core.PodSpec{ - Containers: []core.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, - RestartPolicy: core.RestartPolicyAlways, - DNSPolicy: core.DNSDefault, - SecurityContext: &core.PodSecurityContext{ - AppArmorProfile: &core.AppArmorProfile{ - Type: core.AppArmorProfileTypeLocalhost, - }, + spec: *podtest.MakePod("123", + podtest.SetSecurityContext(&core.PodSecurityContext{ + AppArmorProfile: &core.AppArmorProfile{ + Type: core.AppArmorProfileTypeLocalhost, }, - }, - }, + }), + ), }, "empty AppArmor localhost profile": { expectedError: "Required value: must be set when AppArmor type is Localhost", - spec: core.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "123", - Namespace: "ns", - }, - Spec: core.PodSpec{ - Containers: []core.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, - RestartPolicy: core.RestartPolicyAlways, - DNSPolicy: core.DNSDefault, - SecurityContext: &core.PodSecurityContext{ - AppArmorProfile: &core.AppArmorProfile{ - Type: core.AppArmorProfileTypeLocalhost, - LocalhostProfile: ptr.To(""), - }, + spec: *podtest.MakePod("123", + podtest.SetSecurityContext(&core.PodSecurityContext{ + AppArmorProfile: &core.AppArmorProfile{ + Type: core.AppArmorProfileTypeLocalhost, + LocalhostProfile: ptr.To(""), }, - }, - }, + }), + ), }, "invalid AppArmor localhost profile type": { expectedError: `Invalid value: "foo-bar"`, - spec: core.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "123", - Namespace: "ns", - }, - Spec: core.PodSpec{ - Containers: []core.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, - RestartPolicy: core.RestartPolicyAlways, - DNSPolicy: core.DNSDefault, - SecurityContext: &core.PodSecurityContext{ - AppArmorProfile: &core.AppArmorProfile{ - Type: core.AppArmorProfileTypeRuntimeDefault, - LocalhostProfile: ptr.To("foo-bar"), - }, + spec: *podtest.MakePod("123", + podtest.SetSecurityContext(&core.PodSecurityContext{ + AppArmorProfile: &core.AppArmorProfile{ + Type: core.AppArmorProfileTypeRuntimeDefault, + LocalhostProfile: ptr.To("foo-bar"), }, - }, - }, + }), + ), }, "invalid AppArmor localhost profile": { expectedError: `Invalid value: "foo-bar "`, - spec: core.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "123", - Namespace: "ns", - }, - Spec: core.PodSpec{ - Containers: []core.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, - RestartPolicy: core.RestartPolicyAlways, - DNSPolicy: core.DNSDefault, - SecurityContext: &core.PodSecurityContext{ - AppArmorProfile: &core.AppArmorProfile{ - Type: core.AppArmorProfileTypeLocalhost, - LocalhostProfile: ptr.To("foo-bar "), - }, + spec: *podtest.MakePod("123", + podtest.SetSecurityContext(&core.PodSecurityContext{ + AppArmorProfile: &core.AppArmorProfile{ + Type: core.AppArmorProfileTypeLocalhost, + LocalhostProfile: ptr.To("foo-bar "), }, - }, - }, + }), + ), }, "too long AppArmor localhost profile": { expectedError: "Too long: may not be longer than 4095", - spec: core.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "123", - Namespace: "ns", - }, - Spec: core.PodSpec{ - Containers: []core.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, - RestartPolicy: core.RestartPolicyAlways, - DNSPolicy: core.DNSDefault, - SecurityContext: &core.PodSecurityContext{ - AppArmorProfile: &core.AppArmorProfile{ - Type: core.AppArmorProfileTypeLocalhost, - LocalhostProfile: ptr.To(strings.Repeat("a", 4096)), - }, + spec: *podtest.MakePod("123", + podtest.SetSecurityContext(&core.PodSecurityContext{ + AppArmorProfile: &core.AppArmorProfile{ + Type: core.AppArmorProfileTypeLocalhost, + LocalhostProfile: ptr.To(strings.Repeat("a", 4096)), }, - }, - }, + }), + ), }, "mismatched AppArmor field and annotation types": { expectedError: "Forbidden: apparmor type in annotation and field must match", - spec: core.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "123", - Namespace: "ns", - Annotations: map[string]string{ - core.DeprecatedAppArmorAnnotationKeyPrefix + "ctr": core.DeprecatedAppArmorAnnotationValueRuntimeDefault, - }, - }, - Spec: core.PodSpec{ - Containers: []core.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File", - SecurityContext: &core.SecurityContext{ - AppArmorProfile: &core.AppArmorProfile{ - Type: core.AppArmorProfileTypeUnconfined, - }, - }, - }}, - RestartPolicy: core.RestartPolicyAlways, - DNSPolicy: core.DNSDefault, - }, - }, - }, - "mismatched AppArmor pod field and annotation types": { - expectedError: "Forbidden: apparmor type in annotation and field must match", - spec: core.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "123", - Namespace: "ns", - Annotations: map[string]string{ - core.DeprecatedAppArmorAnnotationKeyPrefix + "ctr": core.DeprecatedAppArmorAnnotationValueRuntimeDefault, - }, - }, - Spec: core.PodSpec{ - SecurityContext: &core.PodSecurityContext{ + spec: *podtest.MakePod("123", + podtest.SetAnnotations(map[string]string{ + core.DeprecatedAppArmorAnnotationKeyPrefix + "ctr": core.DeprecatedAppArmorAnnotationValueRuntimeDefault, + }), + podtest.SetContainers(podtest.MakeContainer("ctr", + podtest.SetContainerSecurityContext(core.SecurityContext{ AppArmorProfile: &core.AppArmorProfile{ Type: core.AppArmorProfileTypeUnconfined, }, + }), + )), + ), + }, + "mismatched AppArmor pod field and annotation types": { + expectedError: "Forbidden: apparmor type in annotation and field must match", + spec: *podtest.MakePod("123", + podtest.SetAnnotations(map[string]string{ + core.DeprecatedAppArmorAnnotationKeyPrefix + "ctr": core.DeprecatedAppArmorAnnotationValueRuntimeDefault, + }), + podtest.SetSecurityContext(&core.PodSecurityContext{ + AppArmorProfile: &core.AppArmorProfile{ + Type: core.AppArmorProfileTypeUnconfined, }, - Containers: []core.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, - RestartPolicy: core.RestartPolicyAlways, - DNSPolicy: core.DNSDefault, - }, - }, + }), + ), }, "mismatched AppArmor localhost profiles": { expectedError: "Forbidden: apparmor profile in annotation and field must match", - spec: core.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "123", - Namespace: "ns", - Annotations: map[string]string{ - core.DeprecatedAppArmorAnnotationKeyPrefix + "ctr": core.DeprecatedAppArmorAnnotationValueLocalhostPrefix + "foo", - }, - }, - Spec: core.PodSpec{ - Containers: []core.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File", - SecurityContext: &core.SecurityContext{ - AppArmorProfile: &core.AppArmorProfile{ - Type: core.AppArmorProfileTypeLocalhost, - LocalhostProfile: ptr.To("bar"), - }, + spec: *podtest.MakePod("123", + podtest.SetAnnotations(map[string]string{ + core.DeprecatedAppArmorAnnotationKeyPrefix + "ctr": core.DeprecatedAppArmorAnnotationValueLocalhostPrefix + "foo", + }), + podtest.SetContainers(podtest.MakeContainer("ctr", + podtest.SetContainerSecurityContext(core.SecurityContext{ + AppArmorProfile: &core.AppArmorProfile{ + Type: core.AppArmorProfileTypeLocalhost, + LocalhostProfile: ptr.To("bar"), }, - }}, - RestartPolicy: core.RestartPolicyAlways, - DNSPolicy: core.DNSDefault, - }, - }, + }), + )), + ), }, "invalid extended resource name in container request": { expectedError: "must be a standard resource for containers", - spec: core.Pod{ - ObjectMeta: metav1.ObjectMeta{Name: "123", Namespace: "ns"}, - Spec: core.PodSpec{ - Containers: []core.Container{{ - Name: "invalid", - Image: "image", - ImagePullPolicy: "IfNotPresent", - Resources: core.ResourceRequirements{ - Requests: core.ResourceList{ - core.ResourceName("invalid-name"): resource.MustParse("2"), + spec: *podtest.MakePod("123", + podtest.SetContainers(podtest.MakeContainer("invalid", + podtest.SetContainerResources( + podtest.MakeResourceRequirements( + map[string]string{ + "invalid-name": "2", }, - Limits: core.ResourceList{ - core.ResourceName("invalid-name"): resource.MustParse("2"), + map[string]string{ + "invalid-name": "2", }, - }, - }}, - RestartPolicy: core.RestartPolicyAlways, - DNSPolicy: core.DNSClusterFirst, - }, - }, + ))), + ), + ), }, "invalid extended resource requirement: request must be == limit": { expectedError: "must be equal to example.com/a", - spec: core.Pod{ - ObjectMeta: metav1.ObjectMeta{Name: "123", Namespace: "ns"}, - Spec: core.PodSpec{ - Containers: []core.Container{{ - Name: "invalid", - Image: "image", - ImagePullPolicy: "IfNotPresent", - Resources: core.ResourceRequirements{ - Requests: core.ResourceList{ - core.ResourceName("example.com/a"): resource.MustParse("2"), + spec: *podtest.MakePod("123", + podtest.SetContainers(podtest.MakeContainer("invalid", + podtest.SetContainerResources( + podtest.MakeResourceRequirements( + map[string]string{ + "example.com/a": "2", }, - Limits: core.ResourceList{ - core.ResourceName("example.com/a"): resource.MustParse("1"), + map[string]string{ + "example.com/a": "1", }, - }, - }}, - RestartPolicy: core.RestartPolicyAlways, - DNSPolicy: core.DNSClusterFirst, - }, - }, + ))), + ), + ), }, "invalid extended resource requirement without limit": { expectedError: "Limit must be set", - spec: core.Pod{ - ObjectMeta: metav1.ObjectMeta{Name: "123", Namespace: "ns"}, - Spec: core.PodSpec{ - Containers: []core.Container{{ - Name: "invalid", - Image: "image", - ImagePullPolicy: "IfNotPresent", - Resources: core.ResourceRequirements{ - Requests: core.ResourceList{ - core.ResourceName("example.com/a"): resource.MustParse("2"), + spec: *podtest.MakePod("123", + podtest.SetContainers(podtest.MakeContainer("invalid", + podtest.SetContainerResources( + podtest.MakeResourceRequirements( + map[string]string{ + "example.com/a": "2", }, - }, - }}, - RestartPolicy: core.RestartPolicyAlways, - DNSPolicy: core.DNSClusterFirst, - }, - }, + map[string]string{}, + ))), + ), + ), }, "invalid fractional extended resource in container request": { expectedError: "must be an integer", - spec: core.Pod{ - ObjectMeta: metav1.ObjectMeta{Name: "123", Namespace: "ns"}, - Spec: core.PodSpec{ - Containers: []core.Container{{ - Name: "invalid", - Image: "image", - ImagePullPolicy: "IfNotPresent", - Resources: core.ResourceRequirements{ - Requests: core.ResourceList{ - core.ResourceName("example.com/a"): resource.MustParse("500m"), + spec: *podtest.MakePod("123", + podtest.SetContainers(podtest.MakeContainer("invalid", + podtest.SetContainerResources( + podtest.MakeResourceRequirements( + map[string]string{ + "example.com/a": "500m", }, - }, - }}, - RestartPolicy: core.RestartPolicyAlways, - DNSPolicy: core.DNSClusterFirst, - }, - }, + map[string]string{}, + ))), + ), + ), }, "invalid fractional extended resource in init container request": { expectedError: "must be an integer", - spec: core.Pod{ - ObjectMeta: metav1.ObjectMeta{Name: "123", Namespace: "ns"}, - Spec: core.PodSpec{ - InitContainers: []core.Container{{ - Name: "invalid", - Image: "image", - ImagePullPolicy: "IfNotPresent", - Resources: core.ResourceRequirements{ - Requests: core.ResourceList{ - core.ResourceName("example.com/a"): resource.MustParse("500m"), + spec: *podtest.MakePod("123", + podtest.SetInitContainers(podtest.MakeContainer("invalid", + podtest.SetContainerResources( + podtest.MakeResourceRequirements( + map[string]string{ + "example.com/a": "500m", }, - }, - }}, - Containers: []core.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, - RestartPolicy: core.RestartPolicyAlways, - DNSPolicy: core.DNSClusterFirst, - }, - }, + map[string]string{}, + ))), + ), + ), }, "invalid fractional extended resource in container limit": { expectedError: "must be an integer", - spec: core.Pod{ - ObjectMeta: metav1.ObjectMeta{Name: "123", Namespace: "ns"}, - Spec: core.PodSpec{ - Containers: []core.Container{{ - Name: "invalid", - Image: "image", - ImagePullPolicy: "IfNotPresent", - Resources: core.ResourceRequirements{ - Requests: core.ResourceList{ - core.ResourceName("example.com/a"): resource.MustParse("5"), + spec: *podtest.MakePod("123", + podtest.SetContainers(podtest.MakeContainer("invalid", + podtest.SetContainerResources( + podtest.MakeResourceRequirements( + map[string]string{ + "example.com/a": "5", }, - Limits: core.ResourceList{ - core.ResourceName("example.com/a"): resource.MustParse("2.5"), + map[string]string{ + "example.com/a": "2.5", }, - }, - }}, - RestartPolicy: core.RestartPolicyAlways, - DNSPolicy: core.DNSClusterFirst, - }, - }, + ))), + ), + ), }, "invalid fractional extended resource in init container limit": { expectedError: "must be an integer", - spec: core.Pod{ - ObjectMeta: metav1.ObjectMeta{Name: "123", Namespace: "ns"}, - Spec: core.PodSpec{ - InitContainers: []core.Container{{ - Name: "invalid", - Image: "image", - ImagePullPolicy: "IfNotPresent", - Resources: core.ResourceRequirements{ - Requests: core.ResourceList{ - core.ResourceName("example.com/a"): resource.MustParse("2.5"), + spec: *podtest.MakePod("123", + podtest.SetInitContainers(podtest.MakeContainer("invalid", + podtest.SetContainerResources( + podtest.MakeResourceRequirements( + map[string]string{ + "example.com/a": "2.5", }, - Limits: core.ResourceList{ - core.ResourceName("example.com/a"): resource.MustParse("2.5"), + map[string]string{ + "example.com/a": "2.5", }, - }, - }}, - Containers: []core.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, - RestartPolicy: core.RestartPolicyAlways, - DNSPolicy: core.DNSClusterFirst, - }, - }, + ))), + ), + ), }, "mirror-pod present without nodeName": { expectedError: "mirror", - spec: core.Pod{ - ObjectMeta: metav1.ObjectMeta{Name: "123", Namespace: "ns", Annotations: map[string]string{core.MirrorPodAnnotationKey: ""}}, - Spec: core.PodSpec{ - Containers: []core.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, - RestartPolicy: core.RestartPolicyAlways, - DNSPolicy: core.DNSClusterFirst, - }, - }, + spec: *podtest.MakePod("123", + podtest.SetAnnotations(map[string]string{core.MirrorPodAnnotationKey: ""}), + ), }, "mirror-pod populated without nodeName": { expectedError: "mirror", - spec: core.Pod{ - ObjectMeta: metav1.ObjectMeta{Name: "123", Namespace: "ns", Annotations: map[string]string{core.MirrorPodAnnotationKey: "foo"}}, - Spec: core.PodSpec{ - Containers: []core.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, - RestartPolicy: core.RestartPolicyAlways, - DNSPolicy: core.DNSClusterFirst, - }, - }, + spec: *podtest.MakePod("123", + podtest.SetAnnotations(map[string]string{core.MirrorPodAnnotationKey: "foo"}), + ), }, "serviceaccount token projected volume with no serviceaccount name specified": { expectedError: "must not be specified when serviceAccountName is not set", - spec: core.Pod{ - ObjectMeta: metav1.ObjectMeta{Name: "123", Namespace: "ns"}, - Spec: core.PodSpec{ - Containers: []core.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, - RestartPolicy: core.RestartPolicyAlways, - DNSPolicy: core.DNSClusterFirst, - Volumes: []core.Volume{{ - Name: "projected-volume", - VolumeSource: core.VolumeSource{ - Projected: &core.ProjectedVolumeSource{ - Sources: []core.VolumeProjection{{ - ServiceAccountToken: &core.ServiceAccountTokenProjection{ - Audience: "foo-audience", - ExpirationSeconds: 6000, - Path: "foo-path", - }, - }}, - }, + spec: *podtest.MakePod("123", + podtest.SetVolumes(core.Volume{ + Name: "projected-volume", + VolumeSource: core.VolumeSource{ + Projected: &core.ProjectedVolumeSource{ + Sources: []core.VolumeProjection{{ + ServiceAccountToken: &core.ServiceAccountTokenProjection{ + Audience: "foo-audience", + ExpirationSeconds: 6000, + Path: "foo-path", + }, + }}, }, - }}, - }, - }, + }, + }), + ), }, "ClusterTrustBundlePEM projected volume using both byName and bySigner": { expectedError: "only one of name and signerName may be used", - spec: core.Pod{ - ObjectMeta: metav1.ObjectMeta{Name: "valid-extended", Namespace: "ns"}, - Spec: core.PodSpec{ - ServiceAccountName: "some-service-account", - Containers: []core.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, - RestartPolicy: core.RestartPolicyAlways, - DNSPolicy: core.DNSClusterFirst, - Volumes: []core.Volume{ - { - Name: "projected-volume", - VolumeSource: core.VolumeSource{ - Projected: &core.ProjectedVolumeSource{ - Sources: []core.VolumeProjection{ - { - ClusterTrustBundle: &core.ClusterTrustBundleProjection{ - Path: "foo-path", - SignerName: utilpointer.String("example.com/foo"), - LabelSelector: &metav1.LabelSelector{ - MatchLabels: map[string]string{ - "version": "live", - }, - }, - Name: utilpointer.String("foo"), + spec: *podtest.MakePod("valid-extended", + podtest.SetVolumes(core.Volume{ + Name: "projected-volume", + VolumeSource: core.VolumeSource{ + Projected: &core.ProjectedVolumeSource{ + Sources: []core.VolumeProjection{ + { + ClusterTrustBundle: &core.ClusterTrustBundleProjection{ + Path: "foo-path", + SignerName: utilpointer.String("example.com/foo"), + LabelSelector: &metav1.LabelSelector{ + MatchLabels: map[string]string{ + "version": "live", }, }, + Name: utilpointer.String("foo"), }, }, }, }, }, - }, - }, + }), + ), }, "ClusterTrustBundlePEM projected volume byName with no name": { expectedError: "must be a valid object name", - spec: core.Pod{ - ObjectMeta: metav1.ObjectMeta{Name: "valid-extended", Namespace: "ns"}, - Spec: core.PodSpec{ - ServiceAccountName: "some-service-account", - Containers: []core.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, - RestartPolicy: core.RestartPolicyAlways, - DNSPolicy: core.DNSClusterFirst, - Volumes: []core.Volume{ - { - Name: "projected-volume", - VolumeSource: core.VolumeSource{ - Projected: &core.ProjectedVolumeSource{ - Sources: []core.VolumeProjection{ - { - ClusterTrustBundle: &core.ClusterTrustBundleProjection{ - Path: "foo-path", - Name: utilpointer.String(""), - }, - }, + spec: *podtest.MakePod("valid-extended", + podtest.SetVolumes(core.Volume{ + Name: "projected-volume", + VolumeSource: core.VolumeSource{ + Projected: &core.ProjectedVolumeSource{ + Sources: []core.VolumeProjection{ + { + ClusterTrustBundle: &core.ClusterTrustBundleProjection{ + Path: "foo-path", + Name: utilpointer.String(""), }, }, }, }, }, - }, - }, + }), + ), }, "ClusterTrustBundlePEM projected volume bySigner with no signer name": { expectedError: "must be a valid signer name", - spec: core.Pod{ - ObjectMeta: metav1.ObjectMeta{Name: "valid-extended", Namespace: "ns"}, - Spec: core.PodSpec{ - ServiceAccountName: "some-service-account", - Containers: []core.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, - RestartPolicy: core.RestartPolicyAlways, - DNSPolicy: core.DNSClusterFirst, - Volumes: []core.Volume{ - { - Name: "projected-volume", - VolumeSource: core.VolumeSource{ - Projected: &core.ProjectedVolumeSource{ - Sources: []core.VolumeProjection{ - { - ClusterTrustBundle: &core.ClusterTrustBundleProjection{ - Path: "foo-path", - SignerName: utilpointer.String(""), - LabelSelector: &metav1.LabelSelector{ - MatchLabels: map[string]string{ - "foo": "bar", - }, - }, + spec: *podtest.MakePod("valid-extended", + podtest.SetVolumes(core.Volume{ + Name: "projected-volume", + VolumeSource: core.VolumeSource{ + Projected: &core.ProjectedVolumeSource{ + Sources: []core.VolumeProjection{ + { + ClusterTrustBundle: &core.ClusterTrustBundleProjection{ + Path: "foo-path", + SignerName: utilpointer.String(""), + LabelSelector: &metav1.LabelSelector{ + MatchLabels: map[string]string{ + "foo": "bar", }, }, }, @@ -13064,102 +12075,67 @@ func TestValidatePod(t *testing.T) { }, }, }, - }, - }, + }), + ), }, "ClusterTrustBundlePEM projected volume bySigner with invalid signer name": { expectedError: "must be a fully qualified domain and path of the form", - spec: core.Pod{ - ObjectMeta: metav1.ObjectMeta{Name: "valid-extended", Namespace: "ns"}, - Spec: core.PodSpec{ - ServiceAccountName: "some-service-account", - Containers: []core.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, - RestartPolicy: core.RestartPolicyAlways, - DNSPolicy: core.DNSClusterFirst, - Volumes: []core.Volume{ - { - Name: "projected-volume", - VolumeSource: core.VolumeSource{ - Projected: &core.ProjectedVolumeSource{ - Sources: []core.VolumeProjection{ - { - ClusterTrustBundle: &core.ClusterTrustBundleProjection{ - Path: "foo-path", - SignerName: utilpointer.String("example.com/foo/invalid"), - }, - }, + spec: *podtest.MakePod("valid-extended", + podtest.SetVolumes(core.Volume{ + Name: "projected-volume", + VolumeSource: core.VolumeSource{ + Projected: &core.ProjectedVolumeSource{ + Sources: []core.VolumeProjection{ + { + ClusterTrustBundle: &core.ClusterTrustBundleProjection{ + Path: "foo-path", + SignerName: utilpointer.String("example.com/foo/invalid"), }, }, }, }, }, - }, - }, + }), + ), }, "final PVC name for ephemeral volume must be valid": { expectedError: "spec.volumes[1].name: Invalid value: \"" + longVolName + "\": PVC name \"" + longPodName + "-" + longVolName + "\": must be no more than 253 characters", - spec: core.Pod{ - ObjectMeta: metav1.ObjectMeta{Name: longPodName, Namespace: "ns"}, - Spec: core.PodSpec{ - Volumes: []core.Volume{ - {Name: "pvc", VolumeSource: core.VolumeSource{PersistentVolumeClaim: &core.PersistentVolumeClaimVolumeSource{ClaimName: "my-pvc"}}}, - {Name: longVolName, VolumeSource: core.VolumeSource{Ephemeral: &core.EphemeralVolumeSource{VolumeClaimTemplate: &validPVCTemplate}}}, - }, - Containers: []core.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, - RestartPolicy: core.RestartPolicyAlways, - DNSPolicy: core.DNSClusterFirst, - }, - }, + spec: *podtest.MakePod(longPodName, + podtest.SetVolumes( + core.Volume{Name: "pvc", VolumeSource: core.VolumeSource{PersistentVolumeClaim: &core.PersistentVolumeClaimVolumeSource{ClaimName: "my-pvc"}}}, + core.Volume{Name: longVolName, VolumeSource: core.VolumeSource{Ephemeral: &core.EphemeralVolumeSource{VolumeClaimTemplate: &validPVCTemplate}}}, + ), + ), }, "PersistentVolumeClaimVolumeSource must not reference a generated PVC": { expectedError: "spec.volumes[0].persistentVolumeClaim.claimName: Invalid value: \"123-ephemeral-volume\": must not reference a PVC that gets created for an ephemeral volume", - spec: core.Pod{ - ObjectMeta: metav1.ObjectMeta{Name: "123", Namespace: "ns"}, - Spec: core.PodSpec{ - Volumes: []core.Volume{ - {Name: "pvc-volume", VolumeSource: core.VolumeSource{PersistentVolumeClaim: &core.PersistentVolumeClaimVolumeSource{ClaimName: "123-ephemeral-volume"}}}, - {Name: "ephemeral-volume", VolumeSource: core.VolumeSource{Ephemeral: &core.EphemeralVolumeSource{VolumeClaimTemplate: &validPVCTemplate}}}, - }, - Containers: []core.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, - RestartPolicy: core.RestartPolicyAlways, - DNSPolicy: core.DNSClusterFirst, - }, - }, + spec: *podtest.MakePod("123", + podtest.SetVolumes( + core.Volume{Name: "pvc-volume", VolumeSource: core.VolumeSource{PersistentVolumeClaim: &core.PersistentVolumeClaimVolumeSource{ClaimName: "123-ephemeral-volume"}}}, + core.Volume{Name: "ephemeral-volume", VolumeSource: core.VolumeSource{Ephemeral: &core.EphemeralVolumeSource{VolumeClaimTemplate: &validPVCTemplate}}}, + ), + ), }, "invalid pod-deletion-cost": { expectedError: "metadata.annotations[controller.kubernetes.io/pod-deletion-cost]: Invalid value: \"text\": must be a 32bit integer", - spec: core.Pod{ - ObjectMeta: metav1.ObjectMeta{Name: "123", Namespace: "ns", Annotations: map[string]string{core.PodDeletionCost: "text"}}, - Spec: core.PodSpec{ - Containers: []core.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, - RestartPolicy: core.RestartPolicyAlways, - DNSPolicy: core.DNSClusterFirst, - }, - }, + spec: *podtest.MakePod("valid-extended", + podtest.SetAnnotations(map[string]string{core.PodDeletionCost: "text"}), + ), }, "invalid leading zeros pod-deletion-cost": { expectedError: "metadata.annotations[controller.kubernetes.io/pod-deletion-cost]: Invalid value: \"008\": must be a 32bit integer", - spec: core.Pod{ - ObjectMeta: metav1.ObjectMeta{Name: "123", Namespace: "ns", Annotations: map[string]string{core.PodDeletionCost: "008"}}, - Spec: core.PodSpec{ - Containers: []core.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, - RestartPolicy: core.RestartPolicyAlways, - DNSPolicy: core.DNSClusterFirst, - }, - }, + spec: *podtest.MakePod("valid-extended", + podtest.SetAnnotations(map[string]string{core.PodDeletionCost: "008"}), + ), }, "invalid leading plus sign pod-deletion-cost": { expectedError: "metadata.annotations[controller.kubernetes.io/pod-deletion-cost]: Invalid value: \"+10\": must be a 32bit integer", - spec: core.Pod{ - ObjectMeta: metav1.ObjectMeta{Name: "123", Namespace: "ns", Annotations: map[string]string{core.PodDeletionCost: "+10"}}, - Spec: core.PodSpec{ - Containers: []core.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, - RestartPolicy: core.RestartPolicyAlways, - DNSPolicy: core.DNSClusterFirst, - }, - }, + spec: *podtest.MakePod("valid-extended", + podtest.SetAnnotations(map[string]string{core.PodDeletionCost: "+10"}), + ), }, } + for k, v := range errorCases { t.Run(k, func(t *testing.T) { if errs := ValidatePodCreate(&v.spec, PodValidationOptions{}); len(errs) == 0 { @@ -13189,26 +12165,16 @@ func TestValidatePodCreateWithSchedulingGates(t *testing.T) { wantFieldErrors field.ErrorList }{{ name: "create a Pod with nodeName and schedulingGates, feature enabled", - pod: &core.Pod{ - ObjectMeta: metav1.ObjectMeta{Name: "pod", Namespace: "ns"}, - Spec: core.PodSpec{ - NodeName: "node", - SchedulingGates: []core.PodSchedulingGate{ - {Name: "foo"}, - }, - }, - }, + pod: podtest.MakePod("pod", + podtest.SetNodeName("node"), + podtest.SetSchedulingGates(core.PodSchedulingGate{Name: "foo"}), + ), wantFieldErrors: []*field.Error{field.Forbidden(fldPath.Child("nodeName"), "cannot be set until all schedulingGates have been cleared")}, }, { name: "create a Pod with schedulingGates, feature enabled", - pod: &core.Pod{ - ObjectMeta: metav1.ObjectMeta{Name: "pod", Namespace: "ns"}, - Spec: core.PodSpec{ - SchedulingGates: []core.PodSchedulingGate{ - {Name: "foo"}, - }, - }, - }, + pod: podtest.MakePod("pod", + podtest.SetSchedulingGates(core.PodSchedulingGate{Name: "foo"}), + ), wantFieldErrors: nil, }, } @@ -13244,2135 +12210,1355 @@ func TestValidatePodUpdate(t *testing.T) { err string test string }{ - {new: core.Pod{}, old: core.Pod{}, err: "", test: "nothing"}, { - new: core.Pod{ - ObjectMeta: metav1.ObjectMeta{Name: "foo"}, - }, - old: core.Pod{ - ObjectMeta: metav1.ObjectMeta{Name: "bar"}, - }, + {new: *podtest.MakePod(""), old: *podtest.MakePod(""), err: "", test: "nothing"}, { + new: *podtest.MakePod("foo"), + old: *podtest.MakePod("bar"), err: "metadata.name", test: "ids", }, { - new: core.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - Labels: map[string]string{ - "foo": "bar", - }, - }, - }, - old: core.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - Labels: map[string]string{ - "bar": "foo", - }, - }, - }, + new: *podtest.MakePod("foo", podtest.SetLabels(map[string]string{"foo": "bar"})), + old: *podtest.MakePod("foo", podtest.SetLabels(map[string]string{"bar": "foo"})), err: "", test: "labels", }, { - new: core.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - Annotations: map[string]string{ - "foo": "bar", - }, - }, - }, - old: core.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - Annotations: map[string]string{ - "bar": "foo", - }, - }, - }, + new: *podtest.MakePod("foo", podtest.SetAnnotations(map[string]string{"foo": "bar"})), + old: *podtest.MakePod("foo", podtest.SetAnnotations(map[string]string{"bar": "foo"})), err: "", test: "annotations", }, { - new: core.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - }, - Spec: core.PodSpec{ - Containers: []core.Container{{ - Image: "foo:V1", - }}, - }, - }, - old: core.Pod{ - ObjectMeta: metav1.ObjectMeta{Name: "foo"}, - Spec: core.PodSpec{ - Containers: []core.Container{{ - Image: "foo:V2", - }, { - Image: "bar:V2", - }}, - }, - }, + new: *podtest.MakePod("foo", podtest.SetContainers( + podtest.MakeContainer("foo", podtest.SetContainerImage("foo:V2")))), + old: *podtest.MakePod("foo", podtest.SetContainers( + podtest.MakeContainer("foo", podtest.SetContainerImage("foo:V1")), + podtest.MakeContainer("bar", podtest.SetContainerImage("bar:V1")))), err: "may not add or remove containers", test: "less containers", }, { - new: core.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - }, - Spec: core.PodSpec{ - Containers: []core.Container{{ - Image: "foo:V1", - }, { - Image: "bar:V2", - }}, - }, - }, - old: core.Pod{ - ObjectMeta: metav1.ObjectMeta{Name: "foo"}, - Spec: core.PodSpec{ - Containers: []core.Container{{ - Image: "foo:V2", - }}, - }, - }, + new: *podtest.MakePod("foo", podtest.SetContainers( + podtest.MakeContainer("foo", podtest.SetContainerImage("foo:V2")), + podtest.MakeContainer("bar", podtest.SetContainerImage("bar:V2")))), + old: *podtest.MakePod("foo", podtest.SetContainers( + podtest.MakeContainer("foo", podtest.SetContainerImage("foo:V1")))), err: "may not add or remove containers", test: "more containers", }, { - new: core.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - }, - Spec: core.PodSpec{ - InitContainers: []core.Container{{ - Image: "foo:V1", - }}, - }, - }, - old: core.Pod{ - ObjectMeta: metav1.ObjectMeta{Name: "foo"}, - Spec: core.PodSpec{ - InitContainers: []core.Container{{ - Image: "foo:V2", - }, { - Image: "bar:V2", - }}, - }, - }, + new: *podtest.MakePod("foo", podtest.SetInitContainers( + podtest.MakeContainer("foo", podtest.SetContainerImage("foo:V2")))), + old: *podtest.MakePod("foo", podtest.SetInitContainers( + podtest.MakeContainer("foo", podtest.SetContainerImage("foo:V1")), + podtest.MakeContainer("bar", podtest.SetContainerImage("bar:V1")))), err: "may not add or remove containers", test: "more init containers", }, { - new: core.Pod{ - ObjectMeta: metav1.ObjectMeta{Name: "foo"}, - Spec: core.PodSpec{Containers: []core.Container{{Image: "foo:V1"}}}, - }, - old: core.Pod{ - ObjectMeta: metav1.ObjectMeta{Name: "foo", DeletionTimestamp: &now}, - Spec: core.PodSpec{Containers: []core.Container{{Image: "foo:V1"}}}, - }, + new: *podtest.MakePod("foo"), + old: *podtest.MakePod("foo", podtest.SetObjectMeta(metav1.ObjectMeta{DeletionTimestamp: &now})), err: "metadata.deletionTimestamp", test: "deletion timestamp removed", }, { - new: core.Pod{ - ObjectMeta: metav1.ObjectMeta{Name: "foo", DeletionTimestamp: &now}, - Spec: core.PodSpec{Containers: []core.Container{{Image: "foo:V1"}}}, - }, - old: core.Pod{ - ObjectMeta: metav1.ObjectMeta{Name: "foo"}, - Spec: core.PodSpec{Containers: []core.Container{{Image: "foo:V1"}}}, - }, + new: *podtest.MakePod("foo", podtest.SetObjectMeta(metav1.ObjectMeta{DeletionTimestamp: &now})), + old: *podtest.MakePod("foo"), err: "metadata.deletionTimestamp", test: "deletion timestamp added", }, { - new: core.Pod{ - ObjectMeta: metav1.ObjectMeta{Name: "foo", DeletionTimestamp: &now, DeletionGracePeriodSeconds: &grace}, - Spec: core.PodSpec{Containers: []core.Container{{Image: "foo:V1"}}}, - }, - old: core.Pod{ - ObjectMeta: metav1.ObjectMeta{Name: "foo", DeletionTimestamp: &now, DeletionGracePeriodSeconds: &grace2}, - Spec: core.PodSpec{Containers: []core.Container{{Image: "foo:V1"}}}, - }, + new: *podtest.MakePod("foo", + podtest.SetObjectMeta(metav1.ObjectMeta{DeletionTimestamp: &now, DeletionGracePeriodSeconds: &grace})), + old: *podtest.MakePod("foo", + podtest.SetObjectMeta(metav1.ObjectMeta{DeletionTimestamp: &now, DeletionGracePeriodSeconds: &grace2})), err: "metadata.deletionGracePeriodSeconds", test: "deletion grace period seconds changed", }, { - new: core.Pod{ - ObjectMeta: metav1.ObjectMeta{Name: "foo"}, - Spec: core.PodSpec{ - Containers: []core.Container{{ - Name: "container", - Image: "foo:V1", - TerminationMessagePolicy: "File", - ImagePullPolicy: "Always", - }}, - }, - }, - old: core.Pod{ - ObjectMeta: metav1.ObjectMeta{Name: "foo"}, - Spec: core.PodSpec{ - Containers: []core.Container{{ - Name: "container", - Image: "foo:V2", - TerminationMessagePolicy: "File", - ImagePullPolicy: "Always", - }}, - }, - }, + new: *podtest.MakePod("foo", podtest.SetContainers( + podtest.MakeContainer("container", podtest.SetContainerImage("foo:V1")))), + old: *podtest.MakePod("foo", podtest.SetContainers( + podtest.MakeContainer("container", podtest.SetContainerImage("foo:V2")))), err: "", test: "image change", }, { - new: core.Pod{ - ObjectMeta: metav1.ObjectMeta{Name: "foo"}, - Spec: core.PodSpec{ - InitContainers: []core.Container{{ - Name: "container", - Image: "foo:V1", - TerminationMessagePolicy: "File", - ImagePullPolicy: "Always", - }}, - }, - }, - old: core.Pod{ - ObjectMeta: metav1.ObjectMeta{Name: "foo"}, - Spec: core.PodSpec{ - InitContainers: []core.Container{{ - Name: "container", - Image: "foo:V2", - TerminationMessagePolicy: "File", - ImagePullPolicy: "Always", - }}, - }, - }, + new: *podtest.MakePod("foo", podtest.SetInitContainers( + podtest.MakeContainer("container", podtest.SetContainerImage("foo:V1")))), + old: *podtest.MakePod("foo", podtest.SetInitContainers( + podtest.MakeContainer("container", podtest.SetContainerImage("foo:V2")))), err: "", test: "init container image change", }, { - new: core.Pod{ - ObjectMeta: metav1.ObjectMeta{Name: "foo"}, - Spec: core.PodSpec{ - Containers: []core.Container{{ - Name: "container", - TerminationMessagePolicy: "File", - ImagePullPolicy: "Always", - }}, - }, - }, - old: core.Pod{ - ObjectMeta: metav1.ObjectMeta{Name: "foo"}, - Spec: core.PodSpec{ - Containers: []core.Container{{ - Name: "container", - Image: "foo:V2", - TerminationMessagePolicy: "File", - ImagePullPolicy: "Always", - }}, - }, - }, + new: *podtest.MakePod("foo", podtest.SetContainers( + podtest.MakeContainer("container", podtest.SetContainerImage("")))), + old: *podtest.MakePod("foo", podtest.SetContainers( + podtest.MakeContainer("container", podtest.SetContainerImage("foo:V2")))), err: "spec.containers[0].image", test: "image change to empty", }, { - new: core.Pod{ - ObjectMeta: metav1.ObjectMeta{Name: "foo"}, - Spec: core.PodSpec{ - InitContainers: []core.Container{{ - Name: "container", - TerminationMessagePolicy: "File", - ImagePullPolicy: "Always", - }}, - }, - }, - old: core.Pod{ - ObjectMeta: metav1.ObjectMeta{Name: "foo"}, - Spec: core.PodSpec{ - InitContainers: []core.Container{{ - Name: "container", - Image: "foo:V2", - TerminationMessagePolicy: "File", - ImagePullPolicy: "Always", - }}, - }, - }, + new: *podtest.MakePod("foo", podtest.SetInitContainers( + podtest.MakeContainer("container", podtest.SetContainerImage("")))), + old: *podtest.MakePod("foo", podtest.SetInitContainers( + podtest.MakeContainer("container", podtest.SetContainerImage("foo:V2")))), err: "spec.initContainers[0].image", test: "init container image change to empty", }, { - new: core.Pod{ - ObjectMeta: metav1.ObjectMeta{Name: "foo"}, - Spec: core.PodSpec{ - EphemeralContainers: []core.EphemeralContainer{{ - EphemeralContainerCommon: core.EphemeralContainerCommon{ - Name: "ephemeral", - Image: "busybox", - }, - }}, - }, - }, - old: core.Pod{ - ObjectMeta: metav1.ObjectMeta{Name: "foo"}, - Spec: core.PodSpec{}, - }, + new: *podtest.MakePod("foo", + podtest.SetEphemeralContainers(core.EphemeralContainer{ + EphemeralContainerCommon: core.EphemeralContainerCommon{ + Name: "ephemeral", + Image: "busybox", + }, + }), + ), + old: *podtest.MakePod("foo"), err: "Forbidden: pod updates may not change fields other than", test: "ephemeralContainer changes are not allowed via normal pod update", }, { - new: core.Pod{ - Spec: core.PodSpec{}, - }, - old: core.Pod{ - Spec: core.PodSpec{}, - }, + new: *podtest.MakePod(""), + old: *podtest.MakePod(""), err: "", test: "activeDeadlineSeconds no change, nil", }, { - new: core.Pod{ - Spec: core.PodSpec{ - ActiveDeadlineSeconds: &activeDeadlineSecondsPositive, - }, - }, - old: core.Pod{ - Spec: core.PodSpec{ - ActiveDeadlineSeconds: &activeDeadlineSecondsPositive, - }, - }, + new: *podtest.MakePod("", + podtest.SetActiveDeadlineSeconds(activeDeadlineSecondsPositive)), + old: *podtest.MakePod("", + podtest.SetActiveDeadlineSeconds(activeDeadlineSecondsPositive)), err: "", test: "activeDeadlineSeconds no change, set", }, { - new: core.Pod{ - Spec: core.PodSpec{ - ActiveDeadlineSeconds: &activeDeadlineSecondsPositive, - }, - }, - old: core.Pod{}, + new: *podtest.MakePod("", + podtest.SetActiveDeadlineSeconds(activeDeadlineSecondsPositive)), + old: *podtest.MakePod(""), err: "", test: "activeDeadlineSeconds change to positive from nil", }, { - new: core.Pod{ - Spec: core.PodSpec{ - ActiveDeadlineSeconds: &activeDeadlineSecondsPositive, - }, - }, - old: core.Pod{ - Spec: core.PodSpec{ - ActiveDeadlineSeconds: &activeDeadlineSecondsLarger, - }, - }, + new: *podtest.MakePod("", + podtest.SetActiveDeadlineSeconds(activeDeadlineSecondsPositive)), + old: *podtest.MakePod("", + podtest.SetActiveDeadlineSeconds(activeDeadlineSecondsLarger)), err: "", test: "activeDeadlineSeconds change to smaller positive", }, { - new: core.Pod{ - Spec: core.PodSpec{ - ActiveDeadlineSeconds: &activeDeadlineSecondsLarger, - }, - }, - old: core.Pod{ - Spec: core.PodSpec{ - ActiveDeadlineSeconds: &activeDeadlineSecondsPositive, - }, - }, + new: *podtest.MakePod("", + podtest.SetActiveDeadlineSeconds(activeDeadlineSecondsLarger)), + old: *podtest.MakePod("", + podtest.SetActiveDeadlineSeconds(activeDeadlineSecondsPositive)), err: "spec.activeDeadlineSeconds", test: "activeDeadlineSeconds change to larger positive", - }, - - { - new: core.Pod{ - Spec: core.PodSpec{ - ActiveDeadlineSeconds: &activeDeadlineSecondsNegative, - }, - }, - old: core.Pod{}, + }, { + new: *podtest.MakePod("", + podtest.SetActiveDeadlineSeconds(activeDeadlineSecondsNegative)), + old: *podtest.MakePod(""), err: "spec.activeDeadlineSeconds", test: "activeDeadlineSeconds change to negative from nil", }, { - new: core.Pod{ - Spec: core.PodSpec{ - ActiveDeadlineSeconds: &activeDeadlineSecondsNegative, - }, - }, - old: core.Pod{ - Spec: core.PodSpec{ - ActiveDeadlineSeconds: &activeDeadlineSecondsPositive, - }, - }, + new: *podtest.MakePod("", + podtest.SetActiveDeadlineSeconds(activeDeadlineSecondsNegative)), + old: *podtest.MakePod("", + podtest.SetActiveDeadlineSeconds(activeDeadlineSecondsPositive)), err: "spec.activeDeadlineSeconds", test: "activeDeadlineSeconds change to negative from positive", }, { - new: core.Pod{ - Spec: core.PodSpec{ - ActiveDeadlineSeconds: &activeDeadlineSecondsZero, - }, - }, - old: core.Pod{ - Spec: core.PodSpec{ - ActiveDeadlineSeconds: &activeDeadlineSecondsPositive, - }, - }, + new: *podtest.MakePod("", + podtest.SetActiveDeadlineSeconds(activeDeadlineSecondsZero)), + old: *podtest.MakePod("", + podtest.SetActiveDeadlineSeconds(activeDeadlineSecondsPositive)), err: "spec.activeDeadlineSeconds", test: "activeDeadlineSeconds change to zero from positive", }, { - new: core.Pod{ - Spec: core.PodSpec{ - ActiveDeadlineSeconds: &activeDeadlineSecondsZero, - }, - }, - old: core.Pod{}, + new: *podtest.MakePod("", + podtest.SetActiveDeadlineSeconds(activeDeadlineSecondsZero)), + old: *podtest.MakePod(""), err: "spec.activeDeadlineSeconds", test: "activeDeadlineSeconds change to zero from nil", }, { - new: core.Pod{}, - old: core.Pod{ - Spec: core.PodSpec{ - ActiveDeadlineSeconds: &activeDeadlineSecondsPositive, - }, - }, + new: *podtest.MakePod(""), + old: *podtest.MakePod("", + podtest.SetActiveDeadlineSeconds(activeDeadlineSecondsPositive)), err: "spec.activeDeadlineSeconds", test: "activeDeadlineSeconds change to nil from positive", }, { - new: core.Pod{ - ObjectMeta: metav1.ObjectMeta{Name: "pod"}, - Spec: core.PodSpec{ - Containers: []core.Container{{ - Name: "container", - TerminationMessagePolicy: "File", - ImagePullPolicy: "Always", - Image: "foo:V2", - Resources: core.ResourceRequirements{ - Limits: getResources("200m", "0", "1Gi"), - }, - }}, - }, - }, - old: core.Pod{ - ObjectMeta: metav1.ObjectMeta{Name: "pod"}, - Spec: core.PodSpec{ - Containers: []core.Container{{ - Name: "container", - TerminationMessagePolicy: "File", - ImagePullPolicy: "Always", - Image: "foo:V2", - Resources: core.ResourceRequirements{ - Limits: getResources("100m", "0", "1Gi"), - }, - }}, - }, - }, + new: *podtest.MakePod("pod", + podtest.SetContainers(podtest.MakeContainer("container", + podtest.SetContainerResources(core.ResourceRequirements{ + Limits: getResources("200m", "0", "1Gi"), + }))), + ), + old: *podtest.MakePod("pod", + podtest.SetContainers(podtest.MakeContainer("container", + podtest.SetContainerResources(core.ResourceRequirements{ + Limits: getResources("100m", "0", "1Gi"), + }))), + ), err: "", test: "cpu limit change", }, { - new: core.Pod{ - ObjectMeta: metav1.ObjectMeta{Name: "pod"}, - Spec: core.PodSpec{ - Containers: []core.Container{{ - Name: "container", - TerminationMessagePolicy: "File", - ImagePullPolicy: "Always", - Image: "foo:V1", - Resources: core.ResourceRequirements{ - Limits: getResourceLimits("100m", "100Mi"), - }, - }}, - }, - }, - old: core.Pod{ - ObjectMeta: metav1.ObjectMeta{Name: "pod"}, - Spec: core.PodSpec{ - Containers: []core.Container{{ - Name: "container", - TerminationMessagePolicy: "File", - ImagePullPolicy: "Always", - Image: "foo:V2", - Resources: core.ResourceRequirements{ - Limits: getResourceLimits("100m", "200Mi"), - }, - }}, - }, - }, + new: *podtest.MakePod("pod", + podtest.SetContainers(podtest.MakeContainer("container", + podtest.SetContainerResources(core.ResourceRequirements{ + Limits: getResourceLimits("100m", "100Mi"), + }))), + ), + old: *podtest.MakePod("pod", + podtest.SetContainers(podtest.MakeContainer("container", + podtest.SetContainerResources(core.ResourceRequirements{ + Limits: getResourceLimits("100m", "200Mi"), + }))), + ), err: "", test: "memory limit change", }, { - new: core.Pod{ - ObjectMeta: metav1.ObjectMeta{Name: "pod"}, - Spec: core.PodSpec{ - Containers: []core.Container{{ - Name: "container", - TerminationMessagePolicy: "File", - ImagePullPolicy: "Always", - Image: "foo:V1", - Resources: core.ResourceRequirements{ - Limits: getResources("100m", "100Mi", "1Gi"), - }, - }}, - }, - }, - old: core.Pod{ - ObjectMeta: metav1.ObjectMeta{Name: "pod"}, - Spec: core.PodSpec{ - Containers: []core.Container{{ - Name: "container", - TerminationMessagePolicy: "File", - ImagePullPolicy: "Always", - Image: "foo:V2", - Resources: core.ResourceRequirements{ - Limits: getResources("100m", "100Mi", "2Gi"), - }, - }}, - }, - }, + new: *podtest.MakePod("pod", + podtest.SetContainers(podtest.MakeContainer("container", + podtest.SetContainerResources(core.ResourceRequirements{ + Limits: getResources("100m", "100Mi", "1Gi"), + }))), + ), + old: *podtest.MakePod("pod", + podtest.SetContainers(podtest.MakeContainer("container", + podtest.SetContainerResources(core.ResourceRequirements{ + Limits: getResources("100m", "100Mi", "2Gi"), + }))), + ), err: "Forbidden: pod updates may not change fields other than", test: "storage limit change", }, { - new: core.Pod{ - ObjectMeta: metav1.ObjectMeta{Name: "pod"}, - Spec: core.PodSpec{ - Containers: []core.Container{{ - Name: "container", - TerminationMessagePolicy: "File", - ImagePullPolicy: "Always", - Image: "foo:V1", - Resources: core.ResourceRequirements{ - Requests: getResourceLimits("100m", "0"), - }, - }}, - }, - }, - old: core.Pod{ - ObjectMeta: metav1.ObjectMeta{Name: "pod"}, - Spec: core.PodSpec{ - Containers: []core.Container{{ - Name: "container", - TerminationMessagePolicy: "File", - ImagePullPolicy: "Always", - Image: "foo:V2", - Resources: core.ResourceRequirements{ - Requests: getResourceLimits("200m", "0"), - }, - }}, - }, - }, + new: *podtest.MakePod("pod", + podtest.SetContainers(podtest.MakeContainer("container", + podtest.SetContainerResources(core.ResourceRequirements{ + Requests: getResourceLimits("100m", "0"), + }))), + ), + old: *podtest.MakePod("pod", + podtest.SetContainers(podtest.MakeContainer("container", + podtest.SetContainerResources(core.ResourceRequirements{ + Requests: getResourceLimits("200m", "0"), + }))), + ), err: "", test: "cpu request change", }, { - new: core.Pod{ - ObjectMeta: metav1.ObjectMeta{Name: "pod"}, - Spec: core.PodSpec{ - Containers: []core.Container{{ - Name: "container", - TerminationMessagePolicy: "File", - ImagePullPolicy: "Always", - Image: "foo:V1", - Resources: core.ResourceRequirements{ - Requests: getResourceLimits("0", "200Mi"), - }, - }}, - }, - }, - old: core.Pod{ - ObjectMeta: metav1.ObjectMeta{Name: "pod"}, - Spec: core.PodSpec{ - Containers: []core.Container{{ - Name: "container", - TerminationMessagePolicy: "File", - ImagePullPolicy: "Always", - Image: "foo:V2", - Resources: core.ResourceRequirements{ - Requests: getResourceLimits("0", "100Mi"), - }, - }}, - }, - }, + new: *podtest.MakePod("pod", + podtest.SetContainers(podtest.MakeContainer("container", + podtest.SetContainerResources(core.ResourceRequirements{ + Requests: getResourceLimits("0", "200Mi"), + }))), + ), + old: *podtest.MakePod("pod", + podtest.SetContainers(podtest.MakeContainer("container", + podtest.SetContainerResources(core.ResourceRequirements{ + Requests: getResourceLimits("0", "100Mi"), + }))), + ), err: "", test: "memory request change", }, { - new: core.Pod{ - ObjectMeta: metav1.ObjectMeta{Name: "pod"}, - Spec: core.PodSpec{ - Containers: []core.Container{{ - Name: "container", - TerminationMessagePolicy: "File", - ImagePullPolicy: "Always", - Image: "foo:V1", - Resources: core.ResourceRequirements{ - Requests: getResources("100m", "0", "2Gi"), - }, - }}, - }, - }, - old: core.Pod{ - ObjectMeta: metav1.ObjectMeta{Name: "pod"}, - Spec: core.PodSpec{ - Containers: []core.Container{{ - Name: "container", - TerminationMessagePolicy: "File", - ImagePullPolicy: "Always", - Image: "foo:V2", - Resources: core.ResourceRequirements{ - Requests: getResources("100m", "0", "1Gi"), - }, - }}, - }, - }, + new: *podtest.MakePod("pod", + podtest.SetContainers(podtest.MakeContainer("container", + podtest.SetContainerResources(core.ResourceRequirements{ + Requests: getResources("100m", "0", "2Gi"), + }))), + ), + old: *podtest.MakePod("pod", + podtest.SetContainers(podtest.MakeContainer("container", + podtest.SetContainerResources(core.ResourceRequirements{ + Requests: getResources("100m", "0", "1Gi"), + }))), + ), err: "Forbidden: pod updates may not change fields other than", test: "storage request change", }, { - new: core.Pod{ - ObjectMeta: metav1.ObjectMeta{Name: "pod"}, - Spec: core.PodSpec{ - Containers: []core.Container{{ - Name: "container", - TerminationMessagePolicy: "File", - ImagePullPolicy: "Always", - Image: "foo:V1", - Resources: core.ResourceRequirements{ - Limits: getResources("200m", "400Mi", "1Gi"), - Requests: getResources("200m", "400Mi", "1Gi"), - }, - }}, - }, - }, - old: core.Pod{ - ObjectMeta: metav1.ObjectMeta{Name: "pod"}, - Spec: core.PodSpec{ - Containers: []core.Container{{ - Name: "container", - TerminationMessagePolicy: "File", - ImagePullPolicy: "Always", - Image: "foo:V1", - Resources: core.ResourceRequirements{ - Limits: getResources("100m", "100Mi", "1Gi"), - Requests: getResources("100m", "100Mi", "1Gi"), - }, - }}, - }, - }, + new: *podtest.MakePod("pod", + podtest.SetContainers(podtest.MakeContainer("container", + podtest.SetContainerResources(core.ResourceRequirements{ + Limits: getResources("200m", "400Mi", "1Gi"), + Requests: getResources("200m", "400Mi", "1Gi"), + }))), + ), + old: *podtest.MakePod("pod", + podtest.SetContainers(podtest.MakeContainer("container", + podtest.SetContainerResources(core.ResourceRequirements{ + Limits: getResources("100m", "100Mi", "1Gi"), + Requests: getResources("100m", "100Mi", "1Gi"), + }))), + ), err: "", test: "Pod QoS unchanged, guaranteed -> guaranteed", }, { - new: core.Pod{ - ObjectMeta: metav1.ObjectMeta{Name: "pod"}, - Spec: core.PodSpec{ - Containers: []core.Container{{ - Name: "container", - TerminationMessagePolicy: "File", - ImagePullPolicy: "Always", - Image: "foo:V1", - Resources: core.ResourceRequirements{ - Limits: getResources("200m", "200Mi", "2Gi"), - Requests: getResources("100m", "100Mi", "1Gi"), - }, - }}, - }, - }, - old: core.Pod{ - ObjectMeta: metav1.ObjectMeta{Name: "pod"}, - Spec: core.PodSpec{ - Containers: []core.Container{{ - Name: "container", - TerminationMessagePolicy: "File", - ImagePullPolicy: "Always", - Image: "foo:V1", - Resources: core.ResourceRequirements{ - Limits: getResources("400m", "400Mi", "2Gi"), - Requests: getResources("200m", "200Mi", "1Gi"), - }, - }}, - }, - }, + new: *podtest.MakePod("pod", + podtest.SetContainers(podtest.MakeContainer("container", + podtest.SetContainerResources(core.ResourceRequirements{ + Limits: getResources("200m", "200Mi", "2Gi"), + Requests: getResources("100m", "100Mi", "1Gi"), + }))), + ), + old: *podtest.MakePod("pod", + podtest.SetContainers(podtest.MakeContainer("container", + podtest.SetContainerResources(core.ResourceRequirements{ + Limits: getResources("400m", "400Mi", "2Gi"), + Requests: getResources("200m", "200Mi", "1Gi"), + }))), + ), err: "", test: "Pod QoS unchanged, burstable -> burstable", }, { - new: core.Pod{ - ObjectMeta: metav1.ObjectMeta{Name: "pod"}, - Spec: core.PodSpec{ - Containers: []core.Container{{ - Name: "container", - TerminationMessagePolicy: "File", - ImagePullPolicy: "Always", - Image: "foo:V2", - Resources: core.ResourceRequirements{ - Limits: getResourceLimits("200m", "200Mi"), - Requests: getResourceLimits("100m", "100Mi"), - }, - }}, - }, - }, - old: core.Pod{ - ObjectMeta: metav1.ObjectMeta{Name: "pod"}, - Spec: core.PodSpec{ - Containers: []core.Container{{ - Name: "container", - TerminationMessagePolicy: "File", - ImagePullPolicy: "Always", - Image: "foo:V2", - Resources: core.ResourceRequirements{ - Requests: getResourceLimits("100m", "100Mi"), - }, - }}, - }, - }, + new: *podtest.MakePod("pod", + podtest.SetContainers(podtest.MakeContainer("container", + podtest.SetContainerResources(core.ResourceRequirements{ + Limits: getResourceLimits("200m", "200Mi"), + Requests: getResourceLimits("100m", "100Mi"), + }))), + ), + old: *podtest.MakePod("pod", + podtest.SetContainers(podtest.MakeContainer("container", + podtest.SetContainerResources(core.ResourceRequirements{ + Requests: getResourceLimits("100m", "100Mi"), + }))), + ), err: "", test: "Pod QoS unchanged, burstable -> burstable, add limits", }, { - new: core.Pod{ - ObjectMeta: metav1.ObjectMeta{Name: "pod"}, - Spec: core.PodSpec{ - Containers: []core.Container{{ - Name: "container", - TerminationMessagePolicy: "File", - ImagePullPolicy: "Always", - Image: "foo:V2", - Resources: core.ResourceRequirements{ - Requests: getResourceLimits("100m", "100Mi"), - }, - }}, - }, - }, - old: core.Pod{ - ObjectMeta: metav1.ObjectMeta{Name: "pod"}, - Spec: core.PodSpec{ - Containers: []core.Container{{ - Name: "container", - TerminationMessagePolicy: "File", - ImagePullPolicy: "Always", - Image: "foo:V2", - Resources: core.ResourceRequirements{ - Limits: getResourceLimits("200m", "200Mi"), - Requests: getResourceLimits("100m", "100Mi"), - }, - }}, - }, - }, + new: *podtest.MakePod("pod", + podtest.SetContainers(podtest.MakeContainer("container", + podtest.SetContainerResources(core.ResourceRequirements{ + Requests: getResourceLimits("100m", "100Mi"), + }))), + ), + old: *podtest.MakePod("pod", + podtest.SetContainers(podtest.MakeContainer("container", + podtest.SetContainerResources(core.ResourceRequirements{ + Limits: getResourceLimits("200m", "200Mi"), + Requests: getResourceLimits("100m", "100Mi"), + }))), + ), err: "", test: "Pod QoS unchanged, burstable -> burstable, remove limits", }, { - new: core.Pod{ - ObjectMeta: metav1.ObjectMeta{Name: "pod"}, - Spec: core.PodSpec{ - Containers: []core.Container{{ - Name: "container", - TerminationMessagePolicy: "File", - ImagePullPolicy: "Always", - Image: "foo:V2", - Resources: core.ResourceRequirements{ - Limits: getResources("400m", "", "1Gi"), - Requests: getResources("300m", "", "1Gi"), - }, - }}, - }, - }, - old: core.Pod{ - ObjectMeta: metav1.ObjectMeta{Name: "pod"}, - Spec: core.PodSpec{ - Containers: []core.Container{{ - Name: "container", - TerminationMessagePolicy: "File", - ImagePullPolicy: "Always", - Image: "foo:V2", - Resources: core.ResourceRequirements{ - Limits: getResources("200m", "500Mi", "1Gi"), - }, - }}, - }, - }, + new: *podtest.MakePod("pod", + podtest.SetContainers(podtest.MakeContainer("container", + podtest.SetContainerResources(core.ResourceRequirements{ + Limits: getResources("400m", "", "1Gi"), + Requests: getResources("300m", "", "1Gi"), + }))), + ), + old: *podtest.MakePod("pod", + podtest.SetContainers(podtest.MakeContainer("container", + podtest.SetContainerResources(core.ResourceRequirements{ + Limits: getResources("200m", "500Mi", "1Gi"), + }))), + ), err: "", test: "Pod QoS unchanged, burstable -> burstable, add requests", }, { - new: core.Pod{ - ObjectMeta: metav1.ObjectMeta{Name: "pod"}, - Spec: core.PodSpec{ - Containers: []core.Container{{ - Name: "container", - TerminationMessagePolicy: "File", - ImagePullPolicy: "Always", - Image: "foo:V2", - Resources: core.ResourceRequirements{ - Limits: getResources("400m", "500Mi", "2Gi"), - }, - }}, - }, - }, - old: core.Pod{ - ObjectMeta: metav1.ObjectMeta{Name: "pod"}, - Spec: core.PodSpec{ - Containers: []core.Container{{ - Name: "container", - TerminationMessagePolicy: "File", - ImagePullPolicy: "Always", - Image: "foo:V2", - Resources: core.ResourceRequirements{ - Limits: getResources("200m", "300Mi", "2Gi"), - Requests: getResourceLimits("100m", "200Mi"), - }, - }}, - }, - }, + new: *podtest.MakePod("pod", + podtest.SetContainers(podtest.MakeContainer("container", + podtest.SetContainerResources(core.ResourceRequirements{ + Limits: getResources("400m", "500Mi", "2Gi"), + }))), + ), + old: *podtest.MakePod("pod", + podtest.SetContainers(podtest.MakeContainer("container", + podtest.SetContainerResources(core.ResourceRequirements{ + Limits: getResources("200m", "300Mi", "2Gi"), + Requests: getResourceLimits("100m", "200Mi"), + }))), + ), err: "", test: "Pod QoS unchanged, burstable -> burstable, remove requests", }, { - new: core.Pod{ - ObjectMeta: metav1.ObjectMeta{Name: "pod"}, - Spec: core.PodSpec{ - Containers: []core.Container{{ - Name: "container", - TerminationMessagePolicy: "File", - ImagePullPolicy: "Always", - Image: "foo:V2", - Resources: core.ResourceRequirements{ - Limits: getResourceLimits("200m", "200Mi"), - Requests: getResourceLimits("100m", "100Mi"), - }, - }}, - }, - }, - old: core.Pod{ - ObjectMeta: metav1.ObjectMeta{Name: "pod"}, - Spec: core.PodSpec{ - Containers: []core.Container{{ - Name: "container", - TerminationMessagePolicy: "File", - ImagePullPolicy: "Always", - Image: "foo:V2", - Resources: core.ResourceRequirements{ - Limits: getResourceLimits("100m", "100Mi"), - Requests: getResourceLimits("100m", "100Mi"), - }, - }}, - }, - }, + new: *podtest.MakePod("pod", + podtest.SetContainers(podtest.MakeContainer("container", + podtest.SetContainerResources(core.ResourceRequirements{ + Limits: getResourceLimits("200m", "200Mi"), + Requests: getResourceLimits("100m", "100Mi"), + }))), + ), + old: *podtest.MakePod("pod", + podtest.SetContainers(podtest.MakeContainer("container", + podtest.SetContainerResources(core.ResourceRequirements{ + Limits: getResourceLimits("100m", "100Mi"), + Requests: getResourceLimits("100m", "100Mi"), + }))), + ), err: "Pod QoS is immutable", test: "Pod QoS change, guaranteed -> burstable", }, { - new: core.Pod{ - ObjectMeta: metav1.ObjectMeta{Name: "pod"}, - Spec: core.PodSpec{ - Containers: []core.Container{{ - Name: "container", - TerminationMessagePolicy: "File", - ImagePullPolicy: "Always", - Image: "foo:V2", - Resources: core.ResourceRequirements{ - Limits: getResourceLimits("100m", "100Mi"), - Requests: getResourceLimits("100m", "100Mi"), - }, - }}, - }, - }, - old: core.Pod{ - ObjectMeta: metav1.ObjectMeta{Name: "pod"}, - Spec: core.PodSpec{ - Containers: []core.Container{{ - Name: "container", - TerminationMessagePolicy: "File", - ImagePullPolicy: "Always", - Image: "foo:V2", - Resources: core.ResourceRequirements{ - Requests: getResourceLimits("100m", "100Mi"), - }, - }}, - }, - }, + new: *podtest.MakePod("pod", + podtest.SetContainers(podtest.MakeContainer("container", + podtest.SetContainerResources(core.ResourceRequirements{ + Limits: getResourceLimits("100m", "100Mi"), + Requests: getResourceLimits("100m", "100Mi"), + }))), + ), + old: *podtest.MakePod("pod", + podtest.SetContainers(podtest.MakeContainer("container", + podtest.SetContainerResources(core.ResourceRequirements{ + Requests: getResourceLimits("100m", "100Mi"), + }))), + ), err: "Pod QoS is immutable", test: "Pod QoS change, burstable -> guaranteed", }, { - new: core.Pod{ - ObjectMeta: metav1.ObjectMeta{Name: "pod"}, - Spec: core.PodSpec{ - Containers: []core.Container{{ - Name: "container", - TerminationMessagePolicy: "File", - ImagePullPolicy: "Always", - Image: "foo:V2", - Resources: core.ResourceRequirements{ - Limits: getResourceLimits("200m", "200Mi"), - Requests: getResourceLimits("100m", "100Mi"), - }, - }}, - }, - }, - old: core.Pod{ - ObjectMeta: metav1.ObjectMeta{Name: "pod"}, - Spec: core.PodSpec{ - Containers: []core.Container{{ - Name: "container", - TerminationMessagePolicy: "File", - ImagePullPolicy: "Always", - Image: "foo:V2", - }}, - }, - }, + new: *podtest.MakePod("pod", + podtest.SetContainers(podtest.MakeContainer("container", + podtest.SetContainerResources(core.ResourceRequirements{ + Limits: getResourceLimits("200m", "200Mi"), + Requests: getResourceLimits("100m", "100Mi"), + }))), + ), + old: *podtest.MakePod("pod"), err: "Pod QoS is immutable", test: "Pod QoS change, besteffort -> burstable", }, { - new: core.Pod{ - ObjectMeta: metav1.ObjectMeta{Name: "pod"}, - Spec: core.PodSpec{ - Containers: []core.Container{{ - Name: "container", - TerminationMessagePolicy: "File", - ImagePullPolicy: "Always", - Image: "foo:V2", - }}, - }, - }, - old: core.Pod{ - ObjectMeta: metav1.ObjectMeta{Name: "pod"}, - Spec: core.PodSpec{ - Containers: []core.Container{{ - Name: "container", - TerminationMessagePolicy: "File", - ImagePullPolicy: "Always", - Image: "foo:V2", - Resources: core.ResourceRequirements{ - Limits: getResourceLimits("200m", "200Mi"), - Requests: getResourceLimits("100m", "100Mi"), - }, - }}, - }, - }, + new: *podtest.MakePod("pod"), + old: *podtest.MakePod("pod", + podtest.SetContainers(podtest.MakeContainer("container", + podtest.SetContainerResources(core.ResourceRequirements{ + Limits: getResourceLimits("200m", "200Mi"), + Requests: getResourceLimits("100m", "100Mi"), + }))), + ), err: "Pod QoS is immutable", test: "Pod QoS change, burstable -> besteffort", }, { - new: core.Pod{ - ObjectMeta: metav1.ObjectMeta{Name: "foo"}, - Spec: core.PodSpec{ - Containers: []core.Container{{ - Image: "foo:V1", - }}, - SecurityContext: &core.PodSecurityContext{ - FSGroupChangePolicy: &validfsGroupChangePolicy, - }, - }, - }, - old: core.Pod{ - ObjectMeta: metav1.ObjectMeta{Name: "foo"}, - Spec: core.PodSpec{ - Containers: []core.Container{{ - Image: "foo:V2", - }}, - SecurityContext: &core.PodSecurityContext{ - FSGroupChangePolicy: nil, - }, - }, - }, + new: *podtest.MakePod("pod", + podtest.SetSecurityContext(&core.PodSecurityContext{ + FSGroupChangePolicy: &validfsGroupChangePolicy, + }), + ), + old: *podtest.MakePod("pod", + podtest.SetSecurityContext(&core.PodSecurityContext{ + FSGroupChangePolicy: nil, + }), + ), err: "spec: Forbidden: pod updates may not change fields", test: "fsGroupChangePolicy change", }, { - new: core.Pod{ - ObjectMeta: metav1.ObjectMeta{Name: "foo"}, - Spec: core.PodSpec{ - Containers: []core.Container{{ - Image: "foo:V1", - Ports: []core.ContainerPort{ - {HostPort: 8080, ContainerPort: 80}, - }, - }}, - }, - }, - old: core.Pod{ - ObjectMeta: metav1.ObjectMeta{Name: "foo"}, - Spec: core.PodSpec{ - Containers: []core.Container{{ - Image: "foo:V2", - Ports: []core.ContainerPort{ - {HostPort: 8000, ContainerPort: 80}, - }, - }}, - }, - }, + new: *podtest.MakePod("pod", + podtest.SetContainers(podtest.MakeContainer("container", + podtest.SetContainerPorts(core.ContainerPort{HostPort: 8080, ContainerPort: 80}))), + ), + old: *podtest.MakePod("pod", + podtest.SetContainers(podtest.MakeContainer("container", + podtest.SetContainerPorts(core.ContainerPort{HostPort: 8000, ContainerPort: 80}))), + ), err: "spec: Forbidden: pod updates may not change fields", test: "port change", }, { - new: core.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - Labels: map[string]string{ - "foo": "bar", - }, - }, - }, - old: core.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - Labels: map[string]string{ - "Bar": "foo", - }, - }, - }, + new: *podtest.MakePod("foo", podtest.SetLabels(map[string]string{"foo": "bar"})), + old: *podtest.MakePod("foo", podtest.SetLabels(map[string]string{"bar": "foo"})), err: "", test: "bad label change", }, { - new: core.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - }, - Spec: core.PodSpec{ - NodeName: "node1", - Tolerations: []core.Toleration{{Key: "key1", Value: "value2"}}, - }, - }, - old: core.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - }, - Spec: core.PodSpec{ - NodeName: "node1", - Tolerations: []core.Toleration{{Key: "key1", Value: "value1"}}, - }, - }, + new: *podtest.MakePod("foo", + podtest.SetNodeName("node1"), + podtest.SetTolerations(core.Toleration{Key: "key1", Value: "value2"}), + ), + old: *podtest.MakePod("foo", + podtest.SetNodeName("node1"), + podtest.SetTolerations(core.Toleration{Key: "key1", Value: "value1"}), + ), err: "spec.tolerations: Forbidden", test: "existing toleration value modified in pod spec updates", }, { - new: core.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - }, - Spec: core.PodSpec{ - NodeName: "node1", - Tolerations: []core.Toleration{{Key: "key1", Value: "value2", Operator: "Equal", Effect: "NoExecute", TolerationSeconds: nil}}, - }, - }, - old: core.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - }, - Spec: core.PodSpec{ - NodeName: "node1", - Tolerations: []core.Toleration{{Key: "key1", Value: "value1", Operator: "Equal", Effect: "NoExecute", TolerationSeconds: &[]int64{10}[0]}}, - }, - }, + new: *podtest.MakePod("foo", + podtest.SetNodeName("node1"), + podtest.SetTolerations(core.Toleration{Key: "key1", Value: "value2", Operator: "Equal", Effect: "NoExecute", TolerationSeconds: nil}), + ), + old: *podtest.MakePod("foo", + podtest.SetNodeName("node1"), + podtest.SetTolerations(core.Toleration{Key: "key1", Value: "value1", Operator: "Equal", Effect: "NoExecute", TolerationSeconds: &[]int64{10}[0]}), + ), err: "spec.tolerations: Forbidden", test: "existing toleration value modified in pod spec updates with modified tolerationSeconds", }, { - new: core.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - }, - Spec: core.PodSpec{ - NodeName: "node1", - Tolerations: []core.Toleration{{Key: "key1", Value: "value1", Operator: "Equal", Effect: "NoExecute", TolerationSeconds: &[]int64{10}[0]}}, - }, - }, - old: core.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - }, - Spec: core.PodSpec{ - NodeName: "node1", - Tolerations: []core.Toleration{{Key: "key1", Value: "value1", Operator: "Equal", Effect: "NoExecute", TolerationSeconds: &[]int64{20}[0]}}, - }}, + new: *podtest.MakePod("foo", + podtest.SetNodeName("node1"), + podtest.SetTolerations(core.Toleration{Key: "key1", Value: "value1", Operator: "Equal", Effect: "NoExecute", TolerationSeconds: &[]int64{10}[0]}), + ), + old: *podtest.MakePod("foo", + podtest.SetNodeName("node1"), + podtest.SetTolerations(core.Toleration{Key: "key1", Value: "value1", Operator: "Equal", Effect: "NoExecute", TolerationSeconds: &[]int64{20}[0]}), + ), err: "", test: "modified tolerationSeconds in existing toleration value in pod spec updates", }, { - new: core.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - }, - Spec: core.PodSpec{ - Tolerations: []core.Toleration{{Key: "key1", Value: "value2"}}, - }, - }, - old: core.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - }, - Spec: core.PodSpec{ - NodeName: "", - Tolerations: []core.Toleration{{Key: "key1", Value: "value1"}}, - }, - }, + new: *podtest.MakePod("foo", + podtest.SetTolerations(core.Toleration{Key: "key1", Value: "value2"}), + ), + old: *podtest.MakePod("foo", + podtest.SetNodeName(""), + podtest.SetTolerations(core.Toleration{Key: "key1", Value: "value1"}), + ), err: "spec.tolerations: Forbidden", test: "toleration modified in updates to an unscheduled pod", }, { - new: core.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - }, - Spec: core.PodSpec{ - NodeName: "node1", - Tolerations: []core.Toleration{{Key: "key1", Value: "value1"}}, - }, - }, - old: core.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - }, - Spec: core.PodSpec{ - NodeName: "node1", - Tolerations: []core.Toleration{{Key: "key1", Value: "value1"}}, - }, - }, + new: *podtest.MakePod("foo", + podtest.SetNodeName("node1"), + podtest.SetTolerations(core.Toleration{Key: "key1", Value: "value1"}), + ), + old: *podtest.MakePod("foo", + podtest.SetNodeName("node1"), + podtest.SetTolerations(core.Toleration{Key: "key1", Value: "value1"}), + ), err: "", test: "tolerations unmodified in updates to a scheduled pod", }, { - new: core.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - }, - Spec: core.PodSpec{ - NodeName: "node1", - Tolerations: []core.Toleration{ - {Key: "key1", Value: "value1", Operator: "Equal", Effect: "NoExecute", TolerationSeconds: &[]int64{20}[0]}, - {Key: "key2", Value: "value2", Operator: "Equal", Effect: "NoExecute", TolerationSeconds: &[]int64{30}[0]}, - }, - }}, - old: core.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - }, - Spec: core.PodSpec{ - NodeName: "node1", - Tolerations: []core.Toleration{{Key: "key1", Value: "value1", Operator: "Equal", Effect: "NoExecute", TolerationSeconds: &[]int64{10}[0]}}, - }, - }, + new: *podtest.MakePod("foo", + podtest.SetNodeName("node1"), + podtest.SetTolerations( + core.Toleration{Key: "key1", Value: "value1", Operator: "Equal", Effect: "NoExecute", TolerationSeconds: &[]int64{20}[0]}, + core.Toleration{Key: "key2", Value: "value2", Operator: "Equal", Effect: "NoExecute", TolerationSeconds: &[]int64{30}[0]}), + ), + old: *podtest.MakePod("foo", + podtest.SetNodeName("node1"), + podtest.SetTolerations( + core.Toleration{Key: "key1", Value: "value1", Operator: "Equal", Effect: "NoExecute", TolerationSeconds: &[]int64{10}[0]}), + ), err: "", test: "added valid new toleration to existing tolerations in pod spec updates", }, { - new: core.Pod{ - ObjectMeta: metav1.ObjectMeta{Name: "foo"}, Spec: core.PodSpec{ - NodeName: "node1", - Tolerations: []core.Toleration{ - {Key: "key1", Value: "value1", Operator: "Equal", Effect: "NoExecute", TolerationSeconds: &[]int64{20}[0]}, - {Key: "key2", Value: "value2", Operator: "Equal", Effect: "NoSchedule", TolerationSeconds: &[]int64{30}[0]}, - }, - }}, - old: core.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - }, - Spec: core.PodSpec{ - NodeName: "node1", Tolerations: []core.Toleration{{Key: "key1", Value: "value1", Operator: "Equal", Effect: "NoExecute", TolerationSeconds: &[]int64{10}[0]}}, - }}, + new: *podtest.MakePod("foo", + podtest.SetNodeName("node1"), + podtest.SetTolerations( + core.Toleration{Key: "key1", Value: "value1", Operator: "Equal", Effect: "NoExecute", TolerationSeconds: &[]int64{20}[0]}, + core.Toleration{Key: "key2", Value: "value2", Operator: "Equal", Effect: "NoSchedule", TolerationSeconds: &[]int64{30}[0]}, + ), + ), + old: *podtest.MakePod("foo", + podtest.SetNodeName("node1"), + podtest.SetTolerations(core.Toleration{Key: "key1", Value: "value1", Operator: "Equal", Effect: "NoExecute", TolerationSeconds: &[]int64{10}[0]}), + ), err: "spec.tolerations[1].effect", test: "added invalid new toleration to existing tolerations in pod spec updates", }, { - new: core.Pod{ObjectMeta: metav1.ObjectMeta{Name: "foo"}, Spec: core.PodSpec{NodeName: "foo"}}, - old: core.Pod{ObjectMeta: metav1.ObjectMeta{Name: "foo"}}, + new: *podtest.MakePod("foo", + podtest.SetNodeName("foo")), + old: *podtest.MakePod("foo"), err: "spec: Forbidden: pod updates may not change fields", test: "removed nodeName from pod spec", }, { - new: core.Pod{ObjectMeta: metav1.ObjectMeta{Name: "foo", Annotations: map[string]string{core.MirrorPodAnnotationKey: ""}}, Spec: core.PodSpec{NodeName: "foo"}}, - old: core.Pod{ObjectMeta: metav1.ObjectMeta{Name: "foo"}, Spec: core.PodSpec{NodeName: "foo"}}, + new: *podtest.MakePod("foo", + podtest.SetAnnotations(map[string]string{core.MirrorPodAnnotationKey: ""}), + podtest.SetNodeName("foo")), + old: *podtest.MakePod("foo", + podtest.SetNodeName("foo")), err: "metadata.annotations[kubernetes.io/config.mirror]", test: "added mirror pod annotation", }, { - new: core.Pod{ObjectMeta: metav1.ObjectMeta{Name: "foo"}, Spec: core.PodSpec{NodeName: "foo"}}, - old: core.Pod{ObjectMeta: metav1.ObjectMeta{Name: "foo", Annotations: map[string]string{core.MirrorPodAnnotationKey: ""}}, Spec: core.PodSpec{NodeName: "foo"}}, + new: *podtest.MakePod("foo", + podtest.SetNodeName("foo")), + old: *podtest.MakePod("foo", + podtest.SetAnnotations(map[string]string{core.MirrorPodAnnotationKey: ""}), + podtest.SetNodeName("foo")), err: "metadata.annotations[kubernetes.io/config.mirror]", test: "removed mirror pod annotation", }, { - new: core.Pod{ObjectMeta: metav1.ObjectMeta{Name: "foo", Annotations: map[string]string{core.MirrorPodAnnotationKey: "foo"}}, Spec: core.PodSpec{NodeName: "foo"}}, - old: core.Pod{ObjectMeta: metav1.ObjectMeta{Name: "foo", Annotations: map[string]string{core.MirrorPodAnnotationKey: "bar"}}, Spec: core.PodSpec{NodeName: "foo"}}, + new: *podtest.MakePod("foo", + podtest.SetAnnotations(map[string]string{core.MirrorPodAnnotationKey: "foo"}), + podtest.SetNodeName("foo")), + old: *podtest.MakePod("foo", + podtest.SetAnnotations(map[string]string{core.MirrorPodAnnotationKey: "bar"}), + podtest.SetNodeName("foo")), err: "metadata.annotations[kubernetes.io/config.mirror]", test: "changed mirror pod annotation", }, { - new: core.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - }, - Spec: core.PodSpec{ - NodeName: "node1", - PriorityClassName: "bar-priority", - }, - }, - old: core.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - }, - Spec: core.PodSpec{ - NodeName: "node1", - PriorityClassName: "foo-priority", - }, - }, + new: *podtest.MakePod("foo", + podtest.SetNodeName("node1"), + podtest.SetPriorityClassName("bar-priority"), + ), + old: *podtest.MakePod("foo", + podtest.SetNodeName("node1"), + podtest.SetPriorityClassName("foo-priority"), + ), err: "spec: Forbidden: pod updates", test: "changed priority class name", }, { - new: core.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - }, - Spec: core.PodSpec{ - NodeName: "node1", - PriorityClassName: "", - }, - }, - old: core.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - }, - Spec: core.PodSpec{ - NodeName: "node1", - PriorityClassName: "foo-priority", - }, - }, + new: *podtest.MakePod("foo", + podtest.SetNodeName("node1"), + podtest.SetPriorityClassName(""), + ), + old: *podtest.MakePod("foo", + podtest.SetNodeName("node1"), + podtest.SetPriorityClassName("foo-priority"), + ), err: "spec: Forbidden: pod updates", test: "removed priority class name", }, { - new: core.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - }, - Spec: core.PodSpec{ - TerminationGracePeriodSeconds: utilpointer.Int64(1), - }, - }, - old: core.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - }, - Spec: core.PodSpec{ - TerminationGracePeriodSeconds: utilpointer.Int64(-1), - }, - }, + new: *podtest.MakePod("foo", + podtest.SetTerminationGracePeriodSeconds(1), + ), + old: *podtest.MakePod("foo", + podtest.SetTerminationGracePeriodSeconds(-1), + ), err: "", test: "update termination grace period seconds", }, { - new: core.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - }, - Spec: core.PodSpec{ - TerminationGracePeriodSeconds: utilpointer.Int64(0), - }, - }, - old: core.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - }, - Spec: core.PodSpec{ - TerminationGracePeriodSeconds: utilpointer.Int64(-1), - }, - }, + new: *podtest.MakePod("foo", + podtest.SetTerminationGracePeriodSeconds(0), + ), + old: *podtest.MakePod("foo", + podtest.SetTerminationGracePeriodSeconds(-1), + ), err: "spec: Forbidden: pod updates", test: "update termination grace period seconds not 1", }, { - new: core.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - }, - Spec: core.PodSpec{ - OS: &core.PodOS{Name: core.Windows}, - SecurityContext: &core.PodSecurityContext{SELinuxOptions: &core.SELinuxOptions{Role: "dummy"}}, - }, - }, - old: core.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - }, - Spec: core.PodSpec{ - OS: &core.PodOS{Name: core.Linux}, - SecurityContext: &core.PodSecurityContext{SELinuxOptions: &core.SELinuxOptions{Role: "dummy"}}, - }, - }, + new: *podtest.MakePod("foo", + podtest.SetOS(core.Windows), + podtest.SetSecurityContext(&core.PodSecurityContext{SELinuxOptions: &core.SELinuxOptions{Role: "dummy"}}), + ), + old: *podtest.MakePod("foo", + podtest.SetOS(core.Linux), + podtest.SetSecurityContext(&core.PodSecurityContext{SELinuxOptions: &core.SELinuxOptions{Role: "dummy"}}), + ), err: "Forbidden: pod updates may not change fields other than `spec.containers[*].image", test: "pod OS changing from Linux to Windows, IdentifyPodOS featuregate set", }, { - new: core.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - }, - Spec: core.PodSpec{ - OS: &core.PodOS{Name: core.Windows}, - SecurityContext: &core.PodSecurityContext{SELinuxOptions: &core.SELinuxOptions{Role: "dummy"}}, - }, - }, - old: core.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - }, - Spec: core.PodSpec{ - OS: &core.PodOS{Name: core.Linux}, - SecurityContext: &core.PodSecurityContext{SELinuxOptions: &core.SELinuxOptions{Role: "dummy"}}, - }, - }, + new: *podtest.MakePod("foo", + podtest.SetOS(core.Windows), + podtest.SetSecurityContext(&core.PodSecurityContext{SELinuxOptions: &core.SELinuxOptions{Role: "dummy"}}), + ), + old: *podtest.MakePod("foo", + podtest.SetOS(core.Linux), + podtest.SetSecurityContext(&core.PodSecurityContext{SELinuxOptions: &core.SELinuxOptions{Role: "dummy"}}), + ), err: "spec.securityContext.seLinuxOptions: Forbidden", test: "pod OS changing from Linux to Windows, IdentifyPodOS featuregate set, we'd get SELinux errors as well", }, { - new: core.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - }, - Spec: core.PodSpec{ - OS: &core.PodOS{Name: "dummy"}, - }, - }, - old: core.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - }, - Spec: core.PodSpec{}, - }, + new: *podtest.MakePod("foo", + podtest.SetOS("dummy"), + ), + old: *podtest.MakePod("foo"), err: "Forbidden: pod updates may not change fields other than `spec.containers[*].image", test: "invalid PodOS update, IdentifyPodOS featuregate set", }, { - new: core.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - }, - Spec: core.PodSpec{ - OS: &core.PodOS{Name: core.Linux}, - }, - }, - old: core.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - }, - Spec: core.PodSpec{ - OS: &core.PodOS{Name: core.Windows}, - }, - }, + new: *podtest.MakePod("foo", + podtest.SetOS(core.Linux), + ), + old: *podtest.MakePod("foo", + podtest.SetOS(core.Windows), + ), err: "Forbidden: pod updates may not change fields other than ", test: "update pod spec OS to a valid value, featuregate disabled", }, { - new: core.Pod{ - Spec: core.PodSpec{ - SchedulingGates: []core.PodSchedulingGate{{Name: "foo"}}, - }, - }, - old: core.Pod{}, + new: *podtest.MakePod("foo", + podtest.SetSchedulingGates(core.PodSchedulingGate{Name: "foo"}), + ), + old: *podtest.MakePod("foo"), err: "Forbidden: only deletion is allowed, but found new scheduling gate 'foo'", test: "update pod spec schedulingGates: add new scheduling gate", }, { - new: core.Pod{ - Spec: core.PodSpec{ - SchedulingGates: []core.PodSchedulingGate{{Name: "bar"}}, - }, - }, - old: core.Pod{ - Spec: core.PodSpec{ - SchedulingGates: []core.PodSchedulingGate{{Name: "foo"}}, - }, - }, + new: *podtest.MakePod("foo", + podtest.SetSchedulingGates(core.PodSchedulingGate{Name: "bar"}), + ), + old: *podtest.MakePod("foo", + podtest.SetSchedulingGates(core.PodSchedulingGate{Name: "foo"}), + ), err: "Forbidden: only deletion is allowed, but found new scheduling gate 'bar'", test: "update pod spec schedulingGates: mutating an existing scheduling gate", }, { - new: core.Pod{ - Spec: core.PodSpec{ - SchedulingGates: []core.PodSchedulingGate{{Name: "baz"}}, - }, - }, - old: core.Pod{ - Spec: core.PodSpec{ - SchedulingGates: []core.PodSchedulingGate{{Name: "foo"}, {Name: "bar"}}, - }, - }, + new: *podtest.MakePod("foo", + podtest.SetSchedulingGates(core.PodSchedulingGate{Name: "baz"}), + ), + old: *podtest.MakePod("foo", + podtest.SetSchedulingGates( + core.PodSchedulingGate{Name: "foo"}, + core.PodSchedulingGate{Name: "bar"}), + ), err: "Forbidden: only deletion is allowed, but found new scheduling gate 'baz'", test: "update pod spec schedulingGates: mutating an existing scheduling gate along with deletion", }, { - new: core.Pod{}, - old: core.Pod{ - Spec: core.PodSpec{ - SchedulingGates: []core.PodSchedulingGate{{Name: "foo"}}, - }, - }, + new: *podtest.MakePod("foo"), + old: *podtest.MakePod("foo", + podtest.SetSchedulingGates(core.PodSchedulingGate{Name: "foo"}), + ), err: "", test: "update pod spec schedulingGates: legal deletion", }, { - old: core.Pod{ - Spec: core.PodSpec{ - SchedulingGates: []core.PodSchedulingGate{{Name: "baz"}}, - }, - }, - new: core.Pod{ - Spec: core.PodSpec{ - NodeSelector: map[string]string{ - "foo": "bar", - }, - SchedulingGates: []core.PodSchedulingGate{{Name: "baz"}}, - }, - }, + old: *podtest.MakePod("foo", + podtest.SetSchedulingGates(core.PodSchedulingGate{Name: "baz"}), + ), + new: *podtest.MakePod("foo", + podtest.SetNodeSelector(map[string]string{ + "foo": "bar", + }), + podtest.SetSchedulingGates(core.PodSchedulingGate{Name: "baz"}), + ), test: "adding node selector is allowed for gated pods", }, { - old: core.Pod{ - Spec: core.PodSpec{ - NodeSelector: map[string]string{ - "foo": "bar", - }, + old: *podtest.MakePod("foo", + podtest.SetNodeSelector(map[string]string{ + "foo": "bar", }, - }, - new: core.Pod{ - Spec: core.PodSpec{ - NodeSelector: map[string]string{ - "foo": "bar", - "foo2": "bar2", - }, + ), + ), + new: *podtest.MakePod("foo", + podtest.SetNodeSelector(map[string]string{ + "foo": "bar", + "foo2": "bar2", }, - }, + ), + ), err: "Forbidden: pod updates may not change fields other than `spec.containers[*].image", test: "adding node selector is not allowed for non-gated pods", }, { - old: core.Pod{ - Spec: core.PodSpec{ - NodeSelector: map[string]string{ - "foo": "bar", - }, - SchedulingGates: []core.PodSchedulingGate{{Name: "baz"}}, - }, - }, - new: core.Pod{ - Spec: core.PodSpec{ - SchedulingGates: []core.PodSchedulingGate{{Name: "baz"}}, - }, - }, + old: *podtest.MakePod("foo", + podtest.SetNodeSelector(map[string]string{ + "foo": "bar", + }), + podtest.SetSchedulingGates(core.PodSchedulingGate{Name: "baz"}), + ), + new: *podtest.MakePod("foo", + podtest.SetSchedulingGates(core.PodSchedulingGate{Name: "baz"}), + ), err: "spec.nodeSelector: Invalid value:", test: "removing node selector is not allowed for gated pods", }, { - old: core.Pod{ - Spec: core.PodSpec{ - NodeSelector: map[string]string{ - "foo": "bar", - }, + old: *podtest.MakePod("foo", + podtest.SetNodeSelector(map[string]string{ + "foo": "bar", }, - }, - new: core.Pod{}, + ), + ), + new: *podtest.MakePod("foo"), err: "Forbidden: pod updates may not change fields other than `spec.containers[*].image", test: "removing node selector is not allowed for non-gated pods", }, { - old: core.Pod{ - Spec: core.PodSpec{ - NodeSelector: map[string]string{ - "foo": "bar", - }, - SchedulingGates: []core.PodSchedulingGate{{Name: "baz"}}, - }, - }, - new: core.Pod{ - Spec: core.PodSpec{ - NodeSelector: map[string]string{ - "foo": "bar", - "foo2": "bar2", - }, - }, - }, + old: *podtest.MakePod("foo", + podtest.SetNodeSelector(map[string]string{ + "foo": "bar", + }), + podtest.SetSchedulingGates(core.PodSchedulingGate{Name: "baz"}), + ), + new: *podtest.MakePod("foo", + podtest.SetNodeSelector(map[string]string{ + "foo": "bar", + "foo2": "bar2", + }), + ), test: "old pod spec has scheduling gate, new pod spec does not, and node selector is added", }, { - old: core.Pod{ - Spec: core.PodSpec{ - NodeSelector: map[string]string{ - "foo": "bar", - }, - SchedulingGates: []core.PodSchedulingGate{{Name: "baz"}}, - }, - }, - new: core.Pod{ - Spec: core.PodSpec{ - NodeSelector: map[string]string{ - "foo": "new value", - }, - SchedulingGates: []core.PodSchedulingGate{{Name: "baz"}}, - }, - }, + old: *podtest.MakePod("foo", + podtest.SetNodeSelector(map[string]string{ + "foo": "bar", + }), + podtest.SetSchedulingGates(core.PodSchedulingGate{Name: "baz"}), + ), + new: *podtest.MakePod("foo", + podtest.SetNodeSelector(map[string]string{ + "foo": "new value", + }), + podtest.SetSchedulingGates(core.PodSchedulingGate{Name: "baz"}), + ), err: "spec.nodeSelector: Invalid value:", test: "modifying value of existing node selector is not allowed", }, { - old: core.Pod{ - Spec: core.PodSpec{ - Affinity: &core.Affinity{ - NodeAffinity: &core.NodeAffinity{ - RequiredDuringSchedulingIgnoredDuringExecution: &core.NodeSelector{ - NodeSelectorTerms: []core.NodeSelectorTerm{{ - MatchExpressions: []core.NodeSelectorRequirement{{ - Key: "expr", - Operator: core.NodeSelectorOpIn, - Values: []string{"foo"}, - }}, + old: *podtest.MakePod("foo", + podtest.SetAffinity(&core.Affinity{ + NodeAffinity: &core.NodeAffinity{ + RequiredDuringSchedulingIgnoredDuringExecution: &core.NodeSelector{ + NodeSelectorTerms: []core.NodeSelectorTerm{{ + MatchExpressions: []core.NodeSelectorRequirement{{ + Key: "expr", + Operator: core.NodeSelectorOpIn, + Values: []string{"foo"}, }}, - }, - }, - }, - SchedulingGates: []core.PodSchedulingGate{{Name: "baz"}}, - }, - }, - new: core.Pod{ - Spec: core.PodSpec{ - Affinity: &core.Affinity{ - NodeAffinity: &core.NodeAffinity{ - RequiredDuringSchedulingIgnoredDuringExecution: &core.NodeSelector{ - // Add 1 MatchExpression and 1 MatchField. - NodeSelectorTerms: []core.NodeSelectorTerm{{ - MatchExpressions: []core.NodeSelectorRequirement{{ - Key: "expr", - Operator: core.NodeSelectorOpIn, - Values: []string{"foo"}, - }, { - Key: "expr2", - Operator: core.NodeSelectorOpIn, - Values: []string{"foo2"}, - }}, - MatchFields: []core.NodeSelectorRequirement{{ - Key: "metadata.name", - Operator: core.NodeSelectorOpIn, - Values: []string{"foo"}, - }}, + }}, + }}}), + podtest.SetSchedulingGates(core.PodSchedulingGate{Name: "baz"}), + ), + new: *podtest.MakePod("foo", + podtest.SetAffinity(&core.Affinity{ + NodeAffinity: &core.NodeAffinity{ + RequiredDuringSchedulingIgnoredDuringExecution: &core.NodeSelector{ + // Add 1 MatchExpression and 1 MatchField. + NodeSelectorTerms: []core.NodeSelectorTerm{{ + MatchExpressions: []core.NodeSelectorRequirement{{ + Key: "expr", + Operator: core.NodeSelectorOpIn, + Values: []string{"foo"}, + }, { + Key: "expr2", + Operator: core.NodeSelectorOpIn, + Values: []string{"foo2"}, }}, - }, - }, - }, - SchedulingGates: []core.PodSchedulingGate{{Name: "baz"}}, - }, - }, + MatchFields: []core.NodeSelectorRequirement{{ + Key: "metadata.name", + Operator: core.NodeSelectorOpIn, + Values: []string{"foo"}, + }}, + }}, + }}, + }), + podtest.SetSchedulingGates(core.PodSchedulingGate{Name: "baz"}), + ), test: "addition to nodeAffinity is allowed for gated pods", }, { - old: core.Pod{ - Spec: core.PodSpec{ - Affinity: &core.Affinity{ - NodeAffinity: &core.NodeAffinity{ - RequiredDuringSchedulingIgnoredDuringExecution: &core.NodeSelector{ - NodeSelectorTerms: []core.NodeSelectorTerm{{ - MatchExpressions: []core.NodeSelectorRequirement{{ - Key: "expr", - Operator: core.NodeSelectorOpIn, - Values: []string{"foo"}, - }}, + old: *podtest.MakePod("foo", + podtest.SetAffinity(&core.Affinity{ + NodeAffinity: &core.NodeAffinity{ + RequiredDuringSchedulingIgnoredDuringExecution: &core.NodeSelector{ + NodeSelectorTerms: []core.NodeSelectorTerm{{ + MatchExpressions: []core.NodeSelectorRequirement{{ + Key: "expr", + Operator: core.NodeSelectorOpIn, + Values: []string{"foo"}, }}, - }, - }, - }, - SchedulingGates: []core.PodSchedulingGate{{Name: "baz"}}, - }, - }, - new: core.Pod{ - Spec: core.PodSpec{ - Affinity: &core.Affinity{ - NodeAffinity: &core.NodeAffinity{}, - }, - SchedulingGates: []core.PodSchedulingGate{{Name: "baz"}}, - }, - }, + }}, + }}, + }), + podtest.SetSchedulingGates(core.PodSchedulingGate{Name: "baz"}), + ), + new: *podtest.MakePod("foo", + podtest.SetAffinity(&core.Affinity{ + NodeAffinity: &core.NodeAffinity{}, + }), + podtest.SetSchedulingGates(core.PodSchedulingGate{Name: "baz"}), + ), err: "spec.affinity.nodeAffinity.requiredDuringSchedulingIgnoredDuringExecution.nodeSelectorTerms: Invalid value:", test: "old RequiredDuringSchedulingIgnoredDuringExecution is non-nil, new RequiredDuringSchedulingIgnoredDuringExecution is nil, pod is gated", }, { - old: core.Pod{ - Spec: core.PodSpec{ - Affinity: &core.Affinity{ - NodeAffinity: &core.NodeAffinity{ - RequiredDuringSchedulingIgnoredDuringExecution: &core.NodeSelector{ - NodeSelectorTerms: []core.NodeSelectorTerm{{ - MatchExpressions: []core.NodeSelectorRequirement{{ - Key: "expr", - Operator: core.NodeSelectorOpIn, - Values: []string{"foo"}, - }}, + old: *podtest.MakePod("foo", + podtest.SetAffinity(&core.Affinity{ + NodeAffinity: &core.NodeAffinity{ + RequiredDuringSchedulingIgnoredDuringExecution: &core.NodeSelector{ + NodeSelectorTerms: []core.NodeSelectorTerm{{ + MatchExpressions: []core.NodeSelectorRequirement{{ + Key: "expr", + Operator: core.NodeSelectorOpIn, + Values: []string{"foo"}, }}, - }, - }, - }, - }, - }, - new: core.Pod{ - Spec: core.PodSpec{ - Affinity: &core.Affinity{ - NodeAffinity: &core.NodeAffinity{ - RequiredDuringSchedulingIgnoredDuringExecution: &core.NodeSelector{ - // Add 1 MatchExpression and 1 MatchField. - NodeSelectorTerms: []core.NodeSelectorTerm{{ - MatchExpressions: []core.NodeSelectorRequirement{{ - Key: "expr", - Operator: core.NodeSelectorOpIn, - Values: []string{"foo"}, - }, { - Key: "expr2", - Operator: core.NodeSelectorOpIn, - Values: []string{"foo2"}, - }}, - MatchFields: []core.NodeSelectorRequirement{{ - Key: "metadata.name", - Operator: core.NodeSelectorOpIn, - Values: []string{"foo"}, - }}, + }}, + }}, + }), + ), + new: *podtest.MakePod("foo", + podtest.SetAffinity(&core.Affinity{ + NodeAffinity: &core.NodeAffinity{ + RequiredDuringSchedulingIgnoredDuringExecution: &core.NodeSelector{ + // Add 1 MatchExpression and 1 MatchField. + NodeSelectorTerms: []core.NodeSelectorTerm{{ + MatchExpressions: []core.NodeSelectorRequirement{{ + Key: "expr", + Operator: core.NodeSelectorOpIn, + Values: []string{"foo"}, + }, { + Key: "expr2", + Operator: core.NodeSelectorOpIn, + Values: []string{"foo2"}, }}, - }, - }, - }, - }, - }, + MatchFields: []core.NodeSelectorRequirement{{ + Key: "metadata.name", + Operator: core.NodeSelectorOpIn, + Values: []string{"foo"}, + }}, + }}, + }}, + }), + ), err: "Forbidden: pod updates may not change fields other than `spec.containers[*].image", test: "addition to nodeAffinity is not allowed for non-gated pods", }, { - old: core.Pod{ - Spec: core.PodSpec{ - Affinity: &core.Affinity{ - NodeAffinity: &core.NodeAffinity{ - RequiredDuringSchedulingIgnoredDuringExecution: &core.NodeSelector{ - NodeSelectorTerms: []core.NodeSelectorTerm{{ - MatchExpressions: []core.NodeSelectorRequirement{{ - Key: "expr", - Operator: core.NodeSelectorOpIn, - Values: []string{"foo"}, - }}, + old: *podtest.MakePod("foo", + podtest.SetAffinity(&core.Affinity{ + NodeAffinity: &core.NodeAffinity{ + RequiredDuringSchedulingIgnoredDuringExecution: &core.NodeSelector{ + NodeSelectorTerms: []core.NodeSelectorTerm{{ + MatchExpressions: []core.NodeSelectorRequirement{{ + Key: "expr", + Operator: core.NodeSelectorOpIn, + Values: []string{"foo"}, }}, - }, - }, - }, - SchedulingGates: []core.PodSchedulingGate{{Name: "baz"}}, - }, - }, - new: core.Pod{ - Spec: core.PodSpec{ - Affinity: &core.Affinity{ - NodeAffinity: &core.NodeAffinity{ - RequiredDuringSchedulingIgnoredDuringExecution: &core.NodeSelector{ - // Add 1 MatchExpression and 1 MatchField. - NodeSelectorTerms: []core.NodeSelectorTerm{{ - MatchExpressions: []core.NodeSelectorRequirement{{ - Key: "expr", - Operator: core.NodeSelectorOpIn, - Values: []string{"foo"}, - }, { - Key: "expr2", - Operator: core.NodeSelectorOpIn, - Values: []string{"foo2"}, - }}, - MatchFields: []core.NodeSelectorRequirement{{ - Key: "metadata.name", - Operator: core.NodeSelectorOpIn, - Values: []string{"foo"}, - }}, + }}, + }}, + }), + podtest.SetSchedulingGates(core.PodSchedulingGate{Name: "baz"}), + ), + new: *podtest.MakePod("foo", + podtest.SetAffinity(&core.Affinity{ + NodeAffinity: &core.NodeAffinity{ + RequiredDuringSchedulingIgnoredDuringExecution: &core.NodeSelector{ + // Add 1 MatchExpression and 1 MatchField. + NodeSelectorTerms: []core.NodeSelectorTerm{{ + MatchExpressions: []core.NodeSelectorRequirement{{ + Key: "expr", + Operator: core.NodeSelectorOpIn, + Values: []string{"foo"}, + }, { + Key: "expr2", + Operator: core.NodeSelectorOpIn, + Values: []string{"foo2"}, }}, - }, - }, - }, - }, - }, + MatchFields: []core.NodeSelectorRequirement{{ + Key: "metadata.name", + Operator: core.NodeSelectorOpIn, + Values: []string{"foo"}, + }}, + }}, + }}, + }), + ), test: "old pod spec has scheduling gate, new pod spec does not, and node affinity addition occurs", }, { - old: core.Pod{ - Spec: core.PodSpec{ - Affinity: &core.Affinity{ - NodeAffinity: &core.NodeAffinity{ - RequiredDuringSchedulingIgnoredDuringExecution: &core.NodeSelector{ - NodeSelectorTerms: []core.NodeSelectorTerm{{ - MatchExpressions: []core.NodeSelectorRequirement{{ - Key: "expr", - Operator: core.NodeSelectorOpIn, - Values: []string{"foo"}, - }}, + old: *podtest.MakePod("foo", + podtest.SetAffinity(&core.Affinity{ + NodeAffinity: &core.NodeAffinity{ + RequiredDuringSchedulingIgnoredDuringExecution: &core.NodeSelector{ + NodeSelectorTerms: []core.NodeSelectorTerm{{ + MatchExpressions: []core.NodeSelectorRequirement{{ + Key: "expr", + Operator: core.NodeSelectorOpIn, + Values: []string{"foo"}, }}, - }, - }, - }, - SchedulingGates: []core.PodSchedulingGate{{Name: "baz"}}, - }, - }, - new: core.Pod{ - Spec: core.PodSpec{ - Affinity: &core.Affinity{ - NodeAffinity: &core.NodeAffinity{ - RequiredDuringSchedulingIgnoredDuringExecution: &core.NodeSelector{ - NodeSelectorTerms: []core.NodeSelectorTerm{{ - MatchFields: []core.NodeSelectorRequirement{{ - Key: "metadata.name", - Operator: core.NodeSelectorOpIn, - Values: []string{"foo"}, - }}, + }}, + }}, + }), + podtest.SetSchedulingGates(core.PodSchedulingGate{Name: "baz"}), + ), + new: *podtest.MakePod("foo", + podtest.SetAffinity(&core.Affinity{ + NodeAffinity: &core.NodeAffinity{ + RequiredDuringSchedulingIgnoredDuringExecution: &core.NodeSelector{ + NodeSelectorTerms: []core.NodeSelectorTerm{{ + MatchFields: []core.NodeSelectorRequirement{{ + Key: "metadata.name", + Operator: core.NodeSelectorOpIn, + Values: []string{"foo"}, }}, - }, - }, - }, - SchedulingGates: []core.PodSchedulingGate{{Name: "baz"}}, - }, - }, + }}, + }}, + }), + podtest.SetSchedulingGates(core.PodSchedulingGate{Name: "baz"}), + ), err: "spec.affinity.nodeAffinity.requiredDuringSchedulingIgnoredDuringExecution.nodeSelectorTerms[0]: Invalid value:", test: "nodeAffinity deletion from MatchExpressions not allowed", }, { - old: core.Pod{ - Spec: core.PodSpec{ - Affinity: &core.Affinity{ - NodeAffinity: &core.NodeAffinity{ - RequiredDuringSchedulingIgnoredDuringExecution: &core.NodeSelector{ - NodeSelectorTerms: []core.NodeSelectorTerm{{ - MatchExpressions: []core.NodeSelectorRequirement{{ - Key: "expr", - Operator: core.NodeSelectorOpIn, - Values: []string{"foo"}, - }}, - MatchFields: []core.NodeSelectorRequirement{{ - Key: "metadata.name", - Operator: core.NodeSelectorOpIn, - Values: []string{"foo"}, - }}, + old: *podtest.MakePod("foo", + podtest.SetAffinity(&core.Affinity{ + NodeAffinity: &core.NodeAffinity{ + RequiredDuringSchedulingIgnoredDuringExecution: &core.NodeSelector{ + NodeSelectorTerms: []core.NodeSelectorTerm{{ + MatchExpressions: []core.NodeSelectorRequirement{{ + Key: "expr", + Operator: core.NodeSelectorOpIn, + Values: []string{"foo"}, }}, - }, - }, - }, - SchedulingGates: []core.PodSchedulingGate{{Name: "baz"}}, - }, - }, - new: core.Pod{ - Spec: core.PodSpec{ - Affinity: &core.Affinity{ - NodeAffinity: &core.NodeAffinity{ - RequiredDuringSchedulingIgnoredDuringExecution: &core.NodeSelector{ - // Add 1 MatchExpression and 1 MatchField. - NodeSelectorTerms: []core.NodeSelectorTerm{{ - MatchExpressions: []core.NodeSelectorRequirement{{ - Key: "expr", - Operator: core.NodeSelectorOpIn, - Values: []string{"foo"}, - }}, + MatchFields: []core.NodeSelectorRequirement{{ + Key: "metadata.name", + Operator: core.NodeSelectorOpIn, + Values: []string{"foo"}, }}, - }, - }, - }, - SchedulingGates: []core.PodSchedulingGate{{Name: "baz"}}, - }, - }, + }}, + }}, + }), + podtest.SetSchedulingGates(core.PodSchedulingGate{Name: "baz"}), + ), + new: *podtest.MakePod("foo", + podtest.SetAffinity(&core.Affinity{ + NodeAffinity: &core.NodeAffinity{ + RequiredDuringSchedulingIgnoredDuringExecution: &core.NodeSelector{ + // Add 1 MatchExpression and 1 MatchField. + NodeSelectorTerms: []core.NodeSelectorTerm{{ + MatchExpressions: []core.NodeSelectorRequirement{{ + Key: "expr", + Operator: core.NodeSelectorOpIn, + Values: []string{"foo"}, + }}, + }}, + }}, + }), + podtest.SetSchedulingGates(core.PodSchedulingGate{Name: "baz"}), + ), err: "spec.affinity.nodeAffinity.requiredDuringSchedulingIgnoredDuringExecution.nodeSelectorTerms[0]: Invalid value:", test: "nodeAffinity deletion from MatchFields not allowed", }, { - old: core.Pod{ - Spec: core.PodSpec{ - Affinity: &core.Affinity{ - NodeAffinity: &core.NodeAffinity{ - RequiredDuringSchedulingIgnoredDuringExecution: &core.NodeSelector{ - NodeSelectorTerms: []core.NodeSelectorTerm{{ - MatchExpressions: []core.NodeSelectorRequirement{{ - Key: "expr", - Operator: core.NodeSelectorOpIn, - Values: []string{"foo"}, - }}, - MatchFields: []core.NodeSelectorRequirement{{ - Key: "metadata.name", - Operator: core.NodeSelectorOpIn, - Values: []string{"foo"}, - }}, + old: *podtest.MakePod("foo", + podtest.SetAffinity(&core.Affinity{ + NodeAffinity: &core.NodeAffinity{ + RequiredDuringSchedulingIgnoredDuringExecution: &core.NodeSelector{ + NodeSelectorTerms: []core.NodeSelectorTerm{{ + MatchExpressions: []core.NodeSelectorRequirement{{ + Key: "expr", + Operator: core.NodeSelectorOpIn, + Values: []string{"foo"}, }}, - }, - }, - }, - SchedulingGates: []core.PodSchedulingGate{{Name: "baz"}}, - }, - }, - new: core.Pod{ - Spec: core.PodSpec{ - Affinity: &core.Affinity{ - NodeAffinity: &core.NodeAffinity{ - RequiredDuringSchedulingIgnoredDuringExecution: &core.NodeSelector{ - // Add 1 MatchExpression and 1 MatchField. - NodeSelectorTerms: []core.NodeSelectorTerm{{ - MatchExpressions: []core.NodeSelectorRequirement{{ - Key: "expr", - Operator: core.NodeSelectorOpIn, - Values: []string{"bar"}, - }}, - MatchFields: []core.NodeSelectorRequirement{{ - Key: "metadata.name", - Operator: core.NodeSelectorOpIn, - Values: []string{"foo"}, - }}, + MatchFields: []core.NodeSelectorRequirement{{ + Key: "metadata.name", + Operator: core.NodeSelectorOpIn, + Values: []string{"foo"}, }}, - }, - }, - }, - SchedulingGates: []core.PodSchedulingGate{{Name: "baz"}}, - }, - }, + }}, + }}, + }), + podtest.SetSchedulingGates(core.PodSchedulingGate{Name: "baz"}), + ), + new: *podtest.MakePod("foo", + podtest.SetAffinity(&core.Affinity{ + NodeAffinity: &core.NodeAffinity{ + RequiredDuringSchedulingIgnoredDuringExecution: &core.NodeSelector{ + // Add 1 MatchExpression and 1 MatchField. + NodeSelectorTerms: []core.NodeSelectorTerm{{ + MatchExpressions: []core.NodeSelectorRequirement{{ + Key: "expr", + Operator: core.NodeSelectorOpIn, + Values: []string{"bar"}, + }}, + MatchFields: []core.NodeSelectorRequirement{{ + Key: "metadata.name", + Operator: core.NodeSelectorOpIn, + Values: []string{"foo"}, + }}, + }}, + }}, + }), + podtest.SetSchedulingGates(core.PodSchedulingGate{Name: "baz"}), + ), err: "spec.affinity.nodeAffinity.requiredDuringSchedulingIgnoredDuringExecution.nodeSelectorTerms[0]: Invalid value:", test: "nodeAffinity modification of item in MatchExpressions not allowed", }, { - old: core.Pod{ - Spec: core.PodSpec{ - Affinity: &core.Affinity{ - NodeAffinity: &core.NodeAffinity{ - RequiredDuringSchedulingIgnoredDuringExecution: &core.NodeSelector{ - NodeSelectorTerms: []core.NodeSelectorTerm{{ - MatchExpressions: []core.NodeSelectorRequirement{{ - Key: "expr", - Operator: core.NodeSelectorOpIn, - Values: []string{"foo"}, - }}, - MatchFields: []core.NodeSelectorRequirement{{ - Key: "metadata.name", - Operator: core.NodeSelectorOpIn, - Values: []string{"foo"}, - }}, + old: *podtest.MakePod("foo", + podtest.SetAffinity(&core.Affinity{ + NodeAffinity: &core.NodeAffinity{ + RequiredDuringSchedulingIgnoredDuringExecution: &core.NodeSelector{ + NodeSelectorTerms: []core.NodeSelectorTerm{{ + MatchExpressions: []core.NodeSelectorRequirement{{ + Key: "expr", + Operator: core.NodeSelectorOpIn, + Values: []string{"foo"}, }}, - }, - }, - }, - SchedulingGates: []core.PodSchedulingGate{{Name: "baz"}}, - }, - }, - new: core.Pod{ - Spec: core.PodSpec{ - Affinity: &core.Affinity{ - NodeAffinity: &core.NodeAffinity{ - RequiredDuringSchedulingIgnoredDuringExecution: &core.NodeSelector{ - NodeSelectorTerms: []core.NodeSelectorTerm{{ - MatchExpressions: []core.NodeSelectorRequirement{{ - Key: "expr", - Operator: core.NodeSelectorOpIn, - Values: []string{"foo"}, - }}, - MatchFields: []core.NodeSelectorRequirement{{ - Key: "metadata.name", - Operator: core.NodeSelectorOpIn, - Values: []string{"bar"}, - }}, + MatchFields: []core.NodeSelectorRequirement{{ + Key: "metadata.name", + Operator: core.NodeSelectorOpIn, + Values: []string{"foo"}, }}, - }, - }, - }, - SchedulingGates: []core.PodSchedulingGate{{Name: "baz"}}, - }, - }, + }}, + }}, + }), + podtest.SetSchedulingGates(core.PodSchedulingGate{Name: "baz"}), + ), + new: *podtest.MakePod("foo", + podtest.SetAffinity(&core.Affinity{ + NodeAffinity: &core.NodeAffinity{ + RequiredDuringSchedulingIgnoredDuringExecution: &core.NodeSelector{ + NodeSelectorTerms: []core.NodeSelectorTerm{{ + MatchExpressions: []core.NodeSelectorRequirement{{ + Key: "expr", + Operator: core.NodeSelectorOpIn, + Values: []string{"foo"}, + }}, + MatchFields: []core.NodeSelectorRequirement{{ + Key: "metadata.name", + Operator: core.NodeSelectorOpIn, + Values: []string{"bar"}, + }}, + }}, + }}, + }), + podtest.SetSchedulingGates(core.PodSchedulingGate{Name: "baz"}), + ), err: "spec.affinity.nodeAffinity.requiredDuringSchedulingIgnoredDuringExecution.nodeSelectorTerms[0]: Invalid value:", test: "nodeAffinity modification of item in MatchFields not allowed", }, { - old: core.Pod{ - Spec: core.PodSpec{ - Affinity: &core.Affinity{ - NodeAffinity: &core.NodeAffinity{ - RequiredDuringSchedulingIgnoredDuringExecution: &core.NodeSelector{ - NodeSelectorTerms: []core.NodeSelectorTerm{{ - MatchExpressions: []core.NodeSelectorRequirement{{ - Key: "expr", - Operator: core.NodeSelectorOpIn, - Values: []string{"foo"}, - }}, - MatchFields: []core.NodeSelectorRequirement{{ - Key: "metadata.name", - Operator: core.NodeSelectorOpIn, - Values: []string{"foo"}, - }}, + old: *podtest.MakePod("foo", + podtest.SetAffinity(&core.Affinity{ + NodeAffinity: &core.NodeAffinity{ + RequiredDuringSchedulingIgnoredDuringExecution: &core.NodeSelector{ + NodeSelectorTerms: []core.NodeSelectorTerm{{ + MatchExpressions: []core.NodeSelectorRequirement{{ + Key: "expr", + Operator: core.NodeSelectorOpIn, + Values: []string{"foo"}, }}, - }, - }, - }, - SchedulingGates: []core.PodSchedulingGate{{Name: "baz"}}, - }, - }, - new: core.Pod{ - Spec: core.PodSpec{ - Affinity: &core.Affinity{ - NodeAffinity: &core.NodeAffinity{ - RequiredDuringSchedulingIgnoredDuringExecution: &core.NodeSelector{ - NodeSelectorTerms: []core.NodeSelectorTerm{{ - MatchExpressions: []core.NodeSelectorRequirement{{ - Key: "expr", - Operator: core.NodeSelectorOpIn, - Values: []string{"foo"}, - }}, - MatchFields: []core.NodeSelectorRequirement{{ - Key: "metadata.name", - Operator: core.NodeSelectorOpIn, - Values: []string{"bar"}, - }}, - }, { - MatchExpressions: []core.NodeSelectorRequirement{{ - Key: "expr", - Operator: core.NodeSelectorOpIn, - Values: []string{"foo2"}, - }}, - MatchFields: []core.NodeSelectorRequirement{{ - Key: "metadata.name", - Operator: core.NodeSelectorOpIn, - Values: []string{"bar2"}, - }}, + MatchFields: []core.NodeSelectorRequirement{{ + Key: "metadata.name", + Operator: core.NodeSelectorOpIn, + Values: []string{"foo"}, }}, - }, - }, - }, - SchedulingGates: []core.PodSchedulingGate{{Name: "baz"}}, - }, - }, + }}, + }}, + }), + podtest.SetSchedulingGates(core.PodSchedulingGate{Name: "baz"}), + ), + new: *podtest.MakePod("foo", + podtest.SetAffinity(&core.Affinity{ + NodeAffinity: &core.NodeAffinity{ + RequiredDuringSchedulingIgnoredDuringExecution: &core.NodeSelector{ + NodeSelectorTerms: []core.NodeSelectorTerm{{ + MatchExpressions: []core.NodeSelectorRequirement{{ + Key: "expr", + Operator: core.NodeSelectorOpIn, + Values: []string{"foo"}, + }}, + MatchFields: []core.NodeSelectorRequirement{{ + Key: "metadata.name", + Operator: core.NodeSelectorOpIn, + Values: []string{"bar"}, + }}, + }, { + MatchExpressions: []core.NodeSelectorRequirement{{ + Key: "expr", + Operator: core.NodeSelectorOpIn, + Values: []string{"foo2"}, + }}, + MatchFields: []core.NodeSelectorRequirement{{ + Key: "metadata.name", + Operator: core.NodeSelectorOpIn, + Values: []string{"bar2"}, + }}, + }}, + }}, + }), + podtest.SetSchedulingGates(core.PodSchedulingGate{Name: "baz"}), + ), err: "spec.affinity.nodeAffinity.requiredDuringSchedulingIgnoredDuringExecution.nodeSelectorTerms: Invalid value:", test: "nodeSelectorTerms addition on gated pod should fail", }, { - old: core.Pod{ - Spec: core.PodSpec{ - Affinity: &core.Affinity{ - NodeAffinity: &core.NodeAffinity{ - PreferredDuringSchedulingIgnoredDuringExecution: []core.PreferredSchedulingTerm{{ - Weight: 1.0, - Preference: core.NodeSelectorTerm{ - MatchExpressions: []core.NodeSelectorRequirement{{ - Key: "expr", - Operator: core.NodeSelectorOpIn, - Values: []string{"foo"}, - }}, - }, - }}, - }, - }, - SchedulingGates: []core.PodSchedulingGate{{Name: "baz"}}, - }, - }, - new: core.Pod{ - Spec: core.PodSpec{ - Affinity: &core.Affinity{ - NodeAffinity: &core.NodeAffinity{ - PreferredDuringSchedulingIgnoredDuringExecution: []core.PreferredSchedulingTerm{{ - Weight: 1.0, - Preference: core.NodeSelectorTerm{ - MatchExpressions: []core.NodeSelectorRequirement{{ - Key: "expr", - Operator: core.NodeSelectorOpIn, - Values: []string{"foo2"}, - }}, - }, - }}, - }, - }, - SchedulingGates: []core.PodSchedulingGate{{Name: "baz"}}, - }, - }, - test: "preferredDuringSchedulingIgnoredDuringExecution can modified for gated pods", - }, { - old: core.Pod{ - Spec: core.PodSpec{ - Affinity: &core.Affinity{ - NodeAffinity: &core.NodeAffinity{ - PreferredDuringSchedulingIgnoredDuringExecution: []core.PreferredSchedulingTerm{{ - Weight: 1.0, - Preference: core.NodeSelectorTerm{ - MatchExpressions: []core.NodeSelectorRequirement{{ - Key: "expr", - Operator: core.NodeSelectorOpIn, - Values: []string{"foo"}, - }}, - }, - }}, - }, - }, - SchedulingGates: []core.PodSchedulingGate{{Name: "baz"}}, - }, - }, - new: core.Pod{ - Spec: core.PodSpec{ - Affinity: &core.Affinity{ - NodeAffinity: &core.NodeAffinity{ - PreferredDuringSchedulingIgnoredDuringExecution: []core.PreferredSchedulingTerm{{ - Weight: 1.0, - Preference: core.NodeSelectorTerm{ - MatchExpressions: []core.NodeSelectorRequirement{{ - Key: "expr", - Operator: core.NodeSelectorOpIn, - Values: []string{"foo"}, - }, { - Key: "expr2", - Operator: core.NodeSelectorOpIn, - Values: []string{"foo2"}, - }}, - MatchFields: []core.NodeSelectorRequirement{{ - Key: "metadata.name", - Operator: core.NodeSelectorOpIn, - Values: []string{"bar"}, - }}, - }, - }}, - }, - }, - SchedulingGates: []core.PodSchedulingGate{{Name: "baz"}}, - }, - }, - test: "preferredDuringSchedulingIgnoredDuringExecution can have additions for gated pods", - }, { - old: core.Pod{ - Spec: core.PodSpec{ - Affinity: &core.Affinity{ - NodeAffinity: &core.NodeAffinity{ - PreferredDuringSchedulingIgnoredDuringExecution: []core.PreferredSchedulingTerm{{ - Weight: 1.0, - Preference: core.NodeSelectorTerm{ - MatchExpressions: []core.NodeSelectorRequirement{{ - Key: "expr", - Operator: core.NodeSelectorOpIn, - Values: []string{"foo"}, - }}, - }, - }}, - }, - }, - SchedulingGates: []core.PodSchedulingGate{{Name: "baz"}}, - }, - }, - new: core.Pod{ - Spec: core.PodSpec{ - SchedulingGates: []core.PodSchedulingGate{{Name: "baz"}}, - }, - }, - test: "preferredDuringSchedulingIgnoredDuringExecution can have removals for gated pods", - }, { - old: core.Pod{ - Spec: core.PodSpec{ - Affinity: &core.Affinity{ - NodeAffinity: &core.NodeAffinity{ - RequiredDuringSchedulingIgnoredDuringExecution: &core.NodeSelector{ - NodeSelectorTerms: []core.NodeSelectorTerm{{ - MatchExpressions: []core.NodeSelectorRequirement{{ - Key: "expr", - Operator: core.NodeSelectorOpIn, - Values: []string{"foo"}, - }}, + old: *podtest.MakePod("foo", + podtest.SetAffinity(&core.Affinity{ + NodeAffinity: &core.NodeAffinity{ + PreferredDuringSchedulingIgnoredDuringExecution: []core.PreferredSchedulingTerm{{ + Weight: 1.0, + Preference: core.NodeSelectorTerm{ + MatchExpressions: []core.NodeSelectorRequirement{{ + Key: "expr", + Operator: core.NodeSelectorOpIn, + Values: []string{"foo"}, }}, }, - }, - }, - SchedulingGates: []core.PodSchedulingGate{{Name: "baz"}}, - }, - }, - new: core.Pod{ - Spec: core.PodSpec{ - Affinity: &core.Affinity{}, - SchedulingGates: []core.PodSchedulingGate{{Name: "baz"}}, - }, - }, + }}, + }}), + podtest.SetSchedulingGates(core.PodSchedulingGate{Name: "baz"}), + ), + new: *podtest.MakePod("foo", + podtest.SetAffinity(&core.Affinity{ + NodeAffinity: &core.NodeAffinity{ + PreferredDuringSchedulingIgnoredDuringExecution: []core.PreferredSchedulingTerm{{ + Weight: 1.0, + Preference: core.NodeSelectorTerm{ + MatchExpressions: []core.NodeSelectorRequirement{{ + Key: "expr", + Operator: core.NodeSelectorOpIn, + Values: []string{"foo2"}, + }}, + }, + }}, + }}), + podtest.SetSchedulingGates(core.PodSchedulingGate{Name: "baz"}), + ), + test: "preferredDuringSchedulingIgnoredDuringExecution can modified for gated pods", + }, { + old: *podtest.MakePod("foo", + podtest.SetAffinity(&core.Affinity{ + NodeAffinity: &core.NodeAffinity{ + PreferredDuringSchedulingIgnoredDuringExecution: []core.PreferredSchedulingTerm{{ + Weight: 1.0, + Preference: core.NodeSelectorTerm{ + MatchExpressions: []core.NodeSelectorRequirement{{ + Key: "expr", + Operator: core.NodeSelectorOpIn, + Values: []string{"foo"}, + }}, + }, + }}, + }}), + podtest.SetSchedulingGates(core.PodSchedulingGate{Name: "baz"}), + ), + new: *podtest.MakePod("foo", + podtest.SetAffinity(&core.Affinity{ + NodeAffinity: &core.NodeAffinity{ + PreferredDuringSchedulingIgnoredDuringExecution: []core.PreferredSchedulingTerm{{ + Weight: 1.0, + Preference: core.NodeSelectorTerm{ + MatchExpressions: []core.NodeSelectorRequirement{{ + Key: "expr", + Operator: core.NodeSelectorOpIn, + Values: []string{"foo"}, + }, { + Key: "expr2", + Operator: core.NodeSelectorOpIn, + Values: []string{"foo2"}, + }}, + MatchFields: []core.NodeSelectorRequirement{{ + Key: "metadata.name", + Operator: core.NodeSelectorOpIn, + Values: []string{"bar"}, + }}, + }, + }}, + }}), + podtest.SetSchedulingGates(core.PodSchedulingGate{Name: "baz"}), + ), + test: "preferredDuringSchedulingIgnoredDuringExecution can have additions for gated pods", + }, { + old: *podtest.MakePod("foo", + podtest.SetAffinity(&core.Affinity{ + NodeAffinity: &core.NodeAffinity{ + PreferredDuringSchedulingIgnoredDuringExecution: []core.PreferredSchedulingTerm{{ + Weight: 1.0, + Preference: core.NodeSelectorTerm{ + MatchExpressions: []core.NodeSelectorRequirement{{ + Key: "expr", + Operator: core.NodeSelectorOpIn, + Values: []string{"foo"}, + }}, + }, + }}, + }}), + podtest.SetSchedulingGates(core.PodSchedulingGate{Name: "baz"}), + ), + new: *podtest.MakePod("foo", + podtest.SetSchedulingGates(core.PodSchedulingGate{Name: "baz"}), + ), + test: "preferredDuringSchedulingIgnoredDuringExecution can have removals for gated pods", + }, { + old: *podtest.MakePod("foo", + podtest.SetAffinity(&core.Affinity{ + NodeAffinity: &core.NodeAffinity{ + RequiredDuringSchedulingIgnoredDuringExecution: &core.NodeSelector{ + NodeSelectorTerms: []core.NodeSelectorTerm{{ + MatchExpressions: []core.NodeSelectorRequirement{{ + Key: "expr", + Operator: core.NodeSelectorOpIn, + Values: []string{"foo"}, + }}, + }}, + }}, + }), + podtest.SetSchedulingGates(core.PodSchedulingGate{Name: "baz"}), + ), + new: *podtest.MakePod("foo", + podtest.SetAffinity(&core.Affinity{}), + podtest.SetSchedulingGates(core.PodSchedulingGate{Name: "baz"}), + ), err: "spec.affinity.nodeAffinity.requiredDuringSchedulingIgnoredDuringExecution.nodeSelectorTerms: Invalid value:", test: "new node affinity is nil", }, { - old: core.Pod{ - Spec: core.PodSpec{ - Affinity: &core.Affinity{ - NodeAffinity: &core.NodeAffinity{ - PreferredDuringSchedulingIgnoredDuringExecution: []core.PreferredSchedulingTerm{{ - Weight: 1.0, - Preference: core.NodeSelectorTerm{ - MatchExpressions: []core.NodeSelectorRequirement{{ - Key: "expr", - Operator: core.NodeSelectorOpIn, - Values: []string{"foo"}, - }}, - }, - }}, - }, - }, - SchedulingGates: []core.PodSchedulingGate{{Name: "baz"}}, - }, - }, - new: core.Pod{ - Spec: core.PodSpec{ - SchedulingGates: []core.PodSchedulingGate{{Name: "baz"}}, - }, - }, - test: "preferredDuringSchedulingIgnoredDuringExecution can have removals for gated pods", - }, { - old: core.Pod{ - Spec: core.PodSpec{ - Affinity: &core.Affinity{ - NodeAffinity: &core.NodeAffinity{ - RequiredDuringSchedulingIgnoredDuringExecution: &core.NodeSelector{ - NodeSelectorTerms: []core.NodeSelectorTerm{ - {}, - }, - }, - }, - }, - SchedulingGates: []core.PodSchedulingGate{{Name: "baz"}}, - }, - }, - new: core.Pod{ - Spec: core.PodSpec{ - Affinity: &core.Affinity{ - NodeAffinity: &core.NodeAffinity{ - RequiredDuringSchedulingIgnoredDuringExecution: &core.NodeSelector{ - NodeSelectorTerms: []core.NodeSelectorTerm{{ - MatchExpressions: []core.NodeSelectorRequirement{{ - Key: "expr", - Operator: core.NodeSelectorOpIn, - Values: []string{"foo"}, - }}, + old: *podtest.MakePod("foo", + podtest.SetAffinity(&core.Affinity{ + NodeAffinity: &core.NodeAffinity{ + PreferredDuringSchedulingIgnoredDuringExecution: []core.PreferredSchedulingTerm{{ + Weight: 1.0, + Preference: core.NodeSelectorTerm{ + MatchExpressions: []core.NodeSelectorRequirement{{ + Key: "expr", + Operator: core.NodeSelectorOpIn, + Values: []string{"foo"}, }}, }, + }}, + }}), + podtest.SetSchedulingGates(core.PodSchedulingGate{Name: "baz"}), + ), + new: *podtest.MakePod("foo", + podtest.SetSchedulingGates(core.PodSchedulingGate{Name: "baz"}), + ), + test: "preferredDuringSchedulingIgnoredDuringExecution can have removals for gated pods", + }, { + old: *podtest.MakePod("foo", + podtest.SetAffinity(&core.Affinity{ + NodeAffinity: &core.NodeAffinity{ + RequiredDuringSchedulingIgnoredDuringExecution: &core.NodeSelector{ + NodeSelectorTerms: []core.NodeSelectorTerm{ + {}, + }, }, }, - SchedulingGates: []core.PodSchedulingGate{{Name: "baz"}}, - }, - }, + }), + podtest.SetSchedulingGates(core.PodSchedulingGate{Name: "baz"}), + ), + new: *podtest.MakePod("foo", + podtest.SetAffinity(&core.Affinity{ + NodeAffinity: &core.NodeAffinity{ + RequiredDuringSchedulingIgnoredDuringExecution: &core.NodeSelector{ + NodeSelectorTerms: []core.NodeSelectorTerm{{ + MatchExpressions: []core.NodeSelectorRequirement{{ + Key: "expr", + Operator: core.NodeSelectorOpIn, + Values: []string{"foo"}, + }}, + }}, + }}, + }), + podtest.SetSchedulingGates(core.PodSchedulingGate{Name: "baz"}), + ), err: "spec.affinity.nodeAffinity.requiredDuringSchedulingIgnoredDuringExecution.nodeSelectorTerms[0]: Invalid value:", test: "empty NodeSelectorTerm (selects nothing) cannot become populated (selects something)", }, { - old: core.Pod{ - Spec: core.PodSpec{ - Affinity: nil, - SchedulingGates: []core.PodSchedulingGate{{Name: "baz"}}, - }, - }, - new: core.Pod{ - Spec: core.PodSpec{ - Affinity: &core.Affinity{ - NodeAffinity: &core.NodeAffinity{ - RequiredDuringSchedulingIgnoredDuringExecution: &core.NodeSelector{ - NodeSelectorTerms: []core.NodeSelectorTerm{{ - MatchExpressions: []core.NodeSelectorRequirement{{ - Key: "expr", - Operator: core.NodeSelectorOpIn, - Values: []string{"foo"}, - }}, + old: *podtest.MakePod("foo", + podtest.SetAffinity(nil), + podtest.SetSchedulingGates(core.PodSchedulingGate{Name: "baz"}), + ), + new: *podtest.MakePod("foo", + podtest.SetAffinity(&core.Affinity{ + NodeAffinity: &core.NodeAffinity{ + RequiredDuringSchedulingIgnoredDuringExecution: &core.NodeSelector{ + NodeSelectorTerms: []core.NodeSelectorTerm{{ + MatchExpressions: []core.NodeSelectorRequirement{{ + Key: "expr", + Operator: core.NodeSelectorOpIn, + Values: []string{"foo"}, }}, - }, - }, - }, - SchedulingGates: []core.PodSchedulingGate{{Name: "baz"}}, - }, - }, + }}, + }}, + }), + podtest.SetSchedulingGates(core.PodSchedulingGate{Name: "baz"}), + ), test: "nil affinity can be mutated for gated pods", }, { - old: core.Pod{ - Spec: core.PodSpec{ - Affinity: nil, - SchedulingGates: []core.PodSchedulingGate{{Name: "baz"}}, - }, - }, - new: core.Pod{ - Spec: core.PodSpec{ - Affinity: &core.Affinity{ - NodeAffinity: &core.NodeAffinity{ - RequiredDuringSchedulingIgnoredDuringExecution: &core.NodeSelector{ - NodeSelectorTerms: []core.NodeSelectorTerm{{ - MatchExpressions: []core.NodeSelectorRequirement{{ - Key: "expr", - Operator: core.NodeSelectorOpIn, - Values: []string{"foo"}, - }}, + old: *podtest.MakePod("foo", + podtest.SetAffinity(nil), + podtest.SetSchedulingGates(core.PodSchedulingGate{Name: "baz"}), + ), + new: *podtest.MakePod("foo", + podtest.SetAffinity(&core.Affinity{ + NodeAffinity: &core.NodeAffinity{ + RequiredDuringSchedulingIgnoredDuringExecution: &core.NodeSelector{ + NodeSelectorTerms: []core.NodeSelectorTerm{{ + MatchExpressions: []core.NodeSelectorRequirement{{ + Key: "expr", + Operator: core.NodeSelectorOpIn, + Values: []string{"foo"}, }}, + }}, + }}, + PodAffinity: &core.PodAffinity{ + RequiredDuringSchedulingIgnoredDuringExecution: []core.PodAffinityTerm{{ + TopologyKey: "foo", + LabelSelector: &metav1.LabelSelector{ + MatchLabels: map[string]string{"foo": "bar"}, }, - }, - PodAffinity: &core.PodAffinity{ - RequiredDuringSchedulingIgnoredDuringExecution: []core.PodAffinityTerm{ - { - TopologyKey: "foo", - LabelSelector: &metav1.LabelSelector{ - MatchLabels: map[string]string{"foo": "bar"}, - }, - }, - }, - }, + }}, }, - SchedulingGates: []core.PodSchedulingGate{{Name: "baz"}}, - }, - }, + }), + podtest.SetSchedulingGates(core.PodSchedulingGate{Name: "baz"}), + ), err: "pod updates may not change fields other than", test: "the podAffinity cannot be updated on gated pods", }, { - old: core.Pod{ - Spec: core.PodSpec{ - Affinity: nil, - SchedulingGates: []core.PodSchedulingGate{{Name: "baz"}}, - }, - }, - new: core.Pod{ - Spec: core.PodSpec{ - Affinity: &core.Affinity{ - NodeAffinity: &core.NodeAffinity{ - RequiredDuringSchedulingIgnoredDuringExecution: &core.NodeSelector{ - NodeSelectorTerms: []core.NodeSelectorTerm{{ - MatchExpressions: []core.NodeSelectorRequirement{{ - Key: "expr", - Operator: core.NodeSelectorOpIn, - Values: []string{"foo"}, - }}, + old: *podtest.MakePod("foo", + podtest.SetAffinity(nil), + podtest.SetSchedulingGates(core.PodSchedulingGate{Name: "baz"}), + ), + new: *podtest.MakePod("foo", + podtest.SetAffinity(&core.Affinity{ + NodeAffinity: &core.NodeAffinity{ + RequiredDuringSchedulingIgnoredDuringExecution: &core.NodeSelector{ + NodeSelectorTerms: []core.NodeSelectorTerm{{ + MatchExpressions: []core.NodeSelectorRequirement{{ + Key: "expr", + Operator: core.NodeSelectorOpIn, + Values: []string{"foo"}, }}, - }, - }, - PodAntiAffinity: &core.PodAntiAffinity{ - RequiredDuringSchedulingIgnoredDuringExecution: []core.PodAffinityTerm{ - { - TopologyKey: "foo", - LabelSelector: &metav1.LabelSelector{ - MatchLabels: map[string]string{"foo": "bar"}, - }, + }}, + }}, + PodAntiAffinity: &core.PodAntiAffinity{ + RequiredDuringSchedulingIgnoredDuringExecution: []core.PodAffinityTerm{ + { + TopologyKey: "foo", + LabelSelector: &metav1.LabelSelector{ + MatchLabels: map[string]string{"foo": "bar"}, }, }, }, }, - SchedulingGates: []core.PodSchedulingGate{{Name: "baz"}}, - }, - }, + }), + podtest.SetSchedulingGates(core.PodSchedulingGate{Name: "baz"}), + ), err: "pod updates may not change fields other than", test: "the podAntiAffinity cannot be updated on gated pods", }, @@ -15425,103 +13611,60 @@ func TestValidatePodStatusUpdate(t *testing.T) { err string test string }{{ - core.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - }, - Spec: core.PodSpec{ - NodeName: "node1", - }, - Status: core.PodStatus{ + *podtest.MakePod("foo", + podtest.SetNodeName("node1"), + podtest.SetStatus(core.PodStatus{ NominatedNodeName: "node1", - }, - }, - core.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - }, - Spec: core.PodSpec{ - NodeName: "node1", - }, - Status: core.PodStatus{}, - }, + }), + ), + *podtest.MakePod("foo", + podtest.SetNodeName("node1"), + podtest.SetStatus(core.PodStatus{}), + ), "", "removed nominatedNodeName", }, { - core.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - }, - Spec: core.PodSpec{ - NodeName: "node1", - }, - }, - core.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - }, - Spec: core.PodSpec{ - NodeName: "node1", - }, - Status: core.PodStatus{ + *podtest.MakePod("foo", + podtest.SetNodeName("node1"), + ), + *podtest.MakePod("foo", + podtest.SetNodeName("node1"), + podtest.SetStatus(core.PodStatus{ NominatedNodeName: "node1", - }, - }, + }), + ), "", "add valid nominatedNodeName", }, { - core.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - }, - Spec: core.PodSpec{ - NodeName: "node1", - }, - Status: core.PodStatus{ + *podtest.MakePod("foo", + podtest.SetNodeName("node1"), + podtest.SetStatus(core.PodStatus{ NominatedNodeName: "Node1", - }, - }, - core.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - }, - Spec: core.PodSpec{ - NodeName: "node1", - }, - }, + }), + ), + *podtest.MakePod("foo", + podtest.SetNodeName("node1"), + ), "nominatedNodeName", "Add invalid nominatedNodeName", }, { - core.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - }, - Spec: core.PodSpec{ - NodeName: "node1", - }, - Status: core.PodStatus{ + *podtest.MakePod("foo", + podtest.SetNodeName("node1"), + podtest.SetStatus(core.PodStatus{ NominatedNodeName: "node1", - }, - }, - core.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - }, - Spec: core.PodSpec{ - NodeName: "node1", - }, - Status: core.PodStatus{ + }), + ), + *podtest.MakePod("foo", + podtest.SetNodeName("node1"), + podtest.SetStatus(core.PodStatus{ NominatedNodeName: "node2", - }, - }, + }), + ), "", "Update nominatedNodeName", }, { - core.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - }, - Status: core.PodStatus{ + *podtest.MakePod("foo", + podtest.SetStatus(core.PodStatus{ InitContainerStatuses: []core.ContainerStatus{{ ContainerID: "docker://numbers", Image: "alpine", @@ -15546,21 +13689,14 @@ func TestValidatePodStatusUpdate(t *testing.T) { }, }, }}, - }, - }, - core.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - }, - }, + }), + ), + *podtest.MakePod("foo"), "", "Container statuses pending", }, { - core.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - }, - Status: core.PodStatus{ + *podtest.MakePod("foo", + podtest.SetStatus(core.PodStatus{ InitContainerStatuses: []core.ContainerStatus{{ ContainerID: "docker://numbers", Image: "alpine", @@ -15587,13 +13723,10 @@ func TestValidatePodStatusUpdate(t *testing.T) { }, }, }}, - }, - }, - core.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - }, - Status: core.PodStatus{ + }), + ), + *podtest.MakePod("foo", + podtest.SetStatus(core.PodStatus{ InitContainerStatuses: []core.ContainerStatus{{ ContainerID: "docker://numbers", Image: "alpine", @@ -15617,16 +13750,13 @@ func TestValidatePodStatusUpdate(t *testing.T) { }, }, }}, - }, - }, + }), + ), "", "Container statuses running", }, { - core.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - }, - Status: core.PodStatus{ + *podtest.MakePod("foo", + podtest.SetStatus(core.PodStatus{ ContainerStatuses: []core.ContainerStatus{{ ContainerID: "docker://numbers", Image: "nginx:alpine", @@ -15651,13 +13781,10 @@ func TestValidatePodStatusUpdate(t *testing.T) { }, }, }}, - }, - }, - core.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - }, - Status: core.PodStatus{ + }), + ), + *podtest.MakePod("foo", + podtest.SetStatus(core.PodStatus{ ContainerStatuses: []core.ContainerStatus{{ ContainerID: "docker://numbers", Image: "nginx:alpine", @@ -15671,16 +13798,13 @@ func TestValidatePodStatusUpdate(t *testing.T) { }, }, }}, - }, - }, + }), + ), "", "Container statuses add ephemeral container", }, { - core.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - }, - Status: core.PodStatus{ + *podtest.MakePod("foo", + podtest.SetStatus(core.PodStatus{ ContainerStatuses: []core.ContainerStatus{{ ContainerID: "docker://numbers", Image: "nginx:alpine", @@ -15706,13 +13830,10 @@ func TestValidatePodStatusUpdate(t *testing.T) { }, }, }}, - }, - }, - core.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - }, - Status: core.PodStatus{ + }), + ), + *podtest.MakePod("foo", + podtest.SetStatus(core.PodStatus{ ContainerStatuses: []core.ContainerStatus{{ ContainerID: "docker://numbers", Image: "nginx:alpine", @@ -15737,16 +13858,13 @@ func TestValidatePodStatusUpdate(t *testing.T) { }, }, }}, - }, - }, + }), + ), "", "Container statuses ephemeral container running", }, { - core.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - }, - Status: core.PodStatus{ + *podtest.MakePod("foo", + podtest.SetStatus(core.PodStatus{ ContainerStatuses: []core.ContainerStatus{{ ContainerID: "docker://numbers", Image: "nginx:alpine", @@ -15775,13 +13893,10 @@ func TestValidatePodStatusUpdate(t *testing.T) { }, }, }}, - }, - }, - core.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - }, - Status: core.PodStatus{ + }), + ), + *podtest.MakePod("foo", + podtest.SetStatus(core.PodStatus{ ContainerStatuses: []core.ContainerStatus{{ ContainerID: "docker://numbers", Image: "nginx:alpine", @@ -15807,16 +13922,13 @@ func TestValidatePodStatusUpdate(t *testing.T) { }, }, }}, - }, - }, + }), + ), "", "Container statuses ephemeral container exited", }, { - core.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - }, - Status: core.PodStatus{ + *podtest.MakePod("foo", + podtest.SetStatus(core.PodStatus{ InitContainerStatuses: []core.ContainerStatus{{ ContainerID: "docker://numbers", Image: "alpine", @@ -15861,13 +13973,10 @@ func TestValidatePodStatusUpdate(t *testing.T) { }, }, }}, - }, - }, - core.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - }, - Status: core.PodStatus{ + }), + ), + *podtest.MakePod("foo", + podtest.SetStatus(core.PodStatus{ InitContainerStatuses: []core.ContainerStatus{{ ContainerID: "docker://numbers", Image: "alpine", @@ -15906,135 +14015,76 @@ func TestValidatePodStatusUpdate(t *testing.T) { }, }, }}, - }, - }, + }), + ), "", "Container statuses all containers terminated", }, { - core.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - }, - Status: core.PodStatus{ + *podtest.MakePod("foo", + podtest.SetStatus(core.PodStatus{ ResourceClaimStatuses: []core.PodResourceClaimStatus{ {Name: "no-such-claim", ResourceClaimName: utilpointer.String("my-claim")}, }, - }, - }, - core.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - }, - }, + }), + ), + *podtest.MakePod("foo"), "status.resourceClaimStatuses[0].name: Invalid value: \"no-such-claim\": must match the name of an entry in `spec.resourceClaims`", "Non-existent PodResourceClaim", }, { - core.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - }, - Spec: core.PodSpec{ - ResourceClaims: []core.PodResourceClaim{ - {Name: "my-claim"}, - }, - }, - Status: core.PodStatus{ + *podtest.MakePod("foo", + podtest.SetResourceClaims(core.PodResourceClaim{Name: "my-claim"}), + podtest.SetStatus(core.PodStatus{ ResourceClaimStatuses: []core.PodResourceClaimStatus{ {Name: "my-claim", ResourceClaimName: utilpointer.String("%$!#")}, }, - }, - }, - core.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - }, - Spec: core.PodSpec{ - ResourceClaims: []core.PodResourceClaim{ - {Name: "my-claim"}, - }, - }, - }, + }), + ), + *podtest.MakePod("foo", + podtest.SetResourceClaims(core.PodResourceClaim{Name: "my-claim"}), + ), `status.resourceClaimStatuses[0].name: Invalid value: "%$!#": a lowercase RFC 1123 subdomain must consist of`, "Invalid ResourceClaim name", }, { - core.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - }, - Spec: core.PodSpec{ - ResourceClaims: []core.PodResourceClaim{ - {Name: "my-claim"}, - {Name: "my-other-claim"}, - }, - }, - Status: core.PodStatus{ + *podtest.MakePod("foo", + podtest.SetResourceClaims( + core.PodResourceClaim{Name: "my-claim"}, + core.PodResourceClaim{Name: "my-other-claim"}, + ), + podtest.SetStatus(core.PodStatus{ ResourceClaimStatuses: []core.PodResourceClaimStatus{ {Name: "my-claim", ResourceClaimName: utilpointer.String("foo-my-claim-12345")}, {Name: "my-other-claim", ResourceClaimName: nil}, {Name: "my-other-claim", ResourceClaimName: nil}, }, - }, - }, - core.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - }, - Spec: core.PodSpec{ - ResourceClaims: []core.PodResourceClaim{ - {Name: "my-claim"}, - }, - }, - }, + }), + ), + *podtest.MakePod("foo", + podtest.SetResourceClaims(core.PodResourceClaim{Name: "my-claim"}), + ), `status.resourceClaimStatuses[2].name: Duplicate value: "my-other-claim"`, "Duplicate ResourceClaimStatuses.Name", }, { - core.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - }, - Spec: core.PodSpec{ - ResourceClaims: []core.PodResourceClaim{ - {Name: "my-claim"}, - {Name: "my-other-claim"}, - }, - }, - Status: core.PodStatus{ + *podtest.MakePod("foo", + podtest.SetResourceClaims( + core.PodResourceClaim{Name: "my-claim"}, + core.PodResourceClaim{Name: "my-other-claim"}, + ), + podtest.SetStatus(core.PodStatus{ ResourceClaimStatuses: []core.PodResourceClaimStatus{ {Name: "my-claim", ResourceClaimName: utilpointer.String("foo-my-claim-12345")}, {Name: "my-other-claim", ResourceClaimName: nil}, }, - }, - }, - core.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - }, - Spec: core.PodSpec{ - ResourceClaims: []core.PodResourceClaim{ - {Name: "my-claim"}, - }, - }, - }, + }), + ), + *podtest.MakePod("foo", + podtest.SetResourceClaims(core.PodResourceClaim{Name: "my-claim"}), + ), "", "ResourceClaimStatuses okay", }, { - core.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - }, - Spec: core.PodSpec{ - InitContainers: []core.Container{ - { - Name: "init", - }, - }, - Containers: []core.Container{ - { - Name: "nginx", - }, - }, - }, - Status: core.PodStatus{ + *podtest.MakePod("foo", + podtest.SetInitContainers(podtest.MakeContainer("init")), + podtest.SetStatus(core.PodStatus{ InitContainerStatuses: []core.ContainerStatus{{ ContainerID: "docker://numbers", Image: "alpine", @@ -16060,26 +14110,12 @@ func TestValidatePodStatusUpdate(t *testing.T) { }, }, }}, - }, - }, - core.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - }, - Spec: core.PodSpec{ - InitContainers: []core.Container{ - { - Name: "init", - }, - }, - Containers: []core.Container{ - { - Name: "nginx", - }, - }, - RestartPolicy: core.RestartPolicyNever, - }, - Status: core.PodStatus{ + }), + ), + *podtest.MakePod("foo", + podtest.SetInitContainers(podtest.MakeContainer("init")), + podtest.SetRestartPolicy(core.RestartPolicyNever), + podtest.SetStatus(core.PodStatus{ InitContainerStatuses: []core.ContainerStatus{{ ContainerID: "docker://numbers", Image: "alpine", @@ -16106,30 +14142,15 @@ func TestValidatePodStatusUpdate(t *testing.T) { }, }, }}, - }, - }, + }), + ), `status.initContainerStatuses[0].state: Forbidden: may not be transitioned to non-terminated state`, "init container cannot restart if RestartPolicyNever", }, { - core.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - }, - Spec: core.PodSpec{ - InitContainers: []core.Container{ - { - Name: "restartable-init", - RestartPolicy: &containerRestartPolicyAlways, - }, - }, - Containers: []core.Container{ - { - Name: "nginx", - }, - }, - RestartPolicy: core.RestartPolicyNever, - }, - Status: core.PodStatus{ + *podtest.MakePod("foo", + podtest.SetInitContainers(podtest.MakeContainer("restartable-init", podtest.SetContainerRestartPolicy(containerRestartPolicyAlways))), + podtest.SetRestartPolicy(core.RestartPolicyNever), + podtest.SetStatus(core.PodStatus{ InitContainerStatuses: []core.ContainerStatus{{ ContainerID: "docker://numbers", Image: "alpine", @@ -16155,27 +14176,12 @@ func TestValidatePodStatusUpdate(t *testing.T) { }, }, }}, - }, - }, - core.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - }, - Spec: core.PodSpec{ - InitContainers: []core.Container{ - { - Name: "restartable-init", - RestartPolicy: &containerRestartPolicyAlways, - }, - }, - Containers: []core.Container{ - { - Name: "nginx", - }, - }, - RestartPolicy: core.RestartPolicyNever, - }, - Status: core.PodStatus{ + }), + ), + *podtest.MakePod("foo", + podtest.SetInitContainers(podtest.MakeContainer("restartable-init", podtest.SetContainerRestartPolicy(containerRestartPolicyAlways))), + podtest.SetRestartPolicy(core.RestartPolicyNever), + podtest.SetStatus(core.PodStatus{ InitContainerStatuses: []core.ContainerStatus{{ ContainerID: "docker://numbers", Image: "alpine", @@ -16202,30 +14208,15 @@ func TestValidatePodStatusUpdate(t *testing.T) { }, }, }}, - }, - }, + }), + ), "", "restartable init container can restart if RestartPolicyNever", }, { - core.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - }, - Spec: core.PodSpec{ - InitContainers: []core.Container{ - { - Name: "restartable-init", - RestartPolicy: &containerRestartPolicyAlways, - }, - }, - Containers: []core.Container{ - { - Name: "nginx", - }, - }, - RestartPolicy: core.RestartPolicyOnFailure, - }, - Status: core.PodStatus{ + *podtest.MakePod("foo", + podtest.SetInitContainers(podtest.MakeContainer("restartable-init", podtest.SetContainerRestartPolicy(containerRestartPolicyAlways))), + podtest.SetRestartPolicy(core.RestartPolicyOnFailure), + podtest.SetStatus(core.PodStatus{ InitContainerStatuses: []core.ContainerStatus{{ ContainerID: "docker://numbers", Image: "alpine", @@ -16251,27 +14242,12 @@ func TestValidatePodStatusUpdate(t *testing.T) { }, }, }}, - }, - }, - core.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - }, - Spec: core.PodSpec{ - InitContainers: []core.Container{ - { - Name: "restartable-init", - RestartPolicy: &containerRestartPolicyAlways, - }, - }, - Containers: []core.Container{ - { - Name: "nginx", - }, - }, - RestartPolicy: core.RestartPolicyOnFailure, - }, - Status: core.PodStatus{ + }), + ), + *podtest.MakePod("foo", + podtest.SetInitContainers(podtest.MakeContainer("restartable-init", podtest.SetContainerRestartPolicy(containerRestartPolicyAlways))), + podtest.SetRestartPolicy(core.RestartPolicyOnFailure), + podtest.SetStatus(core.PodStatus{ InitContainerStatuses: []core.ContainerStatus{{ ContainerID: "docker://numbers", Image: "alpine", @@ -16298,30 +14274,15 @@ func TestValidatePodStatusUpdate(t *testing.T) { }, }, }}, - }, - }, + }), + ), "", "restartable init container can restart if RestartPolicyOnFailure", }, { - core.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - }, - Spec: core.PodSpec{ - InitContainers: []core.Container{ - { - Name: "restartable-init", - RestartPolicy: &containerRestartPolicyAlways, - }, - }, - Containers: []core.Container{ - { - Name: "nginx", - }, - }, - RestartPolicy: core.RestartPolicyAlways, - }, - Status: core.PodStatus{ + *podtest.MakePod("foo", + podtest.SetInitContainers(podtest.MakeContainer("restartable-init", podtest.SetContainerRestartPolicy(containerRestartPolicyAlways))), + podtest.SetRestartPolicy(core.RestartPolicyAlways), + podtest.SetStatus(core.PodStatus{ InitContainerStatuses: []core.ContainerStatus{{ ContainerID: "docker://numbers", Image: "alpine", @@ -16347,27 +14308,12 @@ func TestValidatePodStatusUpdate(t *testing.T) { }, }, }}, - }, - }, - core.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - }, - Spec: core.PodSpec{ - InitContainers: []core.Container{ - { - Name: "restartable-init", - RestartPolicy: &containerRestartPolicyAlways, - }, - }, - Containers: []core.Container{ - { - Name: "nginx", - }, - }, - RestartPolicy: core.RestartPolicyAlways, - }, - Status: core.PodStatus{ + }), + ), + *podtest.MakePod("foo", + podtest.SetInitContainers(podtest.MakeContainer("restartable-init", podtest.SetContainerRestartPolicy(containerRestartPolicyAlways))), + podtest.SetRestartPolicy(core.RestartPolicyAlways), + podtest.SetStatus(core.PodStatus{ InitContainerStatuses: []core.ContainerStatus{{ ContainerID: "docker://numbers", Image: "alpine", @@ -16394,8 +14340,8 @@ func TestValidatePodStatusUpdate(t *testing.T) { }, }, }}, - }, - }, + }), + ), "", "restartable init container can restart if RestartPolicyAlways", }, @@ -16441,26 +14387,17 @@ func makeValidService() core.Service { func TestValidatePodEphemeralContainersUpdate(t *testing.T) { makePod := func(ephemeralContainers []core.EphemeralContainer) *core.Pod { - return &core.Pod{ - ObjectMeta: metav1.ObjectMeta{ + return podtest.MakePod("", + podtest.SetObjectMeta(metav1.ObjectMeta{ Annotations: map[string]string{}, Labels: map[string]string{}, Name: "pod", Namespace: "ns", ResourceVersion: "1", - }, - Spec: core.PodSpec{ - Containers: []core.Container{{ - Name: "cnt", - Image: "image", - ImagePullPolicy: "IfNotPresent", - TerminationMessagePolicy: "File", - }}, - DNSPolicy: core.DNSClusterFirst, - EphemeralContainers: ephemeralContainers, - RestartPolicy: core.RestartPolicyOnFailure, - }, - } + }), + podtest.SetEphemeralContainers(ephemeralContainers...), + podtest.SetRestartPolicy(core.RestartPolicyOnFailure), + ) } // Some tests use Windows host pods as an example of fields that might @@ -16469,37 +14406,29 @@ func TestValidatePodEphemeralContainersUpdate(t *testing.T) { AllowPrivileged: true, }) makeWindowsHostPod := func(ephemeralContainers []core.EphemeralContainer) *core.Pod { - return &core.Pod{ - ObjectMeta: metav1.ObjectMeta{ + return podtest.MakePod("", + podtest.SetObjectMeta(metav1.ObjectMeta{ Annotations: map[string]string{}, Labels: map[string]string{}, Name: "pod", Namespace: "ns", ResourceVersion: "1", - }, - Spec: core.PodSpec{ - Containers: []core.Container{{ - Name: "cnt", - Image: "image", - ImagePullPolicy: "IfNotPresent", - SecurityContext: &core.SecurityContext{ - WindowsOptions: &core.WindowsSecurityContextOptions{ - HostProcess: proto.Bool(true), - }, - }, - TerminationMessagePolicy: "File", - }}, - DNSPolicy: core.DNSClusterFirst, - EphemeralContainers: ephemeralContainers, - RestartPolicy: core.RestartPolicyOnFailure, - SecurityContext: &core.PodSecurityContext{ - HostNetwork: true, + }), + podtest.SetContainers(podtest.MakeContainer("cnt", + podtest.SetContainerSecurityContext(core.SecurityContext{ WindowsOptions: &core.WindowsSecurityContextOptions{ HostProcess: proto.Bool(true), - }, + }}), + )), + podtest.SetEphemeralContainers(ephemeralContainers...), + podtest.SetRestartPolicy(core.RestartPolicyOnFailure), + podtest.SetSecurityContext(&core.PodSecurityContext{ + HostNetwork: true, + WindowsOptions: &core.WindowsSecurityContextOptions{ + HostProcess: proto.Bool(true), }, - }, - } + }), + ) } tests := []struct { @@ -18328,11 +16257,7 @@ func TestValidateReplicationControllerUpdate(t *testing.T) { ObjectMeta: metav1.ObjectMeta{ Labels: validSelector, }, - Spec: core.PodSpec{ - RestartPolicy: core.RestartPolicyAlways, - DNSPolicy: core.DNSClusterFirst, - Containers: []core.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, - }, + Spec: podtest.MakePod("").Spec, }, } readWriteVolumePodTemplate := core.PodTemplate{ @@ -18340,24 +16265,18 @@ func TestValidateReplicationControllerUpdate(t *testing.T) { ObjectMeta: metav1.ObjectMeta{ Labels: validSelector, }, - Spec: core.PodSpec{ - RestartPolicy: core.RestartPolicyAlways, - DNSPolicy: core.DNSClusterFirst, - Containers: []core.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, - Volumes: []core.Volume{{Name: "gcepd", VolumeSource: core.VolumeSource{GCEPersistentDisk: &core.GCEPersistentDiskVolumeSource{PDName: "my-PD", FSType: "ext4", Partition: 1, ReadOnly: false}}}}, - }, + Spec: podtest.MakePod("", + podtest.SetVolumes(core.Volume{Name: "gcepd", VolumeSource: core.VolumeSource{GCEPersistentDisk: &core.GCEPersistentDiskVolumeSource{PDName: "my-PD", FSType: "ext4", Partition: 1, ReadOnly: false}}}), + ).Spec, }, } invalidSelector := map[string]string{"NoUppercaseOrSpecialCharsLike=Equals": "b"} invalidPodTemplate := core.PodTemplate{ Template: core.PodTemplateSpec{ - Spec: core.PodSpec{ - RestartPolicy: core.RestartPolicyAlways, - DNSPolicy: core.DNSClusterFirst, - }, ObjectMeta: metav1.ObjectMeta{ Labels: invalidSelector, }, + Spec: podtest.MakePod("").Spec, }, } type rcUpdateTest struct { @@ -18489,11 +16408,7 @@ func TestValidateReplicationController(t *testing.T) { ObjectMeta: metav1.ObjectMeta{ Labels: validSelector, }, - Spec: core.PodSpec{ - RestartPolicy: core.RestartPolicyAlways, - DNSPolicy: core.DNSClusterFirst, - Containers: []core.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, - }, + Spec: podtest.MakePod("").Spec, }, } readWriteVolumePodTemplate := core.PodTemplate{ @@ -18501,12 +16416,9 @@ func TestValidateReplicationController(t *testing.T) { ObjectMeta: metav1.ObjectMeta{ Labels: validSelector, }, - Spec: core.PodSpec{ - Volumes: []core.Volume{{Name: "gcepd", VolumeSource: core.VolumeSource{GCEPersistentDisk: &core.GCEPersistentDiskVolumeSource{PDName: "my-PD", FSType: "ext4", Partition: 1, ReadOnly: false}}}}, - RestartPolicy: core.RestartPolicyAlways, - DNSPolicy: core.DNSClusterFirst, - Containers: []core.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, - }, + Spec: podtest.MakePod("", + podtest.SetVolumes(core.Volume{Name: "gcepd", VolumeSource: core.VolumeSource{GCEPersistentDisk: &core.GCEPersistentDiskVolumeSource{PDName: "my-PD", FSType: "ext4", Partition: 1, ReadOnly: false}}}), + ).Spec, }, } hostnetPodTemplate := core.PodTemplate{ @@ -18514,32 +16426,22 @@ func TestValidateReplicationController(t *testing.T) { ObjectMeta: metav1.ObjectMeta{ Labels: validSelector, }, - Spec: core.PodSpec{ - SecurityContext: &core.PodSecurityContext{ + Spec: podtest.MakePod("", + podtest.SetSecurityContext(&core.PodSecurityContext{ HostNetwork: true, - }, - RestartPolicy: core.RestartPolicyAlways, - DNSPolicy: core.DNSClusterFirst, - Containers: []core.Container{{ - Name: "abc", - Image: "image", - ImagePullPolicy: "IfNotPresent", - TerminationMessagePolicy: "File", - Ports: []core.ContainerPort{{ + }), + podtest.SetContainers(podtest.MakeContainer("abc", podtest.SetContainerPorts( + core.ContainerPort{ ContainerPort: 12345, Protocol: core.ProtocolTCP, - }}, - }}, - }, + }))), + ).Spec, }, } invalidSelector := map[string]string{"NoUppercaseOrSpecialCharsLike=Equals": "b"} invalidPodTemplate := core.PodTemplate{ Template: core.PodTemplateSpec{ - Spec: core.PodSpec{ - RestartPolicy: core.RestartPolicyAlways, - DNSPolicy: core.DNSClusterFirst, - }, + Spec: podtest.MakePod("").Spec, ObjectMeta: metav1.ObjectMeta{ Labels: invalidSelector, }, @@ -18673,11 +16575,9 @@ func TestValidateReplicationController(t *testing.T) { Spec: core.ReplicationControllerSpec{ Selector: validSelector, Template: &core.PodTemplateSpec{ - Spec: core.PodSpec{ - RestartPolicy: core.RestartPolicyOnFailure, - DNSPolicy: core.DNSClusterFirst, - Containers: []core.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, - }, + Spec: podtest.MakePod("", + podtest.SetRestartPolicy(core.RestartPolicyOnFailure), + ).Spec, ObjectMeta: metav1.ObjectMeta{ Labels: validSelector, }, @@ -18692,11 +16592,9 @@ func TestValidateReplicationController(t *testing.T) { Spec: core.ReplicationControllerSpec{ Selector: validSelector, Template: &core.PodTemplateSpec{ - Spec: core.PodSpec{ - RestartPolicy: core.RestartPolicyNever, - DNSPolicy: core.DNSClusterFirst, - Containers: []core.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, - }, + Spec: podtest.MakePod("", + podtest.SetRestartPolicy(core.RestartPolicyNever), + ).Spec, ObjectMeta: metav1.ObjectMeta{ Labels: validSelector, }, @@ -18712,12 +16610,9 @@ func TestValidateReplicationController(t *testing.T) { ObjectMeta: metav1.ObjectMeta{ Labels: validSelector, }, - Spec: core.PodSpec{ - RestartPolicy: core.RestartPolicyAlways, - DNSPolicy: core.DNSClusterFirst, - Containers: []core.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, - EphemeralContainers: []core.EphemeralContainer{{EphemeralContainerCommon: core.EphemeralContainerCommon{Name: "debug", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}}, - }, + Spec: podtest.MakePod("", + podtest.SetEphemeralContainers(core.EphemeralContainer{EphemeralContainerCommon: core.EphemeralContainerCommon{Name: "debug", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}), + ).Spec, }, }, }, @@ -24960,26 +22855,16 @@ func TestValidatePodTemplateSpecSeccomp(t *testing.T) { "container.seccomp.security.alpha.kubernetes.io/test2": "unconfined", }, }, - Spec: core.PodSpec{ - Containers: []core.Container{{ - Name: "test1", - Image: "alpine", - ImagePullPolicy: core.PullAlways, - TerminationMessagePolicy: core.TerminationMessageFallbackToLogsOnError, - }, { - SecurityContext: &core.SecurityContext{ - SeccompProfile: &core.SeccompProfile{ - Type: core.SeccompProfileTypeRuntimeDefault, - }, - }, - Name: "test2", - Image: "alpine", - ImagePullPolicy: core.PullAlways, - TerminationMessagePolicy: core.TerminationMessageFallbackToLogsOnError, - }}, - RestartPolicy: core.RestartPolicyAlways, - DNSPolicy: core.DNSDefault, - }, + Spec: podtest.MakePod("", + podtest.SetContainers( + podtest.MakeContainer("test1"), + podtest.MakeContainer("test2", + podtest.SetContainerSecurityContext(core.SecurityContext{ + SeccompProfile: &core.SeccompProfile{ + Type: core.SeccompProfileTypeRuntimeDefault, + }, + }))), + ).Spec, }, }, { description: "seccomp field and pod annotation must match", @@ -24995,21 +22880,13 @@ func TestValidatePodTemplateSpecSeccomp(t *testing.T) { "seccomp.security.alpha.kubernetes.io/pod": "runtime/default", }, }, - Spec: core.PodSpec{ - SecurityContext: &core.PodSecurityContext{ + Spec: podtest.MakePod("", + podtest.SetSecurityContext(&core.PodSecurityContext{ SeccompProfile: &core.SeccompProfile{ Type: core.SeccompProfileTypeUnconfined, }, - }, - Containers: []core.Container{{ - Name: "test", - Image: "alpine", - ImagePullPolicy: core.PullAlways, - TerminationMessagePolicy: core.TerminationMessageFallbackToLogsOnError, - }}, - RestartPolicy: core.RestartPolicyAlways, - DNSPolicy: core.DNSDefault, - }, + }), + ).Spec, }, }, { description: "init seccomp field and container annotation must match", @@ -25025,27 +22902,14 @@ func TestValidatePodTemplateSpecSeccomp(t *testing.T) { "container.seccomp.security.alpha.kubernetes.io/init-test": "unconfined", }, }, - Spec: core.PodSpec{ - Containers: []core.Container{{ - Name: "test", - Image: "alpine", - ImagePullPolicy: core.PullAlways, - TerminationMessagePolicy: core.TerminationMessageFallbackToLogsOnError, - }}, - InitContainers: []core.Container{{ - Name: "init-test", - SecurityContext: &core.SecurityContext{ + Spec: podtest.MakePod("", + podtest.SetInitContainers(podtest.MakeContainer("init-test", + podtest.SetContainerSecurityContext(core.SecurityContext{ SeccompProfile: &core.SeccompProfile{ Type: core.SeccompProfileTypeRuntimeDefault, }, - }, - Image: "alpine", - ImagePullPolicy: core.PullAlways, - TerminationMessagePolicy: core.TerminationMessageFallbackToLogsOnError, - }}, - RestartPolicy: core.RestartPolicyAlways, - DNSPolicy: core.DNSDefault, - }, + }))), + ).Spec, }, }, } @@ -25860,186 +23724,157 @@ func TestValidateDynamicResourceAllocation(t *testing.T) { shortPodName := &metav1.ObjectMeta{ Name: "some-pod", } - goodClaimTemplate := core.PodSpec{ - Containers: []core.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File", Resources: core.ResourceRequirements{Claims: []core.ResourceClaim{{Name: "my-claim-template"}}}}}, - RestartPolicy: core.RestartPolicyAlways, - DNSPolicy: core.DNSClusterFirst, - ResourceClaims: []core.PodResourceClaim{{ + goodClaimTemplate := *podtest.MakePod("", + podtest.SetContainers(podtest.MakeContainer("ctr", podtest.SetContainerResources(core.ResourceRequirements{Claims: []core.ResourceClaim{{Name: "my-claim-template"}}}))), + podtest.SetRestartPolicy(core.RestartPolicyAlways), + podtest.SetResourceClaims(core.PodResourceClaim{ Name: "my-claim-template", ResourceClaimTemplateName: &externalClaimTemplateName, - }}, - } - goodClaimReference := core.PodSpec{ - Containers: []core.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File", Resources: core.ResourceRequirements{Claims: []core.ResourceClaim{{Name: "my-claim-reference"}}}}}, - RestartPolicy: core.RestartPolicyAlways, - DNSPolicy: core.DNSClusterFirst, - ResourceClaims: []core.PodResourceClaim{{ + }), + ) + goodClaimReference := *podtest.MakePod("", + podtest.SetContainers(podtest.MakeContainer("ctr", podtest.SetContainerResources(core.ResourceRequirements{Claims: []core.ResourceClaim{{Name: "my-claim-reference"}}}))), + podtest.SetRestartPolicy(core.RestartPolicyAlways), + podtest.SetResourceClaims(core.PodResourceClaim{ Name: "my-claim-reference", ResourceClaimName: &externalClaimName, - }}, - } + }), + ) - successCases := map[string]core.PodSpec{ - "resource claim reference": goodClaimTemplate, + successCases := map[string]core.Pod{ + "resource claim reference": goodClaimReference, "resource claim template": goodClaimTemplate, - "multiple claims": { - Containers: []core.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File", Resources: core.ResourceRequirements{Claims: []core.ResourceClaim{{Name: "my-claim"}, {Name: "another-claim"}}}}}, - RestartPolicy: core.RestartPolicyAlways, - DNSPolicy: core.DNSClusterFirst, - ResourceClaims: []core.PodResourceClaim{{ + "multiple claims": *podtest.MakePod("", + podtest.SetContainers(podtest.MakeContainer("ctr", podtest.SetContainerResources(core.ResourceRequirements{Claims: []core.ResourceClaim{{Name: "my-claim"}, {Name: "another-claim"}}}))), + podtest.SetResourceClaims( + core.PodResourceClaim{ + Name: "my-claim", + ResourceClaimName: &externalClaimName, + }, + core.PodResourceClaim{ + Name: "another-claim", + ResourceClaimName: &externalClaimName, + }), + ), + "init container": *podtest.MakePod("", + podtest.SetInitContainers(podtest.MakeContainer("ctr-init", podtest.SetContainerResources(core.ResourceRequirements{Claims: []core.ResourceClaim{{Name: "my-claim"}}}))), + podtest.SetResourceClaims(core.PodResourceClaim{ Name: "my-claim", ResourceClaimName: &externalClaimName, - }, { - Name: "another-claim", - ResourceClaimName: &externalClaimName, - }}, - }, - "init container": { - Containers: []core.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File", Resources: core.ResourceRequirements{Claims: []core.ResourceClaim{{Name: "my-claim"}}}}}, - InitContainers: []core.Container{{Name: "ctr-init", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File", Resources: core.ResourceRequirements{Claims: []core.ResourceClaim{{Name: "my-claim"}}}}}, - RestartPolicy: core.RestartPolicyAlways, - DNSPolicy: core.DNSClusterFirst, - ResourceClaims: []core.PodResourceClaim{{ - Name: "my-claim", - ResourceClaimName: &externalClaimName, - }}, - }, + }), + ), } for k, v := range successCases { t.Run(k, func(t *testing.T) { - if errs := ValidatePodSpec(&v, shortPodName, field.NewPath("field"), PodValidationOptions{}); len(errs) != 0 { + if errs := ValidatePodSpec(&v.Spec, shortPodName, field.NewPath("field"), PodValidationOptions{}); len(errs) != 0 { t.Errorf("expected success: %v", errs) } }) } - failureCases := map[string]core.PodSpec{ - "pod claim name with prefix": { - Containers: []core.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, - RestartPolicy: core.RestartPolicyAlways, - DNSPolicy: core.DNSClusterFirst, - ResourceClaims: []core.PodResourceClaim{{ + failureCases := map[string]core.Pod{ + "pod claim name with prefix": *podtest.MakePod("", + podtest.SetResourceClaims(core.PodResourceClaim{ Name: "../my-claim", ResourceClaimName: &externalClaimName, - }}, - }, - "pod claim name with path": { - Containers: []core.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, - RestartPolicy: core.RestartPolicyAlways, - DNSPolicy: core.DNSClusterFirst, - ResourceClaims: []core.PodResourceClaim{{ + }), + ), + "pod claim name with path": *podtest.MakePod("", + podtest.SetResourceClaims(core.PodResourceClaim{ Name: "my/claim", ResourceClaimName: &externalClaimName, - }}, - }, - "pod claim name empty": { - Containers: []core.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, - RestartPolicy: core.RestartPolicyAlways, - DNSPolicy: core.DNSClusterFirst, - ResourceClaims: []core.PodResourceClaim{{ + }), + ), + "pod claim name empty": *podtest.MakePod("", + podtest.SetResourceClaims(core.PodResourceClaim{ Name: "", ResourceClaimName: &externalClaimName, - }}, - }, - "duplicate pod claim entries": { - Containers: []core.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, - RestartPolicy: core.RestartPolicyAlways, - DNSPolicy: core.DNSClusterFirst, - ResourceClaims: []core.PodResourceClaim{{ - Name: "my-claim", - ResourceClaimName: &externalClaimName, - }, { - Name: "my-claim", - ResourceClaimName: &externalClaimName, - }}, - }, - "resource claim source empty": { - Containers: []core.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File", Resources: core.ResourceRequirements{Claims: []core.ResourceClaim{{Name: "my-claim"}}}}}, - RestartPolicy: core.RestartPolicyAlways, - DNSPolicy: core.DNSClusterFirst, - ResourceClaims: []core.PodResourceClaim{{ + }), + ), + "duplicate pod claim entries": *podtest.MakePod("", + podtest.SetResourceClaims( + core.PodResourceClaim{ + Name: "my-claim", + ResourceClaimName: &externalClaimName, + }, + core.PodResourceClaim{ + Name: "my-claim", + ResourceClaimName: &externalClaimName, + }), + ), + "resource claim source empty": *podtest.MakePod("", + podtest.SetResourceClaims(core.PodResourceClaim{ Name: "my-claim", - }}, - }, - "resource claim reference and template": { - Containers: []core.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File", Resources: core.ResourceRequirements{Claims: []core.ResourceClaim{{Name: "my-claim"}}}}}, - RestartPolicy: core.RestartPolicyAlways, - DNSPolicy: core.DNSClusterFirst, - ResourceClaims: []core.PodResourceClaim{{ + }), + ), + "resource claim reference and template": *podtest.MakePod("", + podtest.SetContainers(podtest.MakeContainer("ctr", podtest.SetContainerResources(core.ResourceRequirements{Claims: []core.ResourceClaim{{Name: "my-claim"}}}))), + podtest.SetResourceClaims(core.PodResourceClaim{ Name: "my-claim", ResourceClaimName: &externalClaimName, ResourceClaimTemplateName: &externalClaimTemplateName, - }}, - }, - "claim not found": { - Containers: []core.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File", Resources: core.ResourceRequirements{Claims: []core.ResourceClaim{{Name: "no-such-claim"}}}}}, - RestartPolicy: core.RestartPolicyAlways, - DNSPolicy: core.DNSClusterFirst, - ResourceClaims: []core.PodResourceClaim{{ + }), + ), + "claim not found": *podtest.MakePod("", + podtest.SetContainers(podtest.MakeContainer("ctr", podtest.SetContainerResources(core.ResourceRequirements{Claims: []core.ResourceClaim{{Name: "no-such-claim"}}}))), + podtest.SetResourceClaims(core.PodResourceClaim{ Name: "my-claim", ResourceClaimName: &externalClaimName, - }}, - }, - "claim name empty": { - Containers: []core.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File", Resources: core.ResourceRequirements{Claims: []core.ResourceClaim{{Name: ""}}}}}, - RestartPolicy: core.RestartPolicyAlways, - DNSPolicy: core.DNSClusterFirst, - ResourceClaims: []core.PodResourceClaim{{ + }), + ), + "claim name empty": *podtest.MakePod("", + podtest.SetContainers(podtest.MakeContainer("ctr", podtest.SetContainerResources(core.ResourceRequirements{Claims: []core.ResourceClaim{{Name: ""}}}))), + podtest.SetResourceClaims(core.PodResourceClaim{ Name: "my-claim", ResourceClaimName: &externalClaimName, - }}, - }, - "pod claim name duplicates": { - Containers: []core.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File", Resources: core.ResourceRequirements{Claims: []core.ResourceClaim{{Name: "my-claim"}, {Name: "my-claim"}}}}}, - RestartPolicy: core.RestartPolicyAlways, - DNSPolicy: core.DNSClusterFirst, - ResourceClaims: []core.PodResourceClaim{{ + }), + ), + "pod claim name duplicates": *podtest.MakePod("", + podtest.SetContainers(podtest.MakeContainer("ctr", podtest.SetContainerResources(core.ResourceRequirements{Claims: []core.ResourceClaim{{Name: "my-claim"}, {Name: "my-claim"}}}))), + podtest.SetResourceClaims(core.PodResourceClaim{ Name: "my-claim", ResourceClaimName: &externalClaimName, - }}, - }, - "no claims defined": { - Containers: []core.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File", Resources: core.ResourceRequirements{Claims: []core.ResourceClaim{{Name: "my-claim"}}}}}, - RestartPolicy: core.RestartPolicyAlways, - DNSPolicy: core.DNSClusterFirst, - }, - "duplicate pod claim name": { - Containers: []core.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File", Resources: core.ResourceRequirements{Claims: []core.ResourceClaim{{Name: "my-claim"}}}}}, - RestartPolicy: core.RestartPolicyAlways, - DNSPolicy: core.DNSClusterFirst, - ResourceClaims: []core.PodResourceClaim{{ + }), + ), + "no claims defined": *podtest.MakePod("", + podtest.SetContainers(podtest.MakeContainer("ctr", podtest.SetContainerResources(core.ResourceRequirements{Claims: []core.ResourceClaim{{Name: "my-claim"}}}))), + podtest.SetRestartPolicy(core.RestartPolicyAlways), + ), + "duplicate pod claim name": *podtest.MakePod("", + podtest.SetContainers(podtest.MakeContainer("ctr", podtest.SetContainerResources(core.ResourceRequirements{Claims: []core.ResourceClaim{{Name: "my-claim"}}}))), + podtest.SetRestartPolicy(core.RestartPolicyAlways), + podtest.SetResourceClaims( + core.PodResourceClaim{ + Name: "my-claim", + ResourceClaimName: &externalClaimName, + }, + core.PodResourceClaim{ + Name: "my-claim", + ResourceClaimName: &externalClaimName, + }), + ), + "ephemeral container don't support resource requirements": *podtest.MakePod("", + podtest.SetEphemeralContainers(core.EphemeralContainer{EphemeralContainerCommon: core.EphemeralContainerCommon{Name: "ctr-ephemeral", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File", Resources: core.ResourceRequirements{Claims: []core.ResourceClaim{{Name: "my-claim"}}}}, TargetContainerName: "ctr"}), + podtest.SetResourceClaims(core.PodResourceClaim{ Name: "my-claim", ResourceClaimName: &externalClaimName, - }, { - Name: "my-claim", - ResourceClaimName: &externalClaimName, - }}, - }, - "ephemeral container don't support resource requirements": { - Containers: []core.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File", Resources: core.ResourceRequirements{Claims: []core.ResourceClaim{{Name: "my-claim"}}}}}, - EphemeralContainers: []core.EphemeralContainer{{EphemeralContainerCommon: core.EphemeralContainerCommon{Name: "ctr-ephemeral", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File", Resources: core.ResourceRequirements{Claims: []core.ResourceClaim{{Name: "my-claim"}}}}, TargetContainerName: "ctr"}}, - RestartPolicy: core.RestartPolicyAlways, - DNSPolicy: core.DNSClusterFirst, - ResourceClaims: []core.PodResourceClaim{{ - Name: "my-claim", - ResourceClaimName: &externalClaimName, - }}, - }, - "invalid claim template name": func() core.PodSpec { - spec := goodClaimTemplate.DeepCopy() + }), + ), + "invalid claim template name": func() core.Pod { + pod := goodClaimTemplate.DeepCopy() notLabel := ".foo_bar" - spec.ResourceClaims[0].ResourceClaimTemplateName = ¬Label - return *spec + pod.Spec.ResourceClaims[0].ResourceClaimTemplateName = ¬Label + return *pod }(), - "invalid claim reference name": func() core.PodSpec { - spec := goodClaimReference.DeepCopy() + "invalid claim reference name": func() core.Pod { + pod := goodClaimReference.DeepCopy() notLabel := ".foo_bar" - spec.ResourceClaims[0].ResourceClaimName = ¬Label - return *spec + pod.Spec.ResourceClaims[0].ResourceClaimName = ¬Label + return *pod }(), } for k, v := range failureCases { - if errs := ValidatePodSpec(&v, nil, field.NewPath("field"), PodValidationOptions{}); len(errs) == 0 { + if errs := ValidatePodSpec(&v.Spec, nil, field.NewPath("field"), PodValidationOptions{}); len(errs) == 0 { t.Errorf("expected failure for %q", k) } } @@ -26198,7 +24033,7 @@ func TestValidateSleepAction(t *testing.T) { for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - errs := validateSleepAction(tc.action, tc.gracePeriod, fldPath) + errs := validateSleepAction(tc.action, &tc.gracePeriod, fldPath) if len(tc.expectErr) > 0 && len(errs) == 0 { t.Errorf("Unexpected success") @@ -26262,18 +24097,12 @@ func TestValidatePodSpecWithSupplementalGroupsPolicy(t *testing.T) { } for name, tt := range validatePodSpecTestCases { t.Run(name, func(t *testing.T) { - podSpec := &core.PodSpec{ - SecurityContext: tt.securityContext, - Containers: []core.Container{ - {Name: "con", Image: "pause", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}, - }, - RestartPolicy: core.RestartPolicyAlways, - DNSPolicy: core.DNSClusterFirst, - } + podSpec := podtest.MakePodSpec(core.RestartPolicyAlways, podtest.SetSecurityContext(tt.securityContext), podtest.SetContainers(podtest.MakeContainer("con"))) + if tt.wantFieldErrors == nil { tt.wantFieldErrors = field.ErrorList{} } - errs := ValidatePodSpec(podSpec, nil, fldPath, PodValidationOptions{}) + errs := ValidatePodSpec(&podSpec, nil, fldPath, PodValidationOptions{}) if diff := cmp.Diff(tt.wantFieldErrors, errs); diff != "" { t.Errorf("unexpected field errors (-want, +got):\n%s", diff) } @@ -26309,19 +24138,11 @@ func TestValidateWindowsPodSecurityContextSupplementalGroupsPolicy(t *testing.T) for name, tt := range testCases { t.Run(name, func(t *testing.T) { - podSpec := &core.PodSpec{ - OS: &core.PodOS{Name: core.Windows}, - SecurityContext: tt.securityContext, - Containers: []core.Container{ - {Name: "con", Image: "pause", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}, - }, - RestartPolicy: core.RestartPolicyAlways, - DNSPolicy: core.DNSClusterFirst, - } + podSpec := podtest.MakePodSpec(core.RestartPolicyAlways, podtest.SetSecurityContext(tt.securityContext), podtest.SetOS(core.Windows), podtest.SetContainers(podtest.MakeContainer("con"))) if tt.wantFieldErrors == nil { tt.wantFieldErrors = field.ErrorList{} } - errs := validateWindows(podSpec, fldPath) + errs := validateWindows(&podSpec, fldPath) if diff := cmp.Diff(tt.wantFieldErrors, errs); diff != "" { t.Errorf("unexpected field errors (-want, +got):\n%s", diff) } diff --git a/pkg/kubelet/config/common_test.go b/pkg/kubelet/config/common_test.go index f390b6f95cb..c6025d85f98 100644 --- a/pkg/kubelet/config/common_test.go +++ b/pkg/kubelet/config/common_test.go @@ -29,6 +29,7 @@ import ( "k8s.io/apimachinery/pkg/types" clientscheme "k8s.io/client-go/kubernetes/scheme" "k8s.io/kubernetes/pkg/api/legacyscheme" + podtest "k8s.io/kubernetes/pkg/api/pod/testing" "k8s.io/kubernetes/pkg/apis/core" "k8s.io/kubernetes/pkg/apis/core/validation" "k8s.io/kubernetes/pkg/securitycontext" @@ -290,7 +291,7 @@ func TestStaticPodNameGenerate(t *testing.T) { } for _, c := range testCases { assert.Equal(t, c.expected, generatePodName(c.podName, c.nodeName), "wrong pod name generated") - pod := &core.Pod{} + pod := podtest.MakePod("") pod.Name = c.podName if c.overwrite != "" { pod.Name = c.overwrite diff --git a/pkg/registry/apps/daemonset/storage/storage_test.go b/pkg/registry/apps/daemonset/storage/storage_test.go index eaf15ffcdae..37667011392 100644 --- a/pkg/registry/apps/daemonset/storage/storage_test.go +++ b/pkg/registry/apps/daemonset/storage/storage_test.go @@ -26,6 +26,7 @@ import ( "k8s.io/apiserver/pkg/registry/generic" genericregistrytest "k8s.io/apiserver/pkg/registry/generic/testing" etcd3testing "k8s.io/apiserver/pkg/storage/etcd3/testing" + podtest "k8s.io/kubernetes/pkg/api/pod/testing" "k8s.io/kubernetes/pkg/apis/apps" api "k8s.io/kubernetes/pkg/apis/core" "k8s.io/kubernetes/pkg/registry/registrytest" @@ -62,18 +63,7 @@ func newValidDaemonSet() *apps.DaemonSet { ObjectMeta: metav1.ObjectMeta{ Labels: map[string]string{"a": "b"}, }, - Spec: api.PodSpec{ - Containers: []api.Container{ - { - Name: "test", - Image: "test_image", - ImagePullPolicy: api.PullIfNotPresent, - TerminationMessagePolicy: api.TerminationMessageReadFile, - }, - }, - RestartPolicy: api.RestartPolicyAlways, - DNSPolicy: api.DNSClusterFirst, - }, + Spec: podtest.MakePod("").Spec, }, }, } diff --git a/pkg/registry/apps/daemonset/strategy_test.go b/pkg/registry/apps/daemonset/strategy_test.go index 21e42cd25af..77add6fb737 100644 --- a/pkg/registry/apps/daemonset/strategy_test.go +++ b/pkg/registry/apps/daemonset/strategy_test.go @@ -23,6 +23,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/util/validation/field" genericapirequest "k8s.io/apiserver/pkg/endpoints/request" + podtest "k8s.io/kubernetes/pkg/api/pod/testing" "k8s.io/kubernetes/pkg/apis/apps" api "k8s.io/kubernetes/pkg/apis/core" ) @@ -138,11 +139,7 @@ func newDaemonSetWithSelectorLabels(selectorLabels map[string]string, templateGe ObjectMeta: metav1.ObjectMeta{ Labels: selectorLabels, }, - Spec: api.PodSpec{ - RestartPolicy: api.RestartPolicyAlways, - DNSPolicy: api.DNSClusterFirst, - Containers: []api.Container{{Name: fakeImageName, Image: fakeImage, ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: api.TerminationMessageReadFile}}, - }, + Spec: podtest.MakePod("").Spec, }, }, } diff --git a/pkg/registry/apps/deployment/storage/storage_test.go b/pkg/registry/apps/deployment/storage/storage_test.go index 08824a4cfb9..6a1bd0533ec 100644 --- a/pkg/registry/apps/deployment/storage/storage_test.go +++ b/pkg/registry/apps/deployment/storage/storage_test.go @@ -39,6 +39,7 @@ import ( "k8s.io/apiserver/pkg/registry/rest" storeerr "k8s.io/apiserver/pkg/storage/errors" etcd3testing "k8s.io/apiserver/pkg/storage/etcd3/testing" + podtest "k8s.io/kubernetes/pkg/api/pod/testing" "k8s.io/kubernetes/pkg/apis/apps" "k8s.io/kubernetes/pkg/apis/autoscaling" api "k8s.io/kubernetes/pkg/apis/core" @@ -79,18 +80,7 @@ func validNewDeployment() *apps.Deployment { ObjectMeta: metav1.ObjectMeta{ Labels: map[string]string{"a": "b"}, }, - Spec: api.PodSpec{ - Containers: []api.Container{ - { - Name: "test", - Image: "test_image", - ImagePullPolicy: api.PullIfNotPresent, - TerminationMessagePolicy: api.TerminationMessageReadFile, - }, - }, - RestartPolicy: api.RestartPolicyAlways, - DNSPolicy: api.DNSClusterFirst, - }, + Spec: podtest.MakePod("").Spec, }, Replicas: 7, }, diff --git a/pkg/registry/apps/deployment/strategy_test.go b/pkg/registry/apps/deployment/strategy_test.go index dd3df773c16..37f4c810fbe 100644 --- a/pkg/registry/apps/deployment/strategy_test.go +++ b/pkg/registry/apps/deployment/strategy_test.go @@ -26,13 +26,12 @@ import ( "k8s.io/apimachinery/pkg/util/intstr" "k8s.io/apimachinery/pkg/util/validation/field" genericapirequest "k8s.io/apiserver/pkg/endpoints/request" + podtest "k8s.io/kubernetes/pkg/api/pod/testing" "k8s.io/kubernetes/pkg/apis/apps" api "k8s.io/kubernetes/pkg/apis/core" ) const ( - fakeImageName = "fake-name" - fakeImage = "fakeimage" deploymentName = "test-deployment" namespace = "test-namespace" ) @@ -175,11 +174,7 @@ func newDeploymentWithSelectorLabels(selectorLabels map[string]string) *apps.Dep ObjectMeta: metav1.ObjectMeta{ Labels: selectorLabels, }, - Spec: api.PodSpec{ - RestartPolicy: api.RestartPolicyAlways, - DNSPolicy: api.DNSDefault, - Containers: []api.Container{{Name: fakeImageName, Image: fakeImage, ImagePullPolicy: api.PullNever, TerminationMessagePolicy: api.TerminationMessageReadFile}}, - }, + Spec: podtest.MakePod("").Spec, }, }, } @@ -210,15 +205,9 @@ func newDeploymentWithHugePageValue(resourceName api.ResourceName, value resourc Name: "foo", Labels: map[string]string{"foo": "bar"}, }, - Spec: api.PodSpec{ - RestartPolicy: api.RestartPolicyAlways, - DNSPolicy: api.DNSDefault, - Containers: []api.Container{{ - Name: fakeImageName, - Image: fakeImage, - ImagePullPolicy: api.PullNever, - TerminationMessagePolicy: api.TerminationMessageReadFile, - Resources: api.ResourceRequirements{ + Spec: podtest.MakePodSpec(api.RestartPolicyAlways, + podtest.SetContainers(podtest.MakeContainer("ctr", podtest.SetContainerResources( + api.ResourceRequirements{ Requests: api.ResourceList{ api.ResourceName(api.ResourceCPU): resource.MustParse("10"), api.ResourceName(resourceName): value, @@ -227,8 +216,8 @@ func newDeploymentWithHugePageValue(resourceName api.ResourceName, value resourc api.ResourceName(api.ResourceCPU): resource.MustParse("10"), api.ResourceName(resourceName): value, }, - }}, - }}, + }))), + ), }, }, } diff --git a/pkg/registry/apps/replicaset/storage/storage_test.go b/pkg/registry/apps/replicaset/storage/storage_test.go index d1ee204745e..63411e21a42 100644 --- a/pkg/registry/apps/replicaset/storage/storage_test.go +++ b/pkg/registry/apps/replicaset/storage/storage_test.go @@ -34,6 +34,7 @@ import ( genericregistrytest "k8s.io/apiserver/pkg/registry/generic/testing" "k8s.io/apiserver/pkg/registry/rest" etcd3testing "k8s.io/apiserver/pkg/storage/etcd3/testing" + podtest "k8s.io/kubernetes/pkg/api/pod/testing" "k8s.io/kubernetes/pkg/apis/apps" "k8s.io/kubernetes/pkg/apis/autoscaling" api "k8s.io/kubernetes/pkg/apis/core" @@ -75,18 +76,7 @@ func validNewReplicaSet() *apps.ReplicaSet { ObjectMeta: metav1.ObjectMeta{ Labels: map[string]string{"a": "b"}, }, - Spec: api.PodSpec{ - Containers: []api.Container{ - { - Name: "test", - Image: "test_image", - ImagePullPolicy: api.PullIfNotPresent, - TerminationMessagePolicy: api.TerminationMessageReadFile, - }, - }, - RestartPolicy: api.RestartPolicyAlways, - DNSPolicy: api.DNSClusterFirst, - }, + Spec: podtest.MakePod("").Spec, }, Replicas: 7, }, diff --git a/pkg/registry/apps/replicaset/strategy_test.go b/pkg/registry/apps/replicaset/strategy_test.go index d76ed810be8..06efdd2da55 100644 --- a/pkg/registry/apps/replicaset/strategy_test.go +++ b/pkg/registry/apps/replicaset/strategy_test.go @@ -23,6 +23,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/util/validation/field" genericapirequest "k8s.io/apiserver/pkg/endpoints/request" + podtest "k8s.io/kubernetes/pkg/api/pod/testing" "k8s.io/kubernetes/pkg/apis/apps" api "k8s.io/kubernetes/pkg/apis/core" ) @@ -49,11 +50,7 @@ func TestReplicaSetStrategy(t *testing.T) { ObjectMeta: metav1.ObjectMeta{ Labels: validSelector, }, - Spec: api.PodSpec{ - RestartPolicy: api.RestartPolicyAlways, - DNSPolicy: api.DNSClusterFirst, - Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: api.TerminationMessageReadFile}}, - }, + Spec: podtest.MakePod("").Spec, }, } rs := &apps.ReplicaSet{ @@ -218,11 +215,7 @@ func newReplicaSetWithSelectorLabels(selectorLabels map[string]string) *apps.Rep ObjectMeta: metav1.ObjectMeta{ Labels: selectorLabels, }, - Spec: api.PodSpec{ - RestartPolicy: api.RestartPolicyAlways, - DNSPolicy: api.DNSClusterFirst, - Containers: []api.Container{{Name: fakeImageName, Image: fakeImage, ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: api.TerminationMessageReadFile}}, - }, + Spec: podtest.MakePod("").Spec, }, }, } diff --git a/pkg/registry/batch/cronjob/storage/storage_test.go b/pkg/registry/batch/cronjob/storage/storage_test.go index e2c98d8c14e..46a5019fe22 100644 --- a/pkg/registry/batch/cronjob/storage/storage_test.go +++ b/pkg/registry/batch/cronjob/storage/storage_test.go @@ -26,6 +26,7 @@ import ( "k8s.io/apiserver/pkg/registry/generic" genericregistrytest "k8s.io/apiserver/pkg/registry/generic/testing" etcd3testing "k8s.io/apiserver/pkg/storage/etcd3/testing" + podtest "k8s.io/kubernetes/pkg/api/pod/testing" "k8s.io/kubernetes/pkg/apis/batch" api "k8s.io/kubernetes/pkg/apis/core" "k8s.io/kubernetes/pkg/registry/registrytest" @@ -59,15 +60,7 @@ func validNewCronJob() *batch.CronJob { JobTemplate: batch.JobTemplateSpec{ Spec: batch.JobSpec{ Template: api.PodTemplateSpec{ - Spec: api.PodSpec{ - RestartPolicy: api.RestartPolicyOnFailure, - DNSPolicy: api.DNSClusterFirst, - Containers: []api.Container{{ - Name: "abc", Image: "image", - ImagePullPolicy: api.PullIfNotPresent, - TerminationMessagePolicy: api.TerminationMessageReadFile, - }}, - }, + Spec: podtest.MakePodSpec(api.RestartPolicyOnFailure), }, }, }, @@ -85,9 +78,15 @@ func TestCreate(t *testing.T) { test.TestCreate( // valid validCronJob, - // invalid (empty spec) + // invalid (no containers) &batch.CronJob{ - Spec: batch.CronJobSpec{}, + Spec: batch.CronJobSpec{ + JobTemplate: batch.JobTemplateSpec{ + Spec: batch.JobSpec{ + Template: api.PodTemplateSpec{}, + }, + }, + }, }, ) } diff --git a/pkg/registry/batch/cronjob/strategy_test.go b/pkg/registry/batch/cronjob/strategy_test.go index 677ce014fb2..be645fcb43d 100644 --- a/pkg/registry/batch/cronjob/strategy_test.go +++ b/pkg/registry/batch/cronjob/strategy_test.go @@ -22,6 +22,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" genericapirequest "k8s.io/apiserver/pkg/endpoints/request" "k8s.io/apiserver/pkg/registry/rest" + podtest "k8s.io/kubernetes/pkg/api/pod/testing" "k8s.io/kubernetes/pkg/apis/batch" api "k8s.io/kubernetes/pkg/apis/core" "k8s.io/utils/ptr" @@ -29,11 +30,7 @@ import ( var ( validPodTemplateSpec = api.PodTemplateSpec{ - Spec: api.PodSpec{ - RestartPolicy: api.RestartPolicyOnFailure, - DNSPolicy: api.DNSClusterFirst, - Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: api.TerminationMessageReadFile}}, - }, + Spec: podtest.MakePodSpec(api.RestartPolicyOnFailure), } validCronjobSpec = batch.CronJobSpec{ Schedule: "5 5 * * ?", diff --git a/pkg/registry/batch/job/storage/storage_test.go b/pkg/registry/batch/job/storage/storage_test.go index 42093735421..8b5112cd3b0 100644 --- a/pkg/registry/batch/job/storage/storage_test.go +++ b/pkg/registry/batch/job/storage/storage_test.go @@ -34,6 +34,7 @@ import ( "k8s.io/apiserver/pkg/registry/rest" etcd3testing "k8s.io/apiserver/pkg/storage/etcd3/testing" "k8s.io/apiserver/pkg/warning" + podtest "k8s.io/kubernetes/pkg/api/pod/testing" "k8s.io/kubernetes/pkg/apis/batch" api "k8s.io/kubernetes/pkg/apis/core" "k8s.io/kubernetes/pkg/registry/registrytest" @@ -73,18 +74,7 @@ func validNewJob() *batch.Job { ObjectMeta: metav1.ObjectMeta{ Labels: map[string]string{"a": "b"}, }, - Spec: api.PodSpec{ - Containers: []api.Container{ - { - Name: "test", - Image: "test_image", - ImagePullPolicy: api.PullIfNotPresent, - TerminationMessagePolicy: api.TerminationMessageReadFile, - }, - }, - RestartPolicy: api.RestartPolicyOnFailure, - DNSPolicy: api.DNSClusterFirst, - }, + Spec: podtest.MakePodSpec(api.RestartPolicyOnFailure), }, }, } diff --git a/pkg/registry/batch/job/strategy_test.go b/pkg/registry/batch/job/strategy_test.go index aa48e4a2e5a..acd4b0ab9a0 100644 --- a/pkg/registry/batch/job/strategy_test.go +++ b/pkg/registry/batch/job/strategy_test.go @@ -30,6 +30,7 @@ import ( "k8s.io/apiserver/pkg/registry/rest" utilfeature "k8s.io/apiserver/pkg/util/feature" featuregatetesting "k8s.io/component-base/featuregate/testing" + podtest "k8s.io/kubernetes/pkg/api/pod/testing" apitesting "k8s.io/kubernetes/pkg/api/testing" "k8s.io/kubernetes/pkg/apis/batch" _ "k8s.io/kubernetes/pkg/apis/batch/install" @@ -1020,11 +1021,7 @@ func TestJobStrategy_ValidateUpdate(t *testing.T) { ObjectMeta: metav1.ObjectMeta{ Labels: validSelector.MatchLabels, }, - Spec: api.PodSpec{ - RestartPolicy: api.RestartPolicyOnFailure, - DNSPolicy: api.DNSClusterFirst, - Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: api.TerminationMessageReadFile}}, - }, + Spec: podtest.MakePodSpec(api.RestartPolicyOnFailure), } validPodTemplateSpecNever := *validPodTemplateSpec.DeepCopy() validPodTemplateSpecNever.Spec.RestartPolicy = api.RestartPolicyNever @@ -1226,11 +1223,7 @@ func TestJobStrategy_ValidateUpdate(t *testing.T) { ObjectMeta: metav1.ObjectMeta{ Labels: map[string]string{batch.LegacyJobNameLabel: "myjob", batch.LegacyControllerUidLabel: "test"}, }, - Spec: api.PodSpec{ - RestartPolicy: api.RestartPolicyOnFailure, - DNSPolicy: api.DNSClusterFirst, - Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: api.TerminationMessageReadFile}}, - }, + Spec: podtest.MakePodSpec(api.RestartPolicyOnFailure), }, }, }, @@ -1256,11 +1249,7 @@ func TestJobStrategy_ValidateUpdate(t *testing.T) { ObjectMeta: metav1.ObjectMeta{ Labels: map[string]string{batch.LegacyJobNameLabel: "myjob", batch.JobNameLabel: "myjob", batch.LegacyControllerUidLabel: "test", batch.ControllerUidLabel: "test"}, }, - Spec: api.PodSpec{ - RestartPolicy: api.RestartPolicyOnFailure, - DNSPolicy: api.DNSClusterFirst, - Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: api.TerminationMessageReadFile}}, - }, + Spec: podtest.MakePodSpec(api.RestartPolicyOnFailure), }, }, }, @@ -1326,11 +1315,7 @@ func TestJobStrategy_WarningsOnUpdate(t *testing.T) { ObjectMeta: metav1.ObjectMeta{ Labels: validSelector.MatchLabels, }, - Spec: api.PodSpec{ - RestartPolicy: api.RestartPolicyOnFailure, - DNSPolicy: api.DNSClusterFirst, - Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: api.TerminationMessageReadFile}}, - }, + Spec: podtest.MakePodSpec(api.RestartPolicyOnFailure), } cases := map[string]struct { oldJob *batch.Job @@ -1485,11 +1470,7 @@ func TestJobStrategy_WarningsOnCreate(t *testing.T) { ObjectMeta: metav1.ObjectMeta{ Labels: validSelector.MatchLabels, }, - Spec: api.PodSpec{ - RestartPolicy: api.RestartPolicyOnFailure, - DNSPolicy: api.DNSClusterFirst, - Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: api.TerminationMessageReadFile}}, - }, + Spec: podtest.MakePodSpec(api.RestartPolicyOnFailure), } validSpec := batch.JobSpec{ CompletionMode: completionModePtr(batch.NonIndexedCompletion), @@ -1556,13 +1537,8 @@ func TestJobStrategy_Validate(t *testing.T) { batchLabels := getValidBatchLabels() labelsWithNonBatch := getValidBatchLabelsWithNonBatch() defaultSelector := &metav1.LabelSelector{MatchLabels: map[string]string{batch.ControllerUidLabel: string(theUID)}} - validPodSpec := api.PodSpec{ - RestartPolicy: api.RestartPolicyOnFailure, - DNSPolicy: api.DNSClusterFirst, - Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: api.TerminationMessageReadFile}}, - } - validPodSpecNever := *validPodSpec.DeepCopy() - validPodSpecNever.RestartPolicy = api.RestartPolicyNever + validPodSpec := podtest.MakePodSpec(api.RestartPolicyOnFailure) + validPodSpecNever := podtest.MakePodSpec(api.RestartPolicyNever) validObjectMeta := getValidObjectMeta(0) testcases := map[string]struct { enableJobPodFailurePolicy bool @@ -1745,12 +1721,8 @@ func TestJobStrategy_Validate(t *testing.T) { ObjectMeta: metav1.ObjectMeta{ Labels: labelsWithNonBatch, }, - Spec: api.PodSpec{ - RestartPolicy: api.RestartPolicyOnFailure, - DNSPolicy: api.DNSClusterFirst, - Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: api.TerminationMessageReadFile}}, - Volumes: []api.Volume{{Name: "volume-name"}}, - }, + Spec: podtest.MakePodSpec(api.RestartPolicyOnFailure, + podtest.SetVolumes(api.Volume{Name: "volume-name"})), }, }, }, @@ -1763,12 +1735,8 @@ func TestJobStrategy_Validate(t *testing.T) { ObjectMeta: metav1.ObjectMeta{ Labels: labelsWithNonBatch, }, - Spec: api.PodSpec{ - RestartPolicy: api.RestartPolicyOnFailure, - DNSPolicy: api.DNSClusterFirst, - Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: api.TerminationMessageReadFile}}, - Volumes: []api.Volume{{Name: "volume-name"}}, - }, + Spec: podtest.MakePodSpec(api.RestartPolicyOnFailure, + podtest.SetVolumes(api.Volume{Name: "volume-name"})), }, }, }, diff --git a/pkg/registry/core/pod/storage/storage_test.go b/pkg/registry/core/pod/storage/storage_test.go index d0311b30d69..d516a6577a7 100644 --- a/pkg/registry/core/pod/storage/storage_test.go +++ b/pkg/registry/core/pod/storage/storage_test.go @@ -42,6 +42,7 @@ import ( apiserverstorage "k8s.io/apiserver/pkg/storage" storeerr "k8s.io/apiserver/pkg/storage/errors" etcd3testing "k8s.io/apiserver/pkg/storage/etcd3/testing" + podtest "k8s.io/kubernetes/pkg/api/pod/testing" api "k8s.io/kubernetes/pkg/apis/core" "k8s.io/kubernetes/pkg/registry/registrytest" "k8s.io/kubernetes/pkg/securitycontext" @@ -63,34 +64,18 @@ func newStorage(t *testing.T) (*REST, *BindingREST, *StatusREST, *etcd3testing.E } func validNewPod() *api.Pod { - grace := int64(30) enableServiceLinks := v1.DefaultEnableServiceLinks - return &api.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - Namespace: metav1.NamespaceDefault, - }, - Spec: api.PodSpec{ - RestartPolicy: api.RestartPolicyAlways, - DNSPolicy: api.DNSClusterFirst, - TerminationGracePeriodSeconds: &grace, - Containers: []api.Container{ - { - Name: "foo", - Image: "test", - ImagePullPolicy: api.PullAlways, + pod := podtest.MakePod("foo", + podtest.SetContainers(podtest.MakeContainer("foo", + podtest.SetContainerSecurityContext(*securitycontext.ValidInternalSecurityContextWithContainerDefaults()))), + podtest.SetSecurityContext(&api.PodSecurityContext{}), + ) + pod.Spec.SchedulerName = v1.DefaultSchedulerName + pod.Spec.EnableServiceLinks = &enableServiceLinks + pod.Spec.Containers[0].TerminationMessagePath = api.TerminationMessagePathDefault - TerminationMessagePath: api.TerminationMessagePathDefault, - TerminationMessagePolicy: api.TerminationMessageReadFile, - SecurityContext: securitycontext.ValidInternalSecurityContextWithContainerDefaults(), - }, - }, - SecurityContext: &api.PodSecurityContext{}, - SchedulerName: v1.DefaultSchedulerName, - EnableServiceLinks: &enableServiceLinks, - }, - } + return pod } func validChangedPod() *api.Pod { diff --git a/pkg/registry/core/pod/strategy_test.go b/pkg/registry/core/pod/strategy_test.go index 6813ac58ab2..d9fe54d2d50 100644 --- a/pkg/registry/core/pod/strategy_test.go +++ b/pkg/registry/core/pod/strategy_test.go @@ -43,6 +43,7 @@ import ( featuregatetesting "k8s.io/component-base/featuregate/testing" ptr "k8s.io/utils/ptr" + podtest "k8s.io/kubernetes/pkg/api/pod/testing" apitesting "k8s.io/kubernetes/pkg/api/testing" api "k8s.io/kubernetes/pkg/apis/core" "k8s.io/kubernetes/pkg/features" @@ -827,33 +828,24 @@ func TestPodIndexFunc(t *testing.T) { } func newPodWithHugePageValue(resourceName api.ResourceName, value resource.Quantity) *api.Pod { - return &api.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: "default", - Name: "foo", - ResourceVersion: "1", - }, - Spec: api.PodSpec{ - RestartPolicy: api.RestartPolicyAlways, - DNSPolicy: api.DNSDefault, - Containers: []api.Container{{ - Name: "foo", - Image: "image", - ImagePullPolicy: "IfNotPresent", - TerminationMessagePolicy: "File", - Resources: api.ResourceRequirements{ - Requests: api.ResourceList{ - api.ResourceCPU: resource.MustParse("10"), - resourceName: value, - }, - Limits: api.ResourceList{ - api.ResourceCPU: resource.MustParse("10"), - resourceName: value, - }, - }}, - }, - }, - } + return podtest.MakePod("", podtest.SetObjectMeta(metav1.ObjectMeta{ + Namespace: "default", + Name: "foo", + ResourceVersion: "1", + }), + podtest.SetContainers(podtest.MakeContainer("foo", + podtest.SetContainerResources(api.ResourceRequirements{ + Requests: api.ResourceList{ + api.ResourceCPU: resource.MustParse("10"), + resourceName: value, + }, + Limits: api.ResourceList{ + api.ResourceCPU: resource.MustParse("10"), + resourceName: value, + }, + }), + )), + ) } func TestPodStrategyValidate(t *testing.T) { @@ -871,102 +863,58 @@ func TestPodStrategyValidate(t *testing.T) { }, { name: "a new pod setting init-container with indivisible hugepages values", - pod: &api.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: "default", - Name: "foo", - }, - Spec: api.PodSpec{ - RestartPolicy: api.RestartPolicyAlways, - DNSPolicy: api.DNSDefault, - InitContainers: []api.Container{{ - Name: containerName, - Image: "image", - ImagePullPolicy: "IfNotPresent", - TerminationMessagePolicy: "File", - Resources: api.ResourceRequirements{ - Requests: api.ResourceList{ - api.ResourceName(api.ResourceHugePagesPrefix + "64Ki"): resource.MustParse("127Ki"), - }, - Limits: api.ResourceList{ - api.ResourceName(api.ResourceHugePagesPrefix + "64Ki"): resource.MustParse("127Ki"), - }, - }}, - }, - }, - }, + pod: podtest.MakePod("foo", + podtest.SetInitContainers(podtest.MakeContainer(containerName, podtest.SetContainerResources( + api.ResourceRequirements{ + Requests: api.ResourceList{ + api.ResourceName(api.ResourceHugePagesPrefix + "64Ki"): resource.MustParse("127Ki"), + }, + Limits: api.ResourceList{ + api.ResourceName(api.ResourceHugePagesPrefix + "64Ki"): resource.MustParse("127Ki"), + }, + }))), + ), wantErr: true, }, { name: "a new pod setting init-container with indivisible hugepages values while container with divisible hugepages values", - pod: &api.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: "default", - Name: "foo", - }, - Spec: api.PodSpec{ - RestartPolicy: api.RestartPolicyAlways, - DNSPolicy: api.DNSDefault, - InitContainers: []api.Container{{ - Name: containerName, - Image: "image", - ImagePullPolicy: "IfNotPresent", - TerminationMessagePolicy: "File", - Resources: api.ResourceRequirements{ - Requests: api.ResourceList{ - api.ResourceName(api.ResourceHugePagesPrefix + "2Mi"): resource.MustParse("5.1Mi"), - }, - Limits: api.ResourceList{ - api.ResourceName(api.ResourceHugePagesPrefix + "2Mi"): resource.MustParse("5.1Mi"), - }, - }}, - }, - Containers: []api.Container{{ - Name: containerName, - Image: "image", - ImagePullPolicy: "IfNotPresent", - TerminationMessagePolicy: "File", - Resources: api.ResourceRequirements{ - Requests: api.ResourceList{ - api.ResourceName(api.ResourceHugePagesPrefix + "1Gi"): resource.MustParse("2Gi"), - }, - Limits: api.ResourceList{ - api.ResourceName(api.ResourceHugePagesPrefix + "1Gi"): resource.MustParse("2Gi"), - }, - }}, - }, - }, - }, + pod: podtest.MakePod("foo", + podtest.SetInitContainers(podtest.MakeContainer(containerName, podtest.SetContainerResources( + api.ResourceRequirements{ + Requests: api.ResourceList{ + api.ResourceName(api.ResourceHugePagesPrefix + "2Mi"): resource.MustParse("5.1Mi"), + }, + Limits: api.ResourceList{ + api.ResourceName(api.ResourceHugePagesPrefix + "2Mi"): resource.MustParse("5.1Mi"), + }, + }))), + podtest.SetContainers(podtest.MakeContainer(containerName, podtest.SetContainerResources( + api.ResourceRequirements{ + Requests: api.ResourceList{ + api.ResourceName(api.ResourceHugePagesPrefix + "1Gi"): resource.MustParse("2Gi"), + }, + Limits: api.ResourceList{ + api.ResourceName(api.ResourceHugePagesPrefix + "1Gi"): resource.MustParse("2Gi"), + }, + }))), + ), wantErr: true, }, { name: "a new pod setting container with divisible hugepages values", - pod: &api.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: "default", - Name: "foo", - }, - Spec: api.PodSpec{ - RestartPolicy: api.RestartPolicyAlways, - DNSPolicy: api.DNSDefault, - Containers: []api.Container{{ - Name: containerName, - Image: "image", - ImagePullPolicy: "IfNotPresent", - TerminationMessagePolicy: "File", - Resources: api.ResourceRequirements{ - Requests: api.ResourceList{ - api.ResourceName(api.ResourceCPU): resource.MustParse("10"), - api.ResourceName(api.ResourceHugePagesPrefix + "1Mi"): resource.MustParse("2Mi"), - }, - Limits: api.ResourceList{ - api.ResourceName(api.ResourceCPU): resource.MustParse("10"), - api.ResourceName(api.ResourceHugePagesPrefix + "1Mi"): resource.MustParse("2Mi"), - }, - }}, - }, - }, - }, + pod: podtest.MakePod("foo", + podtest.SetContainers(podtest.MakeContainer(containerName, podtest.SetContainerResources( + api.ResourceRequirements{ + Requests: api.ResourceList{ + api.ResourceName(api.ResourceCPU): resource.MustParse("10"), + api.ResourceName(api.ResourceHugePagesPrefix + "1Mi"): resource.MustParse("2Mi"), + }, + Limits: api.ResourceList{ + api.ResourceName(api.ResourceCPU): resource.MustParse("10"), + api.ResourceName(api.ResourceHugePagesPrefix + "1Mi"): resource.MustParse("2Mi"), + }, + }))), + ), }, } @@ -992,54 +940,20 @@ func TestEphemeralContainerStrategyValidateUpdate(t *testing.T) { }{ { name: "add ephemeral container to regular pod and expect success", - oldPod: &api.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "test-pod", - Namespace: "test-ns", - ResourceVersion: "1", - }, - Spec: api.PodSpec{ - RestartPolicy: api.RestartPolicyAlways, - DNSPolicy: api.DNSDefault, - Containers: []api.Container{ - { - Name: "container", - Image: "image", - ImagePullPolicy: "IfNotPresent", - TerminationMessagePolicy: "File", - }, + oldPod: podtest.MakePod("test-pod", + podtest.SetResourceVersion("1"), + ), + newPod: podtest.MakePod("test-pod", + podtest.SetResourceVersion("1"), + podtest.SetEphemeralContainers(api.EphemeralContainer{ + EphemeralContainerCommon: api.EphemeralContainerCommon{ + Name: "debugger", + Image: "image", + ImagePullPolicy: "IfNotPresent", + TerminationMessagePolicy: "File", }, - }, - }, - newPod: &api.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "test-pod", - Namespace: "test-ns", - ResourceVersion: "1", - }, - Spec: api.PodSpec{ - RestartPolicy: api.RestartPolicyAlways, - DNSPolicy: api.DNSDefault, - Containers: []api.Container{ - { - Name: "container", - Image: "image", - ImagePullPolicy: "IfNotPresent", - TerminationMessagePolicy: "File", - }, - }, - EphemeralContainers: []api.EphemeralContainer{ - { - EphemeralContainerCommon: api.EphemeralContainerCommon{ - Name: "debugger", - Image: "image", - ImagePullPolicy: "IfNotPresent", - TerminationMessagePolicy: "File", - }, - }, - }, - }, - }, + }), + ), }, } @@ -1059,170 +973,64 @@ func TestEphemeralContainerStrategyValidateUpdate(t *testing.T) { }{ { name: "add ephemeral container to static pod and expect failure", - oldPod: &api.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "test-pod", - Namespace: "test-ns", - ResourceVersion: "1", - Annotations: map[string]string{api.MirrorPodAnnotationKey: "someVal"}, - }, - Spec: api.PodSpec{ - RestartPolicy: api.RestartPolicyAlways, - DNSPolicy: api.DNSDefault, - Containers: []api.Container{ - { - Name: "container", - Image: "image", - ImagePullPolicy: "IfNotPresent", - TerminationMessagePolicy: "File", - }, + oldPod: podtest.MakePod("test-pod", + podtest.SetAnnotations(map[string]string{api.MirrorPodAnnotationKey: "someVal"}), + podtest.SetNodeName("example.com"), + ), + newPod: podtest.MakePod("test-pod", + podtest.SetAnnotations(map[string]string{api.MirrorPodAnnotationKey: "someVal"}), + podtest.SetEphemeralContainers(api.EphemeralContainer{ + EphemeralContainerCommon: api.EphemeralContainerCommon{ + Name: "debugger", + Image: "image", + ImagePullPolicy: "IfNotPresent", + TerminationMessagePolicy: "File", }, - NodeName: "example.com", - }, - }, - newPod: &api.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "test-pod", - Namespace: "test-ns", - ResourceVersion: "1", - Annotations: map[string]string{api.MirrorPodAnnotationKey: "someVal"}, - }, - Spec: api.PodSpec{ - RestartPolicy: api.RestartPolicyAlways, - DNSPolicy: api.DNSDefault, - Containers: []api.Container{ - { - Name: "container", - Image: "image", - ImagePullPolicy: "IfNotPresent", - TerminationMessagePolicy: "File", - }, - }, - EphemeralContainers: []api.EphemeralContainer{ - { - EphemeralContainerCommon: api.EphemeralContainerCommon{ - Name: "debugger", - Image: "image", - ImagePullPolicy: "IfNotPresent", - TerminationMessagePolicy: "File", - }, - }, - }, - NodeName: "example.com", - }, - }, + }), + podtest.SetNodeName("example.com"), + ), }, { name: "remove ephemeral container from regular pod and expect failure", - newPod: &api.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "test-pod", - Namespace: "test-ns", - ResourceVersion: "1", - }, - Spec: api.PodSpec{ - RestartPolicy: api.RestartPolicyAlways, - DNSPolicy: api.DNSDefault, - Containers: []api.Container{ - { - Name: "container", - Image: "image", - ImagePullPolicy: "IfNotPresent", - TerminationMessagePolicy: "File", - }, + newPod: podtest.MakePod("test-pod", + podtest.SetResourceVersion("1"), + ), + oldPod: podtest.MakePod("test-pod", + podtest.SetResourceVersion("1"), + podtest.SetEphemeralContainers(api.EphemeralContainer{ + EphemeralContainerCommon: api.EphemeralContainerCommon{ + Name: "debugger", + Image: "image", + ImagePullPolicy: "IfNotPresent", + TerminationMessagePolicy: "File", }, - }, - }, - oldPod: &api.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "test-pod", - Namespace: "test-ns", - ResourceVersion: "1", - }, - Spec: api.PodSpec{ - RestartPolicy: api.RestartPolicyAlways, - DNSPolicy: api.DNSDefault, - Containers: []api.Container{ - { - Name: "container", - Image: "image", - ImagePullPolicy: "IfNotPresent", - TerminationMessagePolicy: "File", - }, - }, - EphemeralContainers: []api.EphemeralContainer{ - { - EphemeralContainerCommon: api.EphemeralContainerCommon{ - Name: "debugger", - Image: "image", - ImagePullPolicy: "IfNotPresent", - TerminationMessagePolicy: "File", - }, - }, - }, - }, - }, + }), + ), }, { name: "change ephemeral container from regular pod and expect failure", - newPod: &api.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "test-pod", - Namespace: "test-ns", - ResourceVersion: "1", - }, - Spec: api.PodSpec{ - RestartPolicy: api.RestartPolicyAlways, - DNSPolicy: api.DNSDefault, - Containers: []api.Container{ - { - Name: "container", - Image: "image", - ImagePullPolicy: "IfNotPresent", - TerminationMessagePolicy: "File", - }, + newPod: podtest.MakePod("test-pod", + podtest.SetResourceVersion("1"), + podtest.SetEphemeralContainers(api.EphemeralContainer{ + EphemeralContainerCommon: api.EphemeralContainerCommon{ + Name: "debugger", + Image: "image2", + ImagePullPolicy: "IfNotPresent", + TerminationMessagePolicy: "File", }, - EphemeralContainers: []api.EphemeralContainer{ - { - EphemeralContainerCommon: api.EphemeralContainerCommon{ - Name: "debugger", - Image: "image2", - ImagePullPolicy: "IfNotPresent", - TerminationMessagePolicy: "File", - }, - }, + }), + ), + oldPod: podtest.MakePod("test-pod", + podtest.SetResourceVersion("1"), + podtest.SetEphemeralContainers(api.EphemeralContainer{ + EphemeralContainerCommon: api.EphemeralContainerCommon{ + Name: "debugger", + Image: "image", + ImagePullPolicy: "IfNotPresent", + TerminationMessagePolicy: "File", }, - }, - }, - oldPod: &api.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "test-pod", - Namespace: "test-ns", - ResourceVersion: "1", - }, - Spec: api.PodSpec{ - RestartPolicy: api.RestartPolicyAlways, - DNSPolicy: api.DNSDefault, - Containers: []api.Container{ - { - Name: "container", - Image: "image", - ImagePullPolicy: "IfNotPresent", - TerminationMessagePolicy: "File", - }, - }, - EphemeralContainers: []api.EphemeralContainer{ - { - EphemeralContainerCommon: api.EphemeralContainerCommon{ - Name: "debugger", - Image: "image", - ImagePullPolicy: "IfNotPresent", - TerminationMessagePolicy: "File", - }, - }, - }, - }, - }, + }), + ), }, } @@ -1530,24 +1338,7 @@ func TestNodeInclusionPolicyEnablementInCreating(t *testing.T) { t.Run(tc.name, func(t *testing.T) { featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.NodeInclusionPolicyInPodTopologySpread, tc.enableNodeInclusionPolicy) - pod := &api.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: "default", - Name: "foo", - }, - Spec: api.PodSpec{ - RestartPolicy: api.RestartPolicyAlways, - DNSPolicy: api.DNSDefault, - Containers: []api.Container{ - { - Name: "container", - Image: "image", - ImagePullPolicy: "IfNotPresent", - TerminationMessagePolicy: "File", - }, - }, - }, - } + pod := podtest.MakePod("foo") wantPod := pod.DeepCopy() pod.Spec.TopologySpreadConstraints = append(pod.Spec.TopologySpreadConstraints, tc.topologySpreadConstraints...) @@ -1575,34 +1366,15 @@ func TestNodeInclusionPolicyEnablementInUpdating(t *testing.T) { featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.NodeInclusionPolicyInPodTopologySpread, true) ctx := genericapirequest.NewDefaultContext() - pod := &api.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: "default", - Name: "foo", - ResourceVersion: "1", - }, - Spec: api.PodSpec{ - RestartPolicy: api.RestartPolicyAlways, - DNSPolicy: api.DNSDefault, - Containers: []api.Container{ - { - Name: "container", - Image: "image", - ImagePullPolicy: "IfNotPresent", - TerminationMessagePolicy: "File", - }, - }, - TopologySpreadConstraints: []api.TopologySpreadConstraint{ - { - NodeAffinityPolicy: &ignore, - NodeTaintsPolicy: &honor, - WhenUnsatisfiable: api.DoNotSchedule, - TopologyKey: "kubernetes.io/hostname", - MaxSkew: 1, - }, - }, - }, - } + pod := podtest.MakePod("foo", + podtest.SetTopologySpreadConstraints(api.TopologySpreadConstraint{ + NodeAffinityPolicy: &ignore, + NodeTaintsPolicy: &honor, + WhenUnsatisfiable: api.DoNotSchedule, + TopologyKey: "kubernetes.io/hostname", + MaxSkew: 1, + }), + ) errs := Strategy.Validate(ctx, pod) if len(errs) != 0 { diff --git a/pkg/registry/core/podtemplate/storage/storage_test.go b/pkg/registry/core/podtemplate/storage/storage_test.go index 785fc6fcb62..fd177c4b05d 100644 --- a/pkg/registry/core/podtemplate/storage/storage_test.go +++ b/pkg/registry/core/podtemplate/storage/storage_test.go @@ -26,6 +26,7 @@ import ( "k8s.io/apiserver/pkg/registry/generic" genericregistrytest "k8s.io/apiserver/pkg/registry/generic/testing" etcd3testing "k8s.io/apiserver/pkg/storage/etcd3/testing" + podtest "k8s.io/kubernetes/pkg/api/pod/testing" api "k8s.io/kubernetes/pkg/apis/core" "k8s.io/kubernetes/pkg/registry/registrytest" ) @@ -55,20 +56,7 @@ func validNewPodTemplate(name string) *api.PodTemplate { ObjectMeta: metav1.ObjectMeta{ Labels: map[string]string{"test": "foo"}, }, - Spec: api.PodSpec{ - RestartPolicy: api.RestartPolicyAlways, - DNSPolicy: api.DNSClusterFirst, - Containers: []api.Container{ - { - Name: "foo", - Image: "test", - ImagePullPolicy: api.PullAlways, - - TerminationMessagePath: api.TerminationMessagePathDefault, - TerminationMessagePolicy: api.TerminationMessageReadFile, - }, - }, - }, + Spec: podtest.MakePod("").Spec, }, } } diff --git a/pkg/registry/core/podtemplate/strategy_test.go b/pkg/registry/core/podtemplate/strategy_test.go index 7ad0f5634d2..a30a1f9a659 100644 --- a/pkg/registry/core/podtemplate/strategy_test.go +++ b/pkg/registry/core/podtemplate/strategy_test.go @@ -21,6 +21,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" genericapirequest "k8s.io/apiserver/pkg/endpoints/request" + podtest "k8s.io/kubernetes/pkg/api/pod/testing" api "k8s.io/kubernetes/pkg/apis/core" ) @@ -40,11 +41,9 @@ func TestStrategy(t *testing.T) { Generation: 999, }, Template: api.PodTemplateSpec{ - Spec: api.PodSpec{ - RestartPolicy: api.RestartPolicyOnFailure, - DNSPolicy: api.DNSClusterFirst, - Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: api.TerminationMessageReadFile}}, - }, + Spec: podtest.MakePod("", + podtest.SetRestartPolicy(api.RestartPolicyOnFailure), + ).Spec, }, } diff --git a/pkg/registry/core/replicationcontroller/storage/storage_test.go b/pkg/registry/core/replicationcontroller/storage/storage_test.go index b7312a3860c..9fb3f19b190 100644 --- a/pkg/registry/core/replicationcontroller/storage/storage_test.go +++ b/pkg/registry/core/replicationcontroller/storage/storage_test.go @@ -34,6 +34,7 @@ import ( genericregistrytest "k8s.io/apiserver/pkg/registry/generic/testing" "k8s.io/apiserver/pkg/registry/rest" etcd3testing "k8s.io/apiserver/pkg/storage/etcd3/testing" + podtest "k8s.io/kubernetes/pkg/api/pod/testing" "k8s.io/kubernetes/pkg/apis/autoscaling" api "k8s.io/kubernetes/pkg/apis/core" "k8s.io/kubernetes/pkg/registry/registrytest" @@ -82,18 +83,7 @@ func validNewController() *api.ReplicationController { ObjectMeta: metav1.ObjectMeta{ Labels: map[string]string{"a": "b"}, }, - Spec: api.PodSpec{ - Containers: []api.Container{ - { - Name: "test", - Image: "test_image", - ImagePullPolicy: api.PullIfNotPresent, - TerminationMessagePolicy: api.TerminationMessageReadFile, - }, - }, - RestartPolicy: api.RestartPolicyAlways, - DNSPolicy: api.DNSClusterFirst, - }, + Spec: podtest.MakePod("").Spec, }, }, } diff --git a/pkg/registry/core/replicationcontroller/strategy_test.go b/pkg/registry/core/replicationcontroller/strategy_test.go index 252def3201a..bb9e2893832 100644 --- a/pkg/registry/core/replicationcontroller/strategy_test.go +++ b/pkg/registry/core/replicationcontroller/strategy_test.go @@ -22,6 +22,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" genericapirequest "k8s.io/apiserver/pkg/endpoints/request" + podtest "k8s.io/kubernetes/pkg/api/pod/testing" apitesting "k8s.io/kubernetes/pkg/api/testing" api "k8s.io/kubernetes/pkg/apis/core" @@ -44,11 +45,7 @@ func TestControllerStrategy(t *testing.T) { ObjectMeta: metav1.ObjectMeta{ Labels: validSelector, }, - Spec: api.PodSpec{ - RestartPolicy: api.RestartPolicyAlways, - DNSPolicy: api.DNSClusterFirst, - Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: api.TerminationMessageReadFile}}, - }, + Spec: podtest.MakePod("").Spec, }, } rc := &api.ReplicationController{ @@ -163,11 +160,7 @@ func TestValidateUpdate(t *testing.T) { ObjectMeta: metav1.ObjectMeta{ Labels: validSelector, }, - Spec: api.PodSpec{ - RestartPolicy: api.RestartPolicyAlways, - DNSPolicy: api.DNSClusterFirst, - Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, - }, + Spec: podtest.MakePod("").Spec, }, } oldController := &api.ReplicationController{