k8s.io/kubernetes@v1.29.3/pkg/registry/core/replicationcontroller/strategy.go (about) 1 /* 2 Copyright 2014 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 // If you make changes to this file, you should also make the corresponding change in ReplicaSet. 18 19 package replicationcontroller 20 21 import ( 22 "context" 23 "fmt" 24 "strconv" 25 "strings" 26 27 corev1 "k8s.io/api/core/v1" 28 apiequality "k8s.io/apimachinery/pkg/api/equality" 29 "k8s.io/apimachinery/pkg/fields" 30 "k8s.io/apimachinery/pkg/labels" 31 "k8s.io/apimachinery/pkg/runtime" 32 "k8s.io/apimachinery/pkg/runtime/schema" 33 utilvalidation "k8s.io/apimachinery/pkg/util/validation" 34 "k8s.io/apimachinery/pkg/util/validation/field" 35 genericapirequest "k8s.io/apiserver/pkg/endpoints/request" 36 "k8s.io/apiserver/pkg/registry/generic" 37 "k8s.io/apiserver/pkg/registry/rest" 38 apistorage "k8s.io/apiserver/pkg/storage" 39 "k8s.io/apiserver/pkg/storage/names" 40 "k8s.io/kubernetes/pkg/api/legacyscheme" 41 "k8s.io/kubernetes/pkg/api/pod" 42 api "k8s.io/kubernetes/pkg/apis/core" 43 "k8s.io/kubernetes/pkg/apis/core/helper" 44 corevalidation "k8s.io/kubernetes/pkg/apis/core/validation" 45 "sigs.k8s.io/structured-merge-diff/v4/fieldpath" 46 ) 47 48 // rcStrategy implements verification logic for Replication Controllers. 49 type rcStrategy struct { 50 runtime.ObjectTyper 51 names.NameGenerator 52 } 53 54 // Strategy is the default logic that applies when creating and updating Replication Controller objects. 55 var Strategy = rcStrategy{legacyscheme.Scheme, names.SimpleNameGenerator} 56 57 // DefaultGarbageCollectionPolicy returns OrphanDependents for v1 for backwards compatibility, 58 // and DeleteDependents for all other versions. 59 func (rcStrategy) DefaultGarbageCollectionPolicy(ctx context.Context) rest.GarbageCollectionPolicy { 60 var groupVersion schema.GroupVersion 61 if requestInfo, found := genericapirequest.RequestInfoFrom(ctx); found { 62 groupVersion = schema.GroupVersion{Group: requestInfo.APIGroup, Version: requestInfo.APIVersion} 63 } 64 switch groupVersion { 65 case corev1.SchemeGroupVersion: 66 // for back compatibility 67 return rest.OrphanDependents 68 default: 69 return rest.DeleteDependents 70 } 71 } 72 73 // NamespaceScoped returns true because all Replication Controllers need to be within a namespace. 74 func (rcStrategy) NamespaceScoped() bool { 75 return true 76 } 77 78 // GetResetFields returns the set of fields that get reset by the strategy 79 // and should not be modified by the user. 80 func (rcStrategy) GetResetFields() map[fieldpath.APIVersion]*fieldpath.Set { 81 fields := map[fieldpath.APIVersion]*fieldpath.Set{ 82 "v1": fieldpath.NewSet( 83 fieldpath.MakePathOrDie("status"), 84 ), 85 } 86 87 return fields 88 } 89 90 // PrepareForCreate clears the status of a replication controller before creation. 91 func (rcStrategy) PrepareForCreate(ctx context.Context, obj runtime.Object) { 92 controller := obj.(*api.ReplicationController) 93 controller.Status = api.ReplicationControllerStatus{} 94 95 controller.Generation = 1 96 97 pod.DropDisabledTemplateFields(controller.Spec.Template, nil) 98 } 99 100 // PrepareForUpdate clears fields that are not allowed to be set by end users on update. 101 func (rcStrategy) PrepareForUpdate(ctx context.Context, obj, old runtime.Object) { 102 newController := obj.(*api.ReplicationController) 103 oldController := old.(*api.ReplicationController) 104 // update is not allowed to set status 105 newController.Status = oldController.Status 106 107 pod.DropDisabledTemplateFields(newController.Spec.Template, oldController.Spec.Template) 108 109 // Any changes to the spec increment the generation number, any changes to the 110 // status should reflect the generation number of the corresponding object. We push 111 // the burden of managing the status onto the clients because we can't (in general) 112 // know here what version of spec the writer of the status has seen. It may seem like 113 // we can at first -- since obj contains spec -- but in the future we will probably make 114 // status its own object, and even if we don't, writes may be the result of a 115 // read-update-write loop, so the contents of spec may not actually be the spec that 116 // the controller has *seen*. 117 if !apiequality.Semantic.DeepEqual(oldController.Spec, newController.Spec) { 118 newController.Generation = oldController.Generation + 1 119 } 120 } 121 122 // Validate validates a new replication controller. 123 func (rcStrategy) Validate(ctx context.Context, obj runtime.Object) field.ErrorList { 124 controller := obj.(*api.ReplicationController) 125 opts := pod.GetValidationOptionsFromPodTemplate(controller.Spec.Template, nil) 126 return corevalidation.ValidateReplicationController(controller, opts) 127 } 128 129 // WarningsOnCreate returns warnings for the creation of the given object. 130 func (rcStrategy) WarningsOnCreate(ctx context.Context, obj runtime.Object) []string { 131 newRC := obj.(*api.ReplicationController) 132 var warnings []string 133 if msgs := utilvalidation.IsDNS1123Label(newRC.Name); len(msgs) != 0 { 134 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)) 135 } 136 warnings = append(warnings, pod.GetWarningsForPodTemplate(ctx, field.NewPath("spec", "template"), newRC.Spec.Template, nil)...) 137 return warnings 138 } 139 140 // Canonicalize normalizes the object after validation. 141 func (rcStrategy) Canonicalize(obj runtime.Object) { 142 } 143 144 // AllowCreateOnUpdate is false for replication controllers; this means a POST is 145 // needed to create one. 146 func (rcStrategy) AllowCreateOnUpdate() bool { 147 return false 148 } 149 150 // ValidateUpdate is the default update validation for an end user. 151 func (rcStrategy) ValidateUpdate(ctx context.Context, obj, old runtime.Object) field.ErrorList { 152 oldRc := old.(*api.ReplicationController) 153 newRc := obj.(*api.ReplicationController) 154 155 opts := pod.GetValidationOptionsFromPodTemplate(newRc.Spec.Template, oldRc.Spec.Template) 156 validationErrorList := corevalidation.ValidateReplicationController(newRc, opts) 157 updateErrorList := corevalidation.ValidateReplicationControllerUpdate(newRc, oldRc, opts) 158 errs := append(validationErrorList, updateErrorList...) 159 160 for key, value := range helper.NonConvertibleFields(oldRc.Annotations) { 161 parts := strings.Split(key, "/") 162 if len(parts) != 2 { 163 continue 164 } 165 brokenField := parts[1] 166 167 switch { 168 case strings.Contains(brokenField, "selector"): 169 if !apiequality.Semantic.DeepEqual(oldRc.Spec.Selector, newRc.Spec.Selector) { 170 errs = append(errs, field.Invalid(field.NewPath("spec").Child("selector"), newRc.Spec.Selector, "cannot update non-convertible selector")) 171 } 172 default: 173 errs = append(errs, &field.Error{Type: field.ErrorTypeNotFound, BadValue: value, Field: brokenField, Detail: "unknown non-convertible field"}) 174 } 175 } 176 177 return errs 178 } 179 180 // WarningsOnUpdate returns warnings for the given update. 181 func (rcStrategy) WarningsOnUpdate(ctx context.Context, obj, old runtime.Object) []string { 182 var warnings []string 183 oldRc := old.(*api.ReplicationController) 184 newRc := obj.(*api.ReplicationController) 185 if oldRc.Generation != newRc.Generation { 186 warnings = pod.GetWarningsForPodTemplate(ctx, field.NewPath("spec", "template"), oldRc.Spec.Template, newRc.Spec.Template) 187 } 188 return warnings 189 } 190 191 func (rcStrategy) AllowUnconditionalUpdate() bool { 192 return true 193 } 194 195 // ControllerToSelectableFields returns a field set that represents the object. 196 func ControllerToSelectableFields(controller *api.ReplicationController) fields.Set { 197 objectMetaFieldsSet := generic.ObjectMetaFieldsSet(&controller.ObjectMeta, true) 198 controllerSpecificFieldsSet := fields.Set{ 199 "status.replicas": strconv.Itoa(int(controller.Status.Replicas)), 200 } 201 return generic.MergeFieldsSets(objectMetaFieldsSet, controllerSpecificFieldsSet) 202 } 203 204 // GetAttrs returns labels and fields of a given object for filtering purposes. 205 func GetAttrs(obj runtime.Object) (labels.Set, fields.Set, error) { 206 rc, ok := obj.(*api.ReplicationController) 207 if !ok { 208 return nil, nil, fmt.Errorf("given object is not a replication controller") 209 } 210 return labels.Set(rc.ObjectMeta.Labels), ControllerToSelectableFields(rc), nil 211 } 212 213 // MatchController is the filter used by the generic etcd backend to route 214 // watch events from etcd to clients of the apiserver only interested in specific 215 // labels/fields. 216 func MatchController(label labels.Selector, field fields.Selector) apistorage.SelectionPredicate { 217 return apistorage.SelectionPredicate{ 218 Label: label, 219 Field: field, 220 GetAttrs: GetAttrs, 221 } 222 } 223 224 type rcStatusStrategy struct { 225 rcStrategy 226 } 227 228 // StatusStrategy is the default logic invoked when updating object status. 229 var StatusStrategy = rcStatusStrategy{Strategy} 230 231 // GetResetFields returns the set of fields that get reset by the strategy 232 // and should not be modified by the user. 233 func (rcStatusStrategy) GetResetFields() map[fieldpath.APIVersion]*fieldpath.Set { 234 return map[fieldpath.APIVersion]*fieldpath.Set{ 235 "v1": fieldpath.NewSet( 236 fieldpath.MakePathOrDie("spec"), 237 ), 238 } 239 } 240 241 func (rcStatusStrategy) PrepareForUpdate(ctx context.Context, obj, old runtime.Object) { 242 newRc := obj.(*api.ReplicationController) 243 oldRc := old.(*api.ReplicationController) 244 // update is not allowed to set spec 245 newRc.Spec = oldRc.Spec 246 } 247 248 func (rcStatusStrategy) ValidateUpdate(ctx context.Context, obj, old runtime.Object) field.ErrorList { 249 return corevalidation.ValidateReplicationControllerStatusUpdate(obj.(*api.ReplicationController), old.(*api.ReplicationController)) 250 } 251 252 // WarningsOnUpdate returns warnings for the given update. 253 func (rcStatusStrategy) WarningsOnUpdate(ctx context.Context, obj, old runtime.Object) []string { 254 return nil 255 }