k8s.io/kubernetes@v1.29.3/pkg/registry/apps/deployment/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 deployment 18 19 import ( 20 "context" 21 "fmt" 22 23 appsv1beta1 "k8s.io/api/apps/v1beta1" 24 extensionsv1beta1 "k8s.io/api/extensions/v1beta1" 25 apiequality "k8s.io/apimachinery/pkg/api/equality" 26 apivalidation "k8s.io/apimachinery/pkg/api/validation" 27 "k8s.io/apimachinery/pkg/runtime" 28 "k8s.io/apimachinery/pkg/runtime/schema" 29 utilvalidation "k8s.io/apimachinery/pkg/util/validation" 30 "k8s.io/apimachinery/pkg/util/validation/field" 31 genericapirequest "k8s.io/apiserver/pkg/endpoints/request" 32 "k8s.io/apiserver/pkg/registry/rest" 33 "k8s.io/apiserver/pkg/storage/names" 34 "k8s.io/kubernetes/pkg/api/legacyscheme" 35 "k8s.io/kubernetes/pkg/api/pod" 36 "k8s.io/kubernetes/pkg/apis/apps" 37 appsvalidation "k8s.io/kubernetes/pkg/apis/apps/validation" 38 "sigs.k8s.io/structured-merge-diff/v4/fieldpath" 39 ) 40 41 // deploymentStrategy implements behavior for Deployments. 42 type deploymentStrategy struct { 43 runtime.ObjectTyper 44 names.NameGenerator 45 } 46 47 // Strategy is the default logic that applies when creating and updating Deployment 48 // objects via the REST API. 49 var Strategy = deploymentStrategy{legacyscheme.Scheme, names.SimpleNameGenerator} 50 51 // Make sure we correctly implement the interface. 52 var _ = rest.GarbageCollectionDeleteStrategy(Strategy) 53 54 // DefaultGarbageCollectionPolicy returns DeleteDependents for all currently served versions. 55 func (deploymentStrategy) DefaultGarbageCollectionPolicy(ctx context.Context) rest.GarbageCollectionPolicy { 56 return rest.DeleteDependents 57 } 58 59 // NamespaceScoped is true for deployment. 60 func (deploymentStrategy) NamespaceScoped() bool { 61 return true 62 } 63 64 // GetResetFields returns the set of fields that get reset by the strategy 65 // and should not be modified by the user. 66 func (deploymentStrategy) GetResetFields() map[fieldpath.APIVersion]*fieldpath.Set { 67 fields := map[fieldpath.APIVersion]*fieldpath.Set{ 68 "apps/v1": fieldpath.NewSet( 69 fieldpath.MakePathOrDie("status"), 70 ), 71 } 72 73 return fields 74 } 75 76 // PrepareForCreate clears fields that are not allowed to be set by end users on creation. 77 func (deploymentStrategy) PrepareForCreate(ctx context.Context, obj runtime.Object) { 78 deployment := obj.(*apps.Deployment) 79 deployment.Status = apps.DeploymentStatus{} 80 deployment.Generation = 1 81 82 pod.DropDisabledTemplateFields(&deployment.Spec.Template, nil) 83 } 84 85 // Validate validates a new deployment. 86 func (deploymentStrategy) Validate(ctx context.Context, obj runtime.Object) field.ErrorList { 87 deployment := obj.(*apps.Deployment) 88 opts := pod.GetValidationOptionsFromPodTemplate(&deployment.Spec.Template, nil) 89 return appsvalidation.ValidateDeployment(deployment, opts) 90 } 91 92 // WarningsOnCreate returns warnings for the creation of the given object. 93 func (deploymentStrategy) WarningsOnCreate(ctx context.Context, obj runtime.Object) []string { 94 newDeployment := obj.(*apps.Deployment) 95 var warnings []string 96 if msgs := utilvalidation.IsDNS1123Label(newDeployment.Name); len(msgs) != 0 { 97 warnings = append(warnings, fmt.Sprintf("metadata.name: this is used in Pod names and hostnames, which can result in surprising behavior; a DNS label is recommended: %v", msgs)) 98 } 99 warnings = append(warnings, pod.GetWarningsForPodTemplate(ctx, field.NewPath("spec", "template"), &newDeployment.Spec.Template, nil)...) 100 return warnings 101 } 102 103 // Canonicalize normalizes the object after validation. 104 func (deploymentStrategy) Canonicalize(obj runtime.Object) { 105 } 106 107 // AllowCreateOnUpdate is false for deployments. 108 func (deploymentStrategy) AllowCreateOnUpdate() bool { 109 return false 110 } 111 112 // PrepareForUpdate clears fields that are not allowed to be set by end users on update. 113 func (deploymentStrategy) PrepareForUpdate(ctx context.Context, obj, old runtime.Object) { 114 newDeployment := obj.(*apps.Deployment) 115 oldDeployment := old.(*apps.Deployment) 116 newDeployment.Status = oldDeployment.Status 117 118 pod.DropDisabledTemplateFields(&newDeployment.Spec.Template, &oldDeployment.Spec.Template) 119 120 // Spec updates bump the generation so that we can distinguish between 121 // scaling events and template changes, annotation updates bump the generation 122 // because annotations are copied from deployments to their replica sets. 123 if !apiequality.Semantic.DeepEqual(newDeployment.Spec, oldDeployment.Spec) || 124 !apiequality.Semantic.DeepEqual(newDeployment.Annotations, oldDeployment.Annotations) { 125 newDeployment.Generation = oldDeployment.Generation + 1 126 } 127 } 128 129 // ValidateUpdate is the default update validation for an end user. 130 func (deploymentStrategy) ValidateUpdate(ctx context.Context, obj, old runtime.Object) field.ErrorList { 131 newDeployment := obj.(*apps.Deployment) 132 oldDeployment := old.(*apps.Deployment) 133 134 opts := pod.GetValidationOptionsFromPodTemplate(&newDeployment.Spec.Template, &oldDeployment.Spec.Template) 135 allErrs := appsvalidation.ValidateDeploymentUpdate(newDeployment, oldDeployment, opts) 136 137 // Update is not allowed to set Spec.Selector for all groups/versions except extensions/v1beta1. 138 // If RequestInfo is nil, it is better to revert to old behavior (i.e. allow update to set Spec.Selector) 139 // to prevent unintentionally breaking users who may rely on the old behavior. 140 // TODO(#50791): after apps/v1beta1 and extensions/v1beta1 are removed, 141 // move selector immutability check inside ValidateDeploymentUpdate(). 142 if requestInfo, found := genericapirequest.RequestInfoFrom(ctx); found { 143 groupVersion := schema.GroupVersion{Group: requestInfo.APIGroup, Version: requestInfo.APIVersion} 144 switch groupVersion { 145 case appsv1beta1.SchemeGroupVersion, extensionsv1beta1.SchemeGroupVersion: 146 // no-op for compatibility 147 default: 148 // disallow mutation of selector 149 allErrs = append(allErrs, apivalidation.ValidateImmutableField(newDeployment.Spec.Selector, oldDeployment.Spec.Selector, field.NewPath("spec").Child("selector"))...) 150 } 151 } 152 153 return allErrs 154 } 155 156 // WarningsOnUpdate returns warnings for the given update. 157 func (deploymentStrategy) WarningsOnUpdate(ctx context.Context, obj, old runtime.Object) []string { 158 var warnings []string 159 newDeployment := obj.(*apps.Deployment) 160 oldDeployment := old.(*apps.Deployment) 161 if newDeployment.Generation != oldDeployment.Generation { 162 warnings = pod.GetWarningsForPodTemplate(ctx, field.NewPath("spec", "template"), &newDeployment.Spec.Template, &oldDeployment.Spec.Template) 163 } 164 return warnings 165 } 166 167 func (deploymentStrategy) AllowUnconditionalUpdate() bool { 168 return true 169 } 170 171 type deploymentStatusStrategy struct { 172 deploymentStrategy 173 } 174 175 // StatusStrategy is the default logic invoked when updating object status. 176 var StatusStrategy = deploymentStatusStrategy{Strategy} 177 178 // GetResetFields returns the set of fields that get reset by the strategy 179 // and should not be modified by the user. 180 func (deploymentStatusStrategy) GetResetFields() map[fieldpath.APIVersion]*fieldpath.Set { 181 return map[fieldpath.APIVersion]*fieldpath.Set{ 182 "apps/v1": fieldpath.NewSet( 183 fieldpath.MakePathOrDie("spec"), 184 fieldpath.MakePathOrDie("metadata", "labels"), 185 ), 186 } 187 } 188 189 // PrepareForUpdate clears fields that are not allowed to be set by end users on update of status 190 func (deploymentStatusStrategy) PrepareForUpdate(ctx context.Context, obj, old runtime.Object) { 191 newDeployment := obj.(*apps.Deployment) 192 oldDeployment := old.(*apps.Deployment) 193 newDeployment.Spec = oldDeployment.Spec 194 newDeployment.Labels = oldDeployment.Labels 195 } 196 197 // ValidateUpdate is the default update validation for an end user updating status 198 func (deploymentStatusStrategy) ValidateUpdate(ctx context.Context, obj, old runtime.Object) field.ErrorList { 199 return appsvalidation.ValidateDeploymentStatusUpdate(obj.(*apps.Deployment), old.(*apps.Deployment)) 200 } 201 202 // WarningsOnUpdate returns warnings for the given update. 203 func (deploymentStatusStrategy) WarningsOnUpdate(ctx context.Context, obj, old runtime.Object) []string { 204 return nil 205 }