Merge pull request #113274 from Huang-Wei/kep-3521-A
[KEP-3521] Part 1: New Pod API .spec.schedulingGates
This commit is contained in:
@@ -1013,7 +1013,7 @@ func validateGlusterfsPersistentVolumeSource(glusterfs *core.GlusterfsPersistent
|
||||
func validateFlockerVolumeSource(flocker *core.FlockerVolumeSource, fldPath *field.Path) field.ErrorList {
|
||||
allErrs := field.ErrorList{}
|
||||
if len(flocker.DatasetName) == 0 && len(flocker.DatasetUUID) == 0 {
|
||||
//TODO: consider adding a RequiredOneOf() error for this and similar cases
|
||||
// TODO: consider adding a RequiredOneOf() error for this and similar cases
|
||||
allErrs = append(allErrs, field.Required(fldPath, "one of datasetName and datasetUUID is required"))
|
||||
}
|
||||
if len(flocker.DatasetName) != 0 && len(flocker.DatasetUUID) != 0 {
|
||||
@@ -3272,6 +3272,22 @@ func validateReadinessGates(readinessGates []core.PodReadinessGate, fldPath *fie
|
||||
return allErrs
|
||||
}
|
||||
|
||||
func validateSchedulingGates(schedulingGates []core.PodSchedulingGate, fldPath *field.Path) field.ErrorList {
|
||||
allErrs := field.ErrorList{}
|
||||
// There should be no duplicates in the list of scheduling gates.
|
||||
seen := sets.String{}
|
||||
for i, schedulingGate := range schedulingGates {
|
||||
if schedulingGate.Name == "" {
|
||||
allErrs = append(allErrs, field.Required(fldPath.Index(i), "must not be empty"))
|
||||
}
|
||||
if seen.Has(schedulingGate.Name) {
|
||||
allErrs = append(allErrs, field.Duplicate(fldPath.Index(i), schedulingGate.Name))
|
||||
}
|
||||
seen.Insert(schedulingGate.Name)
|
||||
}
|
||||
return allErrs
|
||||
}
|
||||
|
||||
func validatePodDNSConfig(dnsConfig *core.PodDNSConfig, dnsPolicy *core.DNSPolicy, fldPath *field.Path, opts PodValidationOptions) field.ErrorList {
|
||||
allErrs := field.ErrorList{}
|
||||
|
||||
@@ -3420,6 +3436,28 @@ func validateOnlyAddedTolerations(newTolerations []core.Toleration, oldToleratio
|
||||
return allErrs
|
||||
}
|
||||
|
||||
func validateOnlyDeletedSchedulingGates(newGates, oldGates []core.PodSchedulingGate, fldPath *field.Path) field.ErrorList {
|
||||
allErrs := field.ErrorList{}
|
||||
if len(newGates) == 0 {
|
||||
return allErrs
|
||||
}
|
||||
|
||||
additionalGates := make(map[string]int)
|
||||
for i, newGate := range newGates {
|
||||
additionalGates[newGate.Name] = i
|
||||
}
|
||||
|
||||
for _, oldGate := range oldGates {
|
||||
delete(additionalGates, oldGate.Name)
|
||||
}
|
||||
|
||||
for gate, i := range additionalGates {
|
||||
allErrs = append(allErrs, field.Forbidden(fldPath.Index(i).Child("name"), fmt.Sprintf("only deletion is allowed, but found new scheduling gate '%s'", gate)))
|
||||
}
|
||||
|
||||
return allErrs
|
||||
}
|
||||
|
||||
func ValidateHostAliases(hostAliases []core.HostAlias, fldPath *field.Path) field.ErrorList {
|
||||
allErrs := field.ErrorList{}
|
||||
for _, hostAlias := range hostAliases {
|
||||
@@ -3577,7 +3615,7 @@ func validatePodIPs(pod *core.Pod) field.ErrorList {
|
||||
}
|
||||
|
||||
// There should be no duplicates in list of Pod.PodIPs
|
||||
seen := sets.String{} //:= make(map[string]int)
|
||||
seen := sets.String{} // := make(map[string]int)
|
||||
for i, podIP := range pod.Status.PodIPs {
|
||||
if seen.Has(podIP.IP) {
|
||||
allErrs = append(allErrs, field.Duplicate(podIPsField.Index(i), podIP))
|
||||
@@ -3611,6 +3649,7 @@ func ValidatePodSpec(spec *core.PodSpec, podMeta *metav1.ObjectMeta, fldPath *fi
|
||||
allErrs = append(allErrs, validateAffinity(spec.Affinity, fldPath.Child("affinity"))...)
|
||||
allErrs = append(allErrs, validatePodDNSConfig(spec.DNSConfig, &spec.DNSPolicy, fldPath.Child("dnsConfig"), opts)...)
|
||||
allErrs = append(allErrs, validateReadinessGates(spec.ReadinessGates, fldPath.Child("readinessGates"))...)
|
||||
allErrs = append(allErrs, validateSchedulingGates(spec.SchedulingGates, fldPath.Child("schedulingGates"))...)
|
||||
allErrs = append(allErrs, validateTopologySpreadConstraints(spec.TopologySpreadConstraints, fldPath.Child("topologySpreadConstraints"))...)
|
||||
allErrs = append(allErrs, validateWindowsHostProcessPod(spec, fldPath)...)
|
||||
allErrs = append(allErrs, validateHostUsers(spec, fldPath)...)
|
||||
@@ -4016,7 +4055,7 @@ func validatePodAntiAffinity(podAntiAffinity *core.PodAntiAffinity, fldPath *fie
|
||||
// if podAntiAffinity.RequiredDuringSchedulingRequiredDuringExecution != nil {
|
||||
// allErrs = append(allErrs, validatePodAffinityTerms(podAntiAffinity.RequiredDuringSchedulingRequiredDuringExecution, false,
|
||||
// fldPath.Child("requiredDuringSchedulingRequiredDuringExecution"))...)
|
||||
//}
|
||||
// }
|
||||
if podAntiAffinity.RequiredDuringSchedulingIgnoredDuringExecution != nil {
|
||||
allErrs = append(allErrs, validatePodAffinityTerms(podAntiAffinity.RequiredDuringSchedulingIgnoredDuringExecution,
|
||||
fldPath.Child("requiredDuringSchedulingIgnoredDuringExecution"))...)
|
||||
@@ -4051,7 +4090,7 @@ func validatePodAffinity(podAffinity *core.PodAffinity, fldPath *field.Path) fie
|
||||
// if podAffinity.RequiredDuringSchedulingRequiredDuringExecution != nil {
|
||||
// allErrs = append(allErrs, validatePodAffinityTerms(podAffinity.RequiredDuringSchedulingRequiredDuringExecution, false,
|
||||
// fldPath.Child("requiredDuringSchedulingRequiredDuringExecution"))...)
|
||||
//}
|
||||
// }
|
||||
if podAffinity.RequiredDuringSchedulingIgnoredDuringExecution != nil {
|
||||
allErrs = append(allErrs, validatePodAffinityTerms(podAffinity.RequiredDuringSchedulingIgnoredDuringExecution,
|
||||
fldPath.Child("requiredDuringSchedulingIgnoredDuringExecution"))...)
|
||||
@@ -4258,7 +4297,7 @@ func ValidatePodSecurityContext(securityContext *core.PodSecurityContext, spec *
|
||||
func ValidateContainerUpdates(newContainers, oldContainers []core.Container, fldPath *field.Path) (allErrs field.ErrorList, stop bool) {
|
||||
allErrs = field.ErrorList{}
|
||||
if len(newContainers) != len(oldContainers) {
|
||||
//TODO: Pinpoint the specific container that causes the invalid error after we have strategic merge diff
|
||||
// TODO: Pinpoint the specific container that causes the invalid error after we have strategic merge diff
|
||||
allErrs = append(allErrs, field.Forbidden(fldPath, "pod updates may not add or remove containers"))
|
||||
return allErrs, true
|
||||
}
|
||||
@@ -4285,6 +4324,11 @@ func ValidatePodCreate(pod *core.Pod, opts PodValidationOptions) field.ErrorList
|
||||
if len(pod.Spec.EphemeralContainers) > 0 {
|
||||
allErrs = append(allErrs, field.Forbidden(fldPath.Child("ephemeralContainers"), "cannot be set on create"))
|
||||
}
|
||||
// A Pod cannot be assigned a Node if there are remaining scheduling gates.
|
||||
if utilfeature.DefaultFeatureGate.Enabled(features.PodSchedulingReadiness) &&
|
||||
pod.Spec.NodeName != "" && len(pod.Spec.SchedulingGates) != 0 {
|
||||
allErrs = append(allErrs, field.Forbidden(fldPath.Child("nodeName"), "cannot be set until all schedulingGates have been cleared"))
|
||||
}
|
||||
allErrs = append(allErrs, validateSeccompAnnotationsAndFields(pod.ObjectMeta, &pod.Spec, fldPath)...)
|
||||
|
||||
return allErrs
|
||||
@@ -4370,6 +4414,7 @@ func ValidatePodUpdate(newPod, oldPod *core.Pod, opts PodValidationOptions) fiel
|
||||
// 2. spec.initContainers[*].image
|
||||
// 3. spec.activeDeadlineSeconds
|
||||
// 4. spec.terminationGracePeriodSeconds
|
||||
// 5. spec.schedulingGates
|
||||
|
||||
containerErrs, stop := ValidateContainerUpdates(newPod.Spec.Containers, oldPod.Spec.Containers, specPath.Child("containers"))
|
||||
allErrs = append(allErrs, containerErrs...)
|
||||
@@ -4405,6 +4450,9 @@ func ValidatePodUpdate(newPod, oldPod *core.Pod, opts PodValidationOptions) fiel
|
||||
// Allow only additions to tolerations updates.
|
||||
allErrs = append(allErrs, validateOnlyAddedTolerations(newPod.Spec.Tolerations, oldPod.Spec.Tolerations, specPath.Child("tolerations"))...)
|
||||
|
||||
// Allow only deletions to schedulingGates updates.
|
||||
allErrs = append(allErrs, validateOnlyDeletedSchedulingGates(newPod.Spec.SchedulingGates, oldPod.Spec.SchedulingGates, specPath.Child("schedulingGates"))...)
|
||||
|
||||
// the last thing to check is pod spec equality. If the pod specs are equal, then we can simply return the errors we have
|
||||
// so far and save the cost of a deep copy.
|
||||
if apiequality.Semantic.DeepEqual(newPod.Spec, oldPod.Spec) {
|
||||
@@ -4433,6 +4481,8 @@ func ValidatePodUpdate(newPod, oldPod *core.Pod, opts PodValidationOptions) fiel
|
||||
activeDeadlineSeconds := *oldPod.Spec.ActiveDeadlineSeconds
|
||||
mungedPodSpec.ActiveDeadlineSeconds = &activeDeadlineSeconds
|
||||
}
|
||||
// munge spec.schedulingGates
|
||||
mungedPodSpec.SchedulingGates = oldPod.Spec.SchedulingGates // +k8s:verify-mutation:reason=clone
|
||||
// tolerations are checked before the deep copy, so munge those too
|
||||
mungedPodSpec.Tolerations = oldPod.Spec.Tolerations // +k8s:verify-mutation:reason=clone
|
||||
|
||||
@@ -4444,7 +4494,7 @@ func ValidatePodUpdate(newPod, oldPod *core.Pod, opts PodValidationOptions) fiel
|
||||
|
||||
if !apiequality.Semantic.DeepEqual(mungedPodSpec, oldPod.Spec) {
|
||||
// This diff isn't perfect, but it's a helluva lot better an "I'm not going to tell you what the difference is".
|
||||
//TODO: Pinpoint the specific field that causes the invalid error after we have strategic merge diff
|
||||
// TODO: Pinpoint the specific field that causes the invalid error after we have strategic merge diff
|
||||
specDiff := cmp.Diff(oldPod.Spec, mungedPodSpec)
|
||||
allErrs = append(allErrs, field.Forbidden(specPath, fmt.Sprintf("pod updates may not change fields other than `spec.containers[*].image`, `spec.initContainers[*].image`, `spec.activeDeadlineSeconds`, `spec.tolerations` (only additions to existing tolerations) or `spec.terminationGracePeriodSeconds` (allow it to be set to 1 if it was previously negative)\n%v", specDiff)))
|
||||
}
|
||||
@@ -6119,7 +6169,7 @@ func validateEndpointSubsets(subsets []core.EndpointSubset, fldPath *field.Path)
|
||||
|
||||
// EndpointSubsets must include endpoint address. For headless service, we allow its endpoints not to have ports.
|
||||
if len(ss.Addresses) == 0 && len(ss.NotReadyAddresses) == 0 {
|
||||
//TODO: consider adding a RequiredOneOf() error for this and similar cases
|
||||
// TODO: consider adding a RequiredOneOf() error for this and similar cases
|
||||
allErrs = append(allErrs, field.Required(idxPath, "must specify `addresses` or `notReadyAddresses`"))
|
||||
}
|
||||
for addr := range ss.Addresses {
|
||||
@@ -6208,7 +6258,7 @@ func validateEndpointPort(port *core.EndpointPort, requireName bool, fldPath *fi
|
||||
// ValidateSecurityContext ensures the security context contains valid settings
|
||||
func ValidateSecurityContext(sc *core.SecurityContext, fldPath *field.Path) field.ErrorList {
|
||||
allErrs := field.ErrorList{}
|
||||
//this should only be true for testing since SecurityContext is defaulted by the core
|
||||
// this should only be true for testing since SecurityContext is defaulted by the core
|
||||
if sc == nil {
|
||||
return allErrs
|
||||
}
|
||||
@@ -6724,7 +6774,7 @@ func ValidateServiceClusterIPsRelatedFields(service *core.Service) field.ErrorLi
|
||||
}
|
||||
|
||||
// IPFamilyPolicy stand alone validation
|
||||
//note: nil is ok, defaulted in alloc check registry/core/service/*
|
||||
// note: nil is ok, defaulted in alloc check registry/core/service/*
|
||||
if service.Spec.IPFamilyPolicy != nil {
|
||||
// must have a supported value
|
||||
if !supportedServiceIPFamilyPolicy.Has(string(*(service.Spec.IPFamilyPolicy))) {
|
||||
|
Reference in New Issue
Block a user