Alerting: Filter out synthetic datasource-managed rules when importing to GMA (#106358)

* filter out synthetic datasource-managed rules when importing to GMA through the UI

* address pr feedback
This commit is contained in:
Sonia Aguilar
2025-06-06 12:33:45 +02:00
committed by GitHub
parent f7a52bc04e
commit 32336d5249
2 changed files with 93 additions and 7 deletions
@@ -1,8 +1,11 @@
import { config } from '@grafana/runtime';
import { RulerRulesConfigDTO } from 'app/types/unified-alerting-dto';
import { pluginMeta, pluginMetaToPluginConfig } from '../../testSetup/plugins';
import { SupportedPlugin } from '../../types/pluginBridges';
import { GRAFANA_ORIGIN_LABEL } from '../../utils/labels';
import { filterRulerRulesConfig } from './ConfirmConvertModal';
import { SYNTHETICS_RULE_NAMES, filterRulerRulesConfig } from './ConfirmConvertModal';
describe('filterRulerRulesConfig', () => {
const mockRulesConfig: RulerRulesConfigDTO = {
@@ -21,7 +24,7 @@ describe('filterRulerRulesConfig', () => {
alert: 'Alert2',
expr: 'down == 1',
labels: {
[GRAFANA_ORIGIN_LABEL]: 'true',
[GRAFANA_ORIGIN_LABEL]: `plugin/${SupportedPlugin.Slo}`,
},
},
],
@@ -33,6 +36,13 @@ describe('filterRulerRulesConfig', () => {
alert: 'Alert3',
expr: 'error == 1',
},
{
alert: SYNTHETICS_RULE_NAMES[0],
expr: 'error == 1',
labels: {
namespace: 'synthetic_monitoring',
},
},
],
},
],
@@ -50,6 +60,7 @@ describe('filterRulerRulesConfig', () => {
};
it('should filter by namespace', () => {
config.apps = { [SupportedPlugin.Slo]: pluginMetaToPluginConfig(pluginMeta[SupportedPlugin.Slo]) };
const { filteredConfig, someRulesAreSkipped } = filterRulerRulesConfig(mockRulesConfig, 'namespace1');
expect(filteredConfig).toEqual({
@@ -184,4 +195,46 @@ describe('filterRulerRulesConfig', () => {
expect(filteredConfig).toEqual({});
expect(someRulesAreSkipped).toBe(false);
});
it('should filter out synthetics rules', () => {
const { filteredConfig, someRulesAreSkipped } = filterRulerRulesConfig(mockRulesConfig);
expect(filteredConfig).toEqual({
namespace1: [
{
name: 'group1',
rules: [
{
alert: 'Alert1',
expr: 'up == 0',
labels: {
severity: 'warning',
},
},
],
},
{
name: 'group2',
rules: [
{
alert: 'Alert3',
expr: 'error == 1',
},
],
},
],
namespace2: [
{
name: 'group3',
rules: [
{
alert: 'Alert4',
expr: 'test == 0',
},
],
},
],
});
expect(someRulesAreSkipped).toBe(true);
});
});
@@ -8,17 +8,24 @@ import { locationService } from '@grafana/runtime';
import { Alert, CodeEditor, Collapse, ConfirmModal, Modal, Stack, Text, useStyles2 } from '@grafana/ui';
import { useAppNotification } from 'app/core/copy/appNotification';
import { stringifyErrorLike } from 'app/features/alerting/unified/utils/misc';
import { RulerRulesConfigDTO } from 'app/types/unified-alerting-dto';
import { RulerRuleDTO, RulerRulesConfigDTO } from 'app/types/unified-alerting-dto';
import { trackImportToGMAError, trackImportToGMASuccess } from '../../Analytics';
import { convertToGMAApi } from '../../api/convertToGMAApi';
import { GRAFANA_ORIGIN_LABEL } from '../../utils/labels';
import { createListFilterLink } from '../../utils/navigation';
import { getRuleName, isPluginProvidedRule } from '../../utils/rules';
import { ImportFormValues } from './ImportToGMARules';
import { useGetRulesThatMightBeOverwritten, useGetRulesToBeImported } from './hooks';
import { parseYamlFileToRulerRulesConfigDTO } from './yamlToRulerConverter';
export const SYNTHETICS_RULE_NAMES = [
'SyntheticMonitoringCheckFailureAtHighSensitivity',
'SyntheticMonitoringCheckFailureAtMediumSensitivity',
'SyntheticMonitoringCheckFailureAtLowSensitivity',
'instance_job_severity:probe_success:mean5m',
];
type ModalProps = Pick<ComponentProps<typeof ConfirmModal>, 'isOpen' | 'onDismiss'> & {
isOpen: boolean;
importPayload: ImportFormValues;
@@ -220,7 +227,9 @@ export const ConfirmConversionModal = ({ importPayload, isOpen, onDismiss }: Mod
/**
* Filter the ruler rules config to be imported. It filters the rules by namespace and group name.
* It also filters out the rules that have the '__grafana_origin' label.
* It also filters out the rules that have the '__grafana_origin' label, and rules from synthetics that have the
* 'namespace: synthetic_monitoring' label.
* Precondition: these rules are cloud rules.
* @param rulerRulesConfig - The ruler rules config to be imported
* @param namespace - The namespace to filter the rules by
* @param groupName - The group name to filter the rules by
@@ -248,8 +257,8 @@ export function filterRulerRulesConfig(
})
.map((group) => {
const filteredRules = group.rules.filter((rule) => {
const hasGrafanaOriginLabel = rule.labels?.[GRAFANA_ORIGIN_LABEL];
if (hasGrafanaOriginLabel) {
const shouldSkip = shouldSkipRule(rule);
if (shouldSkip) {
someRulesAreSkipped = true;
return false;
}
@@ -271,6 +280,30 @@ export function filterRulerRulesConfig(
return { filteredConfig, someRulesAreSkipped };
}
/*
This function is used to check if the rule should be skipped.
It checks if the rule has the '__grafana_origin' label, and if the rule is from synthetics.
If the rule has the '__grafana_origin' label, it is skipped.
If the rule is from synthetics, it is skipped.
*/
function shouldSkipRule(rule: RulerRuleDTO): boolean {
// check if the rule has the '__grafana_origin' label
const hasGrafanaOriginLabel = isPluginProvidedRule(rule);
if (hasGrafanaOriginLabel) {
return true;
}
// check if the rule is from synthetics
const hasSyntheticsLabels = rule.labels?.namespace === 'synthetic_monitoring';
if (!hasSyntheticsLabels) {
return false;
}
const ruleName = getRuleName(rule);
return SYNTHETICS_RULE_NAMES.some((name) => name === ruleName);
}
function RulesPreview({ rules }: { rules: RulerRulesConfigDTO }) {
const styles = useStyles2(getStyles);
return (