Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[8.x] [Remote clusters] Per cluster status call (#194420) #195290

Merged
merged 1 commit into from
Oct 7, 2024
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 @@ -9,7 +9,7 @@ import React from 'react';
import PropTypes from 'prop-types';
import { i18n } from '@kbn/i18n';

import { EuiBadge, EuiFlexGroup, EuiFlexItem, EuiIconTip } from '@elastic/eui';
import { EuiHealth, EuiFlexGroup, EuiFlexItem, EuiIconTip } from '@elastic/eui';

import { SNIFF_MODE, PROXY_MODE } from '../../../../../../common/constants';

Expand All @@ -24,7 +24,7 @@ export function ConnectionStatus({ isConnected, mode }) {
return (
<EuiFlexGroup gutterSize="s" alignItems="center">
<EuiFlexItem grow={false}>
<EuiBadge
<EuiHealth
color={isConnected ? 'success' : 'danger'}
data-test-subj="remoteClusterConnectionStatusMessage"
>
Expand All @@ -35,7 +35,7 @@ export function ConnectionStatus({ isConnected, mode }) {
: i18n.translate('xpack.remoteClusters.connectedStatus.notConnectedAriaLabel', {
defaultMessage: 'Not connected',
})}
</EuiBadge>
</EuiHealth>
</EuiFlexItem>

{!isConnected && mode === SNIFF_MODE && (
Expand Down
46 changes: 32 additions & 14 deletions x-pack/plugins/remote_clusters/server/routes/api/get_route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,16 @@
* 2.0.
*/

import { get } from 'lodash';
import { get, chunk, assign } from 'lodash';

import type { IndicesResolveClusterResponse } from '@elastic/elasticsearch/lib/api/types';
import { RequestHandler } from '@kbn/core/server';
import { deserializeCluster } from '../../../common/lib';
import { API_BASE_PATH } from '../../../common/constants';
import { licensePreRoutingFactory } from '../../lib/license_pre_routing_factory';
import { RouteDependencies } from '../../types';

const CLUSTER_STATUS_CHUNK_SIZE = 10;

export const register = (deps: RouteDependencies): void => {
const {
router,
Expand All @@ -35,15 +36,32 @@ export const register = (deps: RouteDependencies): void => {
const clustersByName = await clusterClient.asCurrentUser.cluster.remoteInfo();
const clusterNames = (clustersByName && Object.keys(clustersByName)) || [];

// Retrieve the cluster information for all the configured remote clusters.
// _none is never a valid index/alias/data-stream name so that way we can avoid
// using * which could be computationally expensive.
let clustersStatus: IndicesResolveClusterResponse = {};
if (clusterNames.length > 0) {
clustersStatus = await clusterClient.asCurrentUser.indices.resolveCluster({
name: clusterNames.map((cluster) => `${cluster}:_none`),
});
}
const clusterNamesChunks = chunk(clusterNames, CLUSTER_STATUS_CHUNK_SIZE);
const promises = clusterNamesChunks.map(async (clustersChunk) => {
try {
return await clusterClient.asCurrentUser.indices.resolveCluster(
{
name: clustersChunk.map((cluster) => `${cluster}:*`),
filter_path: '*.connected',
},
{
// Set a longer timeout given that sometimes unresponsive clusters
// can take a while to respond.
// We should be able to be more aggresive with this timeout once
// https://github.com/elastic/elasticsearch/issues/114020 is resolved.
requestTimeout: '60s',
}
);
} catch (error) {
return Promise.resolve(null);
}
});

const resolvedClusterStatus = await Promise.all(promises);
// Flatten the resolved cluster status and filter out any null values
const flattenedClusterStatus = resolvedClusterStatus.flat().filter(Boolean);
// Combine the resolved cluster status into a single object
const clusterStatus = assign({}, ...flattenedClusterStatus);

const body = clusterNames.map((clusterName: string): any => {
const cluster = clustersByName[clusterName];
Expand All @@ -70,9 +88,9 @@ export const register = (deps: RouteDependencies): void => {
config.isCloudEnabled
),
isConfiguredByNode,
// We prioritize the cluster status from the resolve cluster api, and fallback to
// the cluster connected status in case its not present.
isConnected: clustersStatus[clusterName]?.connected || cluster.connected,
// We prioritize the cluster status from the resolve cluster API, and fallback to
// the cluster connected status in case it's not present.
isConnected: clusterStatus[clusterName]?.connected || cluster.connected,
};
});

Expand Down