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