feat: 网元版本操作升级和回退

This commit is contained in:
TsMask
2024-04-12 17:26:30 +08:00
parent b0e3825dd1
commit e87e5c3664
5 changed files with 212 additions and 1 deletions

View File

@@ -27,4 +27,9 @@ type INeVersion interface {
// CheckUniqueTypeAndID 校验网元类型和网元ID是否唯一
CheckUniqueTypeAndID(neType, neId, id string) bool
// Operate 操作版本上传到网元主机执行命令
//
// action 安装行为upgrade rollback
Operate(action string, neVersion model.NeVersion, preinput map[string]string) (string, error)
}

View File

@@ -2,7 +2,12 @@ package service
import (
"fmt"
"os"
"path/filepath"
"strings"
"time"
"be.ems/src/framework/utils/file"
"be.ems/src/modules/network_element/model"
"be.ems/src/modules/network_element/repository"
)
@@ -89,3 +94,146 @@ func (r *NeVersionImpl) CheckUniqueTypeAndID(neType, neId, id string) bool {
}
return uniqueId == ""
}
// Operate 操作版本上传到网元主机执行命令
//
// action 安装行为upgrade rollback
func (r *NeVersionImpl) Operate(action string, neVersion model.NeVersion, preinput map[string]string) (string, error) {
softwarePath := neVersion.Path
if action == "upgrade" {
softwarePath = neVersion.NewPath
}
if action == "rollback" {
softwarePath = neVersion.PrePath
}
// 检查文件是否存在
localFilePath := file.ParseUploadFilePath(softwarePath)
if _, err := os.Stat(localFilePath); err != nil {
return "", fmt.Errorf("file read failure")
}
fileName := filepath.Base(softwarePath)
if strings.Contains(fileName, "*") {
fileName = strings.ReplaceAll(fileName, "*", "_")
}
nePath := "/tmp"
neFilePath := fmt.Sprintf("%s/%s", nePath, fileName)
// 网元主机的SSH客户端
sshClient, err := NewNeInfoImpl.NeRunSSHclient(neVersion.NeType, neVersion.NeId)
if err != nil {
return "", err
}
defer sshClient.Close()
// 网元主机的SSH客户端进行文件传输
sftpClient, err := sshClient.NewClientSFTP()
if err != nil {
return "", err
}
defer sftpClient.Close()
// 上传软件包到 /tmp
if err = sftpClient.CopyFileLocalToRemote(localFilePath, neFilePath); err != nil {
return "", fmt.Errorf("error uploading package")
}
// ========= 安装命令 start =========
// 命令终止结束标记
okFlagStr := fmt.Sprintf("%s version %s successful!", neVersion.NeType, action)
// 安装软件包
pkgCmdStr := fmt.Sprintf("sudo dpkg -i %s", neFilePath)
fileExt := filepath.Ext(strings.ToLower(fileName))
if strings.HasSuffix(fileExt, "rpm") {
pkgCmdStr = fmt.Sprintf("sudo rpm -Uvh %s", neFilePath)
}
// 预先参数
cmdStrArr := []string{}
if neVersion.NeType == "OMC" {
cmdStrArr = append(cmdStrArr, "sudo /usr/local/omc/bin/omcsvc.sh stop")
cmdStrArr = append(cmdStrArr, pkgCmdStr)
cmdStrArr = append(cmdStrArr, "sudo /usr/local/omc/bin/omcsvc.sh restart")
return sshClient.RunCMD(fmt.Sprintf("nohup sh -c \"sleep 15s && %s\" > /dev/null 2>&1 & \n", strings.Join(cmdStrArr, " && ")))
} else if neVersion.NeType == "IMS" {
if !strings.Contains(strings.ToLower(fileName), "ims") {
return "", fmt.Errorf("error file package not ims")
}
cmdStrArr = append(cmdStrArr, "sudo ims-stop \n")
cmdStrArr = append(cmdStrArr, pkgCmdStr+" \n")
// P/I/S-CSCF Config 配置覆盖
if pisCSCF, ok := preinput["pisCSCF"]; ok && pisCSCF != "" {
cmdStrArr = append(cmdStrArr, fmt.Sprintf("%s \n", pisCSCF))
}
cmdStrArr = append(cmdStrArr, "sudo ims-start \n")
} else {
neTypeLower := strings.ToLower(neVersion.NeType)
cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo service %s stop \n", neTypeLower))
cmdStrArr = append(cmdStrArr, pkgCmdStr+" \n")
cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo service %s restart \n", neTypeLower))
}
// 删除软件包
cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo rm %s \n", neFilePath))
// 结束
cmdStrArr = append(cmdStrArr, fmt.Sprintf("echo '%s' \n", okFlagStr))
// ========= 安装命令 end =========
// ssh连接会话
clientSession, err := sshClient.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) // 完成信号
// 超时退出 30s
timeoutTicker := time.NewTicker(30 * time.Second)
defer timeoutTicker.Stop()
// 实时读取SSH消息直接输出
msTicker := time.NewTicker(100 * time.Millisecond)
defer msTicker.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 neVersion.NeType == "IMS" && strings.Contains(outputStr, "(P/I/S-CSCF Config)? <y/n>") {
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
}