mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 01:38:56 -04:00
[ES] Upgrade client to v8.0 (#113950)
* bump to a pre-8.0 version * export KibanaClient from /lib sub-folder * workaround the problem of the absence of estypes * update es client usage in pacakges * export estypes from another path * import errors from root * import errors from root 2 * update transport import * update import path for /api/types * update import path for /api/types * import errors from top export * use TransportResult instead if ApiResponse * fix errors in client_config * fix src/core/server/saved_objects/migrationsv2/actions/integration_tests/actions.test.ts * use KibanaClient in mock. we dont export the original Client * fix client mocks * fix errors on SO * fix remaining core errors * update estype import path * fix errors in data plugin * fix data_views * fix es_ui_shared * fix errors in interactive_setup * fix errors in ./test folder * add @elastic/transport to the runtime deps * fix errors in packages * fix erros in src/core * fix errors in test/ * fix an error in actions plugin * woraround and fix errors in APM plugin * fix errors in canvas * fix errors in event_log * fix errors in fleet * fix errors in ILM * fix errors in infra * fix errors in ingest_pipeline * fix errors in lens * fix errors in license_management * fix errors in licensing * fix errors in logstash * fix errors in ml * fix errors in monitoring * fix errors in observability * fix errors in rule_registry * fix errors in reporting * fix errors in rule_registry * fix errors in security * fix errors in security_solution * fix errors in snapshot_restore * fix errors in transform * fix errors in UA * fix errors in uptime * fix errors in x-pack/test * fix eslint errors * fix new errors * use default HTTP Connection. Undici does not support agent config options keepAlive and maxSockets * create does not accept require_alias option * update deps * use transport types exported from ES client package * fix ErrorCause | string errors * do not use enum * fix errors in data plugin * update x-pack code * fix transport * fix apm search request * do not crash on reporting * fix kbn-test build * mute reporting error to start * fix ftr build * another attempt * update import path * address or mute new errors * REMOVE me. pin transport version temporarily. * remove deep imports from transport package * fix jest crash * fix product check tests * remove unnecessary ts-expect-error * fix a few failed unit tests * bump to canary 24 * remove unnecessary ts-expect-error * remove dependency on transport * fix types in tests * mute errors in xpack tests * product check doesn;t spam in logs anymore * filterPath --> filter_path * ignoreUnavailable --> ignore_unavailable * ignoreUnavailable --> ignore_unavailable * trackScores --> track_scores * trackTotalHits --> track_total_hits * fix es-arcives * fix data plugin crashes * fix watcher test utils * rollback unnecessary changes * fix another problem in es-archiver * fix scroll. for whatever reason scroll fails when request scroll_id in body * add meta: true in kbn-securitysolution-es-utils * bump client to canary 25 * fix errors in accordance with the es client spec * update securityscolution-es-utils * unify scroll api in reporting and fix tests * fix unit tests in watcher * refactor APM to abort request with AbortController API * fix missing es client calls in tests * fix missing meta in detection engine FTR tests * fix another bunch of errors in js tests * fix wrong coercion * remove test-grep pattern * fix apm unit test * rename terminateAfter to terminate_after in infra plugin * rename terminateAfter to terminate_after in uptime plugin * rename terminateAfter to terminate_after in apm plugin * fix security roles FTR tests * fix reference * fix post_privilidges test * fix post_privilidges * bump client to 26 * add meta for index_management test helpers * remove ts-expect-error caused by bad type in reason * bump client to 27 * REMOVE me. workaround until fixed in the es client * fix incorrect type casting * swtich from camelCase params * use `HttpConnection` for FTR-related clients * bump client to 29 * Revert "REMOVE me. workaround until fixed in the es client" This reverts commitc038850c09
. * fix new util * revert repository changes * do not crash if cannot store event_loop data * fix new estypes imports * fix more types * fix security test types and add ts-ignore for custom ES client * fix more estypes imports * yet more ts violations * line by line fixing is hard * adapt `evaluateAlert` from infra as it's also used from FTR tests * use convertToKibanaClient in FTR test instead of meta:true in plugin code * migrate from deprecated API in fleet * fix intergration tests * fix fleet tests * fix another fleet test * fix more tests * let's call it a day * Removes custom header check on 404 responses, includes es client ProductNotSupportedError in EsUnavailableError conditional (#116029) * Removes custom header check on 404 responses, includes es client ProductNotSupportedError in EsUnavailableError conditional * Updates proxy response integration test * disable APM until compatible with client v8 * skip async_search FTR test * use kbnClient in integration tests * bump version to 29 * bump to 30 * have configureClient return a KibanaClient instead of Client, remove resolved violations. * bump to 31 * bump to 31 * Revert "bump to 31" This reverts commit5ac713e640
. * trigger stop to unusubscribe * update generated docs * remove obsolete test * put "as" back * cleanup * skip test * remove new type errors in apm package * remove ErrorCause casting * update a comment * bump version to 32 * remove unnecessary ts-expect-error in apm code * update comments * update to client v33 * remove outdated type definition * bump to 34 without params mutation * unskip the test that should not fail anymore * remove unnecessary ts-expect-error comments * update to v35. body can be string * move `sort` to body and use body friendly syntax * fix a failing test. maps register the same SO that has been already registered by home Co-authored-by: pgayvallet <pierre.gayvallet@gmail.com> Co-authored-by: Christiane (Tina) Heiligers <christiane.heiligers@elastic.co>
This commit is contained in:
parent
252aef80dc
commit
3c8fa527a7
814 changed files with 3045 additions and 3350 deletions
|
@ -9,9 +9,9 @@ Client used to query the elasticsearch cluster.
|
|||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
export declare type ElasticsearchClient = Omit<KibanaClient, 'connectionPool' | 'transport' | 'serializer' | 'extend' | 'child' | 'close'> & {
|
||||
export declare type ElasticsearchClient = Omit<KibanaClient, 'connectionPool' | 'transport' | 'serializer' | 'extend' | 'child' | 'close' | 'diagnostic'> & {
|
||||
transport: {
|
||||
request(params: TransportRequestParams, options?: TransportRequestOptions): TransportRequestPromise<ApiResponse>;
|
||||
request<TResponse = unknown>(params: TransportRequestParams, options?: TransportRequestOptions): Promise<TransportResult<TResponse>>;
|
||||
};
|
||||
};
|
||||
```
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [ElasticsearchErrorDetails](./kibana-plugin-core-server.elasticsearcherrordetails.md) > [error](./kibana-plugin-core-server.elasticsearcherrordetails.error.md)
|
||||
|
||||
## ElasticsearchErrorDetails.error property
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
error?: {
|
||||
type: string;
|
||||
reason?: string;
|
||||
};
|
||||
```
|
|
@ -0,0 +1,19 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [ElasticsearchErrorDetails](./kibana-plugin-core-server.elasticsearcherrordetails.md)
|
||||
|
||||
## ElasticsearchErrorDetails interface
|
||||
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
export interface ElasticsearchErrorDetails
|
||||
```
|
||||
|
||||
## Properties
|
||||
|
||||
| Property | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| [error](./kibana-plugin-core-server.elasticsearcherrordetails.error.md) | <code>{</code><br/><code> type: string;</code><br/><code> reason?: string;</code><br/><code> }</code> | |
|
||||
|
|
@ -71,6 +71,7 @@ The plugin integrates with the core system via lifecycle events: `setup`<!-- -->
|
|||
| [DeprecationsServiceSetup](./kibana-plugin-core-server.deprecationsservicesetup.md) | The deprecations service provides a way for the Kibana platform to communicate deprecated features and configs with its users. These deprecations are only communicated if the deployment is using these features. Allowing for a user tailored experience for upgrading the stack version.<!-- -->The Deprecation service is consumed by the upgrade assistant to assist with the upgrade experience.<!-- -->If a deprecated feature can be resolved without manual user intervention. Using correctiveActions.api allows the Upgrade Assistant to use this api to correct the deprecation upon a user trigger. |
|
||||
| [DiscoveredPlugin](./kibana-plugin-core-server.discoveredplugin.md) | Small container object used to expose information about discovered plugins that may or may not have been started. |
|
||||
| [ElasticsearchConfigPreboot](./kibana-plugin-core-server.elasticsearchconfigpreboot.md) | A limited set of Elasticsearch configuration entries exposed to the <code>preboot</code> plugins at <code>setup</code>. |
|
||||
| [ElasticsearchErrorDetails](./kibana-plugin-core-server.elasticsearcherrordetails.md) | |
|
||||
| [ElasticsearchServicePreboot](./kibana-plugin-core-server.elasticsearchservicepreboot.md) | |
|
||||
| [ElasticsearchServiceSetup](./kibana-plugin-core-server.elasticsearchservicesetup.md) | |
|
||||
| [ElasticsearchServiceStart](./kibana-plugin-core-server.elasticsearchservicestart.md) | |
|
||||
|
|
|
@ -1,23 +0,0 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [SavedObjectsErrorHelpers](./kibana-plugin-core-server.savedobjectserrorhelpers.md) > [createGenericNotFoundEsUnavailableError](./kibana-plugin-core-server.savedobjectserrorhelpers.creategenericnotfoundesunavailableerror.md)
|
||||
|
||||
## SavedObjectsErrorHelpers.createGenericNotFoundEsUnavailableError() method
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
static createGenericNotFoundEsUnavailableError(type?: string | null, id?: string | null): DecoratedError;
|
||||
```
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| type | <code>string | null</code> | |
|
||||
| id | <code>string | null</code> | |
|
||||
|
||||
<b>Returns:</b>
|
||||
|
||||
`DecoratedError`
|
||||
|
|
@ -18,7 +18,6 @@ export declare class SavedObjectsErrorHelpers
|
|||
| [createBadRequestError(reason)](./kibana-plugin-core-server.savedobjectserrorhelpers.createbadrequesterror.md) | <code>static</code> | |
|
||||
| [createConflictError(type, id, reason)](./kibana-plugin-core-server.savedobjectserrorhelpers.createconflicterror.md) | <code>static</code> | |
|
||||
| [createGenericNotFoundError(type, id)](./kibana-plugin-core-server.savedobjectserrorhelpers.creategenericnotfounderror.md) | <code>static</code> | |
|
||||
| [createGenericNotFoundEsUnavailableError(type, id)](./kibana-plugin-core-server.savedobjectserrorhelpers.creategenericnotfoundesunavailableerror.md) | <code>static</code> | |
|
||||
| [createIndexAliasNotFoundError(alias)](./kibana-plugin-core-server.savedobjectserrorhelpers.createindexaliasnotfounderror.md) | <code>static</code> | |
|
||||
| [createInvalidVersionError(versionInput)](./kibana-plugin-core-server.savedobjectserrorhelpers.createinvalidversionerror.md) | <code>static</code> | |
|
||||
| [createTooManyRequestsError(type, id)](./kibana-plugin-core-server.savedobjectserrorhelpers.createtoomanyrequestserror.md) | <code>static</code> | |
|
||||
|
|
|
@ -100,7 +100,7 @@
|
|||
"@elastic/apm-rum-react": "^1.3.1",
|
||||
"@elastic/charts": "38.0.1",
|
||||
"@elastic/datemath": "link:bazel-bin/packages/elastic-datemath",
|
||||
"@elastic/elasticsearch": "npm:@elastic/elasticsearch-canary@^8.0.0-canary.21",
|
||||
"@elastic/elasticsearch": "npm:@elastic/elasticsearch-canary@^8.0.0-canary.35",
|
||||
"@elastic/ems-client": "7.16.0",
|
||||
"@elastic/eui": "40.0.0",
|
||||
"@elastic/filesaver": "1.1.2",
|
||||
|
|
|
@ -35,7 +35,7 @@ export async function cleanWriteTargets({
|
|||
wait_for_completion: false,
|
||||
});
|
||||
|
||||
const task = response.body.task;
|
||||
const task = response.task;
|
||||
|
||||
if (task) {
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
|
@ -45,13 +45,13 @@ export async function cleanWriteTargets({
|
|||
});
|
||||
|
||||
logger.debug(
|
||||
`Polled for task:\n${JSON.stringify(taskResponse.body, ['completed', 'error'], 2)}`
|
||||
`Polled for task:\n${JSON.stringify(taskResponse, ['completed', 'error'], 2)}`
|
||||
);
|
||||
|
||||
if (taskResponse.body.completed) {
|
||||
if (taskResponse.completed) {
|
||||
resolve();
|
||||
} else if (taskResponse.body.error) {
|
||||
reject(taskResponse.body.error);
|
||||
} else if (taskResponse.error) {
|
||||
reject(taskResponse.error);
|
||||
} else {
|
||||
setTimeout(pollForTaskCompletion, 2500);
|
||||
}
|
||||
|
|
|
@ -24,16 +24,15 @@ export async function getWriteTargets({
|
|||
]);
|
||||
|
||||
function getDataStreamName(filter: string) {
|
||||
return datastreamsResponse.body.data_streams.find((stream) => stream.name.includes(filter))
|
||||
?.name;
|
||||
return datastreamsResponse.data_streams.find((stream) => stream.name.includes(filter))?.name;
|
||||
}
|
||||
|
||||
function getAlias(filter: string) {
|
||||
return Object.keys(indicesResponse.body)
|
||||
return Object.keys(indicesResponse)
|
||||
.map((key) => {
|
||||
return {
|
||||
key,
|
||||
writeIndexAlias: Object.entries(indicesResponse.body[key].aliases).find(
|
||||
writeIndexAlias: Object.entries(indicesResponse[key].aliases).find(
|
||||
([_, alias]) => alias.is_write_index
|
||||
)?.[0],
|
||||
};
|
||||
|
|
|
@ -59,7 +59,7 @@ export function uploadEvents({
|
|||
)
|
||||
.then((results) => {
|
||||
const errors = results
|
||||
.flatMap((result) => result.body.items)
|
||||
.flatMap((result) => result.items)
|
||||
.filter((item) => !!item.index?.error)
|
||||
.map((item) => item.index?.error);
|
||||
|
||||
|
|
|
@ -11,7 +11,8 @@ import { mockLoadConfiguration } from './init_apm.test.mocks';
|
|||
import { initApm } from './init_apm';
|
||||
import apm from 'elastic-apm-node';
|
||||
|
||||
describe('initApm', () => {
|
||||
// TODO: unskip when https://github.com/elastic/kibana/issues/116109 is fixed
|
||||
describe.skip('initApm', () => {
|
||||
let apmAddFilterSpy: jest.SpyInstance;
|
||||
let apmStartSpy: jest.SpyInstance;
|
||||
let getConfig: jest.Mock;
|
||||
|
|
|
@ -14,6 +14,9 @@ export const initApm = (
|
|||
isDistributable: boolean,
|
||||
serviceName: string
|
||||
) => {
|
||||
// TODO: re-enabled when https://github.com/elastic/kibana/issues/116109 is fixed
|
||||
return;
|
||||
|
||||
const apmConfigLoader = loadConfiguration(argv, rootDir, isDistributable);
|
||||
const apmConfig = apmConfigLoader.getConfig(serviceName);
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import type { KibanaClient } from '@elastic/elasticsearch/api/kibana';
|
||||
import type { Client } from '@elastic/elasticsearch';
|
||||
import { ToolingLog } from '@kbn/dev-utils';
|
||||
import { KbnClient } from '@kbn/test';
|
||||
|
||||
|
@ -17,7 +17,7 @@ export async function emptyKibanaIndexAction({
|
|||
log,
|
||||
kbnClient,
|
||||
}: {
|
||||
client: KibanaClient;
|
||||
client: Client;
|
||||
log: ToolingLog;
|
||||
kbnClient: KbnClient;
|
||||
}) {
|
||||
|
|
|
@ -11,7 +11,7 @@ import { createReadStream } from 'fs';
|
|||
import { Readable } from 'stream';
|
||||
import { ToolingLog, REPO_ROOT } from '@kbn/dev-utils';
|
||||
import { KbnClient } from '@kbn/test';
|
||||
import type { KibanaClient } from '@elastic/elasticsearch/api/kibana';
|
||||
import type { Client } from '@elastic/elasticsearch';
|
||||
import { createPromiseFromStreams, concatStreamProviders } from '@kbn/utils';
|
||||
import { ES_CLIENT_HEADERS } from '../client_headers';
|
||||
|
||||
|
@ -47,7 +47,7 @@ export async function loadAction({
|
|||
inputDir: string;
|
||||
skipExisting: boolean;
|
||||
useCreate: boolean;
|
||||
client: KibanaClient;
|
||||
client: Client;
|
||||
log: ToolingLog;
|
||||
kbnClient: KbnClient;
|
||||
}) {
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
import { resolve, relative } from 'path';
|
||||
import { createWriteStream, mkdirSync } from 'fs';
|
||||
import { Readable, Writable } from 'stream';
|
||||
import type { KibanaClient } from '@elastic/elasticsearch/api/kibana';
|
||||
import type { Client } from '@elastic/elasticsearch';
|
||||
import { ToolingLog, REPO_ROOT } from '@kbn/dev-utils';
|
||||
import { createListStream, createPromiseFromStreams } from '@kbn/utils';
|
||||
|
||||
|
@ -31,7 +31,7 @@ export async function saveAction({
|
|||
}: {
|
||||
outputDir: string;
|
||||
indices: string | string[];
|
||||
client: KibanaClient;
|
||||
client: Client;
|
||||
log: ToolingLog;
|
||||
raw: boolean;
|
||||
query?: Record<string, any>;
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
import { resolve, relative } from 'path';
|
||||
import { createReadStream } from 'fs';
|
||||
import { Readable, Writable } from 'stream';
|
||||
import type { KibanaClient } from '@elastic/elasticsearch/api/kibana';
|
||||
import type { Client } from '@elastic/elasticsearch';
|
||||
import { ToolingLog, REPO_ROOT } from '@kbn/dev-utils';
|
||||
import { KbnClient } from '@kbn/test';
|
||||
import { createPromiseFromStreams } from '@kbn/utils';
|
||||
|
@ -31,7 +31,7 @@ export async function unloadAction({
|
|||
kbnClient,
|
||||
}: {
|
||||
inputDir: string;
|
||||
client: KibanaClient;
|
||||
client: Client;
|
||||
log: ToolingLog;
|
||||
kbnClient: KbnClient;
|
||||
}) {
|
||||
|
|
|
@ -19,7 +19,7 @@ import Fs from 'fs';
|
|||
|
||||
import { RunWithCommands, createFlagError, CA_CERT_PATH } from '@kbn/dev-utils';
|
||||
import { readConfigFile, KbnClient } from '@kbn/test';
|
||||
import { Client } from '@elastic/elasticsearch';
|
||||
import { Client, HttpConnection } from '@elastic/elasticsearch';
|
||||
|
||||
import { EsArchiver } from './es_archiver';
|
||||
|
||||
|
@ -106,7 +106,8 @@ export function runCli() {
|
|||
|
||||
const client = new Client({
|
||||
node: esUrl,
|
||||
ssl: esCa ? { ca: esCa } : undefined,
|
||||
tls: esCa ? { ca: esCa } : undefined,
|
||||
Connection: HttpConnection,
|
||||
});
|
||||
addCleanupTask(() => client.close());
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
import Fs from 'fs';
|
||||
import Path from 'path';
|
||||
|
||||
import type { KibanaClient } from '@elastic/elasticsearch/api/kibana';
|
||||
import type { Client } from '@elastic/elasticsearch';
|
||||
import { ToolingLog, REPO_ROOT } from '@kbn/dev-utils';
|
||||
import { KbnClient } from '@kbn/test';
|
||||
|
||||
|
@ -23,14 +23,14 @@ import {
|
|||
} from './actions';
|
||||
|
||||
interface Options {
|
||||
client: KibanaClient;
|
||||
client: Client;
|
||||
baseDir?: string;
|
||||
log: ToolingLog;
|
||||
kbnClient: KbnClient;
|
||||
}
|
||||
|
||||
export class EsArchiver {
|
||||
private readonly client: KibanaClient;
|
||||
private readonly client: Client;
|
||||
private readonly baseDir: string;
|
||||
private readonly log: ToolingLog;
|
||||
private readonly kbnClient: KbnClient;
|
||||
|
|
|
@ -99,10 +99,8 @@ it('transforms each input index to a stream of docs using scrollSearch helper',
|
|||
Array [
|
||||
Object {
|
||||
"_source": "true",
|
||||
"body": Object {
|
||||
"query": undefined,
|
||||
},
|
||||
"index": "bar",
|
||||
"query": undefined,
|
||||
"rest_total_hits_as_int": true,
|
||||
"scroll": "1m",
|
||||
"size": 1000,
|
||||
|
@ -116,10 +114,8 @@ it('transforms each input index to a stream of docs using scrollSearch helper',
|
|||
Array [
|
||||
Object {
|
||||
"_source": "true",
|
||||
"body": Object {
|
||||
"query": undefined,
|
||||
},
|
||||
"index": "foo",
|
||||
"query": undefined,
|
||||
"rest_total_hits_as_int": true,
|
||||
"scroll": "1m",
|
||||
"size": 1000,
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
*/
|
||||
|
||||
import { Transform } from 'stream';
|
||||
import type { KibanaClient } from '@elastic/elasticsearch/api/kibana';
|
||||
import type { Client } from '@elastic/elasticsearch';
|
||||
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: KibanaClient;
|
||||
client: Client;
|
||||
stats: Stats;
|
||||
progress: Progress;
|
||||
query?: Record<string, any>;
|
||||
|
@ -37,9 +37,7 @@ export function createGenerateDocRecordsStream({
|
|||
scroll: SCROLL_TIMEOUT,
|
||||
size: SCROLL_SIZE,
|
||||
_source: 'true',
|
||||
body: {
|
||||
query,
|
||||
},
|
||||
query,
|
||||
rest_total_hits_as_int: true,
|
||||
},
|
||||
{
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import type { KibanaClient } from '@elastic/elasticsearch/api/kibana';
|
||||
import type { Client } from '@elastic/elasticsearch';
|
||||
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: KibanaClient,
|
||||
client: Client,
|
||||
stats: Stats,
|
||||
progress: Progress,
|
||||
useCreate: boolean = false
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import type { KibanaClient } from '@elastic/elasticsearch/api/kibana';
|
||||
import type { Client } from '@elastic/elasticsearch';
|
||||
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 = KibanaClient;
|
||||
type StubClient = Client;
|
||||
|
||||
export const createStubClient = (
|
||||
existingIndices: string[] = [],
|
||||
|
|
|
@ -71,6 +71,7 @@ describe('esArchiver: createCreateIndexStream()', () => {
|
|||
"ignore": Array [
|
||||
404,
|
||||
],
|
||||
"meta": true,
|
||||
},
|
||||
],
|
||||
]
|
||||
|
|
|
@ -9,8 +9,8 @@
|
|||
import { Transform, Readable } from 'stream';
|
||||
import { inspect } from 'util';
|
||||
|
||||
import { estypes } from '@elastic/elasticsearch';
|
||||
import type { KibanaClient } from '@elastic/elasticsearch/api/kibana';
|
||||
import * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey';
|
||||
import type { Client } from '@elastic/elasticsearch';
|
||||
import { ToolingLog } from '@kbn/dev-utils';
|
||||
|
||||
import { Stats } from '../stats';
|
||||
|
@ -31,7 +31,7 @@ export function createCreateIndexStream({
|
|||
skipExisting = false,
|
||||
log,
|
||||
}: {
|
||||
client: KibanaClient;
|
||||
client: Client;
|
||||
stats: Stats;
|
||||
skipExisting?: boolean;
|
||||
log: ToolingLog;
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import type { KibanaClient } from '@elastic/elasticsearch/api/kibana';
|
||||
import type { Client } from '@elastic/elasticsearch';
|
||||
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: KibanaClient;
|
||||
client: Client;
|
||||
stats: Stats;
|
||||
index: string | string[];
|
||||
log: ToolingLog;
|
||||
|
@ -32,6 +32,7 @@ export async function deleteIndex(options: {
|
|||
{
|
||||
ignore: [404],
|
||||
headers: ES_CLIENT_HEADERS,
|
||||
meta: true,
|
||||
}
|
||||
);
|
||||
|
||||
|
@ -84,15 +85,13 @@ export function isDeleteWhileSnapshotInProgressError(error: any) {
|
|||
* snapshotting this index to complete.
|
||||
*/
|
||||
export async function waitForSnapshotCompletion(
|
||||
client: KibanaClient,
|
||||
client: Client,
|
||||
index: string | string[],
|
||||
log: ToolingLog
|
||||
) {
|
||||
const isSnapshotPending = async (repository: string, snapshot: string) => {
|
||||
const {
|
||||
body: {
|
||||
snapshots: [status],
|
||||
},
|
||||
snapshots: [status],
|
||||
} = await client.snapshot.status(
|
||||
{
|
||||
repository,
|
||||
|
@ -108,9 +107,7 @@ export async function waitForSnapshotCompletion(
|
|||
};
|
||||
|
||||
const getInProgressSnapshots = async (repository: string) => {
|
||||
const {
|
||||
body: { snapshots: inProgressSnapshots },
|
||||
} = await client.snapshot.get(
|
||||
const { snapshots: inProgressSnapshots } = await client.snapshot.get(
|
||||
{
|
||||
repository,
|
||||
snapshot: '_current',
|
||||
|
@ -123,7 +120,7 @@ export async function waitForSnapshotCompletion(
|
|||
return inProgressSnapshots;
|
||||
};
|
||||
|
||||
const { body: repositoryMap } = await client.snapshot.getRepository({} as any);
|
||||
const repositoryMap = await client.snapshot.getRepository({});
|
||||
for (const repository of Object.keys(repositoryMap)) {
|
||||
const allInProgress = await getInProgressSnapshots(repository);
|
||||
const found = allInProgress?.find((s: any) => s.indices.includes(index));
|
||||
|
|
|
@ -7,14 +7,14 @@
|
|||
*/
|
||||
|
||||
import { Transform } from 'stream';
|
||||
import type { KibanaClient } from '@elastic/elasticsearch/api/kibana';
|
||||
import type { Client } from '@elastic/elasticsearch';
|
||||
import { ToolingLog } from '@kbn/dev-utils';
|
||||
|
||||
import { Stats } from '../stats';
|
||||
import { deleteIndex } from './delete_index';
|
||||
import { cleanKibanaIndices } from './kibana_index';
|
||||
|
||||
export function createDeleteIndexStream(client: KibanaClient, stats: Stats, log: ToolingLog) {
|
||||
export function createDeleteIndexStream(client: Client, stats: Stats, log: ToolingLog) {
|
||||
return new Transform({
|
||||
readableObjectMode: true,
|
||||
writableObjectMode: true,
|
||||
|
|
|
@ -6,12 +6,12 @@
|
|||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import type { Client } from '@elastic/elasticsearch';
|
||||
import { Transform } from 'stream';
|
||||
import type { KibanaClient } from '@elastic/elasticsearch/api/kibana';
|
||||
import { Stats } from '../stats';
|
||||
import { ES_CLIENT_HEADERS } from '../../client_headers';
|
||||
|
||||
export function createGenerateIndexRecordsStream(client: KibanaClient, stats: Stats) {
|
||||
export function createGenerateIndexRecordsStream(client: Client, stats: Stats) {
|
||||
return new Transform({
|
||||
writableObjectMode: true,
|
||||
readableObjectMode: true,
|
||||
|
@ -37,9 +37,10 @@ export function createGenerateIndexRecordsStream(client: KibanaClient, stats: St
|
|||
},
|
||||
{
|
||||
headers: ES_CLIENT_HEADERS,
|
||||
meta: true,
|
||||
}
|
||||
)
|
||||
).body as Record<string, any>;
|
||||
).body;
|
||||
|
||||
for (const [index, { settings, mappings }] of Object.entries(resp)) {
|
||||
const {
|
||||
|
@ -50,6 +51,7 @@ export function createGenerateIndexRecordsStream(client: KibanaClient, stats: St
|
|||
{ index },
|
||||
{
|
||||
headers: ES_CLIENT_HEADERS,
|
||||
meta: true,
|
||||
}
|
||||
);
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
|
||||
import { inspect } from 'util';
|
||||
|
||||
import type { KibanaClient } from '@elastic/elasticsearch/api/kibana';
|
||||
import type { Client } from '@elastic/elasticsearch';
|
||||
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: KibanaClient;
|
||||
client: Client;
|
||||
stats: Stats;
|
||||
log: ToolingLog;
|
||||
}) {
|
||||
|
@ -35,7 +35,7 @@ export async function deleteKibanaIndices({
|
|||
await client.indices.putSettings(
|
||||
{
|
||||
index: indexNames,
|
||||
body: { settings: { blocks: { read_only: false } } },
|
||||
body: { blocks: { read_only: false } },
|
||||
},
|
||||
{
|
||||
headers: ES_CLIENT_HEADERS,
|
||||
|
@ -75,7 +75,7 @@ function isKibanaIndex(index?: string): index is string {
|
|||
);
|
||||
}
|
||||
|
||||
async function fetchKibanaIndices(client: KibanaClient) {
|
||||
async function fetchKibanaIndices(client: Client) {
|
||||
const resp = await client.cat.indices(
|
||||
{ index: '.kibana*', format: 'json' },
|
||||
{
|
||||
|
@ -83,11 +83,11 @@ async function fetchKibanaIndices(client: KibanaClient) {
|
|||
}
|
||||
);
|
||||
|
||||
if (!Array.isArray(resp.body)) {
|
||||
throw new Error(`expected response to be an array ${inspect(resp.body)}`);
|
||||
if (!Array.isArray(resp)) {
|
||||
throw new Error(`expected response to be an array ${inspect(resp)}`);
|
||||
}
|
||||
|
||||
return resp.body.map((x: { index?: string }) => x.index).filter(isKibanaIndex);
|
||||
return resp.map((x: { index?: string }) => x.index).filter(isKibanaIndex);
|
||||
}
|
||||
|
||||
const delay = (delayInMs: number) => new Promise((resolve) => setTimeout(resolve, delayInMs));
|
||||
|
@ -97,7 +97,7 @@ export async function cleanKibanaIndices({
|
|||
stats,
|
||||
log,
|
||||
}: {
|
||||
client: KibanaClient;
|
||||
client: Client;
|
||||
stats: Stats;
|
||||
log: ToolingLog;
|
||||
}) {
|
||||
|
@ -123,11 +123,11 @@ export async function cleanKibanaIndices({
|
|||
}
|
||||
);
|
||||
|
||||
if (resp.body.total !== resp.body.deleted) {
|
||||
if (resp.total !== resp.deleted) {
|
||||
log.warning(
|
||||
'delete by query deleted %d of %d total documents, trying again',
|
||||
resp.body.deleted,
|
||||
resp.body.total
|
||||
resp.deleted,
|
||||
resp.total
|
||||
);
|
||||
await delay(200);
|
||||
continue;
|
||||
|
@ -144,13 +144,7 @@ export async function cleanKibanaIndices({
|
|||
stats.deletedIndex('.kibana');
|
||||
}
|
||||
|
||||
export async function createDefaultSpace({
|
||||
index,
|
||||
client,
|
||||
}: {
|
||||
index: string;
|
||||
client: KibanaClient;
|
||||
}) {
|
||||
export async function createDefaultSpace({ index, client }: { index: string; client: Client }) {
|
||||
await client.create(
|
||||
{
|
||||
index,
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { estypes } from '@elastic/elasticsearch';
|
||||
import * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey';
|
||||
import { SerializableRecord } from '@kbn/utility-types';
|
||||
import { extend, defaults } from 'lodash';
|
||||
import { getTimeZoneFromSettings } from '../utils';
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
*/
|
||||
|
||||
import { isUndefined } from 'lodash';
|
||||
import { estypes } from '@elastic/elasticsearch';
|
||||
import * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey';
|
||||
import { migrateFilter } from './migrate_filter';
|
||||
import { filterMatchesIndex } from './filter_matches_index';
|
||||
import { Filter, cleanFilter, isFilterDisabled } from '../filters';
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { estypes } from '@elastic/elasticsearch';
|
||||
import * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey';
|
||||
import { isString } from 'lodash';
|
||||
|
||||
/**
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import type { estypes } from '@elastic/elasticsearch';
|
||||
import * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey';
|
||||
|
||||
/**
|
||||
* A field's sub type
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { estypes } from '@elastic/elasticsearch';
|
||||
import * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey';
|
||||
import { Filter, FilterMeta, FILTERS, FilterStateStore } from './types';
|
||||
|
||||
/** @public */
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { estypes } from '@elastic/elasticsearch';
|
||||
import * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey';
|
||||
import { has } from 'lodash';
|
||||
import type { Filter, FilterMeta } from './types';
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ import {
|
|||
} from './phrase_filter';
|
||||
import { fields, getField } from '../stubs';
|
||||
import { DataViewBase } from '../../es_query';
|
||||
import { estypes } from '@elastic/elasticsearch';
|
||||
import * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey';
|
||||
|
||||
describe('Phrase filter builder', () => {
|
||||
let indexPattern: DataViewBase;
|
||||
|
|
|
@ -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 * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey';
|
||||
import { get, has, isPlainObject } from 'lodash';
|
||||
import type { Filter, FilterMeta } from './types';
|
||||
import type { IndexPatternFieldBase, IndexPatternBase } from '../../es_query';
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { estypes } from '@elastic/elasticsearch';
|
||||
import * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey';
|
||||
import { Filter, FilterMeta, FILTERS } from './types';
|
||||
import { getPhraseScript, PhraseFilterValue } from './phrase_filter';
|
||||
import type { IndexPatternFieldBase, IndexPatternBase } from '../../es_query';
|
||||
|
|
|
@ -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 * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey';
|
||||
import { map, reduce, mapValues, has, get, keys, pickBy } from 'lodash';
|
||||
import type { Filter, FilterMeta } from './types';
|
||||
import type { IndexPatternBase, IndexPatternFieldBase } from '../../es_query';
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
*/
|
||||
|
||||
import { JsonObject } from '@kbn/utility-types';
|
||||
import { estypes } from '@elastic/elasticsearch';
|
||||
import * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey';
|
||||
import { nodeTypes } from '../node_types/index';
|
||||
import { KQLSyntaxError } from '../kuery_syntax_error';
|
||||
import { KueryNode, KueryParseOptions, KueryQueryOptions } from '../types';
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { estypes } from '@elastic/elasticsearch';
|
||||
import * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey';
|
||||
import { IndexPatternFieldBase, IndexPatternBase, KueryNode, KueryQueryOptions } from '../..';
|
||||
import * as literal from '../node_types/literal';
|
||||
|
||||
|
|
|
@ -109,7 +109,6 @@ describe('kuery functions', () => {
|
|||
const node = nodeTypes.function.buildNode('geoBoundingBox', 'geo', params);
|
||||
const result = geoBoundingBox.toElasticsearchQuery(node, indexPattern);
|
||||
|
||||
// @ts-expect-error @elastic/elasticsearch doesn't support ignore_unmapped in QueryDslGeoBoundingBoxQuery
|
||||
expect(result.geo_bounding_box!.ignore_unmapped).toBe(true);
|
||||
});
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
*/
|
||||
|
||||
import _ from 'lodash';
|
||||
import { estypes } from '@elastic/elasticsearch';
|
||||
import * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey';
|
||||
import { nodeTypes } from '../node_types';
|
||||
import * as ast from '../ast';
|
||||
import { IndexPatternBase, KueryNode, KueryQueryOptions, LatLon } from '../..';
|
||||
|
@ -53,7 +53,6 @@ export function toElasticsearchQuery(
|
|||
}
|
||||
|
||||
return {
|
||||
// @ts-expect-error @elastic/elasticsearch doesn't support ignore_unmapped in QueryDslGeoBoundingBoxQuery
|
||||
geo_bounding_box: {
|
||||
[fieldName]: queryParams,
|
||||
ignore_unmapped: true,
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { estypes } from '@elastic/elasticsearch';
|
||||
import * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey';
|
||||
import { nodeTypes } from '../node_types';
|
||||
import * as ast from '../ast';
|
||||
import { IndexPatternBase, KueryNode, KueryQueryOptions, LatLon } from '../..';
|
||||
|
@ -49,7 +49,6 @@ export function toElasticsearchQuery(
|
|||
}
|
||||
|
||||
return {
|
||||
// @ts-expect-error @elastic/elasticsearch doesn't support ignore_unmapped in QueryDslGeoPolygonQuery
|
||||
geo_polygon: {
|
||||
[fieldName]: queryParams,
|
||||
ignore_unmapped: true,
|
||||
|
|
|
@ -11,7 +11,7 @@ import { fields } from '../../filters/stubs';
|
|||
|
||||
import * as is from './is';
|
||||
import { DataViewBase } from '../..';
|
||||
import { estypes } from '@elastic/elasticsearch';
|
||||
import * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey';
|
||||
|
||||
jest.mock('../grammar');
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
*/
|
||||
|
||||
import { isUndefined } from 'lodash';
|
||||
import { estypes } from '@elastic/elasticsearch';
|
||||
import * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey';
|
||||
import { getPhraseScript } from '../../filters';
|
||||
import { getFields } from './utils/get_fields';
|
||||
import { getTimeZoneFromSettings, getDataViewFieldSubtypeNested } from '../../utils';
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { estypes } from '@elastic/elasticsearch';
|
||||
import * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey';
|
||||
import * as ast from '../ast';
|
||||
import * as literal from '../node_types/literal';
|
||||
import { IndexPatternBase, KueryNode, KueryQueryOptions } from '../..';
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { estypes } from '@elastic/elasticsearch';
|
||||
import * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey';
|
||||
import * as ast from '../ast';
|
||||
import { IndexPatternBase, KueryNode, KueryQueryOptions } from '../..';
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { estypes } from '@elastic/elasticsearch';
|
||||
import * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey';
|
||||
import * as ast from '../ast';
|
||||
import { IndexPatternBase, KueryNode, KueryQueryOptions } from '../..';
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@ import { DataViewBase } from '../..';
|
|||
import { RangeFilterParams } from '../../filters';
|
||||
|
||||
import * as range from './range';
|
||||
import { estypes } from '@elastic/elasticsearch';
|
||||
import * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey';
|
||||
jest.mock('../grammar');
|
||||
|
||||
describe('kuery functions', () => {
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
*/
|
||||
|
||||
import { pick, map, mapValues } from 'lodash';
|
||||
import { estypes } from '@elastic/elasticsearch';
|
||||
import * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey';
|
||||
import { nodeTypes } from '../node_types';
|
||||
import * as ast from '../ast';
|
||||
import { getRangeScript, RangeFilterParams } from '../../filters';
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { estypes } from '@elastic/elasticsearch';
|
||||
import * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey';
|
||||
import { toElasticsearchQuery as astToElasticsearchQuery } from './ast';
|
||||
|
||||
/**
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { estypes } from '@elastic/elasticsearch';
|
||||
import * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey';
|
||||
import { SerializableRecord } from '@kbn/utility-types';
|
||||
import { NodeTypes } from './node_types';
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@ exports.NativeRealm = class NativeRealm {
|
|||
const auth = { username: 'elastic', password: elasticPassword };
|
||||
this._client = new Client(
|
||||
ssl
|
||||
? { node: `https://localhost:${port}`, ssl: { ca: caCert, rejectUnauthorized: true }, auth }
|
||||
? { node: `https://localhost:${port}`, tls: { ca: caCert, rejectUnauthorized: true }, auth }
|
||||
: { node: `http://localhost:${port}`, auth }
|
||||
);
|
||||
this._elasticPassword = elasticPassword;
|
||||
|
@ -67,9 +67,7 @@ exports.NativeRealm = class NativeRealm {
|
|||
async getReservedUsers(retryOpts = {}) {
|
||||
return await this._autoRetry(retryOpts, async () => {
|
||||
const resp = await this._client.security.getUser();
|
||||
const usernames = Object.keys(resp.body).filter(
|
||||
(user) => resp.body[user].metadata._reserved === true
|
||||
);
|
||||
const usernames = Object.keys(resp).filter((user) => resp[user].metadata._reserved === true);
|
||||
|
||||
if (!usernames?.length) {
|
||||
throw new Error('no reserved users found, unable to set native realm passwords');
|
||||
|
@ -82,9 +80,7 @@ exports.NativeRealm = class NativeRealm {
|
|||
async isSecurityEnabled(retryOpts = {}) {
|
||||
try {
|
||||
return await this._autoRetry(retryOpts, async () => {
|
||||
const {
|
||||
body: { features },
|
||||
} = await this._client.xpack.info({ categories: 'features' });
|
||||
const { features } = await this._client.xpack.info({ categories: 'features' });
|
||||
return features.security && features.security.enabled && features.security.available;
|
||||
});
|
||||
} catch (error) {
|
||||
|
|
|
@ -38,12 +38,10 @@ afterAll(() => {
|
|||
|
||||
function mockXPackInfo(available, enabled) {
|
||||
mockClient.xpack.info.mockImplementation(() => ({
|
||||
body: {
|
||||
features: {
|
||||
security: {
|
||||
available,
|
||||
enabled,
|
||||
},
|
||||
features: {
|
||||
security: {
|
||||
available,
|
||||
enabled,
|
||||
},
|
||||
},
|
||||
}));
|
||||
|
@ -97,31 +95,29 @@ describe('setPasswords', () => {
|
|||
mockXPackInfo(true, true);
|
||||
|
||||
mockClient.security.getUser.mockImplementation(() => ({
|
||||
body: {
|
||||
kibana_system: {
|
||||
metadata: {
|
||||
_reserved: true,
|
||||
},
|
||||
kibana_system: {
|
||||
metadata: {
|
||||
_reserved: true,
|
||||
},
|
||||
non_native: {
|
||||
metadata: {
|
||||
_reserved: false,
|
||||
},
|
||||
},
|
||||
non_native: {
|
||||
metadata: {
|
||||
_reserved: false,
|
||||
},
|
||||
logstash_system: {
|
||||
metadata: {
|
||||
_reserved: true,
|
||||
},
|
||||
},
|
||||
logstash_system: {
|
||||
metadata: {
|
||||
_reserved: true,
|
||||
},
|
||||
elastic: {
|
||||
metadata: {
|
||||
_reserved: true,
|
||||
},
|
||||
},
|
||||
elastic: {
|
||||
metadata: {
|
||||
_reserved: true,
|
||||
},
|
||||
beats_system: {
|
||||
metadata: {
|
||||
_reserved: true,
|
||||
},
|
||||
},
|
||||
beats_system: {
|
||||
metadata: {
|
||||
_reserved: true,
|
||||
},
|
||||
},
|
||||
}));
|
||||
|
@ -176,21 +172,19 @@ Array [
|
|||
describe('getReservedUsers', () => {
|
||||
it('returns array of reserved usernames', async () => {
|
||||
mockClient.security.getUser.mockImplementation(() => ({
|
||||
body: {
|
||||
kibana_system: {
|
||||
metadata: {
|
||||
_reserved: true,
|
||||
},
|
||||
kibana_system: {
|
||||
metadata: {
|
||||
_reserved: true,
|
||||
},
|
||||
non_native: {
|
||||
metadata: {
|
||||
_reserved: false,
|
||||
},
|
||||
},
|
||||
non_native: {
|
||||
metadata: {
|
||||
_reserved: false,
|
||||
},
|
||||
logstash_system: {
|
||||
metadata: {
|
||||
_reserved: true,
|
||||
},
|
||||
},
|
||||
logstash_system: {
|
||||
metadata: {
|
||||
_reserved: true,
|
||||
},
|
||||
},
|
||||
}));
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import type { estypes } from '@elastic/elasticsearch';
|
||||
import * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey';
|
||||
import type { EsQueryConfig } from '@kbn/es-query';
|
||||
|
||||
/**
|
||||
|
|
|
@ -16,15 +16,18 @@ export const createBootstrapIndex = async (
|
|||
index: string
|
||||
): Promise<unknown> => {
|
||||
return (
|
||||
await esClient.indices.create({
|
||||
index: `${index}-000001`,
|
||||
body: {
|
||||
aliases: {
|
||||
[index]: {
|
||||
is_write_index: true,
|
||||
await esClient.indices.create(
|
||||
{
|
||||
index: `${index}-000001`,
|
||||
body: {
|
||||
aliases: {
|
||||
[index]: {
|
||||
is_write_index: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
{ meta: true }
|
||||
)
|
||||
).body;
|
||||
};
|
||||
|
|
|
@ -23,8 +23,8 @@ export const decodeVersion = (
|
|||
const parsed = JSON.parse(decoded);
|
||||
if (Array.isArray(parsed) && Number.isInteger(parsed[0]) && Number.isInteger(parsed[1])) {
|
||||
return {
|
||||
ifPrimaryTerm: parsed[1],
|
||||
ifSeqNo: parsed[0],
|
||||
if_primary_term: parsed[1],
|
||||
if_seq_no: parsed[0],
|
||||
};
|
||||
} else {
|
||||
return {};
|
||||
|
|
|
@ -25,7 +25,7 @@ export const deleteAllIndex = async (
|
|||
{
|
||||
index: pattern,
|
||||
},
|
||||
{ ignore: [404] }
|
||||
{ ignore: [404], meta: true }
|
||||
);
|
||||
|
||||
// @ts-expect-error status doesn't exist on response
|
||||
|
|
|
@ -10,10 +10,7 @@ import type { ElasticsearchClient } from '../elasticsearch_client';
|
|||
|
||||
export const deletePolicy = async (
|
||||
esClient: ElasticsearchClient,
|
||||
policy: string
|
||||
name: string
|
||||
): Promise<unknown> => {
|
||||
return (
|
||||
// @ts-expect-error policy_id is required by mistake. fixed in the v8.0
|
||||
(await esClient.ilm.deleteLifecycle({ policy })).body
|
||||
);
|
||||
return (await esClient.ilm.deleteLifecycle({ name }, { meta: true })).body;
|
||||
};
|
||||
|
|
|
@ -13,8 +13,11 @@ export const deleteTemplate = async (
|
|||
name: string
|
||||
): Promise<unknown> => {
|
||||
return (
|
||||
await esClient.indices.deleteTemplate({
|
||||
name,
|
||||
})
|
||||
await esClient.indices.deleteTemplate(
|
||||
{
|
||||
name,
|
||||
},
|
||||
{ meta: true }
|
||||
)
|
||||
).body;
|
||||
};
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
// Copied from src/core/server/elasticsearch/client/types.ts
|
||||
// as these types aren't part of any package yet. Once they are, remove this completely
|
||||
|
||||
import type { KibanaClient } from '@elastic/elasticsearch/api/kibana';
|
||||
import type { KibanaClient } from '@elastic/elasticsearch/lib/api/kibana';
|
||||
|
||||
/**
|
||||
* Client used to query the elasticsearch cluster.
|
||||
|
@ -18,5 +18,5 @@ import type { KibanaClient } from '@elastic/elasticsearch/api/kibana';
|
|||
*/
|
||||
export type ElasticsearchClient = Omit<
|
||||
KibanaClient,
|
||||
'connectionPool' | 'transport' | 'serializer' | 'extend' | 'child' | 'close'
|
||||
'connectionPool' | 'transport' | 'serializer' | 'extend' | 'child' | 'close' | 'diagnostic'
|
||||
>;
|
||||
|
|
|
@ -39,9 +39,12 @@ export const getIndexAliases = async ({
|
|||
esClient: ElasticsearchClient;
|
||||
alias: string;
|
||||
}): Promise<IndexAlias[]> => {
|
||||
const response = await esClient.indices.getAlias<AliasesResponse>({
|
||||
name: alias,
|
||||
});
|
||||
const response = await esClient.indices.getAlias<AliasesResponse>(
|
||||
{
|
||||
name: alias,
|
||||
},
|
||||
{ meta: true }
|
||||
);
|
||||
|
||||
return Object.keys(response.body).map((index) => ({
|
||||
alias,
|
||||
|
|
|
@ -23,9 +23,12 @@ export const getIndexCount = async ({
|
|||
esClient: ElasticsearchClient;
|
||||
index: string;
|
||||
}): Promise<number> => {
|
||||
const response = await esClient.count<{ count: number }>({
|
||||
index,
|
||||
});
|
||||
const response = await esClient.count<{ count: number }>(
|
||||
{
|
||||
index,
|
||||
},
|
||||
{ meta: true }
|
||||
);
|
||||
|
||||
return response.body.count;
|
||||
};
|
||||
|
|
|
@ -13,14 +13,17 @@ export const getIndexExists = async (
|
|||
index: string
|
||||
): Promise<boolean> => {
|
||||
try {
|
||||
const { body: response } = await esClient.search({
|
||||
index,
|
||||
size: 0,
|
||||
allow_no_indices: true,
|
||||
body: {
|
||||
terminate_after: 1,
|
||||
const { body: response } = await esClient.search(
|
||||
{
|
||||
index,
|
||||
size: 0,
|
||||
allow_no_indices: true,
|
||||
body: {
|
||||
terminate_after: 1,
|
||||
},
|
||||
},
|
||||
});
|
||||
{ meta: true }
|
||||
);
|
||||
return response._shards.total > 0;
|
||||
} catch (err) {
|
||||
if (err.body != null && err.body.status === 404) {
|
||||
|
|
|
@ -9,11 +9,11 @@ import type { ElasticsearchClient } from '../elasticsearch_client';
|
|||
|
||||
export const getPolicyExists = async (
|
||||
esClient: ElasticsearchClient,
|
||||
policy: string
|
||||
name: string
|
||||
): Promise<boolean> => {
|
||||
try {
|
||||
await esClient.ilm.getLifecycle({
|
||||
policy,
|
||||
name,
|
||||
});
|
||||
// Return true that there exists a policy which is not 404 or some error
|
||||
// Since there is not a policy exists API, this is how we create one by calling
|
||||
|
|
|
@ -13,8 +13,11 @@ export const getTemplateExists = async (
|
|||
template: string
|
||||
): Promise<boolean> => {
|
||||
return (
|
||||
await esClient.indices.existsTemplate({
|
||||
name: template,
|
||||
})
|
||||
await esClient.indices.existsTemplate(
|
||||
{
|
||||
name: template,
|
||||
},
|
||||
{ meta: true }
|
||||
)
|
||||
).body;
|
||||
};
|
||||
|
|
|
@ -9,7 +9,10 @@
|
|||
import type { ElasticsearchClient } from '../elasticsearch_client';
|
||||
|
||||
export const readIndex = async (esClient: ElasticsearchClient, index: string): Promise<unknown> => {
|
||||
return esClient.indices.get({
|
||||
index,
|
||||
});
|
||||
return esClient.indices.get(
|
||||
{
|
||||
index,
|
||||
},
|
||||
{ meta: true }
|
||||
);
|
||||
};
|
||||
|
|
|
@ -13,60 +13,63 @@ export const readPrivileges = async (
|
|||
index: string
|
||||
): Promise<unknown> => {
|
||||
return (
|
||||
await esClient.security.hasPrivileges({
|
||||
body: {
|
||||
cluster: [
|
||||
'all',
|
||||
'create_snapshot',
|
||||
'manage',
|
||||
'manage_api_key',
|
||||
'manage_ccr',
|
||||
'manage_transform',
|
||||
'manage_ilm',
|
||||
'manage_index_templates',
|
||||
'manage_ingest_pipelines',
|
||||
'manage_ml',
|
||||
'manage_own_api_key',
|
||||
'manage_pipeline',
|
||||
'manage_rollup',
|
||||
'manage_saml',
|
||||
'manage_security',
|
||||
'manage_token',
|
||||
'manage_watcher',
|
||||
'monitor',
|
||||
'monitor_transform',
|
||||
'monitor_ml',
|
||||
'monitor_rollup',
|
||||
'monitor_watcher',
|
||||
'read_ccr',
|
||||
'read_ilm',
|
||||
'transport_client',
|
||||
],
|
||||
index: [
|
||||
{
|
||||
names: [index],
|
||||
privileges: [
|
||||
'all',
|
||||
'create',
|
||||
'create_doc',
|
||||
'create_index',
|
||||
'delete',
|
||||
'delete_index',
|
||||
'index',
|
||||
'manage',
|
||||
'maintenance',
|
||||
'manage_follow_index',
|
||||
'manage_ilm',
|
||||
'manage_leader_index',
|
||||
'monitor',
|
||||
'read',
|
||||
'read_cross_cluster',
|
||||
'view_index_metadata',
|
||||
'write',
|
||||
],
|
||||
},
|
||||
],
|
||||
await esClient.security.hasPrivileges(
|
||||
{
|
||||
body: {
|
||||
cluster: [
|
||||
'all',
|
||||
'create_snapshot',
|
||||
'manage',
|
||||
'manage_api_key',
|
||||
'manage_ccr',
|
||||
'manage_transform',
|
||||
'manage_ilm',
|
||||
'manage_index_templates',
|
||||
'manage_ingest_pipelines',
|
||||
'manage_ml',
|
||||
'manage_own_api_key',
|
||||
'manage_pipeline',
|
||||
'manage_rollup',
|
||||
'manage_saml',
|
||||
'manage_security',
|
||||
'manage_token',
|
||||
'manage_watcher',
|
||||
'monitor',
|
||||
'monitor_transform',
|
||||
'monitor_ml',
|
||||
'monitor_rollup',
|
||||
'monitor_watcher',
|
||||
'read_ccr',
|
||||
'read_ilm',
|
||||
'transport_client',
|
||||
],
|
||||
index: [
|
||||
{
|
||||
names: [index],
|
||||
privileges: [
|
||||
'all',
|
||||
'create',
|
||||
'create_doc',
|
||||
'create_index',
|
||||
'delete',
|
||||
'delete_index',
|
||||
'index',
|
||||
'manage',
|
||||
'maintenance',
|
||||
'manage_follow_index',
|
||||
'manage_ilm',
|
||||
'manage_leader_index',
|
||||
'monitor',
|
||||
'read',
|
||||
'read_cross_cluster',
|
||||
'view_index_metadata',
|
||||
'write',
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
})
|
||||
{ meta: true }
|
||||
)
|
||||
).body;
|
||||
};
|
||||
|
|
|
@ -9,13 +9,16 @@ import type { ElasticsearchClient } from '../elasticsearch_client';
|
|||
|
||||
export const setPolicy = async (
|
||||
esClient: ElasticsearchClient,
|
||||
policy: string,
|
||||
name: string,
|
||||
body: Record<string, unknown>
|
||||
): Promise<unknown> => {
|
||||
return (
|
||||
await esClient.ilm.putLifecycle({
|
||||
policy,
|
||||
body,
|
||||
})
|
||||
await esClient.ilm.putLifecycle(
|
||||
{
|
||||
name,
|
||||
body,
|
||||
},
|
||||
{ meta: true }
|
||||
)
|
||||
).body;
|
||||
};
|
||||
|
|
|
@ -14,9 +14,12 @@ export const setTemplate = async (
|
|||
body: Record<string, unknown>
|
||||
): Promise<unknown> => {
|
||||
return (
|
||||
await esClient.indices.putTemplate({
|
||||
name,
|
||||
body,
|
||||
})
|
||||
await esClient.indices.putTemplate(
|
||||
{
|
||||
name,
|
||||
body,
|
||||
},
|
||||
{ meta: true }
|
||||
)
|
||||
).body;
|
||||
};
|
||||
|
|
|
@ -23,7 +23,7 @@ import {
|
|||
} from '@kbn/securitysolution-io-ts-list-types';
|
||||
import { Filter } from '@kbn/es-query';
|
||||
|
||||
import { QueryDslBoolQuery, QueryDslNestedQuery } from '@elastic/elasticsearch/api/types';
|
||||
import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey';
|
||||
import { hasLargeValueList } from '../has_large_value_list';
|
||||
|
||||
type NonListEntry = EntryMatch | EntryMatchAny | EntryNested | EntryExists;
|
||||
|
@ -40,11 +40,11 @@ export type ExceptionItemSansLargeValueLists =
|
|||
| CreateExceptionListItemNonLargeList;
|
||||
|
||||
export interface BooleanFilter {
|
||||
bool: QueryDslBoolQuery;
|
||||
bool: estypes.QueryDslBoolQuery;
|
||||
}
|
||||
|
||||
export interface NestedFilter {
|
||||
nested: QueryDslNestedQuery;
|
||||
nested: estypes.QueryDslNestedQuery;
|
||||
}
|
||||
|
||||
export const chunkExceptions = (
|
||||
|
|
35
packages/kbn-test/src/es/client_to_kibana_client.ts
Normal file
35
packages/kbn-test/src/es/client_to_kibana_client.ts
Normal file
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
import type { KibanaClient } from '@elastic/elasticsearch/lib/api/kibana';
|
||||
import type {
|
||||
Client,
|
||||
TransportRequestParams,
|
||||
TransportRequestOptions,
|
||||
TransportResult,
|
||||
} from '@elastic/elasticsearch';
|
||||
import { Transport } from '@elastic/elasticsearch';
|
||||
|
||||
// remove once https://github.com/elastic/kibana/issues/116095 is addressed
|
||||
class KibanaTransport extends Transport {
|
||||
request(params: TransportRequestParams, options?: TransportRequestOptions) {
|
||||
const opts: TransportRequestOptions = options || {};
|
||||
// Enforce the client to return TransportResult.
|
||||
// It's required for bwc with responses in 7.x version.
|
||||
if (opts?.meta === undefined) {
|
||||
opts.meta = true;
|
||||
}
|
||||
return super.request(params, opts) as Promise<TransportResult<any, any>>;
|
||||
}
|
||||
}
|
||||
|
||||
export function convertToKibanaClient(esClient: Client): KibanaClient {
|
||||
// @ts-expect-error @elastic/elasticsearch fix discrepancy between clients
|
||||
return esClient.child({
|
||||
Transport: KibanaTransport,
|
||||
});
|
||||
}
|
|
@ -9,3 +9,4 @@
|
|||
export { createTestEsCluster } from './test_es_cluster';
|
||||
export type { CreateTestEsClusterOptions, EsTestCluster, ICluster } from './test_es_cluster';
|
||||
export { esTestConfig } from './es_test_config';
|
||||
export { convertToKibanaClient } from './client_to_kibana_client';
|
||||
|
|
|
@ -11,11 +11,12 @@ import { format } from 'url';
|
|||
import del from 'del';
|
||||
// @ts-expect-error in js
|
||||
import { Cluster } from '@kbn/es';
|
||||
import { Client } from '@elastic/elasticsearch';
|
||||
import type { KibanaClient } from '@elastic/elasticsearch/api/kibana';
|
||||
import { Client, HttpConnection } from '@elastic/elasticsearch';
|
||||
import type { KibanaClient } from '@elastic/elasticsearch/lib/api/kibana';
|
||||
import type { ToolingLog } from '@kbn/dev-utils';
|
||||
import { CI_PARALLEL_PROCESS_PREFIX } from '../ci_parallel_process_prefix';
|
||||
import { esTestConfig } from './es_test_config';
|
||||
import { convertToKibanaClient } from './client_to_kibana_client';
|
||||
|
||||
import { KIBANA_ROOT } from '../';
|
||||
|
||||
|
@ -51,7 +52,8 @@ export interface ICluster {
|
|||
start: () => Promise<void>;
|
||||
stop: () => Promise<void>;
|
||||
cleanup: () => Promise<void>;
|
||||
getClient: () => KibanaClient;
|
||||
getClient: () => Client;
|
||||
getKibanaEsClient: () => KibanaClient;
|
||||
getHostUrls: () => string[];
|
||||
}
|
||||
|
||||
|
@ -280,12 +282,20 @@ export function createTestEsCluster<
|
|||
/**
|
||||
* Returns an ES Client to the configured cluster
|
||||
*/
|
||||
getClient(): KibanaClient {
|
||||
getClient(): Client {
|
||||
return new Client({
|
||||
node: this.getHostUrls()[0],
|
||||
Connection: HttpConnection,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an ES Client to the configured cluster
|
||||
*/
|
||||
getKibanaEsClient(): KibanaClient {
|
||||
return convertToKibanaClient(this.getClient());
|
||||
}
|
||||
|
||||
getUrl() {
|
||||
if (this.nodes.length > 1) {
|
||||
throw new Error(
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { Client } from '@elastic/elasticsearch';
|
||||
import { Client, HttpConnection } from '@elastic/elasticsearch';
|
||||
import { createFailError, ToolingLog } from '@kbn/dev-utils';
|
||||
|
||||
import { TestFailure } from './get_failures';
|
||||
|
@ -34,6 +34,7 @@ export async function reportFailuresToEs(log: ToolingLog, failures: TestFailure[
|
|||
username: process.env.TEST_FAILURES_ES_USERNAME,
|
||||
password: process.env.TEST_FAILURES_ES_PASSWORD,
|
||||
},
|
||||
Connection: HttpConnection,
|
||||
});
|
||||
|
||||
const body = failures.flatMap((failure) => [
|
||||
|
@ -59,7 +60,7 @@ export async function reportFailuresToEs(log: ToolingLog, failures: TestFailure[
|
|||
},
|
||||
]);
|
||||
|
||||
const resp = await client.bulk({ body });
|
||||
const resp = await client.bulk({ body }, { meta: true });
|
||||
if (resp?.body?.errors) {
|
||||
log.error(JSON.stringify(resp.body.items, null, 2));
|
||||
}
|
||||
|
|
|
@ -31,6 +31,7 @@ export {
|
|||
CreateTestEsClusterOptions,
|
||||
EsTestCluster,
|
||||
ICluster,
|
||||
convertToKibanaClient,
|
||||
} from './es';
|
||||
|
||||
export { kbnTestConfig, kibanaServerTestUser, kibanaTestUser, adminTestUser } from './kbn';
|
||||
|
|
|
@ -5,12 +5,11 @@
|
|||
```ts
|
||||
|
||||
import { Action } from 'history';
|
||||
import { ApiResponse } from '@elastic/elasticsearch/lib/Transport';
|
||||
import Boom from '@hapi/boom';
|
||||
import { ConfigPath } from '@kbn/config';
|
||||
import { DetailedPeerCertificate } from 'tls';
|
||||
import { EnvironmentMode } from '@kbn/config';
|
||||
import { estypes } from '@elastic/elasticsearch';
|
||||
import * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey';
|
||||
import { EuiBreadcrumb } from '@elastic/eui';
|
||||
import { EuiButtonEmptyProps } from '@elastic/eui';
|
||||
import { EuiConfirmModalProps } from '@elastic/eui';
|
||||
|
@ -20,7 +19,7 @@ import { History } from 'history';
|
|||
import { Href } from 'history';
|
||||
import { IconType } from '@elastic/eui';
|
||||
import { IncomingHttpHeaders } from 'http';
|
||||
import { KibanaClient } from '@elastic/elasticsearch/api/kibana';
|
||||
import { KibanaClient } from '@elastic/elasticsearch/lib/api/kibana';
|
||||
import { Location } from 'history';
|
||||
import { LocationDescriptorObject } from 'history';
|
||||
import { Logger } from '@kbn/logging';
|
||||
|
@ -38,9 +37,9 @@ import { RecursiveReadonly } from '@kbn/utility-types';
|
|||
import { Request } from '@hapi/hapi';
|
||||
import * as Rx from 'rxjs';
|
||||
import { SchemaTypeError } from '@kbn/config-schema';
|
||||
import { TransportRequestOptions } from '@elastic/elasticsearch/lib/Transport';
|
||||
import { TransportRequestParams } from '@elastic/elasticsearch/lib/Transport';
|
||||
import { TransportRequestPromise } from '@elastic/elasticsearch/lib/Transport';
|
||||
import { TransportRequestOptions } from '@elastic/elasticsearch';
|
||||
import { TransportRequestParams } from '@elastic/elasticsearch';
|
||||
import { TransportResult } from '@elastic/elasticsearch';
|
||||
import { Type } from '@kbn/config-schema';
|
||||
import { TypeOf } from '@kbn/config-schema';
|
||||
import { UiCounterMetricType } from '@kbn/analytics';
|
||||
|
|
|
@ -17,7 +17,7 @@ import {
|
|||
AggregationsFiltersAggregate,
|
||||
AggregationsFiltersBucketItem,
|
||||
SearchTotalHits,
|
||||
} from '@elastic/elasticsearch/api/types';
|
||||
} from '@elastic/elasticsearch/lib/api/typesWithBodyKey';
|
||||
import { CoreContext } from '../core_context';
|
||||
import { ElasticsearchConfigType } from '../elasticsearch/elasticsearch_config';
|
||||
import { HttpConfigType, InternalHttpServiceSetup } from '../http';
|
||||
|
|
|
@ -328,10 +328,10 @@ describe('parseClientOptions', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('ssl config', () => {
|
||||
it('does not generate ssl option is ssl config is not set', () => {
|
||||
expect(parseClientOptions(createConfig({}), false).ssl).toBeUndefined();
|
||||
expect(parseClientOptions(createConfig({}), true).ssl).toBeUndefined();
|
||||
describe('tls config', () => {
|
||||
it('does not generate tls option is ssl config is not set', () => {
|
||||
expect(parseClientOptions(createConfig({}), false).tls).toBeUndefined();
|
||||
expect(parseClientOptions(createConfig({}), true).tls).toBeUndefined();
|
||||
});
|
||||
|
||||
it('handles the `certificateAuthorities` option', () => {
|
||||
|
@ -341,7 +341,7 @@ describe('parseClientOptions', () => {
|
|||
ssl: { verificationMode: 'full', certificateAuthorities: ['content-of-ca-path'] },
|
||||
}),
|
||||
false
|
||||
).ssl!.ca
|
||||
).tls!.ca
|
||||
).toEqual(['content-of-ca-path']);
|
||||
expect(
|
||||
parseClientOptions(
|
||||
|
@ -349,7 +349,7 @@ describe('parseClientOptions', () => {
|
|||
ssl: { verificationMode: 'full', certificateAuthorities: ['content-of-ca-path'] },
|
||||
}),
|
||||
true
|
||||
).ssl!.ca
|
||||
).tls!.ca
|
||||
).toEqual(['content-of-ca-path']);
|
||||
});
|
||||
|
||||
|
@ -363,7 +363,7 @@ describe('parseClientOptions', () => {
|
|||
},
|
||||
}),
|
||||
false
|
||||
).ssl
|
||||
).tls
|
||||
).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"ca": undefined,
|
||||
|
@ -380,7 +380,7 @@ describe('parseClientOptions', () => {
|
|||
},
|
||||
}),
|
||||
false
|
||||
).ssl
|
||||
).tls
|
||||
).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"ca": undefined,
|
||||
|
@ -398,7 +398,7 @@ describe('parseClientOptions', () => {
|
|||
},
|
||||
}),
|
||||
false
|
||||
).ssl
|
||||
).tls
|
||||
).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"ca": undefined,
|
||||
|
@ -416,7 +416,7 @@ describe('parseClientOptions', () => {
|
|||
},
|
||||
}),
|
||||
false
|
||||
).ssl
|
||||
).tls
|
||||
).toThrowErrorMatchingInlineSnapshot(`"Unknown ssl verificationMode: unknown"`);
|
||||
});
|
||||
it('throws for undefined values', () => {
|
||||
|
@ -429,7 +429,7 @@ describe('parseClientOptions', () => {
|
|||
},
|
||||
}),
|
||||
false
|
||||
).ssl
|
||||
).tls
|
||||
).toThrowErrorMatchingInlineSnapshot(`"Unknown ssl verificationMode: undefined"`);
|
||||
});
|
||||
});
|
||||
|
@ -446,7 +446,7 @@ describe('parseClientOptions', () => {
|
|||
},
|
||||
}),
|
||||
false
|
||||
).ssl
|
||||
).tls
|
||||
).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"ca": undefined,
|
||||
|
@ -466,7 +466,7 @@ describe('parseClientOptions', () => {
|
|||
},
|
||||
}),
|
||||
false
|
||||
).ssl
|
||||
).tls
|
||||
).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"ca": undefined,
|
||||
|
@ -487,7 +487,7 @@ describe('parseClientOptions', () => {
|
|||
},
|
||||
}),
|
||||
false
|
||||
).ssl
|
||||
).tls
|
||||
).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"ca": undefined,
|
||||
|
@ -511,7 +511,7 @@ describe('parseClientOptions', () => {
|
|||
},
|
||||
}),
|
||||
true
|
||||
).ssl
|
||||
).tls
|
||||
).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"ca": undefined,
|
||||
|
@ -531,7 +531,7 @@ describe('parseClientOptions', () => {
|
|||
},
|
||||
}),
|
||||
true
|
||||
).ssl
|
||||
).tls
|
||||
).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"ca": undefined,
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
import { ConnectionOptions as TlsConnectionOptions } from 'tls';
|
||||
import { URL } from 'url';
|
||||
import { Duration } from 'moment';
|
||||
import { ClientOptions, NodeOptions } from '@elastic/elasticsearch';
|
||||
import type { ClientOptions } from '@elastic/elasticsearch/lib/client';
|
||||
import { ElasticsearchConfig } from '../elasticsearch_config';
|
||||
import { DEFAULT_HEADERS } from '../default_headers';
|
||||
|
||||
|
@ -93,7 +93,7 @@ export function parseClientOptions(
|
|||
clientOptions.nodes = config.hosts.map((host) => convertHost(host));
|
||||
|
||||
if (config.ssl) {
|
||||
clientOptions.ssl = generateSslConfig(
|
||||
clientOptions.tls = generateSslConfig(
|
||||
config.ssl,
|
||||
scoped && !config.ssl.alwaysPresentCertificate
|
||||
);
|
||||
|
@ -141,7 +141,7 @@ const generateSslConfig = (
|
|||
return ssl;
|
||||
};
|
||||
|
||||
const convertHost = (host: string): NodeOptions => {
|
||||
const convertHost = (host: string): { url: URL } => {
|
||||
const url = new URL(host);
|
||||
const isHTTPS = url.protocol === 'https:';
|
||||
url.port = url.port || (isHTTPS ? '443' : '80');
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { Client } from '@elastic/elasticsearch';
|
||||
import type { KibanaClient } from '@elastic/elasticsearch/lib/api/kibana';
|
||||
import { Logger } from '../../logging';
|
||||
import { GetAuthHeaders, Headers, isKibanaRequest, isRealRequest } from '../../http';
|
||||
import { ensureRawRequest, filterHeaders } from '../../http/router';
|
||||
|
@ -52,8 +52,8 @@ export interface ICustomClusterClient extends IClusterClient {
|
|||
|
||||
/** @internal **/
|
||||
export class ClusterClient implements ICustomClusterClient {
|
||||
public readonly asInternalUser: Client;
|
||||
private readonly rootScopedClient: Client;
|
||||
public readonly asInternalUser: KibanaClient;
|
||||
private readonly rootScopedClient: KibanaClient;
|
||||
private readonly allowListHeaders: string[];
|
||||
|
||||
private isClosed = false;
|
||||
|
|
|
@ -9,13 +9,13 @@
|
|||
import { Buffer } from 'buffer';
|
||||
import { Readable } from 'stream';
|
||||
|
||||
import { RequestEvent, errors } from '@elastic/elasticsearch';
|
||||
import type { Client } from '@elastic/elasticsearch';
|
||||
import { errors } from '@elastic/elasticsearch';
|
||||
import type {
|
||||
TransportRequestOptions,
|
||||
TransportRequestParams,
|
||||
DiagnosticResult,
|
||||
RequestBody,
|
||||
} from '@elastic/elasticsearch/lib/Transport';
|
||||
} from '@elastic/elasticsearch';
|
||||
|
||||
import { parseClientOptionsMock, ClientMock } from './configure_client.test.mocks';
|
||||
import { loggingSystemMock } from '../../logging/logging_system.mock';
|
||||
|
@ -36,7 +36,7 @@ const createFakeClient = () => {
|
|||
const client = new actualEs.Client({
|
||||
nodes: ['http://localhost'], // Enforcing `nodes` because it's mandatory
|
||||
});
|
||||
jest.spyOn(client, 'on');
|
||||
jest.spyOn(client.diagnostic, 'on');
|
||||
return client;
|
||||
};
|
||||
|
||||
|
@ -54,7 +54,7 @@ const createApiResponse = <T>({
|
|||
warnings?: string[];
|
||||
params?: TransportRequestParams;
|
||||
requestOptions?: TransportRequestOptions;
|
||||
}): RequestEvent<T> => {
|
||||
}): DiagnosticResult<T> => {
|
||||
return {
|
||||
body,
|
||||
statusCode,
|
||||
|
@ -70,14 +70,6 @@ const createApiResponse = <T>({
|
|||
};
|
||||
};
|
||||
|
||||
function getProductCheckValue(client: Client) {
|
||||
const tSymbol = Object.getOwnPropertySymbols(client.transport || client).filter(
|
||||
(symbol) => symbol.description === 'product check'
|
||||
)[0];
|
||||
// @ts-expect-error `tSymbol` is missing in the index signature of Transport
|
||||
return (client.transport || client)[tSymbol];
|
||||
}
|
||||
|
||||
describe('configureClient', () => {
|
||||
let logger: ReturnType<typeof loggingSystemMock.createLogger>;
|
||||
let config: ElasticsearchClientConfig;
|
||||
|
@ -124,26 +116,8 @@ describe('configureClient', () => {
|
|||
it('listens to client on `response` events', () => {
|
||||
const client = configureClient(config, { logger, type: 'test', scoped: false });
|
||||
|
||||
expect(client.on).toHaveBeenCalledTimes(1);
|
||||
expect(client.on).toHaveBeenCalledWith('response', expect.any(Function));
|
||||
});
|
||||
|
||||
describe('Product check', () => {
|
||||
it('should not skip the product check for the unscoped client', () => {
|
||||
const client = configureClient(config, { logger, type: 'test', scoped: false });
|
||||
expect(getProductCheckValue(client)).toBe(0);
|
||||
});
|
||||
|
||||
it('should skip the product check for the scoped client', () => {
|
||||
const client = configureClient(config, { logger, type: 'test', scoped: true });
|
||||
expect(getProductCheckValue(client)).toBe(2);
|
||||
});
|
||||
|
||||
it('should skip the product check for the children of the scoped client', () => {
|
||||
const client = configureClient(config, { logger, type: 'test', scoped: true });
|
||||
const asScoped = client.child({ headers: { 'x-custom-header': 'Custom value' } });
|
||||
expect(getProductCheckValue(asScoped)).toBe(2);
|
||||
});
|
||||
expect(client.diagnostic.on).toHaveBeenCalledTimes(1);
|
||||
expect(client.diagnostic.on).toHaveBeenCalledWith('response', expect.any(Function));
|
||||
});
|
||||
|
||||
describe('Client logging', () => {
|
||||
|
@ -176,7 +150,7 @@ describe('configureClient', () => {
|
|||
},
|
||||
});
|
||||
|
||||
client.emit('response', null, response);
|
||||
client.diagnostic.emit('response', null, response);
|
||||
expect(loggingSystemMock.collect(logger).debug).toMatchInlineSnapshot(`
|
||||
Array [
|
||||
Array [
|
||||
|
@ -201,7 +175,7 @@ describe('configureClient', () => {
|
|||
})
|
||||
);
|
||||
|
||||
client.emit('response', null, response);
|
||||
client.diagnostic.emit('response', null, response);
|
||||
expect(loggingSystemMock.collect(logger).debug).toMatchInlineSnapshot(`
|
||||
Array [
|
||||
Array [
|
||||
|
@ -228,7 +202,7 @@ describe('configureClient', () => {
|
|||
)
|
||||
);
|
||||
|
||||
client.emit('response', null, response);
|
||||
client.diagnostic.emit('response', null, response);
|
||||
expect(loggingSystemMock.collect(logger).debug).toMatchInlineSnapshot(`
|
||||
Array [
|
||||
Array [
|
||||
|
@ -255,7 +229,7 @@ describe('configureClient', () => {
|
|||
)
|
||||
);
|
||||
|
||||
client.emit('response', null, response);
|
||||
client.diagnostic.emit('response', null, response);
|
||||
expect(loggingSystemMock.collect(logger).debug).toMatchInlineSnapshot(`
|
||||
Array [
|
||||
Array [
|
||||
|
@ -273,7 +247,7 @@ describe('configureClient', () => {
|
|||
|
||||
const response = createResponseWithBody();
|
||||
|
||||
client.emit('response', null, response);
|
||||
client.diagnostic.emit('response', null, response);
|
||||
expect(loggingSystemMock.collect(logger).debug).toMatchInlineSnapshot(`
|
||||
Array [
|
||||
Array [
|
||||
|
@ -298,7 +272,7 @@ describe('configureClient', () => {
|
|||
},
|
||||
});
|
||||
|
||||
client.emit('response', null, response);
|
||||
client.diagnostic.emit('response', null, response);
|
||||
|
||||
expect(loggingSystemMock.collect(logger).debug).toMatchInlineSnapshot(`
|
||||
Array [
|
||||
|
@ -333,7 +307,7 @@ describe('configureClient', () => {
|
|||
},
|
||||
},
|
||||
});
|
||||
client.emit('response', new errors.ResponseError(response), response);
|
||||
client.diagnostic.emit('response', new errors.ResponseError(response), response);
|
||||
|
||||
expect(loggingSystemMock.collect(logger).debug).toMatchInlineSnapshot(`
|
||||
Array [
|
||||
|
@ -351,7 +325,7 @@ describe('configureClient', () => {
|
|||
const client = configureClient(createFakeConfig(), { logger, type: 'test', scoped: false });
|
||||
|
||||
const response = createApiResponse({ body: {} });
|
||||
client.emit('response', new errors.TimeoutError('message', response), response);
|
||||
client.diagnostic.emit('response', new errors.TimeoutError('message', response), response);
|
||||
|
||||
expect(loggingSystemMock.collect(logger).debug).toMatchInlineSnapshot(`
|
||||
Array [
|
||||
|
@ -381,7 +355,7 @@ describe('configureClient', () => {
|
|||
},
|
||||
},
|
||||
});
|
||||
client.emit('response', new errors.ResponseError(response), response);
|
||||
client.diagnostic.emit('response', new errors.ResponseError(response), response);
|
||||
|
||||
expect(loggingSystemMock.collect(logger).debug).toMatchInlineSnapshot(`
|
||||
Array [
|
||||
|
@ -397,7 +371,7 @@ describe('configureClient', () => {
|
|||
it('logs default error info when the error response body is empty', () => {
|
||||
const client = configureClient(createFakeConfig(), { logger, type: 'test', scoped: false });
|
||||
|
||||
let response: RequestEvent<any, any> = createApiResponse({
|
||||
let response: DiagnosticResult<any, any> = createApiResponse({
|
||||
statusCode: 400,
|
||||
headers: {},
|
||||
params: {
|
||||
|
@ -408,7 +382,7 @@ describe('configureClient', () => {
|
|||
error: {},
|
||||
},
|
||||
});
|
||||
client.emit('response', new errors.ResponseError(response), response);
|
||||
client.diagnostic.emit('response', new errors.ResponseError(response), response);
|
||||
|
||||
expect(loggingSystemMock.collect(logger).debug).toMatchInlineSnapshot(`
|
||||
Array [
|
||||
|
@ -431,7 +405,7 @@ describe('configureClient', () => {
|
|||
},
|
||||
body: undefined,
|
||||
});
|
||||
client.emit('response', new errors.ResponseError(response), response);
|
||||
client.diagnostic.emit('response', new errors.ResponseError(response), response);
|
||||
|
||||
expect(loggingSystemMock.collect(logger).debug).toMatchInlineSnapshot(`
|
||||
Array [
|
||||
|
@ -461,7 +435,7 @@ describe('configureClient', () => {
|
|||
error: {},
|
||||
},
|
||||
});
|
||||
client.emit('response', null, response);
|
||||
client.diagnostic.emit('response', null, response);
|
||||
|
||||
expect(loggingSystemMock.collect(logger).debug[0][1]).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
|
@ -487,7 +461,7 @@ describe('configureClient', () => {
|
|||
},
|
||||
body: {} as any,
|
||||
});
|
||||
client.emit('response', new errors.ResponseError(response), response);
|
||||
client.diagnostic.emit('response', new errors.ResponseError(response), response);
|
||||
|
||||
expect(loggingSystemMock.collect(logger).debug[0][1]).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
|
|
|
@ -8,14 +8,19 @@
|
|||
|
||||
import { Buffer } from 'buffer';
|
||||
import { stringify } from 'querystring';
|
||||
import { ApiError, Client, RequestEvent, errors, Transport } from '@elastic/elasticsearch';
|
||||
import { Client, errors, Transport, HttpConnection } from '@elastic/elasticsearch';
|
||||
import type { KibanaClient } from '@elastic/elasticsearch/lib/api/kibana';
|
||||
import type {
|
||||
RequestBody,
|
||||
TransportRequestParams,
|
||||
TransportRequestOptions,
|
||||
} from '@elastic/elasticsearch/lib/Transport';
|
||||
TransportResult,
|
||||
DiagnosticResult,
|
||||
RequestBody,
|
||||
} from '@elastic/elasticsearch';
|
||||
|
||||
import { Logger } from '../../logging';
|
||||
import { parseClientOptions, ElasticsearchClientConfig } from './client_config';
|
||||
import type { ElasticsearchErrorDetails } from './types';
|
||||
|
||||
const noop = () => undefined;
|
||||
|
||||
|
@ -32,30 +37,33 @@ export const configureClient = (
|
|||
scoped?: boolean;
|
||||
getExecutionContext?: () => string | undefined;
|
||||
}
|
||||
): Client => {
|
||||
): KibanaClient => {
|
||||
const clientOptions = parseClientOptions(config, scoped);
|
||||
class KibanaTransport extends Transport {
|
||||
request(params: TransportRequestParams, options?: TransportRequestOptions) {
|
||||
const opts = options || {};
|
||||
const opts: TransportRequestOptions = options || {};
|
||||
const opaqueId = getExecutionContext();
|
||||
if (opaqueId && !opts.opaqueId) {
|
||||
// rewrites headers['x-opaque-id'] if it presents
|
||||
opts.opaqueId = opaqueId;
|
||||
}
|
||||
return super.request(params, opts);
|
||||
// Enforce the client to return TransportResult.
|
||||
// It's required for bwc with responses in 7.x version.
|
||||
if (opts.meta === undefined) {
|
||||
opts.meta = true;
|
||||
}
|
||||
return super.request(params, opts) as Promise<TransportResult<any, any>>;
|
||||
}
|
||||
}
|
||||
|
||||
const client = new Client({ ...clientOptions, Transport: KibanaTransport });
|
||||
const client = new Client({
|
||||
...clientOptions,
|
||||
Transport: KibanaTransport,
|
||||
Connection: HttpConnection,
|
||||
});
|
||||
addLogging(client, logger.get('query', type));
|
||||
|
||||
// --------------------------------------------------------------------------------- //
|
||||
// Hack to disable the "Product check" only in the scoped clients while we //
|
||||
// come up with a better approach in https://github.com/elastic/kibana/issues/110675 //
|
||||
if (scoped) skipProductCheck(client);
|
||||
// --------------------------------------------------------------------------------- //
|
||||
|
||||
return client;
|
||||
return client as KibanaClient;
|
||||
};
|
||||
|
||||
const convertQueryString = (qs: string | Record<string, any> | undefined): string => {
|
||||
|
@ -76,9 +84,10 @@ function ensureString(body: RequestBody): string {
|
|||
* Returns a debug message from an Elasticsearch error in the following format:
|
||||
* [error type] error reason
|
||||
*/
|
||||
export function getErrorMessage(error: ApiError): string {
|
||||
export function getErrorMessage(error: errors.ElasticsearchClientError): string {
|
||||
if (error instanceof errors.ResponseError) {
|
||||
return `[${error.meta.body?.error?.type}]: ${error.meta.body?.error?.reason ?? error.message}`;
|
||||
const errorBody = error.meta.body as ElasticsearchErrorDetails;
|
||||
return `[${errorBody?.error?.type}]: ${errorBody?.error?.reason ?? error.message}`;
|
||||
}
|
||||
return `[${error.name}]: ${error.message}`;
|
||||
}
|
||||
|
@ -92,7 +101,7 @@ export function getErrorMessage(error: ApiError): string {
|
|||
*
|
||||
* so it could be copy-pasted into the Dev console
|
||||
*/
|
||||
function getResponseMessage(event: RequestEvent): string {
|
||||
function getResponseMessage(event: DiagnosticResult): string {
|
||||
const errorMeta = getRequestDebugMeta(event);
|
||||
const body = errorMeta.body ? `\n${errorMeta.body}` : '';
|
||||
return `${errorMeta.statusCode}\n${errorMeta.method} ${errorMeta.url}${body}`;
|
||||
|
@ -102,7 +111,7 @@ function getResponseMessage(event: RequestEvent): string {
|
|||
* Returns stringified debug information from an Elasticsearch request event
|
||||
* useful for logging in case of an unexpected failure.
|
||||
*/
|
||||
export function getRequestDebugMeta(event: RequestEvent): {
|
||||
export function getRequestDebugMeta(event: DiagnosticResult): {
|
||||
url: string;
|
||||
body: string;
|
||||
statusCode: number | null;
|
||||
|
@ -115,12 +124,12 @@ export function getRequestDebugMeta(event: RequestEvent): {
|
|||
url: `${params.path}${querystring ? `?${querystring}` : ''}`,
|
||||
body: params.body ? `${ensureString(params.body)}` : '',
|
||||
method: params.method,
|
||||
statusCode: event.statusCode,
|
||||
statusCode: event.statusCode!,
|
||||
};
|
||||
}
|
||||
|
||||
const addLogging = (client: Client, logger: Logger) => {
|
||||
client.on('response', (error, event) => {
|
||||
client.diagnostic.on('response', (error, event) => {
|
||||
if (event) {
|
||||
const opaqueId = event.meta.request.options.opaqueId;
|
||||
const meta = opaqueId
|
||||
|
@ -140,21 +149,3 @@ const addLogging = (client: Client, logger: Logger) => {
|
|||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Hack to skip the Product Check performed by the Elasticsearch-js client.
|
||||
* We noticed that the scoped clients are always performing this check because
|
||||
* of the way we initialize the clients. We'll discuss changing this in the issue
|
||||
* https://github.com/elastic/kibana/issues/110675. In the meanwhile, let's skip
|
||||
* it for the scoped clients.
|
||||
*
|
||||
* The hack is copied from the test/utils in the elasticsearch-js repo
|
||||
* (https://github.com/elastic/elasticsearch-js/blob/master/test/utils/index.js#L45-L56)
|
||||
*/
|
||||
function skipProductCheck(client: Client) {
|
||||
const tSymbol = Object.getOwnPropertySymbols(client.transport || client).filter(
|
||||
(symbol) => symbol.description === 'product check'
|
||||
)[0];
|
||||
// @ts-expect-error `tSymbol` is missing in the index signature of Transport
|
||||
(client.transport || client)[tSymbol] = 2;
|
||||
}
|
||||
|
|
|
@ -6,12 +6,8 @@
|
|||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import {
|
||||
ResponseError,
|
||||
ConnectionError,
|
||||
ConfigurationError,
|
||||
} from '@elastic/elasticsearch/lib/errors';
|
||||
import { ApiResponse } from '@elastic/elasticsearch';
|
||||
import { errors } from '@elastic/elasticsearch';
|
||||
import type { TransportResult } from '@elastic/elasticsearch';
|
||||
import { isResponseError, isUnauthorizedError } from './errors';
|
||||
|
||||
const createApiResponseError = ({
|
||||
|
@ -22,7 +18,7 @@ const createApiResponseError = ({
|
|||
statusCode?: number;
|
||||
headers?: Record<string, string>;
|
||||
body?: Record<string, any>;
|
||||
} = {}): ApiResponse => {
|
||||
} = {}): TransportResult => {
|
||||
return {
|
||||
body,
|
||||
statusCode,
|
||||
|
@ -34,38 +30,42 @@ const createApiResponseError = ({
|
|||
|
||||
describe('isResponseError', () => {
|
||||
it('returns `true` when the input is a `ResponseError`', () => {
|
||||
expect(isResponseError(new ResponseError(createApiResponseError()))).toBe(true);
|
||||
expect(isResponseError(new errors.ResponseError(createApiResponseError()))).toBe(true);
|
||||
});
|
||||
|
||||
it('returns `false` when the input is not a `ResponseError`', () => {
|
||||
expect(isResponseError(new Error('foo'))).toBe(false);
|
||||
expect(isResponseError(new ConnectionError('error', createApiResponseError()))).toBe(false);
|
||||
expect(isResponseError(new ConfigurationError('foo'))).toBe(false);
|
||||
expect(isResponseError(new errors.ConnectionError('error', createApiResponseError()))).toBe(
|
||||
false
|
||||
);
|
||||
expect(isResponseError(new errors.ConfigurationError('foo'))).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('isUnauthorizedError', () => {
|
||||
it('returns true when the input is a `ResponseError` and statusCode === 401', () => {
|
||||
expect(
|
||||
isUnauthorizedError(new ResponseError(createApiResponseError({ statusCode: 401 })))
|
||||
isUnauthorizedError(new errors.ResponseError(createApiResponseError({ statusCode: 401 })))
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
it('returns false when the input is a `ResponseError` and statusCode !== 401', () => {
|
||||
expect(
|
||||
isUnauthorizedError(new ResponseError(createApiResponseError({ statusCode: 200 })))
|
||||
isUnauthorizedError(new errors.ResponseError(createApiResponseError({ statusCode: 200 })))
|
||||
).toBe(false);
|
||||
expect(
|
||||
isUnauthorizedError(new ResponseError(createApiResponseError({ statusCode: 403 })))
|
||||
isUnauthorizedError(new errors.ResponseError(createApiResponseError({ statusCode: 403 })))
|
||||
).toBe(false);
|
||||
expect(
|
||||
isUnauthorizedError(new ResponseError(createApiResponseError({ statusCode: 500 })))
|
||||
isUnauthorizedError(new errors.ResponseError(createApiResponseError({ statusCode: 500 })))
|
||||
).toBe(false);
|
||||
});
|
||||
|
||||
it('returns `false` when the input is not a `ResponseError`', () => {
|
||||
expect(isUnauthorizedError(new Error('foo'))).toBe(false);
|
||||
expect(isUnauthorizedError(new ConnectionError('error', createApiResponseError()))).toBe(false);
|
||||
expect(isUnauthorizedError(new ConfigurationError('foo'))).toBe(false);
|
||||
expect(isUnauthorizedError(new errors.ConnectionError('error', createApiResponseError()))).toBe(
|
||||
false
|
||||
);
|
||||
expect(isUnauthorizedError(new errors.ConfigurationError('foo'))).toBe(false);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -6,14 +6,14 @@
|
|||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { ResponseError } from '@elastic/elasticsearch/lib/errors';
|
||||
import { errors } from '@elastic/elasticsearch';
|
||||
|
||||
export type UnauthorizedError = ResponseError & {
|
||||
export type UnauthorizedError = errors.ResponseError & {
|
||||
statusCode: 401;
|
||||
};
|
||||
|
||||
export function isResponseError(error: unknown): error is ResponseError {
|
||||
return error instanceof ResponseError;
|
||||
export function isResponseError(error: unknown): error is errors.ResponseError {
|
||||
return error instanceof errors.ResponseError;
|
||||
}
|
||||
|
||||
export function isUnauthorizedError(error: unknown): error is UnauthorizedError {
|
||||
|
|
|
@ -14,6 +14,7 @@ export type {
|
|||
SearchResponse,
|
||||
GetResponse,
|
||||
DeleteDocumentResponse,
|
||||
ElasticsearchErrorDetails,
|
||||
} from './types';
|
||||
export { ScopedClusterClient } from './scoped_cluster_client';
|
||||
export type { IScopedClusterClient } from './scoped_cluster_client';
|
||||
|
|
|
@ -39,9 +39,9 @@ describe('Mocked client', () => {
|
|||
});
|
||||
|
||||
it('used EventEmitter functions should be mocked', () => {
|
||||
expectMocked(client.on);
|
||||
expectMocked(client.off);
|
||||
expectMocked(client.once);
|
||||
expectMocked(client.diagnostic.on);
|
||||
expectMocked(client.diagnostic.off);
|
||||
expectMocked(client.diagnostic.once);
|
||||
});
|
||||
|
||||
it('`child` should be mocked and return a mocked Client', () => {
|
||||
|
|
|
@ -6,36 +6,33 @@
|
|||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import type { Client, ApiResponse } from '@elastic/elasticsearch';
|
||||
import { TransportRequestPromise } from '@elastic/elasticsearch/lib/Transport';
|
||||
import type { KibanaClient } from '@elastic/elasticsearch/lib/api/kibana';
|
||||
import type { TransportResult } from '@elastic/elasticsearch';
|
||||
import type { DeeplyMockedKeys } from '@kbn/utility-types/jest';
|
||||
import type { PublicKeys } from '@kbn/utility-types';
|
||||
import { ElasticsearchClient } from './types';
|
||||
import { ICustomClusterClient } from './cluster_client';
|
||||
import { PRODUCT_RESPONSE_HEADER } from '../supported_server_response_check';
|
||||
|
||||
const omittedProps = [
|
||||
'diagnostic',
|
||||
'name',
|
||||
'connectionPool',
|
||||
'transport',
|
||||
'serializer',
|
||||
'helpers',
|
||||
] as Array<PublicKeys<KibanaClient>>;
|
||||
|
||||
// the product header expected in every response from es
|
||||
const PRODUCT_RESPONSE_HEADER = 'x-elastic-product';
|
||||
|
||||
// use jest.requireActual() to prevent weird errors when people mock @elastic/elasticsearch
|
||||
const { Client: UnmockedClient } = jest.requireActual('@elastic/elasticsearch');
|
||||
|
||||
const createInternalClientMock = (
|
||||
res?: MockedTransportRequestPromise<unknown>
|
||||
): DeeplyMockedKeys<Client> => {
|
||||
const createInternalClientMock = (res?: Promise<unknown>): DeeplyMockedKeys<KibanaClient> => {
|
||||
// we mimic 'reflection' on a concrete instance of the client to generate the mocked functions.
|
||||
const client = new UnmockedClient({
|
||||
node: 'http://localhost',
|
||||
node: 'http://127.0.0.1',
|
||||
});
|
||||
|
||||
const omittedProps = [
|
||||
'_events',
|
||||
'_eventsCount',
|
||||
'_maxListeners',
|
||||
'constructor',
|
||||
'name',
|
||||
'serializer',
|
||||
'connectionPool',
|
||||
'transport',
|
||||
'helpers',
|
||||
];
|
||||
|
||||
const getAllPropertyDescriptors = (obj: Record<string, any>) => {
|
||||
const descriptors = Object.entries(Object.getOwnPropertyDescriptors(obj));
|
||||
let prototype = Object.getPrototypeOf(obj);
|
||||
|
@ -77,21 +74,21 @@ const createInternalClientMock = (
|
|||
};
|
||||
|
||||
// `on`, `off`, and `once` are properties without a setter.
|
||||
// We can't `client.on = jest.fn()` because the following error will be thrown:
|
||||
// We can't `client.diagnostic.on = jest.fn()` because the following error will be thrown:
|
||||
// TypeError: Cannot set property on of #<Client> which has only a getter
|
||||
mockGetter(client, 'on');
|
||||
mockGetter(client, 'off');
|
||||
mockGetter(client, 'once');
|
||||
mockGetter(client.diagnostic, 'on');
|
||||
mockGetter(client.diagnostic, 'off');
|
||||
mockGetter(client.diagnostic, 'once');
|
||||
client.transport = {
|
||||
request: jest.fn(),
|
||||
};
|
||||
|
||||
return client as DeeplyMockedKeys<Client>;
|
||||
return client as DeeplyMockedKeys<KibanaClient>;
|
||||
};
|
||||
|
||||
export type ElasticsearchClientMock = DeeplyMockedKeys<ElasticsearchClient>;
|
||||
|
||||
const createClientMock = (res?: MockedTransportRequestPromise<unknown>): ElasticsearchClientMock =>
|
||||
const createClientMock = (res?: Promise<unknown>): ElasticsearchClientMock =>
|
||||
createInternalClientMock(res) as unknown as ElasticsearchClientMock;
|
||||
|
||||
export interface ScopedClusterClientMock {
|
||||
|
@ -139,31 +136,23 @@ const createCustomClusterClientMock = () => {
|
|||
return mock;
|
||||
};
|
||||
|
||||
export type MockedTransportRequestPromise<T> = TransportRequestPromise<T> & {
|
||||
abort: jest.MockedFunction<() => undefined>;
|
||||
};
|
||||
|
||||
const createSuccessTransportRequestPromise = <T>(
|
||||
body: T,
|
||||
{ statusCode = 200 }: { statusCode?: number } = {},
|
||||
headers: Record<string, string | string[]> = { [PRODUCT_RESPONSE_HEADER]: 'Elasticsearch' }
|
||||
): MockedTransportRequestPromise<ApiResponse<T>> => {
|
||||
): Promise<TransportResult<T>> => {
|
||||
const response = createApiResponse({ body, statusCode, headers });
|
||||
const promise = Promise.resolve(response);
|
||||
(promise as MockedTransportRequestPromise<ApiResponse<T>>).abort = jest.fn();
|
||||
|
||||
return promise as MockedTransportRequestPromise<ApiResponse<T>>;
|
||||
return Promise.resolve(response) as Promise<TransportResult<T>>;
|
||||
};
|
||||
|
||||
const createErrorTransportRequestPromise = (err: any): MockedTransportRequestPromise<never> => {
|
||||
const promise = Promise.reject(err);
|
||||
(promise as MockedTransportRequestPromise<never>).abort = jest.fn();
|
||||
return promise as MockedTransportRequestPromise<never>;
|
||||
const createErrorTransportRequestPromise = (err: any): Promise<TransportResult<never>> => {
|
||||
return Promise.reject(err);
|
||||
};
|
||||
|
||||
function createApiResponse<TResponse = Record<string, any>>(
|
||||
opts: Partial<ApiResponse<TResponse>> = {}
|
||||
): ApiResponse<TResponse> {
|
||||
opts: Partial<TransportResult<TResponse>> = {}
|
||||
): TransportResult<TResponse> {
|
||||
return {
|
||||
body: {} as any,
|
||||
statusCode: 200,
|
||||
|
|
|
@ -6,13 +6,12 @@
|
|||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import type { KibanaClient } from '@elastic/elasticsearch/api/kibana';
|
||||
import type { KibanaClient } from '@elastic/elasticsearch/lib/api/kibana';
|
||||
import type {
|
||||
ApiResponse,
|
||||
TransportResult,
|
||||
TransportRequestOptions,
|
||||
TransportRequestParams,
|
||||
TransportRequestPromise,
|
||||
} from '@elastic/elasticsearch/lib/Transport';
|
||||
} from '@elastic/elasticsearch';
|
||||
|
||||
/**
|
||||
* Client used to query the elasticsearch cluster.
|
||||
|
@ -21,13 +20,13 @@ import type {
|
|||
*/
|
||||
export type ElasticsearchClient = Omit<
|
||||
KibanaClient,
|
||||
'connectionPool' | 'transport' | 'serializer' | 'extend' | 'child' | 'close'
|
||||
'connectionPool' | 'transport' | 'serializer' | 'extend' | 'child' | 'close' | 'diagnostic'
|
||||
> & {
|
||||
transport: {
|
||||
request(
|
||||
request<TResponse = unknown>(
|
||||
params: TransportRequestParams,
|
||||
options?: TransportRequestOptions
|
||||
): TransportRequestPromise<ApiResponse>;
|
||||
): Promise<TransportResult<TResponse>>;
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -133,3 +132,10 @@ export interface DeleteDocumentResponse {
|
|||
type: string;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export interface ElasticsearchErrorDetails {
|
||||
error?: { type: string; reason?: string };
|
||||
}
|
||||
|
|
|
@ -35,10 +35,6 @@ export type {
|
|||
ShardsResponse,
|
||||
GetResponse,
|
||||
DeleteDocumentResponse,
|
||||
ElasticsearchErrorDetails,
|
||||
} from './client';
|
||||
export { getRequestDebugMeta, getErrorMessage } from './client';
|
||||
export {
|
||||
isSupportedEsServer,
|
||||
isNotFoundFromUnsupportedServer,
|
||||
PRODUCT_RESPONSE_HEADER,
|
||||
} from './supported_server_response_check';
|
||||
|
|
|
@ -52,17 +52,6 @@ describe('elasticsearch clients', () => {
|
|||
);
|
||||
expect(resp2.headers).not.toHaveProperty('warning');
|
||||
});
|
||||
|
||||
it('returns deprecation warning when x-elastic-product-orign header is not set', async () => {
|
||||
const resp =
|
||||
await kibanaServer.coreStart.elasticsearch.client.asInternalUser.indices.getSettings(
|
||||
{ index: '.kibana' },
|
||||
{ headers: { 'x-elastic-product-origin': null } }
|
||||
);
|
||||
|
||||
expect(resp.headers).toHaveProperty('warning');
|
||||
expect(resp.headers!.warning).toMatch('system indices');
|
||||
});
|
||||
});
|
||||
|
||||
function createFakeElasticsearchServer() {
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { estypes } from '@elastic/elasticsearch';
|
||||
import * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey';
|
||||
import { elasticsearchServiceMock } from './elasticsearch_service.mock';
|
||||
import { isInlineScriptingEnabled } from './is_scripting_enabled';
|
||||
|
||||
|
|
|
@ -1,41 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { isNotFoundFromUnsupportedServer } from './supported_server_response_check';
|
||||
|
||||
describe('#isNotFoundFromUnsupportedServer', () => {
|
||||
it('returns true with not found response from unsupported server', () => {
|
||||
const rawResponse = {
|
||||
statusCode: 404,
|
||||
headers: {},
|
||||
};
|
||||
|
||||
const result = isNotFoundFromUnsupportedServer(rawResponse);
|
||||
expect(result).toBe(true);
|
||||
});
|
||||
|
||||
it('returns false with not found response from supported server', async () => {
|
||||
const rawResponse = {
|
||||
statusCode: 404,
|
||||
headers: { 'x-elastic-product': 'Elasticsearch' },
|
||||
};
|
||||
|
||||
const result = isNotFoundFromUnsupportedServer(rawResponse);
|
||||
expect(result).toBe(false);
|
||||
});
|
||||
|
||||
it('returns false when not a 404', async () => {
|
||||
const rawResponse = {
|
||||
statusCode: 200,
|
||||
headers: { 'x-elastic-product': 'Elasticsearch' },
|
||||
};
|
||||
|
||||
const result = isNotFoundFromUnsupportedServer(rawResponse);
|
||||
expect(result).toBe(false);
|
||||
});
|
||||
});
|
|
@ -1,33 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
export const PRODUCT_RESPONSE_HEADER = 'x-elastic-product';
|
||||
/**
|
||||
* Response headers check to determine if the response is from Elasticsearch
|
||||
* @param headers Response headers
|
||||
* @returns boolean
|
||||
*/
|
||||
// This check belongs to the elasticsearch service as a dedicated helper method.
|
||||
export const isSupportedEsServer = (headers: Record<string, string | string[]> | null) => {
|
||||
return !!headers && headers[PRODUCT_RESPONSE_HEADER] === 'Elasticsearch';
|
||||
};
|
||||
|
||||
/**
|
||||
* Check to ensure that a 404 response does not come from Elasticsearch
|
||||
*
|
||||
* WARNING: This is a hack to work around for 404 responses returned from a proxy.
|
||||
* We're aiming to minimise the risk of data loss when consumers act on Not Found errors
|
||||
*
|
||||
* @param response response from elasticsearch client call
|
||||
* @returns boolean 'true' if the status code is 404 and the Elasticsearch product header is missing/unexpected value
|
||||
*/
|
||||
export const isNotFoundFromUnsupportedServer = (args: {
|
||||
statusCode: number | null;
|
||||
headers: Record<string, string | string[]> | null;
|
||||
}): boolean => {
|
||||
return args.statusCode === 404 && !isSupportedEsServer(args.headers);
|
||||
};
|
|
@ -139,6 +139,7 @@ describe('pollEsNodesVersion', () => {
|
|||
});
|
||||
|
||||
const nodeInfosSuccessOnce = (infos: NodesInfo) => {
|
||||
// @ts-expect-error not full interface
|
||||
internalClient.nodes.info.mockImplementationOnce(() => createEsSuccess(infos));
|
||||
};
|
||||
const nodeInfosErrorOnce = (error: any) => {
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
|
||||
import { MockElasticsearchClient } from './core_service.test.mocks';
|
||||
import { elasticsearchClientMock } from '../../elasticsearch/client/mocks';
|
||||
import { ResponseError } from '@elastic/elasticsearch/lib/errors';
|
||||
import { errors } from '@elastic/elasticsearch';
|
||||
import * as kbnTestServer from '../../../test_helpers/kbn_server';
|
||||
import { InternalElasticsearchServiceStart } from '../../elasticsearch';
|
||||
|
||||
|
@ -205,7 +205,7 @@ describe('http service', () => {
|
|||
|
||||
esClient.ping.mockImplementation(() =>
|
||||
elasticsearchClientMock.createErrorTransportRequestPromise(
|
||||
new ResponseError({
|
||||
new errors.ResponseError({
|
||||
statusCode: 401,
|
||||
body: {
|
||||
error: {
|
||||
|
@ -243,7 +243,7 @@ describe('http service', () => {
|
|||
|
||||
esClient.ping.mockImplementation(() =>
|
||||
elasticsearchClientMock.createErrorTransportRequestPromise(
|
||||
new ResponseError({
|
||||
new errors.ResponseError({
|
||||
statusCode: 401,
|
||||
body: {
|
||||
error: {
|
||||
|
@ -279,7 +279,7 @@ describe('http service', () => {
|
|||
|
||||
esClient.ping.mockImplementation(() =>
|
||||
elasticsearchClientMock.createErrorTransportRequestPromise(
|
||||
new ResponseError({
|
||||
new errors.ResponseError({
|
||||
statusCode: 404,
|
||||
body: {
|
||||
error: {
|
||||
|
|
|
@ -15,6 +15,7 @@ import Boom from '@hapi/boom';
|
|||
import * as stream from 'stream';
|
||||
|
||||
import { isResponseError as isElasticsearchResponseError } from '../../elasticsearch/client/errors';
|
||||
import { ElasticsearchErrorDetails } from '../../elasticsearch';
|
||||
|
||||
import {
|
||||
HttpResponsePayload,
|
||||
|
@ -154,7 +155,9 @@ function getErrorMessage(payload?: ResponseError): string {
|
|||
if (typeof payload === 'string') return payload;
|
||||
// for ES response errors include nested error reason message. it doesn't contain sensitive data.
|
||||
if (isElasticsearchResponseError(payload)) {
|
||||
return `[${payload.message}]: ${payload.meta.body?.error?.reason}`;
|
||||
return `[${payload.message}]: ${
|
||||
(payload.meta.body as ElasticsearchErrorDetails)?.error?.reason
|
||||
}`;
|
||||
}
|
||||
|
||||
return getErrorMessage(payload.message);
|
||||
|
|
|
@ -289,10 +289,10 @@ export class Router<Context extends RequestHandlerContext = RequestHandlerContex
|
|||
|
||||
const convertEsUnauthorized = (e: EsNotAuthorizedError): ErrorHttpResponseOptions => {
|
||||
const getAuthenticateHeaderValue = () => {
|
||||
const header = Object.entries(e.headers).find(
|
||||
const header = Object.entries(e.headers || {}).find(
|
||||
([key]) => key.toLowerCase() === 'www-authenticate'
|
||||
);
|
||||
return header ? header[1] : 'Basic realm="Authorization Required"';
|
||||
return header ? (header[1] as string) : 'Basic realm="Authorization Required"';
|
||||
};
|
||||
return {
|
||||
body: e.message,
|
||||
|
|
|
@ -136,6 +136,7 @@ export type {
|
|||
GetResponse,
|
||||
DeleteDocumentResponse,
|
||||
ElasticsearchConfigPreboot,
|
||||
ElasticsearchErrorDetails,
|
||||
} from './elasticsearch';
|
||||
|
||||
export type { IExternalUrlConfig, IExternalUrlPolicy } from './external_url';
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
|
||||
import { getIndexForTypeMock } from './unknown_object_types.test.mocks';
|
||||
|
||||
import { estypes } from '@elastic/elasticsearch';
|
||||
import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey';
|
||||
import { deleteUnknownTypeObjects, getUnknownTypesDeprecations } from './unknown_object_types';
|
||||
import { typeRegistryMock } from '../saved_objects_type_registry.mock';
|
||||
import { elasticsearchClientMock } from '../../elasticsearch/client/mocks';
|
||||
|
|
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