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