1021 lines
30 KiB
Go
1021 lines
30 KiB
Go
package service
|
||
|
||
import (
|
||
"encoding/json"
|
||
"fmt"
|
||
"os"
|
||
"path/filepath"
|
||
"runtime"
|
||
"strings"
|
||
|
||
"be.ems/src/framework/constants"
|
||
"be.ems/src/framework/database/redis"
|
||
"be.ems/src/framework/logger"
|
||
"be.ems/src/framework/ssh"
|
||
"be.ems/src/framework/telnet"
|
||
"be.ems/src/framework/utils/generate"
|
||
"be.ems/src/framework/utils/parse"
|
||
neFetchlink "be.ems/src/modules/network_element/fetch_link"
|
||
"be.ems/src/modules/network_element/model"
|
||
"be.ems/src/modules/network_element/repository"
|
||
)
|
||
|
||
// 实例化服务层 NeInfo 结构体
|
||
var NewNeInfo = &NeInfo{
|
||
neInfoRepository: repository.NewNeInfo,
|
||
neHostService: NewNeHost,
|
||
Para5GData: map[string]string{},
|
||
}
|
||
|
||
// 网元信息 服务层处理
|
||
type NeInfo struct {
|
||
neInfoRepository *repository.NeInfo // 网元信息数据信息
|
||
neHostService *NeHost // 网元主机连接服务
|
||
Para5GData map[string]string
|
||
}
|
||
|
||
// FindByNeTypeAndNeID 通过ne_type和ne_id查询网元信息
|
||
func (r NeInfo) FindByNeTypeAndNeID(neType, neID string) model.NeInfo {
|
||
var neInfo model.NeInfo
|
||
key := fmt.Sprintf("%s:%s:%s", constants.CACHE_NE_INFO, strings.ToUpper(neType), neID)
|
||
jsonStr, _ := redis.Get("", key)
|
||
if len(jsonStr) > 7 {
|
||
err := json.Unmarshal([]byte(jsonStr), &neInfo)
|
||
if err != nil {
|
||
neInfo = model.NeInfo{}
|
||
}
|
||
} else {
|
||
neInfo = r.neInfoRepository.SelectNeInfoByNeTypeAndNeID(neType, neID)
|
||
if neInfo.ID != 0 && neInfo.NeId == neID {
|
||
redis.Del("", key)
|
||
values, _ := json.Marshal(neInfo)
|
||
redis.Set("", key, string(values), 0)
|
||
}
|
||
}
|
||
return neInfo
|
||
}
|
||
|
||
// RefreshByNeTypeAndNeID 通过ne_type和ne_id刷新redis中的缓存
|
||
func (r NeInfo) RefreshByNeTypeAndNeID(neType, neID string) model.NeInfo {
|
||
var neInfo model.NeInfo
|
||
key := fmt.Sprintf("%s:%s:%s", constants.CACHE_NE_INFO, strings.ToUpper(neType), neID)
|
||
redis.Del("", key)
|
||
neInfo = r.neInfoRepository.SelectNeInfoByNeTypeAndNeID(neType, neID)
|
||
if neInfo.ID != 0 && neInfo.NeId == neID {
|
||
values, _ := json.Marshal(neInfo)
|
||
redis.Set("", key, string(values), 0)
|
||
}
|
||
return neInfo
|
||
}
|
||
|
||
// ClearNeCacheByNeType 清除网元类型缓存
|
||
func (r NeInfo) ClearNeCacheByNeType(neType string) bool {
|
||
key := fmt.Sprintf("%s:*", constants.CACHE_NE_INFO)
|
||
if neType != "*" {
|
||
key = fmt.Sprintf("%s:%s*", constants.CACHE_NE_INFO, neType)
|
||
}
|
||
keys, err := redis.GetKeys("", key)
|
||
if err != nil {
|
||
return false
|
||
}
|
||
return redis.DelKeys("", keys) == nil
|
||
}
|
||
|
||
// FindByNeType 通过ne_type查询网元信息
|
||
func (r NeInfo) FindByNeType(neType string) []model.NeInfo {
|
||
neInfo := make([]model.NeInfo, 0)
|
||
key := fmt.Sprintf("%s:%s:*", constants.CACHE_NE_INFO, strings.ToUpper(neType))
|
||
cacheKeys, _ := redis.GetKeys("", key)
|
||
if len(cacheKeys) > 0 {
|
||
for _, key := range cacheKeys {
|
||
var v model.NeInfo
|
||
jsonStr, _ := redis.Get("", key)
|
||
if len(jsonStr) > 7 {
|
||
json.Unmarshal([]byte(jsonStr), &v)
|
||
}
|
||
neInfo = append(neInfo, v)
|
||
}
|
||
return neInfo
|
||
} else {
|
||
neInfo = r.neInfoRepository.SelectList(model.NeInfo{NeType: neType})
|
||
for _, v := range neInfo {
|
||
key := fmt.Sprintf("%s:%s:%s", constants.CACHE_NE_INFO, strings.ToUpper(v.NeType), v.NeId)
|
||
redis.Del("", key)
|
||
values, _ := json.Marshal(v)
|
||
redis.Set("", key, string(values), 0)
|
||
}
|
||
}
|
||
return neInfo
|
||
}
|
||
|
||
// FindByRmuid 通过rmUID查询网元信息
|
||
func (r NeInfo) FindByRmuid(rmUid string) model.NeInfo {
|
||
var neInfo model.NeInfo
|
||
cacheKeys, _ := redis.GetKeys("", constants.CACHE_NE_INFO+":*")
|
||
if len(cacheKeys) > 0 {
|
||
for _, key := range cacheKeys {
|
||
var v model.NeInfo
|
||
jsonStr, _ := redis.Get("", key)
|
||
if len(jsonStr) > 7 {
|
||
json.Unmarshal([]byte(jsonStr), &v)
|
||
}
|
||
if v.RmUID == rmUid {
|
||
neInfo = v
|
||
break
|
||
}
|
||
}
|
||
} else {
|
||
neInfos := r.Find(neInfo, false, false)
|
||
for _, v := range neInfos {
|
||
key := fmt.Sprintf("%s:%s:%s", constants.CACHE_NE_INFO, strings.ToUpper(v.NeType), v.NeId)
|
||
redis.Del("", key)
|
||
values, _ := json.Marshal(v)
|
||
redis.Set("", key, string(values), 0)
|
||
if v.RmUID == rmUid {
|
||
neInfo = v
|
||
}
|
||
}
|
||
}
|
||
return neInfo
|
||
}
|
||
|
||
// FindByPage 根据条件分页查询
|
||
//
|
||
// bandStatus 带状态信息
|
||
func (r NeInfo) FindByPage(query map[string]string, bandStatus bool) ([]model.NeInfo, int64) {
|
||
rows, total := r.neInfoRepository.SelectByPage(query)
|
||
|
||
// 网元直连读取网元服务状态
|
||
if bandStatus {
|
||
r.bandNeStatus(&rows)
|
||
}
|
||
|
||
return rows, total
|
||
}
|
||
|
||
// Find 查询列表
|
||
//
|
||
// bandStatus 带状态信息
|
||
// bandHost 带主机信息
|
||
func (r NeInfo) Find(ne model.NeInfo, bandStatus bool, bandHost bool) []model.NeInfo {
|
||
list := r.neInfoRepository.SelectList(ne)
|
||
|
||
// 网元直连读取网元服务状态
|
||
if bandStatus {
|
||
r.bandNeStatus(&list)
|
||
}
|
||
|
||
// 网元主机信息
|
||
if bandHost {
|
||
r.bandNeHosts(&list)
|
||
}
|
||
|
||
return list
|
||
}
|
||
|
||
// bandNeStatus 网元列表项数据带网元服务状态
|
||
func (r NeInfo) bandNeStatus(arr *[]model.NeInfo) {
|
||
for i := range *arr {
|
||
v := (*arr)[i]
|
||
result, err := neFetchlink.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.UpdateState(v.ID, v.Status)
|
||
}
|
||
continue
|
||
}
|
||
result["online"] = true
|
||
(*arr)[i].ServerState = result
|
||
// 网元状态设置为在线
|
||
var status int64 = 1
|
||
if parse.Boolean(result["standby"]) {
|
||
status = 3
|
||
}
|
||
// 下发网管配置信息给网元
|
||
if _, err = neFetchlink.NeConfigOMC(v); err != nil {
|
||
status = 2
|
||
}
|
||
(*arr)[i].Status = status
|
||
if v.Status != status {
|
||
r.neInfoRepository.UpdateState(v.ID, status)
|
||
r.RefreshByNeTypeAndNeID(v.NeType, v.NeId)
|
||
}
|
||
// 网元版本设置为当前版本
|
||
version, ok := result["version"].(string)
|
||
if ok && version != v.NeVersion {
|
||
r.neInfoRepository.UpdateVersion(v.ID, version)
|
||
r.RefreshByNeTypeAndNeID(v.NeType, v.NeId)
|
||
}
|
||
}
|
||
}
|
||
|
||
// bandNeHosts 网元列表项数据带网元主机信息
|
||
func (r NeInfo) bandNeHosts(arr *[]model.NeInfo) {
|
||
for i := range *arr {
|
||
v := (*arr)[i]
|
||
if v.HostIDs != "" {
|
||
hostIds := strings.Split(v.HostIDs, ",")
|
||
if len(hostIds) <= 1 {
|
||
continue
|
||
}
|
||
for _, v := range hostIds {
|
||
hostId := parse.Number(v)
|
||
neHost := r.neHostService.FindById(hostId)
|
||
if neHost.ID == 0 || neHost.ID != hostId {
|
||
continue
|
||
}
|
||
(*arr)[i].Hosts = append((*arr)[i].Hosts, neHost)
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// FindById 通过ID查询
|
||
//
|
||
// bandHost 带主机信息
|
||
func (r NeInfo) FindById(id int64, bandHost bool) model.NeInfo {
|
||
if id <= 0 {
|
||
return model.NeInfo{}
|
||
}
|
||
neInfos := r.neInfoRepository.SelectByIds([]int64{id})
|
||
if len(neInfos) > 0 {
|
||
// 带主机信息
|
||
if neInfos[0].HostIDs != "" && bandHost {
|
||
r.bandNeHosts(&neInfos)
|
||
}
|
||
return neInfos[0]
|
||
}
|
||
return model.NeInfo{}
|
||
}
|
||
|
||
// Insert 新增信息
|
||
func (r NeInfo) Insert(neInfo model.NeInfo) int64 {
|
||
// 主机信息新增
|
||
if neInfo.Hosts != nil {
|
||
uuid := generate.Code(4)
|
||
var hostIDs []string
|
||
for _, host := range neInfo.Hosts {
|
||
host.Title = fmt.Sprintf("%s_%d_%s", neInfo.NeName, host.Port, uuid)
|
||
host.GroupID = "1"
|
||
host.CreateBy = neInfo.CreateBy
|
||
hostId := r.neHostService.Insert(host)
|
||
if hostId > 0 {
|
||
hostIDs = append(hostIDs, fmt.Sprint(hostId))
|
||
}
|
||
}
|
||
neInfo.HostIDs = strings.Join(hostIDs, ",")
|
||
}
|
||
|
||
insertId := r.neInfoRepository.Insert(neInfo)
|
||
if insertId > 0 {
|
||
// 刷新缓存
|
||
r.RefreshByNeTypeAndNeID(neInfo.NeType, neInfo.NeId)
|
||
}
|
||
return insertId
|
||
}
|
||
|
||
// Update 修改信息
|
||
func (r NeInfo) Update(neInfo model.NeInfo) int64 {
|
||
// 主机信息更新
|
||
if neInfo.Hosts != nil {
|
||
uuid := generate.Code(4)
|
||
for _, host := range neInfo.Hosts {
|
||
if host.ID != 0 {
|
||
host.Title = fmt.Sprintf("%s_%d_%s", neInfo.NeName, host.Port, uuid)
|
||
host.GroupID = "1"
|
||
host.UpdateBy = neInfo.UpdateBy
|
||
r.neHostService.Update(host)
|
||
}
|
||
}
|
||
}
|
||
|
||
num := r.neInfoRepository.Update(neInfo)
|
||
if num > 0 {
|
||
// 刷新缓存
|
||
r.RefreshByNeTypeAndNeID(neInfo.NeType, neInfo.NeId)
|
||
}
|
||
return num
|
||
}
|
||
|
||
// DeleteByIds 批量删除信息
|
||
func (r NeInfo) DeleteByIds(ids []int64) (int64, error) {
|
||
// 检查是否存在
|
||
infos := r.neInfoRepository.SelectByIds(ids)
|
||
if len(infos) <= 0 {
|
||
return 0, fmt.Errorf("neHostCmd.noData")
|
||
}
|
||
|
||
if len(infos) == len(ids) {
|
||
for _, v := range infos {
|
||
// 主机信息删除
|
||
if v.HostIDs != "" {
|
||
hostIds := make([]int64, 0)
|
||
arr := strings.Split(v.HostIDs, ",")
|
||
for _, hostId := range arr {
|
||
hostIds = append(hostIds, parse.Number(hostId))
|
||
}
|
||
r.neHostService.DeleteByIds(hostIds, false)
|
||
}
|
||
// 删除License
|
||
neLicense := NewNeLicense.FindByNeTypeAndNeID(v.NeType, v.NeId)
|
||
if neLicense.NeId == v.NeId {
|
||
NewNeLicense.DeleteByIds([]int64{neLicense.ID})
|
||
}
|
||
// 删除Version
|
||
neVersion := NewNeVersion.FindByNeTypeAndNeID(v.NeType, v.NeId)
|
||
if neVersion.NeId == v.NeId {
|
||
NewNeVersion.DeleteByIds([]int64{neVersion.ID})
|
||
}
|
||
// 缓存信息删除
|
||
redis.Del("", fmt.Sprintf("%s:%s:%s", constants.CACHE_NE_INFO, v.NeType, v.NeId))
|
||
}
|
||
rows := r.neInfoRepository.DeleteByIds(ids)
|
||
return rows, nil
|
||
}
|
||
// 删除信息失败!
|
||
return 0, fmt.Errorf("delete fail")
|
||
}
|
||
|
||
// CheckUniqueNeTypeAndNeId 校验同类型下标识是否唯一
|
||
func (r NeInfo) CheckUniqueNeTypeAndNeId(neType, neId string, id int64) bool {
|
||
uniqueId := r.neInfoRepository.CheckUniqueNeTypeAndNeId(model.NeInfo{
|
||
NeType: neType,
|
||
NeId: neId,
|
||
})
|
||
if uniqueId == id {
|
||
return true
|
||
}
|
||
return uniqueId == 0
|
||
}
|
||
|
||
// NeRunSSHClient 网元主机的SSH客户端-为创建相关连接,注意结束后 Close()
|
||
func (r NeInfo) NeRunSSHClient(neType, neId string) (*ssh.ConnSSH, error) {
|
||
neInfo := r.FindByNeTypeAndNeID(neType, neId)
|
||
if neInfo.NeId != neId {
|
||
logger.Errorf("NeRunSSHClient NeType:%s NeID:%s not found", neType, neId)
|
||
return nil, fmt.Errorf("neinfo 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")
|
||
}
|
||
hostIds := strings.Split(neInfo.HostIDs, ",")
|
||
if len(hostIds) <= 1 {
|
||
logger.Errorf("NeRunTelnetClient hosts id %s not found", neInfo.HostIDs)
|
||
return nil, fmt.Errorf("neinfo host id not found")
|
||
}
|
||
hostId := parse.Number(hostIds[0]) // 网元主机ssh 0:22
|
||
neHost := r.neHostService.FindById(hostId)
|
||
if neHost.ID == 0 || neHost.ID != hostId {
|
||
logger.Errorf("NeRunTelnetClient Hosts %s not found", neInfo.HostIDs)
|
||
return nil, fmt.Errorf("neinfo host not found")
|
||
}
|
||
if neHost.HostType != "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)
|
||
var client *ssh.ConnSSH
|
||
var err error
|
||
if neHost.AuthMode == "2" {
|
||
client, err = connSSH.NewClientByLocalPrivate()
|
||
} else {
|
||
client, err = connSSH.NewClient()
|
||
}
|
||
if err != nil {
|
||
logger.Errorf("NeRunSSHClient NewClient err => %s", err.Error())
|
||
return nil, fmt.Errorf("neinfo ssh client new err")
|
||
}
|
||
return client, nil
|
||
}
|
||
|
||
// NeRunSSHCmd 网元主机的SSH客户端发送cmd命令
|
||
func (r NeInfo) NeRunSSHCmd(neType, neId, cmd string) (string, error) {
|
||
sshClient, err := r.NeRunSSHClient(neType, neId)
|
||
if err != nil {
|
||
return "", err
|
||
}
|
||
defer sshClient.Close()
|
||
|
||
// 执行命令
|
||
output, err := sshClient.RunCMD(cmd)
|
||
if err != nil {
|
||
logger.Errorf("NeRunSSHCmd RunCMD %s err => %s", output, err.Error())
|
||
return "", fmt.Errorf("neinfo ssh run cmd err")
|
||
}
|
||
return output, nil
|
||
}
|
||
|
||
// NeRunTelnetClient 网元主机的Telnet客户端-为创建相关连接,注意结束后 Close()
|
||
// num 是网元主机telnet 1:4100 2:5200(UPF标准版)
|
||
func (r NeInfo) NeRunTelnetClient(neType, neId string, num int) (*telnet.ConnTelnet, error) {
|
||
neInfo := r.FindByNeTypeAndNeID(neType, neId)
|
||
if neInfo.NeId != neId {
|
||
logger.Errorf("NeRunTelnetClient NeType:%s NeID:%s not found", neType, neId)
|
||
return nil, fmt.Errorf("neinfo not found")
|
||
}
|
||
// 取主机信息
|
||
if neInfo.HostIDs == "" {
|
||
logger.Errorf("NeRunTelnetClient NeType:%s NeID:%s hostId not found", neType, neId)
|
||
return nil, fmt.Errorf("neinfo hostId not found")
|
||
}
|
||
hostIds := strings.Split(neInfo.HostIDs, ",")
|
||
if len(hostIds) <= 1 {
|
||
logger.Errorf("NeRunTelnetClient hosts id %s not found", neInfo.HostIDs)
|
||
return nil, fmt.Errorf("neinfo host id not found")
|
||
}
|
||
hostId := parse.Number(hostIds[num]) // 网元主机telnet 1:4100 2:5200
|
||
neHost := r.neHostService.FindById(hostId)
|
||
if neHost.ID == 0 || neHost.ID != hostId {
|
||
logger.Errorf("NeRunTelnetClient Hosts %s not found", neInfo.HostIDs)
|
||
return nil, fmt.Errorf("neinfo host not found")
|
||
}
|
||
|
||
// 创建链接Telnet客户端
|
||
var connTelnet telnet.ConnTelnet
|
||
neHost.CopyTo(&connTelnet)
|
||
telnetClient, err := connTelnet.NewClient()
|
||
if err != nil {
|
||
logger.Errorf("NeRunTelnetClient NewClient err => %s", err.Error())
|
||
return nil, fmt.Errorf("neinfo telnet client new err")
|
||
}
|
||
return telnetClient, nil
|
||
}
|
||
|
||
// NeRunRedisClient 网元主机的Redis客户端-为创建相关连接,注意结束后 Close()
|
||
// 暂时只有UDM有Redis配置项
|
||
func (r NeInfo) NeRunRedisClient(neType, neId string) (*redis.ConnRedis, error) {
|
||
neInfo := r.FindByNeTypeAndNeID(neType, neId)
|
||
if neInfo.NeId != neId {
|
||
logger.Errorf("NeRunRedisClient NeType:%s NeID:%s not found", neType, neId)
|
||
return nil, fmt.Errorf("neinfo not found")
|
||
}
|
||
// 取主机信息
|
||
if neInfo.HostIDs == "" {
|
||
logger.Errorf("NeRunRedisClient NeType:%s NeID:%s hostId not found", neType, neId)
|
||
return nil, fmt.Errorf("neinfo hostId not found")
|
||
}
|
||
hostIds := strings.Split(neInfo.HostIDs, ",")
|
||
if len(hostIds) <= 2 {
|
||
logger.Errorf("NeRunRedisClient hosts id %s not found", neInfo.HostIDs)
|
||
return nil, fmt.Errorf("neinfo host id not found")
|
||
}
|
||
hostId := parse.Number(hostIds[2])
|
||
neHost := r.neHostService.FindById(hostId)
|
||
if neHost.ID == 0 || neHost.ID != hostId {
|
||
logger.Errorf("NeRunRedisClient Hosts %s not found", neInfo.HostIDs)
|
||
return nil, fmt.Errorf("neinfo host not found")
|
||
}
|
||
|
||
// 创建链接Redis客户端
|
||
var connRedis redis.ConnRedis
|
||
neHost.CopyTo(&connRedis)
|
||
redisClient, err := connRedis.NewClient()
|
||
if err != nil {
|
||
logger.Errorf("NeRunRedisClient NewClient err => %s", err.Error())
|
||
return nil, fmt.Errorf("neinfo redis client new err")
|
||
}
|
||
return redisClient, nil
|
||
}
|
||
|
||
// NeConfOAMReadSync 网元OAM配置文件读取
|
||
func (r NeInfo) NeConfOAMReadSync(neType, neId string) (map[string]any, error) {
|
||
oamData, err := r.neConfOAMRead(neType, neId, true)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
// UPF和SMF 全小写的key
|
||
// 网元HTTP服务
|
||
if v, ok := oamData["httpmanagecfg"]; ok && v != nil {
|
||
item := v.(map[string]any)
|
||
if v, ok := item["iptype"]; ok && v != nil {
|
||
item["ipType"] = v
|
||
delete(item, "iptype")
|
||
}
|
||
oamData["httpManageCfg"] = item
|
||
delete(oamData, "httpmanagecfg")
|
||
r.neConfOAMWirte(neType, neId, oamData, false)
|
||
}
|
||
// 对网管HTTP配置
|
||
if v, ok := oamData["oamconfig"]; ok && v != nil {
|
||
item := v.(map[string]any)
|
||
if v, ok := item["iptype"]; ok && v != nil {
|
||
item["ipType"] = v
|
||
delete(item, "iptype")
|
||
}
|
||
if v, ok := item["neconfig"]; ok && v != nil {
|
||
item["neConfig"] = v
|
||
delete(item, "neconfig")
|
||
}
|
||
oamData["oamConfig"] = item
|
||
delete(oamData, "oamconfig")
|
||
r.neConfOAMWirte(neType, neId, oamData, false)
|
||
}
|
||
// 对网管SNMP配置
|
||
if v, ok := oamData["snmpconfig"]; ok && v != nil {
|
||
item := v.(map[string]any)
|
||
if v, ok := item["iptype"]; ok && v != nil {
|
||
item["ipType"] = v
|
||
delete(item, "iptype")
|
||
}
|
||
oamData["snmpConfig"] = item
|
||
delete(oamData, "snmpconfig")
|
||
r.neConfOAMWirte(neType, neId, oamData, false)
|
||
}
|
||
// 对网管KPI上报配置
|
||
if v, ok := oamData["kpiconfig"]; ok && v != nil {
|
||
item := v.(map[string]any)
|
||
oamData["kpiConfig"] = item
|
||
delete(oamData, "kpiconfig")
|
||
r.neConfOAMWirte(neType, neId, oamData, false)
|
||
}
|
||
|
||
// NSSF和MME 配置KPIconfig名不一致时
|
||
if v, ok := oamData["KPIconfig"]; ok && v != nil {
|
||
item := v.(map[string]any)
|
||
oamData["kpiConfig"] = item
|
||
delete(oamData, "KPIconfig")
|
||
r.neConfOAMWirte(neType, neId, oamData, false)
|
||
}
|
||
|
||
return oamData, nil
|
||
}
|
||
|
||
// neConfOAMData 网元OAM配置文件默认格式数据
|
||
func (r NeInfo) neConfOAMData() map[string]any {
|
||
return map[string]any{
|
||
"httpManageCfg": map[string]any{
|
||
"ipType": "ipv4",
|
||
"ipv4": "172.16.5.1", // 必改
|
||
"ipv6": "",
|
||
"port": 33030,
|
||
"scheme": "http",
|
||
},
|
||
"oamConfig": map[string]any{
|
||
"enable": true,
|
||
"ipType": "ipv4",
|
||
"ipv4": "172.16.5.100", // 必改
|
||
"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.16.5.1", // 必改
|
||
"ipv6": "",
|
||
"port": 4957,
|
||
},
|
||
"kpiConfig": map[string]any{
|
||
"enable": true,
|
||
"timer": 60, // 必改
|
||
},
|
||
// "pubConfigPath": "/usr/local/etc/conf/para5G.yaml", // 网元只会读一次后续会置空,建议不放
|
||
}
|
||
}
|
||
|
||
// neConfOAMRead 网元OAM配置文件读取 sync从网元端同步到本地
|
||
func (r NeInfo) neConfOAMRead(neType, neId string, sync bool) (map[string]any, error) {
|
||
neTypeLower := strings.ToLower(neType)
|
||
fileName := "oam_manager.yaml"
|
||
// 网管本地路径
|
||
localFilePath := fmt.Sprintf("/usr/local/omc/backup/ne_config/%s/%s/%s", neTypeLower, neId, fileName)
|
||
if runtime.GOOS == "windows" {
|
||
localFilePath = fmt.Sprintf("C:%s", localFilePath)
|
||
}
|
||
|
||
// 从网元端同步到本地
|
||
if sync {
|
||
// 网元主机的SSH客户端
|
||
sshClient, err := r.NeRunSSHClient(neType, neId)
|
||
if err != nil {
|
||
return nil, fmt.Errorf("ne info ssh client err")
|
||
}
|
||
defer sshClient.Close()
|
||
// 网元主机的SSH客户端进行文件传输
|
||
sftpClient, err := sshClient.NewClientSFTP()
|
||
if err != nil {
|
||
return nil, fmt.Errorf("ne info sftp client err")
|
||
}
|
||
defer sftpClient.Close()
|
||
// 网元端文件路径
|
||
neFilePath := fmt.Sprintf("/usr/local/etc/%s/%s", neTypeLower, fileName)
|
||
// 修改网元文件权限
|
||
sshClient.RunCMD(fmt.Sprintf("sudo touch %s && sudo chmod o+rw %s", neFilePath, neFilePath))
|
||
// 网元端复制到本地
|
||
if err = sftpClient.CopyFileRemoteToLocal(neFilePath, localFilePath); err != nil {
|
||
return nil, fmt.Errorf("copy oam config err")
|
||
}
|
||
}
|
||
|
||
// 读取文件内容
|
||
bytes, err := os.ReadFile(localFilePath)
|
||
if err != nil || len(bytes) == 0 {
|
||
// 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 NeInfo) neConfOAMWirte(neType, neId string, content any, sync bool) error {
|
||
neTypeLower := strings.ToLower(neType)
|
||
fileName := "oam_manager.yaml"
|
||
// 网管本地路径
|
||
omcPath := "/usr/local/omc/backup/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 {
|
||
// 网元主机的SSH客户端
|
||
sshClient, err := r.NeRunSSHClient(neType, neId)
|
||
if err != nil {
|
||
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+rw %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
|
||
}
|
||
|
||
// NeConfOAMWirteSync 网元OAM配置文件生成并同步
|
||
func (r NeInfo) NeConfOAMWirteSync(neInfo model.NeInfo, content map[string]any, sync bool) error {
|
||
oamData, err := r.neConfOAMRead(neInfo.NeType, neInfo.NeId, false)
|
||
if oamData == nil || err != nil {
|
||
return fmt.Errorf("error read OAM file info")
|
||
}
|
||
// 网元HTTP服务
|
||
httpManageCfg, ok := oamData["httpManageCfg"].(map[string]any)
|
||
if !ok {
|
||
neConfOAMData := r.neConfOAMData()
|
||
httpManageCfg = neConfOAMData["httpManageCfg"].(map[string]any)
|
||
}
|
||
httpManageCfg["port"] = neInfo.Port
|
||
if strings.Contains(neInfo.IP, ":") {
|
||
httpManageCfg["ipType"] = "ipv6"
|
||
httpManageCfg["ipv6"] = neInfo.IP
|
||
}
|
||
if strings.Contains(neInfo.IP, ".") {
|
||
httpManageCfg["ipType"] = "ipv4"
|
||
httpManageCfg["ipv4"] = neInfo.IP
|
||
}
|
||
delete(httpManageCfg, "iptype")
|
||
delete(oamData, "httpmanagecfg")
|
||
oamData["httpManageCfg"] = httpManageCfg
|
||
|
||
// 对网管HTTP配置
|
||
oamConfig, ok := oamData["oamConfig"].(map[string]any)
|
||
if !ok {
|
||
neConfOAMData := r.neConfOAMData()
|
||
oamConfig = neConfOAMData["oamConfig"].(map[string]any)
|
||
}
|
||
delete(oamConfig, "neconfig")
|
||
oamConfig["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,
|
||
}
|
||
// 公共参数指定的OMC
|
||
if omcIP, ok := r.Para5GData["OMC_IP"]; ok && omcIP != "" {
|
||
if strings.Contains(omcIP, ":") {
|
||
oamConfig["ipType"] = "ipv6"
|
||
oamConfig["ipv6"] = omcIP
|
||
}
|
||
if strings.Contains(omcIP, ".") {
|
||
oamConfig["ipType"] = "ipv4"
|
||
oamConfig["ipv4"] = omcIP
|
||
}
|
||
}
|
||
// 传入的变更
|
||
if v, ok := content["omcIP"]; ok && v != "" && v != nil {
|
||
omcIP := v.(string)
|
||
if strings.Contains(omcIP, ":") {
|
||
oamConfig["ipType"] = "ipv6"
|
||
oamConfig["ipv6"] = omcIP
|
||
}
|
||
if strings.Contains(omcIP, ".") {
|
||
oamConfig["ipType"] = "ipv4"
|
||
oamConfig["ipv4"] = omcIP
|
||
}
|
||
}
|
||
delete(oamConfig, "iptype")
|
||
if oamEnable, ok := content["oamEnable"]; ok && oamEnable != nil {
|
||
oamConfig["enable"] = parse.Boolean(oamEnable)
|
||
}
|
||
if oamPort, ok := content["oamPort"]; ok && oamPort != nil {
|
||
oamConfig["port"] = parse.Number(oamPort)
|
||
}
|
||
delete(oamData, "oamconfig")
|
||
oamData["oamConfig"] = oamConfig
|
||
|
||
// 对网管SNMP配置
|
||
snmpConfig, ok := oamData["snmpConfig"].(map[string]any)
|
||
if !ok {
|
||
neConfOAMData := r.neConfOAMData()
|
||
snmpConfig = neConfOAMData["snmpConfig"].(map[string]any)
|
||
}
|
||
if strings.Contains(neInfo.IP, ":") {
|
||
snmpConfig["ipType"] = "ipv6"
|
||
snmpConfig["ipv6"] = neInfo.IP
|
||
}
|
||
if strings.Contains(neInfo.IP, ".") {
|
||
snmpConfig["ipType"] = "ipv4"
|
||
snmpConfig["ipv4"] = neInfo.IP
|
||
}
|
||
delete(snmpConfig, "iptype")
|
||
if snmpEnable, ok := content["snmpEnable"]; ok && snmpEnable != nil {
|
||
snmpConfig["enable"] = parse.Boolean(snmpEnable)
|
||
}
|
||
if snmpPort, ok := content["snmpPort"]; ok && snmpPort != nil {
|
||
snmpConfig["port"] = parse.Number(snmpPort)
|
||
}
|
||
delete(oamData, "snmpconfig")
|
||
oamData["snmpConfig"] = snmpConfig
|
||
|
||
// 对网管KPI上报配置
|
||
kpiConfig, ok := oamData["kpiConfig"].(map[string]any)
|
||
if !ok {
|
||
neConfOAMData := r.neConfOAMData()
|
||
kpiConfig = neConfOAMData["kpiConfig"].(map[string]any)
|
||
}
|
||
if neInfo.NeType == "UPF" {
|
||
kpiConfig["timer"] = 5
|
||
} else {
|
||
kpiConfig["timer"] = 60
|
||
}
|
||
if kpiEnable, ok := content["kpiEnable"]; ok && kpiEnable != nil {
|
||
kpiConfig["enable"] = parse.Boolean(kpiEnable)
|
||
}
|
||
if kpiTimer, ok := content["kpiTimer"]; ok && kpiTimer != nil {
|
||
kpiConfig["timer"] = parse.Number(kpiTimer)
|
||
}
|
||
delete(oamData, "kpiconfig")
|
||
oamData["kpiConfig"] = kpiConfig
|
||
|
||
if err := r.neConfOAMWirte(neInfo.NeType, neInfo.NeId, oamData, sync); err != nil {
|
||
return fmt.Errorf("error wirte OAM file info")
|
||
}
|
||
return nil
|
||
}
|
||
|
||
// NeConfPara5GRead 网元公共配置文件读取
|
||
func (r NeInfo) 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 *NeInfo) 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("%s", strings.Join(errMsg, "\r\n"))
|
||
}
|
||
}
|
||
|
||
// 转换一份数据到全局
|
||
r.Para5GData = r.neConfPara5GDataConvert(content)
|
||
return nil
|
||
}
|
||
|
||
// NeConfPara5GConvert 网元公共配置数据转化 content网元公共配置文件读取内容
|
||
func (r NeInfo) neConfPara5GDataConvert(content map[string]any) map[string]string {
|
||
defer func() {
|
||
if err := recover(); err != nil {
|
||
logger.Errorf("NeConfPara5GDataConvert panic: %v", err)
|
||
// 文件异常就删除配置
|
||
omcFilePath := "/usr/local/etc/omc/para5G.yaml"
|
||
if runtime.GOOS == "windows" {
|
||
omcFilePath = fmt.Sprintf("C:%s", omcFilePath)
|
||
}
|
||
os.Remove(omcFilePath)
|
||
}
|
||
}()
|
||
|
||
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.SplitN(n3IPAmdMask, "/", 2)
|
||
n3IP := n3Arr[0]
|
||
n3Mask := "255.255.255.0"
|
||
if len(n3Arr) > 1 {
|
||
n3Mask = parse.ConvertIPMask(parse.Number(n3Arr[1]))
|
||
}
|
||
|
||
n6IPAmdMask := external["upfn6_ip"].(string)
|
||
n6Arr := strings.SplitN(n6IPAmdMask, "/", 2)
|
||
n6IP := n6Arr[0]
|
||
n6Mask := "255.255.255.0"
|
||
if len(n6Arr) > 1 {
|
||
n6Mask = parse.ConvertIPMask(parse.Number(n6Arr[1]))
|
||
}
|
||
|
||
ueIPAmdMask := external["ue_pool"].(string)
|
||
ueArr := strings.SplitN(ueIPAmdMask, "/", 2)
|
||
ueIP := ueArr[0]
|
||
ueCicr := "24"
|
||
ueMask := "255.255.255.0"
|
||
if len(ueArr) > 1 {
|
||
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
|
||
"UPF_DRIVER_TYPE": external["upf_driver_type"].(string), // 网卡驱动 vmxnet3 host dpdk
|
||
"N3_IP": n3IP,
|
||
"N3_MASK": n3Mask,
|
||
"N3_GW": external["upfn3_gw"].(string),
|
||
"N3_PCI": external["upfn3_pci"].(string),
|
||
"N3_MAC": external["upfn3_mac"].(string),
|
||
"N3_NIC_NAME": external["upfn3_card_name"].(string), // 网卡名 eth0
|
||
"N6_IP": n6IP,
|
||
"N6_MASK": n6Mask,
|
||
"N6_GW": external["upfn6_gw"].(string),
|
||
"N6_PCI": external["upfn6_pci"].(string),
|
||
"N6_MAC": external["upfn6_mac"].(string),
|
||
"N6_NIC_NAME": external["upfn6_card_name"].(string), // 网卡名 eth0
|
||
|
||
"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),
|
||
"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),
|
||
"SMSC_IP": sbi["smsc_ip"].(string),
|
||
|
||
"DB_IP": sbi["db_ip"].(string),
|
||
}
|
||
}
|