任务增加手动执行方式

pull/21/merge
ouqiang 2017-04-21 13:36:45 +08:00
parent d1d2685827
commit 4978778579
10 changed files with 108 additions and 42 deletions

View File

@ -119,7 +119,7 @@ func (task *Task) NameExist(name string, id int) (bool, error) {
func(task *Task) Detail(id int) (TaskHost, error) {
taskHost := TaskHost{}
fields := "t.*, host.name,host.username,host.password,host.port,host.auth_type,host.private_key"
fields := "t.*, host.alias,host.name,host.username,host.password,host.port,host.auth_type,host.private_key"
_, err := Db.Alias("t").Join("LEFT", "host", "t.host_id=host.id").Where("t.id=?", id).Cols(fields).Get(&taskHost)
return taskHost, err

View File

@ -23,6 +23,7 @@ type TaskLog struct {
Result string `xorm:"varchar(65535) notnull defalut '' "` // 执行结果
Page int `xorm:"-"`
PageSize int `xorm:"-"`
TotalTime int `xorm:"-"` // 执行总时长
}
func (taskLog *TaskLog) Create() (insertId int64, err error) {
@ -49,6 +50,16 @@ func (taskLog *TaskLog) List() ([]TaskLog, error) {
taskLog.parsePageAndPageSize()
list := make([]TaskLog, 0)
err := Db.Desc("id").Limit(taskLog.PageSize, taskLog.pageLimitOffset()).Find(&list)
if len(list) > 0 {
for i, item := range list {
endTime := item.EndTime
if item.Status == Running {
endTime = time.Now()
}
execSeconds := endTime.Sub(item.StartTime).Seconds()
list[i].TotalTime = int(execSeconds)
}
}
return list, err
}

View File

@ -15,7 +15,9 @@ function Util() {
swal(FAILURE_MESSAGE, response.message ,'error');
return;
}
callback(response.code, response.message, response.data);
if (callback !== undefined) {
callback(response.code, response.message, response.data);
}
};
util.ajaxFailure = function() {
// todo 错误处理

View File

@ -67,6 +67,7 @@ func Register(m *macaron.Macaron) {
m.Post("/remove/:id", task.Remove)
m.Post("/enable/:id", task.Enable)
m.Post("/disable/:id", task.Disable)
m.Get("/run/:id", task.Run)
})
// 主机

View File

@ -145,6 +145,23 @@ func Disable(ctx *macaron.Context) string {
return changeStatus(ctx, models.Disabled)
}
// 手动运行任务
func Run(ctx *macaron.Context) string {
id := ctx.ParamsInt(":id")
json := utils.JsonResponse{}
taskModel := new(models.Task)
task , err := taskModel.Detail(id)
if err != nil || task.Id <= 0 {
return json.CommonFailure("获取任务详情失败", err)
}
task.Spec = "手动运行"
serviceTask := new(service.Task)
serviceTask.Run(task)
return json.Success("任务已开始运行, 请到任务日志中查看结果", nil);
}
// 改变任务状态
func changeStatus(ctx *macaron.Context, status models.Status) string {
id := ctx.ParamsInt(":id")

View File

@ -57,11 +57,15 @@ func (task *Task) Add(taskModel models.TaskHost) {
}
}
// 直接运行任务
func (task *Task) Run(taskModel models.TaskHost) {
go createHandlerJob(taskModel)()
}
type Handler interface {
Run(taskModel models.TaskHost) (string, error)
}
// 本地命令
type LocalCommandHandler struct {}
@ -142,7 +146,6 @@ func (h *SSHCommandHandler) Run(taskModel models.TaskHost) (string, error) {
return ssh.Exec(sshConfig, taskModel.Command)
}
func createTaskLog(taskModel models.TaskHost) (int64, error) {
taskLogModel := new(models.TaskLog)
taskLogModel.TaskId = taskModel.Id

View File

@ -14,6 +14,11 @@
<script type="text/javascript" src="/resource/sweetalert/sweetalert.min.js"></script>
<script type="text/javascript" src="/resource/javascript/vue.min.js"></script>
<script type="text/javascript" src="/resource/javascript/main.js"></script>
<style type="text/css">
body {
overflow-x: hidden;
}
</style>
</head>
<body>
<div class="page">

View File

@ -41,12 +41,15 @@
<td>
<a class="ui purple button" href="/task/edit/{{{.Id}}}">编辑</a>
{{{if eq .Status 1}}}
<button class="ui primary button" onclick="changeStatus({{{.Id}}},{{{.Status}}})">暂停</button>
<button class="ui primary button" @click="changeStatus({{{.Id}}},{{{.Status}}})">暂停</button>
{{{else}}}
<button class="ui blue button" onclick="changeStatus({{{.Id}}},{{{.Status}}})">激活 </button>
<button class="ui blue button" @click="changeStatus({{{.Id}}},{{{.Status}}})">激活 </button>
{{{end}}}
<button class="ui positive button" onclick="util.removeConfirm('/task/remove/{{{.Id}}}')">删除</button>
<button class="ui instagram button">查看日志</button>
<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 instagram button">查看日志</button>
</div>
</td>
</tr>
{{{end}}}
@ -59,18 +62,35 @@
<script type="text/javascript">
$('.ui.checkbox').checkbox();
function changeStatus(id ,status) {
var url = '';
if (status) {
url = '/task/disable';
} else {
url = '/task/enable';
}
url += '/' + id;
util.post(url,{}, function() {
location.reload();
});
}
var vue = new Vue(
{
el: '.ui.violet.table',
methods: {
changeStatus: function (id ,status) {
var url = '';
if (status) {
url = '/task/disable';
} else {
url = '/task/enable';
}
url += '/' + id;
util.post(url,{}, function() {
location.reload();
});
},
remove: function(id) {
util.removeConfirm('/task/remove/' + id);
},
run: function(id) {
util.get("/task/run/" + id, function(code, message) {
swal('操作成功', message, 'success');
})
}
}
}
);
</script>

View File

@ -19,7 +19,6 @@
<div class="content">
<button class="ui small teal button" onclick="clearLog()">清空日志</button>
</div>
</h3>
</div>
</div>
@ -29,10 +28,9 @@
<th>任务名称</th>
<th>cron表达式</th>
<th>协议</th>
<th>超时时间(秒)</th>
<th>超时时间</th>
<th>主机</th>
<th>开始时间</th>
<th>结束时间</th>
<th>执行时长</th>
<th>状态</th>
<th>执行结果</th>
</tr>
@ -43,13 +41,14 @@
<td>{{{.Name}}}</td>
<td>{{{.Spec}}}</td>
<td>{{{if eq .Protocol 1}}} HTTP {{{else if eq .Protocol 2}}} SSH {{{else}}} 本地命令 {{{end}}}</td>
<td>{{{.Timeout}}}</td>
<td>{{{.Timeout}}}</td>
<td>{{{.Hostname}}}</td>
<td>
{{{.StartTime.Format "2006-01-02 15:04:05" }}}
</td>
<td>
{{{.EndTime.Format "2006-01-02 15:04:05" }}}
{{{if gt .TotalTime 0}}}{{{.TotalTime}}}秒{{{else}}}1秒{{{end}}}<br>
开始时间: {{{.StartTime.Format "2006-01-02 15:04:05" }}}<br>
{{{if ne .Status 1}}}
结束时间: {{{.EndTime.Format "2006-01-02 15:04:05" }}}
{{{end}}}
</td>
<td>
{{{if eq .Status 2}}}
@ -63,10 +62,12 @@
{{{end}}}
</td>
<td>
<button class="ui small primary button"
onclick="showResult('{{{.Name}}}', '{{{.Command}}}', '{{{.Result}}}')"
>查看结果
</button>
{{{if ne .Status 1}}}
<button class="ui small primary button"
onclick="showResult('{{{.Name}}}', '{{{.Command}}}', '{{{.Result}}}')"
>查看结果
</button>
{{{end}}}
</td>
</tr>
{{{end}}}
@ -95,6 +96,10 @@
</script>
<script type="text/javascript">
function showTime(startTime, endTime, status) {
}
function showResult(name, command,result) {
$('.message').html($('#task-result').html());
new Vue(

View File

@ -19,14 +19,14 @@
<div class="field">
<label>任务名称</label>
<div class="ui small left icon input">
<input type="text" placeholder="数据库备份" name="name" value="{{{.Task.Task.Name}}}">
<input type="text" name="name" value="{{{.Task.Task.Name}}}">
</div>
</div>
</div>
<div class="two fields">
<div class="field">
<label>crontab表达式 (每行一个表达式)</label>
<textarea rows="5" name="spec" placeholder="*/5 * * * * * *">{{{.Task.Spec}}}</textarea>
<textarea rows="5" name="spec">{{{.Task.Spec}}}</textarea>
</div>
</div>
<div class="three fields">
@ -56,7 +56,7 @@
<div class="ui radio checkbox">
{{{if $.Task}}}
<input type="radio" name="host_id" tabindex="0" class="hidden" value="{{{.Id}}}"
{{{if eq $.Task.HostId .Id}}} checked {{{end}}}
{{{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}}}">
@ -67,14 +67,16 @@
{{{end}}}
</div>
</div>
<div class="field">
<label>命令(shell命令|URL地址, 多条shell命令";"分隔)</label>
<input type="text" name="command" placeholder="tail -n 10 /var/log/nginx/error.log" value="{{{.Task.Command}}}">
<div class="two fields">
<div class="field">
<label>命令(shell命令|URL地址, 多条shell命令";"分隔)</label>
<textarea rows="5" name="command">{{{.Task.Command}}}</textarea>
</div>
</div>
<div class="three fields">
<div class="field">
<label>任务超时时间 (单位秒,0不限制,不能超过24小时)</label>
<input type="text" name="timeout" placeholder="0" value="{{{.Task.Timeout}}}">
<input type="text" name="timeout" value="{{{.Task.Timeout}}}">
</div>
</div>
<div class="three fields">
@ -95,10 +97,10 @@
</div>
</div>
</div>
<div class="two field">
<div class="two fields">
<div class="field">
<label>备注</label>
<textarea rows="5" name="remark" placeholder="任务备注">{{{.Task.Remark}}}</textarea>
<textarea rows="5" name="remark">{{{.Task.Remark}}}</textarea>
</div>
</div>
<div class="ui primary submit button">保存</div>