feat: omc原始代码

This commit is contained in:
TsMask
2024-03-12 10:58:33 +08:00
parent 5133c93971
commit 2d01bb86d1
432 changed files with 66597 additions and 1 deletions

748
features/fm/alarm.go Normal file
View File

@@ -0,0 +1,748 @@
package fm
import (
"database/sql"
"encoding/json"
"fmt"
"io"
"net/http"
"strconv"
"strings"
"time"
"nms_nbi/lib/dborm"
"nms_nbi/lib/global"
"nms_nbi/lib/log"
"nms_nbi/lib/services"
"nms_nbi/restagent/config"
"xorm.io/xorm"
"github.com/go-resty/resty/v2"
_ "github.com/go-sql-driver/mysql"
"github.com/gorilla/mux"
)
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 Response struct {
Data interface{} `json:"data"`
}
type Alarm struct {
AlarmSeq int `json:"alarmSeq"`
AlarmId string `json:"alarmId" xorm:"alarm_id"`
NeId string `json:"neId"`
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"`
}
type AlarmLog struct {
NeType string `json:"neType" xorm:"ne_type"`
NeId string `json:"neId" xorm:"ne_id"`
AlarmSeq int `json:"alarmSeq" xorm:"alarm_seq"`
AlarmId string `json:"alarmId" xorm:"alarm_id"`
AlarmCode int `json:"alarmCode" xorm:"alarm_code"`
AlarmStatus int `json:"alarmStatus" xorm:"alarm_status"`
EventTime string `json:"eventTime" xorm:"event_time"`
// ClearTime sql.NullTime `json:"clearTime" xorm:"clear_time"`
LogTime string `json:"logTime" xorm:"-"`
}
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"
)
var client = resty.New()
func init() {
/*
client.
SetTimeout(10 * time.Second).
SetRetryCount(1).
SetRetryWaitTime(1 * time.Second).
SetRetryMaxWaitTime(2 * time.Second).
SetRetryAfter(func(client *resty.Client, resp *resty.Response) (time.Duration, error) {
return 0, errors.New("quota exceeded")
})
*/
client.
SetTimeout(time.Duration(500 * time.Millisecond))
// SetRetryCount(1).
// SetRetryWaitTime(time.Duration(1 * time.Second)).
// SetRetryMaxWaitTime(time.Duration(2 * time.Second))
//client.SetTimeout(2 * time.Second)
}
var xEngine *xorm.Engine
type DatabaseClient struct {
dbType string
dbUrl string
dbConnMaxLifetime time.Duration
dbMaxIdleConns int
dbMaxOpenConns int
IsShowSQL bool
XEngine *xorm.Engine
}
var DbClient DatabaseClient
func InitDbClient(dbType, dbUser, dbPassword, dbHost, dbPort, dbName string) error {
DbClient.dbUrl = fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=utf8mb4&collation=utf8mb4_general_ci&parseTime=true&loc=Local",
dbUser, dbPassword, dbHost, dbPort, dbName)
DbClient.dbType = dbType
DbClient.dbConnMaxLifetime = 0
DbClient.dbMaxIdleConns = 0
DbClient.dbMaxOpenConns = 0
if log.GetLevel() == log.LOG_TRACE {
DbClient.IsShowSQL = true
}
log.Debugf("dbType:%s dbUrl:%s:******@tcp(%s:%s)/%s??charset=utf8mb4&collation=utf8mb4_general_ci&parseTime=true&loc=Local",
dbType, dbUser, dbHost, dbPort, dbName)
var err error
DbClient.XEngine, err = xorm.NewEngine(DbClient.dbType, DbClient.dbUrl)
if err != nil {
log.Error("Failed to connet database:", err)
return err
}
DbClient.XEngine.SetConnMaxLifetime(DbClient.dbConnMaxLifetime)
DbClient.XEngine.SetMaxIdleConns(DbClient.dbMaxIdleConns)
DbClient.XEngine.SetMaxOpenConns(DbClient.dbMaxOpenConns)
if DbClient.IsShowSQL {
DbClient.XEngine.ShowSQL(true)
}
xEngine = DbClient.XEngine
return nil
}
func XormConnectDatabase(dbType, dbUser, dbPassword, dbHost, dbPort, dbName string) (*xorm.Engine, error) {
sqlStr := fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=utf8mb4&collation=utf8mb4_general_ci&parseTime=true&loc=Local",
dbUser, dbPassword, dbHost, dbPort, dbName)
log.Debugf("dbType:%s Connect to:%s:******@tcp(%s:%s)/%s?charset=utf8mb4&collation=utf8mb4_general_ci&parseTime=true&loc=Local",
dbType, dbUser, dbHost, dbPort, dbName)
var err error
xEngine, err = xorm.NewEngine(dbType, sqlStr) //1、Create xorm engine
if err != nil {
log.Error("Failed to connect database:", err)
return nil, err
}
if log.GetLevel() == log.LOG_TRACE {
xEngine.ShowSQL(true)
}
return xEngine, nil
}
func IsNeedToAckAlarm(valueJson *dborm.ValueJson, alarm *Alarm) bool {
log.Info("IsNeedToAckAlarm processing... ")
if valueJson != nil {
status, _ := strconv.Atoi(valueJson.AlarmStatus)
log.Tracef("alarm.AlarmStatus=%d, alarm.AlarmType=%s, alarm.OrigSeverity=%s", alarm.AlarmStatus, alarm.AlarmType, alarm.OrigSeverity)
log.Tracef("status=%d, valueJson.AlarmType=%s, valueJson.OrigSeverity=%s", status, valueJson.AlarmType, valueJson.OrigSeverity)
if alarm.AlarmStatus == status &&
alarm.AlarmType == valueJson.AlarmType &&
alarm.OrigSeverity == valueJson.OrigSeverity {
return true
}
}
return false
}
func SetAlarmAckInfo(valueJson *dborm.ValueJson, alarm *Alarm) {
log.Info("SetAlarmAckInfo processing... ")
alarm.AckState = AckStateAcked
alarm.AckTime.Valid = true
alarm.AckTime.Time = time.Now()
alarm.AckUser = valueJson.AckUser
}
// process alarm post message from NFs
func PostAlarmFromNF(w http.ResponseWriter, r *http.Request) {
log.Debug("PostAlarmFromNF processing... ")
vars := mux.Vars(r)
apiVer := vars["apiVersion"]
if apiVer != global.ApiVersionV1 {
log.Error("Uri api version is invalid. apiVersion:", apiVer)
services.ResponseNotFound404UriNotExist(w, r)
return
}
body, err := io.ReadAll(io.LimitReader(r.Body, global.RequestBodyMaxLen))
if err != nil {
log.Error("io.ReadAll is failed:", err)
services.ResponseNotFound404UriNotExist(w, r)
return
}
log.Debug("Request body:", string(body))
alarmArray := new([]Alarm)
err = json.Unmarshal(body, &alarmArray)
if err != nil {
log.Error("Failed to Unmarshal:", err)
services.ResponseBadRequest400InvalidJson(w)
return
}
valueJson, err := dborm.XormGetAAConfig()
if err != nil {
log.Error("Failed to XormGetAAConfig:", err)
//services.ResponseInternalServerError500ProcessError(w, err)
//return
}
log.Trace("valueJson:", valueJson)
// session := xEngine.NewSession()
// defer session.Close()
var activeAlarmNum int = 0
for _, alarmData := range *alarmArray {
log.Debug("alarmData:", alarmData)
session := xEngine.NewSession()
defer session.Close()
if alarmData.AlarmStatus == AlarmStatusClear {
alarmData.ClearType = ClearTypeAutoClear
alarmData.ClearTime.Valid = true
tm, _ := time.Parse(time.RFC3339, alarmData.EventTime)
log.Debugf("EventTime:%s tm:%d tm-datetime:%s", alarmData.EventTime, tm, tm.Local().Format(time.DateTime))
alarmData.ClearTime.Time = tm
if IsNeedToAckAlarm(valueJson, &alarmData) {
SetAlarmAckInfo(valueJson, &alarmData)
affected, err := session.Where("ne_type=? and ne_id=? and alarm_id=? and alarm_status=1", alarmData.NeType, alarmData.NeId, alarmData.AlarmId).
Cols("alarm_status", "clear_type", "clear_time", "ack_state", "ack_time", "ack_user").
Update(alarmData)
if err != nil && affected <= 0 {
log.Error("Failed to update alarm data:", err)
services.ResponseInternalServerError500DatabaseOperationFailed(w)
continue
}
} else {
affected, err := session.Where("ne_type=? and ne_id=? and alarm_id=? and alarm_status=1", alarmData.NeType, alarmData.NeId, alarmData.AlarmId).
Cols("alarm_status", "clear_type", "clear_time").
Update(alarmData)
if err != nil && affected <= 0 {
log.Error("Failed to update alarm data:", err)
services.ResponseInternalServerError500DatabaseOperationFailed(w)
continue
}
}
log.Trace("alarmData:", alarmData)
var currentSeq string
var seq int
has, err := xEngine.Table("alarm").
Where("ne_type=? and ne_id=?", alarmData.NeType, alarmData.NeId).
Desc("alarm_seq").
Cols("alarm_seq").
Limit(1).
Get(&currentSeq)
if err != nil {
log.Error("Failed to get alarm:", err)
continue
}
if has {
seq, _ = strconv.Atoi(currentSeq)
}
eventTime := global.GetFmtTimeString(time.RFC3339, alarmData.EventTime, time.DateTime)
alarmLog := new(AlarmLog)
alarmLog.NeType = alarmData.NeType
alarmLog.NeId = alarmData.NeId
alarmLog.AlarmSeq = seq
alarmLog.AlarmId = alarmData.AlarmId
alarmLog.AlarmCode = alarmData.AlarmCode
alarmLog.AlarmStatus = alarmData.AlarmStatus
alarmLog.EventTime = eventTime
log.Debug("alarmLog:", alarmLog)
affected, err := session.Insert(alarmLog)
if err != nil && affected <= 0 {
log.Error("Failed to insert alarm_log:", err)
}
// todo: PerceivedSeverity set color
var severity string
has, err = xEngine.Table("alarm").
Where("ne_type=? and ne_id=? and event_time=? and alarm_status=1", alarmData.NeType, alarmData.NeId, alarmData.EventTime).
//OrderBy("FIELD(orig_severity, 'Critical', 'Major', 'Minor', 'Warning', 'Event') ASC").
Asc("orig_severity").
Cols("orig_severity").
Limit(1).
Get(&severity)
if err != nil {
log.Error("Failed to get alarm:", err)
continue
}
log.Debugf("neType=%s, neId=%s, eventTime=%s, severity=%s", alarmData.NeType, alarmData.NeId, alarmData.EventTime, severity)
if has && severity > alarmData.OrigSeverity {
// update exist record
_, err := session.Table("alarm").
Where("ne_type=? and ne_id=? and event_time=? and alarm_status=1", alarmData.NeType, alarmData.NeId, alarmData.EventTime).
Update(&Alarm{PerceivedSeverity: severity})
if err != nil {
log.Error("Failed to update alarm:", err)
continue
}
}
session.Commit()
// for alarm forward time format
alarmData.EventTime = eventTime
} else {
activeAlarmNum++
has, err := xEngine.Table("alarm").
Where("alarm_id=? and ne_type=? and ne_id=? and alarm_status=1",
alarmData.AlarmId, alarmData.NeType, alarmData.NeId).
Exist()
if err == nil && has {
log.Warn("Exist the same alarm")
continue
}
var currentSeq string
has, err = xEngine.Table("alarm").
Where("ne_type=? and ne_id=?", alarmData.NeType, alarmData.NeId).
Desc("alarm_seq").
//Desc("event_time").
Cols("alarm_seq").
Limit(1).
Get(&currentSeq)
if err != nil {
log.Error("Failed to get alarm:", err)
continue
}
log.Debugf("neType=%s, neId=%s, currentSeq=%s activeAlarmNum=%d",
alarmData.NeType, alarmData.NeId, currentSeq, activeAlarmNum)
if has {
seq, _ := strconv.Atoi(currentSeq)
alarmData.AlarmSeq = seq + 1
if alarmData.AlarmSeq > global.MaxInt32Number {
alarmData.AlarmSeq = AlarmSeqBeginNumber
}
} else {
alarmData.AlarmSeq = AlarmSeqBeginNumber
}
// todo: PerceivedSeverity set color
var severity string
has, err = xEngine.Table("alarm").
Where("ne_type=? and ne_id=? and event_time=? and alarm_status=1", alarmData.NeType, alarmData.NeId, alarmData.EventTime).
//OrderBy("FIELD(orig_severity, 'Critical', 'Major', 'Minor', 'Warning', 'Event') ASC").
Asc("orig_severity").
Cols("orig_severity").
Limit(1).
Get(&severity)
if err != nil {
log.Error("Failed to get alarm:", err)
continue
}
log.Debugf("neType=%s, neId=%s, eventTime=%s, severity=%s", alarmData.NeType, alarmData.NeId, alarmData.EventTime, severity)
if !has || severity == alarmData.OrigSeverity {
alarmData.PerceivedSeverity = alarmData.OrigSeverity
} else if severity > alarmData.OrigSeverity {
alarmData.PerceivedSeverity = alarmData.OrigSeverity
} else {
alarmData.PerceivedSeverity = severity
// update exist record
_, err := session.Table("alarm").
Where("ne_type=? and ne_id=? and event_time=? and alarm_status=1", alarmData.NeType, alarmData.NeId, alarmData.EventTime).
Update(&Alarm{PerceivedSeverity: alarmData.PerceivedSeverity})
if err != nil {
log.Error("Failed to update alarm:", err)
continue
}
}
eventTime := global.GetFmtTimeString(time.RFC3339, alarmData.EventTime, time.DateTime)
alarmData.ObjectUid = alarmData.NeId
alarmData.ObjectType = "VNFM"
alarmData.EventTime = eventTime
if alarmData.LocationInfo == "" {
alarmData.LocationInfo = fmt.Sprintf("Host:%s", r.RemoteAddr)
}
if alarmData.AddInfo == "" {
alarmData.AddInfo = fmt.Sprintf("subNeInfo:%s", alarmData.NeType)
}
if IsNeedToAckAlarm(valueJson, &alarmData) {
SetAlarmAckInfo(valueJson, &alarmData)
}
log.Debug("alarmData:", alarmData)
affected, err := session.Insert(alarmData)
if err != nil && affected <= 0 {
log.Error("Failed to insert alarm data:", err)
services.ResponseInternalServerError500DatabaseOperationFailed(w)
continue
}
alarmLog := new(AlarmLog)
alarmLog.NeType = alarmData.NeType
alarmLog.NeId = alarmData.NeId
alarmLog.AlarmSeq = alarmData.AlarmSeq
alarmLog.AlarmId = alarmData.AlarmId
alarmLog.AlarmCode = alarmData.AlarmCode
alarmLog.AlarmStatus = alarmData.AlarmStatus
alarmLog.EventTime = eventTime
log.Trace("alarmLog:", alarmLog)
affected, err = session.Insert(alarmLog)
if err != nil && affected <= 0 {
log.Error("Failed to insert alarm_log:", err)
}
session.Commit()
}
if config.GetYamlConfig().Alarm.ForwardAlarm {
if err = AlarmEmailForward(&alarmData); err != nil {
log.Error("Failed to AlarmEmailForward:", err)
}
if err = AlarmForwardBySMSC(&alarmData); err != nil {
log.Error("Failed to AlarmForwardBySMSC:", err)
}
}
}
services.ResponseStatusOK200Null(w)
}
// process alarm get from NFs
func GetAlarmFromNF(w http.ResponseWriter, r *http.Request) {
log.Debug("GetAlarmFromNF processing... ")
_, err := services.CheckFrontValidRequest(w, r)
if err != nil {
log.Error("Request error:", err)
return
}
vars := mux.Vars(r)
neType := vars["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.ResponseStatusOK204NoContent(w)
return
}
//var neInfo *dborm.NeInfo
var nes []dborm.NeInfo
_, err = dborm.XormGetAllNeInfo(&nes)
if err != nil {
log.Error("Failed to get all ne info:", err)
services.ResponseInternalServerError500ProcessError(w, err)
return
}
for _, ne := range nes {
hostUri := fmt.Sprintf("http://%s:%v", ne.Ip, ne.Port)
apiUri := fmt.Sprintf(UriAlarmsFmt, strings.ToLower(ne.NeType))
requestURI2NF := fmt.Sprintf("%s%s", hostUri, apiUri)
log.Debug("requestURI2NF: Get ", requestURI2NF)
// client := resty.New()
response, err := client.R().
EnableTrace().
SetHeaders(map[string]string{"User-Agent": config.GetDefaultUserAgent()}).
SetHeaders(map[string]string{"Content-Type": "application/json;charset=UTF-8"}).
Get(requestURI2NF)
if err != nil {
log.Error("Failed to Get:", err)
//services.ResponseInternalServerError500ProcessError(w, err)
continue
}
alarmArray := new([]Alarm)
switch response.StatusCode() {
case http.StatusOK, http.StatusCreated, http.StatusNoContent, http.StatusAccepted:
body := response.Body()
if len(body) == 0 || body == nil {
log.Infof("Empty alarm body from neType=%s, neId=%s", ne.NeType, ne.NeId)
//services.ResponseInternalServerError500ProcessError(w, err)
continue
}
//log.Debug("Request body:", string(body))
err = json.Unmarshal(body, &alarmArray)
if err != nil {
log.Error("Failed to Unmarshal:", err)
//services.ResponseInternalServerError500ProcessError(w, err)
continue
}
default:
log.Error("Failed to get alarms:", response.Status)
continue
}
valueJson, err := dborm.XormGetAAConfig()
if err != nil {
log.Error("Failed to XormGetAAConfig:", err)
//services.ResponseInternalServerError500ProcessError(w, err)
continue
}
if alarmArray == nil {
log.Infof("Not found sync alarms, neType=%s, neId=%s", ne.NeType, ne.NeId)
//services.ResponseInternalServerError500ProcessError(w, err)
continue
}
// session := xEngine.NewSession()
// defer session.Close()
var activeAlarmNum int = 0
for _, alarmData := range *alarmArray {
log.Debug("alarmData:", alarmData)
session := xEngine.NewSession()
defer session.Close()
// todo: clear alarm ....
if alarmData.AlarmStatus == AlarmStatusClear {
exist, err := session.Table("alarm").
Where("ne_type=? and ne_id=? and alarm_id=? and alarm_status=1", alarmData.NeType, alarmData.NeId, alarmData.AlarmId).
Exist()
if err == nil || !exist {
log.Infof("Not found active alarm: ne_id=%s, alarm_id=%s", alarmData.NeId, alarmData.AlarmId)
continue
}
alarmData.ClearType = ClearTypeAutoClear
alarmData.ClearTime.Valid = true
tm, _ := time.Parse(time.RFC3339, alarmData.EventTime)
log.Debugf("EventTime:%s tm:%d tm-datetime:%s", alarmData.EventTime, tm, tm.Local().Format(time.DateTime))
alarmData.ClearTime.Time = tm
if IsNeedToAckAlarm(valueJson, &alarmData) {
SetAlarmAckInfo(valueJson, &alarmData)
log.Debug("alarmData:", alarmData)
affected, err := session.
Where("ne_type=? and ne_id=? and alarm_id=? and alarm_status=1", alarmData.NeType, alarmData.NeId, alarmData.AlarmId).
Cols("alarm_status", "clear_type", "clear_time", "ack_state", "ack_time", "ack_user").
Update(alarmData)
if err != nil && affected <= 0 {
log.Error("Failed to update alarm data:", err)
//services.ResponseInternalServerError500DatabaseOperationFailed(w)
continue
}
} else {
affected, err := session.
Where("ne_type=? and ne_id=? and alarm_id=? and alarm_status=1", alarmData.NeType, alarmData.NeId, alarmData.AlarmId).
Cols("alarm_status", "clear_type", "clear_time").
Update(alarmData)
if err != nil && affected <= 0 {
log.Error("Failed to update alarm data:", err)
//services.ResponseInternalServerError500DatabaseOperationFailed(w)
continue
}
}
eventTime := global.GetFmtTimeString(time.RFC3339, alarmData.EventTime, time.DateTime)
alarmLog := new(AlarmLog)
alarmLog.NeType = alarmData.NeType
alarmLog.NeId = alarmData.NeId
alarmLog.AlarmSeq = alarmData.AlarmSeq
alarmLog.AlarmId = alarmData.AlarmId
alarmLog.AlarmCode = alarmData.AlarmCode
alarmLog.AlarmStatus = alarmData.AlarmStatus
alarmLog.EventTime = eventTime
log.Debug("alarmLog:", alarmLog)
affected, err := session.Insert(alarmLog)
if err != nil && affected <= 0 {
log.Error("Failed to insert alarm_log:", err)
}
// todo: PerceivedSeverity set color
var severity string
has, err := xEngine.Table("alarm").
Where("ne_type=? and ne_id=? and event_time=? and alarm_status=1", alarmData.NeType, alarmData.NeId, alarmData.EventTime).
//OrderBy("FIELD(orig_severity, 'Critical', 'Major', 'Minor', 'Warning', 'Event') ASC").
Asc("orig_severity").
Cols("orig_severity").
Limit(1).
Get(&severity)
if err != nil {
log.Error("Failed to get alarm:", err)
continue
}
log.Debugf("neType=%s, neId=%s, eventTime=%s, severity=%s", alarmData.NeType, alarmData.NeId, alarmData.EventTime, severity)
if has && severity > alarmData.OrigSeverity {
// update exist record
_, err := session.Table("alarm").
Where("ne_type=? and ne_id=? and event_time=?", alarmData.NeType, alarmData.NeId, alarmData.EventTime).
Update(&Alarm{PerceivedSeverity: severity})
if err != nil {
log.Error("Failed to update alarm:", err)
continue
}
}
session.Commit()
// for alarm forward time format
alarmData.EventTime = eventTime
} else {
activeAlarmNum++
has, err := xEngine.Table("alarm").
Where("alarm_id=? and ne_type=? and ne_id=? and alarm_status=1",
alarmData.AlarmId, alarmData.NeType, alarmData.NeId).
Exist()
if err == nil && has {
log.Warn("Exist the same alarm")
continue
}
var currentSeq string
has, err = xEngine.Table("alarm").
Where("ne_type=? and ne_id=?", alarmData.NeType, alarmData.NeId).
Desc("alarm_seq").
//Desc("event_time").
Cols("alarm_seq").
Limit(1).
Get(&currentSeq)
if err != nil {
log.Error("Failed to get alarm:", err)
continue
}
log.Debugf("neType=%s, neId=%s, currentSeq=%s, activeAlarmNum=%d",
alarmData.NeType, alarmData.NeId, currentSeq, activeAlarmNum)
if has {
seq, _ := strconv.Atoi(currentSeq)
alarmData.AlarmSeq = seq + 1
if alarmData.AlarmSeq > global.MaxInt32Number {
alarmData.AlarmSeq = AlarmSeqBeginNumber
}
} else {
alarmData.AlarmSeq = AlarmSeqBeginNumber
}
// todo: PerceivedSeverity set color
var severity string
has, err = xEngine.Table("alarm").
Where("ne_type=? and ne_id=? and event_time=? and alarm_status=1", alarmData.NeType, alarmData.NeId, alarmData.EventTime).
//OrderBy("FIELD(orig_severity, 'Critical', 'Major', 'Minor', 'Warning', 'Event') ASC").
Asc("orig_severity").
Cols("orig_severity").
Limit(1).
Get(&severity)
if err != nil {
log.Error("Failed to get alarm:", err)
continue
}
log.Debugf("neType=%s, neId=%s, eventTime=%s, severity=%s", alarmData.NeType, alarmData.NeId, alarmData.EventTime, severity)
if !has || severity == alarmData.OrigSeverity {
alarmData.PerceivedSeverity = alarmData.OrigSeverity
} else if severity > alarmData.OrigSeverity {
alarmData.PerceivedSeverity = alarmData.OrigSeverity
} else {
alarmData.PerceivedSeverity = severity
// update exist record
_, err := session.Table("alarm").
Where("ne_type=? and ne_id=? and event_time=?", alarmData.NeType, alarmData.NeId, alarmData.EventTime).
Update(&Alarm{PerceivedSeverity: alarmData.PerceivedSeverity})
if err != nil {
log.Error("Failed to update alarm:", err)
continue
}
}
alarmData.ObjectUid = alarmData.NeId
alarmData.ObjectType = "VNFM"
alarmData.EventTime = global.GetFmtTimeString(time.RFC3339, alarmData.EventTime, time.DateTime)
if IsNeedToAckAlarm(valueJson, &alarmData) {
SetAlarmAckInfo(valueJson, &alarmData)
}
log.Trace("alarmData:", alarmData)
affected, err := session.Insert(alarmData)
if err == nil && affected > 0 {
alarmLog := new(AlarmLog)
alarmLog.NeType = alarmData.NeType
alarmLog.NeId = alarmData.NeId
alarmLog.AlarmSeq = alarmData.AlarmSeq
alarmLog.AlarmId = alarmData.AlarmId
alarmLog.AlarmCode = alarmData.AlarmCode
alarmLog.AlarmStatus = alarmData.AlarmStatus
alarmLog.EventTime = global.GetFmtTimeString(time.RFC3339, alarmData.EventTime, time.DateTime)
log.Debug("alarmLog:", alarmLog)
affected, err = session.Insert(alarmLog)
if err != nil && affected <= 0 {
log.Error("Failed to insert data:", err)
//services.ResponseInternalServerError500DatabaseOperationFailed(w)
continue
}
session.Commit()
if config.GetYamlConfig().Alarm.ForwardAlarm {
if err = AlarmEmailForward(&alarmData); err != nil {
log.Error("Failed to AlarmEmailForward:", err)
}
if err = AlarmForwardBySMSC(&alarmData); err != nil {
log.Error("Failed to AlarmForwardBySMSC:", err)
}
}
}
log.Warn("Failed to insert alarm data:", err)
}
}
}
services.ResponseStatusOK204NoContent(w)
}

129
features/fm/email.go Normal file
View File

@@ -0,0 +1,129 @@
package fm
import (
"crypto/tls"
"errors"
"fmt"
"strings"
"nms_nbi/lib/dborm"
"nms_nbi/lib/log"
"nms_nbi/restagent/config"
"gopkg.in/gomail.v2"
)
func AlarmEmailForward(alarmData *Alarm) error {
log.Info("AlarmEmailForward processing... ")
message := fmt.Sprintf(`
<p>Alarm information</p>
<p style="text-indent:2.5em">Sequence: %d</p>
<p style="text-indent:3em">NE name: %s</p>
<p style="text-indent:4em">Title: %s</p>
<p style="text-indent:2.5em">Severity: %s</p>
<p style="text-indent:1.5em">Event Time: %s</p>
<p style="text-indent:0.5em">Alarm Status: %d</p>
<p>Automatic sent by OMC, please do not reply!</p>
`, alarmData.AlarmSeq, alarmData.NeName, alarmData.AlarmTitle, alarmData.OrigSeverity, alarmData.EventTime, alarmData.AlarmStatus)
// message := fmt.Sprintf(`
// Alarm information
// Sequence: %d
// NE name: %s
// Title: %s
// Severity: %s
// Event Time: %s
// Automatic send by OMC, don't reply!
// `, alarmData.AlarmSeq, alarmData.NeName, alarmData.AlarmTitle, alarmData.OrigSeverity, alarmData.EventTime)
// QQ 邮箱:
// SMTP 服务器地址smtp.qq.comSSL协议端口465/994 | 非SSL协议端口25
// 163 邮箱:
// SMTP 服务器地址smtp.163.com端口25
// host := "mail.agrandtech.com"
// port := 25
// userName := "smtpext@agrandtech.com"
// password := "1000smtp@omc!"
host := config.GetYamlConfig().Alarm.Email.Smtp
port := int(config.GetYamlConfig().Alarm.Email.Port)
userName := config.GetYamlConfig().Alarm.Email.User
password := config.GetYamlConfig().Alarm.Email.Password
m := gomail.NewMessage()
m.SetHeader("From", userName) // 发件人
//m.SetHeader("From", "alias"+"<"+"aliastest"+">") // 增加发件人别名
emails, err := dborm.XormGetAlarmForward("Email")
if err != nil {
log.Error("Failed to XormGetAlarmForward:", err)
return err
} else if emails == nil || len(*emails) == 0 {
err := errors.New("not found forward email list")
log.Error(err)
return err
}
forwardLog := &dborm.AlarmForwardLog{
NeType: alarmData.NeType,
NeID: alarmData.NeId,
AlarmID: alarmData.AlarmId,
AlarmTitle: alarmData.AlarmTitle,
AlarmSeq: alarmData.AlarmSeq,
EventTime: alarmData.EventTime,
ToUser: strings.Join(*emails, ","),
}
m.SetHeader("To", *emails...) // 收件人,可以多个收件人,但必须使用相同的 SMTP 连接
//m.SetHeader("To", strings.Join(*emails, " ")) // 收件人,可以多个收件人,但必须使用相同的 SMTP 连接
//m.SetHeader("To", "zhangshuzhong@agrandtech.com", "simonzhangsz@outlook.com") // 收件人,可以多个收件人,但必须使用相同的 SMTP 连接
//m.SetHeader("Cc", "******@qq.com") // 抄送,可以多个
//m.SetHeader("Bcc", "******@qq.com") // 暗送,可以多个
m.SetHeader("Subject", "Alarm from OMC!") // 邮件主题
// text/html 的意思是将文件的 content-type 设置为 text/html 的形式浏览器在获取到这种文件时会自动调用html的解析器对文件进行相应的处理。
// 可以通过 text/html 处理文本格式进行特殊处理,如换行、缩进、加粗等等
//m.SetBody("text/html", fmt.Sprintf(message, *alarm))
m.SetBody("text/html", message)
// text/plain的意思是将文件设置为纯文本的形式浏览器在获取到这种文件时并不会对其进行处理
//m.SetBody("text/plain", message)
// m.Attach("test.sh") // 附件文件,可以是文件,照片,视频等等
// m.Attach("lolcatVideo.mp4") // 视频
// m.Attach("lolcat.jpg") // 照片
d := gomail.NewDialer(
host,
port,
userName,
password,
)
// 关闭SSL协议认证
d.TLSConfig = &tls.Config{InsecureSkipVerify: true}
if !config.GetYamlConfig().Alarm.Email.TlsSkipVerify {
// 打开SSL协议认证
d.TLSConfig = &tls.Config{InsecureSkipVerify: false}
}
if err := d.DialAndSend(m); err != nil {
operResult := fmt.Sprintf("Failed to DialAndSend:%v", err)
log.Error(operResult)
forwardLog.OperResult = operResult
affected, err := dborm.XormInsertAlarmForwardLog(forwardLog)
if err != nil && affected <= 0 {
log.Error("Failed to insert data:", err)
}
return err
}
forwardLog.OperResult = "Email sent successfully!"
affected, err := dborm.XormInsertAlarmForwardLog(forwardLog)
if err != nil && affected <= 0 {
log.Error("Failed to insert data:", err)
return err
}
return nil
}

249
features/fm/smsforward.go Normal file
View File

@@ -0,0 +1,249 @@
package fm
import (
"errors"
"fmt"
"net/http"
"net/url"
"time"
"nms_nbi/lib/dborm"
"nms_nbi/lib/log"
"nms_nbi/restagent/config"
"github.com/linxGnu/gosmpp"
"github.com/linxGnu/gosmpp/data"
"github.com/linxGnu/gosmpp/pdu"
)
func AlarmForwardBySMS(alarmData *Alarm) error {
log.Info("AlarmForwardBySMS processing... ")
SMSFforwardconfig := config.GetYamlConfig().Alarm.SMS
// 阿里云短信API的请求地址
apiURL := SMSFforwardconfig.ApiURL
// 阿里云短信API的AccessKey ID和AccessKey Secret
//accessKeyID := SMSFforwardconfig.AccessKeyID
accessKeySecret := SMSFforwardconfig.AccessKeySecret
toUsers, err := dborm.XormGetAlarmForward("SMS")
if err != nil {
log.Error("Failed to XormGetAlarmForward:", err)
return err
} else if toUsers == nil {
err := errors.New("not found forward phone number")
log.Error(err)
return err
}
for _, toUser := range *toUsers {
// 短信相关参数
params := url.Values{}
params.Set("PhoneNumbers", toUser)
params.Set("SignName", SMSFforwardconfig.SignName)
params.Set("TemplateCode", SMSFforwardconfig.TemplateCode)
params.Set("TemplateParam", `{"message":"alarm"}`)
// 构建请求URL
reqURL := apiURL + "?Action=SendSms&" + params.Encode()
// 创建HTTP请求
req, err := http.NewRequest("GET", reqURL, nil)
if err != nil {
log.Error("Failed to create request:", err)
return err
}
// 添加请求头部
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
req.Header.Set("Authorization", "APPCODE "+accessKeySecret)
forwardLog := &dborm.AlarmForwardLog{
NeType: alarmData.NeType,
NeID: alarmData.NeId,
AlarmID: alarmData.AlarmId,
AlarmTitle: alarmData.AlarmTitle,
AlarmSeq: alarmData.AlarmSeq,
EventTime: alarmData.EventTime,
ToUser: toUser,
}
// 发送请求
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
operResult := fmt.Sprintf("Failed to send request:%v", err)
log.Error(operResult)
forwardLog.OperResult = operResult
affected, err := dborm.XormInsertAlarmForwardLog(forwardLog)
if err != nil && affected <= 0 {
log.Error("Failed to insert data:", err)
}
continue
}
defer resp.Body.Close()
// 解析响应
if resp.StatusCode == http.StatusOK {
operResult := "SMS sent successfully!"
log.Info(operResult)
forwardLog.OperResult = operResult
affected, err := dborm.XormInsertAlarmForwardLog(forwardLog)
if err != nil && affected <= 0 {
log.Error("Failed to insert data:", err)
continue
}
} else {
operResult := fmt.Sprintf("Failed to send SMS, StatusCode=%d", resp.StatusCode)
log.Error(operResult)
forwardLog.OperResult = operResult
affected, err := dborm.XormInsertAlarmForwardLog(forwardLog)
if err != nil && affected <= 0 {
log.Error("Failed to insert data:", err)
continue
}
}
}
return nil
}
func AlarmForwardBySMPP(alarmData *Alarm) error {
log.Info("AlarmForwardBySMPP processing... ")
auth := gosmpp.Auth{
SMSC: config.GetYamlConfig().Alarm.SMSC.Addr,
SystemID: config.GetYamlConfig().Alarm.SMSC.UserName,
Password: config.GetYamlConfig().Alarm.SMSC.Password,
SystemType: "",
}
// conn, err := gosmpp.NonTLSDialer(auth.SMSC)
// connection := gosmpp.NewConnection(conn)
trans, err := gosmpp.NewSession(
gosmpp.TXConnector(gosmpp.NonTLSDialer, auth),
gosmpp.Settings{
ReadTimeout: 2 * time.Second,
OnPDU: func(p pdu.PDU, _ bool) {
log.Debug("%+v", p)
},
OnSubmitError: func(_ pdu.PDU, err error) {
log.Error(err)
},
OnRebindingError: func(err error) {
log.Error(err)
},
OnClosed: func(state gosmpp.State) {
log.Error(state)
},
}, -1)
if err != nil {
log.Error(err)
return err
}
defer func() {
_ = trans.Close()
}()
toUsers, err := dborm.XormGetAlarmForward("SMS")
if err != nil {
log.Error("Failed to XormGetAlarmForward:", err)
return err
} else if toUsers == nil {
err := errors.New("not found forward phone number")
log.Error(err)
return err
}
// sending SMS(s)
for _, toUser := range *toUsers {
forwardLog := &dborm.AlarmForwardLog{
NeType: alarmData.NeType,
NeID: alarmData.NeId,
AlarmID: alarmData.AlarmId,
AlarmTitle: alarmData.AlarmTitle,
AlarmSeq: alarmData.AlarmSeq,
EventTime: alarmData.EventTime,
ToUser: toUser,
}
message := alarmData.AlarmTitle + "from" + alarmData.NeType + alarmData.NeId + "at" + alarmData.EventTime
if err = trans.Transceiver().Submit(newSubmitSM(toUser, message)); err != nil {
operResult := fmt.Sprintf("Failed to submit short message:%v", err)
log.Error(operResult)
forwardLog.OperResult = operResult
} else {
operResult := "SMS sent successfully!"
log.Trace(operResult)
forwardLog.OperResult = operResult
}
affected, err := dborm.XormInsertAlarmForwardLog(forwardLog)
if err != nil && affected <= 0 {
log.Error("Failed to insert data:", err)
continue
}
}
return nil
}
func handlePDU() func(pdu.PDU) (pdu.PDU, bool) {
return func(p pdu.PDU) (pdu.PDU, bool) {
switch pd := p.(type) {
case *pdu.Unbind:
log.Trace("Unbind Received")
return pd.GetResponse(), true
case *pdu.UnbindResp:
log.Trace("UnbindResp Received")
case *pdu.SubmitSMResp:
log.Trace("SubmitSMResp Received")
case *pdu.GenericNack:
log.Trace("GenericNack Received")
case *pdu.EnquireLinkResp:
fmt.Println("EnquireLinkResp Received")
case *pdu.EnquireLink:
log.Trace("EnquireLink Received")
return pd.GetResponse(), false
case *pdu.DataSM:
log.Trace("DataSM receiver")
return pd.GetResponse(), false
case *pdu.DeliverSM:
log.Trace("DeliverSM receiver")
return pd.GetResponse(), false
}
return nil, false
}
}
func newSubmitSM(phoneNumber string, message string) *pdu.SubmitSM {
// build up submitSM
srcAddr := pdu.NewAddress()
srcAddr.SetTon(5)
srcAddr.SetNpi(0)
_ = srcAddr.SetAddress("alarm notification:")
destAddr := pdu.NewAddress()
destAddr.SetTon(1)
destAddr.SetNpi(1)
_ = destAddr.SetAddress(phoneNumber)
submitSM := pdu.NewSubmitSM().(*pdu.SubmitSM)
submitSM.SourceAddr = srcAddr
submitSM.DestAddr = destAddr
_ = submitSM.Message.SetMessageWithEncoding(message, data.UCS2)
submitSM.ProtocolID = 0
submitSM.RegisteredDelivery = 1
submitSM.ReplaceIfPresentFlag = 0
submitSM.EsmClass = 0
return submitSM
}

61
features/fm/ucpcli.go Normal file
View File

@@ -0,0 +1,61 @@
package fm
import (
"fmt"
"strings"
"nms_nbi/lib/log"
"nms_nbi/restagent/config"
"github.com/chzyer/readline"
"github.com/go-gsm/ucp"
)
func AlarmForwardBySMSC(alarmData *Alarm) error {
opt := &ucp.Options{
Addr: config.GetYamlConfig().Alarm.SMSC.Addr,
User: config.GetYamlConfig().Alarm.SMSC.UserName,
Password: config.GetYamlConfig().Alarm.SMSC.Password,
AccessCode: "",
}
client := ucp.New(opt)
if err := client.Connect(); err != nil {
log.Error("Failed to connect:", err)
return err
}
defer client.Close()
reader, _ := readline.New(">>> ")
defer reader.Close()
for {
fmt.Print(">>> ")
lines, _ := reader.Readline()
fields := strings.Fields(lines)
if len(fields) == 1 {
// exit CLI
if fields[0] == "exit" {
return nil
}
// display help message
if fields[0] == "help" {
log.Trace("\n\tSend a 'message' to 'receiver' with a 'sender' mask\n\t>>> sender receiver message\n\n\tExit the cli\n\t>>> exit\n")
}
}
// sender receiver message...
if len(fields) >= 3 {
sender := fields[0]
receiver := fields[1]
message := strings.Join(fields[2:], " ")
ids, err := client.Send(sender, receiver, message)
if err != nil {
log.Error(err)
} else {
log.Debug("%v", ids)
}
}
}
}