Add CrossNamespacePodAffinity quota scope and PodAffinityTerm.NamespaceSelector APIs, and CrossNamespacePodAffinity quota scope implementation.

This commit is contained in:
Abdullah Gharaibeh
2021-01-26 14:28:35 -05:00
parent 4f9317596c
commit 3c5f018f8e
85 changed files with 11392 additions and 3610 deletions

View File

@@ -3564,7 +3564,9 @@ func ValidatePreferredSchedulingTerms(terms []core.PreferredSchedulingTerm, fldP
func validatePodAffinityTerm(podAffinityTerm core.PodAffinityTerm, fldPath *field.Path) field.ErrorList {
allErrs := field.ErrorList{}
allErrs = append(allErrs, unversionedvalidation.ValidateLabelSelector(podAffinityTerm.LabelSelector, fldPath.Child("matchExpressions"))...)
allErrs = append(allErrs, unversionedvalidation.ValidateLabelSelector(podAffinityTerm.LabelSelector, fldPath.Child("labelSelector"))...)
allErrs = append(allErrs, unversionedvalidation.ValidateLabelSelector(podAffinityTerm.NamespaceSelector, fldPath.Child("namespaceSelector"))...)
for _, name := range podAffinityTerm.Namespaces {
for _, msg := range ValidateNamespaceName(name, false) {
allErrs = append(allErrs, field.Invalid(fldPath.Child("namespace"), name, msg))
@@ -5380,7 +5382,7 @@ func ValidateResourceRequirements(requirements *core.ResourceRequirements, fldPa
}
// validateResourceQuotaScopes ensures that each enumerated hard resource constraint is valid for set of scopes
func validateResourceQuotaScopes(resourceQuotaSpec *core.ResourceQuotaSpec, fld *field.Path) field.ErrorList {
func validateResourceQuotaScopes(resourceQuotaSpec *core.ResourceQuotaSpec, opts ResourceQuotaValidationOptions, fld *field.Path) field.ErrorList {
allErrs := field.ErrorList{}
if len(resourceQuotaSpec.Scopes) == 0 {
return allErrs
@@ -5392,7 +5394,7 @@ func validateResourceQuotaScopes(resourceQuotaSpec *core.ResourceQuotaSpec, fld
fldPath := fld.Child("scopes")
scopeSet := sets.NewString()
for _, scope := range resourceQuotaSpec.Scopes {
if !helper.IsStandardResourceQuotaScope(string(scope)) {
if !helper.IsStandardResourceQuotaScope(string(scope), opts.AllowPodAffinityNamespaceSelector) {
allErrs = append(allErrs, field.Invalid(fldPath, resourceQuotaSpec.Scopes, "unsupported scope"))
}
for _, k := range hardLimits.List() {
@@ -5415,7 +5417,7 @@ func validateResourceQuotaScopes(resourceQuotaSpec *core.ResourceQuotaSpec, fld
}
// validateScopedResourceSelectorRequirement tests that the match expressions has valid data
func validateScopedResourceSelectorRequirement(resourceQuotaSpec *core.ResourceQuotaSpec, fld *field.Path) field.ErrorList {
func validateScopedResourceSelectorRequirement(resourceQuotaSpec *core.ResourceQuotaSpec, opts ResourceQuotaValidationOptions, fld *field.Path) field.ErrorList {
allErrs := field.ErrorList{}
hardLimits := sets.NewString()
for k := range resourceQuotaSpec.Hard {
@@ -5424,7 +5426,7 @@ func validateScopedResourceSelectorRequirement(resourceQuotaSpec *core.ResourceQ
fldPath := fld.Child("matchExpressions")
scopeSet := sets.NewString()
for _, req := range resourceQuotaSpec.ScopeSelector.MatchExpressions {
if !helper.IsStandardResourceQuotaScope(string(req.ScopeName)) {
if !helper.IsStandardResourceQuotaScope(string(req.ScopeName), opts.AllowPodAffinityNamespaceSelector) {
allErrs = append(allErrs, field.Invalid(fldPath.Child("scopeName"), req.ScopeName, "unsupported scope"))
}
for _, k := range hardLimits.List() {
@@ -5433,10 +5435,10 @@ func validateScopedResourceSelectorRequirement(resourceQuotaSpec *core.ResourceQ
}
}
switch req.ScopeName {
case core.ResourceQuotaScopeBestEffort, core.ResourceQuotaScopeNotBestEffort, core.ResourceQuotaScopeTerminating, core.ResourceQuotaScopeNotTerminating:
case core.ResourceQuotaScopeBestEffort, core.ResourceQuotaScopeNotBestEffort, core.ResourceQuotaScopeTerminating, core.ResourceQuotaScopeNotTerminating, core.ResourceQuotaScopeCrossNamespacePodAffinity:
if req.Operator != core.ScopeSelectorOpExists {
allErrs = append(allErrs, field.Invalid(fldPath.Child("operator"), req.Operator,
"must be 'Exist' only operator when scope is any of ResourceQuotaScopeTerminating, ResourceQuotaScopeNotTerminating, ResourceQuotaScopeBestEffort and ResourceQuotaScopeNotBestEffort"))
"must be 'Exist' when scope is any of ResourceQuotaScopeTerminating, ResourceQuotaScopeNotTerminating, ResourceQuotaScopeBestEffort, ResourceQuotaScopeNotBestEffort or ResourceQuotaScopeCrossNamespacePodAffinity"))
}
}
@@ -5470,20 +5472,26 @@ func validateScopedResourceSelectorRequirement(resourceQuotaSpec *core.ResourceQ
}
// validateScopeSelector tests that the specified scope selector has valid data
func validateScopeSelector(resourceQuotaSpec *core.ResourceQuotaSpec, fld *field.Path) field.ErrorList {
func validateScopeSelector(resourceQuotaSpec *core.ResourceQuotaSpec, opts ResourceQuotaValidationOptions, fld *field.Path) field.ErrorList {
allErrs := field.ErrorList{}
if resourceQuotaSpec.ScopeSelector == nil {
return allErrs
}
allErrs = append(allErrs, validateScopedResourceSelectorRequirement(resourceQuotaSpec, fld.Child("scopeSelector"))...)
allErrs = append(allErrs, validateScopedResourceSelectorRequirement(resourceQuotaSpec, opts, fld.Child("scopeSelector"))...)
return allErrs
}
// ResourceQuotaValidationOptions contains the different settings for ResourceQuota validation
type ResourceQuotaValidationOptions struct {
// Allow pod-affinity namespace selector validation.
AllowPodAffinityNamespaceSelector bool
}
// ValidateResourceQuota tests if required fields in the ResourceQuota are set.
func ValidateResourceQuota(resourceQuota *core.ResourceQuota) field.ErrorList {
func ValidateResourceQuota(resourceQuota *core.ResourceQuota, opts ResourceQuotaValidationOptions) field.ErrorList {
allErrs := ValidateObjectMeta(&resourceQuota.ObjectMeta, true, ValidateResourceQuotaName, field.NewPath("metadata"))
allErrs = append(allErrs, ValidateResourceQuotaSpec(&resourceQuota.Spec, field.NewPath("spec"))...)
allErrs = append(allErrs, ValidateResourceQuotaSpec(&resourceQuota.Spec, opts, field.NewPath("spec"))...)
allErrs = append(allErrs, ValidateResourceQuotaStatus(&resourceQuota.Status, field.NewPath("status"))...)
return allErrs
@@ -5508,7 +5516,7 @@ func ValidateResourceQuotaStatus(status *core.ResourceQuotaStatus, fld *field.Pa
return allErrs
}
func ValidateResourceQuotaSpec(resourceQuotaSpec *core.ResourceQuotaSpec, fld *field.Path) field.ErrorList {
func ValidateResourceQuotaSpec(resourceQuotaSpec *core.ResourceQuotaSpec, opts ResourceQuotaValidationOptions, fld *field.Path) field.ErrorList {
allErrs := field.ErrorList{}
fldPath := fld.Child("hard")
@@ -5517,8 +5525,9 @@ func ValidateResourceQuotaSpec(resourceQuotaSpec *core.ResourceQuotaSpec, fld *f
allErrs = append(allErrs, ValidateResourceQuotaResourceName(string(k), resPath)...)
allErrs = append(allErrs, ValidateResourceQuantityValue(string(k), v, resPath)...)
}
allErrs = append(allErrs, validateResourceQuotaScopes(resourceQuotaSpec, fld)...)
allErrs = append(allErrs, validateScopeSelector(resourceQuotaSpec, fld)...)
allErrs = append(allErrs, validateResourceQuotaScopes(resourceQuotaSpec, opts, fld)...)
allErrs = append(allErrs, validateScopeSelector(resourceQuotaSpec, opts, fld)...)
return allErrs
}
@@ -5537,9 +5546,9 @@ func ValidateResourceQuantityValue(resource string, value resource.Quantity, fld
// ValidateResourceQuotaUpdate tests to see if the update is legal for an end user to make.
// newResourceQuota is updated with fields that cannot be changed.
func ValidateResourceQuotaUpdate(newResourceQuota, oldResourceQuota *core.ResourceQuota) field.ErrorList {
func ValidateResourceQuotaUpdate(newResourceQuota, oldResourceQuota *core.ResourceQuota, opts ResourceQuotaValidationOptions) field.ErrorList {
allErrs := ValidateObjectMetaUpdate(&newResourceQuota.ObjectMeta, &oldResourceQuota.ObjectMeta, field.NewPath("metadata"))
allErrs = append(allErrs, ValidateResourceQuotaSpec(&newResourceQuota.Spec, field.NewPath("spec"))...)
allErrs = append(allErrs, ValidateResourceQuotaSpec(&newResourceQuota.Spec, opts, field.NewPath("spec"))...)
// ensure scopes cannot change, and that resources are still valid for scope
fldPath := field.NewPath("spec", "scopes")