Alerting: for cortex am, load default config from status if theres no user config (#35769)

This commit is contained in:
Domas
2021-06-23 19:32:42 +03:00
committed by GitHub
parent 15171ffa3b
commit d480bbf262
5 changed files with 110 additions and 11 deletions

View File

@@ -7,8 +7,14 @@ import { locationService, setDataSourceSrv } from '@grafana/runtime';
import { act, render } from '@testing-library/react'; import { act, render } from '@testing-library/react';
import { getAllDataSources } from './utils/config'; import { getAllDataSources } from './utils/config';
import { typeAsJestMock } from 'test/helpers/typeAsJestMock'; import { typeAsJestMock } from 'test/helpers/typeAsJestMock';
import { updateAlertManagerConfig, fetchAlertManagerConfig } from './api/alertmanager'; import { updateAlertManagerConfig, fetchAlertManagerConfig, fetchStatus } from './api/alertmanager';
import { mockDataSource, MockDataSourceSrv, someCloudAlertManagerConfig, someGrafanaAlertManagerConfig } from './mocks'; import {
mockDataSource,
MockDataSourceSrv,
someCloudAlertManagerConfig,
someCloudAlertManagerStatus,
someGrafanaAlertManagerConfig,
} from './mocks';
import { DataSourceType, GRAFANA_RULES_SOURCE_NAME } from './utils/datasource'; import { DataSourceType, GRAFANA_RULES_SOURCE_NAME } from './utils/datasource';
import { fetchNotifiers } from './api/grafana'; import { fetchNotifiers } from './api/grafana';
import { grafanaNotifiersMock } from './mocks/grafana-notifiers'; import { grafanaNotifiersMock } from './mocks/grafana-notifiers';
@@ -27,6 +33,7 @@ const mocks = {
api: { api: {
fetchConfig: typeAsJestMock(fetchAlertManagerConfig), fetchConfig: typeAsJestMock(fetchAlertManagerConfig),
fetchStatus: typeAsJestMock(fetchStatus),
updateConfig: typeAsJestMock(updateAlertManagerConfig), updateConfig: typeAsJestMock(updateAlertManagerConfig),
fetchNotifiers: typeAsJestMock(fetchNotifiers), fetchNotifiers: typeAsJestMock(fetchNotifiers),
}, },
@@ -302,4 +309,25 @@ describe('Receivers', () => {
}, },
}); });
}, 10000); }, 10000);
it('Loads config from status endpoint if there is no user config', async () => {
// loading an empty config with make it fetch config from status endpoint
mocks.api.fetchConfig.mockResolvedValue({
template_files: {},
alertmanager_config: {},
});
mocks.api.fetchStatus.mockResolvedValue(someCloudAlertManagerStatus);
await renderReceivers('CloudManager');
// check that receiver from the default config is represented
const receiversTable = await ui.receiversTable.find();
const receiverRows = receiversTable.querySelectorAll<HTMLTableRowElement>('tbody tr');
expect(receiverRows[0]).toHaveTextContent('default-email');
// check that both config and status endpoints were called
expect(mocks.api.fetchConfig).toHaveBeenCalledTimes(1);
expect(mocks.api.fetchConfig).toHaveBeenLastCalledWith('CloudManager');
expect(mocks.api.fetchStatus).toHaveBeenCalledTimes(1);
expect(mocks.api.fetchStatus).toHaveBeenLastCalledWith('CloudManager');
});
}); });

View File

@@ -7,6 +7,7 @@ import {
Silence, Silence,
SilenceCreatePayload, SilenceCreatePayload,
Matcher, Matcher,
AlertmanagerStatus,
} from 'app/plugins/datasource/alertmanager/types'; } from 'app/plugins/datasource/alertmanager/types';
import { getDatasourceAPIId, GRAFANA_RULES_SOURCE_NAME } from '../utils/datasource'; import { getDatasourceAPIId, GRAFANA_RULES_SOURCE_NAME } from '../utils/datasource';
@@ -131,6 +132,18 @@ export async function fetchAlertGroups(alertmanagerSourceName: string): Promise<
return result.data; return result.data;
} }
export async function fetchStatus(alertManagerSourceName: string): Promise<AlertmanagerStatus> {
const result = await getBackendSrv()
.fetch<AlertmanagerStatus>({
url: `/api/alertmanager/${getDatasourceAPIId(alertManagerSourceName)}/api/v2/status`,
showErrorAlert: false,
showSuccessAlert: false,
})
.toPromise();
return result.data;
}
function escapeQuotes(value: string): string { function escapeQuotes(value: string): string {
return value.replace(/"/g, '\\"'); return value.replace(/"/g, '\\"');
} }

View File

@@ -3,7 +3,11 @@ import { PromAlertingRuleState, PromRuleType } from 'app/types/unified-alerting-
import { AlertingRule, Alert, RecordingRule, RuleGroup, RuleNamespace } from 'app/types/unified-alerting'; import { AlertingRule, Alert, RecordingRule, RuleGroup, RuleNamespace } from 'app/types/unified-alerting';
import DatasourceSrv from 'app/features/plugins/datasource_srv'; import DatasourceSrv from 'app/features/plugins/datasource_srv';
import { DataSourceSrv, GetDataSourceListFilters } from '@grafana/runtime'; import { DataSourceSrv, GetDataSourceListFilters } from '@grafana/runtime';
import { AlertManagerCortexConfig, GrafanaManagedReceiverConfig } from 'app/plugins/datasource/alertmanager/types'; import {
AlertManagerCortexConfig,
AlertmanagerStatus,
GrafanaManagedReceiverConfig,
} from 'app/plugins/datasource/alertmanager/types';
let nextDataSourceId = 1; let nextDataSourceId = 1;
@@ -176,6 +180,37 @@ export const someGrafanaAlertManagerConfig: AlertManagerCortexConfig = {
}, },
}; };
export const someCloudAlertManagerStatus: AlertmanagerStatus = {
cluster: {
peers: [],
status: 'ok',
},
uptime: '10 hours',
versionInfo: {
branch: '',
version: '',
goVersion: '',
buildDate: '',
buildUser: '',
revision: '',
},
config: {
route: {
receiver: 'default-email',
},
receivers: [
{
name: 'default-email',
email_configs: [
{
to: 'example@example.com',
},
],
},
],
},
};
export const someCloudAlertManagerConfig: AlertManagerCortexConfig = { export const someCloudAlertManagerConfig: AlertManagerCortexConfig = {
template_files: { template_files: {
'foo template': 'foo content', 'foo template': 'foo content',

View File

@@ -22,6 +22,7 @@ import {
fetchSilences, fetchSilences,
createOrUpdateSilence, createOrUpdateSilence,
updateAlertManagerConfig, updateAlertManagerConfig,
fetchStatus,
} from '../api/alertmanager'; } from '../api/alertmanager';
import { fetchRules } from '../api/prometheus'; import { fetchRules } from '../api/prometheus';
import { import {
@@ -47,6 +48,7 @@ import {
} from '../utils/rules'; } from '../utils/rules';
import { addDefaultsToAlertmanagerConfig } from '../utils/alertmanager'; import { addDefaultsToAlertmanagerConfig } from '../utils/alertmanager';
import { backendSrv } from 'app/core/services/backend_srv'; import { backendSrv } from 'app/core/services/backend_srv';
import { isEmpty } from 'lodash';
export const fetchPromRulesAction = createAsyncThunk( export const fetchPromRulesAction = createAsyncThunk(
'unifiedalerting/fetchPromRules', 'unifiedalerting/fetchPromRules',
@@ -56,7 +58,18 @@ export const fetchPromRulesAction = createAsyncThunk(
export const fetchAlertManagerConfigAction = createAsyncThunk( export const fetchAlertManagerConfigAction = createAsyncThunk(
'unifiedalerting/fetchAmConfig', 'unifiedalerting/fetchAmConfig',
(alertManagerSourceName: string): Promise<AlertManagerCortexConfig> => (alertManagerSourceName: string): Promise<AlertManagerCortexConfig> =>
withSerializedError(fetchAlertManagerConfig(alertManagerSourceName)) withSerializedError(
fetchAlertManagerConfig(alertManagerSourceName).then((result) => {
// if user config is empty for cortex alertmanager, try to get config from status endpoint
if (isEmpty(result.alertmanager_config) && alertManagerSourceName !== GRAFANA_RULES_SOURCE_NAME) {
return fetchStatus(alertManagerSourceName).then((status) => ({
alertmanager_config: status.config,
template_files: {},
}));
}
return result;
})
)
); );
export const fetchRulerRulesAction = createAsyncThunk( export const fetchRulerRulesAction = createAsyncThunk(

View File

@@ -5,13 +5,6 @@ export type AlertManagerCortexConfig = {
alertmanager_config: AlertmanagerConfig; alertmanager_config: AlertmanagerConfig;
}; };
// NOTE - This type is incomplete! But currently, we don't need more.
export type AlertmanagerStatusPayload = {
config: {
original: string;
};
};
export type TLSConfig = { export type TLSConfig = {
ca_file: string; ca_file: string;
cert_file: string; cert_file: string;
@@ -217,3 +210,20 @@ export type AlertmanagerGroup = {
alerts: AlertmanagerAlert[]; alerts: AlertmanagerAlert[];
id: string; id: string;
}; };
export interface AlertmanagerStatus {
cluster: {
peers: unknown;
status: string;
};
config: AlertmanagerConfig;
uptime: string;
versionInfo: {
branch: string;
buildDate: string;
buildUser: string;
goVersion: string;
revision: string;
version: string;
};
}