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.NewName = neSoftware.Name 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, Status: "3", }) if len(neVersions) > 0 { for _, neVersion := range neVersions { neVersion.NewName = neSoftware.Name neVersion.NewVersion = neSoftware.Version neVersion.NewPath = neSoftware.Path neVersion.Status = "3" 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 == "" } // UpdateVersions 更新软件包对应网元的新版本 func (r *NeSoftwareImpl) UpdateVersions(neSoftware model.NeSoftware, neVersion model.NeVersion) int64 { var rows int64 = 0 // 更新同类型的新包版本 neVersions := NewNeVersionImpl.SelectList(neVersion) if len(neVersions) > 0 { for _, v := range neVersions { v.NewName = neSoftware.Name v.NewVersion = neSoftware.Version v.NewPath = neSoftware.Path v.Status = "3" v.UpdateBy = neVersion.UpdateBy rows += NewNeVersionImpl.Update(v) } } return rows } // InstallToNeHost 安装包上传到网元主机执行安装命令 func (r *NeSoftwareImpl) InstallToNeHost(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 ========= // 命令终止结束标记 okFlagStr := fmt.Sprintf("%s software install successful!", neSoftware.NeType) // 安装软件包 pkgCmdStr := fmt.Sprintf("sudo dpkg -i %s \n", neFilePath) fileExt := filepath.Ext(strings.ToLower(fileName)) if strings.HasSuffix(fileExt, "rpm") { pkgCmdStr = fmt.Sprintf("sudo rpm -Uvh %s \n", neFilePath) } // 预先参数 cmdStrArr := []string{pkgCmdStr} if neSoftware.NeType == "IMS" { if !strings.Contains(strings.ToLower(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后停止服务 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后停止服务 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后停止服务 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)? ") { 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 // 执行到最后语句的更新Version if strings.LastIndex(logMsg, okFlagStr) > 5 { verInfo := NewNeVersionImpl.SelectByNeTypeAndNeID(neSoftware.NeType, neSoftware.NeId) if verInfo.NeId == neSoftware.NeId { verInfo.Name = neSoftware.Name verInfo.Version = neSoftware.Version verInfo.Path = neSoftware.Path verInfo.NewName = "-" verInfo.NewVersion = "-" verInfo.NewPath = "-" verInfo.Status = "1" NewNeVersionImpl.Update(verInfo) } } return logMsg, nil }