Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: 通知方式分组 支持将不同的报警|监控|计划任务的通知 发送到指定的通知分组 #160

Merged
merged 9 commits into from
Apr 16, 2022
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<br>
<small><i>LOGO designed by <a href="https://xio.ng" target="_blank">熊大</a> .</i></small>
<br><br>
<img src="https://img.shields.io/github/workflow/status/naiba/nezha/Dashboard%20image?label=Dash%20v0.12.19&logo=github&style=for-the-badge">&nbsp;<img src="https://img.shields.io/github/v/release/naiba/nezha?color=brightgreen&label=Agent&style=for-the-badge&logo=github">&nbsp;<img src="https://img.shields.io/github/workflow/status/naiba/nezha/Agent%20release?label=Agent%20CI&logo=github&style=for-the-badge">&nbsp;<img src="https://img.shields.io/badge/Installer-v0.8.2-brightgreen?style=for-the-badge&logo=linux">
<img src="https://img.shields.io/github/workflow/status/naiba/nezha/Dashboard%20image?label=Dash%20v0.12.20&logo=github&style=for-the-badge">&nbsp;<img src="https://img.shields.io/github/v/release/naiba/nezha?color=brightgreen&label=Agent&style=for-the-badge&logo=github">&nbsp;<img src="https://img.shields.io/github/workflow/status/naiba/nezha/Agent%20release?label=Agent%20CI&logo=github&style=for-the-badge">&nbsp;<img src="https://img.shields.io/badge/Installer-v0.8.2-brightgreen?style=for-the-badge&logo=linux">
<br>
<br>
<p>:trollface: <b>哪吒监控</b> 一站式轻监控轻运维系统。支持系统状态、HTTP(SSL 证书变更、即将到期、到期)、TCP、Ping 监控报警,计划任务和在线终端。</p>
Expand Down
86 changes: 58 additions & 28 deletions cmd/dashboard/controller/member_api.go
Original file line number Diff line number Diff line change
Expand Up @@ -211,14 +211,15 @@ func (ma *memberAPI) addOrEditServer(c *gin.Context) {
}

type monitorForm struct {
ID uint64
Name string
Target string
Type uint8
Cover uint8
Notify string
SkipServersRaw string
Duration uint64
ID uint64
Name string
Target string
Type uint8
Cover uint8
Notify string
NotificationTag string
SkipServersRaw string
Duration uint64
}

func (ma *memberAPI) addOrEditMonitor(c *gin.Context) {
Expand All @@ -233,10 +234,15 @@ func (ma *memberAPI) addOrEditMonitor(c *gin.Context) {
m.SkipServersRaw = mf.SkipServersRaw
m.Cover = mf.Cover
m.Notify = mf.Notify == "on"
m.NotificationTag = mf.NotificationTag
m.Duration = mf.Duration
err = m.InitSkipServers()
}
if err == nil {
// 保证NotificationTag不为空
if m.NotificationTag == "" {
m.NotificationTag = "default"
}
if m.ID == 0 {
err = singleton.DB.Create(&m).Error
} else {
Expand All @@ -259,13 +265,14 @@ func (ma *memberAPI) addOrEditMonitor(c *gin.Context) {
}

type cronForm struct {
ID uint64
Name string
Scheduler string
Command string
ServersRaw string
Cover uint8
PushSuccessful string
ID uint64
Name string
Scheduler string
Command string
ServersRaw string
Cover uint8
PushSuccessful string
NotificationTag string
}

func (ma *memberAPI) addOrEditCron(c *gin.Context) {
Expand All @@ -278,12 +285,17 @@ func (ma *memberAPI) addOrEditCron(c *gin.Context) {
cr.Command = cf.Command
cr.ServersRaw = cf.ServersRaw
cr.PushSuccessful = cf.PushSuccessful == "on"
cr.NotificationTag = cf.NotificationTag
cr.ID = cf.ID
cr.Cover = cf.Cover
err = utils.Json.Unmarshal([]byte(cf.ServersRaw), &cr.Servers)
}
tx := singleton.DB.Begin()
if err == nil {
// 保证NotificationTag不为空
if cr.NotificationTag == "" {
cr.NotificationTag = "default"
}
if cf.ID == 0 {
err = tx.Create(&cr).Error
} else {
Expand Down Expand Up @@ -376,6 +388,7 @@ func (ma *memberAPI) forceUpdate(c *gin.Context) {
type notificationForm struct {
ID uint64
Name string
Tag string // 分组名
URL string
RequestMethod int
RequestType int
Expand All @@ -390,6 +403,7 @@ func (ma *memberAPI) addOrEditNotification(c *gin.Context) {
err := c.ShouldBindJSON(&nf)
if err == nil {
n.Name = nf.Name
n.Tag = nf.Tag
n.RequestMethod = nf.RequestMethod
n.RequestType = nf.RequestType
n.RequestHeader = nf.RequestHeader
Expand All @@ -401,6 +415,10 @@ func (ma *memberAPI) addOrEditNotification(c *gin.Context) {
err = n.Send("这是测试消息")
}
if err == nil {
// 保证Tag不为空
if n.Tag == "" {
n.Tag = "default"
}
if n.ID == 0 {
err = singleton.DB.Create(&n).Error
} else {
Expand All @@ -414,17 +432,18 @@ func (ma *memberAPI) addOrEditNotification(c *gin.Context) {
})
return
}
singleton.OnRefreshOrAddNotification(n)
singleton.OnRefreshOrAddNotification(&n)
c.JSON(http.StatusOK, model.Response{
Code: http.StatusOK,
})
}

type alertRuleForm struct {
ID uint64
Name string
RulesRaw string
Enable string
ID uint64
Name string
RulesRaw string
NotificationTag string
Enable string
}

func (ma *memberAPI) addOrEditAlertRule(c *gin.Context) {
Expand Down Expand Up @@ -464,9 +483,14 @@ func (ma *memberAPI) addOrEditAlertRule(c *gin.Context) {
if err == nil {
r.Name = arf.Name
r.RulesRaw = arf.RulesRaw
r.NotificationTag = arf.NotificationTag
enable := arf.Enable == "on"
r.Enable = &enable
r.ID = arf.ID
//保证NotificationTag不为空
if r.NotificationTag == "" {
r.NotificationTag = "default"
}
if r.ID == 0 {
err = singleton.DB.Create(&r).Error
} else {
Expand Down Expand Up @@ -517,14 +541,15 @@ func (ma *memberAPI) logout(c *gin.Context) {
}

type settingForm struct {
Title string
Admin string
Theme string
CustomCode string
ViewPassword string
IgnoredIPNotification string
GRPCHost string
Cover uint8
Title string
Admin string
Theme string
CustomCode string
ViewPassword string
IgnoredIPNotification string
IPChangeNotificationTag string // IP变更提醒的通知组
GRPCHost string
Cover uint8

EnableIPChangeNotification string
EnablePlainIPInNotification string
Expand All @@ -544,11 +569,16 @@ func (ma *memberAPI) updateSetting(c *gin.Context) {
singleton.Conf.Cover = sf.Cover
singleton.Conf.GRPCHost = sf.GRPCHost
singleton.Conf.IgnoredIPNotification = sf.IgnoredIPNotification
singleton.Conf.IPChangeNotificationTag = sf.IPChangeNotificationTag
singleton.Conf.Site.Brand = sf.Title
singleton.Conf.Site.Theme = sf.Theme
singleton.Conf.Site.CustomCode = sf.CustomCode
singleton.Conf.Site.ViewPassword = sf.ViewPassword
singleton.Conf.Oauth2.Admin = sf.Admin
// 保证NotificationTag不为空
if singleton.Conf.IPChangeNotificationTag == "" {
singleton.Conf.IPChangeNotificationTag = "default"
}
if err := singleton.Conf.Save(); err != nil {
c.JSON(http.StatusOK, model.Response{
Code: http.StatusBadRequest,
Expand Down
9 changes: 5 additions & 4 deletions model/alertrule.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,11 @@ type CycleTransferStats struct {

type AlertRule struct {
Common
Name string
RulesRaw string
Enable *bool
Rules []Rule `gorm:"-" json:"-"`
Name string
RulesRaw string
Enable *bool
NotificationTag string // 该报警规则所在的通知组
Rules []Rule `gorm:"-" json:"-"`
}

func (r *AlertRule) BeforeSave(tx *gorm.DB) error {
Expand Down
12 changes: 8 additions & 4 deletions model/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,12 +71,13 @@ type Config struct {
ProxyGRPCPort uint
TLS bool

EnableIPChangeNotification bool
EnablePlainIPInNotification bool
EnablePlainIPInNotification bool // 通知信息IP不打码

// IP变更提醒
Cover uint8 // 覆盖范围(0:提醒未被 IgnoredIPNotification 包含的所有服务器; 1:仅提醒被 IgnoredIPNotification 包含的服务器;)
IgnoredIPNotification string // 特定服务器IP(多个服务器用逗号分隔)
EnableIPChangeNotification bool
IPChangeNotificationTag string
Cover uint8 // 覆盖范围(0:提醒未被 IgnoredIPNotification 包含的所有服务器; 1:仅提醒被 IgnoredIPNotification 包含的服务器;)
IgnoredIPNotification string // 特定服务器IP(多个服务器用逗号分隔)

v *viper.Viper
IgnoredIPNotificationServerIDs map[uint64]bool // [ServerID] -> bool(值为true代表当前ServerID在特定服务器列表内)
Expand All @@ -102,6 +103,9 @@ func (c *Config) Read(path string) error {
if c.GRPCPort == 0 {
c.GRPCPort = 5555
}
if c.EnableIPChangeNotification && c.IPChangeNotificationTag == "" {
c.IPChangeNotificationTag = "default"
}

c.updateIgnoredIPNotificationID()
return nil
Expand Down
17 changes: 9 additions & 8 deletions model/cron.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,15 @@ const (

type Cron struct {
Common
Name string
Scheduler string //分钟 小时 天 月 星期
Command string
Servers []uint64 `gorm:"-"`
PushSuccessful bool // 推送成功的通知
LastExecutedAt time.Time // 最后一次执行时间
LastResult bool // 最后一次执行结果
Cover uint8 // 计划任务覆盖范围 (0:仅覆盖特定服务器 1:仅忽略特定服务器)
Name string
Scheduler string //分钟 小时 天 月 星期
Command string
Servers []uint64 `gorm:"-"`
PushSuccessful bool // 推送成功的通知
NotificationTag string // 指定通知方式的分组
LastExecutedAt time.Time // 最后一次执行时间
LastResult bool // 最后一次执行结果
Cover uint8 // 计划任务覆盖范围 (0:仅覆盖特定服务器 1:仅忽略特定服务器)

CronJobID cron.EntryID `gorm:"-"`
ServersRaw string
Expand Down
15 changes: 8 additions & 7 deletions model/monitor.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,14 @@ const (

type Monitor struct {
Common
Name string
Type uint8
Target string
SkipServersRaw string
Duration uint64
Notify bool
Cover uint8
Name string
Type uint8
Target string
SkipServersRaw string
Duration uint64
Notify bool
NotificationTag string // 当前服务监控所属的通知组
Cover uint8

SkipServers map[uint64]bool `gorm:"-" json:"-"`
CronJobID cron.EntryID `gorm:"-" json:"-"`
Expand Down
1 change: 1 addition & 0 deletions model/notification.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ const (
type Notification struct {
Common
Name string
Tag string // 分组名
URL string
RequestMethod int
RequestType int
Expand Down
4 changes: 4 additions & 0 deletions resource/static/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ function addOrEditAlertRule(rule) {
modal.find("input[name=ID]").val(rule ? rule.ID : null);
modal.find("input[name=Name]").val(rule ? rule.Name : null);
modal.find("textarea[name=RulesRaw]").val(rule ? rule.RulesRaw : null);
modal.find("input[name=NotificationTag]").val(rule ? rule.NotificationTag : null);
if (rule && rule.Enable) {
modal.find(".ui.rule-enable.checkbox").checkbox("set checked");
} else {
Expand All @@ -134,6 +135,7 @@ function addOrEditNotification(notification) {
);
modal.find("input[name=ID]").val(notification ? notification.ID : null);
modal.find("input[name=Name]").val(notification ? notification.Name : null);
modal.find("input[name=Tag]").val(notification ? notification.Tag : null);
modal.find("input[name=URL]").val(notification ? notification.URL : null);
modal
.find("textarea[name=RequestHeader]")
Expand Down Expand Up @@ -225,6 +227,7 @@ function addOrEditMonitor(monitor) {
modal.find("input[name=Duration]").val(monitor && monitor.Duration ? monitor.Duration : 30);
modal.find("select[name=Type]").val(monitor ? monitor.Type : 1);
modal.find("select[name=Cover]").val(monitor ? monitor.Cover : 0);
modal.find("input[name=NotificationTag]").val(monitor ? monitor.NotificationTag : null);
if (monitor && monitor.Notify) {
modal.find(".ui.nb-notify.checkbox").checkbox("set checked");
} else {
Expand Down Expand Up @@ -261,6 +264,7 @@ function addOrEditCron(cron) {
);
modal.find("input[name=ID]").val(cron ? cron.ID : null);
modal.find("input[name=Name]").val(cron ? cron.Name : null);
modal.find("input[name=NotificationTag]").val(cron ? cron.NotificationTag : null);
modal.find("input[name=Scheduler]").val(cron ? cron.Scheduler : null);
modal.find("a.ui.label.visible").each((i, el) => {
el.remove();
Expand Down
4 changes: 4 additions & 0 deletions resource/template/component/cron.html
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@
<div class="menu"></div>
</div>
</div>
<div class="field">
<label>通知方式组</label>
<input type="text" name="NotificationTag" placeholder="default">
</div>
<div class="field">
<div class="ui push-successful checkbox">
<input name="PushSuccessful" type="checkbox" tabindex="0" class="hidden">
Expand Down
4 changes: 4 additions & 0 deletions resource/template/component/monitor.html
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,10 @@
<div class="menu"></div>
</div>
</div>
<div class="field">
<label>通知方式组</label>
<input type="text" name="NotificationTag" placeholder="default" />
</div>
<div class="field">
<div class="ui nb-notify checkbox">
<input name="Notify" type="checkbox" tabindex="0" class="hidden" />
Expand Down
4 changes: 4 additions & 0 deletions resource/template/component/notification.html
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@
<label>名称</label>
<input type="text" name="Name">
</div>
<div class="field">
<label>分组</label>
<input type="text" name="Tag" placeholder="default">
</div>
<div class="field">
<label>URL</label>
<input type="text" name="URL">
Expand Down
4 changes: 4 additions & 0 deletions resource/template/component/rule.html
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@
<label>规则</label>
<textarea name="RulesRaw"></textarea>
</div>
<div class="field">
<label>通知方式组</label>
<input type="text" name="NotificationTag" placeholder="default">
</div>
<div class="field">
<div class="ui rule-enable checkbox">
<input name="Enable" type="checkbox" tabindex="0" class="hidden">
Expand Down
2 changes: 2 additions & 0 deletions resource/template/dashboard/cron.html
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
<th>名称</th>
<th>计划</th>
<th>命令</th>
<th>通知方式组</th>
<th>成功推送</th>
<th>覆盖范围</th>
<th>特定服务器</th>
Expand All @@ -32,6 +33,7 @@
<td>{{$cron.Name}}</td>
<td>{{$cron.Scheduler}}</td>
<td>{{$cron.Command}}</td>
<td>{{$cron.NotificationTag}}</td>
<td>{{$cron.PushSuccessful}}</td>
<td>{{if eq $cron.Cover 0}}忽略所有{{else}}覆盖所有{{end}}</td>
<td>{{$cron.ServersRaw}}</td>
Expand Down
Loading