From 6e7fcfe181e2d080d10c3a648a8ca4f64454e915 Mon Sep 17 00:00:00 2001 From: Sandra G Date: Tue, 1 Feb 2022 12:54:19 -0500 Subject: [PATCH] [Stack Monitoring] improve unit tests in fetch functions in alerts (#124033) * add cluster_stats dataset to index pattern of query in fetchClusters * update unit tests to test the params being called with * add node_stats term filter * update test for node_stats filter in missing monitoring fetch rule Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../alerts/fetch_ccr_read_exceptions.test.ts | 115 ++++++++++ .../lib/alerts/fetch_cluster_health.test.ts | 63 ++++- .../server/lib/alerts/fetch_clusters.test.ts | 48 ++++ .../server/lib/alerts/fetch_clusters.ts | 1 + .../fetch_disk_usage_node_stats.test.ts | 136 ++++++++--- .../fetch_elasticsearch_versions.test.ts | 49 ++++ .../lib/alerts/fetch_index_shard_size.test.ts | 215 ++++++++++++++++++ .../lib/alerts/fetch_kibana_versions.test.ts | 62 +++++ .../server/lib/alerts/fetch_licenses.test.ts | 68 +++++- .../alerts/fetch_logstash_versions.test.ts | 67 ++++++ .../fetch_memory_usage_node_stats.test.ts | 173 ++++++++++++++ .../fetch_missing_monitoring_data.test.ts | 81 +++++++ .../alerts/fetch_missing_monitoring_data.ts | 2 + .../fetch_nodes_from_cluster_stats.test.ts | 213 +++++++++++++++++ 14 files changed, 1246 insertions(+), 47 deletions(-) create mode 100644 x-pack/plugins/monitoring/server/lib/alerts/fetch_ccr_read_exceptions.test.ts create mode 100644 x-pack/plugins/monitoring/server/lib/alerts/fetch_index_shard_size.test.ts create mode 100644 x-pack/plugins/monitoring/server/lib/alerts/fetch_memory_usage_node_stats.test.ts create mode 100644 x-pack/plugins/monitoring/server/lib/alerts/fetch_nodes_from_cluster_stats.test.ts diff --git a/x-pack/plugins/monitoring/server/lib/alerts/fetch_ccr_read_exceptions.test.ts b/x-pack/plugins/monitoring/server/lib/alerts/fetch_ccr_read_exceptions.test.ts new file mode 100644 index 00000000000000..da94cc5f975d97 --- /dev/null +++ b/x-pack/plugins/monitoring/server/lib/alerts/fetch_ccr_read_exceptions.test.ts @@ -0,0 +1,115 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { elasticsearchClientMock } from '../../../../../../src/core/server/elasticsearch/client/mocks'; +import { fetchCCRReadExceptions } from './fetch_ccr_read_exceptions'; + +jest.mock('../../static_globals', () => ({ + Globals: { + app: { + config: { + ui: { + ccs: { enabled: true }, + }, + }, + }, + }, +})); +import { Globals } from '../../static_globals'; + +describe('fetchCCReadExceptions', () => { + const esRes = { + aggregations: { + remote_clusters: { + buckets: [], + }, + }, + }; + const esClient = elasticsearchClientMock.createScopedClusterClient().asCurrentUser; + esClient.search.mockReturnValue( + // @ts-expect-error not full response interface + elasticsearchClientMock.createSuccessTransportRequestPromise(esRes) + ); + it('should call ES with correct query', async () => { + await fetchCCRReadExceptions(esClient, 1643306331418, 1643309869056, 10000); + expect(esClient.search).toHaveBeenCalledWith({ + index: + '*:.monitoring-es-*,.monitoring-es-*,*:metrics-elasticsearch.ccr-*,metrics-elasticsearch.ccr-*', + filter_path: ['aggregations.remote_clusters.buckets'], + body: { + size: 0, + query: { + bool: { + filter: [ + { + nested: { + path: 'ccr_stats.read_exceptions', + query: { exists: { field: 'ccr_stats.read_exceptions.exception' } }, + }, + }, + { + bool: { + should: [ + { term: { type: 'ccr_stats' } }, + { term: { 'data_stream.dataset': 'elasticsearch.ccr' } }, + ], + minimum_should_match: 1, + }, + }, + { + range: { + timestamp: { format: 'epoch_millis', gte: 1643306331418, lte: 1643309869056 }, + }, + }, + ], + }, + }, + aggs: { + remote_clusters: { + terms: { field: 'ccr_stats.remote_cluster', size: 10000 }, + aggs: { + follower_indices: { + terms: { field: 'ccr_stats.follower_index', size: 10000 }, + aggs: { + hits: { + top_hits: { + sort: [{ timestamp: { order: 'desc', unmapped_type: 'long' } }], + _source: { + includes: [ + 'cluster_uuid', + 'ccr_stats.read_exceptions', + 'ccr_stats.shard_id', + 'ccr_stats.leader_index', + ], + }, + size: 1, + }, + }, + }, + }, + }, + }, + }, + }, + }); + }); + it('should call ES with correct query when ccs disabled', async () => { + // @ts-ignore + Globals.app.config.ui.ccs.enabled = false; + let params = null; + esClient.search.mockImplementation((...args) => { + params = args[0]; + return elasticsearchClientMock.createSuccessTransportRequestPromise(esRes as any); + }); + + await fetchCCRReadExceptions(esClient, 1643306331418, 1643309869056, 10000); + + // @ts-ignore + expect(params.index).toBe('.monitoring-es-*,metrics-elasticsearch.ccr-*'); + }); +}); diff --git a/x-pack/plugins/monitoring/server/lib/alerts/fetch_cluster_health.test.ts b/x-pack/plugins/monitoring/server/lib/alerts/fetch_cluster_health.test.ts index ea87608a14ef03..46299ff994f6bb 100644 --- a/x-pack/plugins/monitoring/server/lib/alerts/fetch_cluster_health.test.ts +++ b/x-pack/plugins/monitoring/server/lib/alerts/fetch_cluster_health.test.ts @@ -9,7 +9,6 @@ import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths import { elasticsearchClientMock } from '../../../../../../src/core/server/elasticsearch/client/mocks'; import { fetchClusterHealth } from './fetch_cluster_health'; - jest.mock('../../static_globals', () => ({ Globals: { app: { @@ -21,12 +20,14 @@ jest.mock('../../static_globals', () => ({ }, }, })); +import { Globals } from '../../static_globals'; describe('fetchClusterHealth', () => { it('should return the cluster health', async () => { - const status = 'green'; - const clusterUuid = 'sdfdsaj34434'; const esClient = elasticsearchClientMock.createScopedClusterClient().asCurrentUser; + const clusterUuid = 'sdfdsaj34434'; + const clusters = [{ clusterUuid, clusterName: 'foo' }]; + const status = 'green'; esClient.search.mockReturnValue( elasticsearchClientMock.createSuccessTransportRequestPromise({ hits: { @@ -45,8 +46,6 @@ describe('fetchClusterHealth', () => { } as estypes.SearchResponse) ); - const clusters = [{ clusterUuid, clusterName: 'foo' }]; - const health = await fetchClusterHealth(esClient, clusters); expect(health).toEqual([ { @@ -56,4 +55,58 @@ describe('fetchClusterHealth', () => { }, ]); }); + it('should call ES with correct query', async () => { + const esClient = elasticsearchClientMock.createScopedClusterClient().asCurrentUser; + await fetchClusterHealth(esClient, [ + { clusterUuid: '1', clusterName: 'foo1' }, + { clusterUuid: '2', clusterName: 'foo2' }, + ]); + expect(esClient.search).toHaveBeenCalledWith({ + index: + '*:.monitoring-es-*,.monitoring-es-*,*:metrics-elasticsearch.cluster_stats-*,metrics-elasticsearch.cluster_stats-*', + filter_path: [ + 'hits.hits._source.cluster_state.status', + 'hits.hits._source.cluster_uuid', + 'hits.hits._index', + ], + body: { + size: 2, + sort: [{ timestamp: { order: 'desc', unmapped_type: 'long' } }], + query: { + bool: { + filter: [ + { terms: { cluster_uuid: ['1', '2'] } }, + { + bool: { + should: [ + { term: { type: 'cluster_stats' } }, + { term: { 'data_stream.dataset': 'elasticsearch.cluster_stats' } }, + ], + minimum_should_match: 1, + }, + }, + { range: { timestamp: { gte: 'now-2m' } } }, + ], + }, + }, + collapse: { field: 'cluster_uuid' }, + }, + }); + }); + + it('should call ES with correct query when ccs disabled', async () => { + // @ts-ignore + Globals.app.config.ui.ccs.enabled = false; + const esClient = elasticsearchClientMock.createScopedClusterClient().asCurrentUser; + let params = null; + esClient.search.mockImplementation((...args) => { + params = args[0]; + return elasticsearchClientMock.createSuccessTransportRequestPromise({} as any); + }); + + await fetchClusterHealth(esClient, [{ clusterUuid: '1', clusterName: 'foo1' }]); + + // @ts-ignore + expect(params.index).toBe('.monitoring-es-*,metrics-elasticsearch.cluster_stats-*'); + }); }); diff --git a/x-pack/plugins/monitoring/server/lib/alerts/fetch_clusters.test.ts b/x-pack/plugins/monitoring/server/lib/alerts/fetch_clusters.test.ts index fa4fa0269fb1b2..5c4f44df4ac7cc 100644 --- a/x-pack/plugins/monitoring/server/lib/alerts/fetch_clusters.test.ts +++ b/x-pack/plugins/monitoring/server/lib/alerts/fetch_clusters.test.ts @@ -22,6 +22,7 @@ jest.mock('../../static_globals', () => ({ }, }, })); +import { Globals } from '../../static_globals'; describe('fetchClusters', () => { const clusterUuid = '1sdfds734'; @@ -81,4 +82,51 @@ describe('fetchClusters', () => { const params = esClient.search.mock.calls[0][0] as any; expect(params?.body?.query.bool.filter[1].range.timestamp.gte).toBe('now-2m'); }); + + it('should call ES with correct query', async () => { + const esClient = elasticsearchServiceMock.createScopedClusterClient().asCurrentUser; + await fetchClusters(esClient); + expect(esClient.search).toHaveBeenCalledWith({ + index: + '*:.monitoring-es-*,.monitoring-es-*,*:metrics-elasticsearch.cluster_stats-*,metrics-elasticsearch.cluster_stats-*', + filter_path: [ + 'hits.hits._source.cluster_settings.cluster.metadata.display_name', + 'hits.hits._source.cluster_uuid', + 'hits.hits._source.cluster_name', + ], + body: { + size: 1000, + query: { + bool: { + filter: [ + { + bool: { + should: [ + { term: { type: 'cluster_stats' } }, + { term: { 'data_stream.dataset': 'elasticsearch.cluster_stats' } }, + ], + minimum_should_match: 1, + }, + }, + { range: { timestamp: { gte: 'now-2m' } } }, + ], + }, + }, + collapse: { field: 'cluster_uuid' }, + }, + }); + }); + it('should call ES with correct query when ccs disabled', async () => { + // @ts-ignore + Globals.app.config.ui.ccs.enabled = false; + const esClient = elasticsearchServiceMock.createScopedClusterClient().asCurrentUser; + let params = null; + esClient.search.mockImplementation((...args) => { + params = args[0]; + return elasticsearchClientMock.createSuccessTransportRequestPromise({} as any); + }); + await fetchClusters(esClient); + // @ts-ignore + expect(params.index).toBe('.monitoring-es-*,metrics-elasticsearch.cluster_stats-*'); + }); }); diff --git a/x-pack/plugins/monitoring/server/lib/alerts/fetch_clusters.ts b/x-pack/plugins/monitoring/server/lib/alerts/fetch_clusters.ts index 76bd81c24145f4..159fe205df291b 100644 --- a/x-pack/plugins/monitoring/server/lib/alerts/fetch_clusters.ts +++ b/x-pack/plugins/monitoring/server/lib/alerts/fetch_clusters.ts @@ -27,6 +27,7 @@ export async function fetchClusters( const indexPatterns = getNewIndexPatterns({ config: Globals.app.config, moduleType: 'elasticsearch', + dataset: 'cluster_stats', ccs: getConfigCcs(Globals.app.config) ? '*' : undefined, }); const params = { diff --git a/x-pack/plugins/monitoring/server/lib/alerts/fetch_disk_usage_node_stats.test.ts b/x-pack/plugins/monitoring/server/lib/alerts/fetch_disk_usage_node_stats.test.ts index d4bbbe71e9c418..5c7e57818f713c 100644 --- a/x-pack/plugins/monitoring/server/lib/alerts/fetch_disk_usage_node_stats.test.ts +++ b/x-pack/plugins/monitoring/server/lib/alerts/fetch_disk_usage_node_stats.test.ts @@ -21,6 +21,7 @@ jest.mock('../../static_globals', () => ({ }, }, })); +import { Globals } from '../../static_globals'; describe('fetchDiskUsageNodeStats', () => { const esClient = elasticsearchServiceMock.createScopedClusterClient().asCurrentUser; @@ -34,44 +35,45 @@ describe('fetchDiskUsageNodeStats', () => { const duration = '5m'; const size = 10; - it('fetch normal stats', async () => { - esClient.search.mockReturnValue( - // @ts-expect-error not full response interface - elasticsearchClientMock.createSuccessTransportRequestPromise({ - aggregations: { - clusters: { - buckets: [ - { - key: clusters[0].clusterUuid, - nodes: { - buckets: [ - { - key: 'theNodeId', - index: { - buckets: [ - { - key: '.monitoring-es-*', - }, - ], + const esRes = { + aggregations: { + clusters: { + buckets: [ + { + key: clusters[0].clusterUuid, + nodes: { + buckets: [ + { + key: 'theNodeId', + index: { + buckets: [ + { + key: '.monitoring-es-*', }, - name: { - buckets: [ - { - key: 'theNodeName', - }, - ], + ], + }, + name: { + buckets: [ + { + key: 'theNodeName', }, - usage_ratio_percentile: { - value: 10, - }, - }, - ], + ], + }, + usage_ratio_percentile: { + value: 10, + }, }, - }, - ], + ], + }, }, - }, - }) + ], + }, + }, + }; + it('fetch normal stats', async () => { + esClient.search.mockReturnValue( + // @ts-expect-error not full response interface + elasticsearchClientMock.createSuccessTransportRequestPromise(esRes) ); const result = await fetchDiskUsageNodeStats(esClient, clusters, duration, size); @@ -85,4 +87,70 @@ describe('fetchDiskUsageNodeStats', () => { }, ]); }); + it('should call ES with correct query', async () => { + await fetchDiskUsageNodeStats(esClient, clusters, duration, size); + expect(esClient.search).toHaveBeenCalledWith({ + index: + '*:.monitoring-es-*,.monitoring-es-*,*:metrics-elasticsearch.node_stats-*,metrics-elasticsearch.node_stats-*', + filter_path: ['aggregations'], + body: { + size: 0, + query: { + bool: { + filter: [ + { terms: { cluster_uuid: ['cluster123'] } }, + { + bool: { + should: [ + { term: { type: 'node_stats' } }, + { term: { 'data_stream.dataset': 'elasticsearch.node_stats' } }, + ], + minimum_should_match: 1, + }, + }, + { range: { timestamp: { gte: 'now-5m' } } }, + ], + }, + }, + aggs: { + clusters: { + terms: { field: 'cluster_uuid', size: 10, include: ['cluster123'] }, + aggs: { + nodes: { + terms: { field: 'node_stats.node_id', size: 10 }, + aggs: { + index: { terms: { field: '_index', size: 1 } }, + total_in_bytes: { max: { field: 'node_stats.fs.total.total_in_bytes' } }, + available_in_bytes: { max: { field: 'node_stats.fs.total.available_in_bytes' } }, + usage_ratio_percentile: { + bucket_script: { + buckets_path: { + available_in_bytes: 'available_in_bytes', + total_in_bytes: 'total_in_bytes', + }, + script: + '100 - Math.floor((params.available_in_bytes / params.total_in_bytes) * 100)', + }, + }, + name: { terms: { field: 'source_node.name', size: 1 } }, + }, + }, + }, + }, + }, + }, + }); + }); + it('should call ES with correct query when ccs disabled', async () => { + // @ts-ignore + Globals.app.config.ui.ccs.enabled = false; + let params = null; + esClient.search.mockImplementation((...args) => { + params = args[0]; + return elasticsearchClientMock.createSuccessTransportRequestPromise(esRes as any); + }); + await fetchDiskUsageNodeStats(esClient, clusters, duration, size); + // @ts-ignore + expect(params.index).toBe('.monitoring-es-*,metrics-elasticsearch.node_stats-*'); + }); }); diff --git a/x-pack/plugins/monitoring/server/lib/alerts/fetch_elasticsearch_versions.test.ts b/x-pack/plugins/monitoring/server/lib/alerts/fetch_elasticsearch_versions.test.ts index c8505a82614dbe..ca57ddd007cab6 100644 --- a/x-pack/plugins/monitoring/server/lib/alerts/fetch_elasticsearch_versions.test.ts +++ b/x-pack/plugins/monitoring/server/lib/alerts/fetch_elasticsearch_versions.test.ts @@ -22,6 +22,7 @@ jest.mock('../../static_globals', () => ({ }, }, })); +import { Globals } from '../../static_globals'; describe('fetchElasticsearchVersions', () => { const esClient = elasticsearchServiceMock.createScopedClusterClient().asCurrentUser; @@ -66,4 +67,52 @@ describe('fetchElasticsearchVersions', () => { }, ]); }); + it('should call ES with correct query', async () => { + await fetchElasticsearchVersions(esClient, clusters, size); + expect(esClient.search).toHaveBeenCalledWith({ + index: + '*:.monitoring-es-*,.monitoring-es-*,*:metrics-elasticsearch.cluster_stats-*,metrics-elasticsearch.cluster_stats-*', + filter_path: [ + 'hits.hits._source.cluster_stats.nodes.versions', + 'hits.hits._index', + 'hits.hits._source.cluster_uuid', + ], + body: { + size: 1, + sort: [{ timestamp: { order: 'desc', unmapped_type: 'long' } }], + query: { + bool: { + filter: [ + { terms: { cluster_uuid: ['cluster123'] } }, + { + bool: { + should: [ + { term: { type: 'cluster_stats' } }, + { term: { 'data_stream.dataset': 'elasticsearch.cluster_stats' } }, + ], + minimum_should_match: 1, + }, + }, + { range: { timestamp: { gte: 'now-2m' } } }, + ], + }, + }, + collapse: { field: 'cluster_uuid' }, + }, + }); + }); + it('should call ES with correct query when ccs disabled', async () => { + // @ts-ignore + Globals.app.config.ui.ccs.enabled = false; + let params = null; + esClient.search.mockImplementation((...args) => { + params = args[0]; + return elasticsearchClientMock.createSuccessTransportRequestPromise( + {} as estypes.SearchResponse + ); + }); + await fetchElasticsearchVersions(esClient, clusters, size); + // @ts-ignore + expect(params.index).toBe('.monitoring-es-*,metrics-elasticsearch.cluster_stats-*'); + }); }); diff --git a/x-pack/plugins/monitoring/server/lib/alerts/fetch_index_shard_size.test.ts b/x-pack/plugins/monitoring/server/lib/alerts/fetch_index_shard_size.test.ts new file mode 100644 index 00000000000000..65b8be811fff33 --- /dev/null +++ b/x-pack/plugins/monitoring/server/lib/alerts/fetch_index_shard_size.test.ts @@ -0,0 +1,215 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { elasticsearchClientMock } from '../../../../../../src/core/server/elasticsearch/client/mocks'; +import { elasticsearchServiceMock } from 'src/core/server/mocks'; +import { fetchIndexShardSize } from './fetch_index_shard_size'; + +jest.mock('../../static_globals', () => ({ + Globals: { + app: { + getKeyStoreValue: () => '*', + config: { + ui: { + ccs: { enabled: true }, + }, + }, + }, + }, +})); +import { Globals } from '../../static_globals'; + +describe('fetchIndexShardSize', () => { + const esClient = elasticsearchServiceMock.createScopedClusterClient().asCurrentUser; + + const clusters = [ + { + clusterUuid: 'cluster123', + clusterName: 'test-cluster', + }, + ]; + const size = 10; + const shardIndexPatterns = '*'; + const threshold = 0.00000001; + const esRes = { + aggregations: { + clusters: { + buckets: [ + { + key: 'NG2d5jHiSBGPE6HLlUN2Bg', + doc_count: 60, + index: { + doc_count_error_upper_bound: 0, + sum_other_doc_count: 0, + buckets: [ + { + key: '.monitoring-es-7-2022.01.27', + doc_count: 30, + hits: { + hits: { + total: { + value: 30, + relation: 'eq', + }, + max_score: null, + hits: [ + { + _index: '.monitoring-es-7-2022.01.27', + _id: 'JVkunX4BfK-FILsH9Wr_', + _score: null, + _source: { + index_stats: { + shards: { + primaries: 1, + }, + primaries: { + store: { + size_in_bytes: 3537949, + }, + }, + }, + }, + sort: [1643314607570], + }, + ], + }, + }, + }, + { + key: '.monitoring-kibana-7-2022.01.27', + doc_count: 30, + hits: { + hits: { + total: { + value: 30, + relation: 'eq', + }, + max_score: null, + hits: [ + { + _index: '.monitoring-es-7-2022.01.27', + _id: 'JFkunX4BfK-FILsH9Wr_', + _score: null, + _source: { + index_stats: { + shards: { + primaries: 1, + }, + primaries: { + store: { + size_in_bytes: 1017426, + }, + }, + }, + }, + sort: [1643314607570], + }, + ], + }, + }, + }, + ], + }, + }, + ], + }, + }, + }; + it('fetch as expected', async () => { + esClient.search.mockReturnValue( + // @ts-expect-error not full response interface + elasticsearchClientMock.createSuccessTransportRequestPromise(esRes) + ); + + const result = await fetchIndexShardSize( + esClient, + clusters, + threshold, + shardIndexPatterns, + size + ); + expect(result).toEqual([ + { + ccs: undefined, + shardIndex: '.monitoring-es-7-2022.01.27', + shardSize: 0, + clusterUuid: 'NG2d5jHiSBGPE6HLlUN2Bg', + }, + { + ccs: undefined, + shardIndex: '.monitoring-kibana-7-2022.01.27', + shardSize: 0, + clusterUuid: 'NG2d5jHiSBGPE6HLlUN2Bg', + }, + ]); + }); + it('should call ES with correct query', async () => { + await fetchIndexShardSize(esClient, clusters, threshold, shardIndexPatterns, size); + expect(esClient.search).toHaveBeenCalledWith({ + index: + '*:.monitoring-es-*,.monitoring-es-*,*:metrics-elasticsearch.index-*,metrics-elasticsearch.index-*', + filter_path: ['aggregations.clusters.buckets'], + body: { + size: 0, + query: { + bool: { + filter: [ + { + bool: { + should: [ + { term: { type: 'index_stats' } }, + { term: { 'data_stream.dataset': 'elasticsearch.index' } }, + ], + minimum_should_match: 1, + }, + }, + { range: { timestamp: { gte: 'now-5m' } } }, + ], + }, + }, + aggs: { + clusters: { + terms: { include: ['cluster123'], field: 'cluster_uuid', size: 10 }, + aggs: { + index: { + terms: { field: 'index_stats.index', size: 10 }, + aggs: { + hits: { + top_hits: { + sort: [{ timestamp: { order: 'desc', unmapped_type: 'long' } }], + _source: { + includes: [ + '_index', + 'index_stats.shards.primaries', + 'index_stats.primaries.store.size_in_bytes', + ], + }, + size: 1, + }, + }, + }, + }, + }, + }, + }, + }, + }); + }); + it('should call ES with correct query when ccs disabled', async () => { + // @ts-ignore + Globals.app.config.ui.ccs.enabled = false; + let params = null; + esClient.search.mockImplementation((...args) => { + params = args[0]; + return elasticsearchClientMock.createSuccessTransportRequestPromise(esRes as any); + }); + await fetchIndexShardSize(esClient, clusters, threshold, shardIndexPatterns, size); + // @ts-ignore + expect(params.index).toBe('.monitoring-es-*,metrics-elasticsearch.index-*'); + }); +}); diff --git a/x-pack/plugins/monitoring/server/lib/alerts/fetch_kibana_versions.test.ts b/x-pack/plugins/monitoring/server/lib/alerts/fetch_kibana_versions.test.ts index 6bdecaf6f83edc..2e12f0741715b0 100644 --- a/x-pack/plugins/monitoring/server/lib/alerts/fetch_kibana_versions.test.ts +++ b/x-pack/plugins/monitoring/server/lib/alerts/fetch_kibana_versions.test.ts @@ -21,6 +21,7 @@ jest.mock('../../static_globals', () => ({ }, }, })); +import { Globals } from '../../static_globals'; describe('fetchKibanaVersions', () => { const esClient = elasticsearchServiceMock.createScopedClusterClient().asCurrentUser; @@ -87,4 +88,65 @@ describe('fetchKibanaVersions', () => { }, ]); }); + it('should call ES with correct query', async () => { + await fetchKibanaVersions(esClient, clusters, size); + expect(esClient.search).toHaveBeenCalledWith({ + index: + '*:.monitoring-kibana-*,.monitoring-kibana-*,*:metrics-kibana.stats-*,metrics-kibana.stats-*', + filter_path: ['aggregations'], + body: { + size: 0, + query: { + bool: { + filter: [ + { terms: { cluster_uuid: ['cluster123'] } }, + { + bool: { + should: [ + { term: { type: 'kibana_stats' } }, + { term: { 'data_stream.dataset': 'kibana.stats' } }, + ], + minimum_should_match: 1, + }, + }, + { range: { timestamp: { gte: 'now-2m' } } }, + ], + }, + }, + aggs: { + index: { terms: { field: '_index', size: 1 } }, + cluster: { + terms: { field: 'cluster_uuid', size: 1 }, + aggs: { + group_by_kibana: { + terms: { field: 'kibana_stats.kibana.uuid', size: 10 }, + aggs: { + group_by_version: { + terms: { + field: 'kibana_stats.kibana.version', + size: 1, + order: { latest_report: 'desc' }, + }, + aggs: { latest_report: { max: { field: 'timestamp' } } }, + }, + }, + }, + }, + }, + }, + }, + }); + }); + it('should call ES with correct query when ccs disabled', async () => { + // @ts-ignore + Globals.app.config.ui.ccs.enabled = false; + let params = null; + esClient.search.mockImplementation((...args) => { + params = args[0]; + return elasticsearchClientMock.createSuccessTransportRequestPromise({} as any); + }); + await fetchKibanaVersions(esClient, clusters, size); + // @ts-ignore + expect(params.index).toBe('.monitoring-kibana-*,metrics-kibana.stats-*'); + }); }); diff --git a/x-pack/plugins/monitoring/server/lib/alerts/fetch_licenses.test.ts b/x-pack/plugins/monitoring/server/lib/alerts/fetch_licenses.test.ts index fbfe6ba58d5401..190b5956925b10 100644 --- a/x-pack/plugins/monitoring/server/lib/alerts/fetch_licenses.test.ts +++ b/x-pack/plugins/monitoring/server/lib/alerts/fetch_licenses.test.ts @@ -8,7 +8,6 @@ import { fetchLicenses } from './fetch_licenses'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths import { elasticsearchClientMock } from '../../../../../../src/core/server/elasticsearch/client/mocks'; import { elasticsearchServiceMock } from 'src/core/server/mocks'; -import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; jest.mock('../../static_globals', () => ({ Globals: { @@ -21,6 +20,7 @@ jest.mock('../../static_globals', () => ({ }, }, })); +import { Globals } from '../../static_globals'; describe('fetchLicenses', () => { const clusterName = 'MyCluster'; @@ -45,11 +45,10 @@ describe('fetchLicenses', () => { }, ], }, - } as estypes.SearchResponse) + } as any) ); const clusters = [{ clusterUuid, clusterName }]; - const index = '.monitoring-es-*'; - const result = await fetchLicenses(esClient, clusters, index); + const result = await fetchLicenses(esClient, clusters); expect(result).toEqual([ { status: license.status, @@ -63,8 +62,7 @@ describe('fetchLicenses', () => { it('should only search for the clusters provided', async () => { const esClient = elasticsearchServiceMock.createScopedClusterClient().asCurrentUser; const clusters = [{ clusterUuid, clusterName }]; - const index = '.monitoring-es-*'; - await fetchLicenses(esClient, clusters, index); + await fetchLicenses(esClient, clusters); const params = esClient.search.mock.calls[0][0] as any; expect(params?.body?.query.bool.filter[0].terms.cluster_uuid).toEqual([clusterUuid]); }); @@ -72,9 +70,63 @@ describe('fetchLicenses', () => { it('should limit the time period in the query', async () => { const esClient = elasticsearchServiceMock.createScopedClusterClient().asCurrentUser; const clusters = [{ clusterUuid, clusterName }]; - const index = '.monitoring-es-*'; - await fetchLicenses(esClient, clusters, index); + await fetchLicenses(esClient, clusters); const params = esClient.search.mock.calls[0][0] as any; expect(params?.body?.query.bool.filter[2].range.timestamp.gte).toBe('now-2m'); }); + it('should call ES with correct query', async () => { + const esClient = elasticsearchServiceMock.createScopedClusterClient().asCurrentUser; + let params = null; + esClient.search.mockImplementation((...args) => { + params = args[0]; + return elasticsearchClientMock.createSuccessTransportRequestPromise({} as any); + }); + const clusters = [{ clusterUuid, clusterName }]; + await fetchLicenses(esClient, clusters); + expect(params).toStrictEqual({ + index: + '*:.monitoring-es-*,.monitoring-es-*,*:metrics-elasticsearch.cluster_stats-*,metrics-elasticsearch.cluster_stats-*', + filter_path: [ + 'hits.hits._source.license.*', + 'hits.hits._source.cluster_uuid', + 'hits.hits._index', + ], + body: { + size: 1, + sort: [{ timestamp: { order: 'desc', unmapped_type: 'long' } }], + query: { + bool: { + filter: [ + { terms: { cluster_uuid: ['clusterA'] } }, + { + bool: { + should: [ + { term: { type: 'cluster_stats' } }, + { term: { 'data_stream.dataset': 'elasticsearch.cluster_stats' } }, + ], + minimum_should_match: 1, + }, + }, + { range: { timestamp: { gte: 'now-2m' } } }, + ], + }, + }, + collapse: { field: 'cluster_uuid' }, + }, + }); + }); + it('should call ES with correct query when ccs disabled', async () => { + // @ts-ignore + Globals.app.config.ui.ccs.enabled = false; + const esClient = elasticsearchServiceMock.createScopedClusterClient().asCurrentUser; + let params = null; + esClient.search.mockImplementation((...args) => { + params = args[0]; + return elasticsearchClientMock.createSuccessTransportRequestPromise({} as any); + }); + const clusters = [{ clusterUuid, clusterName }]; + await fetchLicenses(esClient, clusters); + // @ts-ignore + expect(params.index).toBe('.monitoring-es-*,metrics-elasticsearch.cluster_stats-*'); + }); }); diff --git a/x-pack/plugins/monitoring/server/lib/alerts/fetch_logstash_versions.test.ts b/x-pack/plugins/monitoring/server/lib/alerts/fetch_logstash_versions.test.ts index a1df1a56ad3b54..754c5d3500dc13 100644 --- a/x-pack/plugins/monitoring/server/lib/alerts/fetch_logstash_versions.test.ts +++ b/x-pack/plugins/monitoring/server/lib/alerts/fetch_logstash_versions.test.ts @@ -21,6 +21,7 @@ jest.mock('../../static_globals', () => ({ }, }, })); +import { Globals } from '../../static_globals'; describe('fetchLogstashVersions', () => { const esClient = elasticsearchServiceMock.createScopedClusterClient().asCurrentUser; @@ -87,4 +88,70 @@ describe('fetchLogstashVersions', () => { }, ]); }); + it('should call ES with correct query', async () => { + let params = null; + esClient.search.mockImplementation((...args) => { + params = args[0]; + return elasticsearchClientMock.createSuccessTransportRequestPromise({} as any); + }); + await fetchLogstashVersions(esClient, clusters, size); + expect(params).toStrictEqual({ + index: + '*:.monitoring-logstash-*,.monitoring-logstash-*,*:metrics-logstash.node_stats-*,metrics-logstash.node_stats-*', + filter_path: ['aggregations'], + body: { + size: 0, + query: { + bool: { + filter: [ + { terms: { cluster_uuid: ['cluster123'] } }, + { + bool: { + should: [ + { term: { type: 'logstash_stats' } }, + { term: { 'data_stream.dataset': 'logstash.node_stats' } }, + ], + minimum_should_match: 1, + }, + }, + { range: { timestamp: { gte: 'now-2m' } } }, + ], + }, + }, + aggs: { + index: { terms: { field: '_index', size: 1 } }, + cluster: { + terms: { field: 'cluster_uuid', size: 1 }, + aggs: { + group_by_logstash: { + terms: { field: 'logstash_stats.logstash.uuid', size: 10 }, + aggs: { + group_by_version: { + terms: { + field: 'logstash_stats.logstash.version', + size: 1, + order: { latest_report: 'desc' }, + }, + aggs: { latest_report: { max: { field: 'timestamp' } } }, + }, + }, + }, + }, + }, + }, + }, + }); + }); + it('should call ES with correct query when ccs disabled', async () => { + // @ts-ignore + Globals.app.config.ui.ccs.enabled = false; + let params = null; + esClient.search.mockImplementation((...args) => { + params = args[0]; + return elasticsearchClientMock.createSuccessTransportRequestPromise({} as any); + }); + await fetchLogstashVersions(esClient, clusters, size); + // @ts-ignore + expect(params.index).toBe('.monitoring-logstash-*,metrics-logstash.node_stats-*'); + }); }); diff --git a/x-pack/plugins/monitoring/server/lib/alerts/fetch_memory_usage_node_stats.test.ts b/x-pack/plugins/monitoring/server/lib/alerts/fetch_memory_usage_node_stats.test.ts new file mode 100644 index 00000000000000..c2cecd4f21fa56 --- /dev/null +++ b/x-pack/plugins/monitoring/server/lib/alerts/fetch_memory_usage_node_stats.test.ts @@ -0,0 +1,173 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { elasticsearchClientMock } from '../../../../../../src/core/server/elasticsearch/client/mocks'; +import { fetchMemoryUsageNodeStats } from './fetch_memory_usage_node_stats'; + +jest.mock('../../static_globals', () => ({ + Globals: { + app: { + config: { + ui: { + ccs: { enabled: true }, + }, + }, + }, + }, +})); +import { Globals } from '../../static_globals'; + +describe('fetchMemoryUsageNodeStats', () => { + const esClient = elasticsearchClientMock.createScopedClusterClient().asCurrentUser; + const clusters = [ + { + clusterUuid: 'abc123', + clusterName: 'test', + }, + ]; + const startMs = 0; + const endMs = 0; + const size = 10; + + const esRes = { + aggregations: { + clusters: { + doc_count_error_upper_bound: 0, + sum_other_doc_count: 0, + buckets: [ + { + key: 'NG2d5jHiSBGPE6HLlUN2Bg', + doc_count: 30, + nodes: { + doc_count_error_upper_bound: 0, + sum_other_doc_count: 0, + buckets: [ + { + key: 'qrLmmSBMSXGSfciYLjL3GA', + doc_count: 30, + cluster_uuid: { + doc_count_error_upper_bound: 0, + sum_other_doc_count: 0, + buckets: [ + { + key: 'NG2d5jHiSBGPE6HLlUN2Bg', + doc_count: 30, + }, + ], + }, + avg_heap: { + value: 46.3, + }, + name: { + doc_count_error_upper_bound: 0, + sum_other_doc_count: 0, + buckets: [ + { + key: 'desktop-dca-192-168-162-170.endgames.local', + doc_count: 30, + }, + ], + }, + index: { + doc_count_error_upper_bound: 0, + sum_other_doc_count: 0, + buckets: [ + { + key: '.monitoring-es-7-2022.01.27', + doc_count: 30, + }, + ], + }, + }, + ], + }, + }, + ], + }, + }, + }; + + it('fetch stats', async () => { + esClient.search.mockReturnValue( + // @ts-expect-error not full response interface + elasticsearchClientMock.createSuccessTransportRequestPromise(esRes) + ); + const result = await fetchMemoryUsageNodeStats(esClient, clusters, startMs, endMs, size); + expect(result).toEqual([ + { + memoryUsage: 46, + clusterUuid: 'NG2d5jHiSBGPE6HLlUN2Bg', + nodeId: 'qrLmmSBMSXGSfciYLjL3GA', + nodeName: 'desktop-dca-192-168-162-170.endgames.local', + ccs: null, + }, + ]); + }); + + it('should call ES with correct query', async () => { + let params = null; + esClient.search.mockImplementation((...args) => { + params = args[0]; + return elasticsearchClientMock.createSuccessTransportRequestPromise(esRes as any); + }); + await fetchMemoryUsageNodeStats(esClient, clusters, startMs, endMs, size); + expect(params).toStrictEqual({ + index: + '*:.monitoring-es-*,.monitoring-es-*,*:metrics-elasticsearch.node_stats-*,metrics-elasticsearch.node_stats-*', + filter_path: ['aggregations'], + body: { + size: 0, + query: { + bool: { + filter: [ + { terms: { cluster_uuid: ['abc123'] } }, + { + bool: { + should: [ + { term: { type: 'node_stats' } }, + { term: { 'data_stream.dataset': 'elasticsearch.node_stats' } }, + ], + minimum_should_match: 1, + }, + }, + { range: { timestamp: { format: 'epoch_millis', gte: 0, lte: 0 } } }, + ], + }, + }, + aggs: { + clusters: { + terms: { field: 'cluster_uuid', size: 10 }, + aggs: { + nodes: { + terms: { field: 'source_node.uuid', size: 10 }, + aggs: { + index: { terms: { field: '_index', size: 1 } }, + avg_heap: { avg: { field: 'node_stats.jvm.mem.heap_used_percent' } }, + cluster_uuid: { terms: { field: 'cluster_uuid', size: 1 } }, + name: { terms: { field: 'source_node.name', size: 1 } }, + }, + }, + }, + }, + }, + }, + }); + }); + it('should call ES with correct query when ccs disabled', async () => { + // @ts-ignore + Globals.app.config.ui.ccs.enabled = false; + let params = null; + esClient.search.mockImplementation((...args) => { + params = args[0]; + return elasticsearchClientMock.createSuccessTransportRequestPromise(esRes as any); + }); + await fetchMemoryUsageNodeStats(esClient, clusters, startMs, endMs, size); + // @ts-ignore + expect(params.index).toBe('.monitoring-es-*,metrics-elasticsearch.node_stats-*'); + }); +}); diff --git a/x-pack/plugins/monitoring/server/lib/alerts/fetch_missing_monitoring_data.test.ts b/x-pack/plugins/monitoring/server/lib/alerts/fetch_missing_monitoring_data.test.ts index a51cced18fd7ba..e47c48d28d19d0 100644 --- a/x-pack/plugins/monitoring/server/lib/alerts/fetch_missing_monitoring_data.test.ts +++ b/x-pack/plugins/monitoring/server/lib/alerts/fetch_missing_monitoring_data.test.ts @@ -20,6 +20,7 @@ jest.mock('../../static_globals', () => ({ }, }, })); +import { Globals } from '../../static_globals'; function getResponse( index: string, @@ -159,4 +160,84 @@ describe('fetchMissingMonitoringData', () => { }, ]); }); + + it('should call ES with correct query', async () => { + const now = 10; + const clusters = [ + { + clusterUuid: 'clusterUuid1', + clusterName: 'clusterName1', + }, + ]; + let params = null; + esClient.search.mockImplementation((...args) => { + params = args[0]; + return elasticsearchClientMock.createSuccessTransportRequestPromise({} as any); + }); + await fetchMissingMonitoringData(esClient, clusters, size, now, startMs); + expect(params).toStrictEqual({ + index: + '*:.monitoring-es-*,.monitoring-es-*,*:metrics-elasticsearch.node_stats-*,metrics-elasticsearch.node_stats-*', + filter_path: ['aggregations.clusters.buckets'], + body: { + size: 0, + query: { + bool: { + filter: [ + { terms: { cluster_uuid: ['clusterUuid1'] } }, + { + bool: { + should: [ + { term: { type: 'node_stats' } }, + { term: { 'data_stream.dataset': 'elasticsearch.node_stats' } }, + ], + minimum_should_match: 1, + }, + }, + { range: { timestamp: { format: 'epoch_millis', gte: 100, lte: 10 } } }, + ], + }, + }, + aggs: { + clusters: { + terms: { field: 'cluster_uuid', size: 10 }, + aggs: { + es_uuids: { + terms: { field: 'node_stats.node_id', size: 10 }, + aggs: { + most_recent: { max: { field: 'timestamp' } }, + document: { + top_hits: { + size: 1, + sort: [{ timestamp: { order: 'desc', unmapped_type: 'long' } }], + _source: { includes: ['_index', 'source_node.name'] }, + }, + }, + }, + }, + }, + }, + }, + }, + }); + }); + it('should call ES with correct query when ccs disabled', async () => { + const now = 10; + const clusters = [ + { + clusterUuid: 'clusterUuid1', + clusterName: 'clusterName1', + }, + ]; + // @ts-ignore + Globals.app.config.ui.ccs.enabled = false; + let params = null; + esClient.search.mockImplementation((...args) => { + params = args[0]; + return elasticsearchClientMock.createSuccessTransportRequestPromise({} as any); + }); + await fetchMissingMonitoringData(esClient, clusters, size, now, startMs); + // @ts-ignore + expect(params.index).toBe('.monitoring-es-*,metrics-elasticsearch.node_stats-*'); + }); }); diff --git a/x-pack/plugins/monitoring/server/lib/alerts/fetch_missing_monitoring_data.ts b/x-pack/plugins/monitoring/server/lib/alerts/fetch_missing_monitoring_data.ts index 93ad44a5fd44bf..9119792dbd988a 100644 --- a/x-pack/plugins/monitoring/server/lib/alerts/fetch_missing_monitoring_data.ts +++ b/x-pack/plugins/monitoring/server/lib/alerts/fetch_missing_monitoring_data.ts @@ -11,6 +11,7 @@ import { AlertCluster, AlertMissingData } from '../../../common/types/alerts'; import { Globals } from '../../static_globals'; import { getConfigCcs } from '../../../common/ccs_utils'; import { getNewIndexPatterns } from '../cluster/get_index_patterns'; +import { createDatasetFilter } from './create_dataset_query_filter'; interface ClusterBucketESResponse { key: string; @@ -73,6 +74,7 @@ export async function fetchMissingMonitoringData( cluster_uuid: clusters.map((cluster) => cluster.clusterUuid), }, }, + createDatasetFilter('node_stats', 'elasticsearch.node_stats'), { range: { timestamp: { diff --git a/x-pack/plugins/monitoring/server/lib/alerts/fetch_nodes_from_cluster_stats.test.ts b/x-pack/plugins/monitoring/server/lib/alerts/fetch_nodes_from_cluster_stats.test.ts new file mode 100644 index 00000000000000..285baa75375ec7 --- /dev/null +++ b/x-pack/plugins/monitoring/server/lib/alerts/fetch_nodes_from_cluster_stats.test.ts @@ -0,0 +1,213 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { elasticsearchClientMock } from '../../../../../../src/core/server/elasticsearch/client/mocks'; +import { fetchNodesFromClusterStats } from './fetch_nodes_from_cluster_stats'; + +jest.mock('../../static_globals', () => ({ + Globals: { + app: { + config: { + ui: { + ccs: { enabled: true }, + }, + }, + }, + }, +})); +import { Globals } from '../../static_globals'; + +describe('fetchNodesFromClusterStats', () => { + const esClient = elasticsearchClientMock.createScopedClusterClient().asCurrentUser; + const clusters = [ + { + clusterUuid: 'NG2d5jHiSBGPE6HLlUN2Bg', + clusterName: 'elasticsearch', + }, + ]; + + const esRes = { + aggregations: { + clusters: { + buckets: [ + { + key: 'NG2d5jHiSBGPE6HLlUN2Bg', + doc_count: 12, + top: { + hits: { + total: { value: 12, relation: 'eq' }, + max_score: null, + hits: [ + { + _index: '.monitoring-es-7-2022.01.27', + _id: 'IlmvnX4BfK-FILsH34eS', + _score: null, + _source: { + cluster_state: { + nodes_hash: 858284333, + nodes: { + qrLmmSBMSXGSfciYLjL3GA: { + transport_address: '127.0.0.1:9300', + roles: [ + 'data', + 'data_cold', + 'data_content', + 'data_frozen', + 'data_hot', + 'data_warm', + 'ingest', + 'master', + 'ml', + 'remote_cluster_client', + 'transform', + ], + name: 'desktop-dca-192-168-162-170.endgames.local', + attributes: { + 'ml.machine_memory': '34359738368', + 'xpack.installed': 'true', + 'ml.max_jvm_size': '1610612736', + }, + ephemeral_id: 'cCXPWB3nSoKkl_m_q2nPFQ', + }, + }, + }, + }, + sort: [1643323056014], + }, + { + _index: '.monitoring-es-7-2022.01.27', + _id: 'GVmvnX4BfK-FILsHuIeF', + _score: null, + _source: { + cluster_state: { + nodes_hash: 858284333, + nodes: { + qrLmmSBMSXGSfciYLjL3GA: { + transport_address: '127.0.0.1:9300', + roles: [ + 'data', + 'data_cold', + 'data_content', + 'data_frozen', + 'data_hot', + 'data_warm', + 'ingest', + 'master', + 'ml', + 'remote_cluster_client', + 'transform', + ], + name: 'desktop-dca-192-168-162-170.endgames.local', + attributes: { + 'ml.machine_memory': '34359738368', + 'xpack.installed': 'true', + 'ml.max_jvm_size': '1610612736', + }, + ephemeral_id: 'cCXPWB3nSoKkl_m_q2nPFQ', + }, + }, + }, + }, + sort: [1643323046019], + }, + ], + }, + }, + }, + ], + }, + }, + }; + + it('fetch stats', async () => { + esClient.search.mockReturnValue( + // @ts-expect-error not full response interface + elasticsearchClientMock.createSuccessTransportRequestPromise(esRes) + ); + const result = await fetchNodesFromClusterStats(esClient, clusters); + expect(result).toEqual([ + { + clusterUuid: 'NG2d5jHiSBGPE6HLlUN2Bg', + recentNodes: [ + { + nodeUuid: 'qrLmmSBMSXGSfciYLjL3GA', + nodeEphemeralId: 'cCXPWB3nSoKkl_m_q2nPFQ', + nodeName: 'desktop-dca-192-168-162-170.endgames.local', + }, + ], + priorNodes: [ + { + nodeUuid: 'qrLmmSBMSXGSfciYLjL3GA', + nodeEphemeralId: 'cCXPWB3nSoKkl_m_q2nPFQ', + nodeName: 'desktop-dca-192-168-162-170.endgames.local', + }, + ], + }, + ]); + }); + + it('should call ES with correct query', async () => { + let params = null; + esClient.search.mockImplementation((...args) => { + params = args[0]; + return elasticsearchClientMock.createSuccessTransportRequestPromise(esRes as any); + }); + await fetchNodesFromClusterStats(esClient, clusters); + expect(params).toStrictEqual({ + index: + '*:.monitoring-es-*,.monitoring-es-*,*:metrics-elasticsearch.cluster_stats-*,metrics-elasticsearch.cluster_stats-*', + filter_path: ['aggregations.clusters.buckets'], + body: { + size: 0, + sort: [{ timestamp: { order: 'desc', unmapped_type: 'long' } }], + query: { + bool: { + filter: [ + { + bool: { + should: [ + { term: { type: 'cluster_stats' } }, + { term: { 'data_stream.dataset': 'elasticsearch.cluster_stats' } }, + ], + minimum_should_match: 1, + }, + }, + { range: { timestamp: { gte: 'now-2m' } } }, + ], + }, + }, + aggs: { + clusters: { + terms: { include: ['NG2d5jHiSBGPE6HLlUN2Bg'], field: 'cluster_uuid' }, + aggs: { + top: { + top_hits: { + sort: [{ timestamp: { order: 'desc', unmapped_type: 'long' } }], + _source: { includes: ['cluster_state.nodes_hash', 'cluster_state.nodes'] }, + size: 2, + }, + }, + }, + }, + }, + }, + }); + }); + it('should call ES with correct query when ccs disabled', async () => { + // @ts-ignore + Globals.app.config.ui.ccs.enabled = false; + let params = null; + esClient.search.mockImplementation((...args) => { + params = args[0]; + return elasticsearchClientMock.createSuccessTransportRequestPromise(esRes as any); + }); + await fetchNodesFromClusterStats(esClient, clusters); + // @ts-ignore + expect(params.index).toBe('.monitoring-es-*,metrics-elasticsearch.cluster_stats-*'); + }); +});