...

Source file src/k8s.io/kubernetes/pkg/registry/apps/replicaset/strategy.go

Documentation: k8s.io/kubernetes/pkg/registry/apps/replicaset

     1  /*
     2  Copyright 2016 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 ReplicationController.
    18  
    19  package replicaset
    20  
    21  import (
    22  	"context"
    23  	"fmt"
    24  	"strconv"
    25  
    26  	extensionsv1beta1 "k8s.io/api/extensions/v1beta1"
    27  	apiequality "k8s.io/apimachinery/pkg/api/equality"
    28  	apivalidation "k8s.io/apimachinery/pkg/api/validation"
    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  	"k8s.io/kubernetes/pkg/apis/apps"
    43  	appsvalidation "k8s.io/kubernetes/pkg/apis/apps/validation"
    44  	"sigs.k8s.io/structured-merge-diff/v4/fieldpath"
    45  )
    46  
    47  // rsStrategy implements verification logic for ReplicaSets.
    48  type rsStrategy struct {
    49  	runtime.ObjectTyper
    50  	names.NameGenerator
    51  }
    52  
    53  // Strategy is the default logic that applies when creating and updating ReplicaSet objects.
    54  var Strategy = rsStrategy{legacyscheme.Scheme, names.SimpleNameGenerator}
    55  
    56  // Make sure we correctly implement the interface.
    57  var _ = rest.GarbageCollectionDeleteStrategy(Strategy)
    58  
    59  // DefaultGarbageCollectionPolicy returns DeleteDependents for all currently served versions.
    60  func (rsStrategy) DefaultGarbageCollectionPolicy(ctx context.Context) rest.GarbageCollectionPolicy {
    61  	return rest.DeleteDependents
    62  }
    63  
    64  // NamespaceScoped returns true because all ReplicaSets need to be within a namespace.
    65  func (rsStrategy) NamespaceScoped() bool {
    66  	return true
    67  }
    68  
    69  // GetResetFields returns the set of fields that get reset by the strategy
    70  // and should not be modified by the user.
    71  func (rsStrategy) GetResetFields() map[fieldpath.APIVersion]*fieldpath.Set {
    72  	fields := map[fieldpath.APIVersion]*fieldpath.Set{
    73  		"apps/v1": fieldpath.NewSet(
    74  			fieldpath.MakePathOrDie("status"),
    75  		),
    76  	}
    77  
    78  	return fields
    79  }
    80  
    81  // PrepareForCreate clears the status of a ReplicaSet before creation.
    82  func (rsStrategy) PrepareForCreate(ctx context.Context, obj runtime.Object) {
    83  	rs := obj.(*apps.ReplicaSet)
    84  	rs.Status = apps.ReplicaSetStatus{}
    85  
    86  	rs.Generation = 1
    87  
    88  	pod.DropDisabledTemplateFields(&rs.Spec.Template, nil)
    89  }
    90  
    91  // PrepareForUpdate clears fields that are not allowed to be set by end users on update.
    92  func (rsStrategy) PrepareForUpdate(ctx context.Context, obj, old runtime.Object) {
    93  	newRS := obj.(*apps.ReplicaSet)
    94  	oldRS := old.(*apps.ReplicaSet)
    95  	// update is not allowed to set status
    96  	newRS.Status = oldRS.Status
    97  
    98  	pod.DropDisabledTemplateFields(&newRS.Spec.Template, &oldRS.Spec.Template)
    99  
   100  	// Any changes to the spec increment the generation number, any changes to the
   101  	// status should reflect the generation number of the corresponding object. We push
   102  	// the burden of managing the status onto the clients because we can't (in general)
   103  	// know here what version of spec the writer of the status has seen. It may seem like
   104  	// we can at first -- since obj contains spec -- but in the future we will probably make
   105  	// status its own object, and even if we don't, writes may be the result of a
   106  	// read-update-write loop, so the contents of spec may not actually be the spec that
   107  	// the ReplicaSet has *seen*.
   108  	if !apiequality.Semantic.DeepEqual(oldRS.Spec, newRS.Spec) {
   109  		newRS.Generation = oldRS.Generation + 1
   110  	}
   111  }
   112  
   113  // Validate validates a new ReplicaSet.
   114  func (rsStrategy) Validate(ctx context.Context, obj runtime.Object) field.ErrorList {
   115  	rs := obj.(*apps.ReplicaSet)
   116  	opts := pod.GetValidationOptionsFromPodTemplate(&rs.Spec.Template, nil)
   117  	return appsvalidation.ValidateReplicaSet(rs, opts)
   118  }
   119  
   120  // WarningsOnCreate returns warnings for the creation of the given object.
   121  func (rsStrategy) WarningsOnCreate(ctx context.Context, obj runtime.Object) []string {
   122  	newRS := obj.(*apps.ReplicaSet)
   123  	var warnings []string
   124  	if msgs := utilvalidation.IsDNS1123Label(newRS.Name); len(msgs) != 0 {
   125  		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))
   126  	}
   127  	warnings = append(warnings, pod.GetWarningsForPodTemplate(ctx, field.NewPath("spec", "template"), &newRS.Spec.Template, nil)...)
   128  	return warnings
   129  }
   130  
   131  // Canonicalize normalizes the object after validation.
   132  func (rsStrategy) Canonicalize(obj runtime.Object) {
   133  }
   134  
   135  // AllowCreateOnUpdate is false for ReplicaSets; this means a POST is
   136  // needed to create one.
   137  func (rsStrategy) AllowCreateOnUpdate() bool {
   138  	return false
   139  }
   140  
   141  // ValidateUpdate is the default update validation for an end user.
   142  func (rsStrategy) ValidateUpdate(ctx context.Context, obj, old runtime.Object) field.ErrorList {
   143  	newReplicaSet := obj.(*apps.ReplicaSet)
   144  	oldReplicaSet := old.(*apps.ReplicaSet)
   145  
   146  	opts := pod.GetValidationOptionsFromPodTemplate(&newReplicaSet.Spec.Template, &oldReplicaSet.Spec.Template)
   147  	allErrs := appsvalidation.ValidateReplicaSet(obj.(*apps.ReplicaSet), opts)
   148  	allErrs = append(allErrs, appsvalidation.ValidateReplicaSetUpdate(newReplicaSet, oldReplicaSet, opts)...)
   149  
   150  	// Update is not allowed to set Spec.Selector for all groups/versions except extensions/v1beta1.
   151  	// If RequestInfo is nil, it is better to revert to old behavior (i.e. allow update to set Spec.Selector)
   152  	// to prevent unintentionally breaking users who may rely on the old behavior.
   153  	// TODO(#50791): after extensions/v1beta1 is removed, move selector immutability check inside ValidateReplicaSetUpdate().
   154  	if requestInfo, found := genericapirequest.RequestInfoFrom(ctx); found {
   155  		groupVersion := schema.GroupVersion{Group: requestInfo.APIGroup, Version: requestInfo.APIVersion}
   156  		switch groupVersion {
   157  		case extensionsv1beta1.SchemeGroupVersion:
   158  			// no-op for compatibility
   159  		default:
   160  			// disallow mutation of selector
   161  			allErrs = append(allErrs, apivalidation.ValidateImmutableField(newReplicaSet.Spec.Selector, oldReplicaSet.Spec.Selector, field.NewPath("spec").Child("selector"))...)
   162  		}
   163  	}
   164  
   165  	return allErrs
   166  }
   167  
   168  // WarningsOnUpdate returns warnings for the given update.
   169  func (rsStrategy) WarningsOnUpdate(ctx context.Context, obj, old runtime.Object) []string {
   170  	var warnings []string
   171  	newReplicaSet := obj.(*apps.ReplicaSet)
   172  	oldReplicaSet := old.(*apps.ReplicaSet)
   173  	if newReplicaSet.Generation != oldReplicaSet.Generation {
   174  		warnings = pod.GetWarningsForPodTemplate(ctx, field.NewPath("spec", "template"), &newReplicaSet.Spec.Template, &oldReplicaSet.Spec.Template)
   175  	}
   176  	return warnings
   177  }
   178  
   179  func (rsStrategy) AllowUnconditionalUpdate() bool {
   180  	return true
   181  }
   182  
   183  // ToSelectableFields returns a field set that represents the object.
   184  func ToSelectableFields(rs *apps.ReplicaSet) fields.Set {
   185  	objectMetaFieldsSet := generic.ObjectMetaFieldsSet(&rs.ObjectMeta, true)
   186  	rsSpecificFieldsSet := fields.Set{
   187  		"status.replicas": strconv.Itoa(int(rs.Status.Replicas)),
   188  	}
   189  	return generic.MergeFieldsSets(objectMetaFieldsSet, rsSpecificFieldsSet)
   190  }
   191  
   192  // GetAttrs returns labels and fields of a given object for filtering purposes.
   193  func GetAttrs(obj runtime.Object) (labels.Set, fields.Set, error) {
   194  	rs, ok := obj.(*apps.ReplicaSet)
   195  	if !ok {
   196  		return nil, nil, fmt.Errorf("given object is not a ReplicaSet")
   197  	}
   198  	return labels.Set(rs.ObjectMeta.Labels), ToSelectableFields(rs), nil
   199  }
   200  
   201  // MatchReplicaSet is the filter used by the generic etcd backend to route
   202  // watch events from etcd to clients of the apiserver only interested in specific
   203  // labels/fields.
   204  func MatchReplicaSet(label labels.Selector, field fields.Selector) apistorage.SelectionPredicate {
   205  	return apistorage.SelectionPredicate{
   206  		Label:    label,
   207  		Field:    field,
   208  		GetAttrs: GetAttrs,
   209  	}
   210  }
   211  
   212  type rsStatusStrategy struct {
   213  	rsStrategy
   214  }
   215  
   216  // StatusStrategy is the default logic invoked when updating object status.
   217  var StatusStrategy = rsStatusStrategy{Strategy}
   218  
   219  // GetResetFields returns the set of fields that get reset by the strategy
   220  // and should not be modified by the user.
   221  func (rsStatusStrategy) GetResetFields() map[fieldpath.APIVersion]*fieldpath.Set {
   222  	return map[fieldpath.APIVersion]*fieldpath.Set{
   223  		"apps/v1": fieldpath.NewSet(
   224  			fieldpath.MakePathOrDie("spec"),
   225  		),
   226  	}
   227  }
   228  
   229  func (rsStatusStrategy) PrepareForUpdate(ctx context.Context, obj, old runtime.Object) {
   230  	newRS := obj.(*apps.ReplicaSet)
   231  	oldRS := old.(*apps.ReplicaSet)
   232  	// update is not allowed to set spec
   233  	newRS.Spec = oldRS.Spec
   234  }
   235  
   236  func (rsStatusStrategy) ValidateUpdate(ctx context.Context, obj, old runtime.Object) field.ErrorList {
   237  	return appsvalidation.ValidateReplicaSetStatusUpdate(obj.(*apps.ReplicaSet), old.(*apps.ReplicaSet))
   238  }
   239  
   240  // WarningsOnUpdate returns warnings for the given update.
   241  func (rsStatusStrategy) WarningsOnUpdate(ctx context.Context, obj, old runtime.Object) []string {
   242  	return nil
   243  }
   244  

View as plain text