From e234d098e9fb08852190daa79232defdd2606308 Mon Sep 17 00:00:00 2001
From: Sonia Aguilar <33540275+soniaAguilarPeiron@users.noreply.github.com>
Date: Tue, 9 Apr 2024 09:02:44 +0200
Subject: [PATCH] Alerting: Get oncall metada only when we have alert manager
configuration data (#85622)
* Get oncall metada from url in settings only when we have alert manager configuration
* Add test in useContactPointsWithStatus hook
* Fix tests
---
.../contact-points/ContactPoints.test.tsx | 12 +-
.../__mocks__/alertmanager.config.mock.json | 13 ++
.../NewContactPoint.test.tsx.snap | 13 ++
.../useContactPoints.test.tsx.snap | 197 ++++++++++++++++++
.../contact-points/useContactPoints.test.tsx | 50 ++++-
.../components/contact-points/utils.ts | 7 +-
.../useReceiversMetadata.ts | 9 +-
.../app/features/alerting/unified/mockApi.ts | 4 +
8 files changed, 293 insertions(+), 12 deletions(-)
diff --git a/public/app/features/alerting/unified/components/contact-points/ContactPoints.test.tsx b/public/app/features/alerting/unified/components/contact-points/ContactPoints.test.tsx
index 325867253b8..7ef6152ab2b 100644
--- a/public/app/features/alerting/unified/components/contact-points/ContactPoints.test.tsx
+++ b/public/app/features/alerting/unified/components/contact-points/ContactPoints.test.tsx
@@ -65,7 +65,7 @@ describe('contact points', () => {
});
expect(screen.getByText('grafana-default-email')).toBeInTheDocument();
- expect(screen.getAllByTestId('contact-point')).toHaveLength(4);
+ expect(screen.getAllByTestId('contact-point')).toHaveLength(5);
// check for available actions – our mock 4 contact points, 1 of them is provisioned
expect(screen.getByRole('link', { name: 'add contact point' })).toBeInTheDocument();
@@ -73,20 +73,20 @@ describe('contact points', () => {
// 2 of them are unused by routes in the mock response
const unusedBadge = screen.getAllByLabelText('unused');
- expect(unusedBadge).toHaveLength(2);
+ expect(unusedBadge).toHaveLength(3);
const viewProvisioned = screen.getByRole('link', { name: 'view-action' });
expect(viewProvisioned).toBeInTheDocument();
expect(viewProvisioned).not.toBeDisabled();
const editButtons = screen.getAllByRole('link', { name: 'edit-action' });
- expect(editButtons).toHaveLength(3);
+ expect(editButtons).toHaveLength(4);
editButtons.forEach((button) => {
expect(button).not.toBeDisabled();
});
const moreActionsButtons = screen.getAllByRole('button', { name: 'more-actions' });
- expect(moreActionsButtons).toHaveLength(4);
+ expect(moreActionsButtons).toHaveLength(5);
moreActionsButtons.forEach((button) => {
expect(button).not.toBeDisabled();
});
@@ -115,11 +115,11 @@ describe('contact points', () => {
// there should be view buttons though
const viewButtons = screen.getAllByRole('link', { name: 'view-action' });
- expect(viewButtons).toHaveLength(4);
+ expect(viewButtons).toHaveLength(5);
// delete should be disabled in the "more" actions
const moreButtons = screen.queryAllByRole('button', { name: 'more-actions' });
- expect(moreButtons).toHaveLength(4);
+ expect(moreButtons).toHaveLength(5);
// check if all of the delete buttons are disabled
for await (const button of moreButtons) {
diff --git a/public/app/features/alerting/unified/components/contact-points/__mocks__/alertmanager.config.mock.json b/public/app/features/alerting/unified/components/contact-points/__mocks__/alertmanager.config.mock.json
index 5bfacc2cdcc..bc99b0531b9 100644
--- a/public/app/features/alerting/unified/components/contact-points/__mocks__/alertmanager.config.mock.json
+++ b/public/app/features/alerting/unified/components/contact-points/__mocks__/alertmanager.config.mock.json
@@ -73,6 +73,19 @@
"secureFields": { "token": true }
}
]
+ },
+ {
+ "name": "OnCall Conctact point",
+ "grafana_managed_receiver_configs": [
+ {
+ "name": "Oncall-integration",
+ "type": "oncall",
+ "settings": {
+ "url": "https://oncall-endpoint.example.com"
+ },
+ "disableResolveMessage": false
+ }
+ ]
}
]
}
diff --git a/public/app/features/alerting/unified/components/contact-points/__snapshots__/NewContactPoint.test.tsx.snap b/public/app/features/alerting/unified/components/contact-points/__snapshots__/NewContactPoint.test.tsx.snap
index 028e88fcac9..8739185052a 100644
--- a/public/app/features/alerting/unified/components/contact-points/__snapshots__/NewContactPoint.test.tsx.snap
+++ b/public/app/features/alerting/unified/components/contact-points/__snapshots__/NewContactPoint.test.tsx.snap
@@ -115,6 +115,19 @@ exports[`should be able to test and save a receiver 2`] = `
],
"name": "Slack with multiple channels",
},
+ {
+ "grafana_managed_receiver_configs": [
+ {
+ "disableResolveMessage": false,
+ "name": "Oncall-integration",
+ "settings": {
+ "url": "https://oncall-endpoint.example.com",
+ },
+ "type": "oncall",
+ },
+ ],
+ "name": "OnCall Conctact point",
+ },
{
"grafana_managed_receiver_configs": [
{
diff --git a/public/app/features/alerting/unified/components/contact-points/__snapshots__/useContactPoints.test.tsx.snap b/public/app/features/alerting/unified/components/contact-points/__snapshots__/useContactPoints.test.tsx.snap
index ea4fc89ca90..2f94d12cef6 100644
--- a/public/app/features/alerting/unified/components/contact-points/__snapshots__/useContactPoints.test.tsx.snap
+++ b/public/app/features/alerting/unified/components/contact-points/__snapshots__/useContactPoints.test.tsx.snap
@@ -60,6 +60,32 @@ exports[`useContactPoints should return contact points with status 1`] = `
"name": "lotsa-emails",
"numberOfPolicies": 0,
},
+ {
+ "grafana_managed_receiver_configs": [
+ {
+ "disableResolveMessage": false,
+ "name": "Oncall-integration",
+ "settings": {
+ "url": "https://oncall-endpoint.example.com",
+ },
+ "type": "oncall",
+ Symbol(receiver_status): undefined,
+ Symbol(receiver_metadata): {
+ "description": undefined,
+ "name": "Oncall",
+ },
+ Symbol(receiver_plugin_metadata): {
+ "description": "grafana-integration",
+ "externalUrl": "/a/grafana-oncall-app/integrations/ABC123",
+ "icon": "public/img/alerting/oncall_logo.svg",
+ "title": "Grafana OnCall",
+ "warning": undefined,
+ },
+ },
+ ],
+ "name": "OnCall Conctact point",
+ "numberOfPolicies": 0,
+ },
{
"grafana_managed_receiver_configs": [
{
@@ -147,3 +173,174 @@ exports[`useContactPoints should return contact points with status 1`] = `
"refetchReceivers": [Function],
}
`;
+
+exports[`useContactPoints when having oncall plugin installed and no alert manager config data should return contact points with oncall metadata 1`] = `
+{
+ "contactPoints": [
+ {
+ "grafana_managed_receiver_configs": [
+ {
+ "disableResolveMessage": false,
+ "name": "grafana-default-email",
+ "secureFields": {},
+ "settings": {
+ "addresses": "gilles.demey@grafana.com",
+ "singleEmail": false,
+ },
+ "type": "email",
+ "uid": "xeKQrBrnk",
+ Symbol(receiver_status): {
+ "lastNotifyAttempt": "2023-07-02T21:35:34.841+02:00",
+ "lastNotifyAttemptDuration": "1ms",
+ "lastNotifyAttemptError": "failed to send notification to email addresses: gilles.demey@grafana.com: dial tcp 192.168.1.21:1025: connect: connection refused",
+ "name": "email",
+ "sendResolved": true,
+ },
+ Symbol(receiver_metadata): {
+ "description": "Sends notifications using Grafana server configured SMTP settings",
+ "name": "Email",
+ },
+ Symbol(receiver_plugin_metadata): undefined,
+ },
+ ],
+ "name": "grafana-default-email",
+ "numberOfPolicies": undefined,
+ },
+ {
+ "grafana_managed_receiver_configs": [
+ {
+ "disableResolveMessage": false,
+ "name": "lotsa-emails",
+ "secureFields": {},
+ "settings": {
+ "addresses": "gilles.demey+1@grafana.com, gilles.demey+2@grafana.com, gilles.demey+3@grafana.com, gilles.demey+4@grafana.com",
+ "singleEmail": false,
+ },
+ "type": "email",
+ "uid": "af306c96-35a2-4d6e-908a-4993e245dbb2",
+ Symbol(receiver_status): {
+ "lastNotifyAttempt": "",
+ "lastNotifyAttemptDuration": "",
+ "name": "email",
+ "sendResolved": true,
+ },
+ Symbol(receiver_metadata): {
+ "description": "Sends notifications using Grafana server configured SMTP settings",
+ "name": "Email",
+ },
+ Symbol(receiver_plugin_metadata): undefined,
+ },
+ ],
+ "name": "lotsa-emails",
+ "numberOfPolicies": undefined,
+ },
+ {
+ "grafana_managed_receiver_configs": [
+ {
+ "disableResolveMessage": false,
+ "name": "Oncall-integration",
+ "settings": {
+ "url": "https://oncall-endpoint.example.com",
+ },
+ "type": "oncall",
+ Symbol(receiver_status): undefined,
+ Symbol(receiver_metadata): {
+ "description": undefined,
+ "name": "Oncall",
+ },
+ Symbol(receiver_plugin_metadata): {
+ "icon": "public/img/alerting/oncall_logo.svg",
+ "title": "Grafana OnCall",
+ },
+ },
+ ],
+ "name": "OnCall Conctact point",
+ "numberOfPolicies": undefined,
+ },
+ {
+ "grafana_managed_receiver_configs": [
+ {
+ "disableResolveMessage": false,
+ "name": "provisioned-contact-point",
+ "provenance": "api",
+ "secureFields": {},
+ "settings": {
+ "addresses": "gilles.demey@grafana.com",
+ "singleEmail": false,
+ },
+ "type": "email",
+ "uid": "s8SdCVjnk",
+ Symbol(receiver_status): {
+ "lastNotifyAttempt": "",
+ "lastNotifyAttemptDuration": "",
+ "name": "email",
+ "sendResolved": true,
+ },
+ Symbol(receiver_metadata): {
+ "description": "Sends notifications using Grafana server configured SMTP settings",
+ "name": "Email",
+ },
+ Symbol(receiver_plugin_metadata): undefined,
+ },
+ ],
+ "name": "provisioned-contact-point",
+ "numberOfPolicies": undefined,
+ },
+ {
+ "grafana_managed_receiver_configs": [
+ {
+ "disableResolveMessage": false,
+ "name": "Slack with multiple channels",
+ "secureFields": {
+ "token": true,
+ },
+ "settings": {
+ "recipient": "test-alerts",
+ },
+ "type": "slack",
+ "uid": "c02ad56a-31da-46b9-becb-4348ec0890fd",
+ Symbol(receiver_status): {
+ "lastNotifyAttempt": "",
+ "lastNotifyAttemptDuration": "",
+ "name": "slack",
+ "sendResolved": true,
+ },
+ Symbol(receiver_metadata): {
+ "description": "Sends notifications to Slack",
+ "name": "Slack",
+ },
+ Symbol(receiver_plugin_metadata): undefined,
+ },
+ {
+ "disableResolveMessage": false,
+ "name": "Slack with multiple channels",
+ "secureFields": {
+ "token": true,
+ },
+ "settings": {
+ "recipient": "test-alerts2",
+ },
+ "type": "slack",
+ "uid": "b286a3be-f690-49e2-8605-b075cbace2df",
+ Symbol(receiver_status): {
+ "lastNotifyAttempt": "",
+ "lastNotifyAttemptDuration": "",
+ "name": "slack",
+ "sendResolved": true,
+ },
+ Symbol(receiver_metadata): {
+ "description": "Sends notifications to Slack",
+ "name": "Slack",
+ },
+ Symbol(receiver_plugin_metadata): undefined,
+ },
+ ],
+ "name": "Slack with multiple channels",
+ "numberOfPolicies": undefined,
+ },
+ ],
+ "error": undefined,
+ "isLoading": false,
+ "refetchReceivers": [Function],
+}
+`;
diff --git a/public/app/features/alerting/unified/components/contact-points/useContactPoints.test.tsx b/public/app/features/alerting/unified/components/contact-points/useContactPoints.test.tsx
index 50f4fdbd03d..a4188d51789 100644
--- a/public/app/features/alerting/unified/components/contact-points/useContactPoints.test.tsx
+++ b/public/app/features/alerting/unified/components/contact-points/useContactPoints.test.tsx
@@ -2,10 +2,12 @@ import { renderHook, waitFor } from '@testing-library/react';
import React from 'react';
import { TestProvider } from 'test/helpers/TestProvider';
+import alertmanagerMock from 'app/features/alerting/unified/components/contact-points/__mocks__/alertmanager.config.mock.json';
import { AccessControlAction } from 'app/types';
-import { setupMswServer } from '../../mockApi';
-import { grantUserPermissions } from '../../mocks';
+import { ONCALL_INTEGRATION_V2_FEATURE } from '../../api/onCallApi';
+import { mockApi, setupMswServer } from '../../mockApi';
+import { grantUserPermissions, onCallPluginMetaMock } from '../../mocks';
import { AlertmanagerProvider } from '../../state/AlertmanagerContext';
import setupGrafanaManagedServer from './__mocks__/grafanaManagedServer';
@@ -23,6 +25,16 @@ describe('useContactPoints', () => {
});
it('should return contact points with status', async () => {
+ mockApi(server).plugins.getPluginSettings({ ...onCallPluginMetaMock, enabled: true });
+ mockApi(server).oncall.features([ONCALL_INTEGRATION_V2_FEATURE]);
+ mockApi(server).oncall.getOnCallIntegrations([
+ {
+ display_name: 'grafana-integration',
+ value: 'ABC123',
+ integration_url: 'https://oncall-endpoint.example.com',
+ },
+ ]);
+ mockApi(server).getContactPointsList(receivers);
const { result } = renderHook(() => useContactPointsWithStatus(), {
wrapper: ({ children }) => (
@@ -32,10 +44,42 @@ describe('useContactPoints', () => {
),
});
-
await waitFor(() => {
expect(result.current.isLoading).toBe(false);
expect(result.current).toMatchSnapshot();
});
});
+ describe('when having oncall plugin installed and no alert manager config data', () => {
+ it('should return contact points with oncall metadata', async () => {
+ mockApi(server).plugins.getPluginSettings({ ...onCallPluginMetaMock, enabled: true });
+ mockApi(server).oncall.features([ONCALL_INTEGRATION_V2_FEATURE]);
+ mockApi(server).oncall.getOnCallIntegrations([
+ {
+ display_name: 'grafana-integration',
+ value: 'ABC123',
+ integration_url: 'https://oncall-endpoint.example.com',
+ },
+ ]);
+ mockApi(server).getContactPointsList(receivers);
+ const { result } = renderHook(
+ () => useContactPointsWithStatus({ includePoliciesCount: false, receiverStatusPollingInterval: 0 }),
+ {
+ wrapper: ({ children }) => (
+
+
+ {children}
+
+
+ ),
+ }
+ );
+
+ await waitFor(() => {
+ expect(result.current.isLoading).toBe(false);
+ expect(result.current).toMatchSnapshot();
+ });
+ });
+ });
});
+
+const receivers = JSON.parse(JSON.stringify(alertmanagerMock)).alertmanager_config.receivers;
diff --git a/public/app/features/alerting/unified/components/contact-points/utils.ts b/public/app/features/alerting/unified/components/contact-points/utils.ts
index a07e3cc03dc..6af5766d473 100644
--- a/public/app/features/alerting/unified/components/contact-points/utils.ts
+++ b/public/app/features/alerting/unified/components/contact-points/utils.ts
@@ -137,12 +137,17 @@ export function enhanceContactPointsWithMetadata(
alertmanagerConfiguration && usedContactPointsByName && (usedContactPointsByName[contactPoint.name] ?? 0),
grafana_managed_receiver_configs: receivers.map((receiver, index) => {
const isOnCallReceiver = receiver.type === ReceiverTypes.OnCall;
+ // if we don't have alertmanagerConfiguration we can't get the metadata for oncall receivers,
+ // because we don't have the url, as we are not using the alertmanager configuration
+ // but the contact points returned by the read only permissions contact points endpoint (/api/v1/notifications/receivers)
return {
...receiver,
[RECEIVER_STATUS_KEY]: statusForReceiver?.integrations[index],
[RECEIVER_META_KEY]: getNotifierMetadata(notifiers, receiver),
// if OnCall plugin is installed, we'll add it to the receiver's plugin metadata
- [RECEIVER_PLUGIN_META_KEY]: isOnCallReceiver ? getOnCallMetadata(onCallIntegrations, receiver) : undefined,
+ [RECEIVER_PLUGIN_META_KEY]: isOnCallReceiver
+ ? getOnCallMetadata(onCallIntegrations, receiver, Boolean(alertmanagerConfiguration))
+ : undefined,
};
}),
};
diff --git a/public/app/features/alerting/unified/components/receivers/grafanaAppReceivers/useReceiversMetadata.ts b/public/app/features/alerting/unified/components/receivers/grafanaAppReceivers/useReceiversMetadata.ts
index ba3f923ea1a..dc803813b4d 100644
--- a/public/app/features/alerting/unified/components/receivers/grafanaAppReceivers/useReceiversMetadata.ts
+++ b/public/app/features/alerting/unified/components/receivers/grafanaAppReceivers/useReceiversMetadata.ts
@@ -16,15 +16,20 @@ export interface ReceiverPluginMetadata {
const onCallReceiverICon = GRAFANA_APP_RECEIVERS_SOURCE_IMAGE[SupportedPlugin.OnCall];
const onCallReceiverTitle = 'Grafana OnCall';
-const onCallReceiverMeta: ReceiverPluginMetadata = {
+export const onCallReceiverMeta: ReceiverPluginMetadata = {
title: onCallReceiverTitle,
icon: onCallReceiverICon,
};
export function getOnCallMetadata(
onCallIntegrations: OnCallIntegrationDTO[] | undefined | null,
- receiver: GrafanaManagedReceiverConfig
+ receiver: GrafanaManagedReceiverConfig,
+ hasAlertManagerConfigData = true
): ReceiverPluginMetadata {
+ if (!hasAlertManagerConfigData) {
+ return onCallReceiverMeta;
+ }
+
// oncall status is still loading
if (onCallIntegrations === undefined) {
return onCallReceiverMeta;
diff --git a/public/app/features/alerting/unified/mockApi.ts b/public/app/features/alerting/unified/mockApi.ts
index 98bef2dccec..7aabf1c3184 100644
--- a/public/app/features/alerting/unified/mockApi.ts
+++ b/public/app/features/alerting/unified/mockApi.ts
@@ -20,6 +20,7 @@ import {
AlertManagerCortexConfig,
AlertmanagerReceiver,
EmailConfig,
+ GrafanaManagedContactPoint,
GrafanaManagedReceiverConfig,
MatcherOperator,
Route,
@@ -218,6 +219,9 @@ export function mockApi(server: SetupServer) {
server.use(http.get(`api/plugins/${response.id}/settings`, () => HttpResponse.json(response)));
},
},
+ getContactPointsList: (response: GrafanaManagedContactPoint[]) => {
+ server.use(http.get(`/api/v1/notifications/receivers`, () => HttpResponse.json(response)));
+ },
oncall: {
getOnCallIntegrations: (response: OnCallIntegrationDTO[]) => {