Move jobs raw definition to their own namespace and the cascading fallout

master
Bel LaPointe 2020-04-24 09:52:34 -06:00
parent 84400e4401
commit f7a346a380
7 changed files with 84 additions and 35 deletions

View File

@ -1,6 +1,7 @@
package ns package ns
var ( var (
Jobs = []string{"jobs"} Jobs = []string{"jobs", "master"}
Output = []string{"jobs", "output"} JobsRaw = []string{"jobs", "raw"}
Output = []string{"jobs", "output"}
) )

View File

@ -70,6 +70,9 @@ func EnqueueBackups() {
if err := lastn.Push(); err != nil { if err := lastn.Push(); err != nil {
log.Println("backup failed:", err) log.Println("backup failed:", err)
} }
if err := lastn.Clean(); err != nil {
log.Println("backup clean failed:", err)
}
for _ = range ticker.C { for _ = range ticker.C {
log.Println("backing up...") log.Println("backing up...")
if err := lastn.Push(); err != nil { if err := lastn.Push(); err != nil {

View File

@ -8,6 +8,7 @@ import (
"local/firestormy/config/ns" "local/firestormy/config/ns"
"local/firestormy/logger" "local/firestormy/logger"
"local/logb" "local/logb"
"local/storage"
"os/exec" "os/exec"
"strings" "strings"
"time" "time"
@ -19,7 +20,6 @@ type Job struct {
Title string Title string
Name string Name string
Schedule string Schedule string
Raw string
Runner Runner Runner Runner
Disabled bool Disabled bool
foo func() foo func()
@ -42,10 +42,13 @@ func newBashJob(schedule, sh string, title ...string) (*Job, error) {
if !validCron(schedule) { if !validCron(schedule) {
return nil, ErrBadCron return nil, ErrBadCron
} }
key := uuid.New().String()
if err := config.Store.Set(key, []byte(sh), ns.JobsRaw...); err != nil {
return nil, err
}
j := &Job{ j := &Job{
Name: uuid.New().String(), Name: key,
Schedule: schedule, Schedule: schedule,
Raw: sh,
Runner: Bash, Runner: Bash,
} }
if len(title) == 0 || len(title[0]) == 0 { 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.Title = title[0]
} }
j.foo = func() { j.foo = func() {
logb.Debugf("[sched] run %s/%s? %v", j.Title, j.Name, j.Disabled) do := func() ([]byte, error) {
if j.Disabled { logb.Debugf("[sched] run %s/%s? %v", j.Title, j.Name, j.Disabled)
return 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) b, err := do()
j.LastRun = time.Now() logb.Debugf("[sched] run %s: (%v) %s", j.Name, err, b)
start := time.Now()
out, err := cmd.CombinedOutput()
j.LastRuntime = time.Since(start)
if err != nil { 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)) j.LastOutput = strings.TrimSpace(string(b))
if cmd != nil && cmd.ProcessState != nil { b2, err := j.Encode()
j.LastStatus = cmd.ProcessState.ExitCode()
}
b, err := j.Encode()
if err == nil { 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 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() { func (j *Job) Run() {
j.foo() j.foo()
} }
@ -97,8 +139,10 @@ func (j *Job) Decode(b []byte) error {
if err != nil { if err != nil {
return err return err
} }
k, err := NewJob(j.Runner, j.Schedule, j.Raw) k, err := NewJob(j.Runner, j.Schedule, "")
if err == nil { if err == nil {
config.Store.Set(k.Name, nil, ns.JobsRaw...)
config.Store.Set(k.Name, nil, ns.Jobs...)
k.Name = j.Name k.Name = j.Name
k.Title = j.Title k.Title = j.Title
k.LastStatus = j.LastStatus k.LastStatus = j.LastStatus

View File

@ -226,7 +226,10 @@ func (s *Scheduler) Remove(j *Job) error {
if was == is { if was == is {
return ErrJobNotFound 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) { func (s *Scheduler) getEntry(j *Job) (cron.EntryID, bool) {

View File

@ -5,6 +5,7 @@ import (
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"local/firestormy/config" "local/firestormy/config"
"local/firestormy/config/ns"
"local/storage" "local/storage"
"os" "os"
"testing" "testing"
@ -215,7 +216,7 @@ func TestSchedulerUpdate(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
time.Sleep(time.Millisecond * 1500) time.Sleep(time.Millisecond * 1500)
j.Raw = "echo 2" config.Store.Set(j.Name, []byte("echo 2"), ns.JobsRaw...)
j.Title = "title 2" j.Title = "title 2"
if err := s.Update(j); err != nil { if err := s.Update(j); err != nil {
t.Fatal(err) t.Fatal(err)
@ -226,8 +227,6 @@ func TestSchedulerUpdate(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} else if j, err := s.loadJobFromStore(j.Name); err != nil { } else if j, err := s.loadJobFromStore(j.Name); err != nil {
t.Fatal(err) t.Fatal(err)
} else if j.Raw != "echo 2" {
t.Error(j.Raw)
} else if j.Title != "title 2" { } else if j.Title != "title 2" {
t.Error(j.Title) t.Error(j.Title)
} else if entry := s.cron.Entry(s.running[j.Name]); entry == s.cron.Entry(-99) { } else if entry := s.cron.Entry(s.running[j.Name]); entry == s.cron.Entry(-99) {

View File

@ -1,6 +1,8 @@
package server package server
import ( import (
"local/firestormy/config"
"local/firestormy/config/ns"
"local/firestormy/scheduler" "local/firestormy/scheduler"
"time" "time"
) )
@ -16,7 +18,8 @@ func toMap(j *scheduler.Job) map[string]interface{} {
out["title"] = j.Title out["title"] = j.Title
out["cron"] = j.Schedule out["cron"] = j.Schedule
out["language"] = j.Runner.String() 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{}{ out["last"] = map[string]interface{}{
"run": j.LastRun.In(tz).Format(`2006-01-02 15:04:05 MST`), "run": j.LastRun.In(tz).Format(`2006-01-02 15:04:05 MST`),
"runtime": j.LastRuntime.String(), "runtime": j.LastRuntime.String(),

View File

@ -10,8 +10,6 @@ import (
"local/firestormy/scheduler" "local/firestormy/scheduler"
"local/logb" "local/logb"
"net/http" "net/http"
"github.com/google/uuid"
) )
type upsertRequest struct { type upsertRequest struct {
@ -58,7 +56,9 @@ func (u *upsertRequest) toJob() (*scheduler.Job, error) {
return nil, err return nil, err
} }
j.Title = u.Title j.Title = u.Title
j.Name = u.ID if u.ID != "" {
err = j.Rename(u.ID)
}
j.Disabled = u.Disabled j.Disabled = u.Disabled
return j, err return j, err
} }
@ -75,11 +75,7 @@ func (s *Server) upsert(w http.ResponseWriter, r *http.Request) {
http.Error(w, err.Error(), http.StatusInternalServerError) http.Error(w, err.Error(), http.StatusInternalServerError)
return return
} }
if job.Name == "" { if upsert.ID == "" {
job.Name = uuid.New().String()
if job.Title == "" {
job.Title = job.Name
}
if err := scheduler.Schedule.Add(job); err != nil { if err := scheduler.Schedule.Add(job); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError) http.Error(w, err.Error(), http.StatusInternalServerError)
return return