From e3731675461883f31fa9e1d54a5832eccb8066a7 Mon Sep 17 00:00:00 2001 From: wang yan Date: Mon, 4 Mar 2019 14:06:20 +0800 Subject: [PATCH] update gc api to support raw cron string Signed-off-by: wang yan --- docs/swagger.yaml | 13 +++------- src/core/api/models/reg_gc.go | 41 ++++++++++++------------------ src/core/api/models/reg_gc_test.go | 37 ++++++++------------------- src/core/api/reg_gc.go | 4 +-- src/core/api/reg_gc_test.go | 7 +++-- 5 files changed, 36 insertions(+), 66 deletions(-) diff --git a/docs/swagger.yaml b/docs/swagger.yaml index 247006946..97bd0906f 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -4671,15 +4671,10 @@ definitions: properties: type: type: string - description: The schedule type. The valid values are daily, weekly and None. 'None' means to cancel the schedule. - weekday: - type: integer - format: int8 - description: 'Optional, only used when the type is weekly. The valid values are 1-7.' - offtime: - type: integer - format: int64 - description: 'The time offset with the UTC 00:00 in seconds.' + description: The schedule type. The valid values are hourly, daily, weekly, custom and None. 'None' means to cancel the schedule. + cron: + type: string + description: A cron expression, a time-based job scheduler. SearchResult: type: object description: The chart search result item diff --git a/src/core/api/models/reg_gc.go b/src/core/api/models/reg_gc.go index 725e0a850..54576db6c 100644 --- a/src/core/api/models/reg_gc.go +++ b/src/core/api/models/reg_gc.go @@ -22,16 +22,20 @@ import ( "github.com/astaxie/beego/validation" "github.com/goharbor/harbor/src/common/job" "github.com/goharbor/harbor/src/common/job/models" - "github.com/goharbor/harbor/src/common/utils" "github.com/goharbor/harbor/src/common/utils/log" "github.com/goharbor/harbor/src/core/config" + "github.com/robfig/cron" ) const ( + // ScheduleHourly : 'Hourly' + ScheduleHourly = "Hourly" // ScheduleDaily : 'Daily' ScheduleDaily = "Daily" // ScheduleWeekly : 'Weekly' ScheduleWeekly = "Weekly" + // ScheduleCustom : 'Custom' + ScheduleCustom = "Custom" // ScheduleManual : 'Manual' ScheduleManual = "Manual" // ScheduleNone : 'None' @@ -48,12 +52,10 @@ type GCReq struct { // ScheduleParam defines the parameter of schedule trigger type ScheduleParam struct { - // Daily, Weekly, Manual, None + // Daily, Weekly, Custom, Manual, None Type string `json:"type"` - // Optional, only used when type is 'weekly' - Weekday int8 `json:"weekday"` - // The time offset with the UTC 00:00 in seconds - Offtime int64 `json:"offtime"` + // The cron string of scheduled job + Cron string `json:"cron"` } // GCRep holds the response of query gc @@ -75,9 +77,9 @@ func (gr *GCReq) Valid(v *validation.Validation) { return } switch gr.Schedule.Type { - case ScheduleDaily, ScheduleWeekly: - if gr.Schedule.Offtime < 0 || gr.Schedule.Offtime > 3600*24 { - v.SetError("offtime", fmt.Sprintf("Invalid schedule trigger parameter offtime: %d", gr.Schedule.Offtime)) + case ScheduleHourly, ScheduleDaily, ScheduleWeekly, ScheduleCustom: + if _, err := cron.Parse(gr.Schedule.Cron); err != nil { + v.SetError("cron", fmt.Sprintf("Invalid schedule trigger parameter cron: %s", gr.Schedule.Cron)) } case ScheduleManual, ScheduleNone: default: @@ -85,26 +87,15 @@ func (gr *GCReq) Valid(v *validation.Validation) { } } -// ToJob converts request to a job reconiged by job service. -func (gr *GCReq) ToJob() (*models.JobData, error) { +// ToJob converts request to a job recognized by job service. +func (gr *GCReq) ToJob() *models.JobData { metadata := &models.JobMetadata{ JobKind: gr.JobKind(), + Cron: gr.Schedule.Cron, // GC job must be unique ... IsUnique: true, } - switch gr.Schedule.Type { - case ScheduleDaily: - h, m, s := utils.ParseOfftime(gr.Schedule.Offtime) - metadata.Cron = fmt.Sprintf("%d %d %d * * *", s, m, h) - case ScheduleWeekly: - h, m, s := utils.ParseOfftime(gr.Schedule.Offtime) - metadata.Cron = fmt.Sprintf("%d %d %d * * %d", s, m, h, gr.Schedule.Weekday%7) - case ScheduleManual, ScheduleNone: - default: - return nil, fmt.Errorf("unsupported schedule trigger type: %s", gr.Schedule.Type) - } - jobData := &models.JobData{ Name: job.ImageGC, Parameters: gr.Parameters, @@ -112,7 +103,7 @@ func (gr *GCReq) ToJob() (*models.JobData, error) { StatusHook: fmt.Sprintf("%s/service/notifications/jobs/adminjob/%d", config.InternalCoreURL(), gr.ID), } - return jobData, nil + return jobData } // IsPeriodic ... @@ -123,7 +114,7 @@ func (gr *GCReq) IsPeriodic() bool { // JobKind ... func (gr *GCReq) JobKind() string { switch gr.Schedule.Type { - case ScheduleDaily, ScheduleWeekly: + case ScheduleHourly, ScheduleDaily, ScheduleWeekly, ScheduleCustom: return job.JobKindPeriodic case ScheduleManual: return job.JobKindGeneric diff --git a/src/core/api/models/reg_gc_test.go b/src/core/api/models/reg_gc_test.go index 0de7c1486..1d8da9c4e 100644 --- a/src/core/api/models/reg_gc_test.go +++ b/src/core/api/models/reg_gc_test.go @@ -41,16 +41,15 @@ func TestMain(m *testing.M) { func TestToJob(t *testing.T) { schedule := &ScheduleParam{ - Type: "Daily", - Offtime: 200, + Type: "Daily", + Cron: "20 3 0 * * *", } adminjob := &GCReq{ Schedule: schedule, } - job, err := adminjob.ToJob() - assert.Nil(t, err) + job := adminjob.ToJob() assert.Equal(t, job.Name, "IMAGE_GC") assert.Equal(t, job.Metadata.JobKind, common_job.JobKindPeriodic) assert.Equal(t, job.Metadata.Cron, "20 3 0 * * *") @@ -65,29 +64,15 @@ func TestToJobManual(t *testing.T) { Schedule: schedule, } - job, err := adminjob.ToJob() - assert.Nil(t, err) + job := adminjob.ToJob() assert.Equal(t, job.Name, "IMAGE_GC") assert.Equal(t, job.Metadata.JobKind, common_job.JobKindGeneric) } -func TestToJobErr(t *testing.T) { - schedule := &ScheduleParam{ - Type: "test", - } - - adminjob := &GCReq{ - Schedule: schedule, - } - - _, err := adminjob.ToJob() - assert.NotNil(t, err) -} - func TestIsPeriodic(t *testing.T) { schedule := &ScheduleParam{ - Type: "Daily", - Offtime: 200, + Type: "Daily", + Cron: "20 3 0 * * *", } adminjob := &GCReq{ @@ -100,8 +85,8 @@ func TestIsPeriodic(t *testing.T) { func TestJobKind(t *testing.T) { schedule := &ScheduleParam{ - Type: "Daily", - Offtime: 200, + Type: "Daily", + Cron: "20 3 0 * * *", } adminjob := &GCReq{ Schedule: schedule, @@ -121,12 +106,12 @@ func TestJobKind(t *testing.T) { func TestCronString(t *testing.T) { schedule := &ScheduleParam{ - Type: "Daily", - Offtime: 102, + Type: "Daily", + Cron: "20 3 0 * * *", } adminjob := &GCReq{ Schedule: schedule, } cronStr := adminjob.CronString() - assert.True(t, strings.EqualFold(cronStr, "{\"type\":\"Daily\",\"Weekday\":0,\"Offtime\":102}")) + assert.True(t, strings.EqualFold(cronStr, "{\"type\":\"Daily\",\"Cron\":\"20 3 0 * * *\"}")) } diff --git a/src/core/api/reg_gc.go b/src/core/api/reg_gc.go index fb1037506..62b67beaf 100644 --- a/src/core/api/reg_gc.go +++ b/src/core/api/reg_gc.go @@ -214,7 +214,7 @@ func (gc *GCAPI) GetLog() { // submitJob submits a job to job service per request func (gc *GCAPI) submitJob(gr *models.GCReq) { - // cannot post multiple schdule for GC job. + // cannot post multiple schedule for GC job. if gr.IsPeriodic() { jobs, err := dao.GetAdminJobs(&common_models.AdminJobQuery{ Name: common_job.ImageGC, @@ -243,7 +243,7 @@ func (gc *GCAPI) submitJob(gr *models.GCReq) { gr.Parameters = map[string]interface{}{ "redis_url_reg": os.Getenv("_REDIS_URL_REG"), } - job, err := gr.ToJob() + job := gr.ToJob() if err != nil { gc.HandleInternalServerError(fmt.Sprintf("%v", err)) return diff --git a/src/core/api/reg_gc_test.go b/src/core/api/reg_gc_test.go index 5c7b7bbea..7581e4a9e 100644 --- a/src/core/api/reg_gc_test.go +++ b/src/core/api/reg_gc_test.go @@ -54,7 +54,7 @@ func TestConvertToGCRep(t *testing.T) { ID: 1, Name: "IMAGE_GC", Kind: "Generic", - Cron: "{\"Type\":\"Manual\",\"Weekday\":0,\"Offtime\":0}", + Cron: "{\"Type\":\"Daily\",\"Cron\":\"20 3 0 * * *\"}", Status: "pending", Deleted: false, }, @@ -63,9 +63,8 @@ func TestConvertToGCRep(t *testing.T) { Name: "IMAGE_GC", Kind: "Generic", Schedule: &api_modes.ScheduleParam{ - Type: "Manual", - Weekday: 0, - Offtime: 0, + Type: "Daily", + Cron: "20 3 0 * * *", }, Status: "pending", Deleted: false,