Merge branch 'main-v2' into lite-ba

This commit is contained in:
TsMask
2025-10-20 18:11:52 +08:00
29 changed files with 1021 additions and 412 deletions

2
.gitignore vendored
View File

@@ -23,5 +23,5 @@ debug/
main
# Build Output
local/*.sqlite
local/*.sqlite*
omc

View File

@@ -1,5 +1,19 @@
# 版本发布日志
## 2.2510.3-20251018
- 优化 忽略本地调试所有sqlite文件
- 新增 添加退出信号监听功能,优雅关闭服务并输出相关信息
- 修复 sqlite模式改为wal支持并发写入临时日志
- 修复 修正删除文件路径构建方式使用filepath.Join确保路径正确
- 优化 移除token过期日志信息输出
- 新增 网元参数配置数据支持版本区分功能,适应mme版本配置
- 新增 使用systemctl脚本操作OMC自身
- 修复 自检告警附加信息错误最佳和触发消除操作
- 修复 数据列表搜索条件排序问题
- 修复 设置分布式锁超时1分钟解除,避免死锁
- 新增 备份网元Log文件到网管支持ftp转存
## 2.2510.2-20251011
- 新增 导出udm-auth未加密数据

File diff suppressed because one or more lines are too long

View File

@@ -8,6 +8,8 @@ CREATE TABLE "ne_info" (
"ne_id" text(32) NOT NULL,
"rm_uid" text(40),
"ne_name" text(64),
"ne_version" text(12),
"schema" text(12),
"ip" text(128),
"port" integer,
"pv_flag" text(32),

View File

@@ -0,0 +1,46 @@
-- ----------------------------
-- Table structure for ne_info
-- ----------------------------
DROP TABLE IF EXISTS "ne_info";
CREATE TABLE "ne_info" (
"id" integer NOT NULL,
"ne_type" text(32) NOT NULL,
"ne_id" text(32) NOT NULL,
"rm_uid" text(40),
"ne_name" text(64),
"ne_version" text(12),
"schema" text(12),
"ip" text(128),
"port" integer(11),
"pv_flag" text(32),
"province" text(32),
"vendor_name" text(64),
"dn" text(255),
"ne_address" text(64),
"host_ids" text(64),
"status" integer(11),
"remark" text(255),
"create_by" text(50),
"create_time" integer(20),
"update_by" text(50),
"update_time" integer(20),
PRIMARY KEY ("id")
);
-- ----------------------------
-- Indexes structure for table ne_info
-- ----------------------------
CREATE UNIQUE INDEX "ux_netype_neid"
ON "ne_info" (
"ne_type" ASC,
"ne_id" ASC
);
-- ADD COLUMN
ALTER TABLE "ne_info" ADD COLUMN "ne_version" text(12);
ALTER TABLE "ne_info" ADD COLUMN "schema" text(12);
-- ----------------------------
-- Records of ne_info
-- ----------------------------
UPDATE "ne_info" SET "ne_version" = '2', "schema" = 'http' WHERE "ne_version" IS NULL OR "schema" IS NULL;

File diff suppressed because one or more lines are too long

View File

@@ -11,6 +11,8 @@ CREATE TABLE `ne_info` (
`ne_id` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '网元ID',
`rm_uid` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '网元资源唯一标识',
`ne_name` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '网元名称',
`ne_version` varchar(12) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '2' COMMENT '网元版本',
`schema` varchar(12) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT 'http' COMMENT '网元模式 http/https',
`ip` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '网元服务IP',
`port` int DEFAULT '0' COMMENT '端口',
`pv_flag` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT 'PNF' COMMENT '网元虚拟化标识 物理PNF 虚拟VNF',

View File

@@ -10,6 +10,8 @@ CREATE TABLE IF NOT EXISTS `ne_info` (
`ne_id` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '网元ID',
`rm_uid` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '网元资源唯一标识',
`ne_name` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '网元名称',
`ne_version` varchar(12) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '2' COMMENT '网元版本',
`schema` varchar(12) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT 'http' COMMENT '网元模式 http/https',
`ip` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '网元服务IP',
`port` int DEFAULT '0' COMMENT '端口',
`pv_flag` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT 'PNF' COMMENT '网元虚拟化标识 物理PNF 虚拟VNF',
@@ -43,13 +45,15 @@ ALTER TABLE `ne_info` MODIFY COLUMN `vendor_name` varchar(64) CHARACTER SET utf8
ALTER TABLE `ne_info` MODIFY COLUMN `dn` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '-' COMMENT '网络标识' AFTER `vendor_name`;
ALTER TABLE `ne_info` MODIFY COLUMN `host_ids` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '网元主机ID组 数据格式(ssh,telnet) UDM(ssh,telnet,redis) UPF(ssh,telnet,telnet)' AFTER `ne_address`;
ALTER TABLE `ne_info` MODIFY COLUMN `status` int(11) NULL DEFAULT 0 COMMENT '网元状态 0离线 1在线 2配置待下发 3备用模式' AFTER `host_ids`;
ALTER TABLE `ne_info` ADD COLUMN `ne_version` varchar(32) NULL DEFAULT '2' COMMENT '网元版本' AFTER `ne_name`;
ALTER TABLE `ne_info` ADD COLUMN `schema` varchar(12) NULL DEFAULT 'http' COMMENT '网元模式 http/https' AFTER `ne_version`;
ALTER TABLE `ne_info` COMMENT = '网元_基础信息表 关联对应版本、授权、主机';
ALTER TABLE `ne_info` MODIFY COLUMN `id` bigint(20) NOT NULL AUTO_INCREMENT;
-- ----------------------------
-- Data for ne_info
-- ----------------------------
INSERT IGNORE INTO `ne_info` VALUES (1, 'OMC', '001', '4400HXOMC001', 'OMC_001', '127.0.0.1', 33030, 'PNF', 'AreaNet', '-', '-', '-', '1,2', 0, '', 'system', 1713928436971, '', 0);
UPDATE `ne_info` SET `ne_version` = '2', `schema` = 'http' WHERE `ne_version` IS NULL OR `schema` IS NULL;
SET FOREIGN_KEY_CHECKS=1;

View File

@@ -0,0 +1,379 @@
mme:
system:
display: "System Config"
sort: 1
list:
- name: "mmeName"
type: "string"
value: "MME1"
filter: "0~32"
display: "MME Name"
- name: "networkName.full"
type: "string"
value: "EPC"
filter: "0~64"
display: "Full Network Name"
- name: "networkName.short"
type: "string"
value: "Next"
filter: "0~16"
display: "Short Network Name"
- name: "s1.mtu"
type: "int"
value: "1500"
access: "read-write"
filter: "576~9000"
display: "MTU"
comment: "Maximum Transmission Unit"
- name: "s1.address"
type: "string"
value: "192.168.8.220"
access: "read-write"
filter: "IP"
display: "S1 Local Address"
comment: "Local IP for S1 interface"
- name: "s6a.local.address"
type: "string"
value: "172.16.5.220"
access: "read-write"
filter: "IP"
display: "Local S6a IP"
comment: "Local IP for Diameter S6a"
- name: "s6a.local.host"
type: "string"
value: "mme.epc.mnc001.mcc001.3gppnetwork.org"
access: "read-write"
filter: "0~128"
display: "Local Hostname"
comment: "MME Diameter Host FQDN"
- name: "s6a.local.realm"
type: "string"
value: "epc.mnc001.mcc001.3gppnetwork.org"
access: "read-write"
filter: "0~128"
display: "Local Realm"
comment: "Diameter Realm"
- name: "s11.local.address"
type: "string"
value: "172.16.5.220"
access: "read-write"
filter: "IP"
display: "Local S11 IP"
- name: "n26.local.address"
type: "string"
value: "172.16.5.210"
access: "read-write"
filter: "IP"
display: "Local N26 IP"
- name: "t3402.value"
type: "string"
value: "12m"
filter: "1s~60m"
display: "T3402 Timer"
- name: "t3412.value"
type: "string"
value: "54m"
display: "T3412 Timer"
- name: "t3423.value"
type: "string"
value: "12m"
display: "T3423 Timer"
- name: "message.gtp.t3ResponseDuration"
type: "string"
value: "2s"
display: "GTP Response Timeout"
- name: "message.gtp.n3ResponseRcount"
type: "int"
value: "3"
display: "GTP Response Retries"
- name: "message.gtp.t3HoldingDuration"
type: "string"
value: "6s"
display: "GTP Holding Duration"
- name: "message.gtp.n3HoldingRcount"
type: "int"
value: "1"
display: "GTP Holding Retries"
- name: "message.s6a"
type: "string"
value: "3s"
display: "S6a Timeout"
- name: "handover.value"
type: "string"
value: "300ms"
display: "Handover Timeout"
- name: "s1Flex.instance"
type: "int"
value: "0"
access: "read-write"
filter: "0~2"
display: "mme instance id for s1 flex"
comment: "mme instance id for s1 flex"
- name: "redisDb.enable"
type: "bool"
value: "false"
access: "read-write"
filter: '{"0":"false","1":"true"}'
display: "Enable Redis"
comment: "true|false"
- name: "redisDb.netType"
type: "string"
value: "tcp"
access: "read-write"
filter: '{"tcp":"tcp"}'
display: "Network Type"
comment: "Network type for Redis (tcp)"
- name: "redisDb.addr"
type: "string"
value: "172.16.5.140:6379"
access: "read-write"
filter: "IP:Port"
display: "Redis Master Address"
comment: "IP:Port format"
- name: "redisDb.slaveAddrList"
type: "string"
value: "172.16.5.148:6379"
access: "read-write"
filter: "IP:Port"
display: "Redis Slave Addresses"
comment: "List of Redis slaves for replication"
- name: "redisDb.poolSize"
type: "int"
value: "10"
access: "read-write"
filter: "1~1000"
display: "Connection Pool Size"
comment: "Max Redis connection pool size"
- name: "relativeCapacity"
type: "int"
value: "255"
filter: "0~255"
display: "MME Relative Capacity"
comment: "Used for load balancing among MMEs"
- name: "logDir"
type: "string"
value: "/var/log/"
access: "read-write"
filter: "0~128"
display: "Log Directory"
comment: "Directory where log files will be stored"
- name: "logNum"
type: "int"
value: "10"
access: "read-write"
filter: "1~100"
display: "Log File Count"
comment: "Maximum number of log files to retain"
- name: "logSize"
type: "int"
value: "200"
access: "read-write"
filter: "1~10000"
display: "Log File Size (MB)"
comment: "Max size per log file"
- name: "logLevel"
type: "enum"
value: "debug"
access: "read-write"
filter: '{"debug":"debug","info":"info","warn":"warn","error":"error"}'
display: "Log Level"
comment: "debug|info|warn|error"
gummei:
display: "GUMMEI List"
sort: 3
array:
- name: "index"
type: "int"
value: "0"
access: "read"
filter: "0~15"
display: "Index"
comment: "0~15"
- name: "plmnId"
type: "regex"
value: "00101"
filter: "^[0-9]{5,6}$"
display: "PLMN ID"
- name: "mmeGid"
type: "int"
value: "2"
filter: "0~65535"
display: "MME Group ID"
- name: "mmeCode"
type: "int"
value: "1"
filter: "0~255"
display: "MME Code"
servedTai:
display: "TAI List"
sort: 4
array:
- name: "index"
type: "int"
value: "0"
access: "read"
filter: "0~15"
display: "Index"
comment: "0~15"
- name: "plmnId"
type: "regex"
value: "00101"
filter: "^[0-9]{5,6}$"
display: "PLMN ID"
- name: "tac"
type: "int"
value: "1"
filter: "0~65535"
display: "TAC"
s6a:
display: "HSS List"
sort: 5
array:
- name: "index"
type: "int"
value: "0"
access: "read"
filter: "0~15"
display: "Index"
comment: "0~15"
- name: "address"
type: "string"
value: "172.16.5.221"
filter: "IP"
display: "HSS Address"
- name: "priority"
type: "int"
value: "1"
filter: "1~10"
display: "Priority"
- name: "plmnId"
type: "string"
value: ["00101"]
filter: "^[0-9]{5,6}$"
display: "PLMN ID"
s11:
display: "SGW List"
sort: 9
array:
- name: "index"
type: "int"
value: "0"
access: "read"
filter: "0~15"
display: "Index"
comment: "0~15"
- name: "address"
type: "string"
value: "172.16.5.222"
filter: "IP"
display: "SGW Address"
- name: "priority"
type: "int"
value: "1"
filter: "1~10"
display: "Priority"
- name: "plmnId"
type: "string"
value: "00101"
filter: "^[0-9]{5,6}$"
display: "PLMN ID"
- name: "tac"
type: "int"
value: "1"
filter: "0~65535"
display: "TAC"
s5s8:
display: "PGW List"
sort: 11
array:
- name: "index"
type: "int"
value: "0"
access: "read"
filter: "0~15"
display: "Index"
comment: "0~15"
- name: "address"
type: "string"
value: "172.16.5.223"
filter: "IP"
display: "PGW Address"
- name: "priority"
type: "int"
value: "1"
filter: "1~10"
display: "Priority"
- name: "plmnId"
type: "string"
value: "00101"
filter: "^[0-9]{5,6}$"
display: "PLMN ID"
- name: "apn"
type: "string"
value: "internet"
filter: "0~128"
display: "APN"
n26:
display: "AMF List"
sort: 13
array:
- name: "index"
type: "int"
value: "0"
access: "read"
filter: "0~15"
display: "Index"
comment: "0~15"
- name: "address"
type: "string"
value: "172.16.5.224"
filter: "IP"
display: "AMF Address"
- name: "priority"
type: "int"
value: "1"
filter: "1~10"
display: "Priority"
- name: "plmnId"
type: "string"
value: "00101"
filter: "^[0-9]{5,6}$"
display: "PLMN ID"
- name: "tac"
type: "int"
value: "1"
filter: "0~65535"
display: "TAC"
enbList:
display: "Enb List Config"
sort: 19
visible: "hide"
array:
- name: "index"
type: "int"
value: "0"
access: "read-only"
filter: "0~128"
display: "Index"
comment: "0~128"
- name: "name"
type: "string"
value: ""
access: "read-write"
filter: "0~64"
display: "ENB Name"
comment: "text content length 0~64"
- name: "address"
type: "string"
value: ""
access: "read-write"
filter: "0~64"
display: "ENB Address"
comment: "text content length 0~64"
- name: "position"
type: "string"
value: ""
access: "read-write"
filter: "0~64"
display: "Position"
comment: "location description. Prohibition of spaces, length of text content 0-64"

View File

@@ -611,6 +611,13 @@ smf:
filter: ""
display: "Local IP"
comment: ""
- name: "ntfyEnable"
type: "bool"
value: "false"
access: "read-write"
filter: ""
display: "DHCP Server Ntfy Enable"
comment: ""
dnnselectdhcpserver:
display: "DNN Select DHCP Server"
sort: 23
@@ -644,7 +651,7 @@ smf:
display: "DHCP Server IP"
comment: "e.g. 192.168.1.1"
offlineChargingConfig:
display: "Offline Charging Config"
display: "Charging Config"
sort: 25
list:
- name: "cdrFileName"
@@ -682,12 +689,19 @@ smf:
filter: "0~9999"
display: "CDR File Max Age"
comment: "Days"
- name: "onlineCdrEnable"
type: "bool"
value: "false"
access: "read-write"
filter: ""
display: "Online Charging CDR Enable"
comment: ""
- name: "freeSubsCdrEnable"
type: "bool"
value: "false"
access: "read-write"
filter: ""
display: "Free Subscribers CDR Enable"
display: "Offline Charging CDR Enable"
comment: ""
- name: "timeThreshold"
type: "int"

26
main.go
View File

@@ -3,7 +3,10 @@ package main
import (
"fmt"
"net/http"
"os"
"os/signal"
"sync"
"syscall"
"time"
_ "net/http/pprof"
@@ -146,6 +149,8 @@ func main() {
src.ConfigurationInit()
app := src.AppEngine()
fmt.Printf("OMC Service %s\n\n", config.Version)
src.DefeatConfig(app)
loadGlobalPre(app)
@@ -156,11 +161,27 @@ func main() {
loadServerWeb()
stopSignal()
// 首次安装启动记录
machine.Launch()
wg.Wait()
}
// stopSignal 监听退出信号
func stopSignal() {
sigCh := make(chan os.Signal, 1)
signal.Notify(sigCh, syscall.SIGINT, syscall.SIGTERM)
wg.Add(1)
go func() {
defer wg.Done()
<-sigCh // 等待退出信号
src.ConfigurationClose()
fmt.Println("\nStop Service... OK")
os.Exit(0)
}()
}
// loadGlobalPre 全局预加载
func loadGlobalPre(app *gin.Engine) {
// Swagger 接口文档
@@ -185,6 +206,7 @@ func loadGlobalPre(app *gin.Engine) {
go func(addr string) {
defer wg.Done()
for i := range maxRetries {
fmt.Printf("pprof HTTP on %s\n", addr)
if err := http.ListenAndServe(addr, nil); err != nil {
logger.Errorf("pprof run err:%v", err)
time.Sleep(retryInterval) // 重试间隔时间
@@ -220,6 +242,7 @@ func loadServerRoute(app *gin.Engine) {
go func(addr string, certFile string, keyFile string) {
defer wg.Done()
for i := range maxRetries {
fmt.Printf("API HTTPS on %s\n", addr)
if err := app.RunTLS(addr, certFile, keyFile); err != nil {
logger.Errorf("routeServer run tls err:%v", err)
time.Sleep(retryInterval) // 重试间隔时间
@@ -233,6 +256,7 @@ func loadServerRoute(app *gin.Engine) {
go func(addr string) {
defer wg.Done()
for i := range maxRetries {
fmt.Printf("API HTTP on %s\n", addr)
if err := app.Run(addr); err != nil {
logger.Errorf("routeServer run err:%v", err)
time.Sleep(retryInterval) // 重试间隔时间
@@ -286,6 +310,7 @@ func loadServerWeb() {
go func(addr string, certFile string, keyFile string) {
defer wg.Done()
for i := range maxRetries {
fmt.Printf("WEB HTTPS on %s\n", addr)
if err := web.RunTLS(addr, certFile, keyFile); err != nil {
logger.Errorf("webServer run tls err:%v", err)
time.Sleep(retryInterval) // 重试间隔时间
@@ -302,6 +327,7 @@ func loadServerWeb() {
go func(addr string) {
defer wg.Done()
for i := range maxRetries {
fmt.Printf("WEB HTTP on %s\n", addr)
if err := web.Run(addr); err != nil {
logger.Errorf("webServer run err:%v", err)
time.Sleep(retryInterval) // 重试间隔时间

View File

@@ -5,6 +5,7 @@ import (
"log"
"os"
"regexp"
"strings"
"time"
"github.com/glebarez/sqlite"
@@ -36,7 +37,15 @@ func loadDialect() map[string]dialectInfo {
// 数据库类型对应的数据库连接
switch item["type"] {
case "sqlite":
dsn := fmt.Sprint(item["database"])
pragmas := []string{
"cache=shared", // Enable shared cache
"_pragma=journal_mode(WAL)", // Enable WAL mode
"_pragma=busy_timeout(5000)", // Set busy timeout 抛出 SQLITE_BUSY 错误 默认0立即设置等待 5 秒5000 毫秒)
"_pragma=synchronous(NORMAL)", // Set synchronous mode
"_pragma=wal_autocheckpoint(5000)", // Set WAL auto-checkpoint threshold 设置较大的自动检查点阈值
"_pragma=mmap_size(67108864)", // Set mmap size 内存映射 I/O 最大字节数为 64MB
}
dsn := fmt.Sprintf("%s?%s", item["database"], strings.Join(pragmas, "&"))
dialects[key] = dialectInfo{
dialectic: sqlite.Open(dsn),
logging: parse.Boolean(item["logging"]),

View File

@@ -14,12 +14,12 @@ import (
// ImportSQL 导入SQL
func ImportSQL() {
sqlPath := config.Get("sqlPath").(string)
if sqlPath == "" {
sqlPath, sqlPathOk := config.Get("sqlPath").(string)
if !sqlPathOk || sqlPath == "" {
return
}
sqlSource := config.Get("sqlSource").(string)
if sqlSource == "" {
sqlSource, sqlSourceOk := config.Get("sqlSource").(string)
if !sqlSourceOk || sqlSource == "" {
sqlSource = config.Get("database.defaultDataSourceName").(string)
}
@@ -61,6 +61,7 @@ func ImportSQL() {
}
// log.Println("process success")
Close()
os.Exit(0)
}
@@ -118,7 +119,6 @@ func processSQLFile(db *gorm.DB, filePath string) {
} else if strings.Contains(errorStr, "doesn't match") {
// 忽略列数不匹配错误
// Error 1136 (21S01): Column count doesn't match value count at row 1
log.Println(err.Error())
} else {
// 其他错误终止程序
log.Fatalln(errorStr)

View File

@@ -10,7 +10,6 @@ import (
"be.ems/src/framework/config"
"be.ems/src/framework/constants"
"be.ems/src/framework/database/redis"
"be.ems/src/framework/logger"
"be.ems/src/framework/utils/parse"
)
@@ -58,7 +57,6 @@ func UserTokenCreate(userId int64, deviceFingerprint, tokenType string) (string,
tokenStr, err := jwtToken.SignedString([]byte(secret))
if err != nil {
logger.Infof("jwt sign err : %v", err)
return "", 0
}
expSeconds := int64(exp.Sub(now).Seconds())
@@ -83,7 +81,6 @@ func UserTokenVerify(tokenStr string, tokenType string) (jwt.MapClaims, error) {
return nil, jwt.ErrSignatureInvalid
})
if err != nil {
logger.Errorf("Token Verify Err: %v", err)
return nil, fmt.Errorf("token invalid")
}
// 如果解析负荷成功并通过签名校验
@@ -98,7 +95,6 @@ func UserTokenVerify(tokenStr string, tokenType string) (jwt.MapClaims, error) {
func UserInfoRemove(tokenStr string) (string, error) {
claims, err := UserTokenVerify(tokenStr, "access")
if err != nil {
logger.Errorf("token verify err %v", err)
return "", err
}
info := UserInfoGet(claims)
@@ -165,7 +161,6 @@ func UserInfoGet(claims jwt.MapClaims) UserInfo {
return info
}
if err := json.Unmarshal([]byte(infoStr), &info); err != nil {
logger.Errorf("info json err : %v", err)
return info
}
}

View File

@@ -112,7 +112,7 @@ func (s *DeleteNeConfigBackupProcessor) Execute(data any) (any, error) {
// deleteFile 删除本地文件
func (s DeleteNeConfigBackupProcessor) deleteFile(neType, neId string, oldFileDate time.Time) {
neTypeLower := strings.ToLower(neType)
localPath := fmt.Sprintf("/usr/local/omc/backup/ne_config/%s/%s ", neTypeLower, neId)
localPath := filepath.Join("/usr/local/omc/backup/ne_config", neTypeLower, neId)
files, err := os.ReadDir(localPath)
if err != nil {
logger.Errorf("logger Remove ne_config File ReadDir err: %v", err.Error())

View File

@@ -3,6 +3,7 @@ package ne_alarm_state_check
import (
"encoding/json"
"fmt"
"sync"
"time"
"github.com/tsmask/go-oam"
@@ -20,12 +21,16 @@ import (
var NewProcessor = &NeAlarmStateCheckProcessor{
neInfoService: neService.NewNeInfo,
count: 0,
triggerMax: 3,
triggerCount: sync.Map{},
}
// NeAlarmStateCheckProcessor 网元告警状态检查
type NeAlarmStateCheckProcessor struct {
neInfoService *neService.NeInfo // 网元信息服务
count int // 执行次数
triggerMax int64 // 阈值:连续触发次数大于该值才会产生告警
triggerCount sync.Map // 阈值连续触发次数,存储每个事件的触发记录
}
// alarmParams 告警参数
@@ -73,14 +78,35 @@ func (s *NeAlarmStateCheckProcessor) Execute(data any) (any, error) {
// 网元在线状态
isOnline := parse.Boolean(neInfo.ServerState["online"])
// 告警状态
alarmStatus := oam.ALARM_STATUS_CLEAR
if !isOnline {
// 重置连续触发次数, 超过阈值才会清除告警
onlineKey := "ONLINE:" + neInfo.RmUID
if v, ok := s.triggerCount.Load(onlineKey); ok {
count := parse.Number(v)
if count < s.triggerMax {
s.triggerCount.Store(onlineKey, count+1)
continue
}
s.triggerCount.Delete(onlineKey)
} else {
s.triggerCount.Store(onlineKey, 0)
continue
}
alarmStatus = oam.ALARM_STATUS_ACTIVE
}
// 附加信息
addInfo := params.AddInfo
if addInfo != "" {
addInfo = fmt.Sprintf("%s, NE Connect Failed %s:%d", addInfo, neInfo.IP, neInfo.Port)
} else {
addInfo = fmt.Sprintf("NE Connect Failed %s:%d", neInfo.IP, neInfo.Port)
}
// 告警ID
params.AlarmId = fmt.Sprintf("%d%d", constants.ALARM_STATE_CHECK, neInfo.CreateTime)
// 告警状态
alarmStatus := oam.ALARM_STATUS_ACTIVE
if isOnline {
alarmStatus = oam.ALARM_STATUS_CLEAR
}
// 创建告警
alarm := oam.Alarm{
NeUid: neInfo.RmUID, // 网元唯一标识
@@ -93,7 +119,7 @@ func (s *NeAlarmStateCheckProcessor) Execute(data any) (any, error) {
AlarmStatus: alarmStatus, // 告警状态
SpecificProblem: params.SpecificProblem, // 告警问题原因
SpecificProblemID: params.SpecificProblemID, // 告警问题原因ID
AddInfo: params.AddInfo, // 告警辅助信息
AddInfo: addInfo, // 告警辅助信息
LocationInfo: "NE State: Heartbeat", // 告警定位信息
}
if err = oamService.NewAlarm.Resolve(alarm); err == nil {

View File

@@ -25,17 +25,13 @@ import (
wsService "be.ems/src/modules/ws/service"
)
var (
triggerMax int64 = 3 // 阈值:连续触发次数大于该值才会产生告警
triggerCount sync.Map // 阈值连续触发次数,存储每个事件的触发记录
triggerWindow time.Duration = 30 * time.Second // 事件触发的时间窗口
)
var NewProcessor = &NeAlarmStateCheckCMDProcessor{
neInfoService: neService.NewNeInfo,
neStateService: neDataService.NewNEState,
wsSendService: wsService.NewWSSend,
count: 0,
triggerMax: 3,
triggerCount: sync.Map{},
}
// NeAlarmStateCheckCMDProcessor 网元告警内存/CPU/磁盘检查
@@ -44,6 +40,8 @@ type NeAlarmStateCheckCMDProcessor struct {
neStateService *neDataService.NEState // 网元状态信息服务
wsSendService *wsService.WSSend // ws发送服务
count int // 执行次数
triggerMax int64 // 阈值:连续触发次数大于该值才会产生告警
triggerCount sync.Map // 阈值连续触发次数,存储每个事件的触发记录
}
// alarmParams 告警参数
@@ -124,53 +122,61 @@ func (s *NeAlarmStateCheckCMDProcessor) Execute(data any) (any, error) {
}
var err error
if len(warnMsg) > 0 {
currentTime := time.Now()
validTimes := []time.Time{}
if v, ok := triggerCount.Load(neInfo.RmUID); ok {
times := v.([]time.Time)
// 清理过期的记录10秒前的触发记录不再计入
for _, t := range times {
if currentTime.Sub(t) <= triggerWindow {
validTimes = append(validTimes, t)
}
}
validTimes = append(validTimes, currentTime)
triggerCount.Store(neInfo.RmUID, validTimes)
var count int64
if v, ok := s.triggerCount.Load(neInfo.RmUID); ok {
count = parse.Number(v)
s.triggerCount.Store(neInfo.RmUID, count+1)
} else {
// 事件第一次触发,初始化记录
validTimes = append(validTimes, currentTime)
triggerCount.Store(neInfo.RmUID, validTimes)
s.triggerCount.Store(neInfo.RmUID, 0)
}
if int64(len(validTimes)) >= triggerMax {
if count >= s.triggerMax {
s.triggerCount.Delete("CLEAR:" + neInfo.RmUID)
s.triggerCount.Delete(neInfo.RmUID)
err = fmt.Errorf("greater than %s", strings.Join(warnMsg, ", "))
}
}
// 检查状态连续触发
// 告警状态
alarmStatus := oam.ALARM_STATUS_ACTIVE
if err == nil {
// 重置连续触发次数, 超过阈值才会清除告警
clearKey := "CLEAR:" + neInfo.RmUID
if v, ok := s.triggerCount.Load(clearKey); ok {
count := parse.Number(v)
if count < s.triggerMax {
s.triggerCount.Store(clearKey, count+1)
continue
}
s.triggerCount.Delete(clearKey)
s.triggerCount.Delete(neInfo.RmUID)
} else {
s.triggerCount.Store(clearKey, 0)
continue
}
alarmStatus = oam.ALARM_STATUS_CLEAR
}
// 附加信息
addInfo := params.AddInfo
if err != nil {
if addInfo != "" {
addInfo = addInfo + ", " + err.Error()
} else {
addInfo = err.Error()
}
// 事件产生时间
alarmTime := time.Now().UnixMilli()
}
// 告警ID
params.AlarmId = fmt.Sprintf("%d%d", constants.ALARM_CMD_CHECK, alarmTime)
params.AlarmId = fmt.Sprintf("%d%d", constants.ALARM_CMD_CHECK, neInfo.CreateTime)
// 创建告警
alarm := oam.Alarm{
NeUid: neInfo.RmUID, // 网元唯一标识
AlarmTime: alarmTime, // 事件产生时间
AlarmTime: time.Now().UnixMilli(), // 事件产生时间
AlarmId: params.AlarmId, // 告警ID 唯一,清除时对应
AlarmCode: constants.ALARM_CMD_CHECK, // 告警状态码
AlarmType: params.AlarmType, // 告警类型
AlarmTitle: params.AlarmTitle, // 告警标题
PerceivedSeverity: params.OrigSeverity, // 告警级别
AlarmStatus: oam.ALARM_STATUS_ACTIVE, // 告警状态
AlarmStatus: alarmStatus, // 告警状态
SpecificProblem: params.SpecificProblem, // 告警问题原因
SpecificProblemID: params.SpecificProblemID, // 告警问题原因ID
AddInfo: addInfo, // 告警辅助信息
@@ -179,7 +185,6 @@ func (s *NeAlarmStateCheckCMDProcessor) Execute(data any) (any, error) {
if err = oamService.NewAlarm.Resolve(alarm); err == nil {
result[neInfo.RmUID] = "cmd alarm"
}
triggerCount.Delete(neInfo.RmUID)
}
// 返回结果,用于记录执行结果
@@ -187,7 +192,7 @@ func (s *NeAlarmStateCheckCMDProcessor) Execute(data any) (any, error) {
}
// serverState 网元状态记录
func (s NeAlarmStateCheckCMDProcessor) serverState(state map[string]any) (float64, float64, float64) {
func (s *NeAlarmStateCheckCMDProcessor) serverState(state map[string]any) (float64, float64, float64) {
// 网元CPU使用率
var nfCpuUsage float64 = 0
// CPU使用率

View File

@@ -85,18 +85,23 @@ func (s *NeAlarmStateCheckLicenseProcessor) Execute(data any) (any, error) {
// 检查状态
err := s.cheackState(neInfo.ServerState, params.DayLt)
if err == nil {
continue
// 告警状态
alarmStatus := oam.ALARM_STATUS_ACTIVE
if err == nil { // 检查状态连续触发
alarmStatus = oam.ALARM_STATUS_CLEAR
}
// 附加信息
addInfo := params.AddInfo
if err != nil {
if addInfo != "" {
addInfo = addInfo + ", " + err.Error()
} else {
addInfo = err.Error()
}
}
// 告警ID
params.AlarmId = fmt.Sprintf("%d%d", constants.ALARM_LICENSE_CHECK, neInfo.CreateTime)
// 创建告警
alarm := oam.Alarm{
NeUid: neInfo.RmUID, // 网元唯一标识
@@ -106,7 +111,7 @@ func (s *NeAlarmStateCheckLicenseProcessor) Execute(data any) (any, error) {
AlarmType: params.AlarmType, // 告警类型
AlarmTitle: params.AlarmTitle, // 告警标题
PerceivedSeverity: params.OrigSeverity, // 告警级别
AlarmStatus: oam.ALARM_STATUS_ACTIVE, // 告警状态
AlarmStatus: alarmStatus, // 告警状态
SpecificProblem: params.SpecificProblem, // 告警问题原因
SpecificProblemID: params.SpecificProblemID, // 告警问题原因ID
AddInfo: addInfo, // 告警辅助信息

View File

@@ -164,18 +164,28 @@ func (s NeConfigController) Remove(c *gin.Context) {
// @Accept json
// @Produce json
// @Param neType path string true "NE Type" Enums(IMS,AMF,AUSF,UDM,SMF,PCF,NSSF,NRF,UPF,MME,CBC,OMC,SGWC,SMSC)
// @Param neId query string true "NE ID" default(001)
// @Success 200 {object} object "Response Results"
// @Security TokenAuth
// @Summary Network Element Parameter Configuration Available Attribute Values List Specify Network Element Type All Unpaged
// @Description Network Element Parameter Configuration Available Attribute Values List Specify Network Element Type All Unpaged
// @Router /ne/config/list/{neType} [get]
func (s NeConfigController) ListByNeType(c *gin.Context) {
language := reqctx.AcceptLanguage(c)
neId := c.DefaultQuery("neId", "001")
neType := c.Param("neType")
if neType == "" {
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_CHEACK, "bind err: neType is empty"))
return
}
data := s.neConfigService.FindByNeType(neType)
neInfo := s.neInfoService.FindByNeTypeAndNeID(neType, neId)
if neInfo.NeId != neId || neInfo.IP == "" {
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.noNEInfo")))
return
}
data := s.neConfigService.FindByNeType(neInfo.NeType, neInfo.NeVersion)
c.JSON(200, resp.OkData(data))
}
@@ -313,8 +323,14 @@ func (s NeConfigController) DataAdd(c *gin.Context) {
return
}
neInfo := s.neInfoService.FindByNeTypeAndNeID(body.NeType, body.NeId)
if neInfo.NeId != body.NeId || neInfo.IP == "" {
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.noNEInfo")))
return
}
// 检查是否array
info := s.neConfigService.FindByNeTypeAndParamName(body.NeType, body.ParamName)
info := s.neConfigService.FindByNeTypeAndParamName(body.NeType, neInfo.NeVersion, body.ParamName)
if info.ParamType != "array" {
c.JSON(200, resp.ErrMsg("this attribute does not support adding"))
return
@@ -326,12 +342,6 @@ func (s NeConfigController) DataAdd(c *gin.Context) {
return
}
neInfo := s.neInfoService.FindByNeTypeAndNeID(body.NeType, body.NeId)
if neInfo.NeId != body.NeId || neInfo.IP == "" {
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.noNEInfo")))
return
}
// 网元直连
resData, err := neFetchlink.NeConfigAdd(neInfo, body.ParamName, body.Loc, body.ParamData)
if err != nil {
@@ -371,19 +381,19 @@ func (s NeConfigController) DataRemove(c *gin.Context) {
return
}
// 检查是否array
info := s.neConfigService.FindByNeTypeAndParamName(query.NeType, query.ParamName)
if info.ParamType != "array" {
c.JSON(200, resp.ErrMsg("this attribute does not support adding"))
return
}
neInfo := s.neInfoService.FindByNeTypeAndNeID(query.NeType, query.NeId)
if neInfo.NeId != query.NeId || neInfo.IP == "" {
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.noNEInfo")))
return
}
// 检查是否array
info := s.neConfigService.FindByNeTypeAndParamName(query.NeType, neInfo.NeVersion, query.ParamName)
if info.ParamType != "array" {
c.JSON(200, resp.ErrMsg("this attribute does not support adding"))
return
}
// 网元直连
resData, err := neFetchlink.NeConfigDelete(neInfo, query.ParamName, query.Loc)
if err != nil {

View File

@@ -395,6 +395,7 @@ func (s NeInfoController) Add(c *gin.Context) {
// 已有网元可获取的信息
if body.ServerState != nil {
if v, ok := body.ServerState["version"]; ok && v != nil {
body.NeVersion = fmt.Sprint(v)
neVersion.Version = fmt.Sprint(v)
}
if v, ok := body.ServerState["sn"]; ok && v != nil {
@@ -497,6 +498,7 @@ func (s NeInfoController) Edit(c *gin.Context) {
// 已有网元可获取的信息
if body.ServerState != nil {
if v, ok := body.ServerState["version"]; ok && v != nil {
body.NeVersion = fmt.Sprint(v)
neVersion.Version = fmt.Sprint(v)
neVersion.UpdateBy = loginUserName
}

View File

@@ -3,7 +3,9 @@ package model
// NeConfig 网元_参数配置可用属性值
type NeConfig struct {
ID int64 `json:"id" gorm:"column:id;primaryKey;autoIncrement"`
UpdateTime int64 `json:"updateTime" gorm:"column:update_time"` // 更新时间
NeType string `json:"neType" binding:"required" gorm:"column:ne_type"` // 网元类型
NeVersion string `json:"neVersion" gorm:"column:ne_version"` // 网元版本 前缀匹配
ParamName string `json:"paramName" binding:"required" gorm:"column:param_name"` // 参数名
ParamDisplay string `json:"paramDisplay" binding:"required" gorm:"column:param_display"` // 参数显示名
ParamType string `json:"paramType" gorm:"column:param_type"` // 参数类型 list列表单层 array数组多层
@@ -11,7 +13,6 @@ type NeConfig struct {
ParamSort int64 `json:"paramSort" gorm:"column:param_sort"` // 参数排序
ParamPerms string `json:"paramPerms" gorm:"column:param_perms"` // 操作权限 get只读 put可编辑 delete可删除 post可新增
Visible string `json:"visible" gorm:"column:visible"` // 可见性 默认public 单独网元self
UpdateTime int64 `json:"updateTime" gorm:"column:update_time"` // 更新时间
// ====== 非数据库字段属性 ======

View File

@@ -3,10 +3,17 @@ package model
// NeInfo 网元信息对象 ne_info
type NeInfo struct {
ID int64 `json:"id" gorm:"column:id;primaryKey;autoIncrement"`
CreateBy string `json:"createBy" gorm:"column:create_by"` // 创建者
CreateTime int64 `json:"createTime" gorm:"column:create_time"` // 创建时间
UpdateBy string `json:"updateBy" gorm:"column:update_by"` // 更新者
UpdateTime int64 `json:"updateTime" gorm:"column:update_time"` // 更新时间
Remark string `json:"remark" gorm:"column:remark"` // 备注
NeType string `json:"neType" gorm:"column:ne_type" binding:"required"` // 网元类型
NeId string `json:"neId" gorm:"column:ne_id" binding:"required"` // 网元ID
RmUID string `json:"rmUid" gorm:"column:rm_uid"` // 网元资源唯一标识
NeName string `json:"neName" gorm:"column:ne_name"` // 网元名称
NeVersion string `json:"neVersion" gorm:"column:ne_version"` // 网元版本
RmUID string `json:"rmUid" gorm:"column:rm_uid"` // 网元资源唯一标识
Schema string `json:"schema" gorm:"column:schema"` // 网元模式 http/https
IP string `json:"ip" gorm:"column:ip" binding:"required"` // 网元服务IP
Port int64 `json:"port" gorm:"column:port" binding:"required,number,max=65535,min=1"` // 端口
PvFlag string `json:"pvFlag" gorm:"column:pv_flag" binding:"omitempty,oneof=PNF VNF"` // 网元虚拟化标识 物理PNF 虚拟VNF
@@ -16,11 +23,6 @@ type NeInfo struct {
NeAddress string `json:"neAddress" gorm:"column:ne_address"` // MAC地址
HostIDs string `json:"hostIds" gorm:"column:host_ids"` // 网元主机ID组 数据格式(ssh,telnet) UDM(ssh,telnet,redis) UPF(ssh,telnet,telnet)
Status int64 `json:"status" gorm:"column:status"` // 网元状态 0离线 1在线 2配置待下发 3备用模式
Remark string `json:"remark" gorm:"column:remark"` // 备注
CreateBy string `json:"createBy" gorm:"column:create_by"` // 创建者
CreateTime int64 `json:"createTime" gorm:"column:create_time"` // 创建时间
UpdateBy string `json:"updateBy" gorm:"column:update_by"` // 更新者
UpdateTime int64 `json:"updateTime" gorm:"column:update_time"` // 更新时间
// ====== 非数据库字段属性 ======

View File

@@ -41,23 +41,39 @@ func TestConfig(t *testing.T) {
if configParamFile == "*" {
for _, v := range fileNameList {
params := parseData(filepath.Join(configParamDir, v))
filePath := filepath.Join(configParamDir, v)
version := parseVersion(filePath)
params := parseData(filePath)
if params == nil {
return
}
saveData(params)
saveData(version, params)
}
} else {
params := parseData(filepath.Join(configParamDir, configParamFile))
filePath := filepath.Join(configParamDir, configParamFile)
version := parseVersion(filePath)
params := parseData(filePath)
if params == nil {
return
}
saveData(params)
saveData(version, params)
}
}
// ========= Main =============
// 根据文件名获取版本号 mme_2_param_config.yaml -> 2
func parseVersion(filePaht string) string {
version := "2"
splits := strings.Split(filepath.Base(filePaht), "_")
if len(splits) > 0 {
if splits[2] == "param" {
version = splits[1]
}
}
return version
}
// parseData 文件转map数据
func parseData(filePaht string) []map[string]string {
data, err := parseStrToMap(filePaht)
@@ -74,7 +90,7 @@ func parseData(filePaht string) []map[string]string {
}
// saveData 保存数据
func saveData(params []map[string]string) {
func saveData(version string, params []map[string]string) {
// 定义排序函数
sort.Slice(params, func(i, j int) bool {
paramSortI := params[i]["paramSort"]
@@ -109,6 +125,7 @@ func saveData(params []map[string]string) {
}
neConfig := model.NeConfig{
NeVersion: version,
NeType: v["neType"],
ParamName: v["paramName"],
ParamDisplay: v["paramDisplay"],
@@ -157,7 +174,7 @@ func saveDB(s model.NeConfig) int64 {
db := connDB()
// 检查是否存在
var id int64
db.Raw("SELECT id FROM ne_config WHERE ne_type = ? AND param_name = ?", s.NeType, s.ParamName).Scan(&id)
db.Raw("SELECT id FROM ne_config WHERE ne_type = ? AND ne_version = ? AND param_name = ?", s.NeType, s.NeVersion, s.ParamName).Scan(&id)
// 更新时间
s.UpdateTime = time.Now().UnixMilli()
if id > 0 {

View File

@@ -239,3 +239,23 @@ func (r NeInfo) UpdateState(id int64, status int64) int64 {
}
return tx.RowsAffected
}
// UpdateVersion 修改网元版本
func (r NeInfo) UpdateVersion(id int64, neVersion string) int64 {
if id <= 0 {
return 0
}
tx := db.DB("").Model(&model.NeInfo{})
// 构建查询条件
tx = tx.Where("id = ?", id)
tx.Updates(map[string]any{
"ne_version": neVersion,
"update_time": time.Now().UnixMilli(),
})
// 执行更新
if err := tx.Error; err != nil {
logger.Errorf("update err => %v", err.Error())
return 0
}
return tx.RowsAffected
}

View File

@@ -21,59 +21,39 @@ type NeConfig struct {
neConfigRepository *repository.NeConfig // 网元参数配置可用属性值表
}
// RefreshByNeType 通过ne_type刷新redis中的缓存
func (r *NeConfig) RefreshByNeTypeAndNeID(neType string) []model.NeConfig {
// 多个
if neType == "" || neType == "*" {
neConfigList := r.neConfigRepository.Select(model.NeConfig{})
if len(neConfigList) > 0 {
// RefreshByNeType 通过ne_type刷新redis中的缓存 并返回分组数据
func (r *NeConfig) RefreshByNeTypeAndNeID(neType string) map[string][]model.NeConfig {
neConfig := model.NeConfig{}
if neType != "*" {
neConfig.NeType = neType
}
neConfigList := r.neConfigRepository.Select(neConfig)
neConfigGroup := map[string][]model.NeConfig{}
for _, v := range neConfigList {
if item, ok := neConfigGroup[v.NeType]; ok {
neConfigGroup[v.NeType] = append(item, v)
if err := json.Unmarshal([]byte(v.ParamJson), &v.ParamData); err != nil {
continue
}
neTypeVerKey := fmt.Sprintf("%s:%s", strings.ToUpper(v.NeType), v.NeVersion)
if item, ok := neConfigGroup[neTypeVerKey]; ok {
neConfigGroup[neTypeVerKey] = append(item, v)
} else {
neConfigGroup[v.NeType] = []model.NeConfig{v}
neConfigGroup[neTypeVerKey] = []model.NeConfig{v}
}
}
for k, v := range neConfigGroup {
key := fmt.Sprintf("%s:NeConfig:%s", constants.CACHE_NE_DATA, strings.ToUpper(k))
key := fmt.Sprintf("%s:NeConfig:%s", constants.CACHE_NE_DATA, k)
redis.Del("", key)
if len(v) > 0 {
for i, item := range v {
if err := json.Unmarshal([]byte(item.ParamJson), &item.ParamData); err != nil {
continue
}
v[i] = item
}
values, _ := json.Marshal(v)
redis.Set("", key, string(values), 0)
}
}
}
return neConfigList
}
// 单个
key := fmt.Sprintf("%s:NeConfig:%s", constants.CACHE_NE_DATA, strings.ToUpper(neType))
redis.Del("", key)
neConfigList := r.neConfigRepository.Select(model.NeConfig{
NeType: neType,
})
if len(neConfigList) > 0 {
for i, v := range neConfigList {
if err := json.Unmarshal([]byte(v.ParamJson), &v.ParamData); err != nil {
continue
}
neConfigList[i] = v
}
values, _ := json.Marshal(neConfigList)
redis.Set("", key, string(values), 0)
}
return neConfigList
return neConfigGroup
}
// ClearNeCacheByNeType 清除网元类型参数配置缓存
func (r *NeConfig) ClearNeCacheByNeType(neType string) bool {
key := fmt.Sprintf("%s:NeConfig:%s", constants.CACHE_NE_DATA, neType)
key := fmt.Sprintf("%s:NeConfig:%s:*", constants.CACHE_NE_DATA, neType)
if neType == "*" {
key = fmt.Sprintf("%s:NeConfig:*", constants.CACHE_NE_DATA)
}
@@ -85,27 +65,41 @@ func (r *NeConfig) ClearNeCacheByNeType(neType string) bool {
}
// FindByNeType 查询网元类型参数配置
func (r *NeConfig) FindByNeType(neType string) []model.NeConfig {
var neConfigList []model.NeConfig
key := fmt.Sprintf("%s:NeConfig:%s", constants.CACHE_NE_DATA, strings.ToUpper(neType))
jsonStr, _ := redis.Get("", key)
if len(jsonStr) > 7 {
err := json.Unmarshal([]byte(jsonStr), &neConfigList)
if err != nil {
neConfigList = []model.NeConfig{}
func (r *NeConfig) FindByNeType(neType, neVersion string) []model.NeConfig {
data := make([]model.NeConfig, 0)
keys, _ := redis.GetKeys("", fmt.Sprintf("%s:NeConfig:%s:*", constants.CACHE_NE_DATA, strings.ToUpper(neType)))
if len(keys) > 0 {
for _, key := range keys {
neTypeVer := strings.Split(key, ":")
if len(neTypeVer) != 4 {
continue
}
} else {
neConfigList = r.RefreshByNeTypeAndNeID(neType)
if strings.HasPrefix(neVersion, neTypeVer[3]) {
if jsonStr, _ := redis.Get("", key); len(jsonStr) > 7 {
json.Unmarshal([]byte(jsonStr), &data)
}
return neConfigList
return data
}
}
}
// 从数据库刷新缓存
neConfigGroup := r.RefreshByNeTypeAndNeID(neType)
for k, v := range neConfigGroup {
neTypeVer := strings.Split(k, ":")
if len(neTypeVer) == 2 && strings.HasPrefix(neVersion, neTypeVer[1]) {
data = v
break
}
}
return data
}
// FindByNeTypeAndParamName 查询网元类型参数配置By参数名
func (r *NeConfig) FindByNeTypeAndParamName(neType, paramName string) model.NeConfig {
neConfigList := r.FindByNeType(neType)
func (r *NeConfig) FindByNeTypeAndParamName(neType, neVersion, paramName string) model.NeConfig {
neConfigList := r.FindByNeType(neType, neVersion)
var neConfig model.NeConfig
for _, v := range neConfigList {
if v.ParamName == paramName {
if strings.HasPrefix(neVersion, v.NeVersion) && v.ParamName == paramName {
neConfig = v
break
}

View File

@@ -37,7 +37,7 @@ func (r NeConfig) GetOMCYaml(paramName string) []map[string]any {
// ModifyOMCYaml 修改OMC网元配置文件
func (r NeConfig) ModifyOMCYaml(paramName, loc string, paramData any) error {
neConfig := r.FindByNeTypeAndParamName("OMC", paramName)
neConfig := r.FindByNeTypeAndParamName("OMC", config.Version, paramName)
if neConfig.ParamType == "list" {
if paramName == "notificationEmail" {
notificationEmailData := config.Get("notification.email").(map[string]any)

View File

@@ -7,7 +7,6 @@ import (
"path/filepath"
"runtime"
"strings"
"time"
"be.ems/src/framework/cmd"
"be.ems/src/framework/constants"
@@ -189,7 +188,6 @@ func (r NeInfo) bandNeStatus(arr *[]model.NeInfo) {
if v.Status != 0 {
v.Status = 0
(*arr)[i].Status = v.Status
(*arr)[i].UpdateTime = time.Now().UnixMilli()
r.neInfoRepository.UpdateState(v.ID, v.Status)
}
continue
@@ -207,8 +205,14 @@ func (r NeInfo) bandNeStatus(arr *[]model.NeInfo) {
}
(*arr)[i].Status = status
if v.Status != status {
(*arr)[i].UpdateTime = time.Now().UnixMilli()
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)
}
}
}

View File

@@ -64,12 +64,12 @@ func (r NeVersion) checkNeVersion(arr *[]model.NeVersion) {
continue
}
if v, ok := result["version"]; ok && v != nil {
ver := v.(string)
ver := fmt.Sprint(v)
if ver == item.Version {
continue
}
item.Name = "-"
item.Path = "-"
// item.Name = "-"
// item.Path = "-"
item.Version = ver
}
if item.NeType != neInfo.NeType || item.NeId != neInfo.NeId {