Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[ResponseOps][OnWeek] Connector logs view #148291

Merged
merged 53 commits into from
Jan 23, 2023
Merged
Show file tree
Hide file tree
Changes from 52 commits
Commits
Show all changes
53 commits
Select commit Hold shift + click to select a range
15009db
Initial commit
doakalexi Dec 6, 2022
3e0b06c
Merge branch 'main' of github.com:elastic/kibana into on-week/connect…
doakalexi Dec 6, 2022
e908595
Fixing query
doakalexi Dec 6, 2022
be35b24
Server side cleanup
doakalexi Jan 3, 2023
5af7883
Reusing components
doakalexi Jan 4, 2023
d42514d
More refactoring
doakalexi Jan 4, 2023
c804e93
Merge branch 'main' of github.com:elastic/kibana into on-week/connect…
doakalexi Jan 4, 2023
6b54903
[CI] Auto-commit changed files from 'node scripts/ts_project_linter -…
kibanamachine Jan 4, 2023
311984a
Fixing failed tests
doakalexi Jan 5, 2023
ee1f371
Merge branch 'on-week/connectors-event-logs' of github.com:doakalexi/…
doakalexi Jan 5, 2023
2b64501
Adding new tests
doakalexi Jan 5, 2023
568bba1
Remove circular dependency
doakalexi Jan 9, 2023
53c5573
[CI] Auto-commit changed files from 'node scripts/ts_project_linter -…
kibanamachine Jan 9, 2023
605e4d1
Fixing other circular dependency
doakalexi Jan 9, 2023
41a6fd3
Merge branch 'on-week/connectors-event-logs' of github.com:doakalexi/…
doakalexi Jan 9, 2023
9f6f15f
Removing alerting
doakalexi Jan 9, 2023
94cf58f
Fixing types and test failures
doakalexi Jan 9, 2023
6b82166
Fixing mappings
doakalexi Jan 9, 2023
5403126
Fixing types again
doakalexi Jan 9, 2023
01996a5
Merge branch 'main' into on-week/connectors-event-logs
doakalexi Jan 9, 2023
05828dd
Update x-pack/plugins/actions/server/actions_client.ts
doakalexi Jan 10, 2023
578d433
Addressing pr feedback
doakalexi Jan 10, 2023
d17da74
Merge branch 'on-week/connectors-event-logs' of github.com:doakalexi/…
doakalexi Jan 10, 2023
6bc2b5c
Adding tests
doakalexi Jan 10, 2023
efc5a50
Fixing query and addressing feedback
doakalexi Jan 10, 2023
a5363af
Merge branch 'main' into on-week/connectors-event-logs
doakalexi Jan 10, 2023
230659b
Merge branch 'main' of github.com:elastic/kibana into on-week/connect…
doakalexi Jan 10, 2023
af043d4
Fixing test failures
doakalexi Jan 11, 2023
46632f0
Merge branch 'on-week/connectors-event-logs' of github.com:doakalexi/…
doakalexi Jan 11, 2023
d60e829
UX changes
doakalexi Jan 11, 2023
2e75a9c
Merge branch 'main' into on-week/connectors-event-logs
doakalexi Jan 11, 2023
f933a09
Addresing pr feedback
doakalexi Jan 12, 2023
9741f88
Fixing failed tests
doakalexi Jan 12, 2023
e426d5b
Adding timed out
doakalexi Jan 13, 2023
b2c742a
Fixing updated aggregation test failures
doakalexi Jan 13, 2023
d6fd762
Fixing types
doakalexi Jan 13, 2023
94cb4dd
Fixing namespace and scrolling bugs
doakalexi Jan 13, 2023
60ffe27
Reverting duration changes
doakalexi Jan 13, 2023
b9cf11e
Merge branch 'main' into on-week/connectors-event-logs
doakalexi Jan 17, 2023
566619b
Changing from get to post
doakalexi Jan 17, 2023
4526a09
Merge branch 'on-week/connectors-event-logs' of github.com:doakalexi/…
doakalexi Jan 17, 2023
5be4c9a
Merge branch 'main' of github.com:elastic/kibana into on-week/connect…
doakalexi Jan 18, 2023
7982161
Merge branch 'main' of github.com:elastic/kibana into on-week/connect…
doakalexi Jan 18, 2023
5104f14
Addressing feedback
doakalexi Jan 18, 2023
cb9821b
Adding space agnostic filter
doakalexi Jan 18, 2023
ad8d2c4
Adding preconfigured to all the logs
doakalexi Jan 19, 2023
e3ed996
Adding connector id field
doakalexi Jan 19, 2023
148e496
Adding functional test
doakalexi Jan 19, 2023
975b39f
Fixing test failures
doakalexi Jan 19, 2023
2a46c93
Merge branch 'main' of github.com:elastic/kibana into on-week/connect…
doakalexi Jan 23, 2023
38e4176
Adding new tests
doakalexi Jan 23, 2023
b9debef
Added hook
doakalexi Jan 23, 2023
b7c1703
Added to the spaces hook
doakalexi Jan 23, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 61 additions & 0 deletions x-pack/plugins/actions/common/execution_log_types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

import { estypes } from '@elastic/elasticsearch';

export interface IExecutionLog {
id: string;
timestamp: string;
duration_ms: number;
status: string;
message: string;
version: string;
schedule_delay_ms: number;
space_ids: string[];
connector_name: string;
connector_id: string;
timed_out: boolean;
}

export interface IExecutionLogResult {
total: number;
data: IExecutionLog[];
}

export interface GetGlobalExecutionLogParams {
dateStart: string;
dateEnd?: string;
filter?: string;
page: number;
perPage: number;
sort: estypes.Sort;
namespaces?: Array<string | undefined>;
}

export interface GetGlobalExecutionKPIParams {
dateStart: string;
dateEnd?: string;
filter?: string;
namespaces?: Array<string | undefined>;
}

export const EMPTY_EXECUTION_KPI_RESULT = {
success: 0,
unknown: 0,
failure: 0,
warning: 0,
};

export type IExecutionKPIResult = typeof EMPTY_EXECUTION_KPI_RESULT;

export const executionLogSortableColumns = [
'timestamp',
'execution_duration',
'schedule_delay',
] as const;

export type ExecutionLogSortFields = typeof executionLogSortableColumns[number];
1 change: 1 addition & 0 deletions x-pack/plugins/actions/common/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export * from './rewrite_request_case';
export * from './mustache_template';
export * from './validate_email_addresses';
export * from './connector_feature_config';
export * from './execution_log_types';

export const BASE_ACTION_API_PATH = '/api/actions';
export const INTERNAL_BASE_ACTION_API_PATH = '/internal/actions';
Expand Down
2 changes: 2 additions & 0 deletions x-pack/plugins/actions/server/actions_client.mock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ const createActionsClientMock = () => {
listTypes: jest.fn(),
isActionTypeEnabled: jest.fn(),
isPreconfigured: jest.fn(),
getGlobalExecutionKpiWithAuth: jest.fn(),
getGlobalExecutionLogWithAuth: jest.fn(),
};
return mocked;
};
Expand Down
141 changes: 141 additions & 0 deletions x-pack/plugins/actions/server/actions_client.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ import { inMemoryMetricsMock } from './monitoring/in_memory_metrics.mock';
import { getOAuthJwtAccessToken } from './lib/get_oauth_jwt_access_token';
import { getOAuthClientCredentialsAccessToken } from './lib/get_oauth_client_credentials_access_token';
import { OAuthParams } from './routes/get_oauth_access_token';
import { eventLogClientMock } from '@kbn/event-log-plugin/server/event_log_client.mock';
import { GetGlobalExecutionKPIParams, GetGlobalExecutionLogParams } from '../common';

jest.mock('@kbn/core-saved-objects-utils-server', () => {
const actual = jest.requireActual('@kbn/core-saved-objects-utils-server');
Expand Down Expand Up @@ -81,6 +83,10 @@ jest.mock('./lib/get_oauth_client_credentials_access_token', () => ({
getOAuthClientCredentialsAccessToken: jest.fn(),
}));

jest.mock('uuid', () => ({
v4: () => 'uuidv4',
}));

const defaultKibanaIndex = '.kibana';
const unsecuredSavedObjectsClient = savedObjectsClientMock.create();
const scopedClusterClient = elasticsearchServiceMock.createScopedClusterClient();
Expand All @@ -96,6 +102,8 @@ const mockUsageCounter = mockUsageCountersSetup.createUsageCounter('test');
const logger = loggingSystemMock.create().get() as jest.Mocked<Logger>;
const mockTaskManager = taskManagerMock.createSetup();
const configurationUtilities = actionsConfigMock.create();
const eventLogClient = eventLogClientMock.create();
const getEventLogClient = jest.fn();

let actionsClient: ActionsClient;
let mockedLicenseState: jest.Mocked<ILicenseState>;
Expand Down Expand Up @@ -139,11 +147,13 @@ beforeEach(() => {
auditLogger,
usageCounter: mockUsageCounter,
connectorTokenClient,
getEventLogClient,
});
(getOAuthJwtAccessToken as jest.Mock).mockResolvedValue(`Bearer jwttokentokentoken`);
(getOAuthClientCredentialsAccessToken as jest.Mock).mockResolvedValue(
`Bearer clienttokentokentoken`
);
getEventLogClient.mockResolvedValue(eventLogClient);
});

describe('create()', () => {
Expand Down Expand Up @@ -566,6 +576,7 @@ describe('create()', () => {
request,
authorization: authorization as unknown as ActionsAuthorization,
connectorTokenClient: connectorTokenClientMock.create(),
getEventLogClient,
});

const savedObjectCreateResult = {
Expand Down Expand Up @@ -687,6 +698,7 @@ describe('get()', () => {
},
],
connectorTokenClient: connectorTokenClientMock.create(),
getEventLogClient,
});

await actionsClient.get({ id: 'testPreconfigured' });
Expand Down Expand Up @@ -747,6 +759,7 @@ describe('get()', () => {
},
],
connectorTokenClient: connectorTokenClientMock.create(),
getEventLogClient,
});

authorization.ensureAuthorized.mockRejectedValue(
Expand Down Expand Up @@ -869,6 +882,7 @@ describe('get()', () => {
},
],
connectorTokenClient: connectorTokenClientMock.create(),
getEventLogClient,
});

const result = await actionsClient.get({ id: 'testPreconfigured' });
Expand Down Expand Up @@ -942,6 +956,7 @@ describe('getAll()', () => {
},
],
connectorTokenClient: connectorTokenClientMock.create(),
getEventLogClient,
});
return actionsClient.getAll();
}
Expand Down Expand Up @@ -1084,6 +1099,7 @@ describe('getAll()', () => {
},
],
connectorTokenClient: connectorTokenClientMock.create(),
getEventLogClient,
});
const result = await actionsClient.getAll();
expect(result).toEqual([
Expand Down Expand Up @@ -1166,6 +1182,7 @@ describe('getBulk()', () => {
},
],
connectorTokenClient: connectorTokenClientMock.create(),
getEventLogClient,
});
return actionsClient.getBulk(['1', 'testPreconfigured']);
}
Expand Down Expand Up @@ -1302,6 +1319,7 @@ describe('getBulk()', () => {
},
],
connectorTokenClient: connectorTokenClientMock.create(),
getEventLogClient,
});
const result = await actionsClient.getBulk(['1', 'testPreconfigured']);
expect(result).toEqual([
Expand Down Expand Up @@ -1361,6 +1379,7 @@ describe('getOAuthAccessToken()', () => {
},
],
connectorTokenClient: connectorTokenClientMock.create(),
getEventLogClient,
});
return actionsClient.getOAuthAccessToken(requestBody, configurationUtilities);
}
Expand Down Expand Up @@ -2194,6 +2213,7 @@ describe('execute()', () => {

test('calls the actionExecutor with the appropriate parameters', async () => {
const actionId = uuidv4();
const actionExecutionId = uuidv4();
actionExecutor.execute.mockResolvedValue({ status: 'ok', actionId });
await expect(
actionsClient.execute({
Expand All @@ -2210,6 +2230,7 @@ describe('execute()', () => {
params: {
name: 'my name',
},
actionExecutionId,
});

await expect(
Expand Down Expand Up @@ -2241,6 +2262,7 @@ describe('execute()', () => {
type: 'some-type',
},
],
actionExecutionId,
});

await expect(
Expand Down Expand Up @@ -2274,6 +2296,7 @@ describe('execute()', () => {
namespace: 'some-namespace',
},
],
actionExecutionId,
});
});
});
Expand Down Expand Up @@ -2525,6 +2548,7 @@ describe('isPreconfigured()', () => {
encryptedSavedObjectsClient: encryptedSavedObjectsMock.createClient(),
logger,
}),
getEventLogClient,
});

expect(actionsClient.isPreconfigured('testPreconfigured')).toEqual(true);
Expand Down Expand Up @@ -2563,8 +2587,125 @@ describe('isPreconfigured()', () => {
encryptedSavedObjectsClient: encryptedSavedObjectsMock.createClient(),
logger,
}),
getEventLogClient,
});

expect(actionsClient.isPreconfigured(uuidv4())).toEqual(false);
});
});

describe('getGlobalExecutionLogWithAuth()', () => {
const opts: GetGlobalExecutionLogParams = {
dateStart: '2023-01-09T08:55:56-08:00',
dateEnd: '2023-01-10T08:55:56-08:00',
page: 1,
perPage: 50,
sort: [{ timestamp: { order: 'desc' } }],
};
const results = {
aggregations: {
executionLogAgg: {
doc_count: 5,
executionUuid: {
doc_count_error_upper_bound: 0,
sum_other_doc_count: 0,
buckets: [],
},
executionUuidCardinality: { doc_count: 5, executionUuidCardinality: { value: 5 } },
},
},
};
describe('authorization', () => {
test('ensures user is authorised to access logs', async () => {
eventLogClient.aggregateEventsWithAuthFilter.mockResolvedValue(results);

(getAuthorizationModeBySource as jest.Mock).mockImplementationOnce(() => {
return AuthorizationMode.RBAC;
});
await actionsClient.getGlobalExecutionLogWithAuth(opts);
expect(authorization.ensureAuthorized).toHaveBeenCalledWith('get');
});

test('throws when user is not authorised to access logs', async () => {
(getAuthorizationModeBySource as jest.Mock).mockImplementationOnce(() => {
return AuthorizationMode.RBAC;
});
authorization.ensureAuthorized.mockRejectedValue(new Error(`Unauthorized to access logs`));

await expect(actionsClient.getGlobalExecutionLogWithAuth(opts)).rejects.toMatchInlineSnapshot(
`[Error: Unauthorized to access logs]`
);

expect(authorization.ensureAuthorized).toHaveBeenCalledWith('get');
});
});

test('calls the eventLogClient with the appropriate parameters', async () => {
eventLogClient.aggregateEventsWithAuthFilter.mockResolvedValue(results);

await expect(actionsClient.getGlobalExecutionLogWithAuth(opts)).resolves.toMatchInlineSnapshot(`
Object {
"data": Array [],
"total": 5,
}
`);
expect(eventLogClient.aggregateEventsWithAuthFilter).toHaveBeenCalled();
});
});

describe('getGlobalExecutionKpiWithAuth()', () => {
const opts: GetGlobalExecutionKPIParams = {
dateStart: '2023-01-09T08:55:56-08:00',
dateEnd: '2023-01-10T08:55:56-08:00',
};
const results = {
aggregations: {
executionKpiAgg: {
doc_count: 5,
executionUuid: {
doc_count_error_upper_bound: 0,
sum_other_doc_count: 0,
buckets: [],
},
},
},
};
describe('authorization', () => {
test('ensures user is authorised to access kpi', async () => {
eventLogClient.aggregateEventsWithAuthFilter.mockResolvedValue(results);

(getAuthorizationModeBySource as jest.Mock).mockImplementationOnce(() => {
return AuthorizationMode.RBAC;
});
await actionsClient.getGlobalExecutionKpiWithAuth(opts);
expect(authorization.ensureAuthorized).toHaveBeenCalledWith('get');
});

test('throws when user is not authorised to access kpi', async () => {
(getAuthorizationModeBySource as jest.Mock).mockImplementationOnce(() => {
return AuthorizationMode.RBAC;
});
authorization.ensureAuthorized.mockRejectedValue(new Error(`Unauthorized to access kpi`));

await expect(actionsClient.getGlobalExecutionKpiWithAuth(opts)).rejects.toMatchInlineSnapshot(
`[Error: Unauthorized to access kpi]`
);

expect(authorization.ensureAuthorized).toHaveBeenCalledWith('get');
});
});

test('calls the eventLogClient with the appropriate parameters', async () => {
eventLogClient.aggregateEventsWithAuthFilter.mockResolvedValue(results);

await expect(actionsClient.getGlobalExecutionKpiWithAuth(opts)).resolves.toMatchInlineSnapshot(`
Object {
"failure": 0,
"success": 0,
"unknown": 0,
"warning": 0,
}
`);
expect(eventLogClient.aggregateEventsWithAuthFilter).toHaveBeenCalled();
});
});
Loading