[Monitoring] "Internal Monitoring" deprecation warning (#72020)

* Internal Monitoring deprecation

* Fixed type

* Added if cloud logic

* Fixed i18n test

* Addressed code review feedback

* Fixed types

* Changed query

* Added delay to fix a test

* Fixed tests

* Fixed text

Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
This commit is contained in:
igoristic 2020-07-27 11:10:25 -04:00 committed by GitHub
parent 02e3fca772
commit 9aa5e1772d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 245 additions and 6 deletions

View file

@ -0,0 +1,123 @@
/*
* 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 React from 'react';
import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n/react';
import { EuiSpacer, EuiLink } from '@elastic/eui';
import { Legacy } from '../legacy_shims';
import { toMountPoint } from '../../../../../src/plugins/kibana_react/public';
import { isInSetupMode, toggleSetupMode } from './setup_mode';
export interface MonitoringIndicesTypes {
legacyIndices: number;
metricbeatIndices: number;
}
const enterSetupModeLabel = () =>
i18n.translate('xpack.monitoring.internalMonitoringToast.enterSetupMode', {
defaultMessage: 'Enter setup mode',
});
const learnMoreLabel = () =>
i18n.translate('xpack.monitoring.internalMonitoringToast.learnMoreAction', {
defaultMessage: 'Learn more',
});
const showIfLegacyOnlyIndices = () => {
const { ELASTIC_WEBSITE_URL } = Legacy.shims.docLinks;
const toast = Legacy.shims.toastNotifications.addWarning({
title: toMountPoint(
<FormattedMessage
id="xpack.monitoring.internalMonitoringToast.title"
defaultMessage="Internal Monitoring Detected"
/>
),
text: toMountPoint(
<div>
<p>
{i18n.translate('xpack.monitoring.internalMonitoringToast.description', {
defaultMessage: `It appears you are using "Legacy Collection" for Stack Monitoring.
This method of monitoring will no longer be supported in the next major release (8.0.0).
Please follow the steps in setup mode to start monitoring with Metricbeat.`,
})}
</p>
<EuiLink
onClick={() => {
Legacy.shims.toastNotifications.remove(toast);
toggleSetupMode(true);
}}
>
{enterSetupModeLabel()}
</EuiLink>
<EuiSpacer />
<EuiLink
href={`${ELASTIC_WEBSITE_URL}blog/external-collection-for-elastic-stack-monitoring-is-now-available-via-metricbeat`}
external
target="_blank"
>
{learnMoreLabel()}
</EuiLink>
</div>
),
});
};
const showIfLegacyAndMetricbeatIndices = () => {
const { ELASTIC_WEBSITE_URL } = Legacy.shims.docLinks;
const toast = Legacy.shims.toastNotifications.addWarning({
title: toMountPoint(
<FormattedMessage
id="xpack.monitoring.internalAndMetricbeatMonitoringToast.title"
defaultMessage="Partial Legacy Monitoring Detected"
/>
),
text: toMountPoint(
<div>
<p>
{i18n.translate('xpack.monitoring.internalAndMetricbeatMonitoringToast.description', {
defaultMessage: `It appears you are using both Metricbeat and "Legacy Collection" for Stack Monitoring.
In 8.0.0, you must use Metricbeat to collect monitoring data.
Please follow the steps in setup mode to migrate the rest of the monitoring to Metricbeat.`,
})}
</p>
<EuiLink
onClick={() => {
Legacy.shims.toastNotifications.remove(toast);
toggleSetupMode(true);
}}
>
{enterSetupModeLabel()}
</EuiLink>
<EuiSpacer />
<EuiLink
href={`${ELASTIC_WEBSITE_URL}blog/external-collection-for-elastic-stack-monitoring-is-now-available-via-metricbeat`}
external
target="_blank"
>
{learnMoreLabel()}
</EuiLink>
</div>
),
});
};
export const showInternalMonitoringToast = ({
legacyIndices,
metricbeatIndices,
}: MonitoringIndicesTypes) => {
if (isInSetupMode()) {
return;
}
if (legacyIndices && !metricbeatIndices) {
showIfLegacyOnlyIndices();
} else if (legacyIndices && metricbeatIndices) {
showIfLegacyAndMetricbeatIndices();
}
};

View file

@ -7,6 +7,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';
function formatClusters(clusters) {
@ -21,6 +22,7 @@ function formatCluster(cluster) {
}
let once = false;
let inTransit = false;
export function monitoringClustersProvider($injector) {
return (clusterUuid, ccs, codePaths) => {
@ -63,19 +65,39 @@ export function monitoringClustersProvider($injector) {
});
}
if (!once) {
function ensureMetricbeatEnabled() {
if (Legacy.shims.isCloud) {
return Promise.resolve();
}
return $http
.get('../api/monitoring/v1/elasticsearch_settings/check/internal_monitoring')
.then(({ data }) => {
showInternalMonitoringToast({
legacyIndices: data.legacy_indices,
metricbeatIndices: data.mb_indices,
});
})
.catch((err) => {
const Private = $injector.get('Private');
const ajaxErrorHandlers = Private(ajaxErrorHandlersProvider);
return ajaxErrorHandlers(err);
});
}
if (!once && !inTransit) {
inTransit = true;
return getClusters().then((clusters) => {
if (clusters.length) {
return ensureAlertsEnabled()
.then(({ data }) => {
Promise.all([ensureAlertsEnabled(), ensureMetricbeatEnabled()])
.then(([{ data }]) => {
showSecurityToast(data);
once = true;
return clusters;
})
.catch(() => {
// Intentionally swallow the error as this will retry the next page load
return clusters;
});
})
.finally(() => (inTransit = false));
}
return clusters;
});

View file

@ -0,0 +1,85 @@
/*
* 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 { RequestHandlerContext } from 'kibana/server';
// @ts-ignore
import { getIndexPatterns } from '../../../../../lib/cluster/get_index_patterns';
// @ts-ignore
import { handleError } from '../../../../../lib/errors';
import { RouteDependencies } from '../../../../../types';
const queryBody = {
size: 0,
aggs: {
types: {
terms: {
field: '_index',
size: 10,
},
},
},
};
const checkLatestMonitoringIsLegacy = async (context: RequestHandlerContext, index: string) => {
const { client: esClient } = context.core.elasticsearch.legacy;
const result = await esClient.callAsCurrentUser('search', {
index,
body: queryBody,
});
const { aggregations } = result;
const counts = {
legacyIndicesCount: 0,
mbIndicesCount: 0,
};
if (!aggregations) {
return counts;
}
const {
types: { buckets },
} = aggregations;
counts.mbIndicesCount = buckets.filter(({ key }: { key: string }) => key.includes('-mb-')).length;
counts.legacyIndicesCount = buckets.length - counts.mbIndicesCount;
return counts;
};
export function internalMonitoringCheckRoute(server: unknown, npRoute: RouteDependencies) {
npRoute.router.get(
{
path: '/api/monitoring/v1/elasticsearch_settings/check/internal_monitoring',
validate: false,
},
async (context, _request, response) => {
try {
const typeCount = {
legacy_indices: 0,
mb_indices: 0,
};
const { esIndexPattern, kbnIndexPattern, lsIndexPattern } = getIndexPatterns(server);
const indexCounts = await Promise.all([
checkLatestMonitoringIsLegacy(context, esIndexPattern),
checkLatestMonitoringIsLegacy(context, kbnIndexPattern),
checkLatestMonitoringIsLegacy(context, lsIndexPattern),
]);
indexCounts.forEach((counts) => {
typeCount.legacy_indices += counts.legacyIndicesCount;
typeCount.mb_indices += counts.mbIndicesCount;
});
return response.ok({
body: typeCount,
});
} catch (err) {
throw handleError(err);
}
}
);
}

View file

@ -4,6 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/
export { internalMonitoringCheckRoute } from './check/internal_monitoring';
export { clusterSettingsCheckRoute } from './check/cluster';
export { nodesSettingsCheckRoute } from './check/nodes';
export { setCollectionEnabledRoute } from './set/collection_enabled';

View file

@ -20,6 +20,7 @@ export {
ccrShardRoute,
} from './elasticsearch';
export {
internalMonitoringCheckRoute,
clusterSettingsCheckRoute,
nodesSettingsCheckRoute,
setCollectionEnabledRoute,

View file

@ -7,6 +7,8 @@
import expect from '@kbn/expect';
import { getLifecycleMethods } from './_get_lifecycle_methods';
const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
export default function ({ getService, getPageObjects }) {
const PageObjects = getPageObjects(['header', 'timePicker']);
const testSubjects = getService('testSubjects');
@ -35,6 +37,11 @@ export default function ({ getService, getPageObjects }) {
});
it('should send another request when changing the time picker', async () => {
/**
* TODO: The value should either be removed or lowered after:
* https://github.com/elastic/kibana/issues/72997 is resolved
*/
await delay(3000);
await PageObjects.timePicker.setAbsoluteRange(
'Aug 15, 2016 @ 21:00:00.000',
'Aug 16, 2016 @ 00:00:00.000'