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:
Sonia Aguilar 2024-05-14 10:01:08 +02:00 committed by GitHub
parent 194039c429
commit 6b1a662f6b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 44 additions and 10 deletions

View File

@ -36,21 +36,23 @@ import * as analytics from './Analytics';
import RuleList from './RuleList';
import { discoverFeatures } from './api/buildInfo';
import { fetchRules } from './api/prometheus';
import * as apiRuler from './api/ruler';
import { deleteNamespace, deleteRulerRulesGroup, fetchRulerRules, setRulerRuleGroup } from './api/ruler';
import {
MockDataSourceSrv,
getPotentiallyPausedRulerRules,
grantUserPermissions,
mockDataSource,
mockFolder,
mockPromAlert,
mockPromAlertingRule,
mockPromRecordingRule,
mockPromRuleGroup,
mockPromRuleNamespace,
mockRulerGrafanaRule,
pausedPromRules,
getPotentiallyPausedRulerRules,
somePromRules,
someRulerRules,
mockFolder,
} from './mocks';
import * as config from './utils/config';
import { DataSourceType, GRAFANA_RULES_SOURCE_NAME } from './utils/datasource';
@ -79,6 +81,7 @@ jest.mock('app/core/core', () => ({
jest.spyOn(analytics, 'logInfo');
jest.spyOn(config, 'getAllDataSources');
jest.spyOn(actions, 'rulesInSameGroupHaveInvalidFor').mockReturnValue([]);
jest.spyOn(apiRuler, 'rulerUrlBuilder');
const mocks = {
getAllDataSourcesMock: jest.mocked(config.getAllDataSources),
@ -93,6 +96,7 @@ const mocks = {
deleteGroup: jest.mocked(deleteRulerRulesGroup),
deleteNamespace: jest.mocked(deleteNamespace),
setRulerRuleGroup: jest.mocked(setRulerRuleGroup),
rulerBuilderMock: jest.mocked(apiRuler.rulerUrlBuilder),
},
};
@ -187,6 +191,11 @@ const configureMockServer = () => {
message: 'rule group updated successfully',
updated: ['foo', 'bar', 'baz'],
});
mockAlertRuleApi(server).rulerRuleGroup(GRAFANA_RULES_SOURCE_NAME, 'NAMESPACE_UID', 'groupPaused', {
name: 'group-1',
interval: '1m',
rules: [mockRulerGrafanaRule()],
});
};
beforeAll(() => {
@ -634,6 +643,13 @@ describe('RuleList', () => {
mocks.api.fetchRules.mockImplementation((sourceName) =>
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 () => {

View File

@ -2,10 +2,13 @@ import { produce } from 'immer';
import React from 'react';
import { Menu } from '@grafana/ui';
import { useAppNotification } from 'app/core/copy/appNotification';
import { alertRuleApi } from 'app/features/alerting/unified/api/alertRuleApi';
import { isGrafanaRulerRule, isGrafanaRulerRulePaused } from 'app/features/alerting/unified/utils/rules';
import { CombinedRule } from 'app/types/unified-alerting';
import { grafanaRulerConfig } from '../hooks/useCombinedRule';
interface Props {
rule: CombinedRule;
/**
@ -19,7 +22,11 @@ interface Props {
* and triggering API call to do so
*/
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 isPaused = isGrafanaRulerRule(rule.rulerRule) && isGrafanaRulerRulePaused(rule.rulerRule);
const icon = isPaused ? 'play' : 'pause';
@ -33,21 +40,32 @@ const MenuItemPauseRule = ({ rule, onPauseChange }: Props) => {
return;
}
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();
if (!targetGroup) {
notifyApp.error(
`Failed to ${newIsPaused ? 'pause' : 'resume'} the rule. Could not get the target group to update the rule.`
);
return;
}
// Parse the rules into correct format for API
const modifiedRules = group.rules.map((groupRule) => {
if (!(isGrafanaRulerRule(groupRule.rulerRule) && groupRule.rulerRule.grafana_alert.uid === ruleUid)) {
return groupRule.rulerRule!;
const modifiedRules = targetGroup.rules.map((groupRule) => {
if (!(isGrafanaRulerRule(groupRule) && groupRule.grafana_alert.uid === ruleUid)) {
return groupRule;
}
return produce(groupRule.rulerRule, (updatedGroupRule) => {
return produce(groupRule, (updatedGroupRule) => {
updatedGroupRule.grafana_alert.is_paused = newIsPaused;
});
});
const payload = {
interval: group.interval!,
name: group.name,
interval: targetGroup.interval!,
name: targetGroup.name,
rules: modifiedRules,
};