From f7a346a380076b3ea76ec6f99f09b3c26b72f002 Mon Sep 17 00:00:00 2001 From: Bel LaPointe Date: Fri, 24 Apr 2020 09:52:34 -0600 Subject: [PATCH] Move jobs raw definition to their own namespace and the cascading fallout --- config/ns/ns.go | 5 ++- main.go | 3 ++ scheduler/job.go | 84 ++++++++++++++++++++++++++++--------- scheduler/scheduler.go | 5 ++- scheduler/scheduler_test.go | 5 +-- server/job.go | 5 ++- server/upsert.go | 12 ++---- 7 files changed, 84 insertions(+), 35 deletions(-) diff --git a/config/ns/ns.go b/config/ns/ns.go index 048ba27..00660a8 100755 --- a/config/ns/ns.go +++ b/config/ns/ns.go @@ -1,6 +1,7 @@ package ns var ( - Jobs = []string{"jobs"} - Output = []string{"jobs", "output"} + Jobs = []string{"jobs", "master"} + JobsRaw = []string{"jobs", "raw"} + Output = []string{"jobs", "output"} ) diff --git a/main.go b/main.go index 22eb2de..9000a49 100755 --- a/main.go +++ b/main.go @@ -70,6 +70,9 @@ func EnqueueBackups() { if err := lastn.Push(); err != nil { log.Println("backup failed:", err) } + if err := lastn.Clean(); err != nil { + log.Println("backup clean failed:", err) + } for _ = range ticker.C { log.Println("backing up...") if err := lastn.Push(); err != nil { diff --git a/scheduler/job.go b/scheduler/job.go index 59b7bfc..f13a2e9 100755 --- a/scheduler/job.go +++ b/scheduler/job.go @@ -8,6 +8,7 @@ import ( "local/firestormy/config/ns" "local/firestormy/logger" "local/logb" + "local/storage" "os/exec" "strings" "time" @@ -19,7 +20,6 @@ type Job struct { Title string Name string Schedule string - Raw string Runner Runner Disabled bool foo func() @@ -42,10 +42,13 @@ func newBashJob(schedule, sh string, title ...string) (*Job, error) { if !validCron(schedule) { return nil, ErrBadCron } + key := uuid.New().String() + if err := config.Store.Set(key, []byte(sh), ns.JobsRaw...); err != nil { + return nil, err + } j := &Job{ - Name: uuid.New().String(), + Name: key, Schedule: schedule, - Raw: sh, Runner: Bash, } if len(title) == 0 || len(title[0]) == 0 { @@ -54,31 +57,70 @@ func newBashJob(schedule, sh string, title ...string) (*Job, error) { j.Title = title[0] } j.foo = func() { - logb.Debugf("[sched] run %s/%s? %v", j.Title, j.Name, j.Disabled) - if j.Disabled { - return + do := func() ([]byte, error) { + logb.Debugf("[sched] run %s/%s? %v", j.Title, j.Name, j.Disabled) + if j.Disabled { + return nil, nil + } + sh, err := config.Store.Get(j.Name, ns.JobsRaw...) + if err != nil { + return nil, err + } + cmd := exec.Command("bash", "-c", string(sh)) + j.LastRun = time.Now() + start := time.Now() + out, err := cmd.CombinedOutput() + j.LastRuntime = time.Since(start) + if cmd != nil && cmd.ProcessState != nil { + j.LastStatus = cmd.ProcessState.ExitCode() + } else { + j.LastStatus = 1 + } + return out, err } - cmd := exec.Command("bash", "-c", sh) - j.LastRun = time.Now() - start := time.Now() - out, err := cmd.CombinedOutput() - j.LastRuntime = time.Since(start) + b, err := do() + logb.Debugf("[sched] run %s: (%v) %s", j.Name, err, b) if err != nil { - out = []byte(fmt.Sprintf("error running command: %v: %s", err, out)) + b = []byte(fmt.Sprintf("err running command: %s: %s", err.Error(), b)) } - j.LastOutput = strings.TrimSpace(string(out)) - if cmd != nil && cmd.ProcessState != nil { - j.LastStatus = cmd.ProcessState.ExitCode() - } - b, err := j.Encode() + j.LastOutput = strings.TrimSpace(string(b)) + b2, err := j.Encode() if err == nil { - config.Store.Set(j.Name, b, ns.Jobs...) + err = config.Store.Set(j.Name, b2, ns.Jobs...) } - logger.New().Info("result", fmt.Sprintf("%+v", j)) + logger.New().Info("result", fmt.Sprintf("(%v) %s", err, b)) } return j, nil } +func (j *Job) Rename(name string) error { + sh, err := config.Store.Get(j.Name, ns.JobsRaw...) + if err != nil { + return err + } + b, err := j.Encode() + if err != nil { + return err + } + + if err := config.Store.Set(name, sh, ns.JobsRaw...); err != nil { + return err + } + if err := config.Store.Set(name, b, ns.Jobs...); err != nil { + return err + } + + if err := config.Store.Set(j.Name, nil, ns.Jobs...); err != nil && err != storage.ErrNotFound { + return err + } + if err := config.Store.Set(j.Name, nil, ns.JobsRaw...); err != nil && err != storage.ErrNotFound { + return err + } + + j.Name = name + return nil +} + func (j *Job) Run() { j.foo() } @@ -97,8 +139,10 @@ func (j *Job) Decode(b []byte) error { if err != nil { return err } - k, err := NewJob(j.Runner, j.Schedule, j.Raw) + k, err := NewJob(j.Runner, j.Schedule, "") if err == nil { + config.Store.Set(k.Name, nil, ns.JobsRaw...) + config.Store.Set(k.Name, nil, ns.Jobs...) k.Name = j.Name k.Title = j.Title k.LastStatus = j.LastStatus diff --git a/scheduler/scheduler.go b/scheduler/scheduler.go index ff77a37..5bc6c0e 100755 --- a/scheduler/scheduler.go +++ b/scheduler/scheduler.go @@ -226,7 +226,10 @@ func (s *Scheduler) Remove(j *Job) error { if was == is { return ErrJobNotFound } - return config.Store.Set(j.Name, nil, ns.Jobs...) + if err := config.Store.Set(j.Name, nil, ns.Jobs...); err != nil { + return err + } + return config.Store.Set(j.Name, nil, ns.JobsRaw...) } func (s *Scheduler) getEntry(j *Job) (cron.EntryID, bool) { diff --git a/scheduler/scheduler_test.go b/scheduler/scheduler_test.go index e367513..e5fe303 100755 --- a/scheduler/scheduler_test.go +++ b/scheduler/scheduler_test.go @@ -5,6 +5,7 @@ import ( "fmt" "io/ioutil" "local/firestormy/config" + "local/firestormy/config/ns" "local/storage" "os" "testing" @@ -215,7 +216,7 @@ func TestSchedulerUpdate(t *testing.T) { t.Fatal(err) } time.Sleep(time.Millisecond * 1500) - j.Raw = "echo 2" + config.Store.Set(j.Name, []byte("echo 2"), ns.JobsRaw...) j.Title = "title 2" if err := s.Update(j); err != nil { t.Fatal(err) @@ -226,8 +227,6 @@ func TestSchedulerUpdate(t *testing.T) { t.Fatal(err) } else if j, err := s.loadJobFromStore(j.Name); err != nil { t.Fatal(err) - } else if j.Raw != "echo 2" { - t.Error(j.Raw) } else if j.Title != "title 2" { t.Error(j.Title) } else if entry := s.cron.Entry(s.running[j.Name]); entry == s.cron.Entry(-99) { diff --git a/server/job.go b/server/job.go index 647e194..7e6c35a 100755 --- a/server/job.go +++ b/server/job.go @@ -1,6 +1,8 @@ package server import ( + "local/firestormy/config" + "local/firestormy/config/ns" "local/firestormy/scheduler" "time" ) @@ -16,7 +18,8 @@ func toMap(j *scheduler.Job) map[string]interface{} { out["title"] = j.Title out["cron"] = j.Schedule out["language"] = j.Runner.String() - out["script"] = j.Raw + b, _ := config.Store.Get(j.Name, ns.JobsRaw...) + out["script"] = string(b) out["last"] = map[string]interface{}{ "run": j.LastRun.In(tz).Format(`2006-01-02 15:04:05 MST`), "runtime": j.LastRuntime.String(), diff --git a/server/upsert.go b/server/upsert.go index 0ec3a25..0a5369c 100755 --- a/server/upsert.go +++ b/server/upsert.go @@ -10,8 +10,6 @@ import ( "local/firestormy/scheduler" "local/logb" "net/http" - - "github.com/google/uuid" ) type upsertRequest struct { @@ -58,7 +56,9 @@ func (u *upsertRequest) toJob() (*scheduler.Job, error) { return nil, err } j.Title = u.Title - j.Name = u.ID + if u.ID != "" { + err = j.Rename(u.ID) + } j.Disabled = u.Disabled return j, err } @@ -75,11 +75,7 @@ func (s *Server) upsert(w http.ResponseWriter, r *http.Request) { http.Error(w, err.Error(), http.StatusInternalServerError) return } - if job.Name == "" { - job.Name = uuid.New().String() - if job.Title == "" { - job.Title = job.Name - } + if upsert.ID == "" { if err := scheduler.Schedule.Add(job); err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return