goploy/controller/CrontabController.go

434 lines
12 KiB
Go
Raw Normal View History

2020-08-04 14:28:25 +08:00
package controller
import (
"bytes"
"crypto/md5"
"encoding/hex"
"github.com/zhenorzz/goploy/core"
"github.com/zhenorzz/goploy/model"
"github.com/zhenorzz/goploy/utils"
"strconv"
"strings"
)
// Crontab struct
type Crontab Controller
// GetList crontab list
2020-09-26 10:45:28 +08:00
func (Crontab) GetList(gp *core.Goploy) *core.Response {
2020-08-04 14:28:25 +08:00
pagination, err := model.PaginationFrom(gp.URLQuery)
if err != nil {
return &core.Response{Code: core.Error, Message: err.Error()}
}
crontabs, err := model.Crontab{NamespaceID: gp.Namespace.ID, Command: gp.URLQuery.Get("command")}.GetList(pagination)
if err != nil {
return &core.Response{Code: core.Error, Message: err.Error()}
}
2020-09-26 11:45:44 +08:00
return &core.Response{
Data: struct {
Crontabs model.Crontabs `json:"list"`
}{Crontabs: crontabs},
}
2020-08-04 14:28:25 +08:00
}
// GetTotal crontab total
2020-09-26 10:45:28 +08:00
func (Crontab) GetTotal(gp *core.Goploy) *core.Response {
2020-08-04 14:28:25 +08:00
total, err := model.Crontab{NamespaceID: gp.Namespace.ID, Command: gp.URLQuery.Get("command")}.GetTotal()
if err != nil {
return &core.Response{Code: core.Error, Message: err.Error()}
}
2020-09-26 11:45:44 +08:00
return &core.Response{
Data: struct {
Total int64 `json:"total"`
}{Total: total},
}
2020-08-04 14:28:25 +08:00
}
2021-05-20 13:21:21 +08:00
// GetCrontabsInRemoteServer crontab list
func (Crontab) GetCrontabsInRemoteServer(gp *core.Goploy) *core.Response {
2020-08-04 14:28:25 +08:00
serverID, err := strconv.ParseInt(gp.URLQuery.Get("serverId"), 10, 64)
if err != nil {
return &core.Response{Code: core.Error, Message: err.Error()}
}
server, err := model.Server{
ID: serverID,
}.GetData()
if err != nil {
return &core.Response{Code: core.Error, Message: err.Error()}
}
2021-02-12 16:21:05 +08:00
client, err := utils.DialSSH(server.Owner, server.Password, server.Path, server.IP, server.Port)
if err != nil {
return &core.Response{Code: core.Error, Message: err.Error()}
}
2020-08-04 14:28:25 +08:00
2021-02-12 16:21:05 +08:00
session, err := client.NewSession()
2020-08-04 14:28:25 +08:00
if err != nil {
return &core.Response{Code: core.Error, Message: err.Error()}
}
var sshOutbuf, sshErrbuf bytes.Buffer
session.Stdout = &sshOutbuf
session.Stderr = &sshErrbuf
sshOutbuf.Reset()
if err = session.Run("crontab -l"); err != nil {
return &core.Response{Code: core.Error, Message: err.Error()}
}
crontabList := strings.Split(sshOutbuf.String(), "\n")
var crontabs []string
for _, crontab := range crontabList {
// windows \r\n
crontab = strings.TrimRight(crontab, "\r")
if len(crontab) == 0 {
continue
}
// skip error format
if len(strings.Split(crontab, " ")) < 5 {
continue
}
// skip comment
if strings.Index("#", crontab) == 0 {
continue
}
crontabs = append(crontabs, crontab)
}
2020-09-26 11:45:44 +08:00
return &core.Response{
Data: struct {
Crontabs []string `json:"list"`
}{Crontabs: crontabs},
}
2020-08-04 14:28:25 +08:00
}
// GetBindServerList project detail
2020-09-26 10:45:28 +08:00
func (Crontab) GetBindServerList(gp *core.Goploy) *core.Response {
2020-08-04 14:28:25 +08:00
id, err := strconv.ParseInt(gp.URLQuery.Get("id"), 10, 64)
if err != nil {
return &core.Response{Code: core.Error, Message: err.Error()}
}
crontabServers, err := model.CrontabServer{CrontabID: id}.GetBindServerListByProjectID()
if err != nil {
return &core.Response{Code: core.Error, Message: err.Error()}
}
2020-09-26 11:45:44 +08:00
return &core.Response{
Data: struct {
CrontabServers model.CrontabServers `json:"list"`
}{CrontabServers: crontabServers},
}
2020-08-04 14:28:25 +08:00
}
// Add one crontab
2020-09-26 10:45:28 +08:00
func (Crontab) Add(gp *core.Goploy) *core.Response {
2020-08-04 14:28:25 +08:00
type ReqData struct {
Command string `json:"command" validate:"required"`
ServerIDs []int64 `json:"serverIds"`
}
var reqData ReqData
if err := verify(gp.Body, &reqData); err != nil {
return &core.Response{Code: core.Error, Message: err.Error()}
}
crontabID, err := model.Crontab{
NamespaceID: gp.Namespace.ID,
Command: reqData.Command,
Creator: gp.UserInfo.Name,
CreatorID: gp.UserInfo.ID,
}.AddRow()
if err != nil {
return &core.Response{Code: core.Error, Message: err.Error()}
}
2020-09-26 11:45:44 +08:00
if len(reqData.ServerIDs) != 0 {
crontabServersModel := model.CrontabServers{}
for _, serverID := range reqData.ServerIDs {
crontabServerModel := model.CrontabServer{
CrontabID: crontabID,
ServerID: serverID,
}
2020-08-04 14:28:25 +08:00
2020-09-26 11:45:44 +08:00
go addCrontab(serverID, reqData.Command)
2020-08-04 14:28:25 +08:00
2020-09-26 11:45:44 +08:00
crontabServersModel = append(crontabServersModel, crontabServerModel)
}
2020-08-04 14:28:25 +08:00
2020-09-26 11:45:44 +08:00
if err := crontabServersModel.AddMany(); err != nil {
return &core.Response{Code: core.Error, Message: err.Error()}
}
2020-08-04 14:28:25 +08:00
}
2020-09-26 11:45:44 +08:00
return &core.Response{
Data: struct {
ID int64 `json:"id"`
}{ID: crontabID},
}
2020-08-04 14:28:25 +08:00
}
// Edit one crontab
2020-09-26 10:45:28 +08:00
func (Crontab) Edit(gp *core.Goploy) *core.Response {
2020-08-04 14:28:25 +08:00
type ReqData struct {
ID int64 `json:"id" validate:"gt=0"`
Command string `json:"command" validate:"required"`
}
var reqData ReqData
if err := verify(gp.Body, &reqData); err != nil {
return &core.Response{Code: core.Error, Message: err.Error()}
}
crontabInfo, err := model.Crontab{ID: reqData.ID}.GetData()
if err != nil {
return &core.Response{Code: core.Error, Message: err.Error()}
}
err = model.Crontab{
ID: reqData.ID,
Command: reqData.Command,
Editor: gp.UserInfo.Name,
EditorID: gp.UserInfo.ID,
}.EditRow()
if err != nil {
return &core.Response{Code: core.Error, Message: err.Error()}
}
// 命令没修改过 不需要修改服务器的定时任务
if crontabInfo.Command == reqData.Command {
return &core.Response{}
}
crontabServers, err := model.CrontabServer{CrontabID: reqData.ID}.GetAllByCrontabID()
if err != nil {
return &core.Response{Code: core.Error, Message: err.Error()}
}
for _, crontabServer := range crontabServers {
go deleteCrontab(crontabServer.ServerID, crontabInfo.Command)
go addCrontab(crontabServer.ServerID, reqData.Command)
}
return &core.Response{}
}
2021-05-21 18:56:23 +08:00
// Import many crontab
2020-09-26 10:45:28 +08:00
func (Crontab) Import(gp *core.Goploy) *core.Response {
2020-08-04 14:28:25 +08:00
type ReqData struct {
2021-03-30 17:49:03 +08:00
ServerID int64 `json:"serverId" validate:"gt=0"`
2020-08-04 14:28:25 +08:00
Commands []string `json:"commands" validate:"required"`
}
var reqData ReqData
if err := verify(gp.Body, &reqData); err != nil {
return &core.Response{Code: core.Error, Message: err.Error()}
}
commands := make(map[string]string)
var commandMD5s []string
for _, command := range reqData.Commands {
if len(command) == 0 {
continue
}
h := md5.New()
h.Write([]byte(command))
commandMD5 := hex.EncodeToString(h.Sum(nil))
commands[commandMD5] = command
commandMD5s = append(commandMD5s, commandMD5)
}
crontabList, err := model.Crontab{}.GetAllInCommandMD5(commandMD5s)
if err != nil {
return &core.Response{Code: core.Error, Message: err.Error()}
}
for _, crontab := range crontabList {
if _, ok := commands[crontab.CommandMD5]; ok {
delete(commands, crontab.CommandMD5)
}
}
2021-03-30 17:49:03 +08:00
crontabServersModel := model.CrontabServers{}
2020-08-04 14:28:25 +08:00
for _, command := range commands {
2021-03-30 17:49:03 +08:00
crontabID, err := model.Crontab{
NamespaceID: gp.Namespace.ID,
Command: command,
Creator: gp.UserInfo.Name,
CreatorID: gp.UserInfo.ID,
}.AddRow()
2020-08-04 14:28:25 +08:00
if err != nil {
return &core.Response{Code: core.Error, Message: err.Error()}
}
2021-03-30 17:49:03 +08:00
crontabServerModel := model.CrontabServer{
CrontabID: crontabID,
ServerID: reqData.ServerID,
}
crontabServersModel = append(crontabServersModel, crontabServerModel)
}
if err := crontabServersModel.AddMany(); err != nil {
return &core.Response{Code: core.Error, Message: err.Error()}
2020-08-04 14:28:25 +08:00
}
return &core.Response{}
}
2021-05-21 18:56:23 +08:00
// Remove one Crontab
2020-09-26 10:45:28 +08:00
func (Crontab) Remove(gp *core.Goploy) *core.Response {
2020-08-04 14:28:25 +08:00
type ReqData struct {
ID int64 `json:"id" validate:"gt=0"`
Radio int8 `json:"radio" validate:"min=0,max=1"`
}
var reqData ReqData
if err := verify(gp.Body, &reqData); err != nil {
return &core.Response{Code: core.Error, Message: err.Error()}
}
if reqData.Radio == 1 {
crontabInfo, err := model.Crontab{ID: reqData.ID}.GetData()
if err != nil {
return &core.Response{Code: core.Error, Message: err.Error()}
}
crontabServers, err := model.CrontabServer{CrontabID: reqData.ID}.GetAllByCrontabID()
if err != nil {
return &core.Response{Code: core.Error, Message: err.Error()}
}
for _, crontabServer := range crontabServers {
go deleteCrontab(crontabServer.ServerID, crontabInfo.Command)
}
}
2020-08-19 10:22:43 +08:00
if err := (model.Crontab{ID: reqData.ID}).DeleteRow(); err != nil {
2020-08-04 14:28:25 +08:00
return &core.Response{Code: core.Error, Message: err.Error()}
}
2020-08-19 10:22:43 +08:00
if err := (model.CrontabServer{CrontabID: reqData.ID}).DeleteByCrontabID(); err != nil {
2020-08-04 14:28:25 +08:00
return &core.Response{Code: core.Error, Message: err.Error()}
}
return &core.Response{}
}
// AddServer one crontab
2020-09-26 10:45:28 +08:00
func (Crontab) AddServer(gp *core.Goploy) *core.Response {
2020-08-04 14:28:25 +08:00
type ReqData struct {
CrontabID int64 `json:"crontabId" validate:"gt=0"`
ServerIDs []int64 `json:"serverIds" validate:"required"`
}
var reqData ReqData
if err := verify(gp.Body, &reqData); err != nil {
return &core.Response{Code: core.Error, Message: err.Error()}
}
crontabID := reqData.CrontabID
crontabInfo, err := model.Crontab{ID: crontabID}.GetData()
if err != nil {
return &core.Response{Code: core.Error, Message: err.Error()}
}
crontabServersModel := model.CrontabServers{}
for _, serverID := range reqData.ServerIDs {
crontabServerModel := model.CrontabServer{
CrontabID: crontabID,
ServerID: serverID,
}
go addCrontab(serverID, crontabInfo.Command)
crontabServersModel = append(crontabServersModel, crontabServerModel)
}
if err := crontabServersModel.AddMany(); err != nil {
return &core.Response{Code: core.Error, Message: err.Error()}
}
return &core.Response{}
}
// RemoveCrontabServer one crontab
2020-09-26 10:45:28 +08:00
func (Crontab) RemoveCrontabServer(gp *core.Goploy) *core.Response {
2020-08-04 14:28:25 +08:00
type ReqData struct {
CrontabServerID int64 `json:"crontabServerId" validate:"gt=0"`
CrontabID int64 `json:"crontabId" validate:"gt=0"`
ServerID int64 `json:"serverId" validate:"gt=0"`
}
var reqData ReqData
if err := verify(gp.Body, &reqData); err != nil {
return &core.Response{Code: core.Error, Message: err.Error()}
}
crontabInfo, err := model.Crontab{ID: reqData.CrontabID}.GetData()
if err != nil {
return &core.Response{Code: core.Error, Message: err.Error()}
}
2020-08-19 10:22:43 +08:00
if err := (model.CrontabServer{ID: reqData.CrontabServerID}).DeleteRow(); err != nil {
2020-08-04 14:28:25 +08:00
return &core.Response{Code: core.Error, Message: err.Error()}
}
go deleteCrontab(reqData.ServerID, crontabInfo.Command)
return &core.Response{}
}
func addCrontab(serverID int64, command string) {
server, err := model.Server{
ID: serverID,
}.GetData()
if err != nil {
core.Log(core.TRACE, "serverID:"+strconv.FormatUint(uint64(serverID), 10)+" get server fail, detail:"+err.Error())
return
}
2021-02-12 16:21:05 +08:00
client, err := utils.DialSSH(server.Owner, server.Password, server.Path, server.IP, server.Port)
2020-08-04 14:28:25 +08:00
if err != nil {
core.Log(core.TRACE, "serverID:"+strconv.FormatUint(uint64(serverID), 10)+" connect server fail, detail:"+err.Error())
return
}
2021-02-12 16:21:05 +08:00
session, err := client.NewSession()
if err != nil {
core.Log(core.TRACE, "serverID:"+strconv.FormatUint(uint64(serverID), 10)+" new session fail, detail:"+err.Error())
return
}
2020-08-04 14:28:25 +08:00
var sshOutbuf, sshErrbuf bytes.Buffer
session.Stdout = &sshOutbuf
session.Stderr = &sshErrbuf
sshOutbuf.Reset()
if err = session.Run(`(crontab -l ; echo "` + command + `") 2>&1 | grep -v "no crontab" | sort | uniq | crontab -`); err != nil {
core.Log(core.TRACE, "serverID:"+strconv.FormatUint(uint64(serverID), 10)+" add "+command+" fail, detail:"+sshErrbuf.String())
return
}
}
func deleteCrontab(serverID int64, command string) {
2020-08-19 10:22:43 +08:00
server, err := model.Server{ID: serverID}.GetData()
2020-08-04 14:28:25 +08:00
if err != nil {
core.Log(core.TRACE, "serverID:"+strconv.FormatUint(uint64(serverID), 10)+" get server fail, detail:"+err.Error())
return
}
2021-02-12 16:21:05 +08:00
client, err := utils.DialSSH(server.Owner, server.Password, server.Path, server.IP, server.Port)
2020-08-04 14:28:25 +08:00
if err != nil {
core.Log(core.TRACE, "serverID:"+strconv.FormatUint(uint64(serverID), 10)+" connect server fail, detail:"+err.Error())
return
}
2021-02-12 16:21:05 +08:00
session, err := client.NewSession()
if err != nil {
core.Log(core.TRACE, "serverID:"+strconv.FormatUint(uint64(serverID), 10)+" new session fail, detail:"+err.Error())
return
}
2020-08-04 14:28:25 +08:00
var sshOutbuf, sshErrbuf bytes.Buffer
session.Stdout = &sshOutbuf
session.Stderr = &sshErrbuf
sshOutbuf.Reset()
if err = session.Run(`(crontab -l ; echo "` + command + `") 2>&1 | grep -v "no crontab" | grep -v -F "` + command + `" | sort | uniq | crontab -`); err != nil {
core.Log(core.TRACE, "serverID:"+strconv.FormatUint(uint64(serverID), 10)+" delete "+command+" fail, detail:"+sshErrbuf.String())
return
}
}