diff --git a/src/modules/network_element/controller/ne_software.go b/src/modules/network_element/controller/ne_software.go index 03d1614c..54123045 100644 --- a/src/modules/network_element/controller/ne_software.go +++ b/src/modules/network_element/controller/ne_software.go @@ -151,40 +151,44 @@ func (s *NeSoftwareController) Remove(c *gin.Context) { c.JSON(200, result.OkMsg(msg)) } -// 网元软件包安装检查 +// 网元软件包安装 // -// POST /checkInstall -func (s *NeSoftwareController) CheckInstall(c *gin.Context) { +// POST /install +func (s *NeSoftwareController) Install(c *gin.Context) { language := ctx.AcceptLanguage(c) - var body model.NeSoftware + var body struct { + Action string `json:"action" binding:"required,oneof=install upgrade"` // 安装行为 + Software model.NeSoftware `json:"software" binding:"required"` // 软件包信息 + Preinput map[string]string `json:"preinput" binding:"required"` // 预先输入参数 + } err := c.ShouldBindBodyWith(&body, binding.JSON) - if err != nil || body.HostId == "" { + if err != nil || body.Software.HostId == "" { c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400"))) return } // 检查是否存在软件包记录 neSoftwares := s.neSoftwareService.SelectList(model.NeSoftware{ - NeType: body.NeType, - Name: body.Name, - Version: body.Version, + NeType: body.Software.NeType, + Name: body.Software.Name, + Version: body.Software.Version, }) if len(neSoftwares) <= 0 { - body.CreateBy = ctx.LoginUserToUserName(c) - body.ID = s.neSoftwareService.Insert(body) + body.Software.CreateBy = ctx.LoginUserToUserName(c) + body.Software.ID = s.neSoftwareService.Insert(body.Software) } else { neSoftware := neSoftwares[0] - neSoftware.Path = body.Path - neSoftware.Description = body.Description + neSoftware.Path = body.Software.Path + neSoftware.Description = body.Software.Description neSoftware.UpdateBy = ctx.LoginUserToUserName(c) s.neSoftwareService.Update(neSoftware) } // 进行安装检查 - cmdStrArr, err := s.neSoftwareService.UploadToNeHost(body) + output, err := s.neSoftwareService.InstallToNeHost(body.Action, body.Software, body.Preinput) if err != nil { - c.JSON(200, result.ErrMsg(err.Error())) + c.JSON(200, result.ErrMsg(i18n.TKey(language, err.Error()))) return } - c.JSON(200, result.OkData(cmdStrArr)) + c.JSON(200, result.OkData(output)) } diff --git a/src/modules/network_element/service/ne_software.go b/src/modules/network_element/service/ne_software.go index 5f5e10f2..9ecfc09d 100644 --- a/src/modules/network_element/service/ne_software.go +++ b/src/modules/network_element/service/ne_software.go @@ -25,7 +25,8 @@ type INeSoftware interface { // CheckUniqueTypeAndNameAndVersion 校验网元类型和文件名版本是否唯一 CheckUniqueTypeAndNameAndVersion(neType, name, version, id string) bool - // UploadToNeHost 安装包上传到网元主机 - // 返回执行命令步骤 - UploadToNeHost(neSoftware model.NeSoftware) ([]string, error) + // InstallToNeHost 安装包上传到网元主机执行安装命令 + // + // action 安装行为:install upgrade + InstallToNeHost(action string, neSoftware model.NeSoftware, preinput map[string]string) (string, error) } diff --git a/src/modules/network_element/service/ne_software.impl.go b/src/modules/network_element/service/ne_software.impl.go index 77783a33..0c4cd6fa 100644 --- a/src/modules/network_element/service/ne_software.impl.go +++ b/src/modules/network_element/service/ne_software.impl.go @@ -5,6 +5,7 @@ import ( "os" "path/filepath" "strings" + "time" "be.ems/src/framework/utils/file" "be.ems/src/framework/utils/ssh" @@ -47,26 +48,66 @@ func (r *NeSoftwareImpl) SelectById(id string) model.NeSoftware { // Insert 新增信息 func (r *NeSoftwareImpl) Insert(neSoftware model.NeSoftware) string { - return r.neSoftwareRepository.Insert(neSoftware) + inserId := r.neSoftwareRepository.Insert(neSoftware) + if inserId != "" { + // 更新同类型的新包版本 + neVersions := NewNeVersionImpl.SelectList(model.NeVersion{NeType: neSoftware.NeType}) + if len(neVersions) > 0 { + for _, neVersion := range neVersions { + neVersion.NewVersion = neSoftware.Version + neVersion.NewPath = neSoftware.Path + neVersion.Status = "3" + neVersion.UpdateBy = neSoftware.CreateBy + NewNeVersionImpl.Update(neVersion) + } + } + } + return inserId } // Update 修改信息 func (r *NeSoftwareImpl) Update(neSoftware model.NeSoftware) int64 { - return r.neSoftwareRepository.Update(neSoftware) + rows := r.neSoftwareRepository.Update(neSoftware) + if rows > 0 { + // 更新同类型的新包版本 + neVersions := NewNeVersionImpl.SelectList(model.NeVersion{ + NeType: neSoftware.NeType, + NewPath: neSoftware.Path, + Status: "3", + }) + if len(neVersions) > 0 { + for _, neVersion := range neVersions { + neVersion.NewVersion = neSoftware.Version + neVersion.UpdateBy = neSoftware.UpdateBy + NewNeVersionImpl.Update(neVersion) + } + } + } + return rows } // DeleteByIds 批量删除信息 func (r *NeSoftwareImpl) DeleteByIds(ids []string) (int64, error) { // 检查是否存在 - rowIds := r.neSoftwareRepository.SelectByIds(ids) - if len(rowIds) <= 0 { + rows := r.neSoftwareRepository.SelectByIds(ids) + if len(rows) <= 0 { return 0, fmt.Errorf("neSoftware.noData") } - if len(rowIds) == len(ids) { + if len(rows) == len(ids) { + // 遍历软件包列表进行文件删除 + for _, row := range rows { + // 检查文件是否存在 + filePath := file.ParseUploadFilePath(row.Path) + if _, err := os.Stat(filePath); err != nil { + continue + } + os.Remove(filePath) + } rows := r.neSoftwareRepository.DeleteByIds(ids) return rows, nil } + // 删除信息失败! return 0, fmt.Errorf("delete fail") } @@ -84,14 +125,14 @@ func (r *NeSoftwareImpl) CheckUniqueTypeAndNameAndVersion(neType, name, version, return uniqueId == "" } -// UploadToNeHost 安装包上传到网元主机 -// 返回执行命令步骤 -func (r *NeSoftwareImpl) UploadToNeHost(neSoftware model.NeSoftware) ([]string, error) { - cmdStrArr := []string{} +// InstallToNeHost 安装包上传到网元主机执行安装命令 +// +// action 安装行为:install upgrade +func (r *NeSoftwareImpl) InstallToNeHost(action string, neSoftware model.NeSoftware, preinput map[string]string) (string, error) { // 检查文件是否存在 filePath := file.ParseUploadFilePath(neSoftware.Path) if _, err := os.Stat(filePath); err != nil { - return cmdStrArr, fmt.Errorf("file read failure") + return "", fmt.Errorf("file read failure") } fileName := filepath.Base(neSoftware.Path) if strings.Contains(fileName, "*") { @@ -103,35 +144,132 @@ func (r *NeSoftwareImpl) UploadToNeHost(neSoftware model.NeSoftware) ([]string, // 检查网元主机 neHostInfo := NewNeHostImpl.SelectById(neSoftware.HostId) if neHostInfo.HostType != "ssh" || neHostInfo.HostID != neSoftware.HostId { - return cmdStrArr, fmt.Errorf("no found host info") + return "", fmt.Errorf("no found host info") } // 上传软件包到 /tmp if err := ssh.FileSCPLocalToNe(neHostInfo.Addr, filePath, neFilePath); err != nil { - return cmdStrArr, fmt.Errorf("error uploading package") + return "", fmt.Errorf("error uploading package") } + // ========= 安装命令 start ========= + cmdStrArr := []string{} + // 命令终止结束标记 + okFlagStr := fmt.Sprintf("%s software %s successful!", neSoftware.NeType, action) // 安装软件包 - cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo dpkg -i %s", neFilePath)) + cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo dpkg -i %s \n", neFilePath)) + // 预先参数 if neSoftware.NeType == "IMS" { + if !strings.Contains(fileName, "ims") { + return "", fmt.Errorf("error file package not ims") + } + // P/I/S-CSCF Config 配置覆盖 + if pisCSCF, ok := preinput["pisCSCF"]; ok && pisCSCF != "" { + cmdStrArr = append(cmdStrArr, fmt.Sprintf("%s \n", pisCSCF)) + } // 公网 PLMN地址 - cmdStrArr = append(cmdStrArr, "sudo /usr/local/etc/ims/default/tools/modipplmn.sh {PUBIP} {MCC} {MNC}") + pubIP, pubIPOk := preinput["pubIP"] + mcc, mccOk := preinput["mcc"] + mnc, mncOk := preinput["mnc"] + if pubIPOk && pubIP != "" && mccOk && mcc != "" && mncOk && mnc != "" { + cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo /usr/local/etc/ims/default/tools/modipplmn.sh %s %s %s \n", pubIP, mcc, mnc)) + } // 内网 服务地址 - cmdStrArr = append(cmdStrArr, "sudo /usr/local/etc/ims/default/tools/modintraip.sh {PRIIP}") - // 10s后停止服务 + if priIP, ok := preinput["priIP"]; ok && priIP != "" { + cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo /usr/local/etc/ims/default/tools/modintraip.sh %s \n", priIP)) + } cmdStrArr = append(cmdStrArr, "sudo ims-start") - cmdStrArr = append(cmdStrArr, `nohup sh -c "sleep 10s && sudo ims-stop" > /dev/null 2>&1 &`) - } else { // 10s后停止服务 - cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo service %s restart", strings.ToLower(neSoftware.NeType))) - cmdStrArr = append(cmdStrArr, fmt.Sprintf(`nohup sh -c "sleep 10s && sudo service %s stop" > /dev/null 2>&1 &`, strings.ToLower(neSoftware.NeType))) + if action == "install" { + cmdStrArr = append(cmdStrArr, "nohup sh -c \"sleep 15s && sudo ims-stop\" > /dev/null 2>&1 & \n") + } + } else if neSoftware.NeType == "OMC" { + cmdStrArr = append(cmdStrArr, "sudo /usr/local/omc/bin/omcsvc.sh restart \n") + // 10s后停止服务 + if action == "install" { + cmdStrArr = append(cmdStrArr, "nohup sh -c \"sleep 15s && sudo /usr/local/omc/bin/omcsvc.sh stop\" > /dev/null 2>&1 & \n") + } + } else { + neTypeLower := strings.ToLower(neSoftware.NeType) + cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo service %s restart \n", neTypeLower)) + // 10s后停止服务 + if action == "install" { + cmdStrArr = append(cmdStrArr, fmt.Sprintf("nohup sh -c \"sleep 15s && sudo service %s stop\" > /dev/null 2>&1 & \n", neTypeLower)) + } } // 删除软件包 - cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo rm %s", neFilePath)) - + cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo rm %s \n", neFilePath)) // 结束 - cmdStrArr = append(cmdStrArr, fmt.Sprintf("echo '%s software install successful!'", neSoftware.NeType)) - return cmdStrArr, nil + cmdStrArr = append(cmdStrArr, fmt.Sprintf("echo '%s' \n", okFlagStr)) + // ========= 安装命令 end ========= + + // ssh连接客户端 + var connSSH ssh.ConnSSH + neHostInfo.CopyTo(&connSSH) + client, err := connSSH.NewClient() + if err != nil { + return "", fmt.Errorf("neinfo ssh client new err") + } + defer client.Close() + // ssh连接会话 + clientSession, err := client.NewClientSession(80, 24) + if err != nil { + return "", fmt.Errorf("neinfo ssh client session new err") + } + defer clientSession.Close() + + firstRead := true // 首次命令进行记录日志信息 + logMsg := "" // 日志信息 + done := make(chan bool) // 完成信号 + // 实时读取SSH消息直接输出 + msTicker := time.NewTicker(100 * time.Millisecond) + defer msTicker.Stop() + // 超时退出 + timeoutTicker := time.NewTicker(30 * time.Second) + defer timeoutTicker.Stop() + go func() { + for { + select { + case <-timeoutTicker.C: + done <- true + return + case <-msTicker.C: + outputByte := clientSession.Read() + if len(outputByte) > 0 { + outputStr := string(outputByte) + // 非首次进行记录命令 + if !firstRead { + logMsg += outputStr + } + // IMS预输入 + if neSoftware.NeType == "IMS" && strings.Contains(outputStr, "(P/I/S-CSCF Config)? ") { + shiftElement := cmdStrArr[0] // 获取第一个元素 + cmdStrArr = cmdStrArr[1:] // 将第一个元素从切片中移除 + clientSession.Write(shiftElement) + continue + } + // 命令终止符后继续执行命令 + if len(cmdStrArr) > 0 && strings.LastIndex(outputStr, "~$ ") > 2 { + if firstRead { + firstRead = false + } + shiftElement := cmdStrArr[0] // 获取第一个元素 + cmdStrArr = cmdStrArr[1:] // 将第一个元素从切片中移除 + clientSession.Write(shiftElement) + continue + } + // 最后输出的退出标记 + if strings.LastIndex(outputStr, okFlagStr) > 5 { + done <- true + break + } + } + } + } + }() + // 等待写入协程完成 + <-done + return logMsg, nil }