From ad9dad3c113bcd75bcb5278f7e08fea93560fa5b Mon Sep 17 00:00:00 2001 From: nnamdifrankie Date: Fri, 17 Apr 2020 20:28:59 -0400 Subject: [PATCH 01/14] EMT-146: use ingest agent for status info --- x-pack/plugins/endpoint/server/mocks.ts | 17 +++- x-pack/plugins/endpoint/server/plugin.test.ts | 4 +- x-pack/plugins/endpoint/server/plugin.ts | 1 + .../server/routes/alerts/alerts.test.ts | 3 +- .../server/routes/alerts/details/handlers.ts | 8 +- .../endpoint/server/routes/metadata/index.ts | 88 +++++++++++++----- .../server/routes/metadata/metadata.test.ts | 72 +++++++++++++- .../routes/metadata/query_builders.test.ts | 8 +- x-pack/plugins/endpoint/server/types.ts | 2 + .../ingest_manager/common/types/index.ts | 10 ++ .../plugins/ingest_manager/server/plugin.ts | 5 +- .../server/services/agent_service.ts | 21 +++++ .../alerts/host_api_feature/data.json.gz | Bin 753 -> 849 bytes 13 files changed, 207 insertions(+), 32 deletions(-) create mode 100644 x-pack/plugins/ingest_manager/server/services/agent_service.ts diff --git a/x-pack/plugins/endpoint/server/mocks.ts b/x-pack/plugins/endpoint/server/mocks.ts index 903aa19cd8843..5c726a370eb4a 100644 --- a/x-pack/plugins/endpoint/server/mocks.ts +++ b/x-pack/plugins/endpoint/server/mocks.ts @@ -4,6 +4,9 @@ * you may not use this file except in compliance with the Elastic License. */ +import { IngestManagerSetupContract } from '../../ingest_manager/server'; +import { AgentService } from '../../ingest_manager/common/types'; + /** * Creates a mock IndexPatternRetriever for use in tests. * @@ -28,6 +31,15 @@ export const createMockMetadataIndexPatternRetriever = () => { return createMockIndexPatternRetriever(MetadataIndexPattern); }; +/** + * Creates a mock AgentService + */ +export const createMockAgentService = (): jest.Mocked => { + return { + getAgentStatus: jest.fn(), + }; +}; + /** * Creates a mock IndexPatternService for use in tests that need to interact with the Ingest Manager's * ESIndexPatternService. @@ -35,10 +47,13 @@ export const createMockMetadataIndexPatternRetriever = () => { * @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) => { +export const createMockIngestManagerSetupContract = ( + indexPattern: string +): IngestManagerSetupContract => { return { esIndexPatternService: { getESIndexPattern: jest.fn().mockResolvedValue(indexPattern), }, + agentService: createMockAgentService(), }; }; diff --git a/x-pack/plugins/endpoint/server/plugin.test.ts b/x-pack/plugins/endpoint/server/plugin.test.ts index 8d55e64f16dcf..c380bc5c3e3d0 100644 --- a/x-pack/plugins/endpoint/server/plugin.test.ts +++ b/x-pack/plugins/endpoint/server/plugin.test.ts @@ -7,7 +7,7 @@ import { EndpointPlugin, EndpointPluginSetupDependencies } from './plugin'; import { coreMock } from '../../../../src/core/server/mocks'; import { PluginSetupContract } from '../../features/server'; -import { createMockIndexPatternService } from './mocks'; +import { createMockIngestManagerSetupContract } from './mocks'; describe('test endpoint plugin', () => { let plugin: EndpointPlugin; @@ -31,7 +31,7 @@ describe('test endpoint plugin', () => { }; mockedEndpointPluginSetupDependencies = { features: mockedPluginSetupContract, - ingestManager: createMockIndexPatternService(''), + ingestManager: createMockIngestManagerSetupContract(''), }; }); diff --git a/x-pack/plugins/endpoint/server/plugin.ts b/x-pack/plugins/endpoint/server/plugin.ts index 6a42014e91130..ce6be5aeaf6db 100644 --- a/x-pack/plugins/endpoint/server/plugin.ts +++ b/x-pack/plugins/endpoint/server/plugin.ts @@ -70,6 +70,7 @@ export class EndpointPlugin plugins.ingestManager.esIndexPatternService, this.initializerContext.logger ), + agentService: plugins.ingestManager.agentService, logFactory: this.initializerContext.logger, config: (): Promise => { return createConfig$(this.initializerContext) diff --git a/x-pack/plugins/endpoint/server/routes/alerts/alerts.test.ts b/x-pack/plugins/endpoint/server/routes/alerts/alerts.test.ts index 6be7b26898206..39fc2ba4c74bb 100644 --- a/x-pack/plugins/endpoint/server/routes/alerts/alerts.test.ts +++ b/x-pack/plugins/endpoint/server/routes/alerts/alerts.test.ts @@ -12,7 +12,7 @@ import { import { registerAlertRoutes } from './index'; import { EndpointConfigSchema } from '../../config'; import { alertingIndexGetQuerySchema } from '../../../common/schema/alert_index'; -import { createMockIndexPatternRetriever } from '../../mocks'; +import { createMockAgentService, createMockIndexPatternRetriever } from '../../mocks'; describe('test alerts route', () => { let routerMock: jest.Mocked; @@ -26,6 +26,7 @@ describe('test alerts route', () => { routerMock = httpServiceMock.createRouter(); registerAlertRoutes(routerMock, { indexPatternRetriever: createMockIndexPatternRetriever('events-endpoint-*'), + agentService: createMockAgentService(), logFactory: loggingServiceMock.create(), config: () => Promise.resolve(EndpointConfigSchema.validate({})), }); diff --git a/x-pack/plugins/endpoint/server/routes/alerts/details/handlers.ts b/x-pack/plugins/endpoint/server/routes/alerts/details/handlers.ts index 86e9f55da5697..9055ee4110fbb 100644 --- a/x-pack/plugins/endpoint/server/routes/alerts/details/handlers.ts +++ b/x-pack/plugins/endpoint/server/routes/alerts/details/handlers.ts @@ -37,7 +37,13 @@ export const alertDetailsHandlerWrapper = function( indexPattern ); - const currentHostInfo = await getHostData(ctx, response._source.host.id, indexPattern); + const currentHostInfo = await getHostData( + { + endpointAppContext, + requestHandlerContext: ctx, + }, + response._source.host.id + ); return res.ok({ body: { diff --git a/x-pack/plugins/endpoint/server/routes/metadata/index.ts b/x-pack/plugins/endpoint/server/routes/metadata/index.ts index 883bb88204fd4..7b25dad155b17 100644 --- a/x-pack/plugins/endpoint/server/routes/metadata/index.ts +++ b/x-pack/plugins/endpoint/server/routes/metadata/index.ts @@ -4,18 +4,29 @@ * you may not use this file except in compliance with the Elastic License. */ -import { IRouter, RequestHandlerContext } from 'kibana/server'; +import { IRouter, Logger, RequestHandlerContext } from 'kibana/server'; import { SearchResponse } from 'elasticsearch'; import { schema } from '@kbn/config-schema'; -import { kibanaRequestToMetadataListESQuery, getESQueryHostMetadataByID } from './query_builders'; +import { getESQueryHostMetadataByID, kibanaRequestToMetadataListESQuery } from './query_builders'; import { HostInfo, HostMetadata, HostResultList, HostStatus } from '../../../common/types'; import { EndpointAppContext } from '../../types'; +import { AgentStatus } from '../../../../ingest_manager/common/types/models'; interface HitSource { _source: HostMetadata; } +interface MetadataRequestContext { + requestHandlerContext: RequestHandlerContext; + endpointAppContext: EndpointAppContext; +} + +const HOST_STATUS_MAPPING = new Map([ + ['online', HostStatus.ONLINE], + ['offline', HostStatus.OFFLINE], +]); + export function registerEndpointRoutes(router: IRouter, endpointAppContext: EndpointAppContext) { router.post( { @@ -62,7 +73,12 @@ export function registerEndpointRoutes(router: IRouter, endpointAppContext: Endp 'search', queryParams )) as SearchResponse; - return res.ok({ body: mapToHostResultList(queryParams, response) }); + return res.ok({ + body: await mapToHostResultList(queryParams, response, { + endpointAppContext, + requestHandlerContext: context, + }), + }); } catch (err) { return res.internalError({ body: err }); } @@ -79,11 +95,13 @@ export function registerEndpointRoutes(router: IRouter, endpointAppContext: Endp }, async (context, req, res) => { try { - const index = await endpointAppContext.indexPatternRetriever.getMetadataIndexPattern( - context + const doc = await getHostData( + { + endpointAppContext, + requestHandlerContext: context, + }, + req.params.id ); - - const doc = await getHostData(context, req.params.id, index); if (doc) { return res.ok({ body: doc }); } @@ -96,12 +114,14 @@ export function registerEndpointRoutes(router: IRouter, endpointAppContext: Endp } export async function getHostData( - context: RequestHandlerContext, - id: string, - index: string + metadataRequestContext: MetadataRequestContext, + id: string ): Promise { + const index = await metadataRequestContext.endpointAppContext.indexPatternRetriever.getMetadataIndexPattern( + metadataRequestContext.requestHandlerContext + ); const query = getESQueryHostMetadataByID(id, index); - const response = (await context.core.elasticsearch.dataClient.callAsCurrentUser( + const response = (await metadataRequestContext.requestHandlerContext.core.elasticsearch.dataClient.callAsCurrentUser( 'search', query )) as SearchResponse; @@ -110,22 +130,25 @@ export async function getHostData( return undefined; } - return enrichHostMetadata(response.hits.hits[0]._source); + return await enrichHostMetadata(response.hits.hits[0]._source, metadataRequestContext); } -function mapToHostResultList( +async function mapToHostResultList( queryParams: Record, - searchResponse: SearchResponse -): HostResultList { + searchResponse: SearchResponse, + metadataRequestContext: MetadataRequestContext +): Promise { const totalNumberOfHosts = searchResponse?.aggregations?.total?.value || 0; if (searchResponse.hits.hits.length > 0) { return { request_page_size: queryParams.size, request_page_index: queryParams.from, - hosts: searchResponse.hits.hits - .map(response => response.inner_hits.most_recent.hits.hits) - .flatMap(data => data as HitSource) - .map(entry => enrichHostMetadata(entry._source)), + hosts: await Promise.all( + searchResponse.hits.hits + .map(response => response.inner_hits.most_recent.hits.hits) + .flatMap(data => data as HitSource) + .map(async entry => enrichHostMetadata(entry._source, metadataRequestContext)) + ), total: totalNumberOfHosts, }; } else { @@ -138,9 +161,32 @@ function mapToHostResultList( } } -function enrichHostMetadata(hostMetadata: HostMetadata): HostInfo { +async function enrichHostMetadata( + hostMetadata: HostMetadata, + metadataRequestContext: MetadataRequestContext +): Promise { + let hostStatus = HostStatus.ERROR; + try { + const status = await metadataRequestContext.endpointAppContext.agentService.getAgentStatus( + metadataRequestContext.requestHandlerContext, + hostMetadata.elastic.agent.id + ); + hostStatus = HOST_STATUS_MAPPING.get(status) || HostStatus.ERROR; + } catch (e) { + if (e.isBoom && e.output.statusCode === 404) { + logger(metadataRequestContext.endpointAppContext).warn( + `agent with id ${hostMetadata.elastic.agent.id} not found` + ); + } else { + throw e; + } + } return { metadata: hostMetadata, - host_status: HostStatus.ERROR, + host_status: hostStatus, }; } + +const logger = (endpointAppContext: EndpointAppContext): Logger => { + return endpointAppContext.logFactory.get('metadata'); +}; diff --git a/x-pack/plugins/endpoint/server/routes/metadata/metadata.test.ts b/x-pack/plugins/endpoint/server/routes/metadata/metadata.test.ts index 9a7d3fb3188a6..50958119902c2 100644 --- a/x-pack/plugins/endpoint/server/routes/metadata/metadata.test.ts +++ b/x-pack/plugins/endpoint/server/routes/metadata/metadata.test.ts @@ -25,7 +25,9 @@ import { SearchResponse } from 'elasticsearch'; import { registerEndpointRoutes } from './index'; import { EndpointConfigSchema } from '../../config'; import * as data from '../../test_data/all_metadata_data.json'; -import { createMockMetadataIndexPatternRetriever } from '../../mocks'; +import { createMockAgentService, createMockMetadataIndexPatternRetriever } from '../../mocks'; +import { AgentService } from '../../../../ingest_manager/common/types'; +import Boom from 'boom'; describe('test endpoint route', () => { let routerMock: jest.Mocked; @@ -35,6 +37,7 @@ describe('test endpoint route', () => { let mockSavedObjectClient: jest.Mocked; let routeHandler: RequestHandler; let routeConfig: RouteConfig; + let mockAgentService: jest.Mocked; beforeEach(() => { mockClusterClient = elasticsearchServiceMock.createClusterClient() as jest.Mocked< @@ -45,8 +48,10 @@ describe('test endpoint route', () => { mockClusterClient.asScoped.mockReturnValue(mockScopedClient); routerMock = httpServiceMock.createRouter(); mockResponse = httpServerMock.createResponseFactory(); + mockAgentService = createMockAgentService(); registerEndpointRoutes(routerMock, { indexPatternRetriever: createMockMetadataIndexPatternRetriever(), + agentService: mockAgentService, logFactory: loggingServiceMock.create(), config: () => Promise.resolve(EndpointConfigSchema.validate({})), }); @@ -83,7 +88,7 @@ describe('test endpoint route', () => { [routeConfig, routeHandler] = routerMock.post.mock.calls.find(([{ path }]) => path.startsWith('/api/endpoint/metadata') )!; - + mockAgentService.getAgentStatus = jest.fn().mockReturnValue('error'); await routeHandler( createRouteHandlerContext(mockScopedClient, mockSavedObjectClient), mockRequest, @@ -113,6 +118,8 @@ describe('test endpoint route', () => { ], }, }); + + mockAgentService.getAgentStatus = jest.fn().mockReturnValue('error'); mockScopedClient.callAsCurrentUser.mockImplementationOnce(() => Promise.resolve((data as unknown) as SearchResponse) ); @@ -154,6 +161,8 @@ describe('test endpoint route', () => { filter: 'not host.ip:10.140.73.246', }, }); + + mockAgentService.getAgentStatus = jest.fn().mockReturnValue('error'); mockScopedClient.callAsCurrentUser.mockImplementationOnce(() => Promise.resolve((data as unknown) as SearchResponse) ); @@ -216,10 +225,10 @@ describe('test endpoint route', () => { }, }) ); + mockAgentService.getAgentStatus = jest.fn().mockReturnValue('error'); [routeConfig, routeHandler] = routerMock.get.mock.calls.find(([{ path }]) => path.startsWith('/api/endpoint/metadata') )!; - await routeHandler( createRouteHandlerContext(mockScopedClient, mockSavedObjectClient), mockRequest, @@ -233,13 +242,14 @@ describe('test endpoint route', () => { expect(message).toEqual('Endpoint Not Found'); }); - it('should return a single endpoint with status error', async () => { + it('should return a single endpoint with status online', async () => { const mockRequest = httpServerMock.createKibanaRequest({ params: { id: (data as any).hits.hits[0]._id }, }); const response: SearchResponse = (data as unknown) as SearchResponse< HostMetadata >; + mockAgentService.getAgentStatus = jest.fn().mockReturnValue('online'); mockScopedClient.callAsCurrentUser.mockImplementationOnce(() => Promise.resolve(response)); [routeConfig, routeHandler] = routerMock.get.mock.calls.find(([{ path }]) => path.startsWith('/api/endpoint/metadata') @@ -256,6 +266,60 @@ describe('test endpoint route', () => { expect(mockResponse.ok).toBeCalled(); const result = mockResponse.ok.mock.calls[0][0]?.body as HostInfo; expect(result).toHaveProperty('metadata.endpoint'); + expect(result.host_status).toEqual(HostStatus.ONLINE); + }); + + it('should return a single endpoint with status error when AgentService throw 404', async () => { + const mockRequest = httpServerMock.createKibanaRequest({ + params: { id: (data as any).hits.hits[0]._id }, + }); + const response: SearchResponse = (data as unknown) as SearchResponse< + HostMetadata + >; + mockAgentService.getAgentStatus = jest.fn().mockImplementation(() => { + throw Boom.notFound('Agent not found'); + }); + mockScopedClient.callAsCurrentUser.mockImplementationOnce(() => Promise.resolve(response)); + [routeConfig, routeHandler] = routerMock.get.mock.calls.find(([{ path }]) => + path.startsWith('/api/endpoint/metadata') + )!; + + await routeHandler( + createRouteHandlerContext(mockScopedClient, mockSavedObjectClient), + mockRequest, + mockResponse + ); + + expect(mockScopedClient.callAsCurrentUser).toBeCalled(); + expect(routeConfig.options).toEqual({ authRequired: true }); + expect(mockResponse.ok).toBeCalled(); + const result = mockResponse.ok.mock.calls[0][0]?.body as HostInfo; + expect(result.host_status).toEqual(HostStatus.ERROR); + }); + + it('should return a single endpoint with status error when status is not offline or online', async () => { + const mockRequest = httpServerMock.createKibanaRequest({ + params: { id: (data as any).hits.hits[0]._id }, + }); + const response: SearchResponse = (data as unknown) as SearchResponse< + HostMetadata + >; + mockAgentService.getAgentStatus = jest.fn().mockReturnValue('warning'); + mockScopedClient.callAsCurrentUser.mockImplementationOnce(() => Promise.resolve(response)); + [routeConfig, routeHandler] = routerMock.get.mock.calls.find(([{ path }]) => + path.startsWith('/api/endpoint/metadata') + )!; + + await routeHandler( + createRouteHandlerContext(mockScopedClient, mockSavedObjectClient), + mockRequest, + mockResponse + ); + + expect(mockScopedClient.callAsCurrentUser).toBeCalled(); + expect(routeConfig.options).toEqual({ authRequired: true }); + expect(mockResponse.ok).toBeCalled(); + const result = mockResponse.ok.mock.calls[0][0]?.body as HostInfo; expect(result.host_status).toEqual(HostStatus.ERROR); }); }); diff --git a/x-pack/plugins/endpoint/server/routes/metadata/query_builders.test.ts b/x-pack/plugins/endpoint/server/routes/metadata/query_builders.test.ts index c8143fbdda1ea..7e6e3f875cd4c 100644 --- a/x-pack/plugins/endpoint/server/routes/metadata/query_builders.test.ts +++ b/x-pack/plugins/endpoint/server/routes/metadata/query_builders.test.ts @@ -6,7 +6,11 @@ import { httpServerMock, loggingServiceMock } from '../../../../../../src/core/server/mocks'; import { EndpointConfigSchema } from '../../config'; import { kibanaRequestToMetadataListESQuery, getESQueryHostMetadataByID } from './query_builders'; -import { createMockMetadataIndexPatternRetriever, MetadataIndexPattern } from '../../mocks'; +import { + createMockAgentService, + createMockMetadataIndexPatternRetriever, + MetadataIndexPattern, +} from '../../mocks'; describe('query builder', () => { describe('MetadataListESQuery', () => { @@ -18,6 +22,7 @@ describe('query builder', () => { mockRequest, { indexPatternRetriever: createMockMetadataIndexPatternRetriever(), + agentService: createMockAgentService(), logFactory: loggingServiceMock.create(), config: () => Promise.resolve(EndpointConfigSchema.validate({})), }, @@ -69,6 +74,7 @@ describe('query builder', () => { mockRequest, { indexPatternRetriever: createMockMetadataIndexPatternRetriever(), + agentService: createMockAgentService(), logFactory: loggingServiceMock.create(), config: () => Promise.resolve(EndpointConfigSchema.validate({})), }, diff --git a/x-pack/plugins/endpoint/server/types.ts b/x-pack/plugins/endpoint/server/types.ts index 46a23060339f4..d43ec58aec428 100644 --- a/x-pack/plugins/endpoint/server/types.ts +++ b/x-pack/plugins/endpoint/server/types.ts @@ -6,12 +6,14 @@ import { LoggerFactory } from 'kibana/server'; import { EndpointConfigType } from './config'; import { IndexPatternRetriever } from './index_pattern'; +import { AgentService } from '../../ingest_manager/common/types'; /** * The context for Endpoint apps. */ export interface EndpointAppContext { indexPatternRetriever: IndexPatternRetriever; + agentService: AgentService; logFactory: LoggerFactory; config(): Promise; } diff --git a/x-pack/plugins/ingest_manager/common/types/index.ts b/x-pack/plugins/ingest_manager/common/types/index.ts index 42f7a9333118e..e5e214ffcea8d 100644 --- a/x-pack/plugins/ingest_manager/common/types/index.ts +++ b/x-pack/plugins/ingest_manager/common/types/index.ts @@ -3,9 +3,19 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ +import { RequestHandlerContext } from 'kibana/server'; +import { AgentStatus } from './models'; + export * from './models'; export * from './rest_spec'; +export interface AgentService { + getAgentStatus( + requestHandlerContext: RequestHandlerContext, + agentId: string + ): Promise; +} + export interface IngestManagerConfigType { enabled: boolean; epm: { diff --git a/x-pack/plugins/ingest_manager/server/plugin.ts b/x-pack/plugins/ingest_manager/server/plugin.ts index 4dd070a7414f0..edba9a0284895 100644 --- a/x-pack/plugins/ingest_manager/server/plugin.ts +++ b/x-pack/plugins/ingest_manager/server/plugin.ts @@ -39,18 +39,20 @@ import { registerInstallScriptRoutes, } from './routes'; -import { IngestManagerConfigType } from '../common'; +import { AgentService, IngestManagerConfigType } from '../common'; import { appContextService, ESIndexPatternService, ESIndexPatternSavedObjectService, } from './services'; +import { createAgentService } from './services/agent_service'; /** * Describes public IngestManager plugin contract returned at the `setup` stage. */ export interface IngestManagerSetupContract { esIndexPatternService: ESIndexPatternService; + agentService: AgentService; } export interface IngestManagerSetupDeps { @@ -148,6 +150,7 @@ export class IngestManagerPlugin implements Plugin { } return deepFreeze({ esIndexPatternService: new ESIndexPatternSavedObjectService(), + agentService: createAgentService(), }); } diff --git a/x-pack/plugins/ingest_manager/server/services/agent_service.ts b/x-pack/plugins/ingest_manager/server/services/agent_service.ts new file mode 100644 index 0000000000000..178fe60cc5661 --- /dev/null +++ b/x-pack/plugins/ingest_manager/server/services/agent_service.ts @@ -0,0 +1,21 @@ +/* + * 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 { RequestHandlerContext } from 'kibana/server'; +import { AgentService, AgentStatus } from '../../common/types'; +import { getAgent, getAgentStatus } from './agents'; + +export const createAgentService = (): AgentService => { + return { + getAgentStatus: async ( + requestHandlerContext: RequestHandlerContext, + agentId: string + ): Promise => { + const agent = await getAgent(requestHandlerContext.core.savedObjects.client, agentId); + return getAgentStatus(agent); + }, + }; +}; diff --git a/x-pack/test/functional/es_archives/endpoint/alerts/host_api_feature/data.json.gz b/x-pack/test/functional/es_archives/endpoint/alerts/host_api_feature/data.json.gz index a71281c0ecfec93e0a51aa3473dbbbf565a10f9b..3d4f0e11a7cc670366fa6098143b6306a1a1c72b 100644 GIT binary patch literal 849 zcmV-X1FrlZiwFo(DwQOZ*BnHmQ8QtHV}sI{uPGL8G#%QsbNp`rYZIi z6fG9$q9}Ucr{mVP3|sbY8sxv1$|hMyaz2pmUIJK#M9yf2e20(bYBU~C+RJsC{4k!x zCQMGcfxTPox{<5$P#)*8o4q{$WhvfI-^HJ5{qg+o^FMyezu%a57OR*(cSg(9ZsuVN zX%*MaeAPls+3glB$UD<*v)hEPFE1lMw)17$wr;sDqf#>oBBeBGdva&uW@*(P_}nLz zT=JBBgzQ2B3Rr_DVSr5_>71xp_{qsvuYKBV=gq2fHI=IDT#g;YP>h;B}*3Pri>V2V}6vXXS5*Ix&rmM-*T=~8nRBtf!JwD97%XS3}qnRkoD z7e!XF`LrE>NSjicV-ymPOZVy4&{RExz1z&)jaa>x^~??nACG81y8FK#U5`drFXzHL z-{Zn;w*H=6FxtF;3p$#RD1(xLx>H%oNJfO(r6kJX(U$F_Trd^?e=cb6rS*j1HD@5= zazH5ws70t<#fR@o3d_%vq7K>S+9^PGrhIT@0`EzK5ZXE9EIEoN zNbwCi2%)U@2@NQ%3Mq`>!VFVBC|+^NKoeW_W=UcBHKYii|JAcaDTMWr4#FoELMSlS zbm$kkoHQpPTM7z2QL_43QV>_N^a6-@q=6{9WBCnd1a>`ydZY_DLJCeD2)qS!z#1a= bNFl(AQj>tC8akZ3k@n(0L$8A>b_@Uj^{t;- literal 753 zcmVQOZ*BnHl}k_CKoEfM`4v&ljJ0p?_EbZuIH0N( zQc+d)u+PM8Y)6h0post8bs!musT1Ah2*=*TtobuWm=8c1(tp{dF z3Wgy8QdowyMyW(*bo6Mo^z}Ti%GOjQG*P36rMt~hYtMI2n^n`?-t5RWKAezDAw^H& zlt=~a1Z9wAjDb9%Bx9I;&eCklhiF&oVwLdAyqOG7moc`y9FH~{cYUXpz4&eIb>m$( zWj)hLHSbuqlC=kC@g1}&!lbbL&tf}O_rY0a9JVF^PE`ubc?^nJ0))ww8b!I3XveB8 z;?M11F-kCsPl^)4(%nR~YnUbk#Ygp)BuykvFcXid`L%Uap>6jp9(zCmX5baXS{St7 zvYK}*85Yy&eML%FUCoCVzK*RjBnXrJrMr4i6iG*6sq0*?iq+Yyqqg0MWKZn}>;JpK z-C%HgIH$*^!|8ZDdrM9Q7YA_4ov@w-px82CK8S2DNcmw^Gjqx zC{L(7m{LZggJ3KK0z!lCkk1(i;3i&6;2e1NT81%t9^L3XdXe3)b@e2;s}24mxwc2{ z Date: Sat, 18 Apr 2020 08:50:27 -0400 Subject: [PATCH 02/14] EMT-146: add integration tests --- .../api_integration/apis/endpoint/index.ts | 1 + .../apis/endpoint/metadata_status.ts | 153 + .../endpoint_status_feature/data.json.gz | Bin 0 -> 34199 bytes .../endpoint_status_feature/mappings.json | 3255 +++++++++++++++++ 4 files changed, 3409 insertions(+) create mode 100644 x-pack/test/api_integration/apis/endpoint/metadata_status.ts create mode 100644 x-pack/test/functional/es_archives/endpoint/metadata/endpoint_status_feature/data.json.gz create mode 100644 x-pack/test/functional/es_archives/endpoint/metadata/endpoint_status_feature/mappings.json diff --git a/x-pack/test/api_integration/apis/endpoint/index.ts b/x-pack/test/api_integration/apis/endpoint/index.ts index 0a5f9aa595b8a..1c373d85365f9 100644 --- a/x-pack/test/api_integration/apis/endpoint/index.ts +++ b/x-pack/test/api_integration/apis/endpoint/index.ts @@ -19,6 +19,7 @@ export default function endpointAPIIntegrationTests({ loadTestFile(require.resolve('./index_pattern')); loadTestFile(require.resolve('./resolver')); loadTestFile(require.resolve('./metadata')); + loadTestFile(require.resolve('./metadata_status')); loadTestFile(require.resolve('./alerts')); }); } diff --git a/x-pack/test/api_integration/apis/endpoint/metadata_status.ts b/x-pack/test/api_integration/apis/endpoint/metadata_status.ts new file mode 100644 index 0000000000000..480ad4d18d3b0 --- /dev/null +++ b/x-pack/test/api_integration/apis/endpoint/metadata_status.ts @@ -0,0 +1,153 @@ +/* + * 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 uuid from 'uuid'; +import expect from '@kbn/expect'; +import { FtrProviderContext } from '../../ftr_provider_context'; +import { getSupertestWithoutAuth } from '../fleet/agents/services'; + +export default function(providerContext: FtrProviderContext) { + const { getService } = providerContext; + const esArchiver = getService('esArchiver'); + const supertest = getService('supertest'); + const supertestWithoutAuth = getSupertestWithoutAuth(providerContext); + const esClient = getService('es'); + // agent that is enrolled and know to fleet + const enrolledAgentId = '3efef370-8164-11ea-bc0d-9196b6de96eb'; + // host that is connected to enrolledAgentId + const enrolledHostId = 'fdb346d9-6f56-426a-90a7-a9328d1b0528'; + // host that is not connected to an enrolled agent id + const notEnrolledHostId = 'bcf0d070-d9f2-40aa-8620-cbc004747722'; + + let apiKey: { id: string; api_key: string }; + + describe('test metadata api status', () => { + describe('/api/endpoint/metadata when index is not empty', () => { + before(async () => { + await esArchiver.load('endpoint/metadata/endpoint_status_feature'); + const { body: apiKeyBody } = await esClient.security.createApiKey({ + body: { + name: `test access api key: ${uuid.v4()}`, + }, + }); + apiKey = apiKeyBody; + const { + body: { _source: agentDoc }, + } = await esClient.get({ + index: '.kibana', + id: `agents:${enrolledAgentId}`, + }); + + agentDoc.agents.access_api_key_id = apiKey.id; + + await esClient.update({ + index: '.kibana', + id: `agents:${enrolledAgentId}`, + refresh: 'true', + body: { + doc: agentDoc, + }, + }); + }); + + after(async () => await esArchiver.unload('endpoint/metadata/endpoint_status_feature')); + it('should return single metadata with status error when agent status is error', async () => { + const { body: metadataResponse } = await supertest + .get(`/api/endpoint/metadata/${enrolledHostId}`) + .set('kbn-xsrf', 'xxx') + .expect(200); + expect(metadataResponse.host_status).to.be('error'); + }); + + it('should return single metadata with status error when agent is not enrolled', async () => { + const { body: metadataResponse } = await supertest + .get(`/api/endpoint/metadata/${notEnrolledHostId}`) + .set('kbn-xsrf', 'xxx') + .expect(200); + expect(metadataResponse.host_status).to.be('error'); + }); + + it('should return metadata list with status error when no agent is not enrolled', async () => { + const { body } = await supertest + .post('/api/endpoint/metadata') + .set('kbn-xsrf', 'xxx') + .expect(200); + expect(body.total).to.eql(2); + expect(body.hosts.length).to.eql(2); + const enrolledHost = body.hosts.filter( + (hostInfo: Record) => hostInfo.metadata.host.id === enrolledHostId + ); + const notEnrolledHost = body.hosts.filter( + (hostInfo: Record) => hostInfo.metadata.host.id === notEnrolledHostId + ); + expect(enrolledHost.host_status === 'error'); + expect(notEnrolledHost.host_status === 'error'); + }); + + it('should return metadata list with status only when agent is checked in', async () => { + const { body: checkInResponse } = await supertestWithoutAuth + .post(`/api/ingest_manager/fleet/agents/${enrolledAgentId}/checkin`) + .set('kbn-xsrf', 'xx') + .set( + 'Authorization', + `ApiKey ${Buffer.from(`${apiKey.id}:${apiKey.api_key}`).toString('base64')}` + ) + .send({ + events: [], + local_metadata: {}, + }) + .expect(200); + + expect(checkInResponse.action).to.be('checkin'); + expect(checkInResponse.success).to.be(true); + + const { body } = await supertest + .post('/api/endpoint/metadata') + .set('kbn-xsrf', 'xxx') + .expect(200); + expect(body.total).to.eql(2); + expect(body.hosts.length).to.eql(2); + const enrolledHost = body.hosts.filter( + (hostInfo: Record) => hostInfo.metadata.host.id === enrolledHostId + ); + const notEnrolledHost = body.hosts.filter( + (hostInfo: Record) => hostInfo.metadata.host.id === notEnrolledHostId + ); + expect(enrolledHost.host_status === 'online'); + expect(notEnrolledHost.host_status === 'error'); + }); + + it('should return single metadata with status online when agent status is online', async () => { + await inactivity(); + const { body: checkInResponse } = await supertestWithoutAuth + .post(`/api/ingest_manager/fleet/agents/${enrolledAgentId}/checkin`) + .set('kbn-xsrf', 'xx') + .set( + 'Authorization', + `ApiKey ${Buffer.from(`${apiKey.id}:${apiKey.api_key}`).toString('base64')}` + ) + .send({ + events: [], + local_metadata: {}, + }) + .expect(200); + + expect(checkInResponse.action).to.be('checkin'); + expect(checkInResponse.success).to.be(true); + + const { body: metadataResponse } = await supertest + .get(`/api/endpoint/metadata/${enrolledHostId}`) + .set('kbn-xsrf', 'xxx') + .expect(200); + expect(metadataResponse.host_status).to.be('online'); + }); + }); + }); +} + +function inactivity() { + return new Promise(resolve => setTimeout(resolve, 35000)); +} diff --git a/x-pack/test/functional/es_archives/endpoint/metadata/endpoint_status_feature/data.json.gz b/x-pack/test/functional/es_archives/endpoint/metadata/endpoint_status_feature/data.json.gz new file mode 100644 index 0000000000000000000000000000000000000000..7042db66daab73f2aa54786a165db8c8d3606bcc GIT binary patch literal 34199 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 Date: Sat, 18 Apr 2020 12:40:14 -0400 Subject: [PATCH 03/14] EMT-146: use beforeEach and afterEach --- .../api_integration/apis/endpoint/metadata_status.ts | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/x-pack/test/api_integration/apis/endpoint/metadata_status.ts b/x-pack/test/api_integration/apis/endpoint/metadata_status.ts index 480ad4d18d3b0..3ea883fbeb4a9 100644 --- a/x-pack/test/api_integration/apis/endpoint/metadata_status.ts +++ b/x-pack/test/api_integration/apis/endpoint/metadata_status.ts @@ -26,7 +26,7 @@ export default function(providerContext: FtrProviderContext) { describe('test metadata api status', () => { describe('/api/endpoint/metadata when index is not empty', () => { - before(async () => { + beforeEach(async () => { await esArchiver.load('endpoint/metadata/endpoint_status_feature'); const { body: apiKeyBody } = await esClient.security.createApiKey({ body: { @@ -53,7 +53,8 @@ export default function(providerContext: FtrProviderContext) { }); }); - after(async () => await esArchiver.unload('endpoint/metadata/endpoint_status_feature')); + afterEach(async () => await esArchiver.unload('endpoint/metadata/endpoint_status_feature')); + it('should return single metadata with status error when agent status is error', async () => { const { body: metadataResponse } = await supertest .get(`/api/endpoint/metadata/${enrolledHostId}`) @@ -121,7 +122,6 @@ export default function(providerContext: FtrProviderContext) { }); it('should return single metadata with status online when agent status is online', async () => { - await inactivity(); const { body: checkInResponse } = await supertestWithoutAuth .post(`/api/ingest_manager/fleet/agents/${enrolledAgentId}/checkin`) .set('kbn-xsrf', 'xx') @@ -147,7 +147,3 @@ export default function(providerContext: FtrProviderContext) { }); }); } - -function inactivity() { - return new Promise(resolve => setTimeout(resolve, 35000)); -} From 4e53a4fe1d76e4b5f02d91a0a4d1aacd974856be Mon Sep 17 00:00:00 2001 From: nnamdifrankie Date: Sat, 18 Apr 2020 16:29:23 -0400 Subject: [PATCH 04/14] EMT-146: remove failing test --- .../apis/endpoint/metadata_status.ts | 62 +------------------ 1 file changed, 1 insertion(+), 61 deletions(-) diff --git a/x-pack/test/api_integration/apis/endpoint/metadata_status.ts b/x-pack/test/api_integration/apis/endpoint/metadata_status.ts index 3ea883fbeb4a9..ccbcfd9c46c91 100644 --- a/x-pack/test/api_integration/apis/endpoint/metadata_status.ts +++ b/x-pack/test/api_integration/apis/endpoint/metadata_status.ts @@ -7,13 +7,12 @@ import uuid from 'uuid'; import expect from '@kbn/expect'; import { FtrProviderContext } from '../../ftr_provider_context'; -import { getSupertestWithoutAuth } from '../fleet/agents/services'; export default function(providerContext: FtrProviderContext) { const { getService } = providerContext; const esArchiver = getService('esArchiver'); const supertest = getService('supertest'); - const supertestWithoutAuth = getSupertestWithoutAuth(providerContext); + // const supertestWithoutAuth = getSupertestWithoutAuth(providerContext); const esClient = getService('es'); // agent that is enrolled and know to fleet const enrolledAgentId = '3efef370-8164-11ea-bc0d-9196b6de96eb'; @@ -58,7 +57,6 @@ export default function(providerContext: FtrProviderContext) { it('should return single metadata with status error when agent status is error', async () => { const { body: metadataResponse } = await supertest .get(`/api/endpoint/metadata/${enrolledHostId}`) - .set('kbn-xsrf', 'xxx') .expect(200); expect(metadataResponse.host_status).to.be('error'); }); @@ -66,7 +64,6 @@ export default function(providerContext: FtrProviderContext) { it('should return single metadata with status error when agent is not enrolled', async () => { const { body: metadataResponse } = await supertest .get(`/api/endpoint/metadata/${notEnrolledHostId}`) - .set('kbn-xsrf', 'xxx') .expect(200); expect(metadataResponse.host_status).to.be('error'); }); @@ -87,63 +84,6 @@ export default function(providerContext: FtrProviderContext) { expect(enrolledHost.host_status === 'error'); expect(notEnrolledHost.host_status === 'error'); }); - - it('should return metadata list with status only when agent is checked in', async () => { - const { body: checkInResponse } = await supertestWithoutAuth - .post(`/api/ingest_manager/fleet/agents/${enrolledAgentId}/checkin`) - .set('kbn-xsrf', 'xx') - .set( - 'Authorization', - `ApiKey ${Buffer.from(`${apiKey.id}:${apiKey.api_key}`).toString('base64')}` - ) - .send({ - events: [], - local_metadata: {}, - }) - .expect(200); - - expect(checkInResponse.action).to.be('checkin'); - expect(checkInResponse.success).to.be(true); - - const { body } = await supertest - .post('/api/endpoint/metadata') - .set('kbn-xsrf', 'xxx') - .expect(200); - expect(body.total).to.eql(2); - expect(body.hosts.length).to.eql(2); - const enrolledHost = body.hosts.filter( - (hostInfo: Record) => hostInfo.metadata.host.id === enrolledHostId - ); - const notEnrolledHost = body.hosts.filter( - (hostInfo: Record) => hostInfo.metadata.host.id === notEnrolledHostId - ); - expect(enrolledHost.host_status === 'online'); - expect(notEnrolledHost.host_status === 'error'); - }); - - it('should return single metadata with status online when agent status is online', async () => { - const { body: checkInResponse } = await supertestWithoutAuth - .post(`/api/ingest_manager/fleet/agents/${enrolledAgentId}/checkin`) - .set('kbn-xsrf', 'xx') - .set( - 'Authorization', - `ApiKey ${Buffer.from(`${apiKey.id}:${apiKey.api_key}`).toString('base64')}` - ) - .send({ - events: [], - local_metadata: {}, - }) - .expect(200); - - expect(checkInResponse.action).to.be('checkin'); - expect(checkInResponse.success).to.be(true); - - const { body: metadataResponse } = await supertest - .get(`/api/endpoint/metadata/${enrolledHostId}`) - .set('kbn-xsrf', 'xxx') - .expect(200); - expect(metadataResponse.host_status).to.be('online'); - }); }); }); } From ba532d03d9c8952574053fb0dafa4e9ba8ce5b5e Mon Sep 17 00:00:00 2001 From: nnamdifrankie Date: Sat, 18 Apr 2020 18:43:43 -0400 Subject: [PATCH 05/14] EMT-146: add back integration test --- .../apis/endpoint/metadata_status.ts | 64 +++++++++++++++++- .../endpoint_status_feature/data.json.gz | Bin 34199 -> 33797 bytes 2 files changed, 61 insertions(+), 3 deletions(-) diff --git a/x-pack/test/api_integration/apis/endpoint/metadata_status.ts b/x-pack/test/api_integration/apis/endpoint/metadata_status.ts index ccbcfd9c46c91..e4a2c639bd33d 100644 --- a/x-pack/test/api_integration/apis/endpoint/metadata_status.ts +++ b/x-pack/test/api_integration/apis/endpoint/metadata_status.ts @@ -7,17 +7,18 @@ import uuid from 'uuid'; import expect from '@kbn/expect'; import { FtrProviderContext } from '../../ftr_provider_context'; +import { getSupertestWithoutAuth } from '../fleet/agents/services'; export default function(providerContext: FtrProviderContext) { const { getService } = providerContext; const esArchiver = getService('esArchiver'); const supertest = getService('supertest'); - // const supertestWithoutAuth = getSupertestWithoutAuth(providerContext); + const supertestWithoutAuth = getSupertestWithoutAuth(providerContext); const esClient = getService('es'); // agent that is enrolled and know to fleet - const enrolledAgentId = '3efef370-8164-11ea-bc0d-9196b6de96eb'; + const enrolledAgentId = '94e689c0-81bd-11ea-a4eb-77680821cd3b'; // host that is connected to enrolledAgentId - const enrolledHostId = 'fdb346d9-6f56-426a-90a7-a9328d1b0528'; + const enrolledHostId = '89ec7354-84a8-4f74-8d87-ba75f0994a17'; // host that is not connected to an enrolled agent id const notEnrolledHostId = 'bcf0d070-d9f2-40aa-8620-cbc004747722'; @@ -84,6 +85,63 @@ export default function(providerContext: FtrProviderContext) { expect(enrolledHost.host_status === 'error'); expect(notEnrolledHost.host_status === 'error'); }); + + it('should return single metadata with status online when agent status is online', async () => { + const { body: checkInResponse } = await supertestWithoutAuth + .post(`/api/ingest_manager/fleet/agents/${enrolledAgentId}/checkin`) + .set('kbn-xsrf', 'xx') + .set( + 'Authorization', + `ApiKey ${Buffer.from(`${apiKey.id}:${apiKey.api_key}`).toString('base64')}` + ) + .send({ + events: [], + local_metadata: {}, + }) + .expect(200); + + expect(checkInResponse.action).to.be('checkin'); + expect(checkInResponse.success).to.be(true); + + const { body: metadataResponse } = await supertest + .get(`/api/endpoint/metadata/${enrolledHostId}`) + .set('kbn-xsrf', 'xxx') + .expect(200); + expect(metadataResponse.host_status).to.be('online'); + }); + + it('should return metadata list with status only when agent is checked in', async () => { + const { body: checkInResponse } = await supertestWithoutAuth + .post(`/api/ingest_manager/fleet/agents/${enrolledAgentId}/checkin`) + .set('kbn-xsrf', 'xx') + .set( + 'Authorization', + `ApiKey ${Buffer.from(`${apiKey.id}:${apiKey.api_key}`).toString('base64')}` + ) + .send({ + events: [], + local_metadata: {}, + }) + .expect(200); + + expect(checkInResponse.action).to.be('checkin'); + expect(checkInResponse.success).to.be(true); + + const { body } = await supertest + .post('/api/endpoint/metadata') + .set('kbn-xsrf', 'xxx') + .expect(200); + expect(body.total).to.eql(2); + expect(body.hosts.length).to.eql(2); + const enrolledHost = body.hosts.filter( + (hostInfo: Record) => hostInfo.metadata.host.id === enrolledHostId + ); + const notEnrolledHost = body.hosts.filter( + (hostInfo: Record) => hostInfo.metadata.host.id === notEnrolledHostId + ); + expect(enrolledHost.host_status === 'online'); + expect(notEnrolledHost.host_status === 'error'); + }); }); }); } diff --git a/x-pack/test/functional/es_archives/endpoint/metadata/endpoint_status_feature/data.json.gz b/x-pack/test/functional/es_archives/endpoint/metadata/endpoint_status_feature/data.json.gz index 7042db66daab73f2aa54786a165db8c8d3606bcc..00b2fcbd7f617f87421fcf695a17165b5020898a 100644 GIT binary patch literal 33797 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 literal 34199 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 Date: Sun, 19 Apr 2020 09:59:13 -0400 Subject: [PATCH 06/14] EMT-146: revert ingest calls --- .../apis/endpoint/metadata_status.ts | 57 ------------------- 1 file changed, 57 deletions(-) diff --git a/x-pack/test/api_integration/apis/endpoint/metadata_status.ts b/x-pack/test/api_integration/apis/endpoint/metadata_status.ts index e4a2c639bd33d..7185a4a9326e9 100644 --- a/x-pack/test/api_integration/apis/endpoint/metadata_status.ts +++ b/x-pack/test/api_integration/apis/endpoint/metadata_status.ts @@ -85,63 +85,6 @@ export default function(providerContext: FtrProviderContext) { expect(enrolledHost.host_status === 'error'); expect(notEnrolledHost.host_status === 'error'); }); - - it('should return single metadata with status online when agent status is online', async () => { - const { body: checkInResponse } = await supertestWithoutAuth - .post(`/api/ingest_manager/fleet/agents/${enrolledAgentId}/checkin`) - .set('kbn-xsrf', 'xx') - .set( - 'Authorization', - `ApiKey ${Buffer.from(`${apiKey.id}:${apiKey.api_key}`).toString('base64')}` - ) - .send({ - events: [], - local_metadata: {}, - }) - .expect(200); - - expect(checkInResponse.action).to.be('checkin'); - expect(checkInResponse.success).to.be(true); - - const { body: metadataResponse } = await supertest - .get(`/api/endpoint/metadata/${enrolledHostId}`) - .set('kbn-xsrf', 'xxx') - .expect(200); - expect(metadataResponse.host_status).to.be('online'); - }); - - it('should return metadata list with status only when agent is checked in', async () => { - const { body: checkInResponse } = await supertestWithoutAuth - .post(`/api/ingest_manager/fleet/agents/${enrolledAgentId}/checkin`) - .set('kbn-xsrf', 'xx') - .set( - 'Authorization', - `ApiKey ${Buffer.from(`${apiKey.id}:${apiKey.api_key}`).toString('base64')}` - ) - .send({ - events: [], - local_metadata: {}, - }) - .expect(200); - - expect(checkInResponse.action).to.be('checkin'); - expect(checkInResponse.success).to.be(true); - - const { body } = await supertest - .post('/api/endpoint/metadata') - .set('kbn-xsrf', 'xxx') - .expect(200); - expect(body.total).to.eql(2); - expect(body.hosts.length).to.eql(2); - const enrolledHost = body.hosts.filter( - (hostInfo: Record) => hostInfo.metadata.host.id === enrolledHostId - ); - const notEnrolledHost = body.hosts.filter( - (hostInfo: Record) => hostInfo.metadata.host.id === notEnrolledHostId - ); - expect(enrolledHost.host_status === 'online'); - expect(notEnrolledHost.host_status === 'error'); - }); }); }); } From 229df97908ca9658fe76761414e5f69f9a3fdfef Mon Sep 17 00:00:00 2001 From: nnamdifrankie Date: Sun, 19 Apr 2020 13:26:57 -0400 Subject: [PATCH 07/14] EMT-146: clean up --- x-pack/test/api_integration/apis/endpoint/metadata_status.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/x-pack/test/api_integration/apis/endpoint/metadata_status.ts b/x-pack/test/api_integration/apis/endpoint/metadata_status.ts index 7185a4a9326e9..e3d506b7e7c59 100644 --- a/x-pack/test/api_integration/apis/endpoint/metadata_status.ts +++ b/x-pack/test/api_integration/apis/endpoint/metadata_status.ts @@ -7,13 +7,11 @@ import uuid from 'uuid'; import expect from '@kbn/expect'; import { FtrProviderContext } from '../../ftr_provider_context'; -import { getSupertestWithoutAuth } from '../fleet/agents/services'; export default function(providerContext: FtrProviderContext) { const { getService } = providerContext; const esArchiver = getService('esArchiver'); const supertest = getService('supertest'); - const supertestWithoutAuth = getSupertestWithoutAuth(providerContext); const esClient = getService('es'); // agent that is enrolled and know to fleet const enrolledAgentId = '94e689c0-81bd-11ea-a4eb-77680821cd3b'; From bcd6e4c2e3780eab92b2155a1ba497c13617f5b8 Mon Sep 17 00:00:00 2001 From: nnamdifrankie Date: Mon, 20 Apr 2020 10:14:49 -0400 Subject: [PATCH 08/14] EMT-146: reorder test load --- x-pack/test/api_integration/apis/endpoint/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/test/api_integration/apis/endpoint/index.ts b/x-pack/test/api_integration/apis/endpoint/index.ts index 1c373d85365f9..2fb4097f7e066 100644 --- a/x-pack/test/api_integration/apis/endpoint/index.ts +++ b/x-pack/test/api_integration/apis/endpoint/index.ts @@ -19,7 +19,7 @@ export default function endpointAPIIntegrationTests({ loadTestFile(require.resolve('./index_pattern')); loadTestFile(require.resolve('./resolver')); loadTestFile(require.resolve('./metadata')); - loadTestFile(require.resolve('./metadata_status')); loadTestFile(require.resolve('./alerts')); + loadTestFile(require.resolve('./metadata_status')); }); } From f591e864ac656763cfd65b1bef626355109c7c6d Mon Sep 17 00:00:00 2001 From: nnamdifrankie Date: Mon, 20 Apr 2020 12:53:19 -0400 Subject: [PATCH 09/14] EMT-146: add ingest calls back --- .../api_integration/apis/endpoint/index.ts | 4 +- .../apis/endpoint/metadata_status.ts | 68 ++++++++++++++++++- 2 files changed, 69 insertions(+), 3 deletions(-) diff --git a/x-pack/test/api_integration/apis/endpoint/index.ts b/x-pack/test/api_integration/apis/endpoint/index.ts index 2fb4097f7e066..8f9a31eab2e5c 100644 --- a/x-pack/test/api_integration/apis/endpoint/index.ts +++ b/x-pack/test/api_integration/apis/endpoint/index.ts @@ -13,13 +13,13 @@ export default function endpointAPIIntegrationTests({ describe('Endpoint plugin', function() { const ingestManager = getService('ingestManager'); this.tags(['endpoint']); - before(async () => { + beforeEach(async () => { await ingestManager.setup(); }); loadTestFile(require.resolve('./index_pattern')); loadTestFile(require.resolve('./resolver')); loadTestFile(require.resolve('./metadata')); - loadTestFile(require.resolve('./alerts')); loadTestFile(require.resolve('./metadata_status')); + loadTestFile(require.resolve('./alerts')); }); } diff --git a/x-pack/test/api_integration/apis/endpoint/metadata_status.ts b/x-pack/test/api_integration/apis/endpoint/metadata_status.ts index e3d506b7e7c59..b5a0aa4b25f51 100644 --- a/x-pack/test/api_integration/apis/endpoint/metadata_status.ts +++ b/x-pack/test/api_integration/apis/endpoint/metadata_status.ts @@ -7,12 +7,14 @@ import uuid from 'uuid'; import expect from '@kbn/expect'; import { FtrProviderContext } from '../../ftr_provider_context'; +import { getSupertestWithoutAuth } from '../fleet/agents/services'; export default function(providerContext: FtrProviderContext) { const { getService } = providerContext; const esArchiver = getService('esArchiver'); const supertest = getService('supertest'); const esClient = getService('es'); + const supertestWithoutAuth = getSupertestWithoutAuth(providerContext); // agent that is enrolled and know to fleet const enrolledAgentId = '94e689c0-81bd-11ea-a4eb-77680821cd3b'; // host that is connected to enrolledAgentId @@ -25,7 +27,7 @@ export default function(providerContext: FtrProviderContext) { describe('test metadata api status', () => { describe('/api/endpoint/metadata when index is not empty', () => { beforeEach(async () => { - await esArchiver.load('endpoint/metadata/endpoint_status_feature'); + await esArchiver.loadIfNeeded('endpoint/metadata/endpoint_status_feature'); const { body: apiKeyBody } = await esClient.security.createApiKey({ body: { name: `test access api key: ${uuid.v4()}`, @@ -49,6 +51,13 @@ export default function(providerContext: FtrProviderContext) { doc: agentDoc, }, }); + await getService('supertest') + .post(`/api/ingest_manager/setup`) + .set('kbn-xsrf', 'xxx') + .send(); + await getService('supertest') + .post(`/api/ingest_manager/fleet/setup`) + .set('kbn-xsrf', 'xxx'); }); afterEach(async () => await esArchiver.unload('endpoint/metadata/endpoint_status_feature')); @@ -83,6 +92,63 @@ export default function(providerContext: FtrProviderContext) { expect(enrolledHost.host_status === 'error'); expect(notEnrolledHost.host_status === 'error'); }); + + it('should return single metadata with status online when agent status is online', async () => { + const { body: checkInResponse } = await supertestWithoutAuth + .post(`/api/ingest_manager/fleet/agents/${enrolledAgentId}/checkin`) + .set('kbn-xsrf', 'xx') + .set( + 'Authorization', + `ApiKey ${Buffer.from(`${apiKey.id}:${apiKey.api_key}`).toString('base64')}` + ) + .send({ + events: [], + local_metadata: {}, + }) + .expect(200); + + expect(checkInResponse.action).to.be('checkin'); + expect(checkInResponse.success).to.be(true); + + const { body: metadataResponse } = await supertest + .get(`/api/endpoint/metadata/${enrolledHostId}`) + .set('kbn-xsrf', 'xxx') + .expect(200); + expect(metadataResponse.host_status).to.be('online'); + }); + + it('should return metadata list with status only when agent is checked in', async () => { + const { body: checkInResponse } = await supertestWithoutAuth + .post(`/api/ingest_manager/fleet/agents/${enrolledAgentId}/checkin`) + .set('kbn-xsrf', 'xx') + .set( + 'Authorization', + `ApiKey ${Buffer.from(`${apiKey.id}:${apiKey.api_key}`).toString('base64')}` + ) + .send({ + events: [], + local_metadata: {}, + }) + .expect(200); + + expect(checkInResponse.action).to.be('checkin'); + expect(checkInResponse.success).to.be(true); + + const { body } = await supertest + .post('/api/endpoint/metadata') + .set('kbn-xsrf', 'xxx') + .expect(200); + expect(body.total).to.eql(2); + expect(body.hosts.length).to.eql(2); + const enrolledHost = body.hosts.filter( + (hostInfo: Record) => hostInfo.metadata.host.id === enrolledHostId + ); + const notEnrolledHost = body.hosts.filter( + (hostInfo: Record) => hostInfo.metadata.host.id === notEnrolledHostId + ); + expect(enrolledHost.host_status === 'online'); + expect(notEnrolledHost.host_status === 'error'); + }); }); }); } From 62eba600d5f36c2c5ce2697fb4a466c215e7daf0 Mon Sep 17 00:00:00 2001 From: nnamdifrankie Date: Mon, 20 Apr 2020 14:27:33 -0400 Subject: [PATCH 10/14] EMT-146: remove metadata status test, it cross some boundaries --- .../api_integration/apis/endpoint/index.ts | 3 +- .../apis/endpoint/metadata_status.ts | 154 - .../endpoint_status_feature/data.json.gz | Bin 33797 -> 0 bytes .../endpoint_status_feature/mappings.json | 3255 ----------------- 4 files changed, 1 insertion(+), 3411 deletions(-) delete mode 100644 x-pack/test/api_integration/apis/endpoint/metadata_status.ts delete mode 100644 x-pack/test/functional/es_archives/endpoint/metadata/endpoint_status_feature/data.json.gz delete mode 100644 x-pack/test/functional/es_archives/endpoint/metadata/endpoint_status_feature/mappings.json diff --git a/x-pack/test/api_integration/apis/endpoint/index.ts b/x-pack/test/api_integration/apis/endpoint/index.ts index 8f9a31eab2e5c..0a5f9aa595b8a 100644 --- a/x-pack/test/api_integration/apis/endpoint/index.ts +++ b/x-pack/test/api_integration/apis/endpoint/index.ts @@ -13,13 +13,12 @@ export default function endpointAPIIntegrationTests({ describe('Endpoint plugin', function() { const ingestManager = getService('ingestManager'); this.tags(['endpoint']); - beforeEach(async () => { + before(async () => { await ingestManager.setup(); }); loadTestFile(require.resolve('./index_pattern')); loadTestFile(require.resolve('./resolver')); loadTestFile(require.resolve('./metadata')); - loadTestFile(require.resolve('./metadata_status')); loadTestFile(require.resolve('./alerts')); }); } diff --git a/x-pack/test/api_integration/apis/endpoint/metadata_status.ts b/x-pack/test/api_integration/apis/endpoint/metadata_status.ts deleted file mode 100644 index b5a0aa4b25f51..0000000000000 --- a/x-pack/test/api_integration/apis/endpoint/metadata_status.ts +++ /dev/null @@ -1,154 +0,0 @@ -/* - * 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 uuid from 'uuid'; -import expect from '@kbn/expect'; -import { FtrProviderContext } from '../../ftr_provider_context'; -import { getSupertestWithoutAuth } from '../fleet/agents/services'; - -export default function(providerContext: FtrProviderContext) { - const { getService } = providerContext; - const esArchiver = getService('esArchiver'); - const supertest = getService('supertest'); - const esClient = getService('es'); - const supertestWithoutAuth = getSupertestWithoutAuth(providerContext); - // agent that is enrolled and know to fleet - const enrolledAgentId = '94e689c0-81bd-11ea-a4eb-77680821cd3b'; - // host that is connected to enrolledAgentId - const enrolledHostId = '89ec7354-84a8-4f74-8d87-ba75f0994a17'; - // host that is not connected to an enrolled agent id - const notEnrolledHostId = 'bcf0d070-d9f2-40aa-8620-cbc004747722'; - - let apiKey: { id: string; api_key: string }; - - describe('test metadata api status', () => { - describe('/api/endpoint/metadata when index is not empty', () => { - beforeEach(async () => { - await esArchiver.loadIfNeeded('endpoint/metadata/endpoint_status_feature'); - const { body: apiKeyBody } = await esClient.security.createApiKey({ - body: { - name: `test access api key: ${uuid.v4()}`, - }, - }); - apiKey = apiKeyBody; - const { - body: { _source: agentDoc }, - } = await esClient.get({ - index: '.kibana', - id: `agents:${enrolledAgentId}`, - }); - - agentDoc.agents.access_api_key_id = apiKey.id; - - await esClient.update({ - index: '.kibana', - id: `agents:${enrolledAgentId}`, - refresh: 'true', - body: { - doc: agentDoc, - }, - }); - await getService('supertest') - .post(`/api/ingest_manager/setup`) - .set('kbn-xsrf', 'xxx') - .send(); - await getService('supertest') - .post(`/api/ingest_manager/fleet/setup`) - .set('kbn-xsrf', 'xxx'); - }); - - afterEach(async () => await esArchiver.unload('endpoint/metadata/endpoint_status_feature')); - - it('should return single metadata with status error when agent status is error', async () => { - const { body: metadataResponse } = await supertest - .get(`/api/endpoint/metadata/${enrolledHostId}`) - .expect(200); - expect(metadataResponse.host_status).to.be('error'); - }); - - it('should return single metadata with status error when agent is not enrolled', async () => { - const { body: metadataResponse } = await supertest - .get(`/api/endpoint/metadata/${notEnrolledHostId}`) - .expect(200); - expect(metadataResponse.host_status).to.be('error'); - }); - - it('should return metadata list with status error when no agent is not enrolled', async () => { - const { body } = await supertest - .post('/api/endpoint/metadata') - .set('kbn-xsrf', 'xxx') - .expect(200); - expect(body.total).to.eql(2); - expect(body.hosts.length).to.eql(2); - const enrolledHost = body.hosts.filter( - (hostInfo: Record) => hostInfo.metadata.host.id === enrolledHostId - ); - const notEnrolledHost = body.hosts.filter( - (hostInfo: Record) => hostInfo.metadata.host.id === notEnrolledHostId - ); - expect(enrolledHost.host_status === 'error'); - expect(notEnrolledHost.host_status === 'error'); - }); - - it('should return single metadata with status online when agent status is online', async () => { - const { body: checkInResponse } = await supertestWithoutAuth - .post(`/api/ingest_manager/fleet/agents/${enrolledAgentId}/checkin`) - .set('kbn-xsrf', 'xx') - .set( - 'Authorization', - `ApiKey ${Buffer.from(`${apiKey.id}:${apiKey.api_key}`).toString('base64')}` - ) - .send({ - events: [], - local_metadata: {}, - }) - .expect(200); - - expect(checkInResponse.action).to.be('checkin'); - expect(checkInResponse.success).to.be(true); - - const { body: metadataResponse } = await supertest - .get(`/api/endpoint/metadata/${enrolledHostId}`) - .set('kbn-xsrf', 'xxx') - .expect(200); - expect(metadataResponse.host_status).to.be('online'); - }); - - it('should return metadata list with status only when agent is checked in', async () => { - const { body: checkInResponse } = await supertestWithoutAuth - .post(`/api/ingest_manager/fleet/agents/${enrolledAgentId}/checkin`) - .set('kbn-xsrf', 'xx') - .set( - 'Authorization', - `ApiKey ${Buffer.from(`${apiKey.id}:${apiKey.api_key}`).toString('base64')}` - ) - .send({ - events: [], - local_metadata: {}, - }) - .expect(200); - - expect(checkInResponse.action).to.be('checkin'); - expect(checkInResponse.success).to.be(true); - - const { body } = await supertest - .post('/api/endpoint/metadata') - .set('kbn-xsrf', 'xxx') - .expect(200); - expect(body.total).to.eql(2); - expect(body.hosts.length).to.eql(2); - const enrolledHost = body.hosts.filter( - (hostInfo: Record) => hostInfo.metadata.host.id === enrolledHostId - ); - const notEnrolledHost = body.hosts.filter( - (hostInfo: Record) => hostInfo.metadata.host.id === notEnrolledHostId - ); - expect(enrolledHost.host_status === 'online'); - expect(notEnrolledHost.host_status === 'error'); - }); - }); - }); -} diff --git a/x-pack/test/functional/es_archives/endpoint/metadata/endpoint_status_feature/data.json.gz b/x-pack/test/functional/es_archives/endpoint/metadata/endpoint_status_feature/data.json.gz deleted file mode 100644 index 00b2fcbd7f617f87421fcf695a17165b5020898a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 33797 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 diff --git a/x-pack/test/functional/es_archives/endpoint/metadata/endpoint_status_feature/mappings.json b/x-pack/test/functional/es_archives/endpoint/metadata/endpoint_status_feature/mappings.json deleted file mode 100644 index dbf6f0ad34023..0000000000000 --- a/x-pack/test/functional/es_archives/endpoint/metadata/endpoint_status_feature/mappings.json +++ /dev/null @@ -1,3255 +0,0 @@ -{ - "type": "index", - "value": { - "aliases": { - }, - "index": "metrics-endpoint-default-1", - "mappings": { - "_meta": { - "package": "foo", - "version": "1.6.0-dev" - }, - "date_detection": false, - "dynamic_templates": [ - { - "strings_as_keyword": { - "mapping": { - "ignore_above": 1024, - "type": "keyword" - }, - "match_mapping_type": "string" - } - } - ], - "properties": { - "@timestamp": { - "type": "date" - }, - "agent": { - "properties": { - "ephemeral_id": { - "ignore_above": 1024, - "type": "keyword" - }, - "hostname": { - "ignore_above": 1024, - "type": "keyword" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "type": { - "ignore_above": 1024, - "type": "keyword" - }, - "version": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "ecs": { - "properties": { - "version": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "elastic": { - "properties": { - "agent": { - "properties": { - "id": { - "ignore_above": 1024, - "type": "keyword" - } - } - } - } - }, - "endpoint": { - "properties": { - "policy": { - "properties": { - "id": { - "ignore_above": 1024, - "type": "keyword" - } - } - } - } - }, - "event": { - "properties": { - "created": { - "type": "date" - } - } - }, - "host": { - "properties": { - "architecture": { - "ignore_above": 1024, - "type": "keyword" - }, - "containerized": { - "type": "boolean" - }, - "hostname": { - "ignore_above": 1024, - "type": "keyword" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "ip": { - "type": "ip" - }, - "mac": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "os": { - "properties": { - "build": { - "ignore_above": 1024, - "type": "keyword" - }, - "codename": { - "ignore_above": 1024, - "type": "keyword" - }, - "family": { - "ignore_above": 1024, - "type": "keyword" - }, - "full": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "kernel": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "platform": { - "ignore_above": 1024, - "type": "keyword" - }, - "variant": { - "ignore_above": 1024, - "type": "keyword" - }, - "version": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "type": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "stream": { - "properties": { - "dataset": { - "type": "constant_keyword" - }, - "namespace": { - "type": "constant_keyword" - }, - "type": { - "type": "constant_keyword" - } - } - } - } - }, - "settings": { - "index": { - "codec": "best_compression", - "lifecycle": { - "name": "metrics-default" - }, - "mapping": { - "total_fields": { - "limit": "10000" - } - }, - "number_of_replicas": "1", - "number_of_shards": "1", - "query": { - "default_field": [ - "message" - ] - }, - "refresh_interval": "5s" - } - } - } -} - -{ - "type": "index", - "value": { - "aliases": { - ".kibana": { - } - }, - "index": ".kibana_1", - "mappings": { - "_meta": { - "migrationMappingPropertyHashes": { - "action": "6e96ac5e648f57523879661ea72525b7", - "action_task_params": "a9d49f184ee89641044be0ca2950fa3a", - "agent_actions": "ed270b46812f0fa1439366c428a2cf17", - "agent_configs": "38abaf89513877745c359e7700c0c66a", - "agent_events": "3231653fafe4ef3196fe3b32ab774bf2", - "agents": "c3eeb7b9d97176f15f6d126370ab23c7", - "alert": "7b44fba6773e37c806ce290ea9b7024e", - "apm-indices": "9bb9b2bf1fa636ed8619cbab5ce6a1dd", - "apm-telemetry": "3525d7c22c42bc80f5e6e9cb3f2b26a2", - "application_usage_totals": "c897e4310c5f24b07caaff3db53ae2c1", - "application_usage_transactional": "965839e75f809fefe04f92dc4d99722a", - "canvas-element": "7390014e1091044523666d97247392fc", - "canvas-workpad": "b0a1706d356228dbdcb4a17e6b9eb231", - "cases": "08b8b110dbca273d37e8aef131ecab61", - "cases-comments": "c2061fb929f585df57425102fa928b4b", - "cases-configure": "42711cbb311976c0687853f4c1354572", - "cases-user-actions": "32277330ec6b721abe3b846cfd939a71", - "config": "ae24d22d5986d04124cc6568f771066f", - "dashboard": "d00f614b29a80360e1190193fd333bab", - "datasources": "624d2ef3babbfa18022829c795ca354e", - "enrollment_api_keys": "28b91e20b105b6f928e2012600085d8f", - "epm-package": "50720890bcdafad30643bcee8a32098b", - "file-upload-telemetry": "0ed4d3e1983d1217a30982630897092e", - "graph-workspace": "cd7ba1330e6682e9cc00b78850874be1", - "index-pattern": "66eccb05066c5a89924f48a9e9736499", - "infrastructure-ui-source": "ddc0ecb18383f6b26101a2fadb2dab0c", - "inventory-view": "5299b67717e96502c77babf1c16fd4d3", - "kql-telemetry": "d12a98a6f19a2d273696597547e064ee", - "lens": "21c3ea0763beb1ecb0162529706b88c5", - "lens-ui-telemetry": "509bfa5978586998e05f9e303c07a327", - "map": "23d7aa4a720d4938ccde3983f87bd58d", - "maps-telemetry": "268da3a48066123fc5baf35abaa55014", - "metrics-explorer-view": "53c5365793677328df0ccb6138bf3cdd", - "migrationVersion": "4a1746014a75ade3a714e1db5763276f", - "ml-telemetry": "257fd1d4b4fdbb9cb4b8a3b27da201e9", - "namespace": "2f4316de49999235636386fe51dc06c1", - "namespaces": "2f4316de49999235636386fe51dc06c1", - "outputs": "aee9782e0d500b867859650a36280165", - "query": "11aaeb7f5f7fa5bb43f25e18ce26e7d9", - "references": "7997cf5a56cc02bdc9c93361bde732b0", - "sample-data-telemetry": "7d3cfeb915303c9641c59681967ffeb4", - "search": "181661168bbadd1eff5902361e2a0d5c", - "server": "ec97f1c5da1a19609a60874e5af1100c", - "siem-detection-engine-rule-actions": "90eee2e4635260f4be0a1da8f5bc0aa0", - "siem-detection-engine-rule-status": "ae783f41c6937db6b7a2ef5c93a9e9b0", - "siem-ui-timeline": "ac8020190f5950dd3250b6499144e7fb", - "siem-ui-timeline-note": "8874706eedc49059d4cf0f5094559084", - "siem-ui-timeline-pinned-event": "20638091112f0e14f0e443d512301c29", - "space": "c5ca8acafa0beaa4d08d014a97b6bc6b", - "telemetry": "36a616f7026dfa617d6655df850fe16d", - "timelion-sheet": "9a2a2748877c7a7b582fef201ab1d4cf", - "tsvb-validation-telemetry": "3a37ef6c8700ae6fc97d5c7da00e9215", - "type": "2f4316de49999235636386fe51dc06c1", - "ui-metric": "0d409297dc5ebe1e3a1da691c6ee32e3", - "updated_at": "00da57df13e94e9d98437d13ace4bfe0", - "upgrade-assistant-reindex-operation": "a53a20fe086b72c9a86da3cc12dad8a6", - "upgrade-assistant-telemetry": "56702cec857e0a9dacfb696655b4ff7b", - "uptime-dynamic-settings": "07a4a5d2952aa47b4528b9d462ac256e", - "url": "c7f66a0df8b1b52f17c28c4adb111105", - "visualization": "52d7a13ad68a150c4525b292d23e12cc" - } - }, - "dynamic": "strict", - "properties": { - "action": { - "properties": { - "actionTypeId": { - "type": "keyword" - }, - "config": { - "enabled": false, - "type": "object" - }, - "name": { - "fields": { - "keyword": { - "type": "keyword" - } - }, - "type": "text" - }, - "secrets": { - "type": "binary" - } - } - }, - "action_task_params": { - "properties": { - "actionId": { - "type": "keyword" - }, - "apiKey": { - "type": "binary" - }, - "params": { - "enabled": false, - "type": "object" - } - } - }, - "agent_actions": { - "properties": { - "agent_id": { - "type": "keyword" - }, - "created_at": { - "type": "date" - }, - "data": { - "type": "flattened" - }, - "sent_at": { - "type": "date" - }, - "type": { - "type": "keyword" - } - } - }, - "agent_configs": { - "properties": { - "datasources": { - "type": "keyword" - }, - "description": { - "type": "text" - }, - "id": { - "type": "keyword" - }, - "is_default": { - "type": "boolean" - }, - "name": { - "type": "text" - }, - "namespace": { - "type": "keyword" - }, - "revision": { - "type": "integer" - }, - "status": { - "type": "keyword" - }, - "updated_by": { - "type": "keyword" - }, - "updated_on": { - "type": "keyword" - } - } - }, - "agent_events": { - "properties": { - "action_id": { - "type": "keyword" - }, - "agent_id": { - "type": "keyword" - }, - "config_id": { - "type": "keyword" - }, - "data": { - "type": "text" - }, - "message": { - "type": "text" - }, - "payload": { - "type": "text" - }, - "stream_id": { - "type": "keyword" - }, - "subtype": { - "type": "keyword" - }, - "timestamp": { - "type": "date" - }, - "type": { - "type": "keyword" - } - } - }, - "agents": { - "properties": { - "access_api_key_id": { - "type": "keyword" - }, - "active": { - "type": "boolean" - }, - "config_id": { - "type": "keyword" - }, - "config_newest_revision": { - "type": "integer" - }, - "config_revision": { - "type": "integer" - }, - "current_error_events": { - "type": "text" - }, - "default_api_key": { - "type": "keyword" - }, - "enrolled_at": { - "type": "date" - }, - "last_checkin": { - "type": "date" - }, - "last_updated": { - "type": "date" - }, - "local_metadata": { - "type": "text" - }, - "shared_id": { - "type": "keyword" - }, - "type": { - "type": "keyword" - }, - "updated_at": { - "type": "date" - }, - "user_provided_metadata": { - "type": "text" - }, - "version": { - "type": "keyword" - } - } - }, - "alert": { - "properties": { - "actions": { - "properties": { - "actionRef": { - "type": "keyword" - }, - "actionTypeId": { - "type": "keyword" - }, - "group": { - "type": "keyword" - }, - "params": { - "enabled": false, - "type": "object" - } - }, - "type": "nested" - }, - "alertTypeId": { - "type": "keyword" - }, - "apiKey": { - "type": "binary" - }, - "apiKeyOwner": { - "type": "keyword" - }, - "consumer": { - "type": "keyword" - }, - "createdAt": { - "type": "date" - }, - "createdBy": { - "type": "keyword" - }, - "enabled": { - "type": "boolean" - }, - "muteAll": { - "type": "boolean" - }, - "mutedInstanceIds": { - "type": "keyword" - }, - "name": { - "fields": { - "keyword": { - "type": "keyword" - } - }, - "type": "text" - }, - "params": { - "enabled": false, - "type": "object" - }, - "schedule": { - "properties": { - "interval": { - "type": "keyword" - } - } - }, - "scheduledTaskId": { - "type": "keyword" - }, - "tags": { - "type": "keyword" - }, - "throttle": { - "type": "keyword" - }, - "updatedBy": { - "type": "keyword" - } - } - }, - "apm-indices": { - "properties": { - "apm_oss": { - "properties": { - "errorIndices": { - "type": "keyword" - }, - "metricsIndices": { - "type": "keyword" - }, - "onboardingIndices": { - "type": "keyword" - }, - "sourcemapIndices": { - "type": "keyword" - }, - "spanIndices": { - "type": "keyword" - }, - "transactionIndices": { - "type": "keyword" - } - } - } - } - }, - "apm-telemetry": { - "properties": { - "agents": { - "properties": { - "dotnet": { - "properties": { - "agent": { - "properties": { - "version": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "service": { - "properties": { - "framework": { - "properties": { - "composite": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "version": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "language": { - "properties": { - "composite": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "version": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "runtime": { - "properties": { - "composite": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "version": { - "ignore_above": 1024, - "type": "keyword" - } - } - } - } - } - } - }, - "go": { - "properties": { - "agent": { - "properties": { - "version": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "service": { - "properties": { - "framework": { - "properties": { - "composite": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "version": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "language": { - "properties": { - "composite": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "version": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "runtime": { - "properties": { - "composite": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "version": { - "ignore_above": 1024, - "type": "keyword" - } - } - } - } - } - } - }, - "java": { - "properties": { - "agent": { - "properties": { - "version": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "service": { - "properties": { - "framework": { - "properties": { - "composite": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "version": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "language": { - "properties": { - "composite": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "version": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "runtime": { - "properties": { - "composite": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "version": { - "ignore_above": 1024, - "type": "keyword" - } - } - } - } - } - } - }, - "js-base": { - "properties": { - "agent": { - "properties": { - "version": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "service": { - "properties": { - "framework": { - "properties": { - "composite": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "version": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "language": { - "properties": { - "composite": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "version": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "runtime": { - "properties": { - "composite": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "version": { - "ignore_above": 1024, - "type": "keyword" - } - } - } - } - } - } - }, - "nodejs": { - "properties": { - "agent": { - "properties": { - "version": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "service": { - "properties": { - "framework": { - "properties": { - "composite": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "version": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "language": { - "properties": { - "composite": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "version": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "runtime": { - "properties": { - "composite": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "version": { - "ignore_above": 1024, - "type": "keyword" - } - } - } - } - } - } - }, - "python": { - "properties": { - "agent": { - "properties": { - "version": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "service": { - "properties": { - "framework": { - "properties": { - "composite": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "version": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "language": { - "properties": { - "composite": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "version": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "runtime": { - "properties": { - "composite": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "version": { - "ignore_above": 1024, - "type": "keyword" - } - } - } - } - } - } - }, - "ruby": { - "properties": { - "agent": { - "properties": { - "version": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "service": { - "properties": { - "framework": { - "properties": { - "composite": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "version": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "language": { - "properties": { - "composite": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "version": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "runtime": { - "properties": { - "composite": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "version": { - "ignore_above": 1024, - "type": "keyword" - } - } - } - } - } - } - }, - "rum-js": { - "properties": { - "agent": { - "properties": { - "version": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "service": { - "properties": { - "framework": { - "properties": { - "composite": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "version": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "language": { - "properties": { - "composite": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "version": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "runtime": { - "properties": { - "composite": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "version": { - "ignore_above": 1024, - "type": "keyword" - } - } - } - } - } - } - } - } - }, - "cardinality": { - "properties": { - "transaction": { - "properties": { - "name": { - "properties": { - "all_agents": { - "properties": { - "1d": { - "type": "long" - } - } - }, - "rum": { - "properties": { - "1d": { - "type": "long" - } - } - } - } - } - } - }, - "user_agent": { - "properties": { - "original": { - "properties": { - "all_agents": { - "properties": { - "1d": { - "type": "long" - } - } - }, - "rum": { - "properties": { - "1d": { - "type": "long" - } - } - } - } - } - } - } - } - }, - "counts": { - "properties": { - "agent_configuration": { - "properties": { - "all": { - "type": "long" - } - } - }, - "error": { - "properties": { - "1d": { - "type": "long" - }, - "all": { - "type": "long" - } - } - }, - "max_error_groups_per_service": { - "properties": { - "1d": { - "type": "long" - } - } - }, - "max_transaction_groups_per_service": { - "properties": { - "1d": { - "type": "long" - } - } - }, - "metric": { - "properties": { - "1d": { - "type": "long" - }, - "all": { - "type": "long" - } - } - }, - "onboarding": { - "properties": { - "1d": { - "type": "long" - }, - "all": { - "type": "long" - } - } - }, - "services": { - "properties": { - "1d": { - "type": "long" - } - } - }, - "sourcemap": { - "properties": { - "1d": { - "type": "long" - }, - "all": { - "type": "long" - } - } - }, - "span": { - "properties": { - "1d": { - "type": "long" - }, - "all": { - "type": "long" - } - } - }, - "traces": { - "properties": { - "1d": { - "type": "long" - } - } - }, - "transaction": { - "properties": { - "1d": { - "type": "long" - }, - "all": { - "type": "long" - } - } - } - } - }, - "has_any_services": { - "type": "boolean" - }, - "indices": { - "properties": { - "all": { - "properties": { - "total": { - "properties": { - "docs": { - "properties": { - "count": { - "type": "long" - } - } - }, - "store": { - "properties": { - "size_in_bytes": { - "type": "long" - } - } - } - } - } - } - }, - "shards": { - "properties": { - "total": { - "type": "long" - } - } - } - } - }, - "integrations": { - "properties": { - "ml": { - "properties": { - "all_jobs_count": { - "type": "long" - } - } - } - } - }, - "retainment": { - "properties": { - "error": { - "properties": { - "ms": { - "type": "long" - } - } - }, - "metric": { - "properties": { - "ms": { - "type": "long" - } - } - }, - "onboarding": { - "properties": { - "ms": { - "type": "long" - } - } - }, - "span": { - "properties": { - "ms": { - "type": "long" - } - } - }, - "transaction": { - "properties": { - "ms": { - "type": "long" - } - } - } - } - }, - "services_per_agent": { - "properties": { - "dotnet": { - "null_value": 0, - "type": "long" - }, - "go": { - "null_value": 0, - "type": "long" - }, - "java": { - "null_value": 0, - "type": "long" - }, - "js-base": { - "null_value": 0, - "type": "long" - }, - "nodejs": { - "null_value": 0, - "type": "long" - }, - "python": { - "null_value": 0, - "type": "long" - }, - "ruby": { - "null_value": 0, - "type": "long" - }, - "rum-js": { - "null_value": 0, - "type": "long" - } - } - }, - "tasks": { - "properties": { - "agent_configuration": { - "properties": { - "took": { - "properties": { - "ms": { - "type": "long" - } - } - } - } - }, - "agents": { - "properties": { - "took": { - "properties": { - "ms": { - "type": "long" - } - } - } - } - }, - "cardinality": { - "properties": { - "took": { - "properties": { - "ms": { - "type": "long" - } - } - } - } - }, - "groupings": { - "properties": { - "took": { - "properties": { - "ms": { - "type": "long" - } - } - } - } - }, - "indices_stats": { - "properties": { - "took": { - "properties": { - "ms": { - "type": "long" - } - } - } - } - }, - "integrations": { - "properties": { - "took": { - "properties": { - "ms": { - "type": "long" - } - } - } - } - }, - "processor_events": { - "properties": { - "took": { - "properties": { - "ms": { - "type": "long" - } - } - } - } - }, - "services": { - "properties": { - "took": { - "properties": { - "ms": { - "type": "long" - } - } - } - } - }, - "versions": { - "properties": { - "took": { - "properties": { - "ms": { - "type": "long" - } - } - } - } - } - } - }, - "version": { - "properties": { - "apm_server": { - "properties": { - "major": { - "type": "long" - }, - "minor": { - "type": "long" - }, - "patch": { - "type": "long" - } - } - } - } - } - } - }, - "application_usage_totals": { - "properties": { - "appId": { - "type": "keyword" - }, - "minutesOnScreen": { - "type": "float" - }, - "numberOfClicks": { - "type": "long" - } - } - }, - "application_usage_transactional": { - "properties": { - "appId": { - "type": "keyword" - }, - "minutesOnScreen": { - "type": "float" - }, - "numberOfClicks": { - "type": "long" - }, - "timestamp": { - "type": "date" - } - } - }, - "canvas-element": { - "dynamic": "false", - "properties": { - "@created": { - "type": "date" - }, - "@timestamp": { - "type": "date" - }, - "content": { - "type": "text" - }, - "help": { - "type": "text" - }, - "image": { - "type": "text" - }, - "name": { - "fields": { - "keyword": { - "type": "keyword" - } - }, - "type": "text" - } - } - }, - "canvas-workpad": { - "dynamic": "false", - "properties": { - "@created": { - "type": "date" - }, - "@timestamp": { - "type": "date" - }, - "name": { - "fields": { - "keyword": { - "type": "keyword" - } - }, - "type": "text" - } - } - }, - "cases": { - "properties": { - "closed_at": { - "type": "date" - }, - "closed_by": { - "properties": { - "email": { - "type": "keyword" - }, - "full_name": { - "type": "keyword" - }, - "username": { - "type": "keyword" - } - } - }, - "created_at": { - "type": "date" - }, - "created_by": { - "properties": { - "email": { - "type": "keyword" - }, - "full_name": { - "type": "keyword" - }, - "username": { - "type": "keyword" - } - } - }, - "description": { - "type": "text" - }, - "external_service": { - "properties": { - "connector_id": { - "type": "keyword" - }, - "connector_name": { - "type": "keyword" - }, - "external_id": { - "type": "keyword" - }, - "external_title": { - "type": "text" - }, - "external_url": { - "type": "text" - }, - "pushed_at": { - "type": "date" - }, - "pushed_by": { - "properties": { - "email": { - "type": "keyword" - }, - "full_name": { - "type": "keyword" - }, - "username": { - "type": "keyword" - } - } - } - } - }, - "status": { - "type": "keyword" - }, - "tags": { - "type": "keyword" - }, - "title": { - "type": "keyword" - }, - "updated_at": { - "type": "date" - }, - "updated_by": { - "properties": { - "email": { - "type": "keyword" - }, - "full_name": { - "type": "keyword" - }, - "username": { - "type": "keyword" - } - } - } - } - }, - "cases-comments": { - "properties": { - "comment": { - "type": "text" - }, - "created_at": { - "type": "date" - }, - "created_by": { - "properties": { - "email": { - "type": "keyword" - }, - "full_name": { - "type": "keyword" - }, - "username": { - "type": "keyword" - } - } - }, - "pushed_at": { - "type": "date" - }, - "pushed_by": { - "properties": { - "email": { - "type": "keyword" - }, - "full_name": { - "type": "keyword" - }, - "username": { - "type": "keyword" - } - } - }, - "updated_at": { - "type": "date" - }, - "updated_by": { - "properties": { - "email": { - "type": "keyword" - }, - "full_name": { - "type": "keyword" - }, - "username": { - "type": "keyword" - } - } - } - } - }, - "cases-configure": { - "properties": { - "closure_type": { - "type": "keyword" - }, - "connector_id": { - "type": "keyword" - }, - "connector_name": { - "type": "keyword" - }, - "created_at": { - "type": "date" - }, - "created_by": { - "properties": { - "email": { - "type": "keyword" - }, - "full_name": { - "type": "keyword" - }, - "username": { - "type": "keyword" - } - } - }, - "updated_at": { - "type": "date" - }, - "updated_by": { - "properties": { - "email": { - "type": "keyword" - }, - "full_name": { - "type": "keyword" - }, - "username": { - "type": "keyword" - } - } - } - } - }, - "cases-user-actions": { - "properties": { - "action": { - "type": "keyword" - }, - "action_at": { - "type": "date" - }, - "action_by": { - "properties": { - "email": { - "type": "keyword" - }, - "full_name": { - "type": "keyword" - }, - "username": { - "type": "keyword" - } - } - }, - "action_field": { - "type": "keyword" - }, - "new_value": { - "type": "text" - }, - "old_value": { - "type": "text" - } - } - }, - "config": { - "dynamic": "true", - "properties": { - "buildNum": { - "type": "keyword" - } - } - }, - "dashboard": { - "properties": { - "description": { - "type": "text" - }, - "hits": { - "type": "integer" - }, - "kibanaSavedObjectMeta": { - "properties": { - "searchSourceJSON": { - "type": "text" - } - } - }, - "optionsJSON": { - "type": "text" - }, - "panelsJSON": { - "type": "text" - }, - "refreshInterval": { - "properties": { - "display": { - "type": "keyword" - }, - "pause": { - "type": "boolean" - }, - "section": { - "type": "integer" - }, - "value": { - "type": "integer" - } - } - }, - "timeFrom": { - "type": "keyword" - }, - "timeRestore": { - "type": "boolean" - }, - "timeTo": { - "type": "keyword" - }, - "title": { - "type": "text" - }, - "version": { - "type": "integer" - } - } - }, - "datasources": { - "properties": { - "config_id": { - "type": "keyword" - }, - "description": { - "type": "text" - }, - "enabled": { - "type": "boolean" - }, - "inputs": { - "properties": { - "config": { - "type": "flattened" - }, - "enabled": { - "type": "boolean" - }, - "processors": { - "type": "keyword" - }, - "streams": { - "properties": { - "config": { - "type": "flattened" - }, - "dataset": { - "type": "keyword" - }, - "enabled": { - "type": "boolean" - }, - "id": { - "type": "keyword" - }, - "pkg_stream": { - "type": "flattened" - }, - "processors": { - "type": "keyword" - } - }, - "type": "nested" - }, - "type": { - "type": "keyword" - } - }, - "type": "nested" - }, - "name": { - "type": "keyword" - }, - "namespace": { - "type": "keyword" - }, - "output_id": { - "type": "keyword" - }, - "package": { - "properties": { - "name": { - "type": "keyword" - }, - "title": { - "type": "keyword" - }, - "version": { - "type": "keyword" - } - } - }, - "revision": { - "type": "integer" - } - } - }, - "enrollment_api_keys": { - "properties": { - "active": { - "type": "boolean" - }, - "api_key": { - "type": "binary" - }, - "api_key_id": { - "type": "keyword" - }, - "config_id": { - "type": "keyword" - }, - "created_at": { - "type": "date" - }, - "expire_at": { - "type": "date" - }, - "name": { - "type": "keyword" - }, - "type": { - "type": "keyword" - }, - "updated_at": { - "type": "date" - } - } - }, - "epm-package": { - "properties": { - "es_index_patterns": { - "dynamic": "false", - "type": "object" - }, - "installed": { - "properties": { - "id": { - "type": "keyword" - }, - "type": { - "type": "keyword" - } - }, - "type": "nested" - }, - "internal": { - "type": "boolean" - }, - "name": { - "type": "keyword" - }, - "version": { - "type": "keyword" - } - } - }, - "file-upload-telemetry": { - "properties": { - "filesUploadedTotalCount": { - "type": "long" - } - } - }, - "graph-workspace": { - "properties": { - "description": { - "type": "text" - }, - "kibanaSavedObjectMeta": { - "properties": { - "searchSourceJSON": { - "type": "text" - } - } - }, - "numLinks": { - "type": "integer" - }, - "numVertices": { - "type": "integer" - }, - "title": { - "type": "text" - }, - "version": { - "type": "integer" - }, - "wsState": { - "type": "text" - } - } - }, - "index-pattern": { - "properties": { - "fieldFormatMap": { - "type": "text" - }, - "fields": { - "type": "text" - }, - "intervalName": { - "type": "keyword" - }, - "notExpandable": { - "type": "boolean" - }, - "sourceFilters": { - "type": "text" - }, - "timeFieldName": { - "type": "keyword" - }, - "title": { - "type": "text" - }, - "type": { - "type": "keyword" - }, - "typeMeta": { - "type": "keyword" - } - } - }, - "infrastructure-ui-source": { - "properties": { - "description": { - "type": "text" - }, - "fields": { - "properties": { - "container": { - "type": "keyword" - }, - "host": { - "type": "keyword" - }, - "pod": { - "type": "keyword" - }, - "tiebreaker": { - "type": "keyword" - }, - "timestamp": { - "type": "keyword" - } - } - }, - "logAlias": { - "type": "keyword" - }, - "logColumns": { - "properties": { - "fieldColumn": { - "properties": { - "field": { - "type": "keyword" - }, - "id": { - "type": "keyword" - } - } - }, - "messageColumn": { - "properties": { - "id": { - "type": "keyword" - } - } - }, - "timestampColumn": { - "properties": { - "id": { - "type": "keyword" - } - } - } - }, - "type": "nested" - }, - "metricAlias": { - "type": "keyword" - }, - "name": { - "type": "text" - } - } - }, - "inventory-view": { - "properties": { - "accountId": { - "type": "keyword" - }, - "autoBounds": { - "type": "boolean" - }, - "autoReload": { - "type": "boolean" - }, - "boundsOverride": { - "properties": { - "max": { - "type": "integer" - }, - "min": { - "type": "integer" - } - } - }, - "customMetrics": { - "properties": { - "aggregation": { - "type": "keyword" - }, - "field": { - "type": "keyword" - }, - "id": { - "type": "keyword" - }, - "label": { - "type": "keyword" - }, - "type": { - "type": "keyword" - } - }, - "type": "nested" - }, - "customOptions": { - "properties": { - "field": { - "type": "keyword" - }, - "text": { - "type": "keyword" - } - }, - "type": "nested" - }, - "filterQuery": { - "properties": { - "expression": { - "type": "keyword" - }, - "kind": { - "type": "keyword" - } - } - }, - "groupBy": { - "properties": { - "field": { - "type": "keyword" - }, - "label": { - "type": "keyword" - } - }, - "type": "nested" - }, - "metric": { - "properties": { - "aggregation": { - "type": "keyword" - }, - "field": { - "type": "keyword" - }, - "id": { - "type": "keyword" - }, - "label": { - "type": "keyword" - }, - "type": { - "type": "keyword" - } - } - }, - "name": { - "type": "keyword" - }, - "nodeType": { - "type": "keyword" - }, - "region": { - "type": "keyword" - }, - "time": { - "type": "long" - }, - "view": { - "type": "keyword" - } - } - }, - "kql-telemetry": { - "properties": { - "optInCount": { - "type": "long" - }, - "optOutCount": { - "type": "long" - } - } - }, - "lens": { - "properties": { - "expression": { - "index": false, - "type": "keyword" - }, - "state": { - "type": "flattened" - }, - "title": { - "type": "text" - }, - "visualizationType": { - "type": "keyword" - } - } - }, - "lens-ui-telemetry": { - "properties": { - "count": { - "type": "integer" - }, - "date": { - "type": "date" - }, - "name": { - "type": "keyword" - }, - "type": { - "type": "keyword" - } - } - }, - "map": { - "properties": { - "bounds": { - "type": "geo_shape" - }, - "description": { - "type": "text" - }, - "layerListJSON": { - "type": "text" - }, - "mapStateJSON": { - "type": "text" - }, - "title": { - "type": "text" - }, - "uiStateJSON": { - "type": "text" - }, - "version": { - "type": "integer" - } - } - }, - "maps-telemetry": { - "properties": { - "attributesPerMap": { - "properties": { - "dataSourcesCount": { - "properties": { - "avg": { - "type": "long" - }, - "max": { - "type": "long" - }, - "min": { - "type": "long" - } - } - }, - "emsVectorLayersCount": { - "dynamic": "true", - "type": "object" - }, - "layerTypesCount": { - "dynamic": "true", - "type": "object" - }, - "layersCount": { - "properties": { - "avg": { - "type": "long" - }, - "max": { - "type": "long" - }, - "min": { - "type": "long" - } - } - } - } - }, - "indexPatternsWithGeoFieldCount": { - "type": "long" - }, - "mapsTotalCount": { - "type": "long" - }, - "settings": { - "properties": { - "showMapVisualizationTypes": { - "type": "boolean" - } - } - }, - "timeCaptured": { - "type": "date" - } - } - }, - "metrics-explorer-view": { - "properties": { - "chartOptions": { - "properties": { - "stack": { - "type": "boolean" - }, - "type": { - "type": "keyword" - }, - "yAxisMode": { - "type": "keyword" - } - } - }, - "currentTimerange": { - "properties": { - "from": { - "type": "keyword" - }, - "interval": { - "type": "keyword" - }, - "to": { - "type": "keyword" - } - } - }, - "name": { - "type": "keyword" - }, - "options": { - "properties": { - "aggregation": { - "type": "keyword" - }, - "filterQuery": { - "type": "keyword" - }, - "groupBy": { - "type": "keyword" - }, - "limit": { - "type": "integer" - }, - "metrics": { - "properties": { - "aggregation": { - "type": "keyword" - }, - "color": { - "type": "keyword" - }, - "field": { - "type": "keyword" - }, - "label": { - "type": "keyword" - } - }, - "type": "nested" - } - } - } - } - }, - "migrationVersion": { - "dynamic": "true", - "properties": { - "dashboard": { - "fields": { - "keyword": { - "ignore_above": 256, - "type": "keyword" - } - }, - "type": "text" - }, - "index-pattern": { - "fields": { - "keyword": { - "ignore_above": 256, - "type": "keyword" - } - }, - "type": "text" - }, - "map": { - "fields": { - "keyword": { - "ignore_above": 256, - "type": "keyword" - } - }, - "type": "text" - }, - "search": { - "fields": { - "keyword": { - "ignore_above": 256, - "type": "keyword" - } - }, - "type": "text" - }, - "space": { - "fields": { - "keyword": { - "ignore_above": 256, - "type": "keyword" - } - }, - "type": "text" - }, - "visualization": { - "fields": { - "keyword": { - "ignore_above": 256, - "type": "keyword" - } - }, - "type": "text" - } - } - }, - "ml-telemetry": { - "properties": { - "file_data_visualizer": { - "properties": { - "index_creation_count": { - "type": "long" - } - } - } - } - }, - "namespace": { - "type": "keyword" - }, - "namespaces": { - "type": "keyword" - }, - "outputs": { - "properties": { - "api_key": { - "type": "keyword" - }, - "ca_sha256": { - "type": "keyword" - }, - "config": { - "type": "flattened" - }, - "fleet_enroll_password": { - "type": "binary" - }, - "fleet_enroll_username": { - "type": "binary" - }, - "hosts": { - "type": "keyword" - }, - "is_default": { - "type": "boolean" - }, - "name": { - "type": "keyword" - }, - "type": { - "type": "keyword" - } - } - }, - "query": { - "properties": { - "description": { - "type": "text" - }, - "filters": { - "enabled": false, - "type": "object" - }, - "query": { - "properties": { - "language": { - "type": "keyword" - }, - "query": { - "index": false, - "type": "keyword" - } - } - }, - "timefilter": { - "enabled": false, - "type": "object" - }, - "title": { - "type": "text" - } - } - }, - "references": { - "properties": { - "id": { - "type": "keyword" - }, - "name": { - "type": "keyword" - }, - "type": { - "type": "keyword" - } - }, - "type": "nested" - }, - "sample-data-telemetry": { - "properties": { - "installCount": { - "type": "long" - }, - "unInstallCount": { - "type": "long" - } - } - }, - "search": { - "properties": { - "columns": { - "type": "keyword" - }, - "description": { - "type": "text" - }, - "hits": { - "type": "integer" - }, - "kibanaSavedObjectMeta": { - "properties": { - "searchSourceJSON": { - "type": "text" - } - } - }, - "sort": { - "type": "keyword" - }, - "title": { - "type": "text" - }, - "version": { - "type": "integer" - } - } - }, - "server": { - "properties": { - "uuid": { - "type": "keyword" - } - } - }, - "siem-detection-engine-rule-actions": { - "properties": { - "actions": { - "properties": { - "action_type_id": { - "type": "keyword" - }, - "group": { - "type": "keyword" - }, - "id": { - "type": "keyword" - }, - "params": { - "dynamic": "true", - "type": "object" - } - } - }, - "alertThrottle": { - "type": "keyword" - }, - "ruleAlertId": { - "type": "keyword" - }, - "ruleThrottle": { - "type": "keyword" - } - } - }, - "siem-detection-engine-rule-status": { - "properties": { - "alertId": { - "type": "keyword" - }, - "bulkCreateTimeDurations": { - "type": "float" - }, - "gap": { - "type": "text" - }, - "lastFailureAt": { - "type": "date" - }, - "lastFailureMessage": { - "type": "text" - }, - "lastLookBackDate": { - "type": "date" - }, - "lastSuccessAt": { - "type": "date" - }, - "lastSuccessMessage": { - "type": "text" - }, - "searchAfterTimeDurations": { - "type": "float" - }, - "status": { - "type": "keyword" - }, - "statusDate": { - "type": "date" - } - } - }, - "siem-ui-timeline": { - "properties": { - "columns": { - "properties": { - "aggregatable": { - "type": "boolean" - }, - "category": { - "type": "keyword" - }, - "columnHeaderType": { - "type": "keyword" - }, - "description": { - "type": "text" - }, - "example": { - "type": "text" - }, - "id": { - "type": "keyword" - }, - "indexes": { - "type": "keyword" - }, - "name": { - "type": "text" - }, - "placeholder": { - "type": "text" - }, - "searchable": { - "type": "boolean" - }, - "type": { - "type": "keyword" - } - } - }, - "created": { - "type": "date" - }, - "createdBy": { - "type": "text" - }, - "dataProviders": { - "properties": { - "and": { - "properties": { - "enabled": { - "type": "boolean" - }, - "excluded": { - "type": "boolean" - }, - "id": { - "type": "keyword" - }, - "kqlQuery": { - "type": "text" - }, - "name": { - "type": "text" - }, - "queryMatch": { - "properties": { - "displayField": { - "type": "text" - }, - "displayValue": { - "type": "text" - }, - "field": { - "type": "text" - }, - "operator": { - "type": "text" - }, - "value": { - "type": "text" - } - } - } - } - }, - "enabled": { - "type": "boolean" - }, - "excluded": { - "type": "boolean" - }, - "id": { - "type": "keyword" - }, - "kqlQuery": { - "type": "text" - }, - "name": { - "type": "text" - }, - "queryMatch": { - "properties": { - "displayField": { - "type": "text" - }, - "displayValue": { - "type": "text" - }, - "field": { - "type": "text" - }, - "operator": { - "type": "text" - }, - "value": { - "type": "text" - } - } - } - } - }, - "dateRange": { - "properties": { - "end": { - "type": "date" - }, - "start": { - "type": "date" - } - } - }, - "description": { - "type": "text" - }, - "eventType": { - "type": "keyword" - }, - "favorite": { - "properties": { - "favoriteDate": { - "type": "date" - }, - "fullName": { - "type": "text" - }, - "keySearch": { - "type": "text" - }, - "userName": { - "type": "text" - } - } - }, - "filters": { - "properties": { - "exists": { - "type": "text" - }, - "match_all": { - "type": "text" - }, - "meta": { - "properties": { - "alias": { - "type": "text" - }, - "controlledBy": { - "type": "text" - }, - "disabled": { - "type": "boolean" - }, - "field": { - "type": "text" - }, - "formattedValue": { - "type": "text" - }, - "index": { - "type": "keyword" - }, - "key": { - "type": "keyword" - }, - "negate": { - "type": "boolean" - }, - "params": { - "type": "text" - }, - "type": { - "type": "keyword" - }, - "value": { - "type": "text" - } - } - }, - "missing": { - "type": "text" - }, - "query": { - "type": "text" - }, - "range": { - "type": "text" - }, - "script": { - "type": "text" - } - } - }, - "kqlMode": { - "type": "keyword" - }, - "kqlQuery": { - "properties": { - "filterQuery": { - "properties": { - "kuery": { - "properties": { - "expression": { - "type": "text" - }, - "kind": { - "type": "keyword" - } - } - }, - "serializedQuery": { - "type": "text" - } - } - } - } - }, - "savedQueryId": { - "type": "keyword" - }, - "sort": { - "properties": { - "columnId": { - "type": "keyword" - }, - "sortDirection": { - "type": "keyword" - } - } - }, - "title": { - "type": "text" - }, - "updated": { - "type": "date" - }, - "updatedBy": { - "type": "text" - } - } - }, - "siem-ui-timeline-note": { - "properties": { - "created": { - "type": "date" - }, - "createdBy": { - "type": "text" - }, - "eventId": { - "type": "keyword" - }, - "note": { - "type": "text" - }, - "timelineId": { - "type": "keyword" - }, - "updated": { - "type": "date" - }, - "updatedBy": { - "type": "text" - } - } - }, - "siem-ui-timeline-pinned-event": { - "properties": { - "created": { - "type": "date" - }, - "createdBy": { - "type": "text" - }, - "eventId": { - "type": "keyword" - }, - "timelineId": { - "type": "keyword" - }, - "updated": { - "type": "date" - }, - "updatedBy": { - "type": "text" - } - } - }, - "space": { - "properties": { - "_reserved": { - "type": "boolean" - }, - "color": { - "type": "keyword" - }, - "description": { - "type": "text" - }, - "disabledFeatures": { - "type": "keyword" - }, - "imageUrl": { - "index": false, - "type": "text" - }, - "initials": { - "type": "keyword" - }, - "name": { - "fields": { - "keyword": { - "ignore_above": 2048, - "type": "keyword" - } - }, - "type": "text" - } - } - }, - "telemetry": { - "properties": { - "allowChangingOptInStatus": { - "type": "boolean" - }, - "enabled": { - "type": "boolean" - }, - "lastReported": { - "type": "date" - }, - "lastVersionChecked": { - "type": "keyword" - }, - "reportFailureCount": { - "type": "integer" - }, - "reportFailureVersion": { - "type": "keyword" - }, - "sendUsageFrom": { - "type": "keyword" - }, - "userHasSeenNotice": { - "type": "boolean" - } - } - }, - "timelion-sheet": { - "properties": { - "description": { - "type": "text" - }, - "hits": { - "type": "integer" - }, - "kibanaSavedObjectMeta": { - "properties": { - "searchSourceJSON": { - "type": "text" - } - } - }, - "timelion_chart_height": { - "type": "integer" - }, - "timelion_columns": { - "type": "integer" - }, - "timelion_interval": { - "type": "keyword" - }, - "timelion_other_interval": { - "type": "keyword" - }, - "timelion_rows": { - "type": "integer" - }, - "timelion_sheet": { - "type": "text" - }, - "title": { - "type": "text" - }, - "version": { - "type": "integer" - } - } - }, - "tsvb-validation-telemetry": { - "properties": { - "failedRequests": { - "type": "long" - } - } - }, - "type": { - "type": "keyword" - }, - "ui-metric": { - "properties": { - "count": { - "type": "integer" - } - } - }, - "updated_at": { - "type": "date" - }, - "upgrade-assistant-reindex-operation": { - "dynamic": "true", - "properties": { - "indexName": { - "type": "keyword" - }, - "status": { - "type": "integer" - } - } - }, - "upgrade-assistant-telemetry": { - "properties": { - "features": { - "properties": { - "deprecation_logging": { - "properties": { - "enabled": { - "null_value": true, - "type": "boolean" - } - } - } - } - }, - "ui_open": { - "properties": { - "cluster": { - "null_value": 0, - "type": "long" - }, - "indices": { - "null_value": 0, - "type": "long" - }, - "overview": { - "null_value": 0, - "type": "long" - } - } - }, - "ui_reindex": { - "properties": { - "close": { - "null_value": 0, - "type": "long" - }, - "open": { - "null_value": 0, - "type": "long" - }, - "start": { - "null_value": 0, - "type": "long" - }, - "stop": { - "null_value": 0, - "type": "long" - } - } - } - } - }, - "uptime-dynamic-settings": { - "properties": { - "certificatesThresholds": { - "properties": { - "errorState": { - "type": "long" - }, - "warningState": { - "type": "long" - } - } - }, - "heartbeatIndices": { - "type": "keyword" - } - } - }, - "url": { - "properties": { - "accessCount": { - "type": "long" - }, - "accessDate": { - "type": "date" - }, - "createDate": { - "type": "date" - }, - "url": { - "fields": { - "keyword": { - "ignore_above": 2048, - "type": "keyword" - } - }, - "type": "text" - } - } - }, - "visualization": { - "properties": { - "description": { - "type": "text" - }, - "kibanaSavedObjectMeta": { - "properties": { - "searchSourceJSON": { - "type": "text" - } - } - }, - "savedSearchRefName": { - "type": "keyword" - }, - "title": { - "type": "text" - }, - "uiStateJSON": { - "type": "text" - }, - "version": { - "type": "integer" - }, - "visState": { - "type": "text" - } - } - } - } - }, - "settings": { - "index": { - "auto_expand_replicas": "0-1", - "number_of_replicas": "0", - "number_of_shards": "1" - } - } - } -} \ No newline at end of file From e990c47ae9b00def3bd01681d2131e175c45f42e Mon Sep 17 00:00:00 2001 From: nnamdifrankie Date: Mon, 20 Apr 2020 17:56:43 -0400 Subject: [PATCH 11/14] EMT-146: review comments and refactor the code --- x-pack/plugins/endpoint/server/mocks.ts | 2 +- .../endpoint/server/routes/metadata/index.ts | 4 ++-- .../server/routes/metadata/metadata.test.ts | 14 ++++++------- .../ingest_manager/common/types/index.ts | 7 ++----- .../plugins/ingest_manager/server/plugin.ts | 6 ++++-- .../server/services/agent_service.ts | 21 ------------------- .../server/services/agents/status.ts | 10 ++++++++- 7 files changed, 25 insertions(+), 39 deletions(-) delete mode 100644 x-pack/plugins/ingest_manager/server/services/agent_service.ts diff --git a/x-pack/plugins/endpoint/server/mocks.ts b/x-pack/plugins/endpoint/server/mocks.ts index 5c726a370eb4a..3881840efe9df 100644 --- a/x-pack/plugins/endpoint/server/mocks.ts +++ b/x-pack/plugins/endpoint/server/mocks.ts @@ -36,7 +36,7 @@ export const createMockMetadataIndexPatternRetriever = () => { */ export const createMockAgentService = (): jest.Mocked => { return { - getAgentStatus: jest.fn(), + getAgentStatusById: jest.fn(), }; }; diff --git a/x-pack/plugins/endpoint/server/routes/metadata/index.ts b/x-pack/plugins/endpoint/server/routes/metadata/index.ts index 7b25dad155b17..6b71d86f9fadb 100644 --- a/x-pack/plugins/endpoint/server/routes/metadata/index.ts +++ b/x-pack/plugins/endpoint/server/routes/metadata/index.ts @@ -167,8 +167,8 @@ async function enrichHostMetadata( ): Promise { let hostStatus = HostStatus.ERROR; try { - const status = await metadataRequestContext.endpointAppContext.agentService.getAgentStatus( - metadataRequestContext.requestHandlerContext, + const status = await metadataRequestContext.endpointAppContext.agentService.getAgentStatusById( + metadataRequestContext.requestHandlerContext.core.savedObjects.client, hostMetadata.elastic.agent.id ); hostStatus = HOST_STATUS_MAPPING.get(status) || HostStatus.ERROR; diff --git a/x-pack/plugins/endpoint/server/routes/metadata/metadata.test.ts b/x-pack/plugins/endpoint/server/routes/metadata/metadata.test.ts index 50958119902c2..818e0886eb1f5 100644 --- a/x-pack/plugins/endpoint/server/routes/metadata/metadata.test.ts +++ b/x-pack/plugins/endpoint/server/routes/metadata/metadata.test.ts @@ -88,7 +88,7 @@ describe('test endpoint route', () => { [routeConfig, routeHandler] = routerMock.post.mock.calls.find(([{ path }]) => path.startsWith('/api/endpoint/metadata') )!; - mockAgentService.getAgentStatus = jest.fn().mockReturnValue('error'); + mockAgentService.getAgentStatusById = jest.fn().mockReturnValue('error'); await routeHandler( createRouteHandlerContext(mockScopedClient, mockSavedObjectClient), mockRequest, @@ -119,7 +119,7 @@ describe('test endpoint route', () => { }, }); - mockAgentService.getAgentStatus = jest.fn().mockReturnValue('error'); + mockAgentService.getAgentStatusById = jest.fn().mockReturnValue('error'); mockScopedClient.callAsCurrentUser.mockImplementationOnce(() => Promise.resolve((data as unknown) as SearchResponse) ); @@ -162,7 +162,7 @@ describe('test endpoint route', () => { }, }); - mockAgentService.getAgentStatus = jest.fn().mockReturnValue('error'); + mockAgentService.getAgentStatusById = jest.fn().mockReturnValue('error'); mockScopedClient.callAsCurrentUser.mockImplementationOnce(() => Promise.resolve((data as unknown) as SearchResponse) ); @@ -225,7 +225,7 @@ describe('test endpoint route', () => { }, }) ); - mockAgentService.getAgentStatus = jest.fn().mockReturnValue('error'); + mockAgentService.getAgentStatusById = jest.fn().mockReturnValue('error'); [routeConfig, routeHandler] = routerMock.get.mock.calls.find(([{ path }]) => path.startsWith('/api/endpoint/metadata') )!; @@ -249,7 +249,7 @@ describe('test endpoint route', () => { const response: SearchResponse = (data as unknown) as SearchResponse< HostMetadata >; - mockAgentService.getAgentStatus = jest.fn().mockReturnValue('online'); + mockAgentService.getAgentStatusById = jest.fn().mockReturnValue('online'); mockScopedClient.callAsCurrentUser.mockImplementationOnce(() => Promise.resolve(response)); [routeConfig, routeHandler] = routerMock.get.mock.calls.find(([{ path }]) => path.startsWith('/api/endpoint/metadata') @@ -276,7 +276,7 @@ describe('test endpoint route', () => { const response: SearchResponse = (data as unknown) as SearchResponse< HostMetadata >; - mockAgentService.getAgentStatus = jest.fn().mockImplementation(() => { + mockAgentService.getAgentStatusById = jest.fn().mockImplementation(() => { throw Boom.notFound('Agent not found'); }); mockScopedClient.callAsCurrentUser.mockImplementationOnce(() => Promise.resolve(response)); @@ -304,7 +304,7 @@ describe('test endpoint route', () => { const response: SearchResponse = (data as unknown) as SearchResponse< HostMetadata >; - mockAgentService.getAgentStatus = jest.fn().mockReturnValue('warning'); + mockAgentService.getAgentStatusById = jest.fn().mockReturnValue('warning'); mockScopedClient.callAsCurrentUser.mockImplementationOnce(() => Promise.resolve(response)); [routeConfig, routeHandler] = routerMock.get.mock.calls.find(([{ path }]) => path.startsWith('/api/endpoint/metadata') diff --git a/x-pack/plugins/ingest_manager/common/types/index.ts b/x-pack/plugins/ingest_manager/common/types/index.ts index e5e214ffcea8d..bc757a4d46251 100644 --- a/x-pack/plugins/ingest_manager/common/types/index.ts +++ b/x-pack/plugins/ingest_manager/common/types/index.ts @@ -3,17 +3,14 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -import { RequestHandlerContext } from 'kibana/server'; +import { SavedObjectsClientContract } from 'kibana/server'; import { AgentStatus } from './models'; export * from './models'; export * from './rest_spec'; export interface AgentService { - getAgentStatus( - requestHandlerContext: RequestHandlerContext, - agentId: string - ): Promise; + getAgentStatusById(soClient: SavedObjectsClientContract, agentId: string): Promise; } export interface IngestManagerConfigType { diff --git a/x-pack/plugins/ingest_manager/server/plugin.ts b/x-pack/plugins/ingest_manager/server/plugin.ts index edba9a0284895..075a0917b9fae 100644 --- a/x-pack/plugins/ingest_manager/server/plugin.ts +++ b/x-pack/plugins/ingest_manager/server/plugin.ts @@ -45,7 +45,7 @@ import { ESIndexPatternService, ESIndexPatternSavedObjectService, } from './services'; -import { createAgentService } from './services/agent_service'; +import { getAgentStatusById } from './services/agents'; /** * Describes public IngestManager plugin contract returned at the `setup` stage. @@ -150,7 +150,9 @@ export class IngestManagerPlugin implements Plugin { } return deepFreeze({ esIndexPatternService: new ESIndexPatternSavedObjectService(), - agentService: createAgentService(), + agentService: { + getAgentStatusById, + }, }); } diff --git a/x-pack/plugins/ingest_manager/server/services/agent_service.ts b/x-pack/plugins/ingest_manager/server/services/agent_service.ts deleted file mode 100644 index 178fe60cc5661..0000000000000 --- a/x-pack/plugins/ingest_manager/server/services/agent_service.ts +++ /dev/null @@ -1,21 +0,0 @@ -/* - * 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 { RequestHandlerContext } from 'kibana/server'; -import { AgentService, AgentStatus } from '../../common/types'; -import { getAgent, getAgentStatus } from './agents'; - -export const createAgentService = (): AgentService => { - return { - getAgentStatus: async ( - requestHandlerContext: RequestHandlerContext, - agentId: string - ): Promise => { - const agent = await getAgent(requestHandlerContext.core.savedObjects.client, agentId); - return getAgentStatus(agent); - }, - }; -}; diff --git a/x-pack/plugins/ingest_manager/server/services/agents/status.ts b/x-pack/plugins/ingest_manager/server/services/agents/status.ts index 21e200d701e69..001b6d01f078e 100644 --- a/x-pack/plugins/ingest_manager/server/services/agents/status.ts +++ b/x-pack/plugins/ingest_manager/server/services/agents/status.ts @@ -5,7 +5,7 @@ */ import { SavedObjectsClientContract } from 'src/core/server'; -import { listAgents } from './crud'; +import { getAgent, listAgents } from './crud'; import { AGENT_EVENT_SAVED_OBJECT_TYPE } from '../../constants'; import { AgentStatus, Agent } from '../../types'; @@ -17,6 +17,14 @@ import { } from '../../constants'; import { AgentStatusKueryHelper } from '../../../common/services'; +export async function getAgentStatusById( + soClient: SavedObjectsClientContract, + agentId: string +): Promise { + const agent = await getAgent(soClient, agentId); + return getAgentStatus(agent); +} + export function getAgentStatus(agent: Agent, now: number = Date.now()): AgentStatus { const { type, last_checkin: lastCheckIn } = agent; const msLastCheckIn = new Date(lastCheckIn || 0).getTime(); From 2bd660141d38739fe79d773c22d4487dc7d2dac1 Mon Sep 17 00:00:00 2001 From: nnamdifrankie Date: Tue, 21 Apr 2020 02:07:52 -0400 Subject: [PATCH 12/14] EMT-146: add more documentation and test --- .../ingest_manager/common/types/index.ts | 8 ++++ .../server/services/agents/status.test.ts | 43 +++++++++++++++++++ 2 files changed, 51 insertions(+) create mode 100644 x-pack/plugins/ingest_manager/server/services/agents/status.test.ts diff --git a/x-pack/plugins/ingest_manager/common/types/index.ts b/x-pack/plugins/ingest_manager/common/types/index.ts index bc757a4d46251..150a4c9d60280 100644 --- a/x-pack/plugins/ingest_manager/common/types/index.ts +++ b/x-pack/plugins/ingest_manager/common/types/index.ts @@ -9,7 +9,15 @@ import { AgentStatus } from './models'; export * from './models'; export * from './rest_spec'; +/** + * A service that provides exported functions that return information about an Agent + */ export interface AgentService { + /** + * Return the status by the Agent's id + * @param soClient + * @param agentId + */ getAgentStatusById(soClient: SavedObjectsClientContract, agentId: string): Promise; } diff --git a/x-pack/plugins/ingest_manager/server/services/agents/status.test.ts b/x-pack/plugins/ingest_manager/server/services/agents/status.test.ts new file mode 100644 index 0000000000000..d19fe883a7780 --- /dev/null +++ b/x-pack/plugins/ingest_manager/server/services/agents/status.test.ts @@ -0,0 +1,43 @@ +/* + * 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 { savedObjectsClientMock } from '../../../../../../src/core/server/saved_objects/service/saved_objects_client.mock'; +import { getAgentStatusById } from './status'; +import { AGENT_TYPE_PERMANENT } from '../../../common/constants'; +import { AgentSOAttributes } from '../../../common/types/models'; +import { SavedObject } from 'kibana/server'; + +describe('Agent status service', () => { + it('should return inactive when agent is not active', async () => { + const mockSavedObjectsClient = savedObjectsClientMock.create(); + mockSavedObjectsClient.get = jest.fn().mockReturnValue({ + id: 'id', + type: AGENT_TYPE_PERMANENT, + attributes: { + active: false, + local_metadata: '{}', + user_provided_metadata: '{}', + }, + } as SavedObject); + const status = await getAgentStatusById(mockSavedObjectsClient, 'id'); + expect(status).toEqual('inactive'); + }); + + it('should return online when agent is active', async () => { + const mockSavedObjectsClient = savedObjectsClientMock.create(); + mockSavedObjectsClient.get = jest.fn().mockReturnValue({ + id: 'id', + type: AGENT_TYPE_PERMANENT, + attributes: { + active: true, + local_metadata: '{}', + user_provided_metadata: '{}', + }, + } as SavedObject); + const status = await getAgentStatusById(mockSavedObjectsClient, 'id'); + expect(status).toEqual('online'); + }); +}); From 6d4c1eda30fa2292e0a8265b768f305686249ee4 Mon Sep 17 00:00:00 2001 From: nnamdifrankie Date: Tue, 21 Apr 2020 09:35:45 -0400 Subject: [PATCH 13/14] EMT-146: fall back to host id if elastic id is missing --- .../endpoint/server/routes/metadata/index.ts | 6 +++++- .../server/routes/metadata/metadata.test.ts | 16 ++++++++++------ 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/x-pack/plugins/endpoint/server/routes/metadata/index.ts b/x-pack/plugins/endpoint/server/routes/metadata/index.ts index 6b71d86f9fadb..958618ae45ca9 100644 --- a/x-pack/plugins/endpoint/server/routes/metadata/index.ts +++ b/x-pack/plugins/endpoint/server/routes/metadata/index.ts @@ -167,9 +167,13 @@ async function enrichHostMetadata( ): Promise { let hostStatus = HostStatus.ERROR; try { + /** + * Get agent status by elastic agent id if available or use the host id. + * https://github.com/elastic/endpoint-app-team/issues/354 + */ const status = await metadataRequestContext.endpointAppContext.agentService.getAgentStatusById( metadataRequestContext.requestHandlerContext.core.savedObjects.client, - hostMetadata.elastic.agent.id + hostMetadata.elastic.agent.id || hostMetadata.host.id ); hostStatus = HOST_STATUS_MAPPING.get(status) || HostStatus.ERROR; } catch (e) { diff --git a/x-pack/plugins/endpoint/server/routes/metadata/metadata.test.ts b/x-pack/plugins/endpoint/server/routes/metadata/metadata.test.ts index 818e0886eb1f5..a1186aabc7a66 100644 --- a/x-pack/plugins/endpoint/server/routes/metadata/metadata.test.ts +++ b/x-pack/plugins/endpoint/server/routes/metadata/metadata.test.ts @@ -270,12 +270,14 @@ describe('test endpoint route', () => { }); it('should return a single endpoint with status error when AgentService throw 404', async () => { - const mockRequest = httpServerMock.createKibanaRequest({ - params: { id: (data as any).hits.hits[0]._id }, - }); const response: SearchResponse = (data as unknown) as SearchResponse< HostMetadata >; + + const mockRequest = httpServerMock.createKibanaRequest({ + params: { id: response.hits.hits[0]._id }, + }); + mockAgentService.getAgentStatusById = jest.fn().mockImplementation(() => { throw Boom.notFound('Agent not found'); }); @@ -298,12 +300,14 @@ describe('test endpoint route', () => { }); it('should return a single endpoint with status error when status is not offline or online', async () => { - const mockRequest = httpServerMock.createKibanaRequest({ - params: { id: (data as any).hits.hits[0]._id }, - }); const response: SearchResponse = (data as unknown) as SearchResponse< HostMetadata >; + + const mockRequest = httpServerMock.createKibanaRequest({ + params: { id: response.hits.hits[0]._id }, + }); + mockAgentService.getAgentStatusById = jest.fn().mockReturnValue('warning'); mockScopedClient.callAsCurrentUser.mockImplementationOnce(() => Promise.resolve(response)); [routeConfig, routeHandler] = routerMock.get.mock.calls.find(([{ path }]) => From 9bb3550626e883599e8489865167f727cb88297e Mon Sep 17 00:00:00 2001 From: nnamdifrankie Date: Tue, 21 Apr 2020 10:01:00 -0400 Subject: [PATCH 14/14] EMT-146: add warning log, and improve logging --- .../endpoint/server/routes/metadata/index.ts | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/x-pack/plugins/endpoint/server/routes/metadata/index.ts b/x-pack/plugins/endpoint/server/routes/metadata/index.ts index 958618ae45ca9..bc79b828576e0 100644 --- a/x-pack/plugins/endpoint/server/routes/metadata/index.ts +++ b/x-pack/plugins/endpoint/server/routes/metadata/index.ts @@ -166,22 +166,29 @@ async function enrichHostMetadata( metadataRequestContext: MetadataRequestContext ): Promise { let hostStatus = HostStatus.ERROR; + let elasticAgentId = hostMetadata?.elastic?.agent?.id; + const log = logger(metadataRequestContext.endpointAppContext); try { /** * Get agent status by elastic agent id if available or use the host id. * https://github.com/elastic/endpoint-app-team/issues/354 */ + + if (!elasticAgentId) { + elasticAgentId = hostMetadata.host.id; + log.warn(`Missing elastic agent id, using host id instead ${elasticAgentId}`); + } + const status = await metadataRequestContext.endpointAppContext.agentService.getAgentStatusById( metadataRequestContext.requestHandlerContext.core.savedObjects.client, - hostMetadata.elastic.agent.id || hostMetadata.host.id + elasticAgentId ); hostStatus = HOST_STATUS_MAPPING.get(status) || HostStatus.ERROR; } catch (e) { if (e.isBoom && e.output.statusCode === 404) { - logger(metadataRequestContext.endpointAppContext).warn( - `agent with id ${hostMetadata.elastic.agent.id} not found` - ); + log.warn(`agent with id ${elasticAgentId} not found`); } else { + log.error(e); throw e; } }