mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-26 21:17:23 +00:00
Refactor container validation
Refactor common validation into methods that validate a single container and call these methods when iterating the three types of container lists. Move initContainer-specific validation from validateContainers to validateInitContainers. This resolves issues where init and ephemeral containers would return duplicate or incorrectly formatted errors for problems detected by validateContainers.
This commit is contained in:
parent
dbbbf8502e
commit
1dc040082c
@ -2930,18 +2930,14 @@ func validateEphemeralContainers(ephemeralContainers []core.EphemeralContainer,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ec.Name == "" {
|
if ec.Name == "" {
|
||||||
allErrs = append(allErrs, field.Required(idxPath, "ephemeralContainer requires a name"))
|
allErrs = append(allErrs, field.Required(idxPath.Child("name"), "ephemeralContainer requires a name"))
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
// Using validateContainers() here isn't ideal because it adds an index to the error message that
|
c := (*core.Container)(&ec.EphemeralContainerCommon)
|
||||||
// doesn't really exist for EphemeralContainers (i.e. ephemeralContainers[0].spec[0].name instead
|
allErrs = append(allErrs, validateContainer(c, volumes, idxPath, opts)...)
|
||||||
// of ephemeralContainers[0].spec.name)
|
|
||||||
// TODO(verb): factor a validateContainer() out of validateContainers() to be used here
|
|
||||||
c := core.Container(ec.EphemeralContainerCommon)
|
|
||||||
allErrs = append(allErrs, validateContainers([]core.Container{c}, false, volumes, idxPath, opts)...)
|
|
||||||
// EphemeralContainers don't require the backwards-compatibility distinction between pod/podTemplate validation
|
// EphemeralContainers don't require the backwards-compatibility distinction between pod/podTemplate validation
|
||||||
allErrs = append(allErrs, validateContainersOnlyForPod([]core.Container{c}, idxPath)...)
|
allErrs = append(allErrs, validateContainerOnlyForPod(c, idxPath)...)
|
||||||
|
|
||||||
if allNames.Has(ec.Name) {
|
if allNames.Has(ec.Name) {
|
||||||
allErrs = append(allErrs, field.Duplicate(idxPath.Child("name"), ec.Name))
|
allErrs = append(allErrs, field.Duplicate(idxPath.Child("name"), ec.Name))
|
||||||
@ -2993,11 +2989,8 @@ func validateFieldAllowList(value interface{}, allowedFields map[string]bool, er
|
|||||||
return allErrs
|
return allErrs
|
||||||
}
|
}
|
||||||
|
|
||||||
func validateInitContainers(containers []core.Container, otherContainers []core.Container, deviceVolumes map[string]core.VolumeSource, fldPath *field.Path, opts PodValidationOptions) field.ErrorList {
|
func validateInitContainers(containers []core.Container, otherContainers []core.Container, volumes map[string]core.VolumeSource, fldPath *field.Path, opts PodValidationOptions) field.ErrorList {
|
||||||
var allErrs field.ErrorList
|
var allErrs field.ErrorList
|
||||||
if len(containers) > 0 {
|
|
||||||
allErrs = append(allErrs, validateContainers(containers, true, deviceVolumes, fldPath, opts)...)
|
|
||||||
}
|
|
||||||
|
|
||||||
allNames := sets.String{}
|
allNames := sets.String{}
|
||||||
for _, ctr := range otherContainers {
|
for _, ctr := range otherContainers {
|
||||||
@ -3007,10 +3000,15 @@ func validateInitContainers(containers []core.Container, otherContainers []core.
|
|||||||
idxPath := fldPath.Index(i)
|
idxPath := fldPath.Index(i)
|
||||||
if allNames.Has(ctr.Name) {
|
if allNames.Has(ctr.Name) {
|
||||||
allErrs = append(allErrs, field.Duplicate(idxPath.Child("name"), ctr.Name))
|
allErrs = append(allErrs, field.Duplicate(idxPath.Child("name"), ctr.Name))
|
||||||
}
|
} else if len(ctr.Name) > 0 {
|
||||||
if len(ctr.Name) > 0 {
|
|
||||||
allNames.Insert(ctr.Name)
|
allNames.Insert(ctr.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
allErrs = append(allErrs, validateContainer(&ctr, volumes, idxPath, opts)...)
|
||||||
|
|
||||||
|
// Check for port conflicts in init containers individually since init containers run one-by-one.
|
||||||
|
allErrs = append(allErrs, checkHostPortConflicts([]core.Container{ctr}, fldPath)...)
|
||||||
|
|
||||||
if ctr.Lifecycle != nil {
|
if ctr.Lifecycle != nil {
|
||||||
allErrs = append(allErrs, field.Invalid(idxPath.Child("lifecycle"), ctr.Lifecycle, "must not be set for init containers"))
|
allErrs = append(allErrs, field.Invalid(idxPath.Child("lifecycle"), ctr.Lifecycle, "must not be set for init containers"))
|
||||||
}
|
}
|
||||||
@ -3024,10 +3022,70 @@ func validateInitContainers(containers []core.Container, otherContainers []core.
|
|||||||
allErrs = append(allErrs, field.Invalid(idxPath.Child("startupProbe"), ctr.StartupProbe, "must not be set for init containers"))
|
allErrs = append(allErrs, field.Invalid(idxPath.Child("startupProbe"), ctr.StartupProbe, "must not be set for init containers"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return allErrs
|
return allErrs
|
||||||
}
|
}
|
||||||
|
|
||||||
func validateContainers(containers []core.Container, isInitContainers bool, volumes map[string]core.VolumeSource, fldPath *field.Path, opts PodValidationOptions) field.ErrorList {
|
func validateContainer(ctr *core.Container, volumes map[string]core.VolumeSource, path *field.Path, opts PodValidationOptions) field.ErrorList {
|
||||||
|
allErrs := field.ErrorList{}
|
||||||
|
|
||||||
|
namePath := path.Child("name")
|
||||||
|
if len(ctr.Name) == 0 {
|
||||||
|
allErrs = append(allErrs, field.Required(namePath, ""))
|
||||||
|
} else {
|
||||||
|
allErrs = append(allErrs, ValidateDNS1123Label(ctr.Name, namePath)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: do not validate leading and trailing whitespace to preserve backward compatibility.
|
||||||
|
// for example: https://github.com/openshift/origin/issues/14659 image = " " is special token in pod template
|
||||||
|
// others may have done similar
|
||||||
|
if len(ctr.Image) == 0 {
|
||||||
|
allErrs = append(allErrs, field.Required(path.Child("image"), ""))
|
||||||
|
}
|
||||||
|
if ctr.Lifecycle != nil {
|
||||||
|
allErrs = append(allErrs, validateLifecycle(ctr.Lifecycle, path.Child("lifecycle"))...)
|
||||||
|
}
|
||||||
|
|
||||||
|
allErrs = append(allErrs, validateProbe(ctr.LivenessProbe, path.Child("livenessProbe"))...)
|
||||||
|
// Readiness-specific validation
|
||||||
|
if ctr.ReadinessProbe != nil && ctr.ReadinessProbe.TerminationGracePeriodSeconds != nil {
|
||||||
|
allErrs = append(allErrs, field.Invalid(path.Child("readinessProbe", "terminationGracePeriodSeconds"), ctr.ReadinessProbe.TerminationGracePeriodSeconds, "must not be set for readinessProbes"))
|
||||||
|
}
|
||||||
|
allErrs = append(allErrs, validateProbe(ctr.StartupProbe, path.Child("startupProbe"))...)
|
||||||
|
// Liveness-specific validation
|
||||||
|
if ctr.LivenessProbe != nil && ctr.LivenessProbe.SuccessThreshold != 1 {
|
||||||
|
allErrs = append(allErrs, field.Invalid(path.Child("livenessProbe", "successThreshold"), ctr.LivenessProbe.SuccessThreshold, "must be 1"))
|
||||||
|
}
|
||||||
|
allErrs = append(allErrs, validateProbe(ctr.StartupProbe, path.Child("startupProbe"))...)
|
||||||
|
// Startup-specific validation
|
||||||
|
if ctr.StartupProbe != nil && ctr.StartupProbe.SuccessThreshold != 1 {
|
||||||
|
allErrs = append(allErrs, field.Invalid(path.Child("startupProbe", "successThreshold"), ctr.StartupProbe.SuccessThreshold, "must be 1"))
|
||||||
|
}
|
||||||
|
|
||||||
|
switch ctr.TerminationMessagePolicy {
|
||||||
|
case core.TerminationMessageReadFile, core.TerminationMessageFallbackToLogsOnError:
|
||||||
|
case "":
|
||||||
|
allErrs = append(allErrs, field.Required(path.Child("terminationMessagePolicy"), "must be 'File' or 'FallbackToLogsOnError'"))
|
||||||
|
default:
|
||||||
|
allErrs = append(allErrs, field.Invalid(path.Child("terminationMessagePolicy"), ctr.TerminationMessagePolicy, "must be 'File' or 'FallbackToLogsOnError'"))
|
||||||
|
}
|
||||||
|
|
||||||
|
volMounts := GetVolumeMountMap(ctr.VolumeMounts)
|
||||||
|
volDevices := GetVolumeDeviceMap(ctr.VolumeDevices)
|
||||||
|
allErrs = append(allErrs, validateProbe(ctr.ReadinessProbe, path.Child("readinessProbe"))...)
|
||||||
|
allErrs = append(allErrs, validateContainerPorts(ctr.Ports, path.Child("ports"))...)
|
||||||
|
allErrs = append(allErrs, ValidateEnv(ctr.Env, path.Child("env"), opts)...)
|
||||||
|
allErrs = append(allErrs, ValidateEnvFrom(ctr.EnvFrom, path.Child("envFrom"))...)
|
||||||
|
allErrs = append(allErrs, ValidateVolumeMounts(ctr.VolumeMounts, volDevices, volumes, ctr, path.Child("volumeMounts"))...)
|
||||||
|
allErrs = append(allErrs, ValidateVolumeDevices(ctr.VolumeDevices, volMounts, volumes, path.Child("volumeDevices"))...)
|
||||||
|
allErrs = append(allErrs, validatePullPolicy(ctr.ImagePullPolicy, path.Child("imagePullPolicy"))...)
|
||||||
|
allErrs = append(allErrs, ValidateResourceRequirements(&ctr.Resources, path.Child("resources"), opts)...)
|
||||||
|
allErrs = append(allErrs, ValidateSecurityContext(ctr.SecurityContext, path.Child("securityContext"))...)
|
||||||
|
|
||||||
|
return allErrs
|
||||||
|
}
|
||||||
|
|
||||||
|
func validateContainers(containers []core.Container, volumes map[string]core.VolumeSource, fldPath *field.Path, opts PodValidationOptions) field.ErrorList {
|
||||||
allErrs := field.ErrorList{}
|
allErrs := field.ErrorList{}
|
||||||
|
|
||||||
if len(containers) == 0 {
|
if len(containers) == 0 {
|
||||||
@ -3037,73 +3095,18 @@ func validateContainers(containers []core.Container, isInitContainers bool, volu
|
|||||||
allNames := sets.String{}
|
allNames := sets.String{}
|
||||||
for i, ctr := range containers {
|
for i, ctr := range containers {
|
||||||
idxPath := fldPath.Index(i)
|
idxPath := fldPath.Index(i)
|
||||||
namePath := idxPath.Child("name")
|
|
||||||
volMounts := GetVolumeMountMap(ctr.VolumeMounts)
|
|
||||||
volDevices := GetVolumeDeviceMap(ctr.VolumeDevices)
|
|
||||||
|
|
||||||
if len(ctr.Name) == 0 {
|
|
||||||
allErrs = append(allErrs, field.Required(namePath, ""))
|
|
||||||
} else {
|
|
||||||
allErrs = append(allErrs, ValidateDNS1123Label(ctr.Name, namePath)...)
|
|
||||||
}
|
|
||||||
if allNames.Has(ctr.Name) {
|
if allNames.Has(ctr.Name) {
|
||||||
allErrs = append(allErrs, field.Duplicate(namePath, ctr.Name))
|
allErrs = append(allErrs, field.Duplicate(idxPath.Child("name"), ctr.Name))
|
||||||
} else {
|
} else {
|
||||||
allNames.Insert(ctr.Name)
|
allNames.Insert(ctr.Name)
|
||||||
}
|
}
|
||||||
// TODO: do not validate leading and trailing whitespace to preserve backward compatibility.
|
|
||||||
// for example: https://github.com/openshift/origin/issues/14659 image = " " is special token in pod template
|
|
||||||
// others may have done similar
|
|
||||||
if len(ctr.Image) == 0 {
|
|
||||||
allErrs = append(allErrs, field.Required(idxPath.Child("image"), ""))
|
|
||||||
}
|
|
||||||
if ctr.Lifecycle != nil {
|
|
||||||
allErrs = append(allErrs, validateLifecycle(ctr.Lifecycle, idxPath.Child("lifecycle"))...)
|
|
||||||
}
|
|
||||||
allErrs = append(allErrs, validateProbe(ctr.LivenessProbe, idxPath.Child("livenessProbe"))...)
|
|
||||||
// Readiness-specific validation
|
|
||||||
if ctr.ReadinessProbe != nil && ctr.ReadinessProbe.TerminationGracePeriodSeconds != nil {
|
|
||||||
allErrs = append(allErrs, field.Invalid(idxPath.Child("readinessProbe", "terminationGracePeriodSeconds"), ctr.ReadinessProbe.TerminationGracePeriodSeconds, "must not be set for readinessProbes"))
|
|
||||||
}
|
|
||||||
allErrs = append(allErrs, validateProbe(ctr.StartupProbe, idxPath.Child("startupProbe"))...)
|
|
||||||
// Liveness-specific validation
|
|
||||||
if ctr.LivenessProbe != nil && ctr.LivenessProbe.SuccessThreshold != 1 {
|
|
||||||
allErrs = append(allErrs, field.Invalid(idxPath.Child("livenessProbe", "successThreshold"), ctr.LivenessProbe.SuccessThreshold, "must be 1"))
|
|
||||||
}
|
|
||||||
allErrs = append(allErrs, validateProbe(ctr.StartupProbe, idxPath.Child("startupProbe"))...)
|
|
||||||
// Startup-specific validation
|
|
||||||
if ctr.StartupProbe != nil && ctr.StartupProbe.SuccessThreshold != 1 {
|
|
||||||
allErrs = append(allErrs, field.Invalid(idxPath.Child("startupProbe", "successThreshold"), ctr.StartupProbe.SuccessThreshold, "must be 1"))
|
|
||||||
}
|
|
||||||
|
|
||||||
switch ctr.TerminationMessagePolicy {
|
allErrs = append(allErrs, validateContainer(&ctr, volumes, idxPath, opts)...)
|
||||||
case core.TerminationMessageReadFile, core.TerminationMessageFallbackToLogsOnError:
|
|
||||||
case "":
|
|
||||||
allErrs = append(allErrs, field.Required(idxPath.Child("terminationMessagePolicy"), "must be 'File' or 'FallbackToLogsOnError'"))
|
|
||||||
default:
|
|
||||||
allErrs = append(allErrs, field.Invalid(idxPath.Child("terminationMessagePolicy"), ctr.TerminationMessagePolicy, "must be 'File' or 'FallbackToLogsOnError'"))
|
|
||||||
}
|
|
||||||
|
|
||||||
allErrs = append(allErrs, validateProbe(ctr.ReadinessProbe, idxPath.Child("readinessProbe"))...)
|
|
||||||
allErrs = append(allErrs, validateContainerPorts(ctr.Ports, idxPath.Child("ports"))...)
|
|
||||||
allErrs = append(allErrs, ValidateEnv(ctr.Env, idxPath.Child("env"), opts)...)
|
|
||||||
allErrs = append(allErrs, ValidateEnvFrom(ctr.EnvFrom, idxPath.Child("envFrom"))...)
|
|
||||||
allErrs = append(allErrs, ValidateVolumeMounts(ctr.VolumeMounts, volDevices, volumes, &ctr, idxPath.Child("volumeMounts"))...)
|
|
||||||
allErrs = append(allErrs, ValidateVolumeDevices(ctr.VolumeDevices, volMounts, volumes, idxPath.Child("volumeDevices"))...)
|
|
||||||
allErrs = append(allErrs, validatePullPolicy(ctr.ImagePullPolicy, idxPath.Child("imagePullPolicy"))...)
|
|
||||||
allErrs = append(allErrs, ValidateResourceRequirements(&ctr.Resources, idxPath.Child("resources"), opts)...)
|
|
||||||
allErrs = append(allErrs, ValidateSecurityContext(ctr.SecurityContext, idxPath.Child("securityContext"))...)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if isInitContainers {
|
// Check for colliding ports across all containers.
|
||||||
// check initContainers one by one since they are running in sequential order.
|
allErrs = append(allErrs, checkHostPortConflicts(containers, fldPath)...)
|
||||||
for _, initContainer := range containers {
|
|
||||||
allErrs = append(allErrs, checkHostPortConflicts([]core.Container{initContainer}, fldPath)...)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Check for colliding ports across all containers.
|
|
||||||
allErrs = append(allErrs, checkHostPortConflicts(containers, fldPath)...)
|
|
||||||
}
|
|
||||||
|
|
||||||
return allErrs
|
return allErrs
|
||||||
}
|
}
|
||||||
@ -3393,10 +3396,15 @@ func ValidateTolerations(tolerations []core.Toleration, fldPath *field.Path) fie
|
|||||||
func validateContainersOnlyForPod(containers []core.Container, fldPath *field.Path) field.ErrorList {
|
func validateContainersOnlyForPod(containers []core.Container, fldPath *field.Path) field.ErrorList {
|
||||||
allErrs := field.ErrorList{}
|
allErrs := field.ErrorList{}
|
||||||
for i, ctr := range containers {
|
for i, ctr := range containers {
|
||||||
idxPath := fldPath.Index(i)
|
allErrs = append(allErrs, validateContainerOnlyForPod(&ctr, fldPath.Index(i))...)
|
||||||
if len(ctr.Image) != len(strings.TrimSpace(ctr.Image)) {
|
}
|
||||||
allErrs = append(allErrs, field.Invalid(idxPath.Child("image"), ctr.Image, "must not have leading or trailing whitespace"))
|
return allErrs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func validateContainerOnlyForPod(ctr *core.Container, path *field.Path) field.ErrorList {
|
||||||
|
allErrs := field.ErrorList{}
|
||||||
|
if len(ctr.Image) != len(strings.TrimSpace(ctr.Image)) {
|
||||||
|
allErrs = append(allErrs, field.Invalid(path.Child("image"), ctr.Image, "must not have leading or trailing whitespace"))
|
||||||
}
|
}
|
||||||
return allErrs
|
return allErrs
|
||||||
}
|
}
|
||||||
@ -3503,7 +3511,7 @@ func ValidatePodSpec(spec *core.PodSpec, podMeta *metav1.ObjectMeta, fldPath *fi
|
|||||||
|
|
||||||
vols, vErrs := ValidateVolumes(spec.Volumes, podMeta, fldPath.Child("volumes"), opts)
|
vols, vErrs := ValidateVolumes(spec.Volumes, podMeta, fldPath.Child("volumes"), opts)
|
||||||
allErrs = append(allErrs, vErrs...)
|
allErrs = append(allErrs, vErrs...)
|
||||||
allErrs = append(allErrs, validateContainers(spec.Containers, false, vols, fldPath.Child("containers"), opts)...)
|
allErrs = append(allErrs, validateContainers(spec.Containers, vols, fldPath.Child("containers"), opts)...)
|
||||||
allErrs = append(allErrs, validateInitContainers(spec.InitContainers, spec.Containers, vols, fldPath.Child("initContainers"), opts)...)
|
allErrs = append(allErrs, validateInitContainers(spec.InitContainers, spec.Containers, vols, fldPath.Child("initContainers"), opts)...)
|
||||||
allErrs = append(allErrs, validateEphemeralContainers(spec.EphemeralContainers, spec.Containers, spec.InitContainers, vols, fldPath.Child("ephemeralContainers"), opts)...)
|
allErrs = append(allErrs, validateEphemeralContainers(spec.EphemeralContainers, spec.Containers, spec.InitContainers, vols, fldPath.Child("ephemeralContainers"), opts)...)
|
||||||
allErrs = append(allErrs, validateRestartPolicy(&spec.RestartPolicy, fldPath.Child("restartPolicy"))...)
|
allErrs = append(allErrs, validateRestartPolicy(&spec.RestartPolicy, fldPath.Child("restartPolicy"))...)
|
||||||
|
@ -6747,28 +6747,28 @@ func TestValidateEphemeralContainers(t *testing.T) {
|
|||||||
[]core.EphemeralContainer{
|
[]core.EphemeralContainer{
|
||||||
{EphemeralContainerCommon: core.EphemeralContainerCommon{}},
|
{EphemeralContainerCommon: core.EphemeralContainerCommon{}},
|
||||||
},
|
},
|
||||||
field.Error{Type: field.ErrorTypeRequired, Field: "ephemeralContainers[0]"},
|
field.Error{Type: field.ErrorTypeRequired, Field: "ephemeralContainers[0].name"},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"empty Container Name",
|
"empty Container Name",
|
||||||
[]core.EphemeralContainer{
|
[]core.EphemeralContainer{
|
||||||
{EphemeralContainerCommon: core.EphemeralContainerCommon{Name: "", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}},
|
{EphemeralContainerCommon: core.EphemeralContainerCommon{Name: "", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}},
|
||||||
},
|
},
|
||||||
field.Error{Type: field.ErrorTypeRequired, Field: "ephemeralContainers[0]"},
|
field.Error{Type: field.ErrorTypeRequired, Field: "ephemeralContainers[0].name"},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"whitespace padded image name",
|
"whitespace padded image name",
|
||||||
[]core.EphemeralContainer{
|
[]core.EphemeralContainer{
|
||||||
{EphemeralContainerCommon: core.EphemeralContainerCommon{Name: "debug", Image: " image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}},
|
{EphemeralContainerCommon: core.EphemeralContainerCommon{Name: "debug", Image: " image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}},
|
||||||
},
|
},
|
||||||
field.Error{Type: field.ErrorTypeInvalid, Field: "ephemeralContainers[0][0].image"},
|
field.Error{Type: field.ErrorTypeInvalid, Field: "ephemeralContainers[0].image"},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"invalid image pull policy",
|
"invalid image pull policy",
|
||||||
[]core.EphemeralContainer{
|
[]core.EphemeralContainer{
|
||||||
{EphemeralContainerCommon: core.EphemeralContainerCommon{Name: "debug", Image: "image", ImagePullPolicy: "PullThreeTimes", TerminationMessagePolicy: "File"}},
|
{EphemeralContainerCommon: core.EphemeralContainerCommon{Name: "debug", Image: "image", ImagePullPolicy: "PullThreeTimes", TerminationMessagePolicy: "File"}},
|
||||||
},
|
},
|
||||||
field.Error{Type: field.ErrorTypeNotSupported, Field: "ephemeralContainers[0][0].imagePullPolicy"},
|
field.Error{Type: field.ErrorTypeNotSupported, Field: "ephemeralContainers[0].imagePullPolicy"},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"TargetContainerName doesn't exist",
|
"TargetContainerName doesn't exist",
|
||||||
@ -7218,7 +7218,7 @@ func TestValidateContainers(t *testing.T) {
|
|||||||
TerminationMessagePolicy: "File",
|
TerminationMessagePolicy: "File",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
if errs := validateContainers(successCase, false, volumeDevices, field.NewPath("field"), PodValidationOptions{}); len(errs) != 0 {
|
if errs := validateContainers(successCase, volumeDevices, field.NewPath("field"), PodValidationOptions{}); len(errs) != 0 {
|
||||||
t.Errorf("expected success: %v", errs)
|
t.Errorf("expected success: %v", errs)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -7704,7 +7704,7 @@ func TestValidateContainers(t *testing.T) {
|
|||||||
}
|
}
|
||||||
for _, tc := range errorCases {
|
for _, tc := range errorCases {
|
||||||
t.Run(tc.title, func(t *testing.T) {
|
t.Run(tc.title, func(t *testing.T) {
|
||||||
errs := validateContainers(tc.containers, false, volumeDevices, field.NewPath("containers"), PodValidationOptions{})
|
errs := validateContainers(tc.containers, volumeDevices, field.NewPath("containers"), PodValidationOptions{})
|
||||||
if len(errs) == 0 {
|
if len(errs) == 0 {
|
||||||
t.Fatalf("expected error but received none")
|
t.Fatalf("expected error but received none")
|
||||||
}
|
}
|
||||||
@ -7798,27 +7798,24 @@ func TestValidateInitContainers(t *testing.T) {
|
|||||||
},
|
},
|
||||||
field.Error{Type: field.ErrorTypeInvalid, Field: "initContainers[0].terminationMessagePolicy"},
|
field.Error{Type: field.ErrorTypeInvalid, Field: "initContainers[0].terminationMessagePolicy"},
|
||||||
},
|
},
|
||||||
/*
|
{
|
||||||
TODO: Validation incorrectly returns duplicate errors for duplicate names.
|
"duplicate names",
|
||||||
|
[]core.Container{
|
||||||
{
|
{
|
||||||
"duplicate names",
|
Name: "init",
|
||||||
[]core.Container{
|
Image: "image",
|
||||||
{
|
ImagePullPolicy: "IfNotPresent",
|
||||||
Name: "init",
|
TerminationMessagePolicy: "File",
|
||||||
Image: "image",
|
|
||||||
ImagePullPolicy: "IfNotPresent",
|
|
||||||
TerminationMessagePolicy: "File",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: "init",
|
|
||||||
Image: "image",
|
|
||||||
ImagePullPolicy: "IfNotPresent",
|
|
||||||
TerminationMessagePolicy: "File",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
field.Error{Type: field.ErrorTypeDuplicate, Field: "initContainers[1].name"},
|
|
||||||
},
|
},
|
||||||
*/
|
{
|
||||||
|
Name: "init",
|
||||||
|
Image: "image",
|
||||||
|
ImagePullPolicy: "IfNotPresent",
|
||||||
|
TerminationMessagePolicy: "File",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
field.Error{Type: field.ErrorTypeDuplicate, Field: "initContainers[1].name"},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"duplicate ports",
|
"duplicate ports",
|
||||||
[]core.Container{
|
[]core.Container{
|
||||||
|
Loading…
Reference in New Issue
Block a user