|
|
|
@ -235,9 +235,6 @@ func (srv PrometheusSrv) RouteGetRuleStatuses(c *contextmodel.ReqContext) respon |
|
|
|
|
return response.JSON(ruleResponse.HTTPStatusCode(), ruleResponse) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// TODO: Refactor this function to reduce the cylomatic complexity
|
|
|
|
|
//
|
|
|
|
|
//nolint:gocyclo
|
|
|
|
|
func PrepareRuleGroupStatuses(log log.Logger, manager state.AlertInstanceManager, store ListAlertRulesStore, opts RuleGroupStatusesOptions) apimodels.RuleResponse { |
|
|
|
|
ruleResponse := apimodels.RuleResponse{ |
|
|
|
|
DiscoveryBase: apimodels.DiscoveryBase{ |
|
|
|
@ -330,28 +327,7 @@ func PrepareRuleGroupStatuses(log log.Logger, manager state.AlertInstanceManager |
|
|
|
|
ruleNamesSet[rn] = struct{}{} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Group rules together by Namespace and Rule Group. Rules are also grouped by Org ID,
|
|
|
|
|
// but in this API all rules belong to the same organization. Also filter by rule name if
|
|
|
|
|
// it was provided as a query param.
|
|
|
|
|
groupedRules := make(map[ngmodels.AlertRuleGroupKey][]*ngmodels.AlertRule) |
|
|
|
|
for _, rule := range ruleList { |
|
|
|
|
if len(ruleNamesSet) > 0 { |
|
|
|
|
if _, exists := ruleNamesSet[rule.Title]; !exists { |
|
|
|
|
continue |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
groupKey := rule.GetGroupKey() |
|
|
|
|
ruleGroup := groupedRules[groupKey] |
|
|
|
|
ruleGroup = append(ruleGroup, rule) |
|
|
|
|
groupedRules[groupKey] = ruleGroup |
|
|
|
|
} |
|
|
|
|
// Sort the rules in each rule group by index. We do this at the end instead of
|
|
|
|
|
// after each append to avoid having to sort each group multiple times.
|
|
|
|
|
for _, groupRules := range groupedRules { |
|
|
|
|
ngmodels.AlertRulesBy(ngmodels.AlertRulesByIndex).Sort(groupRules) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
groupedRules := getGroupedRules(ruleList, ruleNamesSet) |
|
|
|
|
rulesTotals := make(map[string]int64, len(groupedRules)) |
|
|
|
|
for groupKey, rules := range groupedRules { |
|
|
|
|
folder, ok := opts.Namespaces[groupKey.NamespaceUID] |
|
|
|
@ -377,27 +353,7 @@ func PrepareRuleGroupStatuses(log log.Logger, manager state.AlertInstanceManager |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if len(withStates) > 0 { |
|
|
|
|
// Filtering is weird but firing, pending, and normal filters also need to be
|
|
|
|
|
// applied to the rule. Others such as nodata and error should have no effect.
|
|
|
|
|
// This is to match the current behavior in the UI.
|
|
|
|
|
filteredRules := make([]apimodels.AlertingRule, 0, len(ruleGroup.Rules)) |
|
|
|
|
for _, rule := range ruleGroup.Rules { |
|
|
|
|
var state *eval.State |
|
|
|
|
switch rule.State { |
|
|
|
|
case "normal", "inactive": |
|
|
|
|
state = util.Pointer(eval.Normal) |
|
|
|
|
case "alerting", "firing": |
|
|
|
|
state = util.Pointer(eval.Alerting) |
|
|
|
|
case "pending": |
|
|
|
|
state = util.Pointer(eval.Pending) |
|
|
|
|
} |
|
|
|
|
if state != nil { |
|
|
|
|
if _, ok := withStatesFast[*state]; ok { |
|
|
|
|
filteredRules = append(filteredRules, rule) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
ruleGroup.Rules = filteredRules |
|
|
|
|
filterRules(ruleGroup, withStatesFast) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if limitRulesPerGroup > -1 && int64(len(ruleGroup.Rules)) > limitRulesPerGroup { |
|
|
|
@ -418,6 +374,54 @@ func PrepareRuleGroupStatuses(log log.Logger, manager state.AlertInstanceManager |
|
|
|
|
return ruleResponse |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func getGroupedRules(ruleList ngmodels.RulesGroup, ruleNamesSet map[string]struct{}) map[ngmodels.AlertRuleGroupKey][]*ngmodels.AlertRule { |
|
|
|
|
// Group rules together by Namespace and Rule Group. Rules are also grouped by Org ID,
|
|
|
|
|
// but in this API all rules belong to the same organization. Also filter by rule name if
|
|
|
|
|
// it was provided as a query param.
|
|
|
|
|
groupedRules := make(map[ngmodels.AlertRuleGroupKey][]*ngmodels.AlertRule) |
|
|
|
|
for _, rule := range ruleList { |
|
|
|
|
if len(ruleNamesSet) > 0 { |
|
|
|
|
if _, exists := ruleNamesSet[rule.Title]; !exists { |
|
|
|
|
continue |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
groupKey := rule.GetGroupKey() |
|
|
|
|
ruleGroup := groupedRules[groupKey] |
|
|
|
|
ruleGroup = append(ruleGroup, rule) |
|
|
|
|
groupedRules[groupKey] = ruleGroup |
|
|
|
|
} |
|
|
|
|
// Sort the rules in each rule group by index. We do this at the end instead of
|
|
|
|
|
// after each append to avoid having to sort each group multiple times.
|
|
|
|
|
for _, groupRules := range groupedRules { |
|
|
|
|
ngmodels.AlertRulesBy(ngmodels.AlertRulesByIndex).Sort(groupRules) |
|
|
|
|
} |
|
|
|
|
return groupedRules |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func filterRules(ruleGroup *apimodels.RuleGroup, withStatesFast map[eval.State]struct{}) { |
|
|
|
|
// Filtering is weird but firing, pending, and normal filters also need to be
|
|
|
|
|
// applied to the rule. Others such as nodata and error should have no effect.
|
|
|
|
|
// This is to match the current behavior in the UI.
|
|
|
|
|
filteredRules := make([]apimodels.AlertingRule, 0, len(ruleGroup.Rules)) |
|
|
|
|
for _, rule := range ruleGroup.Rules { |
|
|
|
|
var state *eval.State |
|
|
|
|
switch rule.State { |
|
|
|
|
case "normal", "inactive": |
|
|
|
|
state = util.Pointer(eval.Normal) |
|
|
|
|
case "alerting", "firing": |
|
|
|
|
state = util.Pointer(eval.Alerting) |
|
|
|
|
case "pending": |
|
|
|
|
state = util.Pointer(eval.Pending) |
|
|
|
|
} |
|
|
|
|
if state != nil { |
|
|
|
|
if _, ok := withStatesFast[*state]; ok { |
|
|
|
|
filteredRules = append(filteredRules, rule) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
ruleGroup.Rules = filteredRules |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// This is the same as matchers.Matches but avoids the need to create a LabelSet
|
|
|
|
|
func matchersMatch(matchers []*labels.Matcher, labels map[string]string) bool { |
|
|
|
|
for _, m := range matchers { |
|
|
|
|