feat: 新增oam对外开放无限制接口模块
This commit is contained in:
672
src/modules/oam/controller/api_rest.go
Normal file
672
src/modules/oam/controller/api_rest.go
Normal file
@@ -0,0 +1,672 @@
|
|||||||
|
package controller
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/tsmask/go-oam"
|
||||||
|
|
||||||
|
"be.ems/src/framework/logger"
|
||||||
|
"be.ems/src/framework/resp"
|
||||||
|
"be.ems/src/framework/utils/date"
|
||||||
|
"be.ems/src/framework/utils/parse"
|
||||||
|
neFetchlink "be.ems/src/modules/network_element/fetch_link"
|
||||||
|
neModel "be.ems/src/modules/network_element/model"
|
||||||
|
neService "be.ems/src/modules/network_element/service"
|
||||||
|
oamService "be.ems/src/modules/oam/service"
|
||||||
|
)
|
||||||
|
|
||||||
|
// NewAPIRest 实例化控制层
|
||||||
|
var NewAPIRest = &APIRestController{}
|
||||||
|
|
||||||
|
// APIRestController 北向定义 控制层处理
|
||||||
|
//
|
||||||
|
// PATH /api/rest
|
||||||
|
type APIRestController struct{}
|
||||||
|
|
||||||
|
// ResolveAlarm 接收告警
|
||||||
|
//
|
||||||
|
// POST /faultManagement/v1/elementType/:elementTypeValue/objectType/alarms
|
||||||
|
func (s APIRestController) ResolveAlarm(c *gin.Context) {
|
||||||
|
var body []struct {
|
||||||
|
AlarmSeq int `json:"alarmSeq"`
|
||||||
|
AlarmId string `json:"alarmId"`
|
||||||
|
NeId string `json:"neId"` // 收到实际是rmUID
|
||||||
|
AlarmCode int `json:"alarmCode"`
|
||||||
|
AlarmTitle string `json:"alarmTitle"`
|
||||||
|
EventTime string `json:"eventTime"`
|
||||||
|
AlarmType string `json:"alarmType"`
|
||||||
|
OrigSeverity string `json:"origSeverity"`
|
||||||
|
PerceivedSeverity string `json:"perceivedSeverity"`
|
||||||
|
PVFlag string `json:"pvFlag"`
|
||||||
|
NeName string `json:"neName"`
|
||||||
|
NeType string `json:"neType"`
|
||||||
|
ObjectUid string `json:"objectUid"`
|
||||||
|
ObjectName string `json:"objectName"`
|
||||||
|
ObjectType string `json:"objectType"`
|
||||||
|
LocationInfo string `json:"locationInfo"`
|
||||||
|
Province string `json:"province"`
|
||||||
|
AlarmStatus int `json:"alarmStatus"`
|
||||||
|
SpecificProblem string `json:"specificProblem"`
|
||||||
|
SpecificProblemID string `json:"specificProblemID"`
|
||||||
|
AddInfo string `json:"addInfo"`
|
||||||
|
}
|
||||||
|
if err := c.ShouldBindBodyWithJSON(&body); err != nil {
|
||||||
|
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
|
||||||
|
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
elementTypeValue := c.Param("elementTypeValue")
|
||||||
|
|
||||||
|
// alarmTypeValue 映射值
|
||||||
|
alarmTypeValue := func(str string) string {
|
||||||
|
arr := []string{
|
||||||
|
oam.ALARM_TYPE_COMMUNICATION_ALARM,
|
||||||
|
oam.ALARM_TYPE_EQUIPMENT_ALARM,
|
||||||
|
oam.ALARM_TYPE_PROCESSING_FAILURE,
|
||||||
|
oam.ALARM_TYPE_ENVIRONMENTAL_ALARM,
|
||||||
|
oam.ALARM_TYPE_QUALITY_OF_SERVICE_ALARM,
|
||||||
|
}
|
||||||
|
for k, v := range arr {
|
||||||
|
if v == str {
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
if fmt.Sprint(k+1) == str {
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return str
|
||||||
|
}
|
||||||
|
|
||||||
|
// origSeverityValue 映射值
|
||||||
|
origSeverityValue := func(str string) string {
|
||||||
|
arr := []string{
|
||||||
|
oam.ALARM_SEVERITY_CRITICAL,
|
||||||
|
oam.ALARM_SEVERITY_MAJOR,
|
||||||
|
oam.ALARM_SEVERITY_MINOR,
|
||||||
|
oam.ALARM_SEVERITY_WARNING,
|
||||||
|
oam.ALARM_SEVERITY_EVENT,
|
||||||
|
}
|
||||||
|
for k, v := range arr {
|
||||||
|
if v == str {
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
if fmt.Sprint(k+1) == str {
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return str
|
||||||
|
}
|
||||||
|
|
||||||
|
// alarmStatusValue 映射值
|
||||||
|
alarmStatusValue := func(value int) string {
|
||||||
|
arr := []string{
|
||||||
|
oam.ALARM_STATUS_CLEAR,
|
||||||
|
oam.ALARM_STATUS_ACTIVE,
|
||||||
|
}
|
||||||
|
for k, v := range arr {
|
||||||
|
if k == value {
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return oam.ALARM_STATUS_ACTIVE
|
||||||
|
}
|
||||||
|
|
||||||
|
alarmArr := make([]oam.Alarm, 0)
|
||||||
|
for _, v := range body {
|
||||||
|
if !strings.EqualFold(v.NeType, elementTypeValue) {
|
||||||
|
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_CHEACK, "elementType is inconsistent with neType"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// 产生时间
|
||||||
|
eventTime := date.ParseStrToDate(v.EventTime, time.RFC3339)
|
||||||
|
// 创建告警
|
||||||
|
alarm := oam.Alarm{
|
||||||
|
NeUid: v.NeId, // 网元唯一标识
|
||||||
|
AlarmTime: eventTime.UnixMilli(), // 事件产生时间
|
||||||
|
AlarmId: v.AlarmId, // 告警ID 唯一,清除时对应
|
||||||
|
AlarmCode: v.AlarmCode, // 告警状态码
|
||||||
|
AlarmType: alarmTypeValue(v.AlarmType), // 告警类型
|
||||||
|
AlarmTitle: v.AlarmTitle, // 告警标题
|
||||||
|
PerceivedSeverity: origSeverityValue(v.OrigSeverity), // 告警级别
|
||||||
|
AlarmStatus: alarmStatusValue(v.AlarmStatus), // 告警状态
|
||||||
|
SpecificProblem: v.SpecificProblem, // 告警问题原因
|
||||||
|
SpecificProblemID: v.SpecificProblemID, // 告警问题原因ID
|
||||||
|
AddInfo: v.AddInfo, // 告警辅助信息
|
||||||
|
LocationInfo: v.LocationInfo, // 告警定位信息
|
||||||
|
}
|
||||||
|
alarmArr = append(alarmArr, alarm)
|
||||||
|
}
|
||||||
|
|
||||||
|
errArr := make([]string, 0)
|
||||||
|
for _, alarm := range alarmArr {
|
||||||
|
if err := oamService.NewAlarm.Resolve(alarm); err != nil {
|
||||||
|
errArr = append(errArr, err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(errArr) > 0 {
|
||||||
|
c.JSON(200, resp.ErrData(errArr))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
c.JSON(200, resp.Ok(nil))
|
||||||
|
}
|
||||||
|
|
||||||
|
// ResolveCDR 接收话单
|
||||||
|
//
|
||||||
|
// POST /cdrManagement/v1/elementType/:elementTypeValue/objectType/cdrEvent
|
||||||
|
func (s APIRestController) ResolveCDR(c *gin.Context) {
|
||||||
|
var body struct {
|
||||||
|
NeType string `json:"neType" `
|
||||||
|
NeName string `json:"neName" `
|
||||||
|
RmUID string `json:"rmUID" `
|
||||||
|
Timestamp int `json:"timestamp" `
|
||||||
|
CDR map[string]any `json:"CDR" `
|
||||||
|
}
|
||||||
|
if err := c.ShouldBindBodyWithJSON(&body); err != nil {
|
||||||
|
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
|
||||||
|
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
elementTypeValue := c.Param("elementTypeValue")
|
||||||
|
if !strings.EqualFold(body.NeType, elementTypeValue) {
|
||||||
|
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_CHEACK, "elementType is inconsistent with neType"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
recordTime := time.Now()
|
||||||
|
if body.Timestamp > 1e12 {
|
||||||
|
recordTime = time.UnixMilli(int64(body.Timestamp))
|
||||||
|
} else if body.Timestamp > 1e9 {
|
||||||
|
recordTime = time.Unix(int64(body.Timestamp), 0)
|
||||||
|
}
|
||||||
|
// 创建CDR
|
||||||
|
cdr := oam.CDR{
|
||||||
|
NeUid: body.RmUID, // 网元唯一标识
|
||||||
|
RecordTime: recordTime.UnixMilli(), // 记录时间 时间戳毫秒,Push时自动填充
|
||||||
|
Data: body.CDR, // 话单信息
|
||||||
|
}
|
||||||
|
if err := oamService.NewCDR.Resolve(cdr); err != nil {
|
||||||
|
c.JSON(200, resp.ErrMsg(err.Error()))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
c.JSON(200, resp.Ok(nil))
|
||||||
|
}
|
||||||
|
|
||||||
|
// ResolveKPI 接收KPI
|
||||||
|
//
|
||||||
|
// POST /performanceManagement/v1/elementType/:elementTypeValue/objectType/kpiReport/:index
|
||||||
|
func (s APIRestController) ResolveKPI(c *gin.Context) {
|
||||||
|
var body struct {
|
||||||
|
Timestamp string `json:"TimeStamp" binding:"required"`
|
||||||
|
Task struct {
|
||||||
|
Period struct {
|
||||||
|
StartTime string `json:"StartTime"`
|
||||||
|
EndTime string `json:"EndTime"`
|
||||||
|
} `json:"Period" binding:"required"`
|
||||||
|
NE struct {
|
||||||
|
NEName string `json:"NEName"`
|
||||||
|
RmUID string `json:"rmUID"`
|
||||||
|
NeType string `json:"NeType"`
|
||||||
|
KPIs []struct {
|
||||||
|
KPIID string `json:"KPIID"`
|
||||||
|
Value int64 `json:"Value"`
|
||||||
|
Err string `json:"Err"`
|
||||||
|
} `json:"KPIs" binding:"required"`
|
||||||
|
} `json:"NE" binding:"required"`
|
||||||
|
} `json:"Task" binding:"required"`
|
||||||
|
}
|
||||||
|
if err := c.ShouldBindBodyWithJSON(&body); err != nil {
|
||||||
|
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
|
||||||
|
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
elementTypeValue := c.Param("elementTypeValue")
|
||||||
|
if !strings.EqualFold(body.Task.NE.NeType, elementTypeValue) {
|
||||||
|
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_CHEACK, "elementType is inconsistent with neType"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// index := c.Param("index")
|
||||||
|
|
||||||
|
timestamp := body.Timestamp
|
||||||
|
taskPeriod := body.Task.Period
|
||||||
|
taskNeKPIs := body.Task.NE.KPIs
|
||||||
|
// 时间数据处理
|
||||||
|
receiverTime := date.ParseStrToDate(timestamp, date.YYYY_MM_DDTHH_MM_SSZ)
|
||||||
|
startTime := date.ParseStrToDate(taskPeriod.StartTime, date.YYYY_MM_DDTHH_MM_SSZ)
|
||||||
|
endTime := date.ParseStrToDate(taskPeriod.EndTime, date.YYYY_MM_DDTHH_MM_SSZ)
|
||||||
|
granularity := parse.Number(endTime.Sub(startTime).Seconds())
|
||||||
|
// kpi data数据
|
||||||
|
KpiValues := make(map[string]float64, 0)
|
||||||
|
for _, v := range taskNeKPIs {
|
||||||
|
KpiValues[v.KPIID] = float64(v.Value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建KPI
|
||||||
|
kpi := oam.KPI{
|
||||||
|
NeUid: body.Task.NE.RmUID, // 网元唯一标识
|
||||||
|
RecordTime: receiverTime.UnixMilli(), // 记录时间 时间戳毫秒,Push时自动填充
|
||||||
|
Granularity: granularity, // 时间间隔 5/10/.../60/300 (秒)
|
||||||
|
Data: KpiValues, // 指标信息
|
||||||
|
}
|
||||||
|
if err := oamService.NewKPI.Resolve(kpi); err != nil {
|
||||||
|
c.JSON(200, resp.ErrMsg(err.Error()))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
c.JSON(200, resp.Ok(nil))
|
||||||
|
}
|
||||||
|
|
||||||
|
// ResolveNBState 接收基站状态变更
|
||||||
|
//
|
||||||
|
// POST /ueManagement/v1/elementType/:elementTypeValue/objectType/nbState
|
||||||
|
func (s APIRestController) ResolveNBState(c *gin.Context) {
|
||||||
|
var body struct {
|
||||||
|
NeType string `json:"neType" `
|
||||||
|
NeName string `json:"neName" `
|
||||||
|
RmUID string `json:"rmUID"`
|
||||||
|
StateList []struct {
|
||||||
|
Address string `json:"address" `
|
||||||
|
Name string `json:"name" `
|
||||||
|
Position string `json:"position" `
|
||||||
|
NbName string `json:"nbName" `
|
||||||
|
State string `json:"state" ` // "OFF" or "ON"
|
||||||
|
OffTime string `json:"offTime" ` //if State=OFF, will set it
|
||||||
|
OnTime string `json:"onTime" ` //if State=ON , will set it
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err := c.ShouldBindBodyWithJSON(&body); err != nil {
|
||||||
|
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
|
||||||
|
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
elementTypeValue := c.Param("elementTypeValue")
|
||||||
|
if !strings.EqualFold(body.NeType, elementTypeValue) {
|
||||||
|
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_CHEACK, "elementType is inconsistent with neType"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(body.StateList) == 0 {
|
||||||
|
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_CHEACK, "no stateList"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
nbStateArr := make([]oam.NBState, 0)
|
||||||
|
for _, v := range body.StateList {
|
||||||
|
if v.Address == "" || v.State == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
stateTime := date.ParseStrToDate(v.OffTime, time.RFC3339)
|
||||||
|
stateStr := oam.NB_STATE_OFF
|
||||||
|
if v.State == "ON" {
|
||||||
|
stateTime = date.ParseStrToDate(v.OnTime, time.RFC3339)
|
||||||
|
stateStr = oam.NB_STATE_ON
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建NbState
|
||||||
|
nbState := oam.NBState{
|
||||||
|
NeUid: body.RmUID, // 网元唯一标识
|
||||||
|
RecordTime: time.Now().UnixMilli(), // 记录时间 时间戳毫秒,Push时自动填充
|
||||||
|
Address: v.Address, // 基站地址
|
||||||
|
DeviceName: v.NbName, // 基站设备名称
|
||||||
|
State: stateStr, // 基站状态 ON/OFF
|
||||||
|
StateTime: stateTime.UnixMilli(), // 基站状态时间 时间戳毫秒
|
||||||
|
Name: v.Name, // 基站名称 网元标记
|
||||||
|
Position: v.Position, // 基站位置 网元标记
|
||||||
|
}
|
||||||
|
nbStateArr = append(nbStateArr, nbState)
|
||||||
|
}
|
||||||
|
|
||||||
|
errArr := make([]string, 0)
|
||||||
|
for _, nbState := range nbStateArr {
|
||||||
|
if err := oamService.NewNBState.Resolve(nbState); err != nil {
|
||||||
|
errArr = append(errArr, err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(errArr) > 0 {
|
||||||
|
c.JSON(200, resp.ErrData(errArr))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
c.JSON(200, resp.Ok(nil))
|
||||||
|
}
|
||||||
|
|
||||||
|
// ResolveUENB 接收终端接入基站
|
||||||
|
//
|
||||||
|
// POST /logManagement/v1/elementType/:elementTypeValue/objectType/ueEvent
|
||||||
|
func (s APIRestController) ResolveUENB(c *gin.Context) {
|
||||||
|
var body struct {
|
||||||
|
NeType string `json:"neType" `
|
||||||
|
NeName string `json:"neName" `
|
||||||
|
RmUID string `json:"rmUID" `
|
||||||
|
Timestamp int64 `json:"timestamp" `
|
||||||
|
EventType string `json:"eventType" `
|
||||||
|
EventJson map[string]any `json:"eventJSON" `
|
||||||
|
}
|
||||||
|
if err := c.ShouldBindBodyWithJSON(&body); err != nil {
|
||||||
|
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
|
||||||
|
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
elementTypeValue := c.Param("elementTypeValue")
|
||||||
|
if !strings.EqualFold(body.NeType, elementTypeValue) {
|
||||||
|
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_CHEACK, "elementType is inconsistent with neType"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 记录时间
|
||||||
|
recordTime := time.Now()
|
||||||
|
if body.Timestamp > 1e12 {
|
||||||
|
recordTime = time.UnixMilli(int64(body.Timestamp))
|
||||||
|
} else if body.Timestamp > 1e9 {
|
||||||
|
recordTime = time.Unix(int64(body.Timestamp), 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建UENB
|
||||||
|
uenb := oam.UENB{
|
||||||
|
NeUid: body.RmUID, // 网元唯一标识
|
||||||
|
RecordTime: recordTime.UnixMilli(), // 记录时间
|
||||||
|
NBId: "0", // 基站ID
|
||||||
|
CellId: "0", // 小区ID
|
||||||
|
TAC: "", // TAC
|
||||||
|
IMSI: "", // IMSI
|
||||||
|
Result: oam.UENB_RESULT_AUTH_SUCCESS, // 结果值
|
||||||
|
Type: oam.UENB_TYPE_DETACH, // 终端接入基站类型
|
||||||
|
}
|
||||||
|
|
||||||
|
// 基站ID
|
||||||
|
if v, ok := body.EventJson["eNBID"]; ok && v != nil {
|
||||||
|
uenb.NBId = fmt.Sprint(v)
|
||||||
|
}
|
||||||
|
if v, ok := body.EventJson["gNBID"]; ok && v != nil {
|
||||||
|
uenb.NBId = fmt.Sprint(v)
|
||||||
|
}
|
||||||
|
// 小区ID
|
||||||
|
if v, ok := body.EventJson["cellID"]; ok && v != nil {
|
||||||
|
uenb.CellId = fmt.Sprint(v)
|
||||||
|
}
|
||||||
|
// TAC
|
||||||
|
if v, ok := body.EventJson["tacID"]; ok && v != nil {
|
||||||
|
uenb.TAC = fmt.Sprint(v)
|
||||||
|
}
|
||||||
|
// IMSI
|
||||||
|
if v, ok := body.EventJson["imsi"]; ok && v != nil {
|
||||||
|
uenb.IMSI = fmt.Sprint(v)
|
||||||
|
}
|
||||||
|
// 结果值
|
||||||
|
if v, ok := body.EventJson["result"]; ok && v != nil {
|
||||||
|
uenb.Result = fmt.Sprint(v)
|
||||||
|
}
|
||||||
|
// 终端接入基站类型
|
||||||
|
if v, ok := body.EventJson["type"]; ok && v != nil {
|
||||||
|
switch v := fmt.Sprint(v); v {
|
||||||
|
case "detach":
|
||||||
|
uenb.Type = oam.UENB_TYPE_DETACH
|
||||||
|
case "auth-result":
|
||||||
|
uenb.Type = oam.UENB_TYPE_AUTH
|
||||||
|
case "cm-state":
|
||||||
|
uenb.Type = oam.UENB_TYPE_CM
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := oamService.NewUENB.Resolve(uenb); err != nil {
|
||||||
|
c.JSON(200, resp.ErrMsg(err.Error()))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
c.JSON(200, resp.Ok(nil))
|
||||||
|
}
|
||||||
|
|
||||||
|
// ResolveUENBByAMF 接收终端接入基站-AMF
|
||||||
|
//
|
||||||
|
// POST /upload-ue/v1/:eventType
|
||||||
|
func (s APIRestController) ResolveUENBByAMF(c *gin.Context) {
|
||||||
|
var body map[string]any
|
||||||
|
if err := c.ShouldBindBodyWithJSON(&body); err != nil {
|
||||||
|
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
|
||||||
|
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建UENB
|
||||||
|
uenb := oam.UENB{
|
||||||
|
NeUid: "4400HXAMF001", // 网元唯一标识
|
||||||
|
RecordTime: 0, // 记录时间
|
||||||
|
NBId: "0", // 基站ID
|
||||||
|
CellId: "0", // 小区ID
|
||||||
|
TAC: "", // TAC
|
||||||
|
IMSI: "", // IMSI
|
||||||
|
Result: oam.UENB_RESULT_AUTH_SUCCESS, // 结果值
|
||||||
|
Type: oam.UENB_TYPE_DETACH, // 终端接入基站类型
|
||||||
|
}
|
||||||
|
|
||||||
|
// 从eventJson中获取rmUID
|
||||||
|
if v, ok := body["rmUID"]; ok {
|
||||||
|
uenb.NeUid = fmt.Sprint(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 统一格式
|
||||||
|
eventType := c.Param("eventType")
|
||||||
|
switch eventType {
|
||||||
|
case "auth-result":
|
||||||
|
// {"authCode":"200","authMessage":"成功","authTime":"2024-12-07 16:48:37","cellID":"3","gNBID":"1","imsi":"460002082100000","onlineNumber":1,"tacID":"81"}
|
||||||
|
if v, ok := body["imsi"]; ok {
|
||||||
|
uenb.IMSI = fmt.Sprint(v)
|
||||||
|
}
|
||||||
|
if v, ok := body["cellID"]; ok {
|
||||||
|
uenb.CellId = fmt.Sprint(v)
|
||||||
|
}
|
||||||
|
if v, ok := body["gNBID"]; ok {
|
||||||
|
uenb.NBId = fmt.Sprint(v)
|
||||||
|
}
|
||||||
|
if v, ok := body["tacID"]; ok {
|
||||||
|
uenb.TAC = fmt.Sprint(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
if v, ok := body["authCode"]; ok {
|
||||||
|
uenb.Result = fmt.Sprint(v)
|
||||||
|
}
|
||||||
|
if v, ok := body["authTime"]; ok {
|
||||||
|
authTime := date.ParseStrToDate(fmt.Sprint(v), date.YYYY_MM_DD_HH_MM_SS)
|
||||||
|
uenb.RecordTime = authTime.UnixMilli()
|
||||||
|
}
|
||||||
|
uenb.Type = oam.UENB_TYPE_AUTH
|
||||||
|
case "detach":
|
||||||
|
// {"detachResult":0,"detachTime":"2024-12-07 18:00:47","imsi":"460002082100000"}
|
||||||
|
if v, ok := body["imsi"]; ok {
|
||||||
|
uenb.IMSI = fmt.Sprint(v)
|
||||||
|
}
|
||||||
|
if v, ok := body["detachResult"]; ok {
|
||||||
|
if v == "0" {
|
||||||
|
uenb.Result = oam.UENB_RESULT_AUTH_SUCCESS
|
||||||
|
} else {
|
||||||
|
uenb.Result = fmt.Sprint(v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if v, ok := body["detachTime"]; ok {
|
||||||
|
detachTime := date.ParseStrToDate(fmt.Sprint(v), date.YYYY_MM_DD_HH_MM_SS)
|
||||||
|
uenb.RecordTime = detachTime.UnixMilli()
|
||||||
|
}
|
||||||
|
uenb.Type = oam.UENB_TYPE_DETACH
|
||||||
|
case "cm-state":
|
||||||
|
// {"changeTime":"2024-12-07 17:07:52","imsi":"460002082100000","onlineNumber":1,"status":2}
|
||||||
|
if v, ok := body["imsi"]; ok {
|
||||||
|
uenb.IMSI = fmt.Sprint(v)
|
||||||
|
}
|
||||||
|
if v, ok := body["status"]; ok {
|
||||||
|
uenb.Result = fmt.Sprint(v)
|
||||||
|
}
|
||||||
|
if v, ok := body["changeTime"]; ok {
|
||||||
|
changeTime := date.ParseStrToDate(fmt.Sprint(v), date.YYYY_MM_DD_HH_MM_SS)
|
||||||
|
uenb.RecordTime = changeTime.UnixMilli()
|
||||||
|
}
|
||||||
|
uenb.Type = oam.UENB_TYPE_CM
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := oamService.NewUENB.Resolve(uenb); err != nil {
|
||||||
|
c.JSON(200, resp.ErrMsg(err.Error()))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
c.JSON(200, resp.Ok(nil))
|
||||||
|
}
|
||||||
|
|
||||||
|
// ResolveAlarmHistory 拉取告警历史
|
||||||
|
//
|
||||||
|
// GET /faultManagement/v1/elementType/:elementTypeValue/objectType/alarms
|
||||||
|
func (s APIRestController) ResolveAlarmHistory(c *gin.Context) {
|
||||||
|
elementTypeValue := c.Param("elementTypeValue")
|
||||||
|
|
||||||
|
// Get alarms from OMC return 204
|
||||||
|
if strings.ToLower(elementTypeValue) == "omc" {
|
||||||
|
c.JSON(200, resp.OkMsg("omc alarms no content"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// alarmTypeValue 映射值
|
||||||
|
alarmTypeValue := func(str string) string {
|
||||||
|
arr := []string{
|
||||||
|
oam.ALARM_TYPE_COMMUNICATION_ALARM,
|
||||||
|
oam.ALARM_TYPE_EQUIPMENT_ALARM,
|
||||||
|
oam.ALARM_TYPE_PROCESSING_FAILURE,
|
||||||
|
oam.ALARM_TYPE_ENVIRONMENTAL_ALARM,
|
||||||
|
oam.ALARM_TYPE_QUALITY_OF_SERVICE_ALARM,
|
||||||
|
}
|
||||||
|
for k, v := range arr {
|
||||||
|
if v == str {
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
if fmt.Sprint(k+1) == str {
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return str
|
||||||
|
}
|
||||||
|
|
||||||
|
// origSeverityValue 映射值
|
||||||
|
origSeverityValue := func(str string) string {
|
||||||
|
arr := []string{
|
||||||
|
oam.ALARM_SEVERITY_CRITICAL,
|
||||||
|
oam.ALARM_SEVERITY_MAJOR,
|
||||||
|
oam.ALARM_SEVERITY_MINOR,
|
||||||
|
oam.ALARM_SEVERITY_WARNING,
|
||||||
|
oam.ALARM_SEVERITY_EVENT,
|
||||||
|
}
|
||||||
|
for k, v := range arr {
|
||||||
|
if v == str {
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
if fmt.Sprint(k+1) == str {
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return str
|
||||||
|
}
|
||||||
|
|
||||||
|
// alarmStatusValue 映射值
|
||||||
|
alarmStatusValue := func(value int) string {
|
||||||
|
arr := []string{
|
||||||
|
oam.ALARM_STATUS_CLEAR,
|
||||||
|
oam.ALARM_STATUS_ACTIVE,
|
||||||
|
}
|
||||||
|
for k, v := range arr {
|
||||||
|
if k == value {
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return oam.ALARM_STATUS_ACTIVE
|
||||||
|
}
|
||||||
|
|
||||||
|
alarmArr := make([]oam.Alarm, 0)
|
||||||
|
type body struct {
|
||||||
|
AlarmSeq int `json:"alarmSeq"`
|
||||||
|
AlarmId string `json:"alarmId"`
|
||||||
|
NeId string `json:"neId"` // 收到实际是rmUID
|
||||||
|
AlarmCode int `json:"alarmCode"`
|
||||||
|
AlarmTitle string `json:"alarmTitle"`
|
||||||
|
EventTime string `json:"eventTime"`
|
||||||
|
AlarmType string `json:"alarmType"`
|
||||||
|
OrigSeverity string `json:"origSeverity"`
|
||||||
|
PerceivedSeverity string `json:"perceivedSeverity"`
|
||||||
|
PVFlag string `json:"pvFlag"`
|
||||||
|
NeName string `json:"neName"`
|
||||||
|
NeType string `json:"neType"`
|
||||||
|
ObjectUid string `json:"objectUid"`
|
||||||
|
ObjectName string `json:"objectName"`
|
||||||
|
ObjectType string `json:"objectType"`
|
||||||
|
LocationInfo string `json:"locationInfo"`
|
||||||
|
Province string `json:"province"`
|
||||||
|
AlarmStatus int `json:"alarmStatus"`
|
||||||
|
SpecificProblem string `json:"specificProblem"`
|
||||||
|
SpecificProblemID string `json:"specificProblemID"`
|
||||||
|
AddInfo string `json:"addInfo"`
|
||||||
|
}
|
||||||
|
parseItem := func(v body) oam.Alarm {
|
||||||
|
// 产生时间
|
||||||
|
eventTime := date.ParseStrToDate(v.EventTime, time.RFC3339)
|
||||||
|
// 创建告警
|
||||||
|
alarm := oam.Alarm{
|
||||||
|
NeUid: v.NeId, // 网元唯一标识
|
||||||
|
AlarmTime: eventTime.UnixMilli(), // 事件产生时间
|
||||||
|
AlarmId: v.AlarmId, // 告警ID 唯一,清除时对应
|
||||||
|
AlarmCode: v.AlarmCode, // 告警状态码
|
||||||
|
AlarmType: alarmTypeValue(v.AlarmType), // 告警类型
|
||||||
|
AlarmTitle: v.AlarmTitle, // 告警标题
|
||||||
|
PerceivedSeverity: origSeverityValue(v.OrigSeverity), // 告警级别
|
||||||
|
AlarmStatus: alarmStatusValue(v.AlarmStatus), // 告警状态
|
||||||
|
SpecificProblem: v.SpecificProblem, // 告警问题原因
|
||||||
|
SpecificProblemID: v.SpecificProblemID, // 告警问题原因ID
|
||||||
|
AddInfo: v.AddInfo, // 告警辅助信息
|
||||||
|
LocationInfo: v.LocationInfo, // 告警定位信息
|
||||||
|
}
|
||||||
|
return alarm
|
||||||
|
}
|
||||||
|
var neInfos []neModel.NeInfo
|
||||||
|
if elementTypeValue == "all" {
|
||||||
|
neInfos = neService.NewNeInfo.Find(neModel.NeInfo{}, false, false)
|
||||||
|
} else {
|
||||||
|
neInfos = neService.NewNeInfo.FindByNeType(strings.ToUpper(elementTypeValue))
|
||||||
|
}
|
||||||
|
for _, neInfo := range neInfos {
|
||||||
|
data, err := neFetchlink.AlarmHistory(neInfo)
|
||||||
|
if err != nil {
|
||||||
|
logger.Errorf("failed to fetch alarm history:%s", err.Error())
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if len(data) == 0 {
|
||||||
|
logger.Warnf("not found sync alarms %s", neInfo.RmUID)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
bodyArr := make([]body, 0)
|
||||||
|
// 将 []map[string]any 序列化为 JSON 字符串
|
||||||
|
jsonData, err := json.Marshal(data)
|
||||||
|
if err != nil {
|
||||||
|
logger.Errorf("marshal error: %s", err.Error())
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
// 反序列化到结构体
|
||||||
|
err = json.Unmarshal(jsonData, &bodyArr)
|
||||||
|
if err != nil {
|
||||||
|
logger.Errorf("Error unmarshal error: %s", err.Error())
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, v := range bodyArr {
|
||||||
|
alarmArr = append(alarmArr, parseItem(v))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
errArr := make([]string, 0)
|
||||||
|
for _, alarm := range alarmArr {
|
||||||
|
if err := oamService.NewAlarm.Resolve(alarm); err != nil {
|
||||||
|
errArr = append(errArr, err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(errArr) > 0 {
|
||||||
|
c.JSON(200, resp.ErrData(errArr))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
c.JSON(200, resp.Ok(nil))
|
||||||
|
}
|
||||||
40
src/modules/oam/oam.go
Normal file
40
src/modules/oam/oam.go
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
package oam
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/tsmask/go-oam"
|
||||||
|
|
||||||
|
"be.ems/src/framework/logger"
|
||||||
|
"be.ems/src/modules/oam/controller"
|
||||||
|
"be.ems/src/modules/oam/service"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Setup 模块路由注册
|
||||||
|
func Setup(router *gin.Engine) {
|
||||||
|
logger.Infof("开始加载 ====> oam 模块路由")
|
||||||
|
|
||||||
|
// 网管接收端收告警
|
||||||
|
oam.AlarmReceiveRoute(router, service.NewAlarm.Resolve)
|
||||||
|
// 网管接收端收终端接入基站
|
||||||
|
oam.UENBReceiveRoute(router, service.NewUENB.Resolve)
|
||||||
|
// 网管接收端收基站状态
|
||||||
|
oam.NBStateReceiveRoute(router, service.NewNBState.Resolve)
|
||||||
|
// 网管接收端收话单
|
||||||
|
oam.CDRReceiveRoute(router, service.NewCDR.Resolve)
|
||||||
|
// 网管接收端收KPI
|
||||||
|
oam.KPIReceiveRoute(router, service.NewKPI.Resolve)
|
||||||
|
|
||||||
|
// APIRest 北向接收
|
||||||
|
aprRest := controller.NewAPIRest
|
||||||
|
aprRestGroup := router.Group("/api/rest")
|
||||||
|
{
|
||||||
|
aprRestGroup.GET("/faultManagement/v1/elementType/:elementTypeValue/objectType/alarms", aprRest.ResolveAlarmHistory)
|
||||||
|
aprRestGroup.POST("/faultManagement/v1/elementType/:elementTypeValue/objectType/alarms", aprRest.ResolveAlarm)
|
||||||
|
aprRestGroup.POST("/cdrManagement/v1/elementType/:elementTypeValue/objectType/cdrEvent", aprRest.ResolveCDR)
|
||||||
|
aprRestGroup.POST("/performanceManagement/v1/elementType/:elementTypeValue/objectType/kpiReport/:index", aprRest.ResolveKPI)
|
||||||
|
aprRestGroup.POST("/ueManagement/v1/elementType/:elementTypeValue/objectType/nbState", aprRest.ResolveNBState)
|
||||||
|
aprRestGroup.POST("/logManagement/v1/elementType/:elementTypeValue/objectType/ueEvent", aprRest.ResolveUENB)
|
||||||
|
router.POST("/upload-ue/v1/:eventType", aprRest.ResolveUENBByAMF) // AMF特殊上报
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
236
src/modules/oam/service/kpi.go
Normal file
236
src/modules/oam/service/kpi.go
Normal file
@@ -0,0 +1,236 @@
|
|||||||
|
package service
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"be.ems/src/framework/logger"
|
||||||
|
"be.ems/src/framework/utils/date"
|
||||||
|
"be.ems/src/framework/utils/expr"
|
||||||
|
"be.ems/src/framework/utils/parse"
|
||||||
|
"github.com/tsmask/go-oam"
|
||||||
|
|
||||||
|
neDataModel "be.ems/src/modules/network_data/model"
|
||||||
|
neDataService "be.ems/src/modules/network_data/service"
|
||||||
|
neModel "be.ems/src/modules/network_element/model"
|
||||||
|
neService "be.ems/src/modules/network_element/service"
|
||||||
|
wsService "be.ems/src/modules/ws/service"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 实例化服务层 KPI 结构体
|
||||||
|
var NewKPI = &KPI{
|
||||||
|
neInfoService: neService.NewNeInfo,
|
||||||
|
wsService: wsService.NewWSSend,
|
||||||
|
kpiReportService: neDataService.NewKpiReport,
|
||||||
|
kpiCReportService: neDataService.NewKpiCReport,
|
||||||
|
}
|
||||||
|
|
||||||
|
// KPI 消息处理
|
||||||
|
type KPI struct {
|
||||||
|
neInfoService *neService.NeInfo
|
||||||
|
wsService *wsService.WSSend
|
||||||
|
kpiReportService *neDataService.KpiReport
|
||||||
|
kpiCReportService *neDataService.KpiCReport
|
||||||
|
neInfo neModel.NeInfo
|
||||||
|
}
|
||||||
|
|
||||||
|
// Resolve 接收处理
|
||||||
|
func (s *KPI) Resolve(k oam.KPI) error {
|
||||||
|
if len(k.Data) == 0 {
|
||||||
|
return fmt.Errorf("kpi data is nil")
|
||||||
|
}
|
||||||
|
// 是否存在网元
|
||||||
|
s.neInfo = s.neInfoService.FindByRmuid(k.NeUid)
|
||||||
|
if s.neInfo.NeType == "" || s.neInfo.RmUID != k.NeUid {
|
||||||
|
logger.Warnf("resolve kpi network element does not exist %s", k.NeUid)
|
||||||
|
return fmt.Errorf("resolve kpi network element does not exist %s", k.NeUid)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 时间片
|
||||||
|
curTime := time.Now()
|
||||||
|
curSeconds := curTime.Hour()*3600 + curTime.Minute()*60 + curTime.Second()
|
||||||
|
index := int64(curSeconds) / k.Granularity
|
||||||
|
|
||||||
|
if err := s.saveKPIData(k, index); err != nil {
|
||||||
|
logger.Warnf("resolve kpi data fail %s", k.NeUid)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := s.saveKPIDataC(k, index); err != nil {
|
||||||
|
logger.Warnf("resolve kpic data fail %s", k.NeUid)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// saveKPIData 存储KPI数据并推送到ws订阅组
|
||||||
|
func (s *KPI) saveKPIData(k oam.KPI, index int64) error {
|
||||||
|
// 时间数据处理
|
||||||
|
recordTime := time.Now()
|
||||||
|
if k.RecordTime > 1e12 {
|
||||||
|
recordTime = time.UnixMilli(k.RecordTime)
|
||||||
|
} else if k.RecordTime > 1e9 {
|
||||||
|
recordTime = time.Unix(k.RecordTime, 0)
|
||||||
|
}
|
||||||
|
recordDate := date.ParseDateToStr(recordTime, "2006-01-02")
|
||||||
|
recordEndTime := date.ParseDateToStr(recordTime, "15:04:05")
|
||||||
|
startTime := recordTime.Add(-time.Duration(k.Granularity) * time.Second)
|
||||||
|
recordStartTime := date.ParseDateToStr(startTime, "15:04:05")
|
||||||
|
|
||||||
|
// kpi data数据json
|
||||||
|
kpiTitles := s.kpiReportService.FindTitle(s.neInfo.NeType)
|
||||||
|
KpiValues := make([]map[string]any, 0)
|
||||||
|
for _, kt := range kpiTitles {
|
||||||
|
item := map[string]any{
|
||||||
|
"kpiId": kt.KpiId,
|
||||||
|
"value": 0,
|
||||||
|
"err": "",
|
||||||
|
}
|
||||||
|
// 匹配指标记录
|
||||||
|
for k, v := range k.Data {
|
||||||
|
if k == kt.KpiId {
|
||||||
|
item["value"] = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
KpiValues = append(KpiValues, item)
|
||||||
|
}
|
||||||
|
|
||||||
|
KpiValuesByte, _ := json.Marshal(KpiValues)
|
||||||
|
|
||||||
|
// KPI 信息
|
||||||
|
kpiData := neDataModel.KpiReport{
|
||||||
|
NeType: s.neInfo.NeType,
|
||||||
|
NeName: s.neInfo.NeName,
|
||||||
|
RmUid: s.neInfo.RmUID,
|
||||||
|
Date: recordDate,
|
||||||
|
StartTime: recordStartTime,
|
||||||
|
EndTime: recordEndTime,
|
||||||
|
Index: index,
|
||||||
|
Granularity: k.Granularity,
|
||||||
|
KpiValues: string(KpiValuesByte),
|
||||||
|
CreatedAt: k.RecordTime,
|
||||||
|
}
|
||||||
|
insertId := s.kpiReportService.Insert(kpiData)
|
||||||
|
if insertId <= 0 {
|
||||||
|
return fmt.Errorf("add kpi data fail")
|
||||||
|
}
|
||||||
|
kpiData.ID = insertId
|
||||||
|
|
||||||
|
// 指标事件对象
|
||||||
|
data := map[string]any{
|
||||||
|
"neType": kpiData.NeType,
|
||||||
|
"neName": kpiData.NeName,
|
||||||
|
"rmUID": kpiData.RmUid,
|
||||||
|
"startIndex": kpiData.Index,
|
||||||
|
"timeGroup": kpiData.CreatedAt,
|
||||||
|
// kip_id ...
|
||||||
|
}
|
||||||
|
for _, v := range KpiValues {
|
||||||
|
data[fmt.Sprint(v["kpiId"])] = v["value"]
|
||||||
|
}
|
||||||
|
|
||||||
|
// 推送到ws订阅组
|
||||||
|
s.wsService.ByGroupID(fmt.Sprintf("%s_%s_%s", wsService.GROUP_KPI, s.neInfo.NeType, s.neInfo.NeId), data)
|
||||||
|
// 更新UPF总流量
|
||||||
|
if s.neInfo.NeType == "UPF" {
|
||||||
|
upValue := parse.Number(data["UPF.03"])
|
||||||
|
downValue := parse.Number(data["UPF.06"])
|
||||||
|
s.kpiReportService.UPFTodayFlowUpdate(s.neInfo.RmUID, upValue, downValue)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// saveKPIDataC 存储自定义KPI数据并推送到ws订阅组
|
||||||
|
func (s *KPI) saveKPIDataC(k oam.KPI, index int64) error {
|
||||||
|
// 时间数据处理
|
||||||
|
recordTime := time.Now()
|
||||||
|
if k.RecordTime > 1e12 {
|
||||||
|
recordTime = time.UnixMilli(k.RecordTime)
|
||||||
|
} else if k.RecordTime > 1e9 {
|
||||||
|
recordTime = time.Unix(k.RecordTime, 0)
|
||||||
|
}
|
||||||
|
recordDate := date.ParseDateToStr(recordTime, "2006-01-02")
|
||||||
|
recordEndTime := date.ParseDateToStr(recordTime, "15:04:05")
|
||||||
|
startTime := recordTime.Add(-time.Duration(k.Granularity) * time.Second)
|
||||||
|
recordStartTime := date.ParseDateToStr(startTime, "15:04:05")
|
||||||
|
|
||||||
|
// kpi data数据json
|
||||||
|
kpiCTitles := s.kpiCReportService.FindTitle(s.neInfo.NeType)
|
||||||
|
KpiValues := make([]map[string]any, 0)
|
||||||
|
// 自定义指标的表达式环境变量
|
||||||
|
KpiExprEnv := make(map[string]any, 0)
|
||||||
|
for k, v := range k.Data {
|
||||||
|
KpiExprEnv[k] = v
|
||||||
|
}
|
||||||
|
// 自定义指标的计算
|
||||||
|
for _, v := range kpiCTitles {
|
||||||
|
item := map[string]any{
|
||||||
|
"kpiId": v.KpiId,
|
||||||
|
"value": 0,
|
||||||
|
"err": "",
|
||||||
|
}
|
||||||
|
|
||||||
|
// 匹配指标记录
|
||||||
|
if envValue, envOk := KpiExprEnv[v.KpiId]; envOk {
|
||||||
|
item["value"] = envValue
|
||||||
|
}
|
||||||
|
|
||||||
|
// 计算结果
|
||||||
|
exprStr, exprEnv := expr.ParseExprEnv(v.Expression, KpiExprEnv)
|
||||||
|
result, err := expr.Eval(exprStr, exprEnv)
|
||||||
|
if err != nil {
|
||||||
|
item["value"] = 0
|
||||||
|
item["err"] = err.Error()
|
||||||
|
} else {
|
||||||
|
if v.Unit == "%" {
|
||||||
|
resultInt64 := parse.Number(result)
|
||||||
|
if resultInt64 > 100 {
|
||||||
|
result = 100
|
||||||
|
}
|
||||||
|
if resultInt64 < 0 {
|
||||||
|
result = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
item["value"] = result
|
||||||
|
}
|
||||||
|
KpiValues = append(KpiValues, item)
|
||||||
|
}
|
||||||
|
KpiValuesByte, _ := json.Marshal(KpiValues)
|
||||||
|
|
||||||
|
// KPI 信息
|
||||||
|
kpiCData := neDataModel.KpiCReport{
|
||||||
|
NeType: s.neInfo.NeType,
|
||||||
|
NeName: s.neInfo.NeName,
|
||||||
|
RmUid: s.neInfo.RmUID,
|
||||||
|
Date: recordDate,
|
||||||
|
StartTime: recordStartTime,
|
||||||
|
EndTime: recordEndTime,
|
||||||
|
Index: index,
|
||||||
|
Granularity: k.Granularity,
|
||||||
|
KpiValues: string(KpiValuesByte),
|
||||||
|
CreatedAt: k.RecordTime,
|
||||||
|
}
|
||||||
|
insertId := s.kpiCReportService.Insert(kpiCData)
|
||||||
|
if insertId <= 0 {
|
||||||
|
return fmt.Errorf("add kpic data fail")
|
||||||
|
}
|
||||||
|
kpiCData.ID = insertId
|
||||||
|
|
||||||
|
// 指标事件对象
|
||||||
|
data := map[string]any{
|
||||||
|
"neType": kpiCData.NeType,
|
||||||
|
"neName": kpiCData.NeName,
|
||||||
|
"rmUID": kpiCData.RmUid,
|
||||||
|
"startIndex": kpiCData.Index,
|
||||||
|
"timeGroup": kpiCData.CreatedAt,
|
||||||
|
// kip_id ...
|
||||||
|
}
|
||||||
|
for _, v := range KpiValues {
|
||||||
|
data[fmt.Sprint(v["kpiId"])] = v["value"]
|
||||||
|
}
|
||||||
|
|
||||||
|
// 推送到ws订阅组
|
||||||
|
s.wsService.ByGroupID(fmt.Sprintf("%s_%s_%s", wsService.GROUP_KPI_C, s.neInfo.NeType, s.neInfo.NeId), data)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
67
src/modules/oam/service/nb_state.go
Normal file
67
src/modules/oam/service/nb_state.go
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
package service
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"be.ems/src/framework/logger"
|
||||||
|
"be.ems/src/framework/utils/date"
|
||||||
|
"github.com/tsmask/go-oam"
|
||||||
|
|
||||||
|
neDataModel "be.ems/src/modules/network_data/model"
|
||||||
|
neDataService "be.ems/src/modules/network_data/service"
|
||||||
|
neService "be.ems/src/modules/network_element/service"
|
||||||
|
wsService "be.ems/src/modules/ws/service"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 实例化服务层 NBState 结构体
|
||||||
|
var NewNBState = &NBState{
|
||||||
|
neInfoService: neService.NewNeInfo,
|
||||||
|
wsService: wsService.NewWSSend,
|
||||||
|
nbStateService: neDataService.NewNBState,
|
||||||
|
}
|
||||||
|
|
||||||
|
// NBState 消息处理
|
||||||
|
type NBState struct {
|
||||||
|
neInfoService *neService.NeInfo
|
||||||
|
wsService *wsService.WSSend
|
||||||
|
nbStateService *neDataService.NBState
|
||||||
|
}
|
||||||
|
|
||||||
|
// Resolve 接收处理
|
||||||
|
func (s *NBState) Resolve(n oam.NBState) error {
|
||||||
|
// 是否存在网元
|
||||||
|
neInfo := s.neInfoService.FindByRmuid(n.NeUid)
|
||||||
|
if neInfo.NeType == "" || neInfo.RmUID != n.NeUid {
|
||||||
|
logger.Warnf("resolve nb_state network element does not exist %s", n.NeUid)
|
||||||
|
return fmt.Errorf("resolve nb_state network element does not exist %s", n.NeUid)
|
||||||
|
}
|
||||||
|
|
||||||
|
nbState := neDataModel.NBState{
|
||||||
|
NeType: neInfo.NeType,
|
||||||
|
NeId: neInfo.NeId,
|
||||||
|
RmUid: neInfo.RmUID,
|
||||||
|
Address: n.Address,
|
||||||
|
Name: n.Name,
|
||||||
|
Position: n.Position,
|
||||||
|
NbName: n.DeviceName,
|
||||||
|
State: n.State,
|
||||||
|
Time: date.ParseDateToStr(n.StateTime, time.RFC3339),
|
||||||
|
}
|
||||||
|
insertId := s.nbStateService.Insert(nbState)
|
||||||
|
if insertId <= 0 {
|
||||||
|
return fmt.Errorf("add nb_state data fail")
|
||||||
|
}
|
||||||
|
nbState.ID = insertId
|
||||||
|
|
||||||
|
// 推送到ws订阅组
|
||||||
|
switch neInfo.NeType {
|
||||||
|
case "AMF":
|
||||||
|
s.wsService.ByGroupID(wsService.GROUP_AMF_NB, nbState)
|
||||||
|
s.wsService.ByGroupID(fmt.Sprintf("%s_%s", wsService.GROUP_AMF_NB, neInfo.NeId), nbState)
|
||||||
|
case "MME":
|
||||||
|
s.wsService.ByGroupID(wsService.GROUP_MME_NB, nbState)
|
||||||
|
s.wsService.ByGroupID(fmt.Sprintf("%s_%s", wsService.GROUP_MME_NB, neInfo.NeId), nbState)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user