"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.ElasticsearchNodes = ElasticsearchNodes; var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends")); var _eui = require("@elastic/eui"); var _i18n = require("@kbn/i18n"); var _i18nReact = require("@kbn/i18n-react"); var _lodash = require("lodash"); var _react = _interopRequireWildcard(require("react")); var _constants = require("../../../../common/constants"); var _enums = require("../../../../common/enums"); var _status = require("../../../alerts/status"); var _extract_ip = require("../../../lib/extract_ip"); var _get_safe_for_external_link = require("../../../lib/get_safe_for_external_link"); var _setup_mode = require("../../../lib/setup_mode"); var _badge = require("../../setup_mode/badge"); var _listing_callout = require("../../setup_mode/listing_callout"); var _table = require("../../table"); var _cluster_status = require("../cluster_status"); var _cells = require("./cells"); function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); } function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; } /* * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one * or more contributor license agreements. Licensed under the Elastic License * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ // TODO this is only used for elasticsearch nodes summary / node detail, so it should be moved to components/elasticsearch/nodes/lib const getNodeTooltip = node => { const { nodeTypeLabel, nodeTypeClass } = node; const nodeTypeLabelContent = nodeTypeLabel || _i18n.i18n.translate('xpack.monitoring.elasticsearch.nodes.unknownNodeTypeLabel', { defaultMessage: 'Unknown' }); const nodeTypeClassIcon = nodeTypeClass || 'empty'; if (nodeTypeLabel) { return /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/_react.default.createElement(_eui.EuiToolTip, { position: "bottom", content: nodeTypeLabelContent }, /*#__PURE__*/_react.default.createElement(_eui.EuiIcon, { type: nodeTypeClassIcon })), ' ', "\xA0"); } return null; }; const getSortHandler = type => item => (0, _lodash.get)(item, [type, 'summary', 'lastVal']); const getColumns = (showCgroupMetricsElasticsearch, setupMode, clusterUuid, alerts) => { const cols = []; const cpuUsageColumnTitle = _i18n.i18n.translate('xpack.monitoring.elasticsearch.nodes.cpuUsageColumnTitle', { defaultMessage: 'CPU Usage' }); cols.push({ name: _i18n.i18n.translate('xpack.monitoring.elasticsearch.nodes.nameColumnTitle', { defaultMessage: 'Name' }), field: 'name', sortable: true, render: (value, node) => { let nameLink = /*#__PURE__*/_react.default.createElement(_eui.EuiLink, { href: (0, _get_safe_for_external_link.getSafeForExternalLink)(`#/elasticsearch/nodes/${node.resolver}`), "data-test-subj": `nodeLink-${node.resolver}` }, value); let setupModeStatus = null; if ((0, _setup_mode.isSetupModeFeatureEnabled)(_enums.SetupModeFeature.MetricbeatMigration)) { const list = (0, _lodash.get)(setupMode, 'data.byUuid', {}); const status = list[node.resolver] || {}; const instance = { uuid: node.resolver, name: node.name }; setupModeStatus = /*#__PURE__*/_react.default.createElement("div", { className: "monTableCell__setupModeStatus" }, /*#__PURE__*/_react.default.createElement(_badge.SetupModeBadge, { setupMode: setupMode, status: status, instance: instance, productName: _constants.ELASTICSEARCH_SYSTEM_ID, clusterUuid: clusterUuid })); if (status.isNetNewUser) { nameLink = value; } } return /*#__PURE__*/_react.default.createElement("div", null, /*#__PURE__*/_react.default.createElement("div", { className: "monTableCell__name" }, /*#__PURE__*/_react.default.createElement(_eui.EuiText, { size: "m" }, getNodeTooltip(node), /*#__PURE__*/_react.default.createElement("span", { "data-test-subj": "name" }, nameLink))), /*#__PURE__*/_react.default.createElement("div", { className: "monTableCell__transportAddress" }, (0, _extract_ip.extractIp)(node.transport_address)), setupModeStatus); } }); cols.push({ name: _i18n.i18n.translate('xpack.monitoring.elasticsearch.nodes.alertsColumnTitle', { defaultMessage: 'Alerts' }), field: 'alerts', sortable: true, render: (_field, node) => { return /*#__PURE__*/_react.default.createElement(_status.AlertsStatus, { showBadge: true, alerts: alerts, stateFilter: state => (state.nodeId || state.nodeUuid) === node.resolver }); } }); cols.push({ name: _i18n.i18n.translate('xpack.monitoring.elasticsearch.nodes.statusColumnTitle', { defaultMessage: 'Status' }), dataType: 'boolean', field: 'isOnline', sortable: true, render: value => { const status = value ? _i18n.i18n.translate('xpack.monitoring.elasticsearch.nodes.statusColumn.onlineLabel', { defaultMessage: 'Online' }) : _i18n.i18n.translate('xpack.monitoring.elasticsearch.nodes.statusColumn.offlineLabel', { defaultMessage: 'Offline' }); return /*#__PURE__*/_react.default.createElement(_eui.EuiToolTip, { content: status, position: "bottom", trigger: "hover" }, /*#__PURE__*/_react.default.createElement(_eui.EuiHealth, { color: value ? 'success' : 'subdued', "data-test-subj": "statusIcon", alt: _i18n.i18n.translate('xpack.monitoring.elasticsearch.nodes.healthAltIcon', { defaultMessage: 'Status: {status}', values: { status } }) }, status)); } }); cols.push({ name: _i18n.i18n.translate('xpack.monitoring.elasticsearch.nodes.rolesColumnTitle', { defaultMessage: 'Roles' }), field: 'roles', render: roles => { if (!roles) { return _i18n.i18n.translate('xpack.monitoring.formatNumbers.notAvailableLabel', { defaultMessage: 'N/A' }); } if (roles.length === 0) { return /*#__PURE__*/_react.default.createElement(_eui.EuiBadge, null, _i18n.i18n.translate('xpack.monitoring.elasticsearch.nodes.coordinatingNodeLabel', { defaultMessage: 'coordinating only' })); } const head = roles.slice(0, 5); const tail = roles.slice(5); const hasMoreRoles = tail.length > 0; return /*#__PURE__*/_react.default.createElement(_eui.EuiBadgeGroup, { gutterSize: "xs" }, head.map(role => /*#__PURE__*/_react.default.createElement(_eui.EuiBadge, { color: role === 'master' ? 'hollow' : 'default' }, role)), hasMoreRoles && /*#__PURE__*/_react.default.createElement(_eui.EuiToolTip, { anchorProps: { style: { lineHeight: '1' } }, position: "bottom", content: tail.join(', ') }, /*#__PURE__*/_react.default.createElement(_eui.EuiBadge, null, "+", tail.length))); } }); cols.push({ name: _i18n.i18n.translate('xpack.monitoring.elasticsearch.nodes.shardsColumnTitle', { defaultMessage: 'Shards' }), dataType: 'number', field: 'shardCount', sortable: true, render: (value, node) => { return node.isOnline ? /*#__PURE__*/_react.default.createElement("span", { "data-test-subj": "shards" }, value) : /*#__PURE__*/_react.default.createElement(_cells.OfflineCell, null); } }); if (showCgroupMetricsElasticsearch) { cols.push({ name: cpuUsageColumnTitle, dataType: 'number', field: 'node_cgroup_quota', sortable: getSortHandler('node_cgroup_quota'), render: (value, node) => /*#__PURE__*/_react.default.createElement(_cells.MetricCell, { isOnline: node.isOnline, metric: value, isPercent: true, "data-test-subj": "cpuQuota" }) }); cols.push({ name: _i18n.i18n.translate('xpack.monitoring.elasticsearch.nodes.cpuThrottlingColumnTitle', { defaultMessage: 'CPU Throttling' }), dataType: 'number', field: 'node_cgroup_throttled', sortable: getSortHandler('node_cgroup_throttled'), render: (value, node) => /*#__PURE__*/_react.default.createElement(_cells.MetricCell, { isOnline: node.isOnline, metric: value, isPercent: false, "data-test-subj": "cpuThrottled" }) }); } else { cols.push({ name: cpuUsageColumnTitle, dataType: 'number', field: 'node_cpu_utilization', sortable: getSortHandler('node_cpu_utilization'), render: (value, node) => { return /*#__PURE__*/_react.default.createElement(_cells.MetricCell, { isOnline: node.isOnline, metric: value, isPercent: true, "data-test-subj": "cpuUsage" }); } }); cols.push({ name: _i18n.i18n.translate('xpack.monitoring.elasticsearch.nodes.loadAverageColumnTitle', { defaultMessage: 'Load Average' }), dataType: 'number', field: 'node_load_average', sortable: getSortHandler('node_load_average'), render: (value, node) => /*#__PURE__*/_react.default.createElement(_cells.MetricCell, { isOnline: node.isOnline, metric: value, isPercent: false, "data-test-subj": "loadAverage" }) }); } cols.push({ name: _i18n.i18n.translate('xpack.monitoring.elasticsearch.nodes.jvmMemoryColumnTitle', { defaultMessage: '{javaVirtualMachine} Heap', values: { javaVirtualMachine: 'JVM' } }), dataType: 'number', field: 'node_jvm_mem_percent', sortable: getSortHandler('node_jvm_mem_percent'), render: (value, node) => /*#__PURE__*/_react.default.createElement(_cells.MetricCell, { isOnline: node.isOnline, metric: value, isPercent: true, "data-test-subj": "jvmMemory" }) }); cols.push({ name: _i18n.i18n.translate('xpack.monitoring.elasticsearch.nodes.diskFreeSpaceColumnTitle', { defaultMessage: 'Disk Free Space' }), dataType: 'number', field: 'node_free_space', sortable: getSortHandler('node_free_space'), render: (value, node) => /*#__PURE__*/_react.default.createElement(_cells.MetricCell, { isOnline: node.isOnline, metric: value, isPercent: false, "data-test-subj": "diskFreeSpace" }) }); return cols; }; function ElasticsearchNodes({ clusterStatus, showCgroupMetricsElasticsearch, ...props }) { const { sorting, pagination, onTableChange, clusterUuid, setupMode, alerts } = props; const columns = getColumns(showCgroupMetricsElasticsearch, setupMode, clusterUuid, alerts); // Merge the nodes data with the setup data if enabled const nodes = props.nodes || []; if (setupMode && setupMode.enabled && (0, _setup_mode.isSetupModeFeatureEnabled)(_enums.SetupModeFeature.MetricbeatMigration)) { // We want to create a seamless experience for the user by merging in the setup data // and the node data from monitoring indices in the likely scenario where some nodes // are using MB collection and some are using no collection const nodesByUuid = nodes.reduce((byUuid, node) => ({ ...byUuid, [node.id || node.resolver]: node }), {}); nodes.push(...Object.entries(setupMode.data.byUuid).reduce((nodes, [nodeUuid, instance]) => { if (!nodesByUuid[nodeUuid] && instance.node) { nodes.push(instance.node); } return nodes; }, [])); } let setupModeCallout = null; if ((0, _setup_mode.isSetupModeFeatureEnabled)(_enums.SetupModeFeature.MetricbeatMigration)) { setupModeCallout = /*#__PURE__*/_react.default.createElement(_listing_callout.ListingCallOut, { setupModeData: setupMode.data, useNodeIdentifier: true, productName: _constants.ELASTICSEARCH_SYSTEM_ID, customRenderer: () => { const customRenderResponse = { shouldRender: false, componentToRender: null }; const isNetNewUser = setupMode.data.totalUniqueInstanceCount === 0; const hasNoInstances = setupMode.data.totalUniqueInternallyCollectedCount === 0 && setupMode.data.totalUniqueFullyMigratedCount === 0 && setupMode.data.totalUniquePartiallyMigratedCount === 0; if (isNetNewUser || hasNoInstances) { customRenderResponse.shouldRender = true; customRenderResponse.componentToRender = /*#__PURE__*/_react.default.createElement(_react.Fragment, null, /*#__PURE__*/_react.default.createElement(_eui.EuiCallOut, { title: _i18n.i18n.translate('xpack.monitoring.elasticsearch.nodes.metricbeatMigration.detectedNodeTitle', { defaultMessage: 'Elasticsearch node detected' }), color: setupMode.data.totalUniqueInstanceCount > 0 ? 'danger' : 'warning', iconType: "flag" }, /*#__PURE__*/_react.default.createElement("p", null, _i18n.i18n.translate('xpack.monitoring.elasticsearch.nodes.metricbeatMigration.detectedNodeDescription', { defaultMessage: `The following nodes are not monitored. Click 'Monitor with Metricbeat' below to start monitoring.` }))), /*#__PURE__*/_react.default.createElement(_eui.EuiSpacer, { size: "m" })); } else if (setupMode.data.totalUniquePartiallyMigratedCount === setupMode.data.totalUniqueInstanceCount) { const finishMigrationAction = (0, _lodash.get)(setupMode.meta, 'liveClusterUuid') === clusterUuid ? setupMode.shortcutToFinishMigration : setupMode.openFlyout; customRenderResponse.shouldRender = true; customRenderResponse.componentToRender = /*#__PURE__*/_react.default.createElement(_react.Fragment, null, /*#__PURE__*/_react.default.createElement(_eui.EuiCallOut, { title: _i18n.i18n.translate('xpack.monitoring.elasticsearch.nodes.metricbeatMigration.disableInternalCollectionTitle', { defaultMessage: 'Metricbeat is now monitoring your Elasticsearch nodes' }), color: "warning", iconType: "flag" }, /*#__PURE__*/_react.default.createElement("p", null, _i18n.i18n.translate('xpack.monitoring.elasticsearch.nodes.metricbeatMigration.disableInternalCollectionDescription', { defaultMessage: `Disable self monitoring to finish the migration.` })), /*#__PURE__*/_react.default.createElement(_eui.EuiButton, { onClick: finishMigrationAction, size: "s", color: "warning", fill: true }, _i18n.i18n.translate('xpack.monitoring.elasticsearch.nodes.metricbeatMigration.disableInternalCollectionMigrationButtonLabel', { defaultMessage: 'Disable self monitoring' }))), /*#__PURE__*/_react.default.createElement(_eui.EuiSpacer, { size: "m" })); } return customRenderResponse; } }); } function renderClusterStatus() { if (!clusterStatus) { return null; } return /*#__PURE__*/_react.default.createElement(_react.Fragment, null, /*#__PURE__*/_react.default.createElement(_eui.EuiPanel, null, /*#__PURE__*/_react.default.createElement(_cluster_status.ClusterStatus, { stats: clusterStatus, alerts: alerts })), /*#__PURE__*/_react.default.createElement(_eui.EuiSpacer, { size: "m" })); } return /*#__PURE__*/_react.default.createElement(_eui.EuiPage, null, /*#__PURE__*/_react.default.createElement(_eui.EuiPageBody, null, /*#__PURE__*/_react.default.createElement(_eui.EuiScreenReaderOnly, null, /*#__PURE__*/_react.default.createElement("h1", null, /*#__PURE__*/_react.default.createElement(_i18nReact.FormattedMessage, { id: "xpack.monitoring.elasticsearch.nodes.heading", defaultMessage: "Elasticsearch nodes" }))), renderClusterStatus(), setupModeCallout, /*#__PURE__*/_react.default.createElement(_eui.EuiPanel, null, /*#__PURE__*/_react.default.createElement(_table.EuiMonitoringSSPTable, (0, _extends2.default)({ className: "elasticsearchNodesTable", rows: nodes, columns: columns, sorting: sorting, pagination: pagination, setupMode: setupMode, productName: _constants.ELASTICSEARCH_SYSTEM_ID, search: { box: { incremental: true, placeholder: _i18n.i18n.translate('xpack.monitoring.elasticsearch.nodes.monitoringTablePlaceholder', { defaultMessage: 'Filter Nodes…' }) } }, onTableChange: onTableChange }, props))))); }