Skip to content

Commit

Permalink
[Monitoring] Display node roles in Nodes table (#151818)
Browse files Browse the repository at this point in the history
  • Loading branch information
miltonhultgren committed Feb 24, 2023
1 parent 4a37cd5 commit cc15691
Show file tree
Hide file tree
Showing 4 changed files with 126 additions and 19 deletions.
1 change: 1 addition & 0 deletions x-pack/plugins/monitoring/common/types/es.ts
Original file line number Diff line number Diff line change
Expand Up @@ -417,6 +417,7 @@ export interface ElasticsearchMetricbeatNode {
name?: string;
stats?: ElasticsearchNodeStats;
master: boolean;
roles?: string[];
}

export interface ElasticsearchMetricbeatSource {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,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,
Expand All @@ -79,7 +82,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,
Expand Down Expand Up @@ -140,3 +156,35 @@ export const ElasticsearchNodesPage: React.FC<ComponentProps> = ({ clusters }) =
</ElasticsearchTemplate>
);
};

function sortNodeRoles(roles: string[]): string[] | undefined {
if (!roles) {
return undefined;
}

if (roles.length === 0) {
return roles;
}

const roleMap: { [key: string]: string } = {};
roles.forEach((role) => {
roleMap[role] = role;
});

const sortedRoles = [
roleMap.master,
roleMap.voting_only,
roleMap.data,
roleMap.data_content,
roleMap.data_hot,
roleMap.data_warm,
roleMap.data_cold,
roleMap.data_frozen,
roleMap.ingest,
roleMap.transform,
roleMap.ml,
roleMap.remote_cluster_client,
];

return sortedRoles.filter((role) => role);
}
Original file line number Diff line number Diff line change
Expand Up @@ -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 { FormattedMessage } from '@kbn/i18n-react';
import { get } from 'lodash';
import React, { Fragment } from 'react';
import { ELASTICSEARCH_SYSTEM_ID } from '../../../../common/constants';
import { FormattedMessage } from '@kbn/i18n-react';
import { ListingCallOut } from '../../setup_mode/listing_callout';
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 { SetupModeFeature } from '../../../../common/enums';
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;
Expand Down Expand Up @@ -177,6 +179,60 @@ 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>
);
}

if (roles.length > 5) {
const head = roles.slice(0, 5);
const tail = roles.slice(5, roles.length);

return (
<EuiBadgeGroup gutterSize="xs">
{head.map((role) => (
<EuiBadge color={role === 'master' ? 'hollow' : 'default'}>{role}</EuiBadge>
))}
<EuiToolTip
anchorProps={{
style: { lineHeight: '1' },
}}
position="bottom"
content={tail.join(', ')}
>
<EuiBadge>+{tail.length}</EuiBadge>
</EuiToolTip>
</EuiBadgeGroup>
);
}

return (
<EuiBadgeGroup gutterSize="xs">
{roles.map((role) => (
<EuiBadge color={role === 'master' ? 'hollow' : 'default'}>{role}</EuiBadge>
))}
</EuiBadgeGroup>
);
},
});

cols.push({
name: i18n.translate('xpack.monitoring.elasticsearch.nodes.shardsColumnTitle', {
defaultMessage: 'Shards',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { getNodeTypeClassLabel } from '../get_node_type_class_label';
import {
ElasticsearchResponseHit,
ElasticsearchModifiedSource,
ElasticsearchMetricbeatNode,
} from '../../../../../common/types/es';

/**
Expand Down Expand Up @@ -52,6 +53,7 @@ export function mapNodesInfo(
nodeTypeLabel,
nodeTypeClass,
shardCount: nodesShardCount?.nodes[uuid]?.shardCount ?? 0,
roles: (sourceNode as ElasticsearchMetricbeatNode)?.roles,
},
};
}, {});
Expand Down

0 comments on commit cc15691

Please sign in to comment.