...

Source file src/k8s.io/kubernetes/pkg/registry/core/replicationcontroller/strategy.go

Documentation: k8s.io/kubernetes/pkg/registry/core/replicationcontroller

     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  }
   256  

View as plain text