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][EPM] Retrieve Index Pattern from Ingest Manager #63016

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
b69c2ad
Endpoint successfully depending on ingest manager to initialize
jonathan-buttner Apr 7, 2020
7c7eaee
Fixing conflicts
jonathan-buttner Apr 7, 2020
c9f0507
Moving the endpoint functional tests to their own directory to avoid …
jonathan-buttner Apr 8, 2020
b82762b
Removing page objects and other endpoint fields from base functional
jonathan-buttner Apr 8, 2020
cb45dfe
Updating code owners with new functional location
jonathan-buttner Apr 8, 2020
9e4f6e3
Adding index pattern functionality
jonathan-buttner Apr 8, 2020
8cbfa42
Missed a file
jonathan-buttner Apr 8, 2020
a1f2bd0
Pointing resolver tests at endpoint functional tests
jonathan-buttner Apr 8, 2020
f13231a
Pointing space tests at the endpoint functional directory
jonathan-buttner Apr 8, 2020
0c9946d
Merge branch 'endpoint-ingest-setup' into endpoint-ingest-index-pattern
jonathan-buttner Apr 8, 2020
0140395
Adding ingest service to do setup and tests for 500s
jonathan-buttner Apr 8, 2020
6c7b7b4
Correcting services path
jonathan-buttner Apr 8, 2020
745c15d
Merge branch 'master' of github.com:elastic/kibana into endpoint-inge…
jonathan-buttner Apr 8, 2020
661f860
Adding jest test names
jonathan-buttner Apr 8, 2020
b839152
Fixing conflicts
jonathan-buttner Apr 8, 2020
cf1a071
Updating es archives with the correct mapping and index names
jonathan-buttner Apr 8, 2020
9ff1e7b
Fixing import error
jonathan-buttner Apr 9, 2020
8272634
Fixing ci test script conflicts
jonathan-buttner Apr 9, 2020
3599f46
Adding resolver tests to code owners
jonathan-buttner Apr 9, 2020
6c22146
enabling epm flag for functional tests
jonathan-buttner Apr 9, 2020
6457c0f
adding correct tag to test
jonathan-buttner Apr 9, 2020
3fd2dc1
Fixing package conflicts
jonathan-buttner Apr 9, 2020
4d2e8ce
Removing the version information and unneeded xsrf
jonathan-buttner Apr 9, 2020
e94629f
Addressing endpoint index pattern feedback
jonathan-buttner Apr 14, 2020
89dd822
Removing unused import
jonathan-buttner Apr 14, 2020
337ab45
Renaming index pattern to es index pattern
jonathan-buttner Apr 14, 2020
9ced2c8
Merge branch 'master' of github.com:elastic/kibana into endpoint-inge…
jonathan-buttner Apr 14, 2020
4dc5854
Fixing missed index pattern calls
jonathan-buttner Apr 14, 2020
b669294
Removing unused import
jonathan-buttner Apr 14, 2020
cc4a355
Fixing type error
jonathan-buttner Apr 14, 2020
1aa9388
Moving es_index_pattern outside of installed and fixing function name
jonathan-buttner Apr 15, 2020
dd033d4
Keeping the event index the same for now
jonathan-buttner Apr 15, 2020
efdcc2d
Wrapping index pattern await in try catch
jonathan-buttner Apr 15, 2020
2829689
Fixing merge conflicts
jonathan-buttner Apr 15, 2020
6facd1f
Address PR feedback, adding comments
jonathan-buttner Apr 16, 2020
ec0a649
Fixing functional tests merge conflicts
jonathan-buttner Apr 16, 2020
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
3 changes: 3 additions & 0 deletions .github/CODEOWNERS
Validating CODEOWNERS rules …
Original file line number Diff line number Diff line change
Expand Up @@ -209,9 +209,12 @@
# Endpoint
/x-pack/plugins/endpoint/ @elastic/endpoint-app-team
/x-pack/test/api_integration/apis/endpoint/ @elastic/endpoint-app-team
/x-pack/test/endpoint_api_integration_no_ingest/ @elastic/endpoint-app-team
/x-pack/test/functional_endpoint/ @elastic/endpoint-app-team
/x-pack/test/functional_endpoint_ingest_failure/ @elastic/endpoint-app-team
/x-pack/test/functional/es_archives/endpoint/ @elastic/endpoint-app-team
/x-pack/test/plugin_functional/plugins/resolver_test/ @elastic/endpoint-app-team
/x-pack/test/plugin_functional/test_suites/resolver/ @elastic/endpoint-app-team

# SIEM
/x-pack/legacy/plugins/siem/ @elastic/siem
Expand Down
9 changes: 9 additions & 0 deletions x-pack/plugins/endpoint/common/schema/index_pattern.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
/*
* 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.
*/

import { schema } from '@kbn/config-schema';

export const indexPatternGetParamsSchema = schema.object({ datasetPath: schema.string() });
10 changes: 8 additions & 2 deletions x-pack/plugins/endpoint/common/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import { SearchResponse } from 'elasticsearch';
import { TypeOf } from '@kbn/config-schema';
import { alertingIndexGetQuerySchema } from './schema/alert_index';
import { indexPatternGetParamsSchema } from './schema/index_pattern';
import { Datasource, NewDatasource } from '../../ingest_manager/common';

/**
Expand All @@ -33,9 +34,9 @@ export type Direction = 'asc' | 'desc';

export class EndpointAppConstants {
static BASE_API_URL = '/api/endpoint';
static ENDPOINT_INDEX_NAME = 'endpoint-agent*';
static INDEX_PATTERN_ROUTE = `${EndpointAppConstants.BASE_API_URL}/index_pattern`;
static ALERT_INDEX_NAME = 'events-endpoint-1';
static EVENT_INDEX_NAME = 'events-endpoint-*';
static EVENT_DATASET = 'events';
static DEFAULT_TOTAL_HITS = 10000;
/**
* Legacy events are stored in indices with endgame-* prefix
Expand Down Expand Up @@ -446,6 +447,11 @@ export type AlertingIndexGetQueryInput = KbnConfigSchemaInputTypeOf<
*/
export type AlertingIndexGetQueryResult = TypeOf<typeof alertingIndexGetQuerySchema>;

/**
* Result of the validated params when handling an index pattern request.
*/
export type IndexPatternGetParamsResult = TypeOf<typeof indexPatternGetParamsSchema>;

/**
* Endpoint Policy configuration
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,14 @@ import { EndpointAppConstants } from '../../../../../common/types';
export const alertMiddlewareFactory: MiddlewareFactory<AlertListState> = (coreStart, depsStart) => {
async function fetchIndexPatterns(): Promise<IIndexPattern[]> {
const { indexPatterns } = depsStart.data;
const indexName = EndpointAppConstants.ALERT_INDEX_NAME;
const fields = await indexPatterns.getFieldsForWildcard({ pattern: indexName });
const eventsPattern: { indexPattern: string } = await coreStart.http.get(
`${EndpointAppConstants.INDEX_PATTERN_ROUTE}/${EndpointAppConstants.EVENT_DATASET}`
);
const fields = await indexPatterns.getFieldsForWildcard({
pattern: eventsPattern.indexPattern,
});
const indexPattern: IIndexPattern = {
title: indexName,
title: eventsPattern.indexPattern,
fields,
};

Expand Down
2 changes: 1 addition & 1 deletion x-pack/plugins/endpoint/scripts/resolver_generator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ async function main() {
metadataIndex: {
alias: 'mi',
describe: 'index to store host metadata in',
default: 'endpoint-agent-1',
default: 'metrics-endpoint-default-1',
type: 'string',
},
auth: {
Expand Down
77 changes: 77 additions & 0 deletions x-pack/plugins/endpoint/server/index_pattern.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
/*
* 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.
*/
import { Logger, LoggerFactory, RequestHandlerContext } from 'kibana/server';
import { ESIndexPatternService } from '../../ingest_manager/server';
import { EndpointAppConstants } from '../common/types';

export interface IndexPatternRetriever {
getIndexPattern(ctx: RequestHandlerContext, datasetPath: string): Promise<string>;
getEventIndexPattern(ctx: RequestHandlerContext): Promise<string>;
getMetadataIndexPattern(ctx: RequestHandlerContext): Promise<string>;
}

/**
* This class is used to retrieve an index pattern. It should be used in the server side code whenever
* an index pattern is needed to query data within ES. The index pattern is constructed by the Ingest Manager
* based on the contents of the Endpoint Package in the Package Registry.
*/
export class IngestIndexPatternRetriever implements IndexPatternRetriever {
jonathan-buttner marked this conversation as resolved.
Show resolved Hide resolved
private static endpointPackageName = 'endpoint';
private static metadataDataset = 'metadata';
private readonly log: Logger;
constructor(private readonly service: ESIndexPatternService, loggerFactory: LoggerFactory) {
this.log = loggerFactory.get('index-pattern-retriever');
}

/**
* Retrieves the index pattern for querying events within elasticsearch.
*
* @param ctx a RequestHandlerContext from a route handler
* @returns a string representing the index pattern (e.g. `events-endpoint-*`)
*/
async getEventIndexPattern(ctx: RequestHandlerContext) {
return await this.getIndexPattern(ctx, EndpointAppConstants.EVENT_DATASET);
}

/**
* Retrieves the index pattern for querying endpoint metadata within elasticsearch.
*
* @param ctx a RequestHandlerContext from a route handler
* @returns a string representing the index pattern (e.g. `metrics-endpoint-*`)
*/
async getMetadataIndexPattern(ctx: RequestHandlerContext) {
Copy link
Contributor

Choose a reason for hiding this comment

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

would you mind adding a quick doc comment to public methods? maybe

/**
 * fetch and return the index pattern used to store Endpoint host metadata.
 */

I think these types of comments will help a lot, esp. considering the size of the org

return await this.getIndexPattern(ctx, IngestIndexPatternRetriever.metadataDataset);
}

/**
* Retrieves the index pattern for a specific dataset for querying endpoint data.
*
* @param ctx a RequestHandlerContext from a route handler
* @param datasetPath a string of the path being used for a dataset within the Endpoint Package
* (e.g. `events`, `metadata`)
* @returns a string representing the index pattern (e.g. `metrics-endpoint-*`)
*/
async getIndexPattern(ctx: RequestHandlerContext, datasetPath: string) {
try {
const pattern = await this.service.getESIndexPattern(
Copy link
Contributor

Choose a reason for hiding this comment

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

Should (can?) any of these call be cached?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah, I haven't created an issue for it yet but we'll create a cache so we don't have to do so many calls to the saved objects.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

ctx.core.savedObjects.client,
IngestIndexPatternRetriever.endpointPackageName,
datasetPath
);

if (!pattern) {
const msg = `Unable to retrieve the index pattern for dataset: ${datasetPath}`;
this.log.warn(msg);
throw new Error(msg);
}
return pattern;
} catch (error) {
const errMsg = `Error occurred while retrieving pattern for: ${datasetPath} error: ${error}`;
this.log.warn(errMsg);
throw new Error(errMsg);
}
}
}
44 changes: 44 additions & 0 deletions x-pack/plugins/endpoint/server/mocks.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*
* 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.
*/

/**
* Creates a mock IndexPatternRetriever for use in tests.
*
* @param indexPattern a string index pattern to return when any of the mock's public methods are called.
* @returns the same string passed in via `indexPattern`
*/
export const createMockIndexPatternRetriever = (indexPattern: string) => {
jonathan-buttner marked this conversation as resolved.
Show resolved Hide resolved
const mockGetFunc = jest.fn().mockResolvedValue(indexPattern);
return {
getIndexPattern: mockGetFunc,
getEventIndexPattern: mockGetFunc,
getMetadataIndexPattern: mockGetFunc,
};
};

export const MetadataIndexPattern = 'metrics-endpoint-*';

/**
* Creates a mock IndexPatternRetriever for use in tests that returns `metrics-endpoint-*`
*/
export const createMockMetadataIndexPatternRetriever = () => {
return createMockIndexPatternRetriever(MetadataIndexPattern);
};

/**
* Creates a mock IndexPatternService for use in tests that need to interact with the Ingest Manager's
* ESIndexPatternService.
*
* @param indexPattern a string index pattern to return when called by a test
* @returns the same value as `indexPattern` parameter
*/
export const createMockIndexPatternService = (indexPattern: string) => {
return {
esIndexPatternService: {
getESIndexPattern: jest.fn().mockResolvedValue(indexPattern),
},
};
};
6 changes: 5 additions & 1 deletion x-pack/plugins/endpoint/server/plugin.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import { EndpointPlugin, EndpointPluginSetupDependencies } from './plugin';
import { coreMock } from '../../../../src/core/server/mocks';
import { PluginSetupContract } from '../../features/server';
import { createMockIndexPatternService } from './mocks';

describe('test endpoint plugin', () => {
let plugin: EndpointPlugin;
Expand All @@ -28,7 +29,10 @@ describe('test endpoint plugin', () => {
getFeaturesUICapabilities: jest.fn(),
registerLegacyAPI: jest.fn(),
};
mockedEndpointPluginSetupDependencies = { features: mockedPluginSetupContract };
mockedEndpointPluginSetupDependencies = {
features: mockedPluginSetupContract,
ingestManager: createMockIndexPatternService(''),
};
});

it('test properly setup plugin', async () => {
Expand Down
9 changes: 9 additions & 0 deletions x-pack/plugins/endpoint/server/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,23 @@
import { Plugin, CoreSetup, PluginInitializerContext, Logger } from 'kibana/server';
import { first } from 'rxjs/operators';
import { PluginSetupContract as FeaturesPluginSetupContract } from '../../features/server';
import { IngestManagerSetupContract } from '../../ingest_manager/server';
import { createConfig$, EndpointConfigType } from './config';
import { EndpointAppContext } from './types';

import { registerAlertRoutes } from './routes/alerts';
import { registerResolverRoutes } from './routes/resolver';
import { registerIndexPatternRoute } from './routes/index_pattern';
import { registerEndpointRoutes } from './routes/metadata';
import { IngestIndexPatternRetriever } from './index_pattern';

export type EndpointPluginStart = void;
export type EndpointPluginSetup = void;
export interface EndpointPluginStartDependencies {} // eslint-disable-line @typescript-eslint/no-empty-interface

export interface EndpointPluginSetupDependencies {
features: FeaturesPluginSetupContract;
ingestManager: IngestManagerSetupContract;
}

export class EndpointPlugin
Expand Down Expand Up @@ -62,6 +66,10 @@ export class EndpointPlugin
},
});
const endpointContext = {
indexPatternRetriever: new IngestIndexPatternRetriever(
plugins.ingestManager.esIndexPatternService,
this.initializerContext.logger
),
logFactory: this.initializerContext.logger,
config: (): Promise<EndpointConfigType> => {
return createConfig$(this.initializerContext)
Expand All @@ -73,6 +81,7 @@ export class EndpointPlugin
registerEndpointRoutes(router, endpointContext);
registerResolverRoutes(router, endpointContext);
registerAlertRoutes(router, endpointContext);
registerIndexPatternRoute(router, endpointContext);
}

public start() {
Expand Down
2 changes: 2 additions & 0 deletions x-pack/plugins/endpoint/server/routes/alerts/alerts.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
import { registerAlertRoutes } from './index';
import { EndpointConfigSchema } from '../../config';
import { alertingIndexGetQuerySchema } from '../../../common/schema/alert_index';
import { createMockIndexPatternRetriever } from '../../mocks';

describe('test alerts route', () => {
let routerMock: jest.Mocked<IRouter>;
Expand All @@ -24,6 +25,7 @@ describe('test alerts route', () => {
mockClusterClient.asScoped.mockReturnValue(mockScopedClient);
routerMock = httpServiceMock.createRouter();
registerAlertRoutes(routerMock, {
indexPatternRetriever: createMockIndexPatternRetriever('events-endpoint-*'),
logFactory: loggingServiceMock.create(),
config: () => Promise.resolve(EndpointConfigSchema.validate({})),
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,15 +26,18 @@ export const alertDetailsHandlerWrapper = function(
id: alertId,
})) as GetResponse<AlertEvent>;

const indexPattern = await endpointAppContext.indexPatternRetriever.getEventIndexPattern(ctx);

jonathan-buttner marked this conversation as resolved.
Show resolved Hide resolved
const config = await endpointAppContext.config();
const pagination: AlertDetailsPagination = new AlertDetailsPagination(
config,
ctx,
req.params,
response
response,
indexPattern
);

const currentHostInfo = await getHostData(ctx, response._source.host.id);
const currentHostInfo = await getHostData(ctx, response._source.host.id, indexPattern);

return res.ok({
body: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ export class AlertDetailsPagination extends Pagination<
config: EndpointConfigType,
requestContext: RequestHandlerContext,
state: AlertDetailsRequestParams,
data: GetResponse<AlertEvent>
data: GetResponse<AlertEvent>,
private readonly indexPattern: string
) {
super(config, requestContext, state, data);
}
Expand All @@ -54,7 +55,8 @@ export class AlertDetailsPagination extends Pagination<

const response = await searchESForAlerts(
this.requestContext.core.elasticsearch.dataClient,
reqData
reqData,
this.indexPattern
);
return response;
}
Expand Down
10 changes: 6 additions & 4 deletions x-pack/plugins/endpoint/server/routes/alerts/lib/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,8 @@ function buildSort(query: AlertSearchQuery): AlertSort {
* Builds a request body for Elasticsearch, given a set of query params.
**/
const buildAlertSearchQuery = async (
query: AlertSearchQuery
query: AlertSearchQuery,
indexPattern: string
): Promise<AlertSearchRequestWrapper> => {
let totalHitsMin: number = EndpointAppConstants.DEFAULT_TOTAL_HITS;

Expand Down Expand Up @@ -125,7 +126,7 @@ const buildAlertSearchQuery = async (

const reqWrapper: AlertSearchRequestWrapper = {
size: query.pageSize,
index: EndpointAppConstants.ALERT_INDEX_NAME,
index: indexPattern,
body: reqBody,
};

Expand All @@ -141,9 +142,10 @@ const buildAlertSearchQuery = async (
**/
export const searchESForAlerts = async (
dataClient: IScopedClusterClient,
query: AlertSearchQuery
query: AlertSearchQuery,
indexPattern: string
): Promise<SearchResponse<AlertEvent>> => {
const reqWrapper = await buildAlertSearchQuery(query);
const reqWrapper = await buildAlertSearchQuery(query, indexPattern);
const response = (await dataClient.callAsCurrentUser('search', reqWrapper)) as SearchResponse<
AlertEvent
>;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,13 @@ export const alertListHandlerWrapper = function(
res
) => {
try {
const indexPattern = await endpointAppContext.indexPatternRetriever.getEventIndexPattern(ctx);
const reqData = await getRequestData(req, endpointAppContext);
const response = await searchESForAlerts(ctx.core.elasticsearch.dataClient, reqData);
const response = await searchESForAlerts(
ctx.core.elasticsearch.dataClient,
reqData,
indexPattern
);
const mappedBody = await mapToAlertResultList(ctx, endpointAppContext, reqData, response);
return res.ok({ body: mappedBody });
} catch (err) {
Expand Down
Loading