diff --git a/make/migrations/postgresql/0004_1.8.0_schema.up.sql b/make/migrations/postgresql/0004_1.8.0_schema.up.sql index d2cb540a0..846068dc9 100644 --- a/make/migrations/postgresql/0004_1.8.0_schema.up.sql +++ b/make/migrations/postgresql/0004_1.8.0_schema.up.sql @@ -155,3 +155,18 @@ DROP INDEX poid_uptime; DROP INDEX poid_status; DROP TRIGGER replication_job_update_time_at_modtime ON replication_job; ALTER TABLE replication_job RENAME TO replication_schedule_job; + +/* +migrate scan all schedule + +If user set the scan all schedule, move it into table admin_job, and let the api the parse the json data. +*/ +DO $$ +BEGIN + IF exists(select * FROM properties WHERE k = 'scan_all_policy') then + INSERT INTO admin_job (job_name, job_kind, cron_str, status) VALUES ('IMAGE_SCAN_ALL', 'Periodic', (select v FROM properties WHERE k = 'scan_all_policy'), 'pending'); + DELETE FROM properties WHERE k='scan_all_policy'; + END IF; +END $$; + + diff --git a/src/common/models/adminjob.go b/src/common/models/adminjob.go index 37aedfef3..ca31a9c18 100644 --- a/src/common/models/adminjob.go +++ b/src/common/models/adminjob.go @@ -15,6 +15,7 @@ package models import ( + "fmt" "time" ) @@ -51,3 +52,27 @@ type AdminJobQuery struct { Deleted bool Pagination } + +// ScheduleParam ... +type ScheduleParam struct { + Type string `json:"type"` + Weekday int8 `json:"weekday"` + Offtime int64 `json:"offtime"` +} + +// ParseScheduleParamToCron ... +func ParseScheduleParamToCron(param *ScheduleParam) string { + if param == nil { + return "" + } + offtime := param.Offtime + offtime = offtime % (3600 * 24) + hour := int(offtime / 3600) + offtime = offtime % 3600 + minute := int(offtime / 60) + second := int(offtime % 60) + if param.Type == "Weekly" { + return fmt.Sprintf("%d %d %d * * %d", second, minute, hour, param.Weekday%7) + } + return fmt.Sprintf("%d %d %d * * *", second, minute, hour) +} diff --git a/src/core/api/admin_job.go b/src/core/api/admin_job.go index 1fbb1be32..112b3b3c6 100644 --- a/src/core/api/admin_job.go +++ b/src/core/api/admin_job.go @@ -19,7 +19,6 @@ import ( "net/http" "strconv" - "encoding/json" "github.com/goharbor/harbor/src/common/dao" common_http "github.com/goharbor/harbor/src/common/http" common_job "github.com/goharbor/harbor/src/common/job" @@ -283,11 +282,11 @@ func convertToAdminJobRep(job *common_models.AdminJob) (models.AdminJobRep, erro } if len(job.Cron) > 0 { - schedule := &models.ScheduleParam{} - if err := json.Unmarshal([]byte(job.Cron), &schedule); err != nil { + schedule, err := models.ConvertSchedule(job.Cron) + if err != nil { return models.AdminJobRep{}, err } - AdminJobRep.Schedule = schedule + AdminJobRep.Schedule = &schedule } return AdminJobRep, nil } diff --git a/src/core/api/models/admin_job.go b/src/core/api/models/admin_job.go index 1dd3465d2..dfd3da3b8 100644 --- a/src/core/api/models/admin_job.go +++ b/src/core/api/models/admin_job.go @@ -17,11 +17,14 @@ package models import ( "encoding/json" "fmt" + "strings" "time" "github.com/astaxie/beego/validation" "github.com/goharbor/harbor/src/common/job" "github.com/goharbor/harbor/src/common/job/models" + common_models "github.com/goharbor/harbor/src/common/models" + common_utils "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" @@ -139,3 +142,42 @@ func (ar *AdminJobReq) CronString() string { } return string(str) } + +// ConvertSchedule converts different kinds of cron string into one standard for UI to show. +// in the latest design, it uses {"type":"Daily","cron":"0 0 0 * * *"} as the cron item. +// As for supporting migration from older version, it needs to convert {"parameter":{"daily_time":0},"type":"daily"} +// and {"type":"Daily","weekday":0,"offtime":57600} into one standard. +func ConvertSchedule(cronStr string) (ScheduleParam, error) { + if cronStr == "" { + return ScheduleParam{}, nil + } + + convertedSchedule := ScheduleParam{} + convertedSchedule.Type = "custom" + + if strings.Contains(cronStr, "parameter") { + scheduleModel := common_models.ScanAllPolicy{} + if err := json.Unmarshal([]byte(cronStr), &scheduleModel); err != nil { + return ScheduleParam{}, err + } + h, m, s := common_utils.ParseOfftime(int64(scheduleModel.Parm["daily_time"].(float64))) + cron := fmt.Sprintf("%d %d %d * * *", s, m, h) + convertedSchedule.Cron = cron + return convertedSchedule, nil + } else if strings.Contains(cronStr, "offtime") { + scheduleModel := common_models.ScheduleParam{} + if err := json.Unmarshal([]byte(cronStr), &scheduleModel); err != nil { + return ScheduleParam{}, err + } + convertedSchedule.Cron = common_models.ParseScheduleParamToCron(&scheduleModel) + return convertedSchedule, nil + } else if strings.Contains(cronStr, "cron") { + scheduleModel := ScheduleParam{} + if err := json.Unmarshal([]byte(cronStr), &scheduleModel); err != nil { + return ScheduleParam{}, err + } + return scheduleModel, nil + } + + return ScheduleParam{}, fmt.Errorf("unsupported cron format, %s", cronStr) +} diff --git a/src/core/api/models/admin_job_test.go b/src/core/api/models/admin_job_test.go index 51e5394a3..3a149fe12 100644 --- a/src/core/api/models/admin_job_test.go +++ b/src/core/api/models/admin_job_test.go @@ -137,3 +137,20 @@ func TestCronString(t *testing.T) { cronStr := adminjob.CronString() assert.True(t, strings.EqualFold(cronStr, "{\"type\":\"Daily\",\"Cron\":\"20 3 0 * * *\"}")) } + +func TestConvertSchedule(t *testing.T) { + schedule1 := "{\"type\":\"Daily\",\"cron\":\"20 3 0 * * *\"}" + converted1, err1 := ConvertSchedule(schedule1) + assert.Nil(t, err1) + assert.Equal(t, converted1.Cron, "20 3 0 * * *") + + schedule2 := "{\"type\":\"Daily\",\"weekday\":0,\"offtime\":57720}" + converted2, err2 := ConvertSchedule(schedule2) + assert.Nil(t, err2) + assert.Equal(t, converted2.Cron, "0 2 16 * * *") + + schedule3 := "{\"parameter\":{\"daily_time\":57720},\"type\":\"daily\"}" + converted3, err3 := ConvertSchedule(schedule3) + assert.Nil(t, err3) + assert.Equal(t, converted3.Cron, "0 2 16 * * *") +}