diff --git a/x-pack/legacy/plugins/monitoring/public/components/no_data/checking_settings.js b/x-pack/legacy/plugins/monitoring/public/components/no_data/checking_settings.js index 6d0550bacd61b..ee071eaf22bc1 100644 --- a/x-pack/legacy/plugins/monitoring/public/components/no_data/checking_settings.js +++ b/x-pack/legacy/plugins/monitoring/public/components/no_data/checking_settings.js @@ -13,8 +13,13 @@ import { EuiLoadingSpinner } from '@elastic/eui'; import { LookingFor } from './blurbs'; +import { FormattedMessage } from '@kbn/i18n/react'; export function CheckingSettings({ checkMessage }) { + const message = checkMessage || (); return ( @@ -23,12 +28,12 @@ export function CheckingSettings({ checkMessage }) { - {checkMessage}... + {message}... ); } CheckingSettings.propTypes = { - checkMessage: PropTypes.string.isRequired + checkMessage: PropTypes.string }; diff --git a/x-pack/legacy/plugins/monitoring/public/components/no_data/explanations/collection_enabled/__tests__/__snapshots__/collection_enabled.test.js.snap b/x-pack/legacy/plugins/monitoring/public/components/no_data/explanations/collection_enabled/__tests__/__snapshots__/collection_enabled.test.js.snap index 6e75c8b77891d..6734383b4db11 100644 --- a/x-pack/legacy/plugins/monitoring/public/components/no_data/explanations/collection_enabled/__tests__/__snapshots__/collection_enabled.test.js.snap +++ b/x-pack/legacy/plugins/monitoring/public/components/no_data/explanations/collection_enabled/__tests__/__snapshots__/collection_enabled.test.js.snap @@ -2,8 +2,6 @@ exports[`ExplainCollectionEnabled should explain about xpack.monitoring.collection.enabled setting 1`] = ` { beforeEach(() => { enabler.enableCollectionEnabled = sinon.spy(); + const reason = { + property: 'xpack.monitoring.collection.enabled', + data: '-1', + context: 'cluster' + }; component = ( ); }); diff --git a/x-pack/legacy/plugins/monitoring/public/components/no_data/explanations/collection_enabled/collection_enabled.js b/x-pack/legacy/plugins/monitoring/public/components/no_data/explanations/collection_enabled/collection_enabled.js index ad796a84b16d8..48883e43e0ebf 100644 --- a/x-pack/legacy/plugins/monitoring/public/components/no_data/explanations/collection_enabled/collection_enabled.js +++ b/x-pack/legacy/plugins/monitoring/public/components/no_data/explanations/collection_enabled/collection_enabled.js @@ -47,13 +47,13 @@ export class ExplainCollectionEnabled extends React.Component { render() { const { - context, - property, - data, + reason, isCollectionEnabledUpdated, isCollectionEnabledUpdating } = this.props; + const { property, data, context } = reason; + const renderButton = () => ( @@ -151,9 +151,7 @@ export class ExplainCollectionEnabled extends React.Component { ExplainCollectionEnabled.propTypes = { enabler: PropTypes.object.isRequired, - context: PropTypes.string.isRequired, - property: PropTypes.string.isRequired, - data: PropTypes.string.isRequired, + reason: PropTypes.object.isRequired, isCollectionEnabledUpdated: PropTypes.bool, isCollectionEnabledUpdating: PropTypes.bool }; diff --git a/x-pack/legacy/plugins/monitoring/public/components/no_data/explanations/collection_interval/__tests__/__snapshots__/collection_interval.test.js.snap b/x-pack/legacy/plugins/monitoring/public/components/no_data/explanations/collection_interval/__tests__/__snapshots__/collection_interval.test.js.snap index 31f58bd46455e..67e7afc91eff5 100644 --- a/x-pack/legacy/plugins/monitoring/public/components/no_data/explanations/collection_interval/__tests__/__snapshots__/collection_interval.test.js.snap +++ b/x-pack/legacy/plugins/monitoring/public/components/no_data/explanations/collection_interval/__tests__/__snapshots__/collection_interval.test.js.snap @@ -2,8 +2,6 @@ exports[`ExplainCollectionInterval collection interval setting updates should show a success message while updated = true 1`] = ` { beforeEach(() => { @@ -20,9 +25,7 @@ describe('ExplainCollectionInterval', () => { test('should explain about xpack.monitoring.collection.interval setting', () => { const component = ( { test('should have a button that triggers ajax action', () => { const component = ( { test('should show a waiting indicator while updating = true', () => { const component = ( { test('should show a success message while updated = true', () => { const component = ( ( @@ -131,9 +130,7 @@ export class ExplainCollectionInterval extends React.Component { ExplainCollectionInterval.propTypes = { enabler: PropTypes.object.isRequired, - context: PropTypes.string.isRequired, - property: PropTypes.string.isRequired, - data: PropTypes.string.isRequired, + reason: PropTypes.object.isRequired, isCollectionIntervalUpdated: PropTypes.bool, isCollectionIntervalUpdating: PropTypes.bool }; diff --git a/x-pack/legacy/plugins/monitoring/public/components/no_data/explanations/exporters/__tests__/exporters.test.js b/x-pack/legacy/plugins/monitoring/public/components/no_data/explanations/exporters/__tests__/exporters.test.js index 219cf2cf2d371..8eeb9c7b2d465 100644 --- a/x-pack/legacy/plugins/monitoring/public/components/no_data/explanations/exporters/__tests__/exporters.test.js +++ b/x-pack/legacy/plugins/monitoring/public/components/no_data/explanations/exporters/__tests__/exporters.test.js @@ -10,11 +10,15 @@ import { ExplainExporters, ExplainExportersCloud } from '../exporters'; describe('ExplainExporters', () => { test('should explain about xpack.monitoring.exporters setting', () => { + const reason = { + property: 'xpack.monitoring.exporters', + data: 'myMonitoringClusterExporter1', + context: 'esProd001' + }; + const component = renderWithIntl( ); expect(component).toMatchSnapshot(); diff --git a/x-pack/legacy/plugins/monitoring/public/components/no_data/explanations/exporters/exporters.js b/x-pack/legacy/plugins/monitoring/public/components/no_data/explanations/exporters/exporters.js index 5494b15bb2b26..9ecc2e832e93b 100644 --- a/x-pack/legacy/plugins/monitoring/public/components/no_data/explanations/exporters/exporters.js +++ b/x-pack/legacy/plugins/monitoring/public/components/no_data/explanations/exporters/exporters.js @@ -14,7 +14,8 @@ import { import { ChangesNeeded, CloudDeployment } from '../../blurbs'; import { FormattedMessage } from '@kbn/i18n/react'; -export function ExplainExporters({ context, property, data }) { +export function ExplainExporters({ reason }) { + const { context, property, data } = reason; return ( @@ -68,9 +69,7 @@ export function ExplainExporters({ context, property, data }) { } ExplainExporters.propTypes = { - context: PropTypes.string.isRequired, - property: PropTypes.string.isRequired, - data: PropTypes.string.isRequired + reason: PropTypes.object.isRequired, }; export function ExplainExportersCloud() { diff --git a/x-pack/legacy/plugins/monitoring/public/components/no_data/explanations/plugin_enabled/__tests__/plugin_enabled.test.js b/x-pack/legacy/plugins/monitoring/public/components/no_data/explanations/plugin_enabled/__tests__/plugin_enabled.test.js index 3d2989fbe6877..1a9206fd05112 100644 --- a/x-pack/legacy/plugins/monitoring/public/components/no_data/explanations/plugin_enabled/__tests__/plugin_enabled.test.js +++ b/x-pack/legacy/plugins/monitoring/public/components/no_data/explanations/plugin_enabled/__tests__/plugin_enabled.test.js @@ -10,11 +10,14 @@ import { ExplainPluginEnabled } from '../plugin_enabled'; describe('ExplainPluginEnabled', () => { test('should explain about xpack.monitoring.enabled setting', () => { + const reason = { + property: 'xpack.monitoring.enabled', + data: 'false', + context: 'cluster' + }; const component = renderWithIntl( ); expect(component).toMatchSnapshot(); diff --git a/x-pack/legacy/plugins/monitoring/public/components/no_data/explanations/plugin_enabled/plugin_enabled.js b/x-pack/legacy/plugins/monitoring/public/components/no_data/explanations/plugin_enabled/plugin_enabled.js index 7257f1933019b..a10eceba5afd0 100644 --- a/x-pack/legacy/plugins/monitoring/public/components/no_data/explanations/plugin_enabled/plugin_enabled.js +++ b/x-pack/legacy/plugins/monitoring/public/components/no_data/explanations/plugin_enabled/plugin_enabled.js @@ -14,7 +14,8 @@ import { import { ChangesNeeded } from '../../blurbs'; import { FormattedMessage } from '@kbn/i18n/react'; -export function ExplainPluginEnabled({ context, property, data }) { +export function ExplainPluginEnabled({ reason }) { + const { context, property, data } = reason; return ( @@ -41,7 +42,5 @@ export function ExplainPluginEnabled({ context, property, data }) { } ExplainPluginEnabled.propTypes = { - property: PropTypes.string.isRequired, - context: PropTypes.string.isRequired, - data: PropTypes.string.isRequired + reason: PropTypes.object.isRequired }; diff --git a/x-pack/legacy/plugins/monitoring/public/components/no_data/no_data.js b/x-pack/legacy/plugins/monitoring/public/components/no_data/no_data.js index 4671850ceed7c..286727449eb75 100644 --- a/x-pack/legacy/plugins/monitoring/public/components/no_data/no_data.js +++ b/x-pack/legacy/plugins/monitoring/public/components/no_data/no_data.js @@ -20,7 +20,7 @@ import { CheckerErrors } from './checker_errors'; function NoDataMessage(props) { const { isLoading, reason, checkMessage } = props; - if (isLoading && checkMessage !== null) { + if (isLoading) { return ; } diff --git a/x-pack/legacy/plugins/monitoring/public/components/no_data/reasons/reason_found.js b/x-pack/legacy/plugins/monitoring/public/components/no_data/reasons/reason_found.js index cd9dd20956cc3..af0ae7dc066e1 100644 --- a/x-pack/legacy/plugins/monitoring/public/components/no_data/reasons/reason_found.js +++ b/x-pack/legacy/plugins/monitoring/public/components/no_data/reasons/reason_found.js @@ -19,19 +19,28 @@ import { } from '../explanations'; import { FormattedMessage } from '@kbn/i18n/react'; -const ExplainWhyNoData = ({ reason, ...props }) => { +const ExplainWhyNoData = (props) => { + const { reason } = props; const { property, data, context } = reason; switch (property) { case 'xpack.monitoring.collection.enabled': - return ; + return ; case 'xpack.monitoring.collection.interval': - return ; + return ; case 'xpack.monitoring.exporters': - return ; + return ; case 'xpack.monitoring.exporters.cloud_enabled': - return ; + return ; case 'xpack.monitoring.enabled': - return ; + return ; + case 'custom': + return ( + +

+ {reason.message} +

+
+ ); default: return ( diff --git a/x-pack/legacy/plugins/monitoring/public/components/page_loading/__tests__/__snapshots__/page_loading.test.js.snap b/x-pack/legacy/plugins/monitoring/public/components/page_loading/__tests__/__snapshots__/page_loading.test.js.snap index 0d300aabc7d42..7579cad3b8beb 100644 --- a/x-pack/legacy/plugins/monitoring/public/components/page_loading/__tests__/__snapshots__/page_loading.test.js.snap +++ b/x-pack/legacy/plugins/monitoring/public/components/page_loading/__tests__/__snapshots__/page_loading.test.js.snap @@ -3,6 +3,7 @@ exports[`PageLoading should show a simple page loading component 1`] = `
+ { + let catchReason; + try { + const monitoringClustersData = await monitoringClusters(undefined, undefined, [CODE_PATH_LICENSE]); + if (monitoringClustersData && monitoringClustersData.length) { + kbnUrl.redirect('/home'); + return monitoringClustersData; + } + } + catch (err) { + if (err && err.status === 503) { + catchReason = { + property: 'custom', + message: err.data.message, + }; + } + } - constructor($injector, $scope) { - const $executor = $injector.get('$executor'); - this.enableTimefilter($executor); - this.registerCleanup($scope, $executor); + if (catchReason) { + this.reason = catchReason; + } else if (!this.isCollectionEnabledUpdating && !this.isCollectionIntervalUpdating) { + /** + * `no-use-before-define` is fine here, since getData is an async function. + * Needs to be done this way, since there is no `this` before super is executed + * */ + await startChecks(checkers, updateModel); // eslint-disable-line no-use-before-define + } + }; + super({ + title: i18n.translate('xpack.monitoring.noData.routeTitle', { + defaultMessage: 'Setup Monitoring' + }), + getPageData: async () => await getData(), + reactNodeId: 'noDataReact', + $scope, + $injector + }); Object.assign(this, this.getDefaultModel()); - this.start($scope, $injector, $executor); + + //Need to set updateModel after super since there is no `this` otherwise + const { updateModel } = new ModelUpdater($scope, this); + const enabler = new Enabler($http, updateModel); + $scope.$watch(() => this, () => this.render(enabler), true); } getDefaultModel() { return { - hasData: false, // control flag to control a redirect errors: [], // errors can happen from trying to check or set ES settings checkMessage: null, // message to show while waiting for api response isLoading: true, // flag for in-progress state of checking for no data reason @@ -48,79 +87,13 @@ export class NoDataController { }; } - /* - * Start the page logic of observing scope changes, and changes to the data model. - * @param {Object} $scope Angular $scope of the view controller - * @param {Object} $injector Angular $injector service - * @param {Object} $executor Kibana $executor service for Angular - */ - start($scope, $injector, $executor) { - const model = this; - - const $http = $injector.get('$http'); - const kbnUrl = $injector.get('kbnUrl'); - const monitoringClusters = $injector.get('monitoringClusters'); - - const { updateModel } = new ModelUpdater($scope, model); - const checkers = [ - new ClusterSettingsChecker($http), - new NodeSettingsChecker($http) - ]; - const enabler = new Enabler($http, updateModel); - - $scope.$$postDigest(() => { - startChecks(checkers, updateModel); // Start the checkers that use APIs for finding the reason for no data - }); - - $scope.$watch( - () => model, - props => { - render( - - - , - document.getElementById(REACT_NODE_ID_NO_DATA) - ); - }, - true // deep watch - ); - - $scope.$watch( - () => model.hasData, - hasData => { - if (hasData) { - kbnUrl.redirect('/home'); // redirect if to cluster overview if data is found from background refreshes - } - } + render(enabler) { + const props = this; + this.renderReact( + + + ); - - // register the monitoringClusters service. - $executor.register({ - execute: () => monitoringClusters(undefined, undefined, [CODE_PATH_LICENSE]), - handleResponse: clusters => { - if (clusters.length) { - model.hasData = true; // use the control flag because we can't redirect from inside here - } - } - }); - - $executor.start($scope); // start the executor to keep refreshing the search for data } - enableTimefilter($executor) { - timefilter.enableTimeRangeSelector(); - timefilter.enableAutoRefreshSelector(); - - // re-fetch if they change the time filter - timeUpdateSubscription = timefilter.getTimeUpdate$().subscribe(() => $executor.run()); - } - - registerCleanup($scope, $executor) { - // destroy the executor, unmount the react component - $scope.$on('$destroy', () => { - $executor.destroy(); - unmountComponentAtNode(document.getElementById(REACT_NODE_ID_NO_DATA)); - if (timeUpdateSubscription) { timeUpdateSubscription.unsubscribe(); } - }); - } } diff --git a/x-pack/legacy/plugins/monitoring/public/views/no_data/index.js b/x-pack/legacy/plugins/monitoring/public/views/no_data/index.js index bd0cee74225c6..e5a5c99cf1a96 100644 --- a/x-pack/legacy/plugins/monitoring/public/views/no_data/index.js +++ b/x-pack/legacy/plugins/monitoring/public/views/no_data/index.js @@ -7,24 +7,10 @@ import uiRoutes from 'ui/routes'; import template from './index.html'; import { NoDataController } from './controller'; -import { CODE_PATH_LICENSE } from '../../../common/constants'; + uiRoutes .when('/no-data', { template, - resolve: { - clusters: $injector => { - const monitoringClusters = $injector.get('monitoringClusters'); - const kbnUrl = $injector.get('kbnUrl'); - - return monitoringClusters(undefined, undefined, [CODE_PATH_LICENSE]).then(clusters => { - if (clusters && clusters.length) { - kbnUrl.changePath('/home'); - return Promise.reject(); - } - return Promise.resolve(); - }); - } - }, controller: NoDataController }) .otherwise({ redirectTo: '/home' }); diff --git a/x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/verify_ccs_availability.js b/x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/verify_ccs_availability.js new file mode 100644 index 0000000000000..089121337b0fb --- /dev/null +++ b/x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/verify_ccs_availability.js @@ -0,0 +1,23 @@ +/* + * 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 Boom from 'boom'; + +export async function verifyCcsAvailability(req) { + const { callWithRequest } = req.server.plugins.elasticsearch.getCluster('monitoring'); + + const response = await callWithRequest(req, 'cluster.remoteInfo'); + for (const remoteName in response) { + if (!response.hasOwnProperty(remoteName)) { + continue; + } + const remoteInfo = response[remoteName]; + if (!remoteInfo.connected) { + throw Boom.serverUnavailable(`There seems to be some issues with ${remoteName} ` + + `cluster. Please make sure it's connected and has at least one node.`); + } + } +} diff --git a/x-pack/legacy/plugins/monitoring/server/routes/api/v1/cluster/cluster.js b/x-pack/legacy/plugins/monitoring/server/routes/api/v1/cluster/cluster.js index 4746461652b0a..1157bea269335 100644 --- a/x-pack/legacy/plugins/monitoring/server/routes/api/v1/cluster/cluster.js +++ b/x-pack/legacy/plugins/monitoring/server/routes/api/v1/cluster/cluster.js @@ -8,6 +8,7 @@ import Joi from 'joi'; import { getClustersFromRequest } from '../../../../lib/cluster/get_clusters_from_request'; import { handleError } from '../../../../lib/errors'; import { getIndexPatterns } from '../../../../lib/cluster/get_index_patterns'; +import { verifyCcsAvailability } from '../../../../lib/elasticsearch/verify_ccs_availability'; import { INDEX_PATTERN_FILEBEAT } from '../../../../../common/constants'; @@ -34,7 +35,9 @@ export function clusterRoute(server) { }) } }, - handler: (req) => { + handler: async (req) => { + await verifyCcsAvailability(req); + const indexPatterns = getIndexPatterns(server, { filebeatIndexPattern: INDEX_PATTERN_FILEBEAT }); const options = { clusterUuid: req.params.clusterUuid, diff --git a/x-pack/legacy/plugins/monitoring/server/routes/api/v1/cluster/clusters.js b/x-pack/legacy/plugins/monitoring/server/routes/api/v1/cluster/clusters.js index 18daedf674cf2..a594b547e6464 100644 --- a/x-pack/legacy/plugins/monitoring/server/routes/api/v1/cluster/clusters.js +++ b/x-pack/legacy/plugins/monitoring/server/routes/api/v1/cluster/clusters.js @@ -7,6 +7,7 @@ import Joi from 'joi'; import { getClustersFromRequest } from '../../../../lib/cluster/get_clusters_from_request'; import { verifyMonitoringAuth } from '../../../../lib/elasticsearch/verify_monitoring_auth'; +import { verifyCcsAvailability } from '../../../../lib/elasticsearch/verify_ccs_availability'; import { handleError } from '../../../../lib/errors'; import { INDEX_PATTERN_FILEBEAT @@ -40,6 +41,7 @@ export function clustersRoute(server) { // the monitoring data. `try/catch` makes it a little more explicit. try { await verifyMonitoringAuth(req); + await verifyCcsAvailability(req); const indexPatterns = getIndexPatterns(server, { filebeatIndexPattern: INDEX_PATTERN_FILEBEAT }); clusters = await getClustersFromRequest(req, indexPatterns, { codePaths: req.payload.codePaths