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', 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 7d1962939d1fa..1571498928629 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 @@ -119,8 +119,9 @@ describe('StepSelectHosts', () => { waitFor(() => { expect(renderResult.getByText('Agent policy 1')).toBeInTheDocument(); + expect(renderResult.queryByRole('tablist')).toBeInTheDocument(); + expect(renderResult.getByText('Create agent policy')).toBeInTheDocument(); }); - expect(renderResult.queryByRole('tablist')).not.toBeInTheDocument(); }); it('should display tabs with New hosts selected when agent policies exist', () => { 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} /> - ) : ( - ); }; 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 1488e9c83f4d3..0f13ccaa574b1 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/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 064624d364a92..e4112c0bd733a 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 @@ -121,9 +121,10 @@ describe('StepEditHosts', () => { render(); waitFor(() => { - expect(renderResult.getByText('Agent policy 1')).toBeInTheDocument(); + expect(renderResult.queryByRole('tablist')).not.toBeInTheDocument(); + expect(renderResult.getByText('For existing hosts:')).toBeInTheDocument(); + expect(renderResult.getByText('For a new host:')).toBeInTheDocument(); }); - expect(renderResult.queryByRole('tablist')).not.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 = ({ )} - ) : ( - ); }; 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); }