Skip to content

Commit

Permalink
[8.8] [Enterprise Search] Search Apps. - fetch indices one-by-one (el…
Browse files Browse the repository at this point in the history
…astic#156571) (elastic#156624)

# Backport

This will backport the following commits from `main` to `8.8`:
- [[Enterprise Search] Search Apps. - fetch indices one-by-one
(elastic#156571)](elastic#156571)

<!--- Backport version: 8.9.7 -->

### Questions ?
Please refer to the [Backport tool
documentation](https://github.com/sqren/backport)

<!--BACKPORT [{"author":{"name":"Sloane
Perrault","email":"[email protected]"},"sourceCommit":{"committedDate":"2023-05-03T20:39:53Z","message":"[Enterprise
Search] Search Apps. - fetch indices one-by-one (elastic#156571)\n\n##
Summary\r\n\r\nfetches a search application's indices' stats one at a
time.\r\n\r\nif even one index is not available the stats api returns an
error[^1].\r\nwhile fetching them all together is probably more
efficient we have to\r\nget them one-by-one just in case one isn't
available.\r\n\r\n### Checklist\r\n\r\n\r\n- [x] [Unit or
functional\r\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\r\nwere
updated or added to match the most common scenarios\r\n\r\n[^1]:
<details><summary>stats errors response</summary>\r\n <pre>\r\n {\r\n
\"error\": {\r\n \"root_cause\": [\r\n {\r\n \"type\":
\"index_not_found_exception\",\r\n \"reason\": \"no such index
[sloane-books-001]\",\r\n \"resource.type\": \"index_or_alias\",\r\n
\"resource.id\": \"sloane-books-001\",\r\n \"index_uuid\": \"_na_\",\r\n
\"index\": \"sloane-books-001\"\r\n }\r\n ],\r\n \"type\":
\"index_not_found_exception\",\r\n \"reason\": \"no such index
[sloane-books-001]\",\r\n \"resource.type\": \"index_or_alias\",\r\n
\"resource.id\": \"sloane-books-001\",\r\n \"index_uuid\": \"_na_\",\r\n
\"index\": \"sloane-books-001\"\r\n },\r\n \"status\": 404\r\n }\r\n
</pre>\r\n</details>","sha":"23a45bde21b36be49a1174b9bde1fc340de67534","branchLabelMapping":{"^v8.9.0$":"main","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["release_note:skip","Team:EnterpriseSearch","v8.8.0","v8.9.0"],"number":156571,"url":"https://github.com/elastic/kibana/pull/156571","mergeCommit":{"message":"[Enterprise
Search] Search Apps. - fetch indices one-by-one (elastic#156571)\n\n##
Summary\r\n\r\nfetches a search application's indices' stats one at a
time.\r\n\r\nif even one index is not available the stats api returns an
error[^1].\r\nwhile fetching them all together is probably more
efficient we have to\r\nget them one-by-one just in case one isn't
available.\r\n\r\n### Checklist\r\n\r\n\r\n- [x] [Unit or
functional\r\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\r\nwere
updated or added to match the most common scenarios\r\n\r\n[^1]:
<details><summary>stats errors response</summary>\r\n <pre>\r\n {\r\n
\"error\": {\r\n \"root_cause\": [\r\n {\r\n \"type\":
\"index_not_found_exception\",\r\n \"reason\": \"no such index
[sloane-books-001]\",\r\n \"resource.type\": \"index_or_alias\",\r\n
\"resource.id\": \"sloane-books-001\",\r\n \"index_uuid\": \"_na_\",\r\n
\"index\": \"sloane-books-001\"\r\n }\r\n ],\r\n \"type\":
\"index_not_found_exception\",\r\n \"reason\": \"no such index
[sloane-books-001]\",\r\n \"resource.type\": \"index_or_alias\",\r\n
\"resource.id\": \"sloane-books-001\",\r\n \"index_uuid\": \"_na_\",\r\n
\"index\": \"sloane-books-001\"\r\n },\r\n \"status\": 404\r\n }\r\n
</pre>\r\n</details>","sha":"23a45bde21b36be49a1174b9bde1fc340de67534"}},"sourceBranch":"main","suggestedTargetBranches":["8.8"],"targetPullRequestStates":[{"branch":"8.8","label":"v8.8.0","labelRegex":"^v(\\d+).(\\d+).\\d+$","isSourceBranch":false,"state":"NOT_CREATED"},{"branch":"main","label":"v8.9.0","labelRegex":"^v8.9.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/156571","number":156571,"mergeCommit":{"message":"[Enterprise
Search] Search Apps. - fetch indices one-by-one (elastic#156571)\n\n##
Summary\r\n\r\nfetches a search application's indices' stats one at a
time.\r\n\r\nif even one index is not available the stats api returns an
error[^1].\r\nwhile fetching them all together is probably more
efficient we have to\r\nget them one-by-one just in case one isn't
available.\r\n\r\n### Checklist\r\n\r\n\r\n- [x] [Unit or
functional\r\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\r\nwere
updated or added to match the most common scenarios\r\n\r\n[^1]:
<details><summary>stats errors response</summary>\r\n <pre>\r\n {\r\n
\"error\": {\r\n \"root_cause\": [\r\n {\r\n \"type\":
\"index_not_found_exception\",\r\n \"reason\": \"no such index
[sloane-books-001]\",\r\n \"resource.type\": \"index_or_alias\",\r\n
\"resource.id\": \"sloane-books-001\",\r\n \"index_uuid\": \"_na_\",\r\n
\"index\": \"sloane-books-001\"\r\n }\r\n ],\r\n \"type\":
\"index_not_found_exception\",\r\n \"reason\": \"no such index
[sloane-books-001]\",\r\n \"resource.type\": \"index_or_alias\",\r\n
\"resource.id\": \"sloane-books-001\",\r\n \"index_uuid\": \"_na_\",\r\n
\"index\": \"sloane-books-001\"\r\n },\r\n \"status\": 404\r\n }\r\n
</pre>\r\n</details>","sha":"23a45bde21b36be49a1174b9bde1fc340de67534"}}]}]
BACKPORT-->

Co-authored-by: Sloane Perrault <[email protected]>
  • Loading branch information
kibanamachine and Sloane Perrault authored May 3, 2023
1 parent c403354 commit 33efd47
Show file tree
Hide file tree
Showing 6 changed files with 44 additions and 21 deletions.
2 changes: 1 addition & 1 deletion x-pack/plugins/enterprise_search/common/types/engines.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ export interface EnterpriseSearchEngineDetails {
}

export interface EnterpriseSearchEngineIndex {
count: number;
count: number | null;
health: HealthStatus | 'unknown';
name: string;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/*
* 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.
*/

import { IScopedClusterClient } from '@kbn/core-elasticsearch-server';

export const availableIndices = async (
client: IScopedClusterClient,
indices: string[]
): Promise<string[]> => {
if (await client.asCurrentUser.indices.exists({ index: indices })) return indices;

const indicesAndExists: Array<[string, boolean]> = await Promise.all(
indices.map(async (index) => [index, await client.asCurrentUser.indices.exists({ index })])
);
return indicesAndExists.flatMap(([index, exists]) => (exists ? [index] : []));
};
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,14 @@ describe('fetchIndicesStats lib function', () => {
const mockClient = {
asCurrentUser: {
indices: {
exists: jest.fn(),
stats: jest.fn(),
},
},
asInternalUser: {},
};
const indices = ['test-index-name-1', 'test-index-name-2', 'test-index-name-3'];
const indicesStats = {
const indexStats = {
indices: {
'test-index-name-1': {
health: 'GREEN',
Expand Down Expand Up @@ -96,15 +97,11 @@ describe('fetchIndicesStats lib function', () => {
});

it('should return hydrated indices', async () => {
mockClient.asCurrentUser.indices.stats.mockImplementationOnce(() => indicesStats);
mockClient.asCurrentUser.indices.exists.mockImplementationOnce(() => true);
mockClient.asCurrentUser.indices.stats.mockImplementationOnce(() => indexStats);

await expect(
fetchIndicesStats(mockClient as unknown as IScopedClusterClient, indices)
).resolves.toEqual(fetchIndicesStatsResponse);

expect(mockClient.asCurrentUser.indices.stats).toHaveBeenCalledWith({
index: indices,
metric: ['docs'],
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -9,21 +9,23 @@ import { IScopedClusterClient } from '@kbn/core-elasticsearch-server/src/client/

import { EnterpriseSearchEngineIndex } from '../../../common/types/engines';

export const fetchIndicesStats = async (client: IScopedClusterClient, indices: string[]) => {
const { indices: indicesStats = {} } = await client.asCurrentUser.indices.stats({
index: indices,
import { availableIndices } from './available_indices';

export const fetchIndicesStats = async (
client: IScopedClusterClient,
indices: string[]
): Promise<EnterpriseSearchEngineIndex[]> => {
const indicesStats = await client.asCurrentUser.indices.stats({
index: await availableIndices(client, indices),
metric: ['docs'],
});

const indicesWithStats = indices.map((indexName: string) => {
const indexStats = indicesStats[indexName];
const hydratedIndex: EnterpriseSearchEngineIndex = {
count: indexStats?.primaries?.docs?.count ?? 0,
return indices.map((index) => {
const indexStats = indicesStats.indices?.[index];
return {
count: indexStats?.primaries?.docs?.count ?? null,
health: indexStats?.health ?? 'unknown',
name: indexName,
name: index,
};
return hydratedIndex;
});

return indicesWithStats;
};
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ describe('engines field_capabilities', () => {
const mockClient = {
asCurrentUser: {
fieldCaps: jest.fn(),
indices: { exists: jest.fn() },
},
asInternalUser: {},
};
Expand Down Expand Up @@ -44,6 +45,7 @@ describe('engines field_capabilities', () => {
indices: ['index-001'],
};

mockClient.asCurrentUser.indices.exists.mockResolvedValueOnce(true);
mockClient.asCurrentUser.fieldCaps.mockResolvedValueOnce(fieldCapsResponse);
await expect(
fetchEngineFieldCapabilities(mockClient as unknown as IScopedClusterClient, mockEngine)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,18 @@ import {
SchemaField,
} from '../../../common/types/engines';

import { availableIndices } from './available_indices';

export const fetchEngineFieldCapabilities = async (
client: IScopedClusterClient,
engine: EnterpriseSearchEngine
): Promise<EnterpriseSearchEngineFieldCapabilities> => {
const { name, updated_at_millis, indices } = engine;
const fieldCapabilities = await client.asCurrentUser.fieldCaps({
fields: '*',
include_unmapped: true,
index: indices,
filters: '-metadata',
include_unmapped: true,
index: await availableIndices(client, indices),
});
const fields = parseFieldsCapabilities(fieldCapabilities);
return {
Expand Down

0 comments on commit 33efd47

Please sign in to comment.