Files
be.ems/src/modules/network_element/service/ne_info.go

1125 lines
33 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package service
import (
"encoding/json"
"fmt"
"os"
"path/filepath"
"runtime"
"strings"
"be.ems/src/framework/constants"
"be.ems/src/framework/constants/cachekey"
"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,
Para5GData: map[string]string{},
}
// 网元信息 服务层处理
type NeInfo struct {
neInfoRepository *repository.NeInfo // 网元信息数据信息
Para5GData map[string]string
}
// SelectNeInfoByNeTypeAndNeID 通过ne_type和ne_id查询网元信息
func (r *NeInfo) SelectNeInfoByNeTypeAndNeID(neType, neID string) model.NeInfo {
var neInfo model.NeInfo
key := fmt.Sprintf("%s%s:%s", cachekey.NE_KEY, 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 != "" && neInfo.NeId == neID {
redis.Del("", key)
values, _ := json.Marshal(neInfo)
redis.Set("", key, string(values))
}
}
return neInfo
}
// 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 != "" && neInfo.NeId == neID {
redis.Del("", key)
values, _ := json.Marshal(neInfo)
redis.Set("", key, string(values))
}
}
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", cachekey.NE_KEY, strings.ToUpper(neType), neID)
redis.Del("", key)
neInfo = r.neInfoRepository.SelectNeInfoByNeTypeAndNeID(neType, neID)
if neInfo.ID != "" && neInfo.NeId == neID {
values, _ := json.Marshal(neInfo)
redis.Set("", key, string(values))
}
return neInfo
}
// ClearNeCacheByNeType 清除网元类型缓存
func (r *NeInfo) ClearNeCacheByNeType(neType string) bool {
key := fmt.Sprintf("%s*", cachekey.NE_KEY)
if neType != "*" {
key = fmt.Sprintf("%s%s*", cachekey.NE_KEY, neType)
}
keys, err := redis.GetKeys("", key)
if err != nil {
return false
}
err = redis.DelKeys("", keys)
return err == nil
}
// SelectNeInfoByNeType 通过ne_type查询网元信息
func (r *NeInfo) SelectNeInfoByNeType(neType string) []model.NeInfo {
neInfo := make([]model.NeInfo, 0)
key := fmt.Sprintf("%s%s:*", cachekey.NE_KEY, 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", cachekey.NE_KEY, strings.ToUpper(v.NeType), v.NeId)
redis.Del("", key)
values, _ := json.Marshal(v)
redis.Set("", key, string(values))
}
}
return neInfo
}
// FindByNeType 通过ne_type查询网元信息
func (r NeInfo) FindByNeType(neType string) []model.NeInfo {
neInfo := make([]model.NeInfo, 0)
key := fmt.Sprintf("%s%s:*", cachekey.NE_KEY, 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", cachekey.NE_KEY, strings.ToUpper(v.NeType), v.NeId)
redis.Del("", key)
values, _ := json.Marshal(v)
redis.Set("", key, string(values))
}
}
return neInfo
}
// SelectNeInfoByRmuid 通过rmUID查询网元信息
func (r *NeInfo) SelectNeInfoByRmuid(rmUid string) model.NeInfo {
var neInfo model.NeInfo
cacheKeys, _ := redis.GetKeys("", cachekey.NE_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)
}
if v.RmUID == rmUid {
neInfo = v
break
}
}
} else {
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)
values, _ := json.Marshal(v)
redis.Set("", key, string(values))
if v.RmUID == rmUid {
neInfo = v
}
}
}
return neInfo
}
// FindByRmuid 通过rmUID查询网元信息
func (r *NeInfo) FindByRmuid(rmUid string) model.NeInfo {
var neInfo model.NeInfo
cacheKeys, _ := redis.GetKeys("", cachekey.NE_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)
}
if v.RmUID == rmUid {
neInfo = v
break
}
}
} else {
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)
values, _ := json.Marshal(v)
redis.Set("", key, string(values))
if v.RmUID == rmUid {
neInfo = v
}
}
}
return neInfo
}
// SelectPage 根据条件分页查询
//
// bandStatus 带状态信息
func (r *NeInfo) SelectPage(query map[string]string, bandStatus bool) ([]model.NeInfo, int64) {
rows, total := r.neInfoRepository.SelectByPage(query)
// 网元直连读取网元服务状态
if bandStatus {
r.bandNeStatus(&rows)
}
return rows, total
}
// SelectList 查询列表
//
// bandStatus 带状态信息
// bandHost 带主机信息
func (r *NeInfo) SelectList(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
}
// 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
// 网元状态设置为在线
status := "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 _, hostId := range hostIds {
neHost := NewNeHost.SelectById(hostId)
if neHost.HostID == "" || neHost.HostID != hostId {
continue
}
(*arr)[i].Hosts = append((*arr)[i].Hosts, neHost)
}
}
}
}
// SelectByIds 通过ID查询
//
// bandHost 带主机信息
func (r *NeInfo) SelectById(infoId string, bandHost bool) model.NeInfo {
if infoId == "" {
return model.NeInfo{}
}
neInfos := r.neInfoRepository.SelectByIds([]string{infoId})
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) string {
if neInfo.Schema == "" {
neInfo.Schema = "http"
}
if neInfo.NeVersion == "" {
neInfo.NeVersion = "2"
}
// 主机信息新增
if neInfo.Hosts != nil {
var hostIDs []string
for _, host := range neInfo.Hosts {
uuid := generate.Code(4)
host.Title = fmt.Sprintf("%s_%d_%s", neInfo.NeName, host.Port, uuid)
host.GroupID = "1"
host.CreateBy = neInfo.CreateBy
hostId := NewNeHost.Insert(host)
if hostId != "" {
hostIDs = append(hostIDs, hostId)
}
}
neInfo.HostIDs = strings.Join(hostIDs, ",")
}
insertId := r.neInfoRepository.Insert(neInfo)
if insertId != "" {
// 刷新缓存
r.RefreshByNeTypeAndNeID(neInfo.NeType, neInfo.NeId)
}
return insertId
}
// Update 修改信息
func (r *NeInfo) Update(neInfo model.NeInfo) int64 {
// 主机信息更新
if neInfo.Hosts != nil {
for _, host := range neInfo.Hosts {
if host.HostID != "" {
uuid := generate.Code(4)
host.Title = fmt.Sprintf("%s_%d_%s", neInfo.NeName, host.Port, uuid)
host.GroupID = "1"
host.UpdateBy = neInfo.UpdateBy
NewNeHost.Update(host)
}
}
}
num := r.neInfoRepository.Update(neInfo)
if num > 0 {
// 刷新缓存
r.RefreshByNeTypeAndNeID(neInfo.NeType, neInfo.NeId)
}
return num
}
// DeleteByIds 批量删除信息
func (r *NeInfo) DeleteByIds(infoIds []string) (int64, error) {
// 检查是否存在
infos := r.neInfoRepository.SelectByIds(infoIds)
if len(infos) <= 0 {
return 0, fmt.Errorf("neHostCmd.noData")
}
if len(infos) == len(infoIds) {
for _, v := range infos {
// 主机信息删除
if v.HostIDs != "" {
NewNeHost.DeleteByIds(strings.Split(v.HostIDs, ","))
}
// 删除License
neLicense := NewNeLicense.SelectByNeTypeAndNeID(v.NeType, v.NeId)
if neLicense.NeId == v.NeId {
NewNeLicense.DeleteByIds([]string{neLicense.ID})
}
// 删除Version
neVersion := NewNeVersion.SelectByNeTypeAndNeID(v.NeType, v.NeId)
if neVersion.NeId == v.NeId {
NewNeVersion.DeleteByIds([]string{neVersion.ID})
}
// 缓存信息删除
redis.Del("", fmt.Sprintf("%s%s:%s", cachekey.NE_KEY, v.NeType, v.NeId))
}
rows := r.neInfoRepository.DeleteByIds(infoIds)
return rows, nil
}
// 删除信息失败!
return 0, fmt.Errorf("delete fail")
}
// CheckUniqueNeTypeAndNeId 校验同类型下标识是否唯一
func (r *NeInfo) CheckUniqueNeTypeAndNeId(neType, neId, id string) bool {
uniqueId := r.neInfoRepository.CheckUniqueNeTypeAndNeId(model.NeInfo{
NeType: neType,
NeId: neId,
})
if uniqueId == id {
return true
}
return uniqueId == ""
}
// NeRunSSHClient 网元主机的SSH客户端-为创建相关连接,注意结束后 Close()
func (r *NeInfo) NeRunSSHClient(neType, neId string) (*ssh.ConnSSH, error) {
neInfo := r.SelectNeInfoByNeTypeAndNeID(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 := hostIds[0] // 网元主机ssh 022
neHost := NewNeHost.SelectById(hostId)
if neHost.HostID == "" || neHost.HostID != 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 14100 25200UPF标准版
func (r *NeInfo) NeRunTelnetClient(neType, neId string, num int) (*telnet.ConnTelnet, error) {
neInfo := r.SelectNeInfoByNeTypeAndNeID(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 := hostIds[num] // 网元主机telnet 14100 25200
neHost := NewNeHost.SelectById(hostId)
if neHost.HostID == "" || neHost.HostID != 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配置项
// num 是redis 2master 3slave
func (r *NeInfo) NeRunRedisClient(neType, neId string, num int) (*redis.ConnRedis, error) {
neInfo := r.SelectNeInfoByNeTypeAndNeID(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 %d", neInfo.HostIDs, num)
return nil, fmt.Errorf("neinfo host id not found")
}
if len(hostIds) == 3 && num == 3 {
logger.Errorf("NeRunRedisClient hosts id %s not found %d", neInfo.HostIDs, num)
return nil, fmt.Errorf("neinfo host id not found")
}
hostId := hostIds[num]
neHost := NewNeHost.SelectById(hostId)
if neHost.HostID == "" || neHost.HostID != 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),
}
}