From e43a2acc6e7bd45e1596395670a607f9ce06a142 Mon Sep 17 00:00:00 2001 From: Nicolas Chaulet Date: Mon, 29 Nov 2021 14:13:06 -0500 Subject: [PATCH 1/3] [Fleet] Fix preconfiguration variable values (#119749) # Conflicts: # x-pack/plugins/fleet/server/services/preconfiguration.ts --- .../server/services/package_policy.test.ts | 786 +++++++++++++++++- .../fleet/server/services/package_policy.ts | 157 +++- .../fleet/server/services/preconfiguration.ts | 5 +- 3 files changed, 910 insertions(+), 38 deletions(-) diff --git a/x-pack/plugins/fleet/server/services/package_policy.test.ts b/x-pack/plugins/fleet/server/services/package_policy.test.ts index b6207316829ee..7e061349c57dd 100644 --- a/x-pack/plugins/fleet/server/services/package_policy.test.ts +++ b/x-pack/plugins/fleet/server/services/package_policy.test.ts @@ -39,7 +39,8 @@ import type { import { IngestManagerError } from '../errors'; import { - overridePackageInputs, + preconfigurePackageInputs, + updatePackageInputs, packagePolicyService, _applyIndexPrivileges, } from './package_policy'; @@ -1164,7 +1165,776 @@ describe('Package policy service', () => { }); }); - describe('overridePackageInputs', () => { + describe('preconfigurePackageInputs', () => { + describe('when variable is already defined', () => { + it('override original variable value', () => { + const basePackagePolicy: NewPackagePolicy = { + name: 'base-package-policy', + description: 'Base Package Policy', + namespace: 'default', + enabled: true, + policy_id: 'xxxx', + output_id: 'xxxx', + package: { + name: 'test-package', + title: 'Test Package', + version: '0.0.1', + }, + inputs: [ + { + type: 'logs', + policy_template: 'template_1', + enabled: true, + vars: { + path: { + type: 'text', + value: ['/var/log/logfile.log'], + }, + }, + streams: [], + }, + ], + }; + + const packageInfo: PackageInfo = { + name: 'test-package', + description: 'Test Package', + title: 'Test Package', + version: '0.0.1', + latestVersion: '0.0.1', + release: 'experimental', + format_version: '1.0.0', + owner: { github: 'elastic/fleet' }, + policy_templates: [ + { + name: 'template_1', + title: 'Template 1', + description: 'Template 1', + inputs: [ + { + type: 'logs', + title: 'Log', + description: 'Log Input', + vars: [ + { + name: 'path', + type: 'text', + }, + ], + }, + ], + }, + ], + // @ts-ignore + assets: {}, + }; + + const inputsOverride: NewPackagePolicyInput[] = [ + { + type: 'logs', + enabled: true, + streams: [], + vars: { + path: { + type: 'text', + value: '/var/log/new-logfile.log', + }, + }, + }, + ]; + + const result = preconfigurePackageInputs( + basePackagePolicy, + packageInfo, + // TODO: Update this type assertion when the `InputsOverride` type is updated such + // that it no longer causes unresolvable type errors when used directly + inputsOverride as InputsOverride[] + ); + expect(result.inputs[0]?.vars?.path.value).toEqual('/var/log/new-logfile.log'); + }); + }); + + describe('when variable is undefined in original object', () => { + it('adds the variable definition to the resulting object', () => { + const basePackagePolicy: NewPackagePolicy = { + name: 'base-package-policy', + description: 'Base Package Policy', + namespace: 'default', + enabled: true, + policy_id: 'xxxx', + output_id: 'xxxx', + package: { + name: 'test-package', + title: 'Test Package', + version: '0.0.1', + }, + inputs: [ + { + type: 'logs', + policy_template: 'template_1', + enabled: true, + vars: { + path: { + type: 'text', + value: ['/var/log/logfile.log'], + }, + }, + streams: [], + }, + ], + }; + + const packageInfo: PackageInfo = { + name: 'test-package', + description: 'Test Package', + title: 'Test Package', + version: '0.0.1', + latestVersion: '0.0.1', + release: 'experimental', + format_version: '1.0.0', + owner: { github: 'elastic/fleet' }, + policy_templates: [ + { + name: 'template_1', + title: 'Template 1', + description: 'Template 1', + inputs: [ + { + type: 'logs', + title: 'Log', + description: 'Log Input', + vars: [ + { + name: 'path', + type: 'text', + }, + { + name: 'path_2', + type: 'text', + }, + ], + }, + ], + }, + ], + // @ts-ignore + assets: {}, + }; + + const inputsOverride: NewPackagePolicyInput[] = [ + { + type: 'logs', + enabled: true, + streams: [], + policy_template: 'template_1', + vars: { + path: { + type: 'text', + value: '/var/log/new-logfile.log', + }, + path_2: { + type: 'text', + value: '/var/log/custom.log', + }, + }, + }, + ]; + + const result = preconfigurePackageInputs( + basePackagePolicy, + packageInfo, + // TODO: Update this type assertion when the `InputsOverride` type is updated such + // that it no longer causes unresolvable type errors when used directly + inputsOverride as InputsOverride[] + ); + + expect(result.inputs[0]?.vars?.path_2.value).toEqual('/var/log/custom.log'); + }); + }); + + describe('when variable is undefined in original object and policy_template is undefined', () => { + it('adds the variable definition to the resulting object', () => { + const basePackagePolicy: NewPackagePolicy = { + name: 'base-package-policy', + description: 'Base Package Policy', + namespace: 'default', + enabled: true, + policy_id: 'xxxx', + output_id: 'xxxx', + package: { + name: 'test-package', + title: 'Test Package', + version: '0.0.1', + }, + inputs: [ + { + type: 'logs', + policy_template: 'template_1', + enabled: true, + vars: { + path: { + type: 'text', + value: ['/var/log/logfile.log'], + }, + }, + streams: [], + }, + ], + }; + + const packageInfo: PackageInfo = { + name: 'test-package', + description: 'Test Package', + title: 'Test Package', + version: '0.0.1', + latestVersion: '0.0.1', + release: 'experimental', + format_version: '1.0.0', + owner: { github: 'elastic/fleet' }, + policy_templates: [ + { + name: 'template_1', + title: 'Template 1', + description: 'Template 1', + inputs: [ + { + type: 'logs', + title: 'Log', + description: 'Log Input', + vars: [ + { + name: 'path', + type: 'text', + }, + { + name: 'path_2', + type: 'text', + }, + ], + }, + ], + }, + ], + // @ts-ignore + assets: {}, + }; + + const inputsOverride: NewPackagePolicyInput[] = [ + { + type: 'logs', + enabled: true, + streams: [], + policy_template: undefined, // preconfigured input overrides don't have a policy_template + vars: { + path: { + type: 'text', + value: '/var/log/new-logfile.log', + }, + path_2: { + type: 'text', + value: '/var/log/custom.log', + }, + }, + }, + ]; + + const result = preconfigurePackageInputs( + basePackagePolicy, + packageInfo, + // TODO: Update this type assertion when the `InputsOverride` type is updated such + // that it no longer causes unresolvable type errors when used directly + inputsOverride as InputsOverride[] + ); + + expect(result.inputs[0]?.vars?.path_2.value).toEqual('/var/log/custom.log'); + }); + }); + + describe('when an input of the same type exists under multiple policy templates', () => { + it('adds variable definitions to the proper streams', () => { + const basePackagePolicy: NewPackagePolicy = { + name: 'base-package-policy', + description: 'Base Package Policy', + namespace: 'default', + enabled: true, + policy_id: 'xxxx', + output_id: 'xxxx', + package: { + name: 'test-package', + title: 'Test Package', + version: '0.0.1', + }, + inputs: [ + { + type: 'logs', + policy_template: 'template_1', + enabled: true, + streams: [ + { + enabled: true, + data_stream: { + dataset: 'test.logs', + type: 'logfile', + }, + vars: { + log_file_path: { + type: 'text', + }, + }, + }, + ], + }, + { + type: 'logs', + policy_template: 'template_2', + enabled: true, + streams: [ + { + enabled: true, + data_stream: { + dataset: 'test.logs', + type: 'logfile', + }, + vars: { + log_file_path: { + type: 'text', + }, + }, + }, + ], + }, + ], + }; + + const packageInfo: PackageInfo = { + name: 'test-package', + description: 'Test Package', + title: 'Test Package', + version: '0.0.1', + latestVersion: '0.0.1', + release: 'experimental', + format_version: '1.0.0', + owner: { github: 'elastic/fleet' }, + policy_templates: [ + { + name: 'template_1', + title: 'Template 1', + description: 'Template 1', + inputs: [ + { + type: 'logs', + title: 'Log', + description: 'Log Input', + vars: [], + }, + ], + }, + { + name: 'template_2', + title: 'Template 2', + description: 'Template 2', + inputs: [ + { + type: 'logs', + title: 'Log', + description: 'Log Input', + vars: [], + }, + ], + }, + ], + // @ts-ignore + assets: {}, + }; + + const inputsOverride: NewPackagePolicyInput[] = [ + { + type: 'logs', + enabled: true, + policy_template: 'template_1', + streams: [ + { + enabled: true, + data_stream: { + dataset: 'test.logs', + type: 'logfile', + }, + vars: { + log_file_path: { + type: 'text', + value: '/var/log/template1-logfile.log', + }, + }, + }, + ], + }, + { + type: 'logs', + enabled: true, + policy_template: 'template_2', + streams: [ + { + enabled: true, + data_stream: { + dataset: 'test.logs', + type: 'logfile', + }, + vars: { + log_file_path: { + type: 'text', + value: '/var/log/template2-logfile.log', + }, + }, + }, + ], + }, + ]; + + const result = preconfigurePackageInputs( + basePackagePolicy, + packageInfo, + // TODO: Update this type assertion when the `InputsOverride` type is updated such + // that it no longer causes unresolvable type errors when used directly + inputsOverride as InputsOverride[] + ); + + expect(result.inputs).toHaveLength(2); + + const template1Input = result.inputs.find( + (input) => input.policy_template === 'template_1' + ); + const template2Input = result.inputs.find( + (input) => input.policy_template === 'template_2' + ); + + expect(template1Input).toBeDefined(); + expect(template2Input).toBeDefined(); + + expect(template1Input?.streams[0].vars?.log_file_path.value).toBe( + '/var/log/template1-logfile.log' + ); + + expect(template2Input?.streams[0].vars?.log_file_path.value).toBe( + '/var/log/template2-logfile.log' + ); + }); + }); + + describe('when an input or stream is disabled on the original policy object', () => { + it('remains disabled on the resulting policy object', () => { + const basePackagePolicy: NewPackagePolicy = { + name: 'base-package-policy', + description: 'Base Package Policy', + namespace: 'default', + enabled: true, + policy_id: 'xxxx', + output_id: 'xxxx', + package: { + name: 'test-package', + title: 'Test Package', + version: '0.0.1', + }, + inputs: [ + { + type: 'logs', + policy_template: 'template_1', + enabled: false, + streams: [ + { + enabled: false, + data_stream: { + dataset: 'test.logs', + type: 'logfile', + }, + vars: { + log_file_path: { + type: 'text', + }, + }, + }, + { + enabled: true, + data_stream: { + dataset: 'test.logs', + type: 'logfile2', + }, + vars: { + log_file_path_2: { + type: 'text', + }, + }, + }, + ], + }, + { + type: 'logs_2', + policy_template: 'template_1', + enabled: true, + streams: [ + { + enabled: true, + data_stream: { + dataset: 'test.logs', + type: 'logfile', + }, + vars: { + log_file_path: { + type: 'text', + }, + }, + }, + ], + }, + { + type: 'logs', + policy_template: 'template_2', + enabled: true, + streams: [ + { + enabled: true, + data_stream: { + dataset: 'test.logs', + type: 'logfile', + }, + vars: { + log_file_path: { + type: 'text', + }, + }, + }, + ], + }, + ], + }; + + const packageInfo: PackageInfo = { + name: 'test-package', + description: 'Test Package', + title: 'Test Package', + version: '0.0.1', + latestVersion: '0.0.1', + release: 'experimental', + format_version: '1.0.0', + owner: { github: 'elastic/fleet' }, + policy_templates: [ + { + name: 'template_1', + title: 'Template 1', + description: 'Template 1', + inputs: [ + { + type: 'logs', + title: 'Log', + description: 'Log Input', + vars: [], + }, + { + type: 'logs_2', + title: 'Log 2', + description: 'Log Input 2', + vars: [], + }, + ], + }, + { + name: 'template_2', + title: 'Template 2', + description: 'Template 2', + inputs: [ + { + type: 'logs', + title: 'Log', + description: 'Log Input', + vars: [], + }, + ], + }, + ], + // @ts-ignore + assets: {}, + }; + + const inputsOverride: NewPackagePolicyInput[] = [ + { + type: 'logs', + enabled: true, + policy_template: 'template_1', + streams: [ + { + enabled: true, + data_stream: { + dataset: 'test.logs', + type: 'logfile', + }, + vars: { + log_file_path: { + type: 'text', + value: '/var/log/template1-logfile.log', + }, + }, + }, + { + enabled: true, + data_stream: { + dataset: 'test.logs', + type: 'logfile2', + }, + vars: { + log_file_path_2: { + type: 'text', + value: '/var/log/template1-logfile2.log', + }, + }, + }, + ], + }, + { + type: 'logs', + enabled: true, + policy_template: 'template_2', + streams: [ + { + enabled: true, + data_stream: { + dataset: 'test.logs', + type: 'logfile', + }, + vars: { + log_file_path: { + type: 'text', + value: '/var/log/template2-logfile.log', + }, + }, + }, + ], + }, + ]; + + const result = preconfigurePackageInputs( + basePackagePolicy, + packageInfo, + // TODO: Update this type assertion when the `InputsOverride` type is updated such + // that it no longer causes unresolvable type errors when used directly + inputsOverride as InputsOverride[] + ); + + const template1Inputs = result.inputs.filter( + (input) => input.policy_template === 'template_1' + ); + + const template2Inputs = result.inputs.filter( + (input) => input.policy_template === 'template_2' + ); + + expect(template1Inputs).toHaveLength(2); + expect(template2Inputs).toHaveLength(1); + + const logsInput = template1Inputs?.find((input) => input.type === 'logs'); + expect(logsInput?.enabled).toBe(false); + + const logfileStream = logsInput?.streams.find( + (stream) => stream.data_stream.type === 'logfile' + ); + + expect(logfileStream?.enabled).toBe(false); + }); + }); + + describe('when a datastream is deleted from an input', () => { + it('it remove the non existing datastream', () => { + const basePackagePolicy: NewPackagePolicy = { + name: 'base-package-policy', + description: 'Base Package Policy', + namespace: 'default', + enabled: true, + policy_id: 'xxxx', + output_id: 'xxxx', + package: { + name: 'test-package', + title: 'Test Package', + version: '0.0.1', + }, + inputs: [ + { + type: 'logs', + policy_template: 'template_1', + enabled: true, + vars: { + path: { + type: 'text', + value: ['/var/log/logfile.log'], + }, + }, + streams: [ + { + enabled: true, + data_stream: { dataset: 'dataset.test123', type: 'log' }, + }, + ], + }, + ], + }; + + const packageInfo: PackageInfo = { + name: 'test-package', + description: 'Test Package', + title: 'Test Package', + version: '0.0.1', + latestVersion: '0.0.1', + release: 'experimental', + format_version: '1.0.0', + owner: { github: 'elastic/fleet' }, + policy_templates: [ + { + name: 'template_1', + title: 'Template 1', + description: 'Template 1', + inputs: [ + { + type: 'logs', + title: 'Log', + description: 'Log Input', + vars: [ + { + name: 'path', + type: 'text', + }, + ], + }, + ], + }, + ], + // @ts-ignore + assets: {}, + }; + + const inputsOverride: NewPackagePolicyInput[] = [ + { + type: 'logs', + enabled: true, + streams: [], + vars: { + path: { + type: 'text', + value: '/var/log/new-logfile.log', + }, + }, + }, + ]; + + const result = preconfigurePackageInputs( + basePackagePolicy, + packageInfo, + // TODO: Update this type assertion when the `InputsOverride` type is updated such + // that it no longer causes unresolvable type errors when used directly + inputsOverride as InputsOverride[] + ); + expect(result.inputs[0]?.vars?.path.value).toEqual('/var/log/new-logfile.log'); + }); + }); + }); + + describe('updatePackageInputs', () => { describe('when variable is already defined', () => { it('preserves original variable value without overwriting', () => { const basePackagePolicy: NewPackagePolicy = { @@ -1242,7 +2012,7 @@ describe('Package policy service', () => { }, ]; - const result = overridePackageInputs( + const result = updatePackageInputs( basePackagePolicy, packageInfo, // TODO: Update this type assertion when the `InputsOverride` type is updated such @@ -1340,7 +2110,7 @@ describe('Package policy service', () => { }, ]; - const result = overridePackageInputs( + const result = updatePackageInputs( basePackagePolicy, packageInfo, // TODO: Update this type assertion when the `InputsOverride` type is updated such @@ -1439,7 +2209,7 @@ describe('Package policy service', () => { }, ]; - const result = overridePackageInputs( + const result = updatePackageInputs( basePackagePolicy, packageInfo, // TODO: Update this type assertion when the `InputsOverride` type is updated such @@ -1592,7 +2362,7 @@ describe('Package policy service', () => { }, ]; - const result = overridePackageInputs( + const result = updatePackageInputs( basePackagePolicy, packageInfo, // TODO: Update this type assertion when the `InputsOverride` type is updated such @@ -1813,7 +2583,7 @@ describe('Package policy service', () => { }, ]; - const result = overridePackageInputs( + const result = updatePackageInputs( basePackagePolicy, packageInfo, // TODO: Update this type assertion when the `InputsOverride` type is updated such @@ -1926,7 +2696,7 @@ describe('Package policy service', () => { }, ]; - const result = overridePackageInputs( + const result = updatePackageInputs( basePackagePolicy, packageInfo, // TODO: Update this type assertion when the `InputsOverride` type is updated such diff --git a/x-pack/plugins/fleet/server/services/package_policy.ts b/x-pack/plugins/fleet/server/services/package_policy.ts index bb14a8eae9e43..e16cb705af50a 100644 --- a/x-pack/plugins/fleet/server/services/package_policy.ts +++ b/x-pack/plugins/fleet/server/services/package_policy.ts @@ -593,7 +593,7 @@ class PackagePolicyService { try { const { packagePolicy, packageInfo } = await this.getUpgradePackagePolicyInfo(soClient, id); - const updatePackagePolicy = overridePackageInputs( + const updatePackagePolicy = updatePackageInputs( { ...omit(packagePolicy, 'id'), inputs: packagePolicy.inputs, @@ -644,7 +644,7 @@ class PackagePolicyService { packageVersion ); - const updatedPackagePolicy = overridePackageInputs( + const updatedPackagePolicy = updatePackageInputs( { ...omit(packagePolicy, 'id'), inputs: packagePolicy.inputs, @@ -1022,13 +1022,13 @@ export const packagePolicyService = new PackagePolicyService(); export type { PackagePolicyService }; -export function overridePackageInputs( +export function updatePackageInputs( basePackagePolicy: NewPackagePolicy, packageInfo: PackageInfo, - inputsOverride?: InputsOverride[], + inputsUpdated?: InputsOverride[], dryRun?: boolean ): DryRunPackagePolicy { - if (!inputsOverride) return basePackagePolicy; + if (!inputsUpdated) return basePackagePolicy; const availablePolicyTemplates = packageInfo.policy_templates ?? []; @@ -1057,42 +1057,40 @@ export function overridePackageInputs( }), ]; - for (const override of inputsOverride) { - // Preconfiguration does not currently support multiple policy templates, so overrides will have an undefined - // policy template, so we only match on `type` in that case. - let originalInput = override.policy_template - ? inputs.find( - (i) => i.type === override.type && i.policy_template === override.policy_template - ) - : inputs.find((i) => i.type === override.type); + for (const update of inputsUpdated) { + // If update have an undefined policy template + // we only match on `type` . + let originalInput = update.policy_template + ? inputs.find((i) => i.type === update.type && i.policy_template === update.policy_template) + : inputs.find((i) => i.type === update.type); // If there's no corresponding input on the original package policy, just // take the override value from the new package as-is. This case typically // occurs when inputs or package policy templates are added/removed between versions. if (originalInput === undefined) { - inputs.push(override as NewPackagePolicyInput); + inputs.push(update as NewPackagePolicyInput); continue; } // For flags like this, we only want to override the original value if it was set // as `undefined` in the original object. An explicit true/false value should be // persisted from the original object to the result after the override process is complete. - if (originalInput.enabled === undefined && override.enabled !== undefined) { - originalInput.enabled = override.enabled; + if (originalInput.enabled === undefined && update.enabled !== undefined) { + originalInput.enabled = update.enabled; } - if (originalInput.keep_enabled === undefined && override.keep_enabled !== undefined) { - originalInput.keep_enabled = override.keep_enabled; + if (originalInput.keep_enabled === undefined && update.keep_enabled !== undefined) { + originalInput.keep_enabled = update.keep_enabled; } - if (override.vars) { + if (update.vars) { const indexOfInput = inputs.indexOf(originalInput); - inputs[indexOfInput] = deepMergeVars(originalInput, override) as NewPackagePolicyInput; + inputs[indexOfInput] = deepMergeVars(originalInput, update, true) as NewPackagePolicyInput; originalInput = inputs[indexOfInput]; } - if (override.streams) { - for (const stream of override.streams) { + if (update.streams) { + for (const stream of update.streams) { let originalStream = originalInput?.streams.find( (s) => s.data_stream.dataset === stream.data_stream.dataset ); @@ -1110,7 +1108,8 @@ export function overridePackageInputs( const indexOfStream = originalInput.streams.indexOf(originalStream); originalInput.streams[indexOfStream] = deepMergeVars( originalStream, - stream as InputsOverride + stream as InputsOverride, + true ); originalStream = originalInput.streams[indexOfStream]; } @@ -1120,9 +1119,8 @@ export function overridePackageInputs( // Filter all stream that have been removed from the input originalInput.streams = originalInput.streams.filter((originalStream) => { return ( - override.streams?.some( - (s) => s.data_stream.dataset === originalStream.data_stream.dataset - ) ?? false + update.streams?.some((s) => s.data_stream.dataset === originalStream.data_stream.dataset) ?? + false ); }); } @@ -1163,7 +1161,110 @@ export function overridePackageInputs( return resultingPackagePolicy; } -function deepMergeVars(original: any, override: any): any { +export function preconfigurePackageInputs( + basePackagePolicy: NewPackagePolicy, + packageInfo: PackageInfo, + preconfiguredInputs?: InputsOverride[] +): NewPackagePolicy { + if (!preconfiguredInputs) return basePackagePolicy; + + const inputs = [...basePackagePolicy.inputs]; + + for (const preconfiguredInput of preconfiguredInputs) { + // Preconfiguration does not currently support multiple policy templates, so overrides will have an undefined + // policy template, so we only match on `type` in that case. + let originalInput = preconfiguredInput.policy_template + ? inputs.find( + (i) => + i.type === preconfiguredInput.type && + i.policy_template === preconfiguredInput.policy_template + ) + : inputs.find((i) => i.type === preconfiguredInput.type); + + // If the input do not exist skip + if (originalInput === undefined) { + continue; + } + + // For flags like this, we only want to override the original value if it was set + // as `undefined` in the original object. An explicit true/false value should be + // persisted from the original object to the result after the override process is complete. + if (originalInput.enabled === undefined && preconfiguredInput.enabled !== undefined) { + originalInput.enabled = preconfiguredInput.enabled; + } + + if (originalInput.keep_enabled === undefined && preconfiguredInput.keep_enabled !== undefined) { + originalInput.keep_enabled = preconfiguredInput.keep_enabled; + } + + if (preconfiguredInput.vars) { + const indexOfInput = inputs.indexOf(originalInput); + inputs[indexOfInput] = deepMergeVars( + originalInput, + preconfiguredInput + ) as NewPackagePolicyInput; + originalInput = inputs[indexOfInput]; + } + + if (preconfiguredInput.streams) { + for (const stream of preconfiguredInput.streams) { + let originalStream = originalInput?.streams.find( + (s) => s.data_stream.dataset === stream.data_stream.dataset + ); + + if (originalStream === undefined) { + continue; + } + + if (originalStream?.enabled === undefined) { + originalStream.enabled = stream.enabled; + } + + if (stream.vars) { + const indexOfStream = originalInput.streams.indexOf(originalStream); + originalInput.streams[indexOfStream] = deepMergeVars( + originalStream, + stream as InputsOverride + ); + originalStream = originalInput.streams[indexOfStream]; + } + } + } + } + + const resultingPackagePolicy: NewPackagePolicy = { + ...basePackagePolicy, + inputs, + }; + + const validationResults = validatePackagePolicy(resultingPackagePolicy, packageInfo, safeLoad); + + if (validationHasErrors(validationResults)) { + const responseFormattedValidationErrors = Object.entries(getFlattenedObject(validationResults)) + .map(([key, value]) => ({ + key, + message: value, + })) + .filter(({ message }) => !!message); + + if (responseFormattedValidationErrors.length) { + throw new PackagePolicyValidationError( + i18n.translate('xpack.fleet.packagePolicyInvalidError', { + defaultMessage: 'Package policy is invalid: {errors}', + values: { + errors: responseFormattedValidationErrors + .map(({ key, message }) => `${key}: ${message}`) + .join('\n'), + }, + }) + ); + } + } + + return resultingPackagePolicy; +} + +function deepMergeVars(original: any, override: any, keepOriginalValue = false): any { if (!original.vars) { original.vars = { ...override.vars }; } @@ -1184,7 +1285,7 @@ function deepMergeVars(original: any, override: any): any { // Ensure that any value from the original object is persisted on the newly merged resulting object, // even if we merge other data about the given variable - if (originalVar?.value) { + if (keepOriginalValue && originalVar?.value) { result.vars[name].value = originalVar.value; } } diff --git a/x-pack/plugins/fleet/server/services/preconfiguration.ts b/x-pack/plugins/fleet/server/services/preconfiguration.ts index e5fea73815ea7..141ba5f12d63b 100644 --- a/x-pack/plugins/fleet/server/services/preconfiguration.ts +++ b/x-pack/plugins/fleet/server/services/preconfiguration.ts @@ -37,7 +37,7 @@ import { ensurePackagesCompletedInstall } from './epm/packages/install'; import { bulkInstallPackages } from './epm/packages/bulk_install_packages'; import { agentPolicyService, addPackageToAgentPolicy } from './agent_policy'; import type { InputsOverride } from './package_policy'; -import { overridePackageInputs, packagePolicyService } from './package_policy'; +import { preconfigurePackageInputs, packagePolicyService } from './package_policy'; import { appContextService } from './app_context'; import type { UpgradeManagedPackagePoliciesResult } from './managed_package_policies'; import { upgradeManagedPackagePolicies } from './managed_package_policies'; @@ -429,7 +429,8 @@ async function addPreconfiguredPolicyPackages( defaultOutput, name, description, - (policy) => overridePackageInputs(policy, packageInfo, inputs) + (policy) => overridePackageInputs(policy, packageInfo, inputs), + bumpAgentPolicyRevison ); } } From 44e637c763c7727f06b260f6efa4c84879a703da Mon Sep 17 00:00:00 2001 From: Nicolas Chaulet Date: Tue, 30 Nov 2021 11:28:42 -0500 Subject: [PATCH 2/3] Fix merge issue --- 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 141ba5f12d63b..fb1425eca44d4 100644 --- a/x-pack/plugins/fleet/server/services/preconfiguration.ts +++ b/x-pack/plugins/fleet/server/services/preconfiguration.ts @@ -429,7 +429,7 @@ async function addPreconfiguredPolicyPackages( defaultOutput, name, description, - (policy) => overridePackageInputs(policy, packageInfo, inputs), + (policy) => preconfigurePackageInputs(policy, packageInfo, inputs), bumpAgentPolicyRevison ); } From 938d897ecce914612c4b52c77d7e5d619d11a9f7 Mon Sep 17 00:00:00 2001 From: Nicolas Chaulet Date: Tue, 30 Nov 2021 11:49:59 -0500 Subject: [PATCH 3/3] Fix merge issue --- x-pack/plugins/fleet/server/services/preconfiguration.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/x-pack/plugins/fleet/server/services/preconfiguration.ts b/x-pack/plugins/fleet/server/services/preconfiguration.ts index fb1425eca44d4..de55ddc3fda5a 100644 --- a/x-pack/plugins/fleet/server/services/preconfiguration.ts +++ b/x-pack/plugins/fleet/server/services/preconfiguration.ts @@ -429,8 +429,7 @@ async function addPreconfiguredPolicyPackages( defaultOutput, name, description, - (policy) => preconfigurePackageInputs(policy, packageInfo, inputs), - bumpAgentPolicyRevison + (policy) => preconfigurePackageInputs(policy, packageInfo, inputs) ); } }