From ab734c1e292d2de2c3c688f66b0bba55faa9d56e Mon Sep 17 00:00:00 2001 From: jillguyonnet Date: Fri, 14 Jul 2023 13:16:20 +0200 Subject: [PATCH 1/4] [Fleet] Exclude Synthetics from per-policy-outputs --- .../common/services/agent_policies_helpers.ts | 13 ++- x-pack/plugins/fleet/common/services/index.ts | 6 +- .../fleet/common/services/output_helpers.ts | 12 ++- .../hooks.test.tsx | 16 ++-- .../agent_policy_advanced_fields/hooks.tsx | 23 ++--- .../edit_output_flyout/confirm_update.tsx | 4 +- .../agent_policies/output_helpers.test.ts | 4 +- .../agent_policies/outputs_helpers.ts | 5 +- .../fleet/server/services/agent_policy.ts | 5 + .../fleet/server/services/output.test.ts | 92 +++++-------------- .../plugins/fleet/server/services/output.ts | 50 +++++----- 11 files changed, 111 insertions(+), 119 deletions(-) diff --git a/x-pack/plugins/fleet/common/services/agent_policies_helpers.ts b/x-pack/plugins/fleet/common/services/agent_policies_helpers.ts index 9db799997fad3..52ce24634886e 100644 --- a/x-pack/plugins/fleet/common/services/agent_policies_helpers.ts +++ b/x-pack/plugins/fleet/common/services/agent_policies_helpers.ts @@ -6,7 +6,7 @@ */ import type { AgentPolicy } from '../types'; -import { FLEET_SERVER_PACKAGE, FLEET_APM_PACKAGE } from '../constants'; +import { FLEET_SERVER_PACKAGE, FLEET_APM_PACKAGE, FLEET_SYNTHETICS_PACKAGE } from '../constants'; export function policyHasFleetServer(agentPolicy: AgentPolicy) { if (!agentPolicy.package_policies) { @@ -19,8 +19,17 @@ export function policyHasFleetServer(agentPolicy: AgentPolicy) { } export function policyHasAPMIntegration(agentPolicy: AgentPolicy) { + return policyHasIntegration(agentPolicy, FLEET_APM_PACKAGE); +} + +export function policyHasSyntheticsIntegration(agentPolicy: AgentPolicy) { + return policyHasIntegration(agentPolicy, FLEET_SYNTHETICS_PACKAGE); +} + +function policyHasIntegration(agentPolicy: AgentPolicy, packageName: string) { if (!agentPolicy.package_policies) { return false; } - return agentPolicy.package_policies?.some((p) => p.package?.name === FLEET_APM_PACKAGE); + + return agentPolicy.package_policies?.some((p) => p.package?.name === packageName); } diff --git a/x-pack/plugins/fleet/common/services/index.ts b/x-pack/plugins/fleet/common/services/index.ts index 6b392f506b4c6..abf06ac54b07c 100644 --- a/x-pack/plugins/fleet/common/services/index.ts +++ b/x-pack/plugins/fleet/common/services/index.ts @@ -63,7 +63,11 @@ export { export { getAllowedOutputTypeForPolicy } from './output_helpers'; export { agentStatusesToSummary } from './agent_statuses_to_summary'; -export { policyHasFleetServer, policyHasAPMIntegration } from './agent_policies_helpers'; +export { + policyHasFleetServer, + policyHasAPMIntegration, + policyHasSyntheticsIntegration, +} from './agent_policies_helpers'; export { generateNewAgentPolicyWithDefaults, diff --git a/x-pack/plugins/fleet/common/services/output_helpers.ts b/x-pack/plugins/fleet/common/services/output_helpers.ts index d0d8c826878fd..00b480c378b61 100644 --- a/x-pack/plugins/fleet/common/services/output_helpers.ts +++ b/x-pack/plugins/fleet/common/services/output_helpers.ts @@ -6,7 +6,12 @@ */ import type { AgentPolicy } from '../types'; -import { FLEET_APM_PACKAGE, FLEET_SERVER_PACKAGE, outputType } from '../constants'; +import { + FLEET_APM_PACKAGE, + FLEET_SERVER_PACKAGE, + FLEET_SYNTHETICS_PACKAGE, + outputType, +} from '../constants'; /** * Return allowed output type for a given agent policy, @@ -16,7 +21,10 @@ export function getAllowedOutputTypeForPolicy(agentPolicy: AgentPolicy) { const isRestrictedToSameClusterES = agentPolicy.package_policies && agentPolicy.package_policies.some( - (p) => p.package?.name === FLEET_APM_PACKAGE || p.package?.name === FLEET_SERVER_PACKAGE + (p) => + p.package?.name === FLEET_APM_PACKAGE || + p.package?.name === FLEET_SERVER_PACKAGE || + p.package?.name === FLEET_SYNTHETICS_PACKAGE ); if (isRestrictedToSameClusterES) { diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_advanced_fields/hooks.test.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_advanced_fields/hooks.test.tsx index 1a415e51e23a6..2d7eef6b864bf 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_advanced_fields/hooks.test.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_advanced_fields/hooks.test.tsx @@ -130,7 +130,7 @@ describe('useOutputOptions', () => { size="s" > { size="s" > { size="s" > { size="s" > { size="s" > { size="s" > { size="s" > { size="s" > getAllowedOutputTypeForPolicy(agentPolicy as AgentPolicy), [agentPolicy] @@ -89,7 +90,7 @@ export function useOutputOptions(agentPolicy: Partial ) : undefined ), - disabled: !isLicenceAllowingPolicyPerOutput || isOutputTypeUnsupported, + disabled: !isPolicyPerOutputAllowed || isOutputTypeUnsupported, }; }), ]; - }, [outputsRequest, isLicenceAllowingPolicyPerOutput, allowedOutputTypes]); + }, [outputsRequest, isPolicyPerOutputAllowed, allowedOutputTypes]); const monitoringOutputOptions = useMemo(() => { if (outputsRequest.isLoading || !outputsRequest.data) { @@ -135,11 +136,11 @@ export function useOutputOptions(agentPolicy: Partial ({ diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/settings/components/edit_output_flyout/confirm_update.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/settings/components/edit_output_flyout/confirm_update.tsx index 8d96c5f314547..4157c6964f79a 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/settings/components/edit_output_flyout/confirm_update.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/settings/components/edit_output_flyout/confirm_update.tsx @@ -73,13 +73,13 @@ const ConfirmDescription: React.FunctionComponent = ({ title={ } > {' '} diff --git a/x-pack/plugins/fleet/server/services/agent_policies/output_helpers.test.ts b/x-pack/plugins/fleet/server/services/agent_policies/output_helpers.test.ts index 29d48d5d595ef..e43bc275a9c4d 100644 --- a/x-pack/plugins/fleet/server/services/agent_policies/output_helpers.test.ts +++ b/x-pack/plugins/fleet/server/services/agent_policies/output_helpers.test.ts @@ -196,7 +196,7 @@ describe('validateOutputForPolicy', () => { ); }); - it('should not allow logstash output to be used with a policy using fleet server or APM', async () => { + it('should not allow logstash output to be used with a policy using fleet server, synthetics or APM', async () => { mockHasLicence(true); mockedOutputService.get.mockResolvedValue({ type: 'logstash', @@ -217,7 +217,7 @@ describe('validateOutputForPolicy', () => { ); }); - it('should allow elasticsearch output to be used with a policy using fleet server or APM', async () => { + it('should allow elasticsearch output to be used with a policy using fleet server, synthetics or APM', async () => { mockHasLicence(true); mockedOutputService.get.mockResolvedValue({ type: 'elasticsearch', diff --git a/x-pack/plugins/fleet/server/services/agent_policies/outputs_helpers.ts b/x-pack/plugins/fleet/server/services/agent_policies/outputs_helpers.ts index d93bb965295ef..88eab8b699616 100644 --- a/x-pack/plugins/fleet/server/services/agent_policies/outputs_helpers.ts +++ b/x-pack/plugins/fleet/server/services/agent_policies/outputs_helpers.ts @@ -9,7 +9,7 @@ import type { SavedObjectsClientContract } from '@kbn/core/server'; import type { AgentPolicySOAttributes, AgentPolicy } from '../../types'; import { LICENCE_FOR_PER_POLICY_OUTPUT, outputType } from '../../../common/constants'; -import { policyHasFleetServer } from '../../../common/services'; +import { policyHasFleetServer, policyHasSyntheticsIntegration } from '../../../common/services'; import { appContextService } from '..'; import { outputService } from '../output'; import { OutputInvalidError, OutputLicenceError } from '../../errors'; @@ -80,6 +80,9 @@ export async function validateOutputForPolicy( // Validate output when the policy has fleet server if (policyHasFleetServer(data as AgentPolicy)) return; + // Validate output when the policy has synthetics server + if (policyHasSyntheticsIntegration(data as AgentPolicy)) return; + const hasLicence = appContextService .getSecurityLicense() .hasAtLeast(LICENCE_FOR_PER_POLICY_OUTPUT); diff --git a/x-pack/plugins/fleet/server/services/agent_policy.ts b/x-pack/plugins/fleet/server/services/agent_policy.ts index d32737e0eb5c1..6958ea80c00d6 100644 --- a/x-pack/plugins/fleet/server/services/agent_policy.ts +++ b/x-pack/plugins/fleet/server/services/agent_policy.ts @@ -48,6 +48,7 @@ import { packageToPackagePolicy, policyHasFleetServer, policyHasAPMIntegration, + policyHasSyntheticsIntegration, } from '../../common/services'; import { agentPolicyStatuses, @@ -211,6 +212,10 @@ class AgentPolicyService { return policyHasFleetServer(agentPolicy); } + public hasSyntheticsIntegration(agentPolicy: AgentPolicy) { + return policyHasSyntheticsIntegration(agentPolicy); + } + public async create( soClient: SavedObjectsClientContract, esClient: ElasticsearchClient, diff --git a/x-pack/plugins/fleet/server/services/output.test.ts b/x-pack/plugins/fleet/server/services/output.test.ts index 7c0076abfc653..ef31c2dfea698 100644 --- a/x-pack/plugins/fleet/server/services/output.test.ts +++ b/x-pack/plugins/fleet/server/services/output.test.ts @@ -936,36 +936,7 @@ describe('Output Service', () => { const soClient = getMockedSoClient({ defaultOutputId: 'output-test', }); - mockedAgentPolicyService.list.mockResolvedValue({ - items: [ - { - name: 'fleet server policy', - id: 'fleet_server_policy', - is_default_fleet_server: true, - package_policies: [ - { - name: 'fleet-server-123', - package: { - name: 'fleet_server', - }, - }, - ], - }, - { - name: 'agent policy 1', - id: 'agent_policy_1', - is_managed: false, - package_policies: [ - { - name: 'nginx', - package: { - name: 'nginx', - }, - }, - ], - }, - ], - } as unknown as ReturnType); + mockedAgentPolicyService.list.mockResolvedValue(mockedAgentPolicyResolvedValue); mockedAgentPolicyService.hasFleetServerIntegration.mockReturnValue(true); await outputService.update(soClient, esClientMock, 'output-test', { @@ -994,36 +965,7 @@ describe('Output Service', () => { const soClient = getMockedSoClient({ defaultOutputId: 'output-test', }); - mockedAgentPolicyService.list.mockResolvedValue({ - items: [ - { - name: 'fleet server policy', - id: 'fleet_server_policy', - is_default_fleet_server: true, - package_policies: [ - { - name: 'fleet-server-123', - package: { - name: 'fleet_server', - }, - }, - ], - }, - { - name: 'agent policy 1', - id: 'agent_policy_1', - is_managed: false, - package_policies: [ - { - name: 'nginx', - package: { - name: 'nginx', - }, - }, - ], - }, - ], - } as unknown as ReturnType); + mockedAgentPolicyService.list.mockResolvedValue(mockedAgentPolicyResolvedValue); mockedAgentPolicyService.hasFleetServerIntegration.mockReturnValue(true); await outputService.update( @@ -1057,18 +999,32 @@ describe('Output Service', () => { }); it('Should return an error if trying to change the output to logstash for fleet server policy', async () => { + const soClient = getMockedSoClient({}); + mockedAgentPolicyService.list.mockResolvedValue(mockedAgentPolicyResolvedValue); + mockedAgentPolicyService.hasFleetServerIntegration.mockReturnValue(true); + + await expect( + outputService.update(soClient, esClientMock, 'existing-es-output', { + type: 'logstash', + hosts: ['test:4343'], + }) + ).rejects.toThrowError( + 'Logstash output cannot be used with Fleet server integration in fleet server policy. Please create a new ElasticSearch output.' + ); + }); + + it('Should return an error if trying to change the output to logstash for synthetics policy', async () => { const soClient = getMockedSoClient({}); mockedAgentPolicyService.list.mockResolvedValue({ items: [ { - name: 'fleet server policy', - id: 'fleet_server_policy', - is_default_fleet_server: true, + name: 'synthetics policy', + id: 'synthetics_policy', package_policies: [ { - name: 'fleet-server-123', + name: 'synthetics-123', package: { - name: 'fleet_server', + name: 'synthetics', }, }, ], @@ -1088,7 +1044,8 @@ describe('Output Service', () => { }, ], } as unknown as ReturnType); - mockedAgentPolicyService.hasFleetServerIntegration.mockReturnValue(true); + mockedAgentPolicyService.hasFleetServerIntegration.mockReturnValue(false); + mockedAgentPolicyService.hasSyntheticsIntegration.mockReturnValue(true); await expect( outputService.update(soClient, esClientMock, 'existing-es-output', { @@ -1096,7 +1053,7 @@ describe('Output Service', () => { hosts: ['test:4343'], }) ).rejects.toThrowError( - 'Logstash output cannot be used with Fleet Server integration in fleet server policy. Please create a new ElasticSearch output.' + 'Logstash output cannot be used with Synthetics integration in synthetics policy. Please create a new ElasticSearch output.' ); }); @@ -1123,6 +1080,7 @@ describe('Output Service', () => { } as unknown as ReturnType); mockedAgentPolicyService.hasAPMIntegration.mockReturnValue(false); mockedAgentPolicyService.hasFleetServerIntegration.mockReturnValue(false); + mockedAgentPolicyService.hasSyntheticsIntegration.mockReturnValue(false); await outputService.update(soClient, esClientMock, 'existing-es-output', { type: 'kafka', diff --git a/x-pack/plugins/fleet/server/services/output.ts b/x-pack/plugins/fleet/server/services/output.ts index a9e546d878fb5..9762b937c86be 100644 --- a/x-pack/plugins/fleet/server/services/output.ts +++ b/x-pack/plugins/fleet/server/services/output.ts @@ -148,7 +148,7 @@ async function validateLogstashOutputNotUsedInAPMPolicy( } } -async function findPoliciesWithFleetServer( +async function findPoliciesWithFleetServerOrSynthetics( soClient: SavedObjectsClientContract, outputId?: string, isDefault?: boolean @@ -159,23 +159,24 @@ async function findPoliciesWithFleetServer( ? await getAgentPoliciesPerOutput(soClient, outputId, isDefault) : (await agentPolicyService.list(soClient, { withPackagePolicies: true }))?.items; - if (agentPolicies) { - const policiesWithFleetServer = agentPolicies.filter((policy) => - agentPolicyService.hasFleetServerIntegration(policy) - ); - return policiesWithFleetServer; - } - return []; + const policiesWithFleetServer = + agentPolicies?.filter((policy) => agentPolicyService.hasFleetServerIntegration(policy)) || []; + const policiesWithSynthetics = + agentPolicies?.filter((policy) => agentPolicyService.hasSyntheticsIntegration(policy)) || []; + return { policiesWithFleetServer, policiesWithSynthetics }; } -function validateOutputNotUsedInFleetServerPolicy( +function validateOutputNotUsedInPolicy( agentPolicies: AgentPolicy[], - dataOutputType: OutputType['Logstash'] | OutputType['Kafka'] + dataOutputType: OutputType['Logstash'] | OutputType['Kafka'], + integrationName: string ) { - // Validate no policy with fleet server use that policy + // Validate no policy with this integration uses that output for (const agentPolicy of agentPolicies) { throw new OutputInvalidError( - `${_.capitalize(dataOutputType)} output cannot be used with Fleet Server integration in ${ + `${_.capitalize( + dataOutputType + )} output cannot be used with ${integrationName} integration in ${ agentPolicy.name }. Please create a new ElasticSearch output.` ); @@ -192,44 +193,46 @@ async function validateTypeChanges( fromPreconfiguration: boolean ) { const mergedIsDefault = data.is_default ?? originalOutput.is_default; - const fleetServerPolicies = await findPoliciesWithFleetServer(soClient, id, mergedIsDefault); + const { policiesWithFleetServer, policiesWithSynthetics } = + await findPoliciesWithFleetServerOrSynthetics(soClient, id, mergedIsDefault); if (data.type === outputType.Logstash || originalOutput.type === outputType.Logstash) { await validateLogstashOutputNotUsedInAPMPolicy(soClient, id, mergedIsDefault); } - // prevent changing an ES output to logstash or kafka if it's used by fleet server policies + // prevent changing an ES output to logstash or kafka if it's used by fleet server or synthetics policies if ( originalOutput.type === outputType.Elasticsearch && (data?.type === outputType.Logstash || data?.type === outputType.Kafka) ) { // Validate no policy with fleet server use that policy - validateOutputNotUsedInFleetServerPolicy(fleetServerPolicies, data.type); + validateOutputNotUsedInPolicy(policiesWithFleetServer, data.type, 'Fleet server'); + validateOutputNotUsedInPolicy(policiesWithSynthetics, data.type, 'Synthetics'); } - await updateFleetServerPoliciesDataOutputId( + await updateAgentPoliciesDataOutputId( soClient, esClient, data, mergedIsDefault, defaultDataOutputId, - fleetServerPolicies, + _.uniq([...policiesWithFleetServer, ...policiesWithSynthetics]), fromPreconfiguration ); } -async function updateFleetServerPoliciesDataOutputId( +async function updateAgentPoliciesDataOutputId( soClient: SavedObjectsClientContract, esClient: ElasticsearchClient, data: Nullable>, isDefault: boolean, defaultDataOutputId: string | null, - fleetServerPolicies: AgentPolicy[], + agentPolicies: AgentPolicy[], fromPreconfiguration: boolean ) { // if a logstash output is updated to become default // if fleet server policies don't have data_output_id // update them to use the default output if ((data?.type === outputType.Logstash || data?.type === outputType.Kafka) && isDefault) { - for (const policy of fleetServerPolicies) { + for (const policy of agentPolicies) { if (!policy.data_output_id) { await agentPolicyService.update( soClient, @@ -415,14 +418,15 @@ class OutputService { ); } } - const fleetServerPolicies = await findPoliciesWithFleetServer(soClient); - await updateFleetServerPoliciesDataOutputId( + const { policiesWithFleetServer, policiesWithSynthetics } = + await findPoliciesWithFleetServerOrSynthetics(soClient); + await updateAgentPoliciesDataOutputId( soClient, esClient, data, data.is_default, defaultDataOutputId, - fleetServerPolicies, + _.uniq([...policiesWithFleetServer, ...policiesWithSynthetics]), options?.fromPreconfiguration ?? false ); From fc6905b78856c158a5c9f3df6d0b016550f5f529 Mon Sep 17 00:00:00 2001 From: jillguyonnet Date: Fri, 14 Jul 2023 14:34:09 +0200 Subject: [PATCH 2/4] Put back capitalization --- x-pack/plugins/fleet/server/services/output.test.ts | 2 +- x-pack/plugins/fleet/server/services/output.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/x-pack/plugins/fleet/server/services/output.test.ts b/x-pack/plugins/fleet/server/services/output.test.ts index ef31c2dfea698..71520638d1b8c 100644 --- a/x-pack/plugins/fleet/server/services/output.test.ts +++ b/x-pack/plugins/fleet/server/services/output.test.ts @@ -1009,7 +1009,7 @@ describe('Output Service', () => { hosts: ['test:4343'], }) ).rejects.toThrowError( - 'Logstash output cannot be used with Fleet server integration in fleet server policy. Please create a new ElasticSearch output.' + 'Logstash output cannot be used with Fleet Server integration in fleet server policy. Please create a new ElasticSearch output.' ); }); diff --git a/x-pack/plugins/fleet/server/services/output.ts b/x-pack/plugins/fleet/server/services/output.ts index 9762b937c86be..ec5f63cbe3566 100644 --- a/x-pack/plugins/fleet/server/services/output.ts +++ b/x-pack/plugins/fleet/server/services/output.ts @@ -205,7 +205,7 @@ async function validateTypeChanges( (data?.type === outputType.Logstash || data?.type === outputType.Kafka) ) { // Validate no policy with fleet server use that policy - validateOutputNotUsedInPolicy(policiesWithFleetServer, data.type, 'Fleet server'); + validateOutputNotUsedInPolicy(policiesWithFleetServer, data.type, 'Fleet Server'); validateOutputNotUsedInPolicy(policiesWithSynthetics, data.type, 'Synthetics'); } await updateAgentPoliciesDataOutputId( From daa02524eecefb92028adeff8bde57f117776559 Mon Sep 17 00:00:00 2001 From: jillguyonnet Date: Mon, 17 Jul 2023 19:02:29 +0200 Subject: [PATCH 3/4] Add more output unit tests --- .../agent_policies/outputs_helpers.ts | 2 +- .../fleet/server/services/output.test.ts | 298 +++++++++++++++--- 2 files changed, 258 insertions(+), 42 deletions(-) diff --git a/x-pack/plugins/fleet/server/services/agent_policies/outputs_helpers.ts b/x-pack/plugins/fleet/server/services/agent_policies/outputs_helpers.ts index 88eab8b699616..bbe00c49b414f 100644 --- a/x-pack/plugins/fleet/server/services/agent_policies/outputs_helpers.ts +++ b/x-pack/plugins/fleet/server/services/agent_policies/outputs_helpers.ts @@ -80,7 +80,7 @@ export async function validateOutputForPolicy( // Validate output when the policy has fleet server if (policyHasFleetServer(data as AgentPolicy)) return; - // Validate output when the policy has synthetics server + // Validate output when the policy has synthetics integration if (policyHasSyntheticsIntegration(data as AgentPolicy)) return; const hasLicence = appContextService diff --git a/x-pack/plugins/fleet/server/services/output.test.ts b/x-pack/plugins/fleet/server/services/output.test.ts index 71520638d1b8c..af5778c86304a 100644 --- a/x-pack/plugins/fleet/server/services/output.test.ts +++ b/x-pack/plugins/fleet/server/services/output.test.ts @@ -201,7 +201,7 @@ function getMockedSoClient( describe('Output Service', () => { const esClientMock = elasticsearchServiceMock.createElasticsearchClient(); - const mockedAgentPolicyResolvedValue = { + const mockedAgentPolicyWithFleetServerResolvedValue = { items: [ { name: 'fleet server policy', @@ -232,18 +232,50 @@ describe('Output Service', () => { ], } as unknown as ReturnType; + const mockedAgentPolicyWithSyntheticsResolvedValue = { + items: [ + { + name: 'synthetics policy', + id: 'synthetics_policy', + package_policies: [ + { + name: 'synthetics-123', + package: { + name: 'synthetics', + }, + }, + ], + }, + { + name: 'agent policy 1', + id: 'agent_policy_1', + is_managed: false, + package_policies: [ + { + name: 'nginx', + package: { + name: 'nginx', + }, + }, + ], + }, + ], + } as unknown as ReturnType; + beforeEach(() => { mockedAgentPolicyService.list.mockClear(); mockedAgentPolicyService.hasAPMIntegration.mockClear(); mockedAgentPolicyService.hasFleetServerIntegration.mockClear(); + mockedAgentPolicyService.hasSyntheticsIntegration.mockClear(); mockedAgentPolicyService.removeOutputFromAll.mockReset(); mockedAppContextService.getInternalUserSOClient.mockReset(); mockedAppContextService.getEncryptedSavedObjectsSetup.mockReset(); mockedAuditLoggingService.writeCustomSoAuditLog.mockReset(); mockedAgentPolicyService.update.mockReset(); }); + describe('create', () => { - it('work with a predefined id', async () => { + it('works with a predefined id', async () => { const soClient = getMockedSoClient(); await outputService.create( @@ -446,7 +478,7 @@ describe('Output Service', () => { mockedAppContextService.getEncryptedSavedObjectsSetup.mockReturnValue({ canEncrypt: true, } as any); - mockedAgentPolicyService.list.mockResolvedValue(mockedAgentPolicyResolvedValue); + mockedAgentPolicyService.list.mockResolvedValue(mockedAgentPolicyWithFleetServerResolvedValue); mockedAgentPolicyService.hasFleetServerIntegration.mockReturnValue(true); await outputService.create( @@ -470,6 +502,37 @@ describe('Output Service', () => { ); }); + it('should update synthetics policies with data_output_id=default_output_id if a new default logstash output is created', async () => { + const soClient = getMockedSoClient({ + defaultOutputId: 'output-test', + }); + mockedAppContextService.getEncryptedSavedObjectsSetup.mockReturnValue({ + canEncrypt: true, + } as any); + mockedAgentPolicyService.list.mockResolvedValue(mockedAgentPolicyWithSyntheticsResolvedValue); + mockedAgentPolicyService.hasSyntheticsIntegration.mockReturnValue(true); + + await outputService.create( + soClient, + esClientMock, + { + is_default: true, + is_default_monitoring: false, + name: 'Test', + type: 'logstash', + }, + { id: 'output-1' } + ); + + expect(mockedAgentPolicyService.update).toBeCalledWith( + expect.anything(), + expect.anything(), + 'synthetics_policy', + { data_output_id: 'output-test' }, + { force: false } + ); + }); + it('Should allow to create a new logstash output with no errors if is not set as default', async () => { const soClient = getMockedSoClient({ defaultOutputId: 'output-test', @@ -477,7 +540,7 @@ describe('Output Service', () => { mockedAppContextService.getEncryptedSavedObjectsSetup.mockReturnValue({ canEncrypt: true, } as any); - mockedAgentPolicyService.list.mockResolvedValue(mockedAgentPolicyResolvedValue); + mockedAgentPolicyService.list.mockResolvedValue(mockedAgentPolicyWithFleetServerResolvedValue); mockedAgentPolicyService.hasFleetServerIntegration.mockReturnValue(true); await outputService.create( @@ -523,7 +586,7 @@ describe('Output Service', () => { mockedAppContextService.getEncryptedSavedObjectsSetup.mockReturnValue({ canEncrypt: true, } as any); - mockedAgentPolicyService.list.mockResolvedValue(mockedAgentPolicyResolvedValue); + mockedAgentPolicyService.list.mockResolvedValue(mockedAgentPolicyWithFleetServerResolvedValue); mockedAgentPolicyService.hasFleetServerIntegration.mockReturnValue(true); await outputService.create( @@ -547,6 +610,37 @@ describe('Output Service', () => { ); }); + it('Should update synthetics policies with data_output_id=default_output_id if a new default kafka output is created', async () => { + const soClient = getMockedSoClient({ + defaultOutputId: 'output-test', + }); + mockedAppContextService.getEncryptedSavedObjectsSetup.mockReturnValue({ + canEncrypt: true, + } as any); + mockedAgentPolicyService.list.mockResolvedValue(mockedAgentPolicyWithSyntheticsResolvedValue); + mockedAgentPolicyService.hasSyntheticsIntegration.mockReturnValue(true); + + await outputService.create( + soClient, + esClientMock, + { + is_default: true, + is_default_monitoring: false, + name: 'Test', + type: 'kafka', + }, + { id: 'output-1' } + ); + + expect(mockedAgentPolicyService.update).toBeCalledWith( + expect.anything(), + expect.anything(), + 'synthetics_policy', + { data_output_id: 'output-test' }, + { force: false } + ); + }); + it('Should allow to create a new kafka output with no errors if is not set as default', async () => { const soClient = getMockedSoClient({ defaultOutputId: 'output-test', @@ -554,7 +648,7 @@ describe('Output Service', () => { mockedAppContextService.getEncryptedSavedObjectsSetup.mockReturnValue({ canEncrypt: true, } as any); - mockedAgentPolicyService.list.mockResolvedValue(mockedAgentPolicyResolvedValue); + mockedAgentPolicyService.list.mockResolvedValue(mockedAgentPolicyWithFleetServerResolvedValue); mockedAgentPolicyService.hasFleetServerIntegration.mockReturnValue(true); await outputService.create( @@ -878,6 +972,7 @@ describe('Output Service', () => { } as unknown as ReturnType); mockedAgentPolicyService.hasAPMIntegration.mockReturnValue(false); mockedAgentPolicyService.hasFleetServerIntegration.mockReturnValue(false); + mockedAgentPolicyService.hasSyntheticsIntegration.mockReturnValue(false); await outputService.update(soClient, esClientMock, 'existing-es-output', { type: 'logstash', @@ -936,7 +1031,7 @@ describe('Output Service', () => { const soClient = getMockedSoClient({ defaultOutputId: 'output-test', }); - mockedAgentPolicyService.list.mockResolvedValue(mockedAgentPolicyResolvedValue); + mockedAgentPolicyService.list.mockResolvedValue(mockedAgentPolicyWithFleetServerResolvedValue); mockedAgentPolicyService.hasFleetServerIntegration.mockReturnValue(true); await outputService.update(soClient, esClientMock, 'output-test', { @@ -965,7 +1060,7 @@ describe('Output Service', () => { const soClient = getMockedSoClient({ defaultOutputId: 'output-test', }); - mockedAgentPolicyService.list.mockResolvedValue(mockedAgentPolicyResolvedValue); + mockedAgentPolicyService.list.mockResolvedValue(mockedAgentPolicyWithFleetServerResolvedValue); mockedAgentPolicyService.hasFleetServerIntegration.mockReturnValue(true); await outputService.update( @@ -998,9 +1093,75 @@ describe('Output Service', () => { ); }); + it('should update synthetics policies with data_output_id=default_output_id if a default ES output is changed to logstash', async () => { + const soClient = getMockedSoClient({ + defaultOutputId: 'output-test', + }); + mockedAgentPolicyService.list.mockResolvedValue(mockedAgentPolicyWithSyntheticsResolvedValue); + mockedAgentPolicyService.hasSyntheticsIntegration.mockReturnValue(true); + + await outputService.update(soClient, esClientMock, 'output-test', { + type: 'logstash', + hosts: ['test:4343'], + is_default: true, + }); + + expect(soClient.update).toBeCalledWith(expect.anything(), expect.anything(), { + type: 'logstash', + hosts: ['test:4343'], + is_default: true, + ca_sha256: null, + ca_trusted_fingerprint: null, + }); + expect(mockedAgentPolicyService.update).toBeCalledWith( + expect.anything(), + expect.anything(), + 'synthetics_policy', + { data_output_id: 'output-test' }, + { force: false } + ); + }); + + it('should update synthetics policies with data_output_id=default_output_id and force=true if a default ES output is changed to logstash, from preconfiguration', async () => { + const soClient = getMockedSoClient({ + defaultOutputId: 'output-test', + }); + mockedAgentPolicyService.list.mockResolvedValue(mockedAgentPolicyWithSyntheticsResolvedValue); + mockedAgentPolicyService.hasSyntheticsIntegration.mockReturnValue(true); + + await outputService.update( + soClient, + esClientMock, + 'output-test', + { + type: 'logstash', + hosts: ['test:4343'], + is_default: true, + }, + { + fromPreconfiguration: true, + } + ); + + expect(soClient.update).toBeCalledWith(expect.anything(), expect.anything(), { + type: 'logstash', + hosts: ['test:4343'], + is_default: true, + ca_sha256: null, + ca_trusted_fingerprint: null, + }); + expect(mockedAgentPolicyService.update).toBeCalledWith( + expect.anything(), + expect.anything(), + 'synthetics_policy', + { data_output_id: 'output-test' }, + { force: true } + ); + }); + it('Should return an error if trying to change the output to logstash for fleet server policy', async () => { const soClient = getMockedSoClient({}); - mockedAgentPolicyService.list.mockResolvedValue(mockedAgentPolicyResolvedValue); + mockedAgentPolicyService.list.mockResolvedValue(mockedAgentPolicyWithFleetServerResolvedValue); mockedAgentPolicyService.hasFleetServerIntegration.mockReturnValue(true); await expect( @@ -1015,35 +1176,7 @@ describe('Output Service', () => { it('Should return an error if trying to change the output to logstash for synthetics policy', async () => { const soClient = getMockedSoClient({}); - mockedAgentPolicyService.list.mockResolvedValue({ - items: [ - { - name: 'synthetics policy', - id: 'synthetics_policy', - package_policies: [ - { - name: 'synthetics-123', - package: { - name: 'synthetics', - }, - }, - ], - }, - { - name: 'agent policy 1', - id: 'agent_policy_1', - is_managed: false, - package_policies: [ - { - name: 'nginx', - package: { - name: 'nginx', - }, - }, - ], - }, - ], - } as unknown as ReturnType); + mockedAgentPolicyService.list.mockResolvedValue(mockedAgentPolicyWithSyntheticsResolvedValue); mockedAgentPolicyService.hasFleetServerIntegration.mockReturnValue(false); mockedAgentPolicyService.hasSyntheticsIntegration.mockReturnValue(true); @@ -1072,7 +1205,6 @@ describe('Output Service', () => { }); // With Kafka output - it('Should delete ES specific fields if the output type changes to kafka', async () => { const soClient = getMockedSoClient({}); mockedAgentPolicyService.list.mockResolvedValue({ @@ -1138,7 +1270,7 @@ describe('Output Service', () => { const soClient = getMockedSoClient({ defaultOutputId: 'output-test', }); - mockedAgentPolicyService.list.mockResolvedValue(mockedAgentPolicyResolvedValue); + mockedAgentPolicyService.list.mockResolvedValue(mockedAgentPolicyWithFleetServerResolvedValue); mockedAgentPolicyService.hasFleetServerIntegration.mockReturnValue(true); await outputService.update(soClient, esClientMock, 'output-test', { @@ -1176,7 +1308,7 @@ describe('Output Service', () => { const soClient = getMockedSoClient({ defaultOutputId: 'output-test', }); - mockedAgentPolicyService.list.mockResolvedValue(mockedAgentPolicyResolvedValue); + mockedAgentPolicyService.list.mockResolvedValue(mockedAgentPolicyWithFleetServerResolvedValue); mockedAgentPolicyService.hasFleetServerIntegration.mockReturnValue(true); await outputService.update( @@ -1217,6 +1349,90 @@ describe('Output Service', () => { { force: true } ); }); + + it('should update synthetics policies with data_output_id=default_output_id if a default ES output is changed to kafka', async () => { + const soClient = getMockedSoClient({ + defaultOutputId: 'output-test', + }); + mockedAgentPolicyService.list.mockResolvedValue(mockedAgentPolicyWithSyntheticsResolvedValue); + mockedAgentPolicyService.hasSyntheticsIntegration.mockReturnValue(true); + + await outputService.update(soClient, esClientMock, 'output-test', { + type: 'kafka', + hosts: ['http://test:4343'], + is_default: true, + }); + + expect(soClient.update).toBeCalledWith(expect.anything(), expect.anything(), { + type: 'kafka', + hosts: ['http://test:4343'], + is_default: true, + ca_sha256: null, + ca_trusted_fingerprint: null, + client_id: 'Elastic Agent', + compression: 'gzip', + compression_level: 4, + partition: 'hash', + timeout: 30, + version: '1.0.0', + broker_timeout: 10, + broker_ack_reliability: 'Wait for local commit', + broker_buffer_size: 256, + }); + expect(mockedAgentPolicyService.update).toBeCalledWith( + expect.anything(), + expect.anything(), + 'synthetics_policy', + { data_output_id: 'output-test' }, + { force: false } + ); + }); + + it('should update synthetics policies with data_output_id=default_output_id and force=true if a default ES output is changed to kafka, from preconfiguration', async () => { + const soClient = getMockedSoClient({ + defaultOutputId: 'output-test', + }); + mockedAgentPolicyService.list.mockResolvedValue(mockedAgentPolicyWithSyntheticsResolvedValue); + mockedAgentPolicyService.hasSyntheticsIntegration.mockReturnValue(true); + + await outputService.update( + soClient, + esClientMock, + 'output-test', + { + type: 'kafka', + hosts: ['http://test:4343'], + is_default: true, + }, + { + fromPreconfiguration: true, + } + ); + + expect(soClient.update).toBeCalledWith(expect.anything(), expect.anything(), { + type: 'kafka', + hosts: ['http://test:4343'], + is_default: true, + ca_sha256: null, + ca_trusted_fingerprint: null, + client_id: 'Elastic Agent', + compression: 'gzip', + compression_level: 4, + partition: 'hash', + timeout: 30, + version: '1.0.0', + broker_timeout: 10, + broker_ack_reliability: 'Wait for local commit', + broker_buffer_size: 256, + }); + expect(mockedAgentPolicyService.update).toBeCalledWith( + expect.anything(), + expect.anything(), + 'synthetics_policy', + { data_output_id: 'output-test' }, + { force: true } + ); + }); }); describe('delete', () => { From 4460a2dbc8e001775b7bae1c7113fa0846a2da2d Mon Sep 17 00:00:00 2001 From: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Date: Mon, 17 Jul 2023 17:37:07 +0000 Subject: [PATCH 4/4] [CI] Auto-commit changed files from 'node scripts/eslint --no-cache --fix' --- .../fleet/server/services/output.test.ts | 36 ++++++++++++++----- 1 file changed, 27 insertions(+), 9 deletions(-) diff --git a/x-pack/plugins/fleet/server/services/output.test.ts b/x-pack/plugins/fleet/server/services/output.test.ts index af5778c86304a..5ecd3a4a29a40 100644 --- a/x-pack/plugins/fleet/server/services/output.test.ts +++ b/x-pack/plugins/fleet/server/services/output.test.ts @@ -478,7 +478,9 @@ describe('Output Service', () => { mockedAppContextService.getEncryptedSavedObjectsSetup.mockReturnValue({ canEncrypt: true, } as any); - mockedAgentPolicyService.list.mockResolvedValue(mockedAgentPolicyWithFleetServerResolvedValue); + mockedAgentPolicyService.list.mockResolvedValue( + mockedAgentPolicyWithFleetServerResolvedValue + ); mockedAgentPolicyService.hasFleetServerIntegration.mockReturnValue(true); await outputService.create( @@ -540,7 +542,9 @@ describe('Output Service', () => { mockedAppContextService.getEncryptedSavedObjectsSetup.mockReturnValue({ canEncrypt: true, } as any); - mockedAgentPolicyService.list.mockResolvedValue(mockedAgentPolicyWithFleetServerResolvedValue); + mockedAgentPolicyService.list.mockResolvedValue( + mockedAgentPolicyWithFleetServerResolvedValue + ); mockedAgentPolicyService.hasFleetServerIntegration.mockReturnValue(true); await outputService.create( @@ -586,7 +590,9 @@ describe('Output Service', () => { mockedAppContextService.getEncryptedSavedObjectsSetup.mockReturnValue({ canEncrypt: true, } as any); - mockedAgentPolicyService.list.mockResolvedValue(mockedAgentPolicyWithFleetServerResolvedValue); + mockedAgentPolicyService.list.mockResolvedValue( + mockedAgentPolicyWithFleetServerResolvedValue + ); mockedAgentPolicyService.hasFleetServerIntegration.mockReturnValue(true); await outputService.create( @@ -648,7 +654,9 @@ describe('Output Service', () => { mockedAppContextService.getEncryptedSavedObjectsSetup.mockReturnValue({ canEncrypt: true, } as any); - mockedAgentPolicyService.list.mockResolvedValue(mockedAgentPolicyWithFleetServerResolvedValue); + mockedAgentPolicyService.list.mockResolvedValue( + mockedAgentPolicyWithFleetServerResolvedValue + ); mockedAgentPolicyService.hasFleetServerIntegration.mockReturnValue(true); await outputService.create( @@ -1031,7 +1039,9 @@ describe('Output Service', () => { const soClient = getMockedSoClient({ defaultOutputId: 'output-test', }); - mockedAgentPolicyService.list.mockResolvedValue(mockedAgentPolicyWithFleetServerResolvedValue); + mockedAgentPolicyService.list.mockResolvedValue( + mockedAgentPolicyWithFleetServerResolvedValue + ); mockedAgentPolicyService.hasFleetServerIntegration.mockReturnValue(true); await outputService.update(soClient, esClientMock, 'output-test', { @@ -1060,7 +1070,9 @@ describe('Output Service', () => { const soClient = getMockedSoClient({ defaultOutputId: 'output-test', }); - mockedAgentPolicyService.list.mockResolvedValue(mockedAgentPolicyWithFleetServerResolvedValue); + mockedAgentPolicyService.list.mockResolvedValue( + mockedAgentPolicyWithFleetServerResolvedValue + ); mockedAgentPolicyService.hasFleetServerIntegration.mockReturnValue(true); await outputService.update( @@ -1161,7 +1173,9 @@ describe('Output Service', () => { it('Should return an error if trying to change the output to logstash for fleet server policy', async () => { const soClient = getMockedSoClient({}); - mockedAgentPolicyService.list.mockResolvedValue(mockedAgentPolicyWithFleetServerResolvedValue); + mockedAgentPolicyService.list.mockResolvedValue( + mockedAgentPolicyWithFleetServerResolvedValue + ); mockedAgentPolicyService.hasFleetServerIntegration.mockReturnValue(true); await expect( @@ -1270,7 +1284,9 @@ describe('Output Service', () => { const soClient = getMockedSoClient({ defaultOutputId: 'output-test', }); - mockedAgentPolicyService.list.mockResolvedValue(mockedAgentPolicyWithFleetServerResolvedValue); + mockedAgentPolicyService.list.mockResolvedValue( + mockedAgentPolicyWithFleetServerResolvedValue + ); mockedAgentPolicyService.hasFleetServerIntegration.mockReturnValue(true); await outputService.update(soClient, esClientMock, 'output-test', { @@ -1308,7 +1324,9 @@ describe('Output Service', () => { const soClient = getMockedSoClient({ defaultOutputId: 'output-test', }); - mockedAgentPolicyService.list.mockResolvedValue(mockedAgentPolicyWithFleetServerResolvedValue); + mockedAgentPolicyService.list.mockResolvedValue( + mockedAgentPolicyWithFleetServerResolvedValue + ); mockedAgentPolicyService.hasFleetServerIntegration.mockReturnValue(true); await outputService.update(