k8s.io/kubernetes@v1.29.3/pkg/apis/policy/validation/validation.go (about) 1 /* 2 Copyright 2016 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package validation 18 19 import ( 20 "regexp" 21 22 policyapiv1beta1 "k8s.io/api/policy/v1beta1" 23 unversionedvalidation "k8s.io/apimachinery/pkg/apis/meta/v1/validation" 24 "k8s.io/apimachinery/pkg/runtime/schema" 25 "k8s.io/apimachinery/pkg/util/sets" 26 "k8s.io/apimachinery/pkg/util/validation/field" 27 appsvalidation "k8s.io/kubernetes/pkg/apis/apps/validation" 28 apivalidation "k8s.io/kubernetes/pkg/apis/core/validation" 29 "k8s.io/kubernetes/pkg/apis/policy" 30 ) 31 32 var supportedUnhealthyPodEvictionPolicies = sets.NewString( 33 string(policy.IfHealthyBudget), 34 string(policy.AlwaysAllow), 35 ) 36 37 type PodDisruptionBudgetValidationOptions struct { 38 AllowInvalidLabelValueInSelector bool 39 } 40 41 // ValidatePodDisruptionBudget validates a PodDisruptionBudget and returns an ErrorList 42 // with any errors. 43 func ValidatePodDisruptionBudget(pdb *policy.PodDisruptionBudget, opts PodDisruptionBudgetValidationOptions) field.ErrorList { 44 allErrs := ValidatePodDisruptionBudgetSpec(pdb.Spec, opts, field.NewPath("spec")) 45 return allErrs 46 } 47 48 // ValidatePodDisruptionBudgetSpec validates a PodDisruptionBudgetSpec and returns an ErrorList 49 // with any errors. 50 func ValidatePodDisruptionBudgetSpec(spec policy.PodDisruptionBudgetSpec, opts PodDisruptionBudgetValidationOptions, fldPath *field.Path) field.ErrorList { 51 allErrs := field.ErrorList{} 52 53 if spec.MinAvailable != nil && spec.MaxUnavailable != nil { 54 allErrs = append(allErrs, field.Invalid(fldPath, spec, "minAvailable and maxUnavailable cannot be both set")) 55 } 56 57 if spec.MinAvailable != nil { 58 allErrs = append(allErrs, appsvalidation.ValidatePositiveIntOrPercent(*spec.MinAvailable, fldPath.Child("minAvailable"))...) 59 allErrs = append(allErrs, appsvalidation.IsNotMoreThan100Percent(*spec.MinAvailable, fldPath.Child("minAvailable"))...) 60 } 61 62 if spec.MaxUnavailable != nil { 63 allErrs = append(allErrs, appsvalidation.ValidatePositiveIntOrPercent(*spec.MaxUnavailable, fldPath.Child("maxUnavailable"))...) 64 allErrs = append(allErrs, appsvalidation.IsNotMoreThan100Percent(*spec.MaxUnavailable, fldPath.Child("maxUnavailable"))...) 65 } 66 67 labelSelectorValidationOptions := unversionedvalidation.LabelSelectorValidationOptions{AllowInvalidLabelValueInSelector: opts.AllowInvalidLabelValueInSelector} 68 69 allErrs = append(allErrs, unversionedvalidation.ValidateLabelSelector(spec.Selector, labelSelectorValidationOptions, fldPath.Child("selector"))...) 70 71 if spec.UnhealthyPodEvictionPolicy != nil && !supportedUnhealthyPodEvictionPolicies.Has(string(*spec.UnhealthyPodEvictionPolicy)) { 72 allErrs = append(allErrs, field.NotSupported(fldPath.Child("unhealthyPodEvictionPolicy"), *spec.UnhealthyPodEvictionPolicy, supportedUnhealthyPodEvictionPolicies.List())) 73 } 74 75 return allErrs 76 } 77 78 // ValidatePodDisruptionBudgetStatusUpdate validates a PodDisruptionBudgetStatus and returns an ErrorList 79 // with any errors. 80 func ValidatePodDisruptionBudgetStatusUpdate(status, oldStatus policy.PodDisruptionBudgetStatus, fldPath *field.Path, apiVersion schema.GroupVersion) field.ErrorList { 81 allErrs := field.ErrorList{} 82 allErrs = append(allErrs, unversionedvalidation.ValidateConditions(status.Conditions, fldPath.Child("conditions"))...) 83 // Don't run other validations for v1beta1 since we don't want to introduce 84 // new validations retroactively. 85 if apiVersion == policyapiv1beta1.SchemeGroupVersion { 86 return allErrs 87 } 88 allErrs = append(allErrs, apivalidation.ValidateNonnegativeField(int64(status.DisruptionsAllowed), fldPath.Child("disruptionsAllowed"))...) 89 allErrs = append(allErrs, apivalidation.ValidateNonnegativeField(int64(status.CurrentHealthy), fldPath.Child("currentHealthy"))...) 90 allErrs = append(allErrs, apivalidation.ValidateNonnegativeField(int64(status.DesiredHealthy), fldPath.Child("desiredHealthy"))...) 91 allErrs = append(allErrs, apivalidation.ValidateNonnegativeField(int64(status.ExpectedPods), fldPath.Child("expectedPods"))...) 92 return allErrs 93 } 94 95 const sysctlPatternSegmentFmt string = "([a-z0-9][-_a-z0-9]*)?[a-z0-9*]" 96 97 // SysctlContainSlashPatternFmt is a regex that contains a slash used for matching valid sysctl patterns. 98 const SysctlContainSlashPatternFmt string = "(" + apivalidation.SysctlSegmentFmt + "[\\./])*" + sysctlPatternSegmentFmt 99 100 var sysctlContainSlashPatternRegexp = regexp.MustCompile("^" + SysctlContainSlashPatternFmt + "$") 101 102 // IsValidSysctlPattern checks if name is a valid sysctl pattern. 103 // i.e. matches sysctlContainSlashPatternRegexp. 104 // More info: 105 // 106 // https://man7.org/linux/man-pages/man8/sysctl.8.html 107 // https://man7.org/linux/man-pages/man5/sysctl.d.5.html 108 func IsValidSysctlPattern(name string) bool { 109 if len(name) > apivalidation.SysctlMaxLength { 110 return false 111 } 112 return sysctlContainSlashPatternRegexp.MatchString(name) 113 }