mirror of https://github.com/ouqiang/gocron
增加本地命令执行
parent
dcf86e00a3
commit
f99db815de
|
@ -9,6 +9,7 @@ type TaskProtocol int8
|
|||
const (
|
||||
TaskHTTP TaskProtocol = iota + 1 // HTTP协议
|
||||
TaskSSH // SSH命令
|
||||
TaskLocalCommand // 本地命令
|
||||
)
|
||||
|
||||
// 任务
|
||||
|
@ -16,7 +17,7 @@ type Task struct {
|
|||
Id int `xorm:"int pk autoincr"`
|
||||
Name string `xorm:"varchar(64) notnull"` // 任务名称
|
||||
Spec string `xorm:"varchar(64) notnull"` // crontab
|
||||
Protocol TaskProtocol `xorm:"tinyint notnull"` // 协议 1:http 2:ssh-command
|
||||
Protocol TaskProtocol `xorm:"tinyint notnull"` // 协议 1:http 2:ssh-command 3: 本地命令
|
||||
Command string `xorm:"varchar(512) notnull"` // URL地址或shell命令
|
||||
Timeout int `xorm:"mediumint notnull default 0"` // 任务执行超时时间(单位秒),0不限制
|
||||
HostId int16 `xorm:"smallint notnull default 0"` // SSH host id,
|
||||
|
|
|
@ -25,6 +25,7 @@ func init() {
|
|||
}
|
||||
|
||||
func InitEnv() {
|
||||
runtime.GOMAXPROCS(runtime.NumCPU())
|
||||
logger.InitLogger()
|
||||
wd, err := os.Getwd()
|
||||
if err != nil {
|
||||
|
|
|
@ -23,9 +23,26 @@ type Result struct {
|
|||
|
||||
// 执行shell命令
|
||||
func Exec(sshConfig SSHConfig, cmd string) (output string, err error) {
|
||||
client, err := getClient(sshConfig)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer client.Close()
|
||||
|
||||
session, err := client.NewSession()
|
||||
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer session.Close()
|
||||
|
||||
var resultChan chan Result = make(chan Result)
|
||||
var timeoutChan chan bool = make(chan bool)
|
||||
go execCommand(sshConfig, cmd, resultChan)
|
||||
go func() {
|
||||
cmd += fmt.Sprintf(" & { sleep %d; eval 'kill $!' &> /dev/null; }", sshConfig.ExecTimeout)
|
||||
output, err := session.CombinedOutput(cmd)
|
||||
resultChan <- Result{string(output), err}
|
||||
}()
|
||||
go triggerTimeout(timeoutChan, sshConfig.ExecTimeout)
|
||||
select {
|
||||
case result := <- resultChan:
|
||||
|
@ -55,24 +72,6 @@ func getClient(sshConfig SSHConfig) (*ssh.Client, error) {
|
|||
return ssh.Dial("tcp", addr, config)
|
||||
}
|
||||
|
||||
func execCommand(sshConfig SSHConfig, cmd string, result chan Result) {
|
||||
client, err := getClient(sshConfig)
|
||||
if err != nil {
|
||||
result <- Result{"", err}
|
||||
return
|
||||
}
|
||||
defer client.Close()
|
||||
|
||||
session, err := client.NewSession()
|
||||
|
||||
if err != nil {
|
||||
result <- Result{"", err}
|
||||
return
|
||||
}
|
||||
defer session.Close()
|
||||
output, err := session.CombinedOutput(cmd)
|
||||
result <- Result{string(output), err}
|
||||
}
|
||||
|
||||
func triggerTimeout(ch chan bool, timeout int){
|
||||
// 最长执行时间不能超过24小时
|
||||
|
|
|
@ -37,7 +37,7 @@ func Create(ctx *macaron.Context) {
|
|||
type TaskForm struct {
|
||||
Name string `binding:"Required;"`
|
||||
Spec string `binding:"Required;MaxSize(64)"`
|
||||
Protocol models.TaskProtocol `binding:"In(1,2)"`
|
||||
Protocol models.TaskProtocol `binding:"In(1,2,3)"`
|
||||
Command string `binding:"Required;MaxSize(512)"`
|
||||
Timeout int `binding:"Range(0,86400)"`
|
||||
HostId int16
|
||||
|
|
|
@ -9,6 +9,8 @@ import (
|
|||
"github.com/ouqiang/gocron/modules/logger"
|
||||
"github.com/ouqiang/gocron/modules/ssh"
|
||||
"github.com/jakecoffman/cron"
|
||||
"github.com/ouqiang/gocron/modules/utils"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var Cron *cron.Cron
|
||||
|
@ -54,6 +56,19 @@ type Handler interface {
|
|||
Run(taskModel models.TaskHost) (string, error)
|
||||
}
|
||||
|
||||
|
||||
type LocalCommandHandler struct {}
|
||||
|
||||
func (h *LocalCommandHandler) Run(taskModel models.TaskHost) (string, error) {
|
||||
args := strings.Split(taskModel.Command, " ")
|
||||
|
||||
if len(args) > 1 {
|
||||
return utils.ExecShell(args[0], args[1:]...)
|
||||
}
|
||||
|
||||
return utils.ExecShell(args[0])
|
||||
}
|
||||
|
||||
// HTTP任务
|
||||
type HTTPHandler struct{}
|
||||
|
||||
|
@ -138,10 +153,12 @@ func updateTaskLog(taskLogId int64, result string, err error) (int64, error) {
|
|||
func createHandlerJob(taskModel models.TaskHost) cron.FuncJob {
|
||||
var handler Handler = nil
|
||||
switch taskModel.Protocol {
|
||||
case models.TaskHTTP:
|
||||
handler = new(HTTPHandler)
|
||||
case models.TaskSSH:
|
||||
handler = new(SSHCommandHandler)
|
||||
case models.TaskHTTP:
|
||||
handler = new(HTTPHandler)
|
||||
case models.TaskSSH:
|
||||
handler = new(SSHCommandHandler)
|
||||
case models.TaskLocalCommand:
|
||||
handler = new(LocalCommandHandler)
|
||||
}
|
||||
if handler == nil {
|
||||
return nil
|
||||
|
@ -152,17 +169,7 @@ func createHandlerJob(taskModel models.TaskHost) cron.FuncJob {
|
|||
logger.Error("任务开始执行#写入任务日志失败-", err)
|
||||
return
|
||||
}
|
||||
// err != nil 执行失败, 失败重试3次
|
||||
retryTime := 4
|
||||
var result string = ""
|
||||
for i := 0; i < retryTime; i++ {
|
||||
result, err = handler.Run(taskModel)
|
||||
if err == nil {
|
||||
break
|
||||
} else {
|
||||
logger.Error("任务执行失败#tasklog.id-" + strconv.FormatInt(taskLogId, 10) + "#尝试次数-" + strconv.Itoa(i + 1) + "#" + err.Error() + " " + result)
|
||||
}
|
||||
}
|
||||
result, err := handler.Run(taskModel)
|
||||
_, err = updateTaskLog(taskLogId, result, err)
|
||||
if err != nil {
|
||||
logger.Error("任务结束#更新任务日志失败-", err)
|
||||
|
|
|
@ -42,7 +42,7 @@
|
|||
<tr>
|
||||
<td>{{{.Name}}}</td>
|
||||
<td>{{{.Spec}}}</td>
|
||||
<td>{{{if eq .Protocol 1}}} HTTP {{{else}}} SSH {{{end}}}</td>
|
||||
<td>{{{if eq .Protocol 1}}} HTTP {{{else if eq .Protocol 2}}} SSH {{{else}}} 本地命令 {{{end}}}</td>
|
||||
<td>{{{.Timeout}}}</td>
|
||||
<td>{{{.Hostname}}}</td>
|
||||
<td>
|
||||
|
|
|
@ -32,10 +32,11 @@
|
|||
<div class="field">
|
||||
<label>协议</label>
|
||||
<div class="ui dropdown selection">
|
||||
<input type="hidden" name="protocol" value="2">
|
||||
<div class="default text">SSH-Command (执行shell命令)</div>
|
||||
<input type="hidden" name="protocol" value="3">
|
||||
<div class="default text">本地命令</div>
|
||||
<i class="dropdown icon"></i>
|
||||
<div class="menu">
|
||||
<div class="item active" data-value="3">本地命令</div>
|
||||
<div class="item active" data-value="2">SSH</div>
|
||||
<div class="item" data-value="1">HTTP</div>
|
||||
</div>
|
||||
|
|
Loading…
Reference in New Issue