mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 01:38:56 -04:00
ES client : use the new type definitions (#83808)
* Use client from branch * Get type checking working in core * Fix types in other plugins * Update client types + remove type errors from core * migrate Task Manager Elasticsearch typing from legacy library to client library * use SortOrder instead o string in alerts * Update client types + fix core type issues * fix maps ts errors * Update Lens types * Convert Search Profiler body from a string to an object to conform to SearchRequest type. * Fix SOT types * Fix/mute Security/Spaces plugins type errors. * Fix bootstrap types * Fix painless_lab * corrected es typing in Event Log * Use new types from client for inferred search responses * Latest type defs * Integrate latest type defs for APM/UX * fix core errors * fix telemetry errors * fix canvas errors * fix data_enhanced errors * fix event_log errors * mute lens errors * fix or mute maps errors * fix reporting errors * fix security errors * mute errors in task_manager * fix errors in telemetry_collection_xpack * fix errors in data plugins * fix errors in alerts * mute errors in index_management * fix task_manager errors * mute or fix lens errors * fix upgrade_assistant errors * fix or mute errors in index_lifecycle_management * fix discover errors * fix core tests * ML changes * fix core type errors * mute error in kbn-es-archiver * fix error in data plugin * fix error in telemetry plugin * fix error in discover * fix discover errors * fix errors in task_manager * fix security errors * fix wrong conflict resolution * address errors with upstream code * update deps to the last commit * remove outdated comments * fix core errors * fix errors after update * adding more expect errors to ML * pull the lastest changes * fix core errors * fix errors in infra plugin * fix errors in uptime plugin * fix errors in ml * fix errors in xpack telemetry * fix or mute errors in transform * fix errors in upgrade assistant * fix or mute fleet errors * start fixing apm errors * fix errors in osquery * fix telemetry tests * core cleanup * fix asMutableArray imports * cleanup * data_enhanced cleanup * cleanup events_log * cleaup * fix error in kbn-es-archiver * fix errors in kbn-es-archiver * fix errors in kbn-es-archiver * fix ES typings for Hit * fix SO * fix actions plugin * fix fleet * fix maps * fix stack_alerts * fix eslint problems * fix event_log unit tests * fix failures in data_enhanced tests * fix test failure in kbn-es-archiver * fix test failures in index_pattern_management * fixing ML test * remove outdated comment in kbn-es-archiver * fix error type in ml * fix eslint errors in osquery plugin * fix runtime error in infra plugin * revert changes to event_log cluser exist check * fix eslint error in osquery * fixing ML endpoint argument types * fx types * Update api-extractor docs * attempt fix for ese test * Fix lint error * Fix types for ts refs * Fix data_enhanced unit test * fix lens types * generate docs * Fix a number of type issues in monitoring and ml * fix triggers_actions_ui * Fix ILM functional test * Put search.d.ts typings back * fix data plugin * Update typings in typings/elasticsearch * Update snapshots * mute errors in task_manager * mute fleet errors * lens. remove unnecessary ts-expect-errors * fix errors in stack_alerts * mute errors in osquery * fix errors in security_solution * fix errors in lists * fix errors in cases * mute errors in search_examples * use KibanaClient to enforce promise-based API * fix errors in test/ folder * update comment * fix errors in x-pack/test folder * fix errors in ml plugin * fix optional fields in ml api_integartoon tests * fix another casting problem in ml tests * fix another ml test failure * fix fleet problem after conflict resolution * rollback changes in security_solution. trying to fix test * Update type for discover rows * uncomment runtime_mappings as its outdated * address comments from Wylie * remove eslint error due to any * mute error due to incompatibility * Apply suggestions from code review Co-authored-by: John Schulz <github.com@jfsiii.org> * fix type error in lens tests * Update x-pack/plugins/upgrade_assistant/server/lib/reindexing/reindex_service.ts Co-authored-by: Alison Goryachev <alisonmllr20@gmail.com> * Update x-pack/plugins/upgrade_assistant/server/lib/reindexing/reindex_service.test.ts Co-authored-by: Alison Goryachev <alisonmllr20@gmail.com> * update deps * fix errors in core types * fix errors for the new elastic/elasticsearch version * remove unused type * remove unnecessary manual type cast and put optional chaining back * ML: mute Datafeed is missing indices_options * Apply suggestions from code review Co-authored-by: Josh Dover <1813008+joshdover@users.noreply.github.com> * use canary pacakge instead of git commit Co-authored-by: Josh Dover <me@joshdover.com> Co-authored-by: Josh Dover <1813008+joshdover@users.noreply.github.com> Co-authored-by: Gidi Meir Morris <github@gidi.io> Co-authored-by: Nathan Reese <reese.nathan@gmail.com> Co-authored-by: Wylie Conlon <wylieconlon@gmail.com> Co-authored-by: CJ Cenizal <cj@cenizal.com> Co-authored-by: Aleh Zasypkin <aleh.zasypkin@gmail.com> Co-authored-by: Dario Gieselaar <dario.gieselaar@elastic.co> Co-authored-by: restrry <restrry@gmail.com> Co-authored-by: James Gowdy <jgowdy@elastic.co> Co-authored-by: John Schulz <github.com@jfsiii.org> Co-authored-by: Alison Goryachev <alisonmllr20@gmail.com>
This commit is contained in:
parent
9724051f92
commit
238791b942
541 changed files with 3666 additions and 3051 deletions
|
@ -27,10 +27,10 @@ export interface SavedObjectsFindOptions
|
|||
| [preference](./kibana-plugin-core-public.savedobjectsfindoptions.preference.md) | <code>string</code> | An optional ES preference value to be used for the query \* |
|
||||
| [rootSearchFields](./kibana-plugin-core-public.savedobjectsfindoptions.rootsearchfields.md) | <code>string[]</code> | The fields to perform the parsed query against. Unlike the <code>searchFields</code> argument, these are expected to be root fields and will not be modified. If used in conjunction with <code>searchFields</code>, both are concatenated together. |
|
||||
| [search](./kibana-plugin-core-public.savedobjectsfindoptions.search.md) | <code>string</code> | Search documents using the Elasticsearch Simple Query String syntax. See Elasticsearch Simple Query String <code>query</code> argument for more information |
|
||||
| [searchAfter](./kibana-plugin-core-public.savedobjectsfindoptions.searchafter.md) | <code>unknown[]</code> | Use the sort values from the previous page to retrieve the next page of results. |
|
||||
| [searchAfter](./kibana-plugin-core-public.savedobjectsfindoptions.searchafter.md) | <code>estypes.Id[]</code> | Use the sort values from the previous page to retrieve the next page of results. |
|
||||
| [searchFields](./kibana-plugin-core-public.savedobjectsfindoptions.searchfields.md) | <code>string[]</code> | The fields to perform the parsed query against. See Elasticsearch Simple Query String <code>fields</code> argument for more information |
|
||||
| [sortField](./kibana-plugin-core-public.savedobjectsfindoptions.sortfield.md) | <code>string</code> | |
|
||||
| [sortOrder](./kibana-plugin-core-public.savedobjectsfindoptions.sortorder.md) | <code>string</code> | |
|
||||
| [sortOrder](./kibana-plugin-core-public.savedobjectsfindoptions.sortorder.md) | <code>estypes.SortOrder</code> | |
|
||||
| [type](./kibana-plugin-core-public.savedobjectsfindoptions.type.md) | <code>string | string[]</code> | |
|
||||
| [typeToNamespacesMap](./kibana-plugin-core-public.savedobjectsfindoptions.typetonamespacesmap.md) | <code>Map<string, string[] | undefined></code> | This map defines each type to search for, and the namespace(s) to search for the type in; this is only intended to be used by a saved object client wrapper. If this is defined, it supersedes the <code>type</code> and <code>namespaces</code> fields when building the Elasticsearch query. Any types that are not included in this map will be excluded entirely. If a type is included but its value is undefined, the operation will search for that type in the Default namespace. |
|
||||
|
||||
|
|
|
@ -9,5 +9,5 @@ Use the sort values from the previous page to retrieve the next page of results.
|
|||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
searchAfter?: unknown[];
|
||||
searchAfter?: estypes.Id[];
|
||||
```
|
||||
|
|
|
@ -7,5 +7,5 @@
|
|||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
sortOrder?: string;
|
||||
sortOrder?: estypes.SortOrder;
|
||||
```
|
||||
|
|
|
@ -27,10 +27,10 @@ export interface SavedObjectsFindOptions
|
|||
| [preference](./kibana-plugin-core-server.savedobjectsfindoptions.preference.md) | <code>string</code> | An optional ES preference value to be used for the query \* |
|
||||
| [rootSearchFields](./kibana-plugin-core-server.savedobjectsfindoptions.rootsearchfields.md) | <code>string[]</code> | The fields to perform the parsed query against. Unlike the <code>searchFields</code> argument, these are expected to be root fields and will not be modified. If used in conjunction with <code>searchFields</code>, both are concatenated together. |
|
||||
| [search](./kibana-plugin-core-server.savedobjectsfindoptions.search.md) | <code>string</code> | Search documents using the Elasticsearch Simple Query String syntax. See Elasticsearch Simple Query String <code>query</code> argument for more information |
|
||||
| [searchAfter](./kibana-plugin-core-server.savedobjectsfindoptions.searchafter.md) | <code>unknown[]</code> | Use the sort values from the previous page to retrieve the next page of results. |
|
||||
| [searchAfter](./kibana-plugin-core-server.savedobjectsfindoptions.searchafter.md) | <code>estypes.Id[]</code> | Use the sort values from the previous page to retrieve the next page of results. |
|
||||
| [searchFields](./kibana-plugin-core-server.savedobjectsfindoptions.searchfields.md) | <code>string[]</code> | The fields to perform the parsed query against. See Elasticsearch Simple Query String <code>fields</code> argument for more information |
|
||||
| [sortField](./kibana-plugin-core-server.savedobjectsfindoptions.sortfield.md) | <code>string</code> | |
|
||||
| [sortOrder](./kibana-plugin-core-server.savedobjectsfindoptions.sortorder.md) | <code>string</code> | |
|
||||
| [sortOrder](./kibana-plugin-core-server.savedobjectsfindoptions.sortorder.md) | <code>estypes.SortOrder</code> | |
|
||||
| [type](./kibana-plugin-core-server.savedobjectsfindoptions.type.md) | <code>string | string[]</code> | |
|
||||
| [typeToNamespacesMap](./kibana-plugin-core-server.savedobjectsfindoptions.typetonamespacesmap.md) | <code>Map<string, string[] | undefined></code> | This map defines each type to search for, and the namespace(s) to search for the type in; this is only intended to be used by a saved object client wrapper. If this is defined, it supersedes the <code>type</code> and <code>namespaces</code> fields when building the Elasticsearch query. Any types that are not included in this map will be excluded entirely. If a type is included but its value is undefined, the operation will search for that type in the Default namespace. |
|
||||
|
||||
|
|
|
@ -9,5 +9,5 @@ Use the sort values from the previous page to retrieve the next page of results.
|
|||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
searchAfter?: unknown[];
|
||||
searchAfter?: estypes.Id[];
|
||||
```
|
||||
|
|
|
@ -7,5 +7,5 @@
|
|||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
sortOrder?: string;
|
||||
sortOrder?: estypes.SortOrder;
|
||||
```
|
||||
|
|
|
@ -16,5 +16,5 @@ export interface SavedObjectsFindResult<T = unknown> extends SavedObject<T>
|
|||
| Property | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| [score](./kibana-plugin-core-server.savedobjectsfindresult.score.md) | <code>number</code> | The Elasticsearch <code>_score</code> of this result. |
|
||||
| [sort](./kibana-plugin-core-server.savedobjectsfindresult.sort.md) | <code>unknown[]</code> | The Elasticsearch <code>sort</code> value of this result. |
|
||||
| [sort](./kibana-plugin-core-server.savedobjectsfindresult.sort.md) | <code>string[]</code> | The Elasticsearch <code>sort</code> value of this result. |
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@ The Elasticsearch `sort` value of this result.
|
|||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
sort?: unknown[];
|
||||
sort?: string[];
|
||||
```
|
||||
|
||||
## Remarks
|
||||
|
|
|
@ -7,5 +7,5 @@
|
|||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
export declare type IEsSearchResponse<Source = any> = IKibanaSearchResponse<SearchResponse<Source>>;
|
||||
export declare type IEsSearchResponse<Source = any> = IKibanaSearchResponse<estypes.SearchResponse<Source>>;
|
||||
```
|
||||
|
|
|
@ -14,7 +14,7 @@ Fetch this source and reject the returned Promise on error
|
|||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
fetch(options?: ISearchOptions): Promise<import("elasticsearch").SearchResponse<any>>;
|
||||
fetch(options?: ISearchOptions): Promise<import("@elastic/elasticsearch/api/types").SearchResponse<any>>;
|
||||
```
|
||||
|
||||
## Parameters
|
||||
|
@ -25,5 +25,5 @@ fetch(options?: ISearchOptions): Promise<import("elasticsearch").SearchResponse<
|
|||
|
||||
<b>Returns:</b>
|
||||
|
||||
`Promise<import("elasticsearch").SearchResponse<any>>`
|
||||
`Promise<import("@elastic/elasticsearch/api/types").SearchResponse<any>>`
|
||||
|
||||
|
|
|
@ -7,5 +7,5 @@
|
|||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
export declare type IEsSearchResponse<Source = any> = IKibanaSearchResponse<SearchResponse<Source>>;
|
||||
export declare type IEsSearchResponse<Source = any> = IKibanaSearchResponse<estypes.SearchResponse<Source>>;
|
||||
```
|
||||
|
|
|
@ -145,7 +145,8 @@ export const SearchExamplesApp = ({
|
|||
setResponse(res.rawResponse);
|
||||
setTimeTook(res.rawResponse.took);
|
||||
const avgResult: number | undefined = res.rawResponse.aggregations
|
||||
? res.rawResponse.aggregations[1].value
|
||||
? // @ts-expect-error @elastic/elasticsearch no way to declare a type for aggregation in the search response
|
||||
res.rawResponse.aggregations[1].value
|
||||
: undefined;
|
||||
const message = (
|
||||
<EuiText>
|
||||
|
|
|
@ -702,13 +702,15 @@ function doSearch(
|
|||
const startTs = performance.now();
|
||||
|
||||
// Submit the search request using the `data.search` service.
|
||||
// @ts-expect-error request.params is incompatible. Filter is not assignable to QueryContainer
|
||||
return data.search
|
||||
.search(req, { sessionId })
|
||||
.pipe(
|
||||
tap((res) => {
|
||||
if (isCompleteResponse(res)) {
|
||||
const avgResult: number | undefined = res.rawResponse.aggregations
|
||||
? res.rawResponse.aggregations[1]?.value ?? res.rawResponse.aggregations[2]?.value
|
||||
? // @ts-expect-error @elastic/elasticsearch no way to declare a type for aggregation in the search response
|
||||
res.rawResponse.aggregations[1]?.value ?? res.rawResponse.aggregations[2]?.value
|
||||
: undefined;
|
||||
const message = (
|
||||
<EuiText>
|
||||
|
|
|
@ -96,7 +96,7 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"@elastic/datemath": "link:packages/elastic-datemath",
|
||||
"@elastic/elasticsearch": "npm:@elastic/elasticsearch-canary@^8.0.0-canary.3",
|
||||
"@elastic/elasticsearch": "npm:@elastic/elasticsearch-canary@^8.0.0-canary.4",
|
||||
"@elastic/ems-client": "7.12.0",
|
||||
"@elastic/eui": "31.7.0",
|
||||
"@elastic/filesaver": "1.1.2",
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { Client } from '@elastic/elasticsearch';
|
||||
import type { KibanaClient } from '@elastic/elasticsearch/api/kibana';
|
||||
import { ToolingLog } from '@kbn/dev-utils';
|
||||
import { KbnClient } from '@kbn/test';
|
||||
|
||||
|
@ -17,7 +17,7 @@ export async function emptyKibanaIndexAction({
|
|||
log,
|
||||
kbnClient,
|
||||
}: {
|
||||
client: Client;
|
||||
client: KibanaClient;
|
||||
log: ToolingLog;
|
||||
kbnClient: KbnClient;
|
||||
}) {
|
||||
|
|
|
@ -11,7 +11,7 @@ import { createReadStream } from 'fs';
|
|||
import { Readable } from 'stream';
|
||||
import { ToolingLog } from '@kbn/dev-utils';
|
||||
import { KbnClient } from '@kbn/test';
|
||||
import { Client } from '@elastic/elasticsearch';
|
||||
import type { KibanaClient } from '@elastic/elasticsearch/api/kibana';
|
||||
import { createPromiseFromStreams, concatStreamProviders } from '@kbn/utils';
|
||||
import { ES_CLIENT_HEADERS } from '../client_headers';
|
||||
|
||||
|
@ -48,7 +48,7 @@ export async function loadAction({
|
|||
name: string;
|
||||
skipExisting: boolean;
|
||||
useCreate: boolean;
|
||||
client: Client;
|
||||
client: KibanaClient;
|
||||
dataDir: string;
|
||||
log: ToolingLog;
|
||||
kbnClient: KbnClient;
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
import { resolve } from 'path';
|
||||
import { createWriteStream, mkdirSync } from 'fs';
|
||||
import { Readable, Writable } from 'stream';
|
||||
import { Client } from '@elastic/elasticsearch';
|
||||
import type { KibanaClient } from '@elastic/elasticsearch/api/kibana';
|
||||
import { ToolingLog } from '@kbn/dev-utils';
|
||||
import { createListStream, createPromiseFromStreams } from '@kbn/utils';
|
||||
|
||||
|
@ -32,7 +32,7 @@ export async function saveAction({
|
|||
}: {
|
||||
name: string;
|
||||
indices: string | string[];
|
||||
client: Client;
|
||||
client: KibanaClient;
|
||||
dataDir: string;
|
||||
log: ToolingLog;
|
||||
raw: boolean;
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
import { resolve } from 'path';
|
||||
import { createReadStream } from 'fs';
|
||||
import { Readable, Writable } from 'stream';
|
||||
import { Client } from '@elastic/elasticsearch';
|
||||
import type { KibanaClient } from '@elastic/elasticsearch/api/kibana';
|
||||
import { ToolingLog } from '@kbn/dev-utils';
|
||||
import { KbnClient } from '@kbn/test';
|
||||
import { createPromiseFromStreams } from '@kbn/utils';
|
||||
|
@ -32,7 +32,7 @@ export async function unloadAction({
|
|||
kbnClient,
|
||||
}: {
|
||||
name: string;
|
||||
client: Client;
|
||||
client: KibanaClient;
|
||||
dataDir: string;
|
||||
log: ToolingLog;
|
||||
kbnClient: KbnClient;
|
||||
|
|
|
@ -8,4 +8,4 @@
|
|||
|
||||
export const ES_CLIENT_HEADERS = {
|
||||
'x-elastic-product-origin': 'kibana',
|
||||
};
|
||||
} as const;
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { Client } from '@elastic/elasticsearch';
|
||||
import type { KibanaClient } from '@elastic/elasticsearch/api/kibana';
|
||||
import { ToolingLog } from '@kbn/dev-utils';
|
||||
import { KbnClient } from '@kbn/test';
|
||||
|
||||
|
@ -20,14 +20,14 @@ import {
|
|||
} from './actions';
|
||||
|
||||
interface Options {
|
||||
client: Client;
|
||||
client: KibanaClient;
|
||||
dataDir: string;
|
||||
log: ToolingLog;
|
||||
kbnClient: KbnClient;
|
||||
}
|
||||
|
||||
export class EsArchiver {
|
||||
private readonly client: Client;
|
||||
private readonly client: KibanaClient;
|
||||
private readonly dataDir: string;
|
||||
private readonly log: ToolingLog;
|
||||
private readonly kbnClient: KbnClient;
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
*/
|
||||
|
||||
import { Transform } from 'stream';
|
||||
import { Client } from '@elastic/elasticsearch';
|
||||
import type { KibanaClient } from '@elastic/elasticsearch/api/kibana';
|
||||
import { Stats } from '../stats';
|
||||
import { Progress } from '../progress';
|
||||
import { ES_CLIENT_HEADERS } from '../../client_headers';
|
||||
|
@ -21,7 +21,7 @@ export function createGenerateDocRecordsStream({
|
|||
progress,
|
||||
query,
|
||||
}: {
|
||||
client: Client;
|
||||
client: KibanaClient;
|
||||
stats: Stats;
|
||||
progress: Progress;
|
||||
query?: Record<string, any>;
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { Client } from '@elastic/elasticsearch';
|
||||
import type { KibanaClient } from '@elastic/elasticsearch/api/kibana';
|
||||
import AggregateError from 'aggregate-error';
|
||||
import { Writable } from 'stream';
|
||||
import { Stats } from '../stats';
|
||||
|
@ -14,7 +14,7 @@ import { Progress } from '../progress';
|
|||
import { ES_CLIENT_HEADERS } from '../../client_headers';
|
||||
|
||||
export function createIndexDocRecordsStream(
|
||||
client: Client,
|
||||
client: KibanaClient,
|
||||
stats: Stats,
|
||||
progress: Progress,
|
||||
useCreate: boolean = false
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { Client } from '@elastic/elasticsearch';
|
||||
import type { KibanaClient } from '@elastic/elasticsearch/api/kibana';
|
||||
import sinon from 'sinon';
|
||||
import { ToolingLog } from '@kbn/dev-utils';
|
||||
import { Stats } from '../../stats';
|
||||
|
@ -67,7 +67,7 @@ const createEsClientError = (errorType: string) => {
|
|||
const indexAlias = (aliases: Record<string, any>, index: string) =>
|
||||
Object.keys(aliases).find((k) => aliases[k] === index);
|
||||
|
||||
type StubClient = Client;
|
||||
type StubClient = KibanaClient;
|
||||
|
||||
export const createStubClient = (
|
||||
existingIndices: string[] = [],
|
||||
|
|
|
@ -125,7 +125,6 @@ describe('esArchiver: createCreateIndexStream()', () => {
|
|||
]);
|
||||
|
||||
sinon.assert.calledWith(client.indices.create as sinon.SinonSpy, {
|
||||
method: 'PUT',
|
||||
index: 'index',
|
||||
body: {
|
||||
settings: undefined,
|
||||
|
|
|
@ -9,7 +9,8 @@
|
|||
import { Transform, Readable } from 'stream';
|
||||
import { inspect } from 'util';
|
||||
|
||||
import { Client } from '@elastic/elasticsearch';
|
||||
import { estypes } from '@elastic/elasticsearch';
|
||||
import type { KibanaClient } from '@elastic/elasticsearch/api/kibana';
|
||||
import { ToolingLog } from '@kbn/dev-utils';
|
||||
|
||||
import { Stats } from '../stats';
|
||||
|
@ -18,12 +19,9 @@ import { deleteIndex } from './delete_index';
|
|||
import { ES_CLIENT_HEADERS } from '../../client_headers';
|
||||
|
||||
interface DocRecord {
|
||||
value: {
|
||||
value: estypes.IndexState & {
|
||||
index: string;
|
||||
type: string;
|
||||
settings: Record<string, any>;
|
||||
mappings: Record<string, any>;
|
||||
aliases: Record<string, any>;
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -33,7 +31,7 @@ export function createCreateIndexStream({
|
|||
skipExisting = false,
|
||||
log,
|
||||
}: {
|
||||
client: Client;
|
||||
client: KibanaClient;
|
||||
stats: Stats;
|
||||
skipExisting?: boolean;
|
||||
log: ToolingLog;
|
||||
|
@ -66,7 +64,6 @@ export function createCreateIndexStream({
|
|||
|
||||
await client.indices.create(
|
||||
{
|
||||
method: 'PUT',
|
||||
index,
|
||||
body: {
|
||||
settings,
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { Client } from '@elastic/elasticsearch';
|
||||
import type { KibanaClient } from '@elastic/elasticsearch/api/kibana';
|
||||
import { ToolingLog } from '@kbn/dev-utils';
|
||||
import { Stats } from '../stats';
|
||||
import { ES_CLIENT_HEADERS } from '../../client_headers';
|
||||
|
@ -15,7 +15,7 @@ import { ES_CLIENT_HEADERS } from '../../client_headers';
|
|||
const PENDING_SNAPSHOT_STATUSES = ['INIT', 'STARTED', 'WAITING'];
|
||||
|
||||
export async function deleteIndex(options: {
|
||||
client: Client;
|
||||
client: KibanaClient;
|
||||
stats: Stats;
|
||||
index: string | string[];
|
||||
log: ToolingLog;
|
||||
|
@ -84,7 +84,7 @@ export function isDeleteWhileSnapshotInProgressError(error: any) {
|
|||
* snapshotting this index to complete.
|
||||
*/
|
||||
export async function waitForSnapshotCompletion(
|
||||
client: Client,
|
||||
client: KibanaClient,
|
||||
index: string | string[],
|
||||
log: ToolingLog
|
||||
) {
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
*/
|
||||
|
||||
import { Transform } from 'stream';
|
||||
import { Client } from '@elastic/elasticsearch';
|
||||
import type { KibanaClient } from '@elastic/elasticsearch/api/kibana';
|
||||
import { ToolingLog } from '@kbn/dev-utils';
|
||||
|
||||
import { Stats } from '../stats';
|
||||
|
@ -15,7 +15,7 @@ import { deleteIndex } from './delete_index';
|
|||
import { cleanKibanaIndices } from './kibana_index';
|
||||
|
||||
export function createDeleteIndexStream(
|
||||
client: Client,
|
||||
client: KibanaClient,
|
||||
stats: Stats,
|
||||
log: ToolingLog,
|
||||
kibanaPluginIds: string[]
|
||||
|
|
|
@ -7,11 +7,11 @@
|
|||
*/
|
||||
|
||||
import { Transform } from 'stream';
|
||||
import { Client } from '@elastic/elasticsearch';
|
||||
import type { KibanaClient } from '@elastic/elasticsearch/api/kibana';
|
||||
import { Stats } from '../stats';
|
||||
import { ES_CLIENT_HEADERS } from '../../client_headers';
|
||||
|
||||
export function createGenerateIndexRecordsStream(client: Client, stats: Stats) {
|
||||
export function createGenerateIndexRecordsStream(client: KibanaClient, stats: Stats) {
|
||||
return new Transform({
|
||||
writableObjectMode: true,
|
||||
readableObjectMode: true,
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
|
||||
import { inspect } from 'util';
|
||||
|
||||
import { Client } from '@elastic/elasticsearch';
|
||||
import type { KibanaClient } from '@elastic/elasticsearch/api/kibana';
|
||||
import { ToolingLog } from '@kbn/dev-utils';
|
||||
import { KbnClient } from '@kbn/test';
|
||||
import { Stats } from '../stats';
|
||||
|
@ -23,7 +23,7 @@ export async function deleteKibanaIndices({
|
|||
stats,
|
||||
log,
|
||||
}: {
|
||||
client: Client;
|
||||
client: KibanaClient;
|
||||
stats: Stats;
|
||||
log: ToolingLog;
|
||||
}) {
|
||||
|
@ -67,22 +67,27 @@ export async function migrateKibanaIndex(kbnClient: KbnClient) {
|
|||
* with .kibana, then filters out any that aren't actually Kibana's core
|
||||
* index (e.g. we don't want to remove .kibana_task_manager or the like).
|
||||
*/
|
||||
async function fetchKibanaIndices(client: Client) {
|
||||
const resp = await client.cat.indices<unknown>(
|
||||
function isKibanaIndex(index?: string): index is string {
|
||||
return Boolean(
|
||||
index &&
|
||||
(/^\.kibana(:?_\d*)?$/.test(index) ||
|
||||
/^\.kibana(_task_manager)?_(pre)?\d+\.\d+\.\d+/.test(index))
|
||||
);
|
||||
}
|
||||
|
||||
async function fetchKibanaIndices(client: KibanaClient) {
|
||||
const resp = await client.cat.indices(
|
||||
{ index: '.kibana*', format: 'json' },
|
||||
{
|
||||
headers: ES_CLIENT_HEADERS,
|
||||
}
|
||||
);
|
||||
const isKibanaIndex = (index: string) =>
|
||||
/^\.kibana(:?_\d*)?$/.test(index) ||
|
||||
/^\.kibana(_task_manager)?_(pre)?\d+\.\d+\.\d+/.test(index);
|
||||
|
||||
if (!Array.isArray(resp.body)) {
|
||||
throw new Error(`expected response to be an array ${inspect(resp.body)}`);
|
||||
}
|
||||
|
||||
return resp.body.map((x: { index: string }) => x.index).filter(isKibanaIndex);
|
||||
return resp.body.map((x: { index?: string }) => x.index).filter(isKibanaIndex);
|
||||
}
|
||||
|
||||
const delay = (delayInMs: number) => new Promise((resolve) => setTimeout(resolve, delayInMs));
|
||||
|
@ -93,7 +98,7 @@ export async function cleanKibanaIndices({
|
|||
log,
|
||||
kibanaPluginIds,
|
||||
}: {
|
||||
client: Client;
|
||||
client: KibanaClient;
|
||||
stats: Stats;
|
||||
log: ToolingLog;
|
||||
kibanaPluginIds: string[];
|
||||
|
@ -149,7 +154,13 @@ export async function cleanKibanaIndices({
|
|||
stats.deletedIndex('.kibana');
|
||||
}
|
||||
|
||||
export async function createDefaultSpace({ index, client }: { index: string; client: Client }) {
|
||||
export async function createDefaultSpace({
|
||||
index,
|
||||
client,
|
||||
}: {
|
||||
index: string;
|
||||
client: KibanaClient;
|
||||
}) {
|
||||
await client.create(
|
||||
{
|
||||
index,
|
||||
|
|
|
@ -11,6 +11,7 @@ import { ConfigDeprecationProvider } from '@kbn/config';
|
|||
import { ConfigPath } from '@kbn/config';
|
||||
import { DetailedPeerCertificate } from 'tls';
|
||||
import { EnvironmentMode } from '@kbn/config';
|
||||
import { estypes } from '@elastic/elasticsearch';
|
||||
import { EuiBreadcrumb } from '@elastic/eui';
|
||||
import { EuiButtonEmptyProps } from '@elastic/eui';
|
||||
import { EuiConfirmModalProps } from '@elastic/eui';
|
||||
|
@ -1225,12 +1226,12 @@ export interface SavedObjectsFindOptions {
|
|||
preference?: string;
|
||||
rootSearchFields?: string[];
|
||||
search?: string;
|
||||
searchAfter?: unknown[];
|
||||
searchAfter?: estypes.Id[];
|
||||
searchFields?: string[];
|
||||
// (undocumented)
|
||||
sortField?: string;
|
||||
// (undocumented)
|
||||
sortOrder?: string;
|
||||
sortOrder?: estypes.SortOrder;
|
||||
// (undocumented)
|
||||
type: string | string[];
|
||||
typeToNamespacesMap?: Map<string, string[] | undefined>;
|
||||
|
|
|
@ -120,10 +120,10 @@ describe('CoreUsageDataService', () => {
|
|||
body: [
|
||||
{
|
||||
name: '.kibana_task_manager_1',
|
||||
'docs.count': 10,
|
||||
'docs.deleted': 10,
|
||||
'store.size': 1000,
|
||||
'pri.store.size': 2000,
|
||||
'docs.count': '10',
|
||||
'docs.deleted': '10',
|
||||
'store.size': '1000',
|
||||
'pri.store.size': '2000',
|
||||
},
|
||||
],
|
||||
} as any);
|
||||
|
@ -131,10 +131,10 @@ describe('CoreUsageDataService', () => {
|
|||
body: [
|
||||
{
|
||||
name: '.kibana_1',
|
||||
'docs.count': 20,
|
||||
'docs.deleted': 20,
|
||||
'store.size': 2000,
|
||||
'pri.store.size': 4000,
|
||||
'docs.count': '20',
|
||||
'docs.deleted': '20',
|
||||
'store.size': '2000',
|
||||
'pri.store.size': '4000',
|
||||
},
|
||||
],
|
||||
} as any);
|
||||
|
|
|
@ -118,10 +118,14 @@ export class CoreUsageDataService implements CoreService<CoreUsageDataSetup, Cor
|
|||
const stats = body[0];
|
||||
return {
|
||||
alias: kibanaOrTaskManagerIndex(index, this.kibanaConfig!.index),
|
||||
docsCount: stats['docs.count'],
|
||||
docsDeleted: stats['docs.deleted'],
|
||||
storeSizeBytes: stats['store.size'],
|
||||
primaryStoreSizeBytes: stats['pri.store.size'],
|
||||
// @ts-expect-error @elastic/elasticsearch declares it 'docs.count' as optional
|
||||
docsCount: parseInt(stats['docs.count'], 10),
|
||||
// @ts-expect-error @elastic/elasticsearch declares it 'docs.deleted' as optional
|
||||
docsDeleted: parseInt(stats['docs.deleted'], 10),
|
||||
// @ts-expect-error @elastic/elasticsearch declares it 'store.size' as string | number
|
||||
storeSizeBytes: parseInt(stats['store.size'], 10),
|
||||
// @ts-expect-error @elastic/elasticsearch declares it 'pri.store.size' as string | number
|
||||
primaryStoreSizeBytes: parseInt(stats['pri.store.size'], 10),
|
||||
};
|
||||
});
|
||||
})
|
||||
|
|
|
@ -156,9 +156,11 @@ const createErrorTransportRequestPromise = (err: any): MockedTransportRequestPro
|
|||
return promise as MockedTransportRequestPromise<never>;
|
||||
};
|
||||
|
||||
function createApiResponse(opts: Partial<ApiResponse> = {}): ApiResponse {
|
||||
function createApiResponse<TResponse = Record<string, any>>(
|
||||
opts: Partial<ApiResponse<TResponse>> = {}
|
||||
): ApiResponse<TResponse> {
|
||||
return {
|
||||
body: {},
|
||||
body: {} as any,
|
||||
statusCode: 200,
|
||||
headers: {},
|
||||
warnings: [],
|
||||
|
|
|
@ -11,7 +11,7 @@ import { elasticsearchClientMock } from './mocks';
|
|||
import { loggingSystemMock } from '../../logging/logging_system.mock';
|
||||
import { retryCallCluster, migrationRetryCallCluster } from './retry_call_cluster';
|
||||
|
||||
const dummyBody = { foo: 'bar' };
|
||||
const dummyBody: any = { foo: 'bar' };
|
||||
const createErrorReturn = (err: any) =>
|
||||
elasticsearchClientMock.createErrorTransportRequestPromise(err);
|
||||
|
||||
|
@ -29,7 +29,7 @@ describe('retryCallCluster', () => {
|
|||
|
||||
client.asyncSearch.get.mockReturnValue(successReturn);
|
||||
|
||||
const result = await retryCallCluster(() => client.asyncSearch.get());
|
||||
const result = await retryCallCluster(() => client.asyncSearch.get({} as any));
|
||||
expect(result.body).toEqual(dummyBody);
|
||||
});
|
||||
|
||||
|
@ -44,7 +44,7 @@ describe('retryCallCluster', () => {
|
|||
)
|
||||
.mockImplementationOnce(() => successReturn);
|
||||
|
||||
const result = await retryCallCluster(() => client.asyncSearch.get());
|
||||
const result = await retryCallCluster(() => client.asyncSearch.get({} as any));
|
||||
expect(result.body).toEqual(dummyBody);
|
||||
});
|
||||
|
||||
|
|
|
@ -117,6 +117,7 @@ describe('getSortedObjectsForExport()', () => {
|
|||
"keepAlive": "2m",
|
||||
},
|
||||
"search": undefined,
|
||||
"searchAfter": undefined,
|
||||
"sortField": "updated_at",
|
||||
"sortOrder": "desc",
|
||||
"type": Array [
|
||||
|
@ -145,7 +146,7 @@ describe('getSortedObjectsForExport()', () => {
|
|||
type = 'index-pattern',
|
||||
}: {
|
||||
attributes?: Record<string, unknown>;
|
||||
sort?: unknown[];
|
||||
sort?: string[];
|
||||
type?: string;
|
||||
} = {}
|
||||
) {
|
||||
|
@ -461,6 +462,7 @@ describe('getSortedObjectsForExport()', () => {
|
|||
"keepAlive": "2m",
|
||||
},
|
||||
"search": undefined,
|
||||
"searchAfter": undefined,
|
||||
"sortField": "updated_at",
|
||||
"sortOrder": "desc",
|
||||
"type": Array [
|
||||
|
@ -617,6 +619,7 @@ describe('getSortedObjectsForExport()', () => {
|
|||
"keepAlive": "2m",
|
||||
},
|
||||
"search": "foo",
|
||||
"searchAfter": undefined,
|
||||
"sortField": "updated_at",
|
||||
"sortOrder": "desc",
|
||||
"type": Array [
|
||||
|
@ -710,6 +713,7 @@ describe('getSortedObjectsForExport()', () => {
|
|||
"keepAlive": "2m",
|
||||
},
|
||||
"search": undefined,
|
||||
"searchAfter": undefined,
|
||||
"sortField": "updated_at",
|
||||
"sortOrder": "desc",
|
||||
"type": Array [
|
||||
|
@ -808,6 +812,7 @@ describe('getSortedObjectsForExport()', () => {
|
|||
"keepAlive": "2m",
|
||||
},
|
||||
"search": undefined,
|
||||
"searchAfter": undefined,
|
||||
"sortField": "updated_at",
|
||||
"sortOrder": "desc",
|
||||
"type": Array [
|
||||
|
|
|
@ -95,7 +95,7 @@ const checkOriginConflict = async (
|
|||
perPage: 10,
|
||||
fields: ['title'],
|
||||
sortField: 'updated_at',
|
||||
sortOrder: 'desc',
|
||||
sortOrder: 'desc' as const,
|
||||
...(namespace && { namespaces: [namespace] }),
|
||||
};
|
||||
const findResult = await savedObjectsClient.find<{ title?: string }>(findOptions);
|
||||
|
|
|
@ -102,7 +102,7 @@ export type SavedObjectsFieldMapping =
|
|||
|
||||
/** @internal */
|
||||
export interface IndexMapping {
|
||||
dynamic?: string;
|
||||
dynamic?: boolean | 'strict';
|
||||
properties: SavedObjectsMappingProperties;
|
||||
_meta?: IndexMappingMeta;
|
||||
}
|
||||
|
|
|
@ -164,6 +164,7 @@ describe('diffMappings', () => {
|
|||
_meta: {
|
||||
migrationMappingPropertyHashes: { foo: 'bar' },
|
||||
},
|
||||
// @ts-expect-error
|
||||
dynamic: 'abcde',
|
||||
properties: {},
|
||||
};
|
||||
|
|
|
@ -12,11 +12,12 @@
|
|||
* funcationality contained here.
|
||||
*/
|
||||
|
||||
import type { estypes } from '@elastic/elasticsearch';
|
||||
import { IndexMapping } from '../../mappings';
|
||||
|
||||
export interface CallCluster {
|
||||
(path: 'bulk', opts: { body: object[] }): Promise<BulkResult>;
|
||||
(path: 'count', opts: CountOpts): Promise<{ count: number; _shards: ShardsInfo }>;
|
||||
(path: 'count', opts: CountOpts): Promise<{ count: number; _shards: estypes.ShardStatistics }>;
|
||||
(path: 'clearScroll', opts: { scrollId: string }): Promise<any>;
|
||||
(path: 'indices.create', opts: IndexCreationOpts): Promise<any>;
|
||||
(path: 'indices.exists', opts: IndexOpts): Promise<boolean>;
|
||||
|
@ -143,7 +144,7 @@ export interface IndexSettingsResult {
|
|||
}
|
||||
|
||||
export interface RawDoc {
|
||||
_id: string;
|
||||
_id: estypes.Id;
|
||||
_source: any;
|
||||
_type?: string;
|
||||
}
|
||||
|
@ -153,14 +154,7 @@ export interface SearchResults {
|
|||
hits: RawDoc[];
|
||||
};
|
||||
_scroll_id?: string;
|
||||
_shards: ShardsInfo;
|
||||
}
|
||||
|
||||
export interface ShardsInfo {
|
||||
total: number;
|
||||
successful: number;
|
||||
skipped: number;
|
||||
failed: number;
|
||||
_shards: estypes.ShardStatistics;
|
||||
}
|
||||
|
||||
export interface ErrorResponse {
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import type { estypes } from '@elastic/elasticsearch';
|
||||
import _ from 'lodash';
|
||||
import { elasticsearchClientMock } from '../../../elasticsearch/client/mocks';
|
||||
import * as Index from './elastic_index';
|
||||
|
@ -33,41 +34,6 @@ describe('ElasticIndex', () => {
|
|||
expect(client.indices.get).toHaveBeenCalledWith({ index: '.kibana-test' }, { ignore: [404] });
|
||||
});
|
||||
|
||||
test('fails if the index doc type is unsupported', async () => {
|
||||
client.indices.get.mockImplementation((params) => {
|
||||
const index = params!.index as string;
|
||||
return elasticsearchClientMock.createSuccessTransportRequestPromise({
|
||||
[index]: {
|
||||
aliases: { foo: index },
|
||||
mappings: { spock: { dynamic: 'strict', properties: { a: 'b' } } },
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
await expect(Index.fetchInfo(client, '.baz')).rejects.toThrow(
|
||||
/cannot be automatically migrated/
|
||||
);
|
||||
});
|
||||
|
||||
test('fails if there are multiple root types', async () => {
|
||||
client.indices.get.mockImplementation((params) => {
|
||||
const index = params!.index as string;
|
||||
return elasticsearchClientMock.createSuccessTransportRequestPromise({
|
||||
[index]: {
|
||||
aliases: { foo: index },
|
||||
mappings: {
|
||||
doc: { dynamic: 'strict', properties: { a: 'b' } },
|
||||
doctor: { dynamic: 'strict', properties: { a: 'b' } },
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
await expect(Index.fetchInfo(client, '.baz')).rejects.toThrow(
|
||||
/cannot be automatically migrated/
|
||||
);
|
||||
});
|
||||
|
||||
test('decorates index info with exists and indexName', async () => {
|
||||
client.indices.get.mockImplementation((params) => {
|
||||
const index = params!.index as string;
|
||||
|
@ -75,8 +41,9 @@ describe('ElasticIndex', () => {
|
|||
[index]: {
|
||||
aliases: { foo: index },
|
||||
mappings: { dynamic: 'strict', properties: { a: 'b' } },
|
||||
settings: {},
|
||||
},
|
||||
});
|
||||
} as estypes.GetIndexResponse);
|
||||
});
|
||||
|
||||
const info = await Index.fetchInfo(client, '.baz');
|
||||
|
@ -85,6 +52,7 @@ describe('ElasticIndex', () => {
|
|||
mappings: { dynamic: 'strict', properties: { a: 'b' } },
|
||||
exists: true,
|
||||
indexName: '.baz',
|
||||
settings: {},
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -134,7 +102,7 @@ describe('ElasticIndex', () => {
|
|||
test('removes existing alias', async () => {
|
||||
client.indices.getAlias.mockResolvedValue(
|
||||
elasticsearchClientMock.createSuccessTransportRequestPromise({
|
||||
'.my-fanci-index': '.muchacha',
|
||||
'.my-fanci-index': { aliases: { '.muchacha': {} } },
|
||||
})
|
||||
);
|
||||
|
||||
|
@ -157,7 +125,7 @@ describe('ElasticIndex', () => {
|
|||
test('allows custom alias actions', async () => {
|
||||
client.indices.getAlias.mockResolvedValue(
|
||||
elasticsearchClientMock.createSuccessTransportRequestPromise({
|
||||
'.my-fanci-index': '.muchacha',
|
||||
'.my-fanci-index': { aliases: { '.muchacha': {} } },
|
||||
})
|
||||
);
|
||||
|
||||
|
@ -185,14 +153,18 @@ describe('ElasticIndex', () => {
|
|||
test('it creates the destination index, then reindexes to it', async () => {
|
||||
client.indices.getAlias.mockResolvedValue(
|
||||
elasticsearchClientMock.createSuccessTransportRequestPromise({
|
||||
'.my-fanci-index': '.muchacha',
|
||||
'.my-fanci-index': { aliases: { '.muchacha': {} } },
|
||||
})
|
||||
);
|
||||
client.reindex.mockResolvedValue(
|
||||
elasticsearchClientMock.createSuccessTransportRequestPromise({ task: 'abc' })
|
||||
elasticsearchClientMock.createSuccessTransportRequestPromise({
|
||||
task: 'abc',
|
||||
} as estypes.ReindexResponse)
|
||||
);
|
||||
client.tasks.get.mockResolvedValue(
|
||||
elasticsearchClientMock.createSuccessTransportRequestPromise({ completed: true })
|
||||
elasticsearchClientMock.createSuccessTransportRequestPromise({
|
||||
completed: true,
|
||||
} as estypes.GetTaskResponse)
|
||||
);
|
||||
|
||||
const info = {
|
||||
|
@ -200,7 +172,7 @@ describe('ElasticIndex', () => {
|
|||
exists: true,
|
||||
indexName: '.ze-index',
|
||||
mappings: {
|
||||
dynamic: 'strict',
|
||||
dynamic: 'strict' as const,
|
||||
properties: { foo: { type: 'keyword' } },
|
||||
},
|
||||
};
|
||||
|
@ -259,13 +231,16 @@ describe('ElasticIndex', () => {
|
|||
test('throws error if re-index task fails', async () => {
|
||||
client.indices.getAlias.mockResolvedValue(
|
||||
elasticsearchClientMock.createSuccessTransportRequestPromise({
|
||||
'.my-fanci-index': '.muchacha',
|
||||
'.my-fanci-index': { aliases: { '.muchacha': {} } },
|
||||
})
|
||||
);
|
||||
client.reindex.mockResolvedValue(
|
||||
elasticsearchClientMock.createSuccessTransportRequestPromise({ task: 'abc' })
|
||||
elasticsearchClientMock.createSuccessTransportRequestPromise({
|
||||
task: 'abc',
|
||||
} as estypes.ReindexResponse)
|
||||
);
|
||||
client.tasks.get.mockResolvedValue(
|
||||
// @ts-expect-error @elastic/elasticsearch GetTaskResponse requires a `task` property even on errors
|
||||
elasticsearchClientMock.createSuccessTransportRequestPromise({
|
||||
completed: true,
|
||||
error: {
|
||||
|
@ -273,7 +248,7 @@ describe('ElasticIndex', () => {
|
|||
reason: 'all shards failed',
|
||||
failed_shards: [],
|
||||
},
|
||||
})
|
||||
} as estypes.GetTaskResponse)
|
||||
);
|
||||
|
||||
const info = {
|
||||
|
@ -286,6 +261,7 @@ describe('ElasticIndex', () => {
|
|||
},
|
||||
};
|
||||
|
||||
// @ts-expect-error
|
||||
await expect(Index.convertToAlias(client, info, '.muchacha', 10)).rejects.toThrow(
|
||||
/Re-index failed \[search_phase_execution_exception\] all shards failed/
|
||||
);
|
||||
|
@ -319,7 +295,9 @@ describe('ElasticIndex', () => {
|
|||
describe('write', () => {
|
||||
test('writes documents in bulk to the index', async () => {
|
||||
client.bulk.mockResolvedValue(
|
||||
elasticsearchClientMock.createSuccessTransportRequestPromise({ items: [] })
|
||||
elasticsearchClientMock.createSuccessTransportRequestPromise({
|
||||
items: [] as any[],
|
||||
} as estypes.BulkResponse)
|
||||
);
|
||||
|
||||
const index = '.myalias';
|
||||
|
@ -356,7 +334,7 @@ describe('ElasticIndex', () => {
|
|||
client.bulk.mockResolvedValue(
|
||||
elasticsearchClientMock.createSuccessTransportRequestPromise({
|
||||
items: [{ index: { error: { type: 'shazm', reason: 'dern' } } }],
|
||||
})
|
||||
} as estypes.BulkResponse)
|
||||
);
|
||||
|
||||
const index = '.myalias';
|
||||
|
|
|
@ -12,11 +12,12 @@
|
|||
*/
|
||||
|
||||
import _ from 'lodash';
|
||||
import { estypes } from '@elastic/elasticsearch';
|
||||
import { MigrationEsClient } from './migration_es_client';
|
||||
import { CountResponse, SearchResponse } from '../../../elasticsearch';
|
||||
import { IndexMapping } from '../../mappings';
|
||||
import { SavedObjectsMigrationVersion } from '../../types';
|
||||
import { AliasAction, RawDoc, ShardsInfo } from './call_cluster';
|
||||
import { AliasAction, RawDoc } from './call_cluster';
|
||||
import { SavedObjectsRawDocSource } from '../../serialization';
|
||||
|
||||
const settings = { number_of_shards: 1, auto_expand_replicas: '0-1' };
|
||||
|
@ -46,6 +47,7 @@ export async function fetchInfo(client: MigrationEsClient, index: string): Promi
|
|||
|
||||
const [indexName, indexInfo] = Object.entries(body)[0];
|
||||
|
||||
// @ts-expect-error @elastic/elasticsearch IndexState.alias and IndexState.mappings should be required
|
||||
return assertIsSupportedIndex({ ...indexInfo, exists: true, indexName });
|
||||
}
|
||||
|
||||
|
@ -142,7 +144,7 @@ export async function write(client: MigrationEsClient, index: string, docs: RawD
|
|||
return;
|
||||
}
|
||||
|
||||
const exception: any = new Error(err.index.error!.reason);
|
||||
const exception: any = new Error(err.index!.error!.reason);
|
||||
exception.detail = err;
|
||||
throw exception;
|
||||
}
|
||||
|
@ -322,7 +324,7 @@ function assertIsSupportedIndex(indexInfo: FullIndexInfo) {
|
|||
* Object indices should only ever have a single shard. This is more to handle
|
||||
* instances where customers manually expand the shards of an index.
|
||||
*/
|
||||
function assertResponseIncludeAllShards({ _shards }: { _shards: ShardsInfo }) {
|
||||
function assertResponseIncludeAllShards({ _shards }: { _shards: estypes.ShardStatistics }) {
|
||||
if (!_.has(_shards, 'total') || !_.has(_shards, 'successful')) {
|
||||
return;
|
||||
}
|
||||
|
@ -375,11 +377,12 @@ async function reindex(
|
|||
await new Promise((r) => setTimeout(r, pollInterval));
|
||||
|
||||
const { body } = await client.tasks.get({
|
||||
task_id: task,
|
||||
task_id: String(task),
|
||||
});
|
||||
|
||||
if (body.error) {
|
||||
const e = body.error;
|
||||
// @ts-expect-error @elastic/elasticsearch GetTaskResponse doesn't contain `error` property
|
||||
const e = body.error;
|
||||
if (e) {
|
||||
throw new Error(`Re-index failed [${e.type}] ${e.reason} :: ${JSON.stringify(e)}`);
|
||||
}
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
*/
|
||||
|
||||
import _ from 'lodash';
|
||||
import type { estypes } from '@elastic/elasticsearch';
|
||||
import { elasticsearchClientMock } from '../../../elasticsearch/client/mocks';
|
||||
import { SavedObjectUnsanitizedDoc, SavedObjectsSerializer } from '../../serialization';
|
||||
import { SavedObjectTypeRegistry } from '../../saved_objects_type_registry';
|
||||
|
@ -443,23 +444,28 @@ function withIndex(
|
|||
elasticsearchClientMock.createSuccessTransportRequestPromise({
|
||||
task: 'zeid',
|
||||
_shards: { successful: 1, total: 1 },
|
||||
})
|
||||
} as estypes.ReindexResponse)
|
||||
);
|
||||
client.tasks.get.mockReturnValue(
|
||||
elasticsearchClientMock.createSuccessTransportRequestPromise({ completed: true })
|
||||
elasticsearchClientMock.createSuccessTransportRequestPromise({
|
||||
completed: true,
|
||||
} as estypes.GetTaskResponse)
|
||||
);
|
||||
client.search.mockReturnValue(
|
||||
elasticsearchClientMock.createSuccessTransportRequestPromise(searchResult(0))
|
||||
elasticsearchClientMock.createSuccessTransportRequestPromise(searchResult(0) as any)
|
||||
);
|
||||
client.bulk.mockReturnValue(
|
||||
elasticsearchClientMock.createSuccessTransportRequestPromise({ items: [] })
|
||||
elasticsearchClientMock.createSuccessTransportRequestPromise({
|
||||
items: [] as any[],
|
||||
} as estypes.BulkResponse)
|
||||
);
|
||||
client.count.mockReturnValue(
|
||||
elasticsearchClientMock.createSuccessTransportRequestPromise({
|
||||
count: numOutOfDate,
|
||||
_shards: { successful: 1, total: 1 },
|
||||
})
|
||||
} as estypes.CountResponse)
|
||||
);
|
||||
// @ts-expect-error
|
||||
client.scroll.mockImplementation(() => {
|
||||
if (scrollCallCounter <= docs.length) {
|
||||
const result = searchResult(scrollCallCounter);
|
||||
|
|
|
@ -134,7 +134,7 @@ async function deleteIndexTemplates({ client, log, obsoleteIndexTemplatePattern
|
|||
return;
|
||||
}
|
||||
|
||||
const { body: templates } = await client.cat.templates<Array<{ name: string }>>({
|
||||
const { body: templates } = await client.cat.templates({
|
||||
format: 'json',
|
||||
name: obsoleteIndexTemplatePattern,
|
||||
});
|
||||
|
@ -147,7 +147,7 @@ async function deleteIndexTemplates({ client, log, obsoleteIndexTemplatePattern
|
|||
|
||||
log.info(`Removing index templates: ${templateNames}`);
|
||||
|
||||
return Promise.all(templateNames.map((name) => client.indices.deleteTemplate({ name })));
|
||||
return Promise.all(templateNames.map((name) => client.indices.deleteTemplate({ name: name! })));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -185,7 +185,13 @@ async function migrateSourceToDest(context: Context) {
|
|||
await Index.write(
|
||||
client,
|
||||
dest.indexName,
|
||||
await migrateRawDocs(serializer, documentMigrator.migrateAndConvert, docs, log)
|
||||
await migrateRawDocs(
|
||||
serializer,
|
||||
documentMigrator.migrateAndConvert,
|
||||
// @ts-expect-error @elastic/elasticsearch `Hit._id` may be a string | number in ES, but we always expect strings in the SO index.
|
||||
docs,
|
||||
log
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,13 +7,13 @@
|
|||
*/
|
||||
|
||||
import { take } from 'rxjs/operators';
|
||||
import { estypes, errors as esErrors } from '@elastic/elasticsearch';
|
||||
|
||||
import { elasticsearchClientMock } from '../../../elasticsearch/client/mocks';
|
||||
import { KibanaMigratorOptions, KibanaMigrator } from './kibana_migrator';
|
||||
import { loggingSystemMock } from '../../../logging/logging_system.mock';
|
||||
import { SavedObjectTypeRegistry } from '../../saved_objects_type_registry';
|
||||
import { SavedObjectsType } from '../../types';
|
||||
import { errors as esErrors } from '@elastic/elasticsearch';
|
||||
import { DocumentMigrator } from '../core/document_migrator';
|
||||
jest.mock('../core/document_migrator', () => {
|
||||
return {
|
||||
|
@ -105,10 +105,7 @@ describe('KibanaMigrator', () => {
|
|||
const options = mockOptions();
|
||||
|
||||
options.client.cat.templates.mockReturnValue(
|
||||
elasticsearchClientMock.createSuccessTransportRequestPromise(
|
||||
{ templates: [] },
|
||||
{ statusCode: 404 }
|
||||
)
|
||||
elasticsearchClientMock.createSuccessTransportRequestPromise([], { statusCode: 404 })
|
||||
);
|
||||
options.client.indices.get.mockReturnValue(
|
||||
elasticsearchClientMock.createSuccessTransportRequestPromise({}, { statusCode: 404 })
|
||||
|
@ -129,7 +126,8 @@ describe('KibanaMigrator', () => {
|
|||
|
||||
options.client.cat.templates.mockReturnValue(
|
||||
elasticsearchClientMock.createSuccessTransportRequestPromise(
|
||||
{ templates: [] },
|
||||
// @ts-expect-error
|
||||
{ templates: [] } as CatTemplatesResponse,
|
||||
{ statusCode: 404 }
|
||||
)
|
||||
);
|
||||
|
@ -155,7 +153,8 @@ describe('KibanaMigrator', () => {
|
|||
|
||||
options.client.cat.templates.mockReturnValue(
|
||||
elasticsearchClientMock.createSuccessTransportRequestPromise(
|
||||
{ templates: [] },
|
||||
// @ts-expect-error
|
||||
{ templates: [] } as CatTemplatesResponse,
|
||||
{ statusCode: 404 }
|
||||
)
|
||||
);
|
||||
|
@ -193,7 +192,8 @@ describe('KibanaMigrator', () => {
|
|||
|
||||
options.client.cat.templates.mockReturnValue(
|
||||
elasticsearchClientMock.createSuccessTransportRequestPromise(
|
||||
{ templates: [] },
|
||||
// @ts-expect-error
|
||||
{ templates: [] } as CatTemplatesResponse,
|
||||
{ statusCode: 404 }
|
||||
)
|
||||
);
|
||||
|
@ -323,7 +323,7 @@ describe('KibanaMigrator', () => {
|
|||
completed: true,
|
||||
error: { type: 'elatsicsearch_exception', reason: 'task failed with an error' },
|
||||
failures: [],
|
||||
task: { description: 'task description' },
|
||||
task: { description: 'task description' } as any,
|
||||
})
|
||||
);
|
||||
|
||||
|
@ -365,15 +365,17 @@ const mockV2MigrationOptions = () => {
|
|||
elasticsearchClientMock.createSuccessTransportRequestPromise({ acknowledged: true })
|
||||
);
|
||||
options.client.reindex.mockReturnValue(
|
||||
elasticsearchClientMock.createSuccessTransportRequestPromise({ taskId: 'reindex_task_id' })
|
||||
elasticsearchClientMock.createSuccessTransportRequestPromise({
|
||||
taskId: 'reindex_task_id',
|
||||
} as estypes.ReindexResponse)
|
||||
);
|
||||
options.client.tasks.get.mockReturnValue(
|
||||
elasticsearchClientMock.createSuccessTransportRequestPromise({
|
||||
completed: true,
|
||||
error: undefined,
|
||||
failures: [],
|
||||
task: { description: 'task description' },
|
||||
})
|
||||
task: { description: 'task description' } as any,
|
||||
} as estypes.GetTaskResponse)
|
||||
);
|
||||
|
||||
return options;
|
||||
|
|
|
@ -13,9 +13,10 @@ import { ElasticsearchClientError } from '@elastic/elasticsearch/lib/errors';
|
|||
import { pipe } from 'fp-ts/lib/pipeable';
|
||||
import { errors as EsErrors } from '@elastic/elasticsearch';
|
||||
import { flow } from 'fp-ts/lib/function';
|
||||
import type { estypes } from '@elastic/elasticsearch';
|
||||
import { ElasticsearchClient } from '../../../elasticsearch';
|
||||
import { IndexMapping } from '../../mappings';
|
||||
import { SavedObjectsRawDoc } from '../../serialization';
|
||||
import { SavedObjectsRawDoc, SavedObjectsRawDocSource } from '../../serialization';
|
||||
import {
|
||||
catchRetryableEsClientErrors,
|
||||
RetryableEsClientError,
|
||||
|
@ -56,20 +57,22 @@ export type FetchIndexResponse = Record<
|
|||
export const fetchIndices = (
|
||||
client: ElasticsearchClient,
|
||||
indicesToFetch: string[]
|
||||
): TaskEither.TaskEither<RetryableEsClientError, FetchIndexResponse> => () => {
|
||||
return client.indices
|
||||
.get(
|
||||
{
|
||||
index: indicesToFetch,
|
||||
ignore_unavailable: true, // Don't return an error for missing indices. Note this *will* include closed indices, the docs are misleading https://github.com/elastic/elasticsearch/issues/63607
|
||||
},
|
||||
{ ignore: [404], maxRetries: 0 }
|
||||
)
|
||||
.then(({ body }) => {
|
||||
return Either.right(body);
|
||||
})
|
||||
.catch(catchRetryableEsClientErrors);
|
||||
};
|
||||
): TaskEither.TaskEither<RetryableEsClientError, FetchIndexResponse> =>
|
||||
// @ts-expect-error @elastic/elasticsearch IndexState.alias and IndexState.mappings should be required
|
||||
() => {
|
||||
return client.indices
|
||||
.get(
|
||||
{
|
||||
index: indicesToFetch,
|
||||
ignore_unavailable: true, // Don't return an error for missing indices. Note this *will* include closed indices, the docs are misleading https://github.com/elastic/elasticsearch/issues/63607
|
||||
},
|
||||
{ ignore: [404], maxRetries: 0 }
|
||||
)
|
||||
.then(({ body }) => {
|
||||
return Either.right(body);
|
||||
})
|
||||
.catch(catchRetryableEsClientErrors);
|
||||
};
|
||||
|
||||
/**
|
||||
* Sets a write block in place for the given index. If the response includes
|
||||
|
@ -98,7 +101,7 @@ export const setWriteBlock = (
|
|||
},
|
||||
{ maxRetries: 0 /** handle retry ourselves for now */ }
|
||||
)
|
||||
.then((res) => {
|
||||
.then((res: any) => {
|
||||
return res.body.acknowledged === true
|
||||
? Either.right('set_write_block_succeeded' as const)
|
||||
: Either.left({
|
||||
|
@ -134,7 +137,11 @@ export const removeWriteBlock = (
|
|||
// Don't change any existing settings
|
||||
preserve_existing: true,
|
||||
body: {
|
||||
'index.blocks.write': false,
|
||||
index: {
|
||||
blocks: {
|
||||
write: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{ maxRetries: 0 /** handle retry ourselves for now */ }
|
||||
|
@ -285,7 +292,7 @@ interface WaitForTaskResponse {
|
|||
error: Option.Option<{ type: string; reason: string; index: string }>;
|
||||
completed: boolean;
|
||||
failures: Option.Option<any[]>;
|
||||
description: string;
|
||||
description?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -299,12 +306,7 @@ const waitForTask = (
|
|||
timeout: string
|
||||
): TaskEither.TaskEither<RetryableEsClientError, WaitForTaskResponse> => () => {
|
||||
return client.tasks
|
||||
.get<{
|
||||
completed: boolean;
|
||||
response: { failures: any[] };
|
||||
task: { description: string };
|
||||
error: { type: string; reason: string; index: string };
|
||||
}>({
|
||||
.get({
|
||||
task_id: taskId,
|
||||
wait_for_completion: true,
|
||||
timeout,
|
||||
|
@ -314,6 +316,7 @@ const waitForTask = (
|
|||
const failures = body.response?.failures ?? [];
|
||||
return Either.right({
|
||||
completed: body.completed,
|
||||
// @ts-expect-error @elastic/elasticsearch GetTaskResponse doesn't declare `error` property
|
||||
error: Option.fromNullable(body.error),
|
||||
failures: failures.length > 0 ? Option.some(failures) : Option.none,
|
||||
description: body.task.description,
|
||||
|
@ -359,7 +362,7 @@ export const pickupUpdatedMappings = (
|
|||
wait_for_completion: false,
|
||||
})
|
||||
.then(({ body: { task: taskId } }) => {
|
||||
return Either.right({ taskId });
|
||||
return Either.right({ taskId: String(taskId!) });
|
||||
})
|
||||
.catch(catchRetryableEsClientErrors);
|
||||
};
|
||||
|
@ -387,7 +390,6 @@ export const reindex = (
|
|||
.reindex({
|
||||
// Require targetIndex to be an alias. Prevents a new index from being
|
||||
// created if targetIndex doesn't exist.
|
||||
// @ts-expect-error This API isn't documented
|
||||
require_alias: requireAlias,
|
||||
body: {
|
||||
// Ignore version conflicts from existing documents
|
||||
|
@ -416,7 +418,7 @@ export const reindex = (
|
|||
wait_for_completion: false,
|
||||
})
|
||||
.then(({ body: { task: taskId } }) => {
|
||||
return Either.right({ taskId });
|
||||
return Either.right({ taskId: String(taskId) });
|
||||
})
|
||||
.catch(catchRetryableEsClientErrors);
|
||||
};
|
||||
|
@ -624,7 +626,7 @@ export const createIndex = (
|
|||
const aliasesObject = (aliases ?? []).reduce((acc, alias) => {
|
||||
acc[alias] = {};
|
||||
return acc;
|
||||
}, {} as Record<string, {}>);
|
||||
}, {} as Record<string, estypes.Alias>);
|
||||
|
||||
return client.indices
|
||||
.create(
|
||||
|
@ -727,7 +729,7 @@ export const updateAndPickupMappings = (
|
|||
'update_mappings_succeeded'
|
||||
> = () => {
|
||||
return client.indices
|
||||
.putMapping<Record<string, any>, IndexMapping>({
|
||||
.putMapping({
|
||||
index,
|
||||
timeout: DEFAULT_TIMEOUT,
|
||||
body: mappings,
|
||||
|
@ -774,22 +776,16 @@ export const searchForOutdatedDocuments = (
|
|||
query: Record<string, unknown>
|
||||
): TaskEither.TaskEither<RetryableEsClientError, SearchResponse> => () => {
|
||||
return client
|
||||
.search<{
|
||||
// when `filter_path` is specified, ES doesn't return empty arrays, so if
|
||||
// there are no search results res.body.hits will be undefined.
|
||||
hits?: {
|
||||
hits?: SavedObjectsRawDoc[];
|
||||
};
|
||||
}>({
|
||||
.search<SavedObjectsRawDocSource>({
|
||||
index,
|
||||
// Optimize search performance by sorting by the "natural" index order
|
||||
sort: ['_doc'],
|
||||
// Return the _seq_no and _primary_term so we can use optimistic
|
||||
// concurrency control for updates
|
||||
seq_no_primary_term: true,
|
||||
size: BATCH_SIZE,
|
||||
body: {
|
||||
query,
|
||||
// Optimize search performance by sorting by the "natural" index order
|
||||
sort: ['_doc'],
|
||||
},
|
||||
// Return an error when targeting missing or closed indices
|
||||
allow_no_indices: false,
|
||||
|
@ -811,7 +807,9 @@ export const searchForOutdatedDocuments = (
|
|||
'hits.hits._primary_term',
|
||||
],
|
||||
})
|
||||
.then((res) => Either.right({ outdatedDocuments: res.body.hits?.hits ?? [] }))
|
||||
.then((res) =>
|
||||
Either.right({ outdatedDocuments: (res.body.hits?.hits as SavedObjectsRawDoc[]) ?? [] })
|
||||
)
|
||||
.catch(catchRetryableEsClientErrors);
|
||||
};
|
||||
|
||||
|
@ -825,20 +823,7 @@ export const bulkOverwriteTransformedDocuments = (
|
|||
transformedDocs: SavedObjectsRawDoc[]
|
||||
): TaskEither.TaskEither<RetryableEsClientError, 'bulk_index_succeeded'> => () => {
|
||||
return client
|
||||
.bulk<{
|
||||
took: number;
|
||||
errors: boolean;
|
||||
items: [
|
||||
{
|
||||
index: {
|
||||
_id: string;
|
||||
status: number;
|
||||
// the filter_path ensures that only items with errors are returned
|
||||
error: { type: string; reason: string };
|
||||
};
|
||||
}
|
||||
];
|
||||
}>({
|
||||
.bulk({
|
||||
// Because we only add aliases in the MARK_VERSION_INDEX_READY step we
|
||||
// can't bulkIndex to an alias with require_alias=true. This means if
|
||||
// users tamper during this operation (delete indices or restore a
|
||||
|
@ -880,7 +865,7 @@ export const bulkOverwriteTransformedDocuments = (
|
|||
// Filter out version_conflict_engine_exception since these just mean
|
||||
// that another instance already updated these documents
|
||||
const errors = (res.body.items ?? []).filter(
|
||||
(item) => item.index.error.type !== 'version_conflict_engine_exception'
|
||||
(item) => item.index?.error?.type !== 'version_conflict_engine_exception'
|
||||
);
|
||||
if (errors.length === 0) {
|
||||
return Either.right('bulk_index_succeeded' as const);
|
||||
|
|
|
@ -258,7 +258,7 @@ describe('migration actions', () => {
|
|||
index: 'clone_red_then_yellow_index',
|
||||
body: {
|
||||
// Enable all shard allocation so that the index status goes yellow
|
||||
'index.routing.allocation.enable': 'all',
|
||||
index: { routing: { allocation: { enable: 'all' } } },
|
||||
},
|
||||
});
|
||||
indexYellow = true;
|
||||
|
@ -500,7 +500,7 @@ describe('migration actions', () => {
|
|||
|
||||
// Create an index with incompatible mappings
|
||||
await createIndex(client, 'reindex_target_6', {
|
||||
dynamic: 'false',
|
||||
dynamic: false,
|
||||
properties: { title: { type: 'integer' } }, // integer is incompatible with string title
|
||||
})();
|
||||
|
||||
|
@ -926,7 +926,7 @@ describe('migration actions', () => {
|
|||
index: 'red_then_yellow_index',
|
||||
body: {
|
||||
// Disable all shard allocation so that the index status is red
|
||||
'index.routing.allocation.enable': 'all',
|
||||
index: { routing: { allocation: { enable: 'all' } } },
|
||||
},
|
||||
});
|
||||
indexYellow = true;
|
||||
|
|
|
@ -162,7 +162,9 @@ describe('migration v2', () => {
|
|||
const expectedVersions = getExpectedVersionPerType();
|
||||
const res = await esClient.search({
|
||||
index: migratedIndex,
|
||||
sort: ['_doc'],
|
||||
body: {
|
||||
sort: ['_doc'],
|
||||
},
|
||||
size: 10000,
|
||||
});
|
||||
const allDocuments = res.body.hits.hits as SavedObjectsRawDoc[];
|
||||
|
@ -217,7 +219,9 @@ describe('migration v2', () => {
|
|||
const expectedVersions = getExpectedVersionPerType();
|
||||
const res = await esClient.search({
|
||||
index: migratedIndex,
|
||||
sort: ['_doc'],
|
||||
body: {
|
||||
sort: ['_doc'],
|
||||
},
|
||||
size: 10000,
|
||||
});
|
||||
const allDocuments = res.body.hits.hits as SavedObjectsRawDoc[];
|
||||
|
|
|
@ -727,7 +727,6 @@ export const createInitialState = ({
|
|||
};
|
||||
|
||||
const reindexTargetMappings: IndexMapping = {
|
||||
// @ts-expect-error we don't allow plugins to set `dynamic`
|
||||
dynamic: false,
|
||||
properties: {
|
||||
type: { type: 'keyword' },
|
||||
|
|
|
@ -12,7 +12,10 @@ function toArray(value: string | string[]): string[] {
|
|||
/**
|
||||
* Provides an array of paths for ES source filtering
|
||||
*/
|
||||
export function includedFields(type: string | string[] = '*', fields?: string[] | string) {
|
||||
export function includedFields(
|
||||
type: string | string[] = '*',
|
||||
fields?: string[] | string
|
||||
): string[] | undefined {
|
||||
if (!fields || fields.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import type { estypes } from '@elastic/elasticsearch';
|
||||
import type { Logger } from '../../../logging';
|
||||
import type { SavedObjectsFindOptions, SavedObjectsClientContract } from '../../types';
|
||||
import type { SavedObjectsFindResponse } from '../';
|
||||
|
@ -96,12 +96,12 @@ export class PointInTimeFinder implements ISavedObjectsPointInTimeFinder {
|
|||
await this.open();
|
||||
|
||||
let lastResultsCount: number;
|
||||
let lastHitSortValue: unknown[] | undefined;
|
||||
let lastHitSortValue: estypes.Id[] | undefined;
|
||||
do {
|
||||
const results = await this.findNext({
|
||||
findOptions: this.#findOptions,
|
||||
id: this.#pitId,
|
||||
...(lastHitSortValue ? { searchAfter: lastHitSortValue } : {}),
|
||||
searchAfter: lastHitSortValue,
|
||||
});
|
||||
this.#pitId = results.pit_id;
|
||||
lastResultsCount = results.saved_objects.length;
|
||||
|
@ -159,7 +159,7 @@ export class PointInTimeFinder implements ISavedObjectsPointInTimeFinder {
|
|||
}: {
|
||||
findOptions: SavedObjectsFindOptions;
|
||||
id?: string;
|
||||
searchAfter?: unknown[];
|
||||
searchAfter?: estypes.Id[];
|
||||
}) {
|
||||
try {
|
||||
return await this.#client.find({
|
||||
|
@ -168,8 +168,8 @@ export class PointInTimeFinder implements ISavedObjectsPointInTimeFinder {
|
|||
sortOrder: 'desc',
|
||||
// Bump keep_alive by 2m on every new request to allow for the ES client
|
||||
// to make multiple retries in the event of a network failure.
|
||||
...(id ? { pit: { id, keepAlive: '2m' } } : {}),
|
||||
...(searchAfter ? { searchAfter } : {}),
|
||||
pit: id ? { id, keepAlive: '2m' } : undefined,
|
||||
searchAfter,
|
||||
...findOptions,
|
||||
});
|
||||
} catch (e) {
|
||||
|
@ -181,7 +181,7 @@ export class PointInTimeFinder implements ISavedObjectsPointInTimeFinder {
|
|||
}
|
||||
}
|
||||
|
||||
private getLastHitSortValue(res: SavedObjectsFindResponse): unknown[] | undefined {
|
||||
private getLastHitSortValue(res: SavedObjectsFindResponse): estypes.Id[] | undefined {
|
||||
if (res.saved_objects.length < 1) {
|
||||
return undefined;
|
||||
}
|
||||
|
|
|
@ -2782,18 +2782,20 @@ describe('SavedObjectsRepository', () => {
|
|||
await findSuccess({ type, fields: ['title'] });
|
||||
expect(client.search).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
_source: [
|
||||
`${type}.title`,
|
||||
'namespace',
|
||||
'namespaces',
|
||||
'type',
|
||||
'references',
|
||||
'migrationVersion',
|
||||
'coreMigrationVersion',
|
||||
'updated_at',
|
||||
'originId',
|
||||
'title',
|
||||
],
|
||||
body: expect.objectContaining({
|
||||
_source: [
|
||||
`${type}.title`,
|
||||
'namespace',
|
||||
'namespaces',
|
||||
'type',
|
||||
'references',
|
||||
'migrationVersion',
|
||||
'coreMigrationVersion',
|
||||
'updated_at',
|
||||
'originId',
|
||||
'title',
|
||||
],
|
||||
}),
|
||||
}),
|
||||
expect.anything()
|
||||
);
|
||||
|
@ -3837,6 +3839,7 @@ describe('SavedObjectsRepository', () => {
|
|||
id: '6.0.0-alpha1',
|
||||
...mockTimestampFields,
|
||||
version: mockVersion,
|
||||
references: [],
|
||||
attributes: {
|
||||
buildNum: 8468,
|
||||
apiCallsCount: 100,
|
||||
|
|
|
@ -7,13 +7,9 @@
|
|||
*/
|
||||
|
||||
import { omit, isObject } from 'lodash';
|
||||
import {
|
||||
ElasticsearchClient,
|
||||
DeleteDocumentResponse,
|
||||
GetResponse,
|
||||
SearchResponse,
|
||||
} from '../../../elasticsearch/';
|
||||
import { Logger } from '../../../logging';
|
||||
import type { estypes } from '@elastic/elasticsearch';
|
||||
import type { ElasticsearchClient } from '../../../elasticsearch/';
|
||||
import type { Logger } from '../../../logging';
|
||||
import { getRootPropertiesObjects, IndexMapping } from '../../mappings';
|
||||
import {
|
||||
ISavedObjectsPointInTimeFinder,
|
||||
|
@ -397,7 +393,7 @@ export class SavedObjectsRepository {
|
|||
_source: ['type', 'namespaces'],
|
||||
}));
|
||||
const bulkGetResponse = bulkGetDocs.length
|
||||
? await this.client.mget(
|
||||
? await this.client.mget<SavedObjectsRawDocSource>(
|
||||
{
|
||||
body: {
|
||||
docs: bulkGetDocs,
|
||||
|
@ -425,8 +421,9 @@ export class SavedObjectsRepository {
|
|||
if (esRequestIndex !== undefined) {
|
||||
const indexFound = bulkGetResponse?.statusCode !== 404;
|
||||
const actualResult = indexFound ? bulkGetResponse?.body.docs[esRequestIndex] : undefined;
|
||||
const docFound = indexFound && actualResult.found === true;
|
||||
if (docFound && !this.rawDocExistsInNamespace(actualResult, namespace)) {
|
||||
const docFound = indexFound && actualResult?.found === true;
|
||||
// @ts-expect-error MultiGetHit._source is optional
|
||||
if (docFound && !this.rawDocExistsInNamespace(actualResult!, namespace)) {
|
||||
const { id, type } = object;
|
||||
return {
|
||||
tag: 'Left' as 'Left',
|
||||
|
@ -441,7 +438,10 @@ export class SavedObjectsRepository {
|
|||
};
|
||||
}
|
||||
savedObjectNamespaces =
|
||||
initialNamespaces || getSavedObjectNamespaces(namespace, docFound && actualResult);
|
||||
initialNamespaces ||
|
||||
// @ts-expect-error MultiGetHit._source is optional
|
||||
getSavedObjectNamespaces(namespace, docFound ? actualResult : undefined);
|
||||
// @ts-expect-error MultiGetHit._source is optional
|
||||
versionProperties = getExpectedVersionProperties(version, actualResult);
|
||||
} else {
|
||||
if (this._registry.isSingleNamespace(object.type)) {
|
||||
|
@ -500,7 +500,7 @@ export class SavedObjectsRepository {
|
|||
|
||||
const { requestedId, rawMigratedDoc, esRequestIndex } = expectedResult.value;
|
||||
const { error, ...rawResponse } = Object.values(
|
||||
bulkResponse?.body.items[esRequestIndex]
|
||||
bulkResponse?.body.items[esRequestIndex] ?? {}
|
||||
)[0] as any;
|
||||
|
||||
if (error) {
|
||||
|
@ -564,10 +564,10 @@ export class SavedObjectsRepository {
|
|||
const bulkGetDocs = expectedBulkGetResults.filter(isRight).map(({ value: { type, id } }) => ({
|
||||
_id: this._serializer.generateRawId(namespace, type, id),
|
||||
_index: this.getIndexForType(type),
|
||||
_source: ['type', 'namespaces'],
|
||||
_source: { includes: ['type', 'namespaces'] },
|
||||
}));
|
||||
const bulkGetResponse = bulkGetDocs.length
|
||||
? await this.client.mget(
|
||||
? await this.client.mget<SavedObjectsRawDocSource>(
|
||||
{
|
||||
body: {
|
||||
docs: bulkGetDocs,
|
||||
|
@ -586,13 +586,14 @@ export class SavedObjectsRepository {
|
|||
|
||||
const { type, id, esRequestIndex } = expectedResult.value;
|
||||
const doc = bulkGetResponse?.body.docs[esRequestIndex];
|
||||
if (doc.found) {
|
||||
if (doc?.found) {
|
||||
errors.push({
|
||||
id,
|
||||
type,
|
||||
error: {
|
||||
...errorContent(SavedObjectsErrorHelpers.createConflictError(type, id)),
|
||||
...(!this.rawDocExistsInNamespace(doc, namespace) && {
|
||||
// @ts-expect-error MultiGetHit._source is optional
|
||||
...(!this.rawDocExistsInNamespace(doc!, namespace) && {
|
||||
metadata: { isNotOverwritable: true },
|
||||
}),
|
||||
},
|
||||
|
@ -636,7 +637,7 @@ export class SavedObjectsRepository {
|
|||
}
|
||||
}
|
||||
|
||||
const { body, statusCode } = await this.client.delete<DeleteDocumentResponse>(
|
||||
const { body, statusCode } = await this.client.delete(
|
||||
{
|
||||
id: rawId,
|
||||
index: this.getIndexForType(type),
|
||||
|
@ -652,6 +653,7 @@ export class SavedObjectsRepository {
|
|||
}
|
||||
|
||||
const deleteDocNotFound = body.result === 'not_found';
|
||||
// @ts-expect-error 'error' does not exist on type 'DeleteResponse'
|
||||
const deleteIndexNotFound = body.error && body.error.type === 'index_not_found_exception';
|
||||
if (deleteDocNotFound || deleteIndexNotFound) {
|
||||
// see "404s from missing index" above
|
||||
|
@ -813,15 +815,18 @@ export class SavedObjectsRepository {
|
|||
|
||||
const esOptions = {
|
||||
// If `pit` is provided, we drop the `index`, otherwise ES returns 400.
|
||||
...(pit ? {} : { index: this.getIndicesForTypes(allowedTypes) }),
|
||||
index: pit ? undefined : this.getIndicesForTypes(allowedTypes),
|
||||
// If `searchAfter` is provided, we drop `from` as it will not be used for pagination.
|
||||
...(searchAfter ? {} : { from: perPage * (page - 1) }),
|
||||
from: searchAfter ? undefined : perPage * (page - 1),
|
||||
_source: includedFields(type, fields),
|
||||
preference,
|
||||
rest_total_hits_as_int: true,
|
||||
size: perPage,
|
||||
body: {
|
||||
size: perPage,
|
||||
seq_no_primary_term: true,
|
||||
from: perPage * (page - 1),
|
||||
_source: includedFields(type, fields),
|
||||
...getSearchDsl(this._mappings, this._registry, {
|
||||
search,
|
||||
defaultSearchOperator,
|
||||
|
@ -841,7 +846,7 @@ export class SavedObjectsRepository {
|
|||
},
|
||||
};
|
||||
|
||||
const { body, statusCode } = await this.client.search<SearchResponse<any>>(esOptions, {
|
||||
const { body, statusCode } = await this.client.search<SavedObjectsRawDocSource>(esOptions, {
|
||||
ignore: [404],
|
||||
});
|
||||
if (statusCode === 404) {
|
||||
|
@ -860,13 +865,15 @@ export class SavedObjectsRepository {
|
|||
per_page: perPage,
|
||||
total: body.hits.total,
|
||||
saved_objects: body.hits.hits.map(
|
||||
(hit: SavedObjectsRawDoc): SavedObjectsFindResult => ({
|
||||
(hit: estypes.Hit<SavedObjectsRawDocSource>): SavedObjectsFindResult => ({
|
||||
// @ts-expect-error @elastic/elasticsearch declared Id as string | number
|
||||
...this._rawToSavedObject(hit),
|
||||
score: (hit as any)._score,
|
||||
...((hit as any).sort && { sort: (hit as any).sort }),
|
||||
score: hit._score!,
|
||||
// @ts-expect-error @elastic/elasticsearch declared sort as string | number
|
||||
sort: hit.sort,
|
||||
})
|
||||
),
|
||||
...(body.pit_id && { pit_id: body.pit_id }),
|
||||
pit_id: body.pit_id,
|
||||
} as SavedObjectsFindResponse<T>;
|
||||
}
|
||||
|
||||
|
@ -925,10 +932,10 @@ export class SavedObjectsRepository {
|
|||
.map(({ value: { type, id, fields } }) => ({
|
||||
_id: this._serializer.generateRawId(namespace, type, id),
|
||||
_index: this.getIndexForType(type),
|
||||
_source: includedFields(type, fields),
|
||||
_source: { includes: includedFields(type, fields) },
|
||||
}));
|
||||
const bulkGetResponse = bulkGetDocs.length
|
||||
? await this.client.mget(
|
||||
? await this.client.mget<SavedObjectsRawDocSource>(
|
||||
{
|
||||
body: {
|
||||
docs: bulkGetDocs,
|
||||
|
@ -947,7 +954,8 @@ export class SavedObjectsRepository {
|
|||
const { type, id, esRequestIndex } = expectedResult.value;
|
||||
const doc = bulkGetResponse?.body.docs[esRequestIndex];
|
||||
|
||||
if (!doc.found || !this.rawDocExistsInNamespace(doc, namespace)) {
|
||||
// @ts-expect-error MultiGetHit._source is optional
|
||||
if (!doc?.found || !this.rawDocExistsInNamespace(doc, namespace)) {
|
||||
return ({
|
||||
id,
|
||||
type,
|
||||
|
@ -955,6 +963,7 @@ export class SavedObjectsRepository {
|
|||
} as any) as SavedObject<T>;
|
||||
}
|
||||
|
||||
// @ts-expect-error MultiGetHit._source is optional
|
||||
return this.getSavedObjectFromSource(type, id, doc);
|
||||
}),
|
||||
};
|
||||
|
@ -980,7 +989,7 @@ export class SavedObjectsRepository {
|
|||
|
||||
const namespace = normalizeNamespace(options.namespace);
|
||||
|
||||
const { body, statusCode } = await this.client.get<GetResponse<SavedObjectsRawDocSource>>(
|
||||
const { body, statusCode } = await this.client.get<SavedObjectsRawDocSource>(
|
||||
{
|
||||
id: this._serializer.generateRawId(namespace, type, id),
|
||||
index: this.getIndexForType(type),
|
||||
|
@ -988,9 +997,13 @@ export class SavedObjectsRepository {
|
|||
{ ignore: [404] }
|
||||
);
|
||||
|
||||
const docNotFound = body.found === false;
|
||||
const indexNotFound = statusCode === 404;
|
||||
if (docNotFound || indexNotFound || !this.rawDocExistsInNamespace(body, namespace)) {
|
||||
|
||||
if (
|
||||
!isFoundGetResponse(body) ||
|
||||
indexNotFound ||
|
||||
!this.rawDocExistsInNamespace(body, namespace)
|
||||
) {
|
||||
// see "404s from missing index" above
|
||||
throw SavedObjectsErrorHelpers.createGenericNotFoundError(type, id);
|
||||
}
|
||||
|
@ -1026,7 +1039,7 @@ export class SavedObjectsRepository {
|
|||
const time = this._getCurrentTime();
|
||||
|
||||
// retrieve the alias, and if it is not disabled, update it
|
||||
const aliasResponse = await this.client.update(
|
||||
const aliasResponse = await this.client.update<{ 'legacy-url-alias': LegacyUrlAlias }>(
|
||||
{
|
||||
id: rawAliasId,
|
||||
index: this.getIndexForType(LEGACY_URL_ALIAS_TYPE),
|
||||
|
@ -1059,15 +1072,16 @@ export class SavedObjectsRepository {
|
|||
|
||||
if (
|
||||
aliasResponse.statusCode === 404 ||
|
||||
aliasResponse.body.get.found === false ||
|
||||
aliasResponse.body.get._source[LEGACY_URL_ALIAS_TYPE]?.disabled === true
|
||||
aliasResponse.body.get?.found === false ||
|
||||
aliasResponse.body.get?._source[LEGACY_URL_ALIAS_TYPE]?.disabled === true
|
||||
) {
|
||||
// no legacy URL alias exists, or one exists but it's disabled; just attempt to get the object
|
||||
return this.resolveExactMatch(type, id, options);
|
||||
}
|
||||
const legacyUrlAlias: LegacyUrlAlias = aliasResponse.body.get._source[LEGACY_URL_ALIAS_TYPE];
|
||||
|
||||
const legacyUrlAlias: LegacyUrlAlias = aliasResponse.body.get!._source[LEGACY_URL_ALIAS_TYPE];
|
||||
const objectIndex = this.getIndexForType(type);
|
||||
const bulkGetResponse = await this.client.mget(
|
||||
const bulkGetResponse = await this.client.mget<SavedObjectsRawDocSource>(
|
||||
{
|
||||
body: {
|
||||
docs: [
|
||||
|
@ -1090,23 +1104,28 @@ export class SavedObjectsRepository {
|
|||
const exactMatchDoc = bulkGetResponse?.body.docs[0];
|
||||
const aliasMatchDoc = bulkGetResponse?.body.docs[1];
|
||||
const foundExactMatch =
|
||||
// @ts-expect-error MultiGetHit._source is optional
|
||||
exactMatchDoc.found && this.rawDocExistsInNamespace(exactMatchDoc, namespace);
|
||||
const foundAliasMatch =
|
||||
// @ts-expect-error MultiGetHit._source is optional
|
||||
aliasMatchDoc.found && this.rawDocExistsInNamespace(aliasMatchDoc, namespace);
|
||||
|
||||
if (foundExactMatch && foundAliasMatch) {
|
||||
return {
|
||||
// @ts-expect-error MultiGetHit._source is optional
|
||||
saved_object: this.getSavedObjectFromSource(type, id, exactMatchDoc),
|
||||
outcome: 'conflict',
|
||||
aliasTargetId: legacyUrlAlias.targetId,
|
||||
};
|
||||
} else if (foundExactMatch) {
|
||||
return {
|
||||
// @ts-expect-error MultiGetHit._source is optional
|
||||
saved_object: this.getSavedObjectFromSource(type, id, exactMatchDoc),
|
||||
outcome: 'exactMatch',
|
||||
};
|
||||
} else if (foundAliasMatch) {
|
||||
return {
|
||||
// @ts-expect-error MultiGetHit._source is optional
|
||||
saved_object: this.getSavedObjectFromSource(type, legacyUrlAlias.targetId, aliasMatchDoc),
|
||||
outcome: 'aliasMatch',
|
||||
aliasTargetId: legacyUrlAlias.targetId,
|
||||
|
@ -1153,7 +1172,7 @@ export class SavedObjectsRepository {
|
|||
};
|
||||
|
||||
const { body } = await this.client
|
||||
.update({
|
||||
.update<SavedObjectsRawDocSource>({
|
||||
id: this._serializer.generateRawId(namespace, type, id),
|
||||
index: this.getIndexForType(type),
|
||||
...getExpectedVersionProperties(version, preflightResult),
|
||||
|
@ -1173,11 +1192,11 @@ export class SavedObjectsRepository {
|
|||
throw err;
|
||||
});
|
||||
|
||||
const { originId } = body.get._source;
|
||||
let namespaces = [];
|
||||
const { originId } = body.get?._source ?? {};
|
||||
let namespaces: string[] = [];
|
||||
if (!this._registry.isNamespaceAgnostic(type)) {
|
||||
namespaces = body.get._source.namespaces ?? [
|
||||
SavedObjectsUtils.namespaceIdToString(body.get._source.namespace),
|
||||
namespaces = body.get?._source.namespaces ?? [
|
||||
SavedObjectsUtils.namespaceIdToString(body.get?._source.namespace),
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -1185,7 +1204,6 @@ export class SavedObjectsRepository {
|
|||
id,
|
||||
type,
|
||||
updated_at: time,
|
||||
// @ts-expect-error update doesn't have _seq_no, _primary_term as Record<string, any> / any in LP
|
||||
version: encodeHitVersion(body),
|
||||
namespaces,
|
||||
...(originId && { originId }),
|
||||
|
@ -1325,7 +1343,7 @@ export class SavedObjectsRepository {
|
|||
return { namespaces: doc.namespaces };
|
||||
} else {
|
||||
// if there are no namespaces remaining, delete the saved object
|
||||
const { body, statusCode } = await this.client.delete<DeleteDocumentResponse>(
|
||||
const { body, statusCode } = await this.client.delete(
|
||||
{
|
||||
id: this._serializer.generateRawId(undefined, type, id),
|
||||
refresh,
|
||||
|
@ -1343,6 +1361,7 @@ export class SavedObjectsRepository {
|
|||
}
|
||||
|
||||
const deleteDocNotFound = body.result === 'not_found';
|
||||
// @ts-expect-error
|
||||
const deleteIndexNotFound = body.error && body.error.type === 'index_not_found_exception';
|
||||
if (deleteDocNotFound || deleteIndexNotFound) {
|
||||
// see "404s from missing index" above
|
||||
|
@ -1477,9 +1496,10 @@ export class SavedObjectsRepository {
|
|||
if (esRequestIndex !== undefined) {
|
||||
const indexFound = bulkGetResponse?.statusCode !== 404;
|
||||
const actualResult = indexFound ? bulkGetResponse?.body.docs[esRequestIndex] : undefined;
|
||||
const docFound = indexFound && actualResult.found === true;
|
||||
const docFound = indexFound && actualResult?.found === true;
|
||||
if (
|
||||
!docFound ||
|
||||
// @ts-expect-error MultiGetHit is incorrectly missing _id, _source
|
||||
!this.rawDocExistsInNamespace(actualResult, getNamespaceId(objectNamespace))
|
||||
) {
|
||||
return {
|
||||
|
@ -1491,10 +1511,13 @@ export class SavedObjectsRepository {
|
|||
},
|
||||
};
|
||||
}
|
||||
namespaces = actualResult._source.namespaces ?? [
|
||||
SavedObjectsUtils.namespaceIdToString(actualResult._source.namespace),
|
||||
// @ts-expect-error MultiGetHit is incorrectly missing _id, _source
|
||||
namespaces = actualResult!._source.namespaces ?? [
|
||||
// @ts-expect-error MultiGetHit is incorrectly missing _id, _source
|
||||
SavedObjectsUtils.namespaceIdToString(actualResult!._source.namespace),
|
||||
];
|
||||
versionProperties = getExpectedVersionProperties(version, actualResult);
|
||||
// @ts-expect-error MultiGetHit is incorrectly missing _id, _source
|
||||
versionProperties = getExpectedVersionProperties(version, actualResult!);
|
||||
} else {
|
||||
if (this._registry.isSingleNamespace(type)) {
|
||||
// if `objectNamespace` is undefined, fall back to `options.namespace`
|
||||
|
@ -1543,7 +1566,7 @@ export class SavedObjectsRepository {
|
|||
}
|
||||
|
||||
const { type, id, namespaces, documentToSave, esRequestIndex } = expectedResult.value;
|
||||
const response = bulkUpdateResponse?.body.items[esRequestIndex];
|
||||
const response = bulkUpdateResponse?.body.items[esRequestIndex] ?? {};
|
||||
// When a bulk update operation is completed, any fields specified in `_sourceIncludes` will be found in the "get" value of the
|
||||
// returned object. We need to retrieve the `originId` if it exists so we can return it to the consumer.
|
||||
const { error, _seq_no: seqNo, _primary_term: primaryTerm, get } = Object.values(
|
||||
|
@ -1636,7 +1659,7 @@ export class SavedObjectsRepository {
|
|||
}
|
||||
|
||||
return {
|
||||
updated: body.updated,
|
||||
updated: body.updated!,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -1745,7 +1768,7 @@ export class SavedObjectsRepository {
|
|||
|
||||
const raw = this._serializer.savedObjectToRaw(migrated as SavedObjectSanitizedDoc);
|
||||
|
||||
const { body } = await this.client.update({
|
||||
const { body } = await this.client.update<SavedObjectsRawDocSource>({
|
||||
id: raw._id,
|
||||
index: this.getIndexForType(type),
|
||||
refresh,
|
||||
|
@ -1783,17 +1806,16 @@ export class SavedObjectsRepository {
|
|||
},
|
||||
});
|
||||
|
||||
const { originId } = body.get._source;
|
||||
const { originId } = body.get?._source ?? {};
|
||||
return {
|
||||
id,
|
||||
type,
|
||||
...(savedObjectNamespaces && { namespaces: savedObjectNamespaces }),
|
||||
...(originId && { originId }),
|
||||
updated_at: time,
|
||||
references: body.get._source.references,
|
||||
// @ts-expect-error
|
||||
references: body.get?._source.references ?? [],
|
||||
version: encodeHitVersion(body),
|
||||
attributes: body.get._source[type],
|
||||
attributes: body.get?._source[type],
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -1852,9 +1874,13 @@ export class SavedObjectsRepository {
|
|||
const {
|
||||
body,
|
||||
statusCode,
|
||||
} = await this.client.openPointInTime<SavedObjectsOpenPointInTimeResponse>(esOptions, {
|
||||
ignore: [404],
|
||||
});
|
||||
} = await this.client.openPointInTime<SavedObjectsOpenPointInTimeResponse>(
|
||||
// @ts-expect-error @elastic/elasticsearch OpenPointInTimeRequest.index expected to accept string[]
|
||||
esOptions,
|
||||
{
|
||||
ignore: [404],
|
||||
}
|
||||
);
|
||||
if (statusCode === 404) {
|
||||
throw SavedObjectsErrorHelpers.createGenericNotFoundError();
|
||||
}
|
||||
|
@ -1912,6 +1938,7 @@ export class SavedObjectsRepository {
|
|||
const { body } = await this.client.closePointInTime<SavedObjectsClosePointInTimeResponse>({
|
||||
body: { id },
|
||||
});
|
||||
|
||||
return body;
|
||||
}
|
||||
|
||||
|
@ -2054,7 +2081,7 @@ export class SavedObjectsRepository {
|
|||
throw new Error(`Cannot make preflight get request for non-multi-namespace type '${type}'.`);
|
||||
}
|
||||
|
||||
const { body, statusCode } = await this.client.get<GetResponse<SavedObjectsRawDocSource>>(
|
||||
const { body, statusCode } = await this.client.get<SavedObjectsRawDocSource>(
|
||||
{
|
||||
id: this._serializer.generateRawId(undefined, type, id),
|
||||
index: this.getIndexForType(type),
|
||||
|
@ -2065,8 +2092,7 @@ export class SavedObjectsRepository {
|
|||
);
|
||||
|
||||
const indexFound = statusCode !== 404;
|
||||
const docFound = indexFound && body.found === true;
|
||||
if (docFound) {
|
||||
if (indexFound && isFoundGetResponse(body)) {
|
||||
if (!this.rawDocExistsInNamespace(body, namespace)) {
|
||||
throw SavedObjectsErrorHelpers.createConflictError(type, id);
|
||||
}
|
||||
|
@ -2091,7 +2117,7 @@ export class SavedObjectsRepository {
|
|||
}
|
||||
|
||||
const rawId = this._serializer.generateRawId(undefined, type, id);
|
||||
const { body, statusCode } = await this.client.get<GetResponse<SavedObjectsRawDocSource>>(
|
||||
const { body, statusCode } = await this.client.get<SavedObjectsRawDocSource>(
|
||||
{
|
||||
id: rawId,
|
||||
index: this.getIndexForType(type),
|
||||
|
@ -2100,17 +2126,20 @@ export class SavedObjectsRepository {
|
|||
);
|
||||
|
||||
const indexFound = statusCode !== 404;
|
||||
const docFound = indexFound && body.found === true;
|
||||
if (!docFound || !this.rawDocExistsInNamespace(body, namespace)) {
|
||||
if (
|
||||
!indexFound ||
|
||||
!isFoundGetResponse(body) ||
|
||||
!this.rawDocExistsInNamespace(body, namespace)
|
||||
) {
|
||||
throw SavedObjectsErrorHelpers.createGenericNotFoundError(type, id);
|
||||
}
|
||||
return body as SavedObjectsRawDoc;
|
||||
return body;
|
||||
}
|
||||
|
||||
private getSavedObjectFromSource<T>(
|
||||
type: string,
|
||||
id: string,
|
||||
doc: { _seq_no: number; _primary_term: number; _source: SavedObjectsRawDocSource }
|
||||
doc: { _seq_no?: number; _primary_term?: number; _source: SavedObjectsRawDocSource }
|
||||
): SavedObject<T> {
|
||||
const { originId, updated_at: updatedAt } = doc._source;
|
||||
|
||||
|
@ -2220,3 +2249,15 @@ const normalizeNamespace = (namespace?: string) => {
|
|||
const errorContent = (error: DecoratedError) => error.output.payload;
|
||||
|
||||
const unique = (array: string[]) => [...new Set(array)];
|
||||
|
||||
/**
|
||||
* Type and type guard function for converting a possibly not existant doc to an existant doc.
|
||||
*/
|
||||
type GetResponseFound<TDocument = unknown> = estypes.GetResponse<TDocument> &
|
||||
Required<
|
||||
Pick<estypes.GetResponse<TDocument>, '_primary_term' | '_seq_no' | '_version' | '_source'>
|
||||
>;
|
||||
|
||||
const isFoundGetResponse = <TDocument = unknown>(
|
||||
doc: estypes.GetResponse<TDocument>
|
||||
): doc is GetResponseFound<TDocument> => doc.found;
|
||||
|
|
|
@ -86,7 +86,7 @@ describe('getSearchDsl', () => {
|
|||
const opts = {
|
||||
type: 'foo',
|
||||
sortField: 'bar',
|
||||
sortOrder: 'baz',
|
||||
sortOrder: 'asc' as const,
|
||||
pit: { id: 'abc123' },
|
||||
};
|
||||
|
||||
|
@ -109,10 +109,10 @@ describe('getSearchDsl', () => {
|
|||
it('returns searchAfter if provided', () => {
|
||||
getQueryParams.mockReturnValue({ a: 'a' });
|
||||
getSortingParams.mockReturnValue({ b: 'b' });
|
||||
expect(getSearchDsl(mappings, registry, { type: 'foo', searchAfter: [1, 'bar'] })).toEqual({
|
||||
expect(getSearchDsl(mappings, registry, { type: 'foo', searchAfter: ['1', 'bar'] })).toEqual({
|
||||
a: 'a',
|
||||
b: 'b',
|
||||
search_after: [1, 'bar'],
|
||||
search_after: ['1', 'bar'],
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -123,14 +123,14 @@ describe('getSearchDsl', () => {
|
|||
expect(
|
||||
getSearchDsl(mappings, registry, {
|
||||
type: 'foo',
|
||||
searchAfter: [1, 'bar'],
|
||||
searchAfter: ['1', 'bar'],
|
||||
pit: { id: 'abc123' },
|
||||
})
|
||||
).toEqual({
|
||||
a: 'a',
|
||||
b: 'b',
|
||||
pit: { id: 'abc123' },
|
||||
search_after: [1, 'bar'],
|
||||
search_after: ['1', 'bar'],
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
import Boom from '@hapi/boom';
|
||||
|
||||
import type { estypes } from '@elastic/elasticsearch';
|
||||
import { IndexMapping } from '../../../mappings';
|
||||
import { SavedObjectsPitParams } from '../../../types';
|
||||
import { getQueryParams, HasReferenceQueryParams, SearchOperator } from './query_params';
|
||||
|
@ -23,9 +24,9 @@ interface GetSearchDslOptions {
|
|||
defaultSearchOperator?: SearchOperator;
|
||||
searchFields?: string[];
|
||||
rootSearchFields?: string[];
|
||||
searchAfter?: unknown[];
|
||||
searchAfter?: estypes.Id[];
|
||||
sortField?: string;
|
||||
sortOrder?: string;
|
||||
sortOrder?: estypes.SortOrder;
|
||||
namespaces?: string[];
|
||||
pit?: SavedObjectsPitParams;
|
||||
typeToNamespacesMap?: Map<string, string[] | undefined>;
|
||||
|
@ -80,6 +81,6 @@ export function getSearchDsl(
|
|||
}),
|
||||
...getSortingParams(mappings, type, sortField, sortOrder),
|
||||
...(pit ? getPitParams(pit) : {}),
|
||||
...(searchAfter ? { search_after: searchAfter } : {}),
|
||||
search_after: searchAfter,
|
||||
};
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import type { estypes } from '@elastic/elasticsearch';
|
||||
import Boom from '@hapi/boom';
|
||||
import { getProperty, IndexMapping } from '../../../mappings';
|
||||
|
||||
|
@ -15,8 +16,8 @@ export function getSortingParams(
|
|||
mappings: IndexMapping,
|
||||
type: string | string[],
|
||||
sortField?: string,
|
||||
sortOrder?: string
|
||||
) {
|
||||
sortOrder?: estypes.SortOrder
|
||||
): { sort?: estypes.SortContainer[] } {
|
||||
if (!sortField) {
|
||||
return {};
|
||||
}
|
||||
|
|
|
@ -162,7 +162,7 @@ export interface SavedObjectsFindResult<T = unknown> extends SavedObject<T> {
|
|||
* await savedObjectsClient.closePointInTime(page2.pit_id);
|
||||
* ```
|
||||
*/
|
||||
sort?: unknown[];
|
||||
sort?: string[];
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import type { estypes } from '@elastic/elasticsearch';
|
||||
import { SavedObjectsClient } from './service/saved_objects_client';
|
||||
import { SavedObjectsTypeMappingDefinition } from './mappings';
|
||||
import { SavedObjectMigrationMap } from './migrations';
|
||||
|
@ -79,7 +80,7 @@ export interface SavedObjectsFindOptions {
|
|||
page?: number;
|
||||
perPage?: number;
|
||||
sortField?: string;
|
||||
sortOrder?: string;
|
||||
sortOrder?: estypes.SortOrder;
|
||||
/**
|
||||
* An array of fields to include in the results
|
||||
* @example
|
||||
|
@ -93,7 +94,7 @@ export interface SavedObjectsFindOptions {
|
|||
/**
|
||||
* Use the sort values from the previous page to retrieve the next page of results.
|
||||
*/
|
||||
searchAfter?: unknown[];
|
||||
searchAfter?: estypes.Id[];
|
||||
/**
|
||||
* The fields to perform the parsed query against. Unlike the `searchFields` argument, these are expected to be root fields and will not
|
||||
* be modified. If used in conjunction with `searchFields`, both are concatenated together.
|
||||
|
|
|
@ -12,6 +12,6 @@ import { encodeVersion } from './encode_version';
|
|||
* Helper for encoding a version from a "hit" (hits.hits[#] from _search) or
|
||||
* "doc" (body from GET, update, etc) object
|
||||
*/
|
||||
export function encodeHitVersion(response: { _seq_no: number; _primary_term: number }) {
|
||||
export function encodeHitVersion(response: { _seq_no?: number; _primary_term?: number }) {
|
||||
return encodeVersion(response._seq_no, response._primary_term);
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@ import { encodeBase64 } from './base64';
|
|||
* that can be used in the saved object API in place of numeric
|
||||
* version numbers
|
||||
*/
|
||||
export function encodeVersion(seqNo: number, primaryTerm: number) {
|
||||
export function encodeVersion(seqNo?: number, primaryTerm?: number) {
|
||||
if (!Number.isInteger(primaryTerm)) {
|
||||
throw new TypeError('_primary_term from elasticsearch must be an integer');
|
||||
}
|
||||
|
|
|
@ -50,6 +50,7 @@ import { DetailedPeerCertificate } from 'tls';
|
|||
import { Duration } from 'moment';
|
||||
import { Duration as Duration_2 } from 'moment-timezone';
|
||||
import { EnvironmentMode } from '@kbn/config';
|
||||
import { estypes } from '@elastic/elasticsearch';
|
||||
import { ExistsParams } from 'elasticsearch';
|
||||
import { ExplainParams } from 'elasticsearch';
|
||||
import { FieldStatsParams } from 'elasticsearch';
|
||||
|
@ -2507,12 +2508,12 @@ export interface SavedObjectsFindOptions {
|
|||
preference?: string;
|
||||
rootSearchFields?: string[];
|
||||
search?: string;
|
||||
searchAfter?: unknown[];
|
||||
searchAfter?: estypes.Id[];
|
||||
searchFields?: string[];
|
||||
// (undocumented)
|
||||
sortField?: string;
|
||||
// (undocumented)
|
||||
sortOrder?: string;
|
||||
sortOrder?: estypes.SortOrder;
|
||||
// (undocumented)
|
||||
type: string | string[];
|
||||
typeToNamespacesMap?: Map<string, string[] | undefined>;
|
||||
|
@ -2543,7 +2544,7 @@ export interface SavedObjectsFindResponse<T = unknown> {
|
|||
// @public (undocumented)
|
||||
export interface SavedObjectsFindResult<T = unknown> extends SavedObject<T> {
|
||||
score: number;
|
||||
sort?: unknown[];
|
||||
sort?: string[];
|
||||
}
|
||||
|
||||
// @public
|
||||
|
|
|
@ -5,19 +5,18 @@
|
|||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
import type { estypes } from '@elastic/elasticsearch';
|
||||
|
||||
import { SearchResponse } from 'elasticsearch';
|
||||
import { Search } from '@elastic/elasticsearch/api/requestParams';
|
||||
import { IKibanaSearchRequest, IKibanaSearchResponse } from '../types';
|
||||
|
||||
export const ES_SEARCH_STRATEGY = 'es';
|
||||
|
||||
export type ISearchRequestParams<T = Record<string, any>> = {
|
||||
export type ISearchRequestParams = {
|
||||
trackTotalHits?: boolean;
|
||||
} & Search<T>;
|
||||
} & estypes.SearchRequest;
|
||||
|
||||
export interface IEsSearchRequest extends IKibanaSearchRequest<ISearchRequestParams> {
|
||||
indexType?: string;
|
||||
}
|
||||
|
||||
export type IEsSearchResponse<Source = any> = IKibanaSearchResponse<SearchResponse<Source>>;
|
||||
export type IEsSearchResponse<Source = any> = IKibanaSearchResponse<estypes.SearchResponse<Source>>;
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
*/
|
||||
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { SearchResponse } from 'elasticsearch';
|
||||
import type { estypes } from '@elastic/elasticsearch';
|
||||
import { ISearchSource } from 'src/plugins/data/public';
|
||||
import { RequestStatistics } from 'src/plugins/inspector/common';
|
||||
|
||||
|
@ -50,7 +50,7 @@ export function getRequestInspectorStats(searchSource: ISearchSource) {
|
|||
|
||||
/** @public */
|
||||
export function getResponseInspectorStats(
|
||||
resp: SearchResponse<unknown>,
|
||||
resp: estypes.SearchResponse<unknown>,
|
||||
searchSource?: ISearchSource
|
||||
) {
|
||||
const lastRequest =
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { SearchResponse } from 'elasticsearch';
|
||||
import type { estypes } from '@elastic/elasticsearch';
|
||||
import { KbnError } from '../../../../../kibana_utils/common';
|
||||
import { SearchError } from './types';
|
||||
|
||||
|
@ -16,8 +16,8 @@ import { SearchError } from './types';
|
|||
* @param {Object} resp - optional HTTP response
|
||||
*/
|
||||
export class RequestFailure extends KbnError {
|
||||
public resp?: SearchResponse<any>;
|
||||
constructor(err: SearchError | null = null, resp?: SearchResponse<any>) {
|
||||
public resp?: estypes.SearchResponse<any>;
|
||||
constructor(err: SearchError | null = null, resp?: estypes.SearchResponse<any>) {
|
||||
super(`Request to Elasticsearch failed: ${JSON.stringify(resp || err?.message)}`);
|
||||
|
||||
this.resp = resp;
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { SearchResponse } from 'elasticsearch';
|
||||
import type { estypes } from '@elastic/elasticsearch';
|
||||
import { LegacyFetchHandlers } from '../legacy/types';
|
||||
import { GetConfigFn } from '../../../types';
|
||||
|
||||
|
@ -25,7 +25,10 @@ export interface FetchHandlers {
|
|||
* Callback which can be used to hook into responses, modify them, or perform
|
||||
* side effects like displaying UI errors on the client.
|
||||
*/
|
||||
onResponse: (request: SearchRequest, response: SearchResponse<any>) => SearchResponse<any>;
|
||||
onResponse: (
|
||||
request: SearchRequest,
|
||||
response: estypes.SearchResponse<any>
|
||||
) => estypes.SearchResponse<any>;
|
||||
/**
|
||||
* These handlers are only used by the legacy defaultSearchStrategy and can be removed
|
||||
* once that strategy has been deprecated.
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { SearchResponse } from 'elasticsearch';
|
||||
import type { estypes } from '@elastic/elasticsearch';
|
||||
import { FetchHandlers, SearchRequest } from '../fetch';
|
||||
import { defaultSearchStrategy } from './default_search_strategy';
|
||||
import { ISearchOptions } from '../../index';
|
||||
|
@ -21,7 +21,7 @@ export function callClient(
|
|||
[SearchRequest, ISearchOptions]
|
||||
> = searchRequests.map((request, i) => [request, requestsOptions[i]]);
|
||||
const requestOptionsMap = new Map<SearchRequest, ISearchOptions>(requestOptionEntries);
|
||||
const requestResponseMap = new Map<SearchRequest, Promise<SearchResponse<any>>>();
|
||||
const requestResponseMap = new Map<SearchRequest, Promise<estypes.SearchResponse<any>>>();
|
||||
|
||||
const { searching, abort } = defaultSearchStrategy.search({
|
||||
searchRequests,
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { SearchResponse } from 'elasticsearch';
|
||||
import type { estypes } from '@elastic/elasticsearch';
|
||||
import { UI_SETTINGS } from '../../../constants';
|
||||
import { FetchHandlers, SearchRequest } from '../fetch';
|
||||
import { ISearchOptions } from '../../index';
|
||||
|
@ -57,9 +57,11 @@ async function delayedFetch(
|
|||
options: ISearchOptions,
|
||||
fetchHandlers: FetchHandlers,
|
||||
ms: number
|
||||
): Promise<SearchResponse<any>> {
|
||||
): Promise<estypes.SearchResponse<any>> {
|
||||
if (ms === 0) {
|
||||
return callClient([request], [options], fetchHandlers)[0];
|
||||
return callClient([request], [options], fetchHandlers)[0] as Promise<
|
||||
estypes.SearchResponse<any>
|
||||
>;
|
||||
}
|
||||
|
||||
const i = requestsToFetch.length;
|
||||
|
|
|
@ -7,8 +7,7 @@
|
|||
*/
|
||||
|
||||
import { BehaviorSubject } from 'rxjs';
|
||||
import { ApiResponse } from '@elastic/elasticsearch';
|
||||
import { SearchResponse } from 'elasticsearch';
|
||||
import type { estypes, ApiResponse } from '@elastic/elasticsearch';
|
||||
import { FetchHandlers, SearchRequest } from '../fetch';
|
||||
|
||||
interface MsearchHeaders {
|
||||
|
@ -28,7 +27,7 @@ export interface MsearchRequestBody {
|
|||
|
||||
// @internal
|
||||
export interface MsearchResponse {
|
||||
body: ApiResponse<{ responses: Array<SearchResponse<any>> }>;
|
||||
body: ApiResponse<{ responses: Array<estypes.SearchResponse<any>> }>;
|
||||
}
|
||||
|
||||
// @internal
|
||||
|
@ -51,6 +50,6 @@ export interface SearchStrategyProvider {
|
|||
}
|
||||
|
||||
export interface SearchStrategyResponse<T = any> {
|
||||
searching: Promise<Array<SearchResponse<T>>>;
|
||||
searching: Promise<Array<estypes.SearchResponse<T>>>;
|
||||
abort: () => void;
|
||||
}
|
||||
|
|
|
@ -28,6 +28,7 @@ import { DetailedPeerCertificate } from 'tls';
|
|||
import { Ensure } from '@kbn/utility-types';
|
||||
import { EnvironmentMode } from '@kbn/config';
|
||||
import { ErrorToastOptions } from 'src/core/public/notifications';
|
||||
import { estypes } from '@elastic/elasticsearch';
|
||||
import { EuiBreadcrumb } from '@elastic/eui';
|
||||
import { EuiButtonEmptyProps } from '@elastic/eui';
|
||||
import { EuiComboBoxProps } from '@elastic/eui';
|
||||
|
@ -92,8 +93,6 @@ import { SavedObjectsFindOptions } from 'kibana/public';
|
|||
import { SavedObjectsFindResponse } from 'kibana/server';
|
||||
import { SavedObjectsUpdateResponse } from 'kibana/server';
|
||||
import { SchemaTypeError } from '@kbn/config-schema';
|
||||
import { Search } from '@elastic/elasticsearch/api/requestParams';
|
||||
import { SearchResponse } from 'elasticsearch';
|
||||
import { SerializedFieldFormat as SerializedFieldFormat_2 } from 'src/plugins/expressions/common';
|
||||
import { StartServicesAccessor } from 'kibana/public';
|
||||
import { ToastInputFields } from 'src/core/public/notifications';
|
||||
|
@ -1128,7 +1127,7 @@ export interface IEsSearchRequest extends IKibanaSearchRequest<ISearchRequestPar
|
|||
// Warning: (ae-missing-release-tag) "IEsSearchResponse" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
// @public (undocumented)
|
||||
export type IEsSearchResponse<Source = any> = IKibanaSearchResponse<SearchResponse<Source>>;
|
||||
export type IEsSearchResponse<Source = any> = IKibanaSearchResponse<estypes.SearchResponse<Source>>;
|
||||
|
||||
// Warning: (ae-missing-release-tag) "IFieldFormat" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
|
@ -2415,9 +2414,9 @@ export class SearchSource {
|
|||
createChild(options?: {}): SearchSource;
|
||||
createCopy(): SearchSource;
|
||||
destroy(): void;
|
||||
fetch$(options?: ISearchOptions): import("rxjs").Observable<import("elasticsearch").SearchResponse<any>>;
|
||||
fetch$(options?: ISearchOptions): import("rxjs").Observable<import("@elastic/elasticsearch/api/types").SearchResponse<any>>;
|
||||
// @deprecated
|
||||
fetch(options?: ISearchOptions): Promise<import("elasticsearch").SearchResponse<any>>;
|
||||
fetch(options?: ISearchOptions): Promise<import("@elastic/elasticsearch/api/types").SearchResponse<any>>;
|
||||
getField<K extends keyof SearchSourceFields>(field: K, recurse?: boolean): SearchSourceFields[K];
|
||||
getFields(): SearchSourceFields;
|
||||
getId(): string;
|
||||
|
|
|
@ -6,14 +6,14 @@
|
|||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { SearchResponse } from 'elasticsearch';
|
||||
import type { estypes } from '@elastic/elasticsearch';
|
||||
import { ExpressionTypeDefinition } from '../../../../expressions/common';
|
||||
|
||||
const name = 'es_raw_response';
|
||||
|
||||
export interface EsRawResponse<T = unknown> {
|
||||
type: typeof name;
|
||||
body: SearchResponse<T>;
|
||||
body: estypes.SearchResponse<T>;
|
||||
}
|
||||
|
||||
// flattens elasticsearch object into table rows
|
||||
|
@ -46,11 +46,11 @@ function flatten(obj: any, keyPrefix = '') {
|
|||
}
|
||||
}
|
||||
|
||||
const parseRawDocs = (hits: SearchResponse<unknown>['hits']) => {
|
||||
const parseRawDocs = (hits: estypes.SearchResponse<unknown>['hits']) => {
|
||||
return hits.hits.map((hit) => hit.fields || hit._source).filter((hit) => hit);
|
||||
};
|
||||
|
||||
const convertResult = (body: SearchResponse<unknown>) => {
|
||||
const convertResult = (body: estypes.SearchResponse<unknown>) => {
|
||||
return !body.aggregations ? parseRawDocs(body.hits) : flatten(body.aggregations);
|
||||
};
|
||||
|
||||
|
|
|
@ -9,13 +9,13 @@
|
|||
import React from 'react';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { EuiSpacer } from '@elastic/eui';
|
||||
import { SearchResponse } from 'elasticsearch';
|
||||
import type { estypes } from '@elastic/elasticsearch';
|
||||
import { ShardFailureOpenModalButton } from '../../ui/shard_failure_modal';
|
||||
import { toMountPoint } from '../../../../kibana_react/public';
|
||||
import { getNotifications } from '../../services';
|
||||
import { SearchRequest } from '..';
|
||||
|
||||
export function handleResponse(request: SearchRequest, response: SearchResponse<any>) {
|
||||
export function handleResponse(request: SearchRequest, response: estypes.SearchResponse<any>) {
|
||||
if (response.timed_out) {
|
||||
getNotifications().toasts.addWarning({
|
||||
title: i18n.translate('data.search.searchSource.fetch.requestTimedOutNotificationMessage', {
|
||||
|
|
|
@ -21,14 +21,14 @@ import {
|
|||
EuiButtonEmpty,
|
||||
EuiCallOut,
|
||||
} from '@elastic/eui';
|
||||
import { SearchResponse } from 'elasticsearch';
|
||||
import type { estypes } from '@elastic/elasticsearch';
|
||||
import { ShardFailureTable } from './shard_failure_table';
|
||||
import { ShardFailureRequest } from './shard_failure_types';
|
||||
|
||||
export interface Props {
|
||||
onClose: () => void;
|
||||
request: ShardFailureRequest;
|
||||
response: SearchResponse<any>;
|
||||
response: estypes.SearchResponse<any>;
|
||||
title: string;
|
||||
}
|
||||
|
||||
|
|
|
@ -9,8 +9,8 @@
|
|||
import React from 'react';
|
||||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
import { EuiButton, EuiTextAlign } from '@elastic/eui';
|
||||
import type { estypes } from '@elastic/elasticsearch';
|
||||
|
||||
import { SearchResponse } from 'elasticsearch';
|
||||
import { getOverlays } from '../../services';
|
||||
import { toMountPoint } from '../../../../kibana_react/public';
|
||||
import { ShardFailureModal } from './shard_failure_modal';
|
||||
|
@ -19,7 +19,7 @@ import { ShardFailureRequest } from './shard_failure_types';
|
|||
// @internal
|
||||
export interface ShardFailureOpenModalButtonProps {
|
||||
request: ShardFailureRequest;
|
||||
response: SearchResponse<any>;
|
||||
response: estypes.SearchResponse<any>;
|
||||
title: string;
|
||||
}
|
||||
|
||||
|
|
|
@ -12,7 +12,8 @@ import { IRouter, SharedGlobalConfig } from 'kibana/server';
|
|||
|
||||
import { Observable } from 'rxjs';
|
||||
import { first } from 'rxjs/operators';
|
||||
import { IFieldType, Filter } from '../index';
|
||||
import type { estypes } from '@elastic/elasticsearch';
|
||||
import type { IFieldType } from '../index';
|
||||
import { findIndexPatternById, getFieldByName } from '../index_patterns';
|
||||
import { getRequestAbortedSignal } from '../lib';
|
||||
|
||||
|
@ -73,7 +74,7 @@ async function getBody(
|
|||
{ timeout, terminate_after }: Record<string, any>,
|
||||
field: IFieldType | string,
|
||||
query: string,
|
||||
filters: Filter[] = []
|
||||
filters: estypes.QueryContainer[] = []
|
||||
) {
|
||||
const isFieldObject = (f: any): f is IFieldType => Boolean(f && f.name);
|
||||
|
||||
|
@ -82,7 +83,7 @@ async function getBody(
|
|||
q.replace(/[.?+*|{}[\]()"\\#@&<>~]/g, (match) => `\\${match}`);
|
||||
|
||||
// Helps ensure that the regex is not evaluated eagerly against the terms dictionary
|
||||
const executionHint = 'map';
|
||||
const executionHint = 'map' as const;
|
||||
|
||||
// We don't care about the accuracy of the counts, just the content of the terms, so this reduces
|
||||
// the amount of information that needs to be transmitted to the coordinating node
|
||||
|
|
|
@ -8,17 +8,6 @@
|
|||
|
||||
import { ElasticsearchClient } from 'kibana/server';
|
||||
import { convertEsError } from './errors';
|
||||
import { FieldCapsResponse } from './field_capabilities';
|
||||
|
||||
export interface IndicesAliasResponse {
|
||||
[index: string]: IndexAliasResponse;
|
||||
}
|
||||
|
||||
export interface IndexAliasResponse {
|
||||
aliases: {
|
||||
[aliasName: string]: Record<string, any>;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Call the index.getAlias API for a list of indices.
|
||||
|
@ -67,7 +56,7 @@ export async function callFieldCapsApi(
|
|||
fieldCapsOptions: { allow_no_indices: boolean } = { allow_no_indices: false }
|
||||
) {
|
||||
try {
|
||||
return await callCluster.fieldCaps<FieldCapsResponse>({
|
||||
return await callCluster.fieldCaps({
|
||||
index: indices,
|
||||
fields: '*',
|
||||
ignore_unavailable: true,
|
||||
|
|
|
@ -7,23 +7,11 @@
|
|||
*/
|
||||
|
||||
import { uniq } from 'lodash';
|
||||
import type { estypes } from '@elastic/elasticsearch';
|
||||
import { castEsToKbnFieldTypeName } from '../../../../../common';
|
||||
import { shouldReadFieldFromDocValues } from './should_read_field_from_doc_values';
|
||||
import { FieldDescriptor } from '../../../fetcher';
|
||||
|
||||
interface FieldCapObject {
|
||||
type: string;
|
||||
searchable: boolean;
|
||||
aggregatable: boolean;
|
||||
indices?: string[];
|
||||
non_searchable_indices?: string[];
|
||||
non_aggregatable_indices?: string[];
|
||||
}
|
||||
|
||||
export interface FieldCapsResponse {
|
||||
fields: Record<string, Record<string, FieldCapObject>>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the response from the _field_caps API to determine the type and
|
||||
* "aggregatable"/"searchable" status of each field.
|
||||
|
@ -80,7 +68,9 @@ export interface FieldCapsResponse {
|
|||
* @param {FieldCapsResponse} fieldCapsResponse
|
||||
* @return {Array<FieldDescriptor>}
|
||||
*/
|
||||
export function readFieldCapsResponse(fieldCapsResponse: FieldCapsResponse): FieldDescriptor[] {
|
||||
export function readFieldCapsResponse(
|
||||
fieldCapsResponse: estypes.FieldCapabilitiesResponse
|
||||
): FieldDescriptor[] {
|
||||
const capsByNameThenType = fieldCapsResponse.fields;
|
||||
|
||||
const kibanaFormattedCaps = Object.keys(capsByNameThenType).reduce<{
|
||||
|
|
|
@ -7,5 +7,4 @@
|
|||
*/
|
||||
|
||||
export { getFieldCapabilities } from './field_capabilities';
|
||||
export { FieldCapsResponse } from './field_caps_response';
|
||||
export { shouldReadFieldFromDocValues } from './should_read_field_from_doc_values';
|
||||
|
|
|
@ -12,7 +12,7 @@ import moment from 'moment';
|
|||
import { ElasticsearchClient } from 'kibana/server';
|
||||
|
||||
import { timePatternToWildcard } from './time_pattern_to_wildcard';
|
||||
import { callIndexAliasApi, IndicesAliasResponse } from './es_api';
|
||||
import { callIndexAliasApi } from './es_api';
|
||||
|
||||
/**
|
||||
* Convert a time pattern into a list of indexes it could
|
||||
|
@ -28,7 +28,7 @@ import { callIndexAliasApi, IndicesAliasResponse } from './es_api';
|
|||
export async function resolveTimePattern(callCluster: ElasticsearchClient, timePattern: string) {
|
||||
const aliases = await callIndexAliasApi(callCluster, timePatternToWildcard(timePattern));
|
||||
|
||||
const allIndexDetails = chain<IndicesAliasResponse>(aliases.body)
|
||||
const allIndexDetails = chain(aliases.body)
|
||||
.reduce(
|
||||
(acc: string[], index: any, indexName: string) =>
|
||||
acc.concat(indexName, Object.keys(index.aliases || {})),
|
||||
|
|
|
@ -9,18 +9,16 @@
|
|||
import { Observable } from 'rxjs';
|
||||
import { first } from 'rxjs/operators';
|
||||
import { SharedGlobalConfig } from 'kibana/server';
|
||||
import { SearchResponse } from 'elasticsearch';
|
||||
import { CollectorFetchContext } from 'src/plugins/usage_collection/server';
|
||||
import { CollectedUsage, ReportedUsage } from './register';
|
||||
interface SearchTelemetry {
|
||||
'search-telemetry': CollectedUsage;
|
||||
}
|
||||
type ESResponse = SearchResponse<SearchTelemetry>;
|
||||
|
||||
export function fetchProvider(config$: Observable<SharedGlobalConfig>) {
|
||||
return async ({ esClient }: CollectorFetchContext): Promise<ReportedUsage> => {
|
||||
const config = await config$.pipe(first()).toPromise();
|
||||
const { body: esResponse } = await esClient.search<ESResponse>(
|
||||
const { body: esResponse } = await esClient.search<SearchTelemetry>(
|
||||
{
|
||||
index: config.kibana.index,
|
||||
body: {
|
||||
|
@ -37,7 +35,7 @@ export function fetchProvider(config$: Observable<SharedGlobalConfig>) {
|
|||
averageDuration: null,
|
||||
};
|
||||
}
|
||||
const { successCount, errorCount, totalDuration } = esResponse.hits.hits[0]._source[
|
||||
const { successCount, errorCount, totalDuration } = esResponse.hits.hits[0]._source![
|
||||
'search-telemetry'
|
||||
];
|
||||
const averageDuration = totalDuration / successCount;
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
|
||||
import { from, Observable } from 'rxjs';
|
||||
import { first, tap } from 'rxjs/operators';
|
||||
import type { SearchResponse } from 'elasticsearch';
|
||||
import type { Logger, SharedGlobalConfig } from 'kibana/server';
|
||||
import type { ISearchStrategy } from '../types';
|
||||
import type { SearchUsage } from '../collectors';
|
||||
|
@ -44,7 +43,7 @@ export const esSearchStrategyProvider = (
|
|||
...getShardTimeout(config),
|
||||
...request.params,
|
||||
};
|
||||
const promise = esClient.asCurrentUser.search<SearchResponse<unknown>>(params);
|
||||
const promise = esClient.asCurrentUser.search(params);
|
||||
const { body } = await shimAbortSignal(promise, abortSignal);
|
||||
const response = shimHitsTotal(body, options);
|
||||
return toKibanaSearchResponse(response);
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { SearchResponse } from 'elasticsearch';
|
||||
import type { estypes } from '@elastic/elasticsearch';
|
||||
import { ISearchOptions } from '../../../common';
|
||||
|
||||
/**
|
||||
|
@ -14,7 +14,7 @@ import { ISearchOptions } from '../../../common';
|
|||
* not included as it is already included in `successful`.
|
||||
* @internal
|
||||
*/
|
||||
export function getTotalLoaded(response: SearchResponse<unknown>) {
|
||||
export function getTotalLoaded(response: estypes.SearchResponse<unknown>) {
|
||||
const { total, failed, successful } = response._shards;
|
||||
const loaded = failed + successful;
|
||||
return { total, loaded };
|
||||
|
@ -24,7 +24,7 @@ export function getTotalLoaded(response: SearchResponse<unknown>) {
|
|||
* Get the Kibana representation of this response (see `IKibanaSearchResponse`).
|
||||
* @internal
|
||||
*/
|
||||
export function toKibanaSearchResponse(rawResponse: SearchResponse<unknown>) {
|
||||
export function toKibanaSearchResponse(rawResponse: estypes.SearchResponse<unknown>) {
|
||||
return {
|
||||
rawResponse,
|
||||
isPartial: false,
|
||||
|
@ -41,7 +41,7 @@ export function toKibanaSearchResponse(rawResponse: SearchResponse<unknown>) {
|
|||
* @internal
|
||||
*/
|
||||
export function shimHitsTotal(
|
||||
response: SearchResponse<unknown>,
|
||||
response: estypes.SearchResponse<unknown>,
|
||||
{ legacyHitsTotal = true }: ISearchOptions = {}
|
||||
) {
|
||||
if (!legacyHitsTotal) return response;
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
|
||||
import { Observable } from 'rxjs';
|
||||
import { first } from 'rxjs/operators';
|
||||
import { SearchResponse } from 'elasticsearch';
|
||||
import { IUiSettingsClient, IScopedClusterClient, SharedGlobalConfig } from 'src/core/server';
|
||||
|
||||
import type { MsearchRequestBody, MsearchResponse } from '../../../common/search/search_source';
|
||||
|
@ -66,6 +65,7 @@ export function getCallMsearch(dependencies: CallMsearchDependencies) {
|
|||
try {
|
||||
const promise = esClient.asCurrentUser.msearch(
|
||||
{
|
||||
// @ts-expect-error @elastic/elasticsearch client types don't support plain string bodies
|
||||
body: convertRequestBody(params.body, timeout),
|
||||
},
|
||||
{
|
||||
|
@ -78,9 +78,7 @@ export function getCallMsearch(dependencies: CallMsearchDependencies) {
|
|||
body: {
|
||||
...response,
|
||||
body: {
|
||||
responses: response.body.responses?.map((r: SearchResponse<unknown>) =>
|
||||
shimHitsTotal(r)
|
||||
),
|
||||
responses: response.body.responses?.map((r) => shimHitsTotal(r)),
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
|
@ -25,6 +25,7 @@ import { ElasticsearchClient as ElasticsearchClient_2 } from 'kibana/server';
|
|||
import { Ensure } from '@kbn/utility-types';
|
||||
import { EnvironmentMode } from '@kbn/config';
|
||||
import { ErrorToastOptions } from 'src/core/public/notifications';
|
||||
import { estypes } from '@elastic/elasticsearch';
|
||||
import { ExecutionContext } from 'src/plugins/expressions/common';
|
||||
import { ExpressionAstExpression } from 'src/plugins/expressions/common';
|
||||
import { ExpressionFunctionDefinition } from 'src/plugins/expressions/common';
|
||||
|
@ -64,7 +65,6 @@ import { SavedObjectsFindOptions } from 'kibana/server';
|
|||
import { SavedObjectsFindResponse } from 'kibana/server';
|
||||
import { SavedObjectsUpdateResponse } from 'kibana/server';
|
||||
import { Search } from '@elastic/elasticsearch/api/requestParams';
|
||||
import { SearchResponse } from 'elasticsearch';
|
||||
import { SerializedFieldFormat as SerializedFieldFormat_2 } from 'src/plugins/expressions/common';
|
||||
import { SharedGlobalConfig as SharedGlobalConfig_2 } from 'kibana/server';
|
||||
import { ToastInputFields } from 'src/core/public/notifications';
|
||||
|
@ -596,7 +596,7 @@ export function getTime(indexPattern: IIndexPattern | undefined, timeRange: Time
|
|||
}): import("../..").RangeFilter | undefined;
|
||||
|
||||
// @internal
|
||||
export function getTotalLoaded(response: SearchResponse<unknown>): {
|
||||
export function getTotalLoaded(response: estypes.SearchResponse<unknown>): {
|
||||
total: number;
|
||||
loaded: number;
|
||||
};
|
||||
|
@ -631,7 +631,7 @@ export interface IEsSearchRequest extends IKibanaSearchRequest<ISearchRequestPar
|
|||
// Warning: (ae-missing-release-tag) "IEsSearchResponse" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
// @public (undocumented)
|
||||
export type IEsSearchResponse<Source = any> = IKibanaSearchResponse<SearchResponse<Source>>;
|
||||
export type IEsSearchResponse<Source = any> = IKibanaSearchResponse<estypes.SearchResponse<Source>>;
|
||||
|
||||
// Warning: (ae-missing-release-tag) "IFieldFormatsRegistry" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
|
@ -1384,30 +1384,26 @@ export function searchUsageObserver(logger: Logger_2, usage?: SearchUsage, { isR
|
|||
export const shimAbortSignal: <T>(promise: TransportRequestPromise<T>, signal?: AbortSignal | undefined) => TransportRequestPromise<T>;
|
||||
|
||||
// @internal
|
||||
export function shimHitsTotal(response: SearchResponse<unknown>, { legacyHitsTotal }?: ISearchOptions): {
|
||||
export function shimHitsTotal(response: estypes.SearchResponse<unknown>, { legacyHitsTotal }?: ISearchOptions): {
|
||||
hits: {
|
||||
total: any;
|
||||
max_score: number;
|
||||
hits: {
|
||||
_index: string;
|
||||
_type: string;
|
||||
_id: string;
|
||||
_score: number;
|
||||
_source: unknown;
|
||||
_version?: number | undefined;
|
||||
_explanation?: import("elasticsearch").Explanation | undefined;
|
||||
fields?: any;
|
||||
highlight?: any;
|
||||
inner_hits?: any;
|
||||
matched_queries?: string[] | undefined;
|
||||
sort?: string[] | undefined;
|
||||
}[];
|
||||
hits: estypes.Hit<unknown>[];
|
||||
max_score?: number | undefined;
|
||||
};
|
||||
took: number;
|
||||
timed_out: boolean;
|
||||
_shards: estypes.ShardStatistics;
|
||||
aggregations?: Record<string, estypes.Aggregate> | undefined;
|
||||
_clusters?: estypes.ClusterStatistics | undefined;
|
||||
documents?: unknown[] | undefined;
|
||||
fields?: Record<string, any> | undefined;
|
||||
max_score?: number | undefined;
|
||||
num_reduce_phases?: number | undefined;
|
||||
profile?: estypes.Profile | undefined;
|
||||
pit_id?: string | undefined;
|
||||
_scroll_id?: string | undefined;
|
||||
_shards: import("elasticsearch").ShardsResponse;
|
||||
aggregations?: any;
|
||||
suggest?: Record<string, estypes.Suggest<unknown>[]> | undefined;
|
||||
terminated_early?: boolean | undefined;
|
||||
};
|
||||
|
||||
// Warning: (ae-missing-release-tag) "shouldReadFieldFromDocValues" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
|
@ -1425,10 +1421,10 @@ export type TimeRange = {
|
|||
};
|
||||
|
||||
// @internal
|
||||
export function toKibanaSearchResponse(rawResponse: SearchResponse<unknown>): {
|
||||
export function toKibanaSearchResponse(rawResponse: estypes.SearchResponse<unknown>): {
|
||||
total: number;
|
||||
loaded: number;
|
||||
rawResponse: SearchResponse<unknown>;
|
||||
rawResponse: estypes.SearchResponse<unknown>;
|
||||
isPartial: boolean;
|
||||
isRunning: boolean;
|
||||
};
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
import angular, { auto, ICompileService, IScope } from 'angular';
|
||||
import { render } from 'react-dom';
|
||||
import React, { useRef, useEffect, useState, useCallback } from 'react';
|
||||
import type { estypes } from '@elastic/elasticsearch';
|
||||
import { EuiButtonEmpty } from '@elastic/eui';
|
||||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
import { getServices, IIndexPattern } from '../../../kibana_services';
|
||||
|
@ -20,7 +21,7 @@ export interface DocTableLegacyProps {
|
|||
searchDescription?: string;
|
||||
searchTitle?: string;
|
||||
onFilter: (field: IndexPatternField | string, value: string, type: '+' | '-') => void;
|
||||
rows: Array<Record<string, unknown>>;
|
||||
rows: estypes.Hit[];
|
||||
indexPattern: IIndexPattern;
|
||||
minimumVisibleRows: number;
|
||||
onAddColumn?: (column: string) => void;
|
||||
|
|
|
@ -87,6 +87,7 @@ export function ContextAppLegacy(renderProps: ContextAppProps) {
|
|||
minimumVisibleRows,
|
||||
useNewFieldsApi,
|
||||
} = renderProps;
|
||||
// @ts-expect-error doesn't implement full DocTableLegacyProps interface
|
||||
return {
|
||||
columns,
|
||||
indexPattern,
|
||||
|
|
|
@ -140,7 +140,7 @@ export function DiscoverGridFlyout({
|
|||
iconType="documents"
|
||||
flush="left"
|
||||
href={getContextUrl(
|
||||
hit._id,
|
||||
String(hit._id),
|
||||
indexPattern.id,
|
||||
columns,
|
||||
services.filterManager,
|
||||
|
|
|
@ -10,6 +10,7 @@ import React from 'react';
|
|||
import { ReactWrapper, shallow } from 'enzyme';
|
||||
import { getRenderCellValueFn } from './get_render_cell_value';
|
||||
import { indexPatternMock } from '../../../__mocks__/index_pattern';
|
||||
import { ElasticSearchHit } from '../../doc_views/doc_views_types';
|
||||
|
||||
jest.mock('../../../../../kibana_react/public', () => ({
|
||||
useUiSetting: () => true,
|
||||
|
@ -26,7 +27,7 @@ jest.mock('../../../kibana_services', () => ({
|
|||
}),
|
||||
}));
|
||||
|
||||
const rowsSource = [
|
||||
const rowsSource: ElasticSearchHit[] = [
|
||||
{
|
||||
_id: '1',
|
||||
_index: 'test',
|
||||
|
@ -34,12 +35,12 @@ const rowsSource = [
|
|||
_score: 1,
|
||||
_source: { bytes: 100, extension: '.gz' },
|
||||
highlight: {
|
||||
extension: '@kibana-highlighted-field.gz@/kibana-highlighted-field',
|
||||
extension: ['@kibana-highlighted-field.gz@/kibana-highlighted-field'],
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
const rowsFields = [
|
||||
const rowsFields: ElasticSearchHit[] = [
|
||||
{
|
||||
_id: '1',
|
||||
_index: 'test',
|
||||
|
@ -48,12 +49,12 @@ const rowsFields = [
|
|||
_source: undefined,
|
||||
fields: { bytes: [100], extension: ['.gz'] },
|
||||
highlight: {
|
||||
extension: '@kibana-highlighted-field.gz@/kibana-highlighted-field',
|
||||
extension: ['@kibana-highlighted-field.gz@/kibana-highlighted-field'],
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
const rowsFieldsWithTopLevelObject = [
|
||||
const rowsFieldsWithTopLevelObject: ElasticSearchHit[] = [
|
||||
{
|
||||
_id: '1',
|
||||
_index: 'test',
|
||||
|
@ -62,7 +63,7 @@ const rowsFieldsWithTopLevelObject = [
|
|||
_source: undefined,
|
||||
fields: { 'object.value': [100], extension: ['.gz'] },
|
||||
highlight: {
|
||||
extension: '@kibana-highlighted-field.gz@/kibana-highlighted-field',
|
||||
extension: ['@kibana-highlighted-field.gz@/kibana-highlighted-field'],
|
||||
},
|
||||
},
|
||||
];
|
||||
|
@ -167,7 +168,9 @@ describe('Discover grid cell rendering', function () {
|
|||
},
|
||||
"_type": "test",
|
||||
"highlight": Object {
|
||||
"extension": "@kibana-highlighted-field.gz@/kibana-highlighted-field",
|
||||
"extension": Array [
|
||||
"@kibana-highlighted-field.gz@/kibana-highlighted-field",
|
||||
],
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@ -264,7 +267,9 @@ describe('Discover grid cell rendering', function () {
|
|||
],
|
||||
},
|
||||
"highlight": Object {
|
||||
"extension": "@kibana-highlighted-field.gz@/kibana-highlighted-field",
|
||||
"extension": Array [
|
||||
"@kibana-highlighted-field.gz@/kibana-highlighted-field",
|
||||
],
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
@ -87,7 +87,7 @@ describe('DocViewTable at Discover', () => {
|
|||
scripted: 123,
|
||||
_underscore: 123,
|
||||
},
|
||||
};
|
||||
} as any;
|
||||
|
||||
const props = {
|
||||
hit,
|
||||
|
@ -185,7 +185,7 @@ describe('DocViewTable at Discover Context', () => {
|
|||
Integer tincidunt. Cras dapibus. Vivamus elementum semper nisi. Aenean vulputate eleifend tellus. \
|
||||
Phasellus ullamcorper ipsum rutrum nunc. Nunc nonummy metus. Vestibulum volutpat pretium libero. Cras id dui. Aenean ut',
|
||||
},
|
||||
};
|
||||
} as any;
|
||||
const props = {
|
||||
hit,
|
||||
columns: ['extension'],
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
|
||||
import { ComponentType } from 'react';
|
||||
import { IScope } from 'angular';
|
||||
import { SearchResponse } from 'elasticsearch';
|
||||
import type { estypes } from '@elastic/elasticsearch';
|
||||
import { IndexPattern } from '../../../../data/public';
|
||||
|
||||
export interface AngularDirective {
|
||||
|
@ -18,7 +18,7 @@ export interface AngularDirective {
|
|||
|
||||
export type AngularScope = IScope;
|
||||
|
||||
export type ElasticSearchHit<T = unknown> = SearchResponse<T>['hits']['hits'][number];
|
||||
export type ElasticSearchHit<T = unknown> = estypes.SearchResponse<T>['hits']['hits'][number];
|
||||
|
||||
export interface FieldMapping {
|
||||
filterable?: boolean;
|
||||
|
|
|
@ -357,7 +357,7 @@ export class SearchEmbeddable
|
|||
// Apply the changes to the angular scope
|
||||
this.searchScope.$apply(() => {
|
||||
this.searchScope!.hits = resp.hits.hits;
|
||||
this.searchScope!.totalHitCount = resp.hits.total;
|
||||
this.searchScope!.totalHitCount = resp.hits.total as number;
|
||||
this.searchScope!.isLoading = false;
|
||||
});
|
||||
} catch (error) {
|
||||
|
|
|
@ -15,6 +15,7 @@ import * as CSS from 'csstype';
|
|||
import { DetailedPeerCertificate } from 'tls';
|
||||
import { EmbeddableStart as EmbeddableStart_2 } from 'src/plugins/embeddable/public/plugin';
|
||||
import { EnvironmentMode } from '@kbn/config';
|
||||
import { estypes } from '@elastic/elasticsearch';
|
||||
import { EuiBreadcrumb } from '@elastic/eui';
|
||||
import { EuiButtonEmptyProps } from '@elastic/eui';
|
||||
import { EuiConfirmModalProps } from '@elastic/eui';
|
||||
|
|
|
@ -46,8 +46,8 @@ describe('preview_scripted_field route', () => {
|
|||
|
||||
expect(mockClient.search.mock.calls[0][0]).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"_source": undefined,
|
||||
"body": Object {
|
||||
"_source": undefined,
|
||||
"query": Object {
|
||||
"match_all": Object {},
|
||||
},
|
||||
|
@ -59,10 +59,10 @@ describe('preview_scripted_field route', () => {
|
|||
},
|
||||
},
|
||||
},
|
||||
"size": 10,
|
||||
"timeout": "30s",
|
||||
},
|
||||
"index": "kibana_sample_data_logs",
|
||||
"size": 10,
|
||||
"timeout": "30s",
|
||||
}
|
||||
`);
|
||||
|
||||
|
@ -102,12 +102,12 @@ describe('preview_scripted_field route', () => {
|
|||
|
||||
expect(mockClient.search.mock.calls[0][0]).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"_source": Array [
|
||||
"a",
|
||||
"b",
|
||||
"c",
|
||||
],
|
||||
"body": Object {
|
||||
"_source": Array [
|
||||
"a",
|
||||
"b",
|
||||
"c",
|
||||
],
|
||||
"query": Object {
|
||||
"bool": Object {
|
||||
"some": "query",
|
||||
|
@ -121,10 +121,10 @@ describe('preview_scripted_field route', () => {
|
|||
},
|
||||
},
|
||||
},
|
||||
"size": 10,
|
||||
"timeout": "30s",
|
||||
},
|
||||
"index": "kibana_sample_data_logs",
|
||||
"size": 10,
|
||||
"timeout": "30s",
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
|
|
@ -30,10 +30,10 @@ export function registerPreviewScriptedFieldRoute(router: IRouter): void {
|
|||
try {
|
||||
const response = await client.search({
|
||||
index,
|
||||
_source: additionalFields && additionalFields.length > 0 ? additionalFields : undefined,
|
||||
size: 10,
|
||||
timeout: '30s',
|
||||
body: {
|
||||
_source: additionalFields && additionalFields.length > 0 ? additionalFields : undefined,
|
||||
size: 10,
|
||||
timeout: '30s',
|
||||
query: query ?? { match_all: {} },
|
||||
script_fields: {
|
||||
[name]: {
|
||||
|
|
|
@ -58,6 +58,7 @@ export async function getSavedObjectsCounts(
|
|||
};
|
||||
const { body } = await esClient.search(savedObjectCountSearchParams);
|
||||
const buckets: Array<{ key: string; doc_count: number }> =
|
||||
// @ts-expect-error @elastic/elasticsearch Aggregate does not include `buckets`
|
||||
body.aggregations?.types?.buckets || [];
|
||||
|
||||
// Initialise the object with all zeros for all the types
|
||||
|
|
|
@ -27,6 +27,7 @@ describe('checkClusterForUserData', () => {
|
|||
it('returns false if data only exists in system indices', async () => {
|
||||
const esClient = elasticsearchServiceMock.createElasticsearchClient();
|
||||
esClient.cat.indices.mockResolvedValue(
|
||||
// @ts-expect-error @elastic/elasticsearch ES types don't support array response format
|
||||
elasticsearchServiceMock.createApiResponse({
|
||||
body: [
|
||||
{
|
||||
|
@ -55,6 +56,7 @@ describe('checkClusterForUserData', () => {
|
|||
it('returns true if data exists in non-system indices', async () => {
|
||||
const esClient = elasticsearchServiceMock.createElasticsearchClient();
|
||||
esClient.cat.indices.mockResolvedValue(
|
||||
// @ts-expect-error @elastic/elasticsearch ES types don't support array response format
|
||||
elasticsearchServiceMock.createApiResponse({
|
||||
body: [
|
||||
{
|
||||
|
@ -85,6 +87,7 @@ describe('checkClusterForUserData', () => {
|
|||
)
|
||||
.mockRejectedValueOnce(new Error('something terrible happened'))
|
||||
.mockResolvedValueOnce(
|
||||
// @ts-expect-error @elastic/elasticsearch ES types don't support array response format
|
||||
elasticsearchServiceMock.createApiResponse({
|
||||
body: [
|
||||
{
|
||||
|
@ -95,6 +98,7 @@ describe('checkClusterForUserData', () => {
|
|||
})
|
||||
)
|
||||
.mockResolvedValueOnce(
|
||||
// @ts-expect-error @elastic/elasticsearch ES types don't support array response format
|
||||
elasticsearchServiceMock.createApiResponse({
|
||||
body: [
|
||||
{
|
||||
|
|
|
@ -14,17 +14,15 @@ export const createClusterDataCheck = () => {
|
|||
return async function doesClusterHaveUserData(esClient: ElasticsearchClient, log: Logger) {
|
||||
if (!clusterHasUserData) {
|
||||
try {
|
||||
const indices = await esClient.cat.indices<
|
||||
Array<{ index: string; ['docs.count']: string }>
|
||||
>({
|
||||
const indices = await esClient.cat.indices({
|
||||
format: 'json',
|
||||
h: ['index', 'docs.count'],
|
||||
});
|
||||
clusterHasUserData = indices.body.some((indexCount) => {
|
||||
const isInternalIndex =
|
||||
indexCount.index.startsWith('.') || indexCount.index.startsWith('kibana_sample_');
|
||||
indexCount.index?.startsWith('.') || indexCount.index?.startsWith('kibana_sample_');
|
||||
|
||||
return !isInternalIndex && parseInt(indexCount['docs.count'], 10) > 0;
|
||||
return !isInternalIndex && parseInt(indexCount['docs.count']!, 10) > 0;
|
||||
});
|
||||
} catch (e) {
|
||||
log.warn(`Error encountered while checking cluster for user data: ${e}`);
|
||||
|
|
|
@ -8,22 +8,6 @@
|
|||
|
||||
import { ElasticsearchClient } from 'src/core/server';
|
||||
|
||||
// This can be removed when the ES client improves the types
|
||||
export interface ESClusterInfo {
|
||||
cluster_uuid: string;
|
||||
cluster_name: string;
|
||||
version: {
|
||||
number: string;
|
||||
build_flavor?: string;
|
||||
build_type?: string;
|
||||
build_hash?: string;
|
||||
build_date?: string;
|
||||
build_snapshot?: boolean;
|
||||
lucene_version?: string;
|
||||
minimum_wire_compatibility_version?: string;
|
||||
minimum_index_compatibility_version?: string;
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Get the cluster info from the connected cluster.
|
||||
*
|
||||
|
@ -32,6 +16,6 @@ export interface ESClusterInfo {
|
|||
* @param {function} esClient The asInternalUser handler (exposed for testing)
|
||||
*/
|
||||
export async function getClusterInfo(esClient: ElasticsearchClient) {
|
||||
const { body } = await esClient.info<ESClusterInfo>();
|
||||
const { body } = await esClient.info();
|
||||
return body;
|
||||
}
|
||||
|
|
|
@ -261,14 +261,16 @@ export async function getDataTelemetry(esClient: ElasticsearchClient) {
|
|||
const indices = indexNames.map((name) => {
|
||||
const baseIndexInfo = {
|
||||
name,
|
||||
isECS: !!indexMappings[name]?.mappings?.properties.ecs?.properties.version?.type,
|
||||
isECS: !!indexMappings[name]?.mappings?.properties?.ecs?.properties?.version?.type,
|
||||
shipper: indexMappings[name]?.mappings?._meta?.beat,
|
||||
packageName: indexMappings[name]?.mappings?._meta?.package?.name,
|
||||
managedBy: indexMappings[name]?.mappings?._meta?.managed_by,
|
||||
dataStreamDataset:
|
||||
indexMappings[name]?.mappings?.properties.data_stream?.properties.dataset?.value,
|
||||
// @ts-expect-error @elastic/elasticsearch PropertyBase doesn't decalre value
|
||||
indexMappings[name]?.mappings?.properties?.data_stream?.properties?.dataset?.value,
|
||||
dataStreamType:
|
||||
indexMappings[name]?.mappings?.properties.data_stream?.properties.type?.value,
|
||||
// @ts-expect-error @elastic/elasticsearch PropertyBase doesn't decalre value
|
||||
indexMappings[name]?.mappings?.properties?.data_stream?.properties?.type?.value,
|
||||
};
|
||||
|
||||
const stats = (indexStats?.indices || {})[name];
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
*/
|
||||
|
||||
import { merge, omit } from 'lodash';
|
||||
import type { estypes } from '@elastic/elasticsearch';
|
||||
|
||||
import { getLocalStats, handleLocalStats } from './get_local_stats';
|
||||
import {
|
||||
|
@ -34,35 +35,33 @@ function mockGetLocalStats(clusterInfo: any, clusterStats: any) {
|
|||
esClient.cluster.stats
|
||||
// @ts-expect-error we only care about the response body
|
||||
.mockResolvedValue({ body: { ...clusterStats } });
|
||||
esClient.nodes.usage.mockResolvedValue(
|
||||
esClient.nodes.usage.mockResolvedValue({
|
||||
// @ts-expect-error we only care about the response body
|
||||
{
|
||||
body: {
|
||||
cluster_name: 'testCluster',
|
||||
nodes: {
|
||||
some_node_id: {
|
||||
timestamp: 1588617023177,
|
||||
since: 1588616945163,
|
||||
rest_actions: {
|
||||
nodes_usage_action: 1,
|
||||
create_index_action: 1,
|
||||
document_get_action: 1,
|
||||
search_action: 19,
|
||||
nodes_info_action: 36,
|
||||
body: {
|
||||
cluster_name: 'testCluster',
|
||||
nodes: {
|
||||
some_node_id: {
|
||||
timestamp: 1588617023177,
|
||||
since: 1588616945163,
|
||||
rest_actions: {
|
||||
nodes_usage_action: 1,
|
||||
create_index_action: 1,
|
||||
document_get_action: 1,
|
||||
search_action: 19,
|
||||
nodes_info_action: 36,
|
||||
},
|
||||
aggregations: {
|
||||
scripted_metric: {
|
||||
other: 7,
|
||||
},
|
||||
aggregations: {
|
||||
terms: {
|
||||
bytes: 2,
|
||||
},
|
||||
scripted_metric: {
|
||||
other: 7,
|
||||
},
|
||||
terms: {
|
||||
bytes: 2,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
);
|
||||
},
|
||||
});
|
||||
// @ts-expect-error we only care about the response body
|
||||
esClient.indices.getMapping.mockResolvedValue({ body: { mappings: {} } });
|
||||
// @ts-expect-error we only care about the response body
|
||||
|
@ -188,7 +187,7 @@ describe('get_local_stats', () => {
|
|||
describe('handleLocalStats', () => {
|
||||
it('returns expected object without xpack or kibana data', () => {
|
||||
const result = handleLocalStats(
|
||||
clusterInfo,
|
||||
clusterInfo as estypes.RootNodeInfoResponse,
|
||||
clusterStatsWithNodesUsage,
|
||||
void 0,
|
||||
void 0,
|
||||
|
@ -205,7 +204,7 @@ describe('get_local_stats', () => {
|
|||
|
||||
it('returns expected object with xpack', () => {
|
||||
const result = handleLocalStats(
|
||||
clusterInfo,
|
||||
clusterInfo as estypes.RootNodeInfoResponse,
|
||||
clusterStatsWithNodesUsage,
|
||||
void 0,
|
||||
void 0,
|
||||
|
|
|
@ -6,11 +6,12 @@
|
|||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import type { estypes } from '@elastic/elasticsearch';
|
||||
import {
|
||||
StatsGetter,
|
||||
StatsCollectionContext,
|
||||
} from 'src/plugins/telemetry_collection_manager/server';
|
||||
import { getClusterInfo, ESClusterInfo } from './get_cluster_info';
|
||||
import { getClusterInfo } from './get_cluster_info';
|
||||
import { getClusterStats } from './get_cluster_stats';
|
||||
import { getKibana, handleKibanaStats, KibanaUsageStats } from './get_kibana';
|
||||
import { getNodesUsage } from './get_nodes_usage';
|
||||
|
@ -27,7 +28,7 @@ import { getDataTelemetry, DATA_TELEMETRY_ID, DataTelemetryPayload } from './get
|
|||
*/
|
||||
export function handleLocalStats(
|
||||
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||
{ cluster_name, cluster_uuid, version }: ESClusterInfo,
|
||||
{ cluster_name, cluster_uuid, version }: estypes.RootNodeInfoResponse,
|
||||
{ _nodes, cluster_name: clusterName, ...clusterStats }: any,
|
||||
kibana: KibanaUsageStats | undefined,
|
||||
dataTelemetry: DataTelemetryPayload | undefined,
|
||||
|
|
|
@ -16,7 +16,7 @@ export interface NodeAggregation {
|
|||
// we set aggregations as an optional type because it was only added in v7.8.0
|
||||
export interface NodeObj {
|
||||
node_id?: string;
|
||||
timestamp: number;
|
||||
timestamp: number | string;
|
||||
since: number;
|
||||
rest_actions: {
|
||||
[key: string]: number;
|
||||
|
@ -46,9 +46,10 @@ export type NodesUsageGetter = (
|
|||
export async function fetchNodesUsage(
|
||||
esClient: ElasticsearchClient
|
||||
): Promise<NodesFeatureUsageResponse> {
|
||||
const { body } = await esClient.nodes.usage<NodesFeatureUsageResponse>({
|
||||
const { body } = await esClient.nodes.usage({
|
||||
timeout: TIMEOUT,
|
||||
});
|
||||
// @ts-expect-error TODO: Does the client parse `timestamp` to a Date object? Expected a number
|
||||
return body;
|
||||
}
|
||||
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue