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

[Endpoint] EMT-65: make endpoint data types common, restructure #54772

46 changes: 46 additions & 0 deletions x-pack/plugins/endpoint/common/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/

export class EndpointAppConstants {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you mean to move a Class to this types.ts file? I don't see the FE needing it

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@nnamdifrankie see my prior comment here. I don't think you should have a Class in this file (maybe you meant interface?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think @nnamdifrankie is defining constants here, not types necessarily. So I would say that maybe we could move this somewhere else, if we're trying to have this file contain and export types for the app.

static ENDPOINT_INDEX_NAME = 'endpoint-agent*';
}

export interface EndpointResultList {
// the endpoint restricted by the page size
endpoints: EndpointMetadata[];
// the total number of unique endpoints in the index
total: number;
// the page size requested
request_page_size: number;
// the index requested
request_page_index: number;
}

export interface EndpointMetadata {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My last concern, @peluja1012 has a PR where types are being handled a bit differently: https://github.com/elastic/kibana/pull/55800/files#diff-a19f3a4b9567cb1b06760465a6a74d43R25

That PR is using type as opposed to interface.

Thoughts @paul-tavares @peluja1012 @nnamdifrankie @oatkiller

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kevinlog I could be wrong, but I think that when you define a type directly as an object, the (ESLint) formater automatically converts it to an Interface.
The PR you reference is actually assigning a type to another Type (Immutable), thus why I think its ok there. (maybe?? 🤷‍♂ 😄 )

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kevinlog I do not think we should be mixing this two. I prefer the interface and it is advised not to mix both. I think type is good for shorthand or derived type definition.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

got it. still though, we discussed getting everything across the app into a common types file until we need to break things out. Would it still make sense to follow the same pattern for defining an endpoint metadata response and an alert response?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kevinlog like Paul said, the linter will automatically convert types to interfaces when possible, so you probably don't need to think about it.

Copy link
Contributor

@kevinlog kevinlog Jan 27, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@paul-tavares @oatkiller thanks for the knowledge and responses, lgtm then

event: {
created: string;
};
endpoint: {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think endpoint is the correct term to use here. endpoint is the code that is running on the computer. It seems the keys in this endpoint should be moved to host.

policy: {
id: string;
};
};
agent: {
version: string;
id: string;
};
host: {
id: string;
hostname: string;
ip: string[];
mac: string[];
os: {
name: string;
full: string;
version: string;
};
};
}
2 changes: 1 addition & 1 deletion x-pack/plugins/endpoint/server/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ import { first } from 'rxjs/operators';
import { addRoutes } from './routes';
import { PluginSetupContract as FeaturesPluginSetupContract } from '../../features/server';
import { createConfig$, EndpointConfigType } from './config';
import { EndpointAppContext } from './types';
import { registerEndpointRoutes } from './routes/endpoints';
import { EndpointAppContext } from './types';

export type EndpointPluginStart = void;
export type EndpointPluginSetup = void;
Expand Down
22 changes: 11 additions & 11 deletions x-pack/plugins/endpoint/server/routes/endpoints.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@ import {
httpServiceMock,
loggingServiceMock,
} from '../../../../../src/core/server/mocks';
import { EndpointData } from '../types';
import { EndpointMetadata, EndpointResultList } from '../../common/types';
import { SearchResponse } from 'elasticsearch';
import { EndpointResultList, registerEndpointRoutes } from './endpoints';
import { registerEndpointRoutes } from './endpoints';
import { EndpointConfigSchema } from '../config';
import * as data from '../test_data/all_endpoints_data.json';

Expand Down Expand Up @@ -49,8 +49,8 @@ describe('test endpoint route', () => {
it('test find the latest of all endpoints', async () => {
const mockRequest = httpServerMock.createKibanaRequest({});

const response: SearchResponse<EndpointData> = (data as unknown) as SearchResponse<
EndpointData
const response: SearchResponse<EndpointMetadata> = (data as unknown) as SearchResponse<
EndpointMetadata
>;
mockScopedClient.callAsCurrentUser.mockImplementationOnce(() => Promise.resolve(response));
[routeConfig, routeHandler] = routerMock.post.mock.calls.find(([{ path }]) =>
Expand All @@ -73,9 +73,9 @@ describe('test endpoint route', () => {
expect(routeConfig.options).toEqual({ authRequired: true });
expect(mockResponse.ok).toBeCalled();
const endpointResultList = mockResponse.ok.mock.calls[0][0]?.body as EndpointResultList;
expect(endpointResultList.endpoints.length).toEqual(3);
expect(endpointResultList.total).toEqual(3);
expect(endpointResultList.request_index).toEqual(0);
expect(endpointResultList.endpoints.length).toEqual(2);
expect(endpointResultList.total).toEqual(2);
expect(endpointResultList.request_page_index).toEqual(0);
expect(endpointResultList.request_page_size).toEqual(10);
});

Expand All @@ -93,7 +93,7 @@ describe('test endpoint route', () => {
},
});
mockScopedClient.callAsCurrentUser.mockImplementationOnce(() =>
Promise.resolve((data as unknown) as SearchResponse<EndpointData>)
Promise.resolve((data as unknown) as SearchResponse<EndpointMetadata>)
);
[routeConfig, routeHandler] = routerMock.post.mock.calls.find(([{ path }]) =>
path.startsWith('/api/endpoint/endpoints')
Expand All @@ -115,9 +115,9 @@ describe('test endpoint route', () => {
expect(routeConfig.options).toEqual({ authRequired: true });
expect(mockResponse.ok).toBeCalled();
const endpointResultList = mockResponse.ok.mock.calls[0][0]?.body as EndpointResultList;
expect(endpointResultList.endpoints.length).toEqual(3);
expect(endpointResultList.total).toEqual(3);
expect(endpointResultList.request_index).toEqual(10);
expect(endpointResultList.endpoints.length).toEqual(2);
expect(endpointResultList.total).toEqual(2);
expect(endpointResultList.request_page_index).toEqual(10);
expect(endpointResultList.request_page_size).toEqual(10);
});
});
25 changes: 8 additions & 17 deletions x-pack/plugins/endpoint/server/routes/endpoints.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,22 +7,13 @@
import { IRouter } from 'kibana/server';
import { SearchResponse } from 'elasticsearch';
import { schema } from '@kbn/config-schema';
import { EndpointAppContext, EndpointData } from '../types';

import { kibanaRequestToEndpointListQuery } from '../services/endpoint/endpoint_query_builders';
import { EndpointMetadata, EndpointResultList } from '../../common/types';
import { EndpointAppContext } from '../types';

interface HitSource {
_source: EndpointData;
}

export interface EndpointResultList {
// the endpoint restricted by the page size
endpoints: EndpointData[];
// the total number of unique endpoints in the index
total: number;
// the page size requested
request_page_size: number;
// the index requested
request_index: number;
_source: EndpointMetadata;
}

export function registerEndpointRoutes(router: IRouter, endpointAppContext: EndpointAppContext) {
Expand Down Expand Up @@ -53,7 +44,7 @@ export function registerEndpointRoutes(router: IRouter, endpointAppContext: Endp
const response = (await context.core.elasticsearch.dataClient.callAsCurrentUser(
'search',
queryParams
)) as SearchResponse<EndpointData>;
)) as SearchResponse<EndpointMetadata>;
return res.ok({ body: mapToEndpointResultList(queryParams, response) });
} catch (err) {
return res.internalError({ body: err });
Expand All @@ -64,13 +55,13 @@ export function registerEndpointRoutes(router: IRouter, endpointAppContext: Endp

function mapToEndpointResultList(
queryParams: Record<string, any>,
searchResponse: SearchResponse<EndpointData>
searchResponse: SearchResponse<EndpointMetadata>
): EndpointResultList {
const totalNumberOfEndpoints = searchResponse?.aggregations?.total?.value || 0;
if (searchResponse.hits.hits.length > 0) {
return {
request_page_size: queryParams.size,
request_index: queryParams.from,
request_page_index: queryParams.from,
endpoints: searchResponse.hits.hits
.map(response => response.inner_hits.most_recent.hits.hits)
.flatMap(data => data as HitSource)
Expand All @@ -80,7 +71,7 @@ function mapToEndpointResultList(
} else {
return {
request_page_size: queryParams.size,
request_index: queryParams.from,
request_page_index: queryParams.from,
total: totalNumberOfEndpoints,
endpoints: [],
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,23 +23,23 @@ describe('test query builder', () => {
match_all: {},
},
collapse: {
field: 'machine_id',
field: 'host.id.keyword',
inner_hits: {
name: 'most_recent',
size: 1,
sort: [{ created_at: 'desc' }],
sort: [{ 'event.created': 'desc' }],
},
},
aggs: {
total: {
cardinality: {
field: 'machine_id',
field: 'host.id.keyword',
},
},
},
sort: [
{
created_at: {
'event.created': {
order: 'desc',
},
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
* you may not use this file except in compliance with the Elastic License.
*/
import { KibanaRequest } from 'kibana/server';
import { EndpointAppConstants, EndpointAppContext } from '../../types';
import { EndpointAppConstants } from '../../../common/types';
import { EndpointAppContext } from '../../types';

export const kibanaRequestToEndpointListQuery = async (
request: KibanaRequest<any, any, any>,
Expand All @@ -17,23 +18,23 @@ export const kibanaRequestToEndpointListQuery = async (
match_all: {},
},
collapse: {
field: 'machine_id',
field: 'host.id.keyword',
inner_hits: {
name: 'most_recent',
size: 1,
sort: [{ created_at: 'desc' }],
sort: [{ 'event.created': 'desc' }],
},
},
aggs: {
total: {
cardinality: {
field: 'machine_id',
field: 'host.id.keyword',
},
},
},
sort: [
{
created_at: {
'event.created': {
order: 'desc',
},
},
Expand Down
Loading