From ce24b0c1fb8a31d0fe55e5ab176ec42d71e65ba0 Mon Sep 17 00:00:00 2001 From: Jen Huang Date: Wed, 20 Nov 2024 14:28:17 -0800 Subject: [PATCH 1/5] Allow to create integration policy with no agent policies --- .../single_page_layout/hooks/form.tsx | 4 ++-- .../agent_policy/services/devtools_request.tsx | 7 ++++++- .../fleet/public/hooks/use_multiple_agent_policies.ts | 11 ++++++----- 3 files changed, 14 insertions(+), 8 deletions(-) diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/hooks/form.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/hooks/form.tsx index 0c3f54d9e5dff..3dbe300b119bd 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/hooks/form.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/hooks/form.tsx @@ -280,7 +280,7 @@ export function useOnSubmit({ useEffect(() => { if ( - agentPolicies.length > 0 && + (canUseMultipleAgentPolicies || agentPolicies.length > 0) && !isEqual( agentPolicies.map((policy) => policy.id), packagePolicy.policy_ids @@ -290,7 +290,7 @@ export function useOnSubmit({ policy_ids: agentPolicies.map((policy) => policy.id), }); } - }, [packagePolicy, agentPolicies, updatePackagePolicy]); + }, [packagePolicy, agentPolicies, updatePackagePolicy, canUseMultipleAgentPolicies]); const onSaveNavigate = useOnSaveNavigate({ packagePolicy, diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/services/devtools_request.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/services/devtools_request.tsx index 8badac52213e4..aa866106e8421 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/services/devtools_request.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/services/devtools_request.tsx @@ -18,6 +18,7 @@ import type { UpdatePackagePolicy, UpdateAgentPolicyRequest, } from '../../../types'; +import { canUseMultipleAgentPolicies } from '../../../hooks'; function generateKibanaDevToolsRequest(method: string, path: string, body: any) { return `${method} kbn:${path}\n${JSON.stringify(body, null, 2)}\n`; @@ -49,9 +50,13 @@ export function generateCreateAgentPolicyDevToolsRequest( export function generateCreatePackagePolicyDevToolsRequest( packagePolicy: NewPackagePolicy & { force?: boolean } ) { + const canHaveNoAgentPolicies = canUseMultipleAgentPolicies(); + return generateKibanaDevToolsRequest('POST', packagePolicyRouteService.getCreatePath(), { policy_ids: - packagePolicy.policy_ids.length > 0 ? packagePolicy.policy_ids : [''], + packagePolicy.policy_ids.length > 0 || canHaveNoAgentPolicies + ? packagePolicy.policy_ids + : [''], package: formatPackage(packagePolicy.package), ...omit(packagePolicy, 'policy_ids', 'package', 'enabled'), inputs: formatInputs(packagePolicy.inputs), diff --git a/x-pack/plugins/fleet/public/hooks/use_multiple_agent_policies.ts b/x-pack/plugins/fleet/public/hooks/use_multiple_agent_policies.ts index b85b944c6ee00..b2648b1d55da7 100644 --- a/x-pack/plugins/fleet/public/hooks/use_multiple_agent_policies.ts +++ b/x-pack/plugins/fleet/public/hooks/use_multiple_agent_policies.ts @@ -8,15 +8,16 @@ import { LICENCE_FOR_MULTIPLE_AGENT_POLICIES } from '../../common/constants'; import { ExperimentalFeaturesService } from '../services'; -import { useLicense } from './use_license'; +import { licenseService } from './use_license'; export function useMultipleAgentPolicies() { - const licenseService = useLicense(); + return { canUseMultipleAgentPolicies: canUseMultipleAgentPolicies() }; +} + +export function canUseMultipleAgentPolicies() { const { enableReusableIntegrationPolicies } = ExperimentalFeaturesService.get(); const hasEnterpriseLicence = licenseService.hasAtLeast(LICENCE_FOR_MULTIPLE_AGENT_POLICIES); - const canUseMultipleAgentPolicies = enableReusableIntegrationPolicies && hasEnterpriseLicence; - - return { canUseMultipleAgentPolicies }; + return Boolean(enableReusableIntegrationPolicies && hasEnterpriseLicence); } From e3792b31acbfd04052f854d3d0092d0b46706336 Mon Sep 17 00:00:00 2001 From: Jen Huang Date: Thu, 21 Nov 2024 10:54:43 -0800 Subject: [PATCH 2/5] Allow new hosts/existing hosts tab selectors even when no agent policies exist yet --- .../components/steps/step_select_hosts.tsx | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/components/steps/step_select_hosts.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/components/steps/step_select_hosts.tsx index c4504e6596353..5a9d6fd6e31f0 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/components/steps/step_select_hosts.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/components/steps/step_select_hosts.tsx @@ -105,7 +105,7 @@ export const StepSelectHosts: React.FunctionComponent = ({ const handleOnTabClick = (tab: EuiTabbedContentTab) => updateSelectedTab(tab.id as SelectedPolicyTab); - return existingAgentPolicies.length > 0 ? ( + return ( = ({ tabs={tabs} onTabClick={handleOnTabClick} /> - ) : ( - ); }; From 8e4c019cc0c7d97ce97b93d7ea047627228357b0 Mon Sep 17 00:00:00 2001 From: Jen Huang Date: Thu, 21 Nov 2024 10:54:56 -0800 Subject: [PATCH 3/5] Add cypress test --- .../fleet/cypress/e2e/package_policy.cy.ts | 87 +++++++++++++------ .../fleet/cypress/screens/integrations.ts | 1 + 2 files changed, 60 insertions(+), 28 deletions(-) diff --git a/x-pack/plugins/fleet/cypress/e2e/package_policy.cy.ts b/x-pack/plugins/fleet/cypress/e2e/package_policy.cy.ts index 271d2ba7b871d..1c1191e32ded1 100644 --- a/x-pack/plugins/fleet/cypress/e2e/package_policy.cy.ts +++ b/x-pack/plugins/fleet/cypress/e2e/package_policy.cy.ts @@ -4,36 +4,46 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ +import { EXISTING_HOSTS_TAB } from '../screens/fleet'; +import { + ADD_INTEGRATION_POLICY_BTN, + CREATE_PACKAGE_POLICY_SAVE_BTN, + POLICY_EDITOR, +} from '../screens/integrations'; +import { CONFIRM_MODAL } from '../screens/navigation'; import { login } from '../tasks/login'; -describe('Edit package policy', () => { - const policyConfig = { - id: 'policy-1', - name: 'fleet_server-1', - namespace: 'default', - package: { name: 'fleet_server', title: 'Fleet Server', version: '1.1.0' }, - enabled: true, - policy_id: 'fleet-server-policy', - policy_ids: ['fleet-server-policy'], - output_id: 'fleet-default-output', - inputs: [ - { - type: 'fleet-server', - policy_template: 'fleet_server', - enabled: true, - streams: [], - vars: { - host: { value: ['0.0.0.0'], type: 'text' }, - port: { value: [8220], type: 'integer' }, - max_connections: { type: 'integer' }, - custom: { value: '', type: 'yaml' }, - }, - compiled_input: { server: { port: 8220, host: '0.0.0.0' } }, - }, - ], - }; +describe('Package policy', () => { beforeEach(() => { login(); + }); + + it('should edit package policy', () => { + const policyConfig = { + id: 'policy-1', + name: 'fleet_server-1', + namespace: 'default', + package: { name: 'fleet_server', title: 'Fleet Server', version: '1.1.0' }, + enabled: true, + policy_id: 'fleet-server-policy', + policy_ids: ['fleet-server-policy'], + output_id: 'fleet-default-output', + inputs: [ + { + type: 'fleet-server', + policy_template: 'fleet_server', + enabled: true, + streams: [], + vars: { + host: { value: ['0.0.0.0'], type: 'text' }, + port: { value: [8220], type: 'integer' }, + max_connections: { type: 'integer' }, + custom: { value: '', type: 'yaml' }, + }, + compiled_input: { server: { port: 8220, host: '0.0.0.0' } }, + }, + ], + }; cy.intercept('/api/fleet/package_policies/policy-1', { item: policyConfig, @@ -111,9 +121,7 @@ describe('Edit package policy', () => { status: 'not_installed', }, }); - }); - it('should edit package policy', () => { cy.visit('/app/fleet/policies/fleet-server-policy/edit-integration/policy-1'); cy.getBySel('packagePolicyDescriptionInput').clear().type('desc'); @@ -128,4 +136,27 @@ describe('Edit package policy', () => { expect(interception.request.body.description).to.equal('desc'); }); }); + + it('should create a new orphaned package policy', () => { + cy.visit('/app/integrations/detail/system'); + cy.getBySel(ADD_INTEGRATION_POLICY_BTN).click(); + cy.getBySel(EXISTING_HOSTS_TAB).click(); + cy.getBySel(POLICY_EDITOR.AGENT_POLICY_SELECT).should('exist'); + cy.getBySel(POLICY_EDITOR.AGENT_POLICY_CLEAR).should('not.exist'); + cy.getBySel(POLICY_EDITOR.POLICY_NAME_INPUT).clear().type('system-orphaned-test'); + + cy.intercept({ + method: 'POST', + url: '/api/fleet/package_policies', + }).as('createPackagePolicy'); + + cy.getBySel(CREATE_PACKAGE_POLICY_SAVE_BTN).should('be.enabled').click(); + cy.getBySel(CONFIRM_MODAL.CONFIRM_BUTTON).click(); + + cy.wait('@createPackagePolicy').then((interception) => { + expect(interception.request.body.name).to.equal('system-orphaned-test'); + expect(interception.request.body.policy_id).to.equal(undefined); + expect(interception.request.body.policy_ids).to.deep.equal([]); + }); + }); }); diff --git a/x-pack/plugins/fleet/cypress/screens/integrations.ts b/x-pack/plugins/fleet/cypress/screens/integrations.ts index 1a31d2dc5de31..8b29a95265ff2 100644 --- a/x-pack/plugins/fleet/cypress/screens/integrations.ts +++ b/x-pack/plugins/fleet/cypress/screens/integrations.ts @@ -39,6 +39,7 @@ export const POLICY_EDITOR = { POLICY_NAME_INPUT: 'packagePolicyNameInput', DATASET_SELECT: 'datasetComboBox', AGENT_POLICY_SELECT: 'agentPolicyMultiSelect', + AGENT_POLICY_CLEAR: 'comboBoxClearButton', INSPECT_PIPELINES_BTN: 'datastreamInspectPipelineBtn', EDIT_MAPPINGS_BTN: 'datastreamEditMappingsBtn', CREATE_MAPPINGS_BTN: 'datastreamAddCustomComponentTemplateBtn', From 9dd17fd27c2e9c1a8d7cb6d9bf2842a4744139b8 Mon Sep 17 00:00:00 2001 From: Jen Huang Date: Thu, 21 Nov 2024 12:52:16 -0800 Subject: [PATCH 4/5] Fix jest tests --- .../components/steps/step_select_hosts.test.tsx | 2 +- .../components/step_edit_hosts.test.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/components/steps/step_select_hosts.test.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/components/steps/step_select_hosts.test.tsx index 583957861bd79..2c2cd4a670d2f 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/components/steps/step_select_hosts.test.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/components/steps/step_select_hosts.test.tsx @@ -123,7 +123,7 @@ describe('StepSelectHosts', () => { await waitFor(() => { expect(renderResult.getByText('New agent policy name')).toBeInTheDocument(); }); - expect(renderResult.queryByRole('tablist')).not.toBeInTheDocument(); + expect(renderResult.queryByRole('tablist')).toBeInTheDocument(); }); it('should display tabs with New hosts selected when agent policies exist', async () => { diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/edit_package_policy_page/components/step_edit_hosts.test.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/edit_package_policy_page/components/step_edit_hosts.test.tsx index e30fa6c22c5ce..f03de5cbcadbd 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/edit_package_policy_page/components/step_edit_hosts.test.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/edit_package_policy_page/components/step_edit_hosts.test.tsx @@ -125,7 +125,7 @@ describe('StepEditHosts', () => { render(); expect(renderResult.getByText('New agent policy name')).toBeInTheDocument(); - expect(renderResult.queryByRole('tablist')).not.toBeInTheDocument(); + expect(renderResult.queryByRole('tablist')).toBeInTheDocument(); }); it('should display new policy button and existing policies when agent policies exist', () => { From bc40e46880cb84f6629928d4cc41a16e819828ac Mon Sep 17 00:00:00 2001 From: Jen Huang Date: Thu, 21 Nov 2024 13:58:17 -0800 Subject: [PATCH 5/5] Allow orphaned policy on edit, adjust tests --- .../components/steps/step_select_hosts.test.tsx | 1 + .../components/step_edit_hosts.test.tsx | 5 +++-- .../components/step_edit_hosts.tsx | 10 +--------- 3 files changed, 5 insertions(+), 11 deletions(-) diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/components/steps/step_select_hosts.test.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/components/steps/step_select_hosts.test.tsx index 2c2cd4a670d2f..dd3945664bd6f 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/components/steps/step_select_hosts.test.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/components/steps/step_select_hosts.test.tsx @@ -124,6 +124,7 @@ describe('StepSelectHosts', () => { expect(renderResult.getByText('New agent policy name')).toBeInTheDocument(); }); expect(renderResult.queryByRole('tablist')).toBeInTheDocument(); + expect(renderResult.getByText('Create agent policy')).toBeInTheDocument(); }); it('should display tabs with New hosts selected when agent policies exist', async () => { diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/edit_package_policy_page/components/step_edit_hosts.test.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/edit_package_policy_page/components/step_edit_hosts.test.tsx index f03de5cbcadbd..249b037a6f6c3 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/edit_package_policy_page/components/step_edit_hosts.test.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/edit_package_policy_page/components/step_edit_hosts.test.tsx @@ -124,8 +124,9 @@ describe('StepEditHosts', () => { render(); - expect(renderResult.getByText('New agent policy name')).toBeInTheDocument(); - expect(renderResult.queryByRole('tablist')).toBeInTheDocument(); + expect(renderResult.queryByRole('tablist')).not.toBeInTheDocument(); + expect(renderResult.getByText('For existing hosts:')).toBeInTheDocument(); + expect(renderResult.getByText('For a new host:')).toBeInTheDocument(); }); it('should display new policy button and existing policies when agent policies exist', () => { diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/edit_package_policy_page/components/step_edit_hosts.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/edit_package_policy_page/components/step_edit_hosts.tsx index 64d104172af53..54e210eddc3c1 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/edit_package_policy_page/components/step_edit_hosts.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/edit_package_policy_page/components/step_edit_hosts.tsx @@ -60,7 +60,7 @@ export const StepEditHosts: React.FunctionComponent = ({ } }, [existingAgentPolicies.length]); // eslint-disable-line react-hooks/exhaustive-deps - return existingAgentPolicies.length > 0 ? ( + return ( @@ -141,13 +141,5 @@ export const StepEditHosts: React.FunctionComponent = ({ )} - ) : ( - ); };