- For each external alert managers you can define global settings, like server addresses, usernames and
+ For each external Alertmanager you can define global settings, like server addresses, usernames and
password, for all the supported contact points.
diff --git a/public/app/features/alerting/unified/components/receivers/ReceiversTable.test.tsx b/public/app/features/alerting/unified/components/receivers/ReceiversTable.test.tsx
index 646ffea4e3e..fa43942699b 100644
--- a/public/app/features/alerting/unified/components/receivers/ReceiversTable.test.tsx
+++ b/public/app/features/alerting/unified/components/receivers/ReceiversTable.test.tsx
@@ -81,7 +81,7 @@ describe('ReceiversTable', () => {
expect(rows[1].querySelectorAll('td')[1].textContent).toEqual('');
});
- it('render receivers with alert manager notifers', async () => {
+ it('render receivers with alertmanager notifers', async () => {
const receivers: Receiver[] = [
{
name: 'with receivers',
diff --git a/public/app/features/alerting/unified/hooks/useAlertManagerSourceName.ts b/public/app/features/alerting/unified/hooks/useAlertManagerSourceName.ts
index 9e8cc60ff79..9ffbcd069f4 100644
--- a/public/app/features/alerting/unified/hooks/useAlertManagerSourceName.ts
+++ b/public/app/features/alerting/unified/hooks/useAlertManagerSourceName.ts
@@ -40,7 +40,7 @@ export function useAlertManagerSourceName(): [string | undefined, (alertManagerS
if (isAlertManagerSource(querySource)) {
return [querySource, update];
} else {
- // non existing alert manager
+ // non existing alertmanager
return [undefined, update];
}
}
diff --git a/public/app/features/alerting/unified/state/actions.ts b/public/app/features/alerting/unified/state/actions.ts
index 091b36708c2..30475c453fa 100644
--- a/public/app/features/alerting/unified/state/actions.ts
+++ b/public/app/features/alerting/unified/state/actions.ts
@@ -25,6 +25,7 @@ import {
createOrUpdateSilence,
updateAlertManagerConfig,
fetchStatus,
+ deleteAlertManagerConfig,
} from '../api/alertmanager';
import { fetchRules } from '../api/prometheus';
import {
@@ -62,7 +63,11 @@ export const fetchAlertManagerConfigAction = createAsyncThunk(
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) {
+ if (
+ isEmpty(result.alertmanager_config) &&
+ isEmpty(result.template_files) &&
+ alertManagerSourceName !== GRAFANA_RULES_SOURCE_NAME
+ ) {
return fetchStatus(alertManagerSourceName).then((status) => ({
alertmanager_config: status.config,
template_files: {},
@@ -404,7 +409,10 @@ export const updateAlertManagerConfigAction = createAsyncThunk {
const latestConfig = await fetchAlertManagerConfig(alertManagerSourceName);
- if (JSON.stringify(latestConfig) !== JSON.stringify(oldConfig)) {
+ if (
+ !(isEmpty(latestConfig.alertmanager_config) && isEmpty(latestConfig.template_files)) &&
+ JSON.stringify(latestConfig) !== JSON.stringify(oldConfig)
+ ) {
throw new Error(
'It seems configuration has been recently updated. Please reload page and try again to make sure that recent changes are not overwritten.'
);
@@ -569,3 +577,13 @@ export const checkIfLotexSupportsEditingRulesAction = createAsyncThunk(
}
)
);
+
+export const deleteAlertManagerConfigAction = createAsyncThunk(
+ 'unifiedalerting/deleteAlertManagerConfig',
+ async (alertManagerSourceName: string): Promise => {
+ return withAppEvents(withSerializedError(deleteAlertManagerConfig(alertManagerSourceName)), {
+ errorMessage: 'Failed to reset Alertmanager configuration',
+ successMessage: 'Alertmanager configuration reset.',
+ });
+ }
+);
diff --git a/public/app/features/alerting/unified/state/reducers.ts b/public/app/features/alerting/unified/state/reducers.ts
index 8197289461f..09793108dc3 100644
--- a/public/app/features/alerting/unified/state/reducers.ts
+++ b/public/app/features/alerting/unified/state/reducers.ts
@@ -14,6 +14,7 @@ import {
fetchFolderAction,
fetchAlertGroupsAction,
checkIfLotexSupportsEditingRulesAction,
+ deleteAlertManagerConfigAction,
} from './actions';
export const reducer = combineReducers({
@@ -32,6 +33,7 @@ export const reducer = combineReducers({
}),
grafanaNotifiers: createAsyncSlice('grafanaNotifiers', fetchGrafanaNotifiersAction).reducer,
saveAMConfig: createAsyncSlice('saveAMConfig', updateAlertManagerConfigAction).reducer,
+ deleteAMConfig: createAsyncSlice('deleteAMConfig', deleteAlertManagerConfigAction).reducer,
updateSilence: createAsyncSlice('updateSilence', createOrUpdateSilenceAction).reducer,
amAlerts: createAsyncMapSlice('amAlerts', fetchAmAlertsAction, (alertManagerSourceName) => alertManagerSourceName)
.reducer,
diff --git a/public/app/features/alerting/unified/utils/receivers.ts b/public/app/features/alerting/unified/utils/receivers.ts
index 44f0d8a7e89..fbde0d532ea 100644
--- a/public/app/features/alerting/unified/utils/receivers.ts
+++ b/public/app/features/alerting/unified/utils/receivers.ts
@@ -16,7 +16,7 @@ export function extractNotifierTypeCounts(receiver: Receiver, grafanaNotifiers:
function getCortexAlertManagerNotifierTypeCounts(receiver: Receiver): NotifierTypeCounts {
return Object.entries(receiver)
- .filter(([key]) => key !== 'grafana_managed_receiver_configs' && key.endsWith('_configs')) // filter out only properties that are alert manager notifier
+ .filter(([key]) => key !== 'grafana_managed_receiver_configs' && key.endsWith('_configs')) // filter out only properties that are alertmanager notifier
.filter(([_, value]) => Array.isArray(value) && !!value.length) // check that there are actually notifiers of this type configured
.reduce((acc, [key, value]) => {
const type = key.replace('_configs', ''); // remove the `_config` part from the key, making it intto a notifier name
diff --git a/public/app/routes/routes.tsx b/public/app/routes/routes.tsx
index cad127c3b0f..96b340529ea 100644
--- a/public/app/routes/routes.tsx
+++ b/public/app/routes/routes.tsx
@@ -466,6 +466,13 @@ export function getAppRoutes(): RouteDescriptor[] {
import(/* webpackChunkName: "AlertingRedirectToRule"*/ 'app/features/alerting/unified/RedirectToRuleViewer')
),
},
+ {
+ path: '/alerting/admin',
+ roles: () => ['Admin'],
+ component: SafeDynamicImport(
+ () => import(/* webpackChunkName: "AlertingAdmin" */ 'app/features/alerting/unified/Admin')
+ ),
+ },
{
path: '/playlists',
component: SafeDynamicImport(