mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Alerting: Fix deleting rules when silencing/resuming rule from a panel alert tab (#87710)
* Fix deleting rules when silencing/resuming rule from a panel alert tab * fix test and return early when no group target is found * address pr review comment
This commit is contained in:
parent
194039c429
commit
6b1a662f6b
@ -36,21 +36,23 @@ import * as analytics from './Analytics';
|
|||||||
import RuleList from './RuleList';
|
import RuleList from './RuleList';
|
||||||
import { discoverFeatures } from './api/buildInfo';
|
import { discoverFeatures } from './api/buildInfo';
|
||||||
import { fetchRules } from './api/prometheus';
|
import { fetchRules } from './api/prometheus';
|
||||||
|
import * as apiRuler from './api/ruler';
|
||||||
import { deleteNamespace, deleteRulerRulesGroup, fetchRulerRules, setRulerRuleGroup } from './api/ruler';
|
import { deleteNamespace, deleteRulerRulesGroup, fetchRulerRules, setRulerRuleGroup } from './api/ruler';
|
||||||
import {
|
import {
|
||||||
MockDataSourceSrv,
|
MockDataSourceSrv,
|
||||||
|
getPotentiallyPausedRulerRules,
|
||||||
grantUserPermissions,
|
grantUserPermissions,
|
||||||
mockDataSource,
|
mockDataSource,
|
||||||
|
mockFolder,
|
||||||
mockPromAlert,
|
mockPromAlert,
|
||||||
mockPromAlertingRule,
|
mockPromAlertingRule,
|
||||||
mockPromRecordingRule,
|
mockPromRecordingRule,
|
||||||
mockPromRuleGroup,
|
mockPromRuleGroup,
|
||||||
mockPromRuleNamespace,
|
mockPromRuleNamespace,
|
||||||
|
mockRulerGrafanaRule,
|
||||||
pausedPromRules,
|
pausedPromRules,
|
||||||
getPotentiallyPausedRulerRules,
|
|
||||||
somePromRules,
|
somePromRules,
|
||||||
someRulerRules,
|
someRulerRules,
|
||||||
mockFolder,
|
|
||||||
} from './mocks';
|
} from './mocks';
|
||||||
import * as config from './utils/config';
|
import * as config from './utils/config';
|
||||||
import { DataSourceType, GRAFANA_RULES_SOURCE_NAME } from './utils/datasource';
|
import { DataSourceType, GRAFANA_RULES_SOURCE_NAME } from './utils/datasource';
|
||||||
@ -79,6 +81,7 @@ jest.mock('app/core/core', () => ({
|
|||||||
jest.spyOn(analytics, 'logInfo');
|
jest.spyOn(analytics, 'logInfo');
|
||||||
jest.spyOn(config, 'getAllDataSources');
|
jest.spyOn(config, 'getAllDataSources');
|
||||||
jest.spyOn(actions, 'rulesInSameGroupHaveInvalidFor').mockReturnValue([]);
|
jest.spyOn(actions, 'rulesInSameGroupHaveInvalidFor').mockReturnValue([]);
|
||||||
|
jest.spyOn(apiRuler, 'rulerUrlBuilder');
|
||||||
|
|
||||||
const mocks = {
|
const mocks = {
|
||||||
getAllDataSourcesMock: jest.mocked(config.getAllDataSources),
|
getAllDataSourcesMock: jest.mocked(config.getAllDataSources),
|
||||||
@ -93,6 +96,7 @@ const mocks = {
|
|||||||
deleteGroup: jest.mocked(deleteRulerRulesGroup),
|
deleteGroup: jest.mocked(deleteRulerRulesGroup),
|
||||||
deleteNamespace: jest.mocked(deleteNamespace),
|
deleteNamespace: jest.mocked(deleteNamespace),
|
||||||
setRulerRuleGroup: jest.mocked(setRulerRuleGroup),
|
setRulerRuleGroup: jest.mocked(setRulerRuleGroup),
|
||||||
|
rulerBuilderMock: jest.mocked(apiRuler.rulerUrlBuilder),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -187,6 +191,11 @@ const configureMockServer = () => {
|
|||||||
message: 'rule group updated successfully',
|
message: 'rule group updated successfully',
|
||||||
updated: ['foo', 'bar', 'baz'],
|
updated: ['foo', 'bar', 'baz'],
|
||||||
});
|
});
|
||||||
|
mockAlertRuleApi(server).rulerRuleGroup(GRAFANA_RULES_SOURCE_NAME, 'NAMESPACE_UID', 'groupPaused', {
|
||||||
|
name: 'group-1',
|
||||||
|
interval: '1m',
|
||||||
|
rules: [mockRulerGrafanaRule()],
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
beforeAll(() => {
|
beforeAll(() => {
|
||||||
@ -634,6 +643,13 @@ describe('RuleList', () => {
|
|||||||
mocks.api.fetchRules.mockImplementation((sourceName) =>
|
mocks.api.fetchRules.mockImplementation((sourceName) =>
|
||||||
Promise.resolve(sourceName === 'grafana' ? pausedPromRules('grafana') : [])
|
Promise.resolve(sourceName === 'grafana' ? pausedPromRules('grafana') : [])
|
||||||
);
|
);
|
||||||
|
mocks.api.rulerBuilderMock.mockReturnValue({
|
||||||
|
rules: () => ({ path: `api/ruler/${GRAFANA_RULES_SOURCE_NAME}/api/v1/rules` }),
|
||||||
|
namespace: () => ({ path: 'ruler' }),
|
||||||
|
namespaceGroup: () => ({
|
||||||
|
path: `api/ruler/${GRAFANA_RULES_SOURCE_NAME}/api/v1/rules/NAMESPACE_UID/groupPaused`,
|
||||||
|
}),
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test('resuming paused alert rule', async () => {
|
test('resuming paused alert rule', async () => {
|
||||||
|
@ -2,10 +2,13 @@ import { produce } from 'immer';
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import { Menu } from '@grafana/ui';
|
import { Menu } from '@grafana/ui';
|
||||||
|
import { useAppNotification } from 'app/core/copy/appNotification';
|
||||||
import { alertRuleApi } from 'app/features/alerting/unified/api/alertRuleApi';
|
import { alertRuleApi } from 'app/features/alerting/unified/api/alertRuleApi';
|
||||||
import { isGrafanaRulerRule, isGrafanaRulerRulePaused } from 'app/features/alerting/unified/utils/rules';
|
import { isGrafanaRulerRule, isGrafanaRulerRulePaused } from 'app/features/alerting/unified/utils/rules';
|
||||||
import { CombinedRule } from 'app/types/unified-alerting';
|
import { CombinedRule } from 'app/types/unified-alerting';
|
||||||
|
|
||||||
|
import { grafanaRulerConfig } from '../hooks/useCombinedRule';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
rule: CombinedRule;
|
rule: CombinedRule;
|
||||||
/**
|
/**
|
||||||
@ -19,7 +22,11 @@ interface Props {
|
|||||||
* and triggering API call to do so
|
* and triggering API call to do so
|
||||||
*/
|
*/
|
||||||
const MenuItemPauseRule = ({ rule, onPauseChange }: Props) => {
|
const MenuItemPauseRule = ({ rule, onPauseChange }: Props) => {
|
||||||
const { group } = rule;
|
// we need to fetch the group again, as maybe the group has been filtered
|
||||||
|
const [getGroup] = alertRuleApi.endpoints.rulerRuleGroup.useLazyQuery();
|
||||||
|
const notifyApp = useAppNotification();
|
||||||
|
|
||||||
|
// Add any dependencies here
|
||||||
const [updateRule] = alertRuleApi.endpoints.updateRule.useMutation();
|
const [updateRule] = alertRuleApi.endpoints.updateRule.useMutation();
|
||||||
const isPaused = isGrafanaRulerRule(rule.rulerRule) && isGrafanaRulerRulePaused(rule.rulerRule);
|
const isPaused = isGrafanaRulerRule(rule.rulerRule) && isGrafanaRulerRulePaused(rule.rulerRule);
|
||||||
const icon = isPaused ? 'play' : 'pause';
|
const icon = isPaused ? 'play' : 'pause';
|
||||||
@ -33,21 +40,32 @@ const MenuItemPauseRule = ({ rule, onPauseChange }: Props) => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const ruleUid = rule.rulerRule.grafana_alert.uid;
|
const ruleUid = rule.rulerRule.grafana_alert.uid;
|
||||||
|
const targetGroup = await getGroup({
|
||||||
|
rulerConfig: grafanaRulerConfig,
|
||||||
|
namespace: rule.namespace.uid || rule.rulerRule.grafana_alert.namespace_uid,
|
||||||
|
group: rule.group.name,
|
||||||
|
}).unwrap();
|
||||||
|
|
||||||
// Parse the rules into correct format for API
|
if (!targetGroup) {
|
||||||
const modifiedRules = group.rules.map((groupRule) => {
|
notifyApp.error(
|
||||||
if (!(isGrafanaRulerRule(groupRule.rulerRule) && groupRule.rulerRule.grafana_alert.uid === ruleUid)) {
|
`Failed to ${newIsPaused ? 'pause' : 'resume'} the rule. Could not get the target group to update the rule.`
|
||||||
return groupRule.rulerRule!;
|
);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
return produce(groupRule.rulerRule, (updatedGroupRule) => {
|
// Parse the rules into correct format for API
|
||||||
|
const modifiedRules = targetGroup.rules.map((groupRule) => {
|
||||||
|
if (!(isGrafanaRulerRule(groupRule) && groupRule.grafana_alert.uid === ruleUid)) {
|
||||||
|
return groupRule;
|
||||||
|
}
|
||||||
|
return produce(groupRule, (updatedGroupRule) => {
|
||||||
updatedGroupRule.grafana_alert.is_paused = newIsPaused;
|
updatedGroupRule.grafana_alert.is_paused = newIsPaused;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
const payload = {
|
const payload = {
|
||||||
interval: group.interval!,
|
interval: targetGroup.interval!,
|
||||||
name: group.name,
|
name: targetGroup.name,
|
||||||
rules: modifiedRules,
|
rules: modifiedRules,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user