diff --git a/x-pack/plugins/ingest_manager/common/types/models/agent.ts b/x-pack/plugins/ingest_manager/common/types/models/agent.ts index 2b8a306577e7d..c5208f368b74f 100644 --- a/x-pack/plugins/ingest_manager/common/types/models/agent.ts +++ b/x-pack/plugins/ingest_manager/common/types/models/agent.ts @@ -25,22 +25,22 @@ export type AgentActionType = 'CONFIG_CHANGE' | 'DATA_DUMP' | 'RESUME' | 'PAUSE' export interface NewAgentAction { type: AgentActionType; data?: any; - sent_at?: string; } export interface AgentAction extends NewAgentAction { id: string; agent_id: string; created_at: string; + acknowledged_at?: string; } export interface AgentActionSOAttributes { type: AgentActionType; - sent_at?: string; timestamp?: string; created_at: string; agent_id: string; data?: string; + acknowledged_at?: string; } export interface NewAgentEvent { @@ -103,9 +103,11 @@ export interface Agent extends AgentBase { access_api_key?: string; status?: string; packages: string[]; + not_acknowledged_actions: string[]; } export interface AgentSOAttributes extends AgentBase { current_error_events?: string; packages?: string[]; + not_acknowledged_actions?: string[]; } diff --git a/x-pack/plugins/ingest_manager/server/routes/agent/actions_handlers.test.ts b/x-pack/plugins/ingest_manager/server/routes/agent/actions_handlers.test.ts index bcb9a7797f26a..cb00d6e1a569d 100644 --- a/x-pack/plugins/ingest_manager/server/routes/agent/actions_handlers.test.ts +++ b/x-pack/plugins/ingest_manager/server/routes/agent/actions_handlers.test.ts @@ -25,7 +25,6 @@ describe('test actions handlers schema', () => { NewAgentActionSchema.validate({ type: 'CONFIG_CHANGE', data: 'data', - sent_at: '2020-03-14T19:45:02.620Z', }) ).toBeTruthy(); }); @@ -34,7 +33,6 @@ describe('test actions handlers schema', () => { expect(() => { NewAgentActionSchema.validate({ data: 'data', - sent_at: '2020-03-14T19:45:02.620Z', }); }).toThrowError(); }); @@ -55,7 +53,6 @@ describe('test actions handlers', () => { action: { type: 'CONFIG_CHANGE', data: 'data', - sent_at: '2020-03-14T19:45:02.620Z', }, }, params: { @@ -68,7 +65,6 @@ describe('test actions handlers', () => { 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; diff --git a/x-pack/plugins/ingest_manager/server/saved_objects/index.ts b/x-pack/plugins/ingest_manager/server/saved_objects/index.ts index 1bbe3b71bf919..097f1e5da3c47 100644 --- a/x-pack/plugins/ingest_manager/server/saved_objects/index.ts +++ b/x-pack/plugins/ingest_manager/server/saved_objects/index.ts @@ -78,6 +78,7 @@ const savedObjectTypes: { [key: string]: SavedObjectsType } = { updated_at: { type: 'date' }, current_error_events: { type: 'text', index: false }, packages: { type: 'keyword' }, + not_acknowledged_actions: { type: 'keyword', index: false }, }, }, migrations: { @@ -96,8 +97,8 @@ const savedObjectTypes: { [key: string]: SavedObjectsType } = { agent_id: { type: 'keyword' }, type: { type: 'keyword' }, data: { type: 'binary' }, - sent_at: { type: 'date' }, created_at: { type: 'date' }, + acknowledged_at: { type: 'date' }, }, }, }, @@ -351,11 +352,12 @@ export function registerEncryptedSavedObjects( 'unenrolled_at', 'unenrollment_started_at', 'packages', + 'not_acknowledged_actions', ]), }); encryptedSavedObjects.registerType({ type: AGENT_ACTION_SAVED_OBJECT_TYPE, attributesToEncrypt: new Set(['data']), - attributesToExcludeFromAAD: new Set(['agent_id', 'type', 'sent_at', 'created_at']), + attributesToExcludeFromAAD: new Set(['agent_id', 'acknowledged_at', 'type', 'created_at']), }); } diff --git a/x-pack/plugins/ingest_manager/server/services/agents/acks.test.ts b/x-pack/plugins/ingest_manager/server/services/agents/acks.test.ts index 80fdc305d0ba7..e74adcb67d82e 100644 --- a/x-pack/plugins/ingest_manager/server/services/agents/acks.test.ts +++ b/x-pack/plugins/ingest_manager/server/services/agents/acks.test.ts @@ -39,7 +39,7 @@ describe('test agent acks services', () => { attributes: { type: 'CONFIG_CHANGE', agent_id: 'id', - sent_at: '2020-03-14T19:45:02.620Z', + acknowledged_at: '2020-03-14T19:45:02.620Z', timestamp: '2019-01-04T14:32:03.36764-05:00', created_at: '2020-03-14T19:45:02.620Z', }, @@ -56,7 +56,7 @@ describe('test agent acks services', () => { attributes: { type: 'CONFIG_CHANGE', agent_id: 'id', - sent_at: '2020-03-14T19:45:02.620Z', + acknowledged_at: '2020-03-14T19:45:02.620Z', timestamp: '2019-01-04T14:32:03.36764-05:00', created_at: '2020-03-14T19:45:02.620Z', }, @@ -70,6 +70,7 @@ describe('test agent acks services', () => { ({ id: 'id', type: AGENT_TYPE_PERMANENT, + not_acknowledged_actions: [], } as unknown) as Agent, [ { @@ -86,7 +87,7 @@ describe('test agent acks services', () => { type: 'CONFIG_CHANGE', id: 'action1', agent_id: 'id', - sent_at: '2020-03-14T19:45:02.620Z', + acknowledged_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, @@ -112,7 +113,7 @@ describe('test agent acks services', () => { attributes: { type: 'CONFIG_CHANGE', agent_id: 'id', - sent_at: '2020-03-14T19:45:02.620Z', + acknowledged_at: '2020-03-14T19:45:02.620Z', timestamp: '2019-01-04T14:32:03.36764-05:00', created_at: '2020-03-14T19:45:02.620Z', data: JSON.stringify({ @@ -193,7 +194,7 @@ describe('test agent acks services', () => { attributes: { type: 'CONFIG_CHANGE', agent_id: 'id', - sent_at: '2020-03-14T19:45:02.620Z', + acknowledged_at: '2020-03-14T19:45:02.620Z', timestamp: '2019-01-04T14:32:03.36764-05:00', created_at: '2020-03-14T19:45:02.620Z', }, @@ -208,6 +209,7 @@ describe('test agent acks services', () => { id: 'id', type: AGENT_TYPE_PERMANENT, policy_id: 'policy1', + not_acknowledged_actions: ['actionNotAcknowledged:id', 'action1'], } as unknown) as Agent, [ { @@ -224,6 +226,9 @@ describe('test agent acks services', () => { expect(mockSavedObjectsClient.bulkUpdate.mock.calls[0][0][0]).toMatchInlineSnapshot(` Object { "attributes": Object { + "not_acknowledged_actions": Array [ + "actionNotAcknowledged:id", + ], "packages": Array [ "system", ], @@ -254,7 +259,7 @@ describe('test agent acks services', () => { attributes: { type: 'CONFIG_CHANGE', agent_id: 'id', - sent_at: '2020-03-14T19:45:02.620Z', + acknowledged_at: '2020-03-14T19:45:02.620Z', timestamp: '2019-01-04T14:32:03.36764-05:00', created_at: '2020-03-14T19:45:02.620Z', data: JSON.stringify({ @@ -335,7 +340,7 @@ describe('test agent acks services', () => { attributes: { type: 'CONFIG_CHANGE', agent_id: 'id', - sent_at: '2020-03-14T19:45:02.620Z', + acknowledged_at: '2020-03-14T19:45:02.620Z', timestamp: '2019-01-04T14:32:03.36764-05:00', created_at: '2020-03-14T19:45:02.620Z', }, @@ -351,6 +356,7 @@ describe('test agent acks services', () => { type: AGENT_TYPE_PERMANENT, policy_id: 'policy1', policy_revision: 100, + not_acknowledged_actions: [], } as unknown) as Agent, [ { @@ -363,7 +369,7 @@ describe('test agent acks services', () => { ] ); expect(mockSavedObjectsClient.bulkUpdate).toBeCalled(); - expect(mockSavedObjectsClient.bulkUpdate.mock.calls[0][0]).toHaveLength(1); + expect(mockSavedObjectsClient.bulkUpdate.mock.calls[0][0]).toHaveLength(2); }); it('should fail for actions that cannot be found on agent actions list', async () => { @@ -388,6 +394,7 @@ describe('test agent acks services', () => { ({ id: 'id', type: AGENT_TYPE_PERMANENT, + not_acknowledged_actions: [], } as unknown) as Agent, [ ({ @@ -418,7 +425,7 @@ describe('test agent acks services', () => { attributes: { type: 'CONFIG_CHANGE', agent_id: 'id', - sent_at: '2020-03-14T19:45:02.620Z', + acknowledged_at: '2020-03-14T19:45:02.620Z', timestamp: '2019-01-04T14:32:03.36764-05:00', created_at: '2020-03-14T19:45:02.620Z', }, @@ -433,6 +440,7 @@ describe('test agent acks services', () => { ({ id: 'id', type: AGENT_TYPE_PERMANENT, + not_acknowledged_actions: [], } as unknown) as Agent, [ ({ diff --git a/x-pack/plugins/ingest_manager/server/services/agents/acks.ts b/x-pack/plugins/ingest_manager/server/services/agents/acks.ts index 87572ce405ee7..67619085bde12 100644 --- a/x-pack/plugins/ingest_manager/server/services/agents/acks.ts +++ b/x-pack/plugins/ingest_manager/server/services/agents/acks.ts @@ -73,8 +73,17 @@ export async function acknowledgeAgentActions( const agentPolicy = getLatestAgentPolicyIfUpdated(agent, actions); await soClient.bulkUpdate([ - ...(agentPolicy ? [buildUpdateAgentPolicy(agent.id, agentPolicy)] : []), - ...buildUpdateAgentActionSentAt(actionIds), + { + type: AGENT_SAVED_OBJECT_TYPE, + id: agent.id, + attributes: { + ...(agentPolicy ? buildUpdateAgentPolicy(agent.id, agentPolicy) : {}), + not_acknowledged_actions: agent.not_acknowledged_actions.filter( + (actionId) => !actionIds.includes(actionId) + ), + }, + }, + ...buildUpdateAgentActionAcknowledgedAt(actionIds), ]); return actions; @@ -107,24 +116,20 @@ function buildUpdateAgentPolicy(agentId: string, agentPolicy: FullAgentPolicy) { }, []); return { - type: AGENT_SAVED_OBJECT_TYPE, - id: agentId, - attributes: { - policy_revision: agentPolicy.revision, - packages, - }, + policy_revision: agentPolicy.revision, + packages, }; } -function buildUpdateAgentActionSentAt( +function buildUpdateAgentActionAcknowledgedAt( actionsIds: string[], - sentAt: string = new Date().toISOString() + acknowledgedAt: string = new Date().toISOString() ) { return actionsIds.map((actionId) => ({ type: AGENT_ACTION_SAVED_OBJECT_TYPE, id: actionId, attributes: { - sent_at: sentAt, + acknowledged_at: acknowledgedAt, }, })); } diff --git a/x-pack/plugins/ingest_manager/server/services/agents/actions.test.ts b/x-pack/plugins/ingest_manager/server/services/agents/actions.test.ts index c739007952389..c66f6cb2a6e58 100644 --- a/x-pack/plugins/ingest_manager/server/services/agents/actions.test.ts +++ b/x-pack/plugins/ingest_manager/server/services/agents/actions.test.ts @@ -17,7 +17,6 @@ describe('test agent actions services', () => { agent_id: 'agentid', type: 'CONFIG_CHANGE', data: { content: 'data' }, - sent_at: '2020-03-14T19:45:02.620Z', created_at: '2020-03-14T19:45:02.620Z', }; mockSavedObjectsClient.create.mockReturnValue( @@ -32,6 +31,5 @@ describe('test agent actions services', () => { expect(createdAction).toBeDefined(); expect(createdAction?.type).toEqual(newAgentAction.type); expect(createdAction?.data).toEqual(JSON.stringify(newAgentAction.data)); - expect(createdAction?.sent_at).toEqual(newAgentAction.sent_at); }); }); diff --git a/x-pack/plugins/ingest_manager/server/services/agents/actions.ts b/x-pack/plugins/ingest_manager/server/services/agents/actions.ts index 8d1b320c89ae6..9672a5cb080ee 100644 --- a/x-pack/plugins/ingest_manager/server/services/agents/actions.ts +++ b/x-pack/plugins/ingest_manager/server/services/agents/actions.ts @@ -27,22 +27,21 @@ export async function createAgentAction( export async function getAgentActionsForCheckin( soClient: SavedObjectsClientContract, - agentId: string + agent: Agent ): Promise { - const res = await soClient.find({ - type: AGENT_ACTION_SAVED_OBJECT_TYPE, - filter: `not ${AGENT_ACTION_SAVED_OBJECT_TYPE}.attributes.sent_at: * and ${AGENT_ACTION_SAVED_OBJECT_TYPE}.attributes.agent_id:${agentId}`, - }); + if (agent.not_acknowledged_actions.length === 0) { + return []; + } return Promise.all( - res.saved_objects.map(async (so) => { + agent.not_acknowledged_actions.map(async (actionId) => { // Get decrypted actions return savedObjectToAgentAction( await appContextService .getEncryptedSavedObjects() .getDecryptedAsInternalUser( AGENT_ACTION_SAVED_OBJECT_TYPE, - so.id + actionId ) ); }) @@ -80,7 +79,7 @@ export async function getAgentActionByIds( export async function getNewActionsSince(soClient: SavedObjectsClientContract, timestamp: string) { const res = await soClient.find({ type: AGENT_ACTION_SAVED_OBJECT_TYPE, - filter: `not ${AGENT_ACTION_SAVED_OBJECT_TYPE}.attributes.sent_at: * AND ${AGENT_ACTION_SAVED_OBJECT_TYPE}.attributes.created_at >= "${timestamp}"`, + filter: `not ${AGENT_ACTION_SAVED_OBJECT_TYPE}.attributes.acknowledged_at: * AND ${AGENT_ACTION_SAVED_OBJECT_TYPE}.attributes.created_at >= "${timestamp}"`, }); return res.saved_objects.map(savedObjectToAgentAction); diff --git a/x-pack/plugins/ingest_manager/server/services/agents/checkin/index.ts b/x-pack/plugins/ingest_manager/server/services/agents/checkin/index.ts index 78e6a11fa78a4..07353bd7887b5 100644 --- a/x-pack/plugins/ingest_manager/server/services/agents/checkin/index.ts +++ b/x-pack/plugins/ingest_manager/server/services/agents/checkin/index.ts @@ -44,7 +44,7 @@ export async function agentCheckin( } // Check if some actions are not acknowledged - let actions = await getAgentActionsForCheckin(soClient, agent.id); + let actions = await getAgentActionsForCheckin(soClient, agent); if (actions.length > 0) { return { actions }; } diff --git a/x-pack/plugins/ingest_manager/server/services/agents/checkin/state_new_actions.ts b/x-pack/plugins/ingest_manager/server/services/agents/checkin/state_new_actions.ts index e10d013fe84a9..5b56b39c24ee9 100644 --- a/x-pack/plugins/ingest_manager/server/services/agents/checkin/state_new_actions.ts +++ b/x-pack/plugins/ingest_manager/server/services/agents/checkin/state_new_actions.ts @@ -134,7 +134,10 @@ async function createAgentActionFromAgentPolicy( type: 'CONFIG_CHANGE', data: { config: newAgentPolicy } as any, created_at: new Date().toISOString(), - sent_at: undefined, + }); + + await soClient.update(AGENT_SAVED_OBJECT_TYPE, agent.id, { + not_acknowledged_actions: [...agent.not_acknowledged_actions, policyChangeAction.id], }); return [policyChangeAction]; diff --git a/x-pack/plugins/ingest_manager/server/services/agents/saved_objects.ts b/x-pack/plugins/ingest_manager/server/services/agents/saved_objects.ts index 2ab5cc8139f69..0dda0e43a1d18 100644 --- a/x-pack/plugins/ingest_manager/server/services/agents/saved_objects.ts +++ b/x-pack/plugins/ingest_manager/server/services/agents/saved_objects.ts @@ -24,6 +24,7 @@ export function savedObjectToAgent(so: SavedObject): Agent { access_api_key: undefined, status: undefined, packages: so.attributes.packages ?? [], + not_acknowledged_actions: so.attributes.not_acknowledged_actions ?? [], }; } diff --git a/x-pack/plugins/ingest_manager/server/types/models/agent.ts b/x-pack/plugins/ingest_manager/server/types/models/agent.ts index 5ad98cfd40622..49fd6024a96f5 100644 --- a/x-pack/plugins/ingest_manager/server/types/models/agent.ts +++ b/x-pack/plugins/ingest_manager/server/types/models/agent.ts @@ -69,5 +69,4 @@ export const NewAgentActionSchema = schema.object({ schema.literal('PAUSE'), ]), data: schema.maybe(schema.any()), - sent_at: schema.maybe(schema.string()), });