2017-01-11 08:12:37 +00:00
|
|
|
package web
|
|
|
|
|
|
|
|
import (
|
|
|
|
"encoding/json"
|
|
|
|
"net/http"
|
|
|
|
"sort"
|
|
|
|
"strings"
|
|
|
|
|
|
|
|
"github.com/coreos/etcd/clientv3"
|
|
|
|
"github.com/gorilla/mux"
|
|
|
|
|
2017-02-14 10:42:41 +00:00
|
|
|
"sunteng/commons/log"
|
2017-01-11 08:12:37 +00:00
|
|
|
"sunteng/cronsun/conf"
|
|
|
|
"sunteng/cronsun/models"
|
2017-03-10 03:06:40 +00:00
|
|
|
"time"
|
2017-01-11 08:12:37 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
type Job struct{}
|
|
|
|
|
2017-01-16 06:30:55 +00:00
|
|
|
func (j *Job) GetJob(w http.ResponseWriter, r *http.Request) {
|
|
|
|
vars := mux.Vars(r)
|
|
|
|
job, err := models.GetJob(vars["group"], vars["id"])
|
|
|
|
var statusCode int
|
|
|
|
if err != nil {
|
|
|
|
if err == models.ErrNotFound {
|
|
|
|
statusCode = http.StatusNotFound
|
|
|
|
} else {
|
|
|
|
statusCode = http.StatusInternalServerError
|
|
|
|
}
|
2017-03-09 03:39:06 +00:00
|
|
|
outJSONWithCode(w, statusCode, err.Error())
|
2017-01-16 06:30:55 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
outJSON(w, job)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (j *Job) DeleteJob(w http.ResponseWriter, r *http.Request) {
|
|
|
|
vars := mux.Vars(r)
|
|
|
|
_, err := models.DeleteJob(vars["group"], vars["id"])
|
|
|
|
if err != nil {
|
2017-03-09 03:39:06 +00:00
|
|
|
outJSONWithCode(w, http.StatusInternalServerError, err.Error())
|
2017-01-16 06:30:55 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
outJSONWithCode(w, http.StatusNoContent, nil)
|
|
|
|
}
|
|
|
|
|
2017-01-22 07:18:08 +00:00
|
|
|
func (j *Job) ChangeJobStatus(w http.ResponseWriter, r *http.Request) {
|
|
|
|
job := &models.Job{}
|
|
|
|
decoder := json.NewDecoder(r.Body)
|
|
|
|
err := decoder.Decode(&job)
|
|
|
|
if err != nil {
|
2017-03-09 03:39:06 +00:00
|
|
|
outJSONWithCode(w, http.StatusBadRequest, err.Error())
|
2017-01-22 07:18:08 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
r.Body.Close()
|
|
|
|
|
|
|
|
vars := mux.Vars(r)
|
|
|
|
originJob, rev, err := models.GetJobAndRev(vars["group"], vars["id"])
|
|
|
|
if err != nil {
|
2017-03-09 03:39:06 +00:00
|
|
|
outJSONWithCode(w, http.StatusInternalServerError, err.Error())
|
2017-01-22 07:18:08 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
originJob.Pause = job.Pause
|
|
|
|
b, err := json.Marshal(originJob)
|
|
|
|
if err != nil {
|
2017-03-09 03:39:06 +00:00
|
|
|
outJSONWithCode(w, http.StatusInternalServerError, err.Error())
|
2017-01-22 07:18:08 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
_, err = models.DefalutClient.PutWithModRev(originJob.Key(), string(b), rev)
|
|
|
|
if err != nil {
|
2017-03-09 03:39:06 +00:00
|
|
|
outJSONWithCode(w, http.StatusInternalServerError, err.Error())
|
2017-01-22 07:18:08 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
outJSON(w, originJob)
|
|
|
|
}
|
|
|
|
|
2017-01-16 06:30:55 +00:00
|
|
|
func (j *Job) UpdateJob(w http.ResponseWriter, r *http.Request) {
|
2017-02-20 02:56:32 +00:00
|
|
|
var job = &struct {
|
|
|
|
*models.Job
|
|
|
|
OldGroup string `json:"oldGroup"`
|
|
|
|
}{}
|
|
|
|
|
2017-01-11 08:12:37 +00:00
|
|
|
decoder := json.NewDecoder(r.Body)
|
|
|
|
err := decoder.Decode(&job)
|
|
|
|
if err != nil {
|
2017-03-09 03:39:06 +00:00
|
|
|
outJSONWithCode(w, http.StatusBadRequest, err.Error())
|
2017-01-11 08:12:37 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
r.Body.Close()
|
|
|
|
|
2017-01-12 08:35:30 +00:00
|
|
|
if err = job.Check(); err != nil {
|
2017-03-09 03:39:06 +00:00
|
|
|
outJSONWithCode(w, http.StatusBadRequest, err.Error())
|
2017-01-12 08:35:30 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2017-02-20 02:56:32 +00:00
|
|
|
var deleteOldKey string
|
2017-01-12 08:35:30 +00:00
|
|
|
var successCode = http.StatusOK
|
2017-01-11 08:12:37 +00:00
|
|
|
if len(job.ID) == 0 {
|
2017-01-12 08:35:30 +00:00
|
|
|
successCode = http.StatusCreated
|
2017-01-11 08:12:37 +00:00
|
|
|
job.ID = models.NextID()
|
2017-02-20 02:56:32 +00:00
|
|
|
} else {
|
|
|
|
job.OldGroup = strings.TrimSpace(job.OldGroup)
|
|
|
|
if job.OldGroup != job.Group {
|
|
|
|
deleteOldKey = models.JobKey(job.OldGroup, job.ID)
|
|
|
|
}
|
2017-01-11 08:12:37 +00:00
|
|
|
}
|
|
|
|
|
2017-01-12 08:35:30 +00:00
|
|
|
b, err := json.Marshal(job)
|
2017-01-11 08:12:37 +00:00
|
|
|
if err != nil {
|
2017-03-09 03:39:06 +00:00
|
|
|
outJSONWithCode(w, http.StatusInternalServerError, err.Error())
|
2017-01-11 08:12:37 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2017-01-22 07:18:08 +00:00
|
|
|
_, err = models.DefalutClient.Put(job.Key(), string(b))
|
2017-01-11 08:12:37 +00:00
|
|
|
if err != nil {
|
2017-03-09 03:39:06 +00:00
|
|
|
outJSONWithCode(w, http.StatusInternalServerError, err.Error())
|
2017-01-11 08:12:37 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2017-02-20 02:56:32 +00:00
|
|
|
// remove old key
|
|
|
|
if len(deleteOldKey) > 0 {
|
|
|
|
if _, err = models.DefalutClient.Delete(deleteOldKey); err != nil {
|
|
|
|
log.Errorf("failed to remove old job key[%s], err: %s.", deleteOldKey, err.Error())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-01-12 08:35:30 +00:00
|
|
|
outJSONWithCode(w, successCode, nil)
|
2017-01-11 08:12:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (j *Job) GetGroups(w http.ResponseWriter, r *http.Request) {
|
|
|
|
resp, err := models.DefalutClient.Get(conf.Config.Cmd, clientv3.WithPrefix(), clientv3.WithKeysOnly())
|
|
|
|
if err != nil {
|
2017-03-09 03:39:06 +00:00
|
|
|
outJSONWithCode(w, http.StatusInternalServerError, err.Error())
|
2017-01-11 08:12:37 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2017-01-21 10:16:45 +00:00
|
|
|
var cmdKeyLen = len(conf.Config.Cmd)
|
2017-01-11 08:12:37 +00:00
|
|
|
var groupMap = make(map[string]bool, 8)
|
2017-01-21 10:16:45 +00:00
|
|
|
|
2017-01-11 08:12:37 +00:00
|
|
|
for i := range resp.Kvs {
|
2017-01-21 10:16:45 +00:00
|
|
|
ss := strings.Split(string(resp.Kvs[i].Key)[cmdKeyLen:], "/")
|
|
|
|
groupMap[ss[0]] = true
|
2017-01-11 08:12:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
var groupList = make([]string, 0, len(groupMap))
|
|
|
|
for k := range groupMap {
|
|
|
|
groupList = append(groupList, k)
|
|
|
|
}
|
|
|
|
|
|
|
|
sort.Strings(groupList)
|
|
|
|
outJSON(w, groupList)
|
|
|
|
}
|
|
|
|
|
2017-02-16 03:57:58 +00:00
|
|
|
func (j *Job) GetList(w http.ResponseWriter, r *http.Request) {
|
|
|
|
group := strings.TrimSpace(r.FormValue("group"))
|
|
|
|
var prefix = conf.Config.Cmd
|
|
|
|
if len(group) != 0 {
|
|
|
|
prefix += group
|
|
|
|
}
|
|
|
|
|
2017-02-14 10:42:41 +00:00
|
|
|
type jobStatus struct {
|
|
|
|
*models.Job
|
|
|
|
LatestStatus *models.JobLatestLog `json:"latestStatus"`
|
|
|
|
}
|
|
|
|
|
2017-02-16 03:57:58 +00:00
|
|
|
resp, err := models.DefalutClient.Get(prefix, clientv3.WithPrefix(), clientv3.WithSort(clientv3.SortByKey, clientv3.SortAscend))
|
2017-01-11 08:12:37 +00:00
|
|
|
if err != nil {
|
2017-03-09 03:39:06 +00:00
|
|
|
outJSONWithCode(w, http.StatusInternalServerError, err.Error())
|
2017-01-11 08:12:37 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2017-02-14 10:42:41 +00:00
|
|
|
var jobIds []string
|
|
|
|
var jobList = make([]*jobStatus, 0, resp.Count)
|
2017-01-11 08:12:37 +00:00
|
|
|
for i := range resp.Kvs {
|
2017-01-22 07:18:08 +00:00
|
|
|
job := models.Job{}
|
2017-01-11 08:12:37 +00:00
|
|
|
err = json.Unmarshal(resp.Kvs[i].Value, &job)
|
|
|
|
if err != nil {
|
2017-03-09 03:39:06 +00:00
|
|
|
outJSONWithCode(w, http.StatusInternalServerError, err.Error())
|
2017-01-11 08:12:37 +00:00
|
|
|
return
|
|
|
|
}
|
2017-02-14 10:42:41 +00:00
|
|
|
jobList = append(jobList, &jobStatus{Job: &job})
|
|
|
|
jobIds = append(jobIds, job.ID)
|
|
|
|
}
|
|
|
|
|
|
|
|
m, err := models.GetJobLatestLogListByJobIds(jobIds)
|
|
|
|
if err != nil {
|
|
|
|
log.Error("GetJobLatestLogListByJobIds error:", err.Error())
|
|
|
|
} else {
|
|
|
|
for i := range jobList {
|
|
|
|
jobList[i].LatestStatus = m[jobList[i].ID]
|
|
|
|
}
|
2017-01-11 08:12:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
outJSON(w, jobList)
|
|
|
|
}
|
2017-03-10 03:06:40 +00:00
|
|
|
|
|
|
|
func (j *Job) GetExecutingJob(w http.ResponseWriter, r *http.Request) {
|
|
|
|
opt := &ProcFetchOptions{
|
|
|
|
Groups: GetStringArrayFromQuery("groups", ",", r),
|
|
|
|
NodeIds: GetStringArrayFromQuery("nodes", ",", r),
|
|
|
|
JobIds: GetStringArrayFromQuery("jobs", ",", r),
|
|
|
|
}
|
|
|
|
|
|
|
|
gresp, err := models.DefalutClient.Get(conf.Config.Proc, clientv3.WithPrefix())
|
|
|
|
if err != nil {
|
|
|
|
outJSONWithCode(w, http.StatusInternalServerError, err.Error())
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
var list = make([]*models.Process, 0, 8)
|
|
|
|
for i := range gresp.Kvs {
|
|
|
|
proc, err := models.GetProcFromKey(string(gresp.Kvs[i].Key))
|
|
|
|
if err != nil {
|
|
|
|
log.Error("Failed to unmarshal Proc from key: ", err.Error())
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
if !opt.Match(proc) {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
proc.Time, _ = time.Parse(time.RFC3339, string(gresp.Kvs[i].Value))
|
|
|
|
list = append(list, proc)
|
|
|
|
}
|
|
|
|
|
|
|
|
sort.Sort(ByProcTime(list))
|
|
|
|
outJSON(w, list)
|
|
|
|
}
|
|
|
|
|
|
|
|
type ProcFetchOptions struct {
|
|
|
|
Groups []string
|
|
|
|
NodeIds []string
|
|
|
|
JobIds []string
|
|
|
|
}
|
|
|
|
|
|
|
|
func (opt *ProcFetchOptions) Match(proc *models.Process) bool {
|
|
|
|
if len(opt.Groups) > 0 && !InStringArray(proc.Group, opt.Groups) {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(opt.JobIds) > 0 && !InStringArray(proc.JobID, opt.JobIds) {
|
|
|
|
return false
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(opt.NodeIds) > 0 && !InStringArray(proc.NodeID, opt.NodeIds) {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
|
|
|
type ByProcTime []*models.Process
|
|
|
|
|
|
|
|
func (a ByProcTime) Len() int { return len(a) }
|
|
|
|
func (a ByProcTime) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
|
|
|
|
func (a ByProcTime) Less(i, j int) bool { return a[i].Time.After(a[j].Time) }
|