Reload job in ui
parent
19d4b645b8
commit
8138e31e53
24
TODO.md
24
TODO.md
|
|
@ -9,29 +9,29 @@
|
||||||
x last output
|
x last output
|
||||||
x add titles to jobs
|
x add titles to jobs
|
||||||
x job title includes last pass/fail icon
|
x job title includes last pass/fail icon
|
||||||
1. button to modify (copies to upsert form)
|
x button to modify (copies to upsert form)
|
||||||
1. button to delete
|
x button to delete
|
||||||
1. UI to mutate
|
1. UI to mutate
|
||||||
1. submit job
|
x submit job
|
||||||
1. delete job
|
x delete job
|
||||||
1. pause jobs
|
x pause jobs
|
||||||
1. interrupt job
|
1. interrupt job
|
||||||
1. force run
|
1. force run
|
||||||
1. JS
|
x JS
|
||||||
x ajax for json calls
|
x ajax for json calls
|
||||||
|
|
||||||
# Backend
|
# Backend
|
||||||
|
|
||||||
x load from file
|
x load from file
|
||||||
1. interrupt running jobs
|
1. interrupt running jobs
|
||||||
1. temporarily disable jobs
|
1. disable jobs
|
||||||
1. json API
|
1. json API
|
||||||
1. list
|
1. list
|
||||||
1. last run output
|
x last run output
|
||||||
1. last run pass/fail bool
|
x last run pass/fail bool
|
||||||
1. last run timestamp
|
x last run timestamp
|
||||||
1. next run
|
1. next run
|
||||||
1. upsert
|
x upsert
|
||||||
1. delete job
|
1. delete job
|
||||||
1. pause/disable job
|
1. pause/disable job
|
||||||
1. running job
|
1. running job
|
||||||
|
|
@ -41,4 +41,4 @@ x load from file
|
||||||
x add optional second for test main
|
x add optional second for test main
|
||||||
1. test main
|
1. test main
|
||||||
x add titles to jobs
|
x add titles to jobs
|
||||||
1. namespace for jobs, output, lastrun, laststatus
|
x namespace for jobs, output, lastrun, laststatus
|
||||||
|
|
|
||||||
9
main.go
9
main.go
|
|
@ -14,17 +14,14 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
var err error
|
|
||||||
s := scheduler.New()
|
|
||||||
if config.Config != "" {
|
if config.Config != "" {
|
||||||
var err error
|
var err error
|
||||||
s, err = scheduler.NewFromFile(config.Config)
|
scheduler.Schedule, err = scheduler.NewFromFile(config.Config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
err = s.Start()
|
if err := scheduler.Schedule.Start(); err != nil {
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -46,7 +43,7 @@ func main() {
|
||||||
stop := make(chan os.Signal)
|
stop := make(chan os.Signal)
|
||||||
signal.Notify(stop, os.Interrupt)
|
signal.Notify(stop, os.Interrupt)
|
||||||
<-stop
|
<-stop
|
||||||
s.Stop()
|
scheduler.Schedule.Stop()
|
||||||
}
|
}
|
||||||
|
|
||||||
func EnqueueBackups() {
|
func EnqueueBackups() {
|
||||||
|
|
|
||||||
|
|
@ -10,11 +10,12 @@
|
||||||
<summary>Upsert Job</summary>
|
<summary>Upsert Job</summary>
|
||||||
<form id="upsert" action="#" method="get" onsubmit="upsert(); return false;">
|
<form id="upsert" action="#" method="get" onsubmit="upsert(); return false;">
|
||||||
<input type="text" name="id" placeholder="id"/>
|
<input type="text" name="id" placeholder="id"/>
|
||||||
|
<input type="text" name="title" placeholder="title"/>
|
||||||
<label><input type="checkbox" name="disabled"/> Disabled</label>
|
<label><input type="checkbox" name="disabled"/> Disabled</label>
|
||||||
<select name="language" required>
|
<select name="language" required>
|
||||||
<option value="bash" selected>bash</option>
|
<option value="bash" selected>bash</option>
|
||||||
</select>
|
</select>
|
||||||
<input type="text" name="cron" placeholder="cron" value="@daily"/>
|
<input type="text" name="cron" placeholder="cron" value="@daily" required/>
|
||||||
<textarea name="script" placeholder="script" required rows="5"></textarea>
|
<textarea name="script" placeholder="script" required rows="5"></textarea>
|
||||||
<button type="submit">Upsert</button>
|
<button type="submit">Upsert</button>
|
||||||
</form>
|
</form>
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,11 @@ function http(method, remote, callback, body) {
|
||||||
|
|
||||||
function upsert() {
|
function upsert() {
|
||||||
function cb(body, status) {
|
function cb(body, status) {
|
||||||
console.log(status, body)
|
if (status == 200) {
|
||||||
|
init()
|
||||||
|
} else {
|
||||||
|
console.log("error upserting:", status, body)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
http("POST", "/api/job/upsert", cb, jsonifyForm("upsert"))
|
http("POST", "/api/job/upsert", cb, jsonifyForm("upsert"))
|
||||||
}
|
}
|
||||||
|
|
@ -28,14 +32,19 @@ function jsonifyForm(id) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function init() {
|
function init() {
|
||||||
|
var table = document.getElementById("jobs").getElementsByTagName("tbody")[0]
|
||||||
function cb(body, status) {
|
function cb(body, status) {
|
||||||
var jobs = JSON.parse(body)
|
var jobs = JSON.parse(body)
|
||||||
|
getJobsTable().innerHTML = ""
|
||||||
jobs.forEach(function(job) {
|
jobs.forEach(function(job) {
|
||||||
var s = format(job)
|
var s = format(job)
|
||||||
inject(s)
|
inject(s)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
function format(job) {
|
http("GET", "/api/job/list", cb, null)
|
||||||
|
}
|
||||||
|
|
||||||
|
function format(job) {
|
||||||
var pause = "⏸"
|
var pause = "⏸"
|
||||||
var passing = "9711"
|
var passing = "9711"
|
||||||
if (job.last.status != 0) {
|
if (job.last.status != 0) {
|
||||||
|
|
@ -45,6 +54,7 @@ function init() {
|
||||||
passing = `&#${passing};`
|
passing = `&#${passing};`
|
||||||
var buttons = ""
|
var buttons = ""
|
||||||
var btns = [
|
var btns = [
|
||||||
|
{"name":"refresh", "icon":"8635"},
|
||||||
{"name":"disable", "icon":"11035"},
|
{"name":"disable", "icon":"11035"},
|
||||||
{"name":"enable", "icon":"9654"},
|
{"name":"enable", "icon":"9654"},
|
||||||
{"name":"modify", "icon":"9999"},
|
{"name":"modify", "icon":"9999"},
|
||||||
|
|
@ -80,12 +90,14 @@ function init() {
|
||||||
</td></tr>
|
</td></tr>
|
||||||
</table>
|
</table>
|
||||||
</details></td></tr>`
|
</details></td></tr>`
|
||||||
}
|
}
|
||||||
function inject(s) {
|
|
||||||
var table = document.getElementById("jobs").getElementsByTagName("tbody")[0]
|
function inject(s) {
|
||||||
table.innerHTML += s
|
getJobsTable().innerHTML += s
|
||||||
}
|
}
|
||||||
http("GET", "/api/job/list", cb, null)
|
|
||||||
|
function getJobsTable() {
|
||||||
|
return document.getElementById("jobs").getElementsByTagName("tbody")[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
init()
|
init()
|
||||||
|
|
@ -103,7 +115,7 @@ function jobenable(input) {
|
||||||
function jobmodify(input) {
|
function jobmodify(input) {
|
||||||
var form = getForm()
|
var form = getForm()
|
||||||
var job = jobFromInput(input)
|
var job = jobFromInput(input)
|
||||||
var fields = ["id", "language", "cron", "script", "disabled"]
|
var fields = ["id", "language", "cron", "script", "disabled", "title"]
|
||||||
fields.forEach(function(field) {
|
fields.forEach(function(field) {
|
||||||
var e = getField(field)
|
var e = getField(field)
|
||||||
e.checked = job[field]
|
e.checked = job[field]
|
||||||
|
|
@ -117,6 +129,31 @@ function jobdelete(input) {
|
||||||
http("DELETE", "/api/job/delete", cb, null)
|
http("DELETE", "/api/job/delete", cb, null)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function jobrefresh(input) {
|
||||||
|
var job = jobFromInput(input)
|
||||||
|
function cb(body, status) {
|
||||||
|
var table = getJobsTable()
|
||||||
|
var summaries = Array.from(table.getElementsByTagName("summary"))
|
||||||
|
summaries.forEach(function(e) {
|
||||||
|
if (e.getAttribute("name") == job.id) {
|
||||||
|
e = e.parentElement
|
||||||
|
var showing = false
|
||||||
|
if (e.getAttribute("open") != null) {
|
||||||
|
showing = true
|
||||||
|
}
|
||||||
|
e = e.parentElement.parentElement
|
||||||
|
var table = document.createElement("table")
|
||||||
|
table.innerHTML = format(JSON.parse(body))
|
||||||
|
if (showing) {
|
||||||
|
table.getElementsByTagName("details")[0].setAttribute("open", "")
|
||||||
|
}
|
||||||
|
e.innerHTML = table.innerHTML
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
http("GET", "/api/job/get/"+job.id, cb, null)
|
||||||
|
}
|
||||||
|
|
||||||
function jobFromInput(input) {
|
function jobFromInput(input) {
|
||||||
var b64 = input.getAttribute("job")
|
var b64 = input.getAttribute("job")
|
||||||
var json = atob(b64)
|
var json = atob(b64)
|
||||||
|
|
|
||||||
|
|
@ -20,12 +20,12 @@ type Job struct {
|
||||||
Schedule string
|
Schedule string
|
||||||
Raw string
|
Raw string
|
||||||
Runner Runner
|
Runner Runner
|
||||||
|
Disabled bool
|
||||||
foo func()
|
foo func()
|
||||||
LastStatus int
|
LastStatus int
|
||||||
LastOutput string
|
LastOutput string
|
||||||
LastRuntime time.Duration
|
LastRuntime time.Duration
|
||||||
LastRun time.Time
|
LastRun time.Time
|
||||||
Disabled bool
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewJob(runner Runner, schedule, raw string) (*Job, error) {
|
func NewJob(runner Runner, schedule, raw string) (*Job, error) {
|
||||||
|
|
@ -59,7 +59,7 @@ func newBashJob(schedule, sh string, title ...string) (*Job, error) {
|
||||||
out, err := cmd.CombinedOutput()
|
out, err := cmd.CombinedOutput()
|
||||||
j.LastRuntime = time.Since(start)
|
j.LastRuntime = time.Since(start)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
out = []byte(fmt.Sprintf("error running command: %v: %v", err, out))
|
out = []byte(fmt.Sprintf("error running command: %v: %s", err, out))
|
||||||
}
|
}
|
||||||
j.LastOutput = strings.TrimSpace(string(out))
|
j.LastOutput = strings.TrimSpace(string(out))
|
||||||
if cmd != nil && cmd.ProcessState != nil {
|
if cmd != nil && cmd.ProcessState != nil {
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,8 @@ import (
|
||||||
cron "github.com/robfig/cron/v3"
|
cron "github.com/robfig/cron/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var Schedule *Scheduler = New()
|
||||||
|
|
||||||
type Scheduler struct {
|
type Scheduler struct {
|
||||||
cron *cron.Cron
|
cron *cron.Cron
|
||||||
running map[string]cron.EntryID
|
running map[string]cron.EntryID
|
||||||
|
|
@ -154,6 +156,40 @@ func (s *Scheduler) loadJobFromStore(k string) (*Job, error) {
|
||||||
return j, err
|
return j, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Scheduler) Update(j *Job) error {
|
||||||
|
entryID, ok := s.getEntry(j)
|
||||||
|
if !ok {
|
||||||
|
return errors.New("job not found in storage")
|
||||||
|
}
|
||||||
|
|
||||||
|
i, err := s.loadJobFromStore(j.Name)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
j.LastStatus = i.LastStatus
|
||||||
|
j.LastOutput = i.LastOutput
|
||||||
|
j.LastRuntime = i.LastRuntime
|
||||||
|
j.LastRun = i.LastRun
|
||||||
|
|
||||||
|
b, err := j.Encode()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := config.Store.Set(j.Name, b, ns.Jobs...); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
s.cron.Remove(entryID)
|
||||||
|
|
||||||
|
entryID, err = s.cron.AddJob(j.Schedule, j)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
s.running[j.Name] = entryID
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (s *Scheduler) Add(j *Job) error {
|
func (s *Scheduler) Add(j *Job) error {
|
||||||
if _, ok := s.getEntry(j); ok {
|
if _, ok := s.getEntry(j); ok {
|
||||||
return ErrDuplicateJob
|
return ErrDuplicateJob
|
||||||
|
|
|
||||||
|
|
@ -2,11 +2,13 @@ package scheduler
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"local/firestormy/config"
|
"local/firestormy/config"
|
||||||
"local/storage"
|
"local/storage"
|
||||||
"os"
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestSchedulerAddRemove(t *testing.T) {
|
func TestSchedulerAddRemove(t *testing.T) {
|
||||||
|
|
@ -192,3 +194,49 @@ func TestSplitScheduleCommandTitle(t *testing.T) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestSchedulerUpdate(t *testing.T) {
|
||||||
|
config.Store, _ = storage.New(storage.MAP)
|
||||||
|
was := config.Store
|
||||||
|
defer func() {
|
||||||
|
config.Store = was
|
||||||
|
}()
|
||||||
|
s := New()
|
||||||
|
j, err := NewJob(Bash, "* * * * *", "hostname")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if err := s.Add(j); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if list, err := s.List(); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
} else if len(list) != 1 {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
time.Sleep(time.Millisecond * 1500)
|
||||||
|
j.Raw = "echo 2"
|
||||||
|
j.Title = "title 2"
|
||||||
|
if err := s.Update(j); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if list, err := s.List(); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
} else if len(list) != 1 {
|
||||||
|
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) {
|
||||||
|
t.Error(entry)
|
||||||
|
} else if entries := s.cron.Entries(); len(entries) != 1 {
|
||||||
|
t.Error(entries)
|
||||||
|
} else if job, ok := entries[0].Job.(*Job); !ok {
|
||||||
|
t.Error(fmt.Sprintf("%T", entries[0].Job))
|
||||||
|
} else if fmt.Sprintf("%+v", job) != fmt.Sprintf("%+v", j) {
|
||||||
|
t.Error(job)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,28 @@
|
||||||
|
package server
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"local/firestormy/config"
|
||||||
|
"local/firestormy/config/ns"
|
||||||
|
"local/firestormy/scheduler"
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (s *Server) get(w http.ResponseWriter, r *http.Request) {
|
||||||
|
keys := strings.Split(r.URL.Path, "/")
|
||||||
|
key := keys[len(keys)-1]
|
||||||
|
|
||||||
|
j := &scheduler.Job{}
|
||||||
|
b, err := config.Store.Get(key, ns.Jobs...)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, err.Error(), http.StatusNotFound)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := j.Decode(b); err != nil {
|
||||||
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
json.NewEncoder(w).Encode(toMap(j))
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,28 @@
|
||||||
|
package server
|
||||||
|
|
||||||
|
import (
|
||||||
|
"local/firestormy/scheduler"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func toMap(j *scheduler.Job) map[string]interface{} {
|
||||||
|
tz, err := time.LoadLocation("America/Denver")
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
out := make(map[string]interface{})
|
||||||
|
out["disabled"] = j.Disabled
|
||||||
|
out["id"] = j.Name
|
||||||
|
out["title"] = j.Title
|
||||||
|
out["cron"] = j.Schedule
|
||||||
|
out["language"] = j.Runner.String()
|
||||||
|
out["script"] = j.Raw
|
||||||
|
out["last"] = map[string]interface{}{
|
||||||
|
"run": j.LastRun.In(tz).Format(`2006-01-02 15:04:05 MST`),
|
||||||
|
"runtime": j.LastRuntime.String(),
|
||||||
|
"output": strings.ReplaceAll(j.LastOutput, "\n", "<br>"),
|
||||||
|
"status": j.LastStatus,
|
||||||
|
}
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
@ -7,7 +7,6 @@ import (
|
||||||
"local/firestormy/scheduler"
|
"local/firestormy/scheduler"
|
||||||
"net/http"
|
"net/http"
|
||||||
"sort"
|
"sort"
|
||||||
"time"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func (s *Server) list(w http.ResponseWriter, r *http.Request) {
|
func (s *Server) list(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
@ -29,22 +28,7 @@ func (s *Server) list(w http.ResponseWriter, r *http.Request) {
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
tz, err := time.LoadLocation("America/Denver")
|
out[i] = toMap(j)
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
out[i]["disabled"] = j.Disabled
|
|
||||||
out[i]["id"] = j.Name
|
|
||||||
out[i]["title"] = j.Title
|
|
||||||
out[i]["cron"] = j.Schedule
|
|
||||||
out[i]["language"] = j.Runner.String()
|
|
||||||
out[i]["script"] = j.Raw
|
|
||||||
out[i]["last"] = map[string]interface{}{
|
|
||||||
"run": j.LastRun.In(tz).Format(`2006-01-02 15:04:05 MST`),
|
|
||||||
"runtime": j.LastRuntime.String(),
|
|
||||||
"output": string(j.LastOutput),
|
|
||||||
"status": j.LastStatus,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
sort.Slice(out, func(i, j int) bool {
|
sort.Slice(out, func(i, j int) bool {
|
||||||
return out[i]["title"].(string) < out[j]["title"].(string)
|
return out[i]["title"].(string) < out[j]["title"].(string)
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,10 @@ func (s *Server) Routes() error {
|
||||||
path string
|
path string
|
||||||
handler http.HandlerFunc
|
handler http.HandlerFunc
|
||||||
}{
|
}{
|
||||||
|
{
|
||||||
|
path: fmt.Sprintf("/api/job/get/%s", router.Wildcard),
|
||||||
|
handler: s.gzip(s.authenticate(s.get)),
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: fmt.Sprintf("/api/job/upsert"),
|
path: fmt.Sprintf("/api/job/upsert"),
|
||||||
handler: s.gzip(s.authenticate(s.upsert)),
|
handler: s.gzip(s.authenticate(s.upsert)),
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ import (
|
||||||
"io"
|
"io"
|
||||||
"local/firestormy/config"
|
"local/firestormy/config"
|
||||||
"local/firestormy/config/ns"
|
"local/firestormy/config/ns"
|
||||||
"log"
|
"local/firestormy/scheduler"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
|
|
@ -52,12 +52,31 @@ func (u *upsertRequest) validate() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (u *upsertRequest) toJob() (*scheduler.Job, error) {
|
||||||
|
j, err := scheduler.NewJob(scheduler.Bash, u.Cron, u.Script)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
j.Title = u.Title
|
||||||
|
j.Name = u.ID
|
||||||
|
j.Disabled = u.Disabled
|
||||||
|
return j, err
|
||||||
|
}
|
||||||
|
|
||||||
func (s *Server) upsert(w http.ResponseWriter, r *http.Request) {
|
func (s *Server) upsert(w http.ResponseWriter, r *http.Request) {
|
||||||
upsert, err := newUpsertRequest(r.Body)
|
upsert, err := newUpsertRequest(r.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
log.Println("received", upsert)
|
job, err := upsert.toJob()
|
||||||
http.Error(w, "not impl", http.StatusNotImplemented)
|
if err != nil {
|
||||||
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := scheduler.Schedule.Update(job); err != nil {
|
||||||
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
json.NewEncoder(w).Encode(map[string]interface{}{})
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue