k8s.io/kubernetes@v1.29.3/pkg/registry/autoscaling/horizontalpodautoscaler/strategy.go (about)

     1  /*
     2  Copyright 2015 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 horizontalpodautoscaler
    18  
    19  import (
    20  	"context"
    21  
    22  	"k8s.io/apimachinery/pkg/runtime"
    23  	"k8s.io/apimachinery/pkg/util/validation/field"
    24  	"k8s.io/apiserver/pkg/storage/names"
    25  	utilfeature "k8s.io/apiserver/pkg/util/feature"
    26  	"k8s.io/kubernetes/pkg/api/legacyscheme"
    27  	"k8s.io/kubernetes/pkg/apis/autoscaling"
    28  	"k8s.io/kubernetes/pkg/apis/autoscaling/validation"
    29  	"k8s.io/kubernetes/pkg/features"
    30  	"sigs.k8s.io/structured-merge-diff/v4/fieldpath"
    31  )
    32  
    33  // autoscalerStrategy implements behavior for HorizontalPodAutoscalers
    34  type autoscalerStrategy struct {
    35  	runtime.ObjectTyper
    36  	names.NameGenerator
    37  }
    38  
    39  // Strategy is the default logic that applies when creating and updating HorizontalPodAutoscaler
    40  // objects via the REST API.
    41  var Strategy = autoscalerStrategy{legacyscheme.Scheme, names.SimpleNameGenerator}
    42  
    43  // NamespaceScoped is true for autoscaler.
    44  func (autoscalerStrategy) NamespaceScoped() bool {
    45  	return true
    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 (autoscalerStrategy) GetResetFields() map[fieldpath.APIVersion]*fieldpath.Set {
    51  	fields := map[fieldpath.APIVersion]*fieldpath.Set{
    52  		"autoscaling/v1": fieldpath.NewSet(
    53  			fieldpath.MakePathOrDie("status"),
    54  		),
    55  		"autoscaling/v2": fieldpath.NewSet(
    56  			fieldpath.MakePathOrDie("status"),
    57  		),
    58  		"autoscaling/v2beta1": fieldpath.NewSet(
    59  			fieldpath.MakePathOrDie("status"),
    60  		),
    61  		"autoscaling/v2beta2": fieldpath.NewSet(
    62  			fieldpath.MakePathOrDie("status"),
    63  		),
    64  	}
    65  
    66  	return fields
    67  }
    68  
    69  // PrepareForCreate clears fields that are not allowed to be set by end users on creation.
    70  func (autoscalerStrategy) PrepareForCreate(ctx context.Context, obj runtime.Object) {
    71  	newHPA := obj.(*autoscaling.HorizontalPodAutoscaler)
    72  
    73  	// create cannot set status
    74  	newHPA.Status = autoscaling.HorizontalPodAutoscalerStatus{}
    75  
    76  	if !utilfeature.DefaultFeatureGate.Enabled(features.HPAContainerMetrics) {
    77  		dropContainerMetricSources(newHPA.Spec.Metrics)
    78  	}
    79  }
    80  
    81  // Validate validates a new autoscaler.
    82  func (autoscalerStrategy) Validate(ctx context.Context, obj runtime.Object) field.ErrorList {
    83  	autoscaler := obj.(*autoscaling.HorizontalPodAutoscaler)
    84  	return validation.ValidateHorizontalPodAutoscaler(autoscaler)
    85  }
    86  
    87  // WarningsOnCreate returns warnings for the creation of the given object.
    88  func (autoscalerStrategy) WarningsOnCreate(ctx context.Context, obj runtime.Object) []string {
    89  	return nil
    90  }
    91  
    92  // Canonicalize normalizes the object after validation.
    93  func (autoscalerStrategy) Canonicalize(obj runtime.Object) {
    94  }
    95  
    96  // AllowCreateOnUpdate is false for autoscalers.
    97  func (autoscalerStrategy) AllowCreateOnUpdate() bool {
    98  	return false
    99  }
   100  
   101  // PrepareForUpdate clears fields that are not allowed to be set by end users on update.
   102  func (autoscalerStrategy) PrepareForUpdate(ctx context.Context, obj, old runtime.Object) {
   103  	newHPA := obj.(*autoscaling.HorizontalPodAutoscaler)
   104  	oldHPA := old.(*autoscaling.HorizontalPodAutoscaler)
   105  	if !utilfeature.DefaultFeatureGate.Enabled(features.HPAContainerMetrics) && !hasContainerMetricSources(oldHPA) {
   106  		dropContainerMetricSources(newHPA.Spec.Metrics)
   107  	}
   108  	// Update is not allowed to set status
   109  	newHPA.Status = oldHPA.Status
   110  }
   111  
   112  // dropContainerMetricSources ensures all container resource metric sources are nil
   113  func dropContainerMetricSources(metrics []autoscaling.MetricSpec) {
   114  	for i := range metrics {
   115  		metrics[i].ContainerResource = nil
   116  	}
   117  }
   118  
   119  // hasContainerMetricSources returns true if the hpa has any container resource metric sources
   120  func hasContainerMetricSources(hpa *autoscaling.HorizontalPodAutoscaler) bool {
   121  	for i := range hpa.Spec.Metrics {
   122  		if hpa.Spec.Metrics[i].ContainerResource != nil {
   123  			return true
   124  		}
   125  	}
   126  	return false
   127  }
   128  
   129  // ValidateUpdate is the default update validation for an end user.
   130  func (autoscalerStrategy) ValidateUpdate(ctx context.Context, obj, old runtime.Object) field.ErrorList {
   131  	return validation.ValidateHorizontalPodAutoscalerUpdate(obj.(*autoscaling.HorizontalPodAutoscaler), old.(*autoscaling.HorizontalPodAutoscaler))
   132  }
   133  
   134  // WarningsOnUpdate returns warnings for the given update.
   135  func (autoscalerStrategy) WarningsOnUpdate(ctx context.Context, obj, old runtime.Object) []string {
   136  	return nil
   137  }
   138  
   139  func (autoscalerStrategy) AllowUnconditionalUpdate() bool {
   140  	return true
   141  }
   142  
   143  type autoscalerStatusStrategy struct {
   144  	autoscalerStrategy
   145  }
   146  
   147  // StatusStrategy is the default logic invoked when updating object status.
   148  var StatusStrategy = autoscalerStatusStrategy{Strategy}
   149  
   150  // GetResetFields returns the set of fields that get reset by the strategy
   151  // and should not be modified by the user.
   152  func (autoscalerStatusStrategy) GetResetFields() map[fieldpath.APIVersion]*fieldpath.Set {
   153  	fields := map[fieldpath.APIVersion]*fieldpath.Set{
   154  		"autoscaling/v1": fieldpath.NewSet(
   155  			fieldpath.MakePathOrDie("spec"),
   156  		),
   157  		"autoscaling/v2": fieldpath.NewSet(
   158  			fieldpath.MakePathOrDie("spec"),
   159  		),
   160  		"autoscaling/v2beta1": fieldpath.NewSet(
   161  			fieldpath.MakePathOrDie("spec"),
   162  		),
   163  		"autoscaling/v2beta2": fieldpath.NewSet(
   164  			fieldpath.MakePathOrDie("spec"),
   165  		),
   166  	}
   167  
   168  	return fields
   169  }
   170  
   171  func (autoscalerStatusStrategy) PrepareForUpdate(ctx context.Context, obj, old runtime.Object) {
   172  	newAutoscaler := obj.(*autoscaling.HorizontalPodAutoscaler)
   173  	oldAutoscaler := old.(*autoscaling.HorizontalPodAutoscaler)
   174  	// status changes are not allowed to update spec
   175  	newAutoscaler.Spec = oldAutoscaler.Spec
   176  }
   177  
   178  func (autoscalerStatusStrategy) ValidateUpdate(ctx context.Context, obj, old runtime.Object) field.ErrorList {
   179  	return validation.ValidateHorizontalPodAutoscalerStatusUpdate(obj.(*autoscaling.HorizontalPodAutoscaler), old.(*autoscaling.HorizontalPodAutoscaler))
   180  }
   181  
   182  // WarningsOnUpdate returns warnings for the given update.
   183  func (autoscalerStatusStrategy) WarningsOnUpdate(ctx context.Context, obj, old runtime.Object) []string {
   184  	return nil
   185  }