V2.7 增加agent执行器
This commit is contained in:
502
jobs/job.go
502
jobs/job.go
@@ -9,11 +9,18 @@ package jobs
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/astaxie/beego/logs"
|
||||
"github.com/george518/PPGo_Job/libs"
|
||||
"github.com/george518/PPGo_Job/models"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"net/rpc"
|
||||
"net/rpc/jsonrpc"
|
||||
"os/exec"
|
||||
"runtime/debug"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"runtime"
|
||||
@@ -22,25 +29,52 @@ import (
|
||||
|
||||
"encoding/json"
|
||||
"github.com/astaxie/beego"
|
||||
"github.com/axgle/mahonia"
|
||||
"github.com/george518/PPGo_Job/models"
|
||||
"github.com/george518/PPGo_Job/notify"
|
||||
"github.com/linxiaozhi/go-telnet"
|
||||
"github.com/pkg/errors"
|
||||
"golang.org/x/crypto/ssh"
|
||||
)
|
||||
|
||||
type Job struct {
|
||||
jobKey int // jobId = id*10000+serverId
|
||||
id int // taskID
|
||||
logId int64 // 日志记录ID
|
||||
serverId int //服务器信息
|
||||
serverName string //服务器名称
|
||||
name string // 任务名称
|
||||
task *models.Task // 任务对象
|
||||
runFunc func(time.Duration) (string, string, error, bool) // 执行函数
|
||||
status int // 任务状态,大于0表示正在执行中
|
||||
Concurrent bool // 同一个任务是否允许并行执行
|
||||
JobKey int // jobId = id*10000+serverId
|
||||
Id int // taskID
|
||||
LogId int64 // 日志记录ID
|
||||
ServerId int // 执行器信息
|
||||
ServerName string // 执行器名称
|
||||
ServerType int // 执行器类型,2-agent 1-telnet 0-ssh
|
||||
Name string // 任务名称
|
||||
Task *models.Task // 任务对象
|
||||
RunFunc func(time.Duration) *JobResult // 执行函数
|
||||
Status int // 任务状态,大于0表示正在执行中
|
||||
Concurrent bool // 同一个任务是否允许并行执行
|
||||
}
|
||||
|
||||
type JobResult struct {
|
||||
OutMsg string
|
||||
ErrMsg string
|
||||
IsOk bool
|
||||
IsTimeout bool
|
||||
}
|
||||
|
||||
//调度计数器
|
||||
var Counter sync.Map
|
||||
|
||||
func GetCounter(key string) int {
|
||||
if v, ok := Counter.LoadOrStore(key, 0); ok {
|
||||
n := v.(int)
|
||||
return n
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func SetCounter(key string) {
|
||||
if v, ok := Counter.Load(key); ok {
|
||||
n := v.(int)
|
||||
m := n + 1
|
||||
if n > 1000 {
|
||||
m = 0
|
||||
}
|
||||
Counter.Store(key, m)
|
||||
}
|
||||
}
|
||||
|
||||
func NewJobFromTask(task *models.Task) ([]*Job, error) {
|
||||
@@ -53,24 +87,26 @@ func NewJobFromTask(task *models.Task) ([]*Job, error) {
|
||||
}
|
||||
|
||||
TaskServerIdsArr := strings.Split(task.ServerIds, ",")
|
||||
|
||||
jobArr := make([]*Job, 0)
|
||||
|
||||
for _, server_id := range TaskServerIdsArr {
|
||||
if server_id == "0" {
|
||||
//本地执行
|
||||
job := NewCommandJob(task.Id, 0, task.TaskName, task.Command)
|
||||
job.task = task
|
||||
job.Concurrent = task.Concurrent == 1
|
||||
job.serverId = 0
|
||||
job.serverName = "本地服务器"
|
||||
job.Task = task
|
||||
job.Concurrent = false
|
||||
if task.Concurrent == 1 {
|
||||
job.Concurrent = true
|
||||
}
|
||||
//job.Concurrent = task.Concurrent == 1
|
||||
job.ServerId = 0
|
||||
job.ServerName = "本地服务器"
|
||||
jobArr = append(jobArr, job)
|
||||
} else {
|
||||
server_id_int, _ := strconv.Atoi(server_id)
|
||||
//远程执行
|
||||
server, _ := models.TaskServerGetById(server_id_int)
|
||||
|
||||
if server.Status == 1 {
|
||||
if server.Status == 2 {
|
||||
fmt.Println("服务器已禁用")
|
||||
continue
|
||||
}
|
||||
@@ -79,29 +115,54 @@ func NewJobFromTask(task *models.Task) ([]*Job, error) {
|
||||
if server.Type == 0 {
|
||||
//密码验证登录服务器
|
||||
job := RemoteCommandJobByPassword(task.Id, server_id_int, task.TaskName, task.Command, server)
|
||||
job.task = task
|
||||
job.Concurrent = task.Concurrent == 1
|
||||
job.serverId = server_id_int
|
||||
job.serverName = server.ServerName
|
||||
job.Task = task
|
||||
job.Concurrent = false
|
||||
if task.Concurrent == 1 {
|
||||
job.Concurrent = true
|
||||
}
|
||||
//job.Concurrent = task.Concurrent == 1
|
||||
job.ServerId = server_id_int
|
||||
job.ServerName = server.ServerName
|
||||
jobArr = append(jobArr, job)
|
||||
} else {
|
||||
job := RemoteCommandJob(task.Id, server_id_int, task.TaskName, task.Command, server)
|
||||
job.task = task
|
||||
job.Concurrent = task.Concurrent == 1
|
||||
job.serverId = server_id_int
|
||||
job.serverName = server.ServerName
|
||||
job.Task = task
|
||||
job.Concurrent = false
|
||||
if task.Concurrent == 1 {
|
||||
job.Concurrent = true
|
||||
}
|
||||
//job.Concurrent = task.Concurrent == 1
|
||||
job.ServerId = server_id_int
|
||||
job.ServerName = server.ServerName
|
||||
jobArr = append(jobArr, job)
|
||||
}
|
||||
} else if server.ConnectionType == 1 {
|
||||
if server.Type == 0 {
|
||||
//密码验证登录服务器
|
||||
job := RemoteCommandJobByTelnetPassword(task.Id, server_id_int, task.TaskName, task.Command, server)
|
||||
job.task = task
|
||||
job.Concurrent = task.Concurrent == 1
|
||||
job.serverId = server_id_int
|
||||
job.serverName = server.ServerName
|
||||
job.Task = task
|
||||
job.Concurrent = false
|
||||
if task.Concurrent == 1 {
|
||||
job.Concurrent = true
|
||||
}
|
||||
//job.Concurrent = task.Concurrent == 1
|
||||
job.ServerId = server_id_int
|
||||
job.ServerName = server.ServerName
|
||||
jobArr = append(jobArr, job)
|
||||
}
|
||||
} else if server.ConnectionType == 2 {
|
||||
//密码验证登录服务器
|
||||
job := RemoteCommandJobByAgentPassword(task.Id, server_id_int, task.TaskName, task.Command, server)
|
||||
job.Task = task
|
||||
job.Concurrent = false
|
||||
if task.Concurrent == 1 {
|
||||
job.Concurrent = true
|
||||
}
|
||||
//job.Concurrent = task.Concurrent == 1
|
||||
job.ServerId = server_id_int
|
||||
job.ServerName = server.ServerName
|
||||
jobArr = append(jobArr, job)
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -111,12 +172,12 @@ func NewJobFromTask(task *models.Task) ([]*Job, error) {
|
||||
|
||||
func NewCommandJob(id int, serverId int, name string, command string) *Job {
|
||||
job := &Job{
|
||||
id: id,
|
||||
name: name,
|
||||
Id: id,
|
||||
Name: name,
|
||||
}
|
||||
|
||||
job.jobKey = jobKey(id, serverId)
|
||||
job.runFunc = func(timeout time.Duration) (string, string, error, bool) {
|
||||
job.JobKey = libs.JobKey(id, serverId)
|
||||
job.RunFunc = func(timeout time.Duration) (jobresult *JobResult) {
|
||||
bufOut := new(bytes.Buffer)
|
||||
bufErr := new(bytes.Buffer)
|
||||
//cmd := exec.Command("/bin/bash", "-c", command)
|
||||
@@ -130,8 +191,18 @@ func NewCommandJob(id int, serverId int, name string, command string) *Job {
|
||||
cmd.Stderr = bufErr
|
||||
cmd.Start()
|
||||
err, isTimeout := runCmdWithTimeout(cmd, timeout)
|
||||
jobresult = new(JobResult)
|
||||
jobresult.OutMsg = libs.GbkAsUtf8(bufOut.String())
|
||||
jobresult.ErrMsg = libs.GbkAsUtf8(bufErr.String())
|
||||
|
||||
return gbkAsUtf8(bufOut.String()), gbkAsUtf8(bufErr.String()), err, isTimeout
|
||||
jobresult.IsOk = true
|
||||
if err != nil {
|
||||
jobresult.IsOk = false
|
||||
}
|
||||
|
||||
jobresult.IsTimeout = isTimeout
|
||||
|
||||
return jobresult
|
||||
}
|
||||
return job
|
||||
}
|
||||
@@ -139,23 +210,29 @@ func NewCommandJob(id int, serverId int, name string, command string) *Job {
|
||||
//远程执行任务 密钥验证
|
||||
func RemoteCommandJob(id int, serverId int, name string, command string, servers *models.TaskServer) *Job {
|
||||
job := &Job{
|
||||
id: id,
|
||||
name: name,
|
||||
serverId: serverId,
|
||||
Id: id,
|
||||
Name: name,
|
||||
ServerId: serverId,
|
||||
}
|
||||
|
||||
job.jobKey = jobKey(id, serverId)
|
||||
job.JobKey = libs.JobKey(id, serverId)
|
||||
|
||||
job.runFunc = func(timeout time.Duration) (string, string, error, bool) {
|
||||
job.RunFunc = func(timeout time.Duration) (jobresult *JobResult) {
|
||||
jobresult = new(JobResult)
|
||||
jobresult.OutMsg = ""
|
||||
jobresult.ErrMsg = ""
|
||||
jobresult.IsTimeout = false
|
||||
|
||||
key, err := ioutil.ReadFile(servers.PrivateKeySrc)
|
||||
if err != nil {
|
||||
return "", "", err, false
|
||||
jobresult.IsOk = false
|
||||
return
|
||||
}
|
||||
// Create the Signer for this private key.
|
||||
signer, err := ssh.ParsePrivateKey(key)
|
||||
if err != nil {
|
||||
return "", "", err, false
|
||||
jobresult.IsOk = false
|
||||
return
|
||||
}
|
||||
addr := fmt.Sprintf("%s:%d", servers.ServerIp, servers.Port)
|
||||
config := &ssh.ClientConfig{
|
||||
@@ -172,14 +249,16 @@ func RemoteCommandJob(id int, serverId int, name string, command string, servers
|
||||
// Connect to the remote server and perform the SSH handshake.47.93.220.5
|
||||
client, err := ssh.Dial("tcp", addr, config)
|
||||
if err != nil {
|
||||
return "", "", err, false
|
||||
jobresult.IsOk = false
|
||||
return
|
||||
}
|
||||
|
||||
defer client.Close()
|
||||
|
||||
session, err := client.NewSession()
|
||||
if err != nil {
|
||||
return "", "", err, false
|
||||
jobresult.IsOk = false
|
||||
return
|
||||
}
|
||||
defer session.Close()
|
||||
|
||||
@@ -193,10 +272,14 @@ func RemoteCommandJob(id int, serverId int, name string, command string, servers
|
||||
|
||||
//session.Output(command)
|
||||
if err := session.Run(command); err != nil {
|
||||
return "", "", err, false
|
||||
jobresult.IsOk = false
|
||||
return
|
||||
}
|
||||
isTimeout := false
|
||||
return b.String(), c.String(), err, isTimeout
|
||||
jobresult.OutMsg = b.String()
|
||||
jobresult.ErrMsg = c.String()
|
||||
jobresult.IsOk = true
|
||||
jobresult.IsTimeout = false
|
||||
return
|
||||
}
|
||||
return job
|
||||
}
|
||||
@@ -212,12 +295,18 @@ func RemoteCommandJobByPassword(id int, serverId int, name string, command strin
|
||||
)
|
||||
|
||||
job := &Job{
|
||||
id: id,
|
||||
name: name,
|
||||
serverId: serverId,
|
||||
Id: id,
|
||||
Name: name,
|
||||
ServerId: serverId,
|
||||
ServerType: servers.ConnectionType,
|
||||
}
|
||||
job.jobKey = jobKey(id, serverId)
|
||||
job.runFunc = func(timeout time.Duration) (string, string, error, bool) {
|
||||
job.JobKey = libs.JobKey(id, serverId)
|
||||
job.RunFunc = func(timeout time.Duration) (jobresult *JobResult) {
|
||||
jobresult = new(JobResult)
|
||||
jobresult.OutMsg = ""
|
||||
jobresult.ErrMsg = ""
|
||||
jobresult.IsTimeout = false
|
||||
|
||||
// get auth method
|
||||
auth = make([]ssh.AuthMethod, 0)
|
||||
auth = append(auth, ssh.Password(servers.Password))
|
||||
@@ -235,14 +324,16 @@ func RemoteCommandJobByPassword(id int, serverId int, name string, command strin
|
||||
addr = fmt.Sprintf("%s:%d", servers.ServerIp, servers.Port)
|
||||
|
||||
if client, err = ssh.Dial("tcp", addr, clientConfig); err != nil {
|
||||
return "", "", err, false
|
||||
jobresult.IsOk = false
|
||||
return
|
||||
}
|
||||
|
||||
defer client.Close()
|
||||
|
||||
// create session
|
||||
if session, err = client.NewSession(); err != nil {
|
||||
return "", "", err, false
|
||||
jobresult.IsOk = false
|
||||
return
|
||||
}
|
||||
|
||||
var b bytes.Buffer
|
||||
@@ -251,10 +342,14 @@ func RemoteCommandJobByPassword(id int, serverId int, name string, command strin
|
||||
session.Stderr = &c
|
||||
//session.Output(command)
|
||||
if err := session.Run(command); err != nil {
|
||||
return "", "", err, false
|
||||
jobresult.IsOk = false
|
||||
return
|
||||
}
|
||||
isTimeout := false
|
||||
return b.String(), c.String(), err, isTimeout
|
||||
jobresult.OutMsg = b.String()
|
||||
jobresult.ErrMsg = c.String()
|
||||
jobresult.IsOk = true
|
||||
jobresult.IsTimeout = false
|
||||
return
|
||||
}
|
||||
|
||||
return job
|
||||
@@ -263,18 +358,23 @@ func RemoteCommandJobByPassword(id int, serverId int, name string, command strin
|
||||
func RemoteCommandJobByTelnetPassword(id int, serverId int, name string, command string, servers *models.TaskServer) *Job {
|
||||
|
||||
job := &Job{
|
||||
id: id,
|
||||
name: name,
|
||||
serverId: serverId,
|
||||
Id: id,
|
||||
Name: name,
|
||||
ServerId: serverId,
|
||||
}
|
||||
|
||||
job.jobKey = jobKey(id, serverId)
|
||||
job.runFunc = func(timeout time.Duration) (string, string, error, bool) {
|
||||
job.JobKey = libs.JobKey(id, serverId)
|
||||
job.RunFunc = func(timeout time.Duration) (jobresult *JobResult) {
|
||||
jobresult = new(JobResult)
|
||||
jobresult.OutMsg = ""
|
||||
jobresult.ErrMsg = ""
|
||||
jobresult.IsTimeout = false
|
||||
|
||||
addr := fmt.Sprintf("%s:%d", servers.ServerIp, servers.Port)
|
||||
conn, err := gote.DialTimeout("tcp", addr, timeout)
|
||||
if err != nil {
|
||||
return "", "", err, false
|
||||
jobresult.IsOk = false
|
||||
return
|
||||
}
|
||||
|
||||
defer conn.Close()
|
||||
@@ -282,28 +382,35 @@ func RemoteCommandJobByTelnetPassword(id int, serverId int, name string, command
|
||||
buf := make([]byte, 4096)
|
||||
|
||||
if _, err = conn.Read(buf); err != nil {
|
||||
return "", "", err, false
|
||||
jobresult.IsOk = false
|
||||
return
|
||||
}
|
||||
|
||||
if _, err = conn.Write([]byte(servers.ServerAccount + "\r\n")); err != nil {
|
||||
return "", "", err, false
|
||||
jobresult.IsOk = false
|
||||
return
|
||||
}
|
||||
|
||||
if _, err = conn.Read(buf); err != nil {
|
||||
return "", "", err, false
|
||||
jobresult.IsOk = false
|
||||
return
|
||||
}
|
||||
|
||||
if _, err = conn.Write([]byte(servers.Password + "\r\n")); err != nil {
|
||||
return "", "", err, false
|
||||
jobresult.IsOk = false
|
||||
return
|
||||
}
|
||||
|
||||
if _, err = conn.Read(buf); err != nil {
|
||||
return "", "", err, false
|
||||
jobresult.IsOk = false
|
||||
return
|
||||
}
|
||||
|
||||
loginStr := gbkAsUtf8(string(buf[:]))
|
||||
loginStr := libs.GbkAsUtf8(string(buf[:]))
|
||||
if !strings.Contains(loginStr, ">") {
|
||||
return "", "", errors.Errorf("Login failed!"), false
|
||||
jobresult.ErrMsg = jobresult.ErrMsg + "Login failed!"
|
||||
jobresult.IsOk = false
|
||||
return
|
||||
}
|
||||
|
||||
commandArr := strings.Split(command, "\n")
|
||||
@@ -312,44 +419,178 @@ func RemoteCommandJobByTelnetPassword(id int, serverId int, name string, command
|
||||
for _, c := range commandArr {
|
||||
_, err = conn.Write([]byte(c + "\r\n"))
|
||||
if err != nil {
|
||||
return "", "", err, false
|
||||
jobresult.IsOk = false
|
||||
return
|
||||
}
|
||||
|
||||
n, err = conn.Read(buf)
|
||||
|
||||
out = out + gbkAsUtf8(string(buf[0:n]))
|
||||
out = out + libs.GbkAsUtf8(string(buf[0:n]))
|
||||
if err != nil ||
|
||||
strings.Contains(out, "'"+c+"' is not recognized as an internal or external command") ||
|
||||
strings.Contains(out, "'"+c+"' 不是内部或外部命令,也不是可运行的程序") {
|
||||
return out, "", fmt.Errorf(gbkAsUtf8(string(buf[0:n]))), false
|
||||
jobresult.ErrMsg = jobresult.ErrMsg + " " + libs.GbkAsUtf8(string(buf[0:n]))
|
||||
jobresult.IsOk = false
|
||||
jobresult.OutMsg = out
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
return out, "", nil, false
|
||||
jobresult.IsOk = true
|
||||
jobresult.OutMsg = out
|
||||
return
|
||||
}
|
||||
|
||||
return job
|
||||
}
|
||||
|
||||
func (j *Job) Status() int {
|
||||
return j.status
|
||||
func RemoteCommandJobByAgentPassword(id int, serverId int, name string, command string, servers *models.TaskServer) *Job {
|
||||
|
||||
job := &Job{
|
||||
Id: id,
|
||||
Name: name,
|
||||
ServerType: servers.ConnectionType,
|
||||
}
|
||||
|
||||
job.JobKey = libs.JobKey(id, serverId)
|
||||
job.RunFunc = func(timeout time.Duration) *JobResult {
|
||||
return new(JobResult)
|
||||
}
|
||||
return job
|
||||
|
||||
}
|
||||
|
||||
func (j *Job) GetStatus() int {
|
||||
return j.Status
|
||||
}
|
||||
|
||||
func (j *Job) GetName() string {
|
||||
return j.name
|
||||
return j.Name
|
||||
}
|
||||
|
||||
func (j *Job) GetId() int {
|
||||
return j.id
|
||||
return j.Id
|
||||
}
|
||||
|
||||
func (j *Job) GetLogId() int64 {
|
||||
return j.logId
|
||||
return j.LogId
|
||||
}
|
||||
|
||||
type RpcResult struct {
|
||||
Status int
|
||||
Message string
|
||||
}
|
||||
|
||||
func (j *Job) agentRun() (reply *JobResult) {
|
||||
|
||||
server, _ := models.TaskServerGetById(j.ServerId)
|
||||
conn, err := net.Dial("tcp", fmt.Sprintf("%s:%d", server.ServerIp, server.Port))
|
||||
reply = new(JobResult)
|
||||
if err != nil {
|
||||
logs.Error("Net error:", err)
|
||||
reply.IsOk = false
|
||||
reply.ErrMsg = "Net error:" + err.Error()
|
||||
reply.IsTimeout = false
|
||||
reply.OutMsg = ""
|
||||
return reply
|
||||
}
|
||||
|
||||
defer conn.Close()
|
||||
client := rpc.NewClientWithCodec(jsonrpc.NewClientCodec(conn))
|
||||
|
||||
defer client.Close()
|
||||
reply = new(JobResult)
|
||||
|
||||
task := j.Task
|
||||
err = client.Call("RpcTask.RunTask", task, &reply)
|
||||
if err != nil {
|
||||
reply.IsOk = false
|
||||
reply.ErrMsg = "Net error:" + err.Error()
|
||||
reply.IsTimeout = false
|
||||
reply.OutMsg = ""
|
||||
return reply
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func TestServer(server *models.TaskServer) error {
|
||||
if server.ConnectionType == 0 {
|
||||
switch server.Type {
|
||||
case 0:
|
||||
//密码登录
|
||||
return libs.RemoteCommandByPassword(server)
|
||||
case 1:
|
||||
//密钥登录
|
||||
return libs.RemoteCommandByKey(server)
|
||||
default:
|
||||
return errors.New("未知的登录方式")
|
||||
|
||||
}
|
||||
} else if server.ConnectionType == 1 {
|
||||
if server.Type == 0 {
|
||||
//密码登录]
|
||||
return libs.RemoteCommandByTelnetPassword(server)
|
||||
} else {
|
||||
return errors.New("Telnet方式暂不支持密钥登陆!")
|
||||
}
|
||||
|
||||
} else if server.ConnectionType == 2 {
|
||||
return libs.RemoteAgent(server)
|
||||
}
|
||||
|
||||
return errors.New("未知错误")
|
||||
}
|
||||
|
||||
func PollServer(j *Job) bool {
|
||||
//判断是否是当前执行器执行
|
||||
TaskServerIdsArr := strings.Split(j.Task.ServerIds, ",")
|
||||
num := len(TaskServerIdsArr)
|
||||
|
||||
if num == 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
count := GetCounter(strconv.Itoa(j.Task.Id))
|
||||
index := count % num
|
||||
pollServerId, _ := strconv.Atoi(TaskServerIdsArr[index])
|
||||
|
||||
if j.ServerId != pollServerId {
|
||||
return false
|
||||
}
|
||||
|
||||
//本地服务器
|
||||
if pollServerId == 0 {
|
||||
return true
|
||||
}
|
||||
|
||||
//判断执行器或者服务器是否存活
|
||||
server, _ := models.TaskServerGetById(pollServerId)
|
||||
|
||||
if server.Status != 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
if err := TestServer(server); err != nil {
|
||||
server.Status = 1
|
||||
server.Update()
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
|
||||
}
|
||||
|
||||
func (j *Job) Run() {
|
||||
if !j.Concurrent && j.status > 0 {
|
||||
beego.Warn(fmt.Sprintf("任务[%d]上一次执行尚未结束,本次被忽略。", j.jobKey))
|
||||
//执行策略 轮询
|
||||
if j.Task.ServerType == 1 {
|
||||
if !PollServer(j) {
|
||||
return
|
||||
} else {
|
||||
SetCounter(strconv.Itoa(j.Task.Id))
|
||||
}
|
||||
}
|
||||
|
||||
if !j.Concurrent && j.Status > 0 {
|
||||
beego.Warn(fmt.Sprintf("任务[%d]上一次执行尚未结束,本次被忽略。", j.JobKey))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -366,42 +607,50 @@ func (j *Job) Run() {
|
||||
}()
|
||||
}
|
||||
|
||||
beego.Debug(fmt.Sprintf("开始执行任务: %d", j.jobKey))
|
||||
beego.Debug(fmt.Sprintf("开始执行任务: %d", j.JobKey))
|
||||
|
||||
j.status++
|
||||
j.Status++
|
||||
defer func() {
|
||||
j.status--
|
||||
j.Status--
|
||||
}()
|
||||
|
||||
t := time.Now()
|
||||
timeout := time.Duration(time.Hour * 24)
|
||||
if j.task.Timeout > 0 {
|
||||
timeout = time.Second * time.Duration(j.task.Timeout)
|
||||
if j.Task.Timeout > 0 {
|
||||
timeout = time.Second * time.Duration(j.Task.Timeout)
|
||||
}
|
||||
cmdOut, cmdErr, err, isTimeout := j.runFunc(timeout)
|
||||
|
||||
var jobResult = new(JobResult)
|
||||
//anget
|
||||
if j.ServerType == 2 {
|
||||
jobResult = j.agentRun()
|
||||
} else {
|
||||
jobResult = j.RunFunc(timeout)
|
||||
}
|
||||
|
||||
ut := time.Now().Sub(t) / time.Millisecond
|
||||
|
||||
// 插入日志
|
||||
log := new(models.TaskLog)
|
||||
log.TaskId = j.id
|
||||
log.ServerId = j.serverId
|
||||
log.ServerName = j.serverName
|
||||
log.Output = cmdOut
|
||||
log.Error = cmdErr
|
||||
log.TaskId = j.Id
|
||||
log.ServerId = j.ServerId
|
||||
log.ServerName = j.ServerName
|
||||
log.Output = jobResult.OutMsg
|
||||
log.Error = jobResult.ErrMsg
|
||||
log.ProcessTime = int(ut)
|
||||
log.CreateTime = t.Unix()
|
||||
|
||||
if isTimeout {
|
||||
if jobResult.IsTimeout {
|
||||
log.Status = models.TASK_TIMEOUT
|
||||
log.Error = fmt.Sprintf("任务执行超过 %d 秒\n----------------------\n%s\n", int(timeout/time.Second), cmdErr)
|
||||
} else if err != nil {
|
||||
log.Error = fmt.Sprintf("任务执行超过 %d 秒\n----------------------\n%s\n", int(timeout/time.Second), jobResult.ErrMsg)
|
||||
} else if !jobResult.IsOk {
|
||||
log.Status = models.TASK_ERROR
|
||||
log.Error = err.Error() + ":" + cmdErr
|
||||
log.Error = "ERROR:" + jobResult.ErrMsg
|
||||
}
|
||||
|
||||
if log.Status < 0 && j.task.IsNotify == 1 {
|
||||
if j.task.NotifyUserIds != "0" && j.task.NotifyUserIds != "" {
|
||||
adminInfo := AllAdminInfo(j.task.NotifyUserIds)
|
||||
if log.Status < 0 && j.Task.IsNotify == 1 {
|
||||
if j.Task.NotifyUserIds != "0" && j.Task.NotifyUserIds != "" {
|
||||
adminInfo := AllAdminInfo(j.Task.NotifyUserIds)
|
||||
phone := make(map[string]string, 0)
|
||||
dingtalk := make(map[string]string, 0)
|
||||
wechat := make(map[string]string, 0)
|
||||
@@ -432,9 +681,9 @@ func (j *Job) Run() {
|
||||
|
||||
title, content, taskOutput, errOutput := "", "", "", ""
|
||||
|
||||
notifyTpl, err := models.NotifyTplGetById(j.task.NotifyTplId)
|
||||
notifyTpl, err := models.NotifyTplGetById(j.Task.NotifyTplId)
|
||||
if err != nil {
|
||||
notifyTpl, err := models.NotifyTplGetByTplType(j.task.NotifyType, models.NotifyTplTypeSystem)
|
||||
notifyTpl, err := models.NotifyTplGetByTplType(j.Task.NotifyType, models.NotifyTplTypeSystem)
|
||||
if err == nil {
|
||||
title = notifyTpl.Title
|
||||
content = notifyTpl.Content
|
||||
@@ -450,10 +699,10 @@ func (j *Job) Run() {
|
||||
errOutput = strings.Replace(errOutput, "\"", "\\\"", -1)
|
||||
|
||||
if title != "" {
|
||||
title = strings.Replace(title, "{{TaskId}}", strconv.Itoa(j.task.Id), -1)
|
||||
title = strings.Replace(title, "{{ServerId}}", strconv.Itoa(j.serverId), -1)
|
||||
title = strings.Replace(title, "{{TaskName}}", j.task.TaskName, -1)
|
||||
title = strings.Replace(title, "{{ExecuteCommand}}", j.task.Command, -1)
|
||||
title = strings.Replace(title, "{{TaskId}}", strconv.Itoa(j.Task.Id), -1)
|
||||
title = strings.Replace(title, "{{ServerId}}", strconv.Itoa(j.ServerId), -1)
|
||||
title = strings.Replace(title, "{{TaskName}}", j.Task.TaskName, -1)
|
||||
title = strings.Replace(title, "{{ExecuteCommand}}", j.Task.Command, -1)
|
||||
title = strings.Replace(title, "{{ExecuteTime}}", beego.Date(time.Unix(log.CreateTime, 0), "Y-m-d H:i:s"), -1)
|
||||
title = strings.Replace(title, "{{ProcessTime}}", strconv.FormatFloat(float64(log.ProcessTime)/1000, 'f', 6, 64), -1)
|
||||
title = strings.Replace(title, "{{ExecuteStatus}}", TextStatus[status], -1)
|
||||
@@ -462,10 +711,10 @@ func (j *Job) Run() {
|
||||
}
|
||||
|
||||
if content != "" {
|
||||
content = strings.Replace(content, "{{TaskId}}", strconv.Itoa(j.task.Id), -1)
|
||||
content = strings.Replace(content, "{{ServerId}}", strconv.Itoa(j.serverId), -1)
|
||||
content = strings.Replace(content, "{{TaskName}}", j.task.TaskName, -1)
|
||||
content = strings.Replace(content, "{{ExecuteCommand}}", j.task.Command, -1)
|
||||
content = strings.Replace(content, "{{TaskId}}", strconv.Itoa(j.Task.Id), -1)
|
||||
content = strings.Replace(content, "{{ServerId}}", strconv.Itoa(j.ServerId), -1)
|
||||
content = strings.Replace(content, "{{TaskName}}", j.Task.TaskName, -1)
|
||||
content = strings.Replace(content, "{{ExecuteCommand}}", j.Task.Command, -1)
|
||||
content = strings.Replace(content, "{{ExecuteTime}}", beego.Date(time.Unix(log.CreateTime, 0), "Y-m-d H:i:s"), -1)
|
||||
content = strings.Replace(content, "{{ProcessTime}}", strconv.FormatFloat(float64(log.ProcessTime)/1000, 'f', 6, 64), -1)
|
||||
content = strings.Replace(content, "{{ExecuteStatus}}", TextStatus[status], -1)
|
||||
@@ -473,14 +722,14 @@ func (j *Job) Run() {
|
||||
content = strings.Replace(content, "{{ErrorOutput}}", errOutput, -1)
|
||||
}
|
||||
|
||||
if j.task.NotifyType == 0 && toEmail != "" {
|
||||
if j.Task.NotifyType == 0 && toEmail != "" {
|
||||
//邮件
|
||||
mailtype := "html"
|
||||
ok := notify.SendToChan(toEmail, title, content, mailtype)
|
||||
if !ok {
|
||||
fmt.Println("发送邮件错误", toEmail)
|
||||
}
|
||||
} else if j.task.NotifyType == 1 && len(phone) > 0 {
|
||||
} else if j.Task.NotifyType == 1 && len(phone) > 0 {
|
||||
//信息
|
||||
param := make(map[string]string)
|
||||
err := json.Unmarshal([]byte(content), ¶m)
|
||||
@@ -493,7 +742,7 @@ func (j *Job) Run() {
|
||||
if !ok {
|
||||
fmt.Println("发送信息错误", phone)
|
||||
}
|
||||
} else if j.task.NotifyType == 2 && len(dingtalk) > 0 {
|
||||
} else if j.Task.NotifyType == 2 && len(dingtalk) > 0 {
|
||||
//钉钉
|
||||
param := make(map[string]interface{})
|
||||
|
||||
@@ -507,7 +756,7 @@ func (j *Job) Run() {
|
||||
if !ok {
|
||||
fmt.Println("发送钉钉错误", dingtalk)
|
||||
}
|
||||
} else if j.task.NotifyType == 3 && len(wechat) > 0 {
|
||||
} else if j.Task.NotifyType == 3 && len(wechat) > 0 {
|
||||
//微信
|
||||
param := make(map[string]string)
|
||||
err := json.Unmarshal([]byte(content), ¶m)
|
||||
@@ -524,12 +773,12 @@ func (j *Job) Run() {
|
||||
}
|
||||
}
|
||||
|
||||
j.logId, _ = models.TaskLogAdd(log)
|
||||
j.LogId, _ = models.TaskLogAdd(log)
|
||||
|
||||
// 更新上次执行时间
|
||||
j.task.PrevTime = t.Unix()
|
||||
j.task.ExecuteTimes++
|
||||
j.task.Update("PrevTime", "ExecuteTimes")
|
||||
j.Task.PrevTime = t.Unix()
|
||||
j.Task.ExecuteTimes++
|
||||
j.Task.Update("PrevTime", "ExecuteTimes")
|
||||
}
|
||||
|
||||
//冗余代码
|
||||
@@ -572,16 +821,3 @@ func AllAdminInfo(adminIds string) []*adminInfo {
|
||||
|
||||
return adminInfos
|
||||
}
|
||||
|
||||
func gbkAsUtf8(str string) string {
|
||||
srcDecoder := mahonia.NewDecoder("gbk")
|
||||
desDecoder := mahonia.NewDecoder("utf-8")
|
||||
resStr := srcDecoder.ConvertString(str)
|
||||
_, resBytes, _ := desDecoder.Translate([]byte(resStr), true)
|
||||
return string(resBytes)
|
||||
}
|
||||
|
||||
//任务识别码
|
||||
func jobKey(taskId, serverId int) int {
|
||||
return taskId*10000 + serverId
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user