mirror of
https://github.com/k3s-io/kubernetes.git
synced 2026-01-06 16:06:51 +00:00
Downward API hugepages
This commit is contained in:
@@ -497,3 +497,38 @@ func PersistentVolumeClaimHasClass(claim *core.PersistentVolumeClaim) bool {
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func toResourceNames(resources core.ResourceList) []core.ResourceName {
|
||||
result := []core.ResourceName{}
|
||||
for resourceName := range resources {
|
||||
result = append(result, resourceName)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func toSet(resourceNames []core.ResourceName) sets.String {
|
||||
result := sets.NewString()
|
||||
for _, resourceName := range resourceNames {
|
||||
result.Insert(string(resourceName))
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// toContainerResourcesSet returns a set of resources names in container resource requirements
|
||||
func toContainerResourcesSet(ctr *core.Container) sets.String {
|
||||
resourceNames := toResourceNames(ctr.Resources.Requests)
|
||||
resourceNames = append(resourceNames, toResourceNames(ctr.Resources.Limits)...)
|
||||
return toSet(resourceNames)
|
||||
}
|
||||
|
||||
// ToPodResourcesSet returns a set of resource names in all containers in a pod.
|
||||
func ToPodResourcesSet(podSpec *core.PodSpec) sets.String {
|
||||
result := sets.NewString()
|
||||
for i := range podSpec.InitContainers {
|
||||
result = result.Union(toContainerResourcesSet(&podSpec.InitContainers[i]))
|
||||
}
|
||||
for i := range podSpec.Containers {
|
||||
result = result.Union(toContainerResourcesSet(&podSpec.Containers[i]))
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
@@ -26,40 +26,33 @@ func (rn ResourceName) String() string {
|
||||
|
||||
// CPU returns the CPU limit if specified.
|
||||
func (rl *ResourceList) CPU() *resource.Quantity {
|
||||
if val, ok := (*rl)[ResourceCPU]; ok {
|
||||
return &val
|
||||
}
|
||||
return &resource.Quantity{Format: resource.DecimalSI}
|
||||
return rl.Name(ResourceCPU, resource.DecimalSI)
|
||||
}
|
||||
|
||||
// Memory returns the Memory limit if specified.
|
||||
func (rl *ResourceList) Memory() *resource.Quantity {
|
||||
if val, ok := (*rl)[ResourceMemory]; ok {
|
||||
return &val
|
||||
}
|
||||
return &resource.Quantity{Format: resource.BinarySI}
|
||||
return rl.Name(ResourceMemory, resource.BinarySI)
|
||||
}
|
||||
|
||||
// Storage returns the Storage limit if specified.
|
||||
func (rl *ResourceList) Storage() *resource.Quantity {
|
||||
if val, ok := (*rl)[ResourceStorage]; ok {
|
||||
return &val
|
||||
}
|
||||
return &resource.Quantity{Format: resource.BinarySI}
|
||||
return rl.Name(ResourceStorage, resource.BinarySI)
|
||||
}
|
||||
|
||||
// Pods returns the list of pods
|
||||
func (rl *ResourceList) Pods() *resource.Quantity {
|
||||
if val, ok := (*rl)[ResourcePods]; ok {
|
||||
return &val
|
||||
}
|
||||
return &resource.Quantity{}
|
||||
return rl.Name(ResourcePods, resource.DecimalSI)
|
||||
}
|
||||
|
||||
// StorageEphemeral returns the list of ephemeral storage volumes, if any
|
||||
func (rl *ResourceList) StorageEphemeral() *resource.Quantity {
|
||||
if val, ok := (*rl)[ResourceEphemeralStorage]; ok {
|
||||
return rl.Name(ResourceEphemeralStorage, resource.BinarySI)
|
||||
}
|
||||
|
||||
// Name returns the resource with name if specified, otherwise it returns a nil quantity with default format.
|
||||
func (rl *ResourceList) Name(name ResourceName, defaultFormat resource.Format) *resource.Quantity {
|
||||
if val, ok := (*rl)[name]; ok {
|
||||
return &val
|
||||
}
|
||||
return &resource.Quantity{}
|
||||
return &resource.Quantity{Format: defaultFormat}
|
||||
}
|
||||
|
||||
@@ -350,7 +350,7 @@ func ValidateObjectMetaUpdate(newMeta, oldMeta *metav1.ObjectMeta, fldPath *fiel
|
||||
return allErrs
|
||||
}
|
||||
|
||||
func ValidateVolumes(volumes []core.Volume, podMeta *metav1.ObjectMeta, fldPath *field.Path) (map[string]core.VolumeSource, field.ErrorList) {
|
||||
func ValidateVolumes(volumes []core.Volume, podMeta *metav1.ObjectMeta, fldPath *field.Path, opts PodValidationOptions) (map[string]core.VolumeSource, field.ErrorList) {
|
||||
allErrs := field.ErrorList{}
|
||||
|
||||
allNames := sets.String{}
|
||||
@@ -369,7 +369,7 @@ func ValidateVolumes(volumes []core.Volume, podMeta *metav1.ObjectMeta, fldPath
|
||||
for i, vol := range volumes {
|
||||
idxPath := fldPath.Index(i)
|
||||
namePath := idxPath.Child("name")
|
||||
el := validateVolumeSource(&vol.VolumeSource, idxPath, vol.Name, podMeta)
|
||||
el := validateVolumeSource(&vol.VolumeSource, idxPath, vol.Name, podMeta, opts)
|
||||
if len(vol.Name) == 0 {
|
||||
el = append(el, field.Required(namePath, ""))
|
||||
} else {
|
||||
@@ -446,7 +446,7 @@ func devicePathAlreadyExists(devicePath string, mounts map[string]string) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func validateVolumeSource(source *core.VolumeSource, fldPath *field.Path, volName string, podMeta *metav1.ObjectMeta) field.ErrorList {
|
||||
func validateVolumeSource(source *core.VolumeSource, fldPath *field.Path, volName string, podMeta *metav1.ObjectMeta, opts PodValidationOptions) field.ErrorList {
|
||||
numVolumes := 0
|
||||
allErrs := field.ErrorList{}
|
||||
if source.EmptyDir != nil {
|
||||
@@ -576,7 +576,7 @@ func validateVolumeSource(source *core.VolumeSource, fldPath *field.Path, volNam
|
||||
allErrs = append(allErrs, field.Forbidden(fldPath.Child("downwarAPI"), "may not specify more than 1 volume type"))
|
||||
} else {
|
||||
numVolumes++
|
||||
allErrs = append(allErrs, validateDownwardAPIVolumeSource(source.DownwardAPI, fldPath.Child("downwardAPI"))...)
|
||||
allErrs = append(allErrs, validateDownwardAPIVolumeSource(source.DownwardAPI, fldPath.Child("downwardAPI"), opts)...)
|
||||
}
|
||||
}
|
||||
if source.FC != nil {
|
||||
@@ -658,7 +658,7 @@ func validateVolumeSource(source *core.VolumeSource, fldPath *field.Path, volNam
|
||||
allErrs = append(allErrs, field.Forbidden(fldPath.Child("projected"), "may not specify more than 1 volume type"))
|
||||
} else {
|
||||
numVolumes++
|
||||
allErrs = append(allErrs, validateProjectedVolumeSource(source.Projected, fldPath.Child("projected"))...)
|
||||
allErrs = append(allErrs, validateProjectedVolumeSource(source.Projected, fldPath.Child("projected"), opts)...)
|
||||
}
|
||||
}
|
||||
if source.ScaleIO != nil {
|
||||
@@ -1007,9 +1007,8 @@ var validVolumeDownwardAPIFieldPathExpressions = sets.NewString(
|
||||
"metadata.annotations",
|
||||
"metadata.uid")
|
||||
|
||||
func validateDownwardAPIVolumeFile(file *core.DownwardAPIVolumeFile, fldPath *field.Path) field.ErrorList {
|
||||
func validateDownwardAPIVolumeFile(file *core.DownwardAPIVolumeFile, fldPath *field.Path, opts PodValidationOptions) field.ErrorList {
|
||||
allErrs := field.ErrorList{}
|
||||
|
||||
if len(file.Path) == 0 {
|
||||
allErrs = append(allErrs, field.Required(fldPath.Child("path"), ""))
|
||||
}
|
||||
@@ -1020,7 +1019,11 @@ func validateDownwardAPIVolumeFile(file *core.DownwardAPIVolumeFile, fldPath *fi
|
||||
allErrs = append(allErrs, field.Invalid(fldPath, "resource", "fieldRef and resourceFieldRef can not be specified simultaneously"))
|
||||
}
|
||||
} else if file.ResourceFieldRef != nil {
|
||||
allErrs = append(allErrs, validateContainerResourceFieldSelector(file.ResourceFieldRef, &validContainerResourceFieldPathExpressions, fldPath.Child("resourceFieldRef"), true)...)
|
||||
localValidContainerResourceFieldPathPrefixes := validContainerResourceFieldPathPrefixes
|
||||
if opts.AllowDownwardAPIHugePages {
|
||||
localValidContainerResourceFieldPathPrefixes = validContainerResourceFieldPathPrefixesWithDownwardAPIHugePages
|
||||
}
|
||||
allErrs = append(allErrs, validateContainerResourceFieldSelector(file.ResourceFieldRef, &validContainerResourceFieldPathExpressions, &localValidContainerResourceFieldPathPrefixes, fldPath.Child("resourceFieldRef"), true)...)
|
||||
} else {
|
||||
allErrs = append(allErrs, field.Required(fldPath, "one of fieldRef and resourceFieldRef is required"))
|
||||
}
|
||||
@@ -1031,7 +1034,7 @@ func validateDownwardAPIVolumeFile(file *core.DownwardAPIVolumeFile, fldPath *fi
|
||||
return allErrs
|
||||
}
|
||||
|
||||
func validateDownwardAPIVolumeSource(downwardAPIVolume *core.DownwardAPIVolumeSource, fldPath *field.Path) field.ErrorList {
|
||||
func validateDownwardAPIVolumeSource(downwardAPIVolume *core.DownwardAPIVolumeSource, fldPath *field.Path, opts PodValidationOptions) field.ErrorList {
|
||||
allErrs := field.ErrorList{}
|
||||
|
||||
downwardAPIMode := downwardAPIVolume.DefaultMode
|
||||
@@ -1040,12 +1043,12 @@ func validateDownwardAPIVolumeSource(downwardAPIVolume *core.DownwardAPIVolumeSo
|
||||
}
|
||||
|
||||
for _, file := range downwardAPIVolume.Items {
|
||||
allErrs = append(allErrs, validateDownwardAPIVolumeFile(&file, fldPath)...)
|
||||
allErrs = append(allErrs, validateDownwardAPIVolumeFile(&file, fldPath, opts)...)
|
||||
}
|
||||
return allErrs
|
||||
}
|
||||
|
||||
func validateProjectionSources(projection *core.ProjectedVolumeSource, projectionMode *int32, fldPath *field.Path) field.ErrorList {
|
||||
func validateProjectionSources(projection *core.ProjectedVolumeSource, projectionMode *int32, fldPath *field.Path, opts PodValidationOptions) field.ErrorList {
|
||||
allErrs := field.ErrorList{}
|
||||
allPaths := sets.String{}
|
||||
|
||||
@@ -1093,7 +1096,7 @@ func validateProjectionSources(projection *core.ProjectedVolumeSource, projectio
|
||||
if projPath := srcPath.Child("downwardAPI"); source.DownwardAPI != nil {
|
||||
numSources++
|
||||
for _, file := range source.DownwardAPI.Items {
|
||||
allErrs = append(allErrs, validateDownwardAPIVolumeFile(&file, projPath)...)
|
||||
allErrs = append(allErrs, validateDownwardAPIVolumeFile(&file, projPath, opts)...)
|
||||
if len(file.Path) > 0 {
|
||||
curPath := file.Path
|
||||
if !allPaths.Has(curPath) {
|
||||
@@ -1123,7 +1126,7 @@ func validateProjectionSources(projection *core.ProjectedVolumeSource, projectio
|
||||
return allErrs
|
||||
}
|
||||
|
||||
func validateProjectedVolumeSource(projection *core.ProjectedVolumeSource, fldPath *field.Path) field.ErrorList {
|
||||
func validateProjectedVolumeSource(projection *core.ProjectedVolumeSource, fldPath *field.Path, opts PodValidationOptions) field.ErrorList {
|
||||
allErrs := field.ErrorList{}
|
||||
|
||||
projectionMode := projection.DefaultMode
|
||||
@@ -1131,7 +1134,7 @@ func validateProjectedVolumeSource(projection *core.ProjectedVolumeSource, fldPa
|
||||
allErrs = append(allErrs, field.Invalid(fldPath.Child("defaultMode"), *projectionMode, fileModeErrorMsg))
|
||||
}
|
||||
|
||||
allErrs = append(allErrs, validateProjectionSources(projection, projectionMode, fldPath)...)
|
||||
allErrs = append(allErrs, validateProjectionSources(projection, projectionMode, fldPath, opts)...)
|
||||
return allErrs
|
||||
}
|
||||
|
||||
@@ -2138,7 +2141,7 @@ func validateContainerPorts(ports []core.ContainerPort, fldPath *field.Path) fie
|
||||
}
|
||||
|
||||
// ValidateEnv validates env vars
|
||||
func ValidateEnv(vars []core.EnvVar, fldPath *field.Path) field.ErrorList {
|
||||
func ValidateEnv(vars []core.EnvVar, fldPath *field.Path, opts PodValidationOptions) field.ErrorList {
|
||||
allErrs := field.ErrorList{}
|
||||
|
||||
for i, ev := range vars {
|
||||
@@ -2150,7 +2153,7 @@ func ValidateEnv(vars []core.EnvVar, fldPath *field.Path) field.ErrorList {
|
||||
allErrs = append(allErrs, field.Invalid(idxPath.Child("name"), ev.Name, msg))
|
||||
}
|
||||
}
|
||||
allErrs = append(allErrs, validateEnvVarValueFrom(ev, idxPath.Child("valueFrom"))...)
|
||||
allErrs = append(allErrs, validateEnvVarValueFrom(ev, idxPath.Child("valueFrom"), opts)...)
|
||||
}
|
||||
return allErrs
|
||||
}
|
||||
@@ -2166,9 +2169,17 @@ var validEnvDownwardAPIFieldPathExpressions = sets.NewString(
|
||||
// status.podIPs is populated even if IPv6DualStack feature gate
|
||||
// is not enabled. This will work for single stack and dual stack.
|
||||
"status.podIPs")
|
||||
|
||||
var validContainerResourceFieldPathExpressions = sets.NewString("limits.cpu", "limits.memory", "limits.ephemeral-storage", "requests.cpu", "requests.memory", "requests.ephemeral-storage")
|
||||
|
||||
func validateEnvVarValueFrom(ev core.EnvVar, fldPath *field.Path) field.ErrorList {
|
||||
// NOTE: this is only valid with DownwardAPIHugePages enabled
|
||||
var validContainerResourceFieldPathPrefixes = sets.NewString()
|
||||
var validContainerResourceFieldPathPrefixesWithDownwardAPIHugePages = sets.NewString(hugepagesRequestsPrefixDownwardAPI, hugepagesLimitsPrefixDownwardAPI)
|
||||
|
||||
const hugepagesRequestsPrefixDownwardAPI string = `requests.hugepages-`
|
||||
const hugepagesLimitsPrefixDownwardAPI string = `limits.hugepages-`
|
||||
|
||||
func validateEnvVarValueFrom(ev core.EnvVar, fldPath *field.Path, opts PodValidationOptions) field.ErrorList {
|
||||
allErrs := field.ErrorList{}
|
||||
|
||||
if ev.ValueFrom == nil {
|
||||
@@ -2183,7 +2194,11 @@ func validateEnvVarValueFrom(ev core.EnvVar, fldPath *field.Path) field.ErrorLis
|
||||
}
|
||||
if ev.ValueFrom.ResourceFieldRef != nil {
|
||||
numSources++
|
||||
allErrs = append(allErrs, validateContainerResourceFieldSelector(ev.ValueFrom.ResourceFieldRef, &validContainerResourceFieldPathExpressions, fldPath.Child("resourceFieldRef"), false)...)
|
||||
localValidContainerResourceFieldPathPrefixes := validContainerResourceFieldPathPrefixes
|
||||
if opts.AllowDownwardAPIHugePages {
|
||||
localValidContainerResourceFieldPathPrefixes = validContainerResourceFieldPathPrefixesWithDownwardAPIHugePages
|
||||
}
|
||||
allErrs = append(allErrs, validateContainerResourceFieldSelector(ev.ValueFrom.ResourceFieldRef, &validContainerResourceFieldPathExpressions, &localValidContainerResourceFieldPathPrefixes, fldPath.Child("resourceFieldRef"), false)...)
|
||||
}
|
||||
if ev.ValueFrom.ConfigMapKeyRef != nil {
|
||||
numSources++
|
||||
@@ -2246,7 +2261,7 @@ func validateObjectFieldSelector(fs *core.ObjectFieldSelector, expressions *sets
|
||||
return allErrs
|
||||
}
|
||||
|
||||
func validateContainerResourceFieldSelector(fs *core.ResourceFieldSelector, expressions *sets.String, fldPath *field.Path, volume bool) field.ErrorList {
|
||||
func validateContainerResourceFieldSelector(fs *core.ResourceFieldSelector, expressions *sets.String, prefixes *sets.String, fldPath *field.Path, volume bool) field.ErrorList {
|
||||
allErrs := field.ErrorList{}
|
||||
|
||||
if volume && len(fs.ContainerName) == 0 {
|
||||
@@ -2254,7 +2269,18 @@ func validateContainerResourceFieldSelector(fs *core.ResourceFieldSelector, expr
|
||||
} else if len(fs.Resource) == 0 {
|
||||
allErrs = append(allErrs, field.Required(fldPath.Child("resource"), ""))
|
||||
} else if !expressions.Has(fs.Resource) {
|
||||
allErrs = append(allErrs, field.NotSupported(fldPath.Child("resource"), fs.Resource, expressions.List()))
|
||||
// check if the prefix is present
|
||||
foundPrefix := false
|
||||
if prefixes != nil {
|
||||
for _, prefix := range prefixes.List() {
|
||||
if strings.HasPrefix(fs.Resource, prefix) {
|
||||
foundPrefix = true
|
||||
}
|
||||
}
|
||||
}
|
||||
if !foundPrefix {
|
||||
allErrs = append(allErrs, field.NotSupported(fldPath.Child("resource"), fs.Resource, expressions.List()))
|
||||
}
|
||||
}
|
||||
allErrs = append(allErrs, validateContainerResourceDivisor(fs.Resource, fs.Divisor, fldPath)...)
|
||||
return allErrs
|
||||
@@ -2315,6 +2341,7 @@ func validateSecretEnvSource(secretSource *core.SecretEnvSource, fldPath *field.
|
||||
|
||||
var validContainerResourceDivisorForCPU = sets.NewString("1m", "1")
|
||||
var validContainerResourceDivisorForMemory = sets.NewString("1", "1k", "1M", "1G", "1T", "1P", "1E", "1Ki", "1Mi", "1Gi", "1Ti", "1Pi", "1Ei")
|
||||
var validContainerResourceDivisorForHugePages = sets.NewString("1", "1k", "1M", "1G", "1T", "1P", "1E", "1Ki", "1Mi", "1Gi", "1Ti", "1Pi", "1Ei")
|
||||
var validContainerResourceDivisorForEphemeralStorage = sets.NewString("1", "1k", "1M", "1G", "1T", "1P", "1E", "1Ki", "1Mi", "1Gi", "1Ti", "1Pi", "1Ei")
|
||||
|
||||
func validateContainerResourceDivisor(rName string, divisor resource.Quantity, fldPath *field.Path) field.ErrorList {
|
||||
@@ -2337,6 +2364,11 @@ func validateContainerResourceDivisor(rName string, divisor resource.Quantity, f
|
||||
allErrs = append(allErrs, field.Invalid(fldPath.Child("divisor"), rName, "only divisor's values 1, 1k, 1M, 1G, 1T, 1P, 1E, 1Ki, 1Mi, 1Gi, 1Ti, 1Pi, 1Ei are supported with the local ephemeral storage resource"))
|
||||
}
|
||||
}
|
||||
if strings.HasPrefix(rName, hugepagesRequestsPrefixDownwardAPI) || strings.HasPrefix(rName, hugepagesLimitsPrefixDownwardAPI) {
|
||||
if !validContainerResourceDivisorForHugePages.Has(divisor.String()) {
|
||||
allErrs = append(allErrs, field.Invalid(fldPath.Child("divisor"), rName, "only divisor's values 1, 1k, 1M, 1G, 1T, 1P, 1E, 1Ki, 1Mi, 1Gi, 1Ti, 1Pi, 1Ei are supported with the hugepages resource"))
|
||||
}
|
||||
}
|
||||
return allErrs
|
||||
}
|
||||
|
||||
@@ -2674,7 +2706,7 @@ func validatePullPolicy(policy core.PullPolicy, fldPath *field.Path) field.Error
|
||||
return allErrors
|
||||
}
|
||||
|
||||
func validateEphemeralContainers(ephemeralContainers []core.EphemeralContainer, containers, initContainers []core.Container, volumes map[string]core.VolumeSource, fldPath *field.Path) field.ErrorList {
|
||||
func validateEphemeralContainers(ephemeralContainers []core.EphemeralContainer, containers, initContainers []core.Container, volumes map[string]core.VolumeSource, fldPath *field.Path, opts PodValidationOptions) field.ErrorList {
|
||||
allErrs := field.ErrorList{}
|
||||
|
||||
if len(ephemeralContainers) == 0 {
|
||||
@@ -2706,7 +2738,7 @@ func validateEphemeralContainers(ephemeralContainers []core.EphemeralContainer,
|
||||
// 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)...)
|
||||
allErrs = append(allErrs, validateContainers([]core.Container{c}, false, volumes, idxPath, opts)...)
|
||||
// EphemeralContainers don't require the backwards-compatibility distinction between pod/podTemplate validation
|
||||
allErrs = append(allErrs, validateContainersOnlyForPod([]core.Container{c}, idxPath)...)
|
||||
|
||||
@@ -2748,10 +2780,10 @@ func validateFieldAllowList(value interface{}, allowedFields map[string]bool, er
|
||||
return allErrs
|
||||
}
|
||||
|
||||
func validateInitContainers(containers, otherContainers []core.Container, deviceVolumes map[string]core.VolumeSource, fldPath *field.Path) field.ErrorList {
|
||||
func validateInitContainers(containers, otherContainers []core.Container, deviceVolumes map[string]core.VolumeSource, fldPath *field.Path, opts PodValidationOptions) field.ErrorList {
|
||||
var allErrs field.ErrorList
|
||||
if len(containers) > 0 {
|
||||
allErrs = append(allErrs, validateContainers(containers, true, deviceVolumes, fldPath)...)
|
||||
allErrs = append(allErrs, validateContainers(containers, true, deviceVolumes, fldPath, opts)...)
|
||||
}
|
||||
|
||||
allNames := sets.String{}
|
||||
@@ -2782,7 +2814,7 @@ func validateInitContainers(containers, otherContainers []core.Container, device
|
||||
return allErrs
|
||||
}
|
||||
|
||||
func validateContainers(containers []core.Container, isInitContainers bool, volumes map[string]core.VolumeSource, fldPath *field.Path) field.ErrorList {
|
||||
func validateContainers(containers []core.Container, isInitContainers bool, volumes map[string]core.VolumeSource, fldPath *field.Path, opts PodValidationOptions) field.ErrorList {
|
||||
allErrs := field.ErrorList{}
|
||||
|
||||
if len(containers) == 0 {
|
||||
@@ -2836,7 +2868,7 @@ func validateContainers(containers []core.Container, isInitContainers bool, volu
|
||||
|
||||
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"))...)
|
||||
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"))...)
|
||||
@@ -3133,28 +3165,6 @@ func ValidateTolerations(tolerations []core.Toleration, fldPath *field.Path) fie
|
||||
return allErrors
|
||||
}
|
||||
|
||||
func toResourceNames(resources core.ResourceList) []core.ResourceName {
|
||||
result := []core.ResourceName{}
|
||||
for resourceName := range resources {
|
||||
result = append(result, resourceName)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func toSet(resourceNames []core.ResourceName) sets.String {
|
||||
result := sets.NewString()
|
||||
for _, resourceName := range resourceNames {
|
||||
result.Insert(string(resourceName))
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func toContainerResourcesSet(ctr *core.Container) sets.String {
|
||||
resourceNames := toResourceNames(ctr.Resources.Requests)
|
||||
resourceNames = append(resourceNames, toResourceNames(ctr.Resources.Limits)...)
|
||||
return toSet(resourceNames)
|
||||
}
|
||||
|
||||
// validateContainersOnlyForPod does additional validation for containers on a pod versus a pod template
|
||||
// it only does additive validation of fields not covered in validateContainers
|
||||
func validateContainersOnlyForPod(containers []core.Container, fldPath *field.Path) field.ErrorList {
|
||||
@@ -3172,19 +3182,19 @@ func validateContainersOnlyForPod(containers []core.Container, fldPath *field.Pa
|
||||
type PodValidationOptions struct {
|
||||
// Allow pod spec to have more than one huge page resource (with different sizes)
|
||||
AllowMultipleHugePageResources bool
|
||||
// Allow pod spec to use hugepages in downward API
|
||||
AllowDownwardAPIHugePages bool
|
||||
}
|
||||
|
||||
// ValidatePodSingleHugePageResources checks if there are multiple huge
|
||||
// pages resources in the pod object.
|
||||
func ValidatePodSingleHugePageResources(pod *core.Pod, specPath *field.Path) field.ErrorList {
|
||||
allErrs := field.ErrorList{}
|
||||
resourceSet := helper.ToPodResourcesSet(&pod.Spec)
|
||||
hugePageResources := sets.NewString()
|
||||
for i := range pod.Spec.Containers {
|
||||
resourceSet := toContainerResourcesSet(&pod.Spec.Containers[i])
|
||||
for resourceStr := range resourceSet {
|
||||
if v1helper.IsHugePageResourceName(v1.ResourceName(resourceStr)) {
|
||||
hugePageResources.Insert(resourceStr)
|
||||
}
|
||||
for resourceStr := range resourceSet {
|
||||
if v1helper.IsHugePageResourceName(v1.ResourceName(resourceStr)) {
|
||||
hugePageResources.Insert(resourceStr)
|
||||
}
|
||||
}
|
||||
if len(hugePageResources) > 1 {
|
||||
@@ -3199,7 +3209,7 @@ func validatePodMetadataAndSpec(pod *core.Pod, opts PodValidationOptions) field.
|
||||
fldPath := field.NewPath("metadata")
|
||||
allErrs := ValidateObjectMeta(&pod.ObjectMeta, true, ValidatePodName, fldPath)
|
||||
allErrs = append(allErrs, ValidatePodSpecificAnnotations(pod.ObjectMeta.Annotations, &pod.Spec, fldPath.Child("annotations"))...)
|
||||
allErrs = append(allErrs, ValidatePodSpec(&pod.Spec, &pod.ObjectMeta, field.NewPath("spec"))...)
|
||||
allErrs = append(allErrs, ValidatePodSpec(&pod.Spec, &pod.ObjectMeta, field.NewPath("spec"), opts)...)
|
||||
|
||||
// we do additional validation only pertinent for pods and not pod templates
|
||||
// this was done to preserve backwards compatibility
|
||||
@@ -3280,14 +3290,14 @@ func validatePodIPs(pod *core.Pod) field.ErrorList {
|
||||
// tricks.
|
||||
// The pod metadata is needed to validate generic ephemeral volumes. It is optional
|
||||
// and should be left empty unless the spec is from a real pod object.
|
||||
func ValidatePodSpec(spec *core.PodSpec, podMeta *metav1.ObjectMeta, fldPath *field.Path) field.ErrorList {
|
||||
func ValidatePodSpec(spec *core.PodSpec, podMeta *metav1.ObjectMeta, fldPath *field.Path, opts PodValidationOptions) field.ErrorList {
|
||||
allErrs := field.ErrorList{}
|
||||
|
||||
vols, vErrs := ValidateVolumes(spec.Volumes, podMeta, fldPath.Child("volumes"))
|
||||
vols, vErrs := ValidateVolumes(spec.Volumes, podMeta, fldPath.Child("volumes"), opts)
|
||||
allErrs = append(allErrs, vErrs...)
|
||||
allErrs = append(allErrs, validateContainers(spec.Containers, false, vols, fldPath.Child("containers"))...)
|
||||
allErrs = append(allErrs, validateInitContainers(spec.InitContainers, spec.Containers, vols, fldPath.Child("initContainers"))...)
|
||||
allErrs = append(allErrs, validateEphemeralContainers(spec.EphemeralContainers, spec.Containers, spec.InitContainers, vols, fldPath.Child("ephemeralContainers"))...)
|
||||
allErrs = append(allErrs, validateContainers(spec.Containers, false, vols, fldPath.Child("containers"), 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, validateRestartPolicy(&spec.RestartPolicy, fldPath.Child("restartPolicy"))...)
|
||||
allErrs = append(allErrs, validateDNSPolicy(&spec.DNSPolicy, fldPath.Child("dnsPolicy"))...)
|
||||
allErrs = append(allErrs, unversionedvalidation.ValidateLabels(spec.NodeSelector, fldPath.Child("nodeSelector"))...)
|
||||
@@ -4077,7 +4087,7 @@ func validatePodConditions(conditions []core.PodCondition, fldPath *field.Path)
|
||||
|
||||
// ValidatePodEphemeralContainersUpdate tests that a user update to EphemeralContainers is valid.
|
||||
// newPod and oldPod must only differ in their EphemeralContainers.
|
||||
func ValidatePodEphemeralContainersUpdate(newPod, oldPod *core.Pod) field.ErrorList {
|
||||
func ValidatePodEphemeralContainersUpdate(newPod, oldPod *core.Pod, opts PodValidationOptions) field.ErrorList {
|
||||
spec := newPod.Spec
|
||||
specPath := field.NewPath("spec").Child("ephemeralContainers")
|
||||
|
||||
@@ -4085,7 +4095,7 @@ func ValidatePodEphemeralContainersUpdate(newPod, oldPod *core.Pod) field.ErrorL
|
||||
for _, vol := range spec.Volumes {
|
||||
vols[vol.Name] = vol.VolumeSource
|
||||
}
|
||||
allErrs := validateEphemeralContainers(spec.EphemeralContainers, spec.Containers, spec.InitContainers, vols, specPath)
|
||||
allErrs := validateEphemeralContainers(spec.EphemeralContainers, spec.Containers, spec.InitContainers, vols, specPath, opts)
|
||||
|
||||
// Existing EphemeralContainers may not be changed. Order isn't preserved by patch, so check each individually.
|
||||
newContainerIndex := make(map[string]*core.EphemeralContainer)
|
||||
@@ -4121,17 +4131,17 @@ func ValidatePodBinding(binding *core.Binding) field.ErrorList {
|
||||
}
|
||||
|
||||
// ValidatePodTemplate tests if required fields in the pod template are set.
|
||||
func ValidatePodTemplate(pod *core.PodTemplate) field.ErrorList {
|
||||
func ValidatePodTemplate(pod *core.PodTemplate, opts PodValidationOptions) field.ErrorList {
|
||||
allErrs := ValidateObjectMeta(&pod.ObjectMeta, true, ValidatePodName, field.NewPath("metadata"))
|
||||
allErrs = append(allErrs, ValidatePodTemplateSpec(&pod.Template, field.NewPath("template"))...)
|
||||
allErrs = append(allErrs, ValidatePodTemplateSpec(&pod.Template, field.NewPath("template"), opts)...)
|
||||
return allErrs
|
||||
}
|
||||
|
||||
// ValidatePodTemplateUpdate tests to see if the update is legal for an end user to make. newPod is updated with fields
|
||||
// that cannot be changed.
|
||||
func ValidatePodTemplateUpdate(newPod, oldPod *core.PodTemplate) field.ErrorList {
|
||||
func ValidatePodTemplateUpdate(newPod, oldPod *core.PodTemplate, opts PodValidationOptions) field.ErrorList {
|
||||
allErrs := ValidateObjectMetaUpdate(&newPod.ObjectMeta, &oldPod.ObjectMeta, field.NewPath("metadata"))
|
||||
allErrs = append(allErrs, ValidatePodTemplateSpec(&newPod.Template, field.NewPath("template"))...)
|
||||
allErrs = append(allErrs, ValidatePodTemplateSpec(&newPod.Template, field.NewPath("template"), opts)...)
|
||||
return allErrs
|
||||
}
|
||||
|
||||
@@ -4490,16 +4500,16 @@ func ValidateServiceStatusUpdate(service, oldService *core.Service) field.ErrorL
|
||||
}
|
||||
|
||||
// ValidateReplicationController tests if required fields in the replication controller are set.
|
||||
func ValidateReplicationController(controller *core.ReplicationController) field.ErrorList {
|
||||
func ValidateReplicationController(controller *core.ReplicationController, opts PodValidationOptions) field.ErrorList {
|
||||
allErrs := ValidateObjectMeta(&controller.ObjectMeta, true, ValidateReplicationControllerName, field.NewPath("metadata"))
|
||||
allErrs = append(allErrs, ValidateReplicationControllerSpec(&controller.Spec, field.NewPath("spec"))...)
|
||||
allErrs = append(allErrs, ValidateReplicationControllerSpec(&controller.Spec, field.NewPath("spec"), opts)...)
|
||||
return allErrs
|
||||
}
|
||||
|
||||
// ValidateReplicationControllerUpdate tests if required fields in the replication controller are set.
|
||||
func ValidateReplicationControllerUpdate(controller, oldController *core.ReplicationController) field.ErrorList {
|
||||
func ValidateReplicationControllerUpdate(controller, oldController *core.ReplicationController, opts PodValidationOptions) field.ErrorList {
|
||||
allErrs := ValidateObjectMetaUpdate(&controller.ObjectMeta, &oldController.ObjectMeta, field.NewPath("metadata"))
|
||||
allErrs = append(allErrs, ValidateReplicationControllerSpec(&controller.Spec, field.NewPath("spec"))...)
|
||||
allErrs = append(allErrs, ValidateReplicationControllerSpec(&controller.Spec, field.NewPath("spec"), opts)...)
|
||||
return allErrs
|
||||
}
|
||||
|
||||
@@ -4544,7 +4554,7 @@ func ValidateNonEmptySelector(selectorMap map[string]string, fldPath *field.Path
|
||||
}
|
||||
|
||||
// Validates the given template and ensures that it is in accordance with the desired selector and replicas.
|
||||
func ValidatePodTemplateSpecForRC(template *core.PodTemplateSpec, selectorMap map[string]string, replicas int32, fldPath *field.Path) field.ErrorList {
|
||||
func ValidatePodTemplateSpecForRC(template *core.PodTemplateSpec, selectorMap map[string]string, replicas int32, fldPath *field.Path, opts PodValidationOptions) field.ErrorList {
|
||||
allErrs := field.ErrorList{}
|
||||
if template == nil {
|
||||
allErrs = append(allErrs, field.Required(fldPath, ""))
|
||||
@@ -4557,7 +4567,7 @@ func ValidatePodTemplateSpecForRC(template *core.PodTemplateSpec, selectorMap ma
|
||||
allErrs = append(allErrs, field.Invalid(fldPath.Child("metadata", "labels"), template.Labels, "`selector` does not match template `labels`"))
|
||||
}
|
||||
}
|
||||
allErrs = append(allErrs, ValidatePodTemplateSpec(template, fldPath)...)
|
||||
allErrs = append(allErrs, ValidatePodTemplateSpec(template, fldPath, opts)...)
|
||||
if replicas > 1 {
|
||||
allErrs = append(allErrs, ValidateReadOnlyPersistentDisks(template.Spec.Volumes, fldPath.Child("spec", "volumes"))...)
|
||||
}
|
||||
@@ -4573,22 +4583,22 @@ func ValidatePodTemplateSpecForRC(template *core.PodTemplateSpec, selectorMap ma
|
||||
}
|
||||
|
||||
// ValidateReplicationControllerSpec tests if required fields in the replication controller spec are set.
|
||||
func ValidateReplicationControllerSpec(spec *core.ReplicationControllerSpec, fldPath *field.Path) field.ErrorList {
|
||||
func ValidateReplicationControllerSpec(spec *core.ReplicationControllerSpec, fldPath *field.Path, opts PodValidationOptions) field.ErrorList {
|
||||
allErrs := field.ErrorList{}
|
||||
allErrs = append(allErrs, ValidateNonnegativeField(int64(spec.MinReadySeconds), fldPath.Child("minReadySeconds"))...)
|
||||
allErrs = append(allErrs, ValidateNonEmptySelector(spec.Selector, fldPath.Child("selector"))...)
|
||||
allErrs = append(allErrs, ValidateNonnegativeField(int64(spec.Replicas), fldPath.Child("replicas"))...)
|
||||
allErrs = append(allErrs, ValidatePodTemplateSpecForRC(spec.Template, spec.Selector, spec.Replicas, fldPath.Child("template"))...)
|
||||
allErrs = append(allErrs, ValidatePodTemplateSpecForRC(spec.Template, spec.Selector, spec.Replicas, fldPath.Child("template"), opts)...)
|
||||
return allErrs
|
||||
}
|
||||
|
||||
// ValidatePodTemplateSpec validates the spec of a pod template
|
||||
func ValidatePodTemplateSpec(spec *core.PodTemplateSpec, fldPath *field.Path) field.ErrorList {
|
||||
func ValidatePodTemplateSpec(spec *core.PodTemplateSpec, fldPath *field.Path, opts PodValidationOptions) field.ErrorList {
|
||||
allErrs := field.ErrorList{}
|
||||
allErrs = append(allErrs, unversionedvalidation.ValidateLabels(spec.Labels, fldPath.Child("labels"))...)
|
||||
allErrs = append(allErrs, ValidateAnnotations(spec.Annotations, fldPath.Child("annotations"))...)
|
||||
allErrs = append(allErrs, ValidatePodSpecificAnnotations(spec.Annotations, &spec.Spec, fldPath.Child("annotations"))...)
|
||||
allErrs = append(allErrs, ValidatePodSpec(&spec.Spec, nil, fldPath.Child("spec"))...)
|
||||
allErrs = append(allErrs, ValidatePodSpec(&spec.Spec, nil, fldPath.Child("spec"), opts)...)
|
||||
allErrs = append(allErrs, validateSeccompAnnotationsAndFields(spec.ObjectMeta, &spec.Spec, fldPath.Child("spec"))...)
|
||||
|
||||
if len(spec.Spec.EphemeralContainers) > 0 {
|
||||
|
||||
@@ -1307,7 +1307,8 @@ func testValidatePVC(t *testing.T, ephemeral bool) {
|
||||
},
|
||||
},
|
||||
}
|
||||
_, errs = ValidateVolumes(volumes, nil, field.NewPath(""))
|
||||
opts := PodValidationOptions{}
|
||||
_, errs = ValidateVolumes(volumes, nil, field.NewPath(""), opts)
|
||||
} else {
|
||||
errs = ValidatePersistentVolumeClaim(scenario.claim)
|
||||
}
|
||||
@@ -2199,6 +2200,7 @@ func TestValidateVolumes(t *testing.T) {
|
||||
name string
|
||||
vol core.Volume
|
||||
errs []verr
|
||||
opts PodValidationOptions
|
||||
}{
|
||||
// EmptyDir and basic volume names
|
||||
{
|
||||
@@ -3294,6 +3296,79 @@ func TestValidateVolumes(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "hugepages-downwardAPI-enabled",
|
||||
vol: core.Volume{
|
||||
Name: "downwardapi",
|
||||
VolumeSource: core.VolumeSource{
|
||||
DownwardAPI: &core.DownwardAPIVolumeSource{
|
||||
Items: []core.DownwardAPIVolumeFile{
|
||||
{
|
||||
Path: "hugepages_request",
|
||||
ResourceFieldRef: &core.ResourceFieldSelector{
|
||||
ContainerName: "test-container",
|
||||
Resource: "requests.hugepages-2Mi",
|
||||
},
|
||||
},
|
||||
{
|
||||
Path: "hugepages_limit",
|
||||
ResourceFieldRef: &core.ResourceFieldSelector{
|
||||
ContainerName: "test-container",
|
||||
Resource: "limits.hugepages-2Mi",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
opts: PodValidationOptions{AllowDownwardAPIHugePages: true},
|
||||
},
|
||||
{
|
||||
name: "hugepages-downwardAPI-requests-disabled",
|
||||
vol: core.Volume{
|
||||
Name: "downwardapi",
|
||||
VolumeSource: core.VolumeSource{
|
||||
DownwardAPI: &core.DownwardAPIVolumeSource{
|
||||
Items: []core.DownwardAPIVolumeFile{
|
||||
{
|
||||
Path: "hugepages_request",
|
||||
ResourceFieldRef: &core.ResourceFieldSelector{
|
||||
ContainerName: "test-container",
|
||||
Resource: "requests.hugepages-2Mi",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
errs: []verr{{
|
||||
etype: field.ErrorTypeNotSupported,
|
||||
field: "downwardAPI.resourceFieldRef.resource",
|
||||
}},
|
||||
},
|
||||
{
|
||||
name: "hugepages-downwardAPI-limits-disabled",
|
||||
vol: core.Volume{
|
||||
Name: "downwardapi",
|
||||
VolumeSource: core.VolumeSource{
|
||||
DownwardAPI: &core.DownwardAPIVolumeSource{
|
||||
Items: []core.DownwardAPIVolumeFile{
|
||||
{
|
||||
Path: "hugepages_limit",
|
||||
ResourceFieldRef: &core.ResourceFieldSelector{
|
||||
ContainerName: "test-container",
|
||||
Resource: "limits.hugepages-2Mi",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
errs: []verr{{
|
||||
etype: field.ErrorTypeNotSupported,
|
||||
field: "downwardAPI.resourceFieldRef.resource",
|
||||
}},
|
||||
},
|
||||
{
|
||||
name: "downapi valid defaultMode",
|
||||
vol: core.Volume{
|
||||
@@ -3990,7 +4065,7 @@ func TestValidateVolumes(t *testing.T) {
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
names, errs := ValidateVolumes([]core.Volume{tc.vol}, nil, field.NewPath("field"))
|
||||
names, errs := ValidateVolumes([]core.Volume{tc.vol}, nil, field.NewPath("field"), tc.opts)
|
||||
if len(errs) != len(tc.errs) {
|
||||
t.Fatalf("unexpected error(s): got %d, want %d: %v", len(tc.errs), len(errs), errs)
|
||||
}
|
||||
@@ -4016,7 +4091,7 @@ func TestValidateVolumes(t *testing.T) {
|
||||
{Name: "abc", VolumeSource: core.VolumeSource{EmptyDir: &core.EmptyDirVolumeSource{}}},
|
||||
{Name: "abc", VolumeSource: core.VolumeSource{EmptyDir: &core.EmptyDirVolumeSource{}}},
|
||||
}
|
||||
_, errs := ValidateVolumes(dupsCase, nil, field.NewPath("field"))
|
||||
_, errs := ValidateVolumes(dupsCase, nil, field.NewPath("field"), PodValidationOptions{})
|
||||
if len(errs) == 0 {
|
||||
t.Errorf("expected error")
|
||||
} else if len(errs) != 1 {
|
||||
@@ -4029,7 +4104,7 @@ func TestValidateVolumes(t *testing.T) {
|
||||
hugePagesCase := core.VolumeSource{EmptyDir: &core.EmptyDirVolumeSource{Medium: core.StorageMediumHugePages}}
|
||||
|
||||
// Enable HugePages
|
||||
if errs := validateVolumeSource(&hugePagesCase, field.NewPath("field").Index(0), "working", nil); len(errs) != 0 {
|
||||
if errs := validateVolumeSource(&hugePagesCase, field.NewPath("field").Index(0), "working", nil, PodValidationOptions{}); len(errs) != 0 {
|
||||
t.Errorf("Unexpected error when HugePages feature is enabled.")
|
||||
}
|
||||
|
||||
@@ -4208,7 +4283,7 @@ func TestHugePagesIsolation(t *testing.T) {
|
||||
for tcName, tc := range testCases {
|
||||
t.Run(tcName, func(t *testing.T) {
|
||||
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.HugePageStorageMediumSize, tc.enableHugePageStorageMediumSize)()
|
||||
errs := ValidatePodCreate(tc.pod, PodValidationOptions{tc.enableHugePageStorageMediumSize})
|
||||
errs := ValidatePodCreate(tc.pod, PodValidationOptions{AllowMultipleHugePageResources: tc.enableHugePageStorageMediumSize})
|
||||
if tc.expectError && len(errs) == 0 {
|
||||
t.Errorf("Unexpected success")
|
||||
}
|
||||
@@ -4359,7 +4434,7 @@ func TestAlphaLocalStorageCapacityIsolation(t *testing.T) {
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
if errs := validateVolumeSource(&tc, field.NewPath("spec"), "tmpvol", nil); len(errs) != 0 {
|
||||
if errs := validateVolumeSource(&tc, field.NewPath("spec"), "tmpvol", nil, PodValidationOptions{}); len(errs) != 0 {
|
||||
t.Errorf("expected success: %v", errs)
|
||||
}
|
||||
}
|
||||
@@ -4529,12 +4604,55 @@ func TestLocalStorageEnvWithFeatureGate(t *testing.T) {
|
||||
},
|
||||
}
|
||||
for _, testCase := range testCases {
|
||||
if errs := validateEnvVarValueFrom(testCase, field.NewPath("field")); len(errs) != 0 {
|
||||
if errs := validateEnvVarValueFrom(testCase, field.NewPath("field"), PodValidationOptions{}); len(errs) != 0 {
|
||||
t.Errorf("expected success, got: %v", errs)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestHugePagesEnv(t *testing.T) {
|
||||
testCases := []core.EnvVar{
|
||||
{
|
||||
Name: "hugepages-limits",
|
||||
ValueFrom: &core.EnvVarSource{
|
||||
ResourceFieldRef: &core.ResourceFieldSelector{
|
||||
ContainerName: "test-container",
|
||||
Resource: "limits.hugepages-2Mi",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "hugepages-requests",
|
||||
ValueFrom: &core.EnvVarSource{
|
||||
ResourceFieldRef: &core.ResourceFieldSelector{
|
||||
ContainerName: "test-container",
|
||||
Resource: "requests.hugepages-2Mi",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
// enable gate
|
||||
for _, testCase := range testCases {
|
||||
t.Run(testCase.Name, func(t *testing.T) {
|
||||
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.DownwardAPIHugePages, true)()
|
||||
opts := PodValidationOptions{AllowDownwardAPIHugePages: true}
|
||||
if errs := validateEnvVarValueFrom(testCase, field.NewPath("field"), opts); len(errs) != 0 {
|
||||
t.Errorf("expected success, got: %v", errs)
|
||||
}
|
||||
})
|
||||
}
|
||||
// disable gate
|
||||
for _, testCase := range testCases {
|
||||
t.Run(testCase.Name, func(t *testing.T) {
|
||||
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.DownwardAPIHugePages, false)()
|
||||
opts := PodValidationOptions{AllowDownwardAPIHugePages: false}
|
||||
if errs := validateEnvVarValueFrom(testCase, field.NewPath("field"), opts); len(errs) == 0 {
|
||||
t.Errorf("expected failure")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateEnv(t *testing.T) {
|
||||
successCase := []core.EnvVar{
|
||||
{Name: "abc", Value: "value"},
|
||||
@@ -4656,7 +4774,7 @@ func TestValidateEnv(t *testing.T) {
|
||||
},
|
||||
},
|
||||
}
|
||||
if errs := ValidateEnv(successCase, field.NewPath("field")); len(errs) != 0 {
|
||||
if errs := ValidateEnv(successCase, field.NewPath("field"), PodValidationOptions{}); len(errs) != 0 {
|
||||
t.Errorf("expected success, got: %v", errs)
|
||||
}
|
||||
|
||||
@@ -4920,7 +5038,7 @@ func TestValidateEnv(t *testing.T) {
|
||||
},
|
||||
}
|
||||
for _, tc := range errorCases {
|
||||
if errs := ValidateEnv(tc.envs, field.NewPath("field")); len(errs) == 0 {
|
||||
if errs := ValidateEnv(tc.envs, field.NewPath("field"), PodValidationOptions{}); len(errs) == 0 {
|
||||
t.Errorf("expected failure for %s", tc.name)
|
||||
} else {
|
||||
for i := range errs {
|
||||
@@ -5101,7 +5219,7 @@ func TestValidateVolumeMounts(t *testing.T) {
|
||||
{Name: "abc-123", VolumeSource: core.VolumeSource{PersistentVolumeClaim: &core.PersistentVolumeClaimVolumeSource{ClaimName: "testclaim2"}}},
|
||||
{Name: "123", VolumeSource: core.VolumeSource{HostPath: &core.HostPathVolumeSource{Path: "/foo/baz", Type: newHostPathType(string(core.HostPathUnset))}}},
|
||||
}
|
||||
vols, v1err := ValidateVolumes(volumes, nil, field.NewPath("field"))
|
||||
vols, v1err := ValidateVolumes(volumes, nil, field.NewPath("field"), PodValidationOptions{})
|
||||
if len(v1err) > 0 {
|
||||
t.Errorf("Invalid test volume - expected success %v", v1err)
|
||||
return
|
||||
@@ -5164,7 +5282,7 @@ func TestValidateDisabledSubpath(t *testing.T) {
|
||||
{Name: "abc-123", VolumeSource: core.VolumeSource{PersistentVolumeClaim: &core.PersistentVolumeClaimVolumeSource{ClaimName: "testclaim2"}}},
|
||||
{Name: "123", VolumeSource: core.VolumeSource{HostPath: &core.HostPathVolumeSource{Path: "/foo/baz", Type: newHostPathType(string(core.HostPathUnset))}}},
|
||||
}
|
||||
vols, v1err := ValidateVolumes(volumes, nil, field.NewPath("field"))
|
||||
vols, v1err := ValidateVolumes(volumes, nil, field.NewPath("field"), PodValidationOptions{})
|
||||
if len(v1err) > 0 {
|
||||
t.Errorf("Invalid test volume - expected success %v", v1err)
|
||||
return
|
||||
@@ -5226,7 +5344,7 @@ func TestValidateSubpathMutuallyExclusive(t *testing.T) {
|
||||
{Name: "abc-123", VolumeSource: core.VolumeSource{PersistentVolumeClaim: &core.PersistentVolumeClaimVolumeSource{ClaimName: "testclaim2"}}},
|
||||
{Name: "123", VolumeSource: core.VolumeSource{HostPath: &core.HostPathVolumeSource{Path: "/foo/baz", Type: newHostPathType(string(core.HostPathUnset))}}},
|
||||
}
|
||||
vols, v1err := ValidateVolumes(volumes, nil, field.NewPath("field"))
|
||||
vols, v1err := ValidateVolumes(volumes, nil, field.NewPath("field"), PodValidationOptions{})
|
||||
if len(v1err) > 0 {
|
||||
t.Errorf("Invalid test volume - expected success %v", v1err)
|
||||
return
|
||||
@@ -5307,7 +5425,7 @@ func TestValidateDisabledSubpathExpr(t *testing.T) {
|
||||
{Name: "abc-123", VolumeSource: core.VolumeSource{PersistentVolumeClaim: &core.PersistentVolumeClaimVolumeSource{ClaimName: "testclaim2"}}},
|
||||
{Name: "123", VolumeSource: core.VolumeSource{HostPath: &core.HostPathVolumeSource{Path: "/foo/baz", Type: newHostPathType(string(core.HostPathUnset))}}},
|
||||
}
|
||||
vols, v1err := ValidateVolumes(volumes, nil, field.NewPath("field"))
|
||||
vols, v1err := ValidateVolumes(volumes, nil, field.NewPath("field"), PodValidationOptions{})
|
||||
if len(v1err) > 0 {
|
||||
t.Errorf("Invalid test volume - expected success %v", v1err)
|
||||
return
|
||||
@@ -5501,7 +5619,7 @@ func TestValidateMountPropagation(t *testing.T) {
|
||||
volumes := []core.Volume{
|
||||
{Name: "foo", VolumeSource: core.VolumeSource{HostPath: &core.HostPathVolumeSource{Path: "/foo/baz", Type: newHostPathType(string(core.HostPathUnset))}}},
|
||||
}
|
||||
vols2, v2err := ValidateVolumes(volumes, nil, field.NewPath("field"))
|
||||
vols2, v2err := ValidateVolumes(volumes, nil, field.NewPath("field"), PodValidationOptions{})
|
||||
if len(v2err) > 0 {
|
||||
t.Errorf("Invalid test volume - expected success %v", v2err)
|
||||
return
|
||||
@@ -5524,7 +5642,7 @@ func TestAlphaValidateVolumeDevices(t *testing.T) {
|
||||
{Name: "def", VolumeSource: core.VolumeSource{HostPath: &core.HostPathVolumeSource{Path: "/foo/baz", Type: newHostPathType(string(core.HostPathUnset))}}},
|
||||
}
|
||||
|
||||
vols, v1err := ValidateVolumes(volumes, nil, field.NewPath("field"))
|
||||
vols, v1err := ValidateVolumes(volumes, nil, field.NewPath("field"), PodValidationOptions{})
|
||||
if len(v1err) > 0 {
|
||||
t.Errorf("Invalid test volumes - expected success %v", v1err)
|
||||
return
|
||||
@@ -5737,7 +5855,7 @@ func TestValidateEphemeralContainers(t *testing.T) {
|
||||
},
|
||||
},
|
||||
} {
|
||||
if errs := validateEphemeralContainers(ephemeralContainers, containers, initContainers, vols, field.NewPath("ephemeralContainers")); len(errs) != 0 {
|
||||
if errs := validateEphemeralContainers(ephemeralContainers, containers, initContainers, vols, field.NewPath("ephemeralContainers"), PodValidationOptions{}); len(errs) != 0 {
|
||||
t.Errorf("expected success for '%s' but got errors: %v", title, errs)
|
||||
}
|
||||
}
|
||||
@@ -5901,7 +6019,7 @@ func TestValidateEphemeralContainers(t *testing.T) {
|
||||
}
|
||||
|
||||
for _, tc := range tcs {
|
||||
errs := validateEphemeralContainers(tc.ephemeralContainers, containers, initContainers, vols, field.NewPath("ephemeralContainers"))
|
||||
errs := validateEphemeralContainers(tc.ephemeralContainers, containers, initContainers, vols, field.NewPath("ephemeralContainers"), PodValidationOptions{})
|
||||
|
||||
if len(errs) == 0 {
|
||||
t.Errorf("for test %q, expected error but received none", tc.title)
|
||||
@@ -6070,7 +6188,7 @@ func TestValidateContainers(t *testing.T) {
|
||||
},
|
||||
{Name: "abc-1234", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File", SecurityContext: fakeValidSecurityContext(true)},
|
||||
}
|
||||
if errs := validateContainers(successCase, false, volumeDevices, field.NewPath("field")); len(errs) != 0 {
|
||||
if errs := validateContainers(successCase, false, volumeDevices, field.NewPath("field"), PodValidationOptions{}); len(errs) != 0 {
|
||||
t.Errorf("expected success: %v", errs)
|
||||
}
|
||||
|
||||
@@ -6310,7 +6428,7 @@ func TestValidateContainers(t *testing.T) {
|
||||
},
|
||||
}
|
||||
for k, v := range errorCases {
|
||||
if errs := validateContainers(v, false, volumeDevices, field.NewPath("field")); len(errs) == 0 {
|
||||
if errs := validateContainers(v, false, volumeDevices, field.NewPath("field"), PodValidationOptions{}); len(errs) == 0 {
|
||||
t.Errorf("expected failure for %s", k)
|
||||
}
|
||||
}
|
||||
@@ -6344,7 +6462,7 @@ func TestValidateInitContainers(t *testing.T) {
|
||||
TerminationMessagePolicy: "File",
|
||||
},
|
||||
}
|
||||
if errs := validateContainers(successCase, true, volumeDevices, field.NewPath("field")); len(errs) != 0 {
|
||||
if errs := validateContainers(successCase, true, volumeDevices, field.NewPath("field"), PodValidationOptions{}); len(errs) != 0 {
|
||||
t.Errorf("expected success: %v", errs)
|
||||
}
|
||||
|
||||
@@ -6370,7 +6488,7 @@ func TestValidateInitContainers(t *testing.T) {
|
||||
},
|
||||
}
|
||||
for k, v := range errorCases {
|
||||
if errs := validateContainers(v, true, volumeDevices, field.NewPath("field")); len(errs) == 0 {
|
||||
if errs := validateContainers(v, true, volumeDevices, field.NewPath("field"), PodValidationOptions{}); len(errs) == 0 {
|
||||
t.Errorf("expected failure for %s", k)
|
||||
}
|
||||
}
|
||||
@@ -6881,7 +6999,7 @@ func TestValidatePodSpec(t *testing.T) {
|
||||
}
|
||||
for k, v := range successCases {
|
||||
t.Run(k, func(t *testing.T) {
|
||||
if errs := ValidatePodSpec(&v, nil, field.NewPath("field")); len(errs) != 0 {
|
||||
if errs := ValidatePodSpec(&v, nil, field.NewPath("field"), PodValidationOptions{}); len(errs) != 0 {
|
||||
t.Errorf("expected success: %v", errs)
|
||||
}
|
||||
})
|
||||
@@ -7085,7 +7203,7 @@ func TestValidatePodSpec(t *testing.T) {
|
||||
},
|
||||
}
|
||||
for k, v := range failureCases {
|
||||
if errs := ValidatePodSpec(&v, nil, field.NewPath("field")); len(errs) == 0 {
|
||||
if errs := ValidatePodSpec(&v, nil, field.NewPath("field"), PodValidationOptions{}); len(errs) == 0 {
|
||||
t.Errorf("expected failure for %q", k)
|
||||
}
|
||||
}
|
||||
@@ -9875,7 +9993,7 @@ func TestValidatePodEphemeralContainersUpdate(t *testing.T) {
|
||||
for _, test := range tests {
|
||||
new := core.Pod{Spec: core.PodSpec{EphemeralContainers: test.new}}
|
||||
old := core.Pod{Spec: core.PodSpec{EphemeralContainers: test.old}}
|
||||
errs := ValidatePodEphemeralContainersUpdate(&new, &old)
|
||||
errs := ValidatePodEphemeralContainersUpdate(&new, &old, PodValidationOptions{})
|
||||
if test.err == "" {
|
||||
if len(errs) != 0 {
|
||||
t.Errorf("unexpected invalid: %s (%+v)\nA: %+v\nB: %+v", test.test, errs, test.new, test.old)
|
||||
@@ -11508,7 +11626,7 @@ func TestValidateReplicationControllerUpdate(t *testing.T) {
|
||||
for _, successCase := range successCases {
|
||||
successCase.old.ObjectMeta.ResourceVersion = "1"
|
||||
successCase.update.ObjectMeta.ResourceVersion = "1"
|
||||
if errs := ValidateReplicationControllerUpdate(&successCase.update, &successCase.old); len(errs) != 0 {
|
||||
if errs := ValidateReplicationControllerUpdate(&successCase.update, &successCase.old, PodValidationOptions{}); len(errs) != 0 {
|
||||
t.Errorf("expected success: %v", errs)
|
||||
}
|
||||
}
|
||||
@@ -11583,7 +11701,7 @@ func TestValidateReplicationControllerUpdate(t *testing.T) {
|
||||
},
|
||||
}
|
||||
for testName, errorCase := range errorCases {
|
||||
if errs := ValidateReplicationControllerUpdate(&errorCase.update, &errorCase.old); len(errs) == 0 {
|
||||
if errs := ValidateReplicationControllerUpdate(&errorCase.update, &errorCase.old, PodValidationOptions{}); len(errs) == 0 {
|
||||
t.Errorf("expected failure: %s", testName)
|
||||
}
|
||||
}
|
||||
@@ -11653,7 +11771,7 @@ func TestValidateReplicationController(t *testing.T) {
|
||||
},
|
||||
}
|
||||
for _, successCase := range successCases {
|
||||
if errs := ValidateReplicationController(&successCase); len(errs) != 0 {
|
||||
if errs := ValidateReplicationController(&successCase, PodValidationOptions{}); len(errs) != 0 {
|
||||
t.Errorf("expected success: %v", errs)
|
||||
}
|
||||
}
|
||||
@@ -11803,7 +11921,7 @@ func TestValidateReplicationController(t *testing.T) {
|
||||
},
|
||||
}
|
||||
for k, v := range errorCases {
|
||||
errs := ValidateReplicationController(&v)
|
||||
errs := ValidateReplicationController(&v, PodValidationOptions{})
|
||||
if len(errs) == 0 {
|
||||
t.Errorf("expected failure for %s", k)
|
||||
}
|
||||
@@ -16919,7 +17037,7 @@ func TestValidatePodTemplateSpecSeccomp(t *testing.T) {
|
||||
}
|
||||
|
||||
for i, test := range tests {
|
||||
err := ValidatePodTemplateSpec(test.spec, rootFld)
|
||||
err := ValidatePodTemplateSpec(test.spec, rootFld, PodValidationOptions{})
|
||||
asserttestify.Equal(t, test.expectedErr, err, "TestCase[%d]: %s", i, test.description)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user