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 }