mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Alerting: Fixes combination of multiple predicates for rule search (#78910)
This commit is contained in:
parent
ef2c79d22a
commit
7ccdea6f67
@ -166,6 +166,40 @@ describe('filterRules', function () {
|
||||
expect(filtered[0].groups[0].rules[0].name).toBe('Memory too low');
|
||||
});
|
||||
|
||||
it('should be able to combine multiple predicates with AND', () => {
|
||||
const rules = [
|
||||
mockCombinedRule({
|
||||
name: 'Memory too low',
|
||||
labels: { team: 'operations', region: 'EMEA' },
|
||||
promRule: mockPromAlertingRule({
|
||||
health: RuleHealth.Ok,
|
||||
}),
|
||||
}),
|
||||
mockCombinedRule({
|
||||
name: 'Memory too low',
|
||||
labels: { team: 'operations', region: 'NASA' },
|
||||
promRule: mockPromAlertingRule({
|
||||
health: RuleHealth.Ok,
|
||||
}),
|
||||
}),
|
||||
];
|
||||
|
||||
const ns = mockCombinedRuleNamespace({
|
||||
groups: [mockCombinedRuleGroup('Resources usage group', rules)],
|
||||
});
|
||||
|
||||
const filtered = filterRules(
|
||||
[ns],
|
||||
getFilter({
|
||||
ruleHealth: RuleHealth.Ok,
|
||||
labels: ['team=operations', 'region=EMEA'],
|
||||
})
|
||||
);
|
||||
|
||||
expect(filtered[0]?.groups[0]?.rules).toHaveLength(1);
|
||||
expect(filtered[0]?.groups[0]?.rules[0]?.name).toBe('Memory too low');
|
||||
});
|
||||
|
||||
// Typos there are deliberate to test the fuzzy search
|
||||
it.each(['nasa', 'alrt rul', 'nasa ruls'])('should filter out rules by namespace = "%s"', (namespaceFilter) => {
|
||||
const cpuRule = mockCombinedRule({ name: 'High CPU usage' });
|
||||
|
@ -1,6 +1,6 @@
|
||||
import uFuzzy from '@leeoniya/ufuzzy';
|
||||
import { produce } from 'immer';
|
||||
import { compact, isEmpty } from 'lodash';
|
||||
import { chain, compact, isEmpty } from 'lodash';
|
||||
import { useCallback, useEffect, useMemo } from 'react';
|
||||
|
||||
import { getDataSourceSrv } from '@grafana/runtime';
|
||||
@ -124,6 +124,7 @@ export const filterRules = (
|
||||
}
|
||||
|
||||
const namespaceFilter = filterState.namespace;
|
||||
|
||||
if (namespaceFilter) {
|
||||
const namespaceHaystack = filteredNamespaces.map((ns) => ns.name);
|
||||
|
||||
@ -185,45 +186,72 @@ const reduceGroups = (filterState: RulesFilter) => {
|
||||
}
|
||||
|
||||
filteredRules = filteredRules.filter((rule) => {
|
||||
if (filterState.ruleType && filterState.ruleType !== rule.promRule?.type) {
|
||||
return false;
|
||||
const promRuleDefition = rule.promRule;
|
||||
|
||||
// this will track what properties we're checking predicates for
|
||||
// all predicates must be "true" to include the rule in the result set
|
||||
// (this will result in an AND operation for our matchers)
|
||||
const matchesFilterFor = chain(filterState)
|
||||
// ⚠️ keep this list of properties we filter for here up-to-date ⚠️
|
||||
// We are ignoring predicates we've matched before we get here (like "freeFormWords")
|
||||
.pick(['ruleType', 'dataSourceNames', 'ruleHealth', 'labels', 'ruleState'])
|
||||
.omitBy(isEmpty)
|
||||
.mapValues(() => false)
|
||||
.value();
|
||||
|
||||
if ('ruleType' in matchesFilterFor && filterState.ruleType === promRuleDefition?.type) {
|
||||
matchesFilterFor.ruleType = true;
|
||||
}
|
||||
|
||||
const doesNotQueryDs = isGrafanaRulerRule(rule.rulerRule) && !isQueryingDataSource(rule.rulerRule, filterState);
|
||||
if (filterState.dataSourceNames?.length && doesNotQueryDs) {
|
||||
return false;
|
||||
if ('dataSourceNames' in matchesFilterFor) {
|
||||
const doesNotQueryDs = isGrafanaRulerRule(rule.rulerRule) && isQueryingDataSource(rule.rulerRule, filterState);
|
||||
|
||||
if (doesNotQueryDs) {
|
||||
matchesFilterFor.dataSourceNames = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (filterState.ruleHealth && rule.promRule) {
|
||||
const ruleHealth = getRuleHealth(rule.promRule.health);
|
||||
return filterState.ruleHealth === ruleHealth;
|
||||
if ('ruleHealth' in filterState && promRuleDefition) {
|
||||
const ruleHealth = getRuleHealth(promRuleDefition.health);
|
||||
const match = filterState.ruleHealth === ruleHealth;
|
||||
|
||||
if (match) {
|
||||
matchesFilterFor.ruleHealth = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Query strings can match alert name, label keys, and label values
|
||||
if (filterState.labels.length > 0) {
|
||||
// const matchers = parseMatchers(filters.queryString);
|
||||
if ('labels' in matchesFilterFor) {
|
||||
const matchers = compact(filterState.labels.map(looseParseMatcher));
|
||||
|
||||
// check if the label we query for exists in _either_ the rule definition or in any of its alerts
|
||||
const doRuleLabelsMatchQuery = matchers.length > 0 && labelsMatchMatchers(rule.labels, matchers);
|
||||
const doAlertsContainMatchingLabels =
|
||||
matchers.length > 0 &&
|
||||
rule.promRule &&
|
||||
rule.promRule.type === PromRuleType.Alerting &&
|
||||
rule.promRule.alerts &&
|
||||
rule.promRule.alerts.some((alert) => labelsMatchMatchers(alert.labels, matchers));
|
||||
promRuleDefition &&
|
||||
promRuleDefition.type === PromRuleType.Alerting &&
|
||||
promRuleDefition.alerts &&
|
||||
promRuleDefition.alerts.some((alert) => labelsMatchMatchers(alert.labels, matchers));
|
||||
|
||||
if (!(doRuleLabelsMatchQuery || doAlertsContainMatchingLabels)) {
|
||||
return false;
|
||||
if (doRuleLabelsMatchQuery || doAlertsContainMatchingLabels) {
|
||||
matchesFilterFor.labels = true;
|
||||
}
|
||||
}
|
||||
if (
|
||||
filterState.ruleState &&
|
||||
!(rule.promRule && isAlertingRule(rule.promRule) && rule.promRule.state === filterState.ruleState)
|
||||
) {
|
||||
return false;
|
||||
|
||||
if ('ruleState' in matchesFilterFor) {
|
||||
const promRule = rule.promRule;
|
||||
const hasPromRuleDefinition = promRule && isAlertingRule(promRule);
|
||||
|
||||
const ruleStateMatches = hasPromRuleDefinition && promRule.state === filterState.ruleState;
|
||||
|
||||
if (ruleStateMatches) {
|
||||
matchesFilterFor.ruleState = true;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
||||
return Object.values(matchesFilterFor).every((match) => match === true);
|
||||
});
|
||||
|
||||
// Add rules to the group that match the rule list filters
|
||||
if (filteredRules.length) {
|
||||
groupAcc.push({
|
||||
|
Loading…
Reference in New Issue
Block a user