From c9002a25c50b4074aac4a40f67882bf0d88aaba5 Mon Sep 17 00:00:00 2001 From: Chris Roberson Date: Wed, 20 Jan 2021 13:43:53 -0500 Subject: [PATCH] [Monitoring] Convert Elasticsearch-related server files that read from _source to typescript (#88212) * A good chunk of server-side ES changes * CCR files * More areas where we just pass down the source to the client * Some more * Fix tests * Fix tests and types --- x-pack/plugins/monitoring/common/types/es.ts | 206 +++++++++++++++++- .../server/lib/apm/_get_time_of_last_event.ts | 5 +- .../monitoring/server/lib/apm/get_apm_info.ts | 3 +- .../monitoring/server/lib/apm/get_apms.ts | 3 +- .../server/lib/beats/get_beat_summary.ts | 3 +- .../monitoring/server/lib/beats/get_beats.ts | 3 +- ...clusters.js => flag_supported_clusters.ts} | 39 ++-- ...ster_license.js => get_cluster_license.ts} | 12 +- ...luster_status.js => get_cluster_status.ts} | 30 +-- ...lusters_state.js => get_clusters_state.ts} | 20 +- ...lusters_stats.js => get_clusters_stats.ts} | 21 +- .../lib/elasticsearch/{ccr.js => ccr.ts} | 15 +- ..._last_recovery.js => get_last_recovery.ts} | 17 +- .../{get_ml_jobs.js => get_ml_jobs.ts} | 30 ++- ..._index_summary.js => get_index_summary.ts} | 40 ++-- .../{get_indices.js => get_indices.ts} | 75 ++++--- ...et_node_summary.js => get_node_summary.ts} | 88 +++++--- .../get_nodes/{get_nodes.js => get_nodes.ts} | 18 +- ...{handle_response.js => handle_response.ts} | 43 ++-- .../nodes/get_nodes/map_nodes_info.js | 46 ---- .../nodes/get_nodes/map_nodes_info.ts | 57 +++++ ..._allocation.js => get_shard_allocation.ts} | 24 +- .../server/lib/kibana/get_kibana_info.ts | 5 +- .../server/lib/logstash/get_node_info.ts | 3 +- .../logstash/get_pipeline_state_document.ts | 3 +- .../api/v1/elasticsearch/{ccr.js => ccr.ts} | 109 ++++++--- .../{ccr_shard.js => ccr_shard.ts} | 29 +-- x-pack/plugins/monitoring/server/types.ts | 24 -- 28 files changed, 665 insertions(+), 306 deletions(-) rename x-pack/plugins/monitoring/server/lib/cluster/{flag_supported_clusters.js => flag_supported_clusters.ts} (79%) rename x-pack/plugins/monitoring/server/lib/cluster/{get_cluster_license.js => get_cluster_license.ts} (70%) rename x-pack/plugins/monitoring/server/lib/cluster/{get_cluster_status.js => get_cluster_status.ts} (53%) rename x-pack/plugins/monitoring/server/lib/cluster/{get_clusters_state.js => get_clusters_state.ts} (82%) rename x-pack/plugins/monitoring/server/lib/cluster/{get_clusters_stats.js => get_clusters_stats.ts} (83%) rename x-pack/plugins/monitoring/server/lib/elasticsearch/{ccr.js => ccr.ts} (72%) rename x-pack/plugins/monitoring/server/lib/elasticsearch/{get_last_recovery.js => get_last_recovery.ts} (81%) rename x-pack/plugins/monitoring/server/lib/elasticsearch/{get_ml_jobs.js => get_ml_jobs.ts} (79%) rename x-pack/plugins/monitoring/server/lib/elasticsearch/indices/{get_index_summary.js => get_index_summary.ts} (73%) rename x-pack/plugins/monitoring/server/lib/elasticsearch/indices/{get_indices.js => get_indices.ts} (72%) rename x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/{get_node_summary.js => get_node_summary.ts} (59%) rename x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/{get_nodes.js => get_nodes.ts} (87%) rename x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/{handle_response.js => handle_response.ts} (57%) delete mode 100644 x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/map_nodes_info.js create mode 100644 x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/map_nodes_info.ts rename x-pack/plugins/monitoring/server/lib/elasticsearch/shards/{get_shard_allocation.js => get_shard_allocation.ts} (75%) rename x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/{ccr.js => ccr.ts} (72%) rename x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/{ccr_shard.js => ccr_shard.ts} (82%) diff --git a/x-pack/plugins/monitoring/common/types/es.ts b/x-pack/plugins/monitoring/common/types/es.ts index 725ff214ae79..728cd3d73a34 100644 --- a/x-pack/plugins/monitoring/common/types/es.ts +++ b/x-pack/plugins/monitoring/common/types/es.ts @@ -4,6 +4,31 @@ * you may not use this file except in compliance with the Elastic License. */ +export interface ElasticsearchResponse { + hits?: { + hits: ElasticsearchResponseHit[]; + total: { + value: number; + }; + }; + aggregations?: any; +} + +export interface ElasticsearchResponseHit { + _index: string; + _source: ElasticsearchSource; + inner_hits?: { + [field: string]: { + hits?: { + hits: ElasticsearchResponseHit[]; + total: { + value: number; + }; + }; + }; + }; +} + export interface ElasticsearchSourceKibanaStats { timestamp?: string; kibana?: { @@ -34,9 +59,94 @@ export interface ElasticsearchSourceLogstashPipelineVertex { }; } -export interface ElasticsearchSource { +export interface ElasticsearchNodeStats { + indices?: { + docs?: { + count?: number; + }; + store?: { + size_in_bytes?: number; + size?: { + bytes?: number; + }; + }; + }; + fs?: { + total?: { + available_in_bytes?: number; + total_in_bytes?: number; + }; + summary?: { + available?: { + bytes?: number; + }; + total?: { + bytes?: number; + }; + }; + }; + jvm?: { + mem?: { + heap_used_percent?: number; + heap?: { + used?: { + pct?: number; + }; + }; + }; + }; +} + +export interface ElasticsearchLegacySource { timestamp: string; + cluster_uuid: string; + cluster_stats?: { + nodes?: { + count?: { + total?: number; + }; + jvm?: { + max_uptime_in_millis?: number; + mem?: { + heap_used_in_bytes?: number; + heap_max_in_bytes?: number; + }; + }; + versions?: string[]; + }; + indices?: { + count?: number; + docs?: { + count?: number; + }; + shards?: { + total?: number; + }; + store?: { + size_in_bytes?: number; + }; + }; + }; + cluster_state?: { + status?: string; + nodes?: { + [nodeUuid: string]: {}; + }; + master_node?: boolean; + }; + source_node?: { + id?: string; + uuid?: string; + attributes?: {}; + transport_address?: string; + name?: string; + type?: string; + }; kibana_stats?: ElasticsearchSourceKibanaStats; + license?: { + status?: string; + type?: string; + }; logstash_state?: { pipeline?: { representation?: { @@ -108,4 +218,98 @@ export interface ElasticsearchSource { }; }; }; + stack_stats?: { + xpack?: { + ccr?: { + enabled?: boolean; + available?: boolean; + }; + }; + }; + job_stats?: { + job_id?: number; + state?: string; + data_counts?: { + processed_record_count?: number; + }; + model_size_stats?: { + model_bytes?: number; + }; + forecasts_stats?: { + total?: number; + }; + node?: { + id?: number; + name?: string; + }; + }; + index_stats?: { + index?: string; + primaries?: { + docs?: { + count?: number; + }; + store?: { + size_in_bytes?: number; + }; + indexing?: { + index_total?: number; + }; + }; + total?: { + store?: { + size_in_bytes?: number; + }; + search?: { + query_total?: number; + }; + }; + }; + node_stats?: ElasticsearchNodeStats; + service?: { + address?: string; + }; + shard?: { + index?: string; + shard?: string; + primary?: boolean; + relocating_node?: string; + node?: string; + }; + ccr_stats?: { + leader_index?: string; + follower_index?: string; + shard_id?: number; + read_exceptions?: Array<{ + exception?: { + type?: string; + }; + }>; + time_since_last_read_millis?: number; + }; + index_recovery?: { + shards?: ElasticsearchIndexRecoveryShard[]; + }; +} + +export interface ElasticsearchIndexRecoveryShard { + start_time_in_millis: number; + stop_time_in_millis: number; +} + +export interface ElasticsearchMetricbeatNode { + stats?: ElasticsearchNodeStats; +} + +export interface ElasticsearchMetricbeatSource { + elasticsearch?: { + node?: ElasticsearchLegacySource['source_node'] & ElasticsearchMetricbeatNode; + }; +} + +export type ElasticsearchSource = ElasticsearchLegacySource & ElasticsearchMetricbeatSource; + +export interface ElasticsearchModifiedSource extends ElasticsearchSource { + ccs?: string; + isSupported?: boolean; } diff --git a/x-pack/plugins/monitoring/server/lib/apm/_get_time_of_last_event.ts b/x-pack/plugins/monitoring/server/lib/apm/_get_time_of_last_event.ts index fc103959381b..68f16cf23b47 100644 --- a/x-pack/plugins/monitoring/server/lib/apm/_get_time_of_last_event.ts +++ b/x-pack/plugins/monitoring/server/lib/apm/_get_time_of_last_event.ts @@ -8,7 +8,8 @@ import { createApmQuery } from './create_apm_query'; // @ts-ignore import { ApmClusterMetric } from '../metrics'; -import { LegacyRequest, ElasticsearchResponse } from '../../types'; +import { LegacyRequest } from '../../types'; +import { ElasticsearchResponse } from '../../../common/types/es'; export async function getTimeOfLastEvent({ req, @@ -58,5 +59,5 @@ export async function getTimeOfLastEvent({ }; const response = await callWithRequest(req, 'search', params); - return response.hits?.hits.length ? response.hits?.hits[0]._source.timestamp : undefined; + return response.hits?.hits.length ? response.hits?.hits[0]?._source.timestamp : undefined; } diff --git a/x-pack/plugins/monitoring/server/lib/apm/get_apm_info.ts b/x-pack/plugins/monitoring/server/lib/apm/get_apm_info.ts index 7d471d528595..7bc36d559ac3 100644 --- a/x-pack/plugins/monitoring/server/lib/apm/get_apm_info.ts +++ b/x-pack/plugins/monitoring/server/lib/apm/get_apm_info.ts @@ -14,7 +14,8 @@ import { getDiffCalculation } from '../beats/_beats_stats'; // @ts-ignore import { ApmMetric } from '../metrics'; import { getTimeOfLastEvent } from './_get_time_of_last_event'; -import { LegacyRequest, ElasticsearchResponse } from '../../types'; +import { LegacyRequest } from '../../types'; +import { ElasticsearchResponse } from '../../../common/types/es'; export function handleResponse(response: ElasticsearchResponse, apmUuid: string) { if (!response.hits || response.hits.hits.length === 0) { diff --git a/x-pack/plugins/monitoring/server/lib/apm/get_apms.ts b/x-pack/plugins/monitoring/server/lib/apm/get_apms.ts index 7677677ea5e7..4dbd32c88976 100644 --- a/x-pack/plugins/monitoring/server/lib/apm/get_apms.ts +++ b/x-pack/plugins/monitoring/server/lib/apm/get_apms.ts @@ -14,7 +14,8 @@ import { createApmQuery } from './create_apm_query'; import { calculateRate } from '../calculate_rate'; // @ts-ignore import { getDiffCalculation } from './_apm_stats'; -import { LegacyRequest, ElasticsearchResponse, ElasticsearchResponseHit } from '../../types'; +import { LegacyRequest } from '../../types'; +import { ElasticsearchResponse, ElasticsearchResponseHit } from '../../../common/types/es'; export function handleResponse(response: ElasticsearchResponse, start: number, end: number) { const initial = { ids: new Set(), beats: [] }; diff --git a/x-pack/plugins/monitoring/server/lib/beats/get_beat_summary.ts b/x-pack/plugins/monitoring/server/lib/beats/get_beat_summary.ts index 80b5efda4047..0bfc4b85c966 100644 --- a/x-pack/plugins/monitoring/server/lib/beats/get_beat_summary.ts +++ b/x-pack/plugins/monitoring/server/lib/beats/get_beat_summary.ts @@ -5,7 +5,8 @@ */ import { upperFirst } from 'lodash'; -import { LegacyRequest, ElasticsearchResponse } from '../../types'; +import { LegacyRequest } from '../../types'; +import { ElasticsearchResponse } from '../../../common/types/es'; // @ts-ignore import { checkParam } from '../error_missing_required'; // @ts-ignore diff --git a/x-pack/plugins/monitoring/server/lib/beats/get_beats.ts b/x-pack/plugins/monitoring/server/lib/beats/get_beats.ts index aa5ef81a8de3..cd474f77d42c 100644 --- a/x-pack/plugins/monitoring/server/lib/beats/get_beats.ts +++ b/x-pack/plugins/monitoring/server/lib/beats/get_beats.ts @@ -14,7 +14,8 @@ import { createBeatsQuery } from './create_beats_query'; import { calculateRate } from '../calculate_rate'; // @ts-ignore import { getDiffCalculation } from './_beats_stats'; -import { ElasticsearchResponse, LegacyRequest } from '../../types'; +import { LegacyRequest } from '../../types'; +import { ElasticsearchResponse } from '../../../common/types/es'; interface Beat { uuid: string | undefined; diff --git a/x-pack/plugins/monitoring/server/lib/cluster/flag_supported_clusters.js b/x-pack/plugins/monitoring/server/lib/cluster/flag_supported_clusters.ts similarity index 79% rename from x-pack/plugins/monitoring/server/lib/cluster/flag_supported_clusters.js rename to x-pack/plugins/monitoring/server/lib/cluster/flag_supported_clusters.ts index a1674b2f5eb3..248d1604ee20 100644 --- a/x-pack/plugins/monitoring/server/lib/cluster/flag_supported_clusters.js +++ b/x-pack/plugins/monitoring/server/lib/cluster/flag_supported_clusters.ts @@ -4,17 +4,18 @@ * you may not use this file except in compliance with the Elastic License. */ -import { set } from '@elastic/safer-lodash-set'; -import { get, find } from 'lodash'; +// @ts-ignore import { checkParam } from '../error_missing_required'; import { STANDALONE_CLUSTER_CLUSTER_UUID } from '../../../common/constants'; +import { ElasticsearchResponse, ElasticsearchModifiedSource } from '../../../common/types/es'; +import { LegacyRequest } from '../../types'; async function findSupportedBasicLicenseCluster( - req, - clusters, - kbnIndexPattern, - kibanaUuid, - serverLog + req: LegacyRequest, + clusters: ElasticsearchModifiedSource[], + kbnIndexPattern: string, + kibanaUuid: string, + serverLog: (message: string) => void ) { checkParam(kbnIndexPattern, 'kbnIndexPattern in cluster/findSupportedBasicLicenseCluster'); @@ -25,7 +26,7 @@ async function findSupportedBasicLicenseCluster( const { callWithRequest } = req.server.plugins.elasticsearch.getCluster('monitoring'); const gte = req.payload.timeRange.min; const lte = req.payload.timeRange.max; - const kibanaDataResult = await callWithRequest(req, 'search', { + const kibanaDataResult: ElasticsearchResponse = (await callWithRequest(req, 'search', { index: kbnIndexPattern, size: 1, ignoreUnavailable: true, @@ -42,11 +43,13 @@ async function findSupportedBasicLicenseCluster( }, }, }, - }); - const supportedClusterUuid = get(kibanaDataResult, 'hits.hits[0]._source.cluster_uuid'); - const supportedCluster = find(clusters, { cluster_uuid: supportedClusterUuid }); - // only this basic cluster is supported - set(supportedCluster, 'isSupported', true); + })) as ElasticsearchResponse; + const supportedClusterUuid = kibanaDataResult.hits?.hits[0]?._source.cluster_uuid ?? undefined; + for (const cluster of clusters) { + if (cluster.cluster_uuid === supportedClusterUuid) { + cluster.isSupported = true; + } + } serverLog( `Found basic license admin cluster UUID for Monitoring UI support: ${supportedClusterUuid}.` @@ -69,12 +72,12 @@ async function findSupportedBasicLicenseCluster( * Non-Basic license clusters and any cluster in a single-cluster environment * are also flagged as supported in this method. */ -export function flagSupportedClusters(req, kbnIndexPattern) { +export function flagSupportedClusters(req: LegacyRequest, kbnIndexPattern: string) { checkParam(kbnIndexPattern, 'kbnIndexPattern in cluster/flagSupportedClusters'); const config = req.server.config(); - const serverLog = (msg) => req.getLogger('supported-clusters').debug(msg); - const flagAllSupported = (clusters) => { + const serverLog = (message: string) => req.getLogger('supported-clusters').debug(message); + const flagAllSupported = (clusters: ElasticsearchModifiedSource[]) => { clusters.forEach((cluster) => { if (cluster.license) { cluster.isSupported = true; @@ -83,7 +86,7 @@ export function flagSupportedClusters(req, kbnIndexPattern) { return clusters; }; - return async function (clusters) { + return async function (clusters: ElasticsearchModifiedSource[]) { // Standalone clusters are automatically supported in the UI so ignore those for // our calculations here let linkedClusterCount = 0; @@ -110,7 +113,7 @@ export function flagSupportedClusters(req, kbnIndexPattern) { // if all linked are basic licenses if (linkedClusterCount === basicLicenseCount) { - const kibanaUuid = config.get('server.uuid'); + const kibanaUuid = config.get('server.uuid') as string; return await findSupportedBasicLicenseCluster( req, clusters, diff --git a/x-pack/plugins/monitoring/server/lib/cluster/get_cluster_license.js b/x-pack/plugins/monitoring/server/lib/cluster/get_cluster_license.ts similarity index 70% rename from x-pack/plugins/monitoring/server/lib/cluster/get_cluster_license.js rename to x-pack/plugins/monitoring/server/lib/cluster/get_cluster_license.ts index bd84fbb66f96..9f3106f7c04a 100644 --- a/x-pack/plugins/monitoring/server/lib/cluster/get_cluster_license.js +++ b/x-pack/plugins/monitoring/server/lib/cluster/get_cluster_license.ts @@ -4,12 +4,16 @@ * you may not use this file except in compliance with the Elastic License. */ -import { get } from 'lodash'; +// @ts-ignore import { checkParam } from '../error_missing_required'; +// @ts-ignore import { createQuery } from '../create_query'; +// @ts-ignore import { ElasticsearchMetric } from '../metrics'; +import { ElasticsearchResponse } from '../../../common/types/es'; +import { LegacyRequest } from '../../types'; -export function getClusterLicense(req, esIndexPattern, clusterUuid) { +export function getClusterLicense(req: LegacyRequest, esIndexPattern: string, clusterUuid: string) { checkParam(esIndexPattern, 'esIndexPattern in getClusterLicense'); const params = { @@ -28,7 +32,7 @@ export function getClusterLicense(req, esIndexPattern, clusterUuid) { }; const { callWithRequest } = req.server.plugins.elasticsearch.getCluster('monitoring'); - return callWithRequest(req, 'search', params).then((response) => { - return get(response, 'hits.hits[0]._source.license', {}); + return callWithRequest(req, 'search', params).then((response: ElasticsearchResponse) => { + return response.hits?.hits[0]?._source.license; }); } diff --git a/x-pack/plugins/monitoring/server/lib/cluster/get_cluster_status.js b/x-pack/plugins/monitoring/server/lib/cluster/get_cluster_status.ts similarity index 53% rename from x-pack/plugins/monitoring/server/lib/cluster/get_cluster_status.js rename to x-pack/plugins/monitoring/server/lib/cluster/get_cluster_status.ts index cef06bb473c3..3184893d6c63 100644 --- a/x-pack/plugins/monitoring/server/lib/cluster/get_cluster_status.js +++ b/x-pack/plugins/monitoring/server/lib/cluster/get_cluster_status.ts @@ -3,20 +3,20 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ - import { get } from 'lodash'; +import { ElasticsearchSource } from '../../../common/types/es'; /* * @param cluster {Object} clusterStats from getClusterStatus * @param unassignedShards {Object} shardStats from getShardStats * @return top-level cluster summary data */ -export function getClusterStatus(cluster, shardStats) { - const clusterStats = get(cluster, 'cluster_stats', {}); - const clusterNodes = get(clusterStats, 'nodes', {}); - const clusterIndices = get(clusterStats, 'indices', {}); +export function getClusterStatus(cluster: ElasticsearchSource, shardStats: unknown) { + const clusterStats = cluster.cluster_stats ?? {}; + const clusterNodes = clusterStats.nodes ?? {}; + const clusterIndices = clusterStats.indices ?? {}; - const clusterTotalShards = get(clusterIndices, 'shards.total', 0); + const clusterTotalShards = clusterIndices.shards?.total ?? 0; let unassignedShardsTotal = 0; const unassignedShards = get(shardStats, 'indicesTotals.unassigned'); if (unassignedShards !== undefined) { @@ -26,17 +26,17 @@ export function getClusterStatus(cluster, shardStats) { const totalShards = clusterTotalShards + unassignedShardsTotal; return { - status: get(cluster, 'cluster_state.status', 'unknown'), + status: cluster.cluster_state?.status ?? 'unknown', // index-based stats - indicesCount: get(clusterIndices, 'count', 0), - documentCount: get(clusterIndices, 'docs.count', 0), - dataSize: get(clusterIndices, 'store.size_in_bytes', 0), + indicesCount: clusterIndices.count ?? 0, + documentCount: clusterIndices.docs?.count ?? 0, + dataSize: clusterIndices.store?.size_in_bytes ?? 0, // node-based stats - nodesCount: get(clusterNodes, 'count.total', 0), - upTime: get(clusterNodes, 'jvm.max_uptime_in_millis', 0), - version: get(clusterNodes, 'versions', null), - memUsed: get(clusterNodes, 'jvm.mem.heap_used_in_bytes', 0), - memMax: get(clusterNodes, 'jvm.mem.heap_max_in_bytes', 0), + nodesCount: clusterNodes.count?.total ?? 0, + upTime: clusterNodes.jvm?.max_uptime_in_millis ?? 0, + version: clusterNodes.versions ?? null, + memUsed: clusterNodes.jvm?.mem?.heap_used_in_bytes ?? 0, + memMax: clusterNodes.jvm?.mem?.heap_max_in_bytes ?? 0, unassignedShards: unassignedShardsTotal, totalShards, }; diff --git a/x-pack/plugins/monitoring/server/lib/cluster/get_clusters_state.js b/x-pack/plugins/monitoring/server/lib/cluster/get_clusters_state.ts similarity index 82% rename from x-pack/plugins/monitoring/server/lib/cluster/get_clusters_state.js rename to x-pack/plugins/monitoring/server/lib/cluster/get_clusters_state.ts index fa5526728086..c752f218f962 100644 --- a/x-pack/plugins/monitoring/server/lib/cluster/get_clusters_state.js +++ b/x-pack/plugins/monitoring/server/lib/cluster/get_clusters_state.ts @@ -4,8 +4,11 @@ * you may not use this file except in compliance with the Elastic License. */ -import { get, find } from 'lodash'; +import { find } from 'lodash'; +// @ts-ignore import { checkParam } from '../error_missing_required'; +import { ElasticsearchResponse, ElasticsearchModifiedSource } from '../../../common/types/es'; +import { LegacyRequest } from '../../types'; /** * Augment the {@clusters} with their cluster state's from the {@code response}. @@ -15,11 +18,14 @@ import { checkParam } from '../error_missing_required'; * @param {Array} clusters Array of clusters to be augmented * @return {Array} Always {@code clusters}. */ -export function handleResponse(response, clusters) { - const hits = get(response, 'hits.hits', []); +export function handleResponse( + response: ElasticsearchResponse, + clusters: ElasticsearchModifiedSource[] +) { + const hits = response.hits?.hits ?? []; hits.forEach((hit) => { - const currentCluster = get(hit, '_source', {}); + const currentCluster = hit._source; if (currentCluster) { const cluster = find(clusters, { cluster_uuid: currentCluster.cluster_uuid }); @@ -39,7 +45,11 @@ export function handleResponse(response, clusters) { * * If there is no cluster state available for any cluster, then it will be returned without any cluster state information. */ -export function getClustersState(req, esIndexPattern, clusters) { +export function getClustersState( + req: LegacyRequest, + esIndexPattern: string, + clusters: ElasticsearchModifiedSource[] +) { checkParam(esIndexPattern, 'esIndexPattern in cluster/getClustersHealth'); const clusterUuids = clusters diff --git a/x-pack/plugins/monitoring/server/lib/cluster/get_clusters_stats.js b/x-pack/plugins/monitoring/server/lib/cluster/get_clusters_stats.ts similarity index 83% rename from x-pack/plugins/monitoring/server/lib/cluster/get_clusters_stats.js rename to x-pack/plugins/monitoring/server/lib/cluster/get_clusters_stats.ts index 8ddd33837f56..609c8fb2089d 100644 --- a/x-pack/plugins/monitoring/server/lib/cluster/get_clusters_stats.js +++ b/x-pack/plugins/monitoring/server/lib/cluster/get_clusters_stats.ts @@ -4,12 +4,17 @@ * you may not use this file except in compliance with the Elastic License. */ -import { get } from 'lodash'; +// @ts-ignore import { checkParam } from '../error_missing_required'; +// @ts-ignore import { createQuery } from '../create_query'; +// @ts-ignore import { ElasticsearchMetric } from '../metrics'; +// @ts-ignore import { parseCrossClusterPrefix } from '../ccs_utils'; import { getClustersState } from './get_clusters_state'; +import { ElasticsearchResponse, ElasticsearchModifiedSource } from '../../../common/types/es'; +import { LegacyRequest } from '../../types'; /** * This will fetch the cluster stats and cluster state as a single object per cluster. @@ -19,10 +24,10 @@ import { getClustersState } from './get_clusters_state'; * @param {String} clusterUuid (optional) If not undefined, getClusters will filter for a single cluster * @return {Promise} A promise containing an array of clusters. */ -export function getClustersStats(req, esIndexPattern, clusterUuid) { +export function getClustersStats(req: LegacyRequest, esIndexPattern: string, clusterUuid: string) { return ( fetchClusterStats(req, esIndexPattern, clusterUuid) - .then((response) => handleClusterStats(response, req.server)) + .then((response) => handleClusterStats(response)) // augment older documents (e.g., from 2.x - 5.4) with their cluster_state .then((clusters) => getClustersState(req, esIndexPattern, clusters)) ); @@ -36,7 +41,7 @@ export function getClustersStats(req, esIndexPattern, clusterUuid) { * @param {String} clusterUuid (optional) - if not undefined, getClusters filters for a single clusterUuid * @return {Promise} Object representing each cluster. */ -function fetchClusterStats(req, esIndexPattern, clusterUuid) { +function fetchClusterStats(req: LegacyRequest, esIndexPattern: string, clusterUuid: string) { checkParam(esIndexPattern, 'esIndexPattern in getClusters'); const config = req.server.config(); @@ -81,15 +86,15 @@ function fetchClusterStats(req, esIndexPattern, clusterUuid) { * @param {Object} response The response from Elasticsearch. * @return {Array} Objects representing each cluster. */ -export function handleClusterStats(response) { - const hits = get(response, 'hits.hits', []); +export function handleClusterStats(response: ElasticsearchResponse) { + const hits = response?.hits?.hits ?? []; return hits .map((hit) => { - const cluster = get(hit, '_source'); + const cluster = hit._source as ElasticsearchModifiedSource; if (cluster) { - const indexName = get(hit, '_index', ''); + const indexName = hit._index; const ccs = parseCrossClusterPrefix(indexName); // use CCS whenever we come across it so that we can avoid talking to other monitoring clusters whenever possible diff --git a/x-pack/plugins/monitoring/server/lib/elasticsearch/ccr.js b/x-pack/plugins/monitoring/server/lib/elasticsearch/ccr.ts similarity index 72% rename from x-pack/plugins/monitoring/server/lib/elasticsearch/ccr.js rename to x-pack/plugins/monitoring/server/lib/elasticsearch/ccr.ts index 0f0ba49f229b..ec7ccd5ddb9a 100644 --- a/x-pack/plugins/monitoring/server/lib/elasticsearch/ccr.js +++ b/x-pack/plugins/monitoring/server/lib/elasticsearch/ccr.ts @@ -4,19 +4,24 @@ * you may not use this file except in compliance with the Elastic License. */ -import { get } from 'lodash'; import moment from 'moment'; +// @ts-ignore import { checkParam } from '../error_missing_required'; +// @ts-ignore import { ElasticsearchMetric } from '../metrics'; +// @ts-ignore import { createQuery } from '../create_query'; +import { ElasticsearchResponse } from '../../../common/types/es'; +import { LegacyRequest } from '../../types'; -export function handleResponse(response) { - const isEnabled = get(response, 'hits.hits[0]._source.stack_stats.xpack.ccr.enabled'); - const isAvailable = get(response, 'hits.hits[0]._source.stack_stats.xpack.ccr.available'); +export function handleResponse(response: ElasticsearchResponse) { + const isEnabled = response.hits?.hits[0]?._source.stack_stats?.xpack?.ccr?.enabled ?? undefined; + const isAvailable = + response.hits?.hits[0]?._source.stack_stats?.xpack?.ccr?.available ?? undefined; return isEnabled && isAvailable; } -export async function checkCcrEnabled(req, esIndexPattern) { +export async function checkCcrEnabled(req: LegacyRequest, esIndexPattern: string) { checkParam(esIndexPattern, 'esIndexPattern in getNodes'); const start = moment.utc(req.payload.timeRange.min).valueOf(); diff --git a/x-pack/plugins/monitoring/server/lib/elasticsearch/get_last_recovery.js b/x-pack/plugins/monitoring/server/lib/elasticsearch/get_last_recovery.ts similarity index 81% rename from x-pack/plugins/monitoring/server/lib/elasticsearch/get_last_recovery.js rename to x-pack/plugins/monitoring/server/lib/elasticsearch/get_last_recovery.ts index 00e750b17d57..31a58651ecd3 100644 --- a/x-pack/plugins/monitoring/server/lib/elasticsearch/get_last_recovery.js +++ b/x-pack/plugins/monitoring/server/lib/elasticsearch/get_last_recovery.ts @@ -5,9 +5,14 @@ */ import moment from 'moment'; import _ from 'lodash'; +// @ts-ignore import { checkParam } from '../error_missing_required'; +// @ts-ignore import { createQuery } from '../create_query'; +// @ts-ignore import { ElasticsearchMetric } from '../metrics'; +import { ElasticsearchResponse, ElasticsearchIndexRecoveryShard } from '../../../common/types/es'; +import { LegacyRequest } from '../../types'; /** * Filter out shard activity that we do not care about. @@ -20,8 +25,8 @@ import { ElasticsearchMetric } from '../metrics'; * @param {Number} startMs Start time in milliseconds of the polling window * @returns {boolean} true to keep */ -export function filterOldShardActivity(startMs) { - return (activity) => { +export function filterOldShardActivity(startMs: number) { + return (activity: ElasticsearchIndexRecoveryShard) => { // either it's still going and there is no stop time, or the stop time happened after we started looking for one return !_.isNumber(activity.stop_time_in_millis) || activity.stop_time_in_millis >= startMs; }; @@ -35,9 +40,9 @@ export function filterOldShardActivity(startMs) { * @param {Date} start The start time from the request payload (expected to be of type {@code Date}) * @returns {Object[]} An array of shards representing active shard activity from {@code _source.index_recovery.shards}. */ -export function handleLastRecoveries(resp, start) { - if (resp.hits.hits.length === 1) { - const data = _.get(resp.hits.hits[0], '_source.index_recovery.shards', []).filter( +export function handleLastRecoveries(resp: ElasticsearchResponse, start: number) { + if (resp.hits?.hits.length === 1) { + const data = (resp.hits?.hits[0]?._source.index_recovery?.shards ?? []).filter( filterOldShardActivity(moment.utc(start).valueOf()) ); data.sort((a, b) => b.start_time_in_millis - a.start_time_in_millis); @@ -47,7 +52,7 @@ export function handleLastRecoveries(resp, start) { return []; } -export function getLastRecovery(req, esIndexPattern) { +export function getLastRecovery(req: LegacyRequest, esIndexPattern: string) { checkParam(esIndexPattern, 'esIndexPattern in elasticsearch/getLastRecovery'); const start = req.payload.timeRange.min; diff --git a/x-pack/plugins/monitoring/server/lib/elasticsearch/get_ml_jobs.js b/x-pack/plugins/monitoring/server/lib/elasticsearch/get_ml_jobs.ts similarity index 79% rename from x-pack/plugins/monitoring/server/lib/elasticsearch/get_ml_jobs.js rename to x-pack/plugins/monitoring/server/lib/elasticsearch/get_ml_jobs.ts index 71f3633406c9..29f5a38ca3a2 100644 --- a/x-pack/plugins/monitoring/server/lib/elasticsearch/get_ml_jobs.js +++ b/x-pack/plugins/monitoring/server/lib/elasticsearch/get_ml_jobs.ts @@ -4,22 +4,26 @@ * you may not use this file except in compliance with the Elastic License. */ -import Bluebird from 'bluebird'; -import { includes, get } from 'lodash'; +import { includes } from 'lodash'; +// @ts-ignore import { checkParam } from '../error_missing_required'; +// @ts-ignore import { createQuery } from '../create_query'; +// @ts-ignore import { ElasticsearchMetric } from '../metrics'; import { ML_SUPPORTED_LICENSES } from '../../../common/constants'; +import { ElasticsearchResponse, ElasticsearchSource } from '../../../common/types/es'; +import { LegacyRequest } from '../../types'; /* * Get a listing of jobs along with some metric data to use for the listing */ -export function handleResponse(response) { - const hits = get(response, 'hits.hits', []); - return hits.map((hit) => get(hit, '_source.job_stats')); +export function handleResponse(response: ElasticsearchResponse) { + const hits = response.hits?.hits; + return hits?.map((hit) => hit._source.job_stats) ?? []; } -export function getMlJobs(req, esIndexPattern) { +export function getMlJobs(req: LegacyRequest, esIndexPattern: string) { checkParam(esIndexPattern, 'esIndexPattern in getMlJobs'); const config = req.server.config(); @@ -56,8 +60,12 @@ export function getMlJobs(req, esIndexPattern) { * cardinality isn't guaranteed to be accurate is the issue * but it will be as long as the precision threshold is >= the actual value */ -export function getMlJobsForCluster(req, esIndexPattern, cluster) { - const license = get(cluster, 'license', {}); +export function getMlJobsForCluster( + req: LegacyRequest, + esIndexPattern: string, + cluster: ElasticsearchSource +) { + const license = cluster.license ?? {}; if (license.status === 'active' && includes(ML_SUPPORTED_LICENSES, license.type)) { // ML is supported @@ -80,11 +88,11 @@ export function getMlJobsForCluster(req, esIndexPattern, cluster) { const { callWithRequest } = req.server.plugins.elasticsearch.getCluster('monitoring'); - return callWithRequest(req, 'search', params).then((response) => { - return get(response, 'aggregations.jobs_count.value', 0); + return callWithRequest(req, 'search', params).then((response: ElasticsearchResponse) => { + return response.aggregations.jobs_count.value ?? 0; }); } // ML is not supported - return Bluebird.resolve(null); + return Promise.resolve(null); } diff --git a/x-pack/plugins/monitoring/server/lib/elasticsearch/indices/get_index_summary.js b/x-pack/plugins/monitoring/server/lib/elasticsearch/indices/get_index_summary.ts similarity index 73% rename from x-pack/plugins/monitoring/server/lib/elasticsearch/indices/get_index_summary.js rename to x-pack/plugins/monitoring/server/lib/elasticsearch/indices/get_index_summary.ts index 6a0935f2b2d6..3257c5ac3608 100644 --- a/x-pack/plugins/monitoring/server/lib/elasticsearch/indices/get_index_summary.js +++ b/x-pack/plugins/monitoring/server/lib/elasticsearch/indices/get_index_summary.ts @@ -5,22 +5,27 @@ */ import { get } from 'lodash'; -import { checkParam } from '../../error_missing_required'; -import { createQuery } from '../../create_query'; -import { ElasticsearchMetric } from '../../metrics'; import { i18n } from '@kbn/i18n'; +// @ts-ignore +import { checkParam } from '../../error_missing_required'; +// @ts-ignore +import { createQuery } from '../../create_query'; +// @ts-ignore +import { ElasticsearchMetric } from '../../metrics'; +import { ElasticsearchResponse } from '../../../../common/types/es'; +import { LegacyRequest } from '../../../types'; -export function handleResponse(shardStats, indexUuid) { - return (response) => { - const indexStats = get(response, 'hits.hits[0]._source.index_stats'); - const primaries = get(indexStats, 'primaries'); - const total = get(indexStats, 'total'); +export function handleResponse(shardStats: any, indexUuid: string) { + return (response: ElasticsearchResponse) => { + const indexStats = response.hits?.hits[0]?._source.index_stats; + const primaries = indexStats?.primaries; + const total = indexStats?.total; const stats = { - documents: get(primaries, 'docs.count'), + documents: primaries?.docs?.count, dataSize: { - primaries: get(primaries, 'store.size_in_bytes'), - total: get(total, 'store.size_in_bytes'), + primaries: primaries?.store?.size_in_bytes, + total: total?.store?.size_in_bytes, }, }; @@ -55,10 +60,15 @@ export function handleResponse(shardStats, indexUuid) { } export function getIndexSummary( - req, - esIndexPattern, - shardStats, - { clusterUuid, indexUuid, start, end } + req: LegacyRequest, + esIndexPattern: string, + shardStats: any, + { + clusterUuid, + indexUuid, + start, + end, + }: { clusterUuid: string; indexUuid: string; start: number; end: number } ) { checkParam(esIndexPattern, 'esIndexPattern in elasticsearch/getIndexSummary'); diff --git a/x-pack/plugins/monitoring/server/lib/elasticsearch/indices/get_indices.js b/x-pack/plugins/monitoring/server/lib/elasticsearch/indices/get_indices.ts similarity index 72% rename from x-pack/plugins/monitoring/server/lib/elasticsearch/indices/get_indices.js rename to x-pack/plugins/monitoring/server/lib/elasticsearch/indices/get_indices.ts index efea687ef803..bf19fcf8978e 100644 --- a/x-pack/plugins/monitoring/server/lib/elasticsearch/indices/get_indices.js +++ b/x-pack/plugins/monitoring/server/lib/elasticsearch/indices/get_indices.ts @@ -5,43 +5,54 @@ */ import { get } from 'lodash'; -import { checkParam } from '../../error_missing_required'; -import { ElasticsearchMetric } from '../../metrics'; -import { createQuery } from '../../create_query'; -import { calculateRate } from '../../calculate_rate'; -import { getUnassignedShards } from '../shards'; import { i18n } from '@kbn/i18n'; +// @ts-ignore +import { checkParam } from '../../error_missing_required'; +// @ts-ignore +import { ElasticsearchMetric } from '../../metrics'; +// @ts-ignore +import { createQuery } from '../../create_query'; +// @ts-ignore +import { calculateRate } from '../../calculate_rate'; +// @ts-ignore +import { getUnassignedShards } from '../shards'; +import { ElasticsearchResponse } from '../../../../common/types/es'; +import { LegacyRequest } from '../../../types'; -export function handleResponse(resp, min, max, shardStats) { +export function handleResponse( + resp: ElasticsearchResponse, + min: number, + max: number, + shardStats: any +) { // map the hits - const hits = get(resp, 'hits.hits', []); + const hits = resp?.hits?.hits ?? []; return hits.map((hit) => { - const stats = get(hit, '_source.index_stats'); - const earliestStats = get(hit, 'inner_hits.earliest.hits.hits[0]._source.index_stats'); + const stats = hit._source.index_stats; + const earliestStats = hit.inner_hits?.earliest?.hits?.hits[0]?._source.index_stats; const rateOptions = { - hitTimestamp: get(hit, '_source.timestamp'), - earliestHitTimestamp: get(hit, 'inner_hits.earliest.hits.hits[0]._source.timestamp'), + hitTimestamp: hit._source.timestamp, + earliestHitTimestamp: hit.inner_hits?.earliest?.hits?.hits[0]?._source.timestamp, timeWindowMin: min, timeWindowMax: max, }; - const earliestIndexingHit = get(earliestStats, 'primaries.indexing'); + const earliestIndexingHit = earliestStats?.primaries?.indexing; const { rate: indexRate } = calculateRate({ - latestTotal: get(stats, 'primaries.indexing.index_total'), - earliestTotal: get(earliestIndexingHit, 'index_total'), + latestTotal: stats?.primaries?.indexing?.index_total, + earliestTotal: earliestIndexingHit?.index_total, ...rateOptions, }); - const earliestSearchHit = get(earliestStats, 'total.search'); + const earliestSearchHit = earliestStats?.total?.search; const { rate: searchRate } = calculateRate({ - latestTotal: get(stats, 'total.search.query_total'), - earliestTotal: get(earliestSearchHit, 'query_total'), + latestTotal: stats?.total?.search?.query_total, + earliestTotal: earliestSearchHit?.query_total, ...rateOptions, }); - const shardStatsForIndex = get(shardStats, ['indices', stats.index]); - + const shardStatsForIndex = get(shardStats, ['indices', stats?.index ?? '']); let status; let statusSort; let unassignedShards; @@ -65,10 +76,10 @@ export function handleResponse(resp, min, max, shardStats) { } return { - name: stats.index, + name: stats?.index, status, - doc_count: get(stats, 'primaries.docs.count'), - data_size: get(stats, 'total.store.size_in_bytes'), + doc_count: stats?.primaries?.docs?.count, + data_size: stats?.total?.store?.size_in_bytes, index_rate: indexRate, search_rate: searchRate, unassigned_shards: unassignedShards, @@ -78,9 +89,14 @@ export function handleResponse(resp, min, max, shardStats) { } export function buildGetIndicesQuery( - esIndexPattern, - clusterUuid, - { start, end, size, showSystemIndices = false } + esIndexPattern: string, + clusterUuid: string, + { + start, + end, + size, + showSystemIndices = false, + }: { start: number; end: number; size: number; showSystemIndices: boolean } ) { const filters = []; if (!showSystemIndices) { @@ -134,7 +150,12 @@ export function buildGetIndicesQuery( }; } -export function getIndices(req, esIndexPattern, showSystemIndices = false, shardStats) { +export function getIndices( + req: LegacyRequest, + esIndexPattern: string, + showSystemIndices: boolean = false, + shardStats: any +) { checkParam(esIndexPattern, 'esIndexPattern in elasticsearch/getIndices'); const { min: start, max: end } = req.payload.timeRange; @@ -145,7 +166,7 @@ export function getIndices(req, esIndexPattern, showSystemIndices = false, shard start, end, showSystemIndices, - size: config.get('monitoring.ui.max_bucket_size'), + size: parseInt(config.get('monitoring.ui.max_bucket_size') || '', 10), }); const { callWithRequest } = req.server.plugins.elasticsearch.getCluster('monitoring'); diff --git a/x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/get_node_summary.js b/x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/get_node_summary.ts similarity index 59% rename from x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/get_node_summary.js rename to x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/get_node_summary.ts index 06f5d5488a1a..bf7471d77b61 100644 --- a/x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/get_node_summary.js +++ b/x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/get_node_summary.ts @@ -5,35 +5,49 @@ */ import { get } from 'lodash'; -import { checkParam } from '../../error_missing_required'; -import { createQuery } from '../../create_query'; -import { ElasticsearchMetric } from '../../metrics'; -import { getDefaultNodeFromId } from './get_default_node_from_id'; -import { calculateNodeType } from './calculate_node_type'; -import { getNodeTypeClassLabel } from './get_node_type_class_label'; import { i18n } from '@kbn/i18n'; +// @ts-ignore +import { checkParam } from '../../error_missing_required'; +// @ts-ignore +import { createQuery } from '../../create_query'; +// @ts-ignore +import { ElasticsearchMetric } from '../../metrics'; +// @ts-ignore +import { getDefaultNodeFromId } from './get_default_node_from_id'; +// @ts-ignore +import { calculateNodeType } from './calculate_node_type'; +// @ts-ignore +import { getNodeTypeClassLabel } from './get_node_type_class_label'; +import { + ElasticsearchSource, + ElasticsearchResponse, + ElasticsearchLegacySource, + ElasticsearchMetricbeatNode, +} from '../../../../common/types/es'; +import { LegacyRequest } from '../../../types'; -export function handleResponse(clusterState, shardStats, nodeUuid) { - return (response) => { +export function handleResponse( + clusterState: ElasticsearchSource['cluster_state'], + shardStats: any, + nodeUuid: string +) { + return (response: ElasticsearchResponse) => { let nodeSummary = {}; - const nodeStatsHits = get(response, 'hits.hits', []); - const nodes = nodeStatsHits.map((hit) => - get(hit, '_source.elasticsearch.node', hit._source.source_node) - ); // using [0] value because query results are sorted desc per timestamp + const nodeStatsHits = response.hits?.hits ?? []; + const nodes: Array< + ElasticsearchLegacySource['source_node'] | ElasticsearchMetricbeatNode + > = nodeStatsHits.map((hit) => hit._source.elasticsearch?.node || hit._source.source_node); // using [0] value because query results are sorted desc per timestamp const node = nodes[0] || getDefaultNodeFromId(nodeUuid); const sourceStats = - get(response, 'hits.hits[0]._source.elasticsearch.node.stats') || - get(response, 'hits.hits[0]._source.node_stats'); - const clusterNode = get(clusterState, ['nodes', nodeUuid]); + response.hits?.hits[0]?._source.elasticsearch?.node?.stats || + response.hits?.hits[0]?._source.node_stats; + const clusterNode = + clusterState && clusterState.nodes ? clusterState.nodes[nodeUuid] : undefined; const stats = { resolver: nodeUuid, - node_ids: nodes.map((node) => node.id || node.uuid), + node_ids: nodes.map((_node) => node.id || node.uuid), attributes: node.attributes, - transport_address: get( - response, - 'hits.hits[0]._source.service.address', - node.transport_address - ), + transport_address: response.hits?.hits[0]?._source.service?.address || node.transport_address, name: node.name, type: node.type, }; @@ -48,22 +62,19 @@ export function handleResponse(clusterState, shardStats, nodeUuid) { nodeSummary = { type: nodeType, - nodeTypeLabel: nodeTypeLabel, - nodeTypeClass: nodeTypeClass, + nodeTypeLabel, + nodeTypeClass, totalShards: _shardStats.shardCount, indexCount: _shardStats.indexCount, - documents: get(sourceStats, 'indices.docs.count'), + documents: sourceStats?.indices?.docs?.count, dataSize: - get(sourceStats, 'indices.store.size_in_bytes') || - get(sourceStats, 'indices.store.size.bytes'), + sourceStats?.indices?.store?.size_in_bytes || sourceStats?.indices?.store?.size?.bytes, freeSpace: - get(sourceStats, 'fs.total.available_in_bytes') || - get(sourceStats, 'fs.summary.available.bytes'), + sourceStats?.fs?.total?.available_in_bytes || sourceStats?.fs?.summary?.available?.bytes, totalSpace: - get(sourceStats, 'fs.total.total_in_bytes') || get(sourceStats, 'fs.summary.total.bytes'), + sourceStats?.fs?.total?.total_in_bytes || sourceStats?.fs?.summary?.total?.bytes, usedHeap: - get(sourceStats, 'jvm.mem.heap_used_percent') || - get(sourceStats, 'jvm.mem.heap.used.pct'), + sourceStats?.jvm?.mem?.heap_used_percent || sourceStats?.jvm?.mem?.heap?.used?.pct, status: i18n.translate('xpack.monitoring.es.nodes.onlineStatusLabel', { defaultMessage: 'Online', }), @@ -89,11 +100,16 @@ export function handleResponse(clusterState, shardStats, nodeUuid) { } export function getNodeSummary( - req, - esIndexPattern, - clusterState, - shardStats, - { clusterUuid, nodeUuid, start, end } + req: LegacyRequest, + esIndexPattern: string, + clusterState: ElasticsearchSource['cluster_state'], + shardStats: any, + { + clusterUuid, + nodeUuid, + start, + end, + }: { clusterUuid: string; nodeUuid: string; start: number; end: number } ) { checkParam(esIndexPattern, 'esIndexPattern in elasticsearch/getNodeSummary'); diff --git a/x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/get_nodes.js b/x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/get_nodes.ts similarity index 87% rename from x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/get_nodes.js rename to x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/get_nodes.ts index ac4fcea6150a..1e412d2303cc 100644 --- a/x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/get_nodes.js +++ b/x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/get_nodes.ts @@ -5,13 +5,21 @@ */ import moment from 'moment'; +// @ts-ignore import { checkParam } from '../../../error_missing_required'; +// @ts-ignore import { createQuery } from '../../../create_query'; +// @ts-ignore import { calculateAuto } from '../../../calculate_auto'; +// @ts-ignore import { ElasticsearchMetric } from '../../../metrics'; +// @ts-ignore import { getMetricAggs } from './get_metric_aggs'; import { handleResponse } from './handle_response'; +// @ts-ignore import { LISTING_METRICS_NAMES, LISTING_METRICS_PATHS } from './nodes_listing_metrics'; +import { LegacyRequest } from '../../../../types'; +import { ElasticsearchModifiedSource } from '../../../../../common/types/es'; /* Run an aggregation on node_stats to get stat data for the selected time * range for all the active nodes. Every option is a key to a configuration @@ -30,7 +38,13 @@ import { LISTING_METRICS_NAMES, LISTING_METRICS_PATHS } from './nodes_listing_me * @param {Object} nodesShardCount: per-node information about shards * @return {Array} node info combined with metrics for each node from handle_response */ -export async function getNodes(req, esIndexPattern, pageOfNodes, clusterStats, nodesShardCount) { +export async function getNodes( + req: LegacyRequest, + esIndexPattern: string, + pageOfNodes: Array<{ uuid: string }>, + clusterStats: ElasticsearchModifiedSource, + nodesShardCount: { nodes: { [nodeId: string]: { shardCount: number } } } +) { checkParam(esIndexPattern, 'esIndexPattern in getNodes'); const start = moment.utc(req.payload.timeRange.min).valueOf(); @@ -45,7 +59,7 @@ export async function getNodes(req, esIndexPattern, pageOfNodes, clusterStats, n const min = start; const bucketSize = Math.max( - config.get('monitoring.ui.min_interval_seconds'), + parseInt(config.get('monitoring.ui.min_interval_seconds') as string, 10), calculateAuto(100, duration).asSeconds() ); diff --git a/x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/handle_response.js b/x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/handle_response.ts similarity index 57% rename from x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/handle_response.js rename to x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/handle_response.ts index 3f82e8ec3e64..3e248a06318d 100644 --- a/x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/handle_response.js +++ b/x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/handle_response.ts @@ -6,8 +6,11 @@ import { get } from 'lodash'; import { mapNodesInfo } from './map_nodes_info'; +// @ts-ignore import { mapNodesMetrics } from './map_nodes_metrics'; +// @ts-ignore import { uncovertMetricNames } from '../../convert_metric_names'; +import { ElasticsearchResponse, ElasticsearchModifiedSource } from '../../../../../common/types/es'; /* * Process the response from the get_nodes query @@ -18,18 +21,18 @@ import { uncovertMetricNames } from '../../convert_metric_names'; * @return {Array} node info combined with metrics for each node */ export function handleResponse( - response, - clusterStats, - nodesShardCount, - pageOfNodes, + response: ElasticsearchResponse, + clusterStats: ElasticsearchModifiedSource | undefined, + nodesShardCount: { nodes: { [nodeId: string]: { shardCount: number } } } | undefined, + pageOfNodes: Array<{ uuid: string }>, timeOptions = {} ) { if (!get(response, 'hits.hits')) { return []; } - const nodeHits = get(response, 'hits.hits', []); - const nodesInfo = mapNodesInfo(nodeHits, clusterStats, nodesShardCount); + const nodeHits = response.hits?.hits ?? []; + const nodesInfo: { [key: string]: any } = mapNodesInfo(nodeHits, clusterStats, nodesShardCount); /* * Every node bucket is an object with a field for nodeId and fields for @@ -37,19 +40,29 @@ export function handleResponse( * with a sub-object for all the metrics buckets */ const nodeBuckets = get(response, 'aggregations.nodes.buckets', []); - const metricsForNodes = nodeBuckets.reduce((accum, { key: nodeId, by_date: byDate }) => { - return { - ...accum, - [nodeId]: uncovertMetricNames(byDate), - }; - }, {}); - const nodesMetrics = mapNodesMetrics(metricsForNodes, nodesInfo, timeOptions); // summarize the metrics of online nodes + const metricsForNodes = nodeBuckets.reduce( + ( + accum: { [nodeId: string]: any }, + { key: nodeId, by_date: byDate }: { key: string; by_date: any } + ) => { + return { + ...accum, + [nodeId]: uncovertMetricNames(byDate), + }; + }, + {} + ); + const nodesMetrics: { [key: string]: any } = mapNodesMetrics( + metricsForNodes, + nodesInfo, + timeOptions + ); // summarize the metrics of online nodes // nodesInfo is the source of truth for the nodeIds, where nodesMetrics will lack metrics for offline nodes const nodes = pageOfNodes.map((node) => ({ ...node, - ...nodesInfo[node.uuid], - ...nodesMetrics[node.uuid], + ...(nodesInfo && nodesInfo[node.uuid] ? nodesInfo[node.uuid] : {}), + ...(nodesMetrics && nodesMetrics[node.uuid] ? nodesMetrics[node.uuid] : {}), resolver: node.uuid, })); diff --git a/x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/map_nodes_info.js b/x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/map_nodes_info.js deleted file mode 100644 index 317c1cddf57a..000000000000 --- a/x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/map_nodes_info.js +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import { get, isUndefined } from 'lodash'; -import { calculateNodeType, getNodeTypeClassLabel } from '../'; - -/** - * @param {Array} nodeHits: info about each node from the hits in the get_nodes query - * @param {Object} clusterStats: cluster stats from cluster state document - * @param {Object} nodesShardCount: per-node information about shards - * @return {Object} summarized info about each node keyed by nodeId - */ -export function mapNodesInfo(nodeHits, clusterStats, nodesShardCount) { - const clusterState = get(clusterStats, 'cluster_state', { nodes: {} }); - - return nodeHits.reduce((prev, node) => { - const sourceNode = get(node, '_source.source_node') || get(node, '_source.elasticsearch.node'); - - const calculatedNodeType = calculateNodeType(sourceNode, get(clusterState, 'master_node')); - const { nodeType, nodeTypeLabel, nodeTypeClass } = getNodeTypeClassLabel( - sourceNode, - calculatedNodeType - ); - const isOnline = !isUndefined(get(clusterState, ['nodes', sourceNode.uuid || sourceNode.id])); - - return { - ...prev, - [sourceNode.uuid || sourceNode.id]: { - name: sourceNode.name, - transport_address: sourceNode.transport_address, - type: nodeType, - isOnline, - nodeTypeLabel: nodeTypeLabel, - nodeTypeClass: nodeTypeClass, - shardCount: get( - nodesShardCount, - `nodes[${sourceNode.uuid || sourceNode.id}].shardCount`, - 0 - ), - }, - }; - }, {}); -} diff --git a/x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/map_nodes_info.ts b/x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/map_nodes_info.ts new file mode 100644 index 000000000000..a2e80c9ca1d9 --- /dev/null +++ b/x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/map_nodes_info.ts @@ -0,0 +1,57 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { isUndefined } from 'lodash'; +// @ts-ignore +import { calculateNodeType } from '../calculate_node_type'; +// @ts-ignore +import { getNodeTypeClassLabel } from '../get_node_type_class_label'; +import { + ElasticsearchResponseHit, + ElasticsearchModifiedSource, +} from '../../../../../common/types/es'; + +/** + * @param {Array} nodeHits: info about each node from the hits in the get_nodes query + * @param {Object} clusterStats: cluster stats from cluster state document + * @param {Object} nodesShardCount: per-node information about shards + * @return {Object} summarized info about each node keyed by nodeId + */ +export function mapNodesInfo( + nodeHits: ElasticsearchResponseHit[], + clusterStats?: ElasticsearchModifiedSource, + nodesShardCount?: { nodes: { [nodeId: string]: { shardCount: number } } } +) { + const clusterState = clusterStats?.cluster_state ?? { nodes: {} }; + + return nodeHits.reduce((prev, node) => { + const sourceNode = node._source.source_node || node._source.elasticsearch?.node; + + const calculatedNodeType = calculateNodeType(sourceNode, clusterState.master_node); + const { nodeType, nodeTypeLabel, nodeTypeClass } = getNodeTypeClassLabel( + sourceNode, + calculatedNodeType + ); + const uuid = sourceNode?.uuid ?? sourceNode?.id ?? undefined; + if (!uuid) { + return prev; + } + const isOnline = !isUndefined(clusterState.nodes ? clusterState.nodes[uuid] : undefined); + + return { + ...prev, + [uuid]: { + name: sourceNode?.name, + transport_address: sourceNode?.transport_address, + type: nodeType, + isOnline, + nodeTypeLabel, + nodeTypeClass, + shardCount: nodesShardCount?.nodes[uuid]?.shardCount ?? 0, + }, + }; + }, {}); +} diff --git a/x-pack/plugins/monitoring/server/lib/elasticsearch/shards/get_shard_allocation.js b/x-pack/plugins/monitoring/server/lib/elasticsearch/shards/get_shard_allocation.ts similarity index 75% rename from x-pack/plugins/monitoring/server/lib/elasticsearch/shards/get_shard_allocation.js rename to x-pack/plugins/monitoring/server/lib/elasticsearch/shards/get_shard_allocation.ts index 40412c03b0ef..ed37b56b7ad0 100644 --- a/x-pack/plugins/monitoring/server/lib/elasticsearch/shards/get_shard_allocation.js +++ b/x-pack/plugins/monitoring/server/lib/elasticsearch/shards/get_shard_allocation.ts @@ -4,22 +4,26 @@ * you may not use this file except in compliance with the Elastic License. */ -import { get } from 'lodash'; +// @ts-ignore import { checkParam } from '../../error_missing_required'; +// @ts-ignore import { createQuery } from '../../create_query'; +// @ts-ignore import { ElasticsearchMetric } from '../../metrics'; +import { ElasticsearchResponse, ElasticsearchLegacySource } from '../../../../common/types/es'; +import { LegacyRequest } from '../../../types'; -export function handleResponse(response) { - const hits = get(response, 'hits.hits'); +export function handleResponse(response: ElasticsearchResponse) { + const hits = response.hits?.hits; if (!hits) { return []; } // deduplicate any shards from earlier days with the same cluster state state_uuid - const uniqueShards = new Set(); + const uniqueShards = new Set(); // map into object with shard and source properties - return hits.reduce((shards, hit) => { + return hits.reduce((shards: Array, hit) => { const shard = hit._source.shard; if (shard) { @@ -37,9 +41,13 @@ export function handleResponse(response) { } export function getShardAllocation( - req, - esIndexPattern, - { shardFilter, stateUuid, showSystemIndices = false } + req: LegacyRequest, + esIndexPattern: string, + { + shardFilter, + stateUuid, + showSystemIndices = false, + }: { shardFilter: any; stateUuid: string; showSystemIndices: boolean } ) { checkParam(esIndexPattern, 'esIndexPattern in elasticsearch/getShardAllocation'); diff --git a/x-pack/plugins/monitoring/server/lib/kibana/get_kibana_info.ts b/x-pack/plugins/monitoring/server/lib/kibana/get_kibana_info.ts index 0e8903908a55..4a0c598eec30 100644 --- a/x-pack/plugins/monitoring/server/lib/kibana/get_kibana_info.ts +++ b/x-pack/plugins/monitoring/server/lib/kibana/get_kibana_info.ts @@ -9,10 +9,11 @@ import { merge } from 'lodash'; import { checkParam } from '../error_missing_required'; // @ts-ignore import { calculateAvailability } from '../calculate_availability'; -import { LegacyRequest, ElasticsearchResponse } from '../../types'; +import { LegacyRequest } from '../../types'; +import { ElasticsearchResponse } from '../../../common/types/es'; export function handleResponse(resp: ElasticsearchResponse) { - const source = resp.hits?.hits[0]._source.kibana_stats; + const source = resp.hits?.hits[0]?._source.kibana_stats; const kibana = source?.kibana; return merge(kibana, { availability: calculateAvailability(source?.timestamp), diff --git a/x-pack/plugins/monitoring/server/lib/logstash/get_node_info.ts b/x-pack/plugins/monitoring/server/lib/logstash/get_node_info.ts index ead876460778..cdf227742400 100644 --- a/x-pack/plugins/monitoring/server/lib/logstash/get_node_info.ts +++ b/x-pack/plugins/monitoring/server/lib/logstash/get_node_info.ts @@ -9,7 +9,8 @@ import { merge } from 'lodash'; import { checkParam } from '../error_missing_required'; // @ts-ignore import { calculateAvailability } from '../calculate_availability'; -import { LegacyRequest, ElasticsearchResponse } from '../../types'; +import { LegacyRequest } from '../../types'; +import { ElasticsearchResponse } from '../../../common/types/es'; export function handleResponse(resp: ElasticsearchResponse) { const source = resp.hits?.hits[0]?._source?.logstash_stats; diff --git a/x-pack/plugins/monitoring/server/lib/logstash/get_pipeline_state_document.ts b/x-pack/plugins/monitoring/server/lib/logstash/get_pipeline_state_document.ts index 96419ceb4cc7..1556b44f7380 100644 --- a/x-pack/plugins/monitoring/server/lib/logstash/get_pipeline_state_document.ts +++ b/x-pack/plugins/monitoring/server/lib/logstash/get_pipeline_state_document.ts @@ -8,7 +8,8 @@ import { createQuery } from '../create_query'; // @ts-ignore import { LogstashMetric } from '../metrics'; -import { LegacyRequest, ElasticsearchResponse } from '../../types'; +import { LegacyRequest } from '../../types'; +import { ElasticsearchResponse } from '../../../common/types/es'; export async function getPipelineStateDocument( req: LegacyRequest, diff --git a/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/ccr.js b/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/ccr.ts similarity index 72% rename from x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/ccr.js rename to x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/ccr.ts index 9f69ea1465c2..6f41455ebca6 100644 --- a/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/ccr.js +++ b/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/ccr.ts @@ -7,11 +7,15 @@ import { schema } from '@kbn/config-schema'; import moment from 'moment'; import { get, groupBy } from 'lodash'; +// @ts-ignore import { handleError } from '../../../../lib/errors/handle_error'; +// @ts-ignore import { prefixIndexPattern } from '../../../../lib/ccs_utils'; import { INDEX_PATTERN_ELASTICSEARCH } from '../../../../../common/constants'; +import { ElasticsearchResponse, ElasticsearchSource } from '../../../../../common/types/es'; +import { LegacyRequest } from '../../../../types'; -function getBucketScript(max, min) { +function getBucketScript(max: string, min: string) { return { bucket_script: { buckets_path: { @@ -23,7 +27,13 @@ function getBucketScript(max, min) { }; } -function buildRequest(req, config, esIndexPattern) { +function buildRequest( + req: LegacyRequest, + config: { + get: (key: string) => string | undefined; + }, + esIndexPattern: string +) { const min = moment.utc(req.payload.timeRange.min).valueOf(); const max = moment.utc(req.payload.timeRange.max).valueOf(); const maxBucketSize = config.get('monitoring.ui.max_bucket_size'); @@ -168,7 +178,12 @@ function buildRequest(req, config, esIndexPattern) { }; } -export function ccrRoute(server) { +export function ccrRoute(server: { + route: (p: any) => void; + config: () => { + get: (key: string) => string | undefined; + }; +}) { server.route({ method: 'POST', path: '/api/monitoring/v1/clusters/{clusterUuid}/elasticsearch/ccr', @@ -186,14 +201,14 @@ export function ccrRoute(server) { }), }, }, - async handler(req) { + async handler(req: LegacyRequest) { const config = server.config(); const ccs = req.payload.ccs; const esIndexPattern = prefixIndexPattern(config, INDEX_PATTERN_ELASTICSEARCH, ccs); try { const { callWithRequest } = req.server.plugins.elasticsearch.getCluster('monitoring'); - const response = await callWithRequest( + const response: ElasticsearchResponse = await callWithRequest( req, 'search', buildRequest(req, config, esIndexPattern) @@ -203,50 +218,72 @@ export function ccrRoute(server) { return { data: [] }; } - const fullStats = get(response, 'hits.hits').reduce((accum, hit) => { - const innerHits = get(hit, 'inner_hits.by_shard.hits.hits'); - const innerHitsSource = innerHits.map((innerHit) => get(innerHit, '_source.ccr_stats')); - const grouped = groupBy( - innerHitsSource, - (stat) => `${stat.follower_index}:${stat.shard_id}` - ); + const fullStats: { + [key: string]: Array>; + } = + response.hits?.hits.reduce((accum, hit) => { + const innerHits = hit.inner_hits?.by_shard.hits?.hits ?? []; + const innerHitsSource = innerHits.map( + (innerHit) => + innerHit._source.ccr_stats as NonNullable + ); + const grouped = groupBy( + innerHitsSource, + (stat) => `${stat.follower_index}:${stat.shard_id}` + ); - return { - ...accum, - ...grouped, - }; - }, {}); + return { + ...accum, + ...grouped, + }; + }, {}) ?? {}; - const buckets = get(response, 'aggregations.by_follower_index.buckets'); - const data = buckets.reduce((accum, bucket) => { + const buckets = response.aggregations.by_follower_index.buckets; + const data = buckets.reduce((accum: any, bucket: any) => { const leaderIndex = get(bucket, 'leader_index.buckets[0].key'); const remoteCluster = get( bucket, 'leader_index.buckets[0].remote_cluster.buckets[0].key' ); const follows = remoteCluster ? `${leaderIndex} on ${remoteCluster}` : leaderIndex; - const stat = { + const stat: { + [key: string]: any; + shards: Array<{ + error?: string; + opsSynced: number; + syncLagTime: number; + syncLagOps: number; + }>; + } = { id: bucket.key, index: bucket.key, follows, + shards: [], + error: undefined, + opsSynced: undefined, + syncLagTime: undefined, + syncLagOps: undefined, }; - stat.shards = get(bucket, 'by_shard_id.buckets').reduce((accum, shardBucket) => { - const fullStat = get(fullStats[`${bucket.key}:${shardBucket.key}`], '[0]', {}); - const shardStat = { - shardId: shardBucket.key, - error: fullStat.read_exceptions.length - ? fullStat.read_exceptions[0].exception.type - : null, - opsSynced: get(shardBucket, 'ops_synced.value'), - syncLagTime: fullStat.time_since_last_read_millis, - syncLagOps: get(shardBucket, 'lag_ops.value'), - syncLagOpsLeader: get(shardBucket, 'leader_lag_ops.value'), - syncLagOpsFollower: get(shardBucket, 'follower_lag_ops.value'), - }; - accum.push(shardStat); - return accum; - }, []); + stat.shards = get(bucket, 'by_shard_id.buckets').reduce( + (accum2: any, shardBucket: any) => { + const fullStat = fullStats[`${bucket.key}:${shardBucket.key}`][0] ?? {}; + const shardStat = { + shardId: shardBucket.key, + error: fullStat.read_exceptions?.length + ? fullStat.read_exceptions[0].exception?.type + : null, + opsSynced: get(shardBucket, 'ops_synced.value'), + syncLagTime: fullStat.time_since_last_read_millis, + syncLagOps: get(shardBucket, 'lag_ops.value'), + syncLagOpsLeader: get(shardBucket, 'leader_lag_ops.value'), + syncLagOpsFollower: get(shardBucket, 'follower_lag_ops.value'), + }; + accum2.push(shardStat); + return accum2; + }, + [] + ); stat.error = (stat.shards.find((shard) => shard.error) || {}).error; stat.opsSynced = stat.shards.reduce((sum, { opsSynced }) => sum + opsSynced, 0); diff --git a/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/ccr_shard.js b/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/ccr_shard.ts similarity index 82% rename from x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/ccr_shard.js rename to x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/ccr_shard.ts index 92458a31c6bd..fd834cff29aa 100644 --- a/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/ccr_shard.js +++ b/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/ccr_shard.ts @@ -4,15 +4,19 @@ * you may not use this file except in compliance with the Elastic License. */ -import { get } from 'lodash'; import moment from 'moment'; import { schema } from '@kbn/config-schema'; +// @ts-ignore import { handleError } from '../../../../lib/errors/handle_error'; +// @ts-ignore import { prefixIndexPattern } from '../../../../lib/ccs_utils'; +// @ts-ignore import { getMetrics } from '../../../../lib/details/get_metrics'; import { INDEX_PATTERN_ELASTICSEARCH } from '../../../../../common/constants'; +import { ElasticsearchResponse } from '../../../../../common/types/es'; +import { LegacyRequest } from '../../../../types'; -function getFormattedLeaderIndex(leaderIndex) { +function getFormattedLeaderIndex(leaderIndex: string) { let leader = leaderIndex; if (leader.includes(':')) { const leaderSplit = leader.split(':'); @@ -21,7 +25,7 @@ function getFormattedLeaderIndex(leaderIndex) { return leader; } -async function getCcrStat(req, esIndexPattern, filters) { +async function getCcrStat(req: LegacyRequest, esIndexPattern: string, filters: unknown[]) { const min = moment.utc(req.payload.timeRange.min).valueOf(); const max = moment.utc(req.payload.timeRange.max).valueOf(); @@ -68,7 +72,7 @@ async function getCcrStat(req, esIndexPattern, filters) { return await callWithRequest(req, 'search', params); } -export function ccrShardRoute(server) { +export function ccrShardRoute(server: { route: (p: any) => void; config: () => {} }) { server.route({ method: 'POST', path: '/api/monitoring/v1/clusters/{clusterUuid}/elasticsearch/ccr/{index}/shard/{shardId}', @@ -88,7 +92,7 @@ export function ccrShardRoute(server) { }), }, }, - async handler(req) { + async handler(req: LegacyRequest) { const config = server.config(); const index = req.params.index; const shardId = req.params.shardId; @@ -120,7 +124,7 @@ export function ccrShardRoute(server) { ]; try { - const [metrics, ccrResponse] = await Promise.all([ + const [metrics, ccrResponse]: [unknown, ElasticsearchResponse] = await Promise.all([ getMetrics( req, esIndexPattern, @@ -133,18 +137,15 @@ export function ccrShardRoute(server) { getCcrStat(req, esIndexPattern, filters), ]); - const stat = get(ccrResponse, 'hits.hits[0]._source.ccr_stats', {}); - const oldestStat = get( - ccrResponse, - 'hits.hits[0].inner_hits.oldest.hits.hits[0]._source.ccr_stats', - {} - ); + const stat = ccrResponse.hits?.hits[0]?._source.ccr_stats ?? {}; + const oldestStat = + ccrResponse.hits?.hits[0].inner_hits?.oldest.hits?.hits[0]?._source.ccr_stats ?? {}; return { metrics, stat, - formattedLeader: getFormattedLeaderIndex(stat.leader_index), - timestamp: get(ccrResponse, 'hits.hits[0]._source.timestamp'), + formattedLeader: getFormattedLeaderIndex(stat.leader_index ?? ''), + timestamp: ccrResponse.hits?.hits[0]?._source.timestamp, oldestStat, }; } catch (err) { diff --git a/x-pack/plugins/monitoring/server/types.ts b/x-pack/plugins/monitoring/server/types.ts index 47ac3beb8c39..dd6ec9c7930e 100644 --- a/x-pack/plugins/monitoring/server/types.ts +++ b/x-pack/plugins/monitoring/server/types.ts @@ -17,7 +17,6 @@ import { LicensingPluginSetup } from '../../licensing/server'; import { PluginSetupContract as FeaturesPluginSetupContract } from '../../features/server'; import { EncryptedSavedObjectsPluginSetup } from '../../encrypted_saved_objects/server'; import { CloudSetup } from '../../cloud/server'; -import { ElasticsearchSource } from '../common/types/es'; export interface MonitoringLicenseService { refresh: () => Promise; @@ -118,26 +117,3 @@ export interface LegacyServer { }; }; } - -export interface ElasticsearchResponse { - hits?: { - hits: ElasticsearchResponseHit[]; - total: { - value: number; - }; - }; -} - -export interface ElasticsearchResponseHit { - _source: ElasticsearchSource; - inner_hits?: { - [field: string]: { - hits?: { - hits: ElasticsearchResponseHit[]; - total: { - value: number; - }; - }; - }; - }; -}