mirror of
https://github.com/nezhahq/nezha.git
synced 2025-01-22 20:58:14 -05:00
add alert api (#458)
This commit is contained in:
parent
8c452bdaa9
commit
ebc4fad9bc
177
cmd/dashboard/controller/alertrule.go
Normal file
177
cmd/dashboard/controller/alertrule.go
Normal file
@ -0,0 +1,177 @@
|
|||||||
|
package controller
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/jinzhu/copier"
|
||||||
|
|
||||||
|
"github.com/naiba/nezha/model"
|
||||||
|
"github.com/naiba/nezha/service/singleton"
|
||||||
|
)
|
||||||
|
|
||||||
|
// List Alert rules
|
||||||
|
// @Summary List Alert rules
|
||||||
|
// @Security BearerAuth
|
||||||
|
// @Schemes
|
||||||
|
// @Description List Alert rules
|
||||||
|
// @Tags auth required
|
||||||
|
// @Produce json
|
||||||
|
// @Success 200 {object} model.CommonResponse[[]model.AlertRule]
|
||||||
|
// @Router /alert-rule [get]
|
||||||
|
func listAlertRule(c *gin.Context) ([]*model.AlertRule, error) {
|
||||||
|
singleton.AlertsLock.RLock()
|
||||||
|
defer singleton.AlertsLock.RUnlock()
|
||||||
|
|
||||||
|
var ar []*model.AlertRule
|
||||||
|
if err := copier.Copy(&ar, &singleton.Alerts); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return ar, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add Alert Rule
|
||||||
|
// @Summary Add Alert Rule
|
||||||
|
// @Security BearerAuth
|
||||||
|
// @Schemes
|
||||||
|
// @Description Add Alert Rule
|
||||||
|
// @Tags auth required
|
||||||
|
// @Accept json
|
||||||
|
// @param request body model.AlertRuleForm true "AlertRuleForm"
|
||||||
|
// @Produce json
|
||||||
|
// @Success 200 {object} model.CommonResponse[uint64]
|
||||||
|
// @Router /alert-rule [post]
|
||||||
|
func createAlertRule(c *gin.Context) (uint64, error) {
|
||||||
|
var arf model.AlertRuleForm
|
||||||
|
var r model.AlertRule
|
||||||
|
|
||||||
|
if err := c.ShouldBindJSON(&arf); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := validateRule(&r); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
r.Name = arf.Name
|
||||||
|
r.Rules = arf.Rules
|
||||||
|
r.FailTriggerTasks = arf.FailTriggerTasks
|
||||||
|
r.RecoverTriggerTasks = arf.RecoverTriggerTasks
|
||||||
|
r.NotificationGroupID = arf.NotificationGroupID
|
||||||
|
enable := arf.Enable
|
||||||
|
r.TriggerMode = arf.TriggerMode
|
||||||
|
r.Enable = &enable
|
||||||
|
r.ID = arf.ID
|
||||||
|
|
||||||
|
if err := singleton.DB.Create(&r).Error; err != nil {
|
||||||
|
return 0, newGormError("%v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
singleton.OnRefreshOrAddAlert(r)
|
||||||
|
return r.ID, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update Alert Rule
|
||||||
|
// @Summary Update Alert Rule
|
||||||
|
// @Security BearerAuth
|
||||||
|
// @Schemes
|
||||||
|
// @Description Update Alert Rule
|
||||||
|
// @Tags auth required
|
||||||
|
// @Accept json
|
||||||
|
// @param id path uint true "Alert ID"
|
||||||
|
// @param request body model.AlertRuleForm true "AlertRuleForm"
|
||||||
|
// @Produce json
|
||||||
|
// @Success 200 {object} model.CommonResponse[any]
|
||||||
|
// @Router /alert-rule/{id} [patch]
|
||||||
|
func updateAlertRule(c *gin.Context) (any, error) {
|
||||||
|
idStr := c.Param("id")
|
||||||
|
id, err := strconv.ParseUint(idStr, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var arf model.AlertRuleForm
|
||||||
|
if err := c.ShouldBindJSON(&arf); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var r model.AlertRule
|
||||||
|
if err := singleton.DB.First(&r, id).Error; err != nil {
|
||||||
|
return nil, fmt.Errorf("alert id %d does not exist", id)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := validateRule(&r); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
r.Name = arf.Name
|
||||||
|
r.Rules = arf.Rules
|
||||||
|
r.FailTriggerTasks = arf.FailTriggerTasks
|
||||||
|
r.RecoverTriggerTasks = arf.RecoverTriggerTasks
|
||||||
|
r.NotificationGroupID = arf.NotificationGroupID
|
||||||
|
enable := arf.Enable
|
||||||
|
r.TriggerMode = arf.TriggerMode
|
||||||
|
r.Enable = &enable
|
||||||
|
r.ID = arf.ID
|
||||||
|
|
||||||
|
if err := singleton.DB.Save(&r).Error; err != nil {
|
||||||
|
return 0, newGormError("%v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
singleton.OnRefreshOrAddAlert(r)
|
||||||
|
return r.ID, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Batch delete Alert rules
|
||||||
|
// @Summary Batch delete Alert rules
|
||||||
|
// @Security BearerAuth
|
||||||
|
// @Schemes
|
||||||
|
// @Description Batch delete Alert rules
|
||||||
|
// @Tags auth required
|
||||||
|
// @Accept json
|
||||||
|
// @param request body []uint64 true "id list"
|
||||||
|
// @Produce json
|
||||||
|
// @Success 200 {object} model.CommonResponse[any]
|
||||||
|
// @Router /batch-delete/alert-rule [post]
|
||||||
|
func batchDeleteAlertRule(c *gin.Context) (any, error) {
|
||||||
|
var ar []uint64
|
||||||
|
|
||||||
|
if err := c.ShouldBindJSON(&ar); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := singleton.DB.Unscoped().Delete(&model.DDNSProfile{}, "id in (?)", ar).Error; err != nil {
|
||||||
|
return nil, newGormError("%v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
singleton.OnDeleteAlert(ar)
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func validateRule(r *model.AlertRule) error {
|
||||||
|
if len(r.Rules) > 0 {
|
||||||
|
for _, rule := range r.Rules {
|
||||||
|
if !rule.IsTransferDurationRule() {
|
||||||
|
if rule.Duration < 3 {
|
||||||
|
return errors.New("错误: Duration 至少为 3")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if rule.CycleInterval < 1 {
|
||||||
|
return errors.New("错误: cycle_interval 至少为 1")
|
||||||
|
}
|
||||||
|
if rule.CycleStart == nil {
|
||||||
|
return errors.New("错误: cycle_start 未设置")
|
||||||
|
}
|
||||||
|
if rule.CycleStart.After(time.Now()) {
|
||||||
|
return errors.New("错误: cycle_start 是个未来值")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return errors.New("至少定义一条规则")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
@ -92,6 +92,11 @@ func routers(r *gin.Engine) {
|
|||||||
auth.PATCH("/notification/:id", commonHandler(updateNotification))
|
auth.PATCH("/notification/:id", commonHandler(updateNotification))
|
||||||
auth.POST("/batch-delete/notification", commonHandler(batchDeleteNotification))
|
auth.POST("/batch-delete/notification", commonHandler(batchDeleteNotification))
|
||||||
|
|
||||||
|
auth.GET("/alert-rule", commonHandler(listAlertRule))
|
||||||
|
auth.POST("/alert-rule", commonHandler(createAlertRule))
|
||||||
|
auth.PATCH("/alert-rule/:id", commonHandler(updateAlertRule))
|
||||||
|
auth.POST("/batch-delete/alert-rule", commonHandler(batchDeleteAlertRule))
|
||||||
|
|
||||||
auth.GET("/ddns", commonHandler(listDDNS))
|
auth.GET("/ddns", commonHandler(listDDNS))
|
||||||
auth.GET("/ddns/providers", commonHandler(listProviders))
|
auth.GET("/ddns/providers", commonHandler(listProviders))
|
||||||
auth.POST("/ddns", commonHandler(createDDNS))
|
auth.POST("/ddns", commonHandler(createDDNS))
|
||||||
|
@ -4,7 +4,6 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/jinzhu/copier"
|
"github.com/jinzhu/copier"
|
||||||
@ -66,8 +65,7 @@ func createDDNS(c *gin.Context) (uint64, error) {
|
|||||||
p.EnableIPv6 = &enableIPv6
|
p.EnableIPv6 = &enableIPv6
|
||||||
p.MaxRetries = df.MaxRetries
|
p.MaxRetries = df.MaxRetries
|
||||||
p.Provider = df.Provider
|
p.Provider = df.Provider
|
||||||
p.DomainsRaw = df.DomainsRaw
|
p.Domains = df.Domains
|
||||||
p.Domains = strings.Split(p.DomainsRaw, ",")
|
|
||||||
p.AccessID = df.AccessID
|
p.AccessID = df.AccessID
|
||||||
p.AccessSecret = df.AccessSecret
|
p.AccessSecret = df.AccessSecret
|
||||||
p.WebhookURL = df.WebhookURL
|
p.WebhookURL = df.WebhookURL
|
||||||
@ -137,8 +135,7 @@ func updateDDNS(c *gin.Context) (any, error) {
|
|||||||
p.EnableIPv6 = &enableIPv6
|
p.EnableIPv6 = &enableIPv6
|
||||||
p.MaxRetries = df.MaxRetries
|
p.MaxRetries = df.MaxRetries
|
||||||
p.Provider = df.Provider
|
p.Provider = df.Provider
|
||||||
p.DomainsRaw = df.DomainsRaw
|
p.Domains = df.Domains
|
||||||
p.Domains = strings.Split(p.DomainsRaw, ",")
|
|
||||||
p.AccessID = df.AccessID
|
p.AccessID = df.AccessID
|
||||||
p.AccessSecret = df.AccessSecret
|
p.AccessSecret = df.AccessSecret
|
||||||
p.WebhookURL = df.WebhookURL
|
p.WebhookURL = df.WebhookURL
|
||||||
|
@ -75,11 +75,6 @@ func (ma *memberAPI) delete(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
delete(singleton.Crons, id)
|
delete(singleton.Crons, id)
|
||||||
}
|
}
|
||||||
case "alert-rule":
|
|
||||||
err = singleton.DB.Unscoped().Delete(&model.AlertRule{}, "id = ?", id).Error
|
|
||||||
if err == nil {
|
|
||||||
singleton.OnDeleteAlert(id)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.JSON(http.StatusOK, model.Response{
|
c.JSON(http.StatusOK, model.Response{
|
||||||
|
@ -12,16 +12,16 @@ const (
|
|||||||
|
|
||||||
type AlertRule struct {
|
type AlertRule struct {
|
||||||
Common
|
Common
|
||||||
Name string
|
Name string `json:"name,omitempty"`
|
||||||
RulesRaw string
|
RulesRaw string `json:"-"`
|
||||||
Enable *bool
|
Enable *bool `json:"enable,omitempty"`
|
||||||
TriggerMode int `gorm:"default:0"` // 触发模式: 0-始终触发(默认) 1-单次触发
|
TriggerMode int `gorm:"default:0" json:"trigger_mode,omitempty"` // 触发模式: 0-始终触发(默认) 1-单次触发
|
||||||
NotificationGroupID uint64 // 该报警规则所在的通知组
|
NotificationGroupID uint64 `json:"notification_group_id,omitempty"` // 该报警规则所在的通知组
|
||||||
FailTriggerTasksRaw string `gorm:"default:'[]'"`
|
FailTriggerTasksRaw string `gorm:"default:'[]'" json:"-"`
|
||||||
RecoverTriggerTasksRaw string `gorm:"default:'[]'"`
|
RecoverTriggerTasksRaw string `gorm:"default:'[]'" json:"-"`
|
||||||
Rules []Rule `gorm:"-" json:"-"`
|
Rules []Rule `gorm:"-" json:"rules"`
|
||||||
FailTriggerTasks []uint64 `gorm:"-" json:"-"` // 失败时执行的触发任务id
|
FailTriggerTasks []uint64 `gorm:"-" json:"fail_trigger_tasks"` // 失败时执行的触发任务id
|
||||||
RecoverTriggerTasks []uint64 `gorm:"-" json:"-"` // 恢复时执行的触发任务id
|
RecoverTriggerTasks []uint64 `gorm:"-" json:"recover_trigger_tasks"` // 恢复时执行的触发任务id
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *AlertRule) BeforeSave(tx *gorm.DB) error {
|
func (r *AlertRule) BeforeSave(tx *gorm.DB) error {
|
||||||
|
12
model/alertrule_api.go
Normal file
12
model/alertrule_api.go
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
package model
|
||||||
|
|
||||||
|
type AlertRuleForm struct {
|
||||||
|
ID uint64 `json:"id"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Rules []Rule `json:"rules"`
|
||||||
|
FailTriggerTasks []uint64 `json:"fail_trigger_tasks"` // 失败时触发的任务id
|
||||||
|
RecoverTriggerTasks []uint64 `json:"recover_trigger_tasks"` // 恢复时触发的任务id
|
||||||
|
NotificationGroupID uint64 `json:"notification_group_id"`
|
||||||
|
TriggerMode int `json:"trigger_mode"`
|
||||||
|
Enable bool `json:"enable"`
|
||||||
|
}
|
@ -3,6 +3,7 @@ package model
|
|||||||
import (
|
import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/naiba/nezha/pkg/utils"
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -32,33 +33,25 @@ type DDNSProfile struct {
|
|||||||
WebhookRequestBody string `json:"webhook_request_body,omitempty"`
|
WebhookRequestBody string `json:"webhook_request_body,omitempty"`
|
||||||
WebhookHeaders string `json:"webhook_headers,omitempty"`
|
WebhookHeaders string `json:"webhook_headers,omitempty"`
|
||||||
Domains []string `json:"domains,omitempty" gorm:"-"`
|
Domains []string `json:"domains,omitempty" gorm:"-"`
|
||||||
DomainsRaw string `json:"domains_raw,omitempty"`
|
DomainsRaw string `json:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d DDNSProfile) TableName() string {
|
func (d DDNSProfile) TableName() string {
|
||||||
return "ddns"
|
return "ddns"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (d *DDNSProfile) BeforeSave(tx *gorm.DB) error {
|
||||||
|
if data, err := utils.Json.Marshal(d.Domains); err != nil {
|
||||||
|
return err
|
||||||
|
} else {
|
||||||
|
d.DomainsRaw = string(data)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (d *DDNSProfile) AfterFind(tx *gorm.DB) error {
|
func (d *DDNSProfile) AfterFind(tx *gorm.DB) error {
|
||||||
if d.DomainsRaw != "" {
|
if d.DomainsRaw != "" {
|
||||||
d.Domains = strings.Split(d.DomainsRaw, ",")
|
d.Domains = strings.Split(d.DomainsRaw, ",")
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type DDNSForm struct {
|
|
||||||
ID uint64 `json:"id,omitempty"`
|
|
||||||
MaxRetries uint64 `json:"max_retries,omitempty"`
|
|
||||||
EnableIPv4 bool `json:"enable_ipv4,omitempty"`
|
|
||||||
EnableIPv6 bool `json:"enable_ipv6,omitempty"`
|
|
||||||
Name string `json:"name,omitempty"`
|
|
||||||
Provider string `json:"provider,omitempty"`
|
|
||||||
DomainsRaw string `json:"domains_raw,omitempty"`
|
|
||||||
AccessID string `json:"access_id,omitempty"`
|
|
||||||
AccessSecret string `json:"access_secret,omitempty"`
|
|
||||||
WebhookURL string `json:"webhook_url,omitempty"`
|
|
||||||
WebhookMethod uint8 `json:"webhook_method,omitempty"`
|
|
||||||
WebhookRequestType uint8 `json:"webhook_request_type,omitempty"`
|
|
||||||
WebhookRequestBody string `json:"webhook_request_body,omitempty"`
|
|
||||||
WebhookHeaders string `json:"webhook_headers,omitempty"`
|
|
||||||
}
|
|
||||||
|
18
model/ddns_api.go
Normal file
18
model/ddns_api.go
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
package model
|
||||||
|
|
||||||
|
type DDNSForm struct {
|
||||||
|
ID uint64 `json:"id,omitempty"`
|
||||||
|
MaxRetries uint64 `json:"max_retries,omitempty"`
|
||||||
|
EnableIPv4 bool `json:"enable_ipv4,omitempty"`
|
||||||
|
EnableIPv6 bool `json:"enable_ipv6,omitempty"`
|
||||||
|
Name string `json:"name,omitempty"`
|
||||||
|
Provider string `json:"provider,omitempty"`
|
||||||
|
Domains []string `json:"domains,omitempty"`
|
||||||
|
AccessID string `json:"access_id,omitempty"`
|
||||||
|
AccessSecret string `json:"access_secret,omitempty"`
|
||||||
|
WebhookURL string `json:"webhook_url,omitempty"`
|
||||||
|
WebhookMethod uint8 `json:"webhook_method,omitempty"`
|
||||||
|
WebhookRequestType uint8 `json:"webhook_request_type,omitempty"`
|
||||||
|
WebhookRequestBody string `json:"webhook_request_body,omitempty"`
|
||||||
|
WebhookHeaders string `json:"webhook_headers,omitempty"`
|
||||||
|
}
|
@ -175,85 +175,85 @@ func (u *Rule) Snapshot(cycleTransferStats *CycleTransferStats, server *Server,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// IsTransferDurationRule 判断该规则是否属于周期流量规则 属于则返回true
|
// IsTransferDurationRule 判断该规则是否属于周期流量规则 属于则返回true
|
||||||
func (rule Rule) IsTransferDurationRule() bool {
|
func (u *Rule) IsTransferDurationRule() bool {
|
||||||
return strings.HasSuffix(rule.Type, "_cycle")
|
return strings.HasSuffix(u.Type, "_cycle")
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetTransferDurationStart 获取周期流量的起始时间
|
// GetTransferDurationStart 获取周期流量的起始时间
|
||||||
func (rule Rule) GetTransferDurationStart() time.Time {
|
func (u *Rule) GetTransferDurationStart() time.Time {
|
||||||
// Accept uppercase and lowercase
|
// Accept uppercase and lowercase
|
||||||
unit := strings.ToLower(rule.CycleUnit)
|
unit := strings.ToLower(u.CycleUnit)
|
||||||
startTime := *rule.CycleStart
|
startTime := *u.CycleStart
|
||||||
var nextTime time.Time
|
var nextTime time.Time
|
||||||
switch unit {
|
switch unit {
|
||||||
case "year":
|
case "year":
|
||||||
nextTime = startTime.AddDate(int(rule.CycleInterval), 0, 0)
|
nextTime = startTime.AddDate(int(u.CycleInterval), 0, 0)
|
||||||
for time.Now().After(nextTime) {
|
for time.Now().After(nextTime) {
|
||||||
startTime = nextTime
|
startTime = nextTime
|
||||||
nextTime = nextTime.AddDate(int(rule.CycleInterval), 0, 0)
|
nextTime = nextTime.AddDate(int(u.CycleInterval), 0, 0)
|
||||||
}
|
}
|
||||||
case "month":
|
case "month":
|
||||||
nextTime = startTime.AddDate(0, int(rule.CycleInterval), 0)
|
nextTime = startTime.AddDate(0, int(u.CycleInterval), 0)
|
||||||
for time.Now().After(nextTime) {
|
for time.Now().After(nextTime) {
|
||||||
startTime = nextTime
|
startTime = nextTime
|
||||||
nextTime = nextTime.AddDate(0, int(rule.CycleInterval), 0)
|
nextTime = nextTime.AddDate(0, int(u.CycleInterval), 0)
|
||||||
}
|
}
|
||||||
case "week":
|
case "week":
|
||||||
nextTime = startTime.AddDate(0, 0, 7*int(rule.CycleInterval))
|
nextTime = startTime.AddDate(0, 0, 7*int(u.CycleInterval))
|
||||||
for time.Now().After(nextTime) {
|
for time.Now().After(nextTime) {
|
||||||
startTime = nextTime
|
startTime = nextTime
|
||||||
nextTime = nextTime.AddDate(0, 0, 7*int(rule.CycleInterval))
|
nextTime = nextTime.AddDate(0, 0, 7*int(u.CycleInterval))
|
||||||
}
|
}
|
||||||
case "day":
|
case "day":
|
||||||
nextTime = startTime.AddDate(0, 0, int(rule.CycleInterval))
|
nextTime = startTime.AddDate(0, 0, int(u.CycleInterval))
|
||||||
for time.Now().After(nextTime) {
|
for time.Now().After(nextTime) {
|
||||||
startTime = nextTime
|
startTime = nextTime
|
||||||
nextTime = nextTime.AddDate(0, 0, int(rule.CycleInterval))
|
nextTime = nextTime.AddDate(0, 0, int(u.CycleInterval))
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
// For hour unit or not set.
|
// For hour unit or not set.
|
||||||
interval := 3600 * int64(rule.CycleInterval)
|
interval := 3600 * int64(u.CycleInterval)
|
||||||
startTime = time.Unix(rule.CycleStart.Unix()+(time.Now().Unix()-rule.CycleStart.Unix())/interval*interval, 0)
|
startTime = time.Unix(u.CycleStart.Unix()+(time.Now().Unix()-u.CycleStart.Unix())/interval*interval, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
return startTime
|
return startTime
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetTransferDurationEnd 获取周期流量结束时间
|
// GetTransferDurationEnd 获取周期流量结束时间
|
||||||
func (rule Rule) GetTransferDurationEnd() time.Time {
|
func (u *Rule) GetTransferDurationEnd() time.Time {
|
||||||
// Accept uppercase and lowercase
|
// Accept uppercase and lowercase
|
||||||
unit := strings.ToLower(rule.CycleUnit)
|
unit := strings.ToLower(u.CycleUnit)
|
||||||
startTime := *rule.CycleStart
|
startTime := *u.CycleStart
|
||||||
var nextTime time.Time
|
var nextTime time.Time
|
||||||
switch unit {
|
switch unit {
|
||||||
case "year":
|
case "year":
|
||||||
nextTime = startTime.AddDate(int(rule.CycleInterval), 0, 0)
|
nextTime = startTime.AddDate(int(u.CycleInterval), 0, 0)
|
||||||
for time.Now().After(nextTime) {
|
for time.Now().After(nextTime) {
|
||||||
startTime = nextTime
|
startTime = nextTime
|
||||||
nextTime = nextTime.AddDate(int(rule.CycleInterval), 0, 0)
|
nextTime = nextTime.AddDate(int(u.CycleInterval), 0, 0)
|
||||||
}
|
}
|
||||||
case "month":
|
case "month":
|
||||||
nextTime = startTime.AddDate(0, int(rule.CycleInterval), 0)
|
nextTime = startTime.AddDate(0, int(u.CycleInterval), 0)
|
||||||
for time.Now().After(nextTime) {
|
for time.Now().After(nextTime) {
|
||||||
startTime = nextTime
|
startTime = nextTime
|
||||||
nextTime = nextTime.AddDate(0, int(rule.CycleInterval), 0)
|
nextTime = nextTime.AddDate(0, int(u.CycleInterval), 0)
|
||||||
}
|
}
|
||||||
case "week":
|
case "week":
|
||||||
nextTime = startTime.AddDate(0, 0, 7*int(rule.CycleInterval))
|
nextTime = startTime.AddDate(0, 0, 7*int(u.CycleInterval))
|
||||||
for time.Now().After(nextTime) {
|
for time.Now().After(nextTime) {
|
||||||
startTime = nextTime
|
startTime = nextTime
|
||||||
nextTime = nextTime.AddDate(0, 0, 7*int(rule.CycleInterval))
|
nextTime = nextTime.AddDate(0, 0, 7*int(u.CycleInterval))
|
||||||
}
|
}
|
||||||
case "day":
|
case "day":
|
||||||
nextTime = startTime.AddDate(0, 0, int(rule.CycleInterval))
|
nextTime = startTime.AddDate(0, 0, int(u.CycleInterval))
|
||||||
for time.Now().After(nextTime) {
|
for time.Now().After(nextTime) {
|
||||||
startTime = nextTime
|
startTime = nextTime
|
||||||
nextTime = nextTime.AddDate(0, 0, int(rule.CycleInterval))
|
nextTime = nextTime.AddDate(0, 0, int(u.CycleInterval))
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
// For hour unit or not set.
|
// For hour unit or not set.
|
||||||
interval := 3600 * int64(rule.CycleInterval)
|
interval := 3600 * int64(u.CycleInterval)
|
||||||
startTime = time.Unix(rule.CycleStart.Unix()+(time.Now().Unix()-rule.CycleStart.Unix())/interval*interval, 0)
|
startTime = time.Unix(u.CycleStart.Unix()+(time.Now().Unix()-u.CycleStart.Unix())/interval*interval, 0)
|
||||||
nextTime = time.Unix(startTime.Unix()+interval, 0)
|
nextTime = time.Unix(startTime.Unix()+interval, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,7 +27,7 @@ var (
|
|||||||
AlertsLock sync.RWMutex
|
AlertsLock sync.RWMutex
|
||||||
Alerts []*model.AlertRule
|
Alerts []*model.AlertRule
|
||||||
alertsStore map[uint64]map[uint64][][]interface{} // [alert_id][server_id] -> 对应报警规则的检查结果
|
alertsStore map[uint64]map[uint64][][]interface{} // [alert_id][server_id] -> 对应报警规则的检查结果
|
||||||
alertsPrevState map[uint64]map[uint64]uint // [alert_id][server_id] -> 对应报警规则的上一次报警状态
|
alertsPrevState map[uint64]map[uint64]uint8 // [alert_id][server_id] -> 对应报警规则的上一次报警状态
|
||||||
AlertsCycleTransferStatsStore map[uint64]*model.CycleTransferStats // [alert_id] -> 对应报警规则的周期流量统计
|
AlertsCycleTransferStatsStore map[uint64]*model.CycleTransferStats // [alert_id] -> 对应报警规则的周期流量统计
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -60,7 +60,7 @@ func addCycleTransferStatsInfo(alert *model.AlertRule) {
|
|||||||
// AlertSentinelStart 报警器启动
|
// AlertSentinelStart 报警器启动
|
||||||
func AlertSentinelStart() {
|
func AlertSentinelStart() {
|
||||||
alertsStore = make(map[uint64]map[uint64][][]interface{})
|
alertsStore = make(map[uint64]map[uint64][][]interface{})
|
||||||
alertsPrevState = make(map[uint64]map[uint64]uint)
|
alertsPrevState = make(map[uint64]map[uint64]uint8)
|
||||||
AlertsCycleTransferStatsStore = make(map[uint64]*model.CycleTransferStats)
|
AlertsCycleTransferStatsStore = make(map[uint64]*model.CycleTransferStats)
|
||||||
AlertsLock.Lock()
|
AlertsLock.Lock()
|
||||||
if err := DB.Find(&Alerts).Error; err != nil {
|
if err := DB.Find(&Alerts).Error; err != nil {
|
||||||
@ -68,7 +68,7 @@ func AlertSentinelStart() {
|
|||||||
}
|
}
|
||||||
for _, alert := range Alerts {
|
for _, alert := range Alerts {
|
||||||
alertsStore[alert.ID] = make(map[uint64][][]interface{})
|
alertsStore[alert.ID] = make(map[uint64][][]interface{})
|
||||||
alertsPrevState[alert.ID] = make(map[uint64]uint)
|
alertsPrevState[alert.ID] = make(map[uint64]uint8)
|
||||||
addCycleTransferStatsInfo(alert)
|
addCycleTransferStatsInfo(alert)
|
||||||
}
|
}
|
||||||
AlertsLock.Unlock()
|
AlertsLock.Unlock()
|
||||||
@ -107,23 +107,26 @@ func OnRefreshOrAddAlert(alert model.AlertRule) {
|
|||||||
Alerts = append(Alerts, &alert)
|
Alerts = append(Alerts, &alert)
|
||||||
}
|
}
|
||||||
alertsStore[alert.ID] = make(map[uint64][][]interface{})
|
alertsStore[alert.ID] = make(map[uint64][][]interface{})
|
||||||
alertsPrevState[alert.ID] = make(map[uint64]uint)
|
alertsPrevState[alert.ID] = make(map[uint64]uint8)
|
||||||
delete(AlertsCycleTransferStatsStore, alert.ID)
|
delete(AlertsCycleTransferStatsStore, alert.ID)
|
||||||
addCycleTransferStatsInfo(&alert)
|
addCycleTransferStatsInfo(&alert)
|
||||||
}
|
}
|
||||||
|
|
||||||
func OnDeleteAlert(id uint64) {
|
func OnDeleteAlert(id []uint64) {
|
||||||
AlertsLock.Lock()
|
AlertsLock.Lock()
|
||||||
defer AlertsLock.Unlock()
|
defer AlertsLock.Unlock()
|
||||||
delete(alertsStore, id)
|
for _, i := range id {
|
||||||
delete(alertsPrevState, id)
|
delete(alertsStore, i)
|
||||||
for i := 0; i < len(Alerts); i++ {
|
delete(alertsPrevState, i)
|
||||||
if Alerts[i].ID == id {
|
currentAlerts := Alerts[:0]
|
||||||
Alerts = append(Alerts[:i], Alerts[i+1:]...)
|
for _, alert := range Alerts {
|
||||||
i--
|
if alert.ID != i {
|
||||||
|
currentAlerts = append(currentAlerts, alert)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
delete(AlertsCycleTransferStatsStore, id)
|
Alerts = currentAlerts
|
||||||
|
delete(AlertsCycleTransferStatsStore, i)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// checkStatus 检查报警规则并发送报警
|
// checkStatus 检查报警规则并发送报警
|
||||||
|
Loading…
Reference in New Issue
Block a user