k8s.io/kubernetes@v1.31.0-alpha.0.0.20240520171757-56147500dadc/pkg/registry/flowcontrol/prioritylevelconfiguration/strategy.go (about) 1 /* 2 Copyright 2019 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 prioritylevelconfiguration 18 19 import ( 20 "context" 21 22 apiequality "k8s.io/apimachinery/pkg/api/equality" 23 "k8s.io/apimachinery/pkg/runtime" 24 "k8s.io/apimachinery/pkg/runtime/schema" 25 "k8s.io/apimachinery/pkg/util/validation/field" 26 genericapirequest "k8s.io/apiserver/pkg/endpoints/request" 27 "k8s.io/apiserver/pkg/storage/names" 28 "k8s.io/kubernetes/pkg/api/legacyscheme" 29 "k8s.io/kubernetes/pkg/apis/flowcontrol" 30 "k8s.io/kubernetes/pkg/apis/flowcontrol/validation" 31 "sigs.k8s.io/structured-merge-diff/v4/fieldpath" 32 ) 33 34 // priorityLevelConfigurationStrategy implements verification logic for priority level configurations. 35 type priorityLevelConfigurationStrategy struct { 36 runtime.ObjectTyper 37 names.NameGenerator 38 } 39 40 // Strategy is the default logic that applies when creating and updating priority level configuration objects. 41 var Strategy = priorityLevelConfigurationStrategy{legacyscheme.Scheme, names.SimpleNameGenerator} 42 43 // NamespaceScoped returns false because all PriorityClasses are global. 44 func (priorityLevelConfigurationStrategy) NamespaceScoped() bool { 45 return false 46 } 47 48 // GetResetFields returns the set of fields that get reset by the strategy 49 // and should not be modified by the user. 50 func (priorityLevelConfigurationStrategy) GetResetFields() map[fieldpath.APIVersion]*fieldpath.Set { 51 fields := map[fieldpath.APIVersion]*fieldpath.Set{ 52 "flowcontrol.apiserver.k8s.io/v1beta1": fieldpath.NewSet( 53 fieldpath.MakePathOrDie("status"), 54 ), 55 "flowcontrol.apiserver.k8s.io/v1beta2": fieldpath.NewSet( 56 fieldpath.MakePathOrDie("status"), 57 ), 58 "flowcontrol.apiserver.k8s.io/v1beta3": fieldpath.NewSet( 59 fieldpath.MakePathOrDie("status"), 60 ), 61 "flowcontrol.apiserver.k8s.io/v1": fieldpath.NewSet( 62 fieldpath.MakePathOrDie("status"), 63 ), 64 } 65 66 return fields 67 } 68 69 // PrepareForCreate clears the status of a priority-level-configuration before creation. 70 func (priorityLevelConfigurationStrategy) PrepareForCreate(ctx context.Context, obj runtime.Object) { 71 pl := obj.(*flowcontrol.PriorityLevelConfiguration) 72 pl.Status = flowcontrol.PriorityLevelConfigurationStatus{} 73 pl.Generation = 1 74 } 75 76 // PrepareForUpdate clears fields that are not allowed to be set by end users on update. 77 func (priorityLevelConfigurationStrategy) PrepareForUpdate(ctx context.Context, obj, old runtime.Object) { 78 newPriorityLevelConfiguration := obj.(*flowcontrol.PriorityLevelConfiguration) 79 oldPriorityLevelConfiguration := old.(*flowcontrol.PriorityLevelConfiguration) 80 81 // Spec updates bump the generation so that we can distinguish between status updates. 82 if !apiequality.Semantic.DeepEqual(newPriorityLevelConfiguration.Spec, oldPriorityLevelConfiguration.Spec) { 83 newPriorityLevelConfiguration.Generation = oldPriorityLevelConfiguration.Generation + 1 84 } 85 newPriorityLevelConfiguration.Status = oldPriorityLevelConfiguration.Status 86 } 87 88 // Validate validates a new priority-level. 89 func (priorityLevelConfigurationStrategy) Validate(ctx context.Context, obj runtime.Object) field.ErrorList { 90 // 1.28 server is not aware of the roundtrip annotation, and will 91 // default any 0 value persisted (for the NominalConcurrencyShares 92 // field of a priority level configuration object) back to 30 when 93 // reading from etcd. 94 // That means we should not allow 0 values to be introduced, either 95 // via v1 or v1beta3(with the roundtrip annotation) until we know 96 // all servers are at 1.29+ and will honor the zero value correctly. 97 // 98 // TODO(121510): 1.29: don't allow a zero value, either via v1 or 99 // v1beta3 (with the roundtrip annotation) for the 100 // 'nominalConcurrencyShares' field of 'limited' for CREATE operation. 101 // 1:30: lift this restriction, allow zero value via v1 or v1beta3 102 opts := validation.PriorityLevelValidationOptions{ 103 AllowZeroLimitedNominalConcurrencyShares: true, 104 } 105 return validation.ValidatePriorityLevelConfiguration(obj.(*flowcontrol.PriorityLevelConfiguration), getRequestGroupVersion(ctx), opts) 106 } 107 108 // WarningsOnCreate returns warnings for the creation of the given object. 109 func (priorityLevelConfigurationStrategy) WarningsOnCreate(ctx context.Context, obj runtime.Object) []string { 110 return nil 111 } 112 113 // Canonicalize normalizes the object after validation. 114 func (priorityLevelConfigurationStrategy) Canonicalize(obj runtime.Object) { 115 } 116 117 func (priorityLevelConfigurationStrategy) AllowUnconditionalUpdate() bool { 118 return true 119 } 120 121 // AllowCreateOnUpdate is false for priority-level-configurations; this means a POST is needed to create one. 122 func (priorityLevelConfigurationStrategy) AllowCreateOnUpdate() bool { 123 return false 124 } 125 126 // ValidateUpdate is the default update validation for an end user. 127 func (priorityLevelConfigurationStrategy) ValidateUpdate(ctx context.Context, obj, old runtime.Object) field.ErrorList { 128 newPL := obj.(*flowcontrol.PriorityLevelConfiguration) 129 130 // 1.28 server is not aware of the roundtrip annotation, and will 131 // default any 0 value persisted (for the NominalConcurrencyShares 132 // field of a priority level configuration object) back to 30 when 133 // reading from etcd. 134 // That means we should not allow 0 values to be introduced, either 135 // via v1 or v1beta3(with the roundtrip annotation) until we know 136 // all servers are at 1.29+ and will honor the zero value correctly. 137 // 138 // TODO(121510): 1.29: only allow a zero value, either via v1 or 139 // v1beta3 (with the roundtrip annotation) for the 140 // 'nominalConcurrencyShares' field of 'limited' for UPDATE operation, 141 // only if the existing object already contains a zero value. 142 // 1:30: lift this restriction, allow zero value via v1 or v1beta3 143 opts := validation.PriorityLevelValidationOptions{ 144 AllowZeroLimitedNominalConcurrencyShares: true, 145 } 146 return validation.ValidatePriorityLevelConfiguration(newPL, getRequestGroupVersion(ctx), opts) 147 } 148 149 // WarningsOnUpdate returns warnings for the given update. 150 func (priorityLevelConfigurationStrategy) WarningsOnUpdate(ctx context.Context, obj, old runtime.Object) []string { 151 return nil 152 } 153 154 type priorityLevelConfigurationStatusStrategy struct { 155 priorityLevelConfigurationStrategy 156 } 157 158 // StatusStrategy is the default logic that applies when updating priority level configuration objects' status. 159 var StatusStrategy = priorityLevelConfigurationStatusStrategy{Strategy} 160 161 // GetResetFields returns the set of fields that get reset by the strategy 162 // and should not be modified by the user. 163 func (priorityLevelConfigurationStatusStrategy) GetResetFields() map[fieldpath.APIVersion]*fieldpath.Set { 164 fields := map[fieldpath.APIVersion]*fieldpath.Set{ 165 "flowcontrol.apiserver.k8s.io/v1beta1": fieldpath.NewSet( 166 fieldpath.MakePathOrDie("spec"), 167 fieldpath.MakePathOrDie("metadata"), 168 ), 169 "flowcontrol.apiserver.k8s.io/v1beta2": fieldpath.NewSet( 170 fieldpath.MakePathOrDie("spec"), 171 fieldpath.MakePathOrDie("metadata"), 172 ), 173 "flowcontrol.apiserver.k8s.io/v1beta3": fieldpath.NewSet( 174 fieldpath.MakePathOrDie("spec"), 175 fieldpath.MakePathOrDie("metadata"), 176 ), 177 "flowcontrol.apiserver.k8s.io/v1": fieldpath.NewSet( 178 fieldpath.MakePathOrDie("spec"), 179 fieldpath.MakePathOrDie("metadata"), 180 ), 181 } 182 183 return fields 184 } 185 186 func (priorityLevelConfigurationStatusStrategy) PrepareForUpdate(ctx context.Context, obj, old runtime.Object) { 187 newPriorityLevelConfiguration := obj.(*flowcontrol.PriorityLevelConfiguration) 188 oldPriorityLevelConfiguration := old.(*flowcontrol.PriorityLevelConfiguration) 189 190 // managedFields must be preserved since it's been modified to 191 // track changed fields in the status update. 192 managedFields := newPriorityLevelConfiguration.ManagedFields 193 newPriorityLevelConfiguration.ObjectMeta = oldPriorityLevelConfiguration.ObjectMeta 194 newPriorityLevelConfiguration.ManagedFields = managedFields 195 newPriorityLevelConfiguration.Spec = oldPriorityLevelConfiguration.Spec 196 } 197 198 func (priorityLevelConfigurationStatusStrategy) ValidateUpdate(ctx context.Context, obj, old runtime.Object) field.ErrorList { 199 return validation.ValidatePriorityLevelConfigurationStatusUpdate(old.(*flowcontrol.PriorityLevelConfiguration), obj.(*flowcontrol.PriorityLevelConfiguration)) 200 } 201 202 // WarningsOnUpdate returns warnings for the given update. 203 func (priorityLevelConfigurationStatusStrategy) WarningsOnUpdate(ctx context.Context, obj, old runtime.Object) []string { 204 return nil 205 } 206 207 func getRequestGroupVersion(ctx context.Context) schema.GroupVersion { 208 if requestInfo, exists := genericapirequest.RequestInfoFrom(ctx); exists { 209 return schema.GroupVersion{Group: requestInfo.APIGroup, Version: requestInfo.APIVersion} 210 } 211 return schema.GroupVersion{} 212 }