add cron, nat api & refactor alert rule (#459)

* add cron api & refactor alert rule

* add nat api

* fix swagger

* remove unnecessary steps
This commit is contained in:
UUBulb
2024-10-26 23:57:47 +08:00
committed by GitHub
parent ebc4fad9bc
commit 68d7e16773
24 changed files with 573 additions and 144 deletions

View File

@@ -26,9 +26,9 @@ type NotificationHistory struct {
var (
AlertsLock sync.RWMutex
Alerts []*model.AlertRule
alertsStore map[uint64]map[uint64][][]interface{} // [alert_id][server_id] -> 对应报警规则的检查结果
alertsPrevState map[uint64]map[uint64]uint8 // [alert_id][server_id] -> 对应报警规则的上一次报警状态
AlertsCycleTransferStatsStore map[uint64]*model.CycleTransferStats // [alert_id] -> 对应报警规则的周期流量统计
alertsStore map[uint64]map[uint64][][]bool // [alert_id][server_id] -> 对应报警规则的检查结果
alertsPrevState map[uint64]map[uint64]uint8 // [alert_id][server_id] -> 对应报警规则的上一次报警状态
AlertsCycleTransferStatsStore map[uint64]*model.CycleTransferStats // [alert_id] -> 对应报警规则的周期流量统计
)
// addCycleTransferStatsInfo 向AlertsCycleTransferStatsStore中添加周期流量报警统计信息
@@ -59,7 +59,7 @@ func addCycleTransferStatsInfo(alert *model.AlertRule) {
// AlertSentinelStart 报警器启动
func AlertSentinelStart() {
alertsStore = make(map[uint64]map[uint64][][]interface{})
alertsStore = make(map[uint64]map[uint64][][]bool)
alertsPrevState = make(map[uint64]map[uint64]uint8)
AlertsCycleTransferStatsStore = make(map[uint64]*model.CycleTransferStats)
AlertsLock.Lock()
@@ -67,7 +67,7 @@ func AlertSentinelStart() {
panic(err)
}
for _, alert := range Alerts {
alertsStore[alert.ID] = make(map[uint64][][]interface{})
alertsStore[alert.ID] = make(map[uint64][][]bool)
alertsPrevState[alert.ID] = make(map[uint64]uint8)
addCycleTransferStatsInfo(alert)
}
@@ -91,7 +91,7 @@ func AlertSentinelStart() {
}
}
func OnRefreshOrAddAlert(alert model.AlertRule) {
func OnRefreshOrAddAlert(alert *model.AlertRule) {
AlertsLock.Lock()
defer AlertsLock.Unlock()
delete(alertsStore, alert.ID)
@@ -99,17 +99,17 @@ func OnRefreshOrAddAlert(alert model.AlertRule) {
var isEdit bool
for i := 0; i < len(Alerts); i++ {
if Alerts[i].ID == alert.ID {
Alerts[i] = &alert
Alerts[i] = alert
isEdit = true
}
}
if !isEdit {
Alerts = append(Alerts, &alert)
Alerts = append(Alerts, alert)
}
alertsStore[alert.ID] = make(map[uint64][][]interface{})
alertsStore[alert.ID] = make(map[uint64][][]bool)
alertsPrevState[alert.ID] = make(map[uint64]uint8)
delete(AlertsCycleTransferStatsStore, alert.ID)
addCycleTransferStatsInfo(&alert)
addCycleTransferStatsInfo(alert)
}
func OnDeleteAlert(id []uint64) {

View File

@@ -3,6 +3,7 @@ package singleton
import (
"bytes"
"fmt"
"slices"
"sync"
"github.com/jinzhu/copier"
@@ -15,8 +16,10 @@ import (
var (
Cron *cron.Cron
Crons map[uint64]*model.Cron // [CrondID] -> *model.Cron
Crons map[uint64]*model.Cron // [CronID] -> *model.Cron
CronLock sync.RWMutex
CronList []*model.Cron
)
func InitCronTask() {
@@ -27,29 +30,28 @@ func InitCronTask() {
// loadCronTasks 加载计划任务
func loadCronTasks() {
InitCronTask()
var crons []model.Cron
DB.Find(&crons)
DB.Find(&CronList)
var err error
var notificationGroupList []uint64
notificationMsgMap := make(map[uint64]*bytes.Buffer)
for i := 0; i < len(crons); i++ {
for i := 0; i < len(CronList); i++ {
// 触发任务类型无需注册
if crons[i].TaskType == model.CronTypeTriggerTask {
Crons[crons[i].ID] = &crons[i]
if CronList[i].TaskType == model.CronTypeTriggerTask {
Crons[CronList[i].ID] = CronList[i]
continue
}
// 注册计划任务
crons[i].CronJobID, err = Cron.AddFunc(crons[i].Scheduler, CronTrigger(crons[i]))
CronList[i].CronJobID, err = Cron.AddFunc(CronList[i].Scheduler, CronTrigger(CronList[i]))
if err == nil {
Crons[crons[i].ID] = &crons[i]
Crons[CronList[i].ID] = CronList[i]
} else {
// 当前通知组首次出现 将其加入通知组列表并初始化通知组消息缓存
if _, ok := notificationMsgMap[crons[i].NotificationGroupID]; !ok {
notificationGroupList = append(notificationGroupList, crons[i].NotificationGroupID)
notificationMsgMap[crons[i].NotificationGroupID] = bytes.NewBufferString("")
notificationMsgMap[crons[i].NotificationGroupID].WriteString("调度失败的计划任务:[")
if _, ok := notificationMsgMap[CronList[i].NotificationGroupID]; !ok {
notificationGroupList = append(notificationGroupList, CronList[i].NotificationGroupID)
notificationMsgMap[CronList[i].NotificationGroupID] = bytes.NewBufferString("")
notificationMsgMap[CronList[i].NotificationGroupID].WriteString("调度失败的计划任务:[")
}
notificationMsgMap[crons[i].NotificationGroupID].WriteString(fmt.Sprintf("%d,", crons[i].ID))
notificationMsgMap[CronList[i].NotificationGroupID].WriteString(fmt.Sprintf("%d,", CronList[i].ID))
}
}
// 向注册错误的计划任务所在通知组发送通知
@@ -60,7 +62,49 @@ func loadCronTasks() {
Cron.Start()
}
func ManualTrigger(c model.Cron) {
func OnRefreshOrAddCron(c *model.Cron) {
CronLock.Lock()
defer CronLock.Unlock()
crOld := Crons[c.ID]
if crOld != nil && crOld.CronJobID != 0 {
Cron.Remove(crOld.CronJobID)
}
delete(Crons, c.ID)
Crons[c.ID] = c
}
func UpdateCronList() {
CronLock.RLock()
defer CronLock.RUnlock()
CronList = make([]*model.Cron, 0, len(Crons))
for _, c := range Crons {
CronList = append(CronList, c)
}
slices.SortFunc(CronList, func(a, b *model.Cron) int {
if a.ID < b.ID {
return -1
} else if a.ID == b.ID {
return 0
}
return 1
})
}
func OnDeleteCron(id []uint64) {
CronLock.Lock()
defer CronLock.Unlock()
for _, i := range id {
cr := Crons[i]
if cr != nil && cr.CronJobID != 0 {
Cron.Remove(cr.CronJobID)
}
delete(Crons, i)
}
}
func ManualTrigger(c *model.Cron) {
CronTrigger(c)()
}
@@ -76,11 +120,11 @@ func SendTriggerTasks(taskIDs []uint64, triggerServer uint64) {
// 依次调用CronTrigger发送任务
for _, c := range cronLists {
go CronTrigger(*c, triggerServer)()
go CronTrigger(c, triggerServer)()
}
}
func CronTrigger(cr model.Cron, triggerServer ...uint64) func() {
func CronTrigger(cr *model.Cron, triggerServer ...uint64) func() {
crIgnoreMap := make(map[uint64]bool)
for j := 0; j < len(cr.Servers); j++ {
crIgnoreMap[cr.Servers[j]] = true

View File

@@ -21,16 +21,14 @@ var (
)
func initDDNS() {
var ddns []*model.DDNSProfile
DB.Find(&ddns)
DB.Find(&DDNSList)
DDNSCacheLock.Lock()
DDNSCache = make(map[uint64]*model.DDNSProfile)
for i := 0; i < len(ddns); i++ {
DDNSCache[ddns[i].ID] = ddns[i]
for i := 0; i < len(DDNSList); i++ {
DDNSCache[DDNSList[i].ID] = DDNSList[i]
}
DDNSCacheLock.Unlock()
UpdateDDNSList()
OnNameserverUpdate()
}

View File

@@ -1,31 +1,75 @@
package singleton
import (
"slices"
"sync"
"github.com/naiba/nezha/model"
)
var natCache = make(map[string]*model.NAT)
var natCacheRwLock = new(sync.RWMutex)
var (
NATCache = make(map[string]*model.NAT)
NATCacheRwLock sync.RWMutex
NATIDToDomain = make(map[uint64]string)
NATList []*model.NAT
)
func initNAT() {
OnNATUpdate()
}
func OnNATUpdate() {
natCacheRwLock.Lock()
defer natCacheRwLock.Unlock()
var nats []*model.NAT
DB.Find(&nats)
natCache = make(map[string]*model.NAT)
for i := 0; i < len(nats); i++ {
natCache[nats[i].Domain] = nats[i]
DB.Find(&NATList)
NATCacheRwLock.Lock()
defer NATCacheRwLock.Unlock()
NATCache = make(map[string]*model.NAT)
for i := 0; i < len(NATList); i++ {
NATCache[NATList[i].Domain] = NATList[i]
NATIDToDomain[NATList[i].ID] = NATList[i].Domain
}
}
func GetNATConfigByDomain(domain string) *model.NAT {
natCacheRwLock.RLock()
defer natCacheRwLock.RUnlock()
return natCache[domain]
func OnNATUpdate(n *model.NAT) {
NATCacheRwLock.Lock()
defer NATCacheRwLock.Unlock()
if oldDomain, ok := NATIDToDomain[n.ID]; ok && oldDomain != n.Domain {
delete(NATCache, oldDomain)
}
NATCache[n.Domain] = n
NATIDToDomain[n.ID] = n.Domain
}
func OnNATDelete(id []uint64) {
NATCacheRwLock.Lock()
defer NATCacheRwLock.Unlock()
for _, i := range id {
if domain, ok := NATIDToDomain[i]; ok {
delete(NATCache, domain)
delete(NATIDToDomain, i)
}
}
}
func UpdateNATList() {
NATCacheRwLock.RLock()
defer NATCacheRwLock.RUnlock()
NATList = make([]*model.NAT, 0, len(NATCache))
for _, n := range NATCache {
NATList = append(NATList, n)
}
slices.SortFunc(NATList, func(a, b *model.NAT) int {
if a.ID < b.ID {
return -1
} else if a.ID == b.ID {
return 0
}
return 1
})
}
func GetNATConfigByDomain(domain string) *model.NAT {
NATCacheRwLock.RLock()
defer NATCacheRwLock.RUnlock()
return NATCache[domain]
}

View File

@@ -49,14 +49,13 @@ func loadNotifications() {
groupNotifications[n.NotificationGroupID] = append(groupNotifications[n.NotificationGroupID], n.NotificationID)
}
var notifications []model.Notification
if err := DB.Find(&notifications).Error; err != nil {
if err := DB.Find(&NotificationListSorted).Error; err != nil {
panic(err)
}
NotificationMap = make(map[uint64]*model.Notification, len(notifications))
for i := range notifications {
NotificationMap[notifications[i].ID] = &notifications[i]
NotificationMap = make(map[uint64]*model.Notification, len(NotificationListSorted))
for i := range NotificationListSorted {
NotificationMap[NotificationListSorted[i].ID] = NotificationListSorted[i]
}
for gid, nids := range groupNotifications {
@@ -75,7 +74,6 @@ func loadNotifications() {
}
NotificationsLock.Unlock()
UpdateNotificationList()
}
func UpdateNotificationList() {

View File

@@ -45,8 +45,8 @@ func ReSortServer() {
SortedServerLock.Lock()
defer SortedServerLock.Unlock()
SortedServerList = []*model.Server{}
SortedServerListForGuest = []*model.Server{}
SortedServerList = make([]*model.Server, 0, len(ServerList))
var SortedServerListForGuest []*model.Server
for _, s := range ServerList {
SortedServerList = append(SortedServerList, s)
if !s.HideForGuest {