diff --git a/bin/csctl/cmd/import.go b/bin/csctl/cmd/import.go index fb8fea8..8913095 100644 --- a/bin/csctl/cmd/import.go +++ b/bin/csctl/cmd/import.go @@ -4,14 +4,13 @@ import ( "bytes" "encoding/json" "fmt" + "math/rand" "os/exec" "strings" - "time" - "math/rand" - "github.com/shunfei/cronsun" + cron2 "github.com/shunfei/cronsun/node/cron" "github.com/spf13/cobra" ) @@ -33,47 +32,41 @@ var ImportCmd = &cobra.Command{ Use: "import", Short: `it will load the job from the crontab, but you must to confirm you can execute 'crontab -l'`, Run: func(cmd *cobra.Command, args []string) { - ea := NewExitAction() - var nodeInclude []string - if len(importNodes) > 0 { nodeInclude = strings.Split(importNodes, spliter) } - crons := loadCrons() - + ea := NewExitAction() + crons, err := loadCrons() + if err != nil { + ea.Exit("load crontab failed,err:%s", err.Error()) + } total := len(crons) var successCount int - ea.After = func() { fmt.Printf("total:%d,success:%d,failed:%d\n", total, successCount, total-successCount) - cmd.Help() + if err := cmd.Help(); err != nil { + return + } } - rand.Seed(time.Now().Unix()) - for _, cron := range crons { job := cronsun.Job{} job.ID = cronsun.NextID() job.Command = cron.cmd - jr := &cronsun.JobRule{ Timer: "* " + cron.timer, } - jr.NodeIDs = nodeInclude - job.Name = fmt.Sprintf("crontab-%d", rand.Intn(1000)) job.Group = "crontab" job.Rules = append(job.Rules, jr) // 默认先暂停 job.Pause = true - if err := job.Check(); err != nil { ea.Exit("job check error:%s", err.Error()) } - b, err := json.Marshal(job) if err != nil { ea.Exit("json marshal error:%s", err.Error()) @@ -83,31 +76,46 @@ var ImportCmd = &cobra.Command{ if err != nil { ea.Exit("etcd put error:%s", err.Error()) } - successCount++ - fmt.Printf("crontab-%s %s has import to the cronsun, the job id is:%s\n", cron.timer, cron.cmd, job.ID) } - fmt.Printf("import fininsh,success:%d\n", successCount) + fmt.Printf("import fininsh,succes:%d\n", successCount) }, } -func loadCrons() []cron { - var crons []cron - - cmd := exec.Command("crontab", "-l") +func checkCrons(crons []string) (invalid []string) { + for _, item := range crons { + item = strings.TrimSpace(item) + if item != "" && !strings.HasPrefix(item, "#") { + expr := strings.Fields(item) + expr = expr[:5] + _, err := cron2.ParseStandard(strings.Join(expr, " ")) + if err != nil { + invalid = append(invalid, item) + } + } + } + return +} +func loadCrons() (crons []cron, err error) { var b bytes.Buffer + cmd := exec.Command("crontab", "-l") cmd.Stdout = &b cmd.Stderr = &b - - err := cmd.Run() + err = cmd.Run() if err != nil { - fmt.Println(err) + return } result := strings.Split(b.String(), "\n") + invalid := checkCrons(result) + if len(invalid) > 0 { + title := fmt.Sprintf("There are %d invalid cron expression,please check them at first.\n", len(invalid)) + err = fmt.Errorf(title + strings.Join(invalid, "\n")) + return + } for _, item := range result { item = strings.TrimSpace(item) @@ -118,6 +126,5 @@ func loadCrons() []cron { crons = append(crons, cron{timer, cmd}) } } - - return crons + return } diff --git a/bin/csctl/cmd/import_test.go b/bin/csctl/cmd/import_test.go new file mode 100644 index 0000000..262e81d --- /dev/null +++ b/bin/csctl/cmd/import_test.go @@ -0,0 +1,23 @@ +package cmd + +import ( + "strings" + "testing" +) + +func TestCheckCrons(t *testing.T) { + crontab := ` +*/1 * * * * /usr/bine/echo hello +* * * * * /usr/bin/ls +* & * * * /usr/bin/php -v +* * * * /usr/bin/go run main.go +` + invalidCrons := checkCrons(strings.Split(crontab, "\n")) + if len(invalidCrons) != 2 { + t.Error("should have 2 cron expression,but get none.") + } + if invalidCrons[0] != "* & * * * /usr/bin/php -v" || + invalidCrons[1] != "* * * * /usr/bin/go run main.go" { + t.Error("invalid cron expression should * & * * * /usr/bin/php -v and * * * * /usr/bin/go run main.go.") + } +}