diff --git a/alert/alert.go b/alert/alert.go index dfb6e60..031428f 100644 --- a/alert/alert.go +++ b/alert/alert.go @@ -3,16 +3,23 @@ package alert import ( "watchAlert/alert/consumer" "watchAlert/alert/eval" + "watchAlert/alert/task" "watchAlert/internal/global" "watchAlert/pkg/ctx" ) -func Initialize(ctx *ctx.Context) { +var ( + MonEvalTask task.MonitorSSLEval + MonConsumerTask consumer.MonitorSslConsumer +) +func Initialize(ctx *ctx.Context) { consumer.NewInterEvalConsumeWork(ctx).Run() eval.NewInterAlertRuleWork(ctx).Run() initAlarmConfig(ctx) - + MonConsumerTask = consumer.NewMonitorSslConsumer(ctx) + MonEvalTask = task.NewMonitorSSLEval() + MonEvalTask.RePushTask(ctx, &MonConsumerTask) } func initAlarmConfig(ctx *ctx.Context) { diff --git a/alert/consumer/monitor_ssl.go b/alert/consumer/monitor_ssl.go new file mode 100644 index 0000000..b1bf534 --- /dev/null +++ b/alert/consumer/monitor_ssl.go @@ -0,0 +1,103 @@ +package consumer + +import ( + "context" + "fmt" + "sync" + "time" + "watchAlert/alert/process" + "watchAlert/alert/sender" + "watchAlert/internal/global" + "watchAlert/internal/models" + "watchAlert/pkg/ctx" +) + +type MonitorSslConsumer struct { + l sync.RWMutex + consumerPool map[string]context.CancelFunc + ctx *ctx.Context +} + +func NewMonitorSslConsumer(ctx *ctx.Context) MonitorSslConsumer { + return MonitorSslConsumer{ + ctx: ctx, + consumerPool: make(map[string]context.CancelFunc), + } +} + +func (m *MonitorSslConsumer) Add(r models.MonitorSSLRule) { + m.l.Lock() + m.l.Unlock() + + c, cancel := context.WithCancel(context.Background()) + m.consumerPool[r.ID] = cancel + + ticker := time.Tick(time.Second) + go func(ctx context.Context, r models.MonitorSSLRule) { + for { + select { + case <-ticker: + key := fmt.Sprintf("%s:%s%s--", r.TenantId, models.FiringAlertCachePrefix, r.ID) + result := m.ctx.Redis.Event().GetCache(key) + handleAlert(m.ctx, result) + case <-ctx.Done(): + return + } + } + }(c, r) +} + +func (m *MonitorSslConsumer) Stop(id string) { + m.l.Lock() + m.l.Unlock() + + if cancel, exists := m.consumerPool[id]; exists { + cancel() + } +} + +func filterEvent(ctx *ctx.Context, alert models.AlertCurEvent) bool { + var pass bool + if !alert.IsRecovered { + if alert.LastSendTime == 0 || alert.LastEvalTime >= alert.LastSendTime+alert.RepeatNoticeInterval*60 { + alert.LastSendTime = time.Now().Unix() + ctx.Redis.Event().SetCache("Firing", alert, 0) + return true + } + } else { + removeAlertFromCache(ctx, alert) + err := process.RecordAlertHisEvent(ctx, alert) + if err != nil { + global.Logger.Sugar().Error(err.Error()) + } + return true + } + return pass +} + +// 删除缓存 +func removeAlertFromCache(ctx *ctx.Context, alert models.AlertCurEvent) { + key := fmt.Sprintf("%s:%s%s--", alert.TenantId, models.FiringAlertCachePrefix, alert.RuleId) + ctx.Redis.Event().DelCache(key) +} + +// 推送告警 +func handleAlert(ctx *ctx.Context, alert models.AlertCurEvent) { + if alert.RuleId == "" { + return + } + + if filterEvent(ctx, alert) { + r := models.NoticeQuery{ + TenantId: alert.TenantId, + Uuid: alert.NoticeId, + } + noticeData, _ := ctx.DB.Notice().Get(r) + alert.DutyUser = process.GetDutyUser(ctx, noticeData) + err := sender.Sender(ctx, alert, noticeData) + if err != nil { + global.Logger.Sugar().Errorf(err.Error()) + return + } + } +} diff --git a/alert/eval/alert_rule.go b/alert/eval/alert_rule.go index 0b587d3..2a93c54 100644 --- a/alert/eval/alert_rule.go +++ b/alert/eval/alert_rule.go @@ -2,21 +2,20 @@ package eval import ( "context" + "fmt" "sync" "time" "watchAlert/alert/query" "watchAlert/alert/queue" "watchAlert/internal/global" models "watchAlert/internal/models" - "watchAlert/internal/services" "watchAlert/pkg/ctx" ) type AlertRuleWork struct { sync.RWMutex query.RuleQuery - ctx *ctx.Context - services.InterAlertService + ctx *ctx.Context rule chan *models.AlertRule alertEvent models.AlertCurEvent } @@ -49,9 +48,7 @@ func (arw *AlertRuleWork) Run() { } }() - // 重启服务后将历史 Rule 重新推到队列中 - services.AlertService.RePushRule(arw.ctx, arw.rule) - + rePushRule(arw.ctx, arw.rule) } func (arw *AlertRuleWork) worker(rule models.AlertRule, ctx context.Context) { @@ -75,3 +72,41 @@ func (arw *AlertRuleWork) worker(rule models.AlertRule, ctx context.Context) { } } + +func rePushRule(ctx *ctx.Context, alertRule chan *models.AlertRule) { + + var ( + ruleList []models.AlertRule + // 创建一个通道用于接收处理结果 + resultCh = make(chan error) + // 使用 WaitGroup 来等待所有规则的处理完成 + wg sync.WaitGroup + ) + ctx.DB.DB().Where("enabled = ?", "1").Find(&ruleList) + + // 并发处理规则 + for _, rule := range ruleList { + wg.Add(1) + go func(rule models.AlertRule) { + defer wg.Done() + + alertRule <- &rule + + resultCh <- nil + }(rule) + } + + // 等待所有规则的处理完成 + go func() { + wg.Wait() + close(resultCh) + }() + + // 处理结果 + for result := range resultCh { + if result != nil { + fmt.Println("Error:", result) + } + } + +} diff --git a/alert/task/process.go b/alert/task/process.go new file mode 100644 index 0000000..d0b874a --- /dev/null +++ b/alert/task/process.go @@ -0,0 +1,15 @@ +package task + +import ( + "watchAlert/internal/models" + "watchAlert/pkg/ctx" +) + +func SaveMonitorCacheEvent(ctx *ctx.Context, event models.AlertCurEvent) { + firingKey := event.GetFiringAlertCacheKey() + resFiring := ctx.Redis.Event().GetCache(firingKey) + event.FirstTriggerTime = ctx.Redis.Event().GetFirstTime(firingKey) + event.LastEvalTime = ctx.Redis.Event().GetLastEvalTime(firingKey) + event.LastSendTime = resFiring.LastSendTime + ctx.Redis.Event().SetCache("Firing", event, 0) +} diff --git a/alert/task/task.go b/alert/task/task.go new file mode 100644 index 0000000..a433116 --- /dev/null +++ b/alert/task/task.go @@ -0,0 +1,161 @@ +package task + +import ( + "context" + "fmt" + "golang.org/x/sync/errgroup" + "sync" + "time" + "watchAlert/alert/consumer" + "watchAlert/internal/global" + "watchAlert/internal/models" + "watchAlert/pkg/ctx" + "watchAlert/pkg/utils/http" +) + +type MonitorSSLEval struct { + l sync.RWMutex + WatchCtxMap map[string]context.CancelFunc +} + +func NewMonitorSSLEval() MonitorSSLEval { + return MonitorSSLEval{ + WatchCtxMap: make(map[string]context.CancelFunc), + } +} + +func (t *MonitorSSLEval) Submit(ctx *ctx.Context, rule models.MonitorSSLRule) { + t.l.Lock() + defer t.l.Unlock() + + c, cancel := context.WithCancel(context.Background()) + t.WatchCtxMap[rule.ID] = cancel + go t.Eval(c, ctx, rule) +} + +func (t *MonitorSSLEval) Stop(id string) { + t.l.Lock() + defer t.l.Unlock() + + if cancel, exists := t.WatchCtxMap[id]; exists { + cancel() + delete(t.WatchCtxMap, id) + } +} + +func (t *MonitorSSLEval) Eval(ctx context.Context, w8tCtx *ctx.Context, rule models.MonitorSSLRule) { + timer := time.NewTicker(time.Hour * time.Duration(rule.EvalInterval)) + defer timer.Stop() + t.worker(w8tCtx, rule) + + for { + select { + case <-timer.C: + t.worker(w8tCtx, rule) + case <-ctx.Done(): + return + } + } +} + +func (t *MonitorSSLEval) worker(w8tCtx *ctx.Context, rule models.MonitorSSLRule) { + // 记录开始时间 + startTime := time.Now() + + resp, err := http.Get("https://" + rule.Domain) + if err != nil { + return + } + defer resp.Body.Close() + + // 证书为空, 跳过检测 + if resp.TLS == nil { + t.Stop(rule.ID) + return + } + + // 获取证书信息 + certs := resp.TLS.PeerCertificates[0] + certTime := certs.NotAfter.Unix() + currentTime := time.Now().Unix() + + // 计算剩余有效期时间 + TimeRemaining := (certTime - currentTime) / 86400 + + // 创建事件 + event := t.processDefaultEvent(rule) + event.TimeRemaining = TimeRemaining + event.ResponseTime = fmt.Sprintf("%dms", time.Since(startTime).Milliseconds()) + event.Metric = rule.GetMetrics() + event.Annotations = fmt.Sprintf("域名: %s, SSL证书即将到期, 剩余: %d天", rule.Domain, TimeRemaining) + + // 更新规则信息 + rule.TimeRemaining = event.TimeRemaining + rule.ResponseTime = event.ResponseTime + if err := w8tCtx.DB.MonitorSSL().Update(rule); err != nil { + global.Logger.Sugar().Error(err.Error()) + return + } + + // 根据剩余时间与期望时间判断是否触发告警或恢复 + if TimeRemaining <= rule.ExpectTime { + SaveMonitorCacheEvent(w8tCtx, event) + } else { + t.processRecover(w8tCtx, event) + } +} + +func (t *MonitorSSLEval) processDefaultEvent(rule models.MonitorSSLRule) models.AlertCurEvent { + return models.AlertCurEvent{ + TenantId: rule.TenantId, + RuleId: rule.ID, + RuleName: rule.Name, + EvalInterval: rule.EvalInterval, + NoticeId: rule.NoticeId, + IsRecovered: false, + RepeatNoticeInterval: rule.RepeatNoticeInterval, + DutyUser: "暂无", // 默认暂无值班人员, 渲染模版时会实际判断 Notice 是否存在值班人员 + RecoverNotify: rule.RecoverNotify, + } +} + +func (t *MonitorSSLEval) processRecover(ctx *ctx.Context, event models.AlertCurEvent) { + key := fmt.Sprintf("%s:%s%s--", event.TenantId, models.FiringAlertCachePrefix, event.RuleId) + cache := ctx.Redis.Event().GetCache(key) + + // 提前返回,如果缓存中没有相关数据或已经恢复 + if cache.RuleId == "" || cache.IsRecovered { + return + } + + // 检查事件的剩余时间是否大于或等于缓存中的剩余时间 + if event.TimeRemaining >= cache.TimeRemaining { + event.FirstTriggerTime = ctx.Redis.Event().GetFirstTime(key) + event.IsRecovered = true + event.RecoverTime = time.Now().Unix() + event.LastSendTime = 0 + ctx.Redis.Event().SetCache("Firing", event, 0) + } +} + +func (t *MonitorSSLEval) RePushTask(ctx *ctx.Context, consumer *consumer.MonitorSslConsumer) { + var ruleList []models.MonitorSSLRule + if err := ctx.DB.DB().Where("enabled = ?", "1").Find(&ruleList).Error; err != nil { + global.Logger.Sugar().Error(err.Error()) + return + } + + g := new(errgroup.Group) + for _, rule := range ruleList { + rule := rule + g.Go(func() error { + t.Submit(ctx, rule) + consumer.Add(rule) + return nil + }) + } + + if err := g.Wait(); err != nil { + global.Logger.Sugar().Error(err.Error()) + } +} diff --git a/api/entry.go b/api/entry.go index beace90..1dd4f36 100644 --- a/api/entry.go +++ b/api/entry.go @@ -30,6 +30,7 @@ type ApiGroup struct { AWSCloudWatchRDSController SettingsController KubernetesTypesController + MonitorSSLController } var ApiGroupApp = new(ApiGroup) diff --git a/api/monitor_ssl.go b/api/monitor_ssl.go new file mode 100644 index 0000000..2119372 --- /dev/null +++ b/api/monitor_ssl.go @@ -0,0 +1,86 @@ +package api + +import ( + "github.com/gin-gonic/gin" + "watchAlert/internal/middleware" + "watchAlert/internal/models" + "watchAlert/internal/services" +) + +type MonitorSSLController struct{} + +func (m MonitorSSLController) API(gin *gin.RouterGroup) { + mon := gin.Group("monitor") + mon.Use( + middleware.Auth(), + middleware.Permission(), + middleware.ParseTenant(), + ) + { + mon.POST("createMon", m.create) + mon.POST("updateMon", m.update) + mon.POST("deleteMon", m.delete) + mon.GET("listMon", m.list) + mon.GET("getMon", m.get) + } +} + +func (m MonitorSSLController) create(ctx *gin.Context) { + r := new(models.MonitorSSLRule) + BindJson(ctx, r) + + tid, _ := ctx.Get("TenantID") + r.TenantId = tid.(string) + + Service(ctx, func() (interface{}, interface{}) { + return services.MonitorService.Create(r) + }) +} + +func (m MonitorSSLController) update(ctx *gin.Context) { + r := new(models.MonitorSSLRule) + BindJson(ctx, r) + + tid, _ := ctx.Get("TenantID") + r.TenantId = tid.(string) + + Service(ctx, func() (interface{}, interface{}) { + return services.MonitorService.Update(r) + }) +} + +func (m MonitorSSLController) delete(ctx *gin.Context) { + r := new(models.MonitorSSLRuleQuery) + BindJson(ctx, r) + + tid, _ := ctx.Get("TenantID") + r.TenantId = tid.(string) + + Service(ctx, func() (interface{}, interface{}) { + return services.MonitorService.Delete(r) + }) +} + +func (m MonitorSSLController) list(ctx *gin.Context) { + r := new(models.MonitorSSLRuleQuery) + BindQuery(ctx, r) + + tid, _ := ctx.Get("TenantID") + r.TenantId = tid.(string) + + Service(ctx, func() (interface{}, interface{}) { + return services.MonitorService.List(r) + }) +} + +func (m MonitorSSLController) get(ctx *gin.Context) { + r := new(models.MonitorSSLRuleQuery) + BindQuery(ctx, r) + + tid, _ := ctx.Get("TenantID") + r.TenantId = tid.(string) + + Service(ctx, func() (interface{}, interface{}) { + return services.MonitorService.Get(r) + }) +} diff --git a/go.mod b/go.mod index 897b1ee..492e99f 100644 --- a/go.mod +++ b/go.mod @@ -104,6 +104,7 @@ require ( golang.org/x/crypto v0.22.0 // indirect golang.org/x/net v0.24.0 // indirect golang.org/x/oauth2 v0.16.0 // indirect + golang.org/x/sync v0.8.0 // indirect golang.org/x/sys v0.19.0 // indirect golang.org/x/term v0.19.0 // indirect golang.org/x/text v0.14.0 // indirect diff --git a/go.sum b/go.sum index c45421d..8db2af7 100644 --- a/go.sum +++ b/go.sum @@ -520,6 +520,8 @@ golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= +golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= diff --git a/internal/models/alert_current_event.go b/internal/models/alert_current_event.go index 794971d..255abfd 100644 --- a/internal/models/alert_current_event.go +++ b/internal/models/alert_current_event.go @@ -31,6 +31,9 @@ type AlertCurEvent struct { DutyUser string `json:"duty_user" gorm:"-"` EffectiveTime EffectiveTime `json:"effectiveTime" gorm:"effectiveTime;serializer:json"` RecoverNotify *bool `json:"recoverNotify"` + + ResponseTime string `json:"response_time" gorm:"-"` + TimeRemaining int64 `json:"time_remaining" gorm:"-"` } type AlertCurEventQuery struct { diff --git a/internal/models/monitor_ssl.go b/internal/models/monitor_ssl.go new file mode 100644 index 0000000..684af4f --- /dev/null +++ b/internal/models/monitor_ssl.go @@ -0,0 +1,31 @@ +package models + +type MonitorSSLRule struct { + TenantId string `json:"tenantId"` + ID string `json:"id"` + Name string `json:"name"` + Domain string `json:"domain"` + Description string `json:"description"` + ExpectTime int64 `json:"expectTime"` // 预期剩余时间 + EvalInterval int64 `json:"evalInterval"` // Second + NoticeId string `json:"noticeId"` + RepeatNoticeInterval int64 `json:"repeatNoticeInterval"` // 重复通知间隔时间 + TimeRemaining int64 `json:"timeRemaining"` + ResponseTime string `json:"responseTime"` + Enabled *bool `json:"enabled"` + RecoverNotify *bool `json:"recoverNotify"` +} + +type MonitorSSLRuleQuery struct { + TenantId string `json:"tenantId"` + ID string `json:"id" form:"id"` + Name string `json:"name" form:"name"` + Domain string `json:"domain" form:"domain"` + Query string `json:"query" form:"query"` +} + +func (m MonitorSSLRule) GetMetrics() map[string]interface{} { + return map[string]interface{}{ + "DomainName": m.Domain, + } +} diff --git a/internal/models/user_permissions.go b/internal/models/user_permissions.go index 2bbc9ce..b5f334f 100644 --- a/internal/models/user_permissions.go +++ b/internal/models/user_permissions.go @@ -319,5 +319,25 @@ func PermissionsInfo() map[string]UserPermissions { Key: "获取Kubernetes事件类型列表", API: "/api/w8t/kubernetes/getReasonList", }, + "createMon": { + Key: "创建证书监控", + API: "/api/w8t/monitor/createMon", + }, + "updateMon": { + Key: "更新证书监控", + API: "/api/w8t/monitor/updateMon", + }, + "deleteMon": { + Key: "删除证书监控", + API: "/api/w8t/monitor/deleteMon", + }, + "listMon": { + Key: "获取证书监控列表", + API: "/api/w8t/monitor/listMon", + }, + "getMon": { + Key: "获取证书监控信息", + API: "/api/w8t/monitor/getMon", + }, } } diff --git a/internal/repo/entry.go b/internal/repo/entry.go index cb4324e..ffb17d9 100644 --- a/internal/repo/entry.go +++ b/internal/repo/entry.go @@ -31,6 +31,7 @@ type ( UserRole() InterUserRoleRepo UserPermissions() InterUserPermissionsRepo Setting() InterSettingRepo + MonitorSSL() InterMonitorSSLRepo } ) @@ -65,4 +66,5 @@ func (e *entryRepo) UserRole() InterUserRoleRepo { return newUserRoleInterface(e func (e *entryRepo) UserPermissions() InterUserPermissionsRepo { return newInterUserPermissionsRepo(e.db, e.g) } -func (e *entryRepo) Setting() InterSettingRepo { return newSettingRepoInterface(e.db, e.g) } +func (e *entryRepo) Setting() InterSettingRepo { return newSettingRepoInterface(e.db, e.g) } +func (e *entryRepo) MonitorSSL() InterMonitorSSLRepo { return newMonitorSSLInterface(e.db, e.g) } diff --git a/internal/repo/monitor_ssl.go b/internal/repo/monitor_ssl.go new file mode 100644 index 0000000..a0237e8 --- /dev/null +++ b/internal/repo/monitor_ssl.go @@ -0,0 +1,100 @@ +package repo + +import ( + "fmt" + "gorm.io/gorm" + "watchAlert/internal/global" + "watchAlert/internal/models" +) + +type ( + monitorSSLRepo struct { + entryRepo + } + + InterMonitorSSLRepo interface { + Get(r models.MonitorSSLRuleQuery) (models.MonitorSSLRule, error) + List(req models.MonitorSSLRuleQuery) ([]models.MonitorSSLRule, error) + Create(r models.MonitorSSLRule) error + Update(r models.MonitorSSLRule) error + Delete(r models.MonitorSSLRuleQuery) error + } +) + +func newMonitorSSLInterface(db *gorm.DB, g InterGormDBCli) InterMonitorSSLRepo { + return &monitorSSLRepo{ + entryRepo{ + g: g, + db: db, + }, + } +} + +func (m monitorSSLRepo) Create(r models.MonitorSSLRule) error { + err := m.g.Create(models.MonitorSSLRule{}, r) + if err != nil { + return err + } + return nil +} + +func (m monitorSSLRepo) Update(r models.MonitorSSLRule) error { + u := Updates{ + Table: models.MonitorSSLRule{}, + Where: map[string]interface{}{ + "tenant_id = ?": r.TenantId, + "id = ?": r.ID, + }, + Updates: r, + } + fmt.Println("--->", r) + err := m.g.Updates(u) + if err != nil { + global.Logger.Sugar().Error(err.Error()) + return err + } + return nil +} + +func (m monitorSSLRepo) Delete(r models.MonitorSSLRuleQuery) error { + d := Delete{ + Table: models.MonitorSSLRule{}, + Where: map[string]interface{}{ + "tenant_id = ?": r.TenantId, + "id = ?": r.ID, + }, + } + err := m.g.Delete(d) + if err != nil { + return err + } + return nil +} + +func (m monitorSSLRepo) List(req models.MonitorSSLRuleQuery) ([]models.MonitorSSLRule, error) { + var Objects []models.MonitorSSLRule + db := m.db.Model(&models.MonitorSSLRule{}) + db.Where("tenant_id = ?", req.TenantId) + + if req.Query != "" { + db.Where("id LIKE ? OR name LIKE ? OR domain LIKE ?", "%"+req.Query+"%", "%"+req.Query+"%", "%"+req.Query+"%") + } + + err := db.Find(&Objects).Error + if err != nil { + return nil, err + } + + return Objects, nil +} + +func (m monitorSSLRepo) Get(r models.MonitorSSLRuleQuery) (models.MonitorSSLRule, error) { + var Object models.MonitorSSLRule + db := m.db.Model(&models.MonitorSSLRule{}).Where("tenant_id = ? AND id = ?", r.TenantId, r.ID) + err := db.First(&Object).Error + if err != nil { + return Object, err + } + + return Object, nil +} diff --git a/internal/routers/v1/api.go b/internal/routers/v1/api.go index 9fd0087..78e5abc 100644 --- a/internal/routers/v1/api.go +++ b/internal/routers/v1/api.go @@ -42,6 +42,7 @@ func Router(engine *gin.Engine) { AWSRds.API(w8t) Setting.API(w8t) KubeEvent.API(w8t) + Monitor.API(w8t) } } diff --git a/internal/routers/v1/api_entry.go b/internal/routers/v1/api_entry.go index 0c3dd8e..4894da6 100644 --- a/internal/routers/v1/api_entry.go +++ b/internal/routers/v1/api_entry.go @@ -28,4 +28,5 @@ var ( AWSRds = api.ApiGroupApp.AWSCloudWatchRDSController Setting = api.ApiGroupApp.SettingsController KubeEvent = api.ApiGroupApp.KubernetesTypesController + Monitor = api.ApiGroupApp.MonitorSSLController ) diff --git a/internal/services/entry.go b/internal/services/entry.go index 8c84826..35bf0da 100644 --- a/internal/services/entry.go +++ b/internal/services/entry.go @@ -30,6 +30,7 @@ var ( AWSCloudWatchRdsService service2.InterAwsRdsService SettingService InterSettingService ClientService InterClientService + MonitorService InterMonitorService ) func NewServices(ctx *ctx.Context) { @@ -56,4 +57,5 @@ func NewServices(ctx *ctx.Context) { AWSCloudWatchRdsService = service2.NewInterAWSRdsService(ctx) SettingService = newInterSettingService(ctx) ClientService = newInterClientService(ctx) + MonitorService = newInterMonitorService(ctx) } diff --git a/internal/services/monitor_ssl.go b/internal/services/monitor_ssl.go new file mode 100644 index 0000000..5e87acf --- /dev/null +++ b/internal/services/monitor_ssl.go @@ -0,0 +1,112 @@ +package services + +import ( + "fmt" + "watchAlert/alert" + "watchAlert/internal/models" + "watchAlert/pkg/ctx" + "watchAlert/pkg/utils/cmd" +) + +type monitorService struct { + ctx *ctx.Context +} + +type InterMonitorService interface { + Create(req interface{}) (interface{}, interface{}) + Update(req interface{}) (interface{}, interface{}) + Delete(req interface{}) (interface{}, interface{}) + List(req interface{}) (interface{}, interface{}) + Get(req interface{}) (interface{}, interface{}) +} + +func newInterMonitorService(ctx *ctx.Context) InterMonitorService { + return &monitorService{ + ctx: ctx, + } +} + +func (m monitorService) Create(req interface{}) (interface{}, interface{}) { + r := req.(*models.MonitorSSLRule) + r.ID = "m-" + cmd.RandId() + + if *r.Enabled { + alert.MonEvalTask.Submit(m.ctx, *r) + } + + alert.MonConsumerTask.Add(*r) + + err := m.ctx.DB.MonitorSSL().Create(*r) + if err != nil { + return nil, err + } + + return nil, nil +} + +func (m monitorService) Update(req interface{}) (interface{}, interface{}) { + r := req.(*models.MonitorSSLRule) + alert.MonConsumerTask.Stop(r.ID) + alert.MonEvalTask.Stop(r.ID) + if *r.Enabled { + alert.MonEvalTask.Submit(m.ctx, *r) + alert.MonConsumerTask.Add(*r) + } + + err := m.ctx.DB.MonitorSSL().Update(*r) + if err != nil { + return nil, err + } + + return nil, nil +} + +func (m monitorService) Delete(req interface{}) (interface{}, interface{}) { + r := req.(*models.MonitorSSLRuleQuery) + alert.MonEvalTask.Stop(r.ID) + alert.MonConsumerTask.Stop(r.ID) + key := fmt.Sprintf("%s:%s%s--", r.TenantId, models.FiringAlertCachePrefix, r.ID) + m.ctx.Redis.Event().DelCache(key) + + err := m.ctx.DB.MonitorSSL().Delete(*r) + if err != nil { + return nil, err + } + + return nil, nil +} + +func (m monitorService) List(req interface{}) (interface{}, interface{}) { + r := req.(*models.MonitorSSLRuleQuery) + data, err := m.ctx.DB.MonitorSSL().List(*r) + if err != nil { + return nil, err + } + + //for k, v := range data { + // var object models.AlertCurEvent + // key := fmt.Sprintf("%s:%s%s--", r.TenantId, models.FiringAlertCachePrefix, v.ID) + // result, err := m.ctx.Redis.Redis().Get(key).Result() + // if err == nil { + // err = json.Unmarshal([]byte(result), &object) + // if err != nil { + // return nil, err + // } + // } + // + // data[k].ResponseTime = object.ResponseTime + // data[k].TimeRemaining = object.TimeRemaining + //} + + return data, nil +} + +func (m monitorService) Get(req interface{}) (interface{}, interface{}) { + r := req.(*models.MonitorSSLRuleQuery) + data, err := m.ctx.DB.MonitorSSL().Get(*r) + if err != nil { + return nil, err + } + + return data, nil +} diff --git a/pkg/client/db.go b/pkg/client/db.go index a41ea83..3f51ec6 100644 --- a/pkg/client/db.go +++ b/pkg/client/db.go @@ -52,6 +52,7 @@ func InitDB() *gorm.DB { &models.AuditLog{}, &models.Settings{}, &models.TenantLinkedUsers{}, + &models.MonitorSSLRule{}, ) if err != nil { global.Logger.Sugar().Error(err.Error())