From d9aca86bbcda0a5b7c6e701f0a32f7e919c61658 Mon Sep 17 00:00:00 2001 From: Nicolas Chaulet Date: Tue, 21 May 2024 09:09:44 -0400 Subject: [PATCH 1/5] [Fleet] Support kibana_namespace in preconfiguration --- .../common/types/models/preconfiguration.ts | 1 + .../fleet/server/saved_objects/index.ts | 4 +- .../fleet/server/services/agent_policy.ts | 6 +- .../server/services/preconfiguration.test.ts | 64 +++++++++++++++++++ .../fleet/server/services/preconfiguration.ts | 39 +++++++---- .../server/types/models/preconfiguration.ts | 1 + 6 files changed, 101 insertions(+), 14 deletions(-) diff --git a/x-pack/plugins/fleet/common/types/models/preconfiguration.ts b/x-pack/plugins/fleet/common/types/models/preconfiguration.ts index 8363116bf3bb1..4a0823aa82a93 100644 --- a/x-pack/plugins/fleet/common/types/models/preconfiguration.ts +++ b/x-pack/plugins/fleet/common/types/models/preconfiguration.ts @@ -24,6 +24,7 @@ export type InputsOverride = Partial & { export interface PreconfiguredAgentPolicy extends Omit { id: string | number; + kibana_namespace?: string; namespace?: string; package_policies: Array< | (Partial> & { diff --git a/x-pack/plugins/fleet/server/saved_objects/index.ts b/x-pack/plugins/fleet/server/saved_objects/index.ts index 457711b2646e7..8e058a3a3ff8f 100644 --- a/x-pack/plugins/fleet/server/saved_objects/index.ts +++ b/x-pack/plugins/fleet/server/saved_objects/index.ts @@ -587,7 +587,7 @@ export const getSavedObjectTypes = ( name: PACKAGES_SAVED_OBJECT_TYPE, indexPattern: INGEST_SAVED_OBJECT_INDEX, hidden: false, - namespaceType: useSpaceAwareness ? 'single' : 'agnostic', + namespaceType: 'agnostic', management: { importableAndExportable: false, }, @@ -680,7 +680,7 @@ export const getSavedObjectTypes = ( name: ASSETS_SAVED_OBJECT_TYPE, indexPattern: INGEST_SAVED_OBJECT_INDEX, hidden: false, - namespaceType: useSpaceAwareness ? 'single' : 'agnostic', + namespaceType: 'agnostic', management: { importableAndExportable: false, }, diff --git a/x-pack/plugins/fleet/server/services/agent_policy.ts b/x-pack/plugins/fleet/server/services/agent_policy.ts index afa7b7c5d92de..4eb5f6e348842 100644 --- a/x-pack/plugins/fleet/server/services/agent_policy.ts +++ b/x-pack/plugins/fleet/server/services/agent_policy.ts @@ -195,7 +195,11 @@ class AgentPolicyService { created: boolean; policy?: AgentPolicy; }> { - const { id, ...preconfiguredAgentPolicy } = omit(config, 'package_policies'); + const { + id, + kibana_namespace: kibanaNamespace, + ...preconfiguredAgentPolicy + } = omit(config, 'package_policies'); const newAgentPolicyDefaults: Pick = { namespace: 'default', monitoring_enabled: ['logs', 'metrics'], diff --git a/x-pack/plugins/fleet/server/services/preconfiguration.test.ts b/x-pack/plugins/fleet/server/services/preconfiguration.test.ts index 004d4b83a460a..2c7d1452914fe 100644 --- a/x-pack/plugins/fleet/server/services/preconfiguration.test.ts +++ b/x-pack/plugins/fleet/server/services/preconfiguration.test.ts @@ -306,6 +306,7 @@ jest.mock('./app_context', () => ({ getExperimentalFeatures: jest.fn().mockReturnValue({ agentless: false, }), + getInternalUserSOClientForSpaceId: jest.fn(), }, })); @@ -1124,6 +1125,69 @@ describe('policy preconfiguration', () => { expect(policies[0].id).toBe('test-id'); expect(nonFatalErrorsB.length).toBe(0); }); + + it('should used a namespaced saved objet client if the agent policy kibana_namespace is set', async () => { + const TEST_NAMESPACE = 'test'; + const namespacedSOClient = getPutPreconfiguredPackagesMock(); + const soClient = getPutPreconfiguredPackagesMock(); + const esClient = elasticsearchServiceMock.createClusterClient().asInternalUser; + + jest + .mocked(appContextService) + .getInternalUserSOClientForSpaceId.mockReturnValue(namespacedSOClient); + + await ensurePreconfiguredPackagesAndPolicies( + soClient, + esClient, + [ + { + name: 'Test policy', + namespace: 'default', + id: 'test-id', + kibana_namespace: TEST_NAMESPACE, + is_managed: true, + package_policies: [ + { + package: { name: 'test_package' }, + name: 'test_package1', + }, + ], + }, + ] as PreconfiguredAgentPolicy[], + [{ name: 'test_package', version: '3.0.0' }], + mockDefaultOutput, + mockDefaultDownloadService, + DEFAULT_SPACE_ID + ); + + jest.mocked(appContextService.getExperimentalFeatures).mockReturnValue({ + agentless: true, + } as any); + + expect(appContextService.getInternalUserSOClientForSpaceId).toBeCalledTimes(1); + expect(appContextService.getInternalUserSOClientForSpaceId).toBeCalledWith(TEST_NAMESPACE); + + expect(mockedPackagePolicyService.create).toBeCalledTimes(1); + expect(mockedPackagePolicyService.create).toBeCalledWith( + namespacedSOClient, // namespaced so client + expect.anything(), // es client + expect.objectContaining({ + name: 'test_package1', + }), + expect.anything() // options + ); + + expect(spyAgentPolicyServiceUpdate).toBeCalledTimes(1); + expect(spyAgentPolicyServiceUpdate).toBeCalledWith( + namespacedSOClient, // namespaced so client + expect.anything(), // es client + expect.anything(), // id + expect.objectContaining({ + is_managed: true, + }), + expect.anything() // options + ); + }); }); describe('with bundled packages', () => { diff --git a/x-pack/plugins/fleet/server/services/preconfiguration.ts b/x-pack/plugins/fleet/server/services/preconfiguration.ts index 26f633cc8f021..3e61e0ba65459 100644 --- a/x-pack/plugins/fleet/server/services/preconfiguration.ts +++ b/x-pack/plugins/fleet/server/services/preconfiguration.ts @@ -174,14 +174,20 @@ export async function ensurePreconfiguredPackagesAndPolicies( ); } + const namespacedSoClient = preconfiguredAgentPolicy.kibana_namespace + ? appContextService.getInternalUserSOClientForSpaceId( + preconfiguredAgentPolicy.kibana_namespace + ) + : soClient; + const { created, policy } = await agentPolicyService.ensurePreconfiguredAgentPolicy( - soClient, + namespacedSoClient, esClient, - omit(preconfiguredAgentPolicy, 'is_managed') // Don't add `is_managed` until the policy has been fully configured + omit(preconfiguredAgentPolicy, 'is_managed', 'kibana_namespace') // Don't add `is_managed` until the policy has been fully configured ); if (!created) { - if (!policy) return { created, policy }; + if (!policy) return { created, policy, namespacedSoClient }; if (!policy.is_managed && !preconfiguredAgentPolicy.is_managed) return { created, policy }; const { hasChanged, fields } = comparePreconfiguredPolicyToCurrent( preconfiguredAgentPolicy, @@ -194,7 +200,7 @@ export async function ensurePreconfiguredPackagesAndPolicies( }; if (hasChanged) { const updatedPolicy = await agentPolicyService.update( - soClient, + namespacedSoClient, esClient, String(preconfiguredAgentPolicy.id), newFields, @@ -202,14 +208,15 @@ export async function ensurePreconfiguredPackagesAndPolicies( force: true, } ); - return { created, policy: updatedPolicy }; + return { created, policy: updatedPolicy, namespacedSoClient }; } - return { created, policy }; + return { created, policy, namespacedSoClient }; } return { created, policy, + namespacedSoClient, shouldAddIsManagedFlag: preconfiguredAgentPolicy.is_managed, }; }) @@ -227,13 +234,17 @@ export async function ensurePreconfiguredPackagesAndPolicies( continue; } fulfilledPolicies.push(policyResult.value); - const { created, policy, shouldAddIsManagedFlag } = policyResult.value; + const { created, policy, shouldAddIsManagedFlag, namespacedSoClient } = policyResult.value; + if (created || policies[i].is_managed) { + if (!namespacedSoClient) { + throw new Error('No soClient created for that policy'); + } const preconfiguredAgentPolicy = policies[i]; const { package_policies: packagePolicies } = preconfiguredAgentPolicy; const agentPolicyWithPackagePolicies = await agentPolicyService.get( - soClient, + namespacedSoClient, policy!.id, true ); @@ -287,7 +298,7 @@ export async function ensurePreconfiguredPackagesAndPolicies( logger.debug(`Adding preconfigured package policies ${packagePoliciesToAdd}`); const s = apm.startSpan('Add preconfigured package policies', 'preconfiguration'); await addPreconfiguredPolicyPackages( - soClient, + namespacedSoClient, esClient, policy!, packagePoliciesToAdd!, @@ -299,7 +310,7 @@ export async function ensurePreconfiguredPackagesAndPolicies( // Add the is_managed flag after configuring package policies to avoid errors if (shouldAddIsManagedFlag) { await agentPolicyService.update( - soClient, + namespacedSoClient, esClient, policy!.id, { is_managed: true }, @@ -338,7 +349,13 @@ export function comparePreconfiguredPolicyToCurrent( ) { // Namespace is omitted from being compared because even for managed policies, we still // want users to be able to pick their own namespace: https://github.com/elastic/kibana/issues/110533 - const configTopLevelFields = omit(policyFromConfig, 'package_policies', 'id', 'namespace'); + const configTopLevelFields = omit( + policyFromConfig, + 'package_policies', + 'id', + 'namespace', + 'kibana_namespace' + ); const currentTopLevelFields = pick(currentPolicy, ...Object.keys(configTopLevelFields)); return { diff --git a/x-pack/plugins/fleet/server/types/models/preconfiguration.ts b/x-pack/plugins/fleet/server/types/models/preconfiguration.ts index ce8fb7df3937d..297702e7c8b15 100644 --- a/x-pack/plugins/fleet/server/types/models/preconfiguration.ts +++ b/x-pack/plugins/fleet/server/types/models/preconfiguration.ts @@ -134,6 +134,7 @@ export const PreconfiguredFleetProxiesSchema = schema.arrayOf( export const PreconfiguredAgentPoliciesSchema = schema.arrayOf( schema.object({ ...AgentPolicyBaseSchema, + kibana_namespace: schema.maybe(schema.string()), namespace: schema.maybe(AgentPolicyNamespaceSchema), id: schema.maybe(schema.oneOf([schema.string(), schema.number()])), is_default: schema.maybe(schema.boolean()), From 7fbd0091766ba9e17869bcdaa740a40c0ccf85c0 Mon Sep 17 00:00:00 2001 From: Nicolas Chaulet Date: Tue, 21 May 2024 12:56:28 -0400 Subject: [PATCH 2/5] Rename kibana_namespace => space_id --- .../fleet/common/types/models/preconfiguration.ts | 2 +- x-pack/plugins/fleet/server/services/agent_policy.ts | 2 +- .../fleet/server/services/preconfiguration.test.ts | 4 ++-- .../plugins/fleet/server/services/preconfiguration.ts | 10 ++++------ .../fleet/server/types/models/preconfiguration.ts | 2 +- 5 files changed, 9 insertions(+), 11 deletions(-) diff --git a/x-pack/plugins/fleet/common/types/models/preconfiguration.ts b/x-pack/plugins/fleet/common/types/models/preconfiguration.ts index 4a0823aa82a93..14d9bbed5513c 100644 --- a/x-pack/plugins/fleet/common/types/models/preconfiguration.ts +++ b/x-pack/plugins/fleet/common/types/models/preconfiguration.ts @@ -24,7 +24,7 @@ export type InputsOverride = Partial & { export interface PreconfiguredAgentPolicy extends Omit { id: string | number; - kibana_namespace?: string; + space_id?: string; namespace?: string; package_policies: Array< | (Partial> & { diff --git a/x-pack/plugins/fleet/server/services/agent_policy.ts b/x-pack/plugins/fleet/server/services/agent_policy.ts index 4eb5f6e348842..95de0d05e86b9 100644 --- a/x-pack/plugins/fleet/server/services/agent_policy.ts +++ b/x-pack/plugins/fleet/server/services/agent_policy.ts @@ -197,7 +197,7 @@ class AgentPolicyService { }> { const { id, - kibana_namespace: kibanaNamespace, + space_id: kibanaSpaceId, ...preconfiguredAgentPolicy } = omit(config, 'package_policies'); const newAgentPolicyDefaults: Pick = { diff --git a/x-pack/plugins/fleet/server/services/preconfiguration.test.ts b/x-pack/plugins/fleet/server/services/preconfiguration.test.ts index 2c7d1452914fe..f4e6eab5374c0 100644 --- a/x-pack/plugins/fleet/server/services/preconfiguration.test.ts +++ b/x-pack/plugins/fleet/server/services/preconfiguration.test.ts @@ -1126,7 +1126,7 @@ describe('policy preconfiguration', () => { expect(nonFatalErrorsB.length).toBe(0); }); - it('should used a namespaced saved objet client if the agent policy kibana_namespace is set', async () => { + it('should used a namespaced saved objet client if the agent policy space_id is set', async () => { const TEST_NAMESPACE = 'test'; const namespacedSOClient = getPutPreconfiguredPackagesMock(); const soClient = getPutPreconfiguredPackagesMock(); @@ -1144,7 +1144,7 @@ describe('policy preconfiguration', () => { name: 'Test policy', namespace: 'default', id: 'test-id', - kibana_namespace: TEST_NAMESPACE, + space_id: TEST_NAMESPACE, is_managed: true, package_policies: [ { diff --git a/x-pack/plugins/fleet/server/services/preconfiguration.ts b/x-pack/plugins/fleet/server/services/preconfiguration.ts index 3e61e0ba65459..bfc6a07d073ca 100644 --- a/x-pack/plugins/fleet/server/services/preconfiguration.ts +++ b/x-pack/plugins/fleet/server/services/preconfiguration.ts @@ -174,16 +174,14 @@ export async function ensurePreconfiguredPackagesAndPolicies( ); } - const namespacedSoClient = preconfiguredAgentPolicy.kibana_namespace - ? appContextService.getInternalUserSOClientForSpaceId( - preconfiguredAgentPolicy.kibana_namespace - ) + const namespacedSoClient = preconfiguredAgentPolicy.space_id + ? appContextService.getInternalUserSOClientForSpaceId(preconfiguredAgentPolicy.space_id) : soClient; const { created, policy } = await agentPolicyService.ensurePreconfiguredAgentPolicy( namespacedSoClient, esClient, - omit(preconfiguredAgentPolicy, 'is_managed', 'kibana_namespace') // Don't add `is_managed` until the policy has been fully configured + omit(preconfiguredAgentPolicy, 'is_managed', 'space_id') // Don't add `is_managed` until the policy has been fully configured ); if (!created) { @@ -354,7 +352,7 @@ export function comparePreconfiguredPolicyToCurrent( 'package_policies', 'id', 'namespace', - 'kibana_namespace' + 'space_id' ); const currentTopLevelFields = pick(currentPolicy, ...Object.keys(configTopLevelFields)); diff --git a/x-pack/plugins/fleet/server/types/models/preconfiguration.ts b/x-pack/plugins/fleet/server/types/models/preconfiguration.ts index 297702e7c8b15..090d74b38a412 100644 --- a/x-pack/plugins/fleet/server/types/models/preconfiguration.ts +++ b/x-pack/plugins/fleet/server/types/models/preconfiguration.ts @@ -134,7 +134,7 @@ export const PreconfiguredFleetProxiesSchema = schema.arrayOf( export const PreconfiguredAgentPoliciesSchema = schema.arrayOf( schema.object({ ...AgentPolicyBaseSchema, - kibana_namespace: schema.maybe(schema.string()), + space_id: schema.maybe(schema.string()), namespace: schema.maybe(AgentPolicyNamespaceSchema), id: schema.maybe(schema.oneOf([schema.string(), schema.number()])), is_default: schema.maybe(schema.boolean()), From 69009c9be1fb42599a9031e8297d14f8eb84637f Mon Sep 17 00:00:00 2001 From: Nicolas Chaulet Date: Tue, 21 May 2024 14:58:18 -0400 Subject: [PATCH 3/5] Refacto better variables names --- .../fleet/server/services/preconfiguration.ts | 27 ++++++++++--------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/x-pack/plugins/fleet/server/services/preconfiguration.ts b/x-pack/plugins/fleet/server/services/preconfiguration.ts index bfc6a07d073ca..7498dfdd6c420 100644 --- a/x-pack/plugins/fleet/server/services/preconfiguration.ts +++ b/x-pack/plugins/fleet/server/services/preconfiguration.ts @@ -50,7 +50,7 @@ interface PreconfigurationResult { } export async function ensurePreconfiguredPackagesAndPolicies( - soClient: SavedObjectsClientContract, + defaultSoClient: SavedObjectsClientContract, esClient: ElasticsearchClient, policies: PreconfiguredAgentPolicy[] = [], packages: PreconfiguredPackage[] = [], @@ -96,7 +96,7 @@ export async function ensurePreconfiguredPackagesAndPolicies( // Preinstall packages specified in Kibana config const preconfiguredPackages = await bulkInstallPackages({ - savedObjectsClient: soClient, + savedObjectsClient: defaultSoClient, esClient, packagesToInstall, force: true, // Always force outdated packages to be installed if a later version isn't installed @@ -127,7 +127,7 @@ export async function ensurePreconfiguredPackagesAndPolicies( // will occur between upgrading the package and reinstalling the previously failed package. // By moving this outside of the Promise.all, the upgrade will occur first, and then we'll attempt to reinstall any // packages that are stuck in the installing state. - await ensurePackagesCompletedInstall(soClient, esClient); + await ensurePackagesCompletedInstall(defaultSoClient, esClient); // Create policies specified in Kibana config logger.debug(`Creating preconfigured policies`); @@ -140,7 +140,7 @@ export async function ensurePreconfiguredPackagesAndPolicies( searchFields: ['id'], search: escapeSearchQueryPhrase(preconfigurationId), }; - const deletionRecords = await soClient.find({ + const deletionRecords = await defaultSoClient.find({ type: PRECONFIGURATION_DELETION_RECORD_SAVED_OBJECT_TYPE, ...searchParams, }); @@ -176,7 +176,7 @@ export async function ensurePreconfiguredPackagesAndPolicies( const namespacedSoClient = preconfiguredAgentPolicy.space_id ? appContextService.getInternalUserSOClientForSpaceId(preconfiguredAgentPolicy.space_id) - : soClient; + : defaultSoClient; const { created, policy } = await agentPolicyService.ensurePreconfiguredAgentPolicy( namespacedSoClient, @@ -250,7 +250,7 @@ export async function ensurePreconfiguredPackagesAndPolicies( packagePolicies.map(async (preconfiguredPackagePolicy) => { const { package: pkg, ...newPackagePolicy } = preconfiguredPackagePolicy; const installedPackage = await getInstallation({ - savedObjectsClient: soClient, + savedObjectsClient: defaultSoClient, pkgName: pkg.name, }); if (!installedPackage) { @@ -281,7 +281,7 @@ export async function ensurePreconfiguredPackagesAndPolicies( }) ); } - return { installedPackage, packagePolicy: newPackagePolicy }; + return { installedPackage, packagePolicy: newPackagePolicy, namespacedSoClient }; }) ); @@ -296,7 +296,7 @@ export async function ensurePreconfiguredPackagesAndPolicies( logger.debug(`Adding preconfigured package policies ${packagePoliciesToAdd}`); const s = apm.startSpan('Add preconfigured package policies', 'preconfiguration'); await addPreconfiguredPolicyPackages( - namespacedSoClient, + defaultSoClient, esClient, policy!, packagePoliciesToAdd!, @@ -363,11 +363,12 @@ export function comparePreconfiguredPolicyToCurrent( } async function addPreconfiguredPolicyPackages( - soClient: SavedObjectsClientContract, + defaultSoClient: SavedObjectsClientContract, esClient: ElasticsearchClient, agentPolicy: AgentPolicy, installedPackagePolicies: Array<{ installedPackage: Installation; + namespacedSoClient: SavedObjectsClientContract; packagePolicy: | (Partial> & { id?: string | number; @@ -384,13 +385,13 @@ async function addPreconfiguredPolicyPackages( const packageInfoMap = new Map(); // Add packages synchronously to avoid overwriting - for (const { installedPackage, packagePolicy } of installedPackagePolicies) { + for (const { installedPackage, packagePolicy, namespacedSoClient } of installedPackagePolicies) { let packageInfo: PackageInfo; if (packageInfoMap.has(installedPackage.name)) { packageInfo = packageInfoMap.get(installedPackage.name)!; } else { packageInfo = await getPackageInfo({ - savedObjectsClient: soClient, + savedObjectsClient: defaultSoClient, pkgName: installedPackage.name, pkgVersion: installedPackage.version, }); @@ -399,7 +400,7 @@ async function addPreconfiguredPolicyPackages( if (Array.isArray(packagePolicy.inputs)) { const { id, name, description, inputs } = packagePolicy; await addPackageToAgentPolicy( - soClient, + namespacedSoClient, esClient, agentPolicy, packageInfo, @@ -424,7 +425,7 @@ async function addPreconfiguredPolicyPackages( {} ); - await packagePolicyService.create(soClient, esClient, newPackagePolicy, { + await packagePolicyService.create(namespacedSoClient, esClient, newPackagePolicy, { id, bumpRevision: bumpAgentPolicyRevison, skipEnsureInstalled: true, From 50c56990729c24e12d33800a3a6eb84687b36eac Mon Sep 17 00:00:00 2001 From: Nicolas Chaulet Date: Tue, 21 May 2024 15:47:27 -0400 Subject: [PATCH 4/5] remove unsued parameter --- x-pack/plugins/fleet/server/services/preconfiguration.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/x-pack/plugins/fleet/server/services/preconfiguration.ts b/x-pack/plugins/fleet/server/services/preconfiguration.ts index 7498dfdd6c420..15a24eb2c7d92 100644 --- a/x-pack/plugins/fleet/server/services/preconfiguration.ts +++ b/x-pack/plugins/fleet/server/services/preconfiguration.ts @@ -296,7 +296,6 @@ export async function ensurePreconfiguredPackagesAndPolicies( logger.debug(`Adding preconfigured package policies ${packagePoliciesToAdd}`); const s = apm.startSpan('Add preconfigured package policies', 'preconfiguration'); await addPreconfiguredPolicyPackages( - defaultSoClient, esClient, policy!, packagePoliciesToAdd!, @@ -363,7 +362,6 @@ export function comparePreconfiguredPolicyToCurrent( } async function addPreconfiguredPolicyPackages( - defaultSoClient: SavedObjectsClientContract, esClient: ElasticsearchClient, agentPolicy: AgentPolicy, installedPackagePolicies: Array<{ @@ -391,7 +389,7 @@ async function addPreconfiguredPolicyPackages( packageInfo = packageInfoMap.get(installedPackage.name)!; } else { packageInfo = await getPackageInfo({ - savedObjectsClient: defaultSoClient, + savedObjectsClient: namespacedSoClient, pkgName: installedPackage.name, pkgVersion: installedPackage.version, }); From f530ab56117874c8a6588bba536e0edf56b6e3e5 Mon Sep 17 00:00:00 2001 From: Nicolas Chaulet Date: Wed, 22 May 2024 08:12:17 -0400 Subject: [PATCH 5/5] fix after review --- x-pack/plugins/fleet/server/services/preconfiguration.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugins/fleet/server/services/preconfiguration.ts b/x-pack/plugins/fleet/server/services/preconfiguration.ts index 15a24eb2c7d92..04df94d89b636 100644 --- a/x-pack/plugins/fleet/server/services/preconfiguration.ts +++ b/x-pack/plugins/fleet/server/services/preconfiguration.ts @@ -181,7 +181,7 @@ export async function ensurePreconfiguredPackagesAndPolicies( const { created, policy } = await agentPolicyService.ensurePreconfiguredAgentPolicy( namespacedSoClient, esClient, - omit(preconfiguredAgentPolicy, 'is_managed', 'space_id') // Don't add `is_managed` until the policy has been fully configured + omit(preconfiguredAgentPolicy, 'is_managed', 'space_id') // Don't add `is_managed` until the policy has been fully configured and not persist space_id ); if (!created) {