Skip to content

Commit

Permalink
[SecuritySolution][DataQualityDashboard] Migrate data quality dashboa…
Browse files Browse the repository at this point in the history
…rd APIs to versioned router (#169037)

## Summary

#168334
#166271


Before:

<img width="2560" alt="Screenshot 2023-10-16 at 21 45 02"
src="https://github.com/elastic/kibana/assets/6295984/2945179a-fb5b-4946-8b51-4769d20ad30f">
<img width="2558" alt="Screenshot 2023-10-16 at 21 45 09"
src="https://github.com/elastic/kibana/assets/6295984/254e00dd-bee9-4325-b418-e7ee481dea5d">

After:

<img width="2546" alt="Screenshot 2023-10-16 at 22 41 31"
src="https://github.com/elastic/kibana/assets/6295984/166a99a0-6f28-453a-a785-1197508170b5">

---------

Co-authored-by: kibanamachine <[email protected]>
angorayc and kibanamachine authored Oct 17, 2023
1 parent 0554daa commit 843aaf2
Showing 21 changed files with 285 additions and 167 deletions.
Original file line number Diff line number Diff line change
@@ -27,6 +27,7 @@ import type {
} from './types';

const EMPTY_INDEX_NAMES: string[] = [];
export const INTERNAL_API_VERSION = '1';

export const getIndexNames = ({
ilmExplain,
@@ -282,7 +283,7 @@ export const getSizeInBytes = ({
}: {
indexName: string;
stats: Record<string, IndicesStatsIndicesStats> | null;
}): number => (stats && stats[indexName]?.primaries?.store?.size_in_bytes) ?? 0;
}): number => (stats && stats[indexName]?.primaries?.store?.total_data_set_size_in_bytes) ?? 0;

export const getTotalDocsCount = ({
indexNames,
Original file line number Diff line number Diff line change
@@ -53,6 +53,7 @@ export const auditbeatNoResults: PatternRollup = {
primaries: {
store: {
size_in_bytes: 18791790,
total_data_set_size_in_bytes: 18791790,
reserved_in_bytes: 0,
},
},
@@ -70,6 +71,7 @@ export const auditbeatNoResults: PatternRollup = {
primaries: {
store: {
size_in_bytes: 247,
total_data_set_size_in_bytes: 247,
reserved_in_bytes: 0,
},
},
@@ -87,6 +89,7 @@ export const auditbeatNoResults: PatternRollup = {
primaries: {
store: {
size_in_bytes: 28409,
total_data_set_size_in_bytes: 28409,
reserved_in_bytes: 0,
},
},
@@ -182,6 +185,7 @@ export const auditbeatWithAllResults: PatternRollup = {
primaries: {
store: {
size_in_bytes: 18791790,
total_data_set_size_in_bytes: 18791790,
reserved_in_bytes: 0,
},
},
@@ -199,6 +203,7 @@ export const auditbeatWithAllResults: PatternRollup = {
primaries: {
store: {
size_in_bytes: 247,
total_data_set_size_in_bytes: 247,
reserved_in_bytes: 0,
},
},
@@ -216,6 +221,7 @@ export const auditbeatWithAllResults: PatternRollup = {
primaries: {
store: {
size_in_bytes: 28409,
total_data_set_size_in_bytes: 28409,
reserved_in_bytes: 0,
},
},
Original file line number Diff line number Diff line change
@@ -51,6 +51,7 @@ export const packetbeatNoResults: PatternRollup = {
primaries: {
store: {
size_in_bytes: 512194751,
total_data_set_size_in_bytes: 512194751,
reserved_in_bytes: 0,
},
},
@@ -68,6 +69,7 @@ export const packetbeatNoResults: PatternRollup = {
primaries: {
store: {
size_in_bytes: 584326147,
total_data_set_size_in_bytes: 584326147,
reserved_in_bytes: 0,
},
},
Original file line number Diff line number Diff line change
@@ -9,6 +9,7 @@ import type { IlmExplainLifecycleLifecycleExplain } from '@elastic/elasticsearch
import { useEffect, useState } from 'react';

import { useDataQualityContext } from '../data_quality_panel/data_quality_context';
import { INTERNAL_API_VERSION } from '../helpers';
import * as i18n from '../translations';

const ILM_EXPLAIN_ENDPOINT = '/internal/ecs_data_quality_dashboard/ilm_explain';
@@ -43,6 +44,7 @@ export const useIlmExplain = (pattern: string): UseIlmExplain => {
{
method: 'GET',
signal: abortController.signal,
version: INTERNAL_API_VERSION,
}
);

Original file line number Diff line number Diff line change
@@ -9,6 +9,7 @@ import type { HttpHandler } from '@kbn/core-http-browser';
import type { IndicesGetMappingIndexMappingRecord } from '@elastic/elasticsearch/lib/api/types';

import * as i18n from '../translations';
import { INTERNAL_API_VERSION } from '../helpers';

export const MAPPINGS_API_ROUTE = '/internal/ecs_data_quality_dashboard/mappings';

@@ -29,6 +30,7 @@ export async function fetchMappings({
{
method: 'GET',
signal: abortController.signal,
version: INTERNAL_API_VERSION,
}
);
} catch (e) {
Original file line number Diff line number Diff line change
@@ -11,6 +11,7 @@ import { HttpFetchQuery } from '@kbn/core/public';

import { useDataQualityContext } from '../data_quality_panel/data_quality_context';
import * as i18n from '../translations';
import { INTERNAL_API_VERSION } from '../helpers';

const STATS_ENDPOINT = '/internal/ecs_data_quality_dashboard/stats';

@@ -53,6 +54,7 @@ export const useStats = ({
const response = await httpFetch<Record<string, IndicesStatsIndicesStats>>(
`${STATS_ENDPOINT}/${encodedIndexName}`,
{
version: INTERNAL_API_VERSION,
method: 'GET',
signal: abortController.signal,
query,
Original file line number Diff line number Diff line change
@@ -15,6 +15,7 @@ import {
} from './helpers';
import { mockUnallowedValuesResponse } from '../mock/unallowed_values/mock_unallowed_values';
import { UnallowedValueRequestItem, UnallowedValueSearchResult } from '../types';
import { INTERNAL_API_VERSION } from '../helpers';

describe('helpers', () => {
let originalFetch: typeof global['fetch'];
@@ -406,6 +407,7 @@ describe('helpers', () => {
headers: { 'Content-Type': 'application/json' },
method: 'POST',
signal: abortController.signal,
version: INTERNAL_API_VERSION,
}
);
});
Original file line number Diff line number Diff line change
@@ -6,6 +6,7 @@
*/

import type { HttpHandler } from '@kbn/core-http-browser';
import { INTERNAL_API_VERSION } from '../helpers';
import * as i18n from '../translations';
import type {
Bucket,
@@ -81,6 +82,7 @@ export async function fetchUnallowedValues({
headers: { 'Content-Type': 'application/json' },
method: 'POST',
signal: abortController.signal,
version: INTERNAL_API_VERSION,
});
} catch (e) {
throw new Error(
Original file line number Diff line number Diff line change
@@ -13,3 +13,4 @@ export const GET_INDEX_STATS = `${BASE_PATH}/stats/{pattern}`;
export const GET_INDEX_MAPPINGS = `${BASE_PATH}/mappings/{pattern}`;
export const GET_UNALLOWED_FIELD_VALUES = `${BASE_PATH}/unallowed_field_values`;
export const GET_ILM_EXPLAIN = `${BASE_PATH}/ilm_explain/{pattern}`;
export const INTERNAL_API_VERSION = '1';
Original file line number Diff line number Diff line change
@@ -5,35 +5,73 @@
* 2.0.
*/
import { httpServiceMock } from '@kbn/core/server/mocks';
import type { RequestHandler, RouteConfig, KibanaRequest } from '@kbn/core/server';
import type { IRouter, RouteMethod, RequestHandler, KibanaRequest } from '@kbn/core/server';
import type { RequestHandlerContext } from '@kbn/core-http-request-handler-context-server';
import type { RouterMock } from '@kbn/core-http-router-server-mocks';
import type { AddVersionOpts, VersionedRouteConfig } from '@kbn/core-http-server';

import { requestMock } from './request';
import { responseMock as responseFactoryMock } from './response';
import { requestContextMock } from './request_context';
import { responseAdapter } from './test_adapters';
import { INTERNAL_API_VERSION } from '../../common/constants';

interface Route {
config: RouteConfig<unknown, unknown, unknown, 'get' | 'post' | 'delete' | 'patch' | 'put'>;
config: AddVersionOpts<unknown, unknown, unknown>;
handler: RequestHandler;
}

const getRoute = (routerMock: MockServer['router']): Route => {
const routeCalls = [
...routerMock.get.mock.calls,
...routerMock.post.mock.calls,
...routerMock.put.mock.calls,
...routerMock.patch.mock.calls,
...routerMock.delete.mock.calls,
interface RegisteredVersionedRoute {
routeConfig: VersionedRouteConfig<RouterMethod>;
versionConfig: AddVersionOpts<unknown, unknown, unknown>;
routeHandler: RequestHandler;
}

type RouterMethod = Extract<keyof IRouter, RouteMethod>;

export const getRegisteredVersionedRouteMock = (
routerMock: RouterMock,
method: RouterMethod,
path: string,
version: string
): RegisteredVersionedRoute => {
const route = routerMock.versioned.getRoute(method, path);
const routeVersion = route.versions[version];

if (!routeVersion) {
throw new Error(`Handler for [${method}][${path}] with version [${version}] no found!`);
}

return {
routeConfig: route.config,
versionConfig: routeVersion.config,
routeHandler: routeVersion.handler,
};
};

const getRoute = (routerMock: MockServer['router'], request: KibanaRequest): Route => {
const versionedRouteCalls = [
...routerMock.versioned.get.mock.calls,
...routerMock.versioned.post.mock.calls,
...routerMock.versioned.put.mock.calls,
...routerMock.versioned.patch.mock.calls,
...routerMock.versioned.delete.mock.calls,
];

const [route] = routeCalls;
if (!route) {
const [versionedRoute] = versionedRouteCalls;

if (!versionedRoute) {
throw new Error('No route registered!');
}

const [config, handler] = route;
return { config, handler };
const { routeHandler, versionConfig } = getRegisteredVersionedRouteMock(
routerMock,
request.route.method,
request.route.path,
INTERNAL_API_VERSION
);

return { config: versionConfig, handler: routeHandler };
};

const buildResultMock = () => ({ ok: jest.fn((x) => x), badRequest: jest.fn((x) => x) });
@@ -53,17 +91,19 @@ class MockServer {

public async inject(request: KibanaRequest, context: RequestHandlerContext = this.contextMock) {
const validatedRequest = this.validateRequest(request);

const [rejection] = this.resultMock.badRequest.mock.calls;
if (rejection) {
throw new Error(`Request was rejected with message: '${rejection}'`);
}

await this.getRoute().handler(context, validatedRequest, this.responseMock);
await this.getRoute(validatedRequest).handler(context, validatedRequest, this.responseMock);

return responseAdapter(this.responseMock);
}

private getRoute(): Route {
return getRoute(this.router);
private getRoute(request: KibanaRequest): Route {
return getRoute(this.router, request);
}

// eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -72,7 +112,8 @@ class MockServer {
}

private validateRequest(request: KibanaRequest): KibanaRequest {
const validations = this.getRoute().config.validate;
const config = this.getRoute(request).config;
const validations = config.validate && config.validate?.request;
if (!validations) {
return request;
}
8 changes: 4 additions & 4 deletions x-pack/plugins/ecs_data_quality_dashboard/server/plugin.ts
Original file line number Diff line number Diff line change
@@ -29,10 +29,10 @@ export class EcsDataQualityDashboardPlugin
const router = core.http.createRouter(); // this would be deleted when plugin is removed

// Register server side APIs
getIndexMappingsRoute(router);
getIndexStatsRoute(router);
getUnallowedFieldValuesRoute(router);
getILMExplainRoute(router);
getIndexMappingsRoute(router, this.logger);
getIndexStatsRoute(router, this.logger);
getUnallowedFieldValuesRoute(router, this.logger);
getILMExplainRoute(router, this.logger);
return {};
}

Original file line number Diff line number Diff line change
@@ -12,6 +12,7 @@ import { serverMock } from '../__mocks__/server';
import { requestMock } from '../__mocks__/request';
import { requestContextMock } from '../__mocks__/request_context';
import { getILMExplainRoute } from './get_ilm_explain';
import { loggerMock, MockedLogger } from '@kbn/logging-mocks';

jest.mock('../lib', () => ({
fetchILMExplain: jest.fn(),
@@ -20,6 +21,8 @@ jest.mock('../lib', () => ({
describe('getILMExplainRoute route', () => {
let server: ReturnType<typeof serverMock.create>;
let { context } = requestContextMock.createTools();
let logger: MockedLogger;

const req = requestMock.create({
method: 'get',
path: GET_ILM_EXPLAIN,
@@ -32,9 +35,10 @@ describe('getILMExplainRoute route', () => {
jest.clearAllMocks();

server = serverMock.create();
logger = loggerMock.create();
({ context } = requestContextMock.createTools());

getILMExplainRoute(server.router);
getILMExplainRoute(server.router, logger);
});

test('Returns index ilm information', async () => {
@@ -91,11 +95,13 @@ describe('getILMExplainRoute route', () => {

describe('request validation', () => {
let server: ReturnType<typeof serverMock.create>;
let logger: MockedLogger;

beforeEach(() => {
server = serverMock.create();
logger = loggerMock.create();

getILMExplainRoute(server.router);
getILMExplainRoute(server.router, logger);
});

test('disallows invalid pattern', () => {
Original file line number Diff line number Diff line change
@@ -5,41 +5,51 @@
* 2.0.
*/

import { IRouter } from '@kbn/core/server';
import { IRouter, Logger } from '@kbn/core/server';
import { transformError } from '@kbn/securitysolution-es-utils';

import { GET_ILM_EXPLAIN } from '../../common/constants';
import { GET_ILM_EXPLAIN, INTERNAL_API_VERSION } from '../../common/constants';
import { fetchILMExplain } from '../lib';
import { buildResponse } from '../lib/build_response';
import { buildRouteValidation } from '../schemas/common';
import { GetILMExplainParams } from '../schemas/get_ilm_explain';

export const getILMExplainRoute = (router: IRouter) => {
router.get(
{
export const getILMExplainRoute = (router: IRouter, logger: Logger) => {
router.versioned
.get({
path: GET_ILM_EXPLAIN,
validate: { params: buildRouteValidation(GetILMExplainParams) },
},
async (context, request, response) => {
const resp = buildResponse(response);
access: 'internal',
})
.addVersion(
{
version: INTERNAL_API_VERSION,
validate: {
request: {
params: buildRouteValidation(GetILMExplainParams),
},
},
},
async (context, request, response) => {
const resp = buildResponse(response);

try {
const { client } = (await context.core).elasticsearch;
const decodedIndexName = decodeURIComponent(request.params.pattern);
try {
const { client } = (await context.core).elasticsearch;
const decodedIndexName = decodeURIComponent(request.params.pattern);

const ilmExplain = await fetchILMExplain(client, decodedIndexName);
const ilmExplain = await fetchILMExplain(client, decodedIndexName);

return response.ok({
body: ilmExplain.indices,
});
} catch (err) {
const error = transformError(err);
return response.ok({
body: ilmExplain.indices,
});
} catch (err) {
const error = transformError(err);

return resp.error({
body: error.message,
statusCode: error.statusCode,
});
logger.error(error.message);
return resp.error({
body: error.message,
statusCode: error.statusCode,
});
}
}
}
);
);
};
Original file line number Diff line number Diff line change
@@ -12,6 +12,7 @@ import { serverMock } from '../__mocks__/server';
import { requestMock } from '../__mocks__/request';
import { requestContextMock } from '../__mocks__/request_context';
import { getIndexMappingsRoute } from './get_index_mappings';
import { loggerMock, MockedLogger } from '@kbn/logging-mocks';

jest.mock('../lib', () => ({
fetchMappings: jest.fn(),
@@ -20,6 +21,8 @@ jest.mock('../lib', () => ({
describe('getIndexMappingsRoute route', () => {
let server: ReturnType<typeof serverMock.create>;
let { context } = requestContextMock.createTools();
let logger: MockedLogger;

const req = requestMock.create({
method: 'get',
path: GET_INDEX_MAPPINGS,
@@ -32,9 +35,11 @@ describe('getIndexMappingsRoute route', () => {
jest.clearAllMocks();

server = serverMock.create();
logger = loggerMock.create();

({ context } = requestContextMock.createTools());

getIndexMappingsRoute(server.router);
getIndexMappingsRoute(server.router, logger);
});

test('Returns index stats', async () => {
@@ -58,11 +63,11 @@ describe('getIndexMappingsRoute route', () => {

describe('request validation', () => {
let server: ReturnType<typeof serverMock.create>;

let logger: MockedLogger;
beforeEach(() => {
server = serverMock.create();

getIndexMappingsRoute(server.router);
logger = loggerMock.create();
getIndexMappingsRoute(server.router, logger);
});

test('disallows invalid pattern', () => {
Original file line number Diff line number Diff line change
@@ -5,41 +5,47 @@
* 2.0.
*/

import { IRouter } from '@kbn/core/server';
import { IRouter, Logger } from '@kbn/core/server';
import { transformError } from '@kbn/securitysolution-es-utils';

import { fetchMappings } from '../lib';
import { buildResponse } from '../lib/build_response';
import { GET_INDEX_MAPPINGS } from '../../common/constants';
import { GET_INDEX_MAPPINGS, INTERNAL_API_VERSION } from '../../common/constants';
import { GetIndexMappingsParams } from '../schemas/get_index_mappings';
import { buildRouteValidation } from '../schemas/common';

export const getIndexMappingsRoute = (router: IRouter) => {
router.get(
{
export const getIndexMappingsRoute = (router: IRouter, logger: Logger) => {
router.versioned
.get({
path: GET_INDEX_MAPPINGS,
validate: { params: buildRouteValidation(GetIndexMappingsParams) },
},
async (context, request, response) => {
const resp = buildResponse(response);
access: 'internal',
})
.addVersion(
{
version: INTERNAL_API_VERSION,
validate: { request: { params: buildRouteValidation(GetIndexMappingsParams) } },
},
async (context, request, response) => {
const resp = buildResponse(response);

try {
const { client } = (await context.core).elasticsearch;
const decodedIndexName = decodeURIComponent(request.params.pattern);
try {
const { client } = (await context.core).elasticsearch;
const decodedIndexName = decodeURIComponent(request.params.pattern);

const mappings = await fetchMappings(client, decodedIndexName);
const mappings = await fetchMappings(client, decodedIndexName);

return response.ok({
body: mappings,
});
} catch (err) {
const error = transformError(err);
return response.ok({
body: mappings,
});
} catch (err) {
const error = transformError(err);
logger.error(error.message);

return resp.error({
body: error.message,
statusCode: error.statusCode,
});
return resp.error({
body: error.message,
statusCode: error.statusCode,
});
}
}
}
);
);
};
Original file line number Diff line number Diff line change
@@ -12,6 +12,7 @@ import { serverMock } from '../__mocks__/server';
import { requestMock } from '../__mocks__/request';
import { requestContextMock } from '../__mocks__/request_context';
import { getIndexStatsRoute } from './get_index_stats';
import { loggerMock, MockedLogger } from '@kbn/logging-mocks';

jest.mock('../lib', () => ({
fetchStats: jest.fn(),
@@ -21,6 +22,8 @@ jest.mock('../lib', () => ({
describe('getIndexStatsRoute route', () => {
let server: ReturnType<typeof serverMock.create>;
let { context } = requestContextMock.createTools();
let logger: MockedLogger;

const req = requestMock.create({
method: 'get',
path: GET_INDEX_STATS,
@@ -38,9 +41,11 @@ describe('getIndexStatsRoute route', () => {
jest.clearAllMocks();

server = serverMock.create();
logger = loggerMock.create();

({ context } = requestContextMock.createTools());

getIndexStatsRoute(server.router);
getIndexStatsRoute(server.router, logger);
});

test('Returns index stats', async () => {
@@ -127,11 +132,13 @@ describe('getIndexStatsRoute route', () => {

describe('request validation', () => {
let server: ReturnType<typeof serverMock.create>;
let logger: MockedLogger;

beforeEach(() => {
server = serverMock.create();
logger = loggerMock.create();

getIndexStatsRoute(server.router);
getIndexStatsRoute(server.router, logger);
});

test('disallows invalid pattern', () => {
Original file line number Diff line number Diff line change
@@ -5,87 +5,96 @@
* 2.0.
*/
import { i18n } from '@kbn/i18n';
import { IRouter } from '@kbn/core/server';
import { IRouter, Logger } from '@kbn/core/server';
import { transformError } from '@kbn/securitysolution-es-utils';

import { IndicesStatsIndicesStats } from '@elastic/elasticsearch/lib/api/types';
import { fetchStats, fetchAvailableIndices } from '../lib';
import { buildResponse } from '../lib/build_response';
import { GET_INDEX_STATS } from '../../common/constants';
import { GET_INDEX_STATS, INTERNAL_API_VERSION } from '../../common/constants';
import { buildRouteValidation } from '../schemas/common';
import { GetIndexStatsParams, GetIndexStatsQuery } from '../schemas/get_index_stats';

export const getIndexStatsRoute = (router: IRouter) => {
router.get(
{
export const getIndexStatsRoute = (router: IRouter, logger: Logger) => {
router.versioned
.get({
path: GET_INDEX_STATS,
validate: {
params: buildRouteValidation(GetIndexStatsParams),
query: buildRouteValidation(GetIndexStatsQuery),
access: 'internal',
})
.addVersion(
{
version: INTERNAL_API_VERSION,
validate: {
request: {
params: buildRouteValidation(GetIndexStatsParams),
query: buildRouteValidation(GetIndexStatsQuery),
},
},
},
},
async (context, request, response) => {
const resp = buildResponse(response);
async (context, request, response) => {
const resp = buildResponse(response);

try {
const { client } = (await context.core).elasticsearch;
const esClient = client.asCurrentUser;
try {
const { client } = (await context.core).elasticsearch;
const esClient = client.asCurrentUser;

const decodedIndexName = decodeURIComponent(request.params.pattern);
const decodedIndexName = decodeURIComponent(request.params.pattern);

const stats = await fetchStats(client, decodedIndexName);
const { isILMAvailable, startDate, endDate } = request.query;
const stats = await fetchStats(client, decodedIndexName);
const { isILMAvailable, startDate, endDate } = request.query;

if (isILMAvailable === true) {
return response.ok({
body: stats.indices,
});
}
if (isILMAvailable === true) {
return response.ok({
body: stats.indices,
});
}

/**
* If ILM is not available, we need to fetch the available indices with the given date range.
* `fetchAvailableIndices` returns indices that have data in the given date range.
*/
if (startDate && endDate) {
const decodedStartDate = decodeURIComponent(startDate);
const decodedEndDate = decodeURIComponent(endDate);
/**
* If ILM is not available, we need to fetch the available indices with the given date range.
* `fetchAvailableIndices` returns indices that have data in the given date range.
*/
if (startDate && endDate) {
const decodedStartDate = decodeURIComponent(startDate);
const decodedEndDate = decodeURIComponent(endDate);

const indices = await fetchAvailableIndices(esClient, {
indexPattern: decodedIndexName,
startDate: decodedStartDate,
endDate: decodedEndDate,
});
const availableIndices = indices?.aggregations?.index?.buckets?.reduce(
(acc: Record<string, IndicesStatsIndicesStats>, { key }: { key: string }) => {
if (stats.indices?.[key]) {
acc[key] = stats.indices?.[key];
}
return acc;
},
{}
);
const indices = await fetchAvailableIndices(esClient, {
indexPattern: decodedIndexName,
startDate: decodedStartDate,
endDate: decodedEndDate,
});
const availableIndices = indices?.aggregations?.index?.buckets?.reduce(
(acc: Record<string, IndicesStatsIndicesStats>, { key }: { key: string }) => {
if (stats.indices?.[key]) {
acc[key] = stats.indices?.[key];
}
return acc;
},
{}
);

return response.ok({
body: availableIndices,
});
} else {
return resp.error({
body: i18n.translate(
'xpack.ecsDataQualityDashboard.getIndexStats.dateRangeRequiredErrorMessage',
{
defaultMessage: 'startDate and endDate are required',
}
),
statusCode: 400,
});
}
} catch (err) {
const error = transformError(err);
logger.error(error.message);

return response.ok({
body: availableIndices,
});
} else {
return resp.error({
body: i18n.translate(
'xpack.ecsDataQualityDashboard.getIndexStats.dateRangeRequiredErrorMessage',
{
defaultMessage: 'startDate and endDate are required',
}
),
statusCode: 400,
body: error.message,
statusCode: error.statusCode,
});
}
} catch (err) {
const error = transformError(err);
return resp.error({
body: error.message,
statusCode: error.statusCode,
});
}
}
);
);
};
Original file line number Diff line number Diff line change
@@ -12,6 +12,7 @@ import { serverMock } from '../__mocks__/server';
import { requestMock } from '../__mocks__/request';
import { requestContextMock } from '../__mocks__/request_context';
import { getUnallowedFieldValuesRoute } from './get_unallowed_field_values';
import { loggerMock, MockedLogger } from '@kbn/logging-mocks';

jest.mock('../lib', () => ({
getUnallowedFieldValues: jest.fn(),
@@ -20,6 +21,8 @@ jest.mock('../lib', () => ({
describe('getUnallowedFieldValuesRoute route', () => {
let server: ReturnType<typeof serverMock.create>;
let { context } = requestContextMock.createTools();
let logger: MockedLogger;

const req = requestMock.create({
method: 'post',
path: GET_UNALLOWED_FIELD_VALUES,
@@ -37,8 +40,9 @@ describe('getUnallowedFieldValuesRoute route', () => {

server = serverMock.create();
({ context } = requestContextMock.createTools());
logger = loggerMock.create();

getUnallowedFieldValuesRoute(server.router);
getUnallowedFieldValuesRoute(server.router, logger);
});

test('Returns unallowedValues', async () => {
@@ -107,11 +111,13 @@ describe('getUnallowedFieldValuesRoute route', () => {

describe('request validation', () => {
let server: ReturnType<typeof serverMock.create>;
let logger: MockedLogger;

beforeEach(() => {
server = serverMock.create();
logger = loggerMock.create();

getUnallowedFieldValuesRoute(server.router);
getUnallowedFieldValuesRoute(server.router, logger);
});

test('disallows invalid pattern', () => {
Original file line number Diff line number Diff line change
@@ -5,40 +5,46 @@
* 2.0.
*/

import { IRouter } from '@kbn/core/server';
import { IRouter, Logger } from '@kbn/core/server';
import { transformError } from '@kbn/securitysolution-es-utils';

import { getUnallowedFieldValues } from '../lib';
import { buildResponse } from '../lib/build_response';
import { GET_UNALLOWED_FIELD_VALUES } from '../../common/constants';
import { GET_UNALLOWED_FIELD_VALUES, INTERNAL_API_VERSION } from '../../common/constants';
import { buildRouteValidation } from '../schemas/common';
import { GetUnallowedFieldValuesBody } from '../schemas/get_unallowed_field_values';

export const getUnallowedFieldValuesRoute = (router: IRouter) => {
router.post(
{
export const getUnallowedFieldValuesRoute = (router: IRouter, logger: Logger) => {
router.versioned
.post({
path: GET_UNALLOWED_FIELD_VALUES,
validate: { body: buildRouteValidation(GetUnallowedFieldValuesBody) },
},
async (context, request, response) => {
const resp = buildResponse(response);
const esClient = (await context.core).elasticsearch.client.asCurrentUser;
access: 'internal',
})
.addVersion(
{
version: INTERNAL_API_VERSION,
validate: { request: { body: buildRouteValidation(GetUnallowedFieldValuesBody) } },
},
async (context, request, response) => {
const resp = buildResponse(response);
const esClient = (await context.core).elasticsearch.client.asCurrentUser;

try {
const items = request.body;
try {
const items = request.body;

const { responses } = await getUnallowedFieldValues(esClient, items);
return response.ok({
body: responses,
});
} catch (err) {
const error = transformError(err);
const { responses } = await getUnallowedFieldValues(esClient, items);
return response.ok({
body: responses,
});
} catch (err) {
const error = transformError(err);
logger.error(error.message);

return resp.error({
body: error.message,
statusCode: error.statusCode,
});
return resp.error({
body: error.message,
statusCode: error.statusCode,
});
}
}
}
);
);
};
Original file line number Diff line number Diff line change
@@ -7,7 +7,7 @@

import { fold } from 'fp-ts/lib/Either';
import { pipe } from 'fp-ts/lib/pipeable';
import type * as rt from 'io-ts';
import * as rt from 'io-ts';
import { exactCheck, formatErrors } from '@kbn/securitysolution-io-ts-utils';
import type {
RouteValidationFunction,
2 changes: 2 additions & 0 deletions x-pack/plugins/ecs_data_quality_dashboard/tsconfig.json
Original file line number Diff line number Diff line change
@@ -20,6 +20,8 @@
"@kbn/securitysolution-io-ts-utils",
"@kbn/securitysolution-io-ts-types",
"@kbn/i18n",
"@kbn/core-http-router-server-mocks",
"@kbn/logging-mocks",
],
"exclude": [
"target/**/*",

0 comments on commit 843aaf2

Please sign in to comment.