-
Notifications
You must be signed in to change notification settings - Fork 8.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[Ingest]EMT-248: add post action request handler and resources (#60581)
[Ingest]EMT-248: add resource to allow to post new agent action.
- Loading branch information
1 parent
be64c88
commit f146d3a
Showing
13 changed files
with
423 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
103 changes: 103 additions & 0 deletions
103
x-pack/plugins/ingest_manager/server/routes/agent/actions_handlers.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
/* | ||
* 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 { NewAgentActionSchema } from '../../types/models'; | ||
import { | ||
KibanaResponseFactory, | ||
RequestHandlerContext, | ||
SavedObjectsClientContract, | ||
} from 'kibana/server'; | ||
import { savedObjectsClientMock } from '../../../../../../src/core/server/saved_objects/service/saved_objects_client.mock'; | ||
import { httpServerMock } from '../../../../../../src/core/server/http/http_server.mocks'; | ||
import { ActionsService } from '../../services/agents'; | ||
import { AgentAction } from '../../../common/types/models'; | ||
import { postNewAgentActionHandlerBuilder } from './actions_handlers'; | ||
import { | ||
PostNewAgentActionRequest, | ||
PostNewAgentActionResponse, | ||
} from '../../../common/types/rest_spec'; | ||
|
||
describe('test actions handlers schema', () => { | ||
it('validate that new agent actions schema is valid', async () => { | ||
expect( | ||
NewAgentActionSchema.validate({ | ||
type: 'CONFIG_CHANGE', | ||
data: 'data', | ||
sent_at: '2020-03-14T19:45:02.620Z', | ||
}) | ||
).toBeTruthy(); | ||
}); | ||
|
||
it('validate that new agent actions schema is invalid when required properties are not provided', async () => { | ||
expect(() => { | ||
NewAgentActionSchema.validate({ | ||
data: 'data', | ||
sent_at: '2020-03-14T19:45:02.620Z', | ||
}); | ||
}).toThrowError(); | ||
}); | ||
}); | ||
|
||
describe('test actions handlers', () => { | ||
let mockResponse: jest.Mocked<KibanaResponseFactory>; | ||
let mockSavedObjectsClient: jest.Mocked<SavedObjectsClientContract>; | ||
|
||
beforeEach(() => { | ||
mockSavedObjectsClient = savedObjectsClientMock.create(); | ||
mockResponse = httpServerMock.createResponseFactory(); | ||
}); | ||
|
||
it('should succeed on valid new agent action', async () => { | ||
const postNewAgentActionRequest: PostNewAgentActionRequest = { | ||
body: { | ||
action: { | ||
type: 'CONFIG_CHANGE', | ||
data: 'data', | ||
sent_at: '2020-03-14T19:45:02.620Z', | ||
}, | ||
}, | ||
params: { | ||
agentId: 'id', | ||
}, | ||
}; | ||
|
||
const mockRequest = httpServerMock.createKibanaRequest(postNewAgentActionRequest); | ||
|
||
const agentAction = ({ | ||
type: 'CONFIG_CHANGE', | ||
id: 'action1', | ||
sent_at: '2020-03-14T19:45:02.620Z', | ||
timestamp: '2019-01-04T14:32:03.36764-05:00', | ||
created_at: '2020-03-14T19:45:02.620Z', | ||
} as unknown) as AgentAction; | ||
|
||
const actionsService: ActionsService = { | ||
getAgent: jest.fn().mockReturnValueOnce({ | ||
id: 'agent', | ||
}), | ||
updateAgentActions: jest.fn().mockReturnValueOnce(agentAction), | ||
} as jest.Mocked<ActionsService>; | ||
|
||
const postNewAgentActionHandler = postNewAgentActionHandlerBuilder(actionsService); | ||
await postNewAgentActionHandler( | ||
({ | ||
core: { | ||
savedObjects: { | ||
client: mockSavedObjectsClient, | ||
}, | ||
}, | ||
} as unknown) as RequestHandlerContext, | ||
mockRequest, | ||
mockResponse | ||
); | ||
|
||
const expectedAgentActionResponse = (mockResponse.ok.mock.calls[0][0] | ||
?.body as unknown) as PostNewAgentActionResponse; | ||
|
||
expect(expectedAgentActionResponse.item).toEqual(agentAction); | ||
expect(expectedAgentActionResponse.success).toEqual(true); | ||
}); | ||
}); |
57 changes: 57 additions & 0 deletions
57
x-pack/plugins/ingest_manager/server/routes/agent/actions_handlers.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
/* | ||
* 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. | ||
*/ | ||
|
||
// handlers that handle agent actions request | ||
|
||
import { RequestHandler } from 'kibana/server'; | ||
import { TypeOf } from '@kbn/config-schema'; | ||
import { PostNewAgentActionRequestSchema } from '../../types/rest_spec'; | ||
import { ActionsService } from '../../services/agents'; | ||
import { NewAgentAction } from '../../../common/types/models'; | ||
import { PostNewAgentActionResponse } from '../../../common/types/rest_spec'; | ||
|
||
export const postNewAgentActionHandlerBuilder = function( | ||
actionsService: ActionsService | ||
): RequestHandler< | ||
TypeOf<typeof PostNewAgentActionRequestSchema.params>, | ||
undefined, | ||
TypeOf<typeof PostNewAgentActionRequestSchema.body> | ||
> { | ||
return async (context, request, response) => { | ||
try { | ||
const soClient = context.core.savedObjects.client; | ||
|
||
const agent = await actionsService.getAgent(soClient, request.params.agentId); | ||
|
||
const newAgentAction = request.body.action as NewAgentAction; | ||
|
||
const savedAgentAction = await actionsService.updateAgentActions( | ||
soClient, | ||
agent, | ||
newAgentAction | ||
); | ||
|
||
const body: PostNewAgentActionResponse = { | ||
success: true, | ||
item: savedAgentAction, | ||
}; | ||
|
||
return response.ok({ body }); | ||
} catch (e) { | ||
if (e.isBoom) { | ||
return response.customError({ | ||
statusCode: e.output.statusCode, | ||
body: { message: e.message }, | ||
}); | ||
} | ||
|
||
return response.customError({ | ||
statusCode: 500, | ||
body: { message: e.message }, | ||
}); | ||
} | ||
}; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
67 changes: 67 additions & 0 deletions
67
x-pack/plugins/ingest_manager/server/services/agents/actions.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
/* | ||
* 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 { createAgentAction, updateAgentActions } from './actions'; | ||
import { Agent, AgentAction, NewAgentAction } from '../../../common/types/models'; | ||
import { savedObjectsClientMock } from '../../../../../../src/core/server/saved_objects/service/saved_objects_client.mock'; | ||
import { AGENT_TYPE_PERMANENT } from '../../../common/constants'; | ||
|
||
interface UpdatedActions { | ||
actions: AgentAction[]; | ||
} | ||
|
||
describe('test agent actions services', () => { | ||
it('should update agent current actions with new action', async () => { | ||
const mockSavedObjectsClient = savedObjectsClientMock.create(); | ||
|
||
const newAgentAction: NewAgentAction = { | ||
type: 'CONFIG_CHANGE', | ||
data: 'data', | ||
sent_at: '2020-03-14T19:45:02.620Z', | ||
}; | ||
|
||
await updateAgentActions( | ||
mockSavedObjectsClient, | ||
({ | ||
id: 'id', | ||
type: AGENT_TYPE_PERMANENT, | ||
actions: [ | ||
{ | ||
type: 'CONFIG_CHANGE', | ||
id: 'action1', | ||
sent_at: '2020-03-14T19:45:02.620Z', | ||
timestamp: '2019-01-04T14:32:03.36764-05:00', | ||
created_at: '2020-03-14T19:45:02.620Z', | ||
}, | ||
], | ||
} as unknown) as Agent, | ||
newAgentAction | ||
); | ||
|
||
const updatedAgentActions = (mockSavedObjectsClient.update.mock | ||
.calls[0][2] as unknown) as UpdatedActions; | ||
|
||
expect(updatedAgentActions.actions.length).toEqual(2); | ||
const actualAgentAction = updatedAgentActions.actions.find(action => action?.data === 'data'); | ||
expect(actualAgentAction?.type).toEqual(newAgentAction.type); | ||
expect(actualAgentAction?.data).toEqual(newAgentAction.data); | ||
expect(actualAgentAction?.sent_at).toEqual(newAgentAction.sent_at); | ||
}); | ||
|
||
it('should create agent action from new agent action model', async () => { | ||
const newAgentAction: NewAgentAction = { | ||
type: 'CONFIG_CHANGE', | ||
data: 'data', | ||
sent_at: '2020-03-14T19:45:02.620Z', | ||
}; | ||
const now = new Date(); | ||
const agentAction = createAgentAction(now, newAgentAction); | ||
|
||
expect(agentAction.type).toEqual(newAgentAction.type); | ||
expect(agentAction.data).toEqual(newAgentAction.data); | ||
expect(agentAction.sent_at).toEqual(newAgentAction.sent_at); | ||
}); | ||
}); |
50 changes: 50 additions & 0 deletions
50
x-pack/plugins/ingest_manager/server/services/agents/actions.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
/* | ||
* 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 { SavedObjectsClientContract } from 'kibana/server'; | ||
import uuid from 'uuid'; | ||
import { | ||
Agent, | ||
AgentAction, | ||
AgentSOAttributes, | ||
NewAgentAction, | ||
} from '../../../common/types/models'; | ||
import { AGENT_SAVED_OBJECT_TYPE } from '../../../common/constants'; | ||
|
||
export async function updateAgentActions( | ||
soClient: SavedObjectsClientContract, | ||
agent: Agent, | ||
newAgentAction: NewAgentAction | ||
): Promise<AgentAction> { | ||
const agentAction = createAgentAction(new Date(), newAgentAction); | ||
|
||
agent.actions.push(agentAction); | ||
|
||
await soClient.update<AgentSOAttributes>(AGENT_SAVED_OBJECT_TYPE, agent.id, { | ||
actions: agent.actions, | ||
}); | ||
|
||
return agentAction; | ||
} | ||
|
||
export function createAgentAction(createdAt: Date, newAgentAction: NewAgentAction): AgentAction { | ||
const agentAction = { | ||
id: uuid.v4(), | ||
created_at: createdAt.toISOString(), | ||
}; | ||
|
||
return Object.assign(agentAction, newAgentAction); | ||
} | ||
|
||
export interface ActionsService { | ||
getAgent: (soClient: SavedObjectsClientContract, agentId: string) => Promise<Agent>; | ||
|
||
updateAgentActions: ( | ||
soClient: SavedObjectsClientContract, | ||
agent: Agent, | ||
newAgentAction: NewAgentAction | ||
) => Promise<AgentAction>; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.