grafana/public/app/features/alerting/unified/hooks/ruleGroup/useUpdateRuleGroup.ts

191 lines
7.5 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { t } from 'app/core/internationalization';
import { RuleGroupIdentifier } from 'app/types/unified-alerting';
import { alertRuleApi } from '../../api/alertRuleApi';
import { notFoundToNullOrThrow } from '../../api/util';
import {
updateRuleGroupAction,
moveRuleGroupAction,
renameRuleGroupAction,
reorderRulesInRuleGroupAction,
} from '../../reducers/ruler/ruleGroups';
import { isGrafanaRulesSource } from '../../utils/datasource';
import { useAsync } from '../useAsync';
import { useProduceNewRuleGroup } from './useProduceNewRuleGroup';
const ruleUpdateSuccessMessage = () => t('alerting.rule-groups.update.success', 'Successfully updated rule group');
/**
* Update an existing rule group, currently only supports updating the interval.
* Use "useRenameRuleGroup" or "useMoveRuleGroup" for updating the namespace or group name.
*/
export function useUpdateRuleGroupConfiguration() {
const [produceNewRuleGroup] = useProduceNewRuleGroup();
const [upsertRuleGroup] = alertRuleApi.endpoints.upsertRuleGroupForNamespace.useMutation();
return useAsync(async (ruleGroup: RuleGroupIdentifier, interval: string) => {
const { namespaceName } = ruleGroup;
const action = updateRuleGroupAction({ interval });
const { newRuleGroupDefinition, rulerConfig } = await produceNewRuleGroup(ruleGroup, action);
return upsertRuleGroup({
rulerConfig,
namespace: namespaceName,
payload: newRuleGroupDefinition,
notificationOptions: { successMessage: ruleUpdateSuccessMessage() },
}).unwrap();
});
}
/**
* Move a rule group to either another namespace with (optionally) a different name, throws if the action
* targets an existing rule group.
* Optionally, update the rule group evaluation interval.
*/
export function useMoveRuleGroup() {
const [produceNewRuleGroup] = useProduceNewRuleGroup();
const [fetchRuleGroup] = alertRuleApi.endpoints.getRuleGroupForNamespace.useLazyQuery();
const [upsertRuleGroup] = alertRuleApi.endpoints.upsertRuleGroupForNamespace.useMutation();
const [deleteRuleGroup] = alertRuleApi.endpoints.deleteRuleGroupFromNamespace.useMutation();
// @TODO maybe add where we moved it from and to for additional peace of mind
const successMessage = t('alerting.rule-groups.move.success', 'Successfully moved rule group');
return useAsync(
async (ruleGroup: RuleGroupIdentifier, namespaceName: string, groupName?: string, interval?: string) => {
// we could technically support moving rule groups to another folder, though we don't have a "move" wizard yet.
if (isGrafanaRulesSource(ruleGroup.dataSourceName)) {
throw new Error('Moving a Grafana-managed rule group to another folder is currently not supported.');
}
const action = moveRuleGroupAction({ newNamespaceName: namespaceName, groupName, interval });
const { newRuleGroupDefinition, rulerConfig } = await produceNewRuleGroup(ruleGroup, action);
const oldNamespace = ruleGroup.namespaceName;
const targetNamespace = action.payload.newNamespaceName;
const oldGroupName = ruleGroup.groupName;
const targetGroupName = action.payload.groupName;
const isGroupRenamed = Boolean(targetGroupName) && oldGroupName !== targetGroupName;
// if we're also renaming the group, check if the target does not already exist
if (targetGroupName && isGroupRenamed) {
const targetGroup = await fetchRuleGroup({
rulerConfig,
namespace: targetNamespace,
group: targetGroupName,
// since this could throw 404
notificationOptions: { showErrorAlert: false },
})
.unwrap()
.catch(notFoundToNullOrThrow);
if (targetGroup?.rules?.length) {
throw new Error('Target group already has rules, merging rule groups is currently not supported.');
}
}
// create the new group in the target namespace
// ⚠️ it's important to do this before we remove the old group better to have two groups than none if one of these requests fails
await upsertRuleGroup({
rulerConfig,
namespace: targetNamespace,
payload: newRuleGroupDefinition,
notificationOptions: { successMessage },
}).unwrap();
// now remove the old one
const result = await deleteRuleGroup({
rulerConfig,
namespace: oldNamespace,
group: oldGroupName,
notificationOptions: { showSuccessAlert: false },
}).unwrap();
return result;
}
);
}
/**
* Rename a rule group but keep it within the same namespace, throws if the action targets an existing rule group.
* Optionally, update the rule group evaluation interval.
*/
export function useRenameRuleGroup() {
const [produceNewRuleGroup] = useProduceNewRuleGroup();
const [fetchRuleGroup] = alertRuleApi.endpoints.getRuleGroupForNamespace.useLazyQuery();
const [upsertRuleGroup] = alertRuleApi.endpoints.upsertRuleGroupForNamespace.useMutation();
const [deleteRuleGroup] = alertRuleApi.endpoints.deleteRuleGroupFromNamespace.useMutation();
return useAsync(async (ruleGroup: RuleGroupIdentifier, groupName: string, interval?: string) => {
const action = renameRuleGroupAction({ groupName, interval });
const { newRuleGroupDefinition, rulerConfig } = await produceNewRuleGroup(ruleGroup, action);
const oldGroupName = ruleGroup.groupName;
const newGroupName = action.payload.groupName;
const namespaceName = ruleGroup.namespaceName;
const successMessage = t('alerting.rule-groups.rename.success', 'Successfully renamed rule group');
// check if the target group exists
const targetGroup = await fetchRuleGroup({
rulerConfig,
namespace: namespaceName,
group: newGroupName,
// since this could throw 404
notificationOptions: { showErrorAlert: false },
})
.unwrap()
.catch(notFoundToNullOrThrow);
if (targetGroup?.rules?.length) {
throw new Error('Target group has existing rules, merging rule groups is currently not supported.');
}
// if the target group does not exist, create the new group
// ⚠️ it's important to do this before we remove the old group better to have two groups than none if one of these requests fails
const result = await upsertRuleGroup({
rulerConfig,
namespace: namespaceName,
payload: newRuleGroupDefinition,
notificationOptions: { successMessage },
}).unwrap();
// now delete the group we renamed
await deleteRuleGroup({
rulerConfig,
namespace: namespaceName,
group: oldGroupName,
notificationOptions: { showSuccessAlert: false },
}).unwrap();
return result;
});
}
/**
* Reorder rules within an existing rule group. Pass in an array of swap operations Array<[oldIndex, newIndex]>.
* This prevents rules from accidentally being updated and only allows indices to be moved around.
*/
export function useReorderRuleForRuleGroup() {
const [produceNewRuleGroup] = useProduceNewRuleGroup();
const [upsertRuleGroup] = alertRuleApi.endpoints.upsertRuleGroupForNamespace.useMutation();
return useAsync(async (ruleGroup: RuleGroupIdentifier, swaps: Array<[number, number]>) => {
const { namespaceName } = ruleGroup;
const action = reorderRulesInRuleGroupAction({ swaps });
const { newRuleGroupDefinition, rulerConfig } = await produceNewRuleGroup(ruleGroup, action);
return upsertRuleGroup({
rulerConfig,
namespace: namespaceName,
payload: newRuleGroupDefinition,
notificationOptions: { successMessage: ruleUpdateSuccessMessage() },
}).unwrap();
});
}