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 }