k8s.io/kubernetes@v1.31.0-alpha.0.0.20240520171757-56147500dadc/pkg/registry/batch/cronjob/strategy.go (about)

     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  package cronjob
    18  
    19  import (
    20  	"context"
    21  	"fmt"
    22  	"strings"
    23  
    24  	batchv1beta1 "k8s.io/api/batch/v1beta1"
    25  	apiequality "k8s.io/apimachinery/pkg/api/equality"
    26  	"k8s.io/apimachinery/pkg/runtime"
    27  	"k8s.io/apimachinery/pkg/runtime/schema"
    28  	utilvalidation "k8s.io/apimachinery/pkg/util/validation"
    29  	"k8s.io/apimachinery/pkg/util/validation/field"
    30  	genericapirequest "k8s.io/apiserver/pkg/endpoints/request"
    31  	"k8s.io/apiserver/pkg/registry/rest"
    32  	"k8s.io/apiserver/pkg/storage/names"
    33  	"k8s.io/kubernetes/pkg/api/job"
    34  	"k8s.io/kubernetes/pkg/api/legacyscheme"
    35  	"k8s.io/kubernetes/pkg/api/pod"
    36  	"k8s.io/kubernetes/pkg/apis/batch"
    37  	batchvalidation "k8s.io/kubernetes/pkg/apis/batch/validation"
    38  	"sigs.k8s.io/structured-merge-diff/v4/fieldpath"
    39  )
    40  
    41  // cronJobStrategy implements verification logic for Replication Controllers.
    42  type cronJobStrategy struct {
    43  	runtime.ObjectTyper
    44  	names.NameGenerator
    45  }
    46  
    47  // Strategy is the default logic that applies when creating and updating CronJob objects.
    48  var Strategy = cronJobStrategy{legacyscheme.Scheme, names.SimpleNameGenerator}
    49  
    50  // DefaultGarbageCollectionPolicy returns OrphanDependents for batch/v1beta1 for backwards compatibility,
    51  // and DeleteDependents for all other versions.
    52  func (cronJobStrategy) DefaultGarbageCollectionPolicy(ctx context.Context) rest.GarbageCollectionPolicy {
    53  	var groupVersion schema.GroupVersion
    54  	if requestInfo, found := genericapirequest.RequestInfoFrom(ctx); found {
    55  		groupVersion = schema.GroupVersion{Group: requestInfo.APIGroup, Version: requestInfo.APIVersion}
    56  	}
    57  	switch groupVersion {
    58  	case batchv1beta1.SchemeGroupVersion:
    59  		// for back compatibility
    60  		return rest.OrphanDependents
    61  	default:
    62  		return rest.DeleteDependents
    63  	}
    64  }
    65  
    66  // NamespaceScoped returns true because all scheduled jobs need to be within a namespace.
    67  func (cronJobStrategy) NamespaceScoped() bool {
    68  	return true
    69  }
    70  
    71  // GetResetFields returns the set of fields that get reset by the strategy
    72  // and should not be modified by the user.
    73  func (cronJobStrategy) GetResetFields() map[fieldpath.APIVersion]*fieldpath.Set {
    74  	fields := map[fieldpath.APIVersion]*fieldpath.Set{
    75  		"batch/v1": fieldpath.NewSet(
    76  			fieldpath.MakePathOrDie("status"),
    77  		),
    78  		"batch/v1beta1": fieldpath.NewSet(
    79  			fieldpath.MakePathOrDie("status"),
    80  		),
    81  	}
    82  
    83  	return fields
    84  }
    85  
    86  // PrepareForCreate clears the status of a scheduled job before creation.
    87  func (cronJobStrategy) PrepareForCreate(ctx context.Context, obj runtime.Object) {
    88  	cronJob := obj.(*batch.CronJob)
    89  	cronJob.Status = batch.CronJobStatus{}
    90  
    91  	cronJob.Generation = 1
    92  
    93  	pod.DropDisabledTemplateFields(&cronJob.Spec.JobTemplate.Spec.Template, nil)
    94  }
    95  
    96  // PrepareForUpdate clears fields that are not allowed to be set by end users on update.
    97  func (cronJobStrategy) PrepareForUpdate(ctx context.Context, obj, old runtime.Object) {
    98  	newCronJob := obj.(*batch.CronJob)
    99  	oldCronJob := old.(*batch.CronJob)
   100  	newCronJob.Status = oldCronJob.Status
   101  
   102  	pod.DropDisabledTemplateFields(&newCronJob.Spec.JobTemplate.Spec.Template, &oldCronJob.Spec.JobTemplate.Spec.Template)
   103  
   104  	// Any changes to the spec increment the generation number.
   105  	// See metav1.ObjectMeta description for more information on Generation.
   106  	if !apiequality.Semantic.DeepEqual(newCronJob.Spec, oldCronJob.Spec) {
   107  		newCronJob.Generation = oldCronJob.Generation + 1
   108  	}
   109  }
   110  
   111  // Validate validates a new scheduled job.
   112  func (cronJobStrategy) Validate(ctx context.Context, obj runtime.Object) field.ErrorList {
   113  	cronJob := obj.(*batch.CronJob)
   114  	opts := pod.GetValidationOptionsFromPodTemplate(&cronJob.Spec.JobTemplate.Spec.Template, nil)
   115  	return batchvalidation.ValidateCronJobCreate(cronJob, opts)
   116  }
   117  
   118  // WarningsOnCreate returns warnings for the creation of the given object.
   119  func (cronJobStrategy) WarningsOnCreate(ctx context.Context, obj runtime.Object) []string {
   120  	newCronJob := obj.(*batch.CronJob)
   121  	var warnings []string
   122  	if msgs := utilvalidation.IsDNS1123Label(newCronJob.Name); len(msgs) != 0 {
   123  		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))
   124  	}
   125  	warnings = append(warnings, job.WarningsForJobSpec(ctx, field.NewPath("spec", "jobTemplate", "spec"), &newCronJob.Spec.JobTemplate.Spec, nil)...)
   126  	return warnings
   127  }
   128  
   129  // Canonicalize normalizes the object after validation.
   130  func (cronJobStrategy) Canonicalize(obj runtime.Object) {
   131  }
   132  
   133  func (cronJobStrategy) AllowUnconditionalUpdate() bool {
   134  	return true
   135  }
   136  
   137  // AllowCreateOnUpdate is false for scheduled jobs; this means a POST is needed to create one.
   138  func (cronJobStrategy) AllowCreateOnUpdate() bool {
   139  	return false
   140  }
   141  
   142  // ValidateUpdate is the default update validation for an end user.
   143  func (cronJobStrategy) ValidateUpdate(ctx context.Context, obj, old runtime.Object) field.ErrorList {
   144  	newCronJob := obj.(*batch.CronJob)
   145  	oldCronJob := old.(*batch.CronJob)
   146  
   147  	opts := pod.GetValidationOptionsFromPodTemplate(&newCronJob.Spec.JobTemplate.Spec.Template, &oldCronJob.Spec.JobTemplate.Spec.Template)
   148  	return batchvalidation.ValidateCronJobUpdate(newCronJob, oldCronJob, opts)
   149  }
   150  
   151  // WarningsOnUpdate returns warnings for the given update.
   152  func (cronJobStrategy) WarningsOnUpdate(ctx context.Context, obj, old runtime.Object) []string {
   153  	var warnings []string
   154  	newCronJob := obj.(*batch.CronJob)
   155  	oldCronJob := old.(*batch.CronJob)
   156  	if newCronJob.Generation != oldCronJob.Generation {
   157  		warnings = job.WarningsForJobSpec(ctx, field.NewPath("spec", "jobTemplate", "spec"), &newCronJob.Spec.JobTemplate.Spec, &oldCronJob.Spec.JobTemplate.Spec)
   158  	}
   159  	if strings.Contains(newCronJob.Spec.Schedule, "TZ") {
   160  		warnings = append(warnings, fmt.Sprintf("cannot use TZ or CRON_TZ in %s, use timeZone instead, see https://kubernetes.io/docs/concepts/workloads/controllers/cron-jobs/ for more details", field.NewPath("spec", "spec", "schedule")))
   161  	}
   162  	return warnings
   163  }
   164  
   165  type cronJobStatusStrategy struct {
   166  	cronJobStrategy
   167  }
   168  
   169  // StatusStrategy is the default logic invoked when updating object status.
   170  var StatusStrategy = cronJobStatusStrategy{Strategy}
   171  
   172  // GetResetFields returns the set of fields that get reset by the strategy
   173  // and should not be modified by the user.
   174  func (cronJobStatusStrategy) GetResetFields() map[fieldpath.APIVersion]*fieldpath.Set {
   175  	return map[fieldpath.APIVersion]*fieldpath.Set{
   176  		"batch/v1": fieldpath.NewSet(
   177  			fieldpath.MakePathOrDie("spec"),
   178  		),
   179  		"batch/v1beta1": fieldpath.NewSet(
   180  			fieldpath.MakePathOrDie("spec"),
   181  		),
   182  	}
   183  }
   184  
   185  func (cronJobStatusStrategy) PrepareForUpdate(ctx context.Context, obj, old runtime.Object) {
   186  	newJob := obj.(*batch.CronJob)
   187  	oldJob := old.(*batch.CronJob)
   188  	newJob.Spec = oldJob.Spec
   189  }
   190  
   191  func (cronJobStatusStrategy) ValidateUpdate(ctx context.Context, obj, old runtime.Object) field.ErrorList {
   192  	return field.ErrorList{}
   193  }
   194  
   195  // WarningsOnUpdate returns warnings for the given update.
   196  func (cronJobStatusStrategy) WarningsOnUpdate(ctx context.Context, obj, old runtime.Object) []string {
   197  	return nil
   198  }