Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import {
EuiHorizontalRule,
EuiFlexGroup,
EuiToolTip,
EuiBadge
EuiIcon
} from '@elastic/eui';
import { formatTimestampToDuration } from '../../../../common';
import { CALCULATE_DURATION_SINCE } from '../../../../common/constants';
Expand All @@ -39,35 +39,47 @@ export function ApmPanel(props) {
const goToApm = () => props.changeUrl('apm');
const goToInstances = () => props.changeUrl('apm/instances');

const setupModeApmData = get(setupMode.data, 'apm');
const setupModeAPMData = get(setupMode.data, 'apm');
let setupModeInstancesData = null;
if (setupMode.enabled && setupMode.data) {
const migratedNodesCount = Object.values(setupModeApmData.byUuid).filter(node => node.isFullyMigrated).length;
let totalNodesCount = Object.values(setupModeApmData.byUuid).length;
if (totalNodesCount === 0 && get(setupMode.data, 'apm.detected.mightExist', false)) {
totalNodesCount = 1;
}
const {
totalUniqueInstanceCount,
totalUniqueFullyMigratedCount,
totalUniquePartiallyMigratedCount
} = setupModeAPMData;
const hasInstances = totalUniqueInstanceCount > 0 || get(setupModeAPMData, 'detected.mightExist', false);
const allMonitoredByMetricbeat = totalUniqueInstanceCount > 0 &&
(totalUniqueFullyMigratedCount === totalUniqueInstanceCount || totalUniquePartiallyMigratedCount === totalUniqueInstanceCount);
const internalCollectionOn = totalUniquePartiallyMigratedCount > 0;
if (hasInstances && (!allMonitoredByMetricbeat || internalCollectionOn)) {
let tooltipText = null;

const badgeColor = migratedNodesCount === totalNodesCount
? 'secondary'
: 'danger';
if (!allMonitoredByMetricbeat) {
tooltipText = i18n.translate('xpack.monitoring.cluster.overview.apmPanel.setupModeNodesTooltip.oneInternal', {
defaultMessage: `There's at least one server that isn't being monitored using Metricbeat. Click the flag
icon to visit the servers listing page and find out more information about the status of each server.`
});
}
else if (internalCollectionOn) {
tooltipText = i18n.translate('xpack.monitoring.cluster.overview.apmPanel.setupModeNodesTooltip.disableInternal', {
defaultMessage: `All servers are being monitored using Metricbeat but internal collection still needs to be turned
off. Click the flag icon to visit the servers listing page and disable internal collection.`
});
}

setupModeInstancesData = (
<EuiFlexItem grow={false}>
<EuiToolTip
position="top"
content={i18n.translate('xpack.monitoring.cluster.overview.apmPanel.setupModeNodesTooltip', {
defaultMessage: `These numbers indicate how many detected monitored APM servers versus how many ` +
`detected total APM servers. If there are more detected APM servers than monitored APM servers, click the Nodes ` +
`link and you will be guided in how to setup monitoring for the missing node.`
})}
>
<EuiBadge color={badgeColor}>
{migratedNodesCount}/{totalNodesCount}
</EuiBadge>
</EuiToolTip>
</EuiFlexItem>
);
setupModeInstancesData = (
<EuiFlexItem grow={false}>
<EuiToolTip
position="top"
content={tooltipText}
>
<EuiLink onClick={goToInstances}>
<EuiIcon type="flag" color="warning"/>
</EuiLink>
</EuiToolTip>
</EuiFlexItem>
);
}
}

return (
Expand All @@ -85,7 +97,7 @@ export function ApmPanel(props) {
<h3>
<DisabledIfNoDataAndInSetupModeLink
setupModeEnabled={setupMode.enabled}
setupModeData={setupModeApmData}
setupModeData={setupModeAPMData}
onClick={goToApm}
aria-label={i18n.translate('xpack.monitoring.cluster.overview.apmPanel.overviewLinkAriaLabel', {
defaultMessage: 'APM Overview'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import {
EuiHorizontalRule,
EuiFlexGroup,
EuiToolTip,
EuiBadge
EuiIcon
} from '@elastic/eui';
import { ClusterItemContainer, DisabledIfNoDataAndInSetupModeLink } from './helpers';
import { FormattedMessage } from '@kbn/i18n/react';
Expand All @@ -39,32 +39,44 @@ export function BeatsPanel(props) {
const setupModeBeatsData = get(setupMode.data, 'beats');
let setupModeInstancesData = null;
if (setupMode.enabled && setupMode.data) {
const migratedNodesCount = Object.values(setupModeBeatsData.byUuid).filter(node => node.isFullyMigrated).length;
let totalNodesCount = Object.values(setupModeBeatsData.byUuid).length;
if (totalNodesCount === 0 && get(setupMode.data, 'beats.detected.mightExist', false)) {
totalNodesCount = 1;
}
const {
totalUniqueInstanceCount,
totalUniqueFullyMigratedCount,
totalUniquePartiallyMigratedCount
} = setupModeBeatsData;
const hasInstances = totalUniqueInstanceCount > 0 || get(setupModeBeatsData, 'detected.mightExist', false);
const allMonitoredByMetricbeat = totalUniqueInstanceCount > 0 &&
(totalUniqueFullyMigratedCount === totalUniqueInstanceCount || totalUniquePartiallyMigratedCount === totalUniqueInstanceCount);
const internalCollectionOn = totalUniquePartiallyMigratedCount > 0;
if (hasInstances && (!allMonitoredByMetricbeat || internalCollectionOn)) {
let tooltipText = null;

const badgeColor = migratedNodesCount === totalNodesCount
? 'secondary'
: 'danger';
if (!allMonitoredByMetricbeat) {
tooltipText = i18n.translate('xpack.monitoring.cluster.overview.beatsPanel.setupModeNodesTooltip.oneInternal', {
defaultMessage: `There's at least one instance that isn't being monitored using Metricbeat. Click the flag
icon to visit the instances listing page and find out more information about the status of each instance.`
});
}
else if (internalCollectionOn) {
tooltipText = i18n.translate('xpack.monitoring.cluster.overview.beatsPanel.setupModeNodesTooltip.disableInternal', {
defaultMessage: `All instances are being monitored using Metricbeat but internal collection still needs to be turned
off. Click the flag icon to visit the instances listing page and disable internal collection.`
});
}

setupModeInstancesData = (
<EuiFlexItem grow={false}>
<EuiToolTip
position="top"
content={i18n.translate('xpack.monitoring.cluster.overview.beatsPanel.setupModeNodesTooltip', {
defaultMessage: `These numbers indicate how many detected monitored Beats versus how many ` +
`detected total Beats. If there are more detected Beats than monitored Beats, click the Nodes ` +
`link and you will be guided in how to setup monitoring for the missing node.`
})}
>
<EuiBadge color={badgeColor}>
{migratedNodesCount}/{totalNodesCount}
</EuiBadge>
</EuiToolTip>
</EuiFlexItem>
);
setupModeInstancesData = (
<EuiFlexItem grow={false}>
<EuiToolTip
position="top"
content={tooltipText}
>
<EuiLink onClick={goToInstances}>
<EuiIcon type="flag" color="warning"/>
</EuiLink>
</EuiToolTip>
</EuiFlexItem>
);
}
}

const beatTypes = props.beats.types.map((beat, index) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import {
EuiHorizontalRule,
EuiIconTip,
EuiToolTip,
EuiBadge
EuiIcon
} from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n/react';
import { i18n } from '@kbn/i18n';
Expand All @@ -45,32 +45,44 @@ export function LogstashPanel(props) {
const setupModeLogstashData = get(setupMode.data, 'logstash');
let setupModeInstancesData = null;
if (setupMode.enabled && setupMode.data) {
const migratedNodesCount = Object.values(setupModeLogstashData.byUuid).filter(node => node.isFullyMigrated).length;
let totalNodesCount = Object.values(setupModeLogstashData.byUuid).length;
if (totalNodesCount === 0 && get(setupMode.data, 'logstash.detected.mightExist', false)) {
totalNodesCount = 1;
}
const {
totalUniqueInstanceCount,
totalUniqueFullyMigratedCount,
totalUniquePartiallyMigratedCount
} = setupModeLogstashData;
const hasInstances = totalUniqueInstanceCount > 0 || get(setupModeLogstashData, 'detected.mightExist', false);
const allMonitoredByMetricbeat = totalUniqueInstanceCount > 0 &&
(totalUniqueFullyMigratedCount === totalUniqueInstanceCount || totalUniquePartiallyMigratedCount === totalUniqueInstanceCount);
const internalCollectionOn = totalUniquePartiallyMigratedCount > 0;
if (hasInstances && (!allMonitoredByMetricbeat || internalCollectionOn)) {
let tooltipText = null;

const badgeColor = migratedNodesCount === totalNodesCount
? 'secondary'
: 'danger';
if (!allMonitoredByMetricbeat) {
tooltipText = i18n.translate('xpack.monitoring.cluster.overview.logstashPanel.setupModeNodesTooltip.oneInternal', {
defaultMessage: `There's at least one node that isn't being monitored using Metricbeat. Click the flag
icon to visit the nodes listing page and find out more information about the status of each node.`
});
}
else if (internalCollectionOn) {
tooltipText = i18n.translate('xpack.monitoring.cluster.overview.logstashPanel.setupModeNodesTooltip.disableInternal', {
defaultMessage: `All nodes are being monitored using Metricbeat but internal collection still needs to be turned
off. Click the flag icon to visit the nodes listing page and disable internal collection.`
});
}

setupModeInstancesData = (
<EuiFlexItem grow={false}>
<EuiToolTip
position="top"
content={i18n.translate('xpack.monitoring.cluster.overview.logstashPanel.setupModeNodesTooltip', {
defaultMessage: `These numbers indicate how many detected monitored nodes versus how many ` +
`detected total nodes. If there are more detected nodes than monitored nodes, click the Nodes ` +
`link and you will be guided in how to setup monitoring for the missing node.`
})}
>
<EuiBadge color={badgeColor}>
{formatNumber(migratedNodesCount, 'int_commas')}/{formatNumber(totalNodesCount, 'int_commas')}
</EuiBadge>
</EuiToolTip>
</EuiFlexItem>
);
setupModeInstancesData = (
<EuiFlexItem grow={false}>
<EuiToolTip
position="top"
content={tooltipText}
>
<EuiLink onClick={goToNodes}>
<EuiIcon type="flag" color="warning"/>
</EuiLink>
</EuiToolTip>
</EuiFlexItem>
);
}
}

return (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,7 @@ const getColumns = (showCgroupMetricsElasticsearch, setupMode) => {
};

export function ElasticsearchNodes({ clusterStatus, showCgroupMetricsElasticsearch, ...props }) {
const { sorting, pagination, onTableChange, setupMode } = props;
const { sorting, pagination, onTableChange, clusterUuid, setupMode } = props;
const columns = getColumns(showCgroupMetricsElasticsearch, setupMode);

// Merge the nodes data with the setup data if enabled
Expand Down Expand Up @@ -251,6 +251,10 @@ export function ElasticsearchNodes({ clusterStatus, showCgroupMetricsElasticsear
// Think net new user scenario
const hasInstances = setupMode.data.totalUniqueInstanceCount > 0;
if (hasInstances && setupMode.data.totalUniquePartiallyMigratedCount === setupMode.data.totalUniqueInstanceCount) {
const finishMigrationAction = _.get(setupMode.meta, 'liveClusterUuid') === clusterUuid
? setupMode.shortcutToFinishMigration
: setupMode.openFlyout;

disableInternalCollectionForMigrationMessage = (
<Fragment>
<EuiCallOut
Expand All @@ -266,7 +270,7 @@ export function ElasticsearchNodes({ clusterStatus, showCgroupMetricsElasticsear
but you need to disable internal collection to finish the migration.`
})}
</p>
<EuiButton onClick={() => setupMode.openFlyout()} size="s" color="warning" fill>
<EuiButton onClick={finishMigrationAction} size="s" color="warning" fill>
{i18n.translate('xpack.monitoring.elasticsearch.nodes.metribeatMigration.disableInternalCollectionMigrationButtonLabel', {
defaultMessage: 'Disable and finish migration'
})}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,22 +27,18 @@ import {
import { getInstructionSteps } from '../instruction_steps';
import { Storage } from 'ui/storage';
import { STORAGE_KEY, ELASTICSEARCH_CUSTOM_ID } from '../../../../common/constants';
import { ensureMinimumTime } from '../../../lib/ensure_minimum_time';
import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n/react';
import { get } from 'lodash';
import {
INSTRUCTION_STEP_SET_MONITORING_URL,
INSTRUCTION_STEP_ENABLE_METRICBEAT,
INSTRUCTION_STEP_DISABLE_INTERNAL
} from '../constants';
import { KIBANA_SYSTEM_ID, BEATS_SYSTEM_ID } from '../../../../../telemetry/common/constants';
import { ELASTIC_WEBSITE_URL, DOC_LINK_VERSION } from 'ui/documentation_links';
import { setNewlyDiscoveredClusterUuid } from '../../../lib/setup_mode';

const storage = new Storage(window.localStorage);
const ES_MONITORING_URL_KEY = `${STORAGE_KEY}.mb_migration.esMonitoringUrl`;
const AUTO_CHECK_INTERVAL_IN_MS = 5000;
const DEFAULT_ES_MONITORING_URL = 'http://localhost:9200';

export class Flyout extends Component {
Expand All @@ -67,66 +63,18 @@ export class Flyout extends Component {
checkedStatusByStep: {
[INSTRUCTION_STEP_ENABLE_METRICBEAT]: false,
[INSTRUCTION_STEP_DISABLE_INTERNAL]: false,
userAcknowledgedNoClusterUuidPrompt: false
},
checkingMigrationStatus: false,
userAcknowledgedNoClusterUuidPrompt: false
};
}

componentWillUpdate(_nextProps, nextState) {
// We attempt to provide a better UX for the user by automatically rechecking
// the status of their current step, once they have initiated a check manually.
// The logic here aims to remove the recheck one they have moved on from the
// step

const thisActiveStep = this.state.activeStep;
const nextActiveStep = nextState.activeStep;
const nextEnableMbStatus = nextState.checkedStatusByStep[INSTRUCTION_STEP_ENABLE_METRICBEAT];
const nowEnableMbStatus = this.state.checkedStatusByStep[INSTRUCTION_STEP_ENABLE_METRICBEAT];
const nextDisableInternalStatus = nextState.checkedStatusByStep[INSTRUCTION_STEP_DISABLE_INTERNAL];
const nowDisableInternalStatus = this.state.checkedStatusByStep[INSTRUCTION_STEP_DISABLE_INTERNAL];

const setupInterval = (nextEnableMbStatus && !nowEnableMbStatus) || (nextDisableInternalStatus && !nowDisableInternalStatus);
const removeInterval = thisActiveStep !== nextActiveStep;
if (removeInterval) {
clearInterval(this.checkInterval);
this.clearInterval = null;
}

if (setupInterval) {
this.checkInterval = setInterval(async () => {
await this.checkForMigrationStatus();
}, AUTO_CHECK_INTERVAL_IN_MS);
}
}

componentWillUnmount() {
clearInterval(this.checkInterval);
}

checkForMigrationStatus = async () => {
this.setState({ checkingMigrationStatus: true });
await ensureMinimumTime(
this.props.updateProduct(this.props.instance.uuid, true), 1000
);
this.setState(state => ({
...state,
checkingMigrationStatus: false,
checkedStatusByStep: {
...state.checkedStatusByStep,
[this.state.activeStep]: true,
}
}));
}

setEsMonitoringUrl = esMonitoringUrl => {
storage.set(ES_MONITORING_URL_KEY, esMonitoringUrl);
this.setState({ esMonitoringUrl });
}

finishedFlyout() {
const { onClose, meta } = this.props;
setNewlyDiscoveredClusterUuid(get(meta, 'clusterUuid'));
const { onClose } = this.props;
onClose();
}

Expand All @@ -136,7 +84,6 @@ export class Flyout extends Component {
activeStep,
esMonitoringUrl,
checkedStatusByStep,
checkingMigrationStatus,
} = this.state;

switch (activeStep) {
Expand Down Expand Up @@ -166,10 +113,7 @@ export class Flyout extends Component {
const instructionSteps = getInstructionSteps(productName, product, activeStep, meta, {
doneWithMigration: onClose,
esMonitoringUrl,
checkForMigrationStatus: this.checkForMigrationStatus,
checkingMigrationStatus,
hasCheckedStatus: checkedStatusByStep[activeStep],
autoCheckIntervalInMs: AUTO_CHECK_INTERVAL_IN_MS,
});

return (
Expand Down
Loading