From 28e096c1083962f8e72245b2811106159f500d73 Mon Sep 17 00:00:00 2001 From: chrisronline Date: Fri, 4 Dec 2020 12:28:22 -0500 Subject: [PATCH 1/4] First draft --- .../{security_toasts.tsx => alerts_toast.tsx} | 57 ++++++++++++++----- .../monitoring/public/services/clusters.js | 4 +- .../alerts/disable_watcher_cluster_alerts.ts | 38 +++++++++++++ x-pack/plugins/monitoring/server/plugin.ts | 1 + .../server/routes/api/v1/alerts/enable.ts | 20 +++++-- x-pack/plugins/monitoring/server/types.ts | 3 +- 6 files changed, 101 insertions(+), 22 deletions(-) rename x-pack/plugins/monitoring/public/alerts/lib/{security_toasts.tsx => alerts_toast.tsx} (50%) create mode 100644 x-pack/plugins/monitoring/server/lib/alerts/disable_watcher_cluster_alerts.ts diff --git a/x-pack/plugins/monitoring/public/alerts/lib/security_toasts.tsx b/x-pack/plugins/monitoring/public/alerts/lib/alerts_toast.tsx similarity index 50% rename from x-pack/plugins/monitoring/public/alerts/lib/security_toasts.tsx rename to x-pack/plugins/monitoring/public/alerts/lib/alerts_toast.tsx index 2850a5b772c32..32ffd21cedb65 100644 --- a/x-pack/plugins/monitoring/public/alerts/lib/security_toasts.tsx +++ b/x-pack/plugins/monitoring/public/alerts/lib/alerts_toast.tsx @@ -11,9 +11,10 @@ import { EuiSpacer, EuiLink } from '@elastic/eui'; import { Legacy } from '../../legacy_shims'; import { toMountPoint } from '../../../../../../src/plugins/kibana_react/public'; -export interface AlertingFrameworkHealth { - isSufficientlySecure: boolean; - hasPermanentEncryptionKey: boolean; +export interface EnableAlertResponse { + isSufficientlySecure?: boolean; + hasPermanentEncryptionKey?: boolean; + disabledWatcherClusterAlerts?: boolean; } const showTlsAndEncryptionError = () => { @@ -48,18 +49,48 @@ const showTlsAndEncryptionError = () => { }); }; -export const showSecurityToast = (alertingHealth: AlertingFrameworkHealth) => { - const { isSufficientlySecure, hasPermanentEncryptionKey } = alertingHealth; +const showUnableToDisableWatcherClusterAlertsError = () => { + // const { ELASTIC_WEBSITE_URL, DOC_LINK_VERSION } = Legacy.shims.docLinks; - if ( - Array.isArray(alertingHealth) || - (!alertingHealth.hasOwnProperty('isSufficientlySecure') && - !alertingHealth.hasOwnProperty('hasPermanentEncryptionKey')) - ) { - return; - } + Legacy.shims.toastNotifications.addWarning({ + title: toMountPoint( + + ), + text: toMountPoint( +
+

+ {i18n.translate('xpack.monitoring.healthCheck.unableToDisableWatches.text', { + defaultMessage: `We failed to remove legacy cluster alerts. Please check the Kibana server log for more details, or try again later.`, + })} +

+ {/* */} + {/* + {i18n.translate('xpack.monitoring.healthCheck.encryptionErrorAction', { + defaultMessage: 'Learn how.', + })} + */} +
+ ), + }); +}; + +export const showAlertsToast = (response: EnableAlertResponse) => { + const { + isSufficientlySecure, + hasPermanentEncryptionKey, + disabledWatcherClusterAlerts, + } = response; - if (!isSufficientlySecure || !hasPermanentEncryptionKey) { + if (isSufficientlySecure === false || hasPermanentEncryptionKey === false) { showTlsAndEncryptionError(); + } else if (disabledWatcherClusterAlerts === false) { + showUnableToDisableWatcherClusterAlertsError(); } }; diff --git a/x-pack/plugins/monitoring/public/services/clusters.js b/x-pack/plugins/monitoring/public/services/clusters.js index ef97d78b4f745..e94bf990b090c 100644 --- a/x-pack/plugins/monitoring/public/services/clusters.js +++ b/x-pack/plugins/monitoring/public/services/clusters.js @@ -8,7 +8,7 @@ import { ajaxErrorHandlersProvider } from '../lib/ajax_error_handler'; import { Legacy } from '../legacy_shims'; import { STANDALONE_CLUSTER_CLUSTER_UUID } from '../../common/constants'; import { showInternalMonitoringToast } from '../lib/internal_monitoring_toasts'; -import { showSecurityToast } from '../alerts/lib/security_toasts'; +import { showAlertsToast } from '../alerts/lib/alerts_toast'; function formatClusters(clusters) { return clusters.map(formatCluster); @@ -94,7 +94,7 @@ export function monitoringClustersProvider($injector) { if (clusters.length) { try { const [{ data }] = await Promise.all([ensureAlertsEnabled(), ensureMetricbeatEnabled()]); - showSecurityToast(data); + showAlertsToast(data); once = true; } catch (_err) { // Intentionally swallow the error as this will retry the next page load diff --git a/x-pack/plugins/monitoring/server/lib/alerts/disable_watcher_cluster_alerts.ts b/x-pack/plugins/monitoring/server/lib/alerts/disable_watcher_cluster_alerts.ts new file mode 100644 index 0000000000000..93e993a220935 --- /dev/null +++ b/x-pack/plugins/monitoring/server/lib/alerts/disable_watcher_cluster_alerts.ts @@ -0,0 +1,38 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { LegacyAPICaller } from 'src/core/server'; + +async function callMigrationApi(callCluster: LegacyAPICaller) { + // return await callCluster('_monitoring/migrate/alerts'); + return { + exporters: [ + { + name: 'thename', + type: 'http', + migration_complete: true, + reason: 'optional - exception', + }, + { + name: 'thename2', + type: 'local', + migration_complete: false, + reason: 'optional - exception', + }, + ], + }; +} + +export async function disableWatcherClusterAlerts(callCluster: LegacyAPICaller) { + const response = await callMigrationApi(callCluster); + if (!response || response.exporters.length === 0) { + return true; + } + if (response.exporters.every((exp) => exp.migration_complete)) { + return true; + } + return false; +} diff --git a/x-pack/plugins/monitoring/server/plugin.ts b/x-pack/plugins/monitoring/server/plugin.ts index af5e1fca76308..9b95a8213b59d 100644 --- a/x-pack/plugins/monitoring/server/plugin.ts +++ b/x-pack/plugins/monitoring/server/plugin.ts @@ -225,6 +225,7 @@ export class Plugin { this.registerPluginInUI(plugins); requireUIRoutes(this.monitoringCore, { + cluster, router, licenseService: this.licenseService, encryptedSavedObjects: plugins.encryptedSavedObjects, diff --git a/x-pack/plugins/monitoring/server/routes/api/v1/alerts/enable.ts b/x-pack/plugins/monitoring/server/routes/api/v1/alerts/enable.ts index ac38d7a59b773..6cb37866bafc2 100644 --- a/x-pack/plugins/monitoring/server/routes/api/v1/alerts/enable.ts +++ b/x-pack/plugins/monitoring/server/routes/api/v1/alerts/enable.ts @@ -11,6 +11,8 @@ import { RouteDependencies } from '../../../../types'; import { ALERT_ACTION_TYPE_LOG } from '../../../../../common/constants'; import { ActionResult } from '../../../../../../actions/common'; import { AlertingSecurity } from '../../../../lib/elasticsearch/verify_alerting_security'; +import { disableWatcherClusterAlerts } from '../../../../lib/alerts/disable_watcher_cluster_alerts'; +import { Alert } from '../../../../../../alerts/common'; const DEFAULT_SERVER_LOG_NAME = 'Monitoring: Write to Kibana log'; @@ -20,7 +22,7 @@ export function enableAlertsRoute(_server: unknown, npRoute: RouteDependencies) path: '/api/monitoring/v1/alerts/enable', validate: false, }, - async (context, _request, response) => { + async (context, request, response) => { try { const alerts = AlertsFactory.getAll().filter((a) => a.isEnabled(npRoute.licenseService)); @@ -75,12 +77,18 @@ export function enableAlertsRoute(_server: unknown, npRoute: RouteDependencies) }, ]; - const createdAlerts = await Promise.all( - alerts.map( - async (alert) => await alert.createIfDoesNotExist(alertsClient, actionsClient, actions) - ) + let createdAlerts: Alert[] = []; + const disabledWatcherClusterAlerts = await disableWatcherClusterAlerts( + npRoute.cluster.asScoped(request).callAsCurrentUser ); - return response.ok({ body: createdAlerts }); + + if (disabledWatcherClusterAlerts) { + createdAlerts = await Promise.all( + alerts.map((alert) => alert.createIfDoesNotExist(alertsClient, actionsClient, actions)) + ); + } + + return response.ok({ body: { createdAlerts, disabledWatcherClusterAlerts } }); } catch (err) { throw handleError(err); } diff --git a/x-pack/plugins/monitoring/server/types.ts b/x-pack/plugins/monitoring/server/types.ts index a5d7051105797..05e3b00d7cf7b 100644 --- a/x-pack/plugins/monitoring/server/types.ts +++ b/x-pack/plugins/monitoring/server/types.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ import { Observable } from 'rxjs'; -import { IRouter, ILegacyClusterClient, Logger } from 'kibana/server'; +import { IRouter, ILegacyClusterClient, Logger, ILegacyCustomClusterClient } from 'kibana/server'; import { UsageCollectionSetup } from 'src/plugins/usage_collection/server'; import { LicenseFeature, ILicense } from '../../licensing/server'; import { PluginStartContract as ActionsPluginsStartContact } from '../../actions/server'; @@ -52,6 +52,7 @@ export interface MonitoringCoreConfig { } export interface RouteDependencies { + cluster: ILegacyCustomClusterClient; router: IRouter; licenseService: MonitoringLicenseService; encryptedSavedObjects?: EncryptedSavedObjectsPluginSetup; From b5e9ee9d312f75856653c229a456026c60a463dd Mon Sep 17 00:00:00 2001 From: chrisronline Date: Tue, 22 Dec 2020 10:29:02 -0500 Subject: [PATCH 2/4] Update to use actual API --- x-pack/cloud.sh | 13 +++++ .../public/alerts/lib/alerts_toast.tsx | 10 ++-- .../server/es_client/instantiate_client.ts | 3 +- .../monitoring_endpoint_disable_watches.ts | 20 +++++++ .../alerts/disable_watcher_cluster_alerts.ts | 55 +++++++++++-------- x-pack/plugins/monitoring/server/plugin.ts | 1 + .../server/routes/api/v1/alerts/enable.ts | 7 ++- x-pack/plugins/monitoring/server/types.ts | 1 + 8 files changed, 79 insertions(+), 31 deletions(-) create mode 100644 x-pack/cloud.sh create mode 100644 x-pack/plugins/monitoring/server/es_client/monitoring_endpoint_disable_watches.ts diff --git a/x-pack/cloud.sh b/x-pack/cloud.sh new file mode 100644 index 0000000000000..daca843cdd975 --- /dev/null +++ b/x-pack/cloud.sh @@ -0,0 +1,13 @@ +export TEST_BROWSER_HEADLESS=1 +export TEST_KIBANA_HOSTNAME=0b49cea24a5243e4a20b231b046fe103.us-central1.gcp.foundit.no +export TEST_KIBANA_PROTOCOL=https +export TEST_KIBANA_PORT=9243 +export TEST_KIBANA_USER=elastic +export TEST_KIBANA_PASS=k2RnHy9wPrDIlrOOCxXdAjha + +export TEST_ES_HOSTNAME=8ac377326e6d49a3890c53556fcdf200.us-central1.gcp.foundit.no +export TEST_ES_PROTOCOL=https +export TEST_ES_PORT=9243 +export TEST_ES_USER=elastic +export TEST_ES_PASS=k2RnHy9wPrDIlrOOCxXdAjha +node ../scripts/functional_test_runner --grep "Monitoring is turned off" --debug --exclude-tag skipCloud diff --git a/x-pack/plugins/monitoring/public/alerts/lib/alerts_toast.tsx b/x-pack/plugins/monitoring/public/alerts/lib/alerts_toast.tsx index 32ffd21cedb65..f6f341b69c88e 100644 --- a/x-pack/plugins/monitoring/public/alerts/lib/alerts_toast.tsx +++ b/x-pack/plugins/monitoring/public/alerts/lib/alerts_toast.tsx @@ -50,7 +50,7 @@ const showTlsAndEncryptionError = () => { }; const showUnableToDisableWatcherClusterAlertsError = () => { - // const { ELASTIC_WEBSITE_URL, DOC_LINK_VERSION } = Legacy.shims.docLinks; + const { ELASTIC_WEBSITE_URL, DOC_LINK_VERSION } = Legacy.shims.docLinks; Legacy.shims.toastNotifications.addWarning({ title: toMountPoint( @@ -66,16 +66,16 @@ const showUnableToDisableWatcherClusterAlertsError = () => { defaultMessage: `We failed to remove legacy cluster alerts. Please check the Kibana server log for more details, or try again later.`, })}

- {/* */} - {/* + {i18n.translate('xpack.monitoring.healthCheck.encryptionErrorAction', { - defaultMessage: 'Learn how.', + defaultMessage: 'Learn more.', })} - */} + ), }); diff --git a/x-pack/plugins/monitoring/server/es_client/instantiate_client.ts b/x-pack/plugins/monitoring/server/es_client/instantiate_client.ts index d974685384634..734caa7374686 100644 --- a/x-pack/plugins/monitoring/server/es_client/instantiate_client.ts +++ b/x-pack/plugins/monitoring/server/es_client/instantiate_client.ts @@ -7,6 +7,7 @@ import { ConfigOptions } from 'elasticsearch'; import { Logger, ILegacyCustomClusterClient } from 'kibana/server'; // @ts-ignore import { monitoringBulk } from '../kibana_monitoring/lib/monitoring_bulk'; +import { monitoringEndpointDisableWatches } from './monitoring_endpoint_disable_watches'; import { MonitoringElasticsearchConfig } from '../config'; /* Provide a dedicated Elasticsearch client for Monitoring @@ -28,7 +29,7 @@ export function instantiateClient( const isMonitoringCluster = hasMonitoringCluster(elasticsearchConfig); const cluster = createClient('monitoring', { ...(isMonitoringCluster ? elasticsearchConfig : {}), - plugins: [monitoringBulk], + plugins: [monitoringBulk, monitoringEndpointDisableWatches], logQueries: Boolean(elasticsearchConfig.logQueries), } as ESClusterConfig); diff --git a/x-pack/plugins/monitoring/server/es_client/monitoring_endpoint_disable_watches.ts b/x-pack/plugins/monitoring/server/es_client/monitoring_endpoint_disable_watches.ts new file mode 100644 index 0000000000000..ef4358d3eff8b --- /dev/null +++ b/x-pack/plugins/monitoring/server/es_client/monitoring_endpoint_disable_watches.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; + * you may not use this file except in compliance with the Elastic License. + */ + +export function monitoringEndpointDisableWatches(Client: any, _config: any, components: any) { + const ca = components.clientAction.factory; + Client.prototype.monitoring = components.clientAction.namespaceFactory(); + const monitoring = Client.prototype.monitoring.prototype; + monitoring.disableWatches = ca({ + params: {}, + urls: [ + { + fmt: '_monitoring/migrate/alerts', + }, + ], + method: 'POST', + }); +} diff --git a/x-pack/plugins/monitoring/server/lib/alerts/disable_watcher_cluster_alerts.ts b/x-pack/plugins/monitoring/server/lib/alerts/disable_watcher_cluster_alerts.ts index 93e993a220935..5dc0b6d0faaa4 100644 --- a/x-pack/plugins/monitoring/server/lib/alerts/disable_watcher_cluster_alerts.ts +++ b/x-pack/plugins/monitoring/server/lib/alerts/disable_watcher_cluster_alerts.ts @@ -3,36 +3,47 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ - +import { Logger } from 'kibana/server'; import { LegacyAPICaller } from 'src/core/server'; +interface DisableWatchesResponse { + exporters: Array< + Array<{ + name: string; + type: string; + migration_complete: boolean; + reason?: { + type: string; + reason: string; + }; + }> + >; +} + async function callMigrationApi(callCluster: LegacyAPICaller) { - // return await callCluster('_monitoring/migrate/alerts'); - return { - exporters: [ - { - name: 'thename', - type: 'http', - migration_complete: true, - reason: 'optional - exception', - }, - { - name: 'thename2', - type: 'local', - migration_complete: false, - reason: 'optional - exception', - }, - ], - }; + return await callCluster('monitoring.disableWatches'); } -export async function disableWatcherClusterAlerts(callCluster: LegacyAPICaller) { - const response = await callMigrationApi(callCluster); +export async function disableWatcherClusterAlerts(callCluster: LegacyAPICaller, logger: Logger) { + const response: DisableWatchesResponse = await callMigrationApi(callCluster); if (!response || response.exporters.length === 0) { return true; } - if (response.exporters.every((exp) => exp.migration_complete)) { + const list = response.exporters[0]; + if (list.length === 0) { return true; } - return false; + + let removedAll = true; + for (const exporter of list) { + if (!exporter.migration_complete) { + if (exporter.reason) { + logger.warn( + `Unable to remove exporter type=${exporter.type} and name=${exporter.name} because ${exporter.reason.type}: ${exporter.reason.reason}` + ); + removedAll = false; + } + } + } + return removedAll; } diff --git a/x-pack/plugins/monitoring/server/plugin.ts b/x-pack/plugins/monitoring/server/plugin.ts index 496277b2fd69b..94a419c9ccb87 100644 --- a/x-pack/plugins/monitoring/server/plugin.ts +++ b/x-pack/plugins/monitoring/server/plugin.ts @@ -215,6 +215,7 @@ export class Plugin { router, licenseService: this.licenseService, encryptedSavedObjects: plugins.encryptedSavedObjects, + logger: this.log, }); initInfraSource(config, plugins.infra); } diff --git a/x-pack/plugins/monitoring/server/routes/api/v1/alerts/enable.ts b/x-pack/plugins/monitoring/server/routes/api/v1/alerts/enable.ts index 6cb37866bafc2..9d11733ec0386 100644 --- a/x-pack/plugins/monitoring/server/routes/api/v1/alerts/enable.ts +++ b/x-pack/plugins/monitoring/server/routes/api/v1/alerts/enable.ts @@ -12,7 +12,7 @@ import { ALERT_ACTION_TYPE_LOG } from '../../../../../common/constants'; import { ActionResult } from '../../../../../../actions/common'; import { AlertingSecurity } from '../../../../lib/elasticsearch/verify_alerting_security'; import { disableWatcherClusterAlerts } from '../../../../lib/alerts/disable_watcher_cluster_alerts'; -import { Alert } from '../../../../../../alerts/common'; +import { Alert, AlertTypeParams } from '../../../../../../alerts/common'; const DEFAULT_SERVER_LOG_NAME = 'Monitoring: Write to Kibana log'; @@ -77,9 +77,10 @@ export function enableAlertsRoute(_server: unknown, npRoute: RouteDependencies) }, ]; - let createdAlerts: Alert[] = []; + let createdAlerts: Array> = []; const disabledWatcherClusterAlerts = await disableWatcherClusterAlerts( - npRoute.cluster.asScoped(request).callAsCurrentUser + npRoute.cluster.asScoped(request).callAsCurrentUser, + npRoute.logger ); if (disabledWatcherClusterAlerts) { diff --git a/x-pack/plugins/monitoring/server/types.ts b/x-pack/plugins/monitoring/server/types.ts index 5c00605eff9b3..69d5b99081a50 100644 --- a/x-pack/plugins/monitoring/server/types.ts +++ b/x-pack/plugins/monitoring/server/types.ts @@ -56,6 +56,7 @@ export interface RouteDependencies { router: IRouter; licenseService: MonitoringLicenseService; encryptedSavedObjects?: EncryptedSavedObjectsPluginSetup; + logger: Logger; } export interface MonitoringCore { From 830f884e449d081f79d85bb362bb0cb22262ffe7 Mon Sep 17 00:00:00 2001 From: chrisronline Date: Tue, 22 Dec 2020 10:31:23 -0500 Subject: [PATCH 3/4] Remove this file --- x-pack/cloud.sh | 13 ------------- 1 file changed, 13 deletions(-) delete mode 100644 x-pack/cloud.sh diff --git a/x-pack/cloud.sh b/x-pack/cloud.sh deleted file mode 100644 index daca843cdd975..0000000000000 --- a/x-pack/cloud.sh +++ /dev/null @@ -1,13 +0,0 @@ -export TEST_BROWSER_HEADLESS=1 -export TEST_KIBANA_HOSTNAME=0b49cea24a5243e4a20b231b046fe103.us-central1.gcp.foundit.no -export TEST_KIBANA_PROTOCOL=https -export TEST_KIBANA_PORT=9243 -export TEST_KIBANA_USER=elastic -export TEST_KIBANA_PASS=k2RnHy9wPrDIlrOOCxXdAjha - -export TEST_ES_HOSTNAME=8ac377326e6d49a3890c53556fcdf200.us-central1.gcp.foundit.no -export TEST_ES_PROTOCOL=https -export TEST_ES_PORT=9243 -export TEST_ES_USER=elastic -export TEST_ES_PASS=k2RnHy9wPrDIlrOOCxXdAjha -node ../scripts/functional_test_runner --grep "Monitoring is turned off" --debug --exclude-tag skipCloud From 08f3c591e34a0ecbbbbbe9840046e466a6775096 Mon Sep 17 00:00:00 2001 From: chrisronline Date: Mon, 4 Jan 2021 10:44:47 -0500 Subject: [PATCH 4/4] Update translation key --- x-pack/plugins/monitoring/public/alerts/lib/alerts_toast.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugins/monitoring/public/alerts/lib/alerts_toast.tsx b/x-pack/plugins/monitoring/public/alerts/lib/alerts_toast.tsx index f6f341b69c88e..f478545046894 100644 --- a/x-pack/plugins/monitoring/public/alerts/lib/alerts_toast.tsx +++ b/x-pack/plugins/monitoring/public/alerts/lib/alerts_toast.tsx @@ -72,7 +72,7 @@ const showUnableToDisableWatcherClusterAlertsError = () => { external target="_blank" > - {i18n.translate('xpack.monitoring.healthCheck.encryptionErrorAction', { + {i18n.translate('xpack.monitoring.healthCheck.unableToDisableWatches.action', { defaultMessage: 'Learn more.', })}