Skip to content

Commit

Permalink
Support timezone for AdvancedCronJob (openkruise#1070)
Browse files Browse the repository at this point in the history
  • Loading branch information
FillZpp authored Sep 7, 2022
1 parent 6ac9755 commit dfb5ac1
Show file tree
Hide file tree
Showing 27 changed files with 1,290 additions and 445 deletions.
9 changes: 7 additions & 2 deletions apis/apps/v1alpha1/advancedcronjob_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ limitations under the License.
package v1alpha1

import (
batchv1beta1 "k8s.io/api/batch/v1beta1"
batchv1 "k8s.io/api/batch/v1"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
Expand All @@ -31,6 +31,11 @@ type AdvancedCronJobSpec struct {
// The schedule in Cron format, see https://en.wikipedia.org/wiki/Cron.
Schedule string `json:"schedule" protobuf:"bytes,1,opt,name=schedule"`

// The time zone name for the given schedule, see https://en.wikipedia.org/wiki/List_of_tz_database_time_zones.
// If not specified, this will default to the time zone of the kruise-controller-manager process.
// +optional
TimeZone *string `json:"timeZone,omitempty" protobuf:"bytes,8,opt,name=timeZone"`

// +kubebuilder:validation:Minimum=0

// Optional deadline in seconds for starting the job if it misses scheduled
Expand Down Expand Up @@ -73,7 +78,7 @@ type CronJobTemplate struct {
// +optional
// +kubebuilder:pruning:PreserveUnknownFields
// +kubebuilder:validation:Schemaless
JobTemplate *batchv1beta1.JobTemplateSpec `json:"jobTemplate,omitempty" protobuf:"bytes,1,opt,name=jobTemplate"`
JobTemplate *batchv1.JobTemplateSpec `json:"jobTemplate,omitempty" protobuf:"bytes,1,opt,name=jobTemplate"`

// Specifies the broadcastjob that will be created when executing a BroadcastCronJob.
// +optional
Expand Down
43 changes: 24 additions & 19 deletions apis/apps/v1alpha1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions config/crd/bases/apps.kruise.io_advancedcronjobs.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,11 @@ spec:
a CronJob.
x-kubernetes-preserve-unknown-fields: true
type: object
timeZone:
description: The time zone name for the given schedule, see https://en.wikipedia.org/wiki/List_of_tz_database_time_zones.
If not specified, this will default to the time zone of the kruise-controller-manager
process.
type: string
required:
- schedule
- template
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ require (
github.com/opencontainers/image-spec v1.0.2
github.com/pkg/errors v0.9.1
github.com/prometheus/client_golang v1.11.0
github.com/robfig/cron v1.2.0
github.com/robfig/cron/v3 v3.0.1
github.com/spf13/pflag v1.0.5
github.com/stretchr/testify v1.7.0
github.com/xyproto/simpleredis v0.0.0-20200201215242-1ff0da2967b4
Expand Down
3 changes: 1 addition & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -770,8 +770,7 @@ github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
github.com/quobyte/api v0.1.8/go.mod h1:jL7lIHrmqQ7yh05OJ+eEEdHr0u/kmT1Ff9iHd+4H6VI=
github.com/remyoudompheng/bigfft v0.0.0-20170806203942-52369c62f446/go.mod h1:uYEyJGbgTkfkS4+E/PavXkNJcbFIpEtjt2B0KDQ5+9M=
github.com/robfig/cron v1.2.0 h1:ZjScXvvxeQ63Dbyxy76Fj3AT3Ut0aKsyd2/tl3DTMuQ=
github.com/robfig/cron v1.2.0/go.mod h1:JGuDeoQd7Z6yL4zQhZ3OPEVHB7fL6Ka6skscFHfmt2k=
github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
Expand Down
1 change: 1 addition & 0 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import (
_ "net/http/pprof"
"os"
"time"
_ "time/tzdata" // for AdvancedCronJob Time Zone support

"github.com/openkruise/kruise/pkg/util/controllerfinder"
"github.com/spf13/pflag"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,19 +20,17 @@ import (
"sort"
"time"

"sigs.k8s.io/controller-runtime/pkg/controller"

"sigs.k8s.io/controller-runtime/pkg/handler"
"sigs.k8s.io/controller-runtime/pkg/source"

appsv1alpha1 "github.com/openkruise/kruise/apis/apps/v1alpha1"
"github.com/robfig/cron"
"github.com/robfig/cron/v3"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
ref "k8s.io/client-go/tools/reference"
"k8s.io/klog/v2"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/controller"
"sigs.k8s.io/controller-runtime/pkg/handler"
"sigs.k8s.io/controller-runtime/pkg/source"
)

func watchBroadcastJob(c controller.Controller) error {
Expand Down Expand Up @@ -212,7 +210,7 @@ func (r *ReconcileAdvancedCronJob) reconcileBroadcastJob(ctx context.Context, re
and the next run, so that we can know when it's time to reconcile again.
*/
getNextSchedule := func(cronJob *appsv1alpha1.AdvancedCronJob, now time.Time) (lastMissed time.Time, next time.Time, err error) {
sched, err := cron.ParseStandard(cronJob.Spec.Schedule)
sched, err := cron.ParseStandard(formatSchedule(cronJob))
if err != nil {
return time.Time{}, time.Time{}, fmt.Errorf("Unparseable schedule %q: %v", cronJob.Spec.Schedule, err)
}
Expand Down
68 changes: 62 additions & 6 deletions pkg/controller/advancedcronjob/advancedcronjob_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,20 +19,20 @@ package advancedcronjob
import (
"flag"
"testing"

batchv1 "k8s.io/api/batch/v1"

batchv1beta1 "k8s.io/api/batch/v1beta1"
"time"

appsv1alpha1 "github.com/openkruise/kruise/apis/apps/v1alpha1"
"github.com/robfig/cron/v3"
"github.com/stretchr/testify/assert"
"golang.org/x/net/context"
batchv1 "k8s.io/api/batch/v1"
v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/types"
"k8s.io/client-go/tools/record"
"k8s.io/klog/v2"
utilpointer "k8s.io/utils/pointer"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/client/fake"
"sigs.k8s.io/controller-runtime/pkg/reconcile"
Expand All @@ -45,6 +45,63 @@ func init() {
_ = flag.Set("v", "10")
}

func TestScheduleWithTimeZone(t *testing.T) {
cases := []struct {
schedule string
timeZone *string
previousTZ string
expectedNext string
}{
{
schedule: "0 10 * * ?",
timeZone: nil,
previousTZ: "2022-09-05T09:01:00Z",
expectedNext: "2022-09-05T10:00:00Z",
},
{
schedule: "0 10 * * ?",
timeZone: nil,
previousTZ: "2022-09-05T11:01:00Z",
expectedNext: "2022-09-06T10:00:00Z",
},
{
schedule: "0 10 * * ?",
timeZone: utilpointer.String("Asia/Shanghai"),
previousTZ: "2022-09-05T09:01:00Z",
expectedNext: "2022-09-06T02:00:00Z",
},
{
schedule: "0 10 * * ?",
timeZone: utilpointer.String("Asia/Shanghai"),
previousTZ: "2022-09-06T01:01:00Z",
expectedNext: "2022-09-06T02:00:00Z",
},
{
schedule: "TZ=Asia/Shanghai 0 10 * * ?",
timeZone: nil,
previousTZ: "2022-09-06T01:01:00Z",
expectedNext: "2022-09-06T02:00:00Z",
},
}

for i, tc := range cases {
acj := &appsv1alpha1.AdvancedCronJob{Spec: appsv1alpha1.AdvancedCronJobSpec{Schedule: tc.schedule, TimeZone: tc.timeZone}}
sched, err := cron.ParseStandard(formatSchedule(acj))
if err != nil {
t.Fatal(err)
}

previousTZ, err := time.Parse(time.RFC3339, tc.previousTZ)
if err != nil {
t.Fatal(err)
}
gotNext := sched.Next(previousTZ).Format(time.RFC3339)
if gotNext != tc.expectedNext {
t.Fatalf("case %d failed, expected next %s, got %s", i, tc.expectedNext, gotNext)
}
}
}

// Test scenario:
func TestReconcileAdvancedJobCreateBroadcastJob(t *testing.T) {
scheme := runtime.NewScheme()
Expand Down Expand Up @@ -87,7 +144,6 @@ func TestReconcileAdvancedJobCreateJob(t *testing.T) {
scheme := runtime.NewScheme()
_ = appsv1alpha1.AddToScheme(scheme)
_ = batchv1.AddToScheme(scheme)
_ = batchv1beta1.AddToScheme(scheme)
_ = v1.AddToScheme(scheme)

// A job
Expand Down Expand Up @@ -185,7 +241,7 @@ func broadcastJobTemplate() appsv1alpha1.CronJobTemplate {

func jobTemplate() appsv1alpha1.CronJobTemplate {
return appsv1alpha1.CronJobTemplate{
JobTemplate: &batchv1beta1.JobTemplateSpec{
JobTemplate: &batchv1.JobTemplateSpec{
Spec: batchv1.JobSpec{
Template: v1.PodTemplateSpec{
Spec: v1.PodSpec{},
Expand Down
Loading

0 comments on commit dfb5ac1

Please sign in to comment.