diff --git a/x-pack/plugins/observability_solution/synthetics/common/constants/settings_defaults.ts b/x-pack/plugins/observability_solution/synthetics/common/constants/settings_defaults.ts index aa32449713be8..fc382175e182f 100644 --- a/x-pack/plugins/observability_solution/synthetics/common/constants/settings_defaults.ts +++ b/x-pack/plugins/observability_solution/synthetics/common/constants/settings_defaults.ts @@ -16,4 +16,6 @@ export const DYNAMIC_SETTINGS_DEFAULTS: DynamicSettings = { cc: [], bcc: [], }, + defaultTLSRuleEnabled: true, + defaultStatusRuleEnabled: true, }; diff --git a/x-pack/plugins/observability_solution/synthetics/common/runtime_types/dynamic_settings.ts b/x-pack/plugins/observability_solution/synthetics/common/runtime_types/dynamic_settings.ts index 8dc2405085bb5..e222ee5896908 100644 --- a/x-pack/plugins/observability_solution/synthetics/common/runtime_types/dynamic_settings.ts +++ b/x-pack/plugins/observability_solution/synthetics/common/runtime_types/dynamic_settings.ts @@ -34,6 +34,8 @@ export const DynamicSettingsCodec = t.intersection([ }), t.partial({ defaultEmail: DefaultEmailCodec, + defaultTLSRuleEnabled: t.boolean, + defaultStatusRuleEnabled: t.boolean, }), ]); diff --git a/x-pack/plugins/observability_solution/synthetics/common/runtime_types/monitor_management/synthetics_overview_status.ts b/x-pack/plugins/observability_solution/synthetics/common/runtime_types/monitor_management/synthetics_overview_status.ts index 54238d01a915d..7e8a1257e6428 100644 --- a/x-pack/plugins/observability_solution/synthetics/common/runtime_types/monitor_management/synthetics_overview_status.ts +++ b/x-pack/plugins/observability_solution/synthetics/common/runtime_types/monitor_management/synthetics_overview_status.ts @@ -44,7 +44,7 @@ export const OverviewPendingStatusMetaDataCodec = t.intersection([ monitorQueryId: t.string, configId: t.string, status: t.string, - location: t.string, + locationId: t.string, }), t.partial({ timestamp: t.string, diff --git a/x-pack/plugins/observability_solution/synthetics/common/types/default_alerts.ts b/x-pack/plugins/observability_solution/synthetics/common/types/default_alerts.ts new file mode 100644 index 0000000000000..2c02838842ad1 --- /dev/null +++ b/x-pack/plugins/observability_solution/synthetics/common/types/default_alerts.ts @@ -0,0 +1,20 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { SanitizedRule, SanitizedRuleAction, RuleSystemAction } from '@kbn/alerting-plugin/common'; +import { SYNTHETICS_STATUS_RULE, SYNTHETICS_TLS_RULE } from '../constants/synthetics_alerts'; + +export type DefaultRuleType = typeof SYNTHETICS_STATUS_RULE | typeof SYNTHETICS_TLS_RULE; +type SYNTHETICS_DEFAULT_RULE = Omit, 'systemActions' | 'actions'> & { + actions: Array; + ruleTypeId: SanitizedRule['alertTypeId']; +}; + +export interface DEFAULT_ALERT_RESPONSE { + statusRule: SYNTHETICS_DEFAULT_RULE | null; + tlsRule: SYNTHETICS_DEFAULT_RULE | null; +} diff --git a/x-pack/plugins/observability_solution/synthetics/common/types/index.ts b/x-pack/plugins/observability_solution/synthetics/common/types/index.ts index 2a70803a43211..be369427c47e7 100644 --- a/x-pack/plugins/observability_solution/synthetics/common/types/index.ts +++ b/x-pack/plugins/observability_solution/synthetics/common/types/index.ts @@ -7,3 +7,4 @@ export * from './synthetics_monitor'; export * from './monitor_validation'; +export * from './default_alerts'; diff --git a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/alerts/hooks/use_synthetics_alert.ts b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/alerts/hooks/use_synthetics_rules.ts similarity index 91% rename from x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/alerts/hooks/use_synthetics_alert.ts rename to x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/alerts/hooks/use_synthetics_rules.ts index 2f3673287deb1..6e03b69b5d60c 100644 --- a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/alerts/hooks/use_synthetics_alert.ts +++ b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/alerts/hooks/use_synthetics_rules.ts @@ -25,7 +25,7 @@ import { } from '../../../state'; import { ClientPluginsStart } from '../../../../../plugin'; -export const useSyntheticsAlert = (isOpen: boolean) => { +export const useSyntheticsRules = (isOpen: boolean) => { const dispatch = useDispatch(); const defaultRules = useSelector(selectSyntheticsAlerts); @@ -64,14 +64,15 @@ export const useSyntheticsAlert = (isOpen: boolean) => { const { triggersActionsUi } = useKibana().services; const EditAlertFlyout = useMemo(() => { - if (!defaultRules) { + const initialRule = + alertFlyoutVisible === SYNTHETICS_TLS_RULE ? defaultRules?.tlsRule : defaultRules?.statusRule; + if (!initialRule) { return null; } return triggersActionsUi.getEditRuleFlyout({ onClose: () => dispatch(setAlertFlyoutVisible(null)), hideInterval: true, - initialRule: - alertFlyoutVisible === SYNTHETICS_TLS_RULE ? defaultRules.tlsRule : defaultRules.statusRule, + initialRule, }); }, [defaultRules, dispatch, triggersActionsUi, alertFlyoutVisible]); diff --git a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/alerts/toggle_alert_flyout_button.tsx b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/alerts/toggle_alert_flyout_button.tsx index 8bc04d8eb9f9d..0a8e5abf37f1a 100644 --- a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/alerts/toggle_alert_flyout_button.tsx +++ b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/alerts/toggle_alert_flyout_button.tsx @@ -26,7 +26,7 @@ import { import { ManageRulesLink } from '../common/links/manage_rules_link'; import { ClientPluginsStart } from '../../../../plugin'; import { ToggleFlyoutTranslations } from './hooks/translations'; -import { useSyntheticsAlert } from './hooks/use_synthetics_alert'; +import { useSyntheticsRules } from './hooks/use_synthetics_rules'; import { selectAlertFlyoutVisibility, selectMonitorListState, @@ -40,7 +40,7 @@ export const ToggleAlertFlyoutButton = () => { const { application } = useKibana().services; const hasUptimeWrite = application?.capabilities.uptime?.save ?? false; - const { EditAlertFlyout, loading } = useSyntheticsAlert(isOpen); + const { EditAlertFlyout, loading } = useSyntheticsRules(isOpen); const { loaded, data: monitors } = useSelector(selectMonitorListState); diff --git a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/settings/alerting_defaults/alert_defaults_form.tsx b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/settings/alerting_defaults/alert_defaults_form.tsx index f87f1267efcc3..463e7604815a1 100644 --- a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/settings/alerting_defaults/alert_defaults_form.tsx +++ b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/settings/alerting_defaults/alert_defaults_form.tsx @@ -15,6 +15,7 @@ import { EuiFlexItem, EuiForm, EuiSpacer, + EuiSwitch, } from '@elastic/eui'; import { useDispatch, useSelector } from 'react-redux'; import { useKibana } from '@kbn/kibana-react-plugin/public'; @@ -80,6 +81,50 @@ export const AlertDefaultsForm = () => { return ( + + + + + } + description={ + + } + > + + { + setFormFields({ + ...formFields, + defaultStatusRuleEnabled: !(formFields.defaultStatusRuleEnabled ?? true), + }); + }} + /> + + { + setFormFields({ + ...formFields, + defaultTLSRuleEnabled: !(formFields.defaultTLSRuleEnabled ?? true), + }); + }} + /> + { [`test-monitor-4-${location1.id}`]: { configId: 'test-monitor-4', monitorQueryId: 'test-monitor-4', - location: location1.id, + locationId: location1.id, }, }, }, diff --git a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/alert_rules/actions.ts b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/alert_rules/actions.ts index 413c94c0fbd7b..e004b5a34396a 100644 --- a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/alert_rules/actions.ts +++ b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/alert_rules/actions.ts @@ -5,24 +5,21 @@ * 2.0. */ -import { Rule } from '@kbn/triggers-actions-ui-plugin/public'; +import { DEFAULT_ALERT_RESPONSE } from '../../../../../common/types/default_alerts'; import { createAsyncAction } from '../utils/actions'; -export const getDefaultAlertingAction = createAsyncAction< - void, - { statusRule: Rule; tlsRule: Rule } ->('getDefaultAlertingAction'); +export const getDefaultAlertingAction = createAsyncAction( + 'getDefaultAlertingAction' +); -export const enableDefaultAlertingAction = createAsyncAction< - void, - { statusRule: Rule; tlsRule: Rule } ->('enableDefaultAlertingAction'); +export const enableDefaultAlertingAction = createAsyncAction( + 'enableDefaultAlertingAction' +); -export const enableDefaultAlertingSilentlyAction = createAsyncAction< - void, - { statusRule: Rule; tlsRule: Rule } ->('enableDefaultAlertingSilentlyAction'); +export const enableDefaultAlertingSilentlyAction = createAsyncAction( + 'enableDefaultAlertingSilentlyAction' +); -export const updateDefaultAlertingAction = createAsyncAction( +export const updateDefaultAlertingAction = createAsyncAction( 'updateDefaultAlertingAction' ); diff --git a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/alert_rules/api.ts b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/alert_rules/api.ts index ee42d9e1b2508..909976e1f2848 100644 --- a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/alert_rules/api.ts +++ b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/alert_rules/api.ts @@ -5,18 +5,18 @@ * 2.0. */ -import { Rule } from '@kbn/triggers-actions-ui-plugin/public'; import { SYNTHETICS_API_URLS } from '../../../../../common/constants'; +import { DEFAULT_ALERT_RESPONSE } from '../../../../../common/types/default_alerts'; import { apiService } from '../../../../utils/api_service'; -export async function getDefaultAlertingAPI(): Promise<{ statusRule: Rule; tlsRule: Rule }> { +export async function getDefaultAlertingAPI(): Promise { return apiService.get(SYNTHETICS_API_URLS.ENABLE_DEFAULT_ALERTING); } -export async function enableDefaultAlertingAPI(): Promise<{ statusRule: Rule; tlsRule: Rule }> { +export async function enableDefaultAlertingAPI(): Promise { return apiService.post(SYNTHETICS_API_URLS.ENABLE_DEFAULT_ALERTING); } -export async function updateDefaultAlertingAPI(): Promise { +export async function updateDefaultAlertingAPI(): Promise { return apiService.put(SYNTHETICS_API_URLS.ENABLE_DEFAULT_ALERTING); } diff --git a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/alert_rules/index.ts b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/alert_rules/index.ts index 4b8c6688adc1e..7dc44fa1dbf0f 100644 --- a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/alert_rules/index.ts +++ b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/alert_rules/index.ts @@ -6,7 +6,7 @@ */ import { createReducer } from '@reduxjs/toolkit'; -import { Rule } from '@kbn/triggers-actions-ui-plugin/public'; +import { DEFAULT_ALERT_RESPONSE } from '../../../../../common/types/default_alerts'; import { IHttpSerializedFetchError } from '..'; import { enableDefaultAlertingAction, @@ -16,7 +16,7 @@ import { } from './actions'; export interface DefaultAlertingState { - data?: { statusRule: Rule; tlsRule: Rule }; + data?: DEFAULT_ALERT_RESPONSE; success: boolean | null; loading: boolean; error: IHttpSerializedFetchError | null; diff --git a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/settings/api.ts b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/settings/api.ts index 7949cd5120f79..81925415ed3b3 100644 --- a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/settings/api.ts +++ b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/settings/api.ts @@ -36,9 +36,17 @@ export const getDynamicSettings = async (): Promise => { export const setDynamicSettings = async ({ settings, }: SaveApiRequest): Promise => { + const newSettings: DynamicSettings = { + certAgeThreshold: settings.certAgeThreshold, + certExpirationThreshold: settings.certExpirationThreshold, + defaultConnectors: settings.defaultConnectors, + defaultEmail: settings.defaultEmail, + defaultTLSRuleEnabled: settings.defaultTLSRuleEnabled, + defaultStatusRuleEnabled: settings.defaultStatusRuleEnabled, + }; return await apiService.put( SYNTHETICS_API_URLS.DYNAMIC_SETTINGS, - settings, + newSettings, DynamicSettingsSaveCodec, { version: '2023-10-31', diff --git a/x-pack/plugins/observability_solution/synthetics/server/alert_rules/common.test.ts b/x-pack/plugins/observability_solution/synthetics/server/alert_rules/common.test.ts index b0ce8c17c6d0c..47221ff7020d5 100644 --- a/x-pack/plugins/observability_solution/synthetics/server/alert_rules/common.test.ts +++ b/x-pack/plugins/observability_solution/synthetics/server/alert_rules/common.test.ts @@ -274,6 +274,7 @@ describe('setRecoveredAlertsContext', () => { alertDetailsUrl: 'https://localhost:5601/app/observability/alerts/alert-id', monitorName: 'test-monitor', recoveryReason: 'the monitor has been deleted', + 'kibana.alert.reason': 'the monitor has been deleted', recoveryStatus: 'has been deleted', monitorUrl: '(unavailable)', monitorUrlLabel: 'URL', @@ -350,6 +351,7 @@ describe('setRecoveredAlertsContext', () => { alertDetailsUrl: 'https://localhost:5601/app/observability/alerts/alert-id', monitorName: 'test-monitor', recoveryReason: 'this location has been removed from the monitor', + 'kibana.alert.reason': 'this location has been removed from the monitor', recoveryStatus: 'has recovered', stateId: '123456', status: 'recovered', @@ -421,6 +423,8 @@ describe('setRecoveredAlertsContext', () => { status: 'up', recoveryReason: 'the monitor is now up again. It ran successfully at Feb 26, 2023 @ 00:00:00.000', + 'kibana.alert.reason': + 'the monitor is now up again. It ran successfully at Feb 26, 2023 @ 00:00:00.000', recoveryStatus: 'is now up', locationId: location, checkedAt: 'Feb 26, 2023 @ 00:00:00.000', diff --git a/x-pack/plugins/observability_solution/synthetics/server/alert_rules/common.ts b/x-pack/plugins/observability_solution/synthetics/server/alert_rules/common.ts index 25d2265ff3ff6..549bbcff4cdfe 100644 --- a/x-pack/plugins/observability_solution/synthetics/server/alert_rules/common.ts +++ b/x-pack/plugins/observability_solution/synthetics/server/alert_rules/common.ts @@ -19,6 +19,7 @@ import { i18n } from '@kbn/i18n'; import { fromKueryExpression, toElasticsearchQuery } from '@kbn/es-query'; import { legacyExperimentalFieldMap, ObservabilityUptimeAlert } from '@kbn/alerts-as-data-utils'; import { PublicAlertsClient } from '@kbn/alerting-plugin/server/alerts_client/types'; +import { ALERT_REASON } from '@kbn/rule-data-utils'; import { syntheticsRuleFieldMap } from '../../common/rules/synthetics_rule_field_map'; import { combineFiltersAndUserSearch, stringifyKueries } from '../../common/lib'; import { @@ -298,6 +299,7 @@ export const setRecoveredAlertsContext = ({ linkMessage, ...(isUp ? { status: 'up' } : {}), ...(recoveryReason ? { [RECOVERY_REASON]: recoveryReason } : {}), + ...(recoveryReason ? { [ALERT_REASON]: recoveryReason } : {}), ...(basePath && spaceId && alertUuid ? { [ALERT_DETAILS_URL]: getAlertDetailsUrl(basePath, spaceId, alertUuid) } : {}), diff --git a/x-pack/plugins/observability_solution/synthetics/server/alert_rules/status_rule/status_rule_executor.ts b/x-pack/plugins/observability_solution/synthetics/server/alert_rules/status_rule/status_rule_executor.ts index 36ad8783f44ad..4d5ab04d6c10f 100644 --- a/x-pack/plugins/observability_solution/synthetics/server/alert_rules/status_rule/status_rule_executor.ts +++ b/x-pack/plugins/observability_solution/synthetics/server/alert_rules/status_rule/status_rule_executor.ts @@ -79,7 +79,7 @@ export class StatusRuleExecutor { monitorLocationMap, projectMonitorsCount, monitorQueryIdToConfigIdMap, - } = processMonitors(this.monitors, this.server, this.soClient, this.syntheticsMonitorClient); + } = processMonitors(this.monitors); return { enabledMonitorQueryIds, diff --git a/x-pack/plugins/observability_solution/synthetics/server/alert_rules/tls_rule/tls_rule_executor.ts b/x-pack/plugins/observability_solution/synthetics/server/alert_rules/tls_rule/tls_rule_executor.ts index 10c4ae24a1bf2..4c5766b34738f 100644 --- a/x-pack/plugins/observability_solution/synthetics/server/alert_rules/tls_rule/tls_rule_executor.ts +++ b/x-pack/plugins/observability_solution/synthetics/server/alert_rules/tls_rule/tls_rule_executor.ts @@ -74,7 +74,7 @@ export class TLSRuleExecutor { monitorLocationMap, projectMonitorsCount, monitorQueryIdToConfigIdMap, - } = processMonitors(this.monitors, this.server, this.soClient, this.syntheticsMonitorClient); + } = processMonitors(this.monitors); return { enabledMonitorQueryIds, diff --git a/x-pack/plugins/observability_solution/synthetics/server/queries/query_monitor_status.ts b/x-pack/plugins/observability_solution/synthetics/server/queries/query_monitor_status.ts index 4e2873ce77218..2bed9fdb5f643 100644 --- a/x-pack/plugins/observability_solution/synthetics/server/queries/query_monitor_status.ts +++ b/x-pack/plugins/observability_solution/synthetics/server/queries/query_monitor_status.ts @@ -201,7 +201,7 @@ export async function queryMonitorStatus( configId: `${monitorQueryIdToConfigIdMap[queryId]}`, monitorQueryId: queryId, status: 'unknown', - location: loc, + locationId: loc, }; }); } diff --git a/x-pack/plugins/observability_solution/synthetics/server/routes/certs/get_certificates.ts b/x-pack/plugins/observability_solution/synthetics/server/routes/certs/get_certificates.ts index b6b6ad5aec85d..5d6fc1ab61ff3 100644 --- a/x-pack/plugins/observability_solution/synthetics/server/routes/certs/get_certificates.ts +++ b/x-pack/plugins/observability_solution/synthetics/server/routes/certs/get_certificates.ts @@ -34,13 +34,7 @@ export const getSyntheticsCertsRoute: SyntheticsRestApiRouteFactory< to: schema.maybe(schema.string()), }), }, - handler: async ({ - request, - syntheticsEsClient, - savedObjectsClient, - server, - syntheticsMonitorClient, - }) => { + handler: async ({ request, syntheticsEsClient, savedObjectsClient }) => { const queryParams = request.query; const monitors = await getAllMonitors({ @@ -57,12 +51,7 @@ export const getSyntheticsCertsRoute: SyntheticsRestApiRouteFactory< }; } - const { enabledMonitorQueryIds } = processMonitors( - monitors, - server, - savedObjectsClient, - syntheticsMonitorClient - ); + const { enabledMonitorQueryIds } = processMonitors(monitors); const data = await getSyntheticsCerts({ ...queryParams, diff --git a/x-pack/plugins/observability_solution/synthetics/server/routes/default_alerts/default_alert_service.ts b/x-pack/plugins/observability_solution/synthetics/server/routes/default_alerts/default_alert_service.ts index 38606b4d2865f..eb94f095be177 100644 --- a/x-pack/plugins/observability_solution/synthetics/server/routes/default_alerts/default_alert_service.ts +++ b/x-pack/plugins/observability_solution/synthetics/server/routes/default_alerts/default_alert_service.ts @@ -7,6 +7,7 @@ import { SavedObjectsClientContract } from '@kbn/core-saved-objects-api-server'; import { FindActionResult } from '@kbn/actions-plugin/server'; +import { DynamicSettingsAttributes } from '../../runtime_types/settings'; import { savedObjectsAdapter } from '../../saved_objects'; import { populateAlertActions } from '../../../common/rules/alert_actions'; import { @@ -19,12 +20,12 @@ import { SYNTHETICS_STATUS_RULE, SYNTHETICS_TLS_RULE, } from '../../../common/constants/synthetics_alerts'; - -type DefaultRuleType = typeof SYNTHETICS_STATUS_RULE | typeof SYNTHETICS_TLS_RULE; +import { DefaultRuleType } from '../../../common/types/default_alerts'; export class DefaultAlertService { context: UptimeRequestHandlerContext; soClient: SavedObjectsClientContract; server: SyntheticsServerSetup; + settings?: DynamicSettingsAttributes; constructor( context: UptimeRequestHandlerContext, @@ -36,7 +37,16 @@ export class DefaultAlertService { this.soClient = soClient; } + async getSettings() { + if (!this.settings) { + this.settings = await savedObjectsAdapter.getSyntheticsDynamicSettings(this.soClient); + } + return this.settings; + } + async setupDefaultAlerts() { + this.settings = await this.getSettings(); + const [statusRule, tlsRule] = await Promise.allSettled([ this.setupStatusRule(), this.setupTlsRule(), @@ -50,12 +60,15 @@ export class DefaultAlertService { } return { - statusRule: statusRule.status === 'fulfilled' ? statusRule.value : null, - tlsRule: tlsRule.status === 'fulfilled' ? tlsRule.value : null, + statusRule: statusRule.status === 'fulfilled' && statusRule.value ? statusRule.value : null, + tlsRule: tlsRule.status === 'fulfilled' && tlsRule.value ? tlsRule.value : null, }; } setupStatusRule() { + if (this.settings?.defaultStatusRuleEnabled === false) { + return; + } return this.createDefaultAlertIfNotExist( SYNTHETICS_STATUS_RULE, `Synthetics status internal rule`, @@ -64,6 +77,9 @@ export class DefaultAlertService { } setupTlsRule() { + if (this.settings?.defaultTLSRuleEnabled === false) { + return; + } return this.createDefaultAlertIfNotExist( SYNTHETICS_TLS_RULE, `Synthetics internal TLS rule`, @@ -78,7 +94,7 @@ export class DefaultAlertService { options: { page: 1, perPage: 1, - filter: `alert.attributes.alertTypeId:(${ruleType})`, + filter: `alert.attributes.alertTypeId:(${ruleType}) AND alert.attributes.tags:"SYNTHETICS_DEFAULT_ALERT"`, }, }); @@ -88,6 +104,7 @@ export class DefaultAlertService { const { actions = [], systemActions = [], ...alert } = data[0]; return { ...alert, actions: [...actions, ...systemActions], ruleTypeId: alert.alertTypeId }; } + async createDefaultAlertIfNotExist(ruleType: DefaultRuleType, name: string, interval: string) { const alert = await this.getExistingAlert(ruleType); if (alert) { @@ -121,11 +138,30 @@ export class DefaultAlertService { }; } - updateStatusRule() { - return this.updateDefaultAlert(SYNTHETICS_STATUS_RULE, `Synthetics status internal rule`, '1m'); + async updateStatusRule(enabled?: boolean) { + if (enabled) { + return this.updateDefaultAlert( + SYNTHETICS_STATUS_RULE, + `Synthetics status internal rule`, + '1m' + ); + } else { + const rulesClient = (await this.context.alerting)?.getRulesClient(); + await rulesClient.bulkDeleteRules({ + filter: `alert.attributes.alertTypeId:"${SYNTHETICS_STATUS_RULE}" AND alert.attributes.tags:"SYNTHETICS_DEFAULT_ALERT"`, + }); + } } - updateTlsRule() { - return this.updateDefaultAlert(SYNTHETICS_TLS_RULE, `Synthetics internal TLS rule`, '1m'); + + async updateTlsRule(enabled?: boolean) { + if (enabled) { + return this.updateDefaultAlert(SYNTHETICS_TLS_RULE, `Synthetics internal TLS rule`, '1m'); + } else { + const rulesClient = (await this.context.alerting)?.getRulesClient(); + await rulesClient.bulkDeleteRules({ + filter: `alert.attributes.alertTypeId:"${SYNTHETICS_TLS_RULE}" AND alert.attributes.tags:"SYNTHETICS_DEFAULT_ALERT"`, + }); + } } async updateDefaultAlert(ruleType: DefaultRuleType, name: string, interval: string) { @@ -195,14 +231,15 @@ export class DefaultAlertService { async getActionConnectors() { const actionsClient = (await this.context.actions)?.getActionsClient(); - - const settings = await savedObjectsAdapter.getSyntheticsDynamicSettings(this.soClient); + if (!this.settings) { + this.settings = await savedObjectsAdapter.getSyntheticsDynamicSettings(this.soClient); + } let actionConnectors: FindActionResult[] = []; try { actionConnectors = await actionsClient.getAll(); } catch (e) { this.server.logger.error(e); } - return { actionConnectors, settings }; + return { actionConnectors, settings: this.settings }; } } diff --git a/x-pack/plugins/observability_solution/synthetics/server/routes/default_alerts/enable_default_alert.ts b/x-pack/plugins/observability_solution/synthetics/server/routes/default_alerts/enable_default_alert.ts index db403bd6bcd54..4a78ee67ddd1f 100644 --- a/x-pack/plugins/observability_solution/synthetics/server/routes/default_alerts/enable_default_alert.ts +++ b/x-pack/plugins/observability_solution/synthetics/server/routes/default_alerts/enable_default_alert.ts @@ -8,12 +8,13 @@ import { DefaultAlertService } from './default_alert_service'; import { SyntheticsRestApiRouteFactory } from '../types'; import { SYNTHETICS_API_URLS } from '../../../common/constants'; +import { DEFAULT_ALERT_RESPONSE } from '../../../common/types/default_alerts'; export const enableDefaultAlertingRoute: SyntheticsRestApiRouteFactory = () => ({ method: 'POST', path: SYNTHETICS_API_URLS.ENABLE_DEFAULT_ALERTING, validate: {}, - handler: async ({ context, server, savedObjectsClient }): Promise => { + handler: async ({ context, server, savedObjectsClient }): Promise => { const defaultAlertService = new DefaultAlertService(context, server, savedObjectsClient); return defaultAlertService.setupDefaultAlerts(); diff --git a/x-pack/plugins/observability_solution/synthetics/server/routes/default_alerts/get_default_alert.ts b/x-pack/plugins/observability_solution/synthetics/server/routes/default_alerts/get_default_alert.ts index 01d3891d96dbb..7437be6997803 100644 --- a/x-pack/plugins/observability_solution/synthetics/server/routes/default_alerts/get_default_alert.ts +++ b/x-pack/plugins/observability_solution/synthetics/server/routes/default_alerts/get_default_alert.ts @@ -12,19 +12,20 @@ import { import { DefaultAlertService } from './default_alert_service'; import { SyntheticsRestApiRouteFactory } from '../types'; import { SYNTHETICS_API_URLS } from '../../../common/constants'; +import { DEFAULT_ALERT_RESPONSE } from '../../../common/types/default_alerts'; export const getDefaultAlertingRoute: SyntheticsRestApiRouteFactory = () => ({ method: 'GET', path: SYNTHETICS_API_URLS.ENABLE_DEFAULT_ALERTING, validate: {}, - handler: async ({ context, server, savedObjectsClient }): Promise => { + handler: async ({ context, server, savedObjectsClient }): Promise => { const defaultAlertService = new DefaultAlertService(context, server, savedObjectsClient); const statusRule = defaultAlertService.getExistingAlert(SYNTHETICS_STATUS_RULE); const tlsRule = defaultAlertService.getExistingAlert(SYNTHETICS_TLS_RULE); const [status, tls] = await Promise.all([statusRule, tlsRule]); return { - statusRule: status, - tlsRule: tls, + statusRule: status || null, + tlsRule: tls || null, }; }, }); diff --git a/x-pack/plugins/observability_solution/synthetics/server/routes/default_alerts/update_default_alert.ts b/x-pack/plugins/observability_solution/synthetics/server/routes/default_alerts/update_default_alert.ts index bef006d02b87e..406eaef0aad14 100644 --- a/x-pack/plugins/observability_solution/synthetics/server/routes/default_alerts/update_default_alert.ts +++ b/x-pack/plugins/observability_solution/synthetics/server/routes/default_alerts/update_default_alert.ts @@ -8,21 +8,41 @@ import { DefaultAlertService } from './default_alert_service'; import { SyntheticsRestApiRouteFactory } from '../types'; import { SYNTHETICS_API_URLS } from '../../../common/constants'; +import { savedObjectsAdapter } from '../../saved_objects'; +import { DEFAULT_ALERT_RESPONSE } from '../../../common/types/default_alerts'; export const updateDefaultAlertingRoute: SyntheticsRestApiRouteFactory = () => ({ method: 'PUT', path: SYNTHETICS_API_URLS.ENABLE_DEFAULT_ALERTING, validate: {}, - handler: async ({ context, server, savedObjectsClient }): Promise => { + handler: async ({ + request, + context, + server, + savedObjectsClient, + }): Promise => { const defaultAlertService = new DefaultAlertService(context, server, savedObjectsClient); + const { defaultTLSRuleEnabled, defaultStatusRuleEnabled } = + await savedObjectsAdapter.getSyntheticsDynamicSettings(savedObjectsClient); - const [statusRule, tlsRule] = await Promise.all([ - defaultAlertService.updateStatusRule(), - defaultAlertService.updateTlsRule(), - ]); - return { - statusRule, - tlsRule, - }; + const updateStatusRulePromise = defaultAlertService.updateStatusRule(defaultStatusRuleEnabled); + const updateTLSRulePromise = defaultAlertService.updateTlsRule(defaultTLSRuleEnabled); + + try { + const [statusRule, tlsRule] = await Promise.all([ + updateStatusRulePromise, + updateTLSRulePromise, + ]); + return { + statusRule: statusRule || null, + tlsRule: tlsRule || null, + }; + } catch (e) { + server.logger.error(`Error updating default alerting rules: ${e}`); + return { + statusRule: null, + tlsRule: null, + }; + } }, }); diff --git a/x-pack/plugins/observability_solution/synthetics/server/routes/overview_status/overview_status.test.ts b/x-pack/plugins/observability_solution/synthetics/server/routes/overview_status/overview_status.test.ts index 33cf9746fb6e7..c850267245b22 100644 --- a/x-pack/plugins/observability_solution/synthetics/server/routes/overview_status/overview_status.test.ts +++ b/x-pack/plugins/observability_solution/synthetics/server/routes/overview_status/overview_status.test.ts @@ -593,25 +593,25 @@ describe('current status route', () => { pendingConfigs: { 'id3-Asia/Pacific - Japan': { configId: 'id3', - location: 'Asia/Pacific - Japan', + locationId: 'Asia/Pacific - Japan', monitorQueryId: 'project-monitor-id', status: 'unknown', }, 'id3-Europe - Germany': { configId: 'id3', - location: 'Europe - Germany', + locationId: 'Europe - Germany', monitorQueryId: 'project-monitor-id', status: 'unknown', }, 'id4-Asia/Pacific - Japan': { configId: 'id4', - location: 'Asia/Pacific - Japan', + locationId: 'Asia/Pacific - Japan', monitorQueryId: 'id4', status: 'unknown', }, 'id4-Europe - Germany': { configId: 'id4', - location: 'Europe - Germany', + locationId: 'Europe - Germany', monitorQueryId: 'id4', status: 'unknown', }, diff --git a/x-pack/plugins/observability_solution/synthetics/server/routes/overview_status/overview_status.ts b/x-pack/plugins/observability_solution/synthetics/server/routes/overview_status/overview_status.ts index b6373758ac802..d114955fc9213 100644 --- a/x-pack/plugins/observability_solution/synthetics/server/routes/overview_status/overview_status.ts +++ b/x-pack/plugins/observability_solution/synthetics/server/routes/overview_status/overview_status.ts @@ -36,7 +36,7 @@ export function periodToMs(schedule: { number: string; unit: Unit }) { * @returns The counts of up/down/disabled monitor by location, and a map of each monitor:location status. */ export async function getStatus(context: RouteContext, params: OverviewStatusQuery) { - const { syntheticsEsClient, syntheticsMonitorClient, savedObjectsClient, server } = context; + const { syntheticsEsClient, savedObjectsClient } = context; const { query, scopeStatusByLocation = true } = params; @@ -77,13 +77,7 @@ export async function getStatus(context: RouteContext, params: OverviewStatusQue disabledMonitorsCount, projectMonitorsCount, monitorQueryIdToConfigIdMap, - } = processMonitors( - allMonitors, - server, - savedObjectsClient, - syntheticsMonitorClient, - queryLocations - ); + } = processMonitors(allMonitors, queryLocations); // Account for locations filter const listOfLocationAfterFilter = diff --git a/x-pack/plugins/observability_solution/synthetics/server/routes/settings/dynamic_settings.ts b/x-pack/plugins/observability_solution/synthetics/server/routes/settings/dynamic_settings.ts index 07641ef826de3..e9b9bb6da931f 100644 --- a/x-pack/plugins/observability_solution/synthetics/server/routes/settings/dynamic_settings.ts +++ b/x-pack/plugins/observability_solution/synthetics/server/routes/settings/dynamic_settings.ts @@ -22,7 +22,7 @@ export const createGetDynamicSettingsRoute: SyntheticsRestApiRouteFactory< handler: async ({ savedObjectsClient }) => { const dynamicSettingsAttributes: DynamicSettingsAttributes = await savedObjectsAdapter.getSyntheticsDynamicSettings(savedObjectsClient); - return fromAttribute(dynamicSettingsAttributes); + return fromSettingsAttribute(dynamicSettingsAttributes); }, }); @@ -42,16 +42,20 @@ export const createPostDynamicSettingsRoute: SyntheticsRestApiRouteFactory = () ...newSettings, } as DynamicSettingsAttributes); - return fromAttribute(attr as DynamicSettingsAttributes); + return fromSettingsAttribute(attr as DynamicSettingsAttributes); }, }); -const fromAttribute = (attr: DynamicSettingsAttributes) => { +export const fromSettingsAttribute = ( + attr: DynamicSettingsAttributes +): DynamicSettingsAttributes => { return { certExpirationThreshold: attr.certExpirationThreshold, certAgeThreshold: attr.certAgeThreshold, defaultConnectors: attr.defaultConnectors, defaultEmail: attr.defaultEmail, + defaultStatusRuleEnabled: attr.defaultStatusRuleEnabled ?? true, + defaultTLSRuleEnabled: attr.defaultTLSRuleEnabled ?? true, }; }; @@ -72,6 +76,8 @@ export const DynamicSettingsSchema = schema.object({ certAgeThreshold: schema.maybe(schema.number({ min: 1, validate: validateInteger })), certExpirationThreshold: schema.maybe(schema.number({ min: 1, validate: validateInteger })), defaultConnectors: schema.maybe(schema.arrayOf(schema.string())), + defaultStatusRuleEnabled: schema.maybe(schema.boolean()), + defaultTLSRuleEnabled: schema.maybe(schema.boolean()), defaultEmail: schema.maybe( schema.object({ to: schema.arrayOf(schema.string()), diff --git a/x-pack/plugins/observability_solution/synthetics/server/routes/suggestions/route.ts b/x-pack/plugins/observability_solution/synthetics/server/routes/suggestions/route.ts index 3a9c3b064bc0f..85ab73eb10a6e 100644 --- a/x-pack/plugins/observability_solution/synthetics/server/routes/suggestions/route.ts +++ b/x-pack/plugins/observability_solution/synthetics/server/routes/suggestions/route.ts @@ -5,7 +5,7 @@ * 2.0. */ import { SyntheticsRestApiRouteFactory } from '../types'; -import { syntheticsMonitorType } from '../../../common/types/saved_objects'; +import { monitorAttributes, syntheticsMonitorType } from '../../../common/types/saved_objects'; import { ConfigKey, MonitorFiltersResult, @@ -30,7 +30,7 @@ interface AggsResponse { projectsAggs: { buckets: Buckets; }; - monitorTypeAggs: { + monitorTypesAggs: { buckets: Buckets; }; monitorIdsAggs: { @@ -85,7 +85,7 @@ export const getSyntheticsSuggestionsRoute: SyntheticsRestApiRouteFactory< searchFields: SEARCH_FIELDS, }); - const { monitorTypeAggs, tagsAggs, locationsAggs, projectsAggs, monitorIdsAggs } = + const { monitorTypesAggs, tagsAggs, locationsAggs, projectsAggs, monitorIdsAggs } = (data?.aggregations as AggsResponse) ?? {}; const allLocationsMap = new Map(allLocations.map((obj) => [obj.id, obj.label])); @@ -114,7 +114,7 @@ export const getSyntheticsSuggestionsRoute: SyntheticsRestApiRouteFactory< count, })) ?? [], monitorTypes: - monitorTypeAggs?.buckets?.map(({ key, doc_count: count }) => ({ + monitorTypesAggs?.buckets?.map(({ key, doc_count: count }) => ({ label: key, value: key, count, @@ -129,35 +129,42 @@ export const getSyntheticsSuggestionsRoute: SyntheticsRestApiRouteFactory< const aggs = { tagsAggs: { terms: { - field: `${syntheticsMonitorType}.attributes.${ConfigKey.TAGS}`, + field: `${monitorAttributes}.${ConfigKey.TAGS}`, size: 10000, exclude: [''], }, }, monitorTypeAggs: { terms: { - field: `${syntheticsMonitorType}.attributes.${ConfigKey.MONITOR_TYPE}.keyword`, + field: `${monitorAttributes}.${ConfigKey.MONITOR_TYPE}.keyword`, size: 10000, exclude: [''], }, }, locationsAggs: { terms: { - field: `${syntheticsMonitorType}.attributes.${ConfigKey.LOCATIONS}.id`, + field: `${monitorAttributes}.${ConfigKey.LOCATIONS}.id`, size: 10000, exclude: [''], }, }, projectsAggs: { terms: { - field: `${syntheticsMonitorType}.attributes.${ConfigKey.PROJECT_ID}`, + field: `${monitorAttributes}.${ConfigKey.PROJECT_ID}`, + size: 10000, + exclude: [''], + }, + }, + monitorTypesAggs: { + terms: { + field: `${monitorAttributes}.${ConfigKey.MONITOR_TYPE}.keyword`, size: 10000, exclude: [''], }, }, monitorIdsAggs: { terms: { - field: `${syntheticsMonitorType}.attributes.${ConfigKey.MONITOR_QUERY_ID}`, + field: `${monitorAttributes}.${ConfigKey.MONITOR_QUERY_ID}`, size: 10000, exclude: [''], }, diff --git a/x-pack/plugins/observability_solution/synthetics/server/runtime_types/settings.ts b/x-pack/plugins/observability_solution/synthetics/server/runtime_types/settings.ts index 4aff410088683..def512e2f73a8 100644 --- a/x-pack/plugins/observability_solution/synthetics/server/runtime_types/settings.ts +++ b/x-pack/plugins/observability_solution/synthetics/server/runtime_types/settings.ts @@ -25,6 +25,8 @@ export const DynamicSettingsAttributesCodec = t.intersection([ }), t.partial({ defaultEmail: DefaultEmailCodec, + defaultStatusRuleEnabled: t.boolean, + defaultTLSRuleEnabled: t.boolean, }), ]); diff --git a/x-pack/plugins/observability_solution/synthetics/server/saved_objects/saved_objects.ts b/x-pack/plugins/observability_solution/synthetics/server/saved_objects/saved_objects.ts index 419661d832b1d..9b4a365941a7d 100644 --- a/x-pack/plugins/observability_solution/synthetics/server/saved_objects/saved_objects.ts +++ b/x-pack/plugins/observability_solution/synthetics/server/saved_objects/saved_objects.ts @@ -12,6 +12,7 @@ import { } from '@kbn/core/server'; import { EncryptedSavedObjectsPluginSetup } from '@kbn/encrypted-saved-objects-plugin/server'; +import { fromSettingsAttribute } from '../routes/settings/dynamic_settings'; import { syntheticsSettings, syntheticsSettingsObjectId, @@ -62,7 +63,7 @@ export const savedObjectsAdapter = { syntheticsSettingsObjectType, syntheticsSettingsObjectId ); - return obj?.attributes ?? DYNAMIC_SETTINGS_DEFAULT_ATTRIBUTES; + return fromSettingsAttribute(obj?.attributes ?? DYNAMIC_SETTINGS_DEFAULT_ATTRIBUTES); } catch (getErr) { if (SavedObjectsErrorHelpers.isNotFoundError(getErr)) { // If the object doesn't exist, check to see if uptime settings exist diff --git a/x-pack/plugins/observability_solution/synthetics/server/saved_objects/synthetics_monitor/get_all_monitors.test.ts b/x-pack/plugins/observability_solution/synthetics/server/saved_objects/synthetics_monitor/get_all_monitors.test.ts index f17494bac5487..313063662f9d4 100644 --- a/x-pack/plugins/observability_solution/synthetics/server/saved_objects/synthetics_monitor/get_all_monitors.test.ts +++ b/x-pack/plugins/observability_solution/synthetics/server/saved_objects/synthetics_monitor/get_all_monitors.test.ts @@ -6,46 +6,11 @@ */ import { processMonitors } from './get_all_monitors'; -import { mockEncryptedSO } from '../../synthetics_service/utils/mocks'; -import { loggerMock } from '@kbn/logging-mocks'; -import { savedObjectsClientMock } from '@kbn/core-saved-objects-api-server-mocks'; -import { SyntheticsMonitorClient } from '../../synthetics_service/synthetics_monitor/synthetics_monitor_client'; -import { SyntheticsService } from '../../synthetics_service/synthetics_service'; import * as getLocations from '../../synthetics_service/get_all_locations'; -import { SyntheticsServerSetup } from '../../types'; describe('processMonitors', () => { - const mockEsClient = { - search: jest.fn(), - }; - const logger = loggerMock.create(); - const soClient = savedObjectsClientMock.create(); - - const serverMock: SyntheticsServerSetup = { - logger, - syntheticsEsClient: mockEsClient, - authSavedObjectsClient: soClient, - config: { - service: { - username: 'dev', - password: '12345', - manifestUrl: 'http://localhost:8080/api/manifest', - }, - }, - spaces: { - spacesService: { - getSpaceId: jest.fn().mockReturnValue('test-space'), - }, - }, - encryptedSavedObjects: mockEncryptedSO(), - } as unknown as SyntheticsServerSetup; - - const syntheticsService = new SyntheticsService(serverMock); - - const monitorClient = new SyntheticsMonitorClient(syntheticsService, serverMock); - it('should return a processed data', async () => { - const result = processMonitors(testMonitors, serverMock, soClient, monitorClient); + const result = processMonitors(testMonitors); expect(result).toEqual({ allIds: [ 'aa925d91-40b0-4f8f-b695-bb9b53cd4e22', @@ -81,7 +46,7 @@ describe('processMonitors', () => { it('should return a processed data where location label is missing', async () => { testMonitors[0].attributes.locations[0].label = undefined; - const result = processMonitors(testMonitors, serverMock, soClient, monitorClient); + const result = processMonitors(testMonitors); expect(result).toEqual({ allIds: [ 'aa925d91-40b0-4f8f-b695-bb9b53cd4e22', @@ -155,7 +120,7 @@ describe('processMonitors', () => { ) ); - const result = processMonitors(testMonitors, serverMock, soClient, monitorClient); + const result = processMonitors(testMonitors); expect(result).toEqual({ allIds: [ 'aa925d91-40b0-4f8f-b695-bb9b53cd4e22', diff --git a/x-pack/plugins/observability_solution/synthetics/server/saved_objects/synthetics_monitor/get_all_monitors.ts b/x-pack/plugins/observability_solution/synthetics/server/saved_objects/synthetics_monitor/get_all_monitors.ts index c742bf26176ad..e19bc529695ae 100644 --- a/x-pack/plugins/observability_solution/synthetics/server/saved_objects/synthetics_monitor/get_all_monitors.ts +++ b/x-pack/plugins/observability_solution/synthetics/server/saved_objects/synthetics_monitor/get_all_monitors.ts @@ -11,7 +11,6 @@ import { SavedObjectsFindResult, } from '@kbn/core-saved-objects-api-server'; import { intersection } from 'lodash'; -import { SyntheticsServerSetup } from '../../types'; import { syntheticsMonitorType } from '../../../common/types/saved_objects'; import { periodToMs } from '../../routes/overview_status/overview_status'; import { @@ -19,7 +18,6 @@ import { EncryptedSyntheticsMonitorAttributes, SourceType, } from '../../../common/runtime_types'; -import { SyntheticsMonitorClient } from '../../synthetics_service/synthetics_monitor/synthetics_monitor_client'; export const getAllMonitors = async ({ soClient, @@ -57,9 +55,6 @@ export const getAllMonitors = async ({ export const processMonitors = ( allMonitors: Array>, - server: SyntheticsServerSetup, - soClient: SavedObjectsClientContract, - syntheticsMonitorClient: SyntheticsMonitorClient, queryLocations?: string[] | string ) => { /** diff --git a/x-pack/plugins/observability_solution/synthetics/server/types.ts b/x-pack/plugins/observability_solution/synthetics/server/types.ts index 6209055fc6778..2e1fac95023b9 100644 --- a/x-pack/plugins/observability_solution/synthetics/server/types.ts +++ b/x-pack/plugins/observability_solution/synthetics/server/types.ts @@ -17,6 +17,7 @@ import { Logger, SavedObjectsClientContract, } from '@kbn/core/server'; +import { PluginStartContract as AlertingPluginStart } from '@kbn/alerting-plugin/server'; import { SharePluginSetup } from '@kbn/share-plugin/server'; import { ObservabilityPluginSetup } from '@kbn/observability-plugin/server'; import { UsageCollectionSetup } from '@kbn/usage-collection-plugin/server'; @@ -85,6 +86,7 @@ export interface SyntheticsPluginsStartDependencies { taskManager: TaskManagerStartContract; telemetry: TelemetryPluginStart; spaces?: SpacesPluginStart; + alerting: AlertingPluginStart; } export type UptimeRequestHandlerContext = CustomRequestHandlerContext<{ diff --git a/x-pack/plugins/observability_solution/uptime/tsconfig.json b/x-pack/plugins/observability_solution/uptime/tsconfig.json index 041ff7a84a4fb..f797a5a7f930d 100644 --- a/x-pack/plugins/observability_solution/uptime/tsconfig.json +++ b/x-pack/plugins/observability_solution/uptime/tsconfig.json @@ -77,7 +77,7 @@ "@kbn/react-kibana-context-render", "@kbn/react-kibana-context-theme", "@kbn/react-kibana-mount", - "@kbn/deeplinks-observability" + "@kbn/deeplinks-observability", ], "exclude": ["target/**/*"] } diff --git a/x-pack/test/api_integration/apis/synthetics/enable_default_alerting.ts b/x-pack/test/api_integration/apis/synthetics/enable_default_alerting.ts index dd4db37f4adc3..0064ef490bb75 100644 --- a/x-pack/test/api_integration/apis/synthetics/enable_default_alerting.ts +++ b/x-pack/test/api_integration/apis/synthetics/enable_default_alerting.ts @@ -8,6 +8,7 @@ import expect from '@kbn/expect'; import { omit } from 'lodash'; import { HTTPFields } from '@kbn/synthetics-plugin/common/runtime_types'; import { SYNTHETICS_API_URLS } from '@kbn/synthetics-plugin/common/constants'; +import { DYNAMIC_SETTINGS_DEFAULTS } from '@kbn/synthetics-plugin/common/constants/settings_defaults'; import { FtrProviderContext } from '../../ftr_provider_context'; import { getFixtureJson } from './helper/get_fixture_json'; @@ -41,13 +42,19 @@ export default function ({ getService }: FtrProviderContext) { beforeEach(async () => { httpMonitorJson = _httpMonitorJson; await kibanaServer.savedObjects.cleanStandardList(); + await supertest + .put(SYNTHETICS_API_URLS.DYNAMIC_SETTINGS) + .set('kbn-xsrf', 'true') + .send(DYNAMIC_SETTINGS_DEFAULTS) + .expect(200); }); it('returns the created alerted when called', async () => { const apiResponse = await supertest .post(SYNTHETICS_API_URLS.ENABLE_DEFAULT_ALERTING) .set('kbn-xsrf', 'true') - .send({}); + .send() + .expect(200); const omitFields = [ 'id', @@ -76,6 +83,96 @@ export default function ({ getService }: FtrProviderContext) { expect(apiResponse).eql(omitMonitorKeys(newMonitor)); + await retry.tryForTime(30 * 1000, async () => { + const res = await supertest + .get(SYNTHETICS_API_URLS.ENABLE_DEFAULT_ALERTING) + .set('kbn-xsrf', 'true') + .expect(200); + + expect(res.body.statusRule.ruleTypeId).eql('xpack.synthetics.alerts.monitorStatus'); + expect(res.body.tlsRule.ruleTypeId).eql('xpack.synthetics.alerts.tls'); + }); + }); + + it('deletes (and recreates) the default rule when settings are updated', async () => { + const newMonitor = httpMonitorJson; + + const { body: apiResponse } = await addMonitorAPI(newMonitor); + + expect(apiResponse).eql(omitMonitorKeys(newMonitor)); + + await retry.tryForTime(30 * 1000, async () => { + const res = await supertest + .get(SYNTHETICS_API_URLS.ENABLE_DEFAULT_ALERTING) + .set('kbn-xsrf', 'true') + .expect(200); + + expect(res.body.statusRule.ruleTypeId).eql('xpack.synthetics.alerts.monitorStatus'); + expect(res.body.tlsRule.ruleTypeId).eql('xpack.synthetics.alerts.tls'); + }); + const settings = await supertest + .put(SYNTHETICS_API_URLS.DYNAMIC_SETTINGS) + .set('kbn-xsrf', 'true') + .send({ + defaultStatusRuleEnabled: false, + defaultTLSRuleEnabled: false, + }); + + expect(settings.body.defaultStatusRuleEnabled).eql(false); + expect(settings.body.defaultTLSRuleEnabled).eql(false); + + await supertest + .put(SYNTHETICS_API_URLS.ENABLE_DEFAULT_ALERTING) + .set('kbn-xsrf', 'true') + .send() + .expect(200); + + await retry.tryForTime(30 * 1000, async () => { + const res = await supertest + .get(SYNTHETICS_API_URLS.ENABLE_DEFAULT_ALERTING) + .set('kbn-xsrf', 'true') + .expect(200); + + expect(res.body.statusRule).eql(null); + expect(res.body.tlsRule).eql(null); + }); + + const settings2 = await supertest + .put(SYNTHETICS_API_URLS.DYNAMIC_SETTINGS) + .set('kbn-xsrf', 'true') + .send({ + defaultStatusRuleEnabled: true, + defaultTLSRuleEnabled: true, + }) + .expect(200); + + expect(settings2.body.defaultStatusRuleEnabled).eql(true); + expect(settings2.body.defaultTLSRuleEnabled).eql(true); + + await supertest + .put(SYNTHETICS_API_URLS.ENABLE_DEFAULT_ALERTING) + .set('kbn-xsrf', 'true') + .send() + .expect(200); + + await retry.tryForTime(30 * 1000, async () => { + const res = await supertest + .get(SYNTHETICS_API_URLS.ENABLE_DEFAULT_ALERTING) + .set('kbn-xsrf', 'true') + .expect(200); + + expect(res.body.statusRule.ruleTypeId).eql('xpack.synthetics.alerts.monitorStatus'); + expect(res.body.tlsRule.ruleTypeId).eql('xpack.synthetics.alerts.tls'); + }); + }); + + it('doesnt throw errors when rule has already been deleted', async () => { + const newMonitor = httpMonitorJson; + + const { body: apiResponse } = await addMonitorAPI(newMonitor); + + expect(apiResponse).eql(omitMonitorKeys(newMonitor)); + await retry.tryForTime(30 * 1000, async () => { const res = await supertest .get(SYNTHETICS_API_URLS.ENABLE_DEFAULT_ALERTING) @@ -84,6 +181,49 @@ export default function ({ getService }: FtrProviderContext) { expect(res.body.statusRule.ruleTypeId).eql('xpack.synthetics.alerts.monitorStatus'); expect(res.body.tlsRule.ruleTypeId).eql('xpack.synthetics.alerts.tls'); }); + + const settings = await supertest + .put(SYNTHETICS_API_URLS.DYNAMIC_SETTINGS) + .set('kbn-xsrf', 'true') + .send({ + defaultStatusRuleEnabled: false, + defaultTLSRuleEnabled: false, + }); + + expect(settings.body.defaultStatusRuleEnabled).eql(false); + expect(settings.body.defaultTLSRuleEnabled).eql(false); + + await supertest + .put(SYNTHETICS_API_URLS.ENABLE_DEFAULT_ALERTING) + .set('kbn-xsrf', 'true') + .send(); + + await retry.tryForTime(30 * 1000, async () => { + const res = await supertest + .get(SYNTHETICS_API_URLS.ENABLE_DEFAULT_ALERTING) + .set('kbn-xsrf', 'true') + .expect(200); + + expect(res.body.statusRule).eql(null); + expect(res.body.tlsRule).eql(null); + }); + + // call api again with the same settings, make sure its 200 + await supertest + .put(SYNTHETICS_API_URLS.ENABLE_DEFAULT_ALERTING) + .set('kbn-xsrf', 'true') + .send() + .expect(200); + + await retry.tryForTime(30 * 1000, async () => { + const res = await supertest + .get(SYNTHETICS_API_URLS.ENABLE_DEFAULT_ALERTING) + .set('kbn-xsrf', 'true') + .expect(200); + + expect(res.body.statusRule).eql(null); + expect(res.body.tlsRule).eql(null); + }); }); }); }