mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 01:13:23 -04:00
[Monitoring] Display node roles in Nodes table (#152127)
Fixes #151818 <img width="2863" alt="Screenshot 2023-02-24 at 17 29 44" src="https://user-images.githubusercontent.com/2564140/221235055-5742b3d3-522d-4677-9c2d-18bcd860d0b8.png"> Related PR: https://github.com/elastic/beats/pull/34668 --------- Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
parent
d762a2a6bb
commit
118609b18d
7 changed files with 146 additions and 26 deletions
|
@ -417,6 +417,7 @@ export interface ElasticsearchMetricbeatNode {
|
|||
name?: string;
|
||||
stats?: ElasticsearchNodeStats;
|
||||
master: boolean;
|
||||
roles?: string[];
|
||||
}
|
||||
|
||||
export interface ElasticsearchMetricbeatSource {
|
||||
|
|
|
@ -29,6 +29,35 @@ import {
|
|||
RULE_MISSING_MONITORING_DATA,
|
||||
} from '../../../../common/constants';
|
||||
|
||||
type ElasticsearchNodeRole =
|
||||
| 'master'
|
||||
| 'voting_only'
|
||||
| 'data'
|
||||
| 'data_content'
|
||||
| 'data_hot'
|
||||
| 'data_warm'
|
||||
| 'data_cold'
|
||||
| 'data_frozen'
|
||||
| 'ingest'
|
||||
| 'transform'
|
||||
| 'ml'
|
||||
| 'remote_cluster_client';
|
||||
|
||||
const rolesByImportance: ElasticsearchNodeRole[] = [
|
||||
'master',
|
||||
'voting_only',
|
||||
'data',
|
||||
'data_content',
|
||||
'data_hot',
|
||||
'data_warm',
|
||||
'data_cold',
|
||||
'data_frozen',
|
||||
'ingest',
|
||||
'transform',
|
||||
'ml',
|
||||
'remote_cluster_client',
|
||||
];
|
||||
|
||||
export const ElasticsearchNodesPage: React.FC<ComponentProps> = ({ clusters }) => {
|
||||
const globalState = useContext(GlobalStateContext);
|
||||
const { showCgroupMetricsElasticsearch } = useContext(ExternalConfigContext);
|
||||
|
@ -66,7 +95,10 @@ export const ElasticsearchNodesPage: React.FC<ComponentProps> = ({ clusters }) =
|
|||
const url = `../api/monitoring/v1/clusters/${clusterUuid}/elasticsearch/nodes`;
|
||||
if (services.http?.fetch && clusterUuid) {
|
||||
setIsLoading(true);
|
||||
const response = await services.http?.fetch<{ totalNodeCount: number }>(url, {
|
||||
const response = await services.http?.fetch<{
|
||||
totalNodeCount: number;
|
||||
nodes: Array<{ roles: string[] }>;
|
||||
}>(url, {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({
|
||||
ccs,
|
||||
|
@ -79,7 +111,20 @@ export const ElasticsearchNodesPage: React.FC<ComponentProps> = ({ clusters }) =
|
|||
});
|
||||
|
||||
setIsLoading(false);
|
||||
setData(response);
|
||||
|
||||
const { nodes } = response;
|
||||
const nodesWithSortedRoles = nodes.map((node) => {
|
||||
const sortedRoles = sortNodeRoles(node.roles);
|
||||
return {
|
||||
...node,
|
||||
roles: sortedRoles,
|
||||
};
|
||||
});
|
||||
|
||||
setData({
|
||||
...response,
|
||||
nodes: nodesWithSortedRoles,
|
||||
});
|
||||
updateTotalItemCount(response.totalNodeCount);
|
||||
const alertsResponse = await fetchAlerts({
|
||||
fetch: services.http.fetch,
|
||||
|
@ -140,3 +185,16 @@ export const ElasticsearchNodesPage: React.FC<ComponentProps> = ({ clusters }) =
|
|||
</ElasticsearchTemplate>
|
||||
);
|
||||
};
|
||||
|
||||
function sortNodeRoles(roles: string[] | undefined): string[] | undefined {
|
||||
if (!roles) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
if (roles.length === 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const rolesAsSet = new Set(roles);
|
||||
return rolesByImportance.filter((role) => rolesAsSet.has(role));
|
||||
}
|
||||
|
|
|
@ -5,36 +5,38 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import React, { Fragment } from 'react';
|
||||
import { extractIp } from '../../../lib/extract_ip'; // TODO this is only used for elasticsearch nodes summary / node detail, so it should be moved to components/elasticsearch/nodes/lib
|
||||
import { getSafeForExternalLink } from '../../../lib/get_safe_for_external_link';
|
||||
import { ClusterStatus } from '../cluster_status';
|
||||
import { EuiMonitoringSSPTable } from '../../table';
|
||||
import { MetricCell, OfflineCell } from './cells';
|
||||
import { SetupModeBadge } from '../../setup_mode/badge';
|
||||
import {
|
||||
EuiBadge,
|
||||
EuiBadgeGroup,
|
||||
EuiButton,
|
||||
EuiCallOut,
|
||||
EuiHealth,
|
||||
EuiIcon,
|
||||
EuiLink,
|
||||
EuiToolTip,
|
||||
EuiSpacer,
|
||||
EuiPage,
|
||||
EuiPageContent_Deprecated as EuiPageContent,
|
||||
EuiPageBody,
|
||||
EuiPageContent_Deprecated as EuiPageContent,
|
||||
EuiPanel,
|
||||
EuiCallOut,
|
||||
EuiButton,
|
||||
EuiText,
|
||||
EuiScreenReaderOnly,
|
||||
EuiHealth,
|
||||
EuiSpacer,
|
||||
EuiText,
|
||||
EuiToolTip,
|
||||
} from '@elastic/eui';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { get } from 'lodash';
|
||||
import { ELASTICSEARCH_SYSTEM_ID } from '../../../../common/constants';
|
||||
import { FormattedMessage } from '@kbn/i18n-react';
|
||||
import { ListingCallOut } from '../../setup_mode/listing_callout';
|
||||
import { AlertsStatus } from '../../../alerts/status';
|
||||
import { isSetupModeFeatureEnabled } from '../../../lib/setup_mode';
|
||||
import { get } from 'lodash';
|
||||
import React, { Fragment } from 'react';
|
||||
import { ELASTICSEARCH_SYSTEM_ID } from '../../../../common/constants';
|
||||
import { SetupModeFeature } from '../../../../common/enums';
|
||||
import { AlertsStatus } from '../../../alerts/status';
|
||||
import { extractIp } from '../../../lib/extract_ip'; // TODO this is only used for elasticsearch nodes summary / node detail, so it should be moved to components/elasticsearch/nodes/lib
|
||||
import { getSafeForExternalLink } from '../../../lib/get_safe_for_external_link';
|
||||
import { isSetupModeFeatureEnabled } from '../../../lib/setup_mode';
|
||||
import { SetupModeBadge } from '../../setup_mode/badge';
|
||||
import { ListingCallOut } from '../../setup_mode/listing_callout';
|
||||
import { EuiMonitoringSSPTable } from '../../table';
|
||||
import { ClusterStatus } from '../cluster_status';
|
||||
import { MetricCell, OfflineCell } from './cells';
|
||||
|
||||
const getNodeTooltip = (node) => {
|
||||
const { nodeTypeLabel, nodeTypeClass } = node;
|
||||
|
@ -177,6 +179,53 @@ const getColumns = (showCgroupMetricsElasticsearch, setupMode, clusterUuid, aler
|
|||
},
|
||||
});
|
||||
|
||||
cols.push({
|
||||
name: i18n.translate('xpack.monitoring.elasticsearch.nodes.rolesColumnTitle', {
|
||||
defaultMessage: 'Roles',
|
||||
}),
|
||||
field: 'roles',
|
||||
render: (roles) => {
|
||||
if (!roles) {
|
||||
return i18n.translate('xpack.monitoring.formatNumbers.notAvailableLabel', {
|
||||
defaultMessage: 'N/A',
|
||||
});
|
||||
}
|
||||
|
||||
if (roles.length === 0) {
|
||||
return (
|
||||
<EuiBadge>
|
||||
{i18n.translate('xpack.monitoring.elasticsearch.nodes.coordinatingNodeLabel', {
|
||||
defaultMessage: 'coordinating only',
|
||||
})}
|
||||
</EuiBadge>
|
||||
);
|
||||
}
|
||||
|
||||
const head = roles.slice(0, 5);
|
||||
const tail = roles.slice(5);
|
||||
const hasMoreRoles = tail.length > 0;
|
||||
|
||||
return (
|
||||
<EuiBadgeGroup gutterSize="xs">
|
||||
{head.map((role) => (
|
||||
<EuiBadge color={role === 'master' ? 'hollow' : 'default'}>{role}</EuiBadge>
|
||||
))}
|
||||
{hasMoreRoles && (
|
||||
<EuiToolTip
|
||||
anchorProps={{
|
||||
style: { lineHeight: '1' },
|
||||
}}
|
||||
position="bottom"
|
||||
content={tail.join(', ')}
|
||||
>
|
||||
<EuiBadge>+{tail.length}</EuiBadge>
|
||||
</EuiToolTip>
|
||||
)}
|
||||
</EuiBadgeGroup>
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
cols.push({
|
||||
name: i18n.translate('xpack.monitoring.elasticsearch.nodes.shardsColumnTitle', {
|
||||
defaultMessage: 'Shards',
|
||||
|
|
|
@ -8,6 +8,7 @@ Array [
|
|||
"nodeTypeClass": "storage",
|
||||
"nodeTypeLabel": "Node",
|
||||
"resolver": "_x_V2YzPQU-a9KRRBxUxZQ",
|
||||
"roles": undefined,
|
||||
"shardCount": 6,
|
||||
"transport_address": "127.0.0.1:9300",
|
||||
"type": "node",
|
||||
|
@ -19,6 +20,7 @@ Array [
|
|||
"nodeTypeClass": "storage",
|
||||
"nodeTypeLabel": "Node",
|
||||
"resolver": "DAiX7fFjS3Wii7g2HYKrOg",
|
||||
"roles": undefined,
|
||||
"shardCount": 6,
|
||||
"transport_address": "127.0.0.1:9301",
|
||||
"type": "node",
|
||||
|
@ -161,6 +163,7 @@ Array [
|
|||
},
|
||||
},
|
||||
"resolver": "_x_V2YzPQU-a9KRRBxUxZQ",
|
||||
"roles": undefined,
|
||||
"shardCount": 0,
|
||||
"transport_address": "127.0.0.1:9300",
|
||||
"type": "master",
|
||||
|
@ -276,6 +279,7 @@ Array [
|
|||
},
|
||||
},
|
||||
"resolver": "DAiX7fFjS3Wii7g2HYKrOg",
|
||||
"roles": undefined,
|
||||
"shardCount": 0,
|
||||
"transport_address": "127.0.0.1:9301",
|
||||
"type": "node",
|
||||
|
@ -298,6 +302,7 @@ Array [
|
|||
"node_jvm_mem_percent": null,
|
||||
"node_load_average": null,
|
||||
"resolver": "_x_V2YzPQU-a9KRRBxUxZQ",
|
||||
"roles": undefined,
|
||||
"shardCount": 6,
|
||||
"transport_address": "127.0.0.1:9300",
|
||||
"type": "master",
|
||||
|
@ -315,6 +320,7 @@ Array [
|
|||
"node_jvm_mem_percent": null,
|
||||
"node_load_average": null,
|
||||
"resolver": "DAiX7fFjS3Wii7g2HYKrOg",
|
||||
"roles": undefined,
|
||||
"shardCount": 6,
|
||||
"transport_address": "127.0.0.1:9301",
|
||||
"type": "node",
|
||||
|
@ -455,6 +461,7 @@ Array [
|
|||
},
|
||||
},
|
||||
"resolver": "_x_V2YzPQU-a9KRRBxUxZQ",
|
||||
"roles": undefined,
|
||||
"shardCount": 6,
|
||||
"transport_address": "127.0.0.1:9300",
|
||||
"type": "master",
|
||||
|
@ -570,6 +577,7 @@ Array [
|
|||
},
|
||||
},
|
||||
"resolver": "DAiX7fFjS3Wii7g2HYKrOg",
|
||||
"roles": undefined,
|
||||
"shardCount": 6,
|
||||
"transport_address": "127.0.0.1:9301",
|
||||
"type": "node",
|
||||
|
|
|
@ -7,6 +7,7 @@ Object {
|
|||
"name": "node01",
|
||||
"nodeTypeClass": "starFilled",
|
||||
"nodeTypeLabel": "Master Node",
|
||||
"roles": undefined,
|
||||
"shardCount": 57,
|
||||
"transport_address": "127.0.0.1:9300",
|
||||
"type": "master",
|
||||
|
@ -16,6 +17,7 @@ Object {
|
|||
"name": "node02",
|
||||
"nodeTypeClass": "storage",
|
||||
"nodeTypeLabel": "Node",
|
||||
"roles": undefined,
|
||||
"shardCount": 0,
|
||||
"transport_address": "127.0.0.1:9301",
|
||||
"type": "node",
|
||||
|
|
|
@ -11,6 +11,7 @@ import { getNodeTypeClassLabel } from '../get_node_type_class_label';
|
|||
import {
|
||||
ElasticsearchResponseHit,
|
||||
ElasticsearchModifiedSource,
|
||||
ElasticsearchMetricbeatNode,
|
||||
} from '../../../../../common/types/es';
|
||||
|
||||
/**
|
||||
|
@ -52,6 +53,7 @@ export function mapNodesInfo(
|
|||
nodeTypeLabel,
|
||||
nodeTypeClass,
|
||||
shardCount: nodesShardCount?.nodes[uuid]?.shardCount ?? 0,
|
||||
roles: (sourceNode as ElasticsearchMetricbeatNode)?.roles,
|
||||
},
|
||||
};
|
||||
}, {});
|
||||
|
|
|
@ -25,11 +25,11 @@ export function MonitoringElasticsearchNodesProvider({ getService, getPageObject
|
|||
|
||||
const SUBJ_TABLE_SORT_NAME_COL = `tableHeaderCell_name_0`;
|
||||
const SUBJ_TABLE_SORT_STATUS_COL = `tableHeaderCell_isOnline_2`;
|
||||
const SUBJ_TABLE_SORT_SHARDS_COL = `tableHeaderCell_shardCount_3`;
|
||||
const SUBJ_TABLE_SORT_CPU_COL = `tableHeaderCell_node_cpu_utilization_4`;
|
||||
const SUBJ_TABLE_SORT_LOAD_COL = `tableHeaderCell_node_load_average_5`;
|
||||
const SUBJ_TABLE_SORT_MEM_COL = `tableHeaderCell_node_jvm_mem_percent_6`;
|
||||
const SUBJ_TABLE_SORT_DISK_COL = `tableHeaderCell_node_free_space_7`;
|
||||
const SUBJ_TABLE_SORT_SHARDS_COL = `tableHeaderCell_shardCount_4`;
|
||||
const SUBJ_TABLE_SORT_CPU_COL = `tableHeaderCell_node_cpu_utilization_5`;
|
||||
const SUBJ_TABLE_SORT_LOAD_COL = `tableHeaderCell_node_load_average_6`;
|
||||
const SUBJ_TABLE_SORT_MEM_COL = `tableHeaderCell_node_jvm_mem_percent_7`;
|
||||
const SUBJ_TABLE_SORT_DISK_COL = `tableHeaderCell_node_free_space_8`;
|
||||
|
||||
const SUBJ_TABLE_BODY = 'elasticsearchNodesTableContainer';
|
||||
const SUBJ_NODES_NAMES = `${SUBJ_TABLE_BODY} > name`;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue