执行本机系统命令Windows和*nix分别实现

pull/21/merge
ouqiang 2017-05-05 13:44:44 +08:00
parent 14295049d2
commit dfa96bc9f2
8 changed files with 108 additions and 46 deletions

View File

@ -111,7 +111,9 @@ func catchSignal() {
s := <- c
logger.Info("收到信号 -- ", s)
switch s {
case syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM:
case syscall.SIGHUP:
logger.Info("收到终端断开信号, 忽略")
case syscall.SIGINT, syscall.SIGTERM:
shutdown()
}
}

View File

@ -4,48 +4,14 @@ import (
"crypto/md5"
"encoding/hex"
"math/rand"
"os/exec"
"time"
"runtime"
"github.com/Tang-RoseChild/mahonia"
"strings"
"os"
"syscall"
"fmt"
)
// 执行shell命令可设置执行超时时间
// todo Windows不能KILL掉子进程, 需特殊处理
func ExecShellWithTimeout(timeout int, command string, args... string) (string, error) {
cmd := exec.Command(command, args...)
cmd.SysProcAttr = &syscall.SysProcAttr{
Setpgid: true,
}
// 后台运行
if timeout == -1 {
go cmd.CombinedOutput()
return "", nil
}
// 不限制超时
if timeout == 0 {
output ,err := cmd.CombinedOutput()
return string(output), err
}
d := time.Duration(timeout) * time.Second
timer := time.AfterFunc(d, func() {
// 超时kill进程
syscall.Kill(-cmd.Process.Pid, syscall.SIGKILL)
})
output ,err := cmd.CombinedOutput()
timer.Stop()
return string(output), err
}
// 生成长度为length的随机字符串
func RandString(length int64) string {
sources := []byte("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")
@ -122,6 +88,7 @@ func EscapeJson(s string) string {
return ReplaceStrings(s, specialChars, replaceChars)
}
// 判断文件是否存在及是否有权限访问
func FileExist(file string) bool {
_, err := os.Stat(file)
if os.IsNotExist(err) {
@ -132,4 +99,9 @@ func FileExist(file string) bool {
}
return true
}
// 格式化环境变量
func FormatUnixEnv(key, value string) string {
return fmt.Sprintf("export %s=%s; ", key, value)
}

View File

@ -2,13 +2,6 @@ package utils
import "testing"
func TestExecShell(t *testing.T) {
_, err := ExecShell("ls")
if err != nil {
t.Fatal(err)
}
}
func TestRandString(t *testing.T) {
str := RandString(32)
if len(str) != 32 {

View File

@ -0,0 +1,44 @@
// +build !windows
package utils
import (
"os/exec"
"syscall"
"time"
"fmt"
)
// 执行shell命令可设置执行超时时间
func ExecShellWithTimeout(timeout int, command string, args... string) (string, error) {
cmd := exec.Command(command, args...)
cmd.SysProcAttr = &syscall.SysProcAttr{
Setpgid: true,
}
// 后台运行
if timeout == -1 {
go cmd.CombinedOutput()
return "", nil
}
// 不限制超时
if timeout == 0 {
output ,err := cmd.CombinedOutput()
return string(output), err
}
d := time.Duration(timeout) * time.Second
timer := time.AfterFunc(d, func() {
// 超时kill进程
syscall.Kill(-cmd.Process.Pid, syscall.SIGKILL)
})
output ,err := cmd.CombinedOutput()
timer.Stop()
return string(output), err
}
// 格式化环境变量
func FormatEnv(key, value string) string {
return fmt.Sprintf("export %s=%s;", key, value)
}

View File

@ -0,0 +1,44 @@
// +build windows
package utils
import (
"syscall"
"time"
"os/exec"
"strconv"
"fmt"
)
// 执行shell命令可设置执行超时时间
func ExecShellWithTimeout(timeout int, command string, args... string) (string, error) {
cmd := exec.Command(command, args...)
// 隐藏cmd窗口
cmd.SysProcAttr = &syscall.SysProcAttr{HideWindow: true}
// 后台运行
if timeout == -1 {
go cmd.CombinedOutput()
return "", nil
}
// 不限制超时
if timeout <= 0 {
output ,err := cmd.CombinedOutput()
return string(output), err
}
d := time.Duration(timeout) * time.Second
timer := time.AfterFunc(d, func() {
// 超时kill进程
exec.Command("taskkill", "/F", "/T", "/PID", strconv.Itoa(cmd.Process.Pid)).Run()
cmd.Process.Kill()
})
output ,err := cmd.CombinedOutput()
timer.Stop()
return string(output), err
}
// 格式化环境变量
func FormatEnv(key, value string) string {
return fmt.Sprintf("set %s=%s & ", key, value)
}

View File

@ -310,9 +310,16 @@ func beforeExecJob(taskModel *models.TaskHost) (taskLogId int64) {
}
// 设置notifyId到环境变量中
if notifyId != "" {
taskModel.Command = fmt.Sprintf("export GOCRON_TASK_ID=%s;%s", notifyId, taskModel.Command)
envName := "GOCRON_TASK_ID"
if taskModel.Protocol == models.TaskSSH {
taskModel.Command = fmt.Sprintf("%s%s", utils.FormatUnixEnv(envName, notifyId), taskModel.Command)
} else {
taskModel.Command = fmt.Sprintf("%s%s", utils.FormatEnv(envName, notifyId), taskModel.Command)
}
}
logger.Debugf("任务命令-%s", taskModel.Command)
return taskLogId
}

View File

@ -61,7 +61,7 @@
<p>cron {{{.Spec}}}</p>
<p>: {{{if eq .Protocol 1}}} HTTP {{{else if eq .Protocol 2}}} SSH {{{else if eq .Protocol 3}}}{{{end}}}</p>
<p class="sensorStatus">{{{.Command}}}</p>
<p class="sensorStatus">{{{if gt .Timeout 0}}}{{{.Timeout}}}{{{else}}}{{{end}}}</p>
<p class="sensorStatus">{{{if eq .Timeout -1}}}{{{else if eq .Timeout 0}}}{{{.Timeout}}}{{{else}}}{{{end}}}</p>
<p>: {{{.RetryTimes}}}</p>
<p class="sensorStatus">{{{if gt .Multi 0}}}{{{else}}}{{{end}}}</p>
{{{if eq .Protocol 2}}}

View File

@ -72,7 +72,7 @@
<td>{{{.Name}}}</td>
<td>{{{.Spec}}}</td>
<td>{{{if eq .Protocol 1}}} HTTP {{{else if eq .Protocol 2}}} SSH {{{else}}} {{{end}}}</td>
<td>{{{if gt .Timeout 0}}}{{{.Timeout}}}{{{else}}}{{{end}}}</td>
<td>{{{if eq .Timeout -1}}}{{{else if eq .Timeout 0}}}{{{.Timeout}}}{{{else}}}{{{end}}}</td>
<td>{{{.RetryTimes}}}</td>
<td>{{{.Hostname}}}</td>
<td>