...

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

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

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

View as plain text