Alerting: Use new readonly permission endpoints for getting contact points and mute timings (#82132)

* use new read only contact points list endpoint in simplified routing section

* Dont use alertmanager endpoint to get groupby defaults

* Use the new read only endpoint for mute timings in route settings

* review suggestions

* Rename hook

* Use options in params for useContactPointsWithStatus hook

* Refactor useContactPointsWithStatus

* second part of the enhanceContactPointsWithMetadata refactor
This commit is contained in:
Sonia Aguilar
2024-02-09 12:13:37 +01:00
committed by GitHub
parent ed9e26122a
commit 3e93a0991f
6 changed files with 104 additions and 36 deletions

View File

@@ -27,7 +27,13 @@ const RECEIVER_STATUS_POLLING_INTERVAL = 10 * 1000; // 10 seconds
* 3. (if available) additional metadata about Grafana Managed contact points
* 4. (if available) the OnCall plugin metadata
*/
export function useContactPointsWithStatus() {
interface UseContactPointsWithStatusOptions {
includePoliciesCount: boolean;
}
export function useContactPointsWithStatus(
{ includePoliciesCount }: UseContactPointsWithStatusOptions = { includePoliciesCount: true }
) {
const { selectedAlertmanager, isGrafanaAlertmanager } = useAlertmanager();
const { installed: onCallPluginInstalled, loading: onCallPluginStatusLoading } = usePluginBridge(
SupportedPlugin.OnCall
@@ -64,6 +70,7 @@ export function useContactPointsWithStatus() {
}
// fetch the latest config from the Alertmanager
// we use this endpoint only when we need to get the number of policies
const fetchAlertmanagerConfiguration = alertmanagerApi.endpoints.getAlertmanagerConfiguration.useQuery(
selectedAlertmanager!,
{
@@ -73,31 +80,56 @@ export function useContactPointsWithStatus() {
...result,
contactPoints: result.data
? enhanceContactPointsWithMetadata(
result.data,
fetchContactPointsStatus.data,
fetchReceiverMetadata.data,
onCallMetadata
onCallMetadata,
result.data.alertmanager_config.receivers ?? [],
result.data
)
: [],
}),
skip: !includePoliciesCount,
}
);
// for Grafana Managed Alertmanager, we use the new read-only endpoint for getting the list of contact points
const fetchGrafanaContactPoints = alertmanagerApi.endpoints.getContactPointsList.useQuery(undefined, {
refetchOnFocus: true,
refetchOnReconnect: true,
selectFromResult: (result) => ({
...result,
contactPoints: result.data
? enhanceContactPointsWithMetadata(
fetchContactPointsStatus.data,
fetchReceiverMetadata.data,
onCallMetadata,
result.data, // contact points from the new readonly endpoint
undefined //no config data
)
: [],
}),
skip: includePoliciesCount || !isGrafanaAlertmanager,
});
// we will fail silently for fetching OnCall plugin status and integrations
const error = fetchAlertmanagerConfiguration.error ?? fetchContactPointsStatus.error;
const error =
fetchAlertmanagerConfiguration.error || fetchGrafanaContactPoints.error || fetchContactPointsStatus.error;
const isLoading =
fetchAlertmanagerConfiguration.isLoading ||
fetchGrafanaContactPoints.isLoading ||
fetchContactPointsStatus.isLoading ||
onCallPluginStatusLoading ||
onCallPluginIntegrationsLoading;
const contactPoints = fetchAlertmanagerConfiguration.contactPoints.sort((a, b) => a.name.localeCompare(b.name));
const unsortedContactPoints = includePoliciesCount
? fetchAlertmanagerConfiguration.contactPoints
: fetchGrafanaContactPoints.contactPoints;
const contactPoints = unsortedContactPoints.sort((a, b) => a.name.localeCompare(b.name));
return {
error,
isLoading,
contactPoints,
refetchReceivers: fetchAlertmanagerConfiguration.refetch,
refetchReceivers: fetchGrafanaContactPoints.refetch,
};
}

View File

@@ -7,6 +7,7 @@ import {
GrafanaManagedContactPoint,
GrafanaManagedReceiverConfig,
MatcherOperator,
Receiver,
Route,
} from 'app/plugins/datasource/alertmanager/types';
import { NotifierDTO, NotifierStatus, ReceiversStateDTO } from 'app/types';
@@ -30,6 +31,9 @@ export function isProvisioned(contactPoint: GrafanaManagedContactPoint) {
// TODO we should really add some type information to these receiver settings...
export function getReceiverDescription(receiver: ReceiverConfigWithMetadata): ReactNode | undefined {
if (!receiver.settings) {
return undefined;
}
switch (receiver.type) {
case 'email': {
const hasEmailAddresses = 'addresses' in receiver.settings; // when dealing with alertmanager email_configs we don't normalize the settings
@@ -87,7 +91,7 @@ export interface ReceiverConfigWithMetadata extends GrafanaManagedReceiverConfig
}
export interface ContactPointWithMetadata extends GrafanaManagedContactPoint {
numberOfPolicies: number;
numberOfPolicies?: number; // now is optional as we don't have the data from the read-only endpoint
grafana_managed_receiver_configs: ReceiverConfigWithMetadata[];
}
@@ -95,30 +99,36 @@ export interface ContactPointWithMetadata extends GrafanaManagedContactPoint {
* This function adds the status information for each of the integrations (contact point types) in a contact point
* 1. we iterate over all contact points
* 2. for each contact point we "enhance" it with the status or "undefined" for vanilla Alertmanager
* contactPoints: list of contact points
* alertmanagerConfiguration: optional as is passed when we need to get number of policies for each contact point
* and we prefer using the data from the read-only endpoint.
*/
export function enhanceContactPointsWithMetadata(
result: AlertManagerCortexConfig,
status: ReceiversStateDTO[] = [],
notifiers: NotifierDTO[] = [],
onCallIntegrations: OnCallIntegrationDTO[] | undefined | null
onCallIntegrations: OnCallIntegrationDTO[] | undefined | null,
contactPoints: Receiver[],
alertmanagerConfiguration?: AlertManagerCortexConfig
): ContactPointWithMetadata[] {
const contactPoints = result.alertmanager_config.receivers ?? [];
// compute the entire inherited tree before finding what notification policies are using a particular contact point
const fullyInheritedTree = computeInheritedTree(result?.alertmanager_config?.route ?? {});
const fullyInheritedTree = computeInheritedTree(alertmanagerConfiguration?.alertmanager_config?.route ?? {});
const usedContactPoints = getUsedContactPoints(fullyInheritedTree);
const usedContactPointsByName = countBy(usedContactPoints);
return contactPoints.map((contactPoint) => {
const contactPointsList = alertmanagerConfiguration
? alertmanagerConfiguration?.alertmanager_config.receivers ?? []
: contactPoints ?? [];
return contactPointsList.map((contactPoint) => {
const receivers = extractReceivers(contactPoint);
const statusForReceiver = status.find((status) => status.name === contactPoint.name);
return {
...contactPoint,
numberOfPolicies: usedContactPointsByName[contactPoint.name] ?? 0,
numberOfPolicies:
alertmanagerConfiguration && usedContactPointsByName && (usedContactPointsByName[contactPoint.name] ?? 0),
grafana_managed_receiver_configs: receivers.map((receiver, index) => {
const isOnCallReceiver = receiver.type === ReceiverTypes.OnCall;
return {
...receiver,
[RECEIVER_STATUS_KEY]: statusForReceiver?.integrations[index],
@@ -130,6 +140,7 @@ export function enhanceContactPointsWithMetadata(
};
});
}
export function isAutoGeneratedPolicy(route: Route) {
const simplifiedRoutingToggleEnabled = config.featureToggles.alertingSimplifiedRouting ?? false;
if (!simplifiedRoutingToggleEnabled) {