package model import ( "backend/Type" "backend/alibaba" "backend/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 ------------------ 重启完成[鼓掌] 所有人 ` 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 // ------------------ // 关闭完成[鼓掌] // 所有人 // ` // 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 // ------------------ // 启动完成[鼓掌] // 所有人 // ` // 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 } ws, err := util.GetWebsocket(s.AppId, s.ServerId) if err != nil { return "", fmt.Errorf("failed to get websocket: %v", err) } defer ws.Close() req := &msg.ReqReload{} _, err = util.SendAdminMsg(ws, 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 }