mirror of
https://github.com/ccfos/nightingale.git
synced 2026-03-08 00:49:00 +00:00
Compare commits
10 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
037112a9e6 | ||
|
|
c6e75d31a1 | ||
|
|
bd24f5b056 | ||
|
|
89551c8edb | ||
|
|
042b44940d | ||
|
|
8cd8674848 | ||
|
|
7bb6ac8a03 | ||
|
|
76b35276af | ||
|
|
439a21b784 | ||
|
|
47e70a2dba |
@@ -1,6 +1,7 @@
|
||||
package mute
|
||||
|
||||
import (
|
||||
"slices"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
@@ -153,13 +154,7 @@ func MatchMute(event *models.AlertCurEvent, mute *models.AlertMute, clock ...int
|
||||
|
||||
// 如果不是全局的,判断 匹配的 datasource id
|
||||
if len(mute.DatasourceIdsJson) != 0 && mute.DatasourceIdsJson[0] != 0 && event.DatasourceId != 0 {
|
||||
idm := make(map[int64]struct{}, len(mute.DatasourceIdsJson))
|
||||
for i := 0; i < len(mute.DatasourceIdsJson); i++ {
|
||||
idm[mute.DatasourceIdsJson[i]] = struct{}{}
|
||||
}
|
||||
|
||||
// 判断 event.datasourceId 是否包含在 idm 中
|
||||
if _, has := idm[event.DatasourceId]; !has {
|
||||
if !slices.Contains(mute.DatasourceIdsJson, event.DatasourceId) {
|
||||
return false, errors.New("datasource id not match")
|
||||
}
|
||||
}
|
||||
@@ -198,7 +193,7 @@ func MatchMute(event *models.AlertCurEvent, mute *models.AlertMute, clock ...int
|
||||
return false, errors.New("event severity not match mute severity")
|
||||
}
|
||||
|
||||
if mute.ITags == nil || len(mute.ITags) == 0 {
|
||||
if len(mute.ITags) == 0 {
|
||||
return true, nil
|
||||
}
|
||||
if !common.MatchTags(event.TagsMap, mute.ITags) {
|
||||
|
||||
@@ -25,6 +25,7 @@ func (rt *Router) pushEventToQueue(c *gin.Context) {
|
||||
if event.RuleId == 0 {
|
||||
ginx.Bomb(200, "event is illegal")
|
||||
}
|
||||
event.FE2DB()
|
||||
|
||||
event.TagsMap = make(map[string]string)
|
||||
for i := 0; i < len(event.TagsJSON); i++ {
|
||||
@@ -40,7 +41,7 @@ func (rt *Router) pushEventToQueue(c *gin.Context) {
|
||||
|
||||
event.TagsMap[arr[0]] = arr[1]
|
||||
}
|
||||
hit, _ := mute.EventMuteStrategy(event, rt.AlertMuteCache)
|
||||
hit, _ := mute.EventMuteStrategy(event, rt.AlertMuteCache)
|
||||
if hit {
|
||||
logger.Infof("event_muted: rule_id=%d %s", event.RuleId, event.Hash)
|
||||
ginx.NewRender(c).Message(nil)
|
||||
|
||||
@@ -628,6 +628,7 @@ func (rt *Router) Config(r *gin.Engine) {
|
||||
service.GET("/recording-rules", rt.recordingRuleGetsByService)
|
||||
|
||||
service.GET("/alert-mutes", rt.alertMuteGets)
|
||||
service.GET("/active-alert-mutes", rt.activeAlertMuteGets)
|
||||
service.POST("/alert-mutes", rt.alertMuteAddByService)
|
||||
service.DELETE("/alert-mutes", rt.alertMuteDel)
|
||||
|
||||
|
||||
@@ -20,7 +20,8 @@ func (rt *Router) alertMuteGetsByBG(c *gin.Context) {
|
||||
bgid := ginx.UrlParamInt64(c, "id")
|
||||
prods := strings.Fields(ginx.QueryStr(c, "prods", ""))
|
||||
query := ginx.QueryStr(c, "query", "")
|
||||
lst, err := models.AlertMuteGets(rt.Ctx, prods, bgid, -1, query)
|
||||
expired := ginx.QueryInt(c, "expired", -1)
|
||||
lst, err := models.AlertMuteGets(rt.Ctx, prods, bgid, -1, expired, query)
|
||||
|
||||
ginx.NewRender(c).Data(lst, err)
|
||||
}
|
||||
@@ -55,11 +56,17 @@ func (rt *Router) alertMuteGets(c *gin.Context) {
|
||||
bgid := ginx.QueryInt64(c, "bgid", -1)
|
||||
query := ginx.QueryStr(c, "query", "")
|
||||
disabled := ginx.QueryInt(c, "disabled", -1)
|
||||
lst, err := models.AlertMuteGets(rt.Ctx, prods, bgid, disabled, query)
|
||||
expired := ginx.QueryInt(c, "expired", -1)
|
||||
lst, err := models.AlertMuteGets(rt.Ctx, prods, bgid, disabled, expired, query)
|
||||
|
||||
ginx.NewRender(c).Data(lst, err)
|
||||
}
|
||||
|
||||
func (rt *Router) activeAlertMuteGets(c *gin.Context) {
|
||||
lst, err := models.AlertMuteGetsAll(rt.Ctx)
|
||||
ginx.NewRender(c).Data(lst, err)
|
||||
}
|
||||
|
||||
func (rt *Router) alertMuteAdd(c *gin.Context) {
|
||||
|
||||
var f models.AlertMute
|
||||
@@ -69,7 +76,9 @@ func (rt *Router) alertMuteAdd(c *gin.Context) {
|
||||
f.CreateBy = username
|
||||
f.UpdateBy = username
|
||||
f.GroupId = ginx.UrlParamInt64(c, "id")
|
||||
ginx.NewRender(c).Message(f.Add(rt.Ctx))
|
||||
|
||||
ginx.Dangerous(f.Add(rt.Ctx))
|
||||
ginx.NewRender(c).Data(f.Id, nil)
|
||||
}
|
||||
|
||||
type MuteTestForm struct {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,4 +1,5 @@
|
||||
{
|
||||
[
|
||||
{
|
||||
"name": "JMX - Kubernetes",
|
||||
"tags": "Prometheus JMX Kubernetes",
|
||||
"configs": {
|
||||
@@ -1870,4 +1871,5 @@
|
||||
"version": "3.0.0"
|
||||
},
|
||||
"uuid": 1755595969673000
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -230,7 +230,7 @@ func AlertMuteGet(ctx *ctx.Context, where string, args ...interface{}) (*AlertMu
|
||||
return lst[0], err
|
||||
}
|
||||
|
||||
func AlertMuteGets(ctx *ctx.Context, prods []string, bgid int64, disabled int, query string) (lst []AlertMute, err error) {
|
||||
func AlertMuteGets(ctx *ctx.Context, prods []string, bgid int64, disabled int, expired int, query string) (lst []AlertMute, err error) {
|
||||
session := DB(ctx)
|
||||
|
||||
if bgid != -1 {
|
||||
@@ -249,6 +249,15 @@ func AlertMuteGets(ctx *ctx.Context, prods []string, bgid int64, disabled int, q
|
||||
}
|
||||
}
|
||||
|
||||
if expired != -1 {
|
||||
now := time.Now().Unix()
|
||||
if expired == 1 {
|
||||
session = session.Where("mute_time_type = ? AND etime < ?", TimeRange, now)
|
||||
} else {
|
||||
session = session.Where("(mute_time_type = ? AND etime >= ?) OR mute_time_type = ?", TimeRange, now, Periodic)
|
||||
}
|
||||
}
|
||||
|
||||
if query != "" {
|
||||
arr := strings.Fields(query)
|
||||
for i := 0; i < len(arr); i++ {
|
||||
@@ -478,7 +487,7 @@ func AlertMuteGetsAll(ctx *ctx.Context) ([]*AlertMute, error) {
|
||||
// get my cluster's mutes
|
||||
var lst []*AlertMute
|
||||
if !ctx.IsCenter {
|
||||
lst, err := poster.GetByUrls[[]*AlertMute](ctx, "/v1/n9e/alert-mutes?disabled=0")
|
||||
lst, err := poster.GetByUrls[[]*AlertMute](ctx, "/v1/n9e/active-alert-mutes")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -490,6 +499,10 @@ func AlertMuteGetsAll(ctx *ctx.Context) ([]*AlertMute, error) {
|
||||
|
||||
session := DB(ctx).Model(&AlertMute{}).Where("disabled = 0")
|
||||
|
||||
// 只筛选在生效时间内的屏蔽规则, 这里 btime < now+10 是为了避免同步期间有规则满足了生效时间条件
|
||||
now := time.Now().Unix()
|
||||
session = session.Where("(mute_time_type = ? AND btime <= ? AND etime >= ?) OR mute_time_type = ?", TimeRange, now+10, now, Periodic)
|
||||
|
||||
err := session.Find(&lst).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -228,6 +228,9 @@ func TargetTotal(ctx *ctx.Context, options ...BuildTargetWhereOption) (int64, er
|
||||
|
||||
func TargetGets(ctx *ctx.Context, limit, offset int, order string, desc bool, options ...BuildTargetWhereOption) ([]*Target, error) {
|
||||
var lst []*Target
|
||||
|
||||
order = validateOrderField(order, "ident")
|
||||
|
||||
if desc {
|
||||
order += " desc"
|
||||
} else {
|
||||
|
||||
@@ -3,6 +3,7 @@ package models
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
@@ -555,6 +556,47 @@ func UserTotal(ctx *ctx.Context, query string, stime, etime int64) (num int64, e
|
||||
return num, nil
|
||||
}
|
||||
|
||||
var (
|
||||
// 预编译正则表达式,避免重复编译
|
||||
whitespaceRegex = regexp.MustCompile(`\s+`)
|
||||
validOrderRegex = regexp.MustCompile(`^[a-zA-Z_][a-zA-Z0-9_]*(\.[a-zA-Z_][a-zA-Z0-9_]*)?$`)
|
||||
)
|
||||
|
||||
func validateOrderField(order string, defaultField string) string {
|
||||
// 空值检查
|
||||
if order == "" {
|
||||
return defaultField
|
||||
}
|
||||
|
||||
// 长度检查
|
||||
if len(order) > 64 {
|
||||
logger.Warningf("SQL injection attempt detected: order field too long (%d chars)", len(order))
|
||||
return defaultField
|
||||
}
|
||||
|
||||
// 移除所有空白字符
|
||||
order = whitespaceRegex.ReplaceAllString(order, "")
|
||||
if order == "" {
|
||||
return defaultField
|
||||
}
|
||||
|
||||
// 检查危险字符
|
||||
orderLower := strings.ToLower(order)
|
||||
if strings.ContainsAny(order, "();,'\"` --/*\\=+-*/><|&^~") ||
|
||||
strings.Contains(orderLower, "0x") || strings.Contains(orderLower, "0b") {
|
||||
logger.Warningf("SQL injection attempt detected: contains dangerous characters")
|
||||
return defaultField
|
||||
}
|
||||
|
||||
// 使用正则表达式验证格式:只允许字母开头的字段名,可选择性包含表名
|
||||
if !validOrderRegex.MatchString(order) {
|
||||
logger.Warningf("SQL injection attempt detected: invalid order field format")
|
||||
return defaultField
|
||||
}
|
||||
|
||||
return order
|
||||
}
|
||||
|
||||
func UserGets(ctx *ctx.Context, query string, limit, offset int, stime, etime int64,
|
||||
order string, desc bool, usernames, phones, emails []string) ([]User, error) {
|
||||
|
||||
@@ -564,6 +606,8 @@ func UserGets(ctx *ctx.Context, query string, limit, offset int, stime, etime in
|
||||
session = session.Where("last_active_time between ? and ?", stime, etime)
|
||||
}
|
||||
|
||||
order = validateOrderField(order, "username")
|
||||
|
||||
if desc {
|
||||
order = order + " desc"
|
||||
} else {
|
||||
|
||||
@@ -192,6 +192,15 @@ var I18N = `{
|
||||
"View Alerting Engines": "查看告警引擎列表",
|
||||
"View Product Version": "查看产品版本",
|
||||
|
||||
"Some alert rules still in the BusiGroup": "业务组中仍有告警规则",
|
||||
"Some alert mutes still in the BusiGroup": "业务组中仍有屏蔽规则",
|
||||
"Some alert subscribes still in the BusiGroup": "业务组中仍有订阅规则",
|
||||
"Some Board still in the BusiGroup": "业务组中仍有仪表盘",
|
||||
"Some targets still in the BusiGroup": "业务组中仍有监控对象",
|
||||
"Some recording rules still in the BusiGroup": "业务组中仍有记录规则",
|
||||
"Some recovery scripts still in the BusiGroup": "业务组中仍有自愈脚本",
|
||||
"Some target busigroups still in the BusiGroup": "业务组中仍有监控对象",
|
||||
|
||||
"---------zh_CN--------": "---------zh_CN--------"
|
||||
},
|
||||
"zh_HK": {
|
||||
@@ -387,6 +396,15 @@ var I18N = `{
|
||||
"View Alerting Engines": "查看告警引擎列表",
|
||||
"View Product Version": "查看產品版本",
|
||||
|
||||
"Some alert rules still in the BusiGroup": "業務組中仍有告警規則",
|
||||
"Some alert mutes still in the BusiGroup": "業務組中仍有屏蔽規則",
|
||||
"Some alert subscribes still in the BusiGroup": "業務組中仍有訂閱規則",
|
||||
"Some Board still in the BusiGroup": "業務組中仍有儀表板",
|
||||
"Some targets still in the BusiGroup": "業務組中仍有監控對象",
|
||||
"Some recording rules still in the BusiGroup": "業務組中仍有記錄規則",
|
||||
"Some recovery scripts still in the BusiGroup": "業務組中仍有自愈腳本",
|
||||
"Some target busigroups still in the BusiGroup": "業務組中仍有監控對象",
|
||||
|
||||
"---------zh_HK--------": "---------zh_HK--------"
|
||||
},
|
||||
"ja_JP": {
|
||||
@@ -579,6 +597,15 @@ var I18N = `{
|
||||
"View Alerting Engines": "アラートエンジンの表示",
|
||||
"View Product Version": "製品のバージョンを見る",
|
||||
|
||||
"Some alert rules still in the BusiGroup": "ビジネスグループにまだアラートルールがあります",
|
||||
"Some alert mutes still in the BusiGroup": "ビジネスグループにまだミュートルールがあります",
|
||||
"Some alert subscribes still in the BusiGroup": "ビジネスグループにまだサブスクライブルールがあります",
|
||||
"Some Board still in the BusiGroup": "ビジネスグループにまだダッシュボードがあります",
|
||||
"Some targets still in the BusiGroup": "ビジネスグループにまだ監視対象があります",
|
||||
"Some recording rules still in the BusiGroup": "ビジネスグループにまだ記録ルールがあります",
|
||||
"Some recovery scripts still in the BusiGroup": "ビジネスグループにまだ自己回復スクリプトがあります",
|
||||
"Some target busigroups still in the BusiGroup": "ビジネスグループにまだ監視対象があります",
|
||||
|
||||
"---------ja_JP--------": "---------ja_JP--------"
|
||||
},
|
||||
"ru_RU": {
|
||||
@@ -771,6 +798,15 @@ var I18N = `{
|
||||
"View Alerting Engines": "Просмотр списка алертинг-инженеров",
|
||||
"View Product Version": "Просмотр версии продукта",
|
||||
|
||||
"Some alert rules still in the BusiGroup": "В бизнес-группе еще есть правила оповещений",
|
||||
"Some alert mutes still in the BusiGroup": "В бизнес-группе еще есть правила отключения оповещений",
|
||||
"Some alert subscribes still in the BusiGroup": "В бизнес-группе еще есть правила подписки",
|
||||
"Some Board still in the BusiGroup": "В бизнес-группе еще есть панели мониторинга",
|
||||
"Some targets still in the BusiGroup": "В бизнес-группе еще есть объекты мониторинга",
|
||||
"Some recording rules still in the BusiGroup": "В бизнес-группе еще есть правила записи",
|
||||
"Some recovery scripts still in the BusiGroup": "В бизнес-группе еще есть скрипты самоисцеления",
|
||||
"Some target busigroups still in the BusiGroup": "В бизнес-группе еще есть объекты мониторинга",
|
||||
|
||||
"---------ru_RU--------": "---------ru_RU--------"
|
||||
}
|
||||
}`
|
||||
|
||||
Reference in New Issue
Block a user