diff --git a/pkg/apis/batch/types.go b/pkg/apis/batch/types.go index 879ce24501b..e1154e025ab 100644 --- a/pkg/apis/batch/types.go +++ b/pkg/apis/batch/types.go @@ -501,7 +501,6 @@ type CronJobSpec struct { // configuration, the controller will stop creating new new Jobs and will create a system event with the // reason UnknownTimeZone. // More information can be found in https://kubernetes.io/docs/concepts/workloads/controllers/cron-jobs/#time-zones - // This is beta field and must be enabled via the `CronJobTimeZone` feature gate. // +optional TimeZone *string diff --git a/pkg/controller/cronjob/cronjob_controllerv2.go b/pkg/controller/cronjob/cronjob_controllerv2.go index 43ebb1a3201..930c46ab077 100644 --- a/pkg/controller/cronjob/cronjob_controllerv2.go +++ b/pkg/controller/cronjob/cronjob_controllerv2.go @@ -35,7 +35,6 @@ import ( "k8s.io/apimachinery/pkg/types" utilruntime "k8s.io/apimachinery/pkg/util/runtime" "k8s.io/apimachinery/pkg/util/wait" - utilfeature "k8s.io/apiserver/pkg/util/feature" batchv1informers "k8s.io/client-go/informers/batch/v1" clientset "k8s.io/client-go/kubernetes" "k8s.io/client-go/kubernetes/scheme" @@ -48,7 +47,6 @@ import ( "k8s.io/klog/v2" "k8s.io/kubernetes/pkg/controller" "k8s.io/kubernetes/pkg/controller/cronjob/metrics" - "k8s.io/kubernetes/pkg/features" "k8s.io/utils/pointer" ) @@ -380,7 +378,6 @@ func (jm *ControllerV2) enqueueControllerAfter(obj interface{}, t time.Duration) // updateCronJob re-queues the CronJob for next scheduled time if there is a // change in spec.schedule otherwise it re-queues it now func (jm *ControllerV2) updateCronJob(logger klog.Logger, old interface{}, curr interface{}) { - timeZoneEnabled := utilfeature.DefaultFeatureGate.Enabled(features.CronJobTimeZone) oldCJ, okOld := old.(*batchv1.CronJob) newCJ, okNew := curr.(*batchv1.CronJob) @@ -391,9 +388,9 @@ func (jm *ControllerV2) updateCronJob(logger klog.Logger, old interface{}, curr // if the change in schedule results in next requeue having to be sooner than it already was, // it will be handled here by the queue. If the next requeue is further than previous schedule, // the sync loop will essentially be a no-op for the already queued key with old schedule. - if oldCJ.Spec.Schedule != newCJ.Spec.Schedule || (timeZoneEnabled && !pointer.StringEqual(oldCJ.Spec.TimeZone, newCJ.Spec.TimeZone)) { + if oldCJ.Spec.Schedule != newCJ.Spec.Schedule || !pointer.StringEqual(oldCJ.Spec.TimeZone, newCJ.Spec.TimeZone) { // schedule changed, change the requeue time, pass nil recorder so that syncCronJob will output any warnings - sched, err := cron.ParseStandard(formatSchedule(timeZoneEnabled, newCJ, nil)) + sched, err := cron.ParseStandard(formatSchedule(newCJ, nil)) if err != nil { // this is likely a user error in defining the spec value // we should log the error and not reconcile this cronjob until an update to spec @@ -430,7 +427,6 @@ func (jm *ControllerV2) syncCronJob( cronJob = cronJob.DeepCopy() now := jm.now() updateStatus := false - timeZoneEnabled := utilfeature.DefaultFeatureGate.Enabled(features.CronJobTimeZone) childrenJobs := make(map[types.UID]bool) for _, j := range jobs { @@ -499,9 +495,9 @@ func (jm *ControllerV2) syncCronJob( } logger := klog.FromContext(ctx) - if timeZoneEnabled && cronJob.Spec.TimeZone != nil { - if _, err := time.LoadLocation(*cronJob.Spec.TimeZone); err != nil { - timeZone := pointer.StringDeref(cronJob.Spec.TimeZone, "") + if cronJob.Spec.TimeZone != nil { + timeZone := pointer.StringDeref(cronJob.Spec.TimeZone, "") + if _, err := time.LoadLocation(timeZone); err != nil { logger.V(4).Info("Not starting job because timeZone is invalid", "cronjob", klog.KObj(cronJob), "timeZone", timeZone, "err", err) jm.recorder.Eventf(cronJob, corev1.EventTypeWarning, "UnknownTimeZone", "invalid timeZone: %q: %s", timeZone, err) return cronJob, nil, updateStatus, nil @@ -513,7 +509,7 @@ func (jm *ControllerV2) syncCronJob( return cronJob, nil, updateStatus, nil } - sched, err := cron.ParseStandard(formatSchedule(timeZoneEnabled, cronJob, jm.recorder)) + sched, err := cron.ParseStandard(formatSchedule(cronJob, jm.recorder)) if err != nil { // this is likely a user error in defining the spec value // we should log the error and not reconcile this cronjob until an update to spec @@ -733,7 +729,7 @@ func getRef(object runtime.Object) (*corev1.ObjectReference, error) { return ref.GetReference(scheme.Scheme, object) } -func formatSchedule(timeZoneEnabled bool, cj *batchv1.CronJob, recorder record.EventRecorder) string { +func formatSchedule(cj *batchv1.CronJob, recorder record.EventRecorder) string { if strings.Contains(cj.Spec.Schedule, "TZ") { if recorder != nil { recorder.Eventf(cj, corev1.EventTypeWarning, "UnsupportedSchedule", "CRON_TZ or TZ used in schedule %q is not officially supported, see https://kubernetes.io/docs/concepts/workloads/controllers/cron-jobs/ for more details", cj.Spec.Schedule) @@ -742,7 +738,7 @@ func formatSchedule(timeZoneEnabled bool, cj *batchv1.CronJob, recorder record.E return cj.Spec.Schedule } - if timeZoneEnabled && cj.Spec.TimeZone != nil { + if cj.Spec.TimeZone != nil { if _, err := time.LoadLocation(*cj.Spec.TimeZone); err != nil { return cj.Spec.Schedule } diff --git a/pkg/controller/cronjob/cronjob_controllerv2_test.go b/pkg/controller/cronjob/cronjob_controllerv2_test.go index 98fcf0ba934..1c7864984e8 100644 --- a/pkg/controller/cronjob/cronjob_controllerv2_test.go +++ b/pkg/controller/cronjob/cronjob_controllerv2_test.go @@ -30,17 +30,14 @@ import ( "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/types" - "k8s.io/apiserver/pkg/util/feature" "k8s.io/client-go/informers" "k8s.io/client-go/kubernetes/fake" "k8s.io/client-go/tools/record" "k8s.io/client-go/util/workqueue" - featuregatetesting "k8s.io/component-base/featuregate/testing" "k8s.io/klog/v2/ktesting" _ "k8s.io/kubernetes/pkg/apis/batch/install" _ "k8s.io/kubernetes/pkg/apis/core/install" "k8s.io/kubernetes/pkg/controller" - "k8s.io/kubernetes/pkg/features" ) var ( @@ -203,7 +200,6 @@ func TestControllerV2SyncCronJob(t *testing.T) { now time.Time jobCreateError error jobGetErr error - enableTimeZone bool // expectations expectCreate bool @@ -251,7 +247,6 @@ func TestControllerV2SyncCronJob(t *testing.T) { deadline: noDead, jobCreationTime: justAfterThePriorHour(), now: justBeforeTheHour(), - enableTimeZone: true, expectedWarnings: 1, jobPresentInCJActiveStatus: true, }, @@ -291,7 +286,6 @@ func TestControllerV2SyncCronJob(t *testing.T) { deadline: noDead, jobCreationTime: justAfterThePriorHour(), now: justBeforeTheHour(), - enableTimeZone: true, expectRequeueAfter: true, expectedRequeueDuration: 1*time.Minute + nextScheduleDelta, jobPresentInCJActiveStatus: true, @@ -342,7 +336,6 @@ func TestControllerV2SyncCronJob(t *testing.T) { deadline: noDead, jobCreationTime: justAfterThePriorHour(), now: justAfterTheHourInZone(newYork), - enableTimeZone: false, expectCreate: true, expectActive: 1, expectRequeueAfter: true, @@ -357,7 +350,6 @@ func TestControllerV2SyncCronJob(t *testing.T) { deadline: noDead, jobCreationTime: justAfterThePriorHour(), now: justAfterTheHourInZone(newYork), - enableTimeZone: true, expectCreate: true, expectActive: 1, expectRequeueAfter: true, @@ -372,7 +364,6 @@ func TestControllerV2SyncCronJob(t *testing.T) { deadline: noDead, jobCreationTime: justAfterThePriorHour(), now: justAfterTheHourInZone(newYork), - enableTimeZone: true, expectCreate: true, expectedWarnings: 1, expectRequeueAfter: true, @@ -1172,8 +1163,6 @@ func TestControllerV2SyncCronJob(t *testing.T) { tc := tc t.Run(name, func(t *testing.T) { - defer featuregatetesting.SetFeatureGateDuringTest(t, feature.DefaultFeatureGate, features.CronJobTimeZone, tc.enableTimeZone)() - cj := cronJob() cj.Spec.ConcurrencyPolicy = tc.concurrencyPolicy cj.Spec.Suspend = &tc.suspend diff --git a/pkg/features/kube_features.go b/pkg/features/kube_features.go index 4cc0dff05f7..e1cce226500 100644 --- a/pkg/features/kube_features.go +++ b/pkg/features/kube_features.go @@ -188,6 +188,7 @@ const ( // kep: https://kep.k8s.io/3140 // alpha: v1.24 // beta: v1.25 + // GA: 1.27 // // Enables support for time zones in CronJobs. CronJobTimeZone featuregate.Feature = "CronJobTimeZone" @@ -900,7 +901,7 @@ var defaultKubernetesFeatureGates = map[featuregate.Feature]featuregate.FeatureS ConsistentHTTPGetHandlers: {Default: true, PreRelease: featuregate.GA}, - CronJobTimeZone: {Default: true, PreRelease: featuregate.Beta}, + CronJobTimeZone: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.29 DelegateFSGroupToCSIDriver: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.28 diff --git a/pkg/registry/batch/cronjob/strategy.go b/pkg/registry/batch/cronjob/strategy.go index 6a52d381f47..c15a164be0c 100644 --- a/pkg/registry/batch/cronjob/strategy.go +++ b/pkg/registry/batch/cronjob/strategy.go @@ -30,12 +30,10 @@ import ( genericapirequest "k8s.io/apiserver/pkg/endpoints/request" "k8s.io/apiserver/pkg/registry/rest" "k8s.io/apiserver/pkg/storage/names" - utilfeature "k8s.io/apiserver/pkg/util/feature" "k8s.io/kubernetes/pkg/api/legacyscheme" "k8s.io/kubernetes/pkg/api/pod" "k8s.io/kubernetes/pkg/apis/batch" batchvalidation "k8s.io/kubernetes/pkg/apis/batch/validation" - "k8s.io/kubernetes/pkg/features" "sigs.k8s.io/structured-merge-diff/v4/fieldpath" ) @@ -91,10 +89,6 @@ func (cronJobStrategy) PrepareForCreate(ctx context.Context, obj runtime.Object) cronJob.Generation = 1 - if !utilfeature.DefaultFeatureGate.Enabled(features.CronJobTimeZone) { - cronJob.Spec.TimeZone = nil - } - pod.DropDisabledTemplateFields(&cronJob.Spec.JobTemplate.Spec.Template, nil) } @@ -104,10 +98,6 @@ func (cronJobStrategy) PrepareForUpdate(ctx context.Context, obj, old runtime.Ob oldCronJob := old.(*batch.CronJob) newCronJob.Status = oldCronJob.Status - if !utilfeature.DefaultFeatureGate.Enabled(features.CronJobTimeZone) && oldCronJob.Spec.TimeZone == nil { - newCronJob.Spec.TimeZone = nil - } - pod.DropDisabledTemplateFields(&newCronJob.Spec.JobTemplate.Spec.Template, &oldCronJob.Spec.JobTemplate.Spec.Template) // Any changes to the spec increment the generation number. diff --git a/staging/src/k8s.io/api/batch/v1/types.go b/staging/src/k8s.io/api/batch/v1/types.go index bbbe9b16a33..54b450aeb56 100644 --- a/staging/src/k8s.io/api/batch/v1/types.go +++ b/staging/src/k8s.io/api/batch/v1/types.go @@ -517,7 +517,6 @@ type CronJobSpec struct { // configuration, the controller will stop creating new new Jobs and will create a system event with the // reason UnknownTimeZone. // More information can be found in https://kubernetes.io/docs/concepts/workloads/controllers/cron-jobs/#time-zones - // This is beta field and must be enabled via the `CronJobTimeZone` feature gate. // +optional TimeZone *string `json:"timeZone,omitempty" protobuf:"bytes,8,opt,name=timeZone"` diff --git a/staging/src/k8s.io/api/batch/v1beta1/types.go b/staging/src/k8s.io/api/batch/v1beta1/types.go index 7418303a690..976752a926f 100644 --- a/staging/src/k8s.io/api/batch/v1beta1/types.go +++ b/staging/src/k8s.io/api/batch/v1beta1/types.go @@ -95,7 +95,6 @@ type CronJobSpec struct { // configuration, the controller will stop creating new new Jobs and will create a system event with the // reason UnknownTimeZone. // More information can be found in https://kubernetes.io/docs/concepts/workloads/controllers/cron-jobs/#time-zones - // This is beta field and must be enabled via the `CronJobTimeZone` feature gate. // +optional TimeZone *string `json:"timeZone,omitempty" protobuf:"bytes,8,opt,name=timeZone"`