mirror of https://github.com/ouqiang/gocron
主机、任务日志列表增加搜索功能
parent
9339137bca
commit
09c6927884
|
@ -1,6 +1,9 @@
|
||||||
package models
|
package models
|
||||||
|
|
||||||
import "github.com/ouqiang/gocron/modules/ssh"
|
import (
|
||||||
|
"github.com/ouqiang/gocron/modules/ssh"
|
||||||
|
"github.com/go-xorm/xorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -60,10 +63,12 @@ func (host *Host) NameExists(name string, id int16) (bool, error) {
|
||||||
return count > 0, err
|
return count > 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (host *Host) List() ([]Host, error) {
|
func (host *Host) List(params CommonMap) ([]Host, error) {
|
||||||
host.parsePageAndPageSize()
|
host.parsePageAndPageSize()
|
||||||
list := make([]Host, 0)
|
list := make([]Host, 0)
|
||||||
err := Db.Desc("id").Limit(host.PageSize, host.pageLimitOffset()).Find(&list)
|
session := Db.Desc("id")
|
||||||
|
host.parseWhere(session, params)
|
||||||
|
err := session.Limit(host.PageSize, host.pageLimitOffset()).Find(&list)
|
||||||
|
|
||||||
return list, err
|
return list, err
|
||||||
}
|
}
|
||||||
|
@ -80,6 +85,21 @@ func (host *Host) Total() (int64, error) {
|
||||||
return Db.Count(host)
|
return Db.Count(host)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 解析where
|
||||||
|
func (host *Host) parseWhere(session *xorm.Session, params CommonMap) {
|
||||||
|
if len(params) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
id, ok := params["Id"]
|
||||||
|
if ok && id.(int) > 0 {
|
||||||
|
session.And("id = ?", id)
|
||||||
|
}
|
||||||
|
name, ok := params["Name"]
|
||||||
|
if ok && name.(string) != "" {
|
||||||
|
session.And("name = ?", name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (host *Host) parsePageAndPageSize() {
|
func (host *Host) parsePageAndPageSize() {
|
||||||
if host.Page <= 0 {
|
if host.Page <= 0 {
|
||||||
host.Page = Page
|
host.Page = Page
|
||||||
|
|
|
@ -130,7 +130,7 @@ func (task *Task) List(params CommonMap) ([]TaskHost, error) {
|
||||||
list := make([]TaskHost, 0)
|
list := make([]TaskHost, 0)
|
||||||
fields := "t.*, host.alias"
|
fields := "t.*, host.alias"
|
||||||
session := Db.Alias("t").Join("LEFT", "host", "t.host_id=host.id")
|
session := Db.Alias("t").Join("LEFT", "host", "t.host_id=host.id")
|
||||||
parseWhere(session, params)
|
task.parseWhere(session, params)
|
||||||
err := session.Cols(fields).Desc("t.id").Limit(task.PageSize, task.pageLimitOffset()).Find(&list)
|
err := session.Cols(fields).Desc("t.id").Limit(task.PageSize, task.pageLimitOffset()).Find(&list)
|
||||||
|
|
||||||
return list, err
|
return list, err
|
||||||
|
@ -141,17 +141,21 @@ func (task *Task) Total() (int64, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// 解析where
|
// 解析where
|
||||||
func parseWhere(session *xorm.Session, params CommonMap) {
|
func (task *Task) parseWhere(session *xorm.Session, params CommonMap) {
|
||||||
if len(params) == 0 {
|
if len(params) == 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
id, ok := params["Id"]
|
||||||
|
if ok && id.(int) > 0 {
|
||||||
|
session.And("t.id = ?", id)
|
||||||
|
}
|
||||||
hostId, ok := params["HostId"]
|
hostId, ok := params["HostId"]
|
||||||
if ok && hostId.(int) > 0 {
|
if ok && hostId.(int) > 0 {
|
||||||
session.And("host_id = ?", hostId)
|
session.And("host_id = ?", hostId)
|
||||||
}
|
}
|
||||||
name, ok := params["Name"]
|
name, ok := params["Name"]
|
||||||
if ok && name.(string) != "" {
|
if ok && name.(string) != "" {
|
||||||
session.And("name = ?", name)
|
session.And("t.name LIKE ?", "%" + name.(string) + "%")
|
||||||
}
|
}
|
||||||
protocol, ok := params["Protocol"]
|
protocol, ok := params["Protocol"]
|
||||||
if ok && protocol.(int) > 0 {
|
if ok && protocol.(int) > 0 {
|
||||||
|
|
|
@ -2,6 +2,7 @@ package models
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"time"
|
"time"
|
||||||
|
"github.com/go-xorm/xorm"
|
||||||
)
|
)
|
||||||
|
|
||||||
type TaskType int8
|
type TaskType int8
|
||||||
|
@ -20,7 +21,7 @@ type TaskLog struct {
|
||||||
Hostname string `xorm:"varchar(512) notnull defalut '' "` // SSH主机名,逗号分隔
|
Hostname string `xorm:"varchar(512) notnull defalut '' "` // SSH主机名,逗号分隔
|
||||||
StartTime time.Time `xorm:"datetime created"` // 开始执行时间
|
StartTime time.Time `xorm:"datetime created"` // 开始执行时间
|
||||||
EndTime time.Time `xorm:"datetime updated"` // 执行完成(失败)时间
|
EndTime time.Time `xorm:"datetime updated"` // 执行完成(失败)时间
|
||||||
Status Status `xorm:"tinyint notnull default 1"` // 状态 1:执行中 2:执行完毕 0:执行失败
|
Status Status `xorm:"tinyint notnull default 1"` // 状态 0:执行失败 1:执行中 2:执行完毕
|
||||||
Result string `xorm:"varchar(65535) notnull defalut '' "` // 执行结果
|
Result string `xorm:"varchar(65535) notnull defalut '' "` // 执行结果
|
||||||
Page int `xorm:"-"`
|
Page int `xorm:"-"`
|
||||||
PageSize int `xorm:"-"`
|
PageSize int `xorm:"-"`
|
||||||
|
@ -47,10 +48,12 @@ func (taskLog *TaskLog) setStatus(id int64, status Status) (int64, error) {
|
||||||
return taskLog.Update(id, CommonMap{"status": status})
|
return taskLog.Update(id, CommonMap{"status": status})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (taskLog *TaskLog) List() ([]TaskLog, error) {
|
func (taskLog *TaskLog) List(params CommonMap) ([]TaskLog, error) {
|
||||||
taskLog.parsePageAndPageSize()
|
taskLog.parsePageAndPageSize()
|
||||||
list := make([]TaskLog, 0)
|
list := make([]TaskLog, 0)
|
||||||
err := Db.Desc("id").Limit(taskLog.PageSize, taskLog.pageLimitOffset()).Find(&list)
|
session := Db.Desc("id")
|
||||||
|
taskLog.parseWhere(session, params)
|
||||||
|
err := session.Limit(taskLog.PageSize, taskLog.pageLimitOffset()).Find(&list)
|
||||||
if len(list) > 0 {
|
if len(list) > 0 {
|
||||||
for i, item := range list {
|
for i, item := range list {
|
||||||
endTime := item.EndTime
|
endTime := item.EndTime
|
||||||
|
@ -86,3 +89,22 @@ func (taskLog *TaskLog) parsePageAndPageSize() {
|
||||||
func (taskLog *TaskLog) pageLimitOffset() int {
|
func (taskLog *TaskLog) pageLimitOffset() int {
|
||||||
return (taskLog.Page - 1) * taskLog.PageSize
|
return (taskLog.Page - 1) * taskLog.PageSize
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 解析where
|
||||||
|
func (taskLog *TaskLog) parseWhere(session *xorm.Session, params CommonMap) {
|
||||||
|
if len(params) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
taskId, ok := params["TaskId"]
|
||||||
|
if ok && taskId.(int) > 0 {
|
||||||
|
session.And("task_id = ?", taskId)
|
||||||
|
}
|
||||||
|
protocol, ok := params["Protocol"]
|
||||||
|
if ok && protocol.(int) > 0 {
|
||||||
|
session.And("protocol = ?", protocol)
|
||||||
|
}
|
||||||
|
status, ok := params["Status"]
|
||||||
|
if ok && status.(int) > -1 {
|
||||||
|
session.And("status = ?", status)
|
||||||
|
}
|
||||||
|
}
|
|
@ -24,8 +24,6 @@ function Util() {
|
||||||
swal(FAILURE_MESSAGE, '未知错误', 'error');
|
swal(FAILURE_MESSAGE, '未知错误', 'error');
|
||||||
};
|
};
|
||||||
util.get = function(url, callback) {
|
util.get = function(url, callback) {
|
||||||
var SUCCESS = 0; // 操作成功
|
|
||||||
var FAILURE_MESSAGE = '操作失败';
|
|
||||||
$.get(
|
$.get(
|
||||||
url,
|
url,
|
||||||
function(response) {
|
function(response) {
|
||||||
|
@ -76,4 +74,25 @@ function Util() {
|
||||||
return util;
|
return util;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function registerSelectFormValidation(type, $form, $select, selectName) {
|
||||||
|
$.fn.form.settings.rules[type] = function(value) {
|
||||||
|
var success = true;
|
||||||
|
var selectedIndex = $($form).form("get value", selectName);
|
||||||
|
$($select).find("option").each(function() {
|
||||||
|
var value = $(this).val();
|
||||||
|
var match = $(this).data("match");
|
||||||
|
var validateType = $(this).data("validate-type");
|
||||||
|
if (selectedIndex == value && validateType == type && match) {
|
||||||
|
var matchValue = $($form).form("get value", match);
|
||||||
|
if (!$.trim(matchValue)) {
|
||||||
|
success = false;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return success;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
var util = new Util();
|
var util = new Util();
|
|
@ -12,12 +12,14 @@ import (
|
||||||
|
|
||||||
func Index(ctx *macaron.Context) {
|
func Index(ctx *macaron.Context) {
|
||||||
hostModel := new(models.Host)
|
hostModel := new(models.Host)
|
||||||
hosts, err := hostModel.List()
|
queryParams := parseQueryParams(ctx)
|
||||||
|
hosts, err := hostModel.List(queryParams)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error(err)
|
logger.Error(err)
|
||||||
}
|
}
|
||||||
ctx.Data["Title"] = "主机列表"
|
ctx.Data["Title"] = "主机列表"
|
||||||
ctx.Data["Hosts"] = hosts
|
ctx.Data["Hosts"] = hosts
|
||||||
|
ctx.Data["Params"] = queryParams
|
||||||
ctx.HTML(200, "host/index")
|
ctx.HTML(200, "host/index")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -143,3 +145,14 @@ func Remove(ctx *macaron.Context) string {
|
||||||
|
|
||||||
return json.Success("操作成功", nil)
|
return json.Success("操作成功", nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 解析查询参数
|
||||||
|
func parseQueryParams(ctx *macaron.Context) (models.CommonMap) {
|
||||||
|
var params models.CommonMap = models.CommonMap{}
|
||||||
|
params["Id"] = ctx.QueryInt("id")
|
||||||
|
params["Name"] = ctx.QueryTrim("name")
|
||||||
|
params["Page"] = ctx.QueryInt("page")
|
||||||
|
params["PageSize"] = ctx.QueryInt("page_size")
|
||||||
|
|
||||||
|
return params
|
||||||
|
}
|
|
@ -11,7 +11,6 @@ import (
|
||||||
"github.com/go-macaron/session"
|
"github.com/go-macaron/session"
|
||||||
"github.com/go-macaron/csrf"
|
"github.com/go-macaron/csrf"
|
||||||
"github.com/go-macaron/toolbox"
|
"github.com/go-macaron/toolbox"
|
||||||
"github.com/go-macaron/gzip"
|
|
||||||
"strings"
|
"strings"
|
||||||
"github.com/ouqiang/gocron/modules/app"
|
"github.com/ouqiang/gocron/modules/app"
|
||||||
)
|
)
|
||||||
|
@ -35,6 +34,7 @@ func Register(m *macaron.Macaron) {
|
||||||
})
|
})
|
||||||
// 50x错误
|
// 50x错误
|
||||||
m.InternalServerError(func(ctx *macaron.Context) {
|
m.InternalServerError(func(ctx *macaron.Context) {
|
||||||
|
logger.Debug("500错误")
|
||||||
if isGetRequest(ctx) && !isAjaxRequest(ctx) {
|
if isGetRequest(ctx) && !isAjaxRequest(ctx) {
|
||||||
ctx.Data["Title"] = "500 - INTERNAL SERVER ERROR"
|
ctx.Data["Title"] = "500 - INTERNAL SERVER ERROR"
|
||||||
ctx.HTML(500, "error/500")
|
ctx.HTML(500, "error/500")
|
||||||
|
@ -85,7 +85,6 @@ func Register(m *macaron.Macaron) {
|
||||||
func RegisterMiddleware(m *macaron.Macaron) {
|
func RegisterMiddleware(m *macaron.Macaron) {
|
||||||
m.Use(macaron.Logger())
|
m.Use(macaron.Logger())
|
||||||
m.Use(macaron.Recovery())
|
m.Use(macaron.Recovery())
|
||||||
m.Use(gzip.Gziper())
|
|
||||||
m.Use(macaron.Static(StaticDir))
|
m.Use(macaron.Static(StaticDir))
|
||||||
m.Use(macaron.Renderer(macaron.RenderOptions{
|
m.Use(macaron.Renderer(macaron.RenderOptions{
|
||||||
Directory: "templates",
|
Directory: "templates",
|
||||||
|
@ -106,7 +105,7 @@ func RegisterMiddleware(m *macaron.Macaron) {
|
||||||
// 系统未安装,重定向到安装页面
|
// 系统未安装,重定向到安装页面
|
||||||
m.Use(func(ctx *macaron.Context) {
|
m.Use(func(ctx *macaron.Context) {
|
||||||
installUrl := "/install"
|
installUrl := "/install"
|
||||||
if strings.HasPrefix(ctx.Req.RequestURI, installUrl) {
|
if strings.HasPrefix(ctx.Req.URL.Path, installUrl) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if !app.Installed {
|
if !app.Installed {
|
||||||
|
@ -116,6 +115,16 @@ func RegisterMiddleware(m *macaron.Macaron) {
|
||||||
// 设置模板共享变量
|
// 设置模板共享变量
|
||||||
m.Use(func(ctx *macaron.Context) {
|
m.Use(func(ctx *macaron.Context) {
|
||||||
ctx.Data["URI"] = ctx.Req.URL.Path
|
ctx.Data["URI"] = ctx.Req.URL.Path
|
||||||
|
urlPath := strings.TrimPrefix(ctx.Req.URL.Path, "/")
|
||||||
|
paths := strings.Split(urlPath, "/")
|
||||||
|
ctx.Data["Controller"] = ""
|
||||||
|
ctx.Data["Action"] = ""
|
||||||
|
if len(paths) > 0 {
|
||||||
|
ctx.Data["Controller"] = paths[0]
|
||||||
|
}
|
||||||
|
if len(paths) > 1 {
|
||||||
|
ctx.Data["Action"] = paths[1]
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -46,7 +46,7 @@ func Create(ctx *macaron.Context) {
|
||||||
func Edit(ctx *macaron.Context) {
|
func Edit(ctx *macaron.Context) {
|
||||||
id := ctx.ParamsInt(":id")
|
id := ctx.ParamsInt(":id")
|
||||||
hostModel := new(models.Host)
|
hostModel := new(models.Host)
|
||||||
hosts, err := hostModel.List()
|
hosts, err := hostModel.List(models.CommonMap{})
|
||||||
if err != nil || len(hosts) == 0 {
|
if err != nil || len(hosts) == 0 {
|
||||||
logger.Error(err)
|
logger.Error(err)
|
||||||
}
|
}
|
||||||
|
@ -87,11 +87,16 @@ func Store(ctx *macaron.Context, form TaskForm) string {
|
||||||
return json.CommonFailure("请选择主机名")
|
return json.CommonFailure("请选择主机名")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if form.Protocol != models.TaskHTTP {
|
||||||
|
taskModel.HostId = form.HostId
|
||||||
|
} else {
|
||||||
|
taskModel.HostId = 0
|
||||||
|
}
|
||||||
|
|
||||||
taskModel.Name = form.Name
|
taskModel.Name = form.Name
|
||||||
taskModel.Protocol = form.Protocol
|
taskModel.Protocol = form.Protocol
|
||||||
taskModel.Command = form.Command
|
taskModel.Command = form.Command
|
||||||
taskModel.Timeout = form.Timeout
|
taskModel.Timeout = form.Timeout
|
||||||
taskModel.HostId = form.HostId
|
|
||||||
taskModel.Remark = form.Remark
|
taskModel.Remark = form.Remark
|
||||||
taskModel.Status = form.Status
|
taskModel.Status = form.Status
|
||||||
taskModel.RetryTimes = form.RetryTimes
|
taskModel.RetryTimes = form.RetryTimes
|
||||||
|
@ -195,21 +200,20 @@ func addTaskToTimer(id int) {
|
||||||
// 解析查询参数
|
// 解析查询参数
|
||||||
func parseQueryParams(ctx *macaron.Context) (models.CommonMap) {
|
func parseQueryParams(ctx *macaron.Context) (models.CommonMap) {
|
||||||
var params models.CommonMap = models.CommonMap{}
|
var params models.CommonMap = models.CommonMap{}
|
||||||
|
params["Id"] = ctx.QueryInt("id")
|
||||||
params["HostId"] = ctx.QueryInt("host_id")
|
params["HostId"] = ctx.QueryInt("host_id")
|
||||||
params["Name"] = ctx.QueryTrim("name")
|
params["Name"] = ctx.QueryTrim("name")
|
||||||
params["Protocol"] = ctx.QueryInt("protocol")
|
params["Protocol"] = ctx.QueryInt("protocol")
|
||||||
params["Status"] = ctx.QueryInt("status")
|
params["Status"] = ctx.QueryInt("status") - 1
|
||||||
params["Page"] = ctx.QueryInt("page")
|
params["Page"] = ctx.QueryInt("page")
|
||||||
params["PageSize"] = ctx.QueryInt("page_size")
|
params["PageSize"] = ctx.QueryInt("page_size")
|
||||||
|
|
||||||
logger.Debug("%+v", params)
|
|
||||||
|
|
||||||
return params
|
return params
|
||||||
}
|
}
|
||||||
|
|
||||||
func setHostsToTemplate(ctx *macaron.Context) {
|
func setHostsToTemplate(ctx *macaron.Context) {
|
||||||
hostModel := new(models.Host)
|
hostModel := new(models.Host)
|
||||||
hosts, err := hostModel.List()
|
hosts, err := hostModel.List(models.CommonMap{})
|
||||||
if err != nil || len(hosts) == 0 {
|
if err != nil || len(hosts) == 0 {
|
||||||
logger.Error(err)
|
logger.Error(err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,12 +12,14 @@ import (
|
||||||
|
|
||||||
func Index(ctx *macaron.Context) {
|
func Index(ctx *macaron.Context) {
|
||||||
logModel := new(models.TaskLog)
|
logModel := new(models.TaskLog)
|
||||||
logs, err := logModel.List()
|
queryParams := parseQueryParams(ctx)
|
||||||
|
logs, err := logModel.List(queryParams)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error(err)
|
logger.Error(err)
|
||||||
}
|
}
|
||||||
ctx.Data["Title"] = "任务日志"
|
ctx.Data["Title"] = "任务日志"
|
||||||
ctx.Data["Logs"] = logs
|
ctx.Data["Logs"] = logs
|
||||||
|
ctx.Data["Params"] = queryParams
|
||||||
ctx.HTML(200, "task/log")
|
ctx.HTML(200, "task/log")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -32,3 +34,15 @@ func Clear(ctx *macaron.Context) string {
|
||||||
|
|
||||||
return json.Success(utils.SuccessContent, nil)
|
return json.Success(utils.SuccessContent, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 解析查询参数
|
||||||
|
func parseQueryParams(ctx *macaron.Context) (models.CommonMap) {
|
||||||
|
var params models.CommonMap = models.CommonMap{}
|
||||||
|
params["TaskId"] = ctx.QueryInt("task_id")
|
||||||
|
params["Protocol"] = ctx.QueryInt("protocol")
|
||||||
|
params["Status"] = ctx.QueryInt("status") - 1
|
||||||
|
params["Page"] = ctx.QueryInt("page")
|
||||||
|
params["PageSize"] = ctx.QueryInt("page_size")
|
||||||
|
|
||||||
|
return params
|
||||||
|
}
|
|
@ -57,6 +57,7 @@ func (task *Task) Add(taskModel models.TaskHost) {
|
||||||
}
|
}
|
||||||
|
|
||||||
cronName := strconv.Itoa(taskModel.Id)
|
cronName := strconv.Itoa(taskModel.Id)
|
||||||
|
// Cron任务采用数组存储, 删除任务需遍历数组, 并对数组重新赋值, 任务较多时,有性能问题
|
||||||
Cron.RemoveJob(cronName)
|
Cron.RemoveJob(cronName)
|
||||||
err := Cron.AddFunc(taskModel.Spec, taskFunc, cronName)
|
err := Cron.AddFunc(taskModel.Spec, taskFunc, cronName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -123,20 +124,17 @@ func (h *HTTPHandler) Run(taskModel models.TaskHost) (result string, err error)
|
||||||
req.Header.Set("User-Agent", "golang/gocron")
|
req.Header.Set("User-Agent", "golang/gocron")
|
||||||
|
|
||||||
resp, err := client.Do(req)
|
resp, err := client.Do(req)
|
||||||
defer func() {
|
|
||||||
if resp != nil {
|
|
||||||
resp.Body.Close()
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error("任务处理HTTP请求错误-", err.Error())
|
logger.Error("任务处理HTTP请求错误-", err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
body, err := ioutil.ReadAll(resp.Body)
|
body, err := ioutil.ReadAll(resp.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error("任务处理#读取HTTP请求返回值失败-", err.Error())
|
logger.Error("任务处理#读取HTTP请求返回值失败-", err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
// 返回状态码非200,均为失败
|
||||||
if resp.StatusCode != 200 {
|
if resp.StatusCode != 200 {
|
||||||
return string(body), errors.New(fmt.Sprintf("HTTP状态码非200-->%d", resp.StatusCode))
|
return string(body), errors.New(fmt.Sprintf("HTTP状态码非200-->%d", resp.StatusCode))
|
||||||
}
|
}
|
||||||
|
@ -248,10 +246,10 @@ func execJob(handler Handler, taskModel models.TaskHost) TaskResult {
|
||||||
return TaskResult{Result: output, Err: err, RetryTimes: i}
|
return TaskResult{Result: output, Err: err, RetryTimes: i}
|
||||||
}
|
}
|
||||||
i++
|
i++
|
||||||
// 重试规则,每次递增1分钟
|
|
||||||
time.Sleep( time.Duration(i) * 60 * time.Second)
|
|
||||||
if i < execTimes {
|
if i < execTimes {
|
||||||
logger.Warnf("任务执行失败#任务id-%d#重试第%d次#输出-%s#错误-%s", taskModel.Id, i, output, err.Error())
|
logger.Warnf("任务执行失败#任务id-%d#重试第%d次#输出-%s#错误-%s", taskModel.Id, i, output, err.Error())
|
||||||
|
// 重试间隔时间,每次递增1分钟
|
||||||
|
time.Sleep( time.Duration(i) * time.Minute)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<div class="bigcontainer">
|
<div class="bigcontainer">
|
||||||
<div class="fl">
|
<div class="fl">
|
||||||
<p>© 2017 gocron
|
<p>© 2017 gocron
|
||||||
<i class="Github Alternate icon"></i><a href="https://github.com/ouqiang/cron-scheduler" target="_blank">
|
<i class="Github Alternate icon"></i><a href="https://github.com/ouqiang/gocron" target="_blank">
|
||||||
GitHub
|
GitHub
|
||||||
</a>
|
</a>
|
||||||
</p>
|
</p>
|
||||||
|
|
|
@ -18,6 +18,12 @@
|
||||||
body {
|
body {
|
||||||
overflow-x: hidden;
|
overflow-x: hidden;
|
||||||
}
|
}
|
||||||
|
select {
|
||||||
|
height: 40px;
|
||||||
|
}
|
||||||
|
.fields.search > .field {
|
||||||
|
margin-right: 5px;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
@ -53,11 +59,11 @@
|
||||||
<div class="ui teal inverted menu">
|
<div class="ui teal inverted menu">
|
||||||
<div class="bigcontainer">
|
<div class="bigcontainer">
|
||||||
<div class="right menu">
|
<div class="right menu">
|
||||||
<a class="item {{{if eq .URI "/"}}}active{{{end}}}" href="/"><i class="home icon"></i>首页</a>
|
<a class="item {{{if eq .Controller ""}}}active{{{end}}}" href="/"><i class="home icon"></i>首页</a>
|
||||||
<a class="item {{{if eq .URI "/task"}}}active{{{end}}}" href="/task"><i class="tasks icon"></i>任务</a>
|
<a class="item {{{if eq .Controller "task"}}}active{{{end}}}" href="/task"><i class="tasks icon"></i>任务</a>
|
||||||
<a class="item {{{if eq .URI "/host"}}}active{{{end}}}" href="/host"><i class="linux icon"></i>主机</a>
|
<a class="item {{{if eq .Controller "host"}}}active{{{end}}}" href="/host"><i class="linux icon"></i>主机</a>
|
||||||
<a class="item {{{if eq .URI "/user"}}}active{{{end}}}" href="/user"><i class="user icon"></i>账户</a>
|
<a class="item {{{if eq .Controller "user"}}}active{{{end}}}" href="/user"><i class="user icon"></i>账户</a>
|
||||||
<a class="item {{{if eq .URI "/admin"}}}active{{{end}}}" href="/admin"><i class="settings icon"></i>管理</a>
|
<a class="item {{{if eq .Controller "admin"}}}active{{{end}}}" href="/admin"><i class="settings icon"></i>管理</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
|
@ -1,7 +1,6 @@
|
||||||
{{{ template "common/header" . }}}
|
{{{ template "common/header" . }}}
|
||||||
|
|
||||||
<div class="ui grid">
|
<div class="ui grid">
|
||||||
<!--the vertical menu-->
|
|
||||||
{{{ template "host/menu" . }}}
|
{{{ template "host/menu" . }}}
|
||||||
|
|
||||||
<div class="twelve wide column">
|
<div class="twelve wide column">
|
||||||
|
@ -48,19 +47,10 @@
|
||||||
<div class="four fields">
|
<div class="four fields">
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<label>认证方式</label>
|
<label>认证方式</label>
|
||||||
<div class="ui dropdown selection">
|
<select name="auth_type" id="authType">
|
||||||
{{{ if .Host }}}
|
<option value="2" {{{if .Host}}} {{{if eq .Host.AuthType 2}}}selected {{{end}}} {{{end}}} data-validate-type="selectPrivateKey" data-match="private_key">公钥</option>
|
||||||
<input type="hidden" name="auth_type" value="{{{if eq .Host.AuthType 1 }}}1{{{else}}}2{{{end}}}">
|
<option value="1" {{{if .Host}}} {{{if eq .Host.AuthType 1}}}selected {{{end}}} {{{end}}} data-validate-type="selectPassword" data-match="password">密码</option>
|
||||||
{{{else}}}
|
</select>
|
||||||
<input type="hidden" name="auth_type" value="2">
|
|
||||||
{{{end}}}
|
|
||||||
<div class="default text">公钥</div>
|
|
||||||
<i class="dropdown icon"></i>
|
|
||||||
<div class="menu">
|
|
||||||
<div class="item" data-value="2">公钥</div>
|
|
||||||
<div class="item" data-value="1">密码</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="two fields">
|
<div class="two fields">
|
||||||
|
@ -91,12 +81,14 @@
|
||||||
<div class="ui primary submit button">保存</div>
|
<div class="ui primary submit button">保存</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
<!--the newDevice form-->
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
$('.ui.form').form(
|
var $uiForm = $('.ui.form');
|
||||||
|
registerSelectFormValidation("selectPrivateKey", $uiForm, $('#authType'), 'auth_type');
|
||||||
|
registerSelectFormValidation("selectPassword", $uiForm, $('#authType'), 'auth_type');
|
||||||
|
$($uiForm).form(
|
||||||
{
|
{
|
||||||
onSuccess: function(event, fields) {
|
onSuccess: function(event, fields) {
|
||||||
util.post('/host/store', fields, function(code, message) {
|
util.post('/host/store', fields, function(code, message) {
|
||||||
|
@ -137,8 +129,26 @@
|
||||||
identifier : 'port',
|
identifier : 'port',
|
||||||
rules: [
|
rules: [
|
||||||
{
|
{
|
||||||
type : 'integer',
|
type : 'integer[1..65535]',
|
||||||
prompt : '请输入SSH端口'
|
prompt : '请输入有效的端口号'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
PrivateKey: {
|
||||||
|
identifier : 'private_key',
|
||||||
|
rules: [
|
||||||
|
{
|
||||||
|
type : 'selectPrivateKey',
|
||||||
|
prompt : '请输入私钥'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
Password: {
|
||||||
|
identifier : 'password',
|
||||||
|
rules: [
|
||||||
|
{
|
||||||
|
type : 'selectPassword',
|
||||||
|
prompt : '请输入密码'
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,9 +14,23 @@
|
||||||
</h3>
|
</h3>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<form class="ui form">
|
||||||
|
<div class="three fields">
|
||||||
|
<div class="field">
|
||||||
|
<input type="text" placeholder="ID" name="id" value="{{{if gt .Params.Id 0}}}{{{.Params.Id}}}{{{end}}}">
|
||||||
|
</div>
|
||||||
|
<div class="field">
|
||||||
|
<input type="text" placeholder="主机名" name="name" value="{{{.Params.Name}}}">
|
||||||
|
</div>
|
||||||
|
<div class="field">
|
||||||
|
<button class="ui linkedin submit button">搜索</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
<table class="ui striped table">
|
<table class="ui striped table">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
|
<th>ID</th>
|
||||||
<th>主机名</th>
|
<th>主机名</th>
|
||||||
<th>别名</th>
|
<th>别名</th>
|
||||||
<th>用户名</th>
|
<th>用户名</th>
|
||||||
|
@ -28,6 +42,7 @@
|
||||||
<tbody>
|
<tbody>
|
||||||
{{{range $i, $v := .Hosts}}}
|
{{{range $i, $v := .Hosts}}}
|
||||||
<tr>
|
<tr>
|
||||||
|
<td>{{{.Id}}}</td>
|
||||||
<td>{{{.Name}}}</td>
|
<td>{{{.Name}}}</td>
|
||||||
<td>{{{.Alias}}}</td>
|
<td>{{{.Alias}}}</td>
|
||||||
<td>{{{.Username}}}</td>
|
<td>{{{.Username}}}</td>
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
{{{ template "common/header" . }}}
|
{{{ template "common/header" . }}}
|
||||||
|
|
||||||
<div class="ui grid">
|
<div class="ui grid">
|
||||||
{{{template "task/menu" .}}}
|
{{{template "task/menu" .}}}
|
||||||
<div class="twelve wide column">
|
<div class="twelve wide column">
|
||||||
|
@ -14,91 +13,61 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<form class="ui form">
|
<form class="ui form">
|
||||||
<div class="five fields">
|
<div class="six fields search">
|
||||||
<div class="field">
|
<div class="one wide field">
|
||||||
<input type="text" placeholder="任务名称" name="name">
|
<input type="text" placeholder="任务ID" name="id" value="{{{if gt .Params.Id 0}}}{{{.Params.Id}}}{{{end}}}">
|
||||||
</div>
|
</div>
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<label>主机</label>
|
<input type="text" placeholder="任务名称" name="name" value="{{{.Params.Name}}}">
|
||||||
<div class="ui dropdown selection">
|
|
||||||
<input type="hidden" name="protocol" value="{{{if gt .Params.Protocol 0}}}{{{.Params.Protocol}}}{{{else}}}3{{{end}}}">
|
|
||||||
<div class="default text">本地命令</div>
|
|
||||||
<i class="dropdown icon"></i>
|
|
||||||
<div class="menu">
|
|
||||||
<div class="item" data-value="3">本地命令</div>
|
|
||||||
<div class="item" data-value="2">SSH</div>
|
|
||||||
<div class="item" data-value="1">HTTP</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div class="field">
|
||||||
<div class="inline fields">
|
<select name="host_id" id="hostId">
|
||||||
|
<option value="">选择主机</option>
|
||||||
{{{range $i, $v := .Hosts}}}
|
{{{range $i, $v := .Hosts}}}
|
||||||
<div class="field">
|
<option value="{{{.Id}}}" {{{if eq $.Params.HostId .Id }}} selected {{{end}}} >{{{.Alias}}}-{{{.Name}}}</option>
|
||||||
<div class="ui radio checkbox">
|
|
||||||
<input type="radio" name="host_id" tabindex="0" class="hidden" value="{{{.Id}}}"
|
|
||||||
{{{if eq $.Params.HostId .Id }}} checked {{{end}}}>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{{{end}}}
|
{{{end}}}
|
||||||
</div>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<div class="ui dropdown selection">
|
<select name="protocol" id="protocol">
|
||||||
<input type="hidden" name="protocol" value="{{{if gt .Params.Protocol 0}}}{{{.Params.Protocol}}}{{{else}}}3{{{end}}}">
|
<option value="0">选择协议</option>
|
||||||
<div class="default text">本地命令</div>
|
<option value="3" {{{if eq .Params.Protocol 3}}}selected{{{end}}}>本地命令</option>
|
||||||
<i class="dropdown icon"></i>
|
<option value="2" {{{if eq .Params.Protocol 2}}}selected{{{end}}} data-match="host_id" data-validate-type="selectProtocol">SSH</option>
|
||||||
<div class="menu">
|
<option value="1" {{{if eq .Params.Protocol 1}}}selected{{{end}}}>HTTP</option>
|
||||||
<div class="item" data-value="-1">协议</div>
|
</select>
|
||||||
<div class="item" data-value="3">本地命令</div>
|
|
||||||
<div class="item" data-value="2">SSH</div>
|
|
||||||
<div class="item" data-value="1">HTTP</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<div class="ui dropdown selection">
|
<select name="status">
|
||||||
<input type="hidden" name="status" value="{{{if eq .Params.Status 1}}}1{{{else}}}2{{{end}}}">
|
<option value="0">状态</option>
|
||||||
<div class="default text">暂停</div>
|
<option value="1" {{{if eq .Params.Status 0}}}selected{{{end}}} >暂停</option>
|
||||||
<i class="dropdown icon"></i>
|
<option value="2" {{{if eq .Params.Status 1}}}selected{{{end}}}>激活</option>
|
||||||
<div class="menu">
|
</select>
|
||||||
<div class="item" data-value="-1">状态</div>
|
|
||||||
<div class="item" data-value="2">暂停</div>
|
|
||||||
<div class="item" data-value="1">激活</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<button class="ui linkedin submit button">搜索</button>
|
<button class="ui linkedin submit button">搜索</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
<table class="ui violet table">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>任务名称</th>
|
|
||||||
<th>cron表达式</th>
|
|
||||||
<th>协议</th>
|
|
||||||
<th width="5%">命令</th>
|
|
||||||
<th>超时时间(秒)</th>
|
|
||||||
<th>重试次数</th>
|
|
||||||
<th>主机</th>
|
|
||||||
<th>备注</th>
|
|
||||||
<th>状态</th>
|
|
||||||
<th>操作</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
{{{range $i, $v := .Tasks}}}
|
{{{range $i, $v := .Tasks}}}
|
||||||
<tr>
|
<div class="ui device two column middle aligned vertical grid list segment">
|
||||||
<td>{{{.Task.Name}}}</td>
|
<div class="column verborder">
|
||||||
<td>{{{.Spec}}}</td>
|
<div class="ui info segment">
|
||||||
<td>{{{if eq .Protocol 1}}} HTTP {{{else}}} SSH {{{end}}}</td>
|
<h5 class="ui header">{{{.Task.Name}}} {{{if eq .Status 1}}}<i class="large checkmark blue icon"></i> {{{else}}} <i class="large red minus icon"></i> {{{end}}}
|
||||||
<td>{{{.Command}}}</td>
|
</h5>
|
||||||
<td>{{{if gt .Timeout 0}}}{{{.Timeout}}}秒{{{else}}}不限制{{{end}}}</td>
|
<p>任务ID: <span class="stress">{{{.Id}}}</span></p>
|
||||||
<td>{{{.RetryTimes}}}</td>
|
<p>cron表达式: {{{.Spec}}}</p>
|
||||||
<td>{{{.Alias}}}</td>
|
<p>协议: {{{if eq .Protocol 1}}} HTTP {{{else if eq .Protocol 2}}} SSH {{{else if eq .Protocol 3}}}本地命令{{{end}}}</p>
|
||||||
<td>{{{.Remark}}}</td>
|
<p class="sensorStatus">命令:{{{.Command}}}</p>
|
||||||
<td>{{{if eq .Status 1}}}<i class="large checkmark blue icon"></i> {{{else}}} <i class="large red minus icon"></i> {{{end}}}</td>
|
<p class="sensorStatus">超时时间:{{{if gt .Timeout 0}}}{{{.Timeout}}}秒{{{else}}}不限制{{{end}}}</p>
|
||||||
<td>
|
<p>重试次数: {{{.RetryTimes}}}</p>
|
||||||
|
{{{if eq .Protocol 2}}}
|
||||||
|
<p>主机: {{{.Alias}}}</p>
|
||||||
|
{{{end}}}
|
||||||
|
<p>备注: {{{.Remark}}}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="center aligned column">
|
||||||
|
<div class="ui buttons">
|
||||||
<a class="ui purple button" href="/task/edit/{{{.Id}}}">编辑</a>
|
<a class="ui purple button" href="/task/edit/{{{.Id}}}">编辑</a>
|
||||||
{{{if eq .Status 1}}}
|
{{{if eq .Status 1}}}
|
||||||
<button class="ui primary button" @click="changeStatus({{{.Id}}},{{{.Status}}})">暂停</button>
|
<button class="ui primary button" @click="changeStatus({{{.Id}}},{{{.Status}}})">暂停</button>
|
||||||
|
@ -106,15 +75,12 @@
|
||||||
<button class="ui blue button" @click="changeStatus({{{.Id}}},{{{.Status}}})">激活 </button>
|
<button class="ui blue button" @click="changeStatus({{{.Id}}},{{{.Status}}})">激活 </button>
|
||||||
{{{end}}}
|
{{{end}}}
|
||||||
<button class="ui positive button" @click="remove({{{.Id}}})">删除</button> <br>
|
<button class="ui positive button" @click="remove({{{.Id}}})">删除</button> <br>
|
||||||
<div style="margin-top:10px;">
|
|
||||||
<button class="ui twitter button" @click="run({{{.Id}}})">手动运行</button>
|
<button class="ui twitter button" @click="run({{{.Id}}})">手动运行</button>
|
||||||
<a class="ui instagram button" href="/task/log?task_id={{{.Id}}}">查看日志</a>
|
<a class="ui instagram button" href="/task/log?task_id={{{.Id}}}">查看日志</a>
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</div>
|
||||||
</tr>
|
</div>
|
||||||
{{{end}}}
|
{{{end}}}
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -124,7 +90,7 @@
|
||||||
|
|
||||||
var vue = new Vue(
|
var vue = new Vue(
|
||||||
{
|
{
|
||||||
el: '.ui.violet.table',
|
el: '.ui.list',
|
||||||
methods: {
|
methods: {
|
||||||
changeStatus: function (id ,status) {
|
changeStatus: function (id ,status) {
|
||||||
var url = '';
|
var url = '';
|
||||||
|
|
|
@ -22,9 +22,36 @@
|
||||||
</h3>
|
</h3>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<form class="ui form">
|
||||||
|
<div class="six fields search">
|
||||||
|
<div class="field">
|
||||||
|
<input type="text" placeholder="任务ID" name="task_id" value="{{{if gt .Params.TaskId 0}}}{{{.Params.TaskId}}}{{{end}}}">
|
||||||
|
</div>
|
||||||
|
<div class="field">
|
||||||
|
<select name="protocol" id="protocol">
|
||||||
|
<option value="0">协议</option>
|
||||||
|
<option value="3" {{{if eq .Params.Protocol 3}}}selected{{{end}}}>本地命令</option>
|
||||||
|
<option value="2" {{{if eq .Params.Protocol 2}}}selected{{{end}}} data-match="host_id" data-validate-type="selectProtocol">SSH</option>
|
||||||
|
<option value="1" {{{if eq .Params.Protocol 1}}}selected{{{end}}}>HTTP</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="field">
|
||||||
|
<select name="status">
|
||||||
|
<option value="0">状态</option>
|
||||||
|
<option value="1" {{{if eq .Params.Status 0}}}selected{{{end}}} >失败</option>
|
||||||
|
<option value="2" {{{if eq .Params.Status 1}}}selected{{{end}}}>执行中</option>
|
||||||
|
<option value="3" {{{if eq .Params.Status 2}}}selected{{{end}}}>成功</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="field">
|
||||||
|
<button class="ui linkedin submit button">搜索</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
<table class="ui pink table">
|
<table class="ui pink table">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
|
<th>任务ID</th>
|
||||||
<th>任务名称</th>
|
<th>任务名称</th>
|
||||||
<th>cron表达式</th>
|
<th>cron表达式</th>
|
||||||
<th>协议</th>
|
<th>协议</th>
|
||||||
|
@ -39,6 +66,7 @@
|
||||||
<tbody>
|
<tbody>
|
||||||
{{{range $i, $v := .Logs}}}
|
{{{range $i, $v := .Logs}}}
|
||||||
<tr>
|
<tr>
|
||||||
|
<td><a href="/task?id={{{.TaskId}}}">{{{.TaskId}}}</a></td>
|
||||||
<td>{{{.Name}}}</td>
|
<td>{{{.Name}}}</td>
|
||||||
<td>{{{.Spec}}}</td>
|
<td>{{{.Spec}}}</td>
|
||||||
<td>{{{if eq .Protocol 1}}} HTTP {{{else if eq .Protocol 2}}} SSH {{{else}}} 本地命令 {{{end}}}</td>
|
<td>{{{if eq .Protocol 1}}} HTTP {{{else if eq .Protocol 2}}} SSH {{{else}}} 本地命令 {{{end}}}</td>
|
||||||
|
@ -128,55 +156,5 @@
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
$('.ui.form').form(
|
|
||||||
{
|
|
||||||
onSuccess: function(event, fields) {
|
|
||||||
util.post('/host/store', fields, function(code, message) {
|
|
||||||
location.reload();
|
|
||||||
});
|
|
||||||
|
|
||||||
return false;
|
|
||||||
},
|
|
||||||
fields: {
|
|
||||||
name: {
|
|
||||||
identifier : 'name',
|
|
||||||
rules: [
|
|
||||||
{
|
|
||||||
type : 'empty',
|
|
||||||
prompt : '请输入主机名'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
alias: {
|
|
||||||
identifier : 'alias',
|
|
||||||
rules: [
|
|
||||||
{
|
|
||||||
type : 'empty',
|
|
||||||
prompt : '请输入主机别名'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
username: {
|
|
||||||
identifier : 'username',
|
|
||||||
rules: [
|
|
||||||
{
|
|
||||||
type : 'empty',
|
|
||||||
prompt : '请输入SSH用户名'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
port: {
|
|
||||||
identifier : 'port',
|
|
||||||
rules: [
|
|
||||||
{
|
|
||||||
type : 'integer',
|
|
||||||
prompt : '请输入SSH端口'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
inline : true
|
|
||||||
});
|
|
||||||
</script>
|
</script>
|
||||||
{{{ template "common/footer" . }}}
|
{{{ template "common/footer" . }}}
|
|
@ -1,5 +1,4 @@
|
||||||
{{{ template "common/header" . }}}
|
{{{ template "common/header" . }}}
|
||||||
|
|
||||||
<div class="ui grid">
|
<div class="ui grid">
|
||||||
{{{template "task/menu" .}}}
|
{{{template "task/menu" .}}}
|
||||||
<div class="twelve wide column">
|
<div class="twelve wide column">
|
||||||
|
@ -25,47 +24,31 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="two fields">
|
<div class="two fields">
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<label>crontab表达式 (每行一个表达式)</label>
|
<label>crontab表达式</label>
|
||||||
|
<div class="ui small left icon input">
|
||||||
<textarea rows="5" name="spec">{{{.Task.Spec}}}</textarea>
|
<textarea rows="5" name="spec">{{{.Task.Spec}}}</textarea>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
<div class="three fields">
|
<div class="three fields">
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<label>协议</label>
|
<label>协议</label>
|
||||||
<div class="ui dropdown selection">
|
<select name="protocol" id="protocol">
|
||||||
{{{if .Task}}}
|
<option value="3" {{{if .Task}}} {{{if eq .Task.Protocol 3}}}selected{{{end}}} {{{end}}}>本地命令</option>
|
||||||
<input type="hidden" name="protocol" value="{{{if (gt .Task.Protocol 0)}}}{{{.Task.Protocol}}}{{{else}}}3{{{end}}}">
|
<option value="2" {{{if .Task}}} {{{if eq .Task.Protocol 2}}}selected{{{end}}} {{{end}}} data-match="host_id" data-validate-type="selectProtocol">SSH</option>
|
||||||
{{{else}}}
|
<option value="1" {{{if .Task}}} {{{if eq .Task.Protocol 1}}}selected{{{end}}} {{{end}}}>HTTP</option>
|
||||||
<input type="hidden" name="protocol" value="3">
|
</select>
|
||||||
{{{end}}}
|
|
||||||
<div class="default text">本地命令</div>
|
|
||||||
<i class="dropdown icon"></i>
|
|
||||||
<div class="menu">
|
|
||||||
<div class="item" data-value="3">本地命令</div>
|
|
||||||
<div class="item" data-value="2">SSH</div>
|
|
||||||
<div class="item" data-value="1">HTTP</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<label>主机</label>
|
<label>主机</label>
|
||||||
<div class="inline fields">
|
<select name="host_id" id="hostId">
|
||||||
|
<option value="">选择主机</option>
|
||||||
{{{range $i, $v := .Hosts}}}
|
{{{range $i, $v := .Hosts}}}
|
||||||
<div class="field">
|
<option value="{{{.Id}}}" {{{if $.Task}}}{{{if eq $.Task.HostId .Id }}} selected {{{end}}} {{{end}}}>{{{.Alias}}}-{{{.Name}}}</option>
|
||||||
<div class="ui radio checkbox">
|
|
||||||
{{{if $.Task}}}
|
|
||||||
<input type="radio" name="host_id" tabindex="0" class="hidden" value="{{{.Id}}}"
|
|
||||||
{{{if and (eq $.Task.Protocol 2) (eq $.Task.HostId .Id) }}} checked {{{end}}}
|
|
||||||
>
|
|
||||||
{{{else}}}
|
|
||||||
<input type="radio" name="host_id" tabindex="0" class="hidden" value="{{{.Id}}}">
|
|
||||||
{{{end}}}
|
|
||||||
<label>{{{.Alias}}}-{{{.Name}}}</label>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
{{{end}}}
|
{{{end}}}
|
||||||
</div>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div class="two fields">
|
<div class="two fields">
|
||||||
<div class="field">
|
<div class="field">
|
||||||
|
@ -73,32 +56,23 @@
|
||||||
<textarea rows="5" name="command">{{{.Task.Command}}}</textarea>
|
<textarea rows="5" name="command">{{{.Task.Command}}}</textarea>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="two fields">
|
<div class="three fields">
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<label>任务超时时间 (单位秒, 默认0,不限制超时)</label>
|
<label>任务超时时间 (单位秒, 默认0,不限制超时)</label>
|
||||||
<input type="text" name="timeout" value="{{{.Task.Timeout}}}">
|
<input type="text" name="timeout" value="{{{.Task.Timeout}}}">
|
||||||
</div>
|
</div>
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<label>任务执行事变 (单位秒,0不限制,不能超过24小时)</label>
|
<label>任务重试次数 (默认0, 取值范围1-10)</label>
|
||||||
<input type="text" name="timeout" value="{{{.Task.Timeout}}}">
|
<input type="text" name="timeout" value="{{{.Task.Timeout}}}">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="three fields">
|
<div class="three fields">
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<label>任务状态 (任务添加成功后,是否立即调度)</label>
|
<label>任务状态 (任务添加成功后,是否立即调度)</label>
|
||||||
<div class="ui dropdown selection">
|
<select name="status">
|
||||||
{{{if .Task}}}
|
<option value="2"{{{if .Task}}} {{{if eq .Task.Status 2}}}selected{{{end}}} {{{end}}}>暂停</option>
|
||||||
<input type="hidden" name="status" value="{{{if and .Task.Status (eq .Task.Status 1)}}}1{{{else}}}2{{{end}}}">
|
<option value="1" {{{if .Task}}} {{{if eq .Task.Status 1}}}selected{{{end}}} {{{end}}}>激活</option>
|
||||||
{{{else}}}
|
</select>
|
||||||
<input type="hidden" name="status" value="2">
|
|
||||||
{{{end}}}
|
|
||||||
<div class="default text">暂停</div>
|
|
||||||
<i class="dropdown icon"></i>
|
|
||||||
<div class="menu">
|
|
||||||
<div class="item" data-value="2">暂停</div>
|
|
||||||
<div class="item" data-value="1">激活</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="two fields">
|
<div class="two fields">
|
||||||
|
@ -117,7 +91,9 @@
|
||||||
$('.ui.checkbox')
|
$('.ui.checkbox')
|
||||||
.checkbox()
|
.checkbox()
|
||||||
;
|
;
|
||||||
$('.ui.form').form(
|
var $uiForm = $('.ui.form');
|
||||||
|
registerSelectFormValidation("selectProtocol", $uiForm, $('#protocol'), 'protocol');
|
||||||
|
$($uiForm).form(
|
||||||
{
|
{
|
||||||
onSuccess: function(event, fields) {
|
onSuccess: function(event, fields) {
|
||||||
util.post('/task/store', fields, function(code, message) {
|
util.post('/task/store', fields, function(code, message) {
|
||||||
|
@ -153,11 +129,12 @@
|
||||||
prompt : '请输入任务命令'
|
prompt : '请输入任务命令'
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}, hosts: {
|
},
|
||||||
identifier : 'hosts',
|
hosts: {
|
||||||
|
identifier : 'host_id',
|
||||||
rules: [
|
rules: [
|
||||||
{
|
{
|
||||||
type : 'checked',
|
type : 'selectProtocol',
|
||||||
prompt : '请选择主机'
|
prompt : '请选择主机'
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
Loading…
Reference in New Issue