From 2f60c5b95a2636bbe402fe73c35544588d87fd80 Mon Sep 17 00:00:00 2001 From: MichelLosier Date: Wed, 30 Jul 2025 08:34:27 -0700 Subject: [PATCH 01/12] Start extracting createAgentPolicyAndPackagePolicies operations from API handler --- .../server/services/agent_policy_create.ts | 123 +++++++++++++++++- 1 file changed, 122 insertions(+), 1 deletion(-) diff --git a/x-pack/platform/plugins/shared/fleet/server/services/agent_policy_create.ts b/x-pack/platform/plugins/shared/fleet/server/services/agent_policy_create.ts index 07f93852356ae..f9c7c595c616f 100644 --- a/x-pack/platform/plugins/shared/fleet/server/services/agent_policy_create.ts +++ b/x-pack/platform/plugins/shared/fleet/server/services/agent_policy_create.ts @@ -20,7 +20,7 @@ import { FLEET_SYSTEM_PACKAGE, } from '../../common'; -import type { AgentPolicy, NewAgentPolicy } from '../types'; +import type { AgentPolicy, NewAgentPolicy, NewPackagePolicy } from '../types'; import { AgentlessAgentCreateOverProvisionnedError } from '../errors'; @@ -218,3 +218,124 @@ export async function createAgentPolicyWithPackages({ return agentPolicy; } + +interface CreateAgentAndPackagePoliciesParams { + soClient: SavedObjectsClientContract; + esClient: ElasticsearchClient; + newPolicy: NewAgentPolicy; + newPackagePolicies: NewPackagePolicy[]; + hasFleetServer?: boolean; + withSysMonitoring: boolean; + monitoringEnabled?: string[]; + spaceId: string; + user?: AuthenticatedUser; + authorizationHeader?: HTTPAuthorizationHeader | null; + force?: boolean; +} + +export async function createAgentPolicyAndPackagePolicies({ + soClient, + esClient, + newPolicy, + newPackagePolicies, + hasFleetServer, + withSysMonitoring, + monitoringEnabled, + spaceId, + user, + authorizationHeader, + force, +}: CreateAgentAndPackagePoliciesParams) { + const logger = appContextService.getLogger().get('createAgentPolicyAndPackagePolicies'); + + const agentPolicy = await createAgentPolicyWithPackages({ + soClient, + esClient, + newPolicy, + hasFleetServer, + withSysMonitoring, + monitoringEnabled, + spaceId, + user, + authorizationHeader, + force, + }); + + const createdPackagePolicyIds = []; + + try { + for (const newPackagePolicy of newPackagePolicies) { + // Extract the original agent policy ID from the request in order to replace it with the created agent policy ID + const { + policy_id: agentPolicyId, + policy_ids: agentPolicyIds, + ...restOfPackagePolicy + } = newPackagePolicy; + + // Warn if the requested agent policy ID does not match the created agent policy ID + if (agentPolicyId && agentPolicyId !== agentPolicy.id) { + logger.warn( + `Creating package policy with agent policy ID ${agentPolicy.id} instead of requested id ${agentPolicyId}` + ); + } + if ( + agentPolicyIds && + agentPolicyIds.length > 0 && + (!agentPolicyIds.includes(agentPolicy.id) || agentPolicyIds.length > 1) + ) { + logger.warn( + `Creating package policy with agent policy ID ${ + agentPolicy.id + } instead of requested id(s) ${agentPolicyIds.join(',')}` + ); + } + + const newPackagePolicyWithPolicyIds = { + ...restOfPackagePolicy, + policy_ids: [agentPolicy.id], + }; + + const packagePolicy = await packagePolicyService.create( + soClient, + esClient, + newPackagePolicyWithPolicyIds, + { + spaceId, + user, + bumpRevision: false, + authorizationHeader, + force, + } + ); + + createdPackagePolicyIds.push(packagePolicy.id); + } + + return agentPolicyService.get(soClient, agentPolicy.id); + } catch (e) { + // If there is an error creating package policies, delete any created package policy + // and the parent agent policy + const internalSOClient = appContextService.getInternalUserSOClient(); + const internalESClient = appContextService.getInternalUserESClient(); + + if (createdPackagePolicyIds.length > 0) { + await packagePolicyService.delete( + internalSOClient, + internalESClient, + createdPackagePolicyIds, + { + force: true, + skipUnassignFromAgentPolicies: true, + } + ); + } + if (agentPolicy) { + await agentPolicyService.delete(internalSOClient, internalESClient, agentPolicy.id, { + force: true, + }); + } + + // Rethrow + throw e; + } +} From a6607899fa23f61523b76c6ccf5a9a1df9cd620c Mon Sep 17 00:00:00 2001 From: MichelLosier Date: Wed, 30 Jul 2025 14:42:05 -0700 Subject: [PATCH 02/12] Add createWithPackagePolicies to AgentPolicyService --- .../server/routes/agent_policy/handlers.ts | 1 + .../fleet/server/services/agent_policy.ts | 125 +++++++++++++ .../server/services/agent_policy_create.ts | 174 ++++-------------- .../shared/fleet/server/services/index.ts | 2 + 4 files changed, 164 insertions(+), 138 deletions(-) diff --git a/x-pack/platform/plugins/shared/fleet/server/routes/agent_policy/handlers.ts b/x-pack/platform/plugins/shared/fleet/server/routes/agent_policy/handlers.ts index c54faa7ba3db0..57c31e0290812 100644 --- a/x-pack/platform/plugins/shared/fleet/server/routes/agent_policy/handlers.ts +++ b/x-pack/platform/plugins/shared/fleet/server/routes/agent_policy/handlers.ts @@ -370,6 +370,7 @@ export const createAgentPolicyHandler: FleetRequestHandler< const agentPolicy = await createAgentPolicyWithPackages({ soClient, esClient, + agentPolicyService, newPolicy, hasFleetServer, withSysMonitoring, diff --git a/x-pack/platform/plugins/shared/fleet/server/services/agent_policy.ts b/x-pack/platform/plugins/shared/fleet/server/services/agent_policy.ts index b9a841b73a449..da778da7a01cd 100644 --- a/x-pack/platform/plugins/shared/fleet/server/services/agent_policy.ts +++ b/x-pack/platform/plugins/shared/fleet/server/services/agent_policy.ts @@ -120,6 +120,7 @@ import { getPackagePolicySavedObjectType, packagePolicyService } from './package import { incrementPackagePolicyCopyName } from './package_policies'; import { outputService } from './output'; import { agentPolicyUpdateEventHandler } from './agent_policy_update'; +import { createAgentPolicyWithPackages } from './agent_policy_create'; import { escapeSearchQueryPhrase, normalizeKuery as _normalizeKuery } from './saved_object'; import { getFullAgentPolicy, @@ -504,6 +505,130 @@ class AgentPolicyService { return { id: newSo.id, ...newSo.attributes }; } + public async createWithPackagePolicies({ + soClient, + esClient, + agentPolicy, + packagePolicies, + options: { + hasFleetServer, + withSysMonitoring, + monitoringEnabled, + spaceId, + user, + authorizationHeader, + force, + }, + }: { + soClient: SavedObjectsClientContract; + esClient: ElasticsearchClient; + agentPolicy: NewAgentPolicy; + packagePolicies: NewPackagePolicy[]; + options: { + hasFleetServer?: boolean; + withSysMonitoring: boolean; + monitoringEnabled?: string[]; + spaceId: string; + user?: AuthenticatedUser; + authorizationHeader?: HTTPAuthorizationHeader | null; + force?: boolean; + }; + }) { + const logger = appContextService.getLogger().get('createAgentPolicyAndPackagePolicies'); + + const newAgentPolicy = await createAgentPolicyWithPackages({ + soClient, + esClient, + agentPolicyService: this, + newPolicy: agentPolicy, + hasFleetServer, + withSysMonitoring, + monitoringEnabled, + spaceId, + user, + authorizationHeader, + force, + }); + + const createdPackagePolicyIds = []; + + try { + for (const newPackagePolicy of packagePolicies) { + // Extract the original agent policy ID from the request in order to replace it with the created agent policy ID + const { + policy_id: agentPolicyId, + policy_ids: agentPolicyIds, + ...restOfPackagePolicy + } = newPackagePolicy; + + // Warn if the requested agent policy ID does not match the created agent policy ID + if (agentPolicyId && agentPolicyId !== newAgentPolicy.id) { + logger.warn( + `Creating package policy with agent policy ID ${newAgentPolicy.id} instead of requested id ${agentPolicyId}` + ); + } + if ( + agentPolicyIds && + agentPolicyIds.length > 0 && + (!agentPolicyIds.includes(newAgentPolicy.id) || agentPolicyIds.length > 1) + ) { + logger.warn( + `Creating package policy with agent policy ID ${ + agentPolicy.id + } instead of requested id(s) ${agentPolicyIds.join(',')}` + ); + } + + const newPackagePolicyWithPolicyIds = { + ...restOfPackagePolicy, + policy_ids: [newAgentPolicy.id], + }; + + const packagePolicy = await packagePolicyService.create( + soClient, + esClient, + newPackagePolicyWithPolicyIds, + { + spaceId, + user, + bumpRevision: false, + authorizationHeader, + force, + } + ); + + createdPackagePolicyIds.push(packagePolicy.id); + } + + return this.get(soClient, newAgentPolicy.id); + } catch (e) { + // If there is an error creating package policies, delete any created package policy + // and the parent agent policy + const internalSOClient = appContextService.getInternalUserSOClient(); + const internalESClient = appContextService.getInternalUserESClient(); + + if (createdPackagePolicyIds.length > 0) { + await packagePolicyService.delete( + internalSOClient, + internalESClient, + createdPackagePolicyIds, + { + force: true, + skipUnassignFromAgentPolicies: true, + } + ); + } + if (agentPolicy) { + await this.delete(internalSOClient, internalESClient, newAgentPolicy.id, { + force: true, + }); + } + + // Rethrow + throw e; + } + } + public async requireUniqueName( soClient: SavedObjectsClientContract, givenPolicy: { id?: string; name: string; supports_agentless?: boolean | null } diff --git a/x-pack/platform/plugins/shared/fleet/server/services/agent_policy_create.ts b/x-pack/platform/plugins/shared/fleet/server/services/agent_policy_create.ts index f9c7c595c616f..80bd8c87ecee5 100644 --- a/x-pack/platform/plugins/shared/fleet/server/services/agent_policy_create.ts +++ b/x-pack/platform/plugins/shared/fleet/server/services/agent_policy_create.ts @@ -20,18 +20,19 @@ import { FLEET_SYSTEM_PACKAGE, } from '../../common'; -import type { AgentPolicy, NewAgentPolicy, NewPackagePolicy } from '../types'; +import type { AgentPolicy, NewAgentPolicy } from '../types'; import { AgentlessAgentCreateOverProvisionnedError } from '../errors'; -import { agentPolicyService, appContextService, packagePolicyService } from '.'; +import { type AgentPolicyServiceInterface, appContextService, packagePolicyService } from '.'; import { incrementPackageName } from './package_policies'; import { bulkInstallPackages } from './epm/packages'; import { ensureDefaultEnrollmentAPIKeyForAgentPolicy } from './api_keys'; import { agentlessAgentService } from './agents/agentless_agent'; async function getFleetServerAgentPolicyId( - soClient: SavedObjectsClientContract + soClient: SavedObjectsClientContract, + agentPolicyService: AgentPolicyServiceInterface ): Promise { const logger = appContextService.getLogger().get('getFleetServerAgentPolicyId'); @@ -65,6 +66,7 @@ async function getFleetServerAgentPolicyId( async function createPackagePolicy( soClient: SavedObjectsClientContract, esClient: ElasticsearchClient, + agentPolicyService: AgentPolicyServiceInterface, agentPolicy: AgentPolicy, packageToInstall: string, options: { @@ -106,6 +108,7 @@ async function createPackagePolicy( interface CreateAgentPolicyParams { soClient: SavedObjectsClientContract; esClient: ElasticsearchClient; + agentPolicyService: AgentPolicyServiceInterface; newPolicy: NewAgentPolicy; hasFleetServer?: boolean; withSysMonitoring: boolean; @@ -119,6 +122,7 @@ interface CreateAgentPolicyParams { export async function createAgentPolicyWithPackages({ soClient, esClient, + agentPolicyService, newPolicy, hasFleetServer, withSysMonitoring, @@ -141,7 +145,8 @@ export async function createAgentPolicyWithPackages({ if (hasFleetServer) { packagesToInstall.push(FLEET_SERVER_PACKAGE); - agentPolicyId = agentPolicyId || (await getFleetServerAgentPolicyId(soClient)); + agentPolicyId = + agentPolicyId || (await getFleetServerAgentPolicyId(soClient, agentPolicyService)); if (agentPolicyId === getDefaultFleetServerpolicyId(spaceId)) { // setting first fleet server policy to default, so that fleet server can enroll without setting policy_id @@ -179,22 +184,36 @@ export async function createAgentPolicyWithPackages({ // Create the fleet server package policy and add it to agent policy. if (hasFleetServer) { - await createPackagePolicy(soClient, esClient, agentPolicy, FLEET_SERVER_PACKAGE, { - spaceId, - user, - authorizationHeader, - force, - }); + await createPackagePolicy( + soClient, + esClient, + agentPolicyService, + agentPolicy, + FLEET_SERVER_PACKAGE, + { + spaceId, + user, + authorizationHeader, + force, + } + ); } // Create the system monitoring package policy and add it to agent policy. if (withSysMonitoring) { - await createPackagePolicy(soClient, esClient, agentPolicy, FLEET_SYSTEM_PACKAGE, { - spaceId, - user, - authorizationHeader, - force, - }); + await createPackagePolicy( + soClient, + esClient, + agentPolicyService, + agentPolicy, + FLEET_SYSTEM_PACKAGE, + { + spaceId, + user, + authorizationHeader, + force, + } + ); } await ensureDefaultEnrollmentAPIKeyForAgentPolicy(soClient, esClient, agentPolicy.id); @@ -206,7 +225,7 @@ export async function createAgentPolicyWithPackages({ await agentlessAgentService.createAgentlessAgent(esClient, soClient, agentPolicy); } catch (err) { if (err instanceof AgentlessAgentCreateOverProvisionnedError) { - await agentPolicyService.delete(soClient, esClient, agentPolicy.id).catch((deleteError) => { + await agentPolicyService.delete(soClient, esClient, agentPolicy.id).catch(() => { appContextService .getLogger() .error(`Error deleting agentless policy`, { error: agentPolicy }); @@ -218,124 +237,3 @@ export async function createAgentPolicyWithPackages({ return agentPolicy; } - -interface CreateAgentAndPackagePoliciesParams { - soClient: SavedObjectsClientContract; - esClient: ElasticsearchClient; - newPolicy: NewAgentPolicy; - newPackagePolicies: NewPackagePolicy[]; - hasFleetServer?: boolean; - withSysMonitoring: boolean; - monitoringEnabled?: string[]; - spaceId: string; - user?: AuthenticatedUser; - authorizationHeader?: HTTPAuthorizationHeader | null; - force?: boolean; -} - -export async function createAgentPolicyAndPackagePolicies({ - soClient, - esClient, - newPolicy, - newPackagePolicies, - hasFleetServer, - withSysMonitoring, - monitoringEnabled, - spaceId, - user, - authorizationHeader, - force, -}: CreateAgentAndPackagePoliciesParams) { - const logger = appContextService.getLogger().get('createAgentPolicyAndPackagePolicies'); - - const agentPolicy = await createAgentPolicyWithPackages({ - soClient, - esClient, - newPolicy, - hasFleetServer, - withSysMonitoring, - monitoringEnabled, - spaceId, - user, - authorizationHeader, - force, - }); - - const createdPackagePolicyIds = []; - - try { - for (const newPackagePolicy of newPackagePolicies) { - // Extract the original agent policy ID from the request in order to replace it with the created agent policy ID - const { - policy_id: agentPolicyId, - policy_ids: agentPolicyIds, - ...restOfPackagePolicy - } = newPackagePolicy; - - // Warn if the requested agent policy ID does not match the created agent policy ID - if (agentPolicyId && agentPolicyId !== agentPolicy.id) { - logger.warn( - `Creating package policy with agent policy ID ${agentPolicy.id} instead of requested id ${agentPolicyId}` - ); - } - if ( - agentPolicyIds && - agentPolicyIds.length > 0 && - (!agentPolicyIds.includes(agentPolicy.id) || agentPolicyIds.length > 1) - ) { - logger.warn( - `Creating package policy with agent policy ID ${ - agentPolicy.id - } instead of requested id(s) ${agentPolicyIds.join(',')}` - ); - } - - const newPackagePolicyWithPolicyIds = { - ...restOfPackagePolicy, - policy_ids: [agentPolicy.id], - }; - - const packagePolicy = await packagePolicyService.create( - soClient, - esClient, - newPackagePolicyWithPolicyIds, - { - spaceId, - user, - bumpRevision: false, - authorizationHeader, - force, - } - ); - - createdPackagePolicyIds.push(packagePolicy.id); - } - - return agentPolicyService.get(soClient, agentPolicy.id); - } catch (e) { - // If there is an error creating package policies, delete any created package policy - // and the parent agent policy - const internalSOClient = appContextService.getInternalUserSOClient(); - const internalESClient = appContextService.getInternalUserESClient(); - - if (createdPackagePolicyIds.length > 0) { - await packagePolicyService.delete( - internalSOClient, - internalESClient, - createdPackagePolicyIds, - { - force: true, - skipUnassignFromAgentPolicies: true, - } - ); - } - if (agentPolicy) { - await agentPolicyService.delete(internalSOClient, internalESClient, agentPolicy.id, { - force: true, - }); - } - - // Rethrow - throw e; - } -} diff --git a/x-pack/platform/plugins/shared/fleet/server/services/index.ts b/x-pack/platform/plugins/shared/fleet/server/services/index.ts index 71710fc3bc88f..b7171101cdda3 100644 --- a/x-pack/platform/plugins/shared/fleet/server/services/index.ts +++ b/x-pack/platform/plugins/shared/fleet/server/services/index.ts @@ -16,6 +16,7 @@ export { getRegistryUrl } from './epm/registry/registry_url'; export interface AgentPolicyServiceInterface { create: (typeof agentPolicyService)['create']; + createWithPackagePolicies: (typeof agentPolicyService)['createWithPackagePolicies']; get: (typeof agentPolicyService)['get']; list: (typeof agentPolicyService)['list']; delete: (typeof agentPolicyService)['delete']; @@ -24,6 +25,7 @@ export interface AgentPolicyServiceInterface { turnOffAgentTamperProtections: (typeof agentPolicyService)['turnOffAgentTamperProtections']; fetchAllAgentPolicyIds: (typeof agentPolicyService)['fetchAllAgentPolicyIds']; fetchAllAgentPolicies: (typeof agentPolicyService)['fetchAllAgentPolicies']; + deployPolicy: (typeof agentPolicyService)['deployPolicy']; } // Agent services From f31d343ed43f2de133cc236a9c7cc9be30f40a6b Mon Sep 17 00:00:00 2001 From: MichelLosier Date: Thu, 31 Jul 2025 10:36:00 -0700 Subject: [PATCH 03/12] Incorporate agentPolicyService.createWithPackagePolicies into contentConnectors task --- .../server/services/index.ts | 127 +++++++++--------- .../fleet/server/services/agent_policy.ts | 8 +- .../server/services/agent_policy_create.ts | 14 +- 3 files changed, 73 insertions(+), 76 deletions(-) diff --git a/x-pack/platform/plugins/shared/content_connectors/server/services/index.ts b/x-pack/platform/plugins/shared/content_connectors/server/services/index.ts index fe20cb1435190..1964390387db7 100644 --- a/x-pack/platform/plugins/shared/content_connectors/server/services/index.ts +++ b/x-pack/platform/plugins/shared/content_connectors/server/services/index.ts @@ -6,7 +6,7 @@ */ import { ElasticsearchClient } from '@kbn/core-elasticsearch-server'; -import { Agent, PACKAGE_POLICY_SAVED_OBJECT_TYPE, PackagePolicy } from '@kbn/fleet-plugin/common'; +import { Agent, NewAgentPolicy, PACKAGE_POLICY_SAVED_OBJECT_TYPE } from '@kbn/fleet-plugin/common'; import { AgentPolicyServiceInterface, AgentService, @@ -15,7 +15,6 @@ import { import type { Logger, SavedObjectsClientContract } from '@kbn/core/server'; import { NATIVE_CONNECTOR_DEFINITIONS, fetchConnectors } from '@kbn/search-connectors'; import { getPackageInfo } from '@kbn/fleet-plugin/server/services/epm/packages'; -import { createAgentPolicyWithPackages } from '@kbn/fleet-plugin/server/services/agent_policy_create'; import { DEFAULT_SPACE_ID } from '@kbn/spaces-plugin/common'; export interface ConnectorMetadata { @@ -160,7 +159,7 @@ export class AgentlessConnectorsInfraService { return policiesMetadata; }; - public deployConnector = async (connector: ConnectorMetadata): Promise => { + public deployConnector = async (connector: ConnectorMetadata) => { this.logger.info( `Connector ${connector.id} has no integration policy associated with it, creating` ); @@ -186,77 +185,73 @@ export class AgentlessConnectorsInfraService { const pkgVersion = await this.getPackageVersion(); this.logger.debug(`Latest package version for ${pkgName} is ${pkgVersion}`); - const createdPolicy = await createAgentPolicyWithPackages({ + const agentPolicyToCreate: NewAgentPolicy = { + name: `Agentless policy for ${connector.service_type} connector: ${connector.id}`, + description: `Automatically generated on ${new Date(Date.now()).toISOString()}`, + global_data_tags: [ + { + name: 'organization', + value: 'elastic', + }, + { + name: 'division', + value: 'engineering', + }, + { + name: 'team', + value: 'search-extract-and-transform', + }, + ], + namespace: 'default', + monitoring_enabled: ['logs', 'metrics'], + inactivity_timeout: 3600, + is_protected: false, + supports_agentless: true, + }; + + const packagePolicyToCreate = { + policy_ids: [], + package: { + title: pkgTitle, + name: pkgName, + version: pkgVersion, + }, + name: `${connector.service_type} connector ${connector.id}`, + description: '', + namespace: '', + enabled: true, + inputs: [ + { + type: connectorsInputName, + policy_template: connector.service_type, + enabled: true, + vars: { + connector_id: { type: 'string', value: connector.id }, + connector_name: { type: 'string', value: connector.name }, + service_type: { type: 'string', value: connector.service_type }, + }, + streams: [], + }, + ], + supports_agentless: true, + }; + + const agentPolicy = await this.agentPolicyService.createWithPackagePolicies({ soClient: this.soClient, esClient: this.esClient, - newPolicy: { - name: `Agentless policy for ${connector.service_type} connector: ${connector.id}`, - description: `Automatically generated on ${new Date(Date.now()).toISOString()}`, - global_data_tags: [ - { - name: 'organization', - value: 'elastic', - }, - { - name: 'division', - value: 'engineering', - }, - { - name: 'team', - value: 'search-extract-and-transform', - }, - ], - namespace: 'default', - monitoring_enabled: ['logs', 'metrics'], - inactivity_timeout: 3600, - is_protected: false, - supports_agentless: true, + agentPolicy: agentPolicyToCreate, + packagePolicies: [packagePolicyToCreate], + options: { + withSysMonitoring: true, + spaceId: this.soClient.getCurrentNamespace() ?? DEFAULT_SPACE_ID, }, - withSysMonitoring: true, - spaceId: this.soClient.getCurrentNamespace() ?? DEFAULT_SPACE_ID, }); this.logger.info( - `Successfully created agent policy ${createdPolicy.id} for agentless connector ${connector.id}` - ); - this.logger.debug(`Creating a package policy for agentless connector ${connector.id}`); - const packagePolicy = await this.packagePolicyService.create( - this.soClient, - this.esClient, - { - policy_ids: [createdPolicy.id], - package: { - title: pkgTitle, - name: pkgName, - version: pkgVersion, - }, - name: `${connector.service_type} connector ${connector.id}`, - description: '', - namespace: '', - enabled: true, - inputs: [ - { - type: connectorsInputName, - policy_template: connector.service_type, - enabled: true, - vars: { - connector_id: { type: 'string', value: connector.id }, - connector_name: { type: 'string', value: connector.name }, - service_type: { type: 'string', value: connector.service_type }, - }, - streams: [], - }, - ], - supports_agentless: true, - }, - { force: true } - ); - - this.logger.info( - `Successfully created package policy ${packagePolicy.id} for agentless connector ${connector.id}` + `Successfully created agent policy ${agentPolicy.id} for agentless connector ${connector.id}` ); - return packagePolicy; + return agentPolicy; }; public removeDeployment = async (packagePolicyId: string): Promise => { diff --git a/x-pack/platform/plugins/shared/fleet/server/services/agent_policy.ts b/x-pack/platform/plugins/shared/fleet/server/services/agent_policy.ts index da778da7a01cd..93b28a06e8a85 100644 --- a/x-pack/platform/plugins/shared/fleet/server/services/agent_policy.ts +++ b/x-pack/platform/plugins/shared/fleet/server/services/agent_policy.ts @@ -600,7 +600,13 @@ class AgentPolicyService { createdPackagePolicyIds.push(packagePolicy.id); } - return this.get(soClient, newAgentPolicy.id); + const agentPolicyWithPackagePolicies = await this.get(soClient, newAgentPolicy.id); + + if (!agentPolicyWithPackagePolicies) { + throw new Error(`Could not retrieve created agent policy ${newAgentPolicy.id}`); + } + + return agentPolicyWithPackagePolicies; } catch (e) { // If there is an error creating package policies, delete any created package policy // and the parent agent policy diff --git a/x-pack/platform/plugins/shared/fleet/server/services/agent_policy_create.ts b/x-pack/platform/plugins/shared/fleet/server/services/agent_policy_create.ts index 80bd8c87ecee5..f0d41cdb7739f 100644 --- a/x-pack/platform/plugins/shared/fleet/server/services/agent_policy_create.ts +++ b/x-pack/platform/plugins/shared/fleet/server/services/agent_policy_create.ts @@ -22,8 +22,6 @@ import { import type { AgentPolicy, NewAgentPolicy } from '../types'; -import { AgentlessAgentCreateOverProvisionnedError } from '../errors'; - import { type AgentPolicyServiceInterface, appContextService, packagePolicyService } from '.'; import { incrementPackageName } from './package_policies'; import { bulkInstallPackages } from './epm/packages'; @@ -224,13 +222,11 @@ export async function createAgentPolicyWithPackages({ try { await agentlessAgentService.createAgentlessAgent(esClient, soClient, agentPolicy); } catch (err) { - if (err instanceof AgentlessAgentCreateOverProvisionnedError) { - await agentPolicyService.delete(soClient, esClient, agentPolicy.id).catch(() => { - appContextService - .getLogger() - .error(`Error deleting agentless policy`, { error: agentPolicy }); - }); - } + await agentPolicyService.delete(soClient, esClient, agentPolicy.id).catch(() => { + appContextService + .getLogger() + .error(`Error deleting agentless policy`, { error: agentPolicy }); + }); throw err; } } From fad1df7ab54e0f8e705efb5204f5dfcb976f8925 Mon Sep 17 00:00:00 2001 From: MichelLosier Date: Thu, 31 Jul 2025 11:14:32 -0700 Subject: [PATCH 04/12] Update contentConnector deployConnector tests --- .../server/services/index.test.ts | 72 ++++++------------- .../server/services/index.ts | 1 + .../shared/fleet/server/mocks/index.ts | 2 + 3 files changed, 24 insertions(+), 51 deletions(-) diff --git a/x-pack/platform/plugins/shared/content_connectors/server/services/index.test.ts b/x-pack/platform/plugins/shared/content_connectors/server/services/index.test.ts index 4b8c2b1d2bc68..428886c7e59a7 100644 --- a/x-pack/platform/plugins/shared/content_connectors/server/services/index.test.ts +++ b/x-pack/platform/plugins/shared/content_connectors/server/services/index.test.ts @@ -31,13 +31,6 @@ import { } from '@kbn/fleet-plugin/server'; import { AgentPolicy, PackagePolicy, PackagePolicyInput } from '@kbn/fleet-plugin/common'; import { createAgentPolicyMock, createPackagePolicyMock } from '@kbn/fleet-plugin/common/mocks'; -import { createAgentPolicyWithPackages } from '@kbn/fleet-plugin/server/services/agent_policy_create'; - -jest.mock('@kbn/fleet-plugin/server/services/agent_policy_create', () => { - return { - createAgentPolicyWithPackages: jest.fn().mockReturnValue({ id: 'test-policy' }), - }; -}); jest.mock('@kbn/fleet-plugin/server/services/epm/packages', () => { const mockedGetPackageInfo = ({ pkgName }: { pkgName: string }) => { @@ -451,7 +444,7 @@ describe('AgentlessConnectorsInfraService', () => { } }); - test('Does not swallow an error if agent policy creation failed', async () => { + test('Does not swallow an error if agent with package policies creation failed', async () => { const connector = { id: '000000001', name: 'something', @@ -460,29 +453,7 @@ describe('AgentlessConnectorsInfraService', () => { }; const errorMessage = 'Failed to create an agent policy hehe'; - (createAgentPolicyWithPackages as jest.Mock).mockImplementationOnce(() => { - throw new Error(errorMessage); - }); - - try { - await service.deployConnector(connector); - expect(true).toBe(false); - } catch (e) { - expect(e.message).toEqual(errorMessage); - } - }); - - test('Does not swallow an error if package policy creation failed', async () => { - const connector = { - id: '000000001', - name: 'something', - service_type: 'github', - is_deleted: false, - }; - const errorMessage = 'Failed to create a package policy hehe'; - - agentPolicyInterface.create.mockResolvedValue(agentPolicy); - packagePolicyService.create.mockImplementation(() => { + agentPolicyInterface.createWithPackagePolicies.mockImplementationOnce(() => { throw new Error(errorMessage); }); @@ -494,7 +465,7 @@ describe('AgentlessConnectorsInfraService', () => { } }); - test('Returns a created package policy when all goes well', async () => { + test('Returns a created agent policy when all goes well', async () => { const connector = { id: '000000001', name: 'something', @@ -502,11 +473,10 @@ describe('AgentlessConnectorsInfraService', () => { is_deleted: false, }; - agentPolicyInterface.create.mockResolvedValue(agentPolicy); - packagePolicyService.create.mockResolvedValue(sharepointOnlinePackagePolicy); + agentPolicyInterface.createWithPackagePolicies.mockResolvedValue(agentPolicy); const result = await service.deployConnector(connector); - expect(result).toBe(sharepointOnlinePackagePolicy); + expect(result).toBe(agentPolicy); }); test('passes supports_agentless flag and global tags correctly to agent policy creation and package policy creation', async () => { @@ -518,27 +488,27 @@ describe('AgentlessConnectorsInfraService', () => { }; const fakeAgentPolicy = { id: 'agent-policy-005' } as AgentPolicy; - const fakePackagePolicy = { - id: 'package-policy-005', - policy_ids: ['agent-policy-005'], - } as PackagePolicy; - - agentPolicyInterface.create.mockResolvedValue(fakeAgentPolicy); - packagePolicyService.create.mockResolvedValue(fakePackagePolicy); + agentPolicyInterface.createWithPackagePolicies.mockResolvedValue(fakeAgentPolicy); const result = await service.deployConnector(testConnector); - expect(createAgentPolicyWithPackages).toHaveBeenCalled(); - - expect(packagePolicyService.create).toHaveBeenCalledWith( - soClient, - esClient, + expect(agentPolicyInterface.createWithPackagePolicies).toHaveBeenCalledWith( expect.objectContaining({ - supports_agentless: true, - }), - { force: true } + soClient, + esClient, + agentPolicy: expect.objectContaining({ + supports_agentless: true, + }), + packagePolicies: expect.arrayContaining([ + expect.objectContaining({ + supports_agentless: true, + }), + ]), + options: expect.objectContaining({ force: true }), + }) ); - expect(result).toBe(fakePackagePolicy); + + expect(result).toBe(fakeAgentPolicy); }); }); describe('removeDeployment', () => { diff --git a/x-pack/platform/plugins/shared/content_connectors/server/services/index.ts b/x-pack/platform/plugins/shared/content_connectors/server/services/index.ts index 1964390387db7..80c5660c9becc 100644 --- a/x-pack/platform/plugins/shared/content_connectors/server/services/index.ts +++ b/x-pack/platform/plugins/shared/content_connectors/server/services/index.ts @@ -244,6 +244,7 @@ export class AgentlessConnectorsInfraService { options: { withSysMonitoring: true, spaceId: this.soClient.getCurrentNamespace() ?? DEFAULT_SPACE_ID, + force: true, }, }); diff --git a/x-pack/platform/plugins/shared/fleet/server/mocks/index.ts b/x-pack/platform/plugins/shared/fleet/server/mocks/index.ts index b6feab804c115..8765baef3b3f4 100644 --- a/x-pack/platform/plugins/shared/fleet/server/mocks/index.ts +++ b/x-pack/platform/plugins/shared/fleet/server/mocks/index.ts @@ -274,6 +274,7 @@ export const createPackagePolicyServiceMock = (): jest.Mocked => { return { create: jest.fn().mockReturnValue(Promise.resolve()), + createWithPackagePolicies: jest.fn().mockReturnValue(Promise.resolve()), get: jest.fn().mockReturnValue(Promise.resolve()), list: jest.fn().mockReturnValue(Promise.resolve()), delete: jest.fn().mockReturnValue(Promise.resolve()), @@ -282,6 +283,7 @@ export const createMockAgentPolicyService = (): jest.Mocked Date: Thu, 31 Jul 2025 11:30:48 -0700 Subject: [PATCH 05/12] Update agent_policy_create tests --- .../fleet/server/services/agent_policy_create.test.ts | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/x-pack/platform/plugins/shared/fleet/server/services/agent_policy_create.test.ts b/x-pack/platform/plugins/shared/fleet/server/services/agent_policy_create.test.ts index aa85bbbf6c56d..e5b6ae84cafec 100644 --- a/x-pack/platform/plugins/shared/fleet/server/services/agent_policy_create.test.ts +++ b/x-pack/platform/plugins/shared/fleet/server/services/agent_policy_create.test.ts @@ -99,6 +99,7 @@ describe('createAgentPolicyWithPackages', () => { await createAgentPolicyWithPackages({ esClient: esClientMock, soClient: soClientMock, + agentPolicyService: mockedAgentPolicyService, newPolicy: { name: 'Agent policy 1', namespace: 'default' }, withSysMonitoring: true, spaceId: 'default', @@ -121,6 +122,7 @@ describe('createAgentPolicyWithPackages', () => { const response = await createAgentPolicyWithPackages({ esClient: esClientMock, soClient: soClientMock, + agentPolicyService: mockedAgentPolicyService, newPolicy: { name: 'Fleet Server policy', namespace: 'default' }, hasFleetServer: true, withSysMonitoring: true, @@ -154,6 +156,7 @@ describe('createAgentPolicyWithPackages', () => { const response = await createAgentPolicyWithPackages({ esClient: esClientMock, soClient: soClientMock, + agentPolicyService: mockedAgentPolicyService, newPolicy: { name: 'Fleet Server policy 2', namespace: 'default' }, hasFleetServer: true, withSysMonitoring: false, @@ -179,6 +182,7 @@ describe('createAgentPolicyWithPackages', () => { const response = await createAgentPolicyWithPackages({ esClient: esClientMock, soClient: soClientMock, + agentPolicyService: mockedAgentPolicyService, newPolicy: { name: 'Agent policy 1', namespace: 'default' }, withSysMonitoring: true, spaceId: 'default', @@ -215,6 +219,7 @@ describe('createAgentPolicyWithPackages', () => { const response = await createAgentPolicyWithPackages({ esClient: esClientMock, soClient: soClientMock, + agentPolicyService: mockedAgentPolicyService, newPolicy: { name: 'Agent policy 1', namespace: 'default' }, withSysMonitoring: true, spaceId: 'default', @@ -234,6 +239,7 @@ describe('createAgentPolicyWithPackages', () => { const response = await createAgentPolicyWithPackages({ esClient: esClientMock, soClient: soClientMock, + agentPolicyService: mockedAgentPolicyService, newPolicy: { name: 'Agent policy 1', namespace: 'default' }, withSysMonitoring: true, spaceId: 'default', @@ -259,6 +265,7 @@ describe('createAgentPolicyWithPackages', () => { const response = await createAgentPolicyWithPackages({ esClient: esClientMock, soClient: soClientMock, + agentPolicyService: mockedAgentPolicyService, newPolicy: { id: 'policy-1', name: 'Agent policy 1', namespace: 'default' }, withSysMonitoring: false, spaceId: 'default', @@ -272,6 +279,7 @@ describe('createAgentPolicyWithPackages', () => { const response = await createAgentPolicyWithPackages({ esClient: esClientMock, soClient: soClientMock, + agentPolicyService: mockedAgentPolicyService, newPolicy: { id: 'policy-1', name: 'Agent policy 1', namespace: 'default' }, withSysMonitoring: false, spaceId: 'default', @@ -291,6 +299,7 @@ describe('createAgentPolicyWithPackages', () => { const response = await createAgentPolicyWithPackages({ esClient: esClientMock, soClient: soClientMock, + agentPolicyService: mockedAgentPolicyService, newPolicy: { id: 'new_fleet_server_policy', name: 'Fleet Server policy', From 6a81ba31a5f09bf241c632778156656e268e82df Mon Sep 17 00:00:00 2001 From: MichelLosier Date: Thu, 31 Jul 2025 14:13:48 -0700 Subject: [PATCH 06/12] Add agentPolicyService.createWithPackagePolicies tests --- .../server/services/agent_policy.test.ts | 134 ++++++++++++++++++ 1 file changed, 134 insertions(+) diff --git a/x-pack/platform/plugins/shared/fleet/server/services/agent_policy.test.ts b/x-pack/platform/plugins/shared/fleet/server/services/agent_policy.test.ts index 8ca7af0a29edc..8b6e98f2ec2ea 100644 --- a/x-pack/platform/plugins/shared/fleet/server/services/agent_policy.test.ts +++ b/x-pack/platform/plugins/shared/fleet/server/services/agent_policy.test.ts @@ -49,6 +49,7 @@ import { licenseService } from './license'; import type { UninstallTokenServiceInterface } from './security/uninstall_token_service'; import { isSpaceAwarenessEnabled } from './spaces/helpers'; import { scheduleDeployAgentPoliciesTask } from './agent_policies/deploy_agent_policies_task'; +import { createAgentPolicyWithPackages } from './agent_policy_create'; jest.mock('./spaces/helpers'); @@ -130,6 +131,7 @@ jest.mock('./audit_logging'); jest.mock('./agent_policies/full_agent_policy'); jest.mock('./agent_policies/outputs_helpers'); jest.mock('./agent_policies/deploy_agent_policies_task'); +jest.mock('./agent_policy_create'); const mockedAppContextService = appContextService as jest.Mocked; mockedAppContextService.getSecuritySetup.mockImplementation(() => ({ @@ -147,6 +149,9 @@ const mockedPackagePolicyService = packagePolicyService as jest.Mocked >; +const mockedCreateAgentPolicyWithPackages = createAgentPolicyWithPackages as jest.MockedFunction< + typeof createAgentPolicyWithPackages +>; function getAgentPolicyCreateMock() { const soClient = createSavedObjectClientMock(); @@ -536,6 +541,135 @@ describe('Agent policy', () => { }); }); + describe('createWithPackagePolicies', () => { + let deleteSpy: any; + beforeEach(() => { + deleteSpy = jest.spyOn(agentPolicyService, 'delete'); + }); + + afterEach(() => { + deleteSpy.mockRestore(); + }); + it('should create an agent policy with package policies', async () => { + const soClient = createSavedObjectClientMock(); + const esClient = elasticsearchServiceMock.createClusterClient().asInternalUser; + const mockAgentPolicy = { + name: 'Test Agent Policy', + namespace: 'default', + description: 'A test agent policy with package policies', + is_managed: false, + supports_agentless: true, + }; + const mockPackagePolicy = { + name: 'Test Package Policy', + policy_ids: [], + package: { name: 'test-package', title: 'Test Package', version: '1.0.0' }, + inputs: [], + enabled: true, + }; + + mockedCreateAgentPolicyWithPackages.mockResolvedValue(mockAgentPolicy as any); + mockedPackagePolicyService.create.mockResolvedValue(mockPackagePolicy as any); + soClient.bulkGet.mockResolvedValueOnce({ + saved_objects: [ + { + id: 'test-agent-policy', + attributes: { + name: mockAgentPolicy.name, + }, + }, + ], + } as any); + const agentPolicy = await agentPolicyService.createWithPackagePolicies({ + soClient, + esClient, + agentPolicy: mockAgentPolicy, + packagePolicies: [mockPackagePolicy], + options: { withSysMonitoring: true, spaceId: 'default' }, + }); + + expect(agentPolicy.name).toEqual(mockAgentPolicy.name); + }); + + it('should throw error if a package policy creation fails and delete all policies', async () => { + const soClient = createSavedObjectClientMock(); + const esClient = elasticsearchServiceMock.createClusterClient().asInternalUser; + mockedAppContextService.getInternalUserSOClient.mockReturnValue(soClient); + mockedAppContextService.getInternalUserESClient.mockReturnValue(esClient); + + const mockAgentPolicy = { + name: 'Test Agent Policy', + namespace: 'default', + description: 'A test agent policy with package policies', + is_managed: false, + supports_agentless: true, + }; + const mockAgentPolicyId = 'test-agent-policy-id'; + const mockPackagePolicy1 = { + name: 'Test Package Policy 1', + policy_ids: [], + package: { name: 'test-package1', title: 'Test Package1', version: '1.0.0' }, + inputs: [], + enabled: true, + }; + const packagePolicy1Id = 'package-policy-1-id'; + + const mockPackagePolicy2 = { + name: 'Test Package Policy 2', + policy_ids: [], + package: { name: 'test-package2', title: 'Test Package2', version: '1.0.0' }, + inputs: [], + enabled: true, + }; + + const mockError = new Error('Package policy creation failed'); + + mockedCreateAgentPolicyWithPackages.mockResolvedValue({ + id: mockAgentPolicyId, + ...mockAgentPolicy, + } as any); + mockedPackagePolicyService.create.mockImplementation( + (_soClient, _esClient, packagePolicy) => { + if (packagePolicy.name === 'Test Package Policy 2') { + throw mockError; + } else { + return Promise.resolve({ id: packagePolicy1Id, ...packagePolicy } as any); + } + } + ); + + deleteSpy.mockResolvedValueOnce({ id: mockAgentPolicyId, name: mockAgentPolicy.name }); + + let error; + + try { + await agentPolicyService.createWithPackagePolicies({ + soClient, + esClient, + agentPolicy: mockAgentPolicy, + packagePolicies: [mockPackagePolicy1, mockPackagePolicy2], + options: { withSysMonitoring: true, spaceId: 'default' }, + }); + } catch (e) { + error = e; + } + + expect(error).toEqual(mockError); + expect(deleteSpy).toHaveBeenCalledWith( + expect.anything(), + expect.anything(), + mockAgentPolicyId, + expect.anything() + ); + expect(mockedPackagePolicyService.delete).toHaveBeenCalledWith( + expect.anything(), + expect.anything(), + [packagePolicy1Id], + expect.anything() + ); + }); + }); + // TODO: Add more test coverage to `get` service method describe('get', () => { it('should call audit logger', async () => { From 88cdf2a03fe517e530739a81a82e20ba41470f56 Mon Sep 17 00:00:00 2001 From: MichelLosier Date: Thu, 31 Jul 2025 16:05:23 -0700 Subject: [PATCH 07/12] Fix usage of mock --- .../plugins/shared/content_connectors/server/task.test.ts | 4 ++-- .../shared/fleet/scripts/create_agents/create_agents.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/x-pack/platform/plugins/shared/content_connectors/server/task.test.ts b/x-pack/platform/plugins/shared/content_connectors/server/task.test.ts index e1ad9fedd4384..c1c8b26f5cbc1 100644 --- a/x-pack/platform/plugins/shared/content_connectors/server/task.test.ts +++ b/x-pack/platform/plugins/shared/content_connectors/server/task.test.ts @@ -14,7 +14,7 @@ import { PackagePolicyMetadata, } from './services'; import { licensingMock } from '@kbn/licensing-plugin/server/mocks'; -import { createPackagePolicyMock } from '@kbn/fleet-plugin/common/mocks'; +import { createAgentPolicyMock } from '@kbn/fleet-plugin/common/mocks'; import { coreMock } from '@kbn/core/server/mocks'; import { AgentlessConnectorsInfraServiceFactory } from './services/infra_service_factory'; @@ -218,7 +218,7 @@ describe('infraSyncTaskRunner', () => { throw new Error('Cannot deploy these connectors'); } - return createPackagePolicyMock(); + return createAgentPolicyMock(); }); await infraSyncTaskRunner( diff --git a/x-pack/platform/plugins/shared/fleet/scripts/create_agents/create_agents.ts b/x-pack/platform/plugins/shared/fleet/scripts/create_agents/create_agents.ts index 2c510a2ca3ffe..a225c90d336c3 100644 --- a/x-pack/platform/plugins/shared/fleet/scripts/create_agents/create_agents.ts +++ b/x-pack/platform/plugins/shared/fleet/scripts/create_agents/create_agents.ts @@ -31,7 +31,7 @@ const printUsage = () => [--outdated]: agents will show as outdated (their revision is below the policies), defaults to false `); -const DEFAULT_KIBANA_URL = 'http://localhost:5601'; +const DEFAULT_KIBANA_URL = 'http://localhost:5601/kibana'; const DEFAULT_KIBANA_USERNAME = 'elastic'; const DEFAULT_KIBANA_PASSWORD = 'changeme'; const PUBLIC_VERSION_V1 = '2023-10-31'; From d6f74974aa957fa72e086f91e5da6b219e68d89a Mon Sep 17 00:00:00 2001 From: MichelLosier Date: Fri, 1 Aug 2025 11:06:00 -0700 Subject: [PATCH 08/12] Use a FleetError when agent policy can't be found --- .../plugins/shared/fleet/server/services/agent_policy.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/x-pack/platform/plugins/shared/fleet/server/services/agent_policy.ts b/x-pack/platform/plugins/shared/fleet/server/services/agent_policy.ts index 93b28a06e8a85..7547974f7cef2 100644 --- a/x-pack/platform/plugins/shared/fleet/server/services/agent_policy.ts +++ b/x-pack/platform/plugins/shared/fleet/server/services/agent_policy.ts @@ -603,7 +603,9 @@ class AgentPolicyService { const agentPolicyWithPackagePolicies = await this.get(soClient, newAgentPolicy.id); if (!agentPolicyWithPackagePolicies) { - throw new Error(`Could not retrieve created agent policy ${newAgentPolicy.id}`); + throw new AgentPolicyNotFoundError( + `Could not retrieve created agent policy ${newAgentPolicy.id} after creating its package policies` + ); } return agentPolicyWithPackagePolicies; From 5e542da5772d16c1590730024f141c1555b73cce Mon Sep 17 00:00:00 2001 From: MichelLosier Date: Fri, 1 Aug 2025 11:08:04 -0700 Subject: [PATCH 09/12] Remove edit from create_agents script --- .../plugins/shared/fleet/scripts/create_agents/create_agents.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/platform/plugins/shared/fleet/scripts/create_agents/create_agents.ts b/x-pack/platform/plugins/shared/fleet/scripts/create_agents/create_agents.ts index a225c90d336c3..2c510a2ca3ffe 100644 --- a/x-pack/platform/plugins/shared/fleet/scripts/create_agents/create_agents.ts +++ b/x-pack/platform/plugins/shared/fleet/scripts/create_agents/create_agents.ts @@ -31,7 +31,7 @@ const printUsage = () => [--outdated]: agents will show as outdated (their revision is below the policies), defaults to false `); -const DEFAULT_KIBANA_URL = 'http://localhost:5601/kibana'; +const DEFAULT_KIBANA_URL = 'http://localhost:5601'; const DEFAULT_KIBANA_USERNAME = 'elastic'; const DEFAULT_KIBANA_PASSWORD = 'changeme'; const PUBLIC_VERSION_V1 = '2023-10-31'; From 3e9f12863913f061cf92a091c4248ccc18455f6a Mon Sep 17 00:00:00 2001 From: MichelLosier Date: Fri, 1 Aug 2025 11:35:22 -0700 Subject: [PATCH 10/12] Remove policy_id fields from PackagePolicy param, add logging --- .../fleet/server/services/agent_policy.ts | 65 ++++++++----------- 1 file changed, 26 insertions(+), 39 deletions(-) diff --git a/x-pack/platform/plugins/shared/fleet/server/services/agent_policy.ts b/x-pack/platform/plugins/shared/fleet/server/services/agent_policy.ts index 7547974f7cef2..841815e15b20e 100644 --- a/x-pack/platform/plugins/shared/fleet/server/services/agent_policy.ts +++ b/x-pack/platform/plugins/shared/fleet/server/services/agent_policy.ts @@ -523,7 +523,7 @@ class AgentPolicyService { soClient: SavedObjectsClientContract; esClient: ElasticsearchClient; agentPolicy: NewAgentPolicy; - packagePolicies: NewPackagePolicy[]; + packagePolicies: Array>; options: { hasFleetServer?: boolean; withSysMonitoring: boolean; @@ -534,7 +534,9 @@ class AgentPolicyService { force?: boolean; }; }) { - const logger = appContextService.getLogger().get('createAgentPolicyAndPackagePolicies'); + const logger = appContextService.getLogger().get('createWithPackagePolicies'); + + logger.debug(`Creating agent policy ${agentPolicy.name} with package policies`); const newAgentPolicy = await createAgentPolicyWithPackages({ soClient, @@ -553,41 +555,20 @@ class AgentPolicyService { const createdPackagePolicyIds = []; try { - for (const newPackagePolicy of packagePolicies) { - // Extract the original agent policy ID from the request in order to replace it with the created agent policy ID - const { - policy_id: agentPolicyId, - policy_ids: agentPolicyIds, - ...restOfPackagePolicy - } = newPackagePolicy; - - // Warn if the requested agent policy ID does not match the created agent policy ID - if (agentPolicyId && agentPolicyId !== newAgentPolicy.id) { - logger.warn( - `Creating package policy with agent policy ID ${newAgentPolicy.id} instead of requested id ${agentPolicyId}` - ); - } - if ( - agentPolicyIds && - agentPolicyIds.length > 0 && - (!agentPolicyIds.includes(newAgentPolicy.id) || agentPolicyIds.length > 1) - ) { - logger.warn( - `Creating package policy with agent policy ID ${ - agentPolicy.id - } instead of requested id(s) ${agentPolicyIds.join(',')}` - ); - } - - const newPackagePolicyWithPolicyIds = { - ...restOfPackagePolicy, + for (const packagePolicy of packagePolicies) { + const newPackagePolicy: NewPackagePolicy = { + ...packagePolicy, policy_ids: [newAgentPolicy.id], }; - const packagePolicy = await packagePolicyService.create( + logger.debug( + `Creating package policy ${packagePolicy.name} for agent policy ${newAgentPolicy.name}` + ); + + const createdPackagePolicy = await packagePolicyService.create( soClient, esClient, - newPackagePolicyWithPolicyIds, + newPackagePolicy, { spaceId, user, @@ -597,7 +578,7 @@ class AgentPolicyService { } ); - createdPackagePolicyIds.push(packagePolicy.id); + createdPackagePolicyIds.push(createdPackagePolicy.id); } const agentPolicyWithPackagePolicies = await this.get(soClient, newAgentPolicy.id); @@ -610,6 +591,15 @@ class AgentPolicyService { return agentPolicyWithPackagePolicies; } catch (e) { + logger.error( + `Error creating package policies for agent policy ${newAgentPolicy.id}: ${e.message}` + ); + logger.debug( + `Rolling back policy creation: Deleting agent policy ${ + newAgentPolicy.id + } and package policies ${createdPackagePolicyIds.join(', ')}` + ); + // If there is an error creating package policies, delete any created package policy // and the parent agent policy const internalSOClient = appContextService.getInternalUserSOClient(); @@ -626,13 +616,10 @@ class AgentPolicyService { } ); } - if (agentPolicy) { - await this.delete(internalSOClient, internalESClient, newAgentPolicy.id, { - force: true, - }); - } + await this.delete(internalSOClient, internalESClient, newAgentPolicy.id, { + force: true, + }); - // Rethrow throw e; } } From e53dead794f3fa5f781c02e481bbbe6adfa0d050 Mon Sep 17 00:00:00 2001 From: MichelLosier Date: Fri, 1 Aug 2025 12:48:42 -0700 Subject: [PATCH 11/12] Remove unneeded policy_ids field from package policy in content connector task --- .../plugins/shared/content_connectors/server/services/index.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/x-pack/platform/plugins/shared/content_connectors/server/services/index.ts b/x-pack/platform/plugins/shared/content_connectors/server/services/index.ts index 80c5660c9becc..8648347458825 100644 --- a/x-pack/platform/plugins/shared/content_connectors/server/services/index.ts +++ b/x-pack/platform/plugins/shared/content_connectors/server/services/index.ts @@ -210,7 +210,6 @@ export class AgentlessConnectorsInfraService { }; const packagePolicyToCreate = { - policy_ids: [], package: { title: pkgTitle, name: pkgName, From 307e29dcd06fc83ecdcaf05fc2c16218cee2cdfe Mon Sep 17 00:00:00 2001 From: MichelLosier Date: Mon, 4 Aug 2025 12:53:39 -0700 Subject: [PATCH 12/12] Add return type to deployConnector --- .../shared/content_connectors/server/services/index.ts | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/x-pack/platform/plugins/shared/content_connectors/server/services/index.ts b/x-pack/platform/plugins/shared/content_connectors/server/services/index.ts index 8648347458825..726001d1f1dfa 100644 --- a/x-pack/platform/plugins/shared/content_connectors/server/services/index.ts +++ b/x-pack/platform/plugins/shared/content_connectors/server/services/index.ts @@ -6,7 +6,12 @@ */ import { ElasticsearchClient } from '@kbn/core-elasticsearch-server'; -import { Agent, NewAgentPolicy, PACKAGE_POLICY_SAVED_OBJECT_TYPE } from '@kbn/fleet-plugin/common'; +import { + Agent, + AgentPolicy, + NewAgentPolicy, + PACKAGE_POLICY_SAVED_OBJECT_TYPE, +} from '@kbn/fleet-plugin/common'; import { AgentPolicyServiceInterface, AgentService, @@ -159,7 +164,7 @@ export class AgentlessConnectorsInfraService { return policiesMetadata; }; - public deployConnector = async (connector: ConnectorMetadata) => { + public deployConnector = async (connector: ConnectorMetadata): Promise => { this.logger.info( `Connector ${connector.id} has no integration policy associated with it, creating` );