mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 09:48:58 -04:00
Add alertDetailsUrl to the Uptime rule types (#158803)
Closes #158661 ## Summary This PR adds alertDetailsUrl to the Uptime rule types. |Alert|Recovered| |---|---| || It also provides the alertDetailsUrl in the action variables: <img width="920" alt="Screenshot 2023-05-31 at 14 54 06" src="5d3a8195
-ce8f-4ee9-a719-e4d553d63cff"> ## 🧪 How to test - Ensure that `server.publicBaseUrl` is configured in kibana.dev.yml - Create an uptime rule - Add an action to this rule and specify `context.alertDetailsUrl` variable there - After the alert is triggered, open the value of `alertDetailsUrl` in the browser - you should be able to see the related alert on the `Observability > Alerts` page --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
parent
3bc3a362ca
commit
af3f13eaf9
11 changed files with 193 additions and 50 deletions
|
@ -31,6 +31,7 @@ import { CloudSetup } from '@kbn/cloud-plugin/server';
|
|||
import { SpacesPluginStart } from '@kbn/spaces-plugin/server';
|
||||
import { FleetStartContract } from '@kbn/fleet-plugin/server';
|
||||
import { BfetchServerSetup } from '@kbn/bfetch-plugin/server';
|
||||
import { SharePluginSetup } from '@kbn/share-plugin/server';
|
||||
import { UptimeEsClient } from '../../lib';
|
||||
import type { TelemetryEventsSender } from '../../telemetry/sender';
|
||||
import type { UptimeRouter } from '../../../../types';
|
||||
|
@ -60,6 +61,7 @@ export interface UptimeServerSetup {
|
|||
savedObjectsClient?: SavedObjectsClientContract;
|
||||
authSavedObjectsClient?: SavedObjectsClientContract;
|
||||
encryptedSavedObjects: EncryptedSavedObjectsPluginStart;
|
||||
share: SharePluginSetup;
|
||||
stackVersion: string;
|
||||
logger: Logger;
|
||||
telemetry: TelemetryEventsSender;
|
||||
|
@ -81,6 +83,7 @@ export interface UptimeCorePluginsSetup {
|
|||
taskManager: TaskManagerSetupContract;
|
||||
telemetry: TelemetryPluginSetup;
|
||||
bfetch: BfetchServerSetup;
|
||||
share: SharePluginSetup;
|
||||
}
|
||||
|
||||
export interface UptimeCorePluginsStart {
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
|
||||
import { isRight } from 'fp-ts/lib/Either';
|
||||
import Mustache from 'mustache';
|
||||
import { AlertsLocatorParams, getAlertUrl } from '@kbn/observability-plugin/common';
|
||||
import { LocatorPublic } from '@kbn/share-plugin/common';
|
||||
import { legacyExperimentalFieldMap } from '@kbn/alerts-as-data-utils';
|
||||
import { IBasePath } from '@kbn/core/server';
|
||||
import { type IRuleTypeAlerts, RuleExecutorServices } from '@kbn/alerting-plugin/server';
|
||||
|
@ -80,29 +82,42 @@ export const getAlertDetailsUrl = (
|
|||
alertUuid: string | null
|
||||
) => addSpaceIdToPath(basePath.publicBaseUrl, spaceId, `/app/observability/alerts/${alertUuid}`);
|
||||
|
||||
export const setRecoveredAlertsContext = ({
|
||||
export const setRecoveredAlertsContext = async ({
|
||||
alertFactory,
|
||||
basePath,
|
||||
getAlertUuid,
|
||||
defaultStartedAt,
|
||||
getAlertStartedDate,
|
||||
spaceId,
|
||||
alertsLocator,
|
||||
getAlertUuid,
|
||||
}: {
|
||||
alertFactory: RuleExecutorServices['alertFactory'];
|
||||
basePath?: IBasePath;
|
||||
defaultStartedAt: string;
|
||||
getAlertStartedDate: (alertInstanceId: string) => string | null;
|
||||
basePath: IBasePath;
|
||||
spaceId: string;
|
||||
alertsLocator?: LocatorPublic<AlertsLocatorParams>;
|
||||
getAlertUuid?: (alertId: string) => string | null;
|
||||
spaceId?: string;
|
||||
}) => {
|
||||
const { getRecoveredAlerts } = alertFactory.done();
|
||||
for (const alert of getRecoveredAlerts()) {
|
||||
|
||||
for await (const alert of getRecoveredAlerts()) {
|
||||
const recoveredAlertId = alert.getId();
|
||||
const alertUuid = getAlertUuid?.(recoveredAlertId) || undefined;
|
||||
const alertUuid = getAlertUuid?.(recoveredAlertId) || null;
|
||||
const indexedStartedAt = getAlertStartedDate(recoveredAlertId) ?? defaultStartedAt;
|
||||
|
||||
const state = alert.getState();
|
||||
const alertUrl = await getAlertUrl(
|
||||
alertUuid,
|
||||
spaceId,
|
||||
indexedStartedAt,
|
||||
alertsLocator,
|
||||
basePath.publicBaseUrl
|
||||
);
|
||||
|
||||
alert.setContext({
|
||||
...state,
|
||||
...(basePath && spaceId && alertUuid
|
||||
? { [ALERT_DETAILS_URL]: getAlertDetailsUrl(basePath, spaceId, alertUuid) }
|
||||
: {}),
|
||||
[ALERT_DETAILS_URL]: alertUrl,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
|
|
@ -68,6 +68,7 @@ const mockPing: Partial<Ping> = {
|
|||
};
|
||||
|
||||
const mockRecoveredAlerts = mockAnomaliesResult.anomalies.map((result) => ({
|
||||
alertDetailsUrl: 'mockedAlertsLocator > getLocation',
|
||||
firstCheckedAt: 'date',
|
||||
firstTriggeredAt: undefined,
|
||||
lastCheckedAt: 'date',
|
||||
|
@ -108,6 +109,7 @@ const mockOptions = (
|
|||
state,
|
||||
services,
|
||||
setContext,
|
||||
startedAt: new Date(),
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -235,6 +237,7 @@ Response times as high as ${slowestResponse} ms have been detected from location
|
|||
Array [
|
||||
"xpack.uptime.alerts.actionGroups.durationAnomaly",
|
||||
Object {
|
||||
"alertDetailsUrl": "mockedAlertsLocator > getLocation",
|
||||
"anomalyStartTimestamp": "date",
|
||||
"bucketSpan": 900,
|
||||
"expectedResponseTime": "10 ms",
|
||||
|
@ -254,6 +257,7 @@ Response times as high as ${slowestResponse} ms have been detected from location
|
|||
Array [
|
||||
"xpack.uptime.alerts.actionGroups.durationAnomaly",
|
||||
Object {
|
||||
"alertDetailsUrl": "mockedAlertsLocator > getLocation",
|
||||
"anomalyStartTimestamp": "date",
|
||||
"bucketSpan": 900,
|
||||
"expectedResponseTime": "20 ms",
|
||||
|
|
|
@ -4,8 +4,9 @@
|
|||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
import { KibanaRequest, SavedObjectsClientContract } from '@kbn/core/server';
|
||||
|
||||
import moment from 'moment';
|
||||
import { KibanaRequest, SavedObjectsClientContract } from '@kbn/core/server';
|
||||
import { schema } from '@kbn/config-schema';
|
||||
import {
|
||||
ALERT_EVALUATION_VALUE,
|
||||
|
@ -14,6 +15,13 @@ import {
|
|||
} from '@kbn/rule-data-utils';
|
||||
import { ActionGroupIdsOf } from '@kbn/alerting-plugin/common';
|
||||
import { getSeverityType, type MlAnomaliesTableRecord } from '@kbn/ml-anomaly-utils';
|
||||
import {
|
||||
alertsLocatorID,
|
||||
AlertsLocatorParams,
|
||||
getAlertUrl,
|
||||
} from '@kbn/observability-plugin/common';
|
||||
import { LocatorPublic } from '@kbn/share-plugin/common';
|
||||
import { asyncForEach } from '@kbn/std';
|
||||
import { UptimeEsClient } from '../lib';
|
||||
import {
|
||||
updateState,
|
||||
|
@ -32,7 +40,12 @@ import { getMLJobId } from '../../../../common/lib';
|
|||
import { DurationAnomalyTranslations as CommonDurationAnomalyTranslations } from '../../../../common/rules/legacy_uptime/translations';
|
||||
import { getMonitorRouteFromMonitorId } from '../../../../common/utils/get_monitor_url';
|
||||
|
||||
import { ALERT_REASON_MSG, ACTION_VARIABLES, VIEW_IN_APP_URL } from './action_variables';
|
||||
import {
|
||||
ALERT_REASON_MSG,
|
||||
ACTION_VARIABLES,
|
||||
VIEW_IN_APP_URL,
|
||||
ALERT_DETAILS_URL,
|
||||
} from './action_variables';
|
||||
|
||||
export type ActionGroupIds = ActionGroupIdsOf<typeof DURATION_ANOMALY>;
|
||||
|
||||
|
@ -102,6 +115,7 @@ export const durationAnomalyAlertFactory: UptimeAlertTypeFactory<ActionGroupIds>
|
|||
],
|
||||
actionVariables: {
|
||||
context: [
|
||||
ACTION_VARIABLES[ALERT_DETAILS_URL],
|
||||
ACTION_VARIABLES[ALERT_REASON_MSG],
|
||||
ACTION_VARIABLES[VIEW_IN_APP_URL],
|
||||
...durationAnomalyTranslations.actionVariables,
|
||||
|
@ -118,6 +132,7 @@ export const durationAnomalyAlertFactory: UptimeAlertTypeFactory<ActionGroupIds>
|
|||
alertFactory,
|
||||
alertWithLifecycle,
|
||||
getAlertStartedDate,
|
||||
getAlertUuid,
|
||||
savedObjectsClient,
|
||||
scopedClusterClient,
|
||||
},
|
||||
|
@ -129,7 +144,9 @@ export const durationAnomalyAlertFactory: UptimeAlertTypeFactory<ActionGroupIds>
|
|||
savedObjectsClient,
|
||||
scopedClusterClient.asCurrentUser
|
||||
);
|
||||
const { basePath } = server;
|
||||
const { share, basePath } = server;
|
||||
const alertsLocator: LocatorPublic<AlertsLocatorParams> | undefined =
|
||||
share.url.locators.get(alertsLocatorID);
|
||||
|
||||
const { anomalies } =
|
||||
(await getAnomalies(plugins, savedObjectsClient, params, state.lastCheckedAt as string)) ??
|
||||
|
@ -145,7 +162,7 @@ export const durationAnomalyAlertFactory: UptimeAlertTypeFactory<ActionGroupIds>
|
|||
monitorId: params.monitorId,
|
||||
});
|
||||
|
||||
anomalies.forEach((anomaly, index) => {
|
||||
await asyncForEach(anomalies, async (anomaly, index) => {
|
||||
const summary = getAnomalySummary(anomaly, monitorInfo);
|
||||
const alertReasonMessage = generateAlertMessage(
|
||||
CommonDurationAnomalyTranslations.defaultActionMessage,
|
||||
|
@ -154,13 +171,14 @@ export const durationAnomalyAlertFactory: UptimeAlertTypeFactory<ActionGroupIds>
|
|||
|
||||
const alertId = DURATION_ANOMALY.id + index;
|
||||
const indexedStartedAt = getAlertStartedDate(alertId) ?? startedAt.toISOString();
|
||||
const alertUuid = getAlertUuid(alertId);
|
||||
const relativeViewInAppUrl = getMonitorRouteFromMonitorId({
|
||||
monitorId: alertId,
|
||||
dateRangeEnd: 'now',
|
||||
dateRangeStart: indexedStartedAt,
|
||||
});
|
||||
|
||||
const alertInstance = alertWithLifecycle({
|
||||
const alert = alertWithLifecycle({
|
||||
id: alertId,
|
||||
fields: {
|
||||
'monitor.id': params.monitorId,
|
||||
|
@ -173,11 +191,18 @@ export const durationAnomalyAlertFactory: UptimeAlertTypeFactory<ActionGroupIds>
|
|||
[ALERT_REASON]: alertReasonMessage,
|
||||
},
|
||||
});
|
||||
alertInstance.replaceState({
|
||||
alert.replaceState({
|
||||
...updateState(state, false),
|
||||
...summary,
|
||||
});
|
||||
alertInstance.scheduleActions(DURATION_ANOMALY.id, {
|
||||
alert.scheduleActions(DURATION_ANOMALY.id, {
|
||||
[ALERT_DETAILS_URL]: await getAlertUrl(
|
||||
alertUuid,
|
||||
spaceId,
|
||||
indexedStartedAt,
|
||||
alertsLocator,
|
||||
basePath.publicBaseUrl
|
||||
),
|
||||
[ALERT_REASON_MSG]: alertReasonMessage,
|
||||
[VIEW_IN_APP_URL]: getViewInAppUrl(basePath, spaceId, relativeViewInAppUrl),
|
||||
...summary,
|
||||
|
@ -185,7 +210,15 @@ export const durationAnomalyAlertFactory: UptimeAlertTypeFactory<ActionGroupIds>
|
|||
});
|
||||
}
|
||||
|
||||
setRecoveredAlertsContext({ alertFactory });
|
||||
await setRecoveredAlertsContext({
|
||||
alertFactory,
|
||||
alertsLocator,
|
||||
basePath,
|
||||
defaultStartedAt: startedAt.toISOString(),
|
||||
getAlertStartedDate,
|
||||
getAlertUuid,
|
||||
spaceId,
|
||||
});
|
||||
|
||||
return { state: updateState(state, foundAnomalies) };
|
||||
},
|
||||
|
|
|
@ -59,6 +59,7 @@ const mockMonitors = [
|
|||
|
||||
const mockRecoveredAlerts = [
|
||||
{
|
||||
alertDetailsUrl: 'mockedAlertsLocator > getLocation',
|
||||
currentTriggerStarted: '2022-04-25T14:36:31.511Z',
|
||||
firstCheckedAt: '2022-04-25T14:10:30.785Z',
|
||||
firstTriggeredAt: '2022-04-25T14:10:30.785Z',
|
||||
|
@ -81,6 +82,7 @@ const mockRecoveredAlerts = [
|
|||
duration: 315110000000,
|
||||
},
|
||||
{
|
||||
alertDetailsUrl: 'mockedAlertsLocator > getLocation',
|
||||
currentTriggerStarted: '2022-04-25T14:36:31.511Z',
|
||||
firstCheckedAt: '2022-04-25T14:10:30.785Z',
|
||||
firstTriggeredAt: '2022-04-25T14:10:30.785Z',
|
||||
|
@ -182,6 +184,7 @@ const mockOptions = (
|
|||
services,
|
||||
rule,
|
||||
setContext,
|
||||
startedAt: new Date(),
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -300,7 +303,7 @@ describe('status check alert', () => {
|
|||
Array [
|
||||
"xpack.uptime.alerts.actionGroups.monitorStatus",
|
||||
Object {
|
||||
"alertDetailsUrl": "http://localhost:5601/hfe/app/observability/alerts/mock-alert-uuid",
|
||||
"alertDetailsUrl": "mockedAlertsLocator > getLocation",
|
||||
"checkedAt": "July 6, 2020 9:14 PM",
|
||||
"latestErrorMessage": "error message 1",
|
||||
"monitorId": "first",
|
||||
|
@ -382,7 +385,7 @@ describe('status check alert', () => {
|
|||
Array [
|
||||
"xpack.uptime.alerts.actionGroups.monitorStatus",
|
||||
Object {
|
||||
"alertDetailsUrl": "http://localhost:5601/hfe/app/observability/alerts/mock-alert-uuid",
|
||||
"alertDetailsUrl": "mockedAlertsLocator > getLocation",
|
||||
"checkedAt": "July 6, 2020 9:14 PM",
|
||||
"latestErrorMessage": "error message 1",
|
||||
"monitorId": "first",
|
||||
|
@ -867,7 +870,7 @@ describe('status check alert', () => {
|
|||
Array [
|
||||
"xpack.uptime.alerts.actionGroups.monitorStatus",
|
||||
Object {
|
||||
"alertDetailsUrl": "http://localhost:5601/hfe/app/observability/alerts/mock-alert-uuid",
|
||||
"alertDetailsUrl": "mockedAlertsLocator > getLocation",
|
||||
"checkedAt": "July 6, 2020 9:14 PM",
|
||||
"latestErrorMessage": undefined,
|
||||
"monitorId": "foo",
|
||||
|
@ -884,7 +887,7 @@ describe('status check alert', () => {
|
|||
Array [
|
||||
"xpack.uptime.alerts.actionGroups.monitorStatus",
|
||||
Object {
|
||||
"alertDetailsUrl": "http://localhost:5601/hfe/app/observability/alerts/mock-alert-uuid",
|
||||
"alertDetailsUrl": "mockedAlertsLocator > getLocation",
|
||||
"checkedAt": "July 6, 2020 9:14 PM",
|
||||
"latestErrorMessage": undefined,
|
||||
"monitorId": "foo",
|
||||
|
@ -901,7 +904,7 @@ describe('status check alert', () => {
|
|||
Array [
|
||||
"xpack.uptime.alerts.actionGroups.monitorStatus",
|
||||
Object {
|
||||
"alertDetailsUrl": "http://localhost:5601/hfe/app/observability/alerts/mock-alert-uuid",
|
||||
"alertDetailsUrl": "mockedAlertsLocator > getLocation",
|
||||
"checkedAt": "July 6, 2020 9:14 PM",
|
||||
"latestErrorMessage": undefined,
|
||||
"monitorId": "unreliable",
|
||||
|
@ -918,7 +921,7 @@ describe('status check alert', () => {
|
|||
Array [
|
||||
"xpack.uptime.alerts.actionGroups.monitorStatus",
|
||||
Object {
|
||||
"alertDetailsUrl": "http://localhost:5601/hfe/app/observability/alerts/mock-alert-uuid",
|
||||
"alertDetailsUrl": "mockedAlertsLocator > getLocation",
|
||||
"checkedAt": "July 6, 2020 9:14 PM",
|
||||
"latestErrorMessage": undefined,
|
||||
"monitorId": "no-name",
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
* 2.0.
|
||||
*/
|
||||
import { min } from 'lodash';
|
||||
import moment from 'moment';
|
||||
|
||||
import datemath from '@kbn/datemath';
|
||||
import { schema } from '@kbn/config-schema';
|
||||
|
@ -13,8 +14,15 @@ import { JsonObject } from '@kbn/utility-types';
|
|||
import { fromKueryExpression, toElasticsearchQuery } from '@kbn/es-query';
|
||||
import { ALERT_REASON } from '@kbn/rule-data-utils';
|
||||
import { ActionGroupIdsOf } from '@kbn/alerting-plugin/common';
|
||||
import { formatDurationFromTimeUnitChar, TimeUnitChar } from '@kbn/observability-plugin/common';
|
||||
import moment from 'moment';
|
||||
import {
|
||||
alertsLocatorID,
|
||||
AlertsLocatorParams,
|
||||
formatDurationFromTimeUnitChar,
|
||||
getAlertUrl,
|
||||
TimeUnitChar,
|
||||
} from '@kbn/observability-plugin/common';
|
||||
import { LocatorPublic } from '@kbn/share-plugin/common';
|
||||
import { asyncForEach } from '@kbn/std';
|
||||
import { UptimeAlertTypeFactory } from './types';
|
||||
import {
|
||||
StatusCheckFilters,
|
||||
|
@ -27,7 +35,6 @@ import {
|
|||
updateState,
|
||||
getViewInAppUrl,
|
||||
setRecoveredAlertsContext,
|
||||
getAlertDetailsUrl,
|
||||
UptimeRuleTypeAlertDefinition,
|
||||
} from './common';
|
||||
import {
|
||||
|
@ -326,9 +333,7 @@ export const statusCheckAlertFactory: UptimeAlertTypeFactory<ActionGroupIds> = (
|
|||
actionVariables: {
|
||||
context: [
|
||||
ACTION_VARIABLES[MESSAGE],
|
||||
...(plugins.observability.getAlertDetailsConfig()?.uptime.enabled
|
||||
? [ACTION_VARIABLES[ALERT_DETAILS_URL]]
|
||||
: []),
|
||||
ACTION_VARIABLES[ALERT_DETAILS_URL],
|
||||
ACTION_VARIABLES[ALERT_REASON_MSG],
|
||||
ACTION_VARIABLES[VIEW_IN_APP_URL],
|
||||
...commonMonitorStateI18,
|
||||
|
@ -367,7 +372,9 @@ export const statusCheckAlertFactory: UptimeAlertTypeFactory<ActionGroupIds> = (
|
|||
timerangeCount,
|
||||
timerangeUnit,
|
||||
} = rawParams;
|
||||
const { basePath } = server;
|
||||
const { share, basePath } = server;
|
||||
const alertsLocator: LocatorPublic<AlertsLocatorParams> | undefined =
|
||||
share.url.locators.get(alertsLocatorID);
|
||||
const uptimeEsClient = new UptimeEsClient(
|
||||
savedObjectsClient,
|
||||
scopedClusterClient.asCurrentUser
|
||||
|
@ -402,7 +409,7 @@ export const statusCheckAlertFactory: UptimeAlertTypeFactory<ActionGroupIds> = (
|
|||
}
|
||||
|
||||
if (isAutoGenerated) {
|
||||
for (const monitorLoc of downMonitorsByLocation) {
|
||||
for await (const monitorLoc of downMonitorsByLocation) {
|
||||
const monitorInfo = monitorLoc.monitorInfo;
|
||||
const monitorStatusMessageParams = getMonitorDownStatusMessageParams(
|
||||
monitorInfo,
|
||||
|
@ -444,13 +451,27 @@ export const statusCheckAlertFactory: UptimeAlertTypeFactory<ActionGroupIds> = (
|
|||
});
|
||||
|
||||
alert.scheduleActions(MONITOR_STATUS.id, {
|
||||
[ALERT_DETAILS_URL]: getAlertDetailsUrl(basePath, spaceId, alertUuid),
|
||||
[ALERT_DETAILS_URL]: await getAlertUrl(
|
||||
alertUuid,
|
||||
spaceId,
|
||||
indexedStartedAt,
|
||||
alertsLocator,
|
||||
basePath.publicBaseUrl
|
||||
),
|
||||
[VIEW_IN_APP_URL]: getViewInAppUrl(basePath, spaceId, relativeViewInAppUrl),
|
||||
...context,
|
||||
});
|
||||
}
|
||||
|
||||
setRecoveredAlertsContext({ alertFactory, basePath, getAlertUuid, spaceId });
|
||||
await setRecoveredAlertsContext({
|
||||
alertFactory,
|
||||
alertsLocator,
|
||||
basePath,
|
||||
defaultStartedAt: startedAt.toISOString(),
|
||||
getAlertStartedDate,
|
||||
getAlertUuid,
|
||||
spaceId,
|
||||
});
|
||||
|
||||
return { state: updateState(state, downMonitorsByLocation.length > 0) };
|
||||
}
|
||||
|
@ -466,7 +487,7 @@ export const statusCheckAlertFactory: UptimeAlertTypeFactory<ActionGroupIds> = (
|
|||
|
||||
const mergedIdsByLoc = getUniqueIdsByLoc(downMonitorsByLocation, availabilityResults);
|
||||
|
||||
mergedIdsByLoc.forEach((monIdByLoc) => {
|
||||
await asyncForEach(mergedIdsByLoc, async (monIdByLoc) => {
|
||||
const availMonInfo = availabilityResults.find(
|
||||
({ monitorId, location }) => getMonIdByLoc(monitorId, location) === monIdByLoc
|
||||
);
|
||||
|
@ -524,13 +545,27 @@ export const statusCheckAlertFactory: UptimeAlertTypeFactory<ActionGroupIds> = (
|
|||
});
|
||||
|
||||
alert.scheduleActions(MONITOR_STATUS.id, {
|
||||
[ALERT_DETAILS_URL]: getAlertDetailsUrl(basePath, spaceId, alertUuid),
|
||||
[ALERT_DETAILS_URL]: await getAlertUrl(
|
||||
alertUuid,
|
||||
spaceId,
|
||||
indexedStartedAt,
|
||||
alertsLocator,
|
||||
basePath.publicBaseUrl
|
||||
),
|
||||
[VIEW_IN_APP_URL]: getViewInAppUrl(basePath, spaceId, relativeViewInAppUrl),
|
||||
...context,
|
||||
});
|
||||
});
|
||||
|
||||
setRecoveredAlertsContext({ alertFactory, basePath, getAlertUuid, spaceId });
|
||||
await setRecoveredAlertsContext({
|
||||
alertFactory,
|
||||
alertsLocator,
|
||||
basePath,
|
||||
defaultStartedAt: startedAt.toISOString(),
|
||||
getAlertStartedDate,
|
||||
getAlertUuid,
|
||||
spaceId,
|
||||
});
|
||||
|
||||
return { state: updateState(state, downMonitorsByLocation.length > 0) };
|
||||
},
|
||||
|
|
|
@ -9,6 +9,9 @@ import { IBasePath, Logger } from '@kbn/core/server';
|
|||
import type { IRuleDataClient } from '@kbn/rule-registry-plugin/server';
|
||||
import { ruleRegistryMocks } from '@kbn/rule-registry-plugin/server/mocks';
|
||||
import { alertsMock } from '@kbn/alerting-plugin/server/mocks';
|
||||
import type { AlertsLocatorParams } from '@kbn/observability-plugin/common';
|
||||
import { LocatorPublic } from '@kbn/share-plugin/common';
|
||||
import { SharePluginSetup } from '@kbn/share-plugin/server';
|
||||
import { UMServerLibs } from '../../lib';
|
||||
import { UptimeCorePluginsSetup, UptimeServerSetup } from '../../adapters';
|
||||
import type { UptimeRouter } from '../../../../types';
|
||||
|
@ -33,9 +36,27 @@ export const bootstrapDependencies = (
|
|||
publicBaseUrl: 'http://localhost:5601/hfe',
|
||||
serverBasePath: '/hfe',
|
||||
} as IBasePath;
|
||||
|
||||
const alertsLocator = {
|
||||
getLocation: jest.fn().mockImplementation(() => ({
|
||||
path: 'mockedAlertsLocator > getLocation',
|
||||
})),
|
||||
} as any as LocatorPublic<AlertsLocatorParams>;
|
||||
const share = {
|
||||
url: {
|
||||
locators: {
|
||||
get: () => alertsLocator,
|
||||
},
|
||||
},
|
||||
} as any as SharePluginSetup;
|
||||
// these server/libs parameters don't have any functionality, which is fine
|
||||
// because we aren't testing them here
|
||||
const server = { router, config: {}, basePath } as UptimeServerSetup;
|
||||
const server = {
|
||||
router,
|
||||
config: {},
|
||||
basePath,
|
||||
share,
|
||||
} as UptimeServerSetup;
|
||||
const plugins: UptimeCorePluginsSetup = customPlugins as any;
|
||||
const libs: UMServerLibs = { requests: {} } as UMServerLibs;
|
||||
libs.requests = { ...libs.requests, ...customRequests };
|
||||
|
|
|
@ -60,12 +60,14 @@ const mockCertResult: CertResult = {
|
|||
|
||||
const mockRecoveredAlerts = [
|
||||
{
|
||||
alertDetailsUrl: 'mockedAlertsLocator > getLocation',
|
||||
commonName: mockCertResult.certs[0].common_name ?? '',
|
||||
issuer: mockCertResult.certs[0].issuer ?? '',
|
||||
summary: 'sample summary',
|
||||
status: 'expired',
|
||||
},
|
||||
{
|
||||
alertDetailsUrl: 'mockedAlertsLocator > getLocation',
|
||||
commonName: mockCertResult.certs[1].common_name ?? '',
|
||||
issuer: mockCertResult.certs[1].issuer ?? '',
|
||||
summary: 'sample summary 2',
|
||||
|
@ -84,6 +86,7 @@ const mockOptions = (state = {}): any => {
|
|||
state,
|
||||
services,
|
||||
setContext,
|
||||
startedAt: new Date(),
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
@ -4,10 +4,18 @@
|
|||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import moment from 'moment';
|
||||
import { schema } from '@kbn/config-schema';
|
||||
import { ALERT_REASON, ALERT_UUID } from '@kbn/rule-data-utils';
|
||||
import { ActionGroupIdsOf } from '@kbn/alerting-plugin/common';
|
||||
import { schema } from '@kbn/config-schema';
|
||||
import {
|
||||
alertsLocatorID,
|
||||
AlertsLocatorParams,
|
||||
getAlertUrl,
|
||||
} from '@kbn/observability-plugin/common';
|
||||
import { LocatorPublic } from '@kbn/share-plugin/common';
|
||||
import { ALERT_REASON, ALERT_UUID } from '@kbn/rule-data-utils';
|
||||
import { asyncForEach } from '@kbn/std';
|
||||
import { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/types';
|
||||
import { formatFilterString } from './status_check';
|
||||
import { UptimeAlertTypeFactory } from './types';
|
||||
|
@ -15,7 +23,6 @@ import {
|
|||
updateState,
|
||||
generateAlertMessage,
|
||||
setRecoveredAlertsContext,
|
||||
getAlertDetailsUrl,
|
||||
UptimeRuleTypeAlertDefinition,
|
||||
} from './common';
|
||||
import { CLIENT_ALERT_TYPES, TLS } from '../../../../common/constants/uptime_alerts';
|
||||
|
@ -128,9 +135,7 @@ export const tlsAlertFactory: UptimeAlertTypeFactory<ActionGroupIds> = (
|
|||
context: [
|
||||
...tlsTranslations.actionVariables,
|
||||
...commonStateTranslations,
|
||||
...(plugins.observability.getAlertDetailsConfig()?.uptime.enabled
|
||||
? [ACTION_VARIABLES[ALERT_DETAILS_URL]]
|
||||
: []),
|
||||
ACTION_VARIABLES[ALERT_DETAILS_URL],
|
||||
],
|
||||
state: [...tlsTranslations.actionVariables, ...commonStateTranslations],
|
||||
},
|
||||
|
@ -142,14 +147,18 @@ export const tlsAlertFactory: UptimeAlertTypeFactory<ActionGroupIds> = (
|
|||
services: {
|
||||
alertFactory,
|
||||
alertWithLifecycle,
|
||||
getAlertStartedDate,
|
||||
getAlertUuid,
|
||||
savedObjectsClient,
|
||||
scopedClusterClient,
|
||||
},
|
||||
spaceId,
|
||||
startedAt,
|
||||
state,
|
||||
}) {
|
||||
const { basePath } = _server;
|
||||
const { share, basePath } = _server;
|
||||
const alertsLocator: LocatorPublic<AlertsLocatorParams> | undefined =
|
||||
share.url.locators.get(alertsLocatorID);
|
||||
const dynamicSettings = await savedObjectsAdapter.getUptimeDynamicSettings(savedObjectsClient);
|
||||
|
||||
const uptimeEsClient = new UptimeEsClient(
|
||||
|
@ -187,7 +196,7 @@ export const tlsAlertFactory: UptimeAlertTypeFactory<ActionGroupIds> = (
|
|||
const foundCerts = total > 0;
|
||||
|
||||
if (foundCerts) {
|
||||
certs.forEach((cert) => {
|
||||
await asyncForEach(certs, async (cert) => {
|
||||
const absoluteExpirationThreshold = moment().add(certExpirationThreshold, 'd').valueOf();
|
||||
const absoluteAgeThreshold = moment().subtract(certAgeThreshold, 'd').valueOf();
|
||||
const summary = getCertSummary(cert, absoluteExpirationThreshold, absoluteAgeThreshold);
|
||||
|
@ -196,11 +205,12 @@ export const tlsAlertFactory: UptimeAlertTypeFactory<ActionGroupIds> = (
|
|||
return;
|
||||
}
|
||||
|
||||
const id = `${cert.common_name}-${cert.issuer?.replace(/\s/g, '_')}-${cert.sha256}`;
|
||||
const alertUuid = getAlertUuid(id);
|
||||
const alertId = `${cert.common_name}-${cert.issuer?.replace(/\s/g, '_')}-${cert.sha256}`;
|
||||
const alertUuid = getAlertUuid(alertId);
|
||||
const indexedStartedAt = getAlertStartedDate(alertId) ?? startedAt.toISOString();
|
||||
|
||||
const alertInstance = alertWithLifecycle({
|
||||
id,
|
||||
id: alertId,
|
||||
fields: {
|
||||
'tls.server.x509.subject.common_name': cert.common_name,
|
||||
'tls.server.x509.issuer.common_name': cert.issuer,
|
||||
|
@ -218,13 +228,27 @@ export const tlsAlertFactory: UptimeAlertTypeFactory<ActionGroupIds> = (
|
|||
});
|
||||
|
||||
alertInstance.scheduleActions(TLS.id, {
|
||||
alertDetailsUrl: getAlertDetailsUrl(basePath, spaceId, alertUuid),
|
||||
[ALERT_DETAILS_URL]: await getAlertUrl(
|
||||
alertUuid,
|
||||
spaceId,
|
||||
indexedStartedAt,
|
||||
alertsLocator,
|
||||
basePath.publicBaseUrl
|
||||
),
|
||||
...summary,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
setRecoveredAlertsContext({ alertFactory, basePath, getAlertUuid, spaceId });
|
||||
await setRecoveredAlertsContext({
|
||||
alertFactory,
|
||||
alertsLocator,
|
||||
basePath,
|
||||
defaultStartedAt: startedAt.toISOString(),
|
||||
getAlertStartedDate,
|
||||
getAlertUuid,
|
||||
spaceId,
|
||||
});
|
||||
|
||||
return { state: updateState(state, foundCerts) };
|
||||
},
|
||||
|
|
|
@ -82,6 +82,7 @@ export class Plugin implements PluginType {
|
|||
logger: this.logger,
|
||||
telemetry: this.telemetryEventsSender,
|
||||
isDev: this.initContext.env.mode.dev,
|
||||
share: plugins.share,
|
||||
} as UptimeServerSetup;
|
||||
|
||||
this.syntheticsService = new SyntheticsService(this.server);
|
||||
|
|
|
@ -80,6 +80,7 @@
|
|||
"@kbn/observability-shared-plugin",
|
||||
"@kbn/ml-error-utils",
|
||||
"@kbn/ml-anomaly-utils",
|
||||
"@kbn/std",
|
||||
],
|
||||
"exclude": [
|
||||
"target/**/*",
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue