diff --git a/x-pack/plugins/fleet/common/constants/preconfiguration.ts b/x-pack/plugins/fleet/common/constants/preconfiguration.ts index 4cdd8221d4e98..376ba551b1359 100644 --- a/x-pack/plugins/fleet/common/constants/preconfiguration.ts +++ b/x-pack/plugins/fleet/common/constants/preconfiguration.ts @@ -5,4 +5,5 @@ * 2.0. */ -export const PRECONFIGURATION_METADATA_INDEX = '.fleet-preconfiguration'; +export const PRECONFIGURATION_DELETION_RECORD_SAVED_OBJECT_TYPE = + 'fleet-preconfiguration-deletion-record'; diff --git a/x-pack/plugins/fleet/server/constants/index.ts b/x-pack/plugins/fleet/server/constants/index.ts index 951112f443816..27af46d0a757d 100644 --- a/x-pack/plugins/fleet/server/constants/index.ts +++ b/x-pack/plugins/fleet/server/constants/index.ts @@ -52,5 +52,5 @@ export { // Fleet Server index ENROLLMENT_API_KEYS_INDEX, AGENTS_INDEX, - PRECONFIGURATION_METADATA_INDEX, + PRECONFIGURATION_DELETION_RECORD_SAVED_OBJECT_TYPE, } from '../../common'; diff --git a/x-pack/plugins/fleet/server/plugin.ts b/x-pack/plugins/fleet/server/plugin.ts index 20cfae6bc1cf2..d25b1e13904db 100644 --- a/x-pack/plugins/fleet/server/plugin.ts +++ b/x-pack/plugins/fleet/server/plugin.ts @@ -48,6 +48,7 @@ import { AGENT_SAVED_OBJECT_TYPE, AGENT_EVENT_SAVED_OBJECT_TYPE, ENROLLMENT_API_KEYS_SAVED_OBJECT_TYPE, + PRECONFIGURATION_DELETION_RECORD_SAVED_OBJECT_TYPE, } from './constants'; import { registerSavedObjects, registerEncryptedSavedObjects } from './saved_objects'; import { @@ -133,6 +134,7 @@ const allSavedObjectTypes = [ AGENT_SAVED_OBJECT_TYPE, AGENT_EVENT_SAVED_OBJECT_TYPE, ENROLLMENT_API_KEYS_SAVED_OBJECT_TYPE, + PRECONFIGURATION_DELETION_RECORD_SAVED_OBJECT_TYPE, ]; /** diff --git a/x-pack/plugins/fleet/server/saved_objects/index.ts b/x-pack/plugins/fleet/server/saved_objects/index.ts index 8554c0702f733..58ec3972ca517 100644 --- a/x-pack/plugins/fleet/server/saved_objects/index.ts +++ b/x-pack/plugins/fleet/server/saved_objects/index.ts @@ -19,6 +19,7 @@ import { AGENT_ACTION_SAVED_OBJECT_TYPE, ENROLLMENT_API_KEYS_SAVED_OBJECT_TYPE, GLOBAL_SETTINGS_SAVED_OBJECT_TYPE, + PRECONFIGURATION_DELETION_RECORD_SAVED_OBJECT_TYPE, } from '../constants'; import { @@ -358,6 +359,19 @@ const getSavedObjectTypes = ( }, }, }, + [PRECONFIGURATION_DELETION_RECORD_SAVED_OBJECT_TYPE]: { + name: PRECONFIGURATION_DELETION_RECORD_SAVED_OBJECT_TYPE, + hidden: false, + namespaceType: 'agnostic', + management: { + importableAndExportable: false, + }, + mappings: { + properties: { + preconfiguration_id: { type: 'keyword' }, + }, + }, + }, }); export function registerSavedObjects( diff --git a/x-pack/plugins/fleet/server/services/agent_policy.ts b/x-pack/plugins/fleet/server/services/agent_policy.ts index ce71d8a3a5945..59214e287c873 100644 --- a/x-pack/plugins/fleet/server/services/agent_policy.ts +++ b/x-pack/plugins/fleet/server/services/agent_policy.ts @@ -19,7 +19,7 @@ import { DEFAULT_AGENT_POLICY, AGENT_POLICY_SAVED_OBJECT_TYPE, AGENT_SAVED_OBJECT_TYPE, - PRECONFIGURATION_METADATA_INDEX, + PRECONFIGURATION_DELETION_RECORD_SAVED_OBJECT_TYPE, } from '../constants'; import type { PackagePolicy, @@ -585,11 +585,8 @@ class AgentPolicyService { } if (agentPolicy.preconfiguration_id) { - await esClient.index({ - index: PRECONFIGURATION_METADATA_INDEX, - body: { - deleted_preconfiguration_id: String(agentPolicy.preconfiguration_id), - }, + await soClient.create(PRECONFIGURATION_DELETION_RECORD_SAVED_OBJECT_TYPE, { + preconfiguration_id: String(agentPolicy.preconfiguration_id), }); } diff --git a/x-pack/plugins/fleet/server/services/preconfiguration.test.ts b/x-pack/plugins/fleet/server/services/preconfiguration.test.ts index 78b8234ec7c41..8a885f9c5c821 100644 --- a/x-pack/plugins/fleet/server/services/preconfiguration.test.ts +++ b/x-pack/plugins/fleet/server/services/preconfiguration.test.ts @@ -24,19 +24,6 @@ const mockDefaultOutput: Output = { hosts: ['http://127.0.0.1:9201'], }; -const createMockESClient = () => { - const esClient = elasticsearchServiceMock.createInternalClient(); - esClient.search.mockResolvedValue({ - body: { - hits: { - // @ts-ignore - total: 0, - }, - }, - }); - return esClient; -}; - function getPutPreconfiguredPackagesMock() { const soClient = savedObjectsClientMock.create(); soClient.find.mockImplementation(async ({ type, search }) => { @@ -139,7 +126,7 @@ describe('policy preconfiguration', () => { it('should perform a no-op when passed no policies or packages', async () => { const soClient = getPutPreconfiguredPackagesMock(); - const esClient = createMockESClient(); + const esClient = elasticsearchServiceMock.createClusterClient().asInternalUser; const { policies, packages } = await ensurePreconfiguredPackagesAndPolicies( soClient, @@ -155,7 +142,7 @@ describe('policy preconfiguration', () => { it('should install packages successfully', async () => { const soClient = getPutPreconfiguredPackagesMock(); - const esClient = createMockESClient(); + const esClient = elasticsearchServiceMock.createClusterClient().asInternalUser; const { policies, packages } = await ensurePreconfiguredPackagesAndPolicies( soClient, @@ -171,7 +158,7 @@ describe('policy preconfiguration', () => { it('should install packages and configure agent policies successfully', async () => { const soClient = getPutPreconfiguredPackagesMock(); - const esClient = createMockESClient(); + const esClient = elasticsearchServiceMock.createClusterClient().asInternalUser; const { policies, packages } = await ensurePreconfiguredPackagesAndPolicies( soClient, @@ -200,7 +187,7 @@ describe('policy preconfiguration', () => { it('should throw an error when trying to install duplicate packages', async () => { const soClient = getPutPreconfiguredPackagesMock(); - const esClient = createMockESClient(); + const esClient = elasticsearchServiceMock.createClusterClient().asInternalUser; await expect( ensurePreconfiguredPackagesAndPolicies( @@ -220,7 +207,7 @@ describe('policy preconfiguration', () => { it('should not attempt to recreate or modify an agent policy if its ID is unchanged', async () => { const soClient = getPutPreconfiguredPackagesMock(); - const esClient = createMockESClient(); + const esClient = elasticsearchServiceMock.createClusterClient().asInternalUser; const { policies: policiesA } = await ensurePreconfiguredPackagesAndPolicies( soClient, diff --git a/x-pack/plugins/fleet/server/services/preconfiguration.ts b/x-pack/plugins/fleet/server/services/preconfiguration.ts index e49c83f719918..3bd3169673b31 100644 --- a/x-pack/plugins/fleet/server/services/preconfiguration.ts +++ b/x-pack/plugins/fleet/server/services/preconfiguration.ts @@ -19,7 +19,9 @@ import type { PreconfiguredAgentPolicy, PreconfiguredPackage, } from '../../common'; -import { PRECONFIGURATION_METADATA_INDEX } from '../constants'; +import { PRECONFIGURATION_DELETION_RECORD_SAVED_OBJECT_TYPE } from '../constants'; + +import { escapeSearchQueryPhrase } from './saved_object'; import { pkgToPkgKey } from './epm/registry'; import { getInstallation } from './epm/packages'; @@ -70,29 +72,21 @@ export async function ensurePreconfiguredPackagesAndPolicies( // Create policies specified in Kibana config const preconfiguredPolicies = await Promise.all( policies.map(async (preconfiguredAgentPolicy) => { - // Check to see if a preconfigured policy with te same preconfigurationId was already deleted by the user - try { - const preconfigurationId = String(preconfiguredAgentPolicy.preconfiguration_id); - const deletionRecord = await esClient.search({ - index: PRECONFIGURATION_METADATA_INDEX, - body: { - query: { - match: { - deleted_preconfiguration_id: preconfigurationId, - }, - }, - }, - }); - - const { total } = deletionRecord.body.hits; - const wasDeleted = (typeof total === 'number' ? total : total.value) > 0; - if (wasDeleted) { - return { created: false, deleted: preconfigurationId }; - } - } catch (e) { - // If ES failed on an index not found error, ignore it. This means nothing has been deleted yet. - if (e.body.status !== 404) throw e; + // Check to see if a preconfigured policy with the same preconfigurationId was already deleted by the user + const preconfigurationId = String(preconfiguredAgentPolicy.id); + const searchParams = { + searchFields: ['preconfiguration_id'], + search: escapeSearchQueryPhrase(preconfigurationId), + }; + const deletionRecords = await soClient.find({ + type: PRECONFIGURATION_DELETION_RECORD_SAVED_OBJECT_TYPE, + ...searchParams, + }); + const wasDeleted = deletionRecords.total > 0; + if (wasDeleted) { + return { created: false, deleted: preconfigurationId }; } + const { created, policy } = await agentPolicyService.ensurePreconfiguredAgentPolicy( soClient, esClient,