1
0

merge: 合并代码20240531

This commit is contained in:
TsMask
2024-06-01 18:56:18 +08:00
parent 3cc193f57d
commit 3b50e2f3f8
129 changed files with 3705 additions and 11065 deletions

View File

@@ -8,6 +8,7 @@ import (
"be.ems/src/framework/errorcatch"
"be.ems/src/framework/middleware"
"be.ems/src/framework/middleware/security"
"be.ems/src/framework/utils/machine"
"be.ems/src/modules/chart"
"be.ems/src/modules/common"
"be.ems/src/modules/crontask"
@@ -18,7 +19,9 @@ import (
"be.ems/src/modules/trace"
"be.ems/src/modules/ws"
"github.com/chenjiandongx/ginprom"
"github.com/gin-gonic/gin"
"github.com/prometheus/client_golang/prometheus/promhttp"
)
//go:embed assets/*
@@ -28,6 +31,13 @@ var assetsDir embed.FS
func AppEngine() *gin.Engine {
app := initAppEngine()
// TODO 不建议在主分支中加入
// 性能分析监控
if promEnabled := config.Get("pprof.enabled"); promEnabled != nil && promEnabled.(bool) {
app.Use(ginprom.PromMiddleware(nil))
app.GET("/metrics", ginprom.PromHandler(promhttp.Handler()))
}
// 初始全局默认
initDefeat(app)
@@ -37,6 +47,9 @@ func AppEngine() *gin.Engine {
// 设置程序内全局资源访问
config.SetAssetsDirFS(assetsDir)
// 首次安装启动记录
machine.Launch()
// 读取服务配置
app.ForwardedByClientIP = config.Get("server.proxy").(bool)
return app
@@ -108,7 +121,7 @@ func initDefeat(app *gin.Engine) {
app.NoRoute(func(c *gin.Context) {
c.JSON(404, gin.H{
"code": 404,
"msg": fmt.Sprintf("%s Not Found", c.Request.RequestURI),
"msg": fmt.Sprintf("Not Found %s", c.Request.RequestURI),
})
})
}

View File

@@ -1,7 +1,7 @@
# 项目信息
framework:
name: "CN EMS"
version: "2.2404.6"
version: "2.2405.4"
# 应用服务配置
server:
@@ -15,7 +15,7 @@ logger:
fileDir: "/var/log"
fileName: "omc.log"
level: 2 # 日志记录的等级 0:silent<1:info<2:warn<3:error
maxDay: 180 # 日志会保留 180 天
maxDay: 7 # 日志会保留 180 天
maxSize: 10 # 调整按 10MB 大小的切割
# 静态文件配置, 相对项目根路径或填绝对路径

View File

@@ -19,3 +19,6 @@ const STATUS_NO = "0"
// 上下文信息-登录用户
const CTX_LOGIN_USER = "loginuser"
// 启动-引导系统初始
const LAUNCH_BOOTLOADER = "bootloader"

View File

@@ -34,7 +34,7 @@ const (
// NewLogger 实例日志器对象
func NewLogger(env, fileDir, fileName string, level, maxDay, maxSize int) (*Logger, error) {
logFilePath := filepath.Join(fileDir, fileName)
if err := os.MkdirAll(filepath.Dir(logFilePath), 0750); err != nil {
if err := os.MkdirAll(filepath.Dir(logFilePath), 0775); err != nil {
return nil, fmt.Errorf("failed to mkdir logger dir: %v", err)
}
fileHandle, err := os.OpenFile(logFilePath, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)

View File

@@ -10,21 +10,17 @@ import (
"io"
)
// aesKey 字符串AES加解密密钥
const aesKey = "AGT66VfY4SMaiT97"
// StringEncryptByAES 字符串AES加密
func StringEncryptByAES(text string) (string, error) {
if len(text) == 0 {
return "", nil
}
pass := []byte(text)
xpass, err := aesEncryptWithSalt([]byte(aesKey), pass)
if err == nil {
pass64 := base64.StdEncoding.EncodeToString(xpass)
return pass64, err
xpass, err := aesEncryptWithSalt([]byte(text))
if err != nil {
return "", err
}
return "", err
pass64 := base64.StdEncoding.EncodeToString(xpass)
return pass64, nil
}
// StringDecryptByAES 字符串AES解密
@@ -36,53 +32,70 @@ func StringDecryptByAES(text string) (string, error) {
if err != nil {
return "", err
}
var tpass []byte
tpass, err = aesDecryptWithSalt([]byte(aesKey), bytesPass)
if err == nil {
result := string(tpass[:])
return result, err
tpass, err := aesDecryptWithSalt(bytesPass)
if err != nil {
return "", err
}
return "", err
return string(tpass), nil
}
// aesEncryptWithSalt AES加密
func aesEncryptWithSalt(key, plaintext []byte) ([]byte, error) {
blockSize := aes.BlockSize
padding := blockSize - len(plaintext)%blockSize
padtext := bytes.Repeat([]byte{byte(padding)}, padding)
plaintext = append(plaintext, padtext...)
// aesKey 字符串AES加解密密钥
const aesKey = "AGT66VfY4SMaiT97a7df0aef1704d5c5"
block, err := aes.NewCipher(key)
// const aesKey = "AGT66VfY4SMaiT97"
// aesEncryptWithSalt AES加密
func aesEncryptWithSalt(plaintext []byte) ([]byte, error) {
block, err := aes.NewCipher([]byte(aesKey))
if err != nil {
return nil, err
}
blockSize := aes.BlockSize
padding := blockSize - (len(plaintext) % blockSize)
padtext := bytes.Repeat([]byte{byte(padding)}, padding)
plaintext = append(plaintext, padtext...)
ciphertext := make([]byte, blockSize+len(plaintext))
iv := ciphertext[0:blockSize]
iv := ciphertext[:blockSize]
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
return nil, err
}
cbc := cipher.NewCBCEncrypter(block, iv)
cbc.CryptBlocks(ciphertext[blockSize:], plaintext)
mode := cipher.NewCBCEncrypter(block, iv)
mode.CryptBlocks(ciphertext[blockSize:], plaintext)
return ciphertext, nil
}
// aesDecryptWithSalt AES解密
func aesDecryptWithSalt(key, ciphertext []byte) ([]byte, error) {
func aesDecryptWithSalt(ciphertext []byte) ([]byte, error) {
blockSize := aes.BlockSize
var block cipher.Block
block, err := aes.NewCipher(key)
if len(ciphertext) < blockSize {
return nil, fmt.Errorf("ciphertext too short")
}
iv := ciphertext[:blockSize]
ciphertext = ciphertext[blockSize:]
block, err := aes.NewCipher([]byte(aesKey))
if err != nil {
return nil, err
}
if len(ciphertext) < blockSize {
return nil, fmt.Errorf("iciphertext too short")
if len(ciphertext)%blockSize != 0 {
return nil, fmt.Errorf("ciphertext is not a multiple of the block size")
}
iv := ciphertext[:blockSize]
ciphertext = ciphertext[blockSize:]
cbc := cipher.NewCBCDecrypter(block, iv)
cbc.CryptBlocks(ciphertext, ciphertext)
length := len(ciphertext)
unpadding := int(ciphertext[len(ciphertext)-1])
ciphertext = ciphertext[:(length - unpadding)]
mode := cipher.NewCBCDecrypter(block, iv)
mode.CryptBlocks(ciphertext, ciphertext)
// 去除填充
padding := int(ciphertext[len(ciphertext)-1])
if padding > blockSize || padding == 0 {
return nil, fmt.Errorf("invalid padding")
}
ciphertext = ciphertext[:len(ciphertext)-padding]
return ciphertext, nil
}

View File

@@ -20,7 +20,7 @@ func WriterFileCSV(data [][]string, filePath string) error {
dirPath := filepath.Dir(filePath)
// 确保文件夹路径存在
err := os.MkdirAll(dirPath, os.ModePerm)
err := os.MkdirAll(dirPath, 0775)
if err != nil {
logger.Errorf("MkdirAll dir %v", err)
}

View File

@@ -142,7 +142,7 @@ func WriteSheet(headerCells map[string]string, dataCells []map[string]any, fileN
saveFilePath := filepath.Join(dir, filePath, fileName)
// 创建文件目录
if err := os.MkdirAll(filepath.Dir(saveFilePath), 0750); err != nil {
if err := os.MkdirAll(filepath.Dir(saveFilePath), 0775); err != nil {
return "", fmt.Errorf("failed to create save file %v", err)
}

View File

@@ -177,13 +177,13 @@ func ReadUploadFileStream(filePath, headerRange string) (map[string]any, error)
"range": "",
"chunkSize": 0,
"fileSize": 0,
"data": nil,
"data": []byte{},
}
// 文件大小
fileSize := getFileSize(fileAsbPath)
if fileSize <= 0 {
return result, nil
return result, fmt.Errorf("file does not exist")
}
result["fileSize"] = fileSize
@@ -312,12 +312,12 @@ func CopyUploadFile(filePath, dst string) error {
}
defer src.Close()
if err := os.MkdirAll(filepath.Dir(dst), 0750); err != nil {
if err := os.MkdirAll(filepath.Dir(dst), 0775); err != nil {
return err
}
// 如果目标文件已经存在,先将目标文件重命名
if _, err := os.Stat(dst); err == nil {
if info, err := os.Stat(dst); err == nil && !info.IsDir() {
ext := filepath.Ext(dst)
name := dst[0 : len(dst)-len(ext)]
newName := fmt.Sprintf("%s-%s%s", name, time.Now().Format("20060102_150405"), ext)

View File

@@ -16,7 +16,7 @@ func WriterFileJSON(data any, filePath string) error {
dirPath := filepath.Dir(filePath)
// 确保文件夹路径存在
err := os.MkdirAll(dirPath, os.ModePerm)
err := os.MkdirAll(dirPath, 0775)
if err != nil {
logger.Errorf("CreateFile MkdirAll %v", err)
}
@@ -46,7 +46,7 @@ func WriterFileJSONLine(data []any, filePath string) error {
dirPath := filepath.Dir(filePath)
// 确保文件夹路径存在
err := os.MkdirAll(dirPath, os.ModePerm)
err := os.MkdirAll(dirPath, 0775)
if err != nil {
logger.Errorf("CreateFile MkdirAll %v", err)
}

View File

@@ -22,7 +22,7 @@ func WriterFileTXT(data [][]string, sep string, filePath string) error {
dirPath := filepath.Dir(filePath)
// 确保文件夹路径存在
err := os.MkdirAll(dirPath, os.ModePerm)
err := os.MkdirAll(dirPath, 0775)
if err != nil {
logger.Errorf("CreateFile MkdirAll %v", err)
}

View File

@@ -26,7 +26,7 @@ func transferToNewFile(file *multipart.FileHeader, dst string) error {
}
defer src.Close()
if err = os.MkdirAll(filepath.Dir(dst), 0750); err != nil {
if err = os.MkdirAll(filepath.Dir(dst), 0775); err != nil {
return err
}
@@ -66,7 +66,7 @@ func mergeToNewFile(dirPath string, writePath string, fileName string) error {
// 写入到新路径文件
newFilePath := filepath.Join(writePath, fileName)
if err = os.MkdirAll(filepath.Dir(newFilePath), 0750); err != nil {
if err = os.MkdirAll(filepath.Dir(newFilePath), 0775); err != nil {
return err
}

View File

@@ -0,0 +1,178 @@
package machine
import (
"encoding/json"
"fmt"
"hash/fnv"
"os"
"runtime"
"time"
"be.ems/src/framework/constants/common"
"be.ems/src/framework/logger"
"be.ems/src/framework/utils/cmd"
"be.ems/src/framework/utils/crypto"
"be.ems/src/framework/utils/parse"
)
// 机器的唯一标识符
var Code string
// 初始信息
var LaunchInfo map[string]any
// codeGenerate 生成机器的唯一标识符
func codeGenerate() string {
var machineID string
// 获取主机名
hostname, err := os.Hostname()
if err != nil {
panic(err)
}
machineID += hostname
// 获取 CPU 信息
numCPU := runtime.NumCPU()
machineID += fmt.Sprintf("%d", numCPU)
// 获取操作系统信息
osInfo := runtime.GOOS
machineID += osInfo
// 使用哈希函数生成机器码
h := fnv.New32a()
h.Write([]byte(machineID))
machineCode := h.Sum32()
return fmt.Sprintf("%x", machineCode)
}
// 网管本地路径
func filePath() string {
filePath := "/usr/local/etc/omc/machine.ini"
if runtime.GOOS == "windows" {
filePath = fmt.Sprintf("C:%s", filePath)
}
return filePath
}
// codeFileRead 读取机器保留的信息
func codeFileRead() (map[string]any, error) {
var mapData map[string]any
// 读取文件内容
bytes, err := os.ReadFile(filePath())
if err != nil {
logger.Warnf("CodeFileRead ReadFile => %s", err.Error())
return mapData, fmt.Errorf("not file")
}
content := string(bytes)
// 解密
contentDe, err := crypto.StringDecryptByAES(content)
if err != nil {
logger.Errorf("CodeFileRead decrypt: %v", err.Error())
return mapData, fmt.Errorf("decrypt fail")
}
// 序列化Map
mapData, err = parse.ConvertConfigToMap("json", string(contentDe))
if err != nil {
logger.Warnf("NeConfPara5GRead ConvertConfigToMap => %s", err.Error())
return mapData, fmt.Errorf("content error")
}
return mapData, nil
}
// codeFileWrite 写入机器保留的信息
func codeFileWrite(data map[string]any) error {
jsonByte, _ := json.Marshal(data)
// 加密
contentEn, err := crypto.StringEncryptByAES(string(jsonByte))
if err != nil {
logger.Errorf("insert encrypt: %v", err.Error())
return fmt.Errorf("encrypt fail")
}
return parse.ConvertConfigToFile("txt", filePath(), contentEn)
}
// Launch 记录首次安装启动初始信息
func Launch() {
Code = codeGenerate()
// 检查文件是否存在
if _, err := os.Stat(filePath()); err != nil {
LaunchInfo = map[string]any{
"code": Code, // 机器码
"useTime": time.Now().UnixMilli(), // 首次使用时间
common.LAUNCH_BOOTLOADER: true, // 启动引导
common.LAUNCH_BOOTLOADER + "Time": 0, // 引导完成时间
}
codeFileWrite(LaunchInfo)
} else {
// 读取记录文件
data, err := codeFileRead()
if err != nil {
// 文件异常就重新生成
os.Remove(filePath())
Launch()
return
}
LaunchInfo = data
}
}
// SetLaunchInfo 新增额外的初始信息
func SetLaunchInfo(info map[string]any) error {
if info == nil {
return fmt.Errorf("not info")
}
// 固定值禁止变更
constKeys := []string{"code", "useTime"}
for k, v := range info {
constKey := false
for _, ck := range constKeys {
if ck == k {
constKey = true
break
}
}
if constKey {
continue
} else {
LaunchInfo[k] = v
}
}
return codeFileWrite(LaunchInfo)
}
// Bootloader 启动引导标记
func Bootloader(flag bool) error {
return SetLaunchInfo(map[string]any{
common.LAUNCH_BOOTLOADER: flag, // 启动引导 true开 false关
common.LAUNCH_BOOTLOADER + "Time": time.Now().UnixMilli(), // 引导完成时间
})
}
// Reset 引导数据重置
func Reset() error {
// 重置数据库
if runtime.GOOS == "windows" {
// return fmt.Errorf("not support window")
} else {
// 重置数据库
if _, err := cmd.Execf("sudo /usr/local/omc/bin/setomc.sh -m install"); err != nil {
return err
}
// 重启服务
if _, err := cmd.Execf("nohup sh -c \"sleep 1s && %s\" > /dev/null 2>&1 &", "sudo systemctl restart restagent"); err != nil {
return err
}
}
// 重置引导标记
if err := Bootloader(true); err != nil {
return err
}
return nil
}

View File

@@ -1,8 +1,11 @@
package parse
import (
"encoding/json"
"fmt"
"image/color"
"os"
"path/filepath"
"reflect"
"regexp"
"strconv"
@@ -10,6 +13,7 @@ import (
"time"
"github.com/robfig/cron/v3"
"gopkg.in/yaml.v3"
)
// Number 解析数值型
@@ -51,6 +55,8 @@ func Boolean(str any) bool {
case float32, float64:
num := reflect.ValueOf(str).Float()
return num != 0
case bool:
return str
default:
return false
}
@@ -165,3 +171,83 @@ func Color(colorStr string) *color.RGBA {
A: 255, // 不透明
}
}
// ConvertIPMask 转换IP网络地址掩码 24 -> 255.255.255.0
func ConvertIPMask(bits int64) string {
if bits < 0 || bits > 32 {
return "Invalid Mask Bits"
}
// 构建一个32位的uint32类型掩码指定前bits位为1其余为0
mask := uint32((1<<bits - 1) << (32 - bits))
// 将掩码转换为四个八位分组
groups := []string{
fmt.Sprintf("%d", mask>>24),
fmt.Sprintf("%d", (mask>>16)&255),
fmt.Sprintf("%d", (mask>>8)&255),
fmt.Sprintf("%d", mask&255),
}
// 将分组用点号连接起来形成掩码字符串
return strings.Join(groups, ".")
}
// ConvertConfigToMap 将配置内容转换为Map结构数据
//
// configType 类型支持txt json yaml yml
func ConvertConfigToMap(configType, content string) (map[string]any, error) {
// 类型支持viper.SupportedExts
// config := viper.New()
// config.SetConfigType(configType)
// err := config.ReadConfig(bytes.NewBuffer([]byte(content)))
// return config.AllSettings(), err
var configMap map[string]interface{}
var err error
if configType == "" || configType == "txt" {
configMap = map[string]interface{}{
"txt": content,
}
}
if configType == "yaml" || configType == "yml" {
err = yaml.Unmarshal([]byte(content), &configMap)
}
if configType == "json" {
err = json.Unmarshal([]byte(content), &configMap)
}
return configMap, err
}
// ConvertConfigToFile 将数据写入到指定文件内
//
// configType 类型支持txt json yaml yml
func ConvertConfigToFile(configType, filePath string, data any) error {
// viper.SupportedExts
// config := viper.New()
// config.SetConfigType(configType)
// for key, value := range mapData {
// config.Set(key, value)
// }
// return config.WriteConfigAs(filePath)
var dataByte []byte
var err error
if configType == "" || configType == "txt" {
dataByte = []byte(data.(string))
}
if configType == "yaml" || configType == "yml" {
dataByte, err = yaml.Marshal(data)
}
if configType == "json" {
dataByte, err = json.Marshal(data)
}
if err != nil {
return err
}
if err := os.MkdirAll(filepath.Dir(filePath), 0775); err != nil {
return err
}
return os.WriteFile(filePath, dataByte, 0644)
}

View File

@@ -20,7 +20,7 @@ func PageNumSize(pageNum, pageSize any) (int64, int64) {
// 显示记录数
size := parse.Number(pageSize)
if size < 0 {
if size < 1 {
size = 10
}
return num - 1, size

View File

@@ -28,7 +28,7 @@ func FileSCPLocalToNe(neIp, localPath, nePath string) error {
// 网元NE 远程文件复制到本地文件
func FileSCPNeToLocal(neIp, nePath, localPath string) error {
// 确保文件夹路径存在
if err := os.MkdirAll(filepath.Dir(localPath), 0750); err != nil {
if err := os.MkdirAll(filepath.Dir(localPath), 0775); err != nil {
logger.Errorf("FileSCPNeToLocal MkdirAll err %v", err)
return err
}

View File

@@ -6,12 +6,14 @@ import (
"io"
"os"
"os/user"
"path/filepath"
"strings"
"sync"
"time"
"be.ems/src/framework/logger"
"be.ems/src/framework/utils/cmd"
gosftp "github.com/pkg/sftp"
gossh "golang.org/x/crypto/ssh"
)
@@ -133,8 +135,12 @@ func (c *ConnSSH) SendToAuthorizedKeys() error {
return err
}
authorizedKeysEntry := fmt.Sprintln(strings.TrimSpace(publicKey))
cmdStr := "echo '" + authorizedKeysEntry + "' >> ~/.ssh/authorized_keys"
_, err = c.RunCMD(cmdStr)
cmdStrArr := []string{
fmt.Sprintf("sudo mkdir -p /home/%s/.ssh && sudo chown %s:%s /home/%s/.ssh && sudo chmod 700 /home/%s/.ssh", c.User, c.User, c.User, c.User, c.User),
fmt.Sprintf("sudo touch /home/%s/.ssh/authorized_keys && sudo chown %s:%s /home/%s/.ssh/authorized_keys && sudo chmod 600 /home/%s/.ssh/authorized_keys", c.User, c.User, c.User, c.User, c.User),
fmt.Sprintf("echo '%s' | sudo tee -a /home/%s/.ssh/authorized_keys", authorizedKeysEntry, c.User),
}
_, err = c.RunCMD(strings.Join(cmdStrArr, " && "))
if err != nil {
logger.Errorf("SendAuthorizedKeys echo err %s", err.Error())
return err
@@ -156,9 +162,8 @@ func (c *ConnSSH) CurrentUserRsaKey(publicKey bool) (string, error) {
// 是否存在私钥并创建
keyPath := fmt.Sprintf("%s/.ssh/id_rsa", usr.HomeDir)
if _, err := os.Stat(keyPath); err != nil {
_, err2 := cmd.ExecWithCheck("ssh-keygen", "-t", "rsa", "-P", "", "-f", keyPath)
if err2 != nil {
logger.Errorf("CurrentUserPrivateKey ssh-keygen [%s] rsa => %s", usr.Username, err2.Error())
if _, err := cmd.ExecWithCheck("ssh-keygen", "-t", "rsa", "-P", "", "-f", keyPath); err != nil {
logger.Errorf("CurrentUserPrivateKey ssh-keygen [%s] rsa => %s", usr.Username, err.Error())
}
}
@@ -239,12 +244,11 @@ func (s *SSHClientSession) Write(cmd string) (int, error) {
return s.Stdin.Write([]byte(cmd))
}
// Read 读取结果 等待一会才有结果
// Read 读取结果
func (s *SSHClientSession) Read() []byte {
if s.Stdout == nil {
return []byte{}
}
// time.Sleep(300 * time.Millisecond)
bs := s.Stdout.Bytes()
if len(bs) > 0 {
s.Stdout.Reset()
@@ -253,15 +257,6 @@ func (s *SSHClientSession) Read() []byte {
return []byte{}
}
// CombinedOutput 发送命令带结果返回
func (s *SSHClientSession) CombinedOutput(cmd string) (string, error) {
n, err := s.Write(cmd)
if n == 0 || err != nil {
return "", err
}
return string(s.Read()), nil
}
// singleWriter SSH客户端会话消息
type singleWriter struct {
b bytes.Buffer
@@ -283,3 +278,208 @@ func (w *singleWriter) Reset() {
defer w.mu.Unlock()
w.b.Reset()
}
// NewClientSFTP 创建SSH客户端SFTP对象
func (c *ConnSSH) NewClientSFTP() (*SSHClientSFTP, error) {
sftpClient, err := gosftp.NewClient(c.Client)
if err != nil {
logger.Errorf("NewClientSFTP failed to create sftp: => %s", err.Error())
return nil, err
}
return &SSHClientSFTP{
Client: sftpClient,
}, nil
}
// SSHClientSFTP SSH客户端SFTP对象
type SSHClientSFTP struct {
Client *gosftp.Client
}
// Close 关闭会话
func (s *SSHClientSFTP) Close() {
if s.Client != nil {
s.Client.Close()
}
}
// CopyDirRemoteToLocal 复制目录-远程到本地
func (s *SSHClientSFTP) CopyDirRemoteToLocal(remoteDir, localDir string) error {
// 列出远程目录中的文件和子目录
remoteFiles, err := s.Client.ReadDir(remoteDir)
if err != nil {
logger.Errorf("CopyDirRemoteToLocal failed to reading remote directory %s: => %s", remoteDir, err.Error())
return err
}
// 创建本地目录
err = os.MkdirAll(localDir, 0775)
if err != nil {
logger.Errorf("CopyDirRemoteToLocal failed to creating local directory %s: => %s", localDir, err.Error())
return err
}
// 遍历远程文件和子目录并复制到本地
for _, remoteFile := range remoteFiles {
remotePath := filepath.Join(remoteDir, remoteFile.Name())
localPath := filepath.Join(localDir, remoteFile.Name())
if remoteFile.IsDir() {
// 如果是子目录,则递归复制子目录
err = s.CopyDirRemoteToLocal(remotePath, localPath)
if err != nil {
logger.Errorf("CopyDirRemoteToLocal failed to copying remote directory %s: => %s", remotePath, err.Error())
continue
}
} else {
// 如果是文件,则复制文件内容
remoteFile, err := s.Client.Open(remotePath)
if err != nil {
logger.Errorf("CopyDirRemoteToLocal failed to opening remote file %s: => %s", remotePath, err.Error())
continue
}
defer remoteFile.Close()
localFile, err := os.Create(localPath)
if err != nil {
logger.Errorf("CopyDirRemoteToLocal failed to creating local file %s: => %s", localPath, err.Error())
continue
}
defer localFile.Close()
_, err = io.Copy(localFile, remoteFile)
if err != nil {
logger.Errorf("CopyDirRemoteToLocal failed to copying file contents from %s to %s: => %s", remotePath, localPath, err.Error())
continue
}
}
}
return nil
}
// CopyDirRemoteToLocal 复制目录-本地到远程
func (s *SSHClientSFTP) CopyDirLocalToRemote(localDir, remoteDir string) error {
// 创建远程目录
err := s.Client.MkdirAll(remoteDir)
if err != nil {
logger.Errorf("CopyDirLocalToRemote failed to creating remote directory %s: => %s", remoteDir, err.Error())
return err
}
// 遍历本地目录中的文件和子目录并复制到远程
err = filepath.Walk(localDir, func(localPath string, info os.FileInfo, err error) error {
if err != nil {
return err
}
// 生成远程路径
remotePath := filepath.Join(remoteDir, localPath[len(localDir):])
if info.IsDir() {
// 如果是子目录,则创建远程目录
err := s.Client.MkdirAll(remotePath)
if err != nil {
logger.Errorf("CopyDirLocalToRemote failed to creating remote directory %s: => %s", remotePath, err.Error())
return nil
}
} else {
// 如果是文件,则复制文件内容
localFile, err := os.Open(localPath)
if err != nil {
logger.Errorf("CopyDirLocalToRemote failed to opening local file %s: => %s", localPath, err.Error())
return nil
}
defer localFile.Close()
remoteFile, err := s.Client.Create(remotePath)
if err != nil {
logger.Errorf("CopyDirLocalToRemote failed to creating remote file %s: => %s", remotePath, err.Error())
return nil
}
defer remoteFile.Close()
_, err = io.Copy(remoteFile, localFile)
if err != nil {
logger.Errorf("CopyDirLocalToRemote failed to copying file contents from %s to %s: => %s", localPath, remotePath, err.Error())
return nil
}
}
return nil
})
if err != nil {
logger.Errorf("CopyDirLocalToRemote failed to walking local directory: => %s", err.Error())
return err
}
return nil
}
// CopyDirRemoteToLocal 复制文件-远程到本地
func (s *SSHClientSFTP) CopyFileRemoteToLocal(remotePath, localPath string) error {
// 打开远程文件
remoteFile, err := s.Client.Open(remotePath)
if err != nil {
logger.Errorf("CopyFileRemoteToLocal failed to opening remote file: => %s", err.Error())
return err
}
defer remoteFile.Close()
if err := os.MkdirAll(filepath.Dir(localPath), 0775); err != nil {
return err
}
// 如果目标文件已经存在,先将目标文件重命名
// if info, err := os.Stat(localPath); err == nil && !info.IsDir() {
// ext := filepath.Ext(localPath)
// name := localPath[0 : len(localPath)-len(ext)]
// newName := fmt.Sprintf("%s-%s%s", name, time.Now().Format("20060102_150405"), ext)
// err := os.Rename(localPath, newName)
// if err != nil {
// return err
// }
// }
// 创建本地文件
localFile, err := os.Create(localPath)
if err != nil {
logger.Errorf("CopyFileRemoteToLocal failed to creating local file: => %s", err.Error())
return err
}
defer localFile.Close()
// 复制文件内容
_, err = io.Copy(localFile, remoteFile)
if err != nil {
logger.Errorf("CopyFileRemoteToLocal failed to copying contents: => %s", err.Error())
return err
}
return nil
}
// CopyDirRemoteToLocal 复制文件-本地到远程
func (s *SSHClientSFTP) CopyFileLocalToRemote(localPath, remotePath string) error {
// 打开本地文件
localFile, err := os.Open(localPath)
if err != nil {
logger.Errorf("CopyFileLocalToRemote failed to opening local file: => %s", err.Error())
return err
}
defer localFile.Close()
// 创建远程文件
remoteFile, err := s.Client.Create(remotePath)
if err != nil {
logger.Errorf("CopyFileLocalToRemote failed to creating remote file: => %s", err.Error())
return err
}
defer remoteFile.Close()
// 复制文件内容
_, err = io.Copy(remoteFile, localFile)
if err != nil {
logger.Errorf("CopyFileLocalToRemote failed to copying contents: => %s", err.Error())
return err
}
return nil
}

View File

@@ -50,7 +50,13 @@ func (c *ConnTelnet) NewClient() (*ConnTelnet, error) {
// fmt.Fprintln(client, c.User)
// fmt.Fprintln(client, c.Password)
// 需要确保接收方理解并正确处理发送窗口大小设置命令
client.Write([]byte{255, 251, 31}) // 发送窗口大小选项
client.Write([]byte{255, 250, 31, 0, 128, 0, 120, 255, 240}) // 发送窗口行和列的大小
c.Client = &client
// 排空连接登录的信息
c.RunCMD("")
return c, nil
}
@@ -70,32 +76,14 @@ func (c *ConnTelnet) RunCMD(cmd string) (string, error) {
var buf bytes.Buffer
tmp := make([]byte, 1024)
// 排空连接登录的信息
for {
// 设置读取超时时间为100毫秒
conn.SetReadDeadline(time.Now().Add(100 * time.Millisecond))
n, err := conn.Read(tmp)
if err != nil {
// 判断是否是超时错误
if netErr, ok := err.(net.Error); ok && netErr.Timeout() {
break
}
break
}
if n == 0 {
break
}
buf.Write(tmp[:n])
}
buf.Reset()
// 写入命令
_, err := conn.Write([]byte(cmd))
if err != nil {
return "", err
if cmd != "" {
if _, err := conn.Write([]byte(cmd)); err != nil {
return "", err
}
}
// 读取本次响应命令消息
// 读取命令消息
for {
// 设置读取超时时间为1000毫秒
conn.SetReadDeadline(time.Now().Add(1000 * time.Millisecond))
@@ -119,35 +107,12 @@ func (c *ConnTelnet) RunCMD(cmd string) (string, error) {
}
// NewClient 创建Telnet客户端会话对象
func (c *ConnTelnet) NewClientSession() (*TelnetClientSession, error) {
func (c *ConnTelnet) NewClientSession(cols, rows uint8) (*TelnetClientSession, error) {
if c.Client == nil {
return nil, fmt.Errorf("telnet client not connected")
}
conn := *c.Client
var buf bytes.Buffer
tmp := make([]byte, 1024)
// 排空连接登录的信息
for {
// 设置读取超时时间为5毫秒
conn.SetReadDeadline(time.Now().Add(5 * time.Millisecond))
n, err := conn.Read(tmp)
if err != nil {
// 判断是否是超时错误
if netErr, ok := err.(net.Error); ok && netErr.Timeout() {
break
}
break
}
if n == 0 {
break
}
buf.Write(tmp[:n])
}
buf.Reset()
return &TelnetClientSession{
Client: conn,
Client: *c.Client,
}, nil
}

View File

@@ -11,6 +11,7 @@ import (
"be.ems/src/framework/logger"
redisCahe "be.ems/src/framework/redis"
"be.ems/src/framework/utils/generate"
"be.ems/src/framework/utils/machine"
"be.ems/src/framework/vo"
jwt "github.com/golang-jwt/jwt/v5"
@@ -74,7 +75,7 @@ func Create(loginUser *vo.LoginUser, ilobArgs ...string) string {
// 生成令牌设置密钥
secret := config.Get("jwt.secret").(string)
tokenStr, err := jwtToken.SignedString([]byte(secret))
tokenStr, err := jwtToken.SignedString([]byte(machine.Code + "@" + secret))
if err != nil {
logger.Infof("jwt sign err : %v", err)
return ""
@@ -118,7 +119,7 @@ func Verify(tokenString string) (jwt.MapClaims, error) {
// 判断加密算法是预期的加密算法
if _, ok := token.Method.(*jwt.SigningMethodHMAC); ok {
secret := config.Get("jwt.secret").(string)
return []byte(secret), nil
return []byte(machine.Code + "@" + secret), nil
}
return nil, jwt.ErrSignatureInvalid
})

View File

@@ -25,6 +25,14 @@ func Setup(router *gin.Engine) {
// 系统可暴露的配置信息
indexGroup.GET("/sys-conf", controller.NewCommont.SysConfig)
// 系统引导初始化
guideGroup := router.Group("/bootloader")
{
guideGroup.POST("", controller.NewBootloader.Start)
guideGroup.PUT("", middleware.PreAuthorize(nil), controller.NewBootloader.Done)
guideGroup.DELETE("", middleware.PreAuthorize(nil), controller.NewBootloader.Reset)
guideGroup.PUT("/account", middleware.PreAuthorize(nil), controller.NewBootloader.Account)
}
// 验证码操作处理
indexGroup.GET("/captchaImage",

View File

@@ -0,0 +1,181 @@
package controller
import (
adminConstants "be.ems/src/framework/constants/admin"
"be.ems/src/framework/constants/common"
tokenConstants "be.ems/src/framework/constants/token"
"be.ems/src/framework/i18n"
"be.ems/src/framework/utils/ctx"
"be.ems/src/framework/utils/machine"
"be.ems/src/framework/utils/regular"
tokenUtils "be.ems/src/framework/utils/token"
"be.ems/src/framework/vo"
"be.ems/src/framework/vo/result"
commonService "be.ems/src/modules/common/service"
systemService "be.ems/src/modules/system/service"
"github.com/gin-gonic/gin"
)
// 实例化控制层 BootloaderController 结构体
var NewBootloader = &BootloaderController{
accountService: commonService.NewAccountImpl,
sysUserService: systemService.NewSysUserImpl,
}
// 系统引导初始化
//
// PATH /bootloader
type BootloaderController struct {
// 账号身份操作服务
accountService commonService.IAccount
// 用户信息服务
sysUserService systemService.ISysUser
}
// 首次引导开始
//
// POST /
func (s *BootloaderController) Start(c *gin.Context) {
// 是否完成引导
launchInfo := machine.LaunchInfo
if launchInfo == nil {
c.JSON(200, result.Err(nil))
return
}
if v, ok := launchInfo[common.LAUNCH_BOOTLOADER]; ok && !v.(bool) {
c.JSON(200, result.ErrMsg("bootloader done"))
return
}
// 查询用户登录账号
sysUser := s.sysUserService.SelectUserById("1")
if sysUser.UserID != "1" {
c.JSON(200, result.ErrMsg("not found user data"))
return
}
// 登录用户信息
loginUser := vo.LoginUser{
UserID: sysUser.UserID,
DeptID: sysUser.DeptID,
User: sysUser,
Permissions: []string{adminConstants.PERMISSION},
}
// 当前请求信息
ipaddr, location := ctx.IPAddrLocation(c)
os, browser := ctx.UaOsBrowser(c)
// 生成令牌,创建系统访问记录
tokenStr := tokenUtils.Create(&loginUser, ipaddr, location, os, browser)
if tokenStr == "" {
c.JSON(200, result.Err(nil))
return
} else {
s.accountService.UpdateLoginDateAndIP(&loginUser)
}
c.JSON(200, result.OkData(map[string]any{
tokenConstants.RESPONSE_FIELD: tokenStr,
}))
}
// 首次引导完成
//
// PUT /
func (s *BootloaderController) Done(c *gin.Context) {
// 是否完成引导
launchInfo := machine.LaunchInfo
if launchInfo == nil {
c.JSON(200, result.Err(nil))
return
}
if v, ok := launchInfo[common.LAUNCH_BOOTLOADER]; ok && !v.(bool) {
c.JSON(200, result.ErrMsg("bootloader done"))
return
}
// 标记引导完成
if err := machine.Bootloader(false); err != nil {
c.JSON(200, result.ErrMsg(err.Error()))
return
}
// 清除授权信息
tokenUtils.Remove(ctx.Authorization(c))
c.JSON(200, result.Ok(nil))
}
// 引导系统数据重置
//
// DELETE /
func (s *BootloaderController) Reset(c *gin.Context) {
// 是否完成引导
launchInfo := machine.LaunchInfo
if launchInfo == nil {
c.JSON(200, result.Err(nil))
return
}
if v, ok := launchInfo[common.LAUNCH_BOOTLOADER]; ok && v.(bool) {
c.JSON(200, result.ErrMsg("bootloader not done"))
return
}
if err := machine.Reset(); err != nil {
c.JSON(200, result.ErrMsg(err.Error()))
return
}
// 清除授权信息
tokenUtils.Remove(ctx.Authorization(c))
c.JSON(200, result.Ok(nil))
}
// 账号变更
//
// PUT /account
func (s *BootloaderController) Account(c *gin.Context) {
language := ctx.AcceptLanguage(c)
var body struct {
UserName string `json:"username" binding:"required"`
Password string `json:"password" binding:"required"`
}
if err := c.ShouldBindJSON(&body); err != nil {
c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
return
}
if !regular.ValidPassword(body.Password) {
// 登录密码至少包含大小写字母、数字、特殊符号且不少于6位
c.JSON(200, result.ErrMsg(i18n.TKey(language, "user.errPasswd")))
return
}
// 是否完成引导
launchInfo := machine.LaunchInfo
if launchInfo == nil {
c.JSON(200, result.Err(nil))
return
}
if v, ok := launchInfo[common.LAUNCH_BOOTLOADER]; ok && !v.(bool) {
c.JSON(200, result.ErrMsg("bootloader done"))
return
}
// 查询用户登录账号
sysUser := s.sysUserService.SelectUserById("2")
if sysUser.UserID != "2" {
c.JSON(200, result.ErrMsg("not found user data"))
return
}
sysUser.UserName = body.UserName
sysUser.NickName = body.UserName
sysUser.Password = body.Password
sysUser.UpdateBy = ctx.LoginUserToUserName(c)
rows := s.sysUserService.UpdateUser(sysUser)
if rows > 0 {
c.JSON(200, result.Ok(nil))
return
}
c.JSON(200, result.Err(nil))
}

View File

@@ -43,13 +43,6 @@ func (s *FileController) Download(c *gin.Context) {
return
}
routerPath := string(decodedBytes)
// 地址文件名截取
fileName := routerPath[strings.LastIndex(routerPath, "/")+1:]
// 响应头
c.Writer.Header().Set("Content-Disposition", `attachment; filename="`+url.QueryEscape(fileName)+`"`)
c.Writer.Header().Set("Accept-Ranges", "bytes")
c.Writer.Header().Set("Content-Type", "application/octet-stream")
// 断点续传
headerRange := c.GetHeader("Range")
@@ -58,6 +51,12 @@ func (s *FileController) Download(c *gin.Context) {
c.JSON(200, result.ErrMsg(err.Error()))
return
}
// 响应头
c.Writer.Header().Set("Content-Disposition", `attachment; filename="`+url.QueryEscape(filepath.Base(routerPath))+`"`)
c.Writer.Header().Set("Accept-Ranges", "bytes")
c.Writer.Header().Set("Content-Type", "application/octet-stream")
if headerRange != "" {
c.Writer.Header().Set("Content-Range", fmt.Sprint(resultMap["range"]))
c.Writer.Header().Set("Content-Length", fmt.Sprint(resultMap["chunkSize"]))
@@ -65,7 +64,6 @@ func (s *FileController) Download(c *gin.Context) {
} else {
c.Writer.Header().Set("Content-Length", fmt.Sprint(resultMap["fileSize"]))
c.Status(200)
}
c.Writer.Write(resultMap["data"].([]byte))
}
@@ -222,7 +220,7 @@ func (s *CommontController) TransferStaticFile(c *gin.Context) {
delPrefix := strings.Replace(body.StaticPath, static["prefix"].(string), "", 1)
staticPath := strings.Replace(delPrefix, "{language}", lang, 1)
newFile := fmt.Sprintf("%s%s", dir, staticPath)
newFile := filepath.ToSlash(fmt.Sprintf("%s%s", dir, staticPath))
err = file.CopyUploadFile(body.UploadPath, newFile)
if err != nil {

View File

@@ -5,6 +5,8 @@ import (
"be.ems/lib/global"
"be.ems/src/framework/config"
"be.ems/src/framework/constants/common"
"be.ems/src/framework/utils/machine"
systemService "be.ems/src/modules/system/service"
)
@@ -29,6 +31,17 @@ func (s *CommontImpl) SystemConfigInfo() map[string]string {
infoMap["version"] = global.Version
infoMap["buildTime"] = global.BuildTime
infoMap["goVer"] = global.GoVer
// 系统首次使用标记
launchInfo := machine.LaunchInfo
if launchInfo != nil {
if v, ok := launchInfo[common.LAUNCH_BOOTLOADER]; ok {
infoMap[common.LAUNCH_BOOTLOADER] = fmt.Sprint(v)
} else {
infoMap[common.LAUNCH_BOOTLOADER] = "true"
}
} else {
infoMap[common.LAUNCH_BOOTLOADER] = "true"
}
// 序列号
infoMap["serialNum"] = fmt.Sprint(config.Get("omc.sn"))
// 获取LOGO类型

View File

@@ -0,0 +1,80 @@
package controller
import (
"strings"
"be.ems/src/framework/i18n"
"be.ems/src/framework/utils/ctx"
"be.ems/src/framework/utils/parse"
"be.ems/src/framework/vo/result"
"be.ems/src/modules/network_data/model"
neDataService "be.ems/src/modules/network_data/service"
neService "be.ems/src/modules/network_element/service"
"github.com/gin-gonic/gin"
)
// 实例化控制层 IMSController 结构体
var NewSMFController = &SMFController{
neInfoService: neService.NewNeInfoImpl,
cdrEventService: neDataService.NewSMFCDREventImpl,
}
// 网元IMS
//
// PATH /ims
type SMFController struct {
// 网元信息服务
neInfoService neService.INeInfo
// SMF CDR会话事件服务
cdrEventService neDataService.SMFCDREvent
}
// CDR会话列表
//
// GET /cdr/list
func (s *SMFController) CDRList(c *gin.Context) {
language := ctx.AcceptLanguage(c)
var querys model.SMFCDREventQuery
if err := c.ShouldBindQuery(&querys); err != nil {
c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
return
}
// 查询网元获取IP
neInfo := s.neInfoService.SelectNeInfoByNeTypeAndNeID(querys.NeType, querys.NeID)
if neInfo.NeId != querys.NeID || neInfo.IP == "" {
c.JSON(200, result.ErrMsg(i18n.TKey(language, "app.common.noNEInfo")))
return
}
querys.RmUID = neInfo.RmUID
// 查询数据
data := s.cdrEventService.SelectPage(querys)
c.JSON(200, result.Ok(data))
}
// CDR会话删除
//
// DELETE /cdr/:cdrIds
func (s *SMFController) CDRRemove(c *gin.Context) {
language := ctx.AcceptLanguage(c)
cdrIds := c.Param("cdrIds")
if cdrIds == "" {
c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
return
}
// 处理字符转id数组后去重
ids := strings.Split(cdrIds, ",")
uniqueIDs := parse.RemoveDuplicates(ids)
if len(uniqueIDs) <= 0 {
c.JSON(200, result.Err(nil))
return
}
rows, err := s.cdrEventService.DeleteByIds(uniqueIDs)
if err != nil {
c.JSON(200, result.ErrMsg(i18n.TKey(language, err.Error())))
return
}
msg := i18n.TTemplate(language, "app.common.deleteSuccess", map[string]any{"num": rows})
c.JSON(200, result.OkMsg(msg))
}

View File

@@ -2,7 +2,7 @@ package model
import "time"
// CDREvent CDR会话对象 cdr_event
// CDREvent CDR会话对象 cdr_event_ims/cdr_event_smf
type CDREvent struct {
ID string `json:"id" gorm:"column:id;primaryKey;autoIncrement"`
NeType string `json:"neType" gorm:"column:ne_type"`
@@ -15,14 +15,16 @@ type CDREvent struct {
// CDREventQuery CDR会话对象查询参数结构体
type CDREventQuery struct {
NeType string `json:"neType" form:"neType" binding:"required"` // 网元类型, 暂时支持IMS
NeID string `json:"neId" form:"neId" binding:"required"`
RmUID string `json:"rmUID" form:"rmUID"`
RecordType string `json:"recordType" form:"recordType"` // 记录行为 MOC MTC MOSM MTSM
StartTime string `json:"startTime" form:"startTime"`
EndTime string `json:"endTime" form:"endTime"`
SortField string `json:"sortField" form:"sortField" binding:"omitempty,oneof=timestamp"` // 排序字段,填写结果字段
SortOrder string `json:"sortOrder" form:"sortOrder" binding:"omitempty,oneof=asc desc"` // 排序升降序asc desc
PageNum int64 `json:"pageNum" form:"pageNum" binding:"required"`
PageSize int64 `json:"pageSize" form:"pageSize" binding:"required"`
NeType string `json:"neType" form:"neType" binding:"required"` // 网元类型
NeID string `json:"neId" form:"neId" binding:"required"`
RmUID string `json:"rmUID" form:"rmUID"`
RecordType string `json:"recordType" form:"recordType"` // 记录行为 MOC MTC MOSM MTSM
CallerParty string `json:"callerParty" form:"callerParty"` // 主叫号码
CalledParty string `json:"calledParty" form:"calledParty"` // 被叫号码
StartTime string `json:"startTime" form:"startTime"`
EndTime string `json:"endTime" form:"endTime"`
SortField string `json:"sortField" form:"sortField" binding:"omitempty,oneof=timestamp"` // 排序字段,填写结果字段
SortOrder string `json:"sortOrder" form:"sortOrder" binding:"omitempty,oneof=asc desc"` // 排序升降序asc desc
PageNum int64 `json:"pageNum" form:"pageNum" binding:"required"`
PageSize int64 `json:"pageSize" form:"pageSize" binding:"required"`
}

View File

@@ -0,0 +1,35 @@
package model
import "time"
// CDREvent CDR会话对象 cdr_event_smf
type CDREventSMF struct {
ID string `json:"id" gorm:"column:id;primaryKey;autoIncrement"`
NeType string `json:"neType" gorm:"column:ne_type"`
NeName string `json:"neName" gorm:"column:ne_name"`
RmUID string `json:"rmUID" gorm:"column:rm_uid"`
Timestamp int64 `json:"timestamp" gorm:"column:timestamp"`
RecordType string `json:"recordType" gorm:"column:record_type"`
ChargingID string `json:"chargingID" gorm:"column:charging_id"`
SubscriberID string `json:"subscriberID" gorm:"column:subscriber_id"`
Duration string `json:"duration" gorm:"column:duration"`
DataVolumeUplink string `json:"dataVolumeUplink" gorm:"column:data_volume_uplink"`
DataVolumeDownlink string `json:"dataVolumeDownlink" gorm:"column:data_volume_downlink"`
DataTotalVolume string `json:"dataTotalVolume" gorm:"column:data_total_volume"`
PDUAddress string `json:"pduAddress" gorm:"column:pdu_address"`
CreatedAt time.Time `json:"createdAt" gorm:"column:created_at;default:CURRENT_TIMESTAMP"`
}
type SMFCDREventQuery struct {
NeType string `json:"neType" form:"neType" binding:"required"` // SMF
NeID string `json:"neId" form:"neId" binding:"required"`
RmUID string `json:"rmUID" form:"rmUID"`
RecordType string `json:"recordType" form:"recordType"`
SubscriberID string `json:"subscriberID" form:"subscriberID"`
StartTime string `json:"startTime" form:"startTime"`
EndTime string `json:"endTime" form:"endTime"`
SortField string `json:"sortField" form:"sortField" binding:"omitempty,oneof=timestamp"` // 排序字段,填写结果字段
SortOrder string `json:"sortOrder" form:"sortOrder" binding:"omitempty,oneof=asc desc"` // 排序升降序asc desc
PageNum int64 `json:"pageNum" form:"pageNum" binding:"required"`
PageSize int64 `json:"pageSize" form:"pageSize" binding:"required"`
}

View File

@@ -20,6 +20,7 @@ type UEEventQuery struct {
NeID string `json:"neId" form:"neId" binding:"required"`
RmUID string `json:"rmUID" form:"rmUID"`
EventType string `json:"eventType" form:"eventType"` // 事件类型 auth-result detach cm-state
IMSI string `json:"imsi" form:"imsi"` // imsi
StartTime string `json:"startTime" form:"startTime"`
EndTime string `json:"endTime" form:"endTime"`
SortField string `json:"sortField" form:"sortField" binding:"omitempty,oneof=timestamp"` // 排序字段,填写结果字段

View File

@@ -57,6 +57,22 @@ func Setup(router *gin.Engine) {
)
}
// 网元SMF
smfGroup := neDataGroup.Group("/smf")
{
// CDR会话事件列表
smfGroup.GET("/cdr/list",
middleware.PreAuthorize(nil),
controller.NewSMFController.CDRList,
)
// CDR会话删除
smfGroup.DELETE("/cdr/:cdrIds",
middleware.PreAuthorize(nil),
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.smfCDR", collectlogs.BUSINESS_TYPE_DELETE)),
controller.NewSMFController.CDRRemove,
)
}
// 网元AMF
amfGroup := neDataGroup.Group("/amf")
{

View File

@@ -13,3 +13,15 @@ type ICDREvent interface {
// DeleteByIds 批量删除信息
DeleteByIds(cdrIds []string) int64
}
// SMF CDR Event
type SMFCDREvent interface {
// SelectPage 根据条件分页查询
SelectPage(querys model.SMFCDREventQuery) map[string]any
// SelectByIds 通过ID查询
SelectByIds(cdrIds []string) []model.CDREventSMF
// DeleteByIds 批量删除信息
DeleteByIds(cdrIds []string) int64
}

View File

@@ -14,7 +14,7 @@ import (
// 实例化数据层 CDREventImpl 结构体
var NewCDREventImpl = &CDREventImpl{
selectSql: `select id, ne_type, ne_name, rm_uid, timestamp, cdr_json, created_at from cdr_event`,
selectSql: `select id, ne_type, ne_name, rm_uid, timestamp, cdr_json, created_at from cdr_event_ims`,
resultMap: map[string]string{
"id": "ID",
@@ -35,6 +35,36 @@ type CDREventImpl struct {
resultMap map[string]string
}
// Instance of SMF CDREventImpl
var NewSMFCDREventImpl = &SMFCDREventImpl{
selectSql: `select id, ne_type, ne_name, rm_uid, timestamp, JSON_EXTRACT(cdr_json, '$.recordType') AS record_type, JSON_EXTRACT(cdr_json, '$.chargingID') AS charging_id, JSON_EXTRACT(cdr_json, '$.subscriberIdentifier.subscriptionIDData') AS subscriber_id, JSON_EXTRACT(cdr_json, '$.duration') AS duration, JSON_EXTRACT(cdr_json, '$.listOfMultipleUnitUsage[*].usedUnitContainer[*].dataVolumeUplink') AS data_volume_uplink, JSON_EXTRACT(cdr_json, '$.listOfMultipleUnitUsage[*].usedUnitContainer[*].dataVolumeDownlink') AS data_volume_downlink, JSON_EXTRACT(cdr_json, '$.listOfMultipleUnitUsage[*].usedUnitContainer[*].dataTotalVolume') AS data_total_volume, JSON_EXTRACT(cdr_json, '$.pDUSessionChargingInformation.pDUAddress') AS pdu_address, created_at from cdr_event_smf`,
resultMap: map[string]string{
"id": "ID",
"ne_type": "NeType",
"ne_name": "NeName",
"rm_uid": "RmUID",
"timestamp": "Timestamp",
"record_type": "RecordType",
"charging_id": "ChargingID",
"subscriber_id": "SubscriberID",
"duration": "Duration",
"data_volume_uplink": "DataVolumeUplink",
"data_volume_downlink": "DataVolumeDownlink",
"data_total_volume": "DataTotalVolume",
"pdu_address": "PDUAddress",
"created_at": "CreatedAt",
},
}
// CDREventImpl CDR会话事件 数据层处理
type SMFCDREventImpl struct {
// 查询视图对象SQL
selectSql string
// 结果字段与实体映射
resultMap map[string]string
}
// convertResultRows 将结果记录转实体结果组
func (r *CDREventImpl) convertResultRows(rows []map[string]any) []model.CDREvent {
arr := make([]model.CDREvent, 0)
@@ -63,10 +93,6 @@ func (r *CDREventImpl) SelectPage(querys model.CDREventQuery) map[string]any {
conditions = append(conditions, "rm_uid = ?")
params = append(params, querys.RmUID)
}
if querys.RmUID != "" {
conditions = append(conditions, "rm_uid = ?")
params = append(params, querys.RmUID)
}
if querys.StartTime != "" {
conditions = append(conditions, "timestamp >= ?")
beginDate := date.ParseStrToDate(querys.StartTime, date.YYYY_MM_DD_HH_MM_SS)
@@ -77,6 +103,14 @@ func (r *CDREventImpl) SelectPage(querys model.CDREventQuery) map[string]any {
endDate := date.ParseStrToDate(querys.EndTime, date.YYYY_MM_DD_HH_MM_SS)
params = append(params, endDate.Unix())
}
if querys.CallerParty != "" {
conditions = append(conditions, "JSON_EXTRACT(cdr_json, '$.callerParty') = ?")
params = append(params, querys.CallerParty)
}
if querys.CalledParty != "" {
conditions = append(conditions, "JSON_EXTRACT(cdr_json, '$.calledParty') = ?")
params = append(params, querys.CalledParty)
}
if querys.RecordType != "" {
recordTypes := strings.Split(querys.RecordType, ",")
placeholder := repo.KeyPlaceholderByQuery(len(recordTypes))
@@ -98,7 +132,7 @@ func (r *CDREventImpl) SelectPage(querys model.CDREventQuery) map[string]any {
}
// 查询数量 长度为0直接返回
totalSql := "select count(1) as 'total' from cdr_event"
totalSql := "select count(1) as 'total' from cdr_event_ims"
totalRows, err := datasource.RawDB("", totalSql+whereSql, params)
if err != nil {
logger.Errorf("total err => %v", err)
@@ -160,7 +194,146 @@ func (r *CDREventImpl) SelectByIds(cdrIds []string) []model.CDREvent {
// DeleteByIds 批量删除信息
func (r *CDREventImpl) DeleteByIds(cdrIds []string) int64 {
placeholder := repo.KeyPlaceholderByQuery(len(cdrIds))
sql := "delete from cdr_event where id in (" + placeholder + ")"
sql := "delete from cdr_event_ims where id in (" + placeholder + ")"
parameters := repo.ConvertIdsSlice(cdrIds)
results, err := datasource.ExecDB("", sql, parameters)
if err != nil {
logger.Errorf("delete err => %v", err)
return 0
}
return results
}
// convertResultRows 将结果记录转实体结果组
func (r *SMFCDREventImpl) convertResultRows(rows []map[string]any) []model.CDREventSMF {
arr := make([]model.CDREventSMF, 0)
for _, row := range rows {
item := model.CDREventSMF{}
for key, value := range row {
if keyMapper, ok := r.resultMap[key]; ok {
repo.SetFieldValue(&item, keyMapper, value)
}
}
arr = append(arr, item)
}
return arr
}
// SelectPage 根据条件分页查询
func (r *SMFCDREventImpl) SelectPage(querys model.SMFCDREventQuery) map[string]any {
// 查询条件拼接
var conditions []string
var params []any
if querys.NeType != "" {
conditions = append(conditions, "ne_type = ?")
params = append(params, querys.NeType)
}
if querys.RmUID != "" {
conditions = append(conditions, "rm_uid = ?")
params = append(params, querys.RmUID)
}
if querys.StartTime != "" {
conditions = append(conditions, "timestamp >= ?")
beginDate := date.ParseStrToDate(querys.StartTime, date.YYYY_MM_DD_HH_MM_SS)
params = append(params, beginDate.Unix())
}
if querys.EndTime != "" {
conditions = append(conditions, "timestamp <= ?")
endDate := date.ParseStrToDate(querys.EndTime, date.YYYY_MM_DD_HH_MM_SS)
params = append(params, endDate.Unix())
}
if querys.RecordType != "" {
conditions = append(conditions, "JSON_EXTRACT(cdr_json, '$.recordType') = ?")
params = append(params, querys.RecordType)
}
if querys.SubscriberID != "" {
conditions = append(conditions, "JSON_EXTRACT(cdr_json, '$.subscriberIdentifier.subscriptionIDData') = ?")
params = append(params, querys.SubscriberID)
}
// if querys.RecordType != "" {
// recordTypes := strings.Split(querys.RecordType, ",")
// placeholder := repo.KeyPlaceholderByQuery(len(recordTypes))
// conditions = append(conditions, fmt.Sprintf("JSON_EXTRACT(cdr_json, '$.recordType') in (%s)", placeholder))
// for _, recordType := range recordTypes {
// params = append(params, recordType)
// }
// }
// 构建查询条件语句
whereSql := ""
if len(conditions) > 0 {
whereSql += " where " + strings.Join(conditions, " and ")
}
result := map[string]any{
"total": 0,
"rows": []model.CDREventSMF{},
}
// 查询数量 长度为0直接返回
totalSql := "select count(1) as 'total' from cdr_event_smf"
totalRows, err := datasource.RawDB("", totalSql+whereSql, params)
if err != nil {
logger.Errorf("total err => %v", err)
return result
}
total := parse.Number(totalRows[0]["total"])
if total == 0 {
return result
} else {
result["total"] = total
}
// 分页
pageNum, pageSize := repo.PageNumSize(querys.PageNum, querys.PageSize)
pageSql := " limit ?,? "
params = append(params, pageNum*pageSize)
params = append(params, pageSize)
// 排序
orderSql := ""
if querys.SortField != "" {
sortSql := querys.SortField
if querys.SortOrder != "" {
if querys.SortOrder == "desc" {
sortSql += " desc "
} else {
sortSql += " asc "
}
}
orderSql = fmt.Sprintf(" order by id desc, %s ", sortSql)
}
// 查询数据
querySql := r.selectSql + whereSql + orderSql + pageSql
results, err := datasource.RawDB("", querySql, params)
if err != nil {
logger.Errorf("query err => %v", err)
}
// 转换实体
result["rows"] = r.convertResultRows(results)
return result
}
// SelectByIds 通过ID查询
func (r *SMFCDREventImpl) SelectByIds(cdrIds []string) []model.CDREventSMF {
placeholder := repo.KeyPlaceholderByQuery(len(cdrIds))
querySql := r.selectSql + " where id in (" + placeholder + ")"
parameters := repo.ConvertIdsSlice(cdrIds)
results, err := datasource.RawDB("", querySql, parameters)
if err != nil {
logger.Errorf("query err => %v", err)
return []model.CDREventSMF{}
}
// 转换实体
return r.convertResultRows(results)
}
// DeleteByIds 批量删除信息
func (r *SMFCDREventImpl) DeleteByIds(cdrIds []string) int64 {
placeholder := repo.KeyPlaceholderByQuery(len(cdrIds))
sql := "delete from cdr_event_smf where id in (" + placeholder + ")"
parameters := repo.ConvertIdsSlice(cdrIds)
results, err := datasource.ExecDB("", sql, parameters)
if err != nil {

View File

@@ -7,9 +7,15 @@ type IPerfKPI interface {
// SelectGoldKPI 通过网元指标数据信息
SelectGoldKPI(query model.GoldKPIQuery, kpiIds []string) []map[string]any
// select from new kpi report table, exp. kpi_report_upf
SelectKpiReport(query model.GoldKPIQuery, kpiIds []string) []map[string]any
// SelectGoldKPITitle 网元对应的指标名称
SelectGoldKPITitle(neType string) []model.GoldKPITitle
// SelectUPFTotalFlow 查询UPF总流量 N3上行 N6下行
SelectUPFTotalFlow(neType, rmUID, startDate, endDate string) map[string]any
// select upf throughput from new kpi_report
SelectUPFThroughput(neType, rmUID, startDate, endDate string) map[string]any
}

View File

@@ -86,6 +86,79 @@ func (r *PerfKPIImpl) SelectGoldKPI(query model.GoldKPIQuery, kpiIds []string) [
return results
}
func (r *PerfKPIImpl) SelectKpiReport(query model.GoldKPIQuery, kpiIds []string) []map[string]any {
// 查询条件拼接
var conditions []string
var params []any
var tableName string = "kpi_report_"
if query.RmUID != "" {
conditions = append(conditions, "gk.rm_uid = ?")
params = append(params, query.RmUID)
}
if query.NeType != "" {
conditions = append(conditions, "gk.ne_type = ?")
params = append(params, query.NeType)
tableName += strings.ToLower(query.NeType)
}
var dateTimeStr string = "CONCAT(gk.`date`, \" \", gk.start_time)"
if query.StartTime != "" {
conditions = append(conditions, dateTimeStr+" >= ?")
params = append(params, query.StartTime)
}
if query.EndTime != "" {
conditions = append(conditions, dateTimeStr+" <= ?")
params = append(params, query.EndTime)
}
// 构建查询条件语句
whereSql := ""
if len(conditions) > 0 {
whereSql += " where " + strings.Join(conditions, " and ")
}
// 查询字段列
timeFormat := "DATE_FORMAT(" + dateTimeStr + ", '%Y-%m-%d %H:%i:')"
secondGroup := fmt.Sprintf("LPAD(FLOOR(SECOND(gk.start_time) / %d) * %d, 2, '0')", query.Interval, query.Interval)
groupByField := fmt.Sprintf("CONCAT( %s, %s ) AS timeGroup", timeFormat, secondGroup)
if query.Interval > 60 {
minute := query.Interval / 60
timeFormat = "DATE_FORMAT(" + dateTimeStr + ", '%Y-%m-%d %H:')"
minuteGroup := fmt.Sprintf("LPAD(FLOOR(MINUTE(gk.start_time) / %d) * %d, 2, '0')", minute, minute)
groupByField = fmt.Sprintf("CONCAT( %s, %s ) AS timeGroup", timeFormat, minuteGroup)
}
var fields = []string{
groupByField,
"min(CASE WHEN gk.index != '' THEN gk.index ELSE 0 END) AS startIndex",
"min(CASE WHEN gk.ne_type != '' THEN gk.ne_type ELSE 0 END) AS neType",
"min(CASE WHEN gk.ne_name != '' THEN gk.ne_name ELSE 0 END) AS neName",
}
for i, kid := range kpiIds {
// 特殊字段只取最后一次收到的非0值
if kid == "AMF.01" || kid == "UDM.01" || kid == "UDM.02" || kid == "UDM.03" || kid == "SMF.01" {
str := fmt.Sprintf("IFNULL(SUBSTRING_INDEX(GROUP_CONCAT( CASE WHEN JSON_EXTRACT(gk.kpi_values, '$[%d].kpi_id') = '%s' THEN JSON_EXTRACT(gk.kpi_values, '$[%d].value') END ), ',', 1), 0) AS '%s'", i, kid, i, kid)
fields = append(fields, str)
} else {
str := fmt.Sprintf("sum(CASE WHEN JSON_EXTRACT(gk.kpi_values, '$[%d].kpi_id') = '%s' THEN JSON_EXTRACT(gk.kpi_values, '$[%d].value') ELSE 0 END) AS '%s'", i, kid, i, kid)
fields = append(fields, str)
}
}
fieldsSql := strings.Join(fields, ",")
// 查询数据
if query.SortField == "" {
query.SortField = "timeGroup"
}
if query.SortOrder == "" {
query.SortOrder = "desc"
}
orderSql := fmt.Sprintf(" order by %s %s", query.SortField, query.SortOrder)
querySql := fmt.Sprintf("SELECT %s FROM %s gk %s GROUP BY timeGroup %s", fieldsSql, tableName, whereSql, orderSql)
results, err := datasource.RawDB("", querySql, params)
if err != nil {
logger.Errorf("query err => %v", err)
}
return results
}
// SelectGoldKPITitle 网元对应的指标名称
func (r *PerfKPIImpl) SelectGoldKPITitle(neType string) []model.GoldKPITitle {
result := []model.GoldKPITitle{}
@@ -131,3 +204,39 @@ func (r *PerfKPIImpl) SelectUPFTotalFlow(neType, rmUID, startDate, endDate strin
}
return results[0]
}
// SelectUPFTotalFlow 查询UPF总流量 N3上行 N6下行
func (r *PerfKPIImpl) SelectUPFThroughput(neType, rmUID, startDate, endDate string) map[string]any {
// 查询条件拼接
var conditions []string
var params []any
if neType != "" {
conditions = append(conditions, "gk.ne_type = ?")
params = append(params, neType)
}
if rmUID != "" {
conditions = append(conditions, "gk.rm_uid = ?")
params = append(params, rmUID)
}
if startDate != "" {
conditions = append(conditions, "gk.date >= ?")
params = append(params, startDate)
}
if endDate != "" {
conditions = append(conditions, "gk.date <= ?")
params = append(params, endDate)
}
// 构建查询条件语句
whereSql := ""
if len(conditions) > 0 {
whereSql += " where " + strings.Join(conditions, " and ")
}
// 查询数据
querySql := fmt.Sprintf("SELECT sum( CASE WHEN JSON_EXTRACT(gk.kpi_values, '$[2].kpi_id') = 'UPF.03' THEN JSON_EXTRACT(gk.kpi_values, '$[2].value') ELSE 0 END ) AS 'up', sum( CASE WHEN JSON_EXTRACT(gk.kpi_values, '$[5].kpi_id') = 'UPF.06' THEN JSON_EXTRACT(gk.kpi_values, '$[5].value') ELSE 0 END ) AS 'down' FROM kpi_report_upf gk %s", whereSql)
results, err := datasource.RawDB("", querySql, params)
if err != nil {
logger.Errorf("query err => %v", err)
}
return results[0]
}

View File

@@ -74,6 +74,10 @@ func (r *UEEventImpl) SelectPage(querys model.UEEventQuery) map[string]any {
endDate := date.ParseStrToDate(querys.EndTime, date.YYYY_MM_DD_HH_MM_SS)
params = append(params, endDate.Unix())
}
if querys.IMSI != "" {
conditions = append(conditions, "JSON_EXTRACT(event_json, '$.imsi') = ?")
params = append(params, querys.IMSI)
}
if querys.EventType != "" {
eventTypes := strings.Split(querys.EventType, ",")
placeholder := repo.KeyPlaceholderByQuery(len(eventTypes))

View File

@@ -10,3 +10,12 @@ type ICDREvent interface {
// DeleteByIds 批量删除信息
DeleteByIds(cdrIds []string) (int64, error)
}
// CDR会话事件 服务层接口
type SMFCDREvent interface {
// SelectPage 根据条件分页查询
SelectPage(querys model.SMFCDREventQuery) map[string]any
// DeleteByIds 批量删除信息
DeleteByIds(cdrIds []string) (int64, error)
}

View File

@@ -12,12 +12,21 @@ var NewCDREventImpl = &CDREventImpl{
cdrEventRepository: repository.NewCDREventImpl,
}
var NewSMFCDREventImpl = &SMFCDREventImpl{
cdrEventRepository: repository.NewSMFCDREventImpl,
}
// CDREventImpl CDR会话事件 服务层处理
type CDREventImpl struct {
// CDR会话事件数据信息
cdrEventRepository repository.ICDREvent
}
type SMFCDREventImpl struct {
// CDR会话事件数据信息
cdrEventRepository repository.SMFCDREvent
}
// SelectPage 根据条件分页查询
func (r *CDREventImpl) SelectPage(querys model.CDREventQuery) map[string]any {
return r.cdrEventRepository.SelectPage(querys)
@@ -38,3 +47,23 @@ func (r *CDREventImpl) DeleteByIds(cdrIds []string) (int64, error) {
// 删除信息失败!
return 0, fmt.Errorf("delete fail")
}
func (r *SMFCDREventImpl) SelectPage(querys model.SMFCDREventQuery) map[string]any {
return r.cdrEventRepository.SelectPage(querys)
}
// DeleteByIds 批量删除信息
func (r *SMFCDREventImpl) DeleteByIds(cdrIds []string) (int64, error) {
// 检查是否存在
ids := r.cdrEventRepository.SelectByIds(cdrIds)
if len(ids) <= 0 {
return 0, fmt.Errorf("not data")
}
if len(ids) == len(cdrIds) {
rows := r.cdrEventRepository.DeleteByIds(cdrIds)
return rows, nil
}
// 删除信息失败!
return 0, fmt.Errorf("delete fail")
}

View File

@@ -31,7 +31,8 @@ func (r *PerfKPIImpl) SelectGoldKPI(query model.GoldKPIQuery) []map[string]any {
kpiIds = append(kpiIds, kpiId.KPIID)
}
data := r.perfKPIRepository.SelectGoldKPI(query, kpiIds)
//data := r.perfKPIRepository.SelectGoldKPI(query, kpiIds)
data := r.perfKPIRepository.SelectKpiReport(query, kpiIds)
if data == nil {
return []map[string]any{}
}
@@ -66,7 +67,8 @@ func (r *PerfKPIImpl) SelectUPFTotalFlow(neType, rmUID string, day int) map[stri
}
}
info = r.perfKPIRepository.SelectUPFTotalFlow(neType, rmUID, startDate, endDate)
//info = r.perfKPIRepository.SelectUPFTotalFlow(neType, rmUID, startDate, endDate)
info = r.perfKPIRepository.SelectUPFThroughput(neType, rmUID, startDate, endDate)
// 保存到缓存
infoJSON, _ := json.Marshal(info)

View File

@@ -155,3 +155,52 @@ func (s *NeActionController) Files(c *gin.Context) {
"rows": splitRows,
}))
}
// 网元服务操作
//
// PUT /service
func (s *NeActionController) Service(c *gin.Context) {
language := ctx.AcceptLanguage(c)
var body struct {
NeType string `json:"neType" binding:"required"`
NeID string `json:"neId" binding:"required"`
Action string `json:"action" binding:"required,oneof=start restart stop reboot poweroff"` // 操作行为
}
if err := c.ShouldBindBodyWith(&body, binding.JSON); err != nil {
c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
return
}
// 查询网元获取IP
neInfo := s.neInfoService.SelectNeInfoByNeTypeAndNeID(body.NeType, body.NeID)
if neInfo.NeId != body.NeID || neInfo.IP == "" {
c.JSON(200, result.ErrMsg(i18n.TKey(language, "app.common.noNEInfo")))
return
}
neTypeLower := strings.ToLower(neInfo.NeType)
cmdStr := fmt.Sprintf("sudo service %s %s", neTypeLower, body.Action)
if neTypeLower == "omc" {
cmdStr = fmt.Sprintf("nohup sh -c \"sudo systemctl stop restagent && sleep 5s && sudo systemctl %s restagent\" > /dev/null 2>&1 &", body.Action)
} else if neTypeLower == "ims" {
if body.Action == "restart" {
cmdStr = "sudo ims-stop || true && sudo ims-start"
} else {
cmdStr = fmt.Sprintf("sudo ims-%s", body.Action)
}
}
if body.Action == "reboot" {
cmdStr = "sudo shutdown -r now"
}
if body.Action == "poweroff" {
cmdStr = "sudo shutdown -h now"
}
_, err := s.neInfoService.NeRunCMD(body.NeType, body.NeID, cmdStr)
if err != nil {
c.JSON(200, result.ErrMsg(err.Error()))
return
}
c.JSON(200, result.Ok(nil))
}

View File

@@ -167,8 +167,7 @@ func (s *NeHostController) Remove(c *gin.Context) {
func (s *NeHostController) Test(c *gin.Context) {
language := ctx.AcceptLanguage(c)
var body model.NeHost
err := c.ShouldBindBodyWith(&body, binding.JSON)
if err != nil {
if err := c.ShouldBindBodyWith(&body, binding.JSON); err != nil {
c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
return
}
@@ -176,8 +175,13 @@ func (s *NeHostController) Test(c *gin.Context) {
if body.HostType == "ssh" {
var connSSH ssh.ConnSSH
body.CopyTo(&connSSH)
client, err := connSSH.NewClient()
var client *ssh.ConnSSH
var err error
if body.AuthMode == "2" {
client, err = connSSH.NewClientByLocalPrivate()
} else {
client, err = connSSH.NewClient()
}
if err != nil {
// 连接主机失败,请检查连接参数后重试
c.JSON(200, result.ErrMsg(i18n.TKey(language, "neHost.errByHostInfo")))
@@ -199,7 +203,12 @@ func (s *NeHostController) Test(c *gin.Context) {
return
}
defer client.Close()
c.JSON(200, result.Ok(nil))
if strings.HasSuffix(client.LastResult, ">") || strings.HasSuffix(client.LastResult, "> ") || strings.HasSuffix(client.LastResult, "# ") {
c.JSON(200, result.Ok(nil))
} else {
// 连接主机失败,请检查连接参数后重试
c.JSON(200, result.ErrMsg(i18n.TKey(language, "neHost.errByHostInfo")))
}
return
}
}
@@ -213,8 +222,7 @@ func (s *NeHostController) Cmd(c *gin.Context) {
HostID string `json:"hostId" binding:"required"` // 主机ID
Cmd string `json:"cmd" binding:"required"` // 执行命令
}
err := c.ShouldBindBodyWith(&body, binding.JSON)
if err != nil {
if err := c.ShouldBindBodyWith(&body, binding.JSON); err != nil {
c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
return
}
@@ -230,8 +238,13 @@ func (s *NeHostController) Cmd(c *gin.Context) {
if neHost.HostType == "ssh" {
var connSSH ssh.ConnSSH
neHost.CopyTo(&connSSH)
client, err := connSSH.NewClient()
var client *ssh.ConnSSH
var err error
if neHost.AuthMode == "2" {
client, err = connSSH.NewClientByLocalPrivate()
} else {
client, err = connSSH.NewClient()
}
if err != nil {
// 连接主机失败,请检查连接参数后重试
c.JSON(200, result.ErrMsg(i18n.TKey(language, "neHost.errByHostInfo")))
@@ -278,17 +291,21 @@ func (s *NeHostController) Cmd(c *gin.Context) {
func (s *NeHostController) CheckBySSH(c *gin.Context) {
language := ctx.AcceptLanguage(c)
var body model.NeHost
err := c.ShouldBindBodyWith(&body, binding.JSON)
if err != nil {
if err := c.ShouldBindBodyWith(&body, binding.JSON); err != nil {
c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
return
}
var connSSH ssh.ConnSSH
body.CopyTo(&connSSH)
// 创建链接SSH客户端
client, err := connSSH.NewClient()
var client *ssh.ConnSSH
var err error
if body.AuthMode == "2" {
client, err = connSSH.NewClientByLocalPrivate()
} else {
client, err = connSSH.NewClient()
}
if err != nil {
// 连接主机失败,请检查连接参数后重试
c.JSON(200, result.ErrMsg(i18n.TKey(language, "neHost.errByHostInfo")))
@@ -339,18 +356,22 @@ func (s *NeHostController) CheckBySSH(c *gin.Context) {
}
// 本地免密创建链接直连
lcoalConnSSH := ssh.ConnSSH{
User: body.User,
Addr: body.Addr,
Port: body.Port,
}
lcoalClient, err := lcoalConnSSH.NewClientByLocalPrivate()
if err == nil {
if body.AuthMode == "2" {
data["sshLink"] = true
} else {
data["sshLink"] = false
lcoalConnSSH := ssh.ConnSSH{
User: body.User,
Addr: body.Addr,
Port: body.Port,
}
lcoalClient, err := lcoalConnSSH.NewClientByLocalPrivate()
if err == nil {
data["sshLink"] = true
defer lcoalClient.Close()
} else {
data["sshLink"] = false
}
}
defer lcoalClient.Close()
c.JSON(200, result.OkData(data))
}
@@ -361,8 +382,7 @@ func (s *NeHostController) CheckBySSH(c *gin.Context) {
func (s *NeHostController) AuthorizedBySSH(c *gin.Context) {
language := ctx.AcceptLanguage(c)
var body model.NeHost
err := c.ShouldBindBodyWith(&body, binding.JSON)
if err != nil {
if err := c.ShouldBindBodyWith(&body, binding.JSON); err != nil || body.AuthMode == "2" {
c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
return
}
@@ -377,8 +397,8 @@ func (s *NeHostController) AuthorizedBySSH(c *gin.Context) {
lcoalClient, err := lcoalConnSSH.NewClientByLocalPrivate()
if err == nil {
sshLink = true
defer lcoalClient.Close()
}
defer lcoalClient.Close()
if sshLink {
// 连接主机成功,无需重复免密授权认证
c.JSON(200, result.OkMsg(i18n.TKey(language, "neHost.okBySSHLink")))

View File

@@ -17,15 +17,21 @@ import (
// 实例化控制层 NeInfoController 结构体
var NewNeInfo = &NeInfoController{
neInfoService: neService.NewNeInfoImpl,
neInfoService: neService.NewNeInfoImpl,
neLicenseService: neService.NewNeLicenseImpl,
neVersionService: neService.NewNeVersionImpl,
}
// 网元信息请求
//
// PATH /
// PATH /info
type NeInfoController struct {
// 网元信息服务
neInfoService neService.INeInfo
// 网元授权激活信息服务
neLicenseService neService.INeLicense
// 网元版本信息服务
neVersionService neService.INeVersion
}
// neStateCacheMap 网元状态缓存最后一次成功的信息
@@ -114,7 +120,8 @@ func (s *NeInfoController) ListAll(c *gin.Context) {
var querys struct {
NeType string `form:"neType"`
NeId string `form:"neId"`
BandStatus string `form:"bandStatus"`
BandStatus bool `form:"bandStatus"`
BandHost bool `form:"bandHost"`
}
if err := c.ShouldBindQuery(&querys); err != nil {
c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
@@ -129,8 +136,7 @@ func (s *NeInfoController) ListAll(c *gin.Context) {
if querys.NeId != "" {
ne.NeId = querys.NeId
}
bandStatus := parse.Boolean(querys.BandStatus)
neList := s.neInfoService.SelectList(ne, bandStatus)
neList := s.neInfoService.SelectList(ne, querys.BandStatus, querys.BandHost)
if len(neList) == 0 {
c.JSON(200, result.ErrMsg(i18n.TKey(language, "app.common.noNEInfo")))
return
@@ -138,53 +144,74 @@ func (s *NeInfoController) ListAll(c *gin.Context) {
c.JSON(200, result.OkData(neList))
}
// 网元端配置文件读取
// 网元端Para5G配置文件读取
//
// GET /configFile
func (s *NeInfoController) ConfigFileRead(c *gin.Context) {
// GET /para5GFile
func (s *NeInfoController) Para5GFileRead(c *gin.Context) {
data, err := s.neInfoService.NeConfPara5GRead()
if err != nil {
c.JSON(200, result.ErrMsg(err.Error()))
return
}
c.JSON(200, result.OkData(data))
}
// 网元端Para5G配置文件写入
//
// PUT /para5GFile
func (s *NeInfoController) Para5GFileWrite(c *gin.Context) {
language := ctx.AcceptLanguage(c)
var body struct {
Content map[string]any `json:"content" binding:"required"` // 内容
SyncNE []string `json:"syncNe"` // 同步到网元
}
if err := c.ShouldBindBodyWith(&body, binding.JSON); err != nil {
c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
return
}
err := s.neInfoService.NeConfPara5GWirte(body.Content, body.SyncNE)
if err != nil {
c.JSON(200, result.ErrMsg(err.Error()))
return
}
c.JSON(200, result.Ok(nil))
}
// 网元端OAM配置文件读取
//
// GET /oamFile
func (s *NeInfoController) OAMFileRead(c *gin.Context) {
language := ctx.AcceptLanguage(c)
var querys struct {
NeType string `form:"neType" binding:"required"`
NeID string `form:"neId" binding:"required"`
FilePath string `form:"filePath"` // 不带文件路径时进行复制覆盖本地网元配置目录
NeType string `form:"neType" binding:"required"`
NeID string `form:"neId" binding:"required"`
}
if err := c.ShouldBindQuery(&querys); err != nil {
c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
return
}
// 查询网元获取IP
neInfo := s.neInfoService.SelectNeInfoByNeTypeAndNeID(querys.NeType, querys.NeID)
if neInfo.NeId != querys.NeID || neInfo.IP == "" {
c.JSON(200, result.ErrMsg(i18n.TKey(language, "app.common.noNEInfo")))
data, err := s.neInfoService.NeConfOAMRead(querys.NeType, querys.NeID)
if err != nil {
c.JSON(200, result.ErrMsg(err.Error()))
return
}
data := s.neInfoService.NeConfigFileRead(neInfo, querys.FilePath)
if querys.FilePath == "" {
c.JSON(200, result.OkData(data))
return
}
if len(data) > 0 {
c.JSON(200, result.OkData(data[0]))
return
}
c.JSON(200, result.ErrMsg("no data"))
c.JSON(200, result.OkData(data))
}
// 网元端配置文件写入
// 网元端OAM配置文件写入
//
// PUT /configFile
func (s *NeInfoController) ConfigFileWrite(c *gin.Context) {
// PUT /oamFile
func (s *NeInfoController) OAMFileWrite(c *gin.Context) {
language := ctx.AcceptLanguage(c)
var body struct {
NeType string `json:"neType" binding:"required"`
NeID string `json:"neId" binding:"required"`
FilePath string `json:"filePath" binding:"required"`
Content string `json:"content" binding:"required"`
Sync bool `json:"sync"`
NeType string `json:"neType" binding:"required"`
NeID string `json:"neId" binding:"required"`
Content map[string]any `json:"content" binding:"required"` // 内容
Sync bool `json:"sync"` // 同步到网元
}
if err := c.ShouldBindJSON(&body); err != nil {
if err := c.ShouldBindBodyWith(&body, binding.JSON); err != nil {
c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
return
}
@@ -196,7 +223,7 @@ func (s *NeInfoController) ConfigFileWrite(c *gin.Context) {
return
}
err := s.neInfoService.NeConfigFileWirte(neInfo, body.FilePath, body.Content, body.Sync)
err := s.neInfoService.NeConfOAMSync(neInfo, body.Content, body.Sync)
if err != nil {
c.JSON(200, result.ErrMsg(err.Error()))
return
@@ -260,22 +287,53 @@ func (s *NeInfoController) Add(c *gin.Context) {
}
// 获取网元状态是否正常
_, err = neService.NeState(body)
body.ServerState, err = neService.NeState(body)
if err != nil {
body.Status = "1"
body.Status = "0"
} else {
// 下发网管配置信息给网元
_, err = neService.NeConfigOMC(body)
if err == nil {
body.Status = "0"
body.Status = "1"
} else {
body.Status = "3"
body.Status = "2"
}
}
loginUserName := ctx.LoginUserToUserName(c)
// 新增Version信息
neVersion := model.NeVersion{
NeType: body.NeType,
NeId: body.NeId,
CreateBy: loginUserName,
}
// 新增License信息
neLicense := model.NeLicense{
NeType: body.NeType,
NeId: body.NeId,
CreateBy: loginUserName,
}
// 已有网元可获取的信息
if body.ServerState != nil {
if v, ok := body.ServerState["version"]; ok && v != nil {
neVersion.Version = v.(string)
}
if v, ok := body.ServerState["sn"]; ok && v != nil {
neLicense.SerialNum = v.(string)
}
if v, ok := body.ServerState["expire"]; ok && v != nil {
neLicense.ExpiryDate = v.(string)
neLicense.Status = "1"
}
}
s.neVersionService.Insert(neVersion)
s.neLicenseService.Insert(neLicense)
body.CreateBy = loginUserName
insertId := s.neInfoService.Insert(body)
if insertId != "" {
c.JSON(200, result.Ok(nil))
c.JSON(200, result.OkData(insertId))
return
}
c.JSON(200, result.Err(nil))
@@ -294,8 +352,8 @@ func (s *NeInfoController) Edit(c *gin.Context) {
}
// 检查属性值唯一
uniqueHostCmd := s.neInfoService.CheckUniqueNeTypeAndNeId(body.NeType, body.NeId, body.ID)
if !uniqueHostCmd {
uniqueInfo := s.neInfoService.CheckUniqueNeTypeAndNeId(body.NeType, body.NeId, body.ID)
if !uniqueInfo {
// 网元信息操作【%s】失败同类型下标识已存在
msg := i18n.TTemplate(language, "neInfo.errKeyExists", map[string]any{"key": body.NeId})
c.JSON(200, result.ErrMsg(msg))
@@ -309,21 +367,64 @@ func (s *NeInfoController) Edit(c *gin.Context) {
c.JSON(200, result.ErrMsg(i18n.TKey(language, "neInfo.noData")))
return
}
// 赋予主机ID
if neInfo.HostIDs != "" && len(body.Hosts) > 0 {
hostIDs := strings.Split(neInfo.HostIDs, ",")
for index, id := range hostIDs {
body.Hosts[index].HostID = id
}
}
// 获取网元状态是否正常
_, err = neService.NeState(body)
body.ServerState, err = neService.NeState(body)
if err != nil {
body.Status = "1"
body.Status = "0"
} else {
// 下发网管配置信息给网元
_, err = neService.NeConfigOMC(body)
if err == nil {
body.Status = "0"
body.Status = "1"
} else {
body.Status = "3"
body.Status = "2"
}
}
loginUserName := ctx.LoginUserToUserName(c)
neLicense := s.neLicenseService.SelectByNeTypeAndNeID(neInfo.NeType, neInfo.NeId)
neVersion := s.neVersionService.SelectByNeTypeAndNeID(neInfo.NeType, neInfo.NeId)
// 已有网元可获取的信息
if body.ServerState != nil {
if v, ok := body.ServerState["version"]; ok && v != nil {
neVersion.Version = v.(string)
neVersion.UpdateBy = loginUserName
}
if v, ok := body.ServerState["sn"]; ok && v != nil {
neLicense.SerialNum = v.(string)
}
if v, ok := body.ServerState["expire"]; ok && v != nil {
neLicense.ExpiryDate = v.(string)
neLicense.Status = "1"
neLicense.UpdateBy = loginUserName
}
}
if neVersion.ID != "" {
if neVersion.NeType != body.NeType || neVersion.NeId != body.NeId {
neVersion.NeType = body.NeType
neVersion.NeId = body.NeId
}
s.neVersionService.Update(neVersion)
}
if neLicense.ID != "" {
if neLicense.NeType != body.NeType || neLicense.NeId != body.NeId {
neLicense.NeType = body.NeType
neLicense.NeId = body.NeId
}
s.neLicenseService.Update(neLicense)
}
body.UpdateBy = loginUserName
rows := s.neInfoService.Update(body)
if rows > 0 {
c.JSON(200, result.Ok(nil))

View File

@@ -2,11 +2,9 @@ package controller
import (
"fmt"
"strings"
"be.ems/src/framework/i18n"
"be.ems/src/framework/utils/ctx"
"be.ems/src/framework/utils/parse"
"be.ems/src/framework/vo/result"
"be.ems/src/modules/network_element/model"
neService "be.ems/src/modules/network_element/service"
@@ -37,6 +35,14 @@ func (s *NeLicenseController) List(c *gin.Context) {
querys := ctx.QueryMap(c)
data := s.neLicenseService.SelectPage(querys)
// 过滤屏蔽授权文件
rows := data["rows"].([]model.NeLicense)
arr := &rows
for i := range *arr {
(*arr)[i].ActivationRequestCode = "-"
(*arr)[i].LicensePath = "-"
}
c.JSON(200, result.Ok(data))
}
@@ -61,109 +67,28 @@ func (s *NeLicenseController) Info(c *gin.Context) {
c.JSON(200, result.OkData(neLicense))
}
// 网元授权激活信息新增
// 网元neType和neID查询
//
// POST /
func (s *NeLicenseController) Add(c *gin.Context) {
// GET /byTypeAndID
func (s *NeLicenseController) NeTypeAndID(c *gin.Context) {
language := ctx.AcceptLanguage(c)
var body model.NeLicense
err := c.ShouldBindBodyWith(&body, binding.JSON)
if err != nil || body.ID != "" {
var querys struct {
NeType string `form:"neType" binding:"required"`
NeId string `form:"neId" binding:"required"`
}
if err := c.ShouldBindQuery(&querys); err != nil {
c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
return
}
// 查询网元获取IP
neInfo := s.neInfoService.SelectNeInfoByNeTypeAndNeID(body.NeType, body.NeId)
if neInfo.NeId != body.NeId || neInfo.IP == "" {
c.JSON(200, result.ErrMsg(i18n.TKey(language, "app.common.noNEInfo")))
return
}
// 检查属性值唯一
uniqueInfo := s.neLicenseService.CheckUniqueTypeAndID(neInfo.NeType, neInfo.NeId, "")
if !uniqueInfo {
// 网元授权激活操作【%s】失败网元类型信息已存在
msg := i18n.TTemplate(language, "neLicense.errKeyExists", map[string]any{"name": neInfo.NeType})
c.JSON(200, result.ErrMsg(msg))
return
}
// 读取授权码
code, _ := s.neLicenseService.ReadLicenseInfo(neInfo)
body.ActivationRequestCode = code
body.CreateBy = ctx.LoginUserToUserName(c)
insertId := s.neLicenseService.Insert(body)
if insertId != "" {
c.JSON(200, result.Ok(nil))
return
}
c.JSON(200, result.Err(nil))
}
// 网元授权激活信息修改
//
// PUT /
func (s *NeLicenseController) Edit(c *gin.Context) {
language := ctx.AcceptLanguage(c)
var body model.NeLicense
err := c.ShouldBindBodyWith(&body, binding.JSON)
if err != nil || body.ID == "" {
c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
return
}
// 检查属性值唯一
uniqueInfo := s.neLicenseService.CheckUniqueTypeAndID(body.NeType, body.NeId, body.ID)
if !uniqueInfo {
// 网元授权激活操作【%s】失败网元类型信息已存在
msg := i18n.TTemplate(language, "neLicense.errKeyExists", map[string]any{"name": body.NeType})
c.JSON(200, result.ErrMsg(msg))
return
}
// 检查是否存在
neLicense := s.neLicenseService.SelectById(body.ID)
if neLicense.ID != body.ID {
neLicense := s.neLicenseService.SelectByNeTypeAndNeID(querys.NeType, querys.NeId)
if neLicense.NeId != querys.NeId {
// 没有可访问网元授权激活数据!
c.JSON(200, result.ErrMsg(i18n.TKey(language, "neLicense.noData")))
return
}
body.UpdateBy = ctx.LoginUserToUserName(c)
rows := s.neLicenseService.Update(body)
if rows > 0 {
c.JSON(200, result.Ok(nil))
return
}
c.JSON(200, result.Err(nil))
}
// 网元授权激活信息删除
//
// DELETE /:licenseIds
func (s *NeLicenseController) Remove(c *gin.Context) {
language := ctx.AcceptLanguage(c)
licenseIds := c.Param("licenseIds")
if licenseIds == "" {
c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
return
}
// 处理字符转id数组后去重
ids := strings.Split(licenseIds, ",")
uniqueIDs := parse.RemoveDuplicates(ids)
if len(uniqueIDs) <= 0 {
c.JSON(200, result.Err(nil))
return
}
rows, err := s.neLicenseService.DeleteByIds(uniqueIDs)
if err != nil {
c.JSON(200, result.ErrMsg(i18n.TKey(language, err.Error())))
return
}
msg := i18n.TTemplate(language, "app.common.deleteSuccess", map[string]any{"num": rows})
c.JSON(200, result.OkMsg(msg))
c.JSON(200, result.OkData(neLicense))
}
// 网元授权激活授权申请码
@@ -180,15 +105,8 @@ func (s *NeLicenseController) Code(c *gin.Context) {
return
}
// 查询网元获取IP
neInfo := s.neInfoService.SelectNeInfoByNeTypeAndNeID(querys.NeType, querys.NeId)
if neInfo.NeId != querys.NeId || neInfo.IP == "" {
c.JSON(200, result.ErrMsg(i18n.TKey(language, "app.common.noNEInfo")))
return
}
// 检查是否存在授权记录
neLicense := s.neLicenseService.SelectByNeTypeAndNeID(neInfo.NeType, neInfo.NeId)
neLicense := s.neLicenseService.SelectByNeTypeAndNeID(querys.NeType, querys.NeId)
if neLicense.NeId != querys.NeId {
// 没有可访问网元授权激活数据!
c.JSON(200, result.ErrMsg(i18n.TKey(language, "neLicense.noData")))
@@ -196,7 +114,7 @@ func (s *NeLicenseController) Code(c *gin.Context) {
}
// 更新授权码
code, licensePath := s.neLicenseService.ReadLicenseInfo(neInfo)
code, licensePath := s.neLicenseService.ReadLicenseInfo(neLicense)
neLicense.ActivationRequestCode = code
if licensePath != "" {
neLicense.LicensePath = licensePath
@@ -218,7 +136,7 @@ func (s *NeLicenseController) Change(c *gin.Context) {
language := ctx.AcceptLanguage(c)
var body model.NeLicense
err := c.ShouldBindBodyWith(&body, binding.JSON)
if err != nil || body.HostId == "" {
if err != nil || body.LicensePath == "" {
c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
return
}
@@ -226,23 +144,30 @@ func (s *NeLicenseController) Change(c *gin.Context) {
// 检查是否存在授权记录
neLicense := s.neLicenseService.SelectByNeTypeAndNeID(body.NeType, body.NeId)
if neLicense.NeId != body.NeId {
body.Status = "0"
body.CreateBy = ctx.LoginUserToUserName(c)
body.ID = s.neLicenseService.Insert(body)
} else {
neLicense.LicensePath = body.LicensePath
neLicense.Status = "0"
neLicense.UpdateBy = ctx.LoginUserToUserName(c)
s.neLicenseService.Update(neLicense)
}
// 进行上传替换
err = s.neLicenseService.UploadToNeHost(body)
if err != nil {
c.JSON(200, result.ErrMsg(err.Error()))
// 没有可访问网元授权激活数据!
c.JSON(200, result.ErrMsg(i18n.TKey(language, "neLicense.noData")))
return
}
c.JSON(200, result.Ok(nil))
// 更新授权记录
if body.Remark != "" {
neLicense.Remark = body.Remark
}
neLicense.LicensePath = body.LicensePath
neLicense.Status = "0"
neLicense.UpdateBy = ctx.LoginUserToUserName(c)
upRows := s.neLicenseService.Update(neLicense)
if upRows > 0 {
// 进行上传替换
err = s.neLicenseService.UploadLicense(body)
if err != nil {
c.JSON(200, result.ErrMsg(err.Error()))
return
}
c.JSON(200, result.Ok(nil))
return
}
c.JSON(200, result.Err(nil))
}
// 网元授权激活状态
@@ -259,43 +184,41 @@ func (s *NeLicenseController) State(c *gin.Context) {
return
}
// 查询网元获取IP
neInfo := s.neInfoService.SelectNeInfoByNeTypeAndNeID(querys.NeType, querys.NeId)
if neInfo.NeId != querys.NeId || neInfo.IP == "" {
c.JSON(200, result.ErrMsg(i18n.TKey(language, "app.common.noNEInfo")))
return
}
// 检查是否存在授权记录
neLicense := s.neLicenseService.SelectByNeTypeAndNeID(neInfo.NeType, neInfo.NeId)
neLicense := s.neLicenseService.SelectByNeTypeAndNeID(querys.NeType, querys.NeId)
if neLicense.NeId != querys.NeId {
// 没有可访问网元授权激活数据!
c.JSON(200, result.ErrMsg(i18n.TKey(language, "neLicense.noData")))
return
}
// 查询网元状态
neState, err := neService.NeState(neInfo)
if err != nil {
c.JSON(200, result.ErrMsg("network element service anomaly"))
// 查询网元获取IP获取网元状态
neInfo := s.neInfoService.SelectNeInfoByNeTypeAndNeID(neLicense.NeType, neLicense.NeId)
if neInfo.NeId != neLicense.NeId || neInfo.IP == "" {
c.JSON(200, result.ErrMsg(i18n.TKey(language, "app.common.noNEInfo")))
return
}
if neState, err := neService.NeState(neInfo); err == nil {
neLicense.Status = "1"
neLicense.SerialNum = fmt.Sprint(neState["sn"])
neLicense.ExpiryDate = fmt.Sprint(neState["expire"])
code, licensePath := s.neLicenseService.ReadLicenseInfo(neLicense)
neLicense.ActivationRequestCode = code
neLicense.LicensePath = licensePath
} else {
neLicense.Status = "0"
}
// 更新授权信息
neLicense.SerialNum = fmt.Sprint(neState["sn"])
neLicense.ExpiryDate = fmt.Sprint(neState["expire"])
code, licensePath := s.neLicenseService.ReadLicenseInfo(neInfo)
neLicense.ActivationRequestCode = code
neLicense.LicensePath = licensePath
neLicense.Status = "1"
neLicense.UpdateBy = ctx.LoginUserToUserName(c)
rows := s.neLicenseService.Update(neLicense)
if rows > 0 {
s.neLicenseService.Update(neLicense)
if neLicense.Status == "1" {
c.JSON(200, result.OkData(map[string]string{
"sn": neLicense.SerialNum,
"expire": neLicense.ExpiryDate,
}))
return
}
c.JSON(200, result.Err(nil))
c.JSON(200, result.ErrMsg(fmt.Sprintf("%s service status exception", neLicense.NeType)))
}

View File

@@ -69,15 +69,26 @@ func (s *NeSoftwareController) Add(c *gin.Context) {
return
}
// 检查属性值唯一
uniqueSoftware := s.neSoftwareService.CheckUniqueTypeAndNameAndVersion(body.NeType, body.Name, body.Version, "")
if !uniqueSoftware {
// 网元软件包操作【%s】失败网元类型与文件名版本已存在
msg := i18n.TTemplate(language, "neSoftware.errKeyExists", map[string]any{"name": body.Name})
c.JSON(200, result.ErrMsg(msg))
return
// 找到已存在的删除后重新添加
neSoftwares := s.neSoftwareService.SelectList(model.NeSoftware{
NeType: body.NeType,
Name: body.Name,
Version: body.Version,
})
if len(neSoftwares) > 0 {
neSoftware := neSoftwares[0]
s.neSoftwareService.DeleteByIds([]string{neSoftware.ID})
}
// 检查属性值唯一
// uniqueSoftware := s.neSoftwareService.CheckUniqueTypeAndNameAndVersion(body.NeType, body.Name, body.Version, "")
// if !uniqueSoftware {
// // 网元软件包操作【%s】失败网元类型与文件名版本已存在
// msg := i18n.TTemplate(language, "neSoftware.errKeyExists", map[string]any{"name": body.Name})
// c.JSON(200, result.ErrMsg(msg))
// return
// }
body.CreateBy = ctx.LoginUserToUserName(c)
insertId := s.neSoftwareService.Insert(body)
if insertId != "" {
@@ -151,40 +162,32 @@ func (s *NeSoftwareController) Remove(c *gin.Context) {
c.JSON(200, result.OkMsg(msg))
}
// 网元软件包安装检查
// 网元软件包设为网元新版本
//
// POST /checkInstall
func (s *NeSoftwareController) CheckInstall(c *gin.Context) {
// POST /newNeVersion
func (s *NeSoftwareController) NewNeVersion(c *gin.Context) {
language := ctx.AcceptLanguage(c)
var body model.NeSoftware
err := c.ShouldBindBodyWith(&body, binding.JSON)
if err != nil || body.HostId == "" {
if err != nil {
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,
})
if len(neSoftwares) <= 0 {
body.CreateBy = ctx.LoginUserToUserName(c)
body.ID = s.neSoftwareService.Insert(body)
} else {
if len(neSoftwares) > 0 {
neSoftware := neSoftwares[0]
neSoftware.Path = body.Path
neSoftware.Description = body.Description
neSoftware.UpdateBy = ctx.LoginUserToUserName(c)
s.neSoftwareService.Update(neSoftware)
}
// 进行安装检查
cmdStrArr, err := s.neSoftwareService.UploadToNeHost(body)
if err != nil {
c.JSON(200, result.ErrMsg(err.Error()))
s.neSoftwareService.UpdateVersions(neSoftware, model.NeVersion{
NeType: neSoftware.NeType,
UpdateBy: ctx.LoginUserToUserName(c),
})
c.JSON(200, result.Ok(nil))
return
}
c.JSON(200, result.OkData(cmdStrArr))
c.JSON(200, result.Err(nil))
}

View File

@@ -1,13 +1,9 @@
package controller
import (
"strings"
"be.ems/src/framework/i18n"
"be.ems/src/framework/utils/ctx"
"be.ems/src/framework/utils/parse"
"be.ems/src/framework/vo/result"
"be.ems/src/modules/network_element/model"
neService "be.ems/src/modules/network_element/service"
"github.com/gin-gonic/gin"
"github.com/gin-gonic/gin/binding"
@@ -57,96 +53,34 @@ func (s *NeVersionController) Info(c *gin.Context) {
c.JSON(200, result.OkData(neVersion))
}
// 网元版本信息新增
// 网元版本操作
//
// POST /
func (s *NeVersionController) Add(c *gin.Context) {
// POST /operate
func (s *NeVersionController) Operate(c *gin.Context) {
language := ctx.AcceptLanguage(c)
var body model.NeVersion
err := c.ShouldBindBodyWith(&body, binding.JSON)
if err != nil || body.ID != "" {
var body struct {
Action string `json:"action" binding:"required,oneof=install upgrade rollback"` // 操作行为
NeType string `json:"neType" gorm:"ne_type" binding:"required"` // 网元类型
NeId string `json:"neId" gorm:"ne_id" binding:"required"` // 网元ID
Preinput map[string]string `json:"preinput" ` // 预先输入参数
}
if err := c.ShouldBindBodyWith(&body, binding.JSON); err != nil {
c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
return
}
// 检查属性值唯一
uniqueInfo := s.neVersionService.CheckUniqueTypeAndID(body.NeType, body.NeId, "")
if !uniqueInfo {
// 网元版本操作【%s】失败网元类型信息已存在
msg := i18n.TTemplate(language, "neVersion.errKeyExists", map[string]any{"name": body.NeType})
c.JSON(200, result.ErrMsg(msg))
return
}
body.CreateBy = ctx.LoginUserToUserName(c)
insertId := s.neVersionService.Insert(body)
if insertId != "" {
c.JSON(200, result.Ok(nil))
return
}
c.JSON(200, result.Err(nil))
}
// 网元版本信息修改
//
// PUT /
func (s *NeVersionController) Edit(c *gin.Context) {
language := ctx.AcceptLanguage(c)
var body model.NeVersion
err := c.ShouldBindBodyWith(&body, binding.JSON)
if err != nil || body.ID == "" {
c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
return
}
// 检查属性值唯一
uniqueInfo := s.neVersionService.CheckUniqueTypeAndID(body.NeType, body.NeId, body.ID)
if !uniqueInfo {
// 网元版本操作【%s】失败网元类型信息已存在
msg := i18n.TTemplate(language, "neVersion.errKeyExists", map[string]any{"name": body.NeType})
c.JSON(200, result.ErrMsg(msg))
return
}
// 检查是否存在
neVersion := s.neVersionService.SelectById(body.ID)
if neVersion.ID != body.ID {
neVersion := s.neVersionService.SelectByNeTypeAndNeID(body.NeType, body.NeId)
if neVersion.NeId != body.NeId {
// 没有可访问网元版本数据!
c.JSON(200, result.ErrMsg(i18n.TKey(language, "neVersion.noData")))
return
}
body.UpdateBy = ctx.LoginUserToUserName(c)
rows := s.neVersionService.Update(body)
if rows > 0 {
c.JSON(200, result.Ok(nil))
return
}
c.JSON(200, result.Err(nil))
}
// 网元版本信息删除
//
// DELETE /:versionIds
func (s *NeVersionController) Remove(c *gin.Context) {
language := ctx.AcceptLanguage(c)
versionIds := c.Param("versionIds")
if versionIds == "" {
c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
return
}
// 处理字符转id数组后去重
ids := strings.Split(versionIds, ",")
uniqueIDs := parse.RemoveDuplicates(ids)
if len(uniqueIDs) <= 0 {
c.JSON(200, result.Err(nil))
return
}
rows, err := s.neVersionService.DeleteByIds(uniqueIDs)
// 进行相关命令操作
output, err := s.neVersionService.Operate(body.Action, neVersion, body.Preinput)
if err != nil {
c.JSON(200, result.ErrMsg(i18n.TKey(language, err.Error())))
return
}
msg := i18n.TTemplate(language, "app.common.deleteSuccess", map[string]any{"num": rows})
c.JSON(200, result.OkMsg(msg))
c.JSON(200, result.OkData(output))
}

View File

@@ -11,7 +11,7 @@ type NeHost struct {
Addr string `json:"addr" gorm:"column:addr" binding:"required"` // 主机地址
Port int64 `json:"port" gorm:"column:port" binding:"required,number,max=65535,min=1"` // SSH端口
User string `json:"user" gorm:"column:user" binding:"required"` // 主机用户名
AuthMode string `json:"authMode" gorm:"column:auth_mode" binding:"oneof=0 1"` // 认证模式0密码 1主机私钥
AuthMode string `json:"authMode" gorm:"column:auth_mode" binding:"oneof=0 1 2"` // 认证模式0密码 1主机私钥 2已免密
Password string `json:"password" gorm:"column:password"` // 认证密码
PrivateKey string `json:"privateKey" gorm:"column:private_key"` // 认证私钥
PassPhrase string `json:"passPhrase" gorm:"column:pass_phrase"` // 认证私钥密码

View File

@@ -2,21 +2,25 @@ package model
// NeInfo 网元信息对象 ne_info
type NeInfo struct {
ID string `json:"id"`
NeType string `json:"neType" binding:"required"`
NeId string `json:"neId" binding:"required"`
RmUID string `json:"rmUid"`
NeName string `json:"neName"`
IP string `json:"ip" binding:"required"`
Port int64 `json:"port" binding:"required,number,max=65535,min=1"`
PvFlag string `json:"pvFlag" binding:"oneof=PNF VNF"` // enum('PNF','VNF')
Province string `json:"province"`
VendorName string `json:"vendorName"`
Dn string `json:"dn"`
NeAddress string `json:"neAddress"`
Status string `json:"status"` // 0: 在线 1: 下线 2: 备用 3: 待下发配置
UpdateTime string `json:"updateTime"`
HostIDs string `json:"hostIds"` // 网元主机ID组 数据格式(ssh,telnet,telnet)
ID string `json:"id" gorm:"id"`
NeType string `json:"neType" gorm:"ne_type" binding:"required"`
NeId string `json:"neId" gorm:"ne_id" binding:"required"`
RmUID string `json:"rmUid" gorm:"rm_uid"`
NeName string `json:"neName" gorm:"ne_name"`
IP string `json:"ip" gorm:"ip" binding:"required"`
Port int64 `json:"port" gorm:"port" binding:"required,number,max=65535,min=1"`
PvFlag string `json:"pvFlag" gorm:"pv_flag" binding:"oneof=PNF VNF"` // ''PNF'',''VNF''
Province string `json:"province" gorm:"province"` // 省份地域
VendorName string `json:"vendorName" gorm:"vendor_name"`
Dn string `json:"dn" gorm:"dn"`
NeAddress string `json:"neAddress" gorm:"ne_address"` // MAC地址
HostIDs string `json:"hostIds" gorm:"host_ids"` // 网元主机ID组 数据格式(ssh,telnet,telnet)
Status string `json:"status" gorm:"status"` // 0离线 1在线 2配置待下发
Remark string `json:"remark" gorm:"remark"` // 备注
CreateBy string `json:"createBy" gorm:"create_by"` // 创建者
CreateTime int64 `json:"createTime" gorm:"create_time"` // 创建时间
UpdateBy string `json:"updateBy" gorm:"update_by"` // 更新者
UpdateTime int64 `json:"updateTime" gorm:"update_time"` // 更新时间
// ====== 非数据库字段属性 ======

View File

@@ -9,7 +9,7 @@ type NeLicense struct {
LicensePath string `json:"licensePath" gorm:"license_path"` // 激活授权文件
SerialNum string `json:"serialNum" gorm:"serial_num"` // 序列号
ExpiryDate string `json:"expiryDate" gorm:"expiry_date"` // 许可证到期日期
Status string `json:"status" gorm:"status"` // 状态 ''ACTIVE'',''INACTIVE'',''PENDING''
Status string `json:"status" gorm:"status"` // 状态 0无效 1有效
Remark string `json:"remark" gorm:"remark"` // 备注
CreateBy string `json:"createBy" gorm:"create_by"` // 创建者
CreateTime int64 `json:"createTime" gorm:"create_time"` // 创建时间
@@ -18,8 +18,7 @@ type NeLicense struct {
// ====== 非数据库字段属性 ======
Reload bool `json:"reload,omitempty" gorm:"-"` // 刷新重启网元
HostId string `json:"hostId,omitempty" gorm:"-"` // 已记录的主机ID
Reload bool `json:"reload,omitempty" gorm:"-"` // 刷新重启网元
}
// TableName 表名称

View File

@@ -15,7 +15,7 @@ type NeSoftware struct {
// ====== 非数据库字段属性 ======
HostId string `json:"hostId,omitempty" gorm:"-"` // 已记录的主机ID
NeId string `json:"neId,omitempty" gorm:"-"` // 网元ID
}
// TableName 表名称

View File

@@ -5,13 +5,16 @@ type NeVersion struct {
ID string `json:"id" gorm:"id"`
NeType string `json:"neType" gorm:"ne_type" binding:"required"` // 网元类型
NeId string `json:"neId" gorm:"ne_id" binding:"required"` // 网元ID
Name string `json:"name" gorm:"name"` // 当前包名
Version string `json:"version" gorm:"version" binding:"required"` // 当前版本
Path string `json:"path" gorm:"path" binding:"required"` // 当前软件包
PreName string `json:"preName" gorm:"pre_name"` // 上一版本包名
PreVersion string `json:"preVersion" gorm:"pre_version"` // 上一版本
PrePath string `json:"prePath" gorm:"pre_path"` // 上一版本软件包
NewVersion string `json:"newVersion" gorm:"new_version"` // 下一版本
NewPath string `json:"newPath" gorm:"new_path"` // 下一版本软件包
Status string `json:"status" gorm:"status"` // 当前状态 (Uploaded下一版本上传 Inactive下一版本待激活 Active当前已激活)
NewName string `json:"newName" gorm:"new_name"` // 新版本包名
NewVersion string `json:"newVersion" gorm:"new_version"` // 新版本
NewPath string `json:"newPath" gorm:"new_path"` // 新版本软件包
Status string `json:"status" gorm:"status"` // 当前状态 1当前版本 2上一版本 3有新版本
CreateBy string `json:"createBy" gorm:"column:create_by"` // 创建者
CreateTime int64 `json:"createTime" gorm:"column:create_time"` // 创建时间
UpdateBy string `json:"updateBy" gorm:"column:update_by"` // 更新者

View File

@@ -36,6 +36,11 @@ func Setup(router *gin.Engine) {
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.neAction", collectlogs.BUSINESS_TYPE_IMPORT)),
controller.NewNeAction.PushFile,
)
neActionGroup.PUT("/service",
middleware.PreAuthorize(nil),
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.neAction", collectlogs.BUSINESS_TYPE_OTHER)),
controller.NewNeAction.Service,
)
}
// 网元信息
@@ -53,13 +58,23 @@ func Setup(router *gin.Engine) {
middleware.PreAuthorize(nil),
controller.NewNeInfo.ListAll,
)
neInfoGroup.GET("/configFile",
neInfoGroup.GET("/para5GFile",
middleware.PreAuthorize(nil),
controller.NewNeInfo.ConfigFileRead,
controller.NewNeInfo.Para5GFileRead,
)
neInfoGroup.PUT("/configFile",
neInfoGroup.PUT("/para5GFile",
middleware.PreAuthorize(nil),
controller.NewNeInfo.ConfigFileWrite,
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.neInfo", collectlogs.BUSINESS_TYPE_OTHER)),
controller.NewNeInfo.Para5GFileWrite,
)
neInfoGroup.GET("/oamFile",
middleware.PreAuthorize(nil),
controller.NewNeInfo.OAMFileRead,
)
neInfoGroup.PUT("/oamFile",
middleware.PreAuthorize(nil),
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.neInfo", collectlogs.BUSINESS_TYPE_OTHER)),
controller.NewNeInfo.OAMFileWrite,
)
neInfoGroup.GET("/list",
middleware.PreAuthorize(nil),
@@ -173,20 +188,10 @@ func Setup(router *gin.Engine) {
middleware.PreAuthorize(nil),
controller.NewNeVersion.Info,
)
neVersionGroup.POST("",
neVersionGroup.POST("/operate",
middleware.PreAuthorize(nil),
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.neVersion", collectlogs.BUSINESS_TYPE_INSERT)),
controller.NewNeVersion.Add,
)
neVersionGroup.PUT("",
middleware.PreAuthorize(nil),
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.neVersion", collectlogs.BUSINESS_TYPE_UPDATE)),
controller.NewNeVersion.Edit,
)
neVersionGroup.DELETE("/:versionIds",
middleware.PreAuthorize(nil),
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.neVersion", collectlogs.BUSINESS_TYPE_DELETE)),
controller.NewNeVersion.Remove,
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.neVersion", collectlogs.BUSINESS_TYPE_OTHER)),
controller.NewNeVersion.Operate,
)
}
@@ -216,10 +221,10 @@ func Setup(router *gin.Engine) {
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.neSoftware", collectlogs.BUSINESS_TYPE_DELETE)),
controller.NewNeSoftware.Remove,
)
neSoftwareGroup.POST("/checkInstall",
neSoftwareGroup.POST("/newNeVersion",
middleware.PreAuthorize(nil),
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.neSoftware", collectlogs.BUSINESS_TYPE_OTHER)),
controller.NewNeSoftware.CheckInstall,
controller.NewNeSoftware.NewNeVersion,
)
}
@@ -234,20 +239,9 @@ func Setup(router *gin.Engine) {
middleware.PreAuthorize(nil),
controller.NewNeLicense.Info,
)
neLicenseGroup.POST("",
neLicenseGroup.GET("/byTypeAndID",
middleware.PreAuthorize(nil),
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.neLicense", collectlogs.BUSINESS_TYPE_INSERT)),
controller.NewNeLicense.Add,
)
neLicenseGroup.PUT("",
middleware.PreAuthorize(nil),
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.neLicense", collectlogs.BUSINESS_TYPE_UPDATE)),
controller.NewNeLicense.Edit,
)
neLicenseGroup.DELETE("/:licenseIds",
middleware.PreAuthorize(nil),
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.neLicense", collectlogs.BUSINESS_TYPE_DELETE)),
controller.NewNeLicense.Remove,
controller.NewNeLicense.NeTypeAndID,
)
neLicenseGroup.GET("/code",
middleware.PreAuthorize(nil),
@@ -378,4 +372,8 @@ func InitLoad() {
// 启动时,清除缓存-网元类型
service.NewNeInfoImpl.ClearNeCacheByNeType("*")
service.NewNeInfoImpl.SelectNeInfoByRmuid("")
// 启动时,网元公共参数数据记录到全局变量
if para5GMap, err := service.NewNeInfoImpl.NeConfPara5GRead(); para5GMap != nil && err == nil {
service.NewNeInfoImpl.NeConfPara5GWirte(para5GMap, nil)
}
}

View File

@@ -175,21 +175,21 @@ func (r *NeHostImpl) SelectByIds(hostIds []string) []model.NeHost {
for i := range *arr {
passwordDe, err := crypto.StringDecryptByAES((*arr)[i].Password)
if err != nil {
logger.Errorf("selectById %s StringDecryptByAES : %v", (*arr)[i].HostID, err.Error())
logger.Errorf("selectById %s decrypt: %v", (*arr)[i].HostID, err.Error())
(*arr)[i].Password = ""
} else {
(*arr)[i].Password = passwordDe
}
privateKeyDe, err := crypto.StringDecryptByAES((*arr)[i].PrivateKey)
if err != nil {
logger.Errorf("selectById %s StringDecryptByAES : %v", (*arr)[i].HostID, err.Error())
logger.Errorf("selectById %s decrypt: %v", (*arr)[i].HostID, err.Error())
(*arr)[i].PrivateKey = ""
} else {
(*arr)[i].PrivateKey = privateKeyDe
}
passPhraseDe, err := crypto.StringDecryptByAES((*arr)[i].PassPhrase)
if err != nil {
logger.Errorf("selectById %s StringDecryptByAES : %v", (*arr)[i].HostID, err.Error())
logger.Errorf("selectById %s decrypt: %v", (*arr)[i].HostID, err.Error())
(*arr)[i].PassPhrase = ""
} else {
(*arr)[i].PassPhrase = passPhraseDe
@@ -265,7 +265,7 @@ func (r *NeHostImpl) Insert(neHost model.NeHost) string {
if neHost.Password != "" {
passwordEn, err := crypto.StringEncryptByAES(neHost.Password)
if err != nil {
logger.Errorf("insert StringEncryptByAES : %v", err.Error())
logger.Errorf("insert encrypt: %v", err.Error())
return ""
}
params["password"] = passwordEn
@@ -273,7 +273,7 @@ func (r *NeHostImpl) Insert(neHost model.NeHost) string {
if neHost.PrivateKey != "" {
privateKeyEn, err := crypto.StringEncryptByAES(neHost.PrivateKey)
if err != nil {
logger.Errorf("insert StringEncryptByAES : %v", err.Error())
logger.Errorf("insert encrypt: %v", err.Error())
return ""
}
params["private_key"] = privateKeyEn
@@ -281,7 +281,7 @@ func (r *NeHostImpl) Insert(neHost model.NeHost) string {
if neHost.PassPhrase != "" {
passPhraseEn, err := crypto.StringEncryptByAES(neHost.PassPhrase)
if err != nil {
logger.Errorf("insert StringEncryptByAES : %v", err.Error())
logger.Errorf("insert encrypt: %v", err.Error())
return ""
}
params["pass_phrase"] = passPhraseEn
@@ -294,6 +294,20 @@ func (r *NeHostImpl) Insert(neHost model.NeHost) string {
params["create_time"] = time.Now().UnixMilli()
}
// 根据认证模式清除不必要的信息
if neHost.AuthMode == "0" {
params["private_key"] = ""
params["pass_phrase"] = ""
}
if neHost.AuthMode == "1" {
params["password"] = ""
}
if neHost.AuthMode == "2" {
params["password"] = ""
params["private_key"] = ""
params["pass_phrase"] = ""
}
// 构建执行语句
keys, placeholder, values := repo.KeyPlaceholderValueByInsert(params)
sql := "insert into ne_host (" + strings.Join(keys, ",") + ")values(" + placeholder + ")"
@@ -349,7 +363,7 @@ func (r *NeHostImpl) Update(neHost model.NeHost) int64 {
if neHost.Password != "" {
passwordEn, err := crypto.StringEncryptByAES(neHost.Password)
if err != nil {
logger.Errorf("update StringEncryptByAES : %v", err.Error())
logger.Errorf("update encrypt: %v", err.Error())
return 0
}
params["password"] = passwordEn
@@ -357,7 +371,7 @@ func (r *NeHostImpl) Update(neHost model.NeHost) int64 {
if neHost.PrivateKey != "" {
privateKeyEn, err := crypto.StringEncryptByAES(neHost.PrivateKey)
if err != nil {
logger.Errorf("update StringEncryptByAES : %v", err.Error())
logger.Errorf("update encrypt: %v", err.Error())
return 0
}
params["private_key"] = privateKeyEn
@@ -365,7 +379,7 @@ func (r *NeHostImpl) Update(neHost model.NeHost) int64 {
if neHost.PassPhrase != "" {
passPhraseEn, err := crypto.StringEncryptByAES(neHost.PassPhrase)
if err != nil {
logger.Errorf("update StringEncryptByAES : %v", err.Error())
logger.Errorf("update encrypt: %v", err.Error())
return 0
}
params["pass_phrase"] = passPhraseEn
@@ -376,6 +390,20 @@ func (r *NeHostImpl) Update(neHost model.NeHost) int64 {
params["update_time"] = time.Now().UnixMilli()
}
// 根据认证模式清除不必要的信息
if neHost.AuthMode == "0" {
params["private_key"] = ""
params["pass_phrase"] = ""
}
if neHost.AuthMode == "1" {
params["password"] = ""
}
if neHost.AuthMode == "2" {
params["password"] = ""
params["private_key"] = ""
params["pass_phrase"] = ""
}
// 构建执行语句
keys, values := repo.KeyValueByUpdate(params)
sql := "update ne_host set " + strings.Join(keys, ",") + " where host_id = ?"

View File

@@ -16,25 +16,26 @@ import (
// neListSort 网元列表预设排序
var neListSort = []string{
"OMC",
"MME",
"IMS",
"AMF",
"AUSF",
"UDM",
"SMF",
"PCF",
"UPF",
"NRF",
"NSSF",
"IMS",
"N3IWF",
"NEF",
"NRF",
"UPF",
"LMF",
"NEF",
"MME",
"N3IWF",
"MOCNGW",
"SMSC",
}
// 实例化数据层 NeInfoImpl 结构体
var NewNeInfoImpl = &NeInfoImpl{
selectSql: `select id, ne_type, ne_id, rm_uid, ne_name, ip, port, pv_flag, province, vendor_name, dn, ne_address, status, update_time, host_ids from ne_info`,
selectSql: `select id, ne_type, ne_id, rm_uid, ne_name, ip, port, pv_flag, province, vendor_name, dn, ne_address, host_ids, status, remark, create_by, create_time, update_by, update_time from ne_info`,
resultMap: map[string]string{
"id": "ID",
@@ -49,9 +50,13 @@ var NewNeInfoImpl = &NeInfoImpl{
"vendor_name": "VendorName",
"dn": "Dn",
"ne_address": "NeAddress",
"status": "Status",
"update_time": "UpdateTime",
"host_ids": "HostIDs",
"status": "Status",
"remark": "Remark",
"create_by": "CreateBy",
"create_time": "CreateTime",
"update_by": "UpdateBy",
"update_time": "UpdateTime",
},
}
@@ -298,11 +303,19 @@ func (r *NeInfoImpl) Insert(neInfo model.NeInfo) string {
if neInfo.NeAddress != "" {
params["ne_address"] = neInfo.NeAddress
}
params["status"] = neInfo.Status
params["update_time"] = time.Now()
if neInfo.HostIDs != "" {
params["host_ids"] = neInfo.HostIDs
}
if neInfo.Status != "" {
params["status"] = neInfo.Status
}
if neInfo.Remark != "" {
params["remark"] = neInfo.Remark
}
if neInfo.CreateBy != "" {
params["create_by"] = neInfo.CreateBy
params["create_time"] = time.Now().UnixMilli()
}
// 构建执行语句
keys, placeholder, values := repo.KeyPlaceholderValueByInsert(params)
@@ -360,11 +373,17 @@ func (r *NeInfoImpl) Update(neInfo model.NeInfo) int64 {
params["vendor_name"] = neInfo.VendorName
params["dn"] = neInfo.Dn
params["ne_address"] = neInfo.NeAddress
params["status"] = neInfo.Status
params["update_time"] = time.Now()
if neInfo.HostIDs != "" {
params["host_ids"] = neInfo.HostIDs
}
params["remark"] = neInfo.Remark
if neInfo.Status != "" {
params["status"] = neInfo.Status
}
if neInfo.UpdateBy != "" {
params["update_by"] = neInfo.UpdateBy
params["update_time"] = time.Now().UnixMilli()
}
// 构建执行语句
keys, values := repo.KeyValueByUpdate(params)

View File

@@ -21,7 +21,4 @@ type INeLicense interface {
// DeleteByIds 批量删除信息
DeleteByIds(ids []string) int64
// CheckUniqueTypeAndID 校验网元类型和网元ID是否唯一
CheckUniqueTypeAndID(neLicense model.NeLicense) string
}

View File

@@ -1,7 +1,6 @@
package repository
import (
"fmt"
"strings"
"time"
@@ -177,41 +176,6 @@ func (r *NeLicenseImpl) SelectByIds(cmdIds []string) []model.NeLicense {
return r.convertResultRows(results)
}
// CheckUniqueTypeAndID 校验网元类型和网元ID是否唯一
func (r *NeLicenseImpl) CheckUniqueTypeAndID(neLicense model.NeLicense) string {
// 查询条件拼接
var conditions []string
var params []any
if neLicense.NeType != "" {
conditions = append(conditions, "ne_type = ?")
params = append(params, neLicense.NeType)
}
if neLicense.NeId != "" {
conditions = append(conditions, "ne_id = ?")
params = append(params, neLicense.NeId)
}
// 构建查询条件语句
whereSql := ""
if len(conditions) > 0 {
whereSql += " where " + strings.Join(conditions, " and ")
} else {
return ""
}
// 查询数据
querySql := "select id as 'str' from ne_license " + whereSql + " limit 1"
results, err := datasource.RawDB("", querySql, params)
if err != nil {
logger.Errorf("query err %v", err)
return ""
}
if len(results) > 0 {
return fmt.Sprint(results[0]["str"])
}
return ""
}
// Insert 新增信息
func (r *NeLicenseImpl) Insert(neLicense model.NeLicense) string {
// 参数拼接

View File

@@ -61,8 +61,17 @@ func (r *NeSoftwareImpl) SelectPage(query map[string]any) map[string]any {
var conditions []string
var params []any
if v, ok := query["neType"]; ok && v != "" {
conditions = append(conditions, "ne_type = ?")
params = append(params, strings.Trim(v.(string), " "))
softwareType := v.(string)
if strings.Contains(softwareType, ",") {
softwareTypeArr := strings.Split(softwareType, ",")
placeholder := repo.KeyPlaceholderByQuery(len(softwareTypeArr))
conditions = append(conditions, "ne_type in ("+placeholder+")")
parameters := repo.ConvertIdsSlice(softwareTypeArr)
params = append(params, parameters...)
} else {
conditions = append(conditions, "ne_type = ?")
params = append(params, strings.Trim(softwareType, " "))
}
}
if v, ok := query["name"]; ok && v != "" {
conditions = append(conditions, "name like concat(?, '%')")

View File

@@ -21,7 +21,4 @@ type INeVersion interface {
// DeleteByIds 批量删除信息
DeleteByIds(ids []string) int64
// CheckUniqueTypeAndID 校验网元类型和网元ID是否唯一
CheckUniqueTypeAndID(neVersion model.NeVersion) string
}

View File

@@ -1,7 +1,6 @@
package repository
import (
"fmt"
"strings"
"time"
@@ -15,17 +14,20 @@ import (
// 实例化数据层 NewNeVersion 结构体
var NewNeVersionImpl = &NeVersionImpl{
selectSql: `select
id, ne_type, ne_id, version, path, pre_version, pre_path, new_version, new_path, status, create_by, create_time, update_by, update_time
id, ne_type, ne_id, name, version, path, pre_name, pre_version, pre_path, new_name, new_version, new_path, status, create_by, create_time, update_by, update_time
from ne_version`,
resultMap: map[string]string{
"id": "ID",
"ne_type": "NeType",
"ne_id": "NeId",
"name": "name",
"version": "Version",
"path": "Path",
"pre_name": "preName",
"pre_version": "PreVersion",
"pre_path": "PrePath",
"new_name": "NewName",
"new_version": "NewVersion",
"new_path": "NewPath",
"status": "Status",
@@ -76,8 +78,8 @@ func (r *NeVersionImpl) SelectPage(query map[string]any) map[string]any {
conditions = append(conditions, "version like concat(?, '%')")
params = append(params, strings.Trim(v.(string), " "))
}
if v, ok := query["filePath"]; ok && v != "" {
conditions = append(conditions, "file_path like concat(?, '%')")
if v, ok := query["path"]; ok && v != "" {
conditions = append(conditions, "path like concat(?, '%')")
params = append(params, strings.Trim(v.(string), " "))
}
@@ -108,7 +110,7 @@ func (r *NeVersionImpl) SelectPage(query map[string]any) map[string]any {
// 分页
pageNum, pageSize := repo.PageNumSize(query["pageNum"], query["pageSize"])
pageSql := " limit ?,? "
pageSql := " order by update_time desc limit ?,? "
params = append(params, pageNum*pageSize)
params = append(params, pageSize)
@@ -146,6 +148,10 @@ func (r *NeVersionImpl) SelectList(neVersion model.NeVersion) []model.NeVersion
conditions = append(conditions, "path like concat(?, '%')")
params = append(params, neVersion.Path)
}
if neVersion.Status != "" {
conditions = append(conditions, "status = ?")
params = append(params, neVersion.Status)
}
// 构建查询条件语句
whereSql := ""
@@ -178,41 +184,6 @@ func (r *NeVersionImpl) SelectByIds(cmdIds []string) []model.NeVersion {
return r.convertResultRows(results)
}
// CheckUniqueTypeAndID 校验网元类型和网元ID是否唯一
func (r *NeVersionImpl) CheckUniqueTypeAndID(neVersion model.NeVersion) string {
// 查询条件拼接
var conditions []string
var params []any
if neVersion.NeType != "" {
conditions = append(conditions, "ne_type = ?")
params = append(params, neVersion.NeType)
}
if neVersion.NeId != "" {
conditions = append(conditions, "ne_id = ?")
params = append(params, neVersion.NeId)
}
// 构建查询条件语句
whereSql := ""
if len(conditions) > 0 {
whereSql += " where " + strings.Join(conditions, " and ")
} else {
return ""
}
// 查询数据
querySql := "select id as 'str' from ne_version " + whereSql + " limit 1"
results, err := datasource.RawDB("", querySql, params)
if err != nil {
logger.Errorf("query err %v", err)
return ""
}
if len(results) > 0 {
return fmt.Sprint(results[0]["str"])
}
return ""
}
// Insert 新增信息
func (r *NeVersionImpl) Insert(neVersion model.NeVersion) string {
// 参数拼接
@@ -223,18 +194,27 @@ func (r *NeVersionImpl) Insert(neVersion model.NeVersion) string {
if neVersion.NeId != "" {
params["ne_id"] = neVersion.NeId
}
if neVersion.Name != "" {
params["name"] = neVersion.Name
}
if neVersion.Version != "" {
params["version"] = neVersion.Version
}
if neVersion.Path != "" {
params["path"] = neVersion.Path
}
if neVersion.PreName != "" {
params["pre_name"] = neVersion.PreName
}
if neVersion.PreVersion != "" {
params["pre_version"] = neVersion.PreVersion
}
if neVersion.PrePath != "" {
params["pre_path"] = neVersion.PrePath
}
if neVersion.NewName != "" {
params["new_name"] = neVersion.NewName
}
if neVersion.NewVersion != "" {
params["new_version"] = neVersion.NewVersion
}
@@ -286,18 +266,27 @@ func (r *NeVersionImpl) Update(neVersion model.NeVersion) int64 {
if neVersion.NeId != "" {
params["ne_id"] = neVersion.NeId
}
if neVersion.Name != "" {
params["name"] = neVersion.Name
}
if neVersion.Version != "" {
params["version"] = neVersion.Version
}
if neVersion.Path != "" {
params["path"] = neVersion.Path
}
if neVersion.PreName != "" {
params["pre_name"] = neVersion.PreName
}
if neVersion.PreVersion != "" {
params["pre_version"] = neVersion.PreVersion
}
if neVersion.PrePath != "" {
params["pre_path"] = neVersion.PrePath
}
if neVersion.NewName != "" {
params["new_name"] = neVersion.NewName
}
if neVersion.NewVersion != "" {
params["new_version"] = neVersion.NewVersion
}

View File

@@ -15,7 +15,7 @@ import (
func NeState(neInfo model.NeInfo) (map[string]any, error) {
// 网元状态
neUrl := fmt.Sprintf("http://%s:%d/api/rest/systemManagement/v1/elementType/%s/objectType/systemState", neInfo.IP, neInfo.Port, strings.ToLower(neInfo.NeType))
resBytes, err := fetch.Get(neUrl, nil, 250)
resBytes, err := fetch.Get(neUrl, nil, 1000)
if err != nil {
logger.Warnf("NeState %s", err.Error())
return nil, err
@@ -62,8 +62,8 @@ func NeConfigOMC(neInfo model.NeInfo) (map[string]any, error) {
var resData map[string]any
if err != nil {
status := err.Error()
logger.Warnf("NeConfigOMC %s", status)
if strings.HasPrefix(status, "204") {
logger.Warnf("NeConfigOMC %s Put \"%s\"", status, neUrl)
if strings.HasPrefix(status, "201") || strings.HasPrefix(status, "204") {
return resData, nil
}
return nil, err

View File

@@ -1,6 +1,9 @@
package service
import "be.ems/src/modules/network_element/model"
import (
"be.ems/src/framework/utils/ssh"
"be.ems/src/modules/network_element/model"
)
// 网元信息 服务层接口
type INeInfo interface {
@@ -24,7 +27,8 @@ type INeInfo interface {
// SelectList 查询列表
//
// bandStatus 带状态信息
SelectList(ne model.NeInfo, bandStatus bool) []model.NeInfo
// bandHost 带主机信息
SelectList(ne model.NeInfo, bandStatus bool, bandHost bool) []model.NeInfo
// SelectByIds 通过ID查询
//
@@ -41,14 +45,23 @@ type INeInfo interface {
DeleteByIds(infoIds []string) (int64, error)
// CheckUniqueNeTypeAndNeId 校验同类型下标识是否唯一
CheckUniqueNeTypeAndNeId(neType, neId, infoId string) bool
CheckUniqueNeTypeAndNeId(neType, neId, id string) bool
// NeRunSSHclient 网元主机的SSH客户端-为创建相关连接
NeRunSSHclient(neType, neId string) (*ssh.ConnSSH, error)
// NeRunCMD 向网元发送cmd命令
NeRunCMD(neType, neId, cmd string) (string, error)
// NeConfigFileRead 网元配置文件读取 网元配置yaml文件复制到本地后通过filePath读取
NeConfigFileRead(neInfo model.NeInfo, filePath string) []string
// neConfOAMRead 网元OAM配置文件读取
NeConfOAMRead(neType, neId string) (map[string]any, error)
// NeConfigFileWirte 网元配置文件写入 content内容 sync同步到网元端
NeConfigFileWirte(neInfo model.NeInfo, filePath, content string, sync bool) error
// NeConfOAMSync 网元OAM配置文件生成并同步
NeConfOAMSync(neInfo model.NeInfo, content map[string]any, sync bool) error
// NeConfPara5GRead 网元公共配置文件读取
NeConfPara5GRead() (map[string]any, error)
// NeConfPara5GWirte 网元公共配置文件写入 content内容 syncNE同步到网元端NeType@NeId
NeConfPara5GWirte(content map[string]any, syncNE []string) error
}

View File

@@ -4,12 +4,14 @@ import (
"encoding/json"
"fmt"
"os"
"path/filepath"
"runtime"
"strings"
"be.ems/src/framework/constants/cachekey"
"be.ems/src/framework/logger"
"be.ems/src/framework/redis"
"be.ems/src/framework/utils/parse"
"be.ems/src/framework/utils/ssh"
"be.ems/src/modules/network_element/model"
"be.ems/src/modules/network_element/repository"
@@ -18,15 +20,14 @@ import (
// 实例化服务层 NeInfoImpl 结构体
var NewNeInfoImpl = &NeInfoImpl{
neInfoRepository: repository.NewNeInfoImpl,
neHostRepository: repository.NewNeHostImpl,
Para5GData: map[string]string{},
}
// 网元信息 服务层处理
type NeInfoImpl struct {
// 网元信息数据信息
neInfoRepository repository.INeInfo
// 网元主机连接表
neHostRepository repository.INeHost
Para5GData map[string]string
}
// SelectNeInfoByNeTypeAndNeID 通过ne_type和ne_id查询网元信息
@@ -94,7 +95,7 @@ func (r *NeInfoImpl) SelectNeInfoByRmuid(rmUid string) model.NeInfo {
}
}
} else {
neInfos := r.SelectList(neInfo, false)
neInfos := r.SelectList(neInfo, false, false)
for _, v := range neInfos {
key := fmt.Sprintf("%s%s:%s", cachekey.NE_KEY, strings.ToUpper(v.NeType), v.NeId)
redis.Del("", key)
@@ -117,37 +118,7 @@ func (r *NeInfoImpl) SelectPage(query map[string]any, bandStatus bool) map[strin
// 网元直连读取网元服务状态
if bandStatus {
rows := data["rows"].([]model.NeInfo)
arr := &rows
for i := range *arr {
v := (*arr)[i]
result, err := NeState(v)
if err != nil {
(*arr)[i].ServerState = map[string]any{
"online": false,
}
// 网元状态设置为离线
if v.Status != "1" {
v.Status = "1"
(*arr)[i].Status = v.Status
r.neInfoRepository.Update(v)
}
continue
}
result["online"] = true
(*arr)[i].ServerState = result
// 网元状态设置为在线
if v.Status != "0" {
// 下发网管配置信息给网元
_, err = NeConfigOMC(v)
if err != nil {
v.Status = "3"
} else {
v.Status = "0"
}
(*arr)[i].Status = v.Status
r.neInfoRepository.Update(v)
}
}
r.bandNeStatus(&rows)
}
return data
@@ -156,50 +127,70 @@ func (r *NeInfoImpl) SelectPage(query map[string]any, bandStatus bool) map[strin
// SelectList 查询列表
//
// bandStatus 带状态信息
func (r *NeInfoImpl) SelectList(ne model.NeInfo, bandStatus bool) []model.NeInfo {
// bandHost 带主机信息
func (r *NeInfoImpl) SelectList(ne model.NeInfo, bandStatus bool, bandHost bool) []model.NeInfo {
list := r.neInfoRepository.SelectList(ne)
// 网元直连读取网元服务状态
if bandStatus {
neList := &list
for i := range *neList {
v := (*neList)[i]
result, err := NeState(v)
if err != nil {
(*neList)[i].ServerState = map[string]any{
"online": false,
}
// 网元状态设置为离线
if v.Status != "1" {
v.Status = "1"
(*neList)[i].Status = v.Status
r.neInfoRepository.Update(v)
}
continue
}
result["online"] = true
(*neList)[i].ServerState = result
// 网元状态设置为在线
if v.Status != "0" {
// 下发网管配置信息给网元
_, err = NeConfigOMC(v)
if err != nil {
v.Status = "3"
} else {
v.Status = "0"
}
(*neList)[i].Status = v.Status
r.neInfoRepository.Update(v)
}
}
r.bandNeStatus(&list)
}
// 网元主机信息
if bandHost {
r.bandNeHosts(&list)
}
return list
}
// bandNeStatus 网元列表项数据带网元服务状态
func (r *NeInfoImpl) bandNeStatus(arr *[]model.NeInfo) {
for i := range *arr {
v := (*arr)[i]
result, err := NeState(v)
if err != nil {
(*arr)[i].ServerState = map[string]any{
"online": false,
}
// 网元状态设置为离线
if v.Status != "0" {
v.Status = "0"
(*arr)[i].Status = v.Status
r.neInfoRepository.Update(v)
}
continue
}
result["online"] = true
(*arr)[i].ServerState = result
// 网元状态设置为在线
if v.Status != "1" {
// 下发网管配置信息给网元
_, err = NeConfigOMC(v)
if err == nil {
v.Status = "1"
} else {
v.Status = "2"
}
(*arr)[i].Status = v.Status
r.neInfoRepository.Update(v)
}
}
}
// bandNeHosts 网元列表项数据带网元主机信息
func (r *NeInfoImpl) bandNeHosts(arr *[]model.NeInfo) {
for i := range *arr {
v := (*arr)[i]
if v.HostIDs != "" {
(*arr)[i].Hosts = NewNeHostImpl.neHostRepository.SelectByIds(strings.Split(v.HostIDs, ","))
}
}
}
// SelectByIds 通过ID查询
//
// bandStatus 带主机信息
// bandHost 带主机信息
func (r *NeInfoImpl) SelectById(infoId string, bandHost bool) model.NeInfo {
if infoId == "" {
return model.NeInfo{}
@@ -209,7 +200,7 @@ func (r *NeInfoImpl) SelectById(infoId string, bandHost bool) model.NeInfo {
neInfo := neInfos[0]
// 带主机信息
if neInfo.HostIDs != "" && bandHost {
neInfo.Hosts = r.neHostRepository.SelectByIds(strings.Split(neInfo.HostIDs, ","))
neInfo.Hosts = NewNeHostImpl.neHostRepository.SelectByIds(strings.Split(neInfo.HostIDs, ","))
}
return neInfo
}
@@ -224,7 +215,7 @@ func (r *NeInfoImpl) Insert(neInfo model.NeInfo) string {
for _, host := range neInfo.Hosts {
host.Title = fmt.Sprintf("%s_%s_%d", strings.ToUpper(neInfo.NeType), neInfo.NeId, host.Port)
host.GroupID = "1"
hostId := r.neHostRepository.Insert(host)
hostId := NewNeHostImpl.Insert(host)
if hostId != "" {
hostIDs = append(hostIDs, hostId)
}
@@ -248,7 +239,7 @@ func (r *NeInfoImpl) Update(neInfo model.NeInfo) int64 {
if host.HostID != "" {
host.Title = fmt.Sprintf("%s_%s_%d", strings.ToUpper(neInfo.NeType), neInfo.NeId, host.Port)
host.GroupID = "1"
r.neHostRepository.Update(host)
NewNeHostImpl.Update(host)
}
}
}
@@ -273,12 +264,20 @@ func (r *NeInfoImpl) DeleteByIds(infoIds []string) (int64, error) {
for _, v := range infos {
// 主机信息删除
if v.HostIDs != "" {
hostIds := strings.Split(v.HostIDs, ",")
r.neHostRepository.DeleteByIds(hostIds)
NewNeHostImpl.DeleteByIds(strings.Split(v.HostIDs, ","))
}
// 删除License
neLicense := NewNeLicenseImpl.SelectByNeTypeAndNeID(v.NeType, v.NeId)
if neLicense.NeId == v.NeId {
NewNeLicenseImpl.DeleteByIds([]string{neLicense.ID})
}
// 删除Version
neVersion := NewNeVersionImpl.SelectByNeTypeAndNeID(v.NeType, v.NeId)
if neVersion.NeId == v.NeId {
NewNeVersionImpl.DeleteByIds([]string{neVersion.ID})
}
// 缓存信息删除
key := fmt.Sprintf("%s%s:%s", cachekey.NE_KEY, v.NeType, v.NeId)
redis.Del("", key)
redis.Del("", fmt.Sprintf("%s%s:%s", cachekey.NE_KEY, v.NeType, v.NeId))
}
rows := r.neInfoRepository.DeleteByIds(infoIds)
return rows, nil
@@ -288,149 +287,456 @@ func (r *NeInfoImpl) DeleteByIds(infoIds []string) (int64, error) {
}
// CheckUniqueNeTypeAndNeId 校验同类型下标识是否唯一
func (r *NeInfoImpl) CheckUniqueNeTypeAndNeId(neType, neId, infoId string) bool {
func (r *NeInfoImpl) CheckUniqueNeTypeAndNeId(neType, neId, id string) bool {
uniqueId := r.neInfoRepository.CheckUniqueNeTypeAndNeId(model.NeInfo{
NeType: neType,
NeId: neId,
})
if uniqueId == infoId {
if uniqueId == id {
return true
}
return uniqueId == ""
}
// NeRunCMD 向网元发送cmd命令
func (r *NeInfoImpl) NeRunCMD(neType, neId, cmd string) (string, error) {
// NeRunSSHclient 网元主机的SSH客户端-为创建相关连接
func (r *NeInfoImpl) NeRunSSHclient(neType, neId string) (*ssh.ConnSSH, error) {
neInfo := r.SelectNeInfoByNeTypeAndNeID(neType, neId)
if neInfo.NeId != neId {
logger.Errorf("NeRunCMD NeType:%s NeID:%s not found", neType, neId)
return "", fmt.Errorf("neinfo not found")
logger.Errorf("NeRunSSHclient NeType:%s NeID:%s not found", neType, neId)
return nil, fmt.Errorf("neinfo not found")
}
// 主机信息
if neInfo.HostIDs != "" {
neInfo.Hosts = r.neHostRepository.SelectByIds(strings.Split(neInfo.HostIDs, ","))
if len(neInfo.Hosts) <= 0 {
logger.Errorf("NeRunCMD Hosts %s not found", neInfo.HostIDs)
return "", fmt.Errorf("neinfo host not found")
}
// 主机信息
if neInfo.HostIDs == "" {
logger.Errorf("NeRunSSHclient NeType:%s NeID:%s hostId not found", neType, neId)
return nil, fmt.Errorf("neinfo hostId not found")
}
neInfo.Hosts = NewNeHostImpl.neHostRepository.SelectByIds(strings.Split(neInfo.HostIDs, ","))
if len(neInfo.Hosts) <= 0 {
logger.Errorf("NeRunSSHclient Hosts %s not found", neInfo.HostIDs)
return nil, fmt.Errorf("neinfo host not found")
}
neHost := neInfo.Hosts[0]
if neHost.HostType != "ssh" {
logger.Errorf("NeRunCMD Hosts first HostType %s not ssh", neHost.HostType)
return "", fmt.Errorf("neinfo host type not ssh")
logger.Errorf("NeRunSSHclient Hosts first HostType %s not ssh", neHost.HostType)
return nil, fmt.Errorf("neinfo host type not ssh")
}
var connSSH ssh.ConnSSH
neHost.CopyTo(&connSSH)
client, err := connSSH.NewClient()
if err != nil {
logger.Errorf("NeRunCMD NewClient err => %s", err.Error())
return "", fmt.Errorf("neinfo ssh client new err")
var client *ssh.ConnSSH
var err error
if neHost.AuthMode == "2" {
client, err = connSSH.NewClientByLocalPrivate()
} else {
client, err = connSSH.NewClient()
}
defer client.Close()
if err != nil {
logger.Errorf("NeRunSSHclient NewClient err => %s", err.Error())
return nil, fmt.Errorf("neinfo ssh client new err")
}
return client, nil
}
// NeRunCMD 向网元发送cmd命令
func (r *NeInfoImpl) NeRunCMD(neType, neId, cmd string) (string, error) {
sshClient, err := r.NeRunSSHclient(neType, neId)
if err != nil {
return "", err
}
defer sshClient.Close()
// 执行命令
output, err := client.RunCMD(cmd)
output, err := sshClient.RunCMD(cmd)
if err != nil {
logger.Errorf("NeRunCMD RunCMD %s err => %s", output, err.Error())
return "", fmt.Errorf("neinfo ssh run cmd err")
}
return output, nil
}
// NeConfigFileRead 网元配置文件读取 网元配置yaml文件复制到本地后通过filePath读取
func (r *NeInfoImpl) NeConfigFileRead(neInfo model.NeInfo, filePath string) []string {
files := []string{}
neTypeLower := strings.ToLower(neInfo.NeType)
// 网管本地路径
omcPath := "/usr/local/etc/omc/ne_config"
if runtime.GOOS == "windows" {
omcPath = fmt.Sprintf("C:%s", omcPath)
// neConfOAMData 网元OAM配置文件默认格式数据
func (r *NeInfoImpl) neConfOAMData() map[string]any {
return map[string]any{
"httpManageCfg": map[string]any{
"ipType": "ipv4",
// 必改
"ipv4": "172.60.5.2",
"ipv6": "",
"port": 33030,
"scheme": "http",
},
"oamConfig": map[string]any{
"enable": true,
"ipType": "ipv4",
"ipv4": "172.60.5.1", // 必改
"ipv6": "",
"port": 33030,
"scheme": "http",
"neConfig": map[string]any{ // 必改
"neId": "001",
"rmUid": "4400HX1XXX001",
"neName": "XXX_001",
"dn": "-",
"vendorName": "GD",
"province": "-",
"pvFlag": "PNF",
},
},
"snmpConfig": map[string]any{
"enable": false,
"ipType": "ipv4",
"ipv4": "172.60.5.2", // 必改
"ipv6": "",
"port": 4957,
},
"kpiConfig": map[string]any{
"enable": true,
"timer": 60, // 必改
},
// "pubConfigPath": "/usr/local/etc/conf/para5G.yaml", // 网元只会读一次后续会置空,建议不放
}
omcPath = fmt.Sprintf("%s/%s/%s", omcPath, neTypeLower, neInfo.NeId)
// 读取文件内容
if filePath != "" {
bytes, err := os.ReadFile(fmt.Sprintf("%s/%s", omcPath, filePath))
if err != nil {
logger.Warnf("NeConfigFile ReadFile => %s", err.Error())
return files
}
files = append(files, string(bytes))
return files
}
// 删除原有配置文件
// err := os.RemoveAll(omcPath)
// if err != nil {
// logger.Warnf("NeConfigFile Remove => %s", err.Error())
// return files
// }
// 网元端配置路径
nePath := "/usr/local/etc"
nePath = fmt.Sprintf("%s/%s", nePath, neTypeLower)
// 各个网元与网元间约定配置文件
err := ssh.FileSCPNeToLocal(neInfo.IP, nePath+"/oam_manager.yaml", omcPath+"/oam_manager.yaml")
if err == nil {
files = append(files, "oam_manager.yaml")
}
// 根据情况复制网元特殊配置
switch neTypeLower {
case "ausf":
err = ssh.FileSCPNeToLocal(neInfo.IP, nePath+"/ausfcfg.yaml", omcPath+"/ausfcfg.yaml")
if err == nil {
files = append(files, "ausfcfg.yaml")
}
case "smf":
ssh.FileSCPNeToLocal(neInfo.IP, nePath+"/smf_conf.yaml", omcPath+"/smf_conf.yaml")
if err == nil {
files = append(files, "smf_conf.yaml")
}
ssh.FileSCPNeToLocal(neInfo.IP, nePath+"/smf_policy.yaml", omcPath+"/smf_policy.yaml")
if err == nil {
files = append(files, "smf_policy.yaml")
}
case "ims":
}
return files
}
// NeConfigFileWirte 网元配置文件写入 content内容 sync同步到网元端
func (r *NeInfoImpl) NeConfigFileWirte(neInfo model.NeInfo, filePath, content string, sync bool) error {
neTypeLower := strings.ToLower(neInfo.NeType)
// neConfOAMRead 网元OAM配置文件读取
func (r *NeInfoImpl) NeConfOAMRead(neType, neId string) (map[string]any, error) {
neTypeLower := strings.ToLower(neType)
// 网管本地路径
omcPath := "/usr/local/etc/omc/ne_config"
if runtime.GOOS == "windows" {
omcPath = fmt.Sprintf("C:%s", omcPath)
}
localFilePath := fmt.Sprintf("%s/%s/%s/%s", omcPath, neTypeLower, neInfo.NeId, filePath)
localFilePath := fmt.Sprintf("%s/%s/%s/%s", omcPath, neTypeLower, neId, "oam_manager.yaml")
err := os.WriteFile(localFilePath, []byte(content), 0644)
// 读取文件内容
bytes, err := os.ReadFile(localFilePath)
if err != nil {
logger.Warnf("NeConfigFile WriteFile => %s", err.Error())
// logger.Warnf("NeConfOAMRead ReadFile => %s", err.Error())
// return nil, fmt.Errorf("read file error")
// 无保留文件时返回默认文件数据
oamData := r.neConfOAMData()
r.neConfOAMWirte(neType, neId, oamData, false)
return oamData, nil
}
content := string(bytes)
// 序列化Map
mapData, err := parse.ConvertConfigToMap("yaml", content)
if err != nil {
logger.Warnf("NeConfOAMRead ConvertConfigToMap => %s", err.Error())
return nil, fmt.Errorf("content convert type error")
}
return mapData, nil
}
// neConfOAMWirte 网元OAM配置文件写入 content内容 sync同步到网元端
func (r *NeInfoImpl) neConfOAMWirte(neType, neId string, content any, sync bool) error {
neTypeLower := strings.ToLower(neType)
fileName := "oam_manager.yaml"
// 网管本地路径
omcPath := "/usr/local/etc/omc/ne_config"
if runtime.GOOS == "windows" {
omcPath = fmt.Sprintf("C:%s", omcPath)
}
localFilePath := fmt.Sprintf("%s/%s/%s/%s", omcPath, neTypeLower, neId, fileName)
// 写入文件
if err := parse.ConvertConfigToFile("yaml", localFilePath, content); err != nil {
return fmt.Errorf("please check if the file exists or write permissions")
}
// 同步到网元端
if sync {
// 网元端配置路径
neFilePath := fmt.Sprintf("/usr/local/etc/%s/%s", neTypeLower, filePath)
// 修改网元文件权限
r.NeRunCMD(neInfo.NeType, neInfo.NeId, fmt.Sprintf("sudo chmod o+w %s", neFilePath))
// 复制到网元进行覆盖
err = ssh.FileSCPLocalToNe(neInfo.IP, localFilePath, neFilePath)
// 网元主机的SSH客户
sshClient, err := r.NeRunSSHclient(neType, neId)
if err != nil {
logger.Warnf("NeConfigFile SyncFile => %s", err.Error())
return err
}
defer sshClient.Close()
// 网元主机的SSH客户端进行文件传输
sftpClient, err := sshClient.NewClientSFTP()
if err != nil {
return err
}
defer sftpClient.Close()
// 网元端配置路径
neFilePath := fmt.Sprintf("/usr/local/etc/%s/%s", neTypeLower, fileName)
neFileDir := filepath.ToSlash(filepath.Dir(neFilePath))
// 修改网元文件权限
sshClient.RunCMD(fmt.Sprintf("sudo mkdir -p %s && sudo chmod 775 %s && sudo touch %s && sudo chmod o+w %s", neFileDir, neFileDir, neFilePath, neFilePath))
// 复制到网元进行覆盖
if err = sftpClient.CopyFileLocalToRemote(localFilePath, neFilePath); err != nil {
return fmt.Errorf("please check if scp remote copy is allowed")
}
}
return nil
}
// NeConfOAMSync 网元OAM配置文件生成并同步
func (r *NeInfoImpl) NeConfOAMSync(neInfo model.NeInfo, content map[string]any, sync bool) error {
oamData, err := r.NeConfOAMRead(neInfo.NeType, neInfo.NeId)
if oamData == nil || err != nil {
return fmt.Errorf("error read OAM file info")
}
// 网元HTTP服务
if v, ok := oamData["httpManageCfg"]; ok {
item := v.(map[string]any)
item["port"] = neInfo.Port
if strings.Contains(neInfo.IP, ":") {
item["ipType"] = "ipv6"
item["ipv6"] = neInfo.IP
}
if strings.Contains(neInfo.IP, ".") {
item["ipType"] = "ipv4"
item["ipv4"] = neInfo.IP
}
oamData["httpManageCfg"] = item
}
// 对网管HTTP配置
if v, ok := oamData["oamConfig"]; ok {
item := v.(map[string]any)
item["neConfig"] = map[string]string{
"neId": neInfo.NeId,
"rmUid": neInfo.RmUID,
"neName": neInfo.NeName,
"dn": neInfo.Dn,
"vendorName": neInfo.VendorName,
"province": neInfo.Province,
"pvFlag": neInfo.PvFlag,
}
if omcIP, ok := r.Para5GData["OMC_IP"]; ok && omcIP != "" {
if strings.Contains(omcIP, ":") {
item["ipType"] = "ipv6"
item["ipv6"] = omcIP
}
if strings.Contains(omcIP, ".") {
item["ipType"] = "ipv4"
item["ipv4"] = omcIP
}
}
if oamEnable, ok := content["oamEnable"]; ok && oamEnable != nil {
item["enable"] = parse.Boolean(oamEnable)
}
if oamPort, ok := content["oamPort"]; ok && oamPort != nil {
item["port"] = parse.Number(oamPort)
}
oamData["oamConfig"] = item
}
// 对网管SNMP配置
if v, ok := oamData["snmpConfig"]; ok {
item := v.(map[string]any)
if strings.Contains(neInfo.IP, ":") {
item["ipType"] = "ipv6"
item["ipv6"] = neInfo.IP
}
if strings.Contains(neInfo.IP, ".") {
item["ipType"] = "ipv4"
item["ipv4"] = neInfo.IP
}
if snmpEnable, ok := content["snmpEnable"]; ok && snmpEnable != nil {
item["enable"] = parse.Boolean(snmpEnable)
}
if snmpPort, ok := content["snmpPort"]; ok && snmpPort != nil {
item["port"] = parse.Number(snmpPort)
}
oamData["snmpConfig"] = item
}
// 对网管KPI上报配置
if v, ok := oamData["kpiConfig"]; ok {
item := v.(map[string]any)
if neInfo.NeType == "UPF" {
item["timer"] = 5
}
if kpiEnable, ok := content["kpiEnable"]; ok && kpiEnable != nil {
item["enable"] = parse.Boolean(kpiEnable)
}
if kpiTimer, ok := content["kpiTimer"]; ok && kpiTimer != nil {
item["timer"] = parse.Number(kpiTimer)
}
oamData["kpiConfig"] = item
}
if err := NewNeInfoImpl.neConfOAMWirte(neInfo.NeType, neInfo.NeId, oamData, sync); err != nil {
return fmt.Errorf("error wirte OAM file info")
}
return nil
}
// NeConfPara5GRead 网元公共配置文件读取
func (r *NeInfoImpl) NeConfPara5GRead() (map[string]any, error) {
// 网管本地路径
omcFilePath := "/usr/local/etc/omc/para5G.yaml"
if runtime.GOOS == "windows" {
omcFilePath = fmt.Sprintf("C:%s", omcFilePath)
}
// 读取文件内容
bytes, err := os.ReadFile(omcFilePath)
if err != nil {
logger.Warnf("NeConfPara5GRead ReadFile => %s", err.Error())
return nil, fmt.Errorf("read file error")
}
content := string(bytes)
// 序列化Map
mapData, err := parse.ConvertConfigToMap("yaml", content)
if err != nil {
logger.Warnf("NeConfPara5GRead ConvertConfigToMap => %s", err.Error())
return nil, fmt.Errorf("content convert type error")
}
return mapData, nil
}
// NeConfPara5GWirte 网元公共配置文件写入 content内容 syncNE同步到网元端NeType@NeId
func (r *NeInfoImpl) NeConfPara5GWirte(content map[string]any, syncNE []string) error {
// 网管本地路径
omcFilePath := "/usr/local/etc/omc/para5G.yaml"
if runtime.GOOS == "windows" {
omcFilePath = fmt.Sprintf("C:%s", omcFilePath)
}
if err := parse.ConvertConfigToFile("yaml", omcFilePath, content); err != nil {
return fmt.Errorf("please check if the file exists or write permissions")
}
// 同步到网元端
if len(syncNE) > 0 {
errMsg := []string{}
for _, neTI := range syncNE {
ti := strings.SplitN(neTI, "@", 2)
// 网元主机的SSH客户端
sshClient, err := r.NeRunSSHclient(ti[0], ti[1])
if err != nil {
errMsg = append(errMsg, fmt.Sprintf("%s : %s", ti, err.Error()))
continue
}
defer sshClient.Close()
// 网元主机的SSH客户端进行文件传输
sftpClient, err := sshClient.NewClientSFTP()
if err != nil {
errMsg = append(errMsg, fmt.Sprintf("%s : %s", ti, err.Error()))
continue
}
defer sftpClient.Close()
// 网元端配置路径
neFilePath := "/usr/local/etc/conf/para5G.yaml"
neFileDir := filepath.ToSlash(filepath.Dir(neFilePath))
// 修改网元文件权限
sshClient.RunCMD(fmt.Sprintf("sudo mkdir -p %s && sudo chmod 775 %s && sudo touch %s && sudo chmod o+rw %s", neFileDir, neFileDir, neFilePath, neFilePath))
// 复制到网元进行覆盖
if err = sftpClient.CopyFileLocalToRemote(omcFilePath, neFilePath); err != nil {
errMsg = append(errMsg, fmt.Sprintf("%s : please check if scp remote copy is allowed", ti))
continue
}
}
if len(errMsg) > 0 {
return fmt.Errorf(strings.Join(errMsg, "\r\n"))
}
}
// 转换一份数据到全局
r.Para5GData = r.neConfPara5GDataConvert(content)
return nil
}
// NeConfPara5GConvert 网元公共配置数据转化 content网元公共配置文件读取内容
func (r *NeInfoImpl) neConfPara5GDataConvert(content map[string]any) map[string]string {
basic := content["basic"].(map[string]any)
external := content["external"].(map[string]any)
sbi := content["sbi"].(map[string]any)
mcc := "460"
mnc := "01"
mncDomain := "001"
if plmnId, plmnIdOk := basic["plmnId"].(map[string]any); plmnIdOk {
mcc = plmnId["mcc"].(string)
mnc = plmnId["mnc"].(string)
// If a user input two digit MNC, add a leading zero
if len(mnc) == 2 {
mncDomain = fmt.Sprintf("0%s", mnc)
} else {
mncDomain = mnc
}
}
sst := "1"
sd := "000001"
if plmnId, plmnIdOk := basic["snssai"].(map[string]any); plmnIdOk {
sst = plmnId["sst"].(string)
sd = plmnId["sd"].(string)
}
n3IPAmdMask := external["upfn3_ip"].(string)
n3Arr := strings.Split(n3IPAmdMask, "/")
n3IP := n3Arr[0]
n3Mask := parse.ConvertIPMask(parse.Number(n3Arr[1]))
n6IPAmdMask := external["upfn6_ip"].(string)
n6Arr := strings.Split(n6IPAmdMask, "/")
n6IP := n6Arr[0]
n6Mask := parse.ConvertIPMask(parse.Number(n6Arr[1]))
ueIPAmdMask := external["ue_pool"].(string)
ueArr := strings.Split(ueIPAmdMask, "/")
ueIP := ueArr[0]
ueCicr := ueArr[1]
ueMask := parse.ConvertIPMask(parse.Number(ueArr[1]))
return map[string]string{
// basic
"TAC": basic["tac"].(string),
"MCC": mcc,
"MNC": mnc,
"MNC_DOMAIN": mncDomain,
"SST": sst,
"SD": sd,
"DNN_DATA": basic["dnn_data"].(string),
"DNN_IMS": basic["dnn_ims"].(string),
// external
"N2_IP": external["amfn2_ip"].(string),
"UE_POOL": external["ue_pool"].(string),
"UE_IP": ueIP,
"UE_MASK": ueMask,
"UE_CIDR": ueCicr,
"UPF_TYPE": external["upf_type"].(string), // StandardUPF LightUPF
"N3_IP": n3IP,
"N3_MASK": n3Mask,
"N3_GW": external["upfn3_gw"].(string),
"N3_PCI": external["upfn3_pci"].(string),
"N3_MAC": external["upfn3_mac"].(string),
"N6_IP": n6IP,
"N6_MASK": n6Mask,
"N6_GW": external["upfn6_gw"].(string),
"N6_PCI": external["upfn6_pci"].(string),
"N6_MAC": external["upfn6_mac"].(string),
"SIP_IP": external["ims_sip_ip"].(string),
"S1_MMEIP": external["mmes1_ip"].(string),
"S11_MMEIP": external["mmes11_ip"].(string),
"S10_MMEIP": external["mmes10_ip"].(string),
// sbi
"OMC_IP": sbi["omc_ip"].(string),
"IMS_IP": sbi["ims_ip"].(string),
"AMF_IP": sbi["amf_ip"].(string),
"AUSF_IP": sbi["ausf_ip"].(string),
"UDM_IP": sbi["udm_ip"].(string),
"ADB_IP": sbi["adb_ip"].(string),
"SMF_IP": sbi["smf_ip"].(string),
"PCF_IP": sbi["pcf_ip"].(string),
"NSSF_IP": sbi["nssf_ip"].(string),
"NRF_IP": sbi["nrf_ip"].(string),
"UPF_IP": sbi["upf_ip"].(string),
"LMF_IP": sbi["lmf_ip"].(string),
"NEF_IP": sbi["nef_ip"].(string),
"MME_IP": sbi["mme_ip"].(string),
"N3IWF_IP": sbi["n3iwf_ip"].(string),
}
}

View File

@@ -22,16 +22,13 @@ type INeLicense interface {
// DeleteByIds 批量删除信息
DeleteByIds(ids []string) (int64, error)
// CheckUniqueTypeAndID 校验网元类型和网元ID是否唯一
CheckUniqueTypeAndID(neType, neId, id string) bool
// SelectByNeTypeAndNeID 通过ne_type和ne_id查询信息
SelectByNeTypeAndNeID(neType, neId string) model.NeLicense
// ReadLicenseInfo 读取授权文件信息
// 激活申请码, 激活文件
ReadLicenseInfo(neInfo model.NeInfo) (string, string)
// 返回激活申请码, 激活文件
ReadLicenseInfo(neLicense model.NeLicense) (string, string)
// UploadToNeHost 授权文件上传到网元主机
UploadToNeHost(neLicense model.NeLicense) error
// UploadLicense 授权文件上传到网元主机
UploadLicense(neLicense model.NeLicense) error
}

View File

@@ -3,12 +3,12 @@ package service
import (
"fmt"
"os"
"path/filepath"
"runtime"
"strings"
"time"
"be.ems/src/framework/utils/file"
"be.ems/src/framework/utils/ssh"
"be.ems/src/modules/network_element/model"
"be.ems/src/modules/network_element/repository"
)
@@ -84,18 +84,6 @@ func (r *NeLicenseImpl) SelectByTypeAndID(neType, neId string) model.NeLicense {
return model.NeLicense{}
}
// CheckUniqueTypeAndID 校验网元类型和网元ID是否唯一
func (r *NeLicenseImpl) CheckUniqueTypeAndID(neType, neId, id string) bool {
uniqueId := r.neLicenseRepository.CheckUniqueTypeAndID(model.NeLicense{
NeType: neType,
NeId: neId,
})
if uniqueId == id {
return true
}
return uniqueId == ""
}
// SelectByNeTypeAndNeID 通过ne_type和ne_id查询信息
func (r *NeLicenseImpl) SelectByNeTypeAndNeID(neType, neId string) model.NeLicense {
neLicenses := r.neLicenseRepository.SelectList(model.NeLicense{
@@ -109,75 +97,95 @@ func (r *NeLicenseImpl) SelectByNeTypeAndNeID(neType, neId string) model.NeLicen
}
// ReadLicenseInfo 读取授权文件信息
// 激活申请码, 激活文件
func (r *NeLicenseImpl) ReadLicenseInfo(neInfo model.NeInfo) (string, string) {
neTypeLower := strings.ToLower(neInfo.NeType)
// 返回激活申请码, 激活文件
func (r *NeLicenseImpl) ReadLicenseInfo(neLicense model.NeLicense) (string, string) {
neTypeLower := strings.ToLower(neLicense.NeType)
// 网管本地路径
omcPath := "/usr/local/etc/omc/ne_license"
if runtime.GOOS == "windows" {
omcPath = fmt.Sprintf("C:%s", omcPath)
}
omcPath = fmt.Sprintf("%s/%s/%s", omcPath, neTypeLower, neInfo.NeId)
omcPath = fmt.Sprintf("%s/%s/%s", omcPath, neTypeLower, neLicense.NeId)
// 网元端授权文件路径
nePath := fmt.Sprintf("/usr/local/etc/%s/license", neTypeLower)
// 复制授权申请码到本地
err := ssh.FileSCPNeToLocal(neInfo.IP, nePath+"/Activation_request_code.txt", omcPath+"/Activation_request_code.txt")
// 网元主机的SSH客户端
sshClient, err := NewNeInfoImpl.NeRunSSHclient(neLicense.NeType, neLicense.NeId)
if err != nil {
return "", ""
}
defer sshClient.Close()
// 网元主机的SSH客户端进行文件传输
sftpClient, err := sshClient.NewClientSFTP()
if err != nil {
return "", ""
}
defer sftpClient.Close()
// 复制授权申请码到本地
if err = sftpClient.CopyFileRemoteToLocal(nePath+"/Activation_request_code.txt", omcPath+"/Activation_request_code.txt"); err != nil {
return "", ""
}
// 读取文件内容
bytes, err := os.ReadFile(omcPath + "/Activation_request_code.txt")
if err != nil {
return "", ""
}
// 激活文件
// 复制激活文件到本地
licensePath := ""
if err = ssh.FileSCPNeToLocal(neInfo.IP, nePath+"/system.ini", omcPath+"/system.ini"); err == nil {
if err = sftpClient.CopyFileRemoteToLocal(nePath+"/system.ini", omcPath+"/system.ini"); err == nil {
licensePath = omcPath + "/system.ini"
}
return strings.TrimSpace(string(bytes)), licensePath
}
// UploadToNeHost 授权文件上传到网元主机
func (r *NeLicenseImpl) UploadToNeHost(neLicense model.NeLicense) error {
// UploadLicense 授权文件上传到网元主机
func (r *NeLicenseImpl) UploadLicense(neLicense model.NeLicense) error {
// 检查文件是否存在
omcLicensePath := file.ParseUploadFilePath(neLicense.LicensePath)
if _, err := os.Stat(omcLicensePath); err != nil {
return fmt.Errorf("file read failure")
}
// 检查网元主机
neHostInfo := NewNeHostImpl.SelectById(neLicense.HostId)
if neHostInfo.HostType != "ssh" || neHostInfo.HostID != neLicense.HostId {
return fmt.Errorf("no found host info")
// 网元主机的SSH客户端
sshClient, err := NewNeInfoImpl.NeRunSSHclient(neLicense.NeType, neLicense.NeId)
if err != nil {
return err
}
defer sshClient.Close()
// 网元主机的SSH客户端进行文件传输
sftpClient, err := sshClient.NewClientSFTP()
if err != nil {
return err
}
defer sftpClient.Close()
// 网元端授权文件路径
neTypeLower := strings.ToLower(neLicense.NeType)
neLicensePath := fmt.Sprintf("/usr/local/etc/%s/license", neTypeLower)
// 修改文件夹权限
NewNeInfoImpl.NeRunCMD(neLicense.NeType, neLicense.NeId, fmt.Sprintf("sudo chmod o+w %s/", neLicensePath))
neLicensePath := fmt.Sprintf("/usr/local/etc/%s/license/system.ini", neTypeLower)
neLicenseDir := filepath.ToSlash(filepath.Dir(neLicensePath))
// 修改网元文件权限
sshClient.RunCMD(fmt.Sprintf("sudo mkdir -p %s && sudo chmod 775 %s && sudo touch %s && sudo chmod o+rw %s", neLicenseDir, neLicenseDir, neLicensePath, neLicensePath))
// 尝试备份授权文件
neLicensePathBack := fmt.Sprintf("%s/system_%s.ini", neLicensePath, time.Now().Format("20060102_150405"))
NewNeInfoImpl.NeRunCMD(neLicense.NeType, neLicense.NeId, fmt.Sprintf("sudo cp -rf %s/system.ini %s", neLicensePath, neLicensePathBack))
sshClient.RunCMD(fmt.Sprintf("sudo cp -rf %s/system.ini %s", neLicensePath, neLicensePathBack))
// 上传授权文件去覆盖
NewNeInfoImpl.NeRunCMD(neLicense.NeType, neLicense.NeId, fmt.Sprintf("sudo chmod o+w %s/system.ini", neLicensePath))
if err := ssh.FileSCPLocalToNe(neHostInfo.Addr, omcLicensePath, neLicensePath+"/system.ini"); err != nil {
return fmt.Errorf("error uploading license")
if err := sftpClient.CopyFileLocalToRemote(omcLicensePath, neLicensePath); err != nil {
return err
}
// 重启服务
if neLicense.Reload {
cmdStr := fmt.Sprintf("sudo service %s restart", neTypeLower)
if neTypeLower == "ims" {
cmdStr = "sudo ims-stop && sudo ims-start"
cmdStr = "sudo ims-stop || true && sudo ims-start"
} else if neTypeLower == "omc" {
cmdStr = "sudo /usr/local/omc/bin/omcsvc.sh restart"
}
NewNeInfoImpl.NeRunCMD(neLicense.NeType, neLicense.NeId, cmdStr)
sshClient.RunCMD(cmdStr)
}
return nil
}

View File

@@ -25,7 +25,6 @@ type INeSoftware interface {
// CheckUniqueTypeAndNameAndVersion 校验网元类型和文件名版本是否唯一
CheckUniqueTypeAndNameAndVersion(neType, name, version, id string) bool
// UploadToNeHost 安装包上传到网元主机
// 返回执行命令步骤
UploadToNeHost(neSoftware model.NeSoftware) ([]string, error)
// UpdateVersions 更新软件包对应网元的新版本
UpdateVersions(neSoftware model.NeSoftware, neVersion model.NeVersion) int64
}

View File

@@ -3,11 +3,8 @@ package service
import (
"fmt"
"os"
"path/filepath"
"strings"
"be.ems/src/framework/utils/file"
"be.ems/src/framework/utils/ssh"
"be.ems/src/modules/network_element/model"
"be.ems/src/modules/network_element/repository"
)
@@ -47,26 +44,69 @@ 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.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 {
return r.neSoftwareRepository.Update(neSoftware)
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) {
// 检查是否存在
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,54 +124,20 @@ func (r *NeSoftwareImpl) CheckUniqueTypeAndNameAndVersion(neType, name, version,
return uniqueId == ""
}
// UploadToNeHost 安装包上传到网元主机
// 返回执行命令步骤
func (r *NeSoftwareImpl) UploadToNeHost(neSoftware model.NeSoftware) ([]string, error) {
cmdStrArr := []string{}
// 检查文件是否存在
filePath := file.ParseUploadFilePath(neSoftware.Path)
if _, err := os.Stat(filePath); err != nil {
return cmdStrArr, fmt.Errorf("file read failure")
// 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)
}
}
fileName := filepath.Base(neSoftware.Path)
if strings.Contains(fileName, "*") {
fileName = strings.ReplaceAll(fileName, "*", "_")
}
nePath := "/tmp"
neFilePath := fmt.Sprintf("%s/%s", nePath, fileName)
// 检查网元主机
neHostInfo := NewNeHostImpl.SelectById(neSoftware.HostId)
if neHostInfo.HostType != "ssh" || neHostInfo.HostID != neSoftware.HostId {
return cmdStrArr, fmt.Errorf("no found host info")
}
// 上传软件包到 /tmp
if err := ssh.FileSCPLocalToNe(neHostInfo.Addr, filePath, neFilePath); err != nil {
return cmdStrArr, fmt.Errorf("error uploading package")
}
// 安装软件包
cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo dpkg -i %s", neFilePath))
if neSoftware.NeType == "IMS" {
// 公网 PLMN地址
cmdStrArr = append(cmdStrArr, "sudo /usr/local/etc/ims/default/tools/modipplmn.sh {PUBIP} {MCC} {MNC}")
// 内网 服务地址
cmdStrArr = append(cmdStrArr, "sudo /usr/local/etc/ims/default/tools/modintraip.sh {PRIIP}")
// 10s后停止服务
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)))
}
// 删除软件包
cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo rm %s", neFilePath))
// 结束
cmdStrArr = append(cmdStrArr, fmt.Sprintf("echo '%s software install successful!'", neSoftware.NeType))
return cmdStrArr, nil
return rows
}

View File

@@ -22,9 +22,11 @@ type INeVersion interface {
// DeleteByIds 批量删除信息
DeleteByIds(ids []string) (int64, error)
// SelectByTypeAndID 通过网元类型和网元ID查询
SelectByTypeAndID(neType, neId string) model.NeVersion
// SelectByNeTypeAndNeID 通过网元类型和网元ID查询
SelectByNeTypeAndNeID(neType, neId string) model.NeVersion
// CheckUniqueTypeAndID 校验网元类型和网元ID是否唯一
CheckUniqueTypeAndID(neType, neId, id string) bool
// Operate 操作版本上传到网元主机执行命令
//
// action 安装行为install upgrade rollback
Operate(action string, neVersion model.NeVersion, preinput map[string]string) (string, error)
}

View File

@@ -2,7 +2,13 @@ package service
import (
"fmt"
"os"
"path/filepath"
"strings"
"time"
"be.ems/src/framework/utils/file"
"be.ems/src/framework/utils/ssh"
"be.ems/src/modules/network_element/model"
"be.ems/src/modules/network_element/repository"
)
@@ -66,8 +72,8 @@ func (r *NeVersionImpl) DeleteByIds(ids []string) (int64, error) {
return 0, fmt.Errorf("delete fail")
}
// SelectByTypeAndID 通过网元类型和网元ID查询
func (r *NeVersionImpl) SelectByTypeAndID(neType, neId string) model.NeVersion {
// SelectByNeTypeAndNeID 通过网元类型和网元ID查询
func (r *NeVersionImpl) SelectByNeTypeAndNeID(neType, neId string) model.NeVersion {
neVersions := r.neVersionRepository.SelectList(model.NeVersion{
NeType: neType,
NeId: neId,
@@ -78,14 +84,539 @@ func (r *NeVersionImpl) SelectByTypeAndID(neType, neId string) model.NeVersion {
return model.NeVersion{}
}
// CheckUniqueTypeAndID 校验网元类型和网元ID是否唯一
func (r *NeVersionImpl) CheckUniqueTypeAndID(neType, neId, id string) bool {
uniqueId := r.neVersionRepository.CheckUniqueTypeAndID(model.NeVersion{
NeType: neType,
NeId: neId,
})
if uniqueId == id {
return true
// Operate 操作版本上传到网元主机执行命令
//
// action 安装行为install upgrade rollback
func (r *NeVersionImpl) Operate(action string, neVersion model.NeVersion, preinput map[string]string) (string, error) {
// 网元主机的SSH客户端
sshClient, err := NewNeInfoImpl.NeRunSSHclient(neVersion.NeType, neVersion.NeId)
if err != nil {
return "", err
}
return uniqueId == ""
defer sshClient.Close()
// ========= 文件传输阶段 =========
softwarePath := neVersion.Path
if action == "install" || action == "upgrade" {
softwarePath = neVersion.NewPath
}
if action == "rollback" {
softwarePath = neVersion.PrePath
}
neFilePaths, err := r.operateFile(sshClient, softwarePath)
if err != nil {
return "", err
}
// ========= 安装时设置 =========
if action == "install" {
// 网元公共配置文件
para5GMap, err := NewNeInfoImpl.NeConfPara5GRead()
if para5GMap == nil || err != nil {
return "", fmt.Errorf("error read para5G file info")
}
if err := NewNeInfoImpl.NeConfPara5GWirte(para5GMap, []string{fmt.Sprintf("%s@%s", neVersion.NeType, neVersion.NeId)}); err != nil {
return "", fmt.Errorf("error wirte para5G file info")
}
}
// ========= 命令生成阶段 =========
okFlagStr, cmdStrArr, err := r.operateCommand(action, neVersion.NeType, neFilePaths)
if err != nil {
return "", err
}
// 操作自己omc时
if neVersion.NeType == "OMC" {
return sshClient.RunCMD(fmt.Sprintf("nohup sh -c \"sleep 3s && %s\" > /dev/null 2>&1 & \n", strings.Join(cmdStrArr, " && ")))
}
// ========= 执行阶段 =========
commandLine, err := r.operateRun(sshClient, preinput, cmdStrArr, neVersion.NeType, okFlagStr)
if err != nil {
return "", err
}
// ========= 完成阶段 =========
if strings.LastIndex(commandLine, okFlagStr) > 5 {
if err := r.operateDome(action, neVersion); err != nil {
return "", err
}
}
return commandLine, nil
}
// operateDome 操作版本-文件传输阶段
func (r *NeVersionImpl) operateFile(sshClient *ssh.ConnSSH, softwarePath string) ([]string, error) {
// 网元主机的SSH客户端进行文件传输
sftpClient, err := sshClient.NewClientSFTP()
if err != nil {
return nil, err
}
defer sftpClient.Close()
nePath := "/tmp"
copyFileToNeMap := map[string]string{}
// 统一处理多个文件和单个文件的情况
var softwarePaths []string
if strings.Contains(softwarePath, ",") {
softwarePaths = strings.Split(softwarePath, ",")
} else {
softwarePaths = []string{softwarePath}
}
for _, path := range softwarePaths {
// 检查文件是否存在
localFilePath := file.ParseUploadFilePath(path)
if _, err := os.Stat(localFilePath); err != nil {
return nil, fmt.Errorf("file read failure")
}
fileName := filepath.Base(path)
neFilePath := fmt.Sprintf("%s/%s", nePath, fileName)
copyFileToNeMap[localFilePath] = neFilePath
}
// 上传软件包到 /tmp
neFilePaths := []string{}
for k, v := range copyFileToNeMap {
if err = sftpClient.CopyFileLocalToRemote(k, v); err != nil {
return nil, fmt.Errorf("error uploading package")
}
neFilePaths = append(neFilePaths, v)
}
return neFilePaths, nil
}
// operateDome 操作版本-命令生成阶段
func (r *NeVersionImpl) operateCommand(action, neType string, neFilePaths []string) (string, []string, error) {
neTypeLower := strings.ToLower(neType)
// 命令终止结束标记
okFlagStr := fmt.Sprintf("%s version %s successful!", neTypeLower, action)
// 安装软件包
pkgCmdStr := fmt.Sprintf("sudo dpkg -i %s", strings.Join(neFilePaths, " "))
fileExt := filepath.Ext(strings.ToLower(neFilePaths[0]))
if strings.HasSuffix(fileExt, "rpm") {
pkgCmdStr = fmt.Sprintf("sudo rpm -Uvh %s", strings.Join(neFilePaths, " "))
}
// 组合命令输入
cmdStrArr := []string{}
if neType == "OMC" {
cmdStrArr = append(cmdStrArr, pkgCmdStr)
if action == "install" {
cmdStrArr = append(cmdStrArr, "sudo /usr/local/omc/bin/setomc.sh -m install") // 初始化数据库
} else {
cmdStrArr = append(cmdStrArr, "sudo /usr/local/omc/bin/omcsvc.sh stop")
cmdStrArr = append(cmdStrArr, "sudo /usr/local/omc/bin/setomc.sh -m upgrade") // 升级数据库
}
cmdStrArr = append(cmdStrArr, "sudo /usr/local/omc/bin/omcsvc.sh restart")
} else if neType == "IMS" {
if action == "install" {
para5GData := NewNeInfoImpl.Para5GData
cmdStrArr = append(cmdStrArr, pkgCmdStr+" \n")
// 公网 PLMN地址
cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo /usr/local/etc/ims/default/tools/modipplmn.sh %s %s %s \n", para5GData["SIP_IP"], para5GData["MCC"], para5GData["MNC"]))
// 内网 服务地址
cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo /usr/local/etc/ims/default/tools/modintraip.sh %s \n", para5GData["IMS_IP"]))
// IWF连接PCF服务
cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/172.16.5.160/%s/g\" /usr/local/etc/iwf/iwf_conf.yaml \n", para5GData["PCF_IP"]))
// 设置 HOST
cmdStrArr = append(cmdStrArr, fmt.Sprintf("grep -qxF '%s ims' /etc/hosts || echo '%s ims' | sudo tee -a /etc/hosts \n", para5GData["IMS_IP"], para5GData["IMS_IP"]))
mnc_mcc := fmt.Sprintf("mnc%s.mcc%s", para5GData["MNC_DOMAIN"], para5GData["MCC"])
hssHost := fmt.Sprintf("%s hss.ims.%s.3gppnetwork.org hss", para5GData["UDM_IP"], mnc_mcc)
cmdStrArr = append(cmdStrArr, fmt.Sprintf("grep -qxF '%s' /etc/hosts || echo '%s' | sudo tee -a /etc/hosts \n", hssHost, hssHost))
pcrfHost := fmt.Sprintf("%s pcrf.epc.%s.3gppnetwork.org pcrf", para5GData["IMS_IP"], mnc_mcc)
cmdStrArr = append(cmdStrArr, fmt.Sprintf("grep -qxF '%s' /etc/hosts || echo '%s' | sudo tee -a /etc/hosts \n", pcrfHost, pcrfHost))
imsOrgHost := fmt.Sprintf("ims.%s.3gppnetwork.org", mnc_mcc)
imsHost := fmt.Sprintf("%s %s ims", para5GData["SIP_IP"], imsOrgHost)
cmdStrArr = append(cmdStrArr, fmt.Sprintf("grep -qxF '%s' /etc/hosts || echo '%s' | sudo tee -a /etc/hosts \n", imsHost, imsHost))
pcscfHost := fmt.Sprintf("%s pcscf.%s pcscf", para5GData["SIP_IP"], imsOrgHost)
cmdStrArr = append(cmdStrArr, fmt.Sprintf("grep -qxF '%s' /etc/hosts || echo '%s' | sudo tee -a /etc/hosts \n", pcscfHost, pcscfHost))
icscfHost := fmt.Sprintf("%s icscf.%s icscf", para5GData["SIP_IP"], imsOrgHost)
cmdStrArr = append(cmdStrArr, fmt.Sprintf("grep -qxF '%s' /etc/hosts || echo '%s' | sudo tee -a /etc/hosts \n", icscfHost, icscfHost))
scscfHost := fmt.Sprintf("%s scscf.%s scscf", para5GData["SIP_IP"], imsOrgHost)
cmdStrArr = append(cmdStrArr, fmt.Sprintf("grep -qxF '%s' /etc/hosts || echo '%s' | sudo tee -a /etc/hosts \n", scscfHost, scscfHost))
mmtelHost := fmt.Sprintf("%s mmtel.%s mmtel", para5GData["SIP_IP"], imsOrgHost)
cmdStrArr = append(cmdStrArr, fmt.Sprintf("grep -qxF '%s' /etc/hosts || echo '%s' | sudo tee -a /etc/hosts \n", mmtelHost, mmtelHost))
mrfcHost := fmt.Sprintf("%s mrfc.%s mrfc", para5GData["SIP_IP"], imsOrgHost)
cmdStrArr = append(cmdStrArr, fmt.Sprintf("grep -qxF '%s' /etc/hosts || echo '%s' | sudo tee -a /etc/hosts \n", mrfcHost, mrfcHost))
smsHost := fmt.Sprintf("%s smsc.%s smsc", para5GData["SIP_IP"], imsOrgHost)
cmdStrArr = append(cmdStrArr, fmt.Sprintf("grep -qxF '%s' /etc/hosts || echo '%s' | sudo tee -a /etc/hosts \n", smsHost, smsHost))
// adb
cmdStrArr = append(cmdStrArr, "sudo cp /usr/local/etc/adb/default/adb.conf /usr/local/etc/adb/adb.conf \n")
cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/bind 127.0.0.1/bind %s/g\" /usr/local/etc/adb/adb.conf \n", para5GData["ADB_IP"]))
cmdStrArr = append(cmdStrArr, "sudo ims-stop || true && sudo ims-start \n")
// 30s后停止服务
// cmdStrArr = append(cmdStrArr, "nohup sh -c \"sleep 30s && sudo ims-stop\" > /dev/null 2>&1 & \n")
} else {
cmdStrArr = append(cmdStrArr, "sudo ims-stop \n")
cmdStrArr = append(cmdStrArr, pkgCmdStr+" \n")
cmdStrArr = append(cmdStrArr, "sudo ims-start \n")
}
} else {
if action == "install" {
para5GData := NewNeInfoImpl.Para5GData
cmdStrArr = append(cmdStrArr, pkgCmdStr+" \n")
// AMF配置修改
if neTypeLower == "amf" {
cmdStrArr = append(cmdStrArr, "sudo cp /usr/local/etc/amf/default/amfcfg.yaml /usr/local/etc/amf/amfcfg.yaml \n")
cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/172.16.5.120/%s/g\" /usr/local/etc/amf/amfcfg.yaml \n", para5GData["AMF_IP"]))
cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/192.168.8.120/%s/g\" /usr/local/etc/amf/amfcfg.yaml \n", para5GData["N2_IP"]))
cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/mcc: 001/mcc: %s/g\" /usr/local/etc/amf/amfcfg.yaml \n", para5GData["MCC"]))
cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/mnc: 01/mnc: %s/g\" /usr/local/etc/amf/amfcfg.yaml \n", para5GData["MNC"]))
cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/sst: 1/sst: %s/g\" /usr/local/etc/amf/amfcfg.yaml \n", para5GData["SST"]))
cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/sd: 000001/sd: %s/g\" /usr/local/etc/amf/amfcfg.yaml \n", para5GData["SD"]))
cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/- 4388/- %s/g\" /usr/local/etc/amf/amfcfg.yaml \n", para5GData["TAC"]))
cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/172.16.5.130/%s/g\" /usr/local/etc/amf/amfcfg.yaml \n", para5GData["AUSF_IP"]))
cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/172.16.5.140/%s/g\" /usr/local/etc/amf/amfcfg.yaml \n", para5GData["UDM_IP"]))
cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/172.16.5.150/%s/g\" /usr/local/etc/amf/amfcfg.yaml \n", para5GData["SMF_IP"]))
cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/172.16.5.160/%s/g\" /usr/local/etc/amf/amfcfg.yaml \n", para5GData["PCF_IP"]))
cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/172.16.5.180/%s/g\" /usr/local/etc/amf/amfcfg.yaml \n", para5GData["NRF_IP"]))
cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/172.16.5.200/%s/g\" /usr/local/etc/amf/amfcfg.yaml \n", para5GData["LMF_IP"]))
cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/172.16.5.210/%s/g\" /usr/local/etc/amf/amfcfg.yaml \n", para5GData["NEF_IP"]))
cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/- internet/- %s/g\" /usr/local/etc/amf/amfcfg.yaml \n", para5GData["DNN_DATA"]))
cmdStrArr = append(cmdStrArr, fmt.Sprintf("grep -qxF '%s n2' /etc/hosts || echo '%s n2' | sudo tee -a /etc/hosts \n", para5GData["N2_IP"], para5GData["N2_IP"]))
cmdStrArr = append(cmdStrArr, fmt.Sprintf("grep -qxF '%s amf' /etc/hosts || echo '%s amf' | sudo tee -a /etc/hosts \n", para5GData["AMF_IP"], para5GData["AMF_IP"]))
}
// AUSF配置修改
if neTypeLower == "ausf" {
cmdStrArr = append(cmdStrArr, "sudo cp /usr/local/etc/ausf/default/ausfcfg.yaml /usr/local/etc/ausf/ausfcfg.yaml \n")
cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/172.16.5.130/%s/g\" /usr/local/etc/ausf/ausfcfg.yaml \n", para5GData["AUSF_IP"]))
cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/172.16.5.140/%s/g\" /usr/local/etc/ausf/ausfcfg.yaml \n", para5GData["UDM_IP"]))
cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/172.16.5.180/%s/g\" /usr/local/etc/ausf/ausfcfg.yaml \n", para5GData["NRF_IP"]))
cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/mcc: 001/mcc: %s/g\" /usr/local/etc/ausf/ausfcfg.yaml \n", para5GData["MCC"]))
cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/mnc: 01/mnc: %s/g\" /usr/local/etc/ausf/ausfcfg.yaml \n", para5GData["MNC"]))
cmdStrArr = append(cmdStrArr, fmt.Sprintf("grep -qxF '%s ausf' /etc/hosts || echo '%s ausf' | sudo tee -a /etc/hosts \n", para5GData["AUSF_IP"], para5GData["AUSF_IP"]))
}
// UDM配置修改
if neTypeLower == "udm" {
cmdStrArr = append(cmdStrArr, "sudo cp /usr/local/etc/udm/default/udmcfg.yaml /usr/local/etc/udm/udmcfg.yaml \n")
cmdStrArr = append(cmdStrArr, "sudo cp /usr/local/etc/udm/default/nssai.yaml /usr/local/etc/udm/nssai.yaml \n")
cmdStrArr = append(cmdStrArr, "sudo cp /usr/local/etc/udm/default/snssai.yaml /usr/local/etc/udm/snssai.yaml \n")
cmdStrArr = append(cmdStrArr, "sudo cp /usr/local/etc/udm/default/as.yaml /usr/local/etc/udm/as.yaml \n")
cmdStrArr = append(cmdStrArr, "sudo cp /usr/local/etc/udm/default/dnn.yaml /usr/local/etc/udm/dnn.yaml \n")
cmdStrArr = append(cmdStrArr, "sudo cp /usr/local/etc/udm/default/scscfSet.yaml /usr/local/etc/udm/scscfSet.yaml \n")
cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/172.16.5.180/%s/g\" /usr/local/etc/udm/udmcfg.yaml \n", para5GData["NRF_IP"]))
cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/172.16.5.140/%s/g\" /usr/local/etc/udm/udmcfg.yaml \n", para5GData["UDM_IP"]))
cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/172.16.5.130/%s/g\" /usr/local/etc/udm/udmcfg.yaml \n", para5GData["AUSF_IP"]))
cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/172.16.5.120/%s/g\" /usr/local/etc/udm/udmcfg.yaml \n", para5GData["AMF_IP"]))
cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/mcc: 001/mcc: %s/g\" /usr/local/etc/udm/udmcfg.yaml \n", para5GData["MCC"]))
cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/mnc: 01/mnc: %s/g\" /usr/local/etc/udm/udmcfg.yaml \n", para5GData["MNC"]))
cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/mnc001.mcc001/mnc%s.mcc%s/g\" /usr/local/etc/udm/udmcfg.yaml \n", para5GData["MNC_DOMAIN"], para5GData["MCC"]))
cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/mnc001.mcc001/mnc%s.mcc%s/g\" /usr/local/etc/udm/as.yaml \n", para5GData["MNC_DOMAIN"], para5GData["MCC"]))
cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/mnc001.mcc001/mnc%s.mcc%s/g\" /usr/local/etc/udm/scscfSet.yaml \n", para5GData["MNC_DOMAIN"], para5GData["MCC"]))
cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/sst: 1/sst: %s/g\" /usr/local/etc/udm/nssai.yaml \n", para5GData["SST"]))
cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/sst: 1/sst: %s/g\" /usr/local/etc/udm/snssai.yaml \n", para5GData["SST"]))
cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/sd: 000001/sd: %s/g\" /usr/local/etc/udm/nssai.yaml \n", para5GData["SD"]))
cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/sd: 000001/sd: %s/g\" /usr/local/etc/udm/snssai.yaml \n", para5GData["SD"]))
cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/dnn: internet/dnn: %s/g\" /usr/local/etc/udm/snssai.yaml \n", para5GData["DNN_DATA"]))
cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/dnn: ims/dnn: %s/g\" /usr/local/etc/udm/snssai.yaml \n", para5GData["DNN_IMS"]))
cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/serviceSelection: 'internet'/serviceSelection: '%s'/g\" /usr/local/etc/udm/epsApn.yaml \n", para5GData["DNN_DATA"]))
cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/serviceSelection: 'ims'/serviceSelection: '%s'/g\" /usr/local/etc/udm/epsApn.yaml \n", para5GData["DNN_IMS"]))
cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/dnn: internet/dnn: %s/g\" /usr/local/etc/udm/dnn.yaml \n", para5GData["DNN_DATA"]))
cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/dnn: ims/dnn: %s/g\" /usr/local/etc/udm/dnn.yaml \n", para5GData["DNN_IMS"]))
cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/192.168.18.81/%s/g\" /usr/local/etc/udm/as.yaml \n", para5GData["SIP_IP"]))
cmdStrArr = append(cmdStrArr, fmt.Sprintf("grep -qxF '%s udm' /etc/hosts || echo '%s udm' | sudo tee -a /etc/hosts \n", para5GData["UDM_IP"], para5GData["UDM_IP"]))
// adb
cmdStrArr = append(cmdStrArr, "sudo cp /usr/local/etc/adb/default/adb.conf /usr/local/etc/adb/adb.conf \n")
cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/bind 127.0.0.1/bind %s/g\" /usr/local/etc/adb/adb.conf \n", para5GData["ADB_IP"]))
}
// SMF配置修改
if neTypeLower == "smf" {
cmdStrArr = append(cmdStrArr, "sudo cp /usr/local/etc/smf/default/smf_conf.yaml /usr/local/etc/smf/smf_conf.yaml \n")
cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/192.168.8.110/%s/g\" /usr/local/etc/smf/smf_conf.yaml \n", para5GData["SIP_IP"]))
cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/172.16.5.120/%s/g\" /usr/local/etc/smf/smf_conf.yaml \n", para5GData["AMF_IP"]))
cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/172.16.5.140/%s/g\" /usr/local/etc/smf/smf_conf.yaml \n", para5GData["UDM_IP"]))
cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/172.16.5.150/%s/g\" /usr/local/etc/smf/smf_conf.yaml \n", para5GData["SMF_IP"]))
cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/172.16.5.160/%s/g\" /usr/local/etc/smf/smf_conf.yaml \n", para5GData["PCF_IP"]))
cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/172.16.5.180/%s/g\" /usr/local/etc/smf/smf_conf.yaml \n", para5GData["NRF_IP"]))
cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/172.16.5.190/%s/g\" /usr/local/etc/smf/smf_conf.yaml \n", para5GData["UPF_IP"]))
cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s|10.2.1.0/24|%s|g\" /usr/local/etc/smf/smf_conf.yaml \n", para5GData["UE_POOL"]))
cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/internet/%s/g\" /usr/local/etc/smf/smf_conf.yaml \n", para5GData["DNN_DATA"]))
cmdStrArr = append(cmdStrArr, fmt.Sprintf("grep -qxF '%s smf' /etc/hosts || echo '%s smf' | sudo tee -a /etc/hosts \n", para5GData["SMF_IP"], para5GData["SMF_IP"]))
}
// PCF配置修改
if neTypeLower == "pcf" {
cmdStrArr = append(cmdStrArr, "sudo cp /usr/local/etc/pcf/default/pcfcfg.yaml /usr/local/etc/pcf/pcfcfg.yaml \n")
cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/172.16.5.120/%s/g\" /usr/local/etc/pcf/pcfcfg.yaml \n", para5GData["AMF_IP"]))
cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/172.16.5.140/%s/g\" /usr/local/etc/pcf/pcfcfg.yaml \n", para5GData["UDM_IP"]))
cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/172.16.5.160/%s/g\" /usr/local/etc/pcf/pcfcfg.yaml \n", para5GData["PCF_IP"]))
cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/172.16.5.180/%s/g\" /usr/local/etc/pcf/pcfcfg.yaml \n", para5GData["NRF_IP"]))
cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/172.16.5.210/%s/g\" /usr/local/etc/pcf/pcfcfg.yaml \n", para5GData["NEF_IP"]))
cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/mcc: 001/mcc: %s/g\" /usr/local/etc/pcf/pcfcfg.yaml \n", para5GData["MCC"]))
cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/mnc: 01/mnc: %s/g\" /usr/local/etc/pcf/pcfcfg.yaml \n", para5GData["MNC"]))
cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/mnc001.mcc001/mnc%s.mcc%s/g\" /usr/local/etc/pcf/pcfcfg.yaml \n", para5GData["MNC_DOMAIN"], para5GData["MCC"]))
cmdStrArr = append(cmdStrArr, fmt.Sprintf("grep -qxF '%s pcf' /etc/hosts || echo '%s pcf' | sudo tee -a /etc/hosts \n", para5GData["PCF_IP"], para5GData["PCF_IP"]))
}
// NSSF配置修改
if neTypeLower == "nssf" {
cmdStrArr = append(cmdStrArr, "sudo cp /usr/local/etc/nssf/default/nssfcfg.yaml /usr/local/etc/nssf/nssfcfg.yaml \n")
cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/172.16.5.170/%s/g\" /usr/local/etc/nssf/nssfcfg.yaml \n", para5GData["NSSF_IP"]))
cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/172.16.5.180/%s/g\" /usr/local/etc/nssf/nssfcfg.yaml \n", para5GData["NRF_IP"]))
cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/mcc: 001/mcc: %s/g\" /usr/local/etc/nssf/nssfcfg.yaml \n", para5GData["MCC"]))
cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/mnc: 01/mnc: %s/g\" /usr/local/etc/nssf/nssfcfg.yaml \n", para5GData["MNC"]))
cmdStrArr = append(cmdStrArr, fmt.Sprintf("grep -qxF '%s nssf' /etc/hosts || echo '%s nssf' | sudo tee -a /etc/hosts \n", para5GData["NSSF_IP"], para5GData["NSSF_IP"]))
}
// NRF配置修改
if neTypeLower == "nrf" {
cmdStrArr = append(cmdStrArr, "sudo cp /usr/local/etc/nrf/default/nrfcfg.yaml /usr/local/etc/nrf/nrfcfg.yaml \n")
cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/172.16.5.180/%s/g\" /usr/local/etc/nrf/nrfcfg.yaml \n", para5GData["NRF_IP"]))
cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/mcc: 001/mcc: %s/g\" /usr/local/etc/nrf/nrfcfg.yaml \n", para5GData["MCC"]))
cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/mnc: 01/mnc: %s/g\" /usr/local/etc/nrf/nrfcfg.yaml \n", para5GData["MNC"]))
cmdStrArr = append(cmdStrArr, fmt.Sprintf("grep -qxF '%s nrf' /etc/hosts || echo '%s nrf' | sudo tee -a /etc/hosts \n", para5GData["NRF_IP"], para5GData["NRF_IP"]))
}
// UPF配置修改
if neTypeLower == "upf" {
cmdStrArr = append(cmdStrArr, "sudo cp /usr/local/etc/upf/default/upfcfg.yaml /usr/local/etc/upf/upfcfg.yaml \n")
cmdStrArr = append(cmdStrArr, "sudo cp /usr/local/etc/upf/default/upfForwarder_1.yaml /usr/local/etc/upf/upfForwarder_1.yaml \n")
cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/172.16.5.190/%s/g\" /usr/local/etc/upf/upfcfg.yaml \n", para5GData["UPF_IP"]))
cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/localhost/%s/g\" /usr/local/etc/upf/upfForwarder_1.yaml \n", para5GData["UPF_IP"]))
// UE
cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i '/- interfaceType: \"N6\"/,/ueIpv4: 10.2.1.0/s/ueIpv4: 10.2.1.0/ueIpv4: %s/' /usr/local/etc/upf/upfForwarder_1.yaml \n", para5GData["UE_IP"]))
cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i '/- interfaceType: \"N6\"/,/ueIpv4Mask: 255.255.255.0/s/ueIpv4Mask: 255.255.255.0/ueIpv4Mask: %s/' /usr/local/etc/upf/upfForwarder_1.yaml \n", para5GData["UE_MASK"]))
// N3
cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/192.168.8.190/%s/g\" /usr/local/etc/upf/upfForwarder_1.yaml \n", para5GData["N3_IP"]))
cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i '/- interfaceType: \"N3\"/,/ipv4Mask: 255.255.240.0/s/ipv4Mask: 255.255.240.0/ipv4Mask: %s/' /usr/local/etc/upf/upfForwarder_1.yaml \n", para5GData["N3_MASK"]))
cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i '/- interfaceType: \"N3\"/,/gatewayIpv4: 192.168.1.254/s/gatewayIpv4: 192.168.1.254/gatewayIpv4: %s/' /usr/local/etc/upf/upfForwarder_1.yaml \n", para5GData["N3_GW"]))
cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i '/- interfaceType: \"N3\"/,/interfacePCI: \"0000:00:00.0\"/s/interfacePCI: \"0000:00:00.0\"/interfacePCI: \"%s\"/' /usr/local/etc/upf/upfForwarder_1.yaml \n", para5GData["N3_PCI"]))
cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i '/- interfaceType: \"N3\"/,/macAddr: \"00:00:00:00:00:00\"/s/macAddr: \"00:00:00:00:00:00\"/macAddr: \"%s\"/' /usr/local/etc/upf/upfForwarder_1.yaml \n", para5GData["N3_MAC"]))
// 标准版 N6
if para5GData["UPF_TYPE"] == "StandardUPF" {
cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/192.168.8.191/%s/g\" /usr/local/etc/upf/upfForwarder_1.yaml \n", para5GData["N6_IP"]))
cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i '/- interfaceType: \"N6\"/,/ipv4Mask: 255.255.240.0/s/ipv4Mask: 255.255.240.0/ipv4Mask: %s/' /usr/local/etc/upf/upfForwarder_1.yaml \n", para5GData["N6_MASK"]))
cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i '/- interfaceType: \"N6\"/,/gatewayIpv4: 192.168.1.254/s/gatewayIpv4: 192.168.1.254/gatewayIpv4: %s/' /usr/local/etc/upf/upfForwarder_1.yaml \n", para5GData["N6_GW"]))
cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i '/- interfaceType: \"N6\"/,/interfacePCI: \"0000:00:00.0\"/s/interfacePCI: \"0000:00:00.0\"/interfacePCI: \"%s\"/' /usr/local/etc/upf/upfForwarder_1.yaml \n", para5GData["N6_PCI"]))
cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i '/- interfaceType: \"N6\"/,/macAddr: \"00:00:00:00:00:00\"/s/macAddr: \"00:00:00:00:00:00\"/macAddr: \"%s\"/' /usr/local/etc/upf/upfForwarder_1.yaml \n", para5GData["N6_MAC"]))
// 路由
cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo ip route add '%s/%s' via '%s' \n", para5GData["UE_IP"], para5GData["UE_CIDR"], para5GData["N6_IP"]))
}
// 轻量版
if para5GData["UPF_TYPE"] == "LightUPF" {
cmdStrArr = append(cmdStrArr, "sudo sed -i \"s/192.168.8.191/0.0.0.0/g\" /usr/local/etc/upf/upfForwarder_1.yaml \n")
cmdStrArr = append(cmdStrArr, "sudo sed -i \"s/type: upfd/type: tun/g\" /usr/local/etc/upf/upfForwarder_1.yaml \n")
cmdStrArr = append(cmdStrArr, "sudo sed -i 's/driverType: vmxnet3/driverType: \"\"/g' /usr/local/etc/upf/upfForwarder_1.yaml \n")
}
cmdStrArr = append(cmdStrArr, fmt.Sprintf("grep -qxF '%s upf' /etc/hosts || echo '%s upf' | sudo tee -a /etc/hosts \n", para5GData["UPF_IP"], para5GData["UPF_IP"]))
cmdStrArr = append(cmdStrArr, fmt.Sprintf("grep -qxF '%s upfn3' /etc/hosts || echo '%s upfn3' | sudo tee -a /etc/hosts \n", para5GData["N3_IP"], para5GData["N3_IP"]))
cmdStrArr = append(cmdStrArr, fmt.Sprintf("grep -qxF '%s upfn6' /etc/hosts || echo '%s upfn6' | sudo tee -a /etc/hosts \n", para5GData["N6_IP"], para5GData["N6_IP"]))
}
// LMF配置修改 - 已不再维护导致激活License失败
// NEF配置修改 - SNMP无需License
if neTypeLower == "nef" {
cmdStrArr = append(cmdStrArr, "sudo cp /usr/local/etc/nef/default/nef_conf.yaml /usr/local/etc/nef/nef_conf.yaml \n")
cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/172.16.5.110/%s/g\" /usr/local/etc/nef/nef_conf.yaml \n", para5GData["IMS_IP"]))
cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/172.16.5.120/%s/g\" /usr/local/etc/nef/nef_conf.yaml \n", para5GData["AMF_IP"]))
cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/172.16.5.130/%s/g\" /usr/local/etc/nef/nef_conf.yaml \n", para5GData["AUSF_IP"]))
cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/172.16.5.140/%s/g\" /usr/local/etc/nef/nef_conf.yaml \n", para5GData["UDM_IP"]))
cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/172.16.5.150/%s/g\" /usr/local/etc/nef/nef_conf.yaml \n", para5GData["SMF_IP"]))
cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/172.16.5.160/%s/g\" /usr/local/etc/nef/nef_conf.yaml \n", para5GData["PCF_IP"]))
cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/172.16.5.170/%s/g\" /usr/local/etc/nef/nef_conf.yaml \n", para5GData["NSSF_IP"]))
cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/172.16.5.180/%s/g\" /usr/local/etc/nef/nef_conf.yaml \n", para5GData["NRF_IP"]))
cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/172.16.5.190/%s/g\" /usr/local/etc/nef/nef_conf.yaml \n", para5GData["UPF_IP"]))
cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/172.16.5.210/%s/g\" /usr/local/etc/nef/nef_conf.yaml \n", para5GData["NEF_IP"]))
cmdStrArr = append(cmdStrArr, fmt.Sprintf("grep -qxF '%s nef' /etc/hosts || echo '%s nef' | sudo tee -a /etc/hosts \n", para5GData["NEF_IP"], para5GData["NEF_IP"]))
}
// MME配置修改 - 4G
if neTypeLower == "mme" {
cmdStrArr = append(cmdStrArr, "sudo cp /usr/local/etc/mme/default/mme.conf /usr/local/etc/mme/mme.conf \n")
cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/172.16.5.120/%s/g\" /usr/local/etc/mme/mme.conf \n", para5GData["AMF_IP"]))
cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/172.16.5.150/%s/g\" /usr/local/etc/mme/mme.conf \n", para5GData["SMF_IP"]))
cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s|192.168.8.220/20|%s|g\" /usr/local/etc/mme/mme.conf \n", para5GData["S1_MMEIP"]))
cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s|172.16.5.220/24|%s|g\" /usr/local/etc/mme/mme.conf \n", para5GData["S11_MMEIP"]))
cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s|172.16.5.221/24|%s|g\" /usr/local/etc/mme/mme.conf \n", para5GData["S10_MMEIP"]))
cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/mnc001.mcc001/mnc%s.mcc%s/g\" /usr/local/etc/mme/mme.conf \n", para5GData["MNC_DOMAIN"], para5GData["MCC"]))
cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/\"00101\"/\"%s%s\"/g\" /usr/local/etc/mme/mme.conf \n", para5GData["MCC"], para5GData["MNC"]))
cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/MCC=\"001\" ; MNC=\"01\";/MCC=\"%s\" ; MNC=\"%s\";/g\" /usr/local/etc/mme/mme.conf \n", para5GData["MCC"], para5GData["MNC"]))
cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/TAC = \"1\";/TAC = \"%s\";/g\" /usr/local/etc/mme/mme.conf \n", para5GData["TAC"]))
cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/TAC = 1;/TAC = %s;/g\" /usr/local/etc/mme/mme.conf \n", para5GData["TAC"]))
// SMF开启
cmdStrArr = append(cmdStrArr, "sudo sed -i \"/^ *gxcfg:/,/^ *[^ ]/{s/enable: false/enable: true/;b};\" /usr/local/etc/smf/smf_conf.yaml \n")
cmdStrArr = append(cmdStrArr, fmt.Sprintf("grep -qxF '%s mme' /etc/hosts || echo '%s mme' | sudo tee -a /etc/hosts \n", para5GData["S11_MMEIP"], para5GData["S11_MMEIP"]))
}
// N3IWF配置修改
if neTypeLower == "n3iwf" {
cmdStrArr = append(cmdStrArr, "sudo cp /usr/local/etc/n3iwf/default/n3iwfcfg.yaml /usr/local/etc/n3iwf/n3iwfcfg.yaml \n")
cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/MCC: 001/MCC: %s/g\" /usr/local/etc/n3iwf/n3iwfcfg.yaml \n", para5GData["MCC"]))
cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/MNC: 01/MNC: %s/g\" /usr/local/etc/n3iwf/n3iwfcfg.yaml \n", para5GData["MNC"]))
cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/192.168.12.161/%s/g\" /usr/local/etc/n3iwf/n3iwfcfg.yaml \n", para5GData["N3IWF_IP"]))
cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/192.168.12.160/%s/g\" /usr/local/etc/n3iwf/n3iwfcfg.yaml \n", para5GData["N3IWF_IP"]))
cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/192.168.8.27/%s/g\" /usr/local/etc/n3iwf/n3iwfcfg.yaml \n", para5GData["UDM_IP"]))
cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/192.168.1.239/%s/g\" /usr/local/etc/n3iwf/n3iwfcfg.yaml \n", para5GData["SMF_IP"]))
cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/192.168.8.22/%s/g\" /usr/local/etc/n3iwf/n3iwfcfg.yaml \n", para5GData["N2_IP"]))
cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/192.168.1.161/%s/g\" /usr/local/etc/n3iwf/n3iwfcfg.yaml \n", para5GData["N3_IP"]))
cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/192.168.1.160/%s/g\" /usr/local/etc/n3iwf/n3iwfcfg.yaml \n", para5GData["N6_IP"]))
cmdStrArr = append(cmdStrArr, fmt.Sprintf("grep -qxF '%s n3iwf' /etc/hosts || echo '%s n3iwf' | sudo tee -a /etc/hosts \n", para5GData["N3IWF_IP"], para5GData["N3IWF_IP"]))
}
cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo service %s restart \n", neTypeLower))
// 30s后停止服务
// cmdStrArr = append(cmdStrArr, fmt.Sprintf("nohup sh -c \"sleep 30s && sudo service %s stop\" > /dev/null 2>&1 & \n", neTypeLower))
} else {
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", strings.Join(neFilePaths, " ")))
// 结束
cmdStrArr = append(cmdStrArr, fmt.Sprintf("echo '%s' \n", okFlagStr))
return okFlagStr, cmdStrArr, nil
}
// operateDome 操作版本-执行阶段
func (r *NeVersionImpl) operateRun(sshClient *ssh.ConnSSH, preinput map[string]string, cmdStrArr []string, neType string, okFlagStr string) (string, error) {
// ssh连接会话
clientSession, err := sshClient.NewClientSession(127, 42)
if err != nil {
return "", fmt.Errorf("neinfo ssh client session new err")
}
defer clientSession.Close()
firstRead := true // 首次命令进行记录日志信息
commandLineText := "" // 日志信息
done := make(chan bool) // 完成信号
// 超时退出 120s
timeoutTicker := time.NewTicker(120 * 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 {
commandLineText += outputStr
}
// IMS预输入
if neType == "IMS" {
// IMS包 P/I/S-CSCF Config 配置覆盖
if strings.Contains(outputStr, "(P/I/S-CSCF Config)? <y/n>") {
if pisCSCF, ok := preinput["pisCSCF"]; ok && pisCSCF != "" {
clientSession.Write(fmt.Sprintf("%s \n", pisCSCF))
} else {
clientSession.Write("y \n")
}
continue
}
// MF包 etc下目录覆盖
if strings.Contains(outputStr, "/usr/local/etc/mf directory? (Yes/No, default: No)") {
if pisCSCF, ok := preinput["updateMFetc"]; ok && pisCSCF != "" {
clientSession.Write(fmt.Sprintf("%s \n", pisCSCF))
} else {
clientSession.Write("No \n")
}
continue
}
// MF包 share下目录覆盖
if strings.Contains(outputStr, "/usr/local/share/mf directory? (Yes/No, default: No)") {
if pisCSCF, ok := preinput["updateMFshare"]; ok && pisCSCF != "" {
clientSession.Write(fmt.Sprintf("%s \n", pisCSCF))
} else {
clientSession.Write("No \n")
}
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 commandLineText, nil
}
// operateDome 操作版本-完成阶段
func (r *NeVersionImpl) operateDome(action string, neVersion model.NeVersion) error {
if action == "install" {
// 网元信息
neInfo := NewNeInfoImpl.SelectNeInfoByNeTypeAndNeID(neVersion.NeType, neVersion.NeId)
if neInfo.NeId != neVersion.NeId {
return fmt.Errorf("error found neinfo")
}
// ========= 网元OAM配置文件 start ==========
if err := NewNeInfoImpl.NeConfOAMSync(neInfo, nil, true); err != nil {
return fmt.Errorf("error wirte OAM file info")
}
// ========= 网元OAM配置文件 end ===========
}
// 更新Version
verInfo := r.SelectByNeTypeAndNeID(neVersion.NeType, neVersion.NeId)
if verInfo.NeId == neVersion.NeId {
curName := verInfo.Name
curVersion := verInfo.Version
curPath := verInfo.Path
if action == "install" {
verInfo.Name = neVersion.NewName
verInfo.Version = neVersion.NewVersion
verInfo.Path = neVersion.NewPath
verInfo.PreName = "-"
verInfo.PreVersion = "-"
verInfo.PrePath = "-"
verInfo.NewName = "-"
verInfo.NewVersion = "-"
verInfo.NewPath = "-"
}
if action == "upgrade" {
verInfo.Name = neVersion.NewName
verInfo.Version = neVersion.NewVersion
verInfo.Path = neVersion.NewPath
verInfo.PreName = curName
verInfo.PreVersion = curVersion
verInfo.PrePath = curPath
verInfo.NewName = "-"
verInfo.NewVersion = "-"
verInfo.NewPath = "-"
}
if action == "rollback" {
verInfo.Name = neVersion.PreName
verInfo.Version = neVersion.PreVersion
verInfo.Path = neVersion.PrePath
verInfo.PreName = curName
verInfo.PreVersion = curVersion
verInfo.PrePath = curPath
}
verInfo.Status = "1"
NewNeVersionImpl.Update(verInfo)
}
return nil
}

View File

@@ -144,8 +144,14 @@ func (s *WSController) SSH(c *gin.Context) {
// 创建链接SSH客户端
var connSSH ssh.ConnSSH
neHost.CopyTo(&connSSH)
client, err := connSSH.NewClient()
if err != nil {
var client *ssh.ConnSSH
var clientErr error
if neHost.AuthMode == "2" {
client, clientErr = connSSH.NewClientByLocalPrivate()
} else {
client, clientErr = connSSH.NewClient()
}
if clientErr != nil {
// 连接主机失败,请检查连接参数后重试
c.JSON(200, result.ErrMsg(i18n.TKey(language, "neHost.errByHostInfo")))
return
@@ -250,8 +256,19 @@ func (s *WSController) Telnet(c *gin.Context) {
}
defer client.Close()
// 终端单行字符数
cols, err := strconv.Atoi(c.Query("cols"))
if err != nil || cols > 254 {
cols = 80
}
// 终端显示行数
rows, err := strconv.Atoi(c.Query("rows"))
if err != nil || cols > rows {
rows = 40
}
// 创建Telnet客户端会话
clientSession, err := client.NewClientSession()
clientSession, err := client.NewClientSession(uint8(cols), uint8(rows))
if err != nil {
// 连接主机失败,请检查连接参数后重试
c.JSON(200, result.ErrMsg(i18n.TKey(language, "neHost.errByHostInfo")))

View File

@@ -27,3 +27,21 @@ func GetCDRConnect(requestID string, data any) ([]byte, error) {
}))
return resultByte, err
}
// GetCDRConnect 获取CDR会话事件-SMF
func GetSMFCDRConnect(requestID string, data any) ([]byte, error) {
msgByte, _ := json.Marshal(data)
var query neDataModel.SMFCDREventQuery
err := json.Unmarshal(msgByte, &query)
if err != nil {
logger.Warnf("ws processor GetCDRConnect err: %s", err.Error())
return nil, fmt.Errorf("query data structure error")
}
dataMap := neDataService.NewSMFCDREventImpl.SelectPage(query)
resultByte, err := json.Marshal(result.Ok(map[string]any{
"requestId": requestID,
"data": dataMap,
}))
return resultByte, err
}