Files
be.ems/src/modules/network_element/service/ne_software.impl.go
2024-04-11 19:59:45 +08:00

274 lines
8.2 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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"
)
// 实例化服务层 NeSoftwareImpl 结构体
var NewNeSoftwareImpl = &NeSoftwareImpl{
neSoftwareRepository: repository.NewNeSoftwareImpl,
}
// NeSoftwareImpl 网元软件包信息 服务层处理
type NeSoftwareImpl struct {
// 网元软件包信息
neSoftwareRepository repository.INeSoftware
}
// SelectNeHostPage 分页查询列表数据
func (r *NeSoftwareImpl) SelectPage(query map[string]any) map[string]any {
return r.neSoftwareRepository.SelectPage(query)
}
// SelectConfigList 查询列表
func (r *NeSoftwareImpl) SelectList(neSoftware model.NeSoftware) []model.NeSoftware {
return r.neSoftwareRepository.SelectList(neSoftware)
}
// SelectByIds 通过ID查询
func (r *NeSoftwareImpl) SelectById(id string) model.NeSoftware {
if id == "" {
return model.NeSoftware{}
}
neHosts := r.neSoftwareRepository.SelectByIds([]string{id})
if len(neHosts) > 0 {
return neHosts[0]
}
return model.NeSoftware{}
}
// Insert 新增信息
func (r *NeSoftwareImpl) Insert(neSoftware model.NeSoftware) string {
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 {
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) {
// 检查是否存在
rows := r.neSoftwareRepository.SelectByIds(ids)
if len(rows) <= 0 {
return 0, fmt.Errorf("neSoftware.noData")
}
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")
}
// CheckUniqueTypeAndNameAndVersion 校验网元类型和文件名版本是否唯一
func (r *NeSoftwareImpl) CheckUniqueTypeAndNameAndVersion(neType, name, version, id string) bool {
uniqueId := r.neSoftwareRepository.CheckUniqueTypeAndNameAndVersion(model.NeSoftware{
NeType: neType,
Name: name,
Version: version,
})
if uniqueId == id {
return true
}
return uniqueId == ""
}
// InstallToNeHost 安装包上传到网元主机执行安装命令
//
// action 安装行为install upgrade
func (r *NeSoftwareImpl) InstallToNeHost(action string, neSoftware model.NeSoftware, preinput map[string]string) (string, error) {
// 检查文件是否存在
localFilePath := file.ParseUploadFilePath(neSoftware.Path)
if _, err := os.Stat(localFilePath); err != nil {
return "", fmt.Errorf("file read failure")
}
fileName := filepath.Base(neSoftware.Path)
if strings.Contains(fileName, "*") {
fileName = strings.ReplaceAll(fileName, "*", "_")
}
nePath := "/tmp"
neFilePath := fmt.Sprintf("%s/%s", nePath, fileName)
// 网元主机的SSH客户端
sshClient, err := NewNeInfoImpl.NeRunSSHclient(neSoftware.NeType, neSoftware.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 =========
cmdStrArr := []string{}
// 命令终止结束标记
okFlagStr := fmt.Sprintf("%s software %s successful!", neSoftware.NeType, action)
// 安装软件包
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地址
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))
}
// 内网 服务地址
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")
// 10s后停止服务
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 \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 neSoftware.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
}