diff --git a/x-pack/plugins/fleet/common/types/models/preconfiguration.ts b/x-pack/plugins/fleet/common/types/models/preconfiguration.ts index b16234d5a5f97..c9fff1c1581bd 100644 --- a/x-pack/plugins/fleet/common/types/models/preconfiguration.ts +++ b/x-pack/plugins/fleet/common/types/models/preconfiguration.ts @@ -27,3 +27,7 @@ export interface PreconfiguredAgentPolicy extends Omit; } + +export interface PreconfiguredPackage extends Omit { + force?: boolean; +} diff --git a/x-pack/plugins/fleet/server/services/epm/packages/install.ts b/x-pack/plugins/fleet/server/services/epm/packages/install.ts index 7095bb1688c73..168ec55b14876 100644 --- a/x-pack/plugins/fleet/server/services/epm/packages/install.ts +++ b/x-pack/plugins/fleet/server/services/epm/packages/install.ts @@ -115,8 +115,9 @@ export async function ensureInstalledPackage(options: { pkgName: string; esClient: ElasticsearchClient; pkgVersion?: string; + force?: boolean; }): Promise { - const { savedObjectsClient, pkgName, esClient, pkgVersion } = options; + const { savedObjectsClient, pkgName, esClient, pkgVersion, force } = options; const installedPackage = await isPackageVersionInstalled({ savedObjectsClient, pkgName, @@ -136,7 +137,7 @@ export async function ensureInstalledPackage(options: { savedObjectsClient, pkgkey, esClient, - force: true, + force, }); } else { await installLatestPackage({ diff --git a/x-pack/plugins/fleet/server/services/preconfiguration.test.ts b/x-pack/plugins/fleet/server/services/preconfiguration.test.ts index bcde8ade427e5..8a885f9c5c821 100644 --- a/x-pack/plugins/fleet/server/services/preconfiguration.test.ts +++ b/x-pack/plugins/fleet/server/services/preconfiguration.test.ts @@ -66,9 +66,19 @@ function getPutPreconfiguredPackagesMock() { } jest.mock('./epm/packages/install', () => ({ - ensureInstalledPackage({ pkgName, pkgVersion }: { pkgName: string; pkgVersion: string }) { + ensureInstalledPackage({ + pkgName, + pkgVersion, + force, + }: { + pkgName: string; + pkgVersion: string; + force?: boolean; + }) { const installedPackage = mockInstalledPackages.get(pkgName); - if (installedPackage) return installedPackage; + if (installedPackage) { + if (installedPackage.version === pkgVersion) return installedPackage; + } const packageInstallation = { name: pkgName, version: pkgVersion, title: pkgName }; mockInstalledPackages.set(pkgName, packageInstallation); @@ -138,12 +148,12 @@ describe('policy preconfiguration', () => { soClient, esClient, [], - [{ name: 'test-package', version: '3.0.0' }], + [{ name: 'test_package', version: '3.0.0' }], mockDefaultOutput ); expect(policies.length).toBe(0); - expect(packages).toEqual(expect.arrayContaining(['test-package:3.0.0'])); + expect(packages).toEqual(expect.arrayContaining(['test_package-3.0.0'])); }); it('should install packages and configure agent policies successfully', async () => { @@ -160,19 +170,19 @@ describe('policy preconfiguration', () => { id: 'test-id', package_policies: [ { - package: { name: 'test-package' }, + package: { name: 'test_package' }, name: 'Test package', }, ], }, ] as PreconfiguredAgentPolicy[], - [{ name: 'test-package', version: '3.0.0' }], + [{ name: 'test_package', version: '3.0.0' }], mockDefaultOutput ); expect(policies.length).toEqual(1); expect(policies[0].id).toBe('mocked-test-id'); - expect(packages).toEqual(expect.arrayContaining(['test-package:3.0.0'])); + expect(packages).toEqual(expect.arrayContaining(['test_package-3.0.0'])); }); it('should throw an error when trying to install duplicate packages', async () => { @@ -185,13 +195,13 @@ describe('policy preconfiguration', () => { esClient, [], [ - { name: 'test-package', version: '3.0.0' }, - { name: 'test-package', version: '2.0.0' }, + { name: 'test_package', version: '3.0.0' }, + { name: 'test_package', version: '2.0.0' }, ], mockDefaultOutput ) ).rejects.toThrow( - 'Duplicate packages specified in configuration: test-package:3.0.0, test-package:2.0.0' + 'Duplicate packages specified in configuration: test_package-3.0.0, test_package-2.0.0' ); }); diff --git a/x-pack/plugins/fleet/server/services/preconfiguration.ts b/x-pack/plugins/fleet/server/services/preconfiguration.ts index bd1c2ca1f23ef..97480fcf6b2a8 100644 --- a/x-pack/plugins/fleet/server/services/preconfiguration.ts +++ b/x-pack/plugins/fleet/server/services/preconfiguration.ts @@ -7,10 +7,9 @@ import type { ElasticsearchClient, SavedObjectsClientContract } from 'src/core/server'; import { i18n } from '@kbn/i18n'; -import { groupBy } from 'lodash'; +import { groupBy, omit } from 'lodash'; import type { - PackagePolicyPackage, NewPackagePolicy, AgentPolicy, Installation, @@ -18,8 +17,10 @@ import type { NewPackagePolicyInput, NewPackagePolicyInputStream, PreconfiguredAgentPolicy, + PreconfiguredPackage, } from '../../common'; +import { pkgToPkgKey } from './epm/registry'; import { getInstallation } from './epm/packages'; import { ensureInstalledPackage } from './epm/packages/install'; import { agentPolicyService, addPackageToAgentPolicy } from './agent_policy'; @@ -32,7 +33,7 @@ export async function ensurePreconfiguredPackagesAndPolicies( soClient: SavedObjectsClientContract, esClient: ElasticsearchClient, policies: PreconfiguredAgentPolicy[] = [], - packages: Array> = [], + packages: PreconfiguredPackage[] = [], defaultOutput: Output ) { // Validate configured packages to ensure there are no version conflicts @@ -45,7 +46,7 @@ export async function ensurePreconfiguredPackagesAndPolicies( // If there are multiple packages with duplicate versions, separate them with semicolons, e.g // package-a:1.0.0, package-a:2.0.0; package-b:1.0.0, package-b:2.0.0 const duplicateList = duplicatePackages - .map(([, versions]) => versions.map((v) => `${v.name}:${v.version}`).join(', ')) + .map(([, versions]) => versions.map((v) => pkgToPkgKey(v)).join(', ')) .join('; '); throw new Error( @@ -60,8 +61,8 @@ export async function ensurePreconfiguredPackagesAndPolicies( // Preinstall packages specified in Kibana config const preconfiguredPackages = await Promise.all( - packages.map(({ name, version }) => - ensureInstalledPreconfiguredPackage(soClient, esClient, name, version) + packages.map(({ name, version, force }) => + ensureInstalledPreconfiguredPackage(soClient, esClient, name, version, force) ) ); @@ -71,7 +72,7 @@ export async function ensurePreconfiguredPackagesAndPolicies( const { created, policy } = await agentPolicyService.ensurePreconfiguredAgentPolicy( soClient, esClient, - preconfiguredAgentPolicy + omit(preconfiguredAgentPolicy, 'is_managed') // Don't add `is_managed` until the policy has been fully configured ); if (!created) return { created, policy }; @@ -101,12 +102,22 @@ export async function ensurePreconfiguredPackagesAndPolicies( }) ); - return { created, policy, installedPackagePolicies }; + return { + created, + policy, + installedPackagePolicies, + shouldAddIsManagedFlag: preconfiguredAgentPolicy.is_managed, + }; }) ); for (const preconfiguredPolicy of preconfiguredPolicies) { - const { created, policy, installedPackagePolicies } = preconfiguredPolicy; + const { + created, + policy, + installedPackagePolicies, + shouldAddIsManagedFlag, + } = preconfiguredPolicy; if (created) { await addPreconfiguredPolicyPackages( soClient, @@ -115,6 +126,10 @@ export async function ensurePreconfiguredPackagesAndPolicies( installedPackagePolicies!, defaultOutput ); + // Add the is_managed flag after configuring package policies to avoid errors + if (shouldAddIsManagedFlag) { + agentPolicyService.update(soClient, esClient, policy.id, { is_managed: true }); + } } } @@ -123,7 +138,7 @@ export async function ensurePreconfiguredPackagesAndPolicies( id: p.policy.id, updated_at: p.policy.updated_at, })), - packages: preconfiguredPackages.map((pkg) => `${pkg.name}:${pkg.version}`), + packages: preconfiguredPackages.map((pkg) => pkgToPkgKey(pkg)), }; } @@ -160,13 +175,15 @@ async function ensureInstalledPreconfiguredPackage( soClient: SavedObjectsClientContract, esClient: ElasticsearchClient, pkgName: string, - pkgVersion: string + pkgVersion: string, + force?: boolean ) { return ensureInstalledPackage({ savedObjectsClient: soClient, pkgName, esClient, pkgVersion, + force, }); } diff --git a/x-pack/plugins/fleet/server/types/models/preconfiguration.ts b/x-pack/plugins/fleet/server/types/models/preconfiguration.ts index 77a28defaf1bd..0dc0ae8f1db88 100644 --- a/x-pack/plugins/fleet/server/types/models/preconfiguration.ts +++ b/x-pack/plugins/fleet/server/types/models/preconfiguration.ts @@ -33,6 +33,7 @@ export const PreconfiguredPackagesSchema = schema.arrayOf( } }, }), + force: schema.maybe(schema.boolean()), }) ); @@ -41,6 +42,8 @@ export const PreconfiguredAgentPoliciesSchema = schema.arrayOf( ...AgentPolicyBaseSchema, namespace: schema.maybe(NamespaceSchema), id: schema.oneOf([schema.string(), schema.number()]), + is_default: schema.maybe(schema.boolean()), + is_default_fleet_server: schema.maybe(schema.boolean()), package_policies: schema.arrayOf( schema.object({ name: schema.string(),