mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 01:38:56 -04:00
[Actions] Replaces legacy es client with the ElasticsearchClient (#93361)
* [Actions] Replaces legasy es client with the ElasticsearchClient * fixed build * fixed tests
This commit is contained in:
parent
5d119cfcbb
commit
086762da6a
16 changed files with 239 additions and 218 deletions
|
@ -137,10 +137,9 @@ This is the primary function for an action type. Whenever the action needs to ex
|
|||
| --------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| actionId | The action saved object id that the action type is executing for. |
|
||||
| config | The action configuration. If you would like to validate the config before being passed to the executor, define `validate.config` within the action type. |
|
||||
| secrets | The decrypted secrets object given to an action. This comes from the action saved object that is partially or fully encrypted within the data store. If you would like to validate the secrets object before being passed to the executor, define `validate.secrets` within the action type. |
|
||||
| secrets | The decrypted secrets object given to an action. This comes from the action saved object that is partially or fully encrypted within the data store. If you would like to validate the secrets object before being passed to the executor, define `validate.secrets` within the action type. |
|
||||
| params | Parameters for the execution. These will be given at execution time by either an alert or manually provided when calling the plugin provided execute function. |
|
||||
| services.callCluster(path, opts) | Use this to do Elasticsearch queries on the cluster Kibana connects to. This function is the same as any other `callCluster` in Kibana but runs in the context of the user who is calling the action when security is enabled. |
|
||||
| services.getLegacyScopedClusterClient | This function returns an instance of the LegacyScopedClusterClient scoped to the user who is calling the action when security is enabled. |
|
||||
| services.scopedClusterClient | Use this to do Elasticsearch queries on the cluster Kibana connects to. Serves the same purpose as the normal IClusterClient, but exposes an additional `asCurrentUser` method that doesn't use credentials of the Kibana internal user (as `asInternalUser` does) to request Elasticsearch API, but rather passes HTTP headers extracted from the current user request to the API instead.|
|
||||
| services.savedObjectsClient | This is an instance of the saved objects client. This provides the ability to do CRUD on any saved objects within the same space the alert lives in.<br><br>The scope of the saved objects client is tied to the user in context calling the execute API or the API key provided to the execute plugin function (only when security isenabled). |
|
||||
| services.log(tags, [data], [timestamp]) | Use this to create server logs. (This is the same function as server.log)
|
||||
|
||||
|
|
|
@ -27,6 +27,8 @@ import { actionExecutorMock } from './lib/action_executor.mock';
|
|||
import uuid from 'uuid';
|
||||
import { ActionsAuthorization } from './authorization/actions_authorization';
|
||||
import { actionsAuthorizationMock } from './authorization/actions_authorization.mock';
|
||||
// eslint-disable-next-line @kbn/eslint/no-restricted-paths
|
||||
import { elasticsearchClientMock } from '../../../../src/core/server/elasticsearch/client/mocks';
|
||||
|
||||
jest.mock('../../../../src/core/server/saved_objects/service/lib/utils', () => ({
|
||||
SavedObjectsUtils: {
|
||||
|
@ -36,7 +38,7 @@ jest.mock('../../../../src/core/server/saved_objects/service/lib/utils', () => (
|
|||
|
||||
const defaultKibanaIndex = '.kibana';
|
||||
const unsecuredSavedObjectsClient = savedObjectsClientMock.create();
|
||||
const scopedClusterClient = elasticsearchServiceMock.createLegacyScopedClusterClient();
|
||||
const scopedClusterClient = elasticsearchServiceMock.createScopedClusterClient();
|
||||
const actionExecutor = actionExecutorMock.create();
|
||||
const authorization = actionsAuthorizationMock.create();
|
||||
const executionEnqueuer = jest.fn();
|
||||
|
@ -741,12 +743,14 @@ describe('getAll()', () => {
|
|||
],
|
||||
};
|
||||
unsecuredSavedObjectsClient.find.mockResolvedValueOnce(expectedResult);
|
||||
scopedClusterClient.callAsInternalUser.mockResolvedValueOnce({
|
||||
aggregations: {
|
||||
'1': { doc_count: 6 },
|
||||
testPreconfigured: { doc_count: 2 },
|
||||
},
|
||||
});
|
||||
scopedClusterClient.asInternalUser.search.mockResolvedValueOnce(
|
||||
elasticsearchClientMock.createSuccessTransportRequestPromise({
|
||||
aggregations: {
|
||||
'1': { doc_count: 6 },
|
||||
testPreconfigured: { doc_count: 2 },
|
||||
},
|
||||
})
|
||||
);
|
||||
|
||||
actionsClient = new ActionsClient({
|
||||
actionTypeRegistry,
|
||||
|
@ -812,12 +816,14 @@ describe('getAll()', () => {
|
|||
},
|
||||
],
|
||||
});
|
||||
scopedClusterClient.callAsInternalUser.mockResolvedValueOnce({
|
||||
aggregations: {
|
||||
'1': { doc_count: 6 },
|
||||
testPreconfigured: { doc_count: 2 },
|
||||
},
|
||||
});
|
||||
scopedClusterClient.asInternalUser.search.mockResolvedValueOnce(
|
||||
elasticsearchClientMock.createSuccessTransportRequestPromise({
|
||||
aggregations: {
|
||||
'1': { doc_count: 6 },
|
||||
testPreconfigured: { doc_count: 2 },
|
||||
},
|
||||
})
|
||||
);
|
||||
|
||||
await actionsClient.getAll();
|
||||
|
||||
|
@ -870,12 +876,14 @@ describe('getAll()', () => {
|
|||
],
|
||||
};
|
||||
unsecuredSavedObjectsClient.find.mockResolvedValueOnce(expectedResult);
|
||||
scopedClusterClient.callAsInternalUser.mockResolvedValueOnce({
|
||||
aggregations: {
|
||||
'1': { doc_count: 6 },
|
||||
testPreconfigured: { doc_count: 2 },
|
||||
},
|
||||
});
|
||||
scopedClusterClient.asInternalUser.search.mockResolvedValueOnce(
|
||||
elasticsearchClientMock.createSuccessTransportRequestPromise({
|
||||
aggregations: {
|
||||
'1': { doc_count: 6 },
|
||||
testPreconfigured: { doc_count: 2 },
|
||||
},
|
||||
})
|
||||
);
|
||||
|
||||
actionsClient = new ActionsClient({
|
||||
actionTypeRegistry,
|
||||
|
@ -940,12 +948,14 @@ describe('getBulk()', () => {
|
|||
},
|
||||
],
|
||||
});
|
||||
scopedClusterClient.callAsInternalUser.mockResolvedValueOnce({
|
||||
aggregations: {
|
||||
'1': { doc_count: 6 },
|
||||
testPreconfigured: { doc_count: 2 },
|
||||
},
|
||||
});
|
||||
scopedClusterClient.asInternalUser.search.mockResolvedValueOnce(
|
||||
elasticsearchClientMock.createSuccessTransportRequestPromise({
|
||||
aggregations: {
|
||||
'1': { doc_count: 6 },
|
||||
testPreconfigured: { doc_count: 2 },
|
||||
},
|
||||
})
|
||||
);
|
||||
|
||||
actionsClient = new ActionsClient({
|
||||
actionTypeRegistry,
|
||||
|
@ -1008,12 +1018,14 @@ describe('getBulk()', () => {
|
|||
},
|
||||
],
|
||||
});
|
||||
scopedClusterClient.callAsInternalUser.mockResolvedValueOnce({
|
||||
aggregations: {
|
||||
'1': { doc_count: 6 },
|
||||
testPreconfigured: { doc_count: 2 },
|
||||
},
|
||||
});
|
||||
scopedClusterClient.asInternalUser.search.mockResolvedValueOnce(
|
||||
elasticsearchClientMock.createSuccessTransportRequestPromise({
|
||||
aggregations: {
|
||||
'1': { doc_count: 6 },
|
||||
testPreconfigured: { doc_count: 2 },
|
||||
},
|
||||
})
|
||||
);
|
||||
|
||||
await actionsClient.getBulk(['1']);
|
||||
|
||||
|
@ -1063,12 +1075,14 @@ describe('getBulk()', () => {
|
|||
},
|
||||
],
|
||||
});
|
||||
scopedClusterClient.callAsInternalUser.mockResolvedValueOnce({
|
||||
aggregations: {
|
||||
'1': { doc_count: 6 },
|
||||
testPreconfigured: { doc_count: 2 },
|
||||
},
|
||||
});
|
||||
scopedClusterClient.asInternalUser.search.mockResolvedValueOnce(
|
||||
elasticsearchClientMock.createSuccessTransportRequestPromise({
|
||||
aggregations: {
|
||||
'1': { doc_count: 6 },
|
||||
testPreconfigured: { doc_count: 2 },
|
||||
},
|
||||
})
|
||||
);
|
||||
|
||||
actionsClient = new ActionsClient({
|
||||
actionTypeRegistry,
|
||||
|
|
|
@ -10,7 +10,7 @@ import Boom from '@hapi/boom';
|
|||
import { i18n } from '@kbn/i18n';
|
||||
import { omitBy, isUndefined } from 'lodash';
|
||||
import {
|
||||
ILegacyScopedClusterClient,
|
||||
IScopedClusterClient,
|
||||
SavedObjectsClientContract,
|
||||
SavedObjectAttributes,
|
||||
SavedObject,
|
||||
|
@ -62,7 +62,7 @@ export interface CreateOptions {
|
|||
|
||||
interface ConstructorOptions {
|
||||
defaultKibanaIndex: string;
|
||||
scopedClusterClient: ILegacyScopedClusterClient;
|
||||
scopedClusterClient: IScopedClusterClient;
|
||||
actionTypeRegistry: ActionTypeRegistry;
|
||||
unsecuredSavedObjectsClient: SavedObjectsClientContract;
|
||||
preconfiguredActions: PreConfiguredAction[];
|
||||
|
@ -80,7 +80,7 @@ export interface UpdateOptions {
|
|||
|
||||
export class ActionsClient {
|
||||
private readonly defaultKibanaIndex: string;
|
||||
private readonly scopedClusterClient: ILegacyScopedClusterClient;
|
||||
private readonly scopedClusterClient: IScopedClusterClient;
|
||||
private readonly unsecuredSavedObjectsClient: SavedObjectsClientContract;
|
||||
private readonly actionTypeRegistry: ActionTypeRegistry;
|
||||
private readonly preconfiguredActions: PreConfiguredAction[];
|
||||
|
@ -506,7 +506,7 @@ function actionFromSavedObject(savedObject: SavedObject<RawAction>): ActionResul
|
|||
|
||||
async function injectExtraFindData(
|
||||
defaultKibanaIndex: string,
|
||||
scopedClusterClient: ILegacyScopedClusterClient,
|
||||
scopedClusterClient: IScopedClusterClient,
|
||||
actionResults: ActionResult[]
|
||||
): Promise<FindActionResult[]> {
|
||||
const aggs: Record<string, unknown> = {};
|
||||
|
@ -543,7 +543,7 @@ async function injectExtraFindData(
|
|||
},
|
||||
};
|
||||
}
|
||||
const aggregationResult = await scopedClusterClient.callAsInternalUser('search', {
|
||||
const { body: aggregationResult } = await scopedClusterClient.asInternalUser.search({
|
||||
index: defaultKibanaIndex,
|
||||
body: {
|
||||
aggs,
|
||||
|
|
|
@ -18,6 +18,8 @@ import {
|
|||
ESIndexActionType,
|
||||
ESIndexActionTypeExecutorOptions,
|
||||
} from './es_index';
|
||||
// eslint-disable-next-line @kbn/eslint/no-restricted-paths
|
||||
import { elasticsearchClientMock } from '../../../../../src/core/server/elasticsearch/client/mocks';
|
||||
|
||||
const ACTION_TYPE_ID = '.index';
|
||||
|
||||
|
@ -161,14 +163,23 @@ describe('execute()', () => {
|
|||
|
||||
const actionId = 'some-id';
|
||||
|
||||
executorOptions = { actionId, config, secrets, params, services };
|
||||
services.callCluster.mockClear();
|
||||
await actionType.executor(executorOptions);
|
||||
executorOptions = {
|
||||
actionId,
|
||||
config,
|
||||
secrets,
|
||||
params,
|
||||
services,
|
||||
};
|
||||
const scopedClusterClient = elasticsearchClientMock.createClusterClient().asScoped()
|
||||
.asCurrentUser;
|
||||
await actionType.executor({
|
||||
...executorOptions,
|
||||
services: { ...services, scopedClusterClient },
|
||||
});
|
||||
|
||||
expect(services.callCluster.mock.calls).toMatchInlineSnapshot(`
|
||||
expect(scopedClusterClient.bulk.mock.calls).toMatchInlineSnapshot(`
|
||||
Array [
|
||||
Array [
|
||||
"bulk",
|
||||
Object {
|
||||
"body": Array [
|
||||
Object {
|
||||
|
@ -192,17 +203,20 @@ describe('execute()', () => {
|
|||
};
|
||||
|
||||
executorOptions = { actionId, config, secrets, params, services };
|
||||
services.callCluster.mockClear();
|
||||
await actionType.executor(executorOptions);
|
||||
scopedClusterClient.bulk.mockClear();
|
||||
await actionType.executor({
|
||||
...executorOptions,
|
||||
services: { ...services, scopedClusterClient },
|
||||
});
|
||||
|
||||
const calls = services.callCluster.mock.calls;
|
||||
const timeValue = calls[0][1]?.body[1].field_to_use_for_time;
|
||||
const calls = scopedClusterClient.bulk.mock.calls;
|
||||
const timeValue = ((calls[0][0]?.body as unknown[])[1] as Record<string, unknown>)
|
||||
.field_to_use_for_time;
|
||||
expect(timeValue).toBeInstanceOf(Date);
|
||||
delete calls[0][1]?.body[1].field_to_use_for_time;
|
||||
delete ((calls[0][0]?.body as unknown[])[1] as Record<string, unknown>).field_to_use_for_time;
|
||||
expect(calls).toMatchInlineSnapshot(`
|
||||
Array [
|
||||
Array [
|
||||
"bulk",
|
||||
Object {
|
||||
"body": Array [
|
||||
Object {
|
||||
|
@ -226,13 +240,16 @@ describe('execute()', () => {
|
|||
};
|
||||
|
||||
executorOptions = { actionId, config, secrets, params, services };
|
||||
services.callCluster.mockClear();
|
||||
await actionType.executor(executorOptions);
|
||||
|
||||
expect(services.callCluster.mock.calls).toMatchInlineSnapshot(`
|
||||
scopedClusterClient.bulk.mockClear();
|
||||
await actionType.executor({
|
||||
...executorOptions,
|
||||
services: { ...services, scopedClusterClient },
|
||||
});
|
||||
|
||||
expect(scopedClusterClient.bulk.mock.calls).toMatchInlineSnapshot(`
|
||||
Array [
|
||||
Array [
|
||||
"bulk",
|
||||
Object {
|
||||
"body": Array [
|
||||
Object {
|
||||
|
@ -256,13 +273,15 @@ describe('execute()', () => {
|
|||
};
|
||||
|
||||
executorOptions = { actionId, config, secrets, params, services };
|
||||
services.callCluster.mockClear();
|
||||
await actionType.executor(executorOptions);
|
||||
scopedClusterClient.bulk.mockClear();
|
||||
await actionType.executor({
|
||||
...executorOptions,
|
||||
services: { ...services, scopedClusterClient },
|
||||
});
|
||||
|
||||
expect(services.callCluster.mock.calls).toMatchInlineSnapshot(`
|
||||
expect(scopedClusterClient.bulk.mock.calls).toMatchInlineSnapshot(`
|
||||
Array [
|
||||
Array [
|
||||
"bulk",
|
||||
Object {
|
||||
"body": Array [
|
||||
Object {
|
||||
|
@ -295,35 +314,38 @@ describe('execute()', () => {
|
|||
};
|
||||
|
||||
const actionId = 'some-id';
|
||||
|
||||
services.callCluster.mockResolvedValue({
|
||||
took: 0,
|
||||
errors: true,
|
||||
items: [
|
||||
{
|
||||
index: {
|
||||
_index: 'indexme',
|
||||
_id: '7buTjHQB0SuNSiS9Hayt',
|
||||
status: 400,
|
||||
error: {
|
||||
type: 'mapper_parsing_exception',
|
||||
reason: 'failed to parse',
|
||||
caused_by: {
|
||||
type: 'illegal_argument_exception',
|
||||
reason: 'field name cannot be an empty string',
|
||||
const scopedClusterClient = elasticsearchClientMock.createClusterClient().asScoped()
|
||||
.asCurrentUser;
|
||||
scopedClusterClient.bulk.mockResolvedValue(
|
||||
elasticsearchClientMock.createSuccessTransportRequestPromise({
|
||||
took: 0,
|
||||
errors: true,
|
||||
items: [
|
||||
{
|
||||
index: {
|
||||
_index: 'indexme',
|
||||
_id: '7buTjHQB0SuNSiS9Hayt',
|
||||
status: 400,
|
||||
error: {
|
||||
type: 'mapper_parsing_exception',
|
||||
reason: 'failed to parse',
|
||||
caused_by: {
|
||||
type: 'illegal_argument_exception',
|
||||
reason: 'field name cannot be an empty string',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
],
|
||||
})
|
||||
);
|
||||
|
||||
expect(await actionType.executor({ actionId, config, secrets, params, services }))
|
||||
.toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"actionId": "some-id",
|
||||
"message": "error indexing documents",
|
||||
"serviceMessage": "failed to parse (field name cannot be an empty string)",
|
||||
"serviceMessage": "Cannot destructure property 'body' of '(intermediate value)' as it is undefined.",
|
||||
"status": "error",
|
||||
}
|
||||
`);
|
||||
|
|
|
@ -88,7 +88,7 @@ async function executor(
|
|||
};
|
||||
|
||||
try {
|
||||
const result = await services.callCluster('bulk', bulkParams);
|
||||
const { body: result } = await services.scopedClusterClient.bulk(bulkParams);
|
||||
|
||||
const err = find(result.items, 'index.error.reason');
|
||||
if (err) {
|
||||
|
|
|
@ -54,7 +54,6 @@ afterAll(() => fakeTimer.restore());
|
|||
|
||||
const services = {
|
||||
log: jest.fn(),
|
||||
callCluster: jest.fn(),
|
||||
savedObjectsClient: savedObjectsClientMock.create(),
|
||||
};
|
||||
const actionExecutorInitializerParams = {
|
||||
|
|
|
@ -52,8 +52,6 @@ const createServicesMock = () => {
|
|||
savedObjectsClient: ReturnType<typeof savedObjectsClientMock.create>;
|
||||
}
|
||||
> = {
|
||||
callCluster: elasticsearchServiceMock.createLegacyScopedClusterClient().callAsCurrentUser,
|
||||
getLegacyScopedClusterClient: jest.fn(),
|
||||
savedObjectsClient: savedObjectsClientMock.create(),
|
||||
scopedClusterClient: elasticsearchServiceMock.createScopedClusterClient().asCurrentUser,
|
||||
};
|
||||
|
|
|
@ -83,9 +83,7 @@ describe('Actions Plugin', () => {
|
|||
client: {},
|
||||
},
|
||||
elasticsearch: {
|
||||
legacy: {
|
||||
client: jest.fn(),
|
||||
},
|
||||
client: jest.fn(),
|
||||
},
|
||||
},
|
||||
} as unknown) as RequestHandlerContext,
|
||||
|
|
|
@ -16,7 +16,6 @@ import {
|
|||
Logger,
|
||||
IContextProvider,
|
||||
ElasticsearchServiceStart,
|
||||
ILegacyClusterClient,
|
||||
SavedObjectsClientContract,
|
||||
SavedObjectsBulkGetObject,
|
||||
} from '../../../../src/core/server';
|
||||
|
@ -287,7 +286,7 @@ export class ActionsPlugin implements Plugin<PluginSetupContract, PluginStartCon
|
|||
unsecuredSavedObjectsClient,
|
||||
actionTypeRegistry: actionTypeRegistry!,
|
||||
defaultKibanaIndex: kibanaIndex,
|
||||
scopedClusterClient: core.elasticsearch.legacy.client.asScoped(request),
|
||||
scopedClusterClient: core.elasticsearch.client.asScoped(request),
|
||||
preconfiguredActions,
|
||||
request,
|
||||
authorization: instantiateAuthorization(
|
||||
|
@ -406,12 +405,8 @@ export class ActionsPlugin implements Plugin<PluginSetupContract, PluginStartCon
|
|||
elasticsearch: ElasticsearchServiceStart
|
||||
): (request: KibanaRequest) => Services {
|
||||
return (request) => ({
|
||||
callCluster: elasticsearch.legacy.client.asScoped(request).callAsCurrentUser,
|
||||
savedObjectsClient: getScopedClient(request),
|
||||
scopedClusterClient: elasticsearch.client.asScoped(request).asCurrentUser,
|
||||
getLegacyScopedClusterClient(clusterClient: ILegacyClusterClient) {
|
||||
return clusterClient.asScoped(request);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -444,7 +439,7 @@ export class ActionsPlugin implements Plugin<PluginSetupContract, PluginStartCon
|
|||
}),
|
||||
actionTypeRegistry: actionTypeRegistry!,
|
||||
defaultKibanaIndex,
|
||||
scopedClusterClient: context.core.elasticsearch.legacy.client,
|
||||
scopedClusterClient: context.core.elasticsearch.client,
|
||||
preconfiguredActions,
|
||||
request,
|
||||
authorization: instantiateAuthorization(request),
|
||||
|
|
|
@ -11,8 +11,6 @@ import { PluginSetupContract, PluginStartContract } from './plugin';
|
|||
import { ActionsClient } from './actions_client';
|
||||
import { LicenseType } from '../../licensing/common/types';
|
||||
import {
|
||||
ILegacyClusterClient,
|
||||
ILegacyScopedClusterClient,
|
||||
KibanaRequest,
|
||||
SavedObjectsClientContract,
|
||||
SavedObjectAttributes,
|
||||
|
@ -34,13 +32,8 @@ export type ActionTypeSecrets = Record<string, unknown>;
|
|||
export type ActionTypeParams = Record<string, unknown>;
|
||||
|
||||
export interface Services {
|
||||
/**
|
||||
* @deprecated Use `scopedClusterClient` instead.
|
||||
*/
|
||||
callCluster: ILegacyScopedClusterClient['callAsCurrentUser'];
|
||||
savedObjectsClient: SavedObjectsClientContract;
|
||||
scopedClusterClient: ElasticsearchClient;
|
||||
getLegacyScopedClusterClient(clusterClient: ILegacyClusterClient): ILegacyScopedClusterClient;
|
||||
}
|
||||
|
||||
export interface ActionsApiRequestHandlerContext {
|
||||
|
|
|
@ -5,97 +5,100 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
// eslint-disable-next-line @kbn/eslint/no-restricted-paths
|
||||
import { elasticsearchClientMock } from '../../../../../src/core/server/elasticsearch/client/mocks';
|
||||
import { getInUseTotalCount, getTotalCount } from './actions_telemetry';
|
||||
|
||||
describe('actions telemetry', () => {
|
||||
test('getTotalCount should replace first symbol . to __ for action types names', async () => {
|
||||
const mockEsClient = jest.fn();
|
||||
mockEsClient.mockReturnValue({
|
||||
aggregations: {
|
||||
byActionTypeId: {
|
||||
value: {
|
||||
types: { '.index': 1, '.server-log': 1, 'some.type': 1, 'another.type.': 1 },
|
||||
const mockEsClient = elasticsearchClientMock.createClusterClient().asScoped().asInternalUser;
|
||||
mockEsClient.search.mockReturnValue(
|
||||
elasticsearchClientMock.createSuccessTransportRequestPromise({
|
||||
aggregations: {
|
||||
byActionTypeId: {
|
||||
value: {
|
||||
types: { '.index': 1, '.server-log': 1, 'some.type': 1, 'another.type.': 1 },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
hits: {
|
||||
hits: [
|
||||
{
|
||||
_id: 'action:541efb3d-f82a-4d2c-a5c3-636d1ce49b53',
|
||||
_index: '.kibana_1',
|
||||
_score: 0,
|
||||
_source: {
|
||||
action: {
|
||||
actionTypeId: '.index',
|
||||
config: {
|
||||
index: 'kibana_sample_data_ecommerce',
|
||||
refresh: true,
|
||||
executionTimeField: null,
|
||||
hits: {
|
||||
hits: [
|
||||
{
|
||||
_id: 'action:541efb3d-f82a-4d2c-a5c3-636d1ce49b53',
|
||||
_index: '.kibana_1',
|
||||
_score: 0,
|
||||
_source: {
|
||||
action: {
|
||||
actionTypeId: '.index',
|
||||
config: {
|
||||
index: 'kibana_sample_data_ecommerce',
|
||||
refresh: true,
|
||||
executionTimeField: null,
|
||||
},
|
||||
name: 'test',
|
||||
secrets:
|
||||
'UPyn6cit6zBTPMmldfKh/8S2JWypwaLhhEQWBXp+OyTc6TtLHOnW92wehCqTq1FhIY3vA8hwVsggj+tbIoCcfPArpzP5SO7hh8vd6pY13x5TkiM083UgjjaAxbPvKQ==',
|
||||
},
|
||||
name: 'test',
|
||||
secrets:
|
||||
'UPyn6cit6zBTPMmldfKh/8S2JWypwaLhhEQWBXp+OyTc6TtLHOnW92wehCqTq1FhIY3vA8hwVsggj+tbIoCcfPArpzP5SO7hh8vd6pY13x5TkiM083UgjjaAxbPvKQ==',
|
||||
references: [],
|
||||
type: 'action',
|
||||
updated_at: '2020-03-26T18:46:44.449Z',
|
||||
},
|
||||
references: [],
|
||||
type: 'action',
|
||||
updated_at: '2020-03-26T18:46:44.449Z',
|
||||
},
|
||||
},
|
||||
{
|
||||
_id: 'action:00000000-f82a-4d2c-a5c3-636d1ce49b53',
|
||||
_index: '.kibana_1',
|
||||
_score: 0,
|
||||
_source: {
|
||||
action: {
|
||||
actionTypeId: '.server-log',
|
||||
config: {},
|
||||
name: 'test server log',
|
||||
secrets: '',
|
||||
{
|
||||
_id: 'action:00000000-f82a-4d2c-a5c3-636d1ce49b53',
|
||||
_index: '.kibana_1',
|
||||
_score: 0,
|
||||
_source: {
|
||||
action: {
|
||||
actionTypeId: '.server-log',
|
||||
config: {},
|
||||
name: 'test server log',
|
||||
secrets: '',
|
||||
},
|
||||
references: [],
|
||||
type: 'action',
|
||||
updated_at: '2020-03-26T18:46:44.449Z',
|
||||
},
|
||||
references: [],
|
||||
type: 'action',
|
||||
updated_at: '2020-03-26T18:46:44.449Z',
|
||||
},
|
||||
},
|
||||
{
|
||||
_id: 'action:00000000-1',
|
||||
_index: '.kibana_1',
|
||||
_score: 0,
|
||||
_source: {
|
||||
action: {
|
||||
actionTypeId: 'some.type',
|
||||
config: {},
|
||||
name: 'test type',
|
||||
secrets: {},
|
||||
{
|
||||
_id: 'action:00000000-1',
|
||||
_index: '.kibana_1',
|
||||
_score: 0,
|
||||
_source: {
|
||||
action: {
|
||||
actionTypeId: 'some.type',
|
||||
config: {},
|
||||
name: 'test type',
|
||||
secrets: {},
|
||||
},
|
||||
references: [],
|
||||
type: 'action',
|
||||
updated_at: '2020-03-26T18:46:44.449Z',
|
||||
},
|
||||
references: [],
|
||||
type: 'action',
|
||||
updated_at: '2020-03-26T18:46:44.449Z',
|
||||
},
|
||||
},
|
||||
{
|
||||
_id: 'action:00000000-2',
|
||||
_index: '.kibana_1',
|
||||
_score: 0,
|
||||
_source: {
|
||||
action: {
|
||||
actionTypeId: 'another.type.',
|
||||
config: {},
|
||||
name: 'test another type',
|
||||
secrets: {},
|
||||
{
|
||||
_id: 'action:00000000-2',
|
||||
_index: '.kibana_1',
|
||||
_score: 0,
|
||||
_source: {
|
||||
action: {
|
||||
actionTypeId: 'another.type.',
|
||||
config: {},
|
||||
name: 'test another type',
|
||||
secrets: {},
|
||||
},
|
||||
references: [],
|
||||
type: 'action',
|
||||
updated_at: '2020-03-26T18:46:44.449Z',
|
||||
},
|
||||
references: [],
|
||||
type: 'action',
|
||||
updated_at: '2020-03-26T18:46:44.449Z',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
|
||||
],
|
||||
},
|
||||
})
|
||||
);
|
||||
const telemetry = await getTotalCount(mockEsClient, 'test');
|
||||
|
||||
expect(mockEsClient).toHaveBeenCalledTimes(1);
|
||||
expect(mockEsClient.search).toHaveBeenCalledTimes(1);
|
||||
|
||||
expect(telemetry).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
|
@ -111,22 +114,24 @@ Object {
|
|||
});
|
||||
|
||||
test('getInUseTotalCount', async () => {
|
||||
const mockEsClient = jest.fn();
|
||||
mockEsClient.mockReturnValue({
|
||||
aggregations: {
|
||||
refs: {
|
||||
actionRefIds: {
|
||||
value: {
|
||||
connectorIds: { '1': 'action-0', '123': 'action-0' },
|
||||
total: 2,
|
||||
const mockEsClient = elasticsearchClientMock.createClusterClient().asScoped().asInternalUser;
|
||||
mockEsClient.search.mockReturnValue(
|
||||
elasticsearchClientMock.createSuccessTransportRequestPromise({
|
||||
aggregations: {
|
||||
refs: {
|
||||
actionRefIds: {
|
||||
value: {
|
||||
connectorIds: { '1': 'action-0', '123': 'action-0' },
|
||||
total: 2,
|
||||
},
|
||||
},
|
||||
},
|
||||
hits: {
|
||||
hits: [],
|
||||
},
|
||||
},
|
||||
hits: {
|
||||
hits: [],
|
||||
},
|
||||
},
|
||||
});
|
||||
})
|
||||
);
|
||||
const actionsBulkGet = jest.fn();
|
||||
actionsBulkGet.mockReturnValue({
|
||||
saved_objects: [
|
||||
|
@ -146,7 +151,7 @@ Object {
|
|||
});
|
||||
const telemetry = await getInUseTotalCount(mockEsClient, actionsBulkGet, 'test');
|
||||
|
||||
expect(mockEsClient).toHaveBeenCalledTimes(1);
|
||||
expect(mockEsClient.search).toHaveBeenCalledTimes(1);
|
||||
expect(actionsBulkGet).toHaveBeenCalledTimes(1);
|
||||
|
||||
expect(telemetry).toMatchInlineSnapshot(`
|
||||
|
|
|
@ -6,14 +6,14 @@
|
|||
*/
|
||||
|
||||
import {
|
||||
LegacyAPICaller,
|
||||
ElasticsearchClient,
|
||||
SavedObjectsBaseOptions,
|
||||
SavedObjectsBulkGetObject,
|
||||
SavedObjectsBulkResponse,
|
||||
} from 'kibana/server';
|
||||
import { ActionResult } from '../types';
|
||||
|
||||
export async function getTotalCount(callCluster: LegacyAPICaller, kibanaIndex: string) {
|
||||
export async function getTotalCount(esClient: ElasticsearchClient, kibanaIndex: string) {
|
||||
const scriptedMetric = {
|
||||
scripted_metric: {
|
||||
init_script: 'state.types = [:]',
|
||||
|
@ -40,7 +40,7 @@ export async function getTotalCount(callCluster: LegacyAPICaller, kibanaIndex: s
|
|||
},
|
||||
};
|
||||
|
||||
const searchResult = await callCluster('search', {
|
||||
const { body: searchResult } = await esClient.search({
|
||||
index: kibanaIndex,
|
||||
body: {
|
||||
query: {
|
||||
|
@ -61,7 +61,7 @@ export async function getTotalCount(callCluster: LegacyAPICaller, kibanaIndex: s
|
|||
0
|
||||
),
|
||||
countByType: Object.keys(searchResult.aggregations.byActionTypeId.value.types).reduce(
|
||||
// ES DSL aggregations are returned as `any` by callCluster
|
||||
// ES DSL aggregations are returned as `any` by esClient.search
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
(obj: any, key: string) => ({
|
||||
...obj,
|
||||
|
@ -75,7 +75,7 @@ export async function getTotalCount(callCluster: LegacyAPICaller, kibanaIndex: s
|
|||
}
|
||||
|
||||
export async function getInUseTotalCount(
|
||||
callCluster: LegacyAPICaller,
|
||||
esClient: ElasticsearchClient,
|
||||
actionsBulkGet: (
|
||||
objects?: SavedObjectsBulkGetObject[] | undefined,
|
||||
options?: SavedObjectsBaseOptions | undefined
|
||||
|
@ -117,7 +117,7 @@ export async function getInUseTotalCount(
|
|||
},
|
||||
};
|
||||
|
||||
const actionResults = await callCluster('search', {
|
||||
const { body: actionResults } = await esClient.search({
|
||||
index: kibanaIndex,
|
||||
body: {
|
||||
query: {
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
import {
|
||||
Logger,
|
||||
CoreSetup,
|
||||
LegacyAPICaller,
|
||||
SavedObjectsBulkGetObject,
|
||||
SavedObjectsBaseOptions,
|
||||
} from 'kibana/server';
|
||||
|
@ -69,11 +68,14 @@ async function scheduleTasks(logger: Logger, taskManager: TaskManagerStartContra
|
|||
export function telemetryTaskRunner(logger: Logger, core: CoreSetup, kibanaIndex: string) {
|
||||
return ({ taskInstance }: RunContext) => {
|
||||
const { state } = taskInstance;
|
||||
const callCluster = (...args: Parameters<LegacyAPICaller>) => {
|
||||
return core.getStartServices().then(([{ elasticsearch: { legacy: { client } } }]) =>
|
||||
client.callAsInternalUser(...args)
|
||||
const getEsClient = () =>
|
||||
core.getStartServices().then(
|
||||
([
|
||||
{
|
||||
elasticsearch: { client },
|
||||
},
|
||||
]) => client.asInternalUser
|
||||
);
|
||||
};
|
||||
const actionsBulkGet = (
|
||||
objects?: SavedObjectsBulkGetObject[],
|
||||
options?: SavedObjectsBaseOptions
|
||||
|
@ -86,9 +88,10 @@ export function telemetryTaskRunner(logger: Logger, core: CoreSetup, kibanaIndex
|
|||
};
|
||||
return {
|
||||
async run() {
|
||||
const esClient = await getEsClient();
|
||||
return Promise.all([
|
||||
getTotalCount(callCluster, kibanaIndex),
|
||||
getInUseTotalCount(callCluster, actionsBulkGet, kibanaIndex),
|
||||
getTotalCount(esClient, kibanaIndex),
|
||||
getInUseTotalCount(esClient, actionsBulkGet, kibanaIndex),
|
||||
])
|
||||
.then(([totalAggegations, totalInUse]) => {
|
||||
return {
|
||||
|
|
|
@ -64,7 +64,7 @@ function getIndexRecordActionType() {
|
|||
secrets: secretsSchema,
|
||||
},
|
||||
async executor({ config, secrets, params, services, actionId }) {
|
||||
await services.callCluster('index', {
|
||||
await services.scopedClusterClient.index({
|
||||
index: params.index,
|
||||
refresh: 'wait_for',
|
||||
body: {
|
||||
|
@ -95,7 +95,7 @@ function getFailingActionType() {
|
|||
params: paramsSchema,
|
||||
},
|
||||
async executor({ config, secrets, params, services }) {
|
||||
await services.callCluster('index', {
|
||||
await services.scopedClusterClient.index({
|
||||
index: params.index,
|
||||
refresh: 'wait_for',
|
||||
body: {
|
||||
|
@ -128,7 +128,7 @@ function getRateLimitedActionType() {
|
|||
params: paramsSchema,
|
||||
},
|
||||
async executor({ config, params, services }) {
|
||||
await services.callCluster('index', {
|
||||
await services.scopedClusterClient.index({
|
||||
index: params.index,
|
||||
refresh: 'wait_for',
|
||||
body: {
|
||||
|
@ -149,7 +149,6 @@ function getRateLimitedActionType() {
|
|||
}
|
||||
|
||||
function getAuthorizationActionType(core: CoreSetup<FixtureStartDeps>) {
|
||||
const clusterClient = core.elasticsearch.legacy.client;
|
||||
const paramsSchema = schema.object({
|
||||
callClusterAuthorizationIndex: schema.string(),
|
||||
savedObjectsClientType: schema.string(),
|
||||
|
@ -170,7 +169,7 @@ function getAuthorizationActionType(core: CoreSetup<FixtureStartDeps>) {
|
|||
let callClusterSuccess = false;
|
||||
let callClusterError;
|
||||
try {
|
||||
await services.callCluster('index', {
|
||||
await services.scopedClusterClient.index({
|
||||
index: params.callClusterAuthorizationIndex,
|
||||
refresh: 'wait_for',
|
||||
body: {
|
||||
|
@ -182,11 +181,11 @@ function getAuthorizationActionType(core: CoreSetup<FixtureStartDeps>) {
|
|||
callClusterError = e;
|
||||
}
|
||||
// Call scoped cluster
|
||||
const scopedClusterClient = services.getLegacyScopedClusterClient(clusterClient);
|
||||
const scopedClusterClient = services.scopedClusterClient;
|
||||
let callScopedClusterSuccess = false;
|
||||
let callScopedClusterError;
|
||||
try {
|
||||
await scopedClusterClient.callAsCurrentUser('index', {
|
||||
await scopedClusterClient.index({
|
||||
index: params.callClusterAuthorizationIndex,
|
||||
refresh: 'wait_for',
|
||||
body: {
|
||||
|
@ -210,7 +209,7 @@ function getAuthorizationActionType(core: CoreSetup<FixtureStartDeps>) {
|
|||
savedObjectsClientError = e;
|
||||
}
|
||||
// Save the result
|
||||
await services.callCluster('index', {
|
||||
await services.scopedClusterClient.index({
|
||||
index: params.index,
|
||||
refresh: 'wait_for',
|
||||
body: {
|
||||
|
|
|
@ -460,11 +460,9 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
savedObjectsClientSuccess: false,
|
||||
callClusterError: {
|
||||
...indexedRecord._source.state.callClusterError,
|
||||
statusCode: 403,
|
||||
},
|
||||
callScopedClusterError: {
|
||||
...indexedRecord._source.state.callScopedClusterError,
|
||||
statusCode: 403,
|
||||
},
|
||||
savedObjectsClientError: {
|
||||
...indexedRecord._source.state.savedObjectsClientError,
|
||||
|
|
|
@ -652,11 +652,9 @@ instanceStateValue: true
|
|||
savedObjectsClientSuccess: false,
|
||||
callClusterError: {
|
||||
...searchResult.hits.hits[0]._source.state.callClusterError,
|
||||
statusCode: 403,
|
||||
},
|
||||
callScopedClusterError: {
|
||||
...searchResult.hits.hits[0]._source.state.callScopedClusterError,
|
||||
statusCode: 403,
|
||||
},
|
||||
savedObjectsClientError: {
|
||||
...searchResult.hits.hits[0]._source.state.savedObjectsClientError,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue