package fm import ( "database/sql" "encoding/json" "fmt" "net/http" "strings" "be.ems/lib/config" "be.ems/lib/core/ctx" "be.ems/lib/global" "be.ems/lib/log" "be.ems/lib/services" "be.ems/src/framework/constants" "be.ems/src/framework/resp" "be.ems/src/framework/utils/date" 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" neFetchlink "be.ems/src/modules/network_link/fetch_link" traceService "be.ems/src/modules/trace/service" wsService "be.ems/src/modules/ws/service" ) const ( AlarmStatusClear = 0 AlarmStatusActive = 1 AlarmStatusClearString = "0" AlarmStatusActiveString = "1" ) const ( ClearTypeUnclear = 0 ClearTypeAutoClear = 1 ClearTypeManualClear = 2 ) const ( AckStateUnacked = 0 AckStateAcked = 1 ) const ( AlarmTypeCommunicationAlarm = 1 AlarmTypeEquipmentAlarm = 2 AlarmTypeProcessingFailure = 3 AlarmTypeEnvironmentalAlarm = 4 AlarmTypeQualityOfServiceAlarm = 5 ) const ( AlarmPerceivedSeverityCritical = 1 AlarmPerceivedSeverityMajor = 2 AlarmPerceivedSeverityMinor = 3 AlarmPerceivedSeverityWarning = 4 AlarmPerceivedSeverityEvent = 5 ) const ( AlarmSeqBeginNumber = 1 ) type Alarm struct { AlarmSeq int `json:"alarmSeq"` AlarmId string `json:"alarmId" xorm:"alarm_id"` 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" xorm:"pv_flag"` NeName string `json:"neName"` NeType string `json:"neType"` ObjectUid string `json:"objectUid" xorm:"object_uid"` ObjectName string `json:"objectName" xorm:"object_name"` ObjectType string `json:"objectType" xorm:"object_type"` LocationInfo string `json:"locationInfo"` Province string `json:"province"` AlarmStatus int `json:"alarmStatus"` SpecificProblem string `json:"specificProblem"` SpecificProblemID string `json:"specificProblemID" xorm:"specific_problem_id"` AddInfo string `json:"addInfo"` AckState int `json:"ackState"` AckTime sql.NullTime `json:"ackTime"` AckUser string `json:"ackUser"` ClearType int `json:"clearType"` // 0: Unclear, 1: Auto clear, 2: Manual clear ClearTime sql.NullTime `json:"clearTime"` } var ( // alarm management UriAlarms = config.DefaultUriPrefix + "/faultManagement/{apiVersion}/elementType/{elementTypeValue}/objectType/alarms" UriAlarmsFmt = config.DefaultUriPrefix + "/faultManagement/v1/elementType/%s/objectType/alarms" CustomUriAlarms = config.UriPrefix + "/faultManagement/{apiVersion}/elementType/{elementTypeValue}/objectType/alarms" CustomUriAlarmsFmt = config.UriPrefix + "/faultManagement/v1/elementType/%s/objectType/alarms" ) // PostAlarmFromNF 网元告警数据上报接收 func PostAlarmFromNF(w http.ResponseWriter, r *http.Request) { log.Debug("PostAlarmFromNF processing... ") apiVer := ctx.GetParam(r, "apiVersion") if apiVer != global.ApiVersionV1 { log.Error("Uri api version is invalid. apiVersion:", apiVer) services.ResponseWithJson(w, 422, resp.CodeMsg(40422, "api version is invalid")) return } var body []Alarm if err := ctx.ShouldBindJSON(r, &body); err != nil { services.ResponseWithJson(w, 422, resp.ErrMsg(err.Error())) return } // service object neService := neService.NewNeInfo for _, v := range body { log.Debug("alarmData:", v) // 是否存在网元 neId实际是rmUID neInfo := neService.FindByCoreUidAndNeUid("*", v.NeId) if neInfo.NeType != v.NeType { msg := fmt.Sprintf("network element does not exist %s", v.NeId) services.ResponseWithJson(w, 400, resp.ErrMsg(msg)) return } // 记录日志 alarmSaveLog(neInfo, v) // 补充默认信息 if v.LocationInfo == "" { v.LocationInfo = fmt.Sprintf("Remote Host:%s", r.RemoteAddr) } if v.AddInfo == "" { v.AddInfo = fmt.Sprintf("NeInfo:%s", v.NeType) } if v.ObjectUid == "" { v.ObjectUid = neInfo.NeUID } if v.ObjectName == "" { v.ObjectName = neInfo.NeName } if v.ObjectType == "" { v.ObjectType = neInfo.NeType } // 告警事件 if v.OrigSeverity == "Event" || v.OrigSeverity == "5" { if v.AlarmStatus == AlarmStatusClear { // 进行清除 clearAlarmEvent, err := alarmEventClear(neInfo, v) if err != nil { services.ResponseWithJson(w, 400, resp.ErrMsg(err.Error())) return } groupID := fmt.Sprintf("%s_%s_%s", wsService.GROUP_ALARM_EVENT, neInfo.CoreUID, neInfo.NeUID) wsService.NewWSSend.ByGroupID(groupID, clearAlarmEvent) } if v.AlarmStatus == AlarmStatusActive { // 进行新增 newAlarmEvent, err := alarmEventNew(neInfo, v) if err != nil { services.ResponseWithJson(w, 400, resp.ErrMsg(err.Error())) return } groupID := fmt.Sprintf("%s_%s_%s", wsService.GROUP_ALARM_EVENT, neInfo.CoreUID, neInfo.NeUID) wsService.NewWSSend.ByGroupID(groupID, newAlarmEvent) } continue } if v.AlarmStatus == AlarmStatusClear { // 进行清除 clearAlarm, err := alarmClear(neInfo, v) if err != nil { services.ResponseWithJson(w, 400, resp.ErrMsg(err.Error())) return } groupID := fmt.Sprintf("%s_%s_%s", wsService.GROUP_ALARM, neInfo.CoreUID, neInfo.NeUID) wsService.NewWSSend.ByGroupID(groupID, clearAlarm) } if v.AlarmStatus == AlarmStatusActive { // 进行新增 newAlarm, err := alarmNew(neInfo, v) if err != nil { services.ResponseWithJson(w, 400, resp.ErrMsg(err.Error())) return } groupID := fmt.Sprintf("%s_%s_%s", wsService.GROUP_ALARM, neInfo.CoreUID, neInfo.NeUID) wsService.NewWSSend.ByGroupID(groupID, newAlarm) } // for alarm forward 告警转发 alarmForward(v) } services.ResponseStatusOK204NoContent(w) } // alarmTypeValue 映射值 func alarmTypeValue(str string) string { arr := []string{"CommunicationAlarm", "EquipmentAlarm", "ProcessingFailure", "EnvironmentalAlarm", "QualityOfServiceAlarm"} for k, v := range arr { if v == str { return fmt.Sprint(k + 1) } } return str } // origSeverityValue 映射值 func origSeverityValue(str string) string { arr := []string{"Critical", "Major", "Minor", "Warning", "Event"} for k, v := range arr { if v == str { return fmt.Sprint(k + 1) } } return str } // alarmClear 清除告警 func alarmClear(neInfo neModel.NeInfo, v Alarm) (neDataModel.Alarm, error) { alarmService := neDataService.NewAlarm // 检查网元告警ID是否唯一 alarmIdArr := alarmService.Find(neDataModel.Alarm{ CoreUID: neInfo.CoreUID, NeUID: neInfo.NeUID, NeType: neInfo.NeType, AlarmId: v.AlarmId, }) if len(alarmIdArr) != 1 { return neDataModel.Alarm{}, fmt.Errorf("[%s %s] clear alarm not exists alarmId:%s", neInfo.CoreUID, neInfo.NeUID, v.AlarmId) } // 产生时间 eventTime := date.ParseStrToDate(v.EventTime, date.YYYY_MM_DDTHH_MM_SSZ) alarm := neDataModel.Alarm{ ID: alarmIdArr[0].ID, CoreUID: neInfo.CoreUID, NeUID: neInfo.NeUID, NeType: neInfo.NeType, AlarmSeq: alarmIdArr[0].AlarmSeq, // seq 告警序号 AlarmId: v.AlarmId, AlarmTitle: v.AlarmTitle, AlarmCode: int64(v.AlarmCode), EventTime: eventTime.UnixMilli(), AlarmType: alarmTypeValue(v.AlarmType), OrigSeverity: origSeverityValue(v.OrigSeverity), PerceivedSeverity: origSeverityValue(v.PerceivedSeverity), ObjectUid: v.ObjectUid, ObjectName: v.ObjectName, ObjectType: v.ObjectType, LocationInfo: v.LocationInfo, AlarmStatus: fmt.Sprint(v.AlarmStatus), SpecificProblem: v.SpecificProblem, SpecificProblemId: v.SpecificProblemID, AddInfo: v.AddInfo, } // 告警清除 alarm.ClearType = ClearTypeAutoClear alarm.ClearTime = eventTime.UnixMilli() alarm.ClearUser = neInfo.NeName rows := alarmService.Update(alarm) if rows > 0 { return alarm, nil } return neDataModel.Alarm{}, fmt.Errorf("[%s %s] clear alarm fail", neInfo.CoreUID, neInfo.NeUID) } // alarmNew 新增告警 func alarmNew(neInfo neModel.NeInfo, v Alarm) (neDataModel.Alarm, error) { alarmService := neDataService.NewAlarm // 检查网元告警ID是否唯一 alarmIdArr := alarmService.Find(neDataModel.Alarm{ CoreUID: neInfo.CoreUID, NeUID: neInfo.NeUID, NeType: neInfo.NeType, AlarmId: v.AlarmId, }) if len(alarmIdArr) > 0 { return neDataModel.Alarm{}, fmt.Errorf("[%s %s] new alarm already exists alarmId:%s", neInfo.CoreUID, neInfo.NeUID, v.AlarmId) } // seq 告警序号 lastSeq := alarmService.FindAlarmSeqLast(neInfo.CoreUID, neInfo.NeUID) // 产生时间 eventTime := date.ParseStrToDate(v.EventTime, date.YYYY_MM_DDTHH_MM_SSZ) alarm := neDataModel.Alarm{ CoreUID: neInfo.CoreUID, NeUID: neInfo.NeUID, NeType: neInfo.NeType, AlarmSeq: lastSeq + 1, AlarmId: v.AlarmId, AlarmTitle: v.AlarmTitle, AlarmCode: int64(v.AlarmCode), EventTime: eventTime.UnixMilli(), AlarmType: alarmTypeValue(v.AlarmType), OrigSeverity: origSeverityValue(v.OrigSeverity), PerceivedSeverity: origSeverityValue(v.PerceivedSeverity), ObjectUid: v.ObjectUid, ObjectName: v.ObjectName, ObjectType: v.ObjectType, LocationInfo: v.LocationInfo, AlarmStatus: fmt.Sprint(v.AlarmStatus), SpecificProblem: v.SpecificProblem, SpecificProblemId: v.SpecificProblemID, AddInfo: v.AddInfo, } insertId := alarmService.Insert(alarm) if insertId > 0 { alarm.ID = insertId return alarm, nil } return neDataModel.Alarm{}, fmt.Errorf("[%s %s] new alarm fail", neInfo.CoreUID, neInfo.NeUID) } // alarmSaveLog 保存告警日志 func alarmSaveLog(neInfo neModel.NeInfo, v Alarm) int64 { alarmLogService := neDataService.NewAlarmLog eventTime := date.ParseStrToDate(v.EventTime, date.YYYY_MM_DDTHH_MM_SSZ) alarmLog := neDataModel.AlarmLog{ CoreUID: neInfo.CoreUID, NeUID: neInfo.NeUID, NeType: neInfo.NeType, AlarmSeq: int64(v.AlarmSeq), AlarmId: v.AlarmId, AlarmTitle: v.AlarmTitle, AlarmCode: int64(v.AlarmCode), AlarmStatus: fmt.Sprint(v.AlarmStatus), AlarmType: alarmTypeValue(v.AlarmType), OrigSeverity: origSeverityValue(v.OrigSeverity), EventTime: eventTime.UnixMilli(), } return alarmLogService.Insert(alarmLog) } // alarmForward 告警转发 func alarmForward(v Alarm) { if config.GetYamlConfig().Alarm.EmailForward.Enable { if err := AlarmEmailForward(&v); err != nil { log.Error("Failed to AlarmEmailForward:", err) } } if config.GetYamlConfig().Alarm.SMSCForward.Enable { if err := AlarmSMSForward(&v); err != nil { log.Error("Failed to AlarmSMSForward:", err) } } } // alarmEventClear 清除告警事件 func alarmEventClear(neInfo neModel.NeInfo, v Alarm) (neDataModel.AlarmEvent, error) { alarmEventService := neDataService.NewAlarmEvent // 检查网元告警ID是否唯一 alarmIdArr := alarmEventService.Find(neDataModel.AlarmEvent{ CoreUID: neInfo.CoreUID, NeUID: neInfo.NeUID, NeType: neInfo.NeType, AlarmId: v.AlarmId, }) if len(alarmIdArr) != 1 { return neDataModel.AlarmEvent{}, fmt.Errorf("[%s %s] clear alarm event not exists alarmId:%s", neInfo.CoreUID, neInfo.NeUID, v.AlarmId) } // 产生时间 eventTime := date.ParseStrToDate(v.EventTime, date.YYYY_MM_DDTHH_MM_SSZ) alarmEvent := neDataModel.AlarmEvent{ ID: alarmIdArr[0].ID, CoreUID: neInfo.CoreUID, NeUID: neInfo.NeUID, NeType: neInfo.NeType, AlarmSeq: alarmIdArr[0].AlarmSeq, // seq 告警序号 AlarmId: v.AlarmId, AlarmTitle: v.AlarmTitle, AlarmCode: int64(v.AlarmCode), EventTime: eventTime.UnixMilli(), ObjectUid: v.ObjectUid, ObjectName: v.ObjectName, ObjectType: v.ObjectType, LocationInfo: v.LocationInfo, AlarmStatus: fmt.Sprint(v.AlarmStatus), SpecificProblem: v.SpecificProblem, SpecificProblemId: v.SpecificProblemID, AddInfo: v.AddInfo, } // 告警清除 alarmEvent.ClearType = ClearTypeAutoClear alarmEvent.ClearTime = eventTime.UnixMilli() alarmEvent.ClearUser = neInfo.NeName rows := alarmEventService.Update(alarmEvent) if rows > 0 { return alarmEvent, nil } return neDataModel.AlarmEvent{}, fmt.Errorf("[%s %s] clear alarm event fail", neInfo.CoreUID, neInfo.NeUID) } // alarmEventNew 新增告警事件 func alarmEventNew(neInfo neModel.NeInfo, v Alarm) (neDataModel.AlarmEvent, error) { alarmEventService := neDataService.NewAlarmEvent // 检查网元告警ID是否唯一 alarmIdArr := alarmEventService.Find(neDataModel.AlarmEvent{ CoreUID: neInfo.CoreUID, NeUID: neInfo.NeUID, NeType: neInfo.NeType, AlarmId: v.AlarmId, }) if len(alarmIdArr) > 0 { return neDataModel.AlarmEvent{}, fmt.Errorf("[%s %s] new alarm event already exists alarmId:%s", neInfo.CoreUID, neInfo.NeUID, v.AlarmId) } // seq 告警序号 lastSeq := alarmEventService.FindAlarmEventSeqLast(neInfo.CoreUID, neInfo.NeUID) // 产生时间 eventTime := date.ParseStrToDate(v.EventTime, date.YYYY_MM_DDTHH_MM_SSZ) alarmEvent := neDataModel.AlarmEvent{ CoreUID: neInfo.CoreUID, NeUID: neInfo.NeUID, NeType: neInfo.NeType, AlarmSeq: lastSeq + 1, AlarmId: v.AlarmId, AlarmTitle: v.AlarmTitle, AlarmCode: int64(v.AlarmCode), EventTime: eventTime.UnixMilli(), ObjectUid: v.ObjectUid, ObjectName: v.ObjectName, ObjectType: v.ObjectType, LocationInfo: v.LocationInfo, AlarmStatus: fmt.Sprint(v.AlarmStatus), SpecificProblem: v.SpecificProblem, SpecificProblemId: v.SpecificProblemID, AddInfo: v.AddInfo, } insertId := alarmEventService.Insert(alarmEvent) if insertId > 0 { alarmEvent.ID = insertId // 网元重启后,清除活动告警 if v.AlarmCode == constants.ALARM_EVENT_REBOOT { alarmService := neDataService.NewAlarm rows := alarmService.Find(neDataModel.Alarm{ CoreUID: neInfo.CoreUID, NeUID: neInfo.NeUID, NeType: neInfo.NeType, AlarmStatus: "1", }) for _, v := range rows { alarmService.AlarmClearByIds([]int64{v.ID}, "system") } } // 网元重启后,有跟踪任务的需要重新补发启动任务 if v.AlarmCode == constants.ALARM_EVENT_REBOOT { traceService.NewTraceTask.RunUnstopped(neInfo.CoreUID, neInfo.NeUID) } return alarmEvent, nil } return neDataModel.AlarmEvent{}, fmt.Errorf("[%s %s] new alarm event fail", neInfo.CoreUID, neInfo.NeUID) } // mapToAlarm 将 []map[string]any 转换为 []Alarm func mapToAlarm(data []map[string]any) []Alarm { var result []Alarm // 将 []map[string]any 序列化为 JSON 字符串 jsonData, err := json.Marshal(data) if err != nil { log.Error("Error marshaling data:", err) return result } // 反序列化到结构体 err = json.Unmarshal(jsonData, &result) if err != nil { log.Error("Error unmarshaling data:", err) return result } return result } // GetAlarmFromNF 告警历史数据,从网元获取 func GetAlarmFromNF(w http.ResponseWriter, r *http.Request) { log.Debug("GetAlarmFromNF processing... ") neType := ctx.GetParam(r, "elementTypeValue") neTypeLower := strings.ToLower(neType) // Get alarms from OMC return 204 if neTypeLower == strings.ToLower(config.GetYamlConfig().OMC.NeType) { log.Infof("Return no content alarms from %s", neType) services.ResponseWithJson(w, 200, resp.ErrMsg("omc alarms no content")) return } neInfos := neService.NewNeInfo.Find(neModel.NeInfo{}, false, false) for _, neInfo := range neInfos { data, err := neFetchlink.AlarmHistory(neInfo) if err != nil { log.Error("Failed to fetch alarm history:", err) continue } if len(data) == 0 { log.Infof("Not found sync alarms, neType=%s, neId=%s", neInfo.CoreUID, neInfo.NeUID) continue } alarms := mapToAlarm(data) for _, v := range alarms { // 补充默认信息 if v.LocationInfo == "" { v.LocationInfo = fmt.Sprintf("Remote Host:%s", r.RemoteAddr) } if v.AddInfo == "" { v.AddInfo = fmt.Sprintf("NeInfo:%s", v.NeType) } if v.ObjectUid == "" { v.ObjectUid = neInfo.NeUID } if v.ObjectName == "" { v.ObjectName = neInfo.NeName } if v.ObjectType == "" { v.ObjectType = neInfo.NeType } // 告警事件 if v.OrigSeverity == "Event" || v.OrigSeverity == "5" { if v.AlarmStatus == AlarmStatusClear { // 进行清除 if _, err := alarmEventClear(neInfo, v); err != nil { log.Error("Failed to alarmEventClear:", err) continue } } if v.AlarmStatus == AlarmStatusActive { // 进行新增 if _, err := alarmEventNew(neInfo, v); err != nil { log.Error("Failed to alarmEventNew:", err) continue } } continue } if v.AlarmStatus == AlarmStatusClear { // 进行清除 if _, err := alarmClear(neInfo, v); err != nil { log.Error("Failed to alarmClear:", err) continue } } if v.AlarmStatus == AlarmStatusActive { // 进行新增 if _, err := alarmNew(neInfo, v); err != nil { log.Error("Failed to alarmNew:", err) continue } } } } services.ResponseWithJson(w, 200, resp.OkMsg("sync alarms success")) }