Files
be.ems/features/fm/alarm.go

572 lines
17 KiB
Go

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"))
}