package auto import ( "bytes" "fmt" "io" "os" "reflect" "strconv" "strings" "sync" "xg_auto_deploy/internal/config" "xg_auto_deploy/internal/global" "xg_auto_deploy/internal/models" "xg_auto_deploy/internal/remote" "xg_auto_deploy/internal/utils" "golang.org/x/crypto/ssh" ) var wg sync.WaitGroup func AutoDeployALL() { global.Logs.Infoln("----------------开始部署----------------------------") for NodeId, nodeTemp := range global.ServerNodeConfigs { wg.Add(1) func(serverNodeConfig models.ServerNodeConfig, serverNodeId string) { //检查环境 CheckSysEnv(&serverNodeConfig) CheckAppEnv(&serverNodeConfig) //上传文件到目标服务器 UploadFileOrDir(serverNodeId, &serverNodeConfig) //设置xugu.ini AutoXuguini(&serverNodeConfig) //设置cluster if global.ClusterConfigMap["local_file"] != "" || global.ClusterConfigMap["template"] != "" { AutoCluster(&serverNodeConfig, true) } else { global.Logs.Printf("%s节点未设置cluser.ini文件\n", serverNodeConfig.NodeId) } defer wg.Done() }(nodeTemp, NodeId) } wg.Wait() for _, serverNodeConfig := range global.ServerNodeConfigs { PrintServerNodeEnv(&serverNodeConfig) } } // 上传cluster到目标服务器 func AutoCluster(nodeTemp *models.ServerNodeConfig, onOFF bool) { if !onOFF { //获取节点 ,节点ip , //获取集群配置文件 return } id, err := strconv.Atoi(nodeTemp.NodeId) if err != nil { global.Logs.Errorf("%s节点修改cluster文件失败:%s\n", nodeTemp.NodeId, err) return } var ids string if id < 10 { ids = fmt.Sprintf("000%s", strconv.Itoa(id)) } else { ids = fmt.Sprintf("00%s", strconv.Itoa(id)) } clusterTemp := config.SaveClusterConfigBuffer(global.ClusterInfo, ids) err = remote.UploadFileBuffer(nodeTemp, clusterTemp, fmt.Sprintf(nodeTemp.XuguAddr+"/SETUP/cluster.ini")) if err != nil { global.Logs.Errorf("%s节点上传cluster文件失败:%s\n", nodeTemp.NodeId, err) } } // 上传xugu.ini到目标服务器 func AutoXuguini(nodeTemp *models.ServerNodeConfig) { xginiLocal := global.XginiConfigMap["local_file"] // 创建一个 bytes.Buffer xuguIniBuf := new(bytes.Buffer) //设置xuguini内存相关优化 setxginiMemory(nodeTemp, false) //指定上传本地文件xugu.ini, if xginiLocal != "" { // 打开文件 file, err := os.Open(xginiLocal) if err != nil { global.Logs.Errorf("%s节点打开xugu.ini文件失败:%s\n", nodeTemp.NodeId, err) panic(err) } defer file.Close() // 将文件内容复制到 buf 中 if _, err := io.Copy(xuguIniBuf, file); err != nil { global.Logs.Errorf("%s节点修改xugu.ini文件失败:%s\n", nodeTemp.NodeId, err) panic(err) } //将配置文件里[xugu]组下的参数替换xugu.ini文件里的参数 config.SetXginiBuffer(xuguIniBuf, global.XginiConfigMap) //上传到目标节点 err = remote.UploadFileBuffer(nodeTemp, xuguIniBuf, fmt.Sprintf(nodeTemp.XuguAddr+"/SETUP/xugu.ini")) if err != nil { global.Logs.Errorf("%s节点上传xugu.ini文件失败:%s\n", nodeTemp.NodeId, err) } } else { xuguIniDownloadTempbuf := remote.DownloadFileBuffer(nodeTemp, fmt.Sprintf(nodeTemp.XuguAddr+"/SETUP/xugu.ini")) //将配置文件里[xugu]组下的参数替换xugu.ini文件里的参数 config.SetXginiBuffer(xuguIniDownloadTempbuf, global.XginiConfigMap) err := remote.UploadFileBuffer(nodeTemp, xuguIniDownloadTempbuf, fmt.Sprintf(nodeTemp.XuguAddr+"/SETUP/xugu.ini")) if err != nil { global.Logs.Errorf("%s节点上传xugu.ini文件失败:%s\n", nodeTemp.NodeId, err) } } } // 设置xugu.ini配置文件中的内存相关 func setxginiMemory(nodeTemp *models.ServerNodeConfig, onOff bool) { if !onOff { return } // 检测系统内存大小 free -h | awk 'NR==2{print $2}' memoryTemp, err := remote.SingleCmd(nodeTemp, "free -m | awk 'NR==2{print $4}'") if err != nil { global.Logs.Errorf("%s节点系统内存查询失败,取消自动配置xugu.ini:%s\n", nodeTemp.NodeId, err) } //分配到XginiMap memoryTemp = strings.TrimSpace(memoryTemp) memorySize, err := strconv.Atoi(memoryTemp) if err != nil { // 处理转换错误 global.Logs.Errorf("%s节点程序内部计算远端内存大小转换错误::%s\n", nodeTemp.NodeId, err) return } setXgMem := func(memorySize int, para string, fls ...float64) { if memorySize < 8*1024 { } else if memorySize <= 32*1024 { global.XginiConfigMap[para] = strconv.Itoa(int((float64(memorySize) * fls[0] / 1024) * 1024)) } else if memorySize <= 64*1024 { global.XginiConfigMap[para] = strconv.Itoa(int((float64(memorySize) * fls[1] / 1024) * 1024)) } else if memorySize <= 256*1024 { global.XginiConfigMap[para] = strconv.Itoa(int((float64(memorySize) * fls[2] / 1024) * 1024)) } else if memorySize <= 1000*1024 { global.XginiConfigMap[para] = strconv.Itoa(int((float64(memorySize) * fls[3] / 1024) * 1024)) } } //判断配置文件是否有该参数 //data_buff_mem if global.XginiConfigMap["data_buff_mem"] == "" { setXgMem(memorySize, "data_buff_mem", 0.5, 0.6, 0.7, 0.8) } //system_sga_mem if global.XginiConfigMap["system_sga_mem"] == "" { setXgMem(memorySize, "system_sga_mem", 0.1, 0.1, 0.1, 0.05) } } // 上传文件到目标服务器 func UploadFileOrDir(serverNodeId string, serverNodeConfig *models.ServerNodeConfig) { //传送文件 upFiles := func(serverNodeConfig *models.ServerNodeConfig, LocalFile string) { //检测上传为文件还是文件夹 ret, _ := utils.IsFileOrFolder(LocalFile) switch ret { case "file": err := remote.UploadFile(serverNodeConfig, LocalFile, serverNodeConfig.XuguAddr) if err != nil { global.Logs.Fatalf("----- %s节点上传文件失败: %s\n", serverNodeId, err) return } global.Logs.Printf("----- %s节点上传文件成功\n", serverNodeId) remote.SingleCmd(serverNodeConfig, fmt.Sprintf(`chmod -R +x %s`, serverNodeConfig.XuguAddr)) case "folder": // 连接到远程主机 client, err := ssh.Dial("tcp", serverNodeConfig.IpPort, serverNodeConfig.SSHClient) if err != nil { panic(err) } defer client.Close() // 检测远端文件夹是否存在,不存在则创建 [ ! -d "/DATA2/GT/test" ] && mkdir -p /DATA2/GT/test remote.SingleCmd(serverNodeConfig, fmt.Sprintf(`[ ! -d "%s" ] && mkdir -p %s`, serverNodeConfig.XuguAddr, serverNodeConfig.XuguAddr)) // 上传文件夹 err = remote.UploadDir(serverNodeConfig, LocalFile, serverNodeConfig.XuguAddr) if err != nil { global.Logs.Errorf("----- %s节点上传文件夹错误\n", serverNodeId) panic(err) } global.Logs.Printf("----- %s节点上传文件成功\n", serverNodeId) remote.SingleCmd(serverNodeConfig, fmt.Sprintf(`chmod -R +x %s`, serverNodeConfig.XuguAddr)) } } //检测服务器是什么架构 architecture, err := remote.SingleCmd(serverNodeConfig, "uname -m") if err != nil { global.Logs.Printf("检测节点%s 服务器架构失败\n", serverNodeId) panic(err) } if strings.TrimSpace(architecture) == "aarch64" { fileLocal, err := utils.FindDirWithSubstring("./file/xugu", "aarch64") if err != nil { global.Logs.Printf("未查找到虚谷安装包\n") panic(err) } // 传送文件 upFiles(serverNodeConfig, fileLocal) } else if strings.TrimSpace(architecture) == "x86" || strings.TrimSpace(architecture) == "64" { fileLocal, err := utils.FindDirWithSubstring("./file/xugu", "aarch64") if err != nil { global.Logs.Printf("未查找到虚谷安装包\n") panic(err) } upFiles(serverNodeConfig, fileLocal) } } // 打印节点基础环境 func PrintServerNodeEnv(nodeTemp *models.ServerNodeConfig) { printFieldNames := func(i interface{}) { t := reflect.TypeOf(i) if t.Kind() == reflect.Ptr { t = t.Elem() } for i := 0; i < t.NumField(); i++ { field := t.Field(i) //fmt.Println("Field Name:", field.Name) selectNodeEnvInfo(nodeTemp.SysInfo, field.Name) } for i := 0; i < t.NumField(); i++ { field := t.Field(i) //fmt.Println("Field Name:", field.Name) selectNodeEnvInfo(nodeTemp.AppInfo, field.Name) } } //fmt.Printf("节点%s : %s\n", nodeTemp.NodeId, nodeTemp.SysInfo) global.Logs.Printf("--------------------%s节点--------------------------------------:\n", nodeTemp.NodeId) // 使用反射打印字段 printFieldNames(nodeTemp.SysInfo) printFieldNames(nodeTemp.AppInfo) global.Logs.Printf("--------------------------------------------------------------:\n") } func selectNodeEnvInfo(target interface{}, key string) { switch t := target.(type) { case *models.SysInfo: switch key { case "OsStackSize": global.Logs.Printf("系统环境Stack size :%s\n", t.OsStackSize) case "OsOpenFiles": global.Logs.Printf("系统环境Open files :%s\n", t.OsOpenFiles) case "CoreWmemDefault": global.Logs.Printf("系统环境Wmem Default :%s\n", t.CoreWmemDefault) case "CoreRmemDefault": global.Logs.Printf("系统环境Rmem Default :%s\n", t.CoreRmemDefault) case "CoreWmemMax": global.Logs.Printf("系统环境Wmem Max :%s\n", t.CoreWmemMax) } case *models.AppInfo: // 根据key设置对应字段的值 switch key { case "Gcc": global.Logs.Printf("基础包 GCC :%s\n", t.Gcc) case "Libaio": global.Logs.Printf("基础包 Libaio :%s\n", t.Libaio) case "Snmpd": global.Logs.Printf("基础包 Snmpd :%s\n", t.Snmpd) case "Ntpd": global.Logs.Printf("基础包 Ntpd :%s\n", t.Ntpd) } } }