431 lines
14 KiB
Go
431 lines
14 KiB
Go
package model
|
|
|
|
import (
|
|
"backend/Type"
|
|
"backend/client"
|
|
"backend/middleware/alibaba"
|
|
"backend/middleware/feishu"
|
|
"backend/msg"
|
|
util "backend/util"
|
|
"fmt"
|
|
"log"
|
|
"strings"
|
|
|
|
"github.com/Ullaakut/nmap"
|
|
)
|
|
|
|
const (
|
|
DEVOPS_SERVER = "log"
|
|
)
|
|
|
|
type Server struct {
|
|
AppId int `json:"AppId"`
|
|
ServerId int `json:"ServerId"`
|
|
ServerName string `json:"ServerName"`
|
|
Status int `json:"Status"`
|
|
OpenServerTime int `json:"OpenServerTime"`
|
|
Type int `json:"Type"`
|
|
Tags string `json:"Tags"`
|
|
ClientVersion string `json:"ClientVersion"`
|
|
Host string `json:"Host"`
|
|
Port int `json:"Port"`
|
|
WsPort int `json:"WsPort"`
|
|
WorkDir string `json:"WorkDir"`
|
|
Ecs int `json:"Ecs"`
|
|
}
|
|
|
|
func (s *Server) AppList() ([]*Type.App, error) {
|
|
Db := util.MPool.GetGameDB()
|
|
var app []*Type.App
|
|
err := Db.Select(&app, "SELECT `AppId`, `AppName`, `NodeName`, `MysqlName`, `Topic`, `tz`, `WsHost`, `Database`, `Update`, `Path` FROM app")
|
|
defer Db.Close()
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to scan rows: %v", err)
|
|
}
|
|
return app, nil
|
|
}
|
|
|
|
func (s *Server) ServerList() ([]*Type.ServerInfo, error) {
|
|
Db := util.MPool.GetGameDB()
|
|
var server []*Type.ServerInfo
|
|
defer Db.Close()
|
|
err := Db.Select(&server, "SELECT `AppId`, `ServerId`, `ServerName`, `Status`, `CreateTime`, `OpenServerTime`, `Online`, `cpu`, `free_mem`, `version`, `node_tags`, `latency` FROM server where AppId = ? order by `ServerId`", s.AppId)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to scan rows: %v", err)
|
|
}
|
|
for _, s := range server {
|
|
s.Tags = util.ParseNodeTags(s.NodeTags)
|
|
}
|
|
if s.Type == 1 {
|
|
return server, nil
|
|
}
|
|
return server, nil
|
|
}
|
|
|
|
func (s *Server) AddServer() error {
|
|
Db := util.MPool.GetGameDB()
|
|
defer Db.Close()
|
|
_, err := Db.Exec("INSERT INTO server (`AppId`, `ServerId`, `ServerName`, `Status`, `CreateTime`, `OpenServerTime`, `Host`, `Port`, `version`, `ws_port`, `work_dir`, `ecs`) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?,?, ?)",
|
|
s.AppId, s.ServerId, s.ServerName, s.Status, util.Now(), s.OpenServerTime, s.Host, s.Port, s.ClientVersion, s.WsPort, s.WorkDir, s.Ecs)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to insert: %v", err)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (s *Server) EditServer() error {
|
|
Db := util.MPool.GetGameDB()
|
|
defer Db.Close()
|
|
_, err := Db.Exec("UPDATE server SET `ServerName` = ?, `version` = ?, `node_tags` = ? WHERE `AppId` = ? AND `ServerId` = ?",
|
|
s.ServerName, s.ClientVersion, s.Tags, s.AppId, s.ServerId)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to update: %v", err)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (s *Server) UpdateApp() (string, error) {
|
|
nodeInfo := util.GetNodeByName("devops")
|
|
AppConfig, err := util.GetAppConfig(s.AppId)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
SshClient, err := util.NewSshClient(nodeInfo)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
param := Type.AlibabaUpdateCardParam{}
|
|
|
|
defer SshClient.Close()
|
|
_, err = SshClient.RunCommand("cd /data/devops && git pull")
|
|
if err != nil {
|
|
return "", fmt.Errorf("failed to git pull: %v", err)
|
|
}
|
|
resp, err := SshClient.RunCommand(`export PATH="$PATH:$(go env GOPATH)/bin"`)
|
|
fmt.Print(resp)
|
|
|
|
now := util.Now()
|
|
cmd := fmt.Sprintf(`source /etc/profile && export PATH="$PATH:$(go env GOPATH)/bin"`+"&& ansible-playbook /data/devops/playbook/%s.yml -i /data/devops/playbook/hosts", AppConfig.AppName)
|
|
output, err := SshClient.RunCommand(cmd)
|
|
param.UpdateTime = util.NowFormat()
|
|
param.Duration = fmt.Sprintf("%d 秒", util.Now()-now)
|
|
param.Server = util.GetAppName(s.AppId)
|
|
|
|
if err != nil {
|
|
param.SrcGitLog = fmt.Sprintf("- 更新失败: %v\n", err)
|
|
param.DocGitLog = "- output:\n" + output
|
|
content := util.ParseTmpl("./template/update.tmpl", param)
|
|
alibaba.SendStandardMsg("游戏服务更新失败", content, "red")
|
|
return "", err
|
|
}
|
|
// 记录git 更新状态
|
|
cmd = "cd /codes/pet_home_server && git rev-parse HEAD"
|
|
srcHead, err := SshClient.RunCommand(cmd)
|
|
if err != nil {
|
|
log.Printf("警告: 无法获取源码 git head (目录或git命令可能不存在): %v", err)
|
|
// 继续执行,不中断流程
|
|
} else {
|
|
src_git_key := fmt.Sprintf("src_%d", s.AppId)
|
|
srcHead = strings.TrimSpace(srcHead)
|
|
oldSrcHead, _ := util.GetGitHead(src_git_key)
|
|
util.SaveGitHead(src_git_key, srcHead)
|
|
if oldSrcHead != "" && oldSrcHead != srcHead {
|
|
cmd = fmt.Sprintf("cd /codes/pet_home_server && git log %s..%s --pretty=format:'%%h-%%s'", oldSrcHead, srcHead)
|
|
commitMsg, _ := SshClient.RunCommand(cmd)
|
|
if commitMsg != "" {
|
|
param.SrcGitLog = "- server-git log\n" + commitMsg
|
|
}
|
|
}
|
|
}
|
|
|
|
cmd = "cd /data/docs && git rev-parse HEAD"
|
|
docHead, err := SshClient.RunCommand(cmd)
|
|
if err != nil {
|
|
log.Printf("警告: 无法获取文档 git head (目录或git命令可能不存在): %v", err)
|
|
// 继续执行,不中断流程
|
|
} else {
|
|
docs_git_key := fmt.Sprintf("docs_%d", s.AppId)
|
|
docHead = strings.TrimSpace(docHead)
|
|
oldDocHead, _ := util.GetGitHead(docs_git_key)
|
|
util.SaveGitHead(docs_git_key, docHead)
|
|
if oldDocHead != "" && oldDocHead != docHead {
|
|
cmd = fmt.Sprintf("cd /data/docs && git log %s..%s --pretty=format:'%%h-%%s'", oldDocHead, docHead)
|
|
commitMsg, _ := SshClient.RunCommand(cmd)
|
|
if commitMsg != "" {
|
|
param.DocGitLog = "- docs-git log\n" + commitMsg
|
|
}
|
|
}
|
|
}
|
|
|
|
content := util.ParseTmpl("./template/update.tmpl", param)
|
|
|
|
DB := util.MPool.GetGameDB()
|
|
defer DB.Close()
|
|
DB.Exec("UPDATE app SET `Update` = ? WHERE `AppId` = ?", util.Now(), s.AppId)
|
|
alibaba.SendStandardMsg("游戏服务更新完成", content, "green")
|
|
return output, nil
|
|
}
|
|
|
|
func (s *Server) UpdateAppReview() (string, error) {
|
|
nodeInfo := util.GetNodeByName("devops")
|
|
AppConfig, err := util.GetAppConfig(s.AppId)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
SshClient, err := util.NewSshClient(nodeInfo)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
param := Type.AlibabaUpdateCardParam{}
|
|
|
|
defer SshClient.Close()
|
|
_, err = SshClient.RunCommand("cd /data/devops && git pull")
|
|
if err != nil {
|
|
return "", fmt.Errorf("failed to git pull: %v", err)
|
|
}
|
|
now := util.Now()
|
|
cmd := fmt.Sprintf(`source /etc/profile && export PATH="$PATH:$(go env GOPATH)/bin"`+"&& ansible-playbook /data/devops/playbook/%s-review.yml -i /data/devops/playbook/hosts", AppConfig.AppName)
|
|
output, err := SshClient.RunCommand(cmd)
|
|
param.UpdateTime = util.NowFormat()
|
|
param.Duration = fmt.Sprintf("%d 秒", util.Now()-now)
|
|
param.Server = util.GetAppName(s.AppId) + " review"
|
|
|
|
if err != nil {
|
|
param.SrcGitLog = fmt.Sprintf("- 更新失败: %v\n", err)
|
|
param.DocGitLog = "- output:\n" + output
|
|
content := util.ParseTmpl("./template/update.tmpl", param)
|
|
alibaba.SendStandardMsg("游戏服务更新失败", content, "red")
|
|
return "", err
|
|
}
|
|
// 记录git 更新状态
|
|
cmd = "cd /codes/pet_home_server && git rev-parse HEAD"
|
|
srcHead, err := SshClient.RunCommand(cmd)
|
|
if err != nil {
|
|
log.Printf("警告: 无法获取源码 git head (目录或git命令可能不存在): %v", err)
|
|
// 继续执行,不中断流程
|
|
} else {
|
|
srcHead = strings.TrimSpace(srcHead)
|
|
oldSrcHead, _ := util.GetGitHead("src")
|
|
util.SaveGitHead("src", srcHead)
|
|
if oldSrcHead != "" && oldSrcHead != srcHead {
|
|
cmd = fmt.Sprintf("cd /codes/pet_home_server && git log %s..%s --pretty=format:'%%h-%%s'", oldSrcHead, srcHead)
|
|
commitMsg, _ := SshClient.RunCommand(cmd)
|
|
if commitMsg != "" {
|
|
param.SrcGitLog = "- server-git log\n" + commitMsg
|
|
}
|
|
}
|
|
}
|
|
|
|
cmd = "cd /data/docs && git rev-parse HEAD"
|
|
docHead, err := SshClient.RunCommand(cmd)
|
|
if err != nil {
|
|
log.Printf("警告: 无法获取文档 git head (目录或git命令可能不存在): %v", err)
|
|
// 继续执行,不中断流程
|
|
} else {
|
|
docHead = strings.TrimSpace(docHead)
|
|
oldDocHead, _ := util.GetGitHead("doc")
|
|
util.SaveGitHead("doc", docHead)
|
|
if oldDocHead != "" && oldDocHead != docHead {
|
|
cmd = fmt.Sprintf("cd /data/docs && git log %s..%s --pretty=format:'%%h-%%s'", oldDocHead, docHead)
|
|
commitMsg, _ := SshClient.RunCommand(cmd)
|
|
if commitMsg != "" {
|
|
param.DocGitLog = "- docs-git log\n" + commitMsg
|
|
}
|
|
}
|
|
}
|
|
|
|
content := util.ParseTmpl("./template/update.tmpl", param)
|
|
|
|
DB := util.MPool.GetGameDB()
|
|
defer DB.Close()
|
|
DB.Exec("UPDATE app SET `Update` = ? WHERE `AppId` = ?", util.Now(), s.AppId)
|
|
alibaba.SendStandardMsg("游戏review服务更新完成", content, "green")
|
|
return output, nil
|
|
}
|
|
|
|
func (s *Server) UpdateAppFeishu() (string, error) {
|
|
serverInfo := util.GetServer(s.AppId, s.ServerId)
|
|
nodeInfo := util.GetNodeById(serverInfo.Ecs)
|
|
AppConfig, err := util.GetAppConfig(s.AppId)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
SshClient, err := util.NewSshClient(nodeInfo)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
defer SshClient.Close()
|
|
_, err = SshClient.RunCommand("cd /data/devops && git pull")
|
|
if err != nil {
|
|
return "", fmt.Errorf("failed to git pull: %v", err)
|
|
}
|
|
cmd := fmt.Sprintf("ansible-playbook /data/devops/playbook/%s.yml -i /data/devops/playbook/hosts", AppConfig.AppName)
|
|
output, err := SshClient.RunCommand(cmd)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
DB := util.MPool.GetGameDB()
|
|
defer DB.Close()
|
|
DB.Exec("UPDATE app SET `Update` = ? WHERE `AppId` = ?", util.Now(), s.AppId)
|
|
feishu.SendFeishuMsg(fmt.Sprintf("AppName: %s, 执行文件更新完成", AppConfig.AppName))
|
|
return output, nil
|
|
}
|
|
|
|
func (s *Server) RestartServer() (string, error) {
|
|
serverInfo := util.GetServer(s.AppId, s.ServerId)
|
|
nodeInfo := util.GetNodeById(serverInfo.Ecs)
|
|
SshClient, err := util.NewSshClient(nodeInfo)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
defer SshClient.Close()
|
|
workDir := serverInfo.WorkDir
|
|
cmd := fmt.Sprintf("cd %s && ./tool/tool restart node %d", workDir, s.ServerId)
|
|
if serverInfo.NodeType == 0 {
|
|
cmd = fmt.Sprintf("cd %s && ./tool/tool restart center %d", workDir, s.ServerId)
|
|
}
|
|
output, err := SshClient.RunCommand(cmd)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
// feishu.SendFeishuMsg(fmt.Sprintf("AppName: %s, ServerName: %s, 重启完成", AppConfig.AppName, s.ServerName))
|
|
str := `
|
|
# 游戏服务重启
|
|
* 游戏环境:**%s**
|
|
* 节点:%s
|
|
------------------
|
|
重启完成[鼓掌]
|
|
<a>所有人</a>
|
|
`
|
|
alibaba.SendStandardMsg("游戏服务器重启完成", fmt.Sprintf(str, util.GetAppName(s.AppId), serverInfo.Name), "green")
|
|
return output, nil
|
|
}
|
|
|
|
func (s *Server) StopServer() (string, error) {
|
|
serverInfo := util.GetServer(s.AppId, s.ServerId)
|
|
nodeInfo := util.GetNodeById(serverInfo.Ecs)
|
|
SshClient, err := util.NewSshClient(nodeInfo)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
defer SshClient.Close()
|
|
workDir := serverInfo.WorkDir
|
|
cmd := fmt.Sprintf("cd %s && ./tool/tool stop node %d", workDir, s.ServerId)
|
|
if serverInfo.NodeType == 0 {
|
|
cmd = fmt.Sprintf("cd %s && ./tool/tool stop center %d", workDir, s.ServerId)
|
|
}
|
|
output, err := SshClient.RunCommand(cmd)
|
|
if err != nil {
|
|
return output, err
|
|
}
|
|
// feishu.SendFeishuMsg(fmt.Sprintf("AppName: %s, ServerName: %s, 重启完成", AppConfig.AppName, s.ServerName))
|
|
// str := `
|
|
// # 游戏服务关闭
|
|
// * 游戏环境:**%s**
|
|
// * 节点:%s
|
|
// ------------------
|
|
// 关闭完成[鼓掌]
|
|
// <a>所有人</a>
|
|
// `
|
|
// alibaba.SendStandardMsg("游戏服务器关闭完成", fmt.Sprintf(str, util.GetAppName(s.AppId), serverInfo.Name), "green")
|
|
return output, nil
|
|
}
|
|
|
|
func (s *Server) StartServer() (string, error) {
|
|
serverInfo := util.GetServer(s.AppId, s.ServerId)
|
|
nodeInfo := util.GetNodeById(serverInfo.Ecs)
|
|
SshClient, err := util.NewSshClient(nodeInfo)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
defer SshClient.Close()
|
|
workDir := serverInfo.WorkDir
|
|
cmd := fmt.Sprintf("cd %s && ./tool/tool start node %d", workDir, s.ServerId)
|
|
if serverInfo.NodeType == 0 {
|
|
cmd = fmt.Sprintf("cd %s && ./tool/tool start center %d", workDir, s.ServerId)
|
|
}
|
|
output, err := SshClient.RunCommand(cmd)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
// feishu.SendFeishuMsg(fmt.Sprintf("AppName: %s, ServerName: %s, 重启完成", AppConfig.AppName, s.ServerName))
|
|
// str := `
|
|
// # 游戏服务启动
|
|
// * 游戏环境:**%s**
|
|
// * 节点:%s
|
|
// ------------------
|
|
// 启动完成[鼓掌]
|
|
// <a>所有人</a>
|
|
// `
|
|
// alibaba.SendStandardMsg("游戏服务器启动完成", fmt.Sprintf(str, util.GetAppName(s.AppId), serverInfo.Name), "green")
|
|
return output, nil
|
|
}
|
|
|
|
func (s *Server) ReloadServer() (string, error) {
|
|
AppConfig, err := util.GetAppConfig(s.AppId)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
req := &msg.ReqReload{}
|
|
_, err = client.ServerReload(s.AppId, s.ServerId, req)
|
|
if err != nil {
|
|
log.Printf("failed to send admin message: %v", err)
|
|
}
|
|
feishu.SendFeishuMsg(fmt.Sprintf("AppName: %s, ServerName: %s, 配置重载完成", AppConfig.AppName, s.ServerName))
|
|
return "success", nil
|
|
}
|
|
|
|
// 端口扫描
|
|
func PortMap(Ip string, Port string) error {
|
|
// 创建一个新的Nmap扫描器
|
|
scanner, err := nmap.NewScanner(
|
|
nmap.WithTargets(Ip), // 替换为你要扫描的目标IP地址
|
|
nmap.WithPorts(Port), // 替换为你要扫描的端口
|
|
// nmap.WithTCPFINScan(), // 使用TCP扫描
|
|
nmap.WithTimingTemplate(nmap.TimingSneaky),
|
|
)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// 执行扫描
|
|
result, warnings, err := scanner.Run()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// 打印扫描结果
|
|
for _, warning := range warnings {
|
|
log.Printf("nmap 警告: %v", warning)
|
|
}
|
|
|
|
for _, host := range result.Hosts {
|
|
if len(host.Ports) == 0 || host.Status.State != "up" {
|
|
continue
|
|
}
|
|
for _, port := range host.Ports {
|
|
if port.State.State == "filtered" {
|
|
continue
|
|
}
|
|
if port.State.State != "open" {
|
|
return fmt.Errorf("端口 %d 未监听 %v", port.ID, port)
|
|
}
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func GetServerInfo(AppId, ServerId int) (interface{}, error) {
|
|
req := &msg.ReqServerInfo{}
|
|
ws, err := util.GetWebsocket(AppId, ServerId)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to get websocket: %v", err)
|
|
}
|
|
defer ws.Close()
|
|
r, err := util.SendAdminMsg(ws, req)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to send admin message: %v", err)
|
|
}
|
|
return r, nil
|
|
}
|