mirror of https://github.com/grafana/grafana
Alerting: Improved RBAC for Alert managers (#48344)
* Initial support for grafana or cloud only alert managers * Handle missing alert manager * Refactor code, fix tests * Fix redirect url * Bring back the test * Improve missing alert manager warning, add useAlertManagerSourceName tests * Fix lint errors * Rename alert manager hook * Refactor alert manager label creation * Improve warnings' messages * Fix linter * Fix warning condition in RuleEditorpull/48758/head
parent
696405ba7b
commit
65d7d466d7
@ -0,0 +1,42 @@ |
||||
import React from 'react'; |
||||
|
||||
import { Alert } from '@grafana/ui'; |
||||
|
||||
import { useAlertManagerSourceName } from '../hooks/useAlertManagerSourceName'; |
||||
import { AlertManagerDataSource } from '../utils/datasource'; |
||||
|
||||
import { AlertManagerPicker } from './AlertManagerPicker'; |
||||
|
||||
interface Props { |
||||
availableAlertManagers: AlertManagerDataSource[]; |
||||
} |
||||
|
||||
const NoAlertManagersAvailable = () => ( |
||||
<Alert title="No Alertmanager found" severity="warning"> |
||||
We could not find any external Alertmanagers and you may not have access to the built-in Grafana Alertmanager. |
||||
</Alert> |
||||
); |
||||
|
||||
const OtherAlertManagersAvailable = () => ( |
||||
<Alert title="Selected Alertmanager not found. Select a different Alertmanager." severity="warning"> |
||||
Selected Alertmanager no longer exists or you may not have permission to access it. |
||||
</Alert> |
||||
); |
||||
|
||||
export const NoAlertManagerWarning = ({ availableAlertManagers }: Props) => { |
||||
const [_, setAlertManagerSourceName] = useAlertManagerSourceName(availableAlertManagers); |
||||
const hasOtherAMs = availableAlertManagers.length > 0; |
||||
|
||||
return ( |
||||
<div> |
||||
{hasOtherAMs ? ( |
||||
<> |
||||
<AlertManagerPicker onChange={setAlertManagerSourceName} dataSources={availableAlertManagers} /> |
||||
<OtherAlertManagersAvailable /> |
||||
</> |
||||
) : ( |
||||
<NoAlertManagersAvailable /> |
||||
)} |
||||
</div> |
||||
); |
||||
}; |
@ -0,0 +1,103 @@ |
||||
import { renderHook } from '@testing-library/react-hooks'; |
||||
import { createMemoryHistory } from 'history'; |
||||
import React from 'react'; |
||||
import { MemoryRouter, Router } from 'react-router-dom'; |
||||
|
||||
import store from 'app/core/store'; |
||||
|
||||
import { ALERTMANAGER_NAME_LOCAL_STORAGE_KEY } from '../utils/constants'; |
||||
import { AlertManagerDataSource, GRAFANA_RULES_SOURCE_NAME } from '../utils/datasource'; |
||||
|
||||
import { useAlertManagerSourceName } from './useAlertManagerSourceName'; |
||||
|
||||
const grafanaAm: AlertManagerDataSource = { |
||||
name: GRAFANA_RULES_SOURCE_NAME, |
||||
imgUrl: '', |
||||
}; |
||||
|
||||
const externalAmProm: AlertManagerDataSource = { |
||||
name: 'PrometheusAm', |
||||
imgUrl: '', |
||||
}; |
||||
|
||||
const externalAmMimir: AlertManagerDataSource = { |
||||
name: 'MimirAm', |
||||
imgUrl: '', |
||||
}; |
||||
|
||||
describe('useAlertManagerSourceName', () => { |
||||
it('Should return undefined alert manager name when there are no available alert managers', () => { |
||||
const wrapper: React.FC = ({ children }) => <MemoryRouter>{children}</MemoryRouter>; |
||||
const { result } = renderHook(() => useAlertManagerSourceName([]), { wrapper }); |
||||
|
||||
const [alertManager] = result.current; |
||||
|
||||
expect(alertManager).toBeUndefined(); |
||||
}); |
||||
|
||||
it('Should return Grafana AM when it is available and no alert manager query param exists', () => { |
||||
const wrapper: React.FC = ({ children }) => <MemoryRouter>{children}</MemoryRouter>; |
||||
|
||||
const availableAMs = [grafanaAm, externalAmProm, externalAmMimir]; |
||||
const { result } = renderHook(() => useAlertManagerSourceName(availableAMs), { wrapper }); |
||||
|
||||
const [alertManager] = result.current; |
||||
|
||||
expect(alertManager).toBe(grafanaAm.name); |
||||
}); |
||||
|
||||
it('Should return alert manager included in the query param when available', () => { |
||||
const history = createMemoryHistory(); |
||||
history.push({ search: `alertmanager=${externalAmProm.name}` }); |
||||
const wrapper: React.FC = ({ children }) => <Router history={history}>{children}</Router>; |
||||
|
||||
const availableAMs = [grafanaAm, externalAmProm, externalAmMimir]; |
||||
const { result } = renderHook(() => useAlertManagerSourceName(availableAMs), { wrapper }); |
||||
|
||||
const [alertManager] = result.current; |
||||
|
||||
expect(alertManager).toBe(externalAmProm.name); |
||||
}); |
||||
|
||||
it('Should return undefined if alert manager included in the query is not available', () => { |
||||
const history = createMemoryHistory(); |
||||
history.push({ search: `alertmanager=Not available external AM` }); |
||||
const wrapper: React.FC = ({ children }) => <Router history={history}>{children}</Router>; |
||||
|
||||
const availableAMs = [grafanaAm, externalAmProm, externalAmMimir]; |
||||
|
||||
const { result } = renderHook(() => useAlertManagerSourceName(availableAMs), { wrapper }); |
||||
|
||||
const [alertManager] = result.current; |
||||
|
||||
expect(alertManager).toBe(undefined); |
||||
}); |
||||
|
||||
it('Should return alert manager from store if available and query is empty', () => { |
||||
const wrapper: React.FC = ({ children }) => <MemoryRouter>{children}</MemoryRouter>; |
||||
|
||||
const availableAMs = [grafanaAm, externalAmProm, externalAmMimir]; |
||||
store.set(ALERTMANAGER_NAME_LOCAL_STORAGE_KEY, externalAmProm.name); |
||||
|
||||
const { result } = renderHook(() => useAlertManagerSourceName(availableAMs), { wrapper }); |
||||
|
||||
const [alertManager] = result.current; |
||||
|
||||
expect(alertManager).toBe(externalAmProm.name); |
||||
}); |
||||
|
||||
it('Should prioritize the alert manager from query over store', () => { |
||||
const history = createMemoryHistory(); |
||||
history.push({ search: `alertmanager=${externalAmProm.name}` }); |
||||
const wrapper: React.FC = ({ children }) => <Router history={history}>{children}</Router>; |
||||
|
||||
const availableAMs = [grafanaAm, externalAmProm, externalAmMimir]; |
||||
store.set(ALERTMANAGER_NAME_LOCAL_STORAGE_KEY, externalAmMimir.name); |
||||
|
||||
const { result } = renderHook(() => useAlertManagerSourceName(availableAMs), { wrapper }); |
||||
|
||||
const [alertManager] = result.current; |
||||
|
||||
expect(alertManager).toBe(externalAmProm.name); |
||||
}); |
||||
}); |
@ -0,0 +1,7 @@ |
||||
import { useMemo } from 'react'; |
||||
|
||||
import { getAlertManagerDataSourcesByPermission } from '../utils/datasource'; |
||||
|
||||
export function useAlertManagersByPermission(accessType: 'instance' | 'notification') { |
||||
return useMemo(() => getAlertManagerDataSourcesByPermission(accessType), [accessType]); |
||||
} |
Loading…
Reference in new issue