diff --git a/x-pack/plugins/fleet/server/routes/agent/handlers.ts b/x-pack/plugins/fleet/server/routes/agent/handlers.ts index 696e05e9c18bbb..bb43d32b6cfaf4 100644 --- a/x-pack/plugins/fleet/server/routes/agent/handlers.ts +++ b/x-pack/plugins/fleet/server/routes/agent/handlers.ts @@ -186,7 +186,7 @@ export const getAgentsHandler: RequestHandler< kuery: request.query.kuery, sortField: request.query.sortField, sortOrder: request.query.sortOrder, - getTotalInactive: true, + getTotalInactive: request.query.showInactive, }); const { total, page, perPage, totalInactive = 0 } = agentRes; diff --git a/x-pack/plugins/fleet/server/services/agents/action_runner.ts b/x-pack/plugins/fleet/server/services/agents/action_runner.ts index cba8f677c8b0fe..ce338b3d637f3c 100644 --- a/x-pack/plugins/fleet/server/services/agents/action_runner.ts +++ b/x-pack/plugins/fleet/server/services/agents/action_runner.ts @@ -6,7 +6,6 @@ */ import { v4 as uuidv4 } from 'uuid'; -import type { SortResults } from '@elastic/elasticsearch/lib/api/types'; import type { ElasticsearchClient, SavedObjectsClientContract } from '@kbn/core/server'; import { withSpan } from '@kbn/apm-utils'; @@ -21,8 +20,8 @@ import { SO_SEARCH_LIMIT } from '../../../common/constants'; import { getAgentActions } from './actions'; import { closePointInTime, getAgentsByKuery } from './crud'; import type { BulkActionsResolver } from './bulk_actions_resolver'; - -export const MAX_RETRY_COUNT = 5; +import type { RetryParams } from './retry_helper'; +import { getRetryParams, MAX_RETRY_COUNT } from './retry_helper'; export interface ActionParams { kuery: string; @@ -34,13 +33,6 @@ export interface ActionParams { [key: string]: any; } -export interface RetryParams { - pitId: string; - searchAfter?: SortResults; - retryCount?: number; - taskId?: string; -} - export abstract class ActionRunner { protected esClient: ElasticsearchClient; protected soClient: SavedObjectsClientContract; @@ -79,7 +71,9 @@ export abstract class ActionRunner { appContextService .getLogger() .info( - `Running action asynchronously, actionId: ${this.actionParams.actionId}, total agents: ${this.actionParams.total}` + `Running action asynchronously, actionId: ${this.actionParams.actionId}${ + this.actionParams.total ? ', total agents:' + this.actionParams.total : '' + }` ); if (!this.bulkActionsResolver) { @@ -153,10 +147,12 @@ export abstract class ActionRunner { this.actionParams.actionId!, this.getTaskType() + ':check' ); + const retryParams: RetryParams = getRetryParams(this.getTaskType(), this.retryParams); + return await this.bulkActionsResolver!.run( this.actionParams, { - ...this.retryParams, + ...retryParams, retryCount: 1, }, this.getTaskType(), @@ -233,7 +229,9 @@ export abstract class ActionRunner { } } - await closePointInTime(this.esClient, pitId!); + if (pitId) { + await closePointInTime(this.esClient, pitId!); + } appContextService .getLogger() diff --git a/x-pack/plugins/fleet/server/services/agents/bulk_action_types.ts b/x-pack/plugins/fleet/server/services/agents/bulk_action_types.ts new file mode 100644 index 00000000000000..44ab84e0bc72d9 --- /dev/null +++ b/x-pack/plugins/fleet/server/services/agents/bulk_action_types.ts @@ -0,0 +1,14 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export enum BulkActionTaskType { + REASSIGN_RETRY = 'fleet:reassign_action:retry', + UNENROLL_RETRY = 'fleet:unenroll_action:retry', + UPGRADE_RETRY = 'fleet:upgrade_action:retry', + UPDATE_AGENT_TAGS_RETRY = 'fleet:update_agent_tags:retry', + REQUEST_DIAGNOSTICS_RETRY = 'fleet:request_diagnostics:retry', +} diff --git a/x-pack/plugins/fleet/server/services/agents/bulk_actions_resolver.ts b/x-pack/plugins/fleet/server/services/agents/bulk_actions_resolver.ts index b6ec1d082b39a0..b68bae611252a2 100644 --- a/x-pack/plugins/fleet/server/services/agents/bulk_actions_resolver.ts +++ b/x-pack/plugins/fleet/server/services/agents/bulk_actions_resolver.ts @@ -19,16 +19,11 @@ import { ReassignActionRunner } from './reassign_action_runner'; import { UpgradeActionRunner } from './upgrade_action_runner'; import { UpdateAgentTagsActionRunner } from './update_agent_tags_action_runner'; import { UnenrollActionRunner } from './unenroll_action_runner'; -import type { ActionParams, RetryParams } from './action_runner'; +import type { ActionParams } from './action_runner'; import { RequestDiagnosticsActionRunner } from './request_diagnostics_action_runner'; - -export enum BulkActionTaskType { - REASSIGN_RETRY = 'fleet:reassign_action:retry', - UNENROLL_RETRY = 'fleet:unenroll_action:retry', - UPGRADE_RETRY = 'fleet:upgrade_action:retry', - UPDATE_AGENT_TAGS_RETRY = 'fleet:update_agent_tags:retry', - REQUEST_DIAGNOSTICS_RETRY = 'fleet:request_diagnostics:retry', -} +import type { RetryParams } from './retry_helper'; +import { getRetryParams } from './retry_helper'; +import { BulkActionTaskType } from './bulk_action_types'; /** * Create and run retry tasks of agent bulk actions @@ -114,11 +109,7 @@ export class BulkActionsResolver { scope: ['fleet'], state: {}, params: { actionParams, retryParams }, - runAt: - runAt ?? - moment(new Date()) - .add(Math.pow(3, retryParams.retryCount ?? 1), 's') - .toDate(), + runAt: runAt ?? moment(new Date()).add(3, 's').toDate(), }); appContextService.getLogger().info('Scheduling task ' + taskId); return taskId; @@ -146,7 +137,10 @@ export function createRetryTask( const { esClient, soClient } = await getDeps(); - const retryParams = taskInstance.params.retryParams; + const retryParams: RetryParams = getRetryParams( + taskInstance.taskType, + taskInstance.params.retryParams + ); appContextService .getLogger() diff --git a/x-pack/plugins/fleet/server/services/agents/reassign_action_runner.ts b/x-pack/plugins/fleet/server/services/agents/reassign_action_runner.ts index cf6e3988e7bef2..b03146ab6b387b 100644 --- a/x-pack/plugins/fleet/server/services/agents/reassign_action_runner.ts +++ b/x-pack/plugins/fleet/server/services/agents/reassign_action_runner.ts @@ -18,7 +18,7 @@ import { ActionRunner } from './action_runner'; import { bulkUpdateAgents } from './crud'; import { createErrorActionResults, createAgentAction } from './actions'; import { getHostedPolicies, isHostedAgent } from './hosted_agent'; -import { BulkActionTaskType } from './bulk_actions_resolver'; +import { BulkActionTaskType } from './bulk_action_types'; export class ReassignActionRunner extends ActionRunner { protected async processAgents(agents: Agent[]): Promise<{ actionId: string }> { diff --git a/x-pack/plugins/fleet/server/services/agents/request_diagnostics_action_runner.ts b/x-pack/plugins/fleet/server/services/agents/request_diagnostics_action_runner.ts index 9728afedbb0282..d9552f3a1a41e7 100644 --- a/x-pack/plugins/fleet/server/services/agents/request_diagnostics_action_runner.ts +++ b/x-pack/plugins/fleet/server/services/agents/request_diagnostics_action_runner.ts @@ -12,7 +12,7 @@ import type { Agent } from '../../types'; import { ActionRunner } from './action_runner'; import { createAgentAction } from './actions'; -import { BulkActionTaskType } from './bulk_actions_resolver'; +import { BulkActionTaskType } from './bulk_action_types'; export class RequestDiagnosticsActionRunner extends ActionRunner { protected async processAgents(agents: Agent[]): Promise<{ actionId: string }> { diff --git a/x-pack/plugins/fleet/server/services/agents/retry_helper.ts b/x-pack/plugins/fleet/server/services/agents/retry_helper.ts new file mode 100644 index 00000000000000..b15d5faa87c447 --- /dev/null +++ b/x-pack/plugins/fleet/server/services/agents/retry_helper.ts @@ -0,0 +1,30 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { SortResults } from '@elastic/elasticsearch/lib/api/types'; + +import { BulkActionTaskType } from './bulk_action_types'; + +export const MAX_RETRY_COUNT = 20; + +export interface RetryParams { + pitId?: string; + searchAfter?: SortResults; + retryCount?: number; + taskId?: string; +} + +export function getRetryParams(taskType: string, retryParams: RetryParams): RetryParams { + // update tags will retry with tags filter + return taskType === BulkActionTaskType.UPDATE_AGENT_TAGS_RETRY + ? { + ...retryParams, + pitId: undefined, + searchAfter: undefined, + } + : retryParams; +} diff --git a/x-pack/plugins/fleet/server/services/agents/unenroll_action_runner.ts b/x-pack/plugins/fleet/server/services/agents/unenroll_action_runner.ts index 359b016bd1b8c4..8f9a7f3763cc00 100644 --- a/x-pack/plugins/fleet/server/services/agents/unenroll_action_runner.ts +++ b/x-pack/plugins/fleet/server/services/agents/unenroll_action_runner.ts @@ -29,7 +29,7 @@ import { getUnenrollAgentActions, } from './actions'; import { getHostedPolicies, isHostedAgent } from './hosted_agent'; -import { BulkActionTaskType } from './bulk_actions_resolver'; +import { BulkActionTaskType } from './bulk_action_types'; export class UnenrollActionRunner extends ActionRunner { protected async processAgents(agents: Agent[]): Promise<{ actionId: string }> { diff --git a/x-pack/plugins/fleet/server/services/agents/update_agent_tags.test.ts b/x-pack/plugins/fleet/server/services/agents/update_agent_tags.test.ts index d59aee0c700b13..30c56b53640af8 100644 --- a/x-pack/plugins/fleet/server/services/agents/update_agent_tags.test.ts +++ b/x-pack/plugins/fleet/server/services/agents/update_agent_tags.test.ts @@ -8,9 +8,12 @@ import type { SavedObjectsClientContract } from '@kbn/core/server'; import type { ElasticsearchClientMock } from '@kbn/core/server/mocks'; import { elasticsearchServiceMock, savedObjectsClientMock } from '@kbn/core/server/mocks'; +import type { Agent } from '../../types'; + import { createClientMock } from './action.mock'; +import { MAX_RETRY_COUNT } from './retry_helper'; import { updateAgentTags } from './update_agent_tags'; -import { updateTagsBatch } from './update_agent_tags_action_runner'; +import { UpdateAgentTagsActionRunner, updateTagsBatch } from './update_agent_tags_action_runner'; jest.mock('../app_context', () => { return { @@ -74,6 +77,7 @@ describe('update_agent_tags', () => { esClient.updateByQuery.mockResolvedValue({ failures: [], updated: 1 } as any); mockRunAsync.mockClear(); + (UpdateAgentTagsActionRunner as jest.Mock).mockClear(); }); it('should remove duplicate tags', async () => { @@ -83,7 +87,9 @@ describe('update_agent_tags', () => { expect.objectContaining({ conflicts: 'proceed', index: '.fleet-agents', - query: { terms: { _id: ['agent1'] } }, + query: { + terms: { _id: ['agent1'] }, + }, script: expect.objectContaining({ lang: 'painless', params: expect.objectContaining({ @@ -121,37 +127,16 @@ describe('update_agent_tags', () => { expect(actionResults.body[1].error).not.toBeDefined(); }); - it('should update action results on success - kuery', async () => { - await updateTagsBatch( - soClient, - esClient, - [], - {}, - { - tagsToAdd: ['new'], - tagsToRemove: [], - kuery: '', - } - ); - - const actionResults = esClient.bulk.mock.calls[0][0] as any; - const agentIds = actionResults?.body - ?.filter((i: any) => i.agent_id) - .map((i: any) => i.agent_id); - expect(agentIds[0]).toHaveLength(36); // uuid - expect(actionResults.body[1].error).not.toBeDefined(); - }); - it('should skip hosted agent from total when agentIds are passed', async () => { - const { esClient: esClientMock, agentInHostedDoc } = createClientMock(); + const { esClient: esClientMock, agentInHostedDoc, agentInRegularDoc } = createClientMock(); esClientMock.updateByQuery.mockReset(); - esClientMock.updateByQuery.mockResolvedValue({ failures: [], updated: 0, total: 0 } as any); + esClientMock.updateByQuery.mockResolvedValue({ failures: [], updated: 1, total: 1 } as any); await updateAgentTags( soClient, esClientMock, - { agentIds: [agentInHostedDoc._id] }, + { agentIds: [agentInHostedDoc._id, agentInRegularDoc._id] }, ['newName'], [] ); @@ -160,9 +145,9 @@ describe('update_agent_tags', () => { expect(agentAction?.body).toEqual( expect.objectContaining({ action_id: expect.anything(), - agents: [], + agents: [agentInRegularDoc._id], type: 'UPDATE_TAGS', - total: 0, + total: 1, }) ); }); @@ -205,14 +190,14 @@ describe('update_agent_tags', () => { updateTagsBatch( soClient, esClient, - [], + [{ id: 'agent1' } as Agent], {}, { tagsToAdd: ['new'], tagsToRemove: [], kuery: '', total: 100, - retryCount: 5, + retryCount: MAX_RETRY_COUNT, } ) ).rejects.toThrowError('version conflict of 100 agents'); @@ -247,13 +232,24 @@ describe('update_agent_tags', () => { await updateAgentTags(soClient, esClient, { kuery: '', batchSize: 2 }, ['newName'], []); expect(mockRunAsync).toHaveBeenCalled(); + expect(UpdateAgentTagsActionRunner).toHaveBeenCalledWith( + expect.anything(), + expect.anything(), + expect.objectContaining({ + batchSize: 2, + kuery: '(NOT (tags:newName))', + tagsToAdd: ['newName'], + tagsToRemove: [], + }), + expect.anything() + ); }); it('should add tags filter if only one tag to add', async () => { await updateTagsBatch( soClient, esClient, - [], + [{ id: 'agent1' } as Agent, { id: 'agent2' } as Agent], {}, { tagsToAdd: ['new'], @@ -263,94 +259,57 @@ describe('update_agent_tags', () => { ); const updateByQuery = esClient.updateByQuery.mock.calls[0][0] as any; - expect(updateByQuery.query).toMatchInlineSnapshot(` - Object { - "bool": Object { - "filter": Array [ - Object { - "bool": Object { - "must_not": Object { - "bool": Object { - "minimum_should_match": 1, - "should": Array [ - Object { - "bool": Object { - "minimum_should_match": 1, - "should": Array [ - Object { - "match": Object { - "status": "inactive", - }, - }, - ], - }, - }, - Object { - "bool": Object { - "minimum_should_match": 1, - "should": Array [ - Object { - "match": Object { - "status": "unenrolled", - }, - }, - ], - }, - }, - ], - }, - }, - }, - }, - Object { - "bool": Object { - "must_not": Object { - "bool": Object { - "minimum_should_match": 1, - "should": Array [ - Object { - "match": Object { - "tags": "new", - }, - }, - ], - }, - }, - }, - }, - ], - }, - } - `); + expect(updateByQuery.query).toEqual({ + terms: { _id: ['agent1', 'agent2'] }, + }); }); it('should add tags filter if only one tag to remove', async () => { - await updateTagsBatch( + await updateAgentTags(soClient, esClient, { kuery: '' }, [], ['remove']); + + expect(UpdateAgentTagsActionRunner).toHaveBeenCalledWith( + expect.anything(), + expect.anything(), + expect.objectContaining({ + batchSize: 10000, + kuery: '(tags:remove)', + tagsToAdd: [], + tagsToRemove: ['remove'], + }), + expect.anything() + ); + }); + + it('should add tags filter to existing kuery if only one tag to remove', async () => { + await updateAgentTags( soClient, esClient, + { kuery: 'status:healthy OR status:offline' }, [], - {}, - { - tagsToAdd: [], - tagsToRemove: ['remove'], - kuery: '', - } + ['remove'] ); - const updateByQuery = esClient.updateByQuery.mock.calls[0][0] as any; - expect(JSON.stringify(updateByQuery.query)).toContain( - '{"bool":{"should":[{"match":{"tags":"remove"}}],"minimum_should_match":1}}' + expect(UpdateAgentTagsActionRunner).toHaveBeenCalledWith( + expect.anything(), + expect.anything(), + expect.objectContaining({ + batchSize: 10000, + kuery: '(status:healthy OR status:offline) AND (tags:remove)', + tagsToAdd: [], + tagsToRemove: ['remove'], + }), + expect.anything() ); }); - it('should write total from updateByQuery result if query returns less results', async () => { + it('should write total from total param if updateByQuery returns less results', async () => { esClient.updateByQuery.mockReset(); esClient.updateByQuery.mockResolvedValue({ failures: [], updated: 0, total: 50 } as any); await updateTagsBatch( soClient, esClient, - [], + [{ id: 'agent1' } as Agent], {}, { tagsToAdd: ['new'], @@ -364,9 +323,9 @@ describe('update_agent_tags', () => { expect(agentAction?.body).toEqual( expect.objectContaining({ action_id: expect.anything(), - agents: [], + agents: ['agent1'], type: 'UPDATE_TAGS', - total: 50, + total: 100, }) ); }); diff --git a/x-pack/plugins/fleet/server/services/agents/update_agent_tags.ts b/x-pack/plugins/fleet/server/services/agents/update_agent_tags.ts index a53a5f45364202..5e335bfd41996a 100644 --- a/x-pack/plugins/fleet/server/services/agents/update_agent_tags.ts +++ b/x-pack/plugins/fleet/server/services/agents/update_agent_tags.ts @@ -10,7 +10,9 @@ import type { ElasticsearchClient, SavedObjectsClientContract } from '@kbn/core/ import type { Agent } from '../../types'; import { AgentReassignmentError } from '../../errors'; -import { getAgentsById } from './crud'; +import { SO_SEARCH_LIMIT } from '../../constants'; + +import { getAgentsById, getAgentsByKuery, openPointInTime } from './crud'; import type { GetAgentsOptions } from '.'; import { UpdateAgentTagsActionRunner, updateTagsBatch } from './update_agent_tags_action_runner'; @@ -36,16 +38,41 @@ export async function updateAgentTags( } } } else if ('kuery' in options) { + const batchSize = options.batchSize ?? SO_SEARCH_LIMIT; + + const filters = []; + if (options.kuery !== '') { + filters.push(options.kuery); + } + if (tagsToAdd.length === 1 && tagsToRemove.length === 0) { + filters.push(`NOT (tags:${tagsToAdd[0]})`); + } else if (tagsToRemove.length === 1 && tagsToAdd.length === 0) { + filters.push(`tags:${tagsToRemove[0]}`); + } + + const kuery = filters.map((filter) => `(${filter})`).join(' AND '); + const pitId = await openPointInTime(esClient); + + // calculate total count + const res = await getAgentsByKuery(esClient, soClient, { + kuery, + showInactive: options.showInactive ?? false, + perPage: 0, + pitId, + }); + return await new UpdateAgentTagsActionRunner( esClient, soClient, { ...options, - kuery: options.kuery, + kuery, tagsToAdd, tagsToRemove, + batchSize, + total: res.total, }, - { pitId: '' } + { pitId } ).runActionAsyncWithRetry(); } diff --git a/x-pack/plugins/fleet/server/services/agents/update_agent_tags_action_runner.ts b/x-pack/plugins/fleet/server/services/agents/update_agent_tags_action_runner.ts index 9c872594524935..1f12968b67c367 100644 --- a/x-pack/plugins/fleet/server/services/agents/update_agent_tags_action_runner.ts +++ b/x-pack/plugins/fleet/server/services/agents/update_agent_tags_action_runner.ts @@ -8,24 +8,19 @@ import type { SavedObjectsClientContract, ElasticsearchClient } from '@kbn/core/server'; import { v4 as uuidv4 } from 'uuid'; import { uniq } from 'lodash'; -import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import type { Agent } from '../../types'; -import { AGENTS_INDEX, AGENT_POLICY_SAVED_OBJECT_TYPE } from '../../constants'; +import { AGENTS_INDEX } from '../../constants'; import { appContextService } from '../app_context'; -import { agentPolicyService } from '../agent_policy'; +import { ActionRunner } from './action_runner'; -import { SO_SEARCH_LIMIT } from '../../../common/constants'; - -import { ActionRunner, MAX_RETRY_COUNT } from './action_runner'; - -import { BulkActionTaskType } from './bulk_actions_resolver'; +import { BulkActionTaskType } from './bulk_action_types'; import { filterHostedPolicies } from './filter_hosted_agents'; import { bulkCreateAgentActionResults, createAgentAction } from './actions'; -import { getElasticsearchQuery } from './crud'; +import { MAX_RETRY_COUNT } from './retry_helper'; export class UpdateAgentTagsActionRunner extends ActionRunner { protected async processAgents(agents: Agent[]): Promise<{ actionId: string }> { @@ -50,26 +45,6 @@ export class UpdateAgentTagsActionRunner extends ActionRunner { protected getActionType() { return 'UPDATE_TAGS'; } - - async processAgentsInBatches(): Promise<{ actionId: string }> { - const { updated, took } = await updateTagsBatch( - this.soClient, - this.esClient, - [], - {}, - { - tagsToAdd: this.actionParams?.tagsToAdd, - tagsToRemove: this.actionParams?.tagsToRemove, - actionId: this.actionParams.actionId, - total: this.actionParams.total, - kuery: this.actionParams.kuery, - retryCount: this.retryParams.retryCount, - } - ); - - appContextService.getLogger().info(`processed ${updated} agents, took ${took}ms`); - return { actionId: this.actionParams.actionId! }; - } } export async function updateTagsBatch( @@ -97,38 +72,26 @@ export async function updateTagsBatch( ); const agentIds = filteredAgents.map((agent) => agent.id); - let query: estypes.QueryDslQueryContainer | undefined; - if (options.kuery !== undefined) { - const hostedPolicies = await agentPolicyService.list(soClient, { - kuery: `${AGENT_POLICY_SAVED_OBJECT_TYPE}.is_managed:true`, - perPage: SO_SEARCH_LIMIT, - }); - const hostedIds = hostedPolicies.items.map((item) => item.id); - - const extraFilters = []; - if (options.tagsToAdd.length === 1 && options.tagsToRemove.length === 0) { - extraFilters.push(`NOT (tags:${options.tagsToAdd[0]})`); - } else if (options.tagsToRemove.length === 1 && options.tagsToAdd.length === 0) { - extraFilters.push(`tags:${options.tagsToRemove[0]}`); - } - const DEFAULT_STATUS_FILTER = - 'status:online or (status:error or status:degraded) or (status:updating or status:unenrolling or status:enrolling) or status:offline'; - // removing default staus filters, as it is a runtime field and doesn't work with updateByQuery - // this is a quick fix for bulk update tags with default filters - const kuery = options.kuery === DEFAULT_STATUS_FILTER ? '' : options.kuery; - query = getElasticsearchQuery(kuery, false, false, hostedIds, extraFilters); - } else { - query = { - terms: { - _id: agentIds, - }, - }; + const actionId = options.actionId ?? uuidv4(); + if (agentIds.length === 0) { + appContextService.getLogger().debug('No agents to update tags, returning'); + return { actionId, updated: 0, took: 0 }; } + appContextService + .getLogger() + .debug( + `Agents to update tags in batch: ${agentIds.length}, tagsToAdd: ${options.tagsToAdd}, tagsToRemove: ${options.tagsToRemove}` + ); + let res; try { res = await esClient.updateByQuery({ - query, + query: { + terms: { + _id: agentIds, + }, + }, index: AGENTS_INDEX, refresh: true, wait_for_completion: true, @@ -166,16 +129,14 @@ export async function updateTagsBatch( appContextService.getLogger().debug(JSON.stringify(res).slice(0, 1000)); - const actionId = options.actionId ?? uuidv4(); - if (options.retryCount === undefined) { // creating an action doc so that update tags shows up in activity await createAgentAction(esClient, { id: actionId, - agents: options.kuery === undefined ? agentIds : [], + agents: agentIds, created_at: new Date().toISOString(), type: 'UPDATE_TAGS', - total: res.total, + total: options.total ?? res.total, }); } @@ -186,7 +147,7 @@ export async function updateTagsBatch( if (res.updated ?? 0 > 0) { await bulkCreateAgentActionResults( esClient, - (options.kuery === undefined ? agentIds : getUuidArray(res.updated!)).map((id) => ({ + agentIds.map((id) => ({ agentId: id, actionId, })) diff --git a/x-pack/plugins/fleet/server/services/agents/upgrade_action_runner.ts b/x-pack/plugins/fleet/server/services/agents/upgrade_action_runner.ts index 501afe0d540430..ff677db23cacc6 100644 --- a/x-pack/plugins/fleet/server/services/agents/upgrade_action_runner.ts +++ b/x-pack/plugins/fleet/server/services/agents/upgrade_action_runner.ts @@ -24,7 +24,7 @@ import type { GetAgentsOptions } from './crud'; import { bulkUpdateAgents } from './crud'; import { createErrorActionResults, createAgentAction } from './actions'; import { getHostedPolicies, isHostedAgent } from './hosted_agent'; -import { BulkActionTaskType } from './bulk_actions_resolver'; +import { BulkActionTaskType } from './bulk_action_types'; export class UpgradeActionRunner extends ActionRunner { protected async processAgents(agents: Agent[]): Promise<{ actionId: string }> {