Add alertDetailsUrl to the Uptime rule types (#158803)

Closes #158661

## Summary

This PR adds alertDetailsUrl to the Uptime rule types.

|Alert|Recovered|
|---|---|

|![image](2605d32b-e234-49dc-84c8-6b573404dcaa)|

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:
Maryam Saeidi 2023-06-09 10:05:15 +02:00 committed by GitHub
parent 3bc3a362ca
commit af3f13eaf9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 193 additions and 50 deletions

View file

@ -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 {

View file

@ -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,
});
}
};

View file

@ -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",

View file

@ -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) };
},

View file

@ -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",

View file

@ -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) };
},

View file

@ -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 };

View file

@ -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(),
};
};

View file

@ -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) };
},

View file

@ -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);

View file

@ -80,6 +80,7 @@
"@kbn/observability-shared-plugin",
"@kbn/ml-error-utils",
"@kbn/ml-anomaly-utils",
"@kbn/std",
],
"exclude": [
"target/**/*",