mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Alerting: Allow editing of provisioned mutable Alertmanagers (#87385)
This commit is contained in:
parent
8173bd89bf
commit
19e8dca09c
@ -24,8 +24,8 @@ const ui = {
|
||||
builtInAlertmanagerSection: byText('Built-in Alertmanager'),
|
||||
otherAlertmanagerSection: byText('Other Alertmanagers'),
|
||||
|
||||
alertmanagerCard: (name: string) => byTestId(`alertmanager-card-${name}`),
|
||||
builtInAlertmanagerCard: byTestId('alertmanager-card-Grafana built-in'),
|
||||
otherAlertmanagerCard: (name: string) => byTestId(`alertmanager-card-${name}`),
|
||||
|
||||
statusReceiving: byText(/receiving grafana-managed alerts/i),
|
||||
statusNotReceiving: byText(/not receiving/i),
|
||||
@ -34,7 +34,11 @@ const ui = {
|
||||
editConfigurationButton: byRole('button', { name: /edit configuration/i }),
|
||||
saveConfigurationButton: byRole('button', { name: /save/i }),
|
||||
|
||||
enableButton: byRole('button', { name: 'Enable' }),
|
||||
disableButton: byRole('button', { name: 'Disable' }),
|
||||
|
||||
versionsTab: byRole('tab', { name: /versions/i }),
|
||||
provisionedBadge: byText(/^Provisioned$/),
|
||||
};
|
||||
|
||||
describe('Alerting settings', () => {
|
||||
@ -59,7 +63,7 @@ describe('Alerting settings', () => {
|
||||
// check external altermanagers
|
||||
DataSourcesResponse.forEach((ds) => {
|
||||
// get the card for datasource
|
||||
const card = ui.otherAlertmanagerCard(ds.name).get();
|
||||
const card = ui.alertmanagerCard(ds.name).get();
|
||||
|
||||
// expect link to data source, provisioned badge, type, and status
|
||||
expect(within(card).getByRole('link', { name: ds.name })).toBeInTheDocument();
|
||||
@ -120,4 +124,26 @@ describe('Alerting settings', () => {
|
||||
expect(screen.getByText(/last applied/i)).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
it('should correctly render provisioned data sources', async () => {
|
||||
render(<SettingsPage />);
|
||||
|
||||
// wait for loading to be done
|
||||
await waitFor(() => expect(ui.builtInAlertmanagerSection.get()).toBeInTheDocument());
|
||||
|
||||
// provisioned alertmanager card
|
||||
const provisionedCard = ui.alertmanagerCard('Provisioned Mimir-based Alertmanager').get();
|
||||
expect(ui.provisionedBadge.get(provisionedCard)).toBeInTheDocument();
|
||||
|
||||
// should still be editable
|
||||
const editConfigButton = ui.editConfigurationButton.get(provisionedCard);
|
||||
expect(editConfigButton).toBeInTheDocument();
|
||||
|
||||
// enable / disable should not be avaiable when provisioned
|
||||
const enableButton = ui.enableButton.query(provisionedCard);
|
||||
const disableButton = ui.disableButton.query(provisionedCard);
|
||||
|
||||
expect(enableButton).not.toBeInTheDocument();
|
||||
expect(disableButton).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
@ -76,6 +76,7 @@ export function AlertmanagerCard({
|
||||
{/* we'll use the "tags" area to append buttons and actions */}
|
||||
<Card.Tags>
|
||||
<Stack direction="row" gap={1}>
|
||||
{/* ⚠️ provisioned Data sources cannot have their "enable" / "disable" actions but we should still allow editing of the configuration */}
|
||||
<Button onClick={onEditConfiguration} icon={readOnly ? 'eye' : 'edit'} variant="secondary" fill="outline">
|
||||
{readOnly ? 'View configuration' : 'Edit configuration'}
|
||||
</Button>
|
||||
|
@ -14,7 +14,7 @@ import { AlertmanagerProvider } from '../../state/AlertmanagerContext';
|
||||
import AlertmanagerConfig from './AlertmanagerConfig';
|
||||
import {
|
||||
EXTERNAL_VANILLA_ALERTMANAGER_UID,
|
||||
PROVISIONED_VANILLA_ALERTMANAGER_UID,
|
||||
PROVISIONED_MIMIR_ALERTMANAGER_UID,
|
||||
setupGrafanaManagedServer,
|
||||
setupVanillaAlertmanagerServer,
|
||||
} from './__mocks__/server';
|
||||
@ -96,11 +96,11 @@ describe('vanilla Alertmanager', () => {
|
||||
expect(ui.resetButton.query()).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should be read-only when provisioned Alertmanager', async () => {
|
||||
renderConfiguration(PROVISIONED_VANILLA_ALERTMANAGER_UID, {});
|
||||
it('should not be read-only when Mimir Alertmanager', async () => {
|
||||
renderConfiguration(PROVISIONED_MIMIR_ALERTMANAGER_UID, {});
|
||||
|
||||
expect(ui.cancelButton.get()).toBeInTheDocument();
|
||||
expect(ui.saveButton.query()).not.toBeInTheDocument();
|
||||
expect(ui.resetButton.query()).not.toBeInTheDocument();
|
||||
expect(ui.saveButton.get()).toBeInTheDocument();
|
||||
expect(ui.resetButton.get()).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
@ -9,11 +9,7 @@ import { Alert, Button, CodeEditor, ConfirmModal, Stack, useStyles2 } from '@gra
|
||||
import { reportFormErrors } from '../../Analytics';
|
||||
import { useAlertmanagerConfig } from '../../hooks/useAlertmanagerConfig';
|
||||
import { useUnifiedAlertingSelector } from '../../hooks/useUnifiedAlertingSelector';
|
||||
import {
|
||||
GRAFANA_RULES_SOURCE_NAME,
|
||||
isProvisionedDataSource,
|
||||
isVanillaPrometheusAlertManagerDataSource,
|
||||
} from '../../utils/datasource';
|
||||
import { GRAFANA_RULES_SOURCE_NAME, isVanillaPrometheusAlertManagerDataSource } from '../../utils/datasource';
|
||||
import { Spacer } from '../Spacer';
|
||||
|
||||
export interface FormValues {
|
||||
@ -32,9 +28,9 @@ export default function AlertmanagerConfig({ alertmanagerName, onDismiss, onSave
|
||||
const { loading: isSaving, error: savingError } = useUnifiedAlertingSelector((state) => state.saveAMConfig);
|
||||
const [showResetConfirmation, setShowResetConfirmation] = useState(false);
|
||||
|
||||
// ⚠️ provisioned data sources should not prevent the configuration from being edited
|
||||
const immutableDataSource = alertmanagerName ? isVanillaPrometheusAlertManagerDataSource(alertmanagerName) : false;
|
||||
const provisionedDataSource = isProvisionedDataSource(alertmanagerName);
|
||||
const readOnly = immutableDataSource || provisionedDataSource;
|
||||
const readOnly = immutableDataSource;
|
||||
|
||||
const isGrafanaManagedAlertmanager = alertmanagerName === GRAFANA_RULES_SOURCE_NAME;
|
||||
const styles = useStyles2(getStyles);
|
||||
|
@ -7,6 +7,7 @@ import { AlertmanagerChoice } from 'app/plugins/datasource/alertmanager/types';
|
||||
import { ExternalAlertmanagerDataSourceWithStatus } from '../../hooks/useExternalAmSelector';
|
||||
import {
|
||||
isAlertmanagerDataSourceInterestedInAlerts,
|
||||
isProvisionedDataSource,
|
||||
isVanillaPrometheusAlertManagerDataSource,
|
||||
} from '../../utils/datasource';
|
||||
import { createUrl } from '../../utils/url';
|
||||
@ -44,9 +45,9 @@ export const ExternalAlertmanagers = ({ onEditConfiguration }: Props) => {
|
||||
const { status } = alertmanager;
|
||||
|
||||
const isReceiving = isReceivingGrafanaAlerts(alertmanager);
|
||||
const isProvisioned = alertmanager.dataSourceSettings.readOnly === true;
|
||||
const isReadOnly =
|
||||
isProvisioned || isVanillaPrometheusAlertManagerDataSource(alertmanager.dataSourceSettings.name);
|
||||
const isProvisioned = isProvisionedDataSource(alertmanager.dataSourceSettings);
|
||||
const isReadOnly = isVanillaPrometheusAlertManagerDataSource(alertmanager.dataSourceSettings.name);
|
||||
|
||||
const detailHref = createUrl(DATASOURCES_ROUTES.Edit.replace(/:uid/gi, uid));
|
||||
|
||||
const handleEditConfiguration = () => onEditConfiguration(name);
|
||||
|
@ -19,6 +19,26 @@
|
||||
},
|
||||
"readOnly": false
|
||||
},
|
||||
{
|
||||
"id": 183,
|
||||
"uid": "xPVD2XISx",
|
||||
"orgId": 1,
|
||||
"name": "Provisioned Mimir-based Alertmanager",
|
||||
"type": "alertmanager",
|
||||
"typeName": "Alertmanager",
|
||||
"typeLogoUrl": "public/app/plugins/datasource/prometheus/img/prometheus_logo.svg",
|
||||
"access": "proxy",
|
||||
"url": "http://foo.bar:9090/",
|
||||
"user": "",
|
||||
"database": "",
|
||||
"basicAuth": false,
|
||||
"isDefault": false,
|
||||
"jsonData": {
|
||||
"httpMethod": "POST",
|
||||
"implementation": "mimir"
|
||||
},
|
||||
"readOnly": true
|
||||
},
|
||||
{
|
||||
"id": 160,
|
||||
"uid": "iETbvsT4z",
|
||||
|
@ -23,7 +23,7 @@ export { vanillaAlertmanagerConfig as VanillaAlertmanagerConfiguration };
|
||||
export { history as alertmanagerConfigurationHistory };
|
||||
|
||||
export const EXTERNAL_VANILLA_ALERTMANAGER_UID = 'vanilla-alertmanager';
|
||||
export const PROVISIONED_VANILLA_ALERTMANAGER_UID = 'provisioned-alertmanager';
|
||||
export const PROVISIONED_MIMIR_ALERTMANAGER_UID = 'provisioned-alertmanager';
|
||||
|
||||
jest.spyOn(config, 'getAllDataSources');
|
||||
|
||||
@ -40,9 +40,9 @@ const mockDataSources = {
|
||||
implementation: AlertManagerImplementation.prometheus,
|
||||
},
|
||||
}),
|
||||
[PROVISIONED_VANILLA_ALERTMANAGER_UID]: mockDataSource<AlertManagerDataSourceJsonData>({
|
||||
uid: PROVISIONED_VANILLA_ALERTMANAGER_UID,
|
||||
name: PROVISIONED_VANILLA_ALERTMANAGER_UID,
|
||||
[PROVISIONED_MIMIR_ALERTMANAGER_UID]: mockDataSource<AlertManagerDataSourceJsonData>({
|
||||
uid: PROVISIONED_MIMIR_ALERTMANAGER_UID,
|
||||
name: PROVISIONED_MIMIR_ALERTMANAGER_UID,
|
||||
type: DataSourceType.Alertmanager,
|
||||
jsonData: {
|
||||
// this is a mutable data source type but we're making it readOnly
|
||||
@ -70,7 +70,7 @@ export function setupVanillaAlertmanagerServer(server: SetupServerApi) {
|
||||
|
||||
server.use(
|
||||
createVanillaAlertmanagerConfigurationHandler(EXTERNAL_VANILLA_ALERTMANAGER_UID),
|
||||
...createAlertmanagerConfigurationHandlers(PROVISIONED_VANILLA_ALERTMANAGER_UID)
|
||||
...createAlertmanagerConfigurationHandlers(PROVISIONED_MIMIR_ALERTMANAGER_UID)
|
||||
);
|
||||
|
||||
return server;
|
||||
|
@ -210,8 +210,8 @@ export function isVanillaPrometheusAlertManagerDataSource(name: string): boolean
|
||||
);
|
||||
}
|
||||
|
||||
export function isProvisionedDataSource(name: string): boolean {
|
||||
return getAlertmanagerDataSourceByName(name)?.readOnly === true;
|
||||
export function isProvisionedDataSource(dataSource: DataSourceSettings): boolean {
|
||||
return dataSource.readOnly === true;
|
||||
}
|
||||
|
||||
export function isGrafanaRulesSource(
|
||||
|
Loading…
Reference in New Issue
Block a user