mirror of
https://github.com/grafana/grafana.git
synced 2026-08-26 21:37:31 -05:00
Alerting: Stop rule state view from crashing when prom rule state is missing (#91483)
This commit is contained in:
@@ -1,9 +1,15 @@
|
||||
import { lastValueFrom } from 'rxjs';
|
||||
|
||||
import { getBackendSrv } from '@grafana/runtime';
|
||||
import { logInfo } from 'app/features/alerting/unified/Analytics';
|
||||
import { Matcher } from 'app/plugins/datasource/alertmanager/types';
|
||||
import { RuleGroup, RuleIdentifier, RuleNamespace } from 'app/types/unified-alerting';
|
||||
import { PromRuleGroupDTO, PromRulesResponse } from 'app/types/unified-alerting-dto';
|
||||
import {
|
||||
PromAlertingRuleState,
|
||||
PromRuleGroupDTO,
|
||||
PromRulesResponse,
|
||||
PromRuleType,
|
||||
} from 'app/types/unified-alerting-dto';
|
||||
|
||||
import { getDatasourceAPIUid, GRAFANA_RULES_SOURCE_NAME } from '../utils/datasource';
|
||||
import { isCloudRuleIdentifier, isPrometheusRuleIdentifier } from '../utils/rules';
|
||||
@@ -88,6 +94,16 @@ export const groupRulesByFileName = (groups: PromRuleGroupDTO[], dataSourceName:
|
||||
groups.forEach((group) => {
|
||||
group.rules.forEach((rule) => {
|
||||
rule.query = rule.query || '';
|
||||
if (rule.type === PromRuleType.Alerting) {
|
||||
// There's a possibility that a custom/unexpected datasource might response with
|
||||
// `type: alerting` but no state
|
||||
// In this case, we fall back to `Inactive` state so that elsewhere in the UI we don't fail/have to handle the edge case
|
||||
// and log a message so we can identify how frequently this might be happening
|
||||
if (!rule.state) {
|
||||
logInfo('prom rule with type=alerting is missing a state', { dataSourceName, ruleName: rule.name });
|
||||
rule.state = PromAlertingRuleState.Inactive;
|
||||
}
|
||||
}
|
||||
});
|
||||
if (!nsMap[group.file]) {
|
||||
nsMap[group.file] = {
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
import { render, screen } from 'test/test-utils';
|
||||
|
||||
import { setPluginExtensionsHook } from '@grafana/runtime';
|
||||
import { RuleListStateView } from 'app/features/alerting/unified/components/rules/RuleListStateView';
|
||||
import {
|
||||
mockCombinedRule,
|
||||
mockCombinedRuleGroup,
|
||||
mockCombinedRuleNamespace,
|
||||
mockPromAlertingRule,
|
||||
} from 'app/features/alerting/unified/mocks';
|
||||
import { PromAlertingRuleState } from 'app/types/unified-alerting-dto';
|
||||
|
||||
setPluginExtensionsHook(() => ({
|
||||
extensions: [],
|
||||
isLoading: false,
|
||||
}));
|
||||
|
||||
const namespaces = [
|
||||
mockCombinedRuleNamespace({
|
||||
groups: [
|
||||
mockCombinedRuleGroup('Group with a missing state', [
|
||||
mockCombinedRule({
|
||||
name: 'Rule in firing state',
|
||||
promRule: mockPromAlertingRule({
|
||||
state: PromAlertingRuleState.Firing,
|
||||
}),
|
||||
}),
|
||||
mockCombinedRule({
|
||||
name: 'Rule in pending state',
|
||||
promRule: mockPromAlertingRule({
|
||||
state: PromAlertingRuleState.Pending,
|
||||
}),
|
||||
}),
|
||||
mockCombinedRule({
|
||||
name: 'Rule in inactive state',
|
||||
promRule: mockPromAlertingRule({
|
||||
state: PromAlertingRuleState.Inactive,
|
||||
}),
|
||||
}),
|
||||
mockCombinedRule({
|
||||
name: 'Rule with missing prom state',
|
||||
promRule: mockPromAlertingRule({
|
||||
state: undefined,
|
||||
}),
|
||||
}),
|
||||
]),
|
||||
],
|
||||
}),
|
||||
];
|
||||
|
||||
describe('RuleListStateView', () => {
|
||||
it('renders differing prom rule states correctly and does not crash with missing state', () => {
|
||||
render(<RuleListStateView namespaces={namespaces} />);
|
||||
|
||||
expect(screen.getByText(/firing \(1\)/i)).toBeInTheDocument();
|
||||
expect(screen.getByText(/pending \(1\)/i)).toBeInTheDocument();
|
||||
expect(screen.getByText(/normal \(1\)/i)).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
@@ -28,7 +28,10 @@ export const RuleListStateView = ({ namespaces }: Props) => {
|
||||
namespaces.forEach((namespace) =>
|
||||
namespace.groups.forEach((group) =>
|
||||
group.rules.forEach((rule) => {
|
||||
if (rule.promRule && isAlertingRule(rule.promRule)) {
|
||||
// We might hit edge cases where there type = alerting, but there is no state.
|
||||
// In this case, we shouldn't try to group these alerts in the state view
|
||||
// Even though we handle this at the API layer, this is a last catch point for any edge cases
|
||||
if (rule.promRule && isAlertingRule(rule.promRule) && rule.promRule.state) {
|
||||
result[rule.promRule.state].push(rule);
|
||||
}
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user