支持多台服务器同时执行任务+优化页面
一个定时任务可以允许多台服务器同时执行任务,优化页面关闭并刷新列表页
This commit is contained in:
@@ -9,11 +9,11 @@ package controllers
|
||||
|
||||
import (
|
||||
"github.com/astaxie/beego"
|
||||
"github.com/axgle/mahonia"
|
||||
"github.com/george518/PPGo_Job/libs"
|
||||
"github.com/george518/PPGo_Job/models"
|
||||
"strconv"
|
||||
"strings"
|
||||
"github.com/axgle/mahonia"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -361,4 +361,9 @@ func gbkAsUtf8(str string) string {
|
||||
resStr := srcDecoder.ConvertString(str)
|
||||
_, resBytes, _ := desDecoder.Translate([]byte(resStr), true)
|
||||
return string(resBytes)
|
||||
}
|
||||
}
|
||||
|
||||
//任务识别码
|
||||
func jobKey(taskId, serverId int) int {
|
||||
return taskId*10000 + serverId
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
@@ -78,6 +79,15 @@ func (self *TaskController) Edit() {
|
||||
|
||||
self.Data["notify_user_ids"] = notifyUserIds
|
||||
|
||||
server_ids := strings.Split(task.ServerIds, ",")
|
||||
var server_ids_arr []int
|
||||
for _, sv := range server_ids {
|
||||
i, _ := strconv.Atoi(sv)
|
||||
server_ids_arr = append(server_ids_arr, i)
|
||||
}
|
||||
|
||||
self.Data["service_ids"] = server_ids_arr
|
||||
|
||||
notifyTplList, _, err := models.NotifyTplGetByTplTypeList(task.NotifyType)
|
||||
tplList := make([]map[string]interface{}, len(notifyTplList))
|
||||
|
||||
@@ -145,13 +155,28 @@ func (self *TaskController) Detail() {
|
||||
// 分组列表
|
||||
self.Data["taskGroup"] = taskGroupLists(self.taskGroups, self.userId)
|
||||
|
||||
serverName := "本地服务器"
|
||||
if task.ServerId == 0 {
|
||||
serverName := ""
|
||||
if task.ServerIds == "0" {
|
||||
serverName = "本地服务器"
|
||||
} else {
|
||||
server, err := models.TaskServerGetById(task.ServerId)
|
||||
if err == nil {
|
||||
serverName = server.ServerName
|
||||
serverIdSli := strings.Split(task.ServerIds, ",")
|
||||
for _, v := range serverIdSli {
|
||||
if v == "0" {
|
||||
serverName = "本地服务器 "
|
||||
}
|
||||
}
|
||||
servers, n := models.TaskServerGetByIds(task.ServerIds)
|
||||
if n > 0 {
|
||||
for _, server := range servers {
|
||||
fmt.Println(server.Status)
|
||||
if server.Status != 0 {
|
||||
serverName += server.ServerName + "【无效】 "
|
||||
} else {
|
||||
serverName += server.ServerName + " "
|
||||
}
|
||||
}
|
||||
} else {
|
||||
serverName += "服务器异常!!"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -212,7 +237,7 @@ func (self *TaskController) AjaxSave() {
|
||||
task.TaskName = strings.TrimSpace(self.GetString("task_name"))
|
||||
task.Description = strings.TrimSpace(self.GetString("description"))
|
||||
task.Concurrent, _ = self.GetInt("concurrent")
|
||||
task.ServerId, _ = self.GetInt("server_id")
|
||||
task.ServerIds = strings.TrimSpace(self.GetString("server_ids"))
|
||||
task.CronSpec = strings.TrimSpace(self.GetString("cron_spec"))
|
||||
task.Command = strings.TrimSpace(self.GetString("command"))
|
||||
task.Timeout, _ = self.GetInt("timeout")
|
||||
@@ -258,7 +283,7 @@ func (self *TaskController) AjaxSave() {
|
||||
task.Description = strings.TrimSpace(self.GetString("description"))
|
||||
task.GroupId, _ = self.GetInt("group_id")
|
||||
task.Concurrent, _ = self.GetInt("concurrent")
|
||||
task.ServerId, _ = self.GetInt("server_id")
|
||||
task.ServerIds = strings.TrimSpace(self.GetString("server_ids"))
|
||||
task.CronSpec = strings.TrimSpace(self.GetString("cron_spec"))
|
||||
task.Command = strings.TrimSpace(self.GetString("command"))
|
||||
task.Timeout, _ = self.GetInt("timeout")
|
||||
@@ -291,8 +316,6 @@ func (self *TaskController) AjaxSave() {
|
||||
self.ajaxMsg("", MSG_OK)
|
||||
}
|
||||
|
||||
|
||||
|
||||
//检查是否含有禁用命令
|
||||
func checkCommand(command string) (string, bool) {
|
||||
|
||||
@@ -332,8 +355,6 @@ func (self *TaskController) AjaxNopass() {
|
||||
self.ajaxMsg("", MSG_OK)
|
||||
}
|
||||
|
||||
|
||||
|
||||
func (self *TaskController) AjaxStart() {
|
||||
taskId, _ := self.GetInt("id")
|
||||
if taskId == 0 {
|
||||
@@ -349,15 +370,19 @@ func (self *TaskController) AjaxStart() {
|
||||
self.ajaxMsg("任务状态有误", MSG_ERR)
|
||||
}
|
||||
|
||||
job, err := jobs.NewJobFromTask(task)
|
||||
jobArr, err := jobs.NewJobFromTask(task)
|
||||
|
||||
if err != nil {
|
||||
self.ajaxMsg("创建任务失败", MSG_ERR)
|
||||
}
|
||||
|
||||
if jobs.AddJob(task.CronSpec, job) {
|
||||
task.Status = 1
|
||||
task.Update()
|
||||
for _, job := range jobArr {
|
||||
if jobs.AddJob(task.CronSpec, job) {
|
||||
task.Status = 1
|
||||
task.Update()
|
||||
}
|
||||
}
|
||||
|
||||
self.ajaxMsg("", MSG_OK)
|
||||
}
|
||||
|
||||
@@ -372,9 +397,18 @@ func (self *TaskController) AjaxPause() {
|
||||
self.ajaxMsg("查不到该任务", MSG_ERR)
|
||||
}
|
||||
|
||||
jobs.RemoveJob(taskId)
|
||||
//移出任务
|
||||
TaskServerIdsArr := strings.Split(task.ServerIds, ",")
|
||||
|
||||
for _, server_id := range TaskServerIdsArr {
|
||||
server_id_int, _ := strconv.Atoi(server_id)
|
||||
jobKey := jobKey(task.Id, server_id_int)
|
||||
jobs.RemoveJob(jobKey)
|
||||
}
|
||||
|
||||
task.Status = 0
|
||||
task.Update()
|
||||
|
||||
self.ajaxMsg("", MSG_OK)
|
||||
|
||||
}
|
||||
@@ -387,11 +421,14 @@ func (self *TaskController) AjaxRun() {
|
||||
self.ajaxMsg(err.Error(), MSG_ERR)
|
||||
}
|
||||
|
||||
job, err := jobs.NewJobFromTask(task)
|
||||
jobArr, err := jobs.NewJobFromTask(task)
|
||||
if err != nil {
|
||||
self.ajaxMsg(err.Error(), MSG_ERR)
|
||||
}
|
||||
job.Run()
|
||||
for _, job := range jobArr {
|
||||
job.Run()
|
||||
}
|
||||
|
||||
self.ajaxMsg("", MSG_OK)
|
||||
}
|
||||
|
||||
@@ -408,9 +445,12 @@ func (self *TaskController) AjaxBatchStart() {
|
||||
}
|
||||
|
||||
if task, err := models.TaskGetById(id); err == nil {
|
||||
job, err := jobs.NewJobFromTask(task)
|
||||
jobArr, err := jobs.NewJobFromTask(task)
|
||||
if err == nil {
|
||||
jobs.AddJob(task.CronSpec, job)
|
||||
for _, job := range jobArr {
|
||||
jobs.AddJob(task.CronSpec, job)
|
||||
}
|
||||
|
||||
task.Status = 1
|
||||
task.Update()
|
||||
}
|
||||
@@ -430,9 +470,17 @@ func (self *TaskController) AjaxBatchPause() {
|
||||
if id < 1 {
|
||||
continue
|
||||
}
|
||||
jobs.RemoveJob(id)
|
||||
|
||||
if task, err := models.TaskGetById(id); err == nil {
|
||||
task, err := models.TaskGetById(id)
|
||||
//移出任务
|
||||
TaskServerIdsArr := strings.Split(task.ServerIds, ",")
|
||||
|
||||
for _, server_id := range TaskServerIdsArr {
|
||||
server_id_int, _ := strconv.Atoi(server_id)
|
||||
jobKey := jobKey(task.Id, server_id_int)
|
||||
jobs.RemoveJob(jobKey)
|
||||
}
|
||||
if err == nil {
|
||||
task.Status = 0
|
||||
task.Update()
|
||||
}
|
||||
@@ -451,9 +499,19 @@ func (self *TaskController) AjaxBatchDel() {
|
||||
if id < 1 {
|
||||
continue
|
||||
}
|
||||
|
||||
task, _ := models.TaskGetById(id)
|
||||
|
||||
//移出任务
|
||||
TaskServerIdsArr := strings.Split(task.ServerIds, ",")
|
||||
|
||||
for _, server_id := range TaskServerIdsArr {
|
||||
server_id_int, _ := strconv.Atoi(server_id)
|
||||
jobKey := jobKey(task.Id, server_id_int)
|
||||
jobs.RemoveJob(jobKey)
|
||||
}
|
||||
models.TaskDel(id)
|
||||
models.TaskLogDelByTaskId(id)
|
||||
jobs.RemoveJob(id)
|
||||
}
|
||||
self.ajaxMsg("", MSG_OK)
|
||||
}
|
||||
@@ -661,12 +719,12 @@ func (self *TaskController) ApiTask() {
|
||||
task_id, _ := self.GetInt("id")
|
||||
if task_id == 0 {
|
||||
task := new(models.Task)
|
||||
task.CreateId,_ = self.GetInt("create_id")
|
||||
task.CreateId, _ = self.GetInt("create_id")
|
||||
task.GroupId, _ = self.GetInt("group_id")
|
||||
task.TaskName = strings.TrimSpace(self.GetString("task_name"))
|
||||
task.Description = strings.TrimSpace(self.GetString("description"))
|
||||
task.Concurrent, _ = self.GetInt("concurrent")
|
||||
task.ServerId, _ = self.GetInt("server_id")
|
||||
task.ServerIds = strings.TrimSpace(self.GetString("server_ids"))
|
||||
task.CronSpec = strings.TrimSpace(self.GetString("cron_spec"))
|
||||
task.Command = strings.TrimSpace(self.GetString("command"))
|
||||
task.Timeout, _ = self.GetInt("timeout")
|
||||
@@ -716,7 +774,7 @@ func (self *TaskController) ApiTask() {
|
||||
task.Description = strings.TrimSpace(self.GetString("description"))
|
||||
task.GroupId, _ = self.GetInt("group_id")
|
||||
task.Concurrent, _ = self.GetInt("concurrent")
|
||||
task.ServerId, _ = self.GetInt("server_id")
|
||||
task.ServerIds = strings.TrimSpace(self.GetString("server_ids"))
|
||||
task.CronSpec = strings.TrimSpace(self.GetString("cron_spec"))
|
||||
task.Command = strings.TrimSpace(self.GetString("command"))
|
||||
task.Timeout, _ = self.GetInt("timeout")
|
||||
@@ -724,7 +782,7 @@ func (self *TaskController) ApiTask() {
|
||||
task.NotifyType, _ = self.GetInt("notify_type")
|
||||
task.NotifyTplId, _ = self.GetInt("notify_tpl_id")
|
||||
task.NotifyUserIds = strings.TrimSpace(self.GetString("notify_user_ids"))
|
||||
task.UpdateId , _ = self.GetInt("update_id")
|
||||
task.UpdateId, _ = self.GetInt("update_id")
|
||||
task.Status = 0 //接口不需要
|
||||
|
||||
if task.IsNotify == 1 && task.NotifyTplId <= 0 {
|
||||
@@ -761,15 +819,18 @@ func (self *TaskController) ApiStart() {
|
||||
self.ajaxMsg("任务状态有误", MSG_ERR)
|
||||
}
|
||||
|
||||
job, err := jobs.NewJobFromTask(task)
|
||||
jobArr, err := jobs.NewJobFromTask(task)
|
||||
if err != nil {
|
||||
self.ajaxMsg("创建任务失败", MSG_ERR)
|
||||
}
|
||||
|
||||
if jobs.AddJob(task.CronSpec, job) {
|
||||
task.Status = 1
|
||||
task.Update()
|
||||
for _, job := range jobArr {
|
||||
if jobs.AddJob(task.CronSpec, job) {
|
||||
task.Status = 1
|
||||
task.Update()
|
||||
}
|
||||
}
|
||||
|
||||
self.ajaxMsg("", MSG_OK)
|
||||
}
|
||||
|
||||
@@ -784,11 +845,17 @@ func (self *TaskController) ApiPause() {
|
||||
self.ajaxMsg("查不到该任务", MSG_ERR)
|
||||
}
|
||||
|
||||
jobs.RemoveJob(taskId)
|
||||
//移出任务
|
||||
TaskServerIdsArr := strings.Split(task.ServerIds, ",")
|
||||
|
||||
for _, server_id := range TaskServerIdsArr {
|
||||
server_id_int, _ := strconv.Atoi(server_id)
|
||||
jobKey := jobKey(task.Id, server_id_int)
|
||||
jobs.RemoveJob(jobKey)
|
||||
}
|
||||
|
||||
task.Status = 0
|
||||
task.Update()
|
||||
self.ajaxMsg("", MSG_OK)
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/astaxie/beego"
|
||||
"github.com/george518/PPGo_Job/libs"
|
||||
"github.com/george518/PPGo_Job/models"
|
||||
@@ -74,9 +75,12 @@ func (self *TaskLogController) Table() {
|
||||
for k, v := range result {
|
||||
row := make(map[string]interface{})
|
||||
row["id"] = v.Id
|
||||
row["task_id"] = v.TaskId
|
||||
row["task_id"] = jobKey(v.TaskId, v.ServerId)
|
||||
row["start_time"] = beego.Date(time.Unix(v.CreateTime, 0), "Y-m-d H:i:s")
|
||||
row["process_time"] = float64(v.ProcessTime) / 1000
|
||||
|
||||
row["server_id"] = v.ServerId
|
||||
row["server_name"] = v.ServerName + "#" + strconv.Itoa(v.ServerId)
|
||||
if v.Status == 0 {
|
||||
row["output_size"] = libs.SizeFormat(float64(len(v.Output)))
|
||||
} else {
|
||||
@@ -99,6 +103,8 @@ func (self *TaskLogController) Detail() {
|
||||
//日志内容
|
||||
id, _ := self.GetInt("id")
|
||||
tasklog, err := models.TaskLogGetById(id)
|
||||
|
||||
fmt.Println(tasklog)
|
||||
if err != nil {
|
||||
self.Ctx.WriteString("日志不存在")
|
||||
return
|
||||
@@ -119,6 +125,8 @@ func (self *TaskLogController) Detail() {
|
||||
row["output_size"] = libs.SizeFormat(float64(len(tasklog.Error)))
|
||||
}
|
||||
|
||||
row["server_name"] = tasklog.ServerName
|
||||
|
||||
row["output"] = tasklog.Output
|
||||
row["error"] = tasklog.Error
|
||||
|
||||
@@ -149,15 +157,31 @@ func (self *TaskLogController) Detail() {
|
||||
// 分组列表
|
||||
self.Data["taskGroup"] = taskGroupLists(self.taskGroups, self.userId)
|
||||
|
||||
serverName := "本地服务器"
|
||||
if task.ServerId == 0 {
|
||||
serverName := ""
|
||||
if task.ServerIds == "0" {
|
||||
serverName = "本地服务器"
|
||||
} else {
|
||||
server, err := models.TaskServerGetById(task.ServerId)
|
||||
if err == nil {
|
||||
serverName = server.ServerName
|
||||
|
||||
serverIdSli := strings.Split(task.ServerIds, ",")
|
||||
for _, v := range serverIdSli {
|
||||
if v == "0" {
|
||||
serverName = "本地服务器 "
|
||||
}
|
||||
}
|
||||
servers, n := models.TaskServerGetByIds(task.ServerIds)
|
||||
if n > 0 {
|
||||
for _, server := range servers {
|
||||
if server.Status != 0 {
|
||||
serverName += server.ServerName + "【无效】 "
|
||||
} else {
|
||||
serverName += server.ServerName + " "
|
||||
}
|
||||
}
|
||||
} else {
|
||||
serverName = "服务器异常!! "
|
||||
}
|
||||
}
|
||||
|
||||
self.Data["serverName"] = serverName
|
||||
|
||||
//任务分组
|
||||
|
||||
11
jobs/cron.go
11
jobs/cron.go
@@ -32,7 +32,7 @@ func AddJob(spec string, job *Job) bool {
|
||||
lock.Lock()
|
||||
defer lock.Unlock()
|
||||
|
||||
if GetEntryById(job.id) != nil {
|
||||
if GetEntryById(job.jobKey) != nil {
|
||||
return false
|
||||
}
|
||||
err := mainCron.AddJob(spec, job)
|
||||
@@ -40,13 +40,14 @@ func AddJob(spec string, job *Job) bool {
|
||||
beego.Error("AddJob: ", err.Error())
|
||||
return false
|
||||
}
|
||||
//fmt.Println(job)
|
||||
return true
|
||||
}
|
||||
|
||||
func RemoveJob(id int) {
|
||||
func RemoveJob(jobKey int) {
|
||||
mainCron.RemoveJob(func(e *cron.Entry) bool {
|
||||
if v, ok := e.Job.(*Job); ok {
|
||||
if v.id == id {
|
||||
if v.jobKey == jobKey {
|
||||
return true
|
||||
}
|
||||
}
|
||||
@@ -54,11 +55,11 @@ func RemoveJob(id int) {
|
||||
})
|
||||
}
|
||||
|
||||
func GetEntryById(id int) *cron.Entry {
|
||||
func GetEntryById(jobKey int) *cron.Entry {
|
||||
entries := mainCron.Entries()
|
||||
for _, e := range entries {
|
||||
if v, ok := e.Job.(*Job); ok {
|
||||
if v.id == id {
|
||||
if v.jobKey == jobKey {
|
||||
return e
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,12 +18,16 @@ import (
|
||||
func InitJobs() {
|
||||
list, _ := models.TaskGetList(1, 1000000, "status", 1)
|
||||
for _, task := range list {
|
||||
job, err := NewJobFromTask(task)
|
||||
jobs, err := NewJobFromTask(task)
|
||||
if err != nil {
|
||||
beego.Error("InitJobs:", err.Error())
|
||||
continue
|
||||
}
|
||||
AddJob(task.CronSpec, job)
|
||||
|
||||
for _, job := range jobs {
|
||||
AddJob(task.CronSpec, job)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
133
jobs/job.go
133
jobs/job.go
@@ -20,19 +20,22 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"encoding/json"
|
||||
"github.com/astaxie/beego"
|
||||
"github.com/axgle/mahonia"
|
||||
"github.com/george518/PPGo_Job/models"
|
||||
"github.com/george518/PPGo_Job/notify"
|
||||
"golang.org/x/crypto/ssh"
|
||||
"encoding/json"
|
||||
"github.com/axgle/mahonia"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/linxiaozhi/go-telnet"
|
||||
"github.com/pkg/errors"
|
||||
"golang.org/x/crypto/ssh"
|
||||
)
|
||||
|
||||
type Job struct {
|
||||
id int // 任务ID
|
||||
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) // 执行函数
|
||||
@@ -40,51 +43,79 @@ type Job struct {
|
||||
Concurrent bool // 同一个任务是否允许并行执行
|
||||
}
|
||||
|
||||
func NewJobFromTask(task *models.Task) (*Job, error) {
|
||||
func NewJobFromTask(task *models.Task) ([]*Job, error) {
|
||||
if task.Id < 1 {
|
||||
return nil, fmt.Errorf("ToJob: 缺少id")
|
||||
}
|
||||
|
||||
//本地程序执行
|
||||
if task.ServerId == 0 {
|
||||
job := NewCommandJob(task.Id, task.TaskName, task.Command)
|
||||
job.task = task
|
||||
job.Concurrent = task.Concurrent == 1
|
||||
return job, nil
|
||||
if task.ServerIds == "" {
|
||||
return nil, fmt.Errorf("任务执行失败,找不到执行的服务器")
|
||||
}
|
||||
|
||||
server, _ := models.TaskServerGetById(task.ServerId)
|
||||
if server.ConnectionType == 0 {
|
||||
if server.Type == 0 {
|
||||
//密码验证登录服务器
|
||||
job := RemoteCommandJobByPassword(task.Id, task.TaskName, task.Command, server)
|
||||
job.task = task
|
||||
job.Concurrent = task.Concurrent == 1
|
||||
return job, nil
|
||||
}
|
||||
TaskServerIdsArr := strings.Split(task.ServerIds, ",")
|
||||
|
||||
job := RemoteCommandJob(task.Id, task.TaskName, task.Command, server)
|
||||
job.task = task
|
||||
job.Concurrent = task.Concurrent == 1
|
||||
return job, nil
|
||||
} else if server.ConnectionType == 1 {
|
||||
if server.Type == 0 {
|
||||
//密码验证登录服务器
|
||||
job := RemoteCommandJobByTelnetPassword(task.Id, task.TaskName, task.Command, server)
|
||||
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
|
||||
return job, nil
|
||||
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 {
|
||||
fmt.Println("服务器已禁用")
|
||||
continue
|
||||
}
|
||||
|
||||
if server.ConnectionType == 0 {
|
||||
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
|
||||
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
|
||||
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
|
||||
jobArr = append(jobArr, job)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("未知ConnectionType")
|
||||
return jobArr, nil
|
||||
}
|
||||
|
||||
func NewCommandJob(id int, name string, command string) *Job {
|
||||
func NewCommandJob(id int, serverId int, name string, command string) *Job {
|
||||
job := &Job{
|
||||
id: id,
|
||||
name: name,
|
||||
}
|
||||
|
||||
job.jobKey = jobKey(id, serverId)
|
||||
job.runFunc = func(timeout time.Duration) (string, string, error, bool) {
|
||||
bufOut := new(bytes.Buffer)
|
||||
bufErr := new(bytes.Buffer)
|
||||
@@ -106,11 +137,15 @@ func NewCommandJob(id int, name string, command string) *Job {
|
||||
}
|
||||
|
||||
//远程执行任务 密钥验证
|
||||
func RemoteCommandJob(id int, name string, command string, servers *models.TaskServer) *Job {
|
||||
func RemoteCommandJob(id int, serverId int, name string, command string, servers *models.TaskServer) *Job {
|
||||
job := &Job{
|
||||
id: id,
|
||||
name: name,
|
||||
id: id,
|
||||
name: name,
|
||||
serverId: serverId,
|
||||
}
|
||||
|
||||
job.jobKey = jobKey(id, serverId)
|
||||
|
||||
job.runFunc = func(timeout time.Duration) (string, string, error, bool) {
|
||||
|
||||
key, err := ioutil.ReadFile(servers.PrivateKeySrc)
|
||||
@@ -166,7 +201,7 @@ func RemoteCommandJob(id int, name string, command string, servers *models.TaskS
|
||||
return job
|
||||
}
|
||||
|
||||
func RemoteCommandJobByPassword(id int, name string, command string, servers *models.TaskServer) *Job {
|
||||
func RemoteCommandJobByPassword(id int, serverId int, name string, command string, servers *models.TaskServer) *Job {
|
||||
var (
|
||||
auth []ssh.AuthMethod
|
||||
addr string
|
||||
@@ -177,9 +212,11 @@ func RemoteCommandJobByPassword(id int, name string, command string, servers *mo
|
||||
)
|
||||
|
||||
job := &Job{
|
||||
id: id,
|
||||
name: name,
|
||||
id: id,
|
||||
name: name,
|
||||
serverId: serverId,
|
||||
}
|
||||
job.jobKey = jobKey(id, serverId)
|
||||
job.runFunc = func(timeout time.Duration) (string, string, error, bool) {
|
||||
// get auth method
|
||||
auth = make([]ssh.AuthMethod, 0)
|
||||
@@ -223,12 +260,15 @@ func RemoteCommandJobByPassword(id int, name string, command string, servers *mo
|
||||
return job
|
||||
}
|
||||
|
||||
func RemoteCommandJobByTelnetPassword(id int, name string, command string, servers *models.TaskServer) *Job {
|
||||
func RemoteCommandJobByTelnetPassword(id int, serverId int, name string, command string, servers *models.TaskServer) *Job {
|
||||
|
||||
job := &Job{
|
||||
id: id,
|
||||
name: name,
|
||||
id: id,
|
||||
name: name,
|
||||
serverId: serverId,
|
||||
}
|
||||
|
||||
job.jobKey = jobKey(id, serverId)
|
||||
job.runFunc = func(timeout time.Duration) (string, string, error, bool) {
|
||||
|
||||
addr := fmt.Sprintf("%s:%d", servers.ServerIp, servers.Port)
|
||||
@@ -309,7 +349,7 @@ func (j *Job) GetLogId() int64 {
|
||||
|
||||
func (j *Job) Run() {
|
||||
if !j.Concurrent && j.status > 0 {
|
||||
beego.Warn(fmt.Sprintf("任务[%d]上一次执行尚未结束,本次被忽略。", j.id))
|
||||
beego.Warn(fmt.Sprintf("任务[%d]上一次执行尚未结束,本次被忽略。", j.jobKey))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -326,7 +366,7 @@ func (j *Job) Run() {
|
||||
}()
|
||||
}
|
||||
|
||||
beego.Debug(fmt.Sprintf("开始执行任务: %d", j.id))
|
||||
beego.Debug(fmt.Sprintf("开始执行任务: %d", j.jobKey))
|
||||
|
||||
j.status++
|
||||
defer func() {
|
||||
@@ -344,6 +384,8 @@ func (j *Job) Run() {
|
||||
// 插入日志
|
||||
log := new(models.TaskLog)
|
||||
log.TaskId = j.id
|
||||
log.ServerId = j.serverId
|
||||
log.ServerName = j.serverName
|
||||
log.Output = cmdOut
|
||||
log.Error = cmdErr
|
||||
log.ProcessTime = int(ut)
|
||||
@@ -536,3 +578,8 @@ func gbkAsUtf8(str string) string {
|
||||
_, resBytes, _ := desDecoder.Translate([]byte(resStr), true)
|
||||
return string(resBytes)
|
||||
}
|
||||
|
||||
//任务识别码
|
||||
func jobKey(taskId, serverId int) int {
|
||||
return taskId*10000 + serverId
|
||||
}
|
||||
|
||||
@@ -9,6 +9,8 @@ package models
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/astaxie/beego/orm"
|
||||
)
|
||||
@@ -95,6 +97,22 @@ func TaskServerGetById(id int) (*TaskServer, error) {
|
||||
return obj, nil
|
||||
}
|
||||
|
||||
//
|
||||
func TaskServerGetByIds(ids string) ([]*TaskServer, int64) {
|
||||
|
||||
serverFilters := make([]interface{}, 0)
|
||||
//serverFilters = append(serverFilters, "status", 1)
|
||||
|
||||
TaskServerIdsArr := strings.Split(ids, ",")
|
||||
TaskServerIds := make([]int, 0)
|
||||
for _, v := range TaskServerIdsArr {
|
||||
id, _ := strconv.Atoi(v)
|
||||
TaskServerIds = append(TaskServerIds, id)
|
||||
}
|
||||
serverFilters = append(serverFilters, "id__in", TaskServerIds)
|
||||
return TaskServerGetList(1, 1000, serverFilters...)
|
||||
}
|
||||
|
||||
func TaskServerDelById(id int) error {
|
||||
_, err := orm.NewOrm().QueryTable(TableName("task_server")).Filter("id", id).Delete()
|
||||
return err
|
||||
|
||||
@@ -23,7 +23,7 @@ const (
|
||||
type Task struct {
|
||||
Id int
|
||||
GroupId int
|
||||
ServerId int
|
||||
ServerIds string
|
||||
TaskName string
|
||||
Description string
|
||||
CronSpec string
|
||||
|
||||
@@ -14,6 +14,8 @@ import (
|
||||
type TaskLog struct {
|
||||
Id int
|
||||
TaskId int
|
||||
ServerId int
|
||||
ServerName string
|
||||
Output string
|
||||
Error string
|
||||
Status int
|
||||
|
||||
@@ -330,4 +330,13 @@ BEGIN;
|
||||
ALTER TABLE `pp_task_server` ADD `connection_type` TINYINT(1) NOT NULL DEFAULT '0' COMMENT '连接类型 0:SSH;1:Telnet;' AFTER `group_id`;
|
||||
COMMIT;
|
||||
|
||||
BEGIN;
|
||||
ALTER TABLE `ppgo_job2`.`pp_task` CHANGE COLUMN `server_id` `server_ids` varchar(200) NOT NULL DEFAULT '0' COMMENT '服务器id字符串,英文都好隔开';
|
||||
BEGIN;
|
||||
|
||||
BEGIN;
|
||||
ALTER TABLE `ppgo_job2`.`pp_task_log` ADD COLUMN `server_id` int(11) NOT NULL DEFAULT '-1' COMMENT '服务器ID,-1,异常' AFTER `task_id`, CHANGE COLUMN `output` `output` mediumtext NOT NULL COMMENT '任务输出' AFTER `server_id`, CHANGE COLUMN `error` `error` text NOT NULL COMMENT '错误信息' AFTER `output`, CHANGE COLUMN `status` `status` tinyint(4) NOT NULL COMMENT '状态' AFTER `error`, CHANGE COLUMN `process_time` `process_time` int(11) NOT NULL DEFAULT '0' COMMENT '消耗时间/毫秒' AFTER `status`, CHANGE COLUMN `create_time` `create_time` int(11) UNSIGNED NOT NULL DEFAULT '0' COMMENT '创建时间' AFTER `process_time`;
|
||||
ALTER TABLE `ppgo_job2`.`pp_task_log` ADD COLUMN `server_name` varchar(60) NOT NULL DEFAULT '\"\"' COMMENT '服务器名称' AFTER `server_id`, CHANGE COLUMN `output` `output` mediumtext NOT NULL COMMENT '任务输出' AFTER `server_name`, CHANGE COLUMN `error` `error` text NOT NULL COMMENT '错误信息' AFTER `output`, CHANGE COLUMN `status` `status` tinyint(4) NOT NULL COMMENT '状态' AFTER `error`, CHANGE COLUMN `process_time` `process_time` int(11) NOT NULL DEFAULT '0' COMMENT '消耗时间/毫秒' AFTER `status`, CHANGE COLUMN `create_time` `create_time` int(11) UNSIGNED NOT NULL DEFAULT '0' COMMENT '创建时间' AFTER `process_time`;
|
||||
BEGIN;
|
||||
|
||||
SET FOREIGN_KEY_CHECKS = 1;
|
||||
|
||||
@@ -106,7 +106,7 @@ var $;
|
||||
$.post('{{urlfor "AdminController.AjaxSave"}}', form_data, function (out) {
|
||||
if (out.status == 0) {
|
||||
layer.msg("操作成功",{icon: 1,shade:0.3,time:1000},function () {
|
||||
window.location.reload()
|
||||
window.parent.deleteCurrentTab();
|
||||
})
|
||||
} else {
|
||||
layer.msg(out.message)
|
||||
|
||||
@@ -113,7 +113,7 @@ var $;
|
||||
$.post('{{urlfor "AdminController.AjaxSave"}}', form_data, function (out) {
|
||||
if (out.status == 0) {
|
||||
layer.msg("操作成功",{icon: 1,shade:0.3,time:1000},function () {
|
||||
window.location.reload()
|
||||
window.parent.deleteCurrentTab();
|
||||
})
|
||||
} else {
|
||||
layer.msg(out.message)
|
||||
|
||||
@@ -89,8 +89,7 @@
|
||||
$.post('{{urlfor "NotifyTplController.AjaxSave"}}', form_data, function (out) {
|
||||
if (out.status == 0) {
|
||||
layer.msg("操作成功", {icon: 1, shade: 0.3, time: 1000}, function () {
|
||||
// window.history.go(-1)//
|
||||
window.location.reload()
|
||||
window.parent.deleteCurrentTab();
|
||||
})
|
||||
} else {
|
||||
layer.msg(out.message)
|
||||
|
||||
@@ -89,8 +89,7 @@
|
||||
$.post('{{urlfor "NotifyTplController.AjaxSave"}}', form_data, function (out) {
|
||||
if (out.status == 0) {
|
||||
layer.msg("操作成功", {icon: 1, shade: 0.3, time: 1000}, function () {
|
||||
// window.history.go(-1)
|
||||
window.location.reload()
|
||||
window.parent.deleteCurrentTab();
|
||||
})
|
||||
} else {
|
||||
layer.msg(out.message)
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
{{.pageTitle}}
|
||||
</div>
|
||||
<div class="tr fr">
|
||||
<button class="layui-btn layui-btn-radius layui-btn-primary layui-btn-xs" onclick="javascript:window.location.reload();"><i class="fa fa-refresh" aria-hidden="true"></i></button>
|
||||
<button class="layui-btn layui-btn-radius layui-btn-primary layui-btn-xs" onclick="javascript:window.location.reload();"><i class="fa fa-refresh" aria-hidden="true" id="reload"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 公共头部 end-->
|
||||
|
||||
@@ -106,6 +106,29 @@
|
||||
return str;
|
||||
}
|
||||
|
||||
//新页面编辑或者新增,完成后关闭本页并刷新上一页
|
||||
function deleteCurrentTab(){
|
||||
//关闭
|
||||
var lay_id = $(parent.document).find("ul.layui-tab-title").children("li.layui-this").find(".layui-tab-close");
|
||||
lay_id.click();
|
||||
|
||||
//刷新
|
||||
var currents =$(parent.document).find("div.layui-tab-content").find("div.layui-show").find("iframe").contents();
|
||||
$(currents[0]).find("body").find("#reload").click();
|
||||
}
|
||||
|
||||
function getCheckboxValue(name)
|
||||
{
|
||||
var arr = new Array();
|
||||
$("input:checkbox[name="+name+"]:checked").each(function(){
|
||||
console.log($(this).val());
|
||||
arr.push($(this).val());
|
||||
});
|
||||
|
||||
return arr.join(",");
|
||||
}
|
||||
|
||||
|
||||
function openTab(url,title,id,icon){
|
||||
|
||||
if (!url || !title || !id) {
|
||||
@@ -235,6 +258,9 @@
|
||||
layer.tips($(this).attr('data-title'), $(this),{time:1000});
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
element.render();
|
||||
// $("#default_tab").html('<i class="fa fa-home back_space1"></i>系统首页');
|
||||
|
||||
|
||||
@@ -156,7 +156,7 @@
|
||||
if (out.status == 0) {
|
||||
layer.msg("操作成功",{icon: 1,shade:0.3,time:1000},function () {
|
||||
// window.history.go(-1)//
|
||||
window.location.reload()
|
||||
window.parent.deleteCurrentTab();
|
||||
})
|
||||
} else {
|
||||
layer.msg(out.message)
|
||||
|
||||
@@ -154,7 +154,7 @@
|
||||
if (out.status == 0) {
|
||||
layer.msg("操作成功",{icon: 1,shade:0.3,time:1000},function () {
|
||||
//window.location.href = "/server/list"
|
||||
windwo.location.reload();
|
||||
window.parent.deleteCurrentTab();
|
||||
})
|
||||
} else {
|
||||
layer.msg(out.message)
|
||||
|
||||
@@ -155,7 +155,9 @@
|
||||
if (out.status == 0) {
|
||||
layer.msg("操作成功",{icon: 1,shade:0.3,time:1000},function () {
|
||||
// window.history.go(-1)
|
||||
window.location.reload()
|
||||
// window.location.reload()
|
||||
|
||||
window.parent.deleteCurrentTab();
|
||||
})
|
||||
} else {
|
||||
layer.msg(out.message)
|
||||
|
||||
@@ -27,19 +27,22 @@
|
||||
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label mw200">服务器资源</label>
|
||||
<div class="layui-inline">
|
||||
|
||||
<div class="layui-input-inline">
|
||||
<select name="server_id">
|
||||
<option value="0">本地服务器</option>
|
||||
{{range $k, $v := .serverGroup}}
|
||||
<optgroup label="{{$v.GroupName}}">
|
||||
{{range $kk, $vv := $v.Servers}}
|
||||
<option value="{{$kk}}">{{$vv}}</option>
|
||||
<div class="layui-block">
|
||||
<div class="layui-col-md3"></div>
|
||||
<div class="layui-col-md9">
|
||||
<div style="margin-bottom: 20px;">
|
||||
<input type="checkbox" name="server_id" lay-skin="primary" title="本地服务器" value="0">
|
||||
</div>
|
||||
<div class="layui-row layui-col-space10">
|
||||
{{range $k, $v := .serverGroup}}
|
||||
<div class="layui-col-md12" style="background: #efefef;">{{$v.GroupName}}</div>
|
||||
{{range $kk, $vv := $v.Servers}}
|
||||
<div class="layui-col-md4">
|
||||
<input type="checkbox" name="server_id" lay-skin="primary" title="{{$vv}}" value="{{$kk}}">
|
||||
</div>
|
||||
{{end}}
|
||||
{{end}}
|
||||
</optgroup>
|
||||
{{end}}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -129,7 +132,7 @@
|
||||
<input type="checkbox" name="notify_user" lay-filter="notify_user" title="{{$v.RealName}}"
|
||||
value="{{$v.Id}}" lay-skin="primary">
|
||||
{{end}}
|
||||
<input type="hidden" name="notify_user_ids" id="notify_user_ids" value="">
|
||||
|
||||
</div>
|
||||
<div class="layui-form-mid layui-word-aux"></div>
|
||||
</div>
|
||||
@@ -159,7 +162,7 @@
|
||||
layer.tips('设为“是”的话,如果该任务在上一个时间点还没执行完,则略过不执行', '#des', {
|
||||
tips: [1, '#0FA6D8'] //还可配置颜色
|
||||
});
|
||||
})
|
||||
});
|
||||
|
||||
|
||||
var notify_user_ids = [];
|
||||
@@ -176,6 +179,7 @@
|
||||
}
|
||||
$("#notify_user_ids").val(notify_user_ids.join(","));
|
||||
});
|
||||
|
||||
form.on('radio(is_notify)', function (data) {
|
||||
if (data.value == 1) {
|
||||
$(".notify").show()
|
||||
@@ -185,12 +189,36 @@
|
||||
});
|
||||
|
||||
form.on('submit(sub)', function (data) {
|
||||
|
||||
var form_data = data.field;
|
||||
var server_arr = new Array();
|
||||
$("input:checkbox[name=server_id]:checked").each(function(){
|
||||
server_arr.push($(this).val());
|
||||
});
|
||||
|
||||
form_data.server_ids = server_arr.join(",");
|
||||
|
||||
if (form_data.server_ids==="" || form_data.server_ids===null){
|
||||
layer.msg("请选择服务器资源");
|
||||
return false;
|
||||
}
|
||||
|
||||
var notify_user_arr = new Array();
|
||||
$("input:checkbox[name=notify_user]:checked").each(function(){
|
||||
notify_user_arr.push($(this).val());
|
||||
});
|
||||
form_data.notify_user_ids = notify_user_arr.join(",");
|
||||
|
||||
if (form_data.is_notify==1 && form_data.notify_user_ids==="") {
|
||||
layer.msg("请选择通知用户");
|
||||
return false;
|
||||
}
|
||||
|
||||
$.post('{{urlfor "TaskController.AjaxSave"}}', form_data, function (out) {
|
||||
if (out.status == 0) {
|
||||
layer.msg("操作成功", {icon: 1, shade: 0.3, time: 1000}, function () {
|
||||
// window.history.go(-1)
|
||||
window.location.reload();
|
||||
window.parent.deleteCurrentTab();
|
||||
})
|
||||
|
||||
} else {
|
||||
|
||||
@@ -175,7 +175,7 @@
|
||||
if (out.status == 0) {
|
||||
layer.msg("复制成功!,请到列表中查看",{icon: 1,shade:0.3,time:1000},function () {
|
||||
//self.location=document.referrer;
|
||||
window.location.reload();
|
||||
window.parent.deleteCurrentTab();
|
||||
})
|
||||
} else {
|
||||
layer.msg(out.message)
|
||||
|
||||
@@ -26,20 +26,24 @@
|
||||
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label mw200">服务器资源</label>
|
||||
<div class="layui-inline">
|
||||
|
||||
<div class="layui-input-inline">
|
||||
<select name="server_id">
|
||||
<option value="0">本地服务器</option>
|
||||
{{range $k, $v := .serverGroup}}
|
||||
<optgroup label="{{$v.GroupName}}">
|
||||
{{range $kk, $vv := $v.Servers}}
|
||||
<option value="{{$kk}}" {{if eq $kk $.task.ServerId}}selected{{end}} >{{$vv}}</option>
|
||||
<div class="layui-block">
|
||||
<div class="layui-col-md3"></div>
|
||||
<div class="layui-col-md9">
|
||||
<div style="margin-bottom: 20px;">
|
||||
<input type="checkbox" name="server_id" lay-skin="primary" title="本地服务器" value="0" {{range $ks,$vs:=$.service_ids}} {{if eq 0 $vs}}checked{{end}}{{end}}>
|
||||
</div>
|
||||
<div class="layui-row layui-col-space10">
|
||||
{{range $k, $v := .serverGroup}}
|
||||
<div class="layui-col-md12" style="background: #efefef;">{{$v.GroupName}}</div>
|
||||
{{range $kk, $vv := $v.Servers}}
|
||||
<div class="layui-col-md4">
|
||||
<input type="checkbox" name="server_id" lay-skin="primary" title="{{$vv}}" value="{{$kk}}" {{range $ks,$vs:=$.service_ids}} {{if eq $kk $vs}}checked{{end}}{{end}}>
|
||||
</div>
|
||||
{{end}}
|
||||
{{end}}
|
||||
</optgroup>
|
||||
{{end}}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -182,6 +186,7 @@
|
||||
$("#notify_user_ids").val(notify_user_ids.join(","));
|
||||
});
|
||||
|
||||
|
||||
form.on('submit(sub)', function(data){
|
||||
var isAdmin = "{{.isAdmin}}";
|
||||
var msg = "编辑任务需要重新审核,是否确认需要编辑?";
|
||||
@@ -193,15 +198,26 @@
|
||||
}
|
||||
|
||||
layer.confirm(msg, {icon: 3, title:'提示'}, function(index){
|
||||
layer.load();
|
||||
|
||||
var form_data = data.field;
|
||||
var ids = [];
|
||||
$("input[name=server_id][type=checkbox]").each(function() {
|
||||
if ($(this).prop("checked")) {
|
||||
ids.push($(this).val());
|
||||
}
|
||||
});
|
||||
if (ids.length<1){
|
||||
layer.msg("请选择服务资源");
|
||||
return false;
|
||||
}
|
||||
form_data.server_ids = ids.join(",");
|
||||
|
||||
$.post('{{urlfor "TaskController.AjaxSave"}}', form_data, function (out) {
|
||||
if (out.status == 0) {
|
||||
layer.msg(okmsg,{icon: 1,shade:0.3,time:1000},function () {
|
||||
// self.location=document.referrer;
|
||||
window.location.reload();
|
||||
window.parent.deleteCurrentTab();
|
||||
})
|
||||
|
||||
} else {
|
||||
layer.msg(out.message)
|
||||
return
|
||||
|
||||
@@ -50,6 +50,12 @@
|
||||
<td>{{.taskLog.status|str2html}}</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>运行服务器</td>
|
||||
<td>{{.taskLog.server_name}}</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
||||
@@ -46,12 +46,13 @@
|
||||
,url: "/tasklog/table?task_id={{.task_id}}"
|
||||
,cols: [[
|
||||
{checkbox: true, fixed: true}
|
||||
,{field:'id', title: 'ID', align:'center',sort: true, width:150}
|
||||
,{field:'task_id', title: '任务ID', align:'center',sort: true, width:150}
|
||||
// ,{field:'id', title: 'ID', align:'center',sort: true, width:150}
|
||||
,{field:'task_id', title: '任务ID', align:'center',width:100}
|
||||
,{field:'server_name', title: '服务器', width:150}
|
||||
,{field:'start_time',title: '开始时间'}
|
||||
,{field:'process_time',width:100, title: '执行时间'}
|
||||
,{field:'output_size',title: '输出'}
|
||||
,{field:'status', width:170,title: '状态'}
|
||||
,{field:'status', width:100,title: '状态'}
|
||||
,{fixed: 'right', align:'center', title:'操作', toolbar: '#bar'}
|
||||
]]
|
||||
,id: 'listReload'
|
||||
|
||||
Reference in New Issue
Block a user