From a74316faf4b18481880c71511f1e08eb6f13140d Mon Sep 17 00:00:00 2001 From: Lola Date: Tue, 27 Aug 2024 14:40:55 -0400 Subject: [PATCH 01/44] allow agentless deletion on agent and integration policy --- .../single_page_layout/hooks/setup_technology.ts | 1 - .../agent_policy/edit_package_policy_page/index.tsx | 6 ++++-- .../public/components/package_policy_actions_menu.tsx | 9 +-------- x-pack/plugins/fleet/server/services/agent_policy.ts | 6 +++--- .../fleet/server/services/agent_policy_create.ts | 10 ++++------ x-pack/plugins/fleet/server/services/package_policy.ts | 3 +-- 6 files changed, 13 insertions(+), 22 deletions(-) diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/hooks/setup_technology.ts b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/hooks/setup_technology.ts index 5cafedee7db7b..1041ad5a689f9 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/hooks/setup_technology.ts +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/hooks/setup_technology.ts @@ -174,7 +174,6 @@ export function useSetupTechnology({ setNewAgentPolicy({ ...newAgentBasedPolicy.current, supports_agentless: false, - is_managed: false, }); setSelectedPolicyTab(SelectedPolicyTab.NEW); updateAgentPolicies([newAgentBasedPolicy.current] as AgentPolicy[]); diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/edit_package_policy_page/index.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/edit_package_policy_page/index.tsx index 8150a61b93fba..dcacc66e3fdb5 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/edit_package_policy_page/index.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/edit_package_policy_page/index.tsx @@ -107,7 +107,7 @@ export const EditPackagePolicyForm = memo<{ } = useConfig(); const { getHref } = useLink(); const { canUseMultipleAgentPolicies } = useMultipleAgentPolicies(); - const { isAgentlessPackagePolicy } = useAgentless(); + const { isAgentlessAgentPolicy } = useAgentless(); const { // data @@ -439,6 +439,8 @@ export const EditPackagePolicyForm = memo<{ ] ); + const agentlessPolicy = agentPolicies.find((agentPolicy) => agentPolicy?.supports_agentless); + const replaceConfigurePackage = replaceDefineStepView && originalPackagePolicy && packageInfo && ( ); diff --git a/x-pack/plugins/fleet/public/components/package_policy_actions_menu.tsx b/x-pack/plugins/fleet/public/components/package_policy_actions_menu.tsx index 0eb0000af4fa4..3d9803c1c0888 100644 --- a/x-pack/plugins/fleet/public/components/package_policy_actions_menu.tsx +++ b/x-pack/plugins/fleet/public/components/package_policy_actions_menu.tsx @@ -13,8 +13,6 @@ import type { AgentPolicy, InMemoryPackagePolicy } from '../types'; import { useAgentPolicyRefresh, useAuthz, useLink, useStartServices } from '../hooks'; import { policyHasFleetServer } from '../services'; -import { PLUGIN_ID, pagePathGetters } from '../constants'; - import { AgentEnrollmentFlyout } from './agent_enrollment_flyout'; import { ContextMenuActions } from './context_menu_actions'; import { DangerEuiContextMenuItem } from './danger_eui_context_menu_item'; @@ -143,12 +141,7 @@ export const PackagePolicyActionsMenu: React.FunctionComponent<{ onClick={() => { deletePackagePoliciesPrompt([packagePolicy.id], () => { setIsActionsMenuOpen(false); - if (agentPolicy?.supports_agentless) { - // go back to all agent policies - navigateToApp(PLUGIN_ID, { path: pagePathGetters.policies_list()[1] }); - } else { - refreshAgentPolicy(); - } + refreshAgentPolicy(); }); }} > diff --git a/x-pack/plugins/fleet/server/services/agent_policy.ts b/x-pack/plugins/fleet/server/services/agent_policy.ts index 250cd867ee875..e44f9f80bec90 100644 --- a/x-pack/plugins/fleet/server/services/agent_policy.ts +++ b/x-pack/plugins/fleet/server/services/agent_policy.ts @@ -385,7 +385,7 @@ class AgentPolicyService { { ...agentPolicy, status: 'active', - is_managed: (agentPolicy.is_managed || agentPolicy?.supports_agentless) ?? false, + is_managed: agentPolicy.is_managed ?? false, revision: 1, updated_at: new Date().toISOString(), updated_by: options?.user?.username || 'system', @@ -1103,7 +1103,7 @@ class AgentPolicyService { kuery: `${AGENTS_PREFIX}.policy_id:${id}`, }); - if (total > 0) { + if (total > 0 && !agentPolicy?.supports_agentless) { throw new FleetError( 'Cannot delete an agent policy that is assigned to any active or inactive agents' ); @@ -1752,7 +1752,7 @@ export async function addPackageToAgentPolicy( ? String(packagePolicyId) : uuidv5(`${agentPolicy.id}-${packagePolicyName}`, UUID_V5_NAMESPACE); - await packagePolicyService.create(soClient, esClient, newPackagePolicy, { + await packagePolicyService.creaƒte(soClient, esClient, newPackagePolicy, { id, bumpRevision: bumpAgentPolicyRevison, skipEnsureInstalled: true, diff --git a/x-pack/plugins/fleet/server/services/agent_policy_create.ts b/x-pack/plugins/fleet/server/services/agent_policy_create.ts index 4d22820b9aa1c..7807b5f0d070e 100644 --- a/x-pack/plugins/fleet/server/services/agent_policy_create.ts +++ b/x-pack/plugins/fleet/server/services/agent_policy_create.ts @@ -21,8 +21,6 @@ import { import type { AgentPolicy, NewAgentPolicy } from '../types'; -import { agentlessAgentService } from './agents/agentless_agent'; - import { agentPolicyService, packagePolicyService } from '.'; import { incrementPackageName } from './package_policies'; import { bulkInstallPackages } from './epm/packages'; @@ -84,7 +82,7 @@ async function createPackagePolicy( user: options.user, bumpRevision: false, authorizationHeader: options.authorizationHeader, - force: options.force || agentPolicy.supports_agentless === true, + force: options.force, }); } @@ -174,9 +172,9 @@ export async function createAgentPolicyWithPackages({ await agentPolicyService.deployPolicy(soClient, agentPolicy.id); // Create the agentless agent - if (agentPolicy.supports_agentless) { - await agentlessAgentService.createAgentlessAgent(esClient, soClient, agentPolicy); - } + // if (agentPolicy.supports_agentless) { + // // await agentlessAgentService.createAgentlessAgent(esClient, soClient, agentPolicy); + // } return agentPolicy; } diff --git a/x-pack/plugins/fleet/server/services/package_policy.ts b/x-pack/plugins/fleet/server/services/package_policy.ts index a53334c893fec..706bd941ed929 100644 --- a/x-pack/plugins/fleet/server/services/package_policy.ts +++ b/x-pack/plugins/fleet/server/services/package_policy.ts @@ -2952,8 +2952,7 @@ async function validateIsNotHostedPolicy( throw new AgentPolicyNotFoundError('Agent policy not found'); } - const isManagedPolicyWithoutServerlessSupport = - agentPolicy.is_managed && !agentPolicy.supports_agentless && !force; + const isManagedPolicyWithoutServerlessSupport = agentPolicy.is_managed && !force; if (isManagedPolicyWithoutServerlessSupport) { throw new HostedAgentPolicyRestrictionRelatedError( From b76008404f36b9b21df6351b2987330f3b5f1d22 Mon Sep 17 00:00:00 2001 From: Lola Date: Tue, 27 Aug 2024 14:42:46 -0400 Subject: [PATCH 02/44] ensure confirm state is only for agent-based policies and integrations --- .../single_page_layout/hooks/form.tsx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) 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 697731f744721..0cec2a063b2de 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 @@ -316,7 +316,11 @@ export function useOnSubmit({ } if ( agentCount !== 0 && - !(isAgentlessIntegration(packageInfo) || isAgentlessPackagePolicy(packagePolicy)) && + !( + isAgentlessIntegration(packageInfo) || + isAgentlessPackagePolicy(packagePolicy) || + isAgentlessAgentPolicy(overrideCreatedAgentPolicy) + ) && formState !== 'CONFIRM' ) { setFormState('CONFIRM'); From aa1cd50b70c336846553019e88a7c17bf41dd637 Mon Sep 17 00:00:00 2001 From: Lola Date: Tue, 27 Aug 2024 17:56:31 -0400 Subject: [PATCH 03/44] add agentless agent deletion endpoint --- .../fleet/server/services/agent_policy.ts | 7 ++ .../server/services/agents/agentless_agent.ts | 85 ++++++++++++++++++- .../fleet/server/services/utils/agentless.ts | 7 ++ 3 files changed, 98 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/fleet/server/services/agent_policy.ts b/x-pack/plugins/fleet/server/services/agent_policy.ts index e44f9f80bec90..d0842cd508ac4 100644 --- a/x-pack/plugins/fleet/server/services/agent_policy.ts +++ b/x-pack/plugins/fleet/server/services/agent_policy.ts @@ -112,6 +112,7 @@ import { createSoFindIterable } from './utils/create_so_find_iterable'; import { isAgentlessEnabled } from './utils/agentless'; import { validatePolicyNamespaceForSpace } from './spaces/policy_namespaces'; import { isSpaceAwarenessEnabled } from './spaces/helpers'; +import { agentlessAgentService } from './agents/agentless_agent'; const KEY_EDITABLE_FOR_MANAGED_POLICIES = ['namespace']; @@ -1095,6 +1096,7 @@ class AgentPolicyService { if (agentPolicy.is_managed && !options?.force) { throw new HostedAgentPolicyRestrictionRelatedError(`Cannot delete hosted agent policy ${id}`); } + // Prevent deleting policy when assigned agents are inactive const { total } = await getAgentsByKuery(esClient, soClient, { showInactive: true, @@ -1109,6 +1111,11 @@ class AgentPolicyService { ); } + if (agentPolicy?.supports_agentless) { + await agentlessAgentService.deleteAgentlessAgent(id); + logger.debug(`Deleted agentless policy with single agent policy with id ${agentPolicy.id}`); + } + const packagePolicies = await packagePolicyService.findAllForAgentPolicy(soClient, id); if (packagePolicies.length) { diff --git a/x-pack/plugins/fleet/server/services/agents/agentless_agent.ts b/x-pack/plugins/fleet/server/services/agents/agentless_agent.ts index 627bdf38b8fe2..e6f2d13722dd8 100644 --- a/x-pack/plugins/fleet/server/services/agents/agentless_agent.ts +++ b/x-pack/plugins/fleet/server/services/agents/agentless_agent.ts @@ -22,7 +22,11 @@ import { appContextService } from '../app_context'; import { listEnrollmentApiKeys } from '../api_keys'; import { listFleetServerHosts } from '../fleet_server_host'; -import { prependAgentlessApiBasePathToEndpoint, isAgentlessApiEnabled } from '../utils/agentless'; +import { + prependAgentlessApiBasePathToEndpoint, + isAgentlessApiEnabled, + getDeletionEndpointPath, +} from '../utils/agentless'; class AgentlessAgentService { public async createAgentlessAgent( @@ -137,6 +141,85 @@ class AgentlessAgentService { return response; } + public async deleteAgentlessAgent(agentlessPolicyId: string) { + const logger = appContextService.getLogger(); + logger.debug(`Start deleting agentless agent for agent policy - ${agentlessPolicyId}`); + + if (!isAgentlessApiEnabled) { + logger.error( + 'Agentless API is not supported. Deleting agentless agent is not supported in non-cloud or non-serverless environments' + ); + } + + const agentlessConfig = appContextService.getConfig()?.agentless; + if (!agentlessConfig) { + logger.error('kibana.yml is currently missing Agentless API configuration'); + } + + logger.debug(`Deleting agentless agent with TLS config with certificate`); + + const tlsConfig = new SslConfig( + sslSchema.validate({ + enabled: true, + certificate: agentlessConfig?.api?.tls?.certificate, + key: agentlessConfig?.api?.tls?.key, + certificateAuthorities: agentlessConfig?.api?.tls?.ca, + }) + ); + + const requestConfig = { + url: getDeletionEndpointPath(agentlessConfig, `/deployments/${agentlessPolicyId}`), + method: 'DELETE', + headers: { + 'Content-type': 'application/json', + }, + httpsAgent: new https.Agent({ + rejectUnauthorized: tlsConfig.rejectUnauthorized, + cert: tlsConfig.certificate, + key: tlsConfig.key, + ca: tlsConfig.certificateAuthorities, + }), + }; + + logger.debug( + `Deleting agentless agent with request config ${JSON.stringify({ + ...requestConfig, + httpsAgent: { + ...requestConfig.httpsAgent, + options: { + ...requestConfig.httpsAgent.options, + cert: requestConfig.httpsAgent.options.cert ? 'REDACTED' : undefined, + key: requestConfig.httpsAgent.options.key ? 'REDACTED' : undefined, + ca: requestConfig.httpsAgent.options.ca ? 'REDACTED' : undefined, + }, + }, + })}` + ); + + const response = await axios(requestConfig).catch((error: AxiosError) => { + if (!axios.isAxiosError(error)) { + logger.error(`Deleting agentless failed with an error ${error}`); + } + if (error.response) { + logger.error( + `DELETE Agentless Agent Response Error: ${error.response.status} - ${error.response.statusText} Deleting agentless agent failed for agent policy id ${agentlessPolicyId}.` + ); + } else if (error.request) { + logger.error( + `Deleting agentless failed to receive a response from the Agentless API ${JSON.stringify( + error.cause + )}` + ); + } else { + logger.error( + `Deleting agentless failed to delete the request ${JSON.stringify(error.cause)}` + ); + } + }); + + return response; + } + private async getFleetUrlAndTokenForAgentlessAgent( esClient: ElasticsearchClient, policyId: string, diff --git a/x-pack/plugins/fleet/server/services/utils/agentless.ts b/x-pack/plugins/fleet/server/services/utils/agentless.ts index 5c544b1907b25..4828bcff3ebb6 100644 --- a/x-pack/plugins/fleet/server/services/utils/agentless.ts +++ b/x-pack/plugins/fleet/server/services/utils/agentless.ts @@ -38,3 +38,10 @@ export const prependAgentlessApiBasePathToEndpoint = ( : AGENTLESS_ESS_API_BASE_PATH; return `${agentlessConfig.api.url}${endpointPrefix}${endpoint}`; }; + +export const getDeletionEndpointPath = ( + agentlessConfig: FleetConfigType['agentless'], + endpoint: AgentlessApiEndpoints +) => { + return `${agentlessConfig.api.url}${AGENTLESS_ESS_API_BASE_PATH}${endpoint}`; +}; From f50533413cea9c137bd0a3cb0a0ac1f4e89fd954 Mon Sep 17 00:00:00 2001 From: Lola Date: Tue, 27 Aug 2024 18:09:19 -0400 Subject: [PATCH 04/44] uncomment creation of agentless agent --- .../plugins/fleet/server/services/agent_policy_create.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/x-pack/plugins/fleet/server/services/agent_policy_create.ts b/x-pack/plugins/fleet/server/services/agent_policy_create.ts index 7807b5f0d070e..f370867fc493b 100644 --- a/x-pack/plugins/fleet/server/services/agent_policy_create.ts +++ b/x-pack/plugins/fleet/server/services/agent_policy_create.ts @@ -25,6 +25,7 @@ import { agentPolicyService, packagePolicyService } from '.'; import { incrementPackageName } from './package_policies'; import { bulkInstallPackages } from './epm/packages'; import { ensureDefaultEnrollmentAPIKeyForAgentPolicy } from './api_keys'; +import { agentlessAgentService } from './agents/agentless_agent'; const FLEET_SERVER_POLICY_ID = 'fleet-server-policy'; @@ -172,9 +173,9 @@ export async function createAgentPolicyWithPackages({ await agentPolicyService.deployPolicy(soClient, agentPolicy.id); // Create the agentless agent - // if (agentPolicy.supports_agentless) { - // // await agentlessAgentService.createAgentlessAgent(esClient, soClient, agentPolicy); - // } + if (agentPolicy.supports_agentless) { + await agentlessAgentService.createAgentlessAgent(esClient, soClient, agentPolicy); + } return agentPolicy; } From 54e699c3fc233773a25d7c2d6823b6ec8454180e Mon Sep 17 00:00:00 2001 From: Lola Date: Tue, 27 Aug 2024 19:14:10 -0400 Subject: [PATCH 05/44] fix type issues --- .../fleet/public/components/package_policy_actions_menu.tsx | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/x-pack/plugins/fleet/public/components/package_policy_actions_menu.tsx b/x-pack/plugins/fleet/public/components/package_policy_actions_menu.tsx index 3d9803c1c0888..98aded476e9d8 100644 --- a/x-pack/plugins/fleet/public/components/package_policy_actions_menu.tsx +++ b/x-pack/plugins/fleet/public/components/package_policy_actions_menu.tsx @@ -10,7 +10,7 @@ import { EuiContextMenuItem, EuiPortal } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n-react'; import type { AgentPolicy, InMemoryPackagePolicy } from '../types'; -import { useAgentPolicyRefresh, useAuthz, useLink, useStartServices } from '../hooks'; +import { useAgentPolicyRefresh, useAuthz, useLink } from '../hooks'; import { policyHasFleetServer } from '../services'; import { AgentEnrollmentFlyout } from './agent_enrollment_flyout'; @@ -36,9 +36,6 @@ export const PackagePolicyActionsMenu: React.FunctionComponent<{ const [isEnrollmentFlyoutOpen, setIsEnrollmentFlyoutOpen] = useState(false); const { getHref } = useLink(); const authz = useAuthz(); - const { - application: { navigateToApp }, - } = useStartServices(); const agentPolicy = agentPolicies.length > 0 ? agentPolicies[0] : undefined; // TODO: handle multiple agent policies const canWriteIntegrationPolicies = authz.integrations.writeIntegrationPolicies; From e946f9cfa99d280273fc66bc215516267187fb6c Mon Sep 17 00:00:00 2001 From: Lola Date: Tue, 27 Aug 2024 20:09:33 -0400 Subject: [PATCH 06/44] fix typo --- x-pack/plugins/fleet/server/services/agent_policy.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugins/fleet/server/services/agent_policy.ts b/x-pack/plugins/fleet/server/services/agent_policy.ts index d0842cd508ac4..8c03e2525a668 100644 --- a/x-pack/plugins/fleet/server/services/agent_policy.ts +++ b/x-pack/plugins/fleet/server/services/agent_policy.ts @@ -1759,7 +1759,7 @@ export async function addPackageToAgentPolicy( ? String(packagePolicyId) : uuidv5(`${agentPolicy.id}-${packagePolicyName}`, UUID_V5_NAMESPACE); - await packagePolicyService.creaƒte(soClient, esClient, newPackagePolicy, { + await packagePolicyService.create(soClient, esClient, newPackagePolicy, { id, bumpRevision: bumpAgentPolicyRevison, skipEnsureInstalled: true, From 55f6abf50748231d4d303efd0b221eceb4b7b837 Mon Sep 17 00:00:00 2001 From: Lola Date: Thu, 29 Aug 2024 13:44:48 -0400 Subject: [PATCH 07/44] test deletion of the agentless agent only --- .../fleet/server/services/agent_policy.ts | 81 ++++++++++--------- 1 file changed, 45 insertions(+), 36 deletions(-) diff --git a/x-pack/plugins/fleet/server/services/agent_policy.ts b/x-pack/plugins/fleet/server/services/agent_policy.ts index 8c03e2525a668..2fe03c9c3bdfd 100644 --- a/x-pack/plugins/fleet/server/services/agent_policy.ts +++ b/x-pack/plugins/fleet/server/services/agent_policy.ts @@ -44,7 +44,7 @@ import { LEGACY_AGENT_POLICY_SAVED_OBJECT_TYPE, AGENTS_PREFIX, FLEET_AGENT_POLICIES_SCHEMA_VERSION, - PRECONFIGURATION_DELETION_RECORD_SAVED_OBJECT_TYPE, + // PRECONFIGURATION_DELETION_RECORD_SAVED_OBJECT_TYPE, SO_SEARCH_LIMIT, } from '../constants'; import type { @@ -113,7 +113,6 @@ import { isAgentlessEnabled } from './utils/agentless'; import { validatePolicyNamespaceForSpace } from './spaces/policy_namespaces'; import { isSpaceAwarenessEnabled } from './spaces/helpers'; import { agentlessAgentService } from './agents/agentless_agent'; - const KEY_EDITABLE_FOR_MANAGED_POLICIES = ['namespace']; function normalizeKuery(savedObjectType: string, kuery: string) { @@ -1112,8 +1111,15 @@ class AgentPolicyService { } if (agentPolicy?.supports_agentless) { - await agentlessAgentService.deleteAgentlessAgent(id); - logger.debug(`Deleted agentless policy with single agent policy with id ${agentPolicy.id}`); + try { + await agentlessAgentService.deleteAgentlessAgent(id); + logger.debug( + `[Agentless API] Successfully deleted agentless policy with single agent policy with id ${id}` + ); + } catch (error) { + logger.error(`[Agentless API] Error deleting agentless agent for policy with id ${id}`); + logger.error(error); + } } const packagePolicies = await packagePolicyService.findAllForAgentPolicy(soClient, id); @@ -1131,15 +1137,16 @@ class AgentPolicyService { this.packagePoliciesWithSingleAndMultiplePolicies(packagePolicies); if (packagePoliciesToDelete.length > 0) { - await packagePolicyService.delete( - soClient, - esClient, - packagePoliciesToDelete.map((p) => p.id), - { - force: options?.force, - skipUnassignFromAgentPolicies: true, - } - ); + // Todo: Uncomment after Agentless Deletion agent is working + // await packagePolicyService.delete( + // soClient, + // esClient, + // packagePoliciesToDelete.map((p) => p.id), + // { + // force: options?.force, + // skipUnassignFromAgentPolicies: true, + // } + // ); logger.debug( `Deleted package policies with single agent policy with ids ${packagePoliciesToDelete .map((policy) => policy.id) @@ -1148,18 +1155,19 @@ class AgentPolicyService { } if (policiesWithMultipleAP.length > 0) { - await packagePolicyService.bulkUpdate( - soClient, - esClient, - policiesWithMultipleAP.map((policy) => { - const newPolicyIds = policy.policy_ids.filter((policyId) => policyId !== id); - return { - ...policy, - policy_id: newPolicyIds[0], - policy_ids: newPolicyIds, - }; - }) - ); + // Todo: Uncomment after Agentless Deletion agent is working + // await packagePolicyService.bulkUpdate( + // soClient, + // esClient, + // policiesWithMultipleAP.map((policy) => { + // const newPolicyIds = policy.policy_ids.filter((policyId) => policyId !== id); + // return { + // ...policy, + // policy_id: newPolicyIds[0], + // policy_ids: newPolicyIds, + // }; + // }) + // ); logger.debug( `Updated package policies with multiple agent policies with ids ${policiesWithMultipleAP .map((policy) => policy.id) @@ -1168,19 +1176,20 @@ class AgentPolicyService { } } - if (agentPolicy.is_preconfigured && !options?.force) { - await soClient.create(PRECONFIGURATION_DELETION_RECORD_SAVED_OBJECT_TYPE, { - id: String(id), - }); - } + // Todo: Uncomment after Agentless Deletion agent is working + // if (agentPolicy.is_preconfigured && !options?.force) { + // await soClient.create(PRECONFIGURATION_DELETION_RECORD_SAVED_OBJECT_TYPE, { + // id: String(id), + // }); + // } - await soClient.delete(savedObjectType, id); - await this.triggerAgentPolicyUpdatedEvent(esClient, 'deleted', id, { - spaceId: soClient.getCurrentNamespace(), - }); + // await soClient.delete(savedObjectType, id); + // await this.triggerAgentPolicyUpdatedEvent(esClient, 'deleted', id, { + // spaceId: soClient.getCurrentNamespace(), + // }); - // cleanup .fleet-policies docs on delete - await this.deleteFleetServerPoliciesForPolicyId(esClient, id); + // // cleanup .fleet-policies docs on delete + // await this.deleteFleetServerPoliciesForPolicyId(esClient, id); logger.debug(`Deleted agent policy ${id}`); return { From 9b665c5cced6346d724cb0a8a4a92a4585ca63b4 Mon Sep 17 00:00:00 2001 From: Lola Date: Thu, 29 Aug 2024 18:21:47 -0400 Subject: [PATCH 08/44] enable button to delete agentless policies with agent --- .../agent_policy/components/actions_menu.tsx | 1 + .../agent_policy_delete_provider.tsx | 44 ++++++++++++------- 2 files changed, 30 insertions(+), 15 deletions(-) diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/actions_menu.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/actions_menu.tsx index 48f391a4e545d..8345742f3d4da 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/actions_menu.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/actions_menu.tsx @@ -146,6 +146,7 @@ export const AgentPolicyActionMenu = memo<{ {(deleteAgentPolicyPrompt) => ( diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_delete_provider.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_delete_provider.tsx index 58b764ed68add..cc7607a03acf8 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_delete_provider.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_delete_provider.tsx @@ -23,12 +23,13 @@ import { sendGetAgents, } from '../../../hooks'; -import type { PackagePolicy } from '../../../types'; +import type { AgentPolicy, PackagePolicy } from '../../../types'; interface Props { children: (deleteAgentPolicy: DeleteAgentPolicy) => React.ReactElement; hasFleetServer: boolean; packagePolicies?: PackagePolicy[]; + agentPolicy: AgentPolicy; } export type DeleteAgentPolicy = (agentPolicy: string, onSuccess?: OnSuccessCallback) => void; @@ -39,12 +40,13 @@ export const AgentPolicyDeleteProvider: React.FunctionComponent = ({ children, hasFleetServer, packagePolicies, + agentPolicy, }) => { const { notifications } = useStartServices(); const { agents: { enabled: isFleetEnabled }, } = useConfig(); - const [agentPolicy, setAgentPolicy] = useState(); + const [agentPolicyId, setAgentPolicyId] = useState(); const [isModalOpen, setIsModalOpen] = useState(false); const [isLoadingAgentsCount, setIsLoadingAgentsCount] = useState(false); const [agentsCount, setAgentsCount] = useState(0); @@ -63,13 +65,13 @@ export const AgentPolicyDeleteProvider: React.FunctionComponent = ({ throw new Error('No agent policy specified for deletion'); } setIsModalOpen(true); - setAgentPolicy(agentPolicyToDelete); + setAgentPolicyId(agentPolicyToDelete); fetchAgentsCount(agentPolicyToDelete); onSuccessCallback.current = onSuccess; }; const closeModal = () => { - setAgentPolicy(undefined); + setAgentPolicyId(undefined); setIsLoading(false); setIsLoadingAgentsCount(false); setIsModalOpen(false); @@ -80,7 +82,7 @@ export const AgentPolicyDeleteProvider: React.FunctionComponent = ({ try { const { data } = await deleteAgentPolicyMutation.mutateAsync({ - agentPolicyId: agentPolicy!, + agentPolicyId: agentPolicyId!, }); if (data) { @@ -91,13 +93,13 @@ export const AgentPolicyDeleteProvider: React.FunctionComponent = ({ }) ); if (onSuccessCallback.current) { - onSuccessCallback.current(agentPolicy!); + onSuccessCallback.current(agentPolicyId!); } } else { notifications.toasts.addDanger( i18n.translate('xpack.fleet.deleteAgentPolicy.failureSingleNotificationTitle', { defaultMessage: "Error deleting agent policy ''{id}''", - values: { id: agentPolicy }, + values: { id: agentPolicyId }, }) ); } @@ -173,7 +175,9 @@ export const AgentPolicyDeleteProvider: React.FunctionComponent = ({ ) } buttonColor="danger" - confirmButtonDisabled={isLoading || isLoadingAgentsCount || !!agentsCount} + confirmButtonDisabled={ + isLoading || isLoadingAgentsCount || (!agentPolicy?.supports_agentless && !!agentsCount) + } > {packagePoliciesWithMultiplePolicies && ( <> @@ -206,13 +210,23 @@ export const AgentPolicyDeleteProvider: React.FunctionComponent = ({ } )} > - + {agentPolicy?.supports_agentless ? ( + + ) : ( + + )} ) : hasFleetServer ? ( Date: Thu, 29 Aug 2024 18:22:52 -0400 Subject: [PATCH 09/44] move deletion of agentless agent before deleting integration --- .../plugins/fleet/server/services/package_policy.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/x-pack/plugins/fleet/server/services/package_policy.ts b/x-pack/plugins/fleet/server/services/package_policy.ts index 706bd941ed929..8609514109372 100644 --- a/x-pack/plugins/fleet/server/services/package_policy.ts +++ b/x-pack/plugins/fleet/server/services/package_policy.ts @@ -1319,6 +1319,12 @@ class PackagePolicyClientImpl implements PackagePolicyClient { } } + if (agentlessAgentPolicies.length > 0) { + for (const agentPolicyId of agentlessAgentPolicies) { + await agentPolicyService.delete(soClient, esClient, agentPolicyId, { force: true }); + } + } + const idsToDelete: string[] = []; ids.forEach((id) => { @@ -1386,12 +1392,6 @@ class PackagePolicyClientImpl implements PackagePolicyClient { }); } - if (agentlessAgentPolicies.length > 0) { - for (const agentPolicyId of agentlessAgentPolicies) { - await agentPolicyService.delete(soClient, esClient, agentPolicyId, { force: true }); - } - } - if (!options?.skipUnassignFromAgentPolicies) { let uniquePolicyIdsR = [ ...new Set( From 1ab7cc35a2327a829a5eae87476bbe00d77e3bd4 Mon Sep 17 00:00:00 2001 From: Lola Date: Tue, 3 Sep 2024 15:55:52 -0400 Subject: [PATCH 10/44] test with agent policy deletion --- .../fleet/server/services/agent_policy.ts | 77 ++++++++++--------- .../server/services/agents/agentless_agent.ts | 22 +++--- 2 files changed, 52 insertions(+), 47 deletions(-) diff --git a/x-pack/plugins/fleet/server/services/agent_policy.ts b/x-pack/plugins/fleet/server/services/agent_policy.ts index 2fe03c9c3bdfd..a6101d78b6457 100644 --- a/x-pack/plugins/fleet/server/services/agent_policy.ts +++ b/x-pack/plugins/fleet/server/services/agent_policy.ts @@ -44,7 +44,7 @@ import { LEGACY_AGENT_POLICY_SAVED_OBJECT_TYPE, AGENTS_PREFIX, FLEET_AGENT_POLICIES_SCHEMA_VERSION, - // PRECONFIGURATION_DELETION_RECORD_SAVED_OBJECT_TYPE, + PRECONFIGURATION_DELETION_RECORD_SAVED_OBJECT_TYPE, SO_SEARCH_LIMIT, } from '../constants'; import type { @@ -113,6 +113,7 @@ import { isAgentlessEnabled } from './utils/agentless'; import { validatePolicyNamespaceForSpace } from './spaces/policy_namespaces'; import { isSpaceAwarenessEnabled } from './spaces/helpers'; import { agentlessAgentService } from './agents/agentless_agent'; + const KEY_EDITABLE_FOR_MANAGED_POLICIES = ['namespace']; function normalizeKuery(savedObjectType: string, kuery: string) { @@ -1112,12 +1113,15 @@ class AgentPolicyService { if (agentPolicy?.supports_agentless) { try { + // Deleting agentless deployment await agentlessAgentService.deleteAgentlessAgent(id); logger.debug( - `[Agentless API] Successfully deleted agentless policy with single agent policy with id ${id}` + `[Agentless API] Successfully deleted agentless deployment with single agent policy with id ${id}` ); } catch (error) { - logger.error(`[Agentless API] Error deleting agentless agent for policy with id ${id}`); + logger.error( + `[Agentless API] Error deleting agentless deployment for single agent policy id ${id} and agentless agent id ${agentlessAgent?.id}` + ); logger.error(error); } } @@ -1137,16 +1141,15 @@ class AgentPolicyService { this.packagePoliciesWithSingleAndMultiplePolicies(packagePolicies); if (packagePoliciesToDelete.length > 0) { - // Todo: Uncomment after Agentless Deletion agent is working - // await packagePolicyService.delete( - // soClient, - // esClient, - // packagePoliciesToDelete.map((p) => p.id), - // { - // force: options?.force, - // skipUnassignFromAgentPolicies: true, - // } - // ); + await packagePolicyService.delete( + soClient, + esClient, + packagePoliciesToDelete.map((p) => p.id), + { + force: options?.force, + skipUnassignFromAgentPolicies: true, + } + ); logger.debug( `Deleted package policies with single agent policy with ids ${packagePoliciesToDelete .map((policy) => policy.id) @@ -1155,19 +1158,18 @@ class AgentPolicyService { } if (policiesWithMultipleAP.length > 0) { - // Todo: Uncomment after Agentless Deletion agent is working - // await packagePolicyService.bulkUpdate( - // soClient, - // esClient, - // policiesWithMultipleAP.map((policy) => { - // const newPolicyIds = policy.policy_ids.filter((policyId) => policyId !== id); - // return { - // ...policy, - // policy_id: newPolicyIds[0], - // policy_ids: newPolicyIds, - // }; - // }) - // ); + await packagePolicyService.bulkUpdate( + soClient, + esClient, + policiesWithMultipleAP.map((policy) => { + const newPolicyIds = policy.policy_ids.filter((policyId) => policyId !== id); + return { + ...policy, + policy_id: newPolicyIds[0], + policy_ids: newPolicyIds, + }; + }) + ); logger.debug( `Updated package policies with multiple agent policies with ids ${policiesWithMultipleAP .map((policy) => policy.id) @@ -1176,20 +1178,19 @@ class AgentPolicyService { } } - // Todo: Uncomment after Agentless Deletion agent is working - // if (agentPolicy.is_preconfigured && !options?.force) { - // await soClient.create(PRECONFIGURATION_DELETION_RECORD_SAVED_OBJECT_TYPE, { - // id: String(id), - // }); - // } + if (agentPolicy.is_preconfigured && !options?.force) { + await soClient.create(PRECONFIGURATION_DELETION_RECORD_SAVED_OBJECT_TYPE, { + id: String(id), + }); + } - // await soClient.delete(savedObjectType, id); - // await this.triggerAgentPolicyUpdatedEvent(esClient, 'deleted', id, { - // spaceId: soClient.getCurrentNamespace(), - // }); + await soClient.delete(savedObjectType, id); + await this.triggerAgentPolicyUpdatedEvent(esClient, 'deleted', id, { + spaceId: soClient.getCurrentNamespace(), + }); - // // cleanup .fleet-policies docs on delete - // await this.deleteFleetServerPoliciesForPolicyId(esClient, id); + // cleanup .fleet-policies docs on delete + await this.deleteFleetServerPoliciesForPolicyId(esClient, id); logger.debug(`Deleted agent policy ${id}`); return { diff --git a/x-pack/plugins/fleet/server/services/agents/agentless_agent.ts b/x-pack/plugins/fleet/server/services/agents/agentless_agent.ts index e6f2d13722dd8..3fe2662793e56 100644 --- a/x-pack/plugins/fleet/server/services/agents/agentless_agent.ts +++ b/x-pack/plugins/fleet/server/services/agents/agentless_agent.ts @@ -143,20 +143,22 @@ class AgentlessAgentService { public async deleteAgentlessAgent(agentlessPolicyId: string) { const logger = appContextService.getLogger(); - logger.debug(`Start deleting agentless agent for agent policy - ${agentlessPolicyId}`); + logger.debug( + `[Agentless API] Start deleting agentless agent for agent policy - ${agentlessPolicyId}` + ); if (!isAgentlessApiEnabled) { logger.error( - 'Agentless API is not supported. Deleting agentless agent is not supported in non-cloud or non-serverless environments' + '[Agentless API] Agentless API is not supported. Deleting agentless agent is not supported in non-cloud or non-serverless environments' ); } const agentlessConfig = appContextService.getConfig()?.agentless; if (!agentlessConfig) { - logger.error('kibana.yml is currently missing Agentless API configuration'); + logger.error('[Agentless API] kibana.yml is currently missing Agentless API configuration'); } - logger.debug(`Deleting agentless agent with TLS config with certificate`); + logger.debug(`[Agentless API] Deleting agentless agent with TLS config with certificate`); const tlsConfig = new SslConfig( sslSchema.validate({ @@ -182,7 +184,7 @@ class AgentlessAgentService { }; logger.debug( - `Deleting agentless agent with request config ${JSON.stringify({ + `[Agentless API] Deleting agentless agent with request config ${JSON.stringify({ ...requestConfig, httpsAgent: { ...requestConfig.httpsAgent, @@ -198,21 +200,23 @@ class AgentlessAgentService { const response = await axios(requestConfig).catch((error: AxiosError) => { if (!axios.isAxiosError(error)) { - logger.error(`Deleting agentless failed with an error ${error}`); + logger.error(`[Agentless API] Deleting agentless failed with an error ${error}`); } if (error.response) { logger.error( - `DELETE Agentless Agent Response Error: ${error.response.status} - ${error.response.statusText} Deleting agentless agent failed for agent policy id ${agentlessPolicyId}.` + `[Agentless API] DELETE Agentless Agent Response Error: ${error.response.status} - ${error.response.statusText} Deleting agentless agent failed for agent policy id ${agentlessPolicyId}.` ); } else if (error.request) { logger.error( - `Deleting agentless failed to receive a response from the Agentless API ${JSON.stringify( + `[Agentless API] Deleting agentless failed to receive a response from the Agentless API ${JSON.stringify( error.cause )}` ); } else { logger.error( - `Deleting agentless failed to delete the request ${JSON.stringify(error.cause)}` + `[Agentless API] Deleting agentless failed to delete the request ${JSON.stringify( + error.cause + )}` ); } }); From ad3687226ef625575e98b1cb9c9ec445a722ad6c Mon Sep 17 00:00:00 2001 From: Lola Date: Tue, 3 Sep 2024 16:16:45 -0400 Subject: [PATCH 11/44] fix types issue --- .../fleet/sections/debug/components/agent_policy_debugger.tsx | 1 + x-pack/plugins/fleet/server/services/agent_policy.ts | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/debug/components/agent_policy_debugger.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/debug/components/agent_policy_debugger.tsx index 78be94ef07048..98eed3cb63b4d 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/debug/components/agent_policy_debugger.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/debug/components/agent_policy_debugger.tsx @@ -128,6 +128,7 @@ export const AgentPolicyDebugger: React.FunctionComponent = () => { {selectedPolicyId && ( {(deleteAgentPolicyPrompt) => { diff --git a/x-pack/plugins/fleet/server/services/agent_policy.ts b/x-pack/plugins/fleet/server/services/agent_policy.ts index a6101d78b6457..d38658965099b 100644 --- a/x-pack/plugins/fleet/server/services/agent_policy.ts +++ b/x-pack/plugins/fleet/server/services/agent_policy.ts @@ -1120,7 +1120,7 @@ class AgentPolicyService { ); } catch (error) { logger.error( - `[Agentless API] Error deleting agentless deployment for single agent policy id ${id} and agentless agent id ${agentlessAgent?.id}` + `[Agentless API] Error deleting agentless deployment for single agent policy id ${id}` ); logger.error(error); } From a27a9ef74071ff6e79b705e5e27a88e1e19dd468 Mon Sep 17 00:00:00 2001 From: Lola Date: Tue, 3 Sep 2024 17:40:18 -0400 Subject: [PATCH 12/44] fix translations --- .../agent_policy_delete_provider.tsx | 3 -- .../translations/translations/fr-FR.json | 28 +++++++++---------- .../translations/translations/ja-JP.json | 28 +++++++++---------- .../translations/translations/zh-CN.json | 28 +++++++++---------- 4 files changed, 42 insertions(+), 45 deletions(-) diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_delete_provider.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_delete_provider.tsx index cc7607a03acf8..0ba6a539984ca 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_delete_provider.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_delete_provider.tsx @@ -214,9 +214,6 @@ export const AgentPolicyDeleteProvider: React.FunctionComponent = ({ ) : ( Date: Wed, 4 Sep 2024 09:12:06 -0400 Subject: [PATCH 13/44] move to delete agentless policies back down to avoid loading button being disabled --- x-pack/plugins/fleet/server/services/agent_policy.ts | 2 +- .../plugins/fleet/server/services/package_policy.ts | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/x-pack/plugins/fleet/server/services/agent_policy.ts b/x-pack/plugins/fleet/server/services/agent_policy.ts index 1a1903a4b3f22..272c3c593e58f 100644 --- a/x-pack/plugins/fleet/server/services/agent_policy.ts +++ b/x-pack/plugins/fleet/server/services/agent_policy.ts @@ -1116,7 +1116,7 @@ class AgentPolicyService { // Deleting agentless deployment await agentlessAgentService.deleteAgentlessAgent(id); logger.debug( - `[Agentless API] Successfully deleted agentless deployment with single agent policy with id ${id}` + `[Agentless API] Successfully deleted agentless deployment for single agent policy id ${id}` ); } catch (error) { logger.error( diff --git a/x-pack/plugins/fleet/server/services/package_policy.ts b/x-pack/plugins/fleet/server/services/package_policy.ts index 27041cf99cdb5..508f5f8fbeaef 100644 --- a/x-pack/plugins/fleet/server/services/package_policy.ts +++ b/x-pack/plugins/fleet/server/services/package_policy.ts @@ -1336,12 +1336,6 @@ class PackagePolicyClientImpl implements PackagePolicyClient { } } - if (agentlessAgentPolicies.length > 0) { - for (const agentPolicyId of agentlessAgentPolicies) { - await agentPolicyService.delete(soClient, esClient, agentPolicyId, { force: true }); - } - } - const idsToDelete: string[] = []; ids.forEach((id) => { @@ -1409,6 +1403,12 @@ class PackagePolicyClientImpl implements PackagePolicyClient { }); } + if (agentlessAgentPolicies.length > 0) { + for (const agentPolicyId of agentlessAgentPolicies) { + await agentPolicyService.delete(soClient, esClient, agentPolicyId, { force: true }); + } + } + if (!options?.skipUnassignFromAgentPolicies) { let uniquePolicyIdsR = [ ...new Set( From 99cabd90f43594e807f6d75874ab4db703aa1683 Mon Sep 17 00:00:00 2001 From: Lola Date: Thu, 5 Sep 2024 17:38:43 -0400 Subject: [PATCH 14/44] remove throw error on soClient deletion for agentless --- x-pack/plugins/fleet/server/services/agent_policy.ts | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/fleet/server/services/agent_policy.ts b/x-pack/plugins/fleet/server/services/agent_policy.ts index 272c3c593e58f..0b2ddb9a10c68 100644 --- a/x-pack/plugins/fleet/server/services/agent_policy.ts +++ b/x-pack/plugins/fleet/server/services/agent_policy.ts @@ -1184,7 +1184,16 @@ class AgentPolicyService { }); } - await soClient.delete(savedObjectType, id); + try { + await soClient.delete(savedObjectType, id); + } catch (error) { + // Temporarily ignore 404 until we resolve save object 404 errors with agentless policy + if (error.statusCode === 404 && !agentPolicy.supports_agentless) { + throw error; + } + logger.error(`Error deleting save object for agent policy ${id}`); + } + await this.triggerAgentPolicyUpdatedEvent(esClient, 'deleted', id, { spaceId: soClient.getCurrentNamespace(), }); From bdb68ded9b61b3c748388d6c755deb915fe9a148 Mon Sep 17 00:00:00 2001 From: Lola Date: Fri, 6 Sep 2024 19:46:02 -0400 Subject: [PATCH 15/44] update logging --- .../server/services/agents/agentless_agent.ts | 92 ++++++++++++------- 1 file changed, 57 insertions(+), 35 deletions(-) diff --git a/x-pack/plugins/fleet/server/services/agents/agentless_agent.ts b/x-pack/plugins/fleet/server/services/agents/agentless_agent.ts index 167a3f0e620a7..d7a2ea9ae991c 100644 --- a/x-pack/plugins/fleet/server/services/agents/agentless_agent.ts +++ b/x-pack/plugins/fleet/server/services/agents/agentless_agent.ts @@ -35,22 +35,22 @@ class AgentlessAgentService { agentlessAgentPolicy: AgentPolicy ) { const logger = appContextService.getLogger(); - logger.debug(`Creating agentless agent ${agentlessAgentPolicy.id}`); + logger.debug(`[Agentless API] Creating agentless agent ${agentlessAgentPolicy.id}`); if (!isAgentlessApiEnabled) { logger.error( - 'Creating agentless agent not supported in non-cloud or non-serverless environments' + '[Agentless API] Creating agentless agent not supported in non-cloud or non-serverless environments' ); throw new AgentlessAgentCreateError('Agentless agent not supported'); } if (!agentlessAgentPolicy.supports_agentless) { - logger.error('Agentless agent policy does not have agentless enabled'); + logger.error('[Agentless API] Agentless agent policy does not have agentless enabled'); throw new AgentlessAgentCreateError('Agentless agent policy does not have agentless enabled'); } const agentlessConfig = appContextService.getConfig()?.agentless; if (!agentlessConfig) { - logger.error('Missing agentless configuration'); + logger.error('[Agentless API] Missing agentless configuration'); throw new AgentlessAgentCreateError('missing agentless configuration'); } @@ -61,9 +61,11 @@ class AgentlessAgentService { soClient ); - logger.debug(`Creating agentless agent with fleetUrl ${fleetUrl} and fleetToken ${fleetToken}`); + logger.debug( + `[Agentless API] Creating agentless agent with fleetUrl ${fleetUrl} and fleetToken ${fleetToken}` + ); - logger.debug(`Creating agentless agent with TLS config with certificate: ${agentlessConfig.api.tls.certificate}, + logger.debug(`[Agentless API] Creating agentless agent with TLS config with certificate: ${agentlessConfig.api.tls.certificate}, and key: ${agentlessConfig.api.tls.key}`); const tlsConfig = new SslConfig( @@ -112,13 +114,15 @@ class AgentlessAgentService { }, }); - logger.debug(`Creating agentless agent with request config ${requestConfigDebug}`); + logger.debug( + `[Agentless API] Creating agentless agent with request config ${requestConfigDebug}` + ); const response = await axios(requestConfig).catch( (error: Error | AxiosError) => { if (!axios.isAxiosError(error)) { logger.error( - `Creating agentless failed with an error ${error} ${JSON.stringify( + `[Agentless API] Creating agentless failed with an error ${error} ${JSON.stringify( requestConfigDebug )}` ); @@ -130,7 +134,7 @@ class AgentlessAgentService { if (error.response) { // The request was made and the server responded with a status code and error data logger.error( - `Creating agentless failed because the Agentless API responding with a status code that falls out of the range of 2xx: ${JSON.stringify( + `[Agentless API] Creating agentless failed because the Agentless API responding with a status code that falls out of the range of 2xx: ${JSON.stringify( error.response.status )}} ${JSON.stringify(error.response.data)}} ${JSON.stringify(requestConfigDebug)}` ); @@ -140,7 +144,7 @@ class AgentlessAgentService { } else if (error.request) { // The request was made but no response was received logger.error( - `Creating agentless agent failed while sending the request to the Agentless API: ${errorLogCodeCause} ${JSON.stringify( + `[Agentless API] Creating agentless agent failed while sending the request to the Agentless API: ${errorLogCodeCause} ${JSON.stringify( requestConfigDebug )}` ); @@ -148,7 +152,7 @@ class AgentlessAgentService { } else { // Something happened in setting up the request that triggered an Error logger.error( - `Creating agentless agent failed to be created ${errorLogCodeCause} ${JSON.stringify( + `[Agentless API] Creating agentless agent failed to be created ${errorLogCodeCause} ${JSON.stringify( requestConfigDebug )}` ); @@ -159,29 +163,13 @@ class AgentlessAgentService { } ); - logger.debug(`Created an agentless agent ${response}`); + logger.debug(`[Agentless API] Created an agentless agent ${response}`); return response; } public async deleteAgentlessAgent(agentlessPolicyId: string) { const logger = appContextService.getLogger(); - logger.debug( - `[Agentless API] Start deleting agentless agent for agent policy - ${agentlessPolicyId}` - ); - - if (!isAgentlessApiEnabled) { - logger.error( - '[Agentless API] Agentless API is not supported. Deleting agentless agent is not supported in non-cloud or non-serverless environments' - ); - } - const agentlessConfig = appContextService.getConfig()?.agentless; - if (!agentlessConfig) { - logger.error('[Agentless API] kibana.yml is currently missing Agentless API configuration'); - } - - logger.debug(`[Agentless API] Deleting agentless agent with TLS config with certificate`); - const tlsConfig = new SslConfig( sslSchema.validate({ enabled: true, @@ -205,8 +193,38 @@ class AgentlessAgentService { }), }; + const requestConfigDebug = JSON.stringify({ + url: getDeletionEndpointPath(agentlessConfig, `/deployments/${agentlessPolicyId}`), + method: 'DELETE', + headers: { + 'Content-type': 'application/json', + }, + httpsAgent: new https.Agent({ + rejectUnauthorized: tlsConfig.rejectUnauthorized, + cert: tlsConfig.certificate, + key: tlsConfig.key, + ca: tlsConfig.certificateAuthorities, + }), + }); + + logger.debug( + `[Agentless API] Start deleting agentless agent for agent policy ${requestConfigDebug}` + ); + + if (!isAgentlessApiEnabled) { + logger.error( + '[Agentless API] Agentless API is not supported. Deleting agentless agent is not supported in non-cloud or non-serverless environments' + ); + } + + if (!agentlessConfig) { + logger.error('[Agentless API] kibana.yml is currently missing Agentless API configuration'); + } + + logger.debug(`[Agentless API] Deleting agentless agent with TLS config with certificate`); + logger.debug( - `[Agentless API] Deleting agentless agent with request config ${JSON.stringify({ + `[Agentless API] Deleting agentless deployment with request config ${JSON.stringify({ ...requestConfig, httpsAgent: { ...requestConfig.httpsAgent, @@ -221,23 +239,27 @@ class AgentlessAgentService { ); const response = await axios(requestConfig).catch((error: AxiosError) => { + const errorLogCodeCause = `${error.code} ${this.convertCauseErrorsToString(error)}`; + if (!axios.isAxiosError(error)) { - logger.error(`[Agentless API] Deleting agentless failed with an error ${error}`); + logger.error(`[Agentless API] Deleting agentless deployment failed with an error ${error}`); } if (error.response) { logger.error( - `[Agentless API] DELETE Agentless Agent Response Error: ${error.response.status} - ${error.response.statusText} Deleting agentless agent failed for agent policy id ${agentlessPolicyId}.` + `[Agentless API] Deleting Agentless deployment Failed Response Error: ${JSON.stringify( + error.response.status + )}} ${JSON.stringify(error.response.data)}} ${requestConfigDebug} ` ); } else if (error.request) { logger.error( - `[Agentless API] Deleting agentless failed to receive a response from the Agentless API ${JSON.stringify( - error.cause + `[Agentless API] Deleting agentless deployment failed to receive a response from the Agentless API ${errorLogCodeCause} ${JSON.stringify( + requestConfigDebug )}` ); } else { logger.error( - `[Agentless API] Deleting agentless failed to delete the request ${JSON.stringify( - error.cause + `[Agentless API] Deleting agentless deployment failed to delete the request ${errorLogCodeCause} ${JSON.stringify( + requestConfigDebug )}` ); } From c0eec909a46e73bbce574b424a863ce7a2d7747b Mon Sep 17 00:00:00 2001 From: Lola Date: Sat, 7 Sep 2024 08:25:59 -0400 Subject: [PATCH 16/44] update messaging for agentless deletion --- .../components/agent_policy_delete_provider.tsx | 2 +- .../plugins/fleet/server/services/agents/agentless_agent.ts | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_delete_provider.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_delete_provider.tsx index 0ba6a539984ca..adbe0a748be2a 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_delete_provider.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_delete_provider.tsx @@ -213,7 +213,7 @@ export const AgentPolicyDeleteProvider: React.FunctionComponent = ({ {agentPolicy?.supports_agentless ? ( ) : ( Date: Mon, 9 Sep 2024 15:02:31 -0400 Subject: [PATCH 17/44] remove try/catch logic to fix SO client error --- .../plugins/fleet/server/services/agent_policy.ts | 13 ++----------- .../fleet/server/services/agent_policy_create.ts | 8 ++++---- 2 files changed, 6 insertions(+), 15 deletions(-) diff --git a/x-pack/plugins/fleet/server/services/agent_policy.ts b/x-pack/plugins/fleet/server/services/agent_policy.ts index 0b2ddb9a10c68..b5dbbff70ab5e 100644 --- a/x-pack/plugins/fleet/server/services/agent_policy.ts +++ b/x-pack/plugins/fleet/server/services/agent_policy.ts @@ -112,7 +112,7 @@ import { createSoFindIterable } from './utils/create_so_find_iterable'; import { isAgentlessEnabled } from './utils/agentless'; import { validatePolicyNamespaceForSpace } from './spaces/policy_namespaces'; import { isSpaceAwarenessEnabled } from './spaces/helpers'; -import { agentlessAgentService } from './agents/agentless_agent'; +// import { agentlessAgentService } from './agents/agentless_agent'; const KEY_EDITABLE_FOR_MANAGED_POLICIES = ['namespace']; @@ -1184,16 +1184,7 @@ class AgentPolicyService { }); } - try { - await soClient.delete(savedObjectType, id); - } catch (error) { - // Temporarily ignore 404 until we resolve save object 404 errors with agentless policy - if (error.statusCode === 404 && !agentPolicy.supports_agentless) { - throw error; - } - logger.error(`Error deleting save object for agent policy ${id}`); - } - + await soClient.delete(savedObjectType, id); await this.triggerAgentPolicyUpdatedEvent(esClient, 'deleted', id, { spaceId: soClient.getCurrentNamespace(), }); diff --git a/x-pack/plugins/fleet/server/services/agent_policy_create.ts b/x-pack/plugins/fleet/server/services/agent_policy_create.ts index f370867fc493b..b0ca05b61ea7c 100644 --- a/x-pack/plugins/fleet/server/services/agent_policy_create.ts +++ b/x-pack/plugins/fleet/server/services/agent_policy_create.ts @@ -25,7 +25,6 @@ import { agentPolicyService, packagePolicyService } from '.'; import { incrementPackageName } from './package_policies'; import { bulkInstallPackages } from './epm/packages'; import { ensureDefaultEnrollmentAPIKeyForAgentPolicy } from './api_keys'; -import { agentlessAgentService } from './agents/agentless_agent'; const FLEET_SERVER_POLICY_ID = 'fleet-server-policy'; @@ -172,10 +171,11 @@ export async function createAgentPolicyWithPackages({ await ensureDefaultEnrollmentAPIKeyForAgentPolicy(soClient, esClient, agentPolicy.id); await agentPolicyService.deployPolicy(soClient, agentPolicy.id); + // Temporarily disable to test SO object error // Create the agentless agent - if (agentPolicy.supports_agentless) { - await agentlessAgentService.createAgentlessAgent(esClient, soClient, agentPolicy); - } + // if (agentPolicy.supports_agentless) { + // await agentlessAgentService.createAgentlessAgent(esClient, soClient, agentPolicy); + // } return agentPolicy; } From 1eb25a958e9f056539b5f5171b4bdee793c6966a Mon Sep 17 00:00:00 2001 From: Lola Date: Mon, 9 Sep 2024 17:44:42 -0400 Subject: [PATCH 18/44] fix save object 404 error --- .../package_policy_delete_provider.tsx | 27 +++++++++++++++++-- .../public/hooks/use_request/agent_policy.ts | 18 +++++++------ .../fleet/server/services/agent_policy.ts | 2 +- .../fleet/server/services/package_policy.ts | 6 ----- 4 files changed, 36 insertions(+), 17 deletions(-) diff --git a/x-pack/plugins/fleet/public/components/package_policy_delete_provider.tsx b/x-pack/plugins/fleet/public/components/package_policy_delete_provider.tsx index 6369d344a2d9f..cf72732ace3e4 100644 --- a/x-pack/plugins/fleet/public/components/package_policy_delete_provider.tsx +++ b/x-pack/plugins/fleet/public/components/package_policy_delete_provider.tsx @@ -10,7 +10,12 @@ import { EuiCallOut, EuiConfirmModal, EuiSpacer, EuiIconTip } from '@elastic/eui import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n-react'; -import { useStartServices, sendDeletePackagePolicy, useConfig } from '../hooks'; +import { + useStartServices, + sendDeletePackagePolicy, + sendDeleteAgentPolicy, + useConfig, +} from '../hooks'; import { AGENTS_PREFIX } from '../../common/constants'; import type { AgentPolicy } from '../types'; import { sendGetAgents, useMultipleAgentPolicies } from '../hooks'; @@ -126,6 +131,24 @@ export const PackagePolicyDeleteProvider: React.FunctionComponent = ({ defaultMessage: "Deleted integration ''{id}''", values: { id: successfulResults[0].name || successfulResults[0].id }, }); + + const agentlessPolicy = agentPolicies?.find((policy) => policy.supports_agentless); + + if (!!agentlessPolicy) { + try { + await sendDeleteAgentPolicy({ agentPolicyId: agentlessPolicy.id }); + } catch (e) { + notifications.toasts.addDanger( + i18n.translate( + 'xpack.fleet.deletePackagePolicy.fatalErrorAgentlessNotificationTitle', + { + defaultMessage: 'Error deleting agentless deployment', + } + ) + ); + } + } + notifications.toasts.addSuccess(successMessage); } @@ -155,7 +178,7 @@ export const PackagePolicyDeleteProvider: React.FunctionComponent = ({ } closeModal(); }, - [closeModal, packagePolicies, notifications.toasts] + [closeModal, packagePolicies, notifications.toasts, agentPolicies] ); const renderModal = () => { diff --git a/x-pack/plugins/fleet/public/hooks/use_request/agent_policy.ts b/x-pack/plugins/fleet/public/hooks/use_request/agent_policy.ts index b1a76f5a334f2..9e4fb2344fc29 100644 --- a/x-pack/plugins/fleet/public/hooks/use_request/agent_policy.ts +++ b/x-pack/plugins/fleet/public/hooks/use_request/agent_policy.ts @@ -164,18 +164,20 @@ export const sendCopyAgentPolicy = ( }); }; +export const sendDeleteAgentPolicy = (body: DeleteAgentPolicyRequest['body']) => { + return sendRequest({ + path: agentPolicyRouteService.getDeletePath(), + method: 'post', + body: JSON.stringify(body), + version: API_VERSIONS.public.v1, + }); +}; + export function useDeleteAgentPolicyMutation() { const queryClient = useQueryClient(); return useMutation({ - mutationFn: function sendDeleteAgentPolicy(body: DeleteAgentPolicyRequest['body']) { - return sendRequest({ - path: agentPolicyRouteService.getDeletePath(), - method: 'post', - body: JSON.stringify(body), - version: API_VERSIONS.public.v1, - }); - }, + mutationFn: sendDeleteAgentPolicy, onSuccess: () => { return queryClient.invalidateQueries(['agentPolicies']); }, diff --git a/x-pack/plugins/fleet/server/services/agent_policy.ts b/x-pack/plugins/fleet/server/services/agent_policy.ts index b5dbbff70ab5e..272c3c593e58f 100644 --- a/x-pack/plugins/fleet/server/services/agent_policy.ts +++ b/x-pack/plugins/fleet/server/services/agent_policy.ts @@ -112,7 +112,7 @@ import { createSoFindIterable } from './utils/create_so_find_iterable'; import { isAgentlessEnabled } from './utils/agentless'; import { validatePolicyNamespaceForSpace } from './spaces/policy_namespaces'; import { isSpaceAwarenessEnabled } from './spaces/helpers'; -// import { agentlessAgentService } from './agents/agentless_agent'; +import { agentlessAgentService } from './agents/agentless_agent'; const KEY_EDITABLE_FOR_MANAGED_POLICIES = ['namespace']; diff --git a/x-pack/plugins/fleet/server/services/package_policy.ts b/x-pack/plugins/fleet/server/services/package_policy.ts index 508f5f8fbeaef..2ea7b6bf1c448 100644 --- a/x-pack/plugins/fleet/server/services/package_policy.ts +++ b/x-pack/plugins/fleet/server/services/package_policy.ts @@ -1403,12 +1403,6 @@ class PackagePolicyClientImpl implements PackagePolicyClient { }); } - if (agentlessAgentPolicies.length > 0) { - for (const agentPolicyId of agentlessAgentPolicies) { - await agentPolicyService.delete(soClient, esClient, agentPolicyId, { force: true }); - } - } - if (!options?.skipUnassignFromAgentPolicies) { let uniquePolicyIdsR = [ ...new Set( From 7c9b866b174f7dd0d0265b869ce2d1999df1c8ec Mon Sep 17 00:00:00 2001 From: Lola Date: Mon, 9 Sep 2024 20:05:46 -0400 Subject: [PATCH 19/44] fix unit tests --- .../package_policy_actions_menu.test.tsx | 23 +++---------------- .../server/services/agent_policy.test.ts | 8 +++---- 2 files changed, 7 insertions(+), 24 deletions(-) diff --git a/x-pack/plugins/fleet/public/components/package_policy_actions_menu.test.tsx b/x-pack/plugins/fleet/public/components/package_policy_actions_menu.test.tsx index 90e680c2ff845..d9223b3449fba 100644 --- a/x-pack/plugins/fleet/public/components/package_policy_actions_menu.test.tsx +++ b/x-pack/plugins/fleet/public/components/package_policy_actions_menu.test.tsx @@ -7,12 +7,12 @@ import React from 'react'; -import { act, fireEvent } from '@testing-library/react'; +import { act } from '@testing-library/react'; import type { AgentPolicy, InMemoryPackagePolicy } from '../types'; import { createIntegrationsTestRendererMock } from '../mock'; -import { useMultipleAgentPolicies, useStartServices, useLink } from '../hooks'; +import { useMultipleAgentPolicies, useLink } from '../hooks'; import { PackagePolicyActionsMenu } from './package_policy_actions_menu'; @@ -154,7 +154,7 @@ describe('PackagePolicyActionsMenu', () => { }); it('Should be able to delete integration from a managed agentless policy', async () => { - const agentPolicies = createMockAgentPolicies({ is_managed: true, supports_agentless: true }); + const agentPolicies = createMockAgentPolicies({ is_managed: false, supports_agentless: true }); const packagePolicy = createMockPackagePolicy(); const { utils } = renderMenu({ agentPolicies, packagePolicy }); await act(async () => { @@ -162,23 +162,6 @@ describe('PackagePolicyActionsMenu', () => { }); }); - it('Should navigate on delete integration when having an agentless policy', async () => { - const agentPolicies = createMockAgentPolicies({ is_managed: true, supports_agentless: true }); - const packagePolicy = createMockPackagePolicy(); - const { utils } = renderMenu({ agentPolicies, packagePolicy }); - - await act(async () => { - fireEvent.click(utils.getByTestId('PackagePolicyActionsDeleteItem')); - }); - await act(async () => { - fireEvent.click(utils.getByTestId('confirmModalConfirmButton')); - }); - expect(useStartServices().application.navigateToApp as jest.Mock).toHaveBeenCalledWith( - 'fleet', - { path: '/policies' } - ); - }); - it('Should show add button if the policy is not managed and showAddAgent=true', async () => { const agentPolicies = createMockAgentPolicies(); const packagePolicy = createMockPackagePolicy({ hasUpgrade: true }); diff --git a/x-pack/plugins/fleet/server/services/agent_policy.test.ts b/x-pack/plugins/fleet/server/services/agent_policy.test.ts index 37bc2abe4c27c..39f866091339c 100644 --- a/x-pack/plugins/fleet/server/services/agent_policy.test.ts +++ b/x-pack/plugins/fleet/server/services/agent_policy.test.ts @@ -363,7 +363,7 @@ describe('Agent policy', () => { ); }); - it('should create a policy with is_managed true if agentless feature flag is set and in serverless env', async () => { + it('should create a policy without is_managed as true and agentless feature flag is set and in serverless env', async () => { jest .spyOn(appContextService, 'getExperimentalFeatures') .mockReturnValue({ agentless: true } as any); @@ -392,7 +392,7 @@ describe('Agent policy', () => { namespace: 'default', supports_agentless: true, status: 'active', - is_managed: true, + is_managed: false, revision: 1, updated_at: expect.anything(), updated_by: 'system', @@ -401,7 +401,7 @@ describe('Agent policy', () => { }); }); - it('should create a policy with is_managed true if agentless feature flag is set and in cloud env', async () => { + it('should create a policy without is_managed as true if agentless feature flag is set and in cloud env', async () => { jest.spyOn(appContextService, 'getCloud').mockReturnValue({ isCloudEnabled: true } as any); jest.spyOn(appContextService, 'getConfig').mockReturnValue({ agentless: { enabled: true }, @@ -428,7 +428,7 @@ describe('Agent policy', () => { namespace: 'default', supports_agentless: true, status: 'active', - is_managed: true, + is_managed: false, revision: 1, updated_at: expect.anything(), updated_by: 'system', From 12bbe241d77c09dacd9bfef1dcddb15b5aa553d7 Mon Sep 17 00:00:00 2001 From: Lola Date: Mon, 9 Sep 2024 20:25:24 -0400 Subject: [PATCH 20/44] fix api-integration tests --- x-pack/test/fleet_api_integration/apis/package_policy/delete.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/test/fleet_api_integration/apis/package_policy/delete.ts b/x-pack/test/fleet_api_integration/apis/package_policy/delete.ts index ebe7a91019094..fddf71eaf98a1 100644 --- a/x-pack/test/fleet_api_integration/apis/package_policy/delete.ts +++ b/x-pack/test/fleet_api_integration/apis/package_policy/delete.ts @@ -166,7 +166,7 @@ export default function (providerContext: FtrProviderContext) { .set('kbn-xsrf', 'xxxx') .expect(200); - await supertest.get(`/api/fleet/agent_policies/${agentPolicy.id}`).expect(404); + await supertest.get(`/api/fleet/agent_policies/${agentPolicy.id}`).expect(200); }); }); describe('Delete bulk', () => { From 3ff29b98031f29cf994374c606f886f96925e448 Mon Sep 17 00:00:00 2001 From: Lola Date: Mon, 9 Sep 2024 20:33:14 -0400 Subject: [PATCH 21/44] uncomment agentless api creation --- .../plugins/fleet/server/services/agent_policy_create.ts | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/x-pack/plugins/fleet/server/services/agent_policy_create.ts b/x-pack/plugins/fleet/server/services/agent_policy_create.ts index b0ca05b61ea7c..5ec2bc166482c 100644 --- a/x-pack/plugins/fleet/server/services/agent_policy_create.ts +++ b/x-pack/plugins/fleet/server/services/agent_policy_create.ts @@ -171,11 +171,10 @@ export async function createAgentPolicyWithPackages({ await ensureDefaultEnrollmentAPIKeyForAgentPolicy(soClient, esClient, agentPolicy.id); await agentPolicyService.deployPolicy(soClient, agentPolicy.id); - // Temporarily disable to test SO object error // Create the agentless agent - // if (agentPolicy.supports_agentless) { - // await agentlessAgentService.createAgentlessAgent(esClient, soClient, agentPolicy); - // } + if (agentPolicy.supports_agentless) { + await agentlessAgentService.createAgentlessAgent(esClient, soClient, agentPolicy); + } return agentPolicy; } From d10f369c898ca8620d4fc811a36ebde7d9f0fbd3 Mon Sep 17 00:00:00 2001 From: Lola Date: Tue, 10 Sep 2024 12:26:19 -0400 Subject: [PATCH 22/44] change error notification messaging --- .../single_page_layout/hooks/form.tsx | 14 +++++++++++--- x-pack/plugins/fleet/server/errors/index.ts | 6 ++++++ .../fleet/server/services/agent_policy.ts | 17 +++++++++++++++-- .../server/services/agent_policy_create.ts | 1 + 4 files changed, 33 insertions(+), 5 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 c71b4c4bdcdc5..07aa702c1ed79 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 @@ -343,10 +343,18 @@ export function useOnSubmit({ } } catch (e) { setFormState('VALID'); + const agentlessPolicy = agentPolicies.find( + (policy) => policy?.supports_agentless === true + ); + notifications.toasts.addError(e, { - title: i18n.translate('xpack.fleet.createAgentPolicy.errorNotificationTitle', { - defaultMessage: 'Unable to create agent policy', - }), + title: agentlessPolicy?.supports_agentless + ? i18n.translate('xpack.fleet.createAgentlessPolicy.errorNotificationTitle', { + defaultMessage: 'Unable to create agentless integration', + }) + : i18n.translate('xpack.fleet.createAgentPolicy.errorNotificationTitle', { + defaultMessage: 'Unable to create agent policy', + }), }); return; } diff --git a/x-pack/plugins/fleet/server/errors/index.ts b/x-pack/plugins/fleet/server/errors/index.ts index 80d8116baaaa3..caedf038eb7d6 100644 --- a/x-pack/plugins/fleet/server/errors/index.ts +++ b/x-pack/plugins/fleet/server/errors/index.ts @@ -57,6 +57,12 @@ export class AgentlessAgentCreateError extends FleetError { } } +export class AgentlessPackagePolicyRequestError extends FleetError { + constructor(message: string) { + super(`Unable to create agentless integration. ${message}`); + } +} + export class AgentPolicyNameExistsError extends AgentPolicyError {} export class AgentReassignmentError extends FleetError {} export class PackagePolicyIneligibleForUpgradeError extends FleetError {} diff --git a/x-pack/plugins/fleet/server/services/agent_policy.ts b/x-pack/plugins/fleet/server/services/agent_policy.ts index 272c3c593e58f..37892698fc0c6 100644 --- a/x-pack/plugins/fleet/server/services/agent_policy.ts +++ b/x-pack/plugins/fleet/server/services/agent_policy.ts @@ -83,6 +83,7 @@ import { FleetUnauthorizedError, HostedAgentPolicyRestrictionRelatedError, PackagePolicyRestrictionRelatedError, + AgentlessPackagePolicyRequestError, } from '../errors'; import type { FullAgentConfigMap } from '../../common/types/models/agent_cm'; @@ -410,7 +411,7 @@ class AgentPolicyService { public async requireUniqueName( soClient: SavedObjectsClientContract, - givenPolicy: { id?: string; name: string } + givenPolicy: { id?: string; name: string; supports_agentless?: boolean | null } ) { const savedObjectType = await getAgentPolicySavedObjectType(); @@ -422,7 +423,11 @@ class AgentPolicyService { const idsWithName = results.total && results.saved_objects.map(({ id }) => id); if (Array.isArray(idsWithName)) { const isEditingSelf = givenPolicy.id && idsWithName.includes(givenPolicy.id); - if (!givenPolicy.id || !isEditingSelf) { + + if ( + (!givenPolicy?.supports_agentless && !givenPolicy.id) || + (!givenPolicy?.supports_agentless && !isEditingSelf) + ) { const isSinglePolicy = idsWithName.length === 1; const existClause = isSinglePolicy ? `Agent Policy '${idsWithName[0]}' already exists` @@ -430,6 +435,13 @@ class AgentPolicyService { throw new AgentPolicyNameExistsError(`${existClause} with name '${givenPolicy.name}'`); } + + if (givenPolicy?.supports_agentless && !givenPolicy.id) { + const integrationName = givenPolicy.name.split(' ').pop(); + throw new AgentlessPackagePolicyRequestError( + `${givenPolicy.name} already exist. Please rename ${integrationName} integration.` + ); + } } } @@ -646,6 +658,7 @@ class AgentPolicyService { await this.requireUniqueName(soClient, { id, name: agentPolicy.name, + supports_agentless: agentPolicy?.supports_agentless, }); } if (agentPolicy.namespace) { diff --git a/x-pack/plugins/fleet/server/services/agent_policy_create.ts b/x-pack/plugins/fleet/server/services/agent_policy_create.ts index 5ec2bc166482c..f370867fc493b 100644 --- a/x-pack/plugins/fleet/server/services/agent_policy_create.ts +++ b/x-pack/plugins/fleet/server/services/agent_policy_create.ts @@ -25,6 +25,7 @@ import { agentPolicyService, packagePolicyService } from '.'; import { incrementPackageName } from './package_policies'; import { bulkInstallPackages } from './epm/packages'; import { ensureDefaultEnrollmentAPIKeyForAgentPolicy } from './api_keys'; +import { agentlessAgentService } from './agents/agentless_agent'; const FLEET_SERVER_POLICY_ID = 'fleet-server-policy'; From 13f42a0e01a0111075a6a56ef4f0d97487751f6d Mon Sep 17 00:00:00 2001 From: Lola Date: Tue, 10 Sep 2024 17:40:13 -0400 Subject: [PATCH 23/44] disables fleet actions for agentless --- .../components/actions_menu.test.tsx | 66 +++++++ .../agent_policy/components/actions_menu.tsx | 167 ++++++++++-------- .../agent_policy_advanced_fields/index.tsx | 46 ++++- .../components/agent_policy_form.tsx | 2 +- .../components/header/right_content.tsx | 2 +- 5 files changed, 202 insertions(+), 81 deletions(-) diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/actions_menu.test.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/actions_menu.test.tsx index 9781270d9dd81..4df4b4fe912d9 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/actions_menu.test.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/actions_menu.test.tsx @@ -109,6 +109,39 @@ describe('AgentPolicyActionMenu', () => { const deleteButton = result.getByTestId('agentPolicyActionMenuDeleteButton'); expect(deleteButton).toHaveAttribute('disabled'); }); + + it('is disabled when agent policy support agentless is true', () => { + const testRenderer = createFleetTestRendererMock(); + const agentlessPolicy: AgentPolicy = { + ...baseAgentPolicy, + supports_agentless: true, + package_policies: [ + { + id: 'test-package-policy', + is_managed: false, + created_at: new Date().toISOString(), + created_by: 'test', + enabled: true, + inputs: [], + name: 'test-package-policy', + namespace: 'default', + policy_id: 'test', + policy_ids: ['test'], + revision: 1, + updated_at: new Date().toISOString(), + updated_by: 'test', + }, + ], + }; + + const result = testRenderer.render(); + + const agentActionsButton = result.getByTestId('agentActionsBtn'); + agentActionsButton.click(); + + const deleteButton = result.getByTestId('agentPolicyActionMenuDeleteButton'); + expect(deleteButton).not.toHaveAttribute('disabled'); + }); }); describe('add agent', () => { @@ -176,6 +209,39 @@ describe('AgentPolicyActionMenu', () => { const addButton = result.getByTestId('agentPolicyActionMenuAddAgentButton'); expect(addButton).toHaveAttribute('disabled'); }); + + it('should remove add agent button when agent policy support agentless is true', () => { + const testRenderer = createFleetTestRendererMock(); + const agentlessPolicy: AgentPolicy = { + ...baseAgentPolicy, + supports_agentless: true, + package_policies: [ + { + id: 'test-package-policy', + is_managed: false, + created_at: new Date().toISOString(), + created_by: 'test', + enabled: true, + inputs: [], + name: 'test-package-policy', + namespace: 'default', + policy_id: 'test', + policy_ids: ['test'], + revision: 1, + updated_at: new Date().toISOString(), + updated_by: 'test', + }, + ], + }; + + const result = testRenderer.render(); + + const agentActionsButton = result.getByTestId('agentActionsBtn'); + agentActionsButton.click(); + + const addAgentActionButton = result.queryByTestId('agentPolicyActionMenuAddAgentButton'); + expect(addAgentActionButton).toBeNull(); + }); }); describe('add fleet server', () => { diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/actions_menu.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/actions_menu.tsx index 8345742f3d4da..007220611f079 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/actions_menu.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/actions_menu.tsx @@ -100,83 +100,105 @@ export const AgentPolicyActionMenu = memo<{ ); - const menuItems = agentPolicy?.is_managed - ? [viewPolicyItem] - : [ + const deletePolicyItem = ( + + {(deleteAgentPolicyPrompt) => ( + ) : undefined } - data-test-subj="agentPolicyActionMenuAddAgentButton" - onClick={() => { - setIsContextMenuOpen(false); - setIsEnrollmentFlyoutOpen(true); - }} - key="enrollAgents" - > - {isFleetServerPolicy ? ( - - ) : ( - - )} - , - viewPolicyItem, - { - setIsContextMenuOpen(false); - copyAgentPolicyPrompt(agentPolicy, onCopySuccess); + deleteAgentPolicyPrompt(agentPolicy.id); }} - key="copyPolicy" > - , - - {(deleteAgentPolicyPrompt) => ( - - ) : undefined - } - icon="trash" - onClick={() => { - deleteAgentPolicyPrompt(agentPolicy.id); - }} - > - - - )} - , - ]; + + )} + + ); + + const copyPolicyItem = ( + { + setIsContextMenuOpen(false); + copyAgentPolicyPrompt(agentPolicy, onCopySuccess); + }} + key="copyPolicy" + > + + + ); + + const managedMenuItems = [viewPolicyItem]; + const agentBasedMenuItems = [ + { + setIsContextMenuOpen(false); + setIsEnrollmentFlyoutOpen(true); + }} + key="enrollAgents" + > + {isFleetServerPolicy ? ( + + ) : ( + + )} + , + viewPolicyItem, + copyPolicyItem, + deletePolicyItem, + ]; + const agentlessMenuItems = [viewPolicyItem, deletePolicyItem]; + + let menuItems; + if (agentPolicy?.is_managed) { + menuItems = managedMenuItems; + } else if (!agentPolicy?.supports_agentless) { + menuItems = agentBasedMenuItems; + } else { + menuItems = agentlessMenuItems; + } - if (authz.fleet.allAgents && !agentPolicy?.is_managed) { + if ( + authz.fleet.allAgents && + !agentPolicy?.is_managed && + !agentPolicy?.supports_agentless + ) { menuItems.push( = ); const AgentTamperProtectionSection = useMemo(() => { - if (agentTamperProtectionEnabled && licenseService.isPlatinum() && !agentPolicy.is_managed) { + if ( + agentTamperProtectionEnabled && + licenseService.isPlatinum() && + !agentPolicy.is_managed && + !agentPolicy.supports_agentless + ) { if (AgentTamperProtectionWrapper) { return ( @@ -212,6 +217,7 @@ export const AgentPolicyAdvancedOptionsContent: React.FunctionComponent = agentPolicy.is_managed, AgentTamperProtectionWrapper, AgentTamperProtectionSectionContent, + agentPolicy.supports_agentless, ]); return ( @@ -402,7 +408,9 @@ export const AgentPolicyAdvancedOptionsContent: React.FunctionComponent = } > = > { @@ -568,7 +580,11 @@ export const AgentPolicyAdvancedOptionsContent: React.FunctionComponent = isInvalid={Boolean(touchedFields.fleet_server_host_id && validation.fleet_server_host_id)} > = isDisabled={disabled} > = isDisabled={disabled} > = isDisabled={disabled} > = > = > { diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_form.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_form.tsx index 66b3f41408c8f..42130e051f2c8 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_form.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_form.tsx @@ -188,7 +188,7 @@ export const AgentPolicyForm: React.FunctionComponent = ({ ) : null} diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/details_page/components/header/right_content.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/details_page/components/header/right_content.tsx index 5dd391450b0cb..6603698a80186 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/details_page/components/header/right_content.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/details_page/components/header/right_content.tsx @@ -106,7 +106,7 @@ export const HeaderRightContent: React.FunctionComponent Date: Tue, 10 Sep 2024 19:32:44 -0400 Subject: [PATCH 24/44] fix edit flow ftr --- .../agent_policy/edit_package_policy_page/index.tsx | 6 ++---- .../security/config.cloud_security_posture.agentless.ts | 6 ++++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/edit_package_policy_page/index.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/edit_package_policy_page/index.tsx index f9770046ce21f..cabb2b8c59d7c 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/edit_package_policy_page/index.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/edit_package_policy_page/index.tsx @@ -106,7 +106,7 @@ export const EditPackagePolicyForm = memo<{ } = useConfig(); const { getHref } = useLink(); const { canUseMultipleAgentPolicies } = useMultipleAgentPolicies(); - const { isAgentlessAgentPolicy } = useAgentless(); + const { isAgentlessEnabled } = useAgentless(); const { // data @@ -441,8 +441,6 @@ export const EditPackagePolicyForm = memo<{ ] ); - const agentlessPolicy = agentPolicies.find((agentPolicy) => agentPolicy?.supports_agentless); - const replaceConfigurePackage = replaceDefineStepView && originalPackagePolicy && packageInfo && ( ); diff --git a/x-pack/test_serverless/functional/test_suites/security/config.cloud_security_posture.agentless.ts b/x-pack/test_serverless/functional/test_suites/security/config.cloud_security_posture.agentless.ts index 948a418279ac9..ff2238351fb57 100644 --- a/x-pack/test_serverless/functional/test_suites/security/config.cloud_security_posture.agentless.ts +++ b/x-pack/test_serverless/functional/test_suites/security/config.cloud_security_posture.agentless.ts @@ -16,9 +16,11 @@ export default createTestConfig({ kbnServerArgs: [ `--xpack.fleet.packages.0.name=cloud_security_posture`, `--xpack.fleet.packages.0.version=${CLOUD_CREDENTIALS_PACKAGE_VERSION}`, + `--xpack.fleet.agentless.enabled=true`, + `--xpack.fleet.agents.fleet_server.hosts=["https://ftr.kibana:8220"]`, + `--xpack.fleet.internal.fleetServerStandalone=true`, - // Agentless Configuration based on Serverless Security Dev Yaml - config/serverless.security.dev.yml - `--xpack.fleet.enableExperimental.0=agentless`, + // Agentless Configuration based on Serverless Secu`--xpack.fleet.agentless.enabled=true`, `--xpack.fleet.agentPolicies.0.id=agentless`, `--xpack.fleet.agentPolicies.0.name=agentless`, `--xpack.fleet.agentPolicies.0.package_policies=[]`, From 4bbd39d703cb76dff2d2f157f7d9d27989e9e7ef Mon Sep 17 00:00:00 2001 From: Lola Date: Wed, 11 Sep 2024 12:32:15 -0400 Subject: [PATCH 25/44] fix save and edit ftr test --- .../config.cloud_security_posture.agentless.ts | 12 +++++++++++- .../agentless/cis_integration_aws.ts | 7 +++++-- .../agentless/cis_integration_gcp.ts | 5 +++++ 3 files changed, 21 insertions(+), 3 deletions(-) diff --git a/x-pack/test_serverless/functional/test_suites/security/config.cloud_security_posture.agentless.ts b/x-pack/test_serverless/functional/test_suites/security/config.cloud_security_posture.agentless.ts index ff2238351fb57..692ae096265fb 100644 --- a/x-pack/test_serverless/functional/test_suites/security/config.cloud_security_posture.agentless.ts +++ b/x-pack/test_serverless/functional/test_suites/security/config.cloud_security_posture.agentless.ts @@ -6,8 +6,10 @@ */ import { CLOUD_CREDENTIALS_PACKAGE_VERSION } from '@kbn/cloud-security-posture-plugin/common/constants'; +import { CA_CERT_PATH, KBN_CERT_PATH, KBN_KEY_PATH } from '@kbn/dev-utils'; import { createTestConfig } from '../../config.base'; +// TODO: Remove the agentless default config once Serverless API is merged and default policy is deleted export default createTestConfig({ serverlessProject: 'security', junit: { @@ -20,11 +22,19 @@ export default createTestConfig({ `--xpack.fleet.agents.fleet_server.hosts=["https://ftr.kibana:8220"]`, `--xpack.fleet.internal.fleetServerStandalone=true`, - // Agentless Configuration based on Serverless Secu`--xpack.fleet.agentless.enabled=true`, + // Agentless Configuration based on Serverless Default policy`, `--xpack.fleet.agentPolicies.0.id=agentless`, `--xpack.fleet.agentPolicies.0.name=agentless`, `--xpack.fleet.agentPolicies.0.package_policies=[]`, `--xpack.cloud.serverless.project_id=some_fake_project_id`, + `--xpack.fleet.agentPolicies.0.is_default=true`, + `--xpack.fleet.agentPolicies.0.is_default_fleet_server=true`, + + // Serverless Agentless API + `--xpack.fleet.agentless.api.url=http://localhost:8089`, + `--xpack.fleet.agentless.api.tls.certificate=${KBN_CERT_PATH}`, + `--xpack.fleet.agentless.api.tls.key=${KBN_KEY_PATH}`, + `--xpack.fleet.agentless.api.tls.ca=${CA_CERT_PATH}`, ], // load tests in the index file testFiles: [require.resolve('./ftr/cloud_security_posture/agentless')], diff --git a/x-pack/test_serverless/functional/test_suites/security/ftr/cloud_security_posture/agentless/cis_integration_aws.ts b/x-pack/test_serverless/functional/test_suites/security/ftr/cloud_security_posture/agentless/cis_integration_aws.ts index 6adbbac3cdc57..17255162fc85c 100644 --- a/x-pack/test_serverless/functional/test_suites/security/ftr/cloud_security_posture/agentless/cis_integration_aws.ts +++ b/x-pack/test_serverless/functional/test_suites/security/ftr/cloud_security_posture/agentless/cis_integration_aws.ts @@ -6,8 +6,9 @@ */ import { CLOUD_CREDENTIALS_PACKAGE_VERSION } from '@kbn/cloud-security-posture-plugin/common/constants'; import expect from '@kbn/expect'; - +import * as http from 'http'; import type { FtrProviderContext } from '../../../../../ftr_provider_context'; +import { setupMockServer } from '../agentless_api/mock_agentless_api'; export default function ({ getPageObjects, getService }: FtrProviderContext) { const pageObjects = getPageObjects([ 'settings', @@ -24,9 +25,12 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { let cisIntegration: typeof pageObjects.cisAddIntegration; let cisIntegrationAws: typeof pageObjects.cisAddIntegration.cisAws; let testSubjectIds: typeof pageObjects.cisAddIntegration.testSubjectIds; + const mockAgentlessApiService = setupMockServer(); + let mockApiServer: http.Server; const previousPackageVersion = '1.9.0'; before(async () => { + mockApiServer = mockAgentlessApiService.listen(8089); await pageObjects.svlCommonPage.loginAsAdmin(); cisIntegration = pageObjects.cisAddIntegration; cisIntegrationAws = pageObjects.cisAddIntegration.cisAws; @@ -142,7 +146,6 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { ).to.be('true'); }); }); - // FLAKY: https://github.com/elastic/kibana/issues/191017 describe.skip('Serverless - Agentless CIS_AWS Create flow', () => { it(`user should save agentless integration policy when there are no api or validation errors and button is not disabled`, async () => { diff --git a/x-pack/test_serverless/functional/test_suites/security/ftr/cloud_security_posture/agentless/cis_integration_gcp.ts b/x-pack/test_serverless/functional/test_suites/security/ftr/cloud_security_posture/agentless/cis_integration_gcp.ts index cd9e5b2168d1a..5fa7dfc602b4f 100644 --- a/x-pack/test_serverless/functional/test_suites/security/ftr/cloud_security_posture/agentless/cis_integration_gcp.ts +++ b/x-pack/test_serverless/functional/test_suites/security/ftr/cloud_security_posture/agentless/cis_integration_gcp.ts @@ -7,7 +7,9 @@ import expect from '@kbn/expect'; import { CLOUD_CREDENTIALS_PACKAGE_VERSION } from '@kbn/cloud-security-posture-plugin/common/constants'; +import * as http from 'http'; import type { FtrProviderContext } from '../../../../../ftr_provider_context'; +import { setupMockServer } from '../agentless_api/mock_agentless_api'; export default function ({ getPageObjects, getService }: FtrProviderContext) { const pageObjects = getPageObjects(['common', 'svlCommonPage', 'cisAddIntegration', 'header']); @@ -20,8 +22,11 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { let cisIntegration: typeof pageObjects.cisAddIntegration; let cisIntegrationGcp: typeof pageObjects.cisAddIntegration.cisGcp; let testSubjectIds: typeof pageObjects.cisAddIntegration.testSubjectIds; + let mockApiServer: http.Server; + const mockAgentlessApiService = setupMockServer(); before(async () => { + mockApiServer = mockAgentlessApiService.listen(8089); await pageObjects.svlCommonPage.loginAsAdmin(); cisIntegration = pageObjects.cisAddIntegration; cisIntegrationGcp = pageObjects.cisAddIntegration.cisGcp; From 891e5af521b1fc12b2ff945698509053ed315138 Mon Sep 17 00:00:00 2001 From: Lola Date: Wed, 11 Sep 2024 14:06:03 -0400 Subject: [PATCH 26/44] fix type build error --- .../cloud_security_posture/agentless/cis_integration_aws.ts | 2 +- .../cloud_security_posture/agentless/cis_integration_gcp.ts | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/x-pack/test_serverless/functional/test_suites/security/ftr/cloud_security_posture/agentless/cis_integration_aws.ts b/x-pack/test_serverless/functional/test_suites/security/ftr/cloud_security_posture/agentless/cis_integration_aws.ts index 17255162fc85c..1c9683c599cfd 100644 --- a/x-pack/test_serverless/functional/test_suites/security/ftr/cloud_security_posture/agentless/cis_integration_aws.ts +++ b/x-pack/test_serverless/functional/test_suites/security/ftr/cloud_security_posture/agentless/cis_integration_aws.ts @@ -10,6 +10,7 @@ import * as http from 'http'; import type { FtrProviderContext } from '../../../../../ftr_provider_context'; import { setupMockServer } from '../agentless_api/mock_agentless_api'; export default function ({ getPageObjects, getService }: FtrProviderContext) { + const mockAgentlessApiService = setupMockServer(); const pageObjects = getPageObjects([ 'settings', 'common', @@ -25,7 +26,6 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { let cisIntegration: typeof pageObjects.cisAddIntegration; let cisIntegrationAws: typeof pageObjects.cisAddIntegration.cisAws; let testSubjectIds: typeof pageObjects.cisAddIntegration.testSubjectIds; - const mockAgentlessApiService = setupMockServer(); let mockApiServer: http.Server; const previousPackageVersion = '1.9.0'; diff --git a/x-pack/test_serverless/functional/test_suites/security/ftr/cloud_security_posture/agentless/cis_integration_gcp.ts b/x-pack/test_serverless/functional/test_suites/security/ftr/cloud_security_posture/agentless/cis_integration_gcp.ts index 5fa7dfc602b4f..fbad2e13cb8d3 100644 --- a/x-pack/test_serverless/functional/test_suites/security/ftr/cloud_security_posture/agentless/cis_integration_gcp.ts +++ b/x-pack/test_serverless/functional/test_suites/security/ftr/cloud_security_posture/agentless/cis_integration_gcp.ts @@ -22,8 +22,9 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { let cisIntegration: typeof pageObjects.cisAddIntegration; let cisIntegrationGcp: typeof pageObjects.cisAddIntegration.cisGcp; let testSubjectIds: typeof pageObjects.cisAddIntegration.testSubjectIds; - let mockApiServer: http.Server; + const mockAgentlessApiService = setupMockServer(); + let mockApiServer: http.Server; before(async () => { mockApiServer = mockAgentlessApiService.listen(8089); @@ -41,6 +42,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { .set('kbn-xsrf', 'xxxx') .send({ force: true }) .expect(200); + mockApiServer.close(); }); describe('Agentless CIS_GCP Single Account Launch Cloud shell', () => { From a63da94f9687b07512e9bf85e2d8e3374e642f64 Mon Sep 17 00:00:00 2001 From: Lola Date: Wed, 11 Sep 2024 16:12:45 -0400 Subject: [PATCH 27/44] fix build --- .../agent_policy/components/agent_policy_delete_provider.tsx | 2 +- .../ftr/cloud_security_posture/agentless/cis_integration_aws.ts | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_delete_provider.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_delete_provider.tsx index adbe0a748be2a..8a7e9ec272f33 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_delete_provider.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_delete_provider.tsx @@ -213,7 +213,7 @@ export const AgentPolicyDeleteProvider: React.FunctionComponent = ({ {agentPolicy?.supports_agentless ? ( ) : ( { From 0b03d5a5f43c11a3da2c498beb80974bf61ece2a Mon Sep 17 00:00:00 2001 From: Lola Date: Wed, 11 Sep 2024 18:31:24 -0400 Subject: [PATCH 28/44] remove fleet actions agentless agent in agents page --- .../agent_details_page/components/actions_menu.tsx | 2 +- .../agent_list_page/components/table_row_actions.tsx | 11 ++++++++--- .../agent_policy_selection.tsx | 12 +++++++----- 3 files changed, 16 insertions(+), 9 deletions(-) diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/actions_menu.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/actions_menu.tsx index feefebf4fa2d6..231b10782eca7 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/actions_menu.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/actions_menu.tsx @@ -71,7 +71,7 @@ export const AgentDetailsActionMenu: React.FunctionComponent<{ onClick={() => { setIsReassignFlyoutOpen(true); }} - disabled={!agent.active && !agentPolicy} + disabled={(!agent.active && !agentPolicy) || agentPolicy?.supports_agentless === true} key="reassignPolicy" > { onReassignClick(); }} - disabled={!agent.active} + disabled={!agent.active || agentPolicy?.supports_agentless === true} key="reassignPolicy" > { onUpgradeClick(); }} @@ -138,7 +138,12 @@ export const TableRowActions: React.FunctionComponent<{ ); } - if (authz.fleet.allAgents && agentTamperProtectionEnabled && agent.policy_id) { + if ( + authz.fleet.allAgents && + agentTamperProtectionEnabled && + agent.policy_id && + !agentPolicy?.supports_agentless + ) { menuItems.push( >; + agentPolicies: Array>; selectedPolicyId?: string; setSelectedPolicyId: (agentPolicyId?: string) => void; excludeFleetServer?: boolean; @@ -115,10 +115,12 @@ export const AgentPolicySelection: React.FC = (props) => { ({ - value: agentPolicy.id, - text: agentPolicy.name, - }))} + options={agentPolicies + .filter((policy) => !policy?.supports_agentless) + .map((agentPolicy) => ({ + value: agentPolicy.id, + text: agentPolicy.name, + }))} value={selectedPolicyId} onChange={onChangeCallback} aria-label={i18n.translate( From 1155b8933c615eb8f9cbdb7e6d0d022f2b6db8cc Mon Sep 17 00:00:00 2001 From: Lola Date: Wed, 11 Sep 2024 18:32:46 -0400 Subject: [PATCH 29/44] fix 404 so client error when deleting agent policy with an active agent --- x-pack/plugins/fleet/server/services/agent_policy.ts | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/x-pack/plugins/fleet/server/services/agent_policy.ts b/x-pack/plugins/fleet/server/services/agent_policy.ts index f03ca0fe2dece..81c3d4eca4c6a 100644 --- a/x-pack/plugins/fleet/server/services/agent_policy.ts +++ b/x-pack/plugins/fleet/server/services/agent_policy.ts @@ -1155,6 +1155,10 @@ class AgentPolicyService { ); logger.error(error); } + // unenroll offline agents for agentless policies + await this.triggerAgentPolicyUpdatedEvent(esClient, 'deleted', id, { + spaceId: soClient.getCurrentNamespace(), + }); } const packagePolicies = await packagePolicyService.findAllForAgentPolicy(soClient, id); @@ -1216,9 +1220,11 @@ class AgentPolicyService { } await soClient.delete(savedObjectType, id); - await this.triggerAgentPolicyUpdatedEvent(esClient, 'deleted', id, { - spaceId: soClient.getCurrentNamespace(), - }); + if (!agentPolicy?.supports_agentless) { + await this.triggerAgentPolicyUpdatedEvent(esClient, 'deleted', id, { + spaceId: soClient.getCurrentNamespace(), + }); + } // cleanup .fleet-policies docs on delete await this.deleteFleetServerPoliciesForPolicyId(esClient, id); From 580d31fbf42f2dcf19e41c26900e0236ac40c2b7 Mon Sep 17 00:00:00 2001 From: Lola Date: Thu, 12 Sep 2024 13:15:31 -0400 Subject: [PATCH 30/44] remove irrevelant package policy action items for agentless integrations --- .../package_policy_actions_menu.test.tsx | 20 +++++++++++++++++++ .../package_policy_actions_menu.tsx | 8 ++++++-- 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/x-pack/plugins/fleet/public/components/package_policy_actions_menu.test.tsx b/x-pack/plugins/fleet/public/components/package_policy_actions_menu.test.tsx index d9223b3449fba..dbf3969ffc226 100644 --- a/x-pack/plugins/fleet/public/components/package_policy_actions_menu.test.tsx +++ b/x-pack/plugins/fleet/public/components/package_policy_actions_menu.test.tsx @@ -135,6 +135,17 @@ describe('PackagePolicyActionsMenu', () => { }); }); + it('Should not enable upgrade button if package has upgrade and agentless policy is enabled', async () => { + const agentPolicies = createMockAgentPolicies({ supports_agentless: true }); + const packagePolicy = createMockPackagePolicy({ hasUpgrade: true }); + const { utils } = renderMenu({ agentPolicies, packagePolicy }); + + await act(async () => { + const upgradeButton = utils.getByTestId('PackagePolicyActionsUpgradeItem'); + expect(upgradeButton).toBeDisabled(); + }); + }); + it('Should not be able to delete integration from a managed policy', async () => { const agentPolicies = createMockAgentPolicies({ is_managed: true }); const packagePolicy = createMockPackagePolicy(); @@ -180,6 +191,15 @@ describe('PackagePolicyActionsMenu', () => { }); }); + it('Should not show add button if the policy is agentless and showAddAgent=true', async () => { + const agentPolicies = createMockAgentPolicies({ supports_agentless: true }); + const packagePolicy = createMockPackagePolicy({ hasUpgrade: true }); + const { utils } = renderMenu({ agentPolicies, packagePolicy, showAddAgent: true }); + await act(async () => { + expect(utils.queryByText('Add agent')).toBeNull(); + }); + }); + it('Should show Edit integration with correct href when agentPolicy is defined', async () => { const agentPolicies = createMockAgentPolicies(); const packagePolicy = createMockPackagePolicy(); diff --git a/x-pack/plugins/fleet/public/components/package_policy_actions_menu.tsx b/x-pack/plugins/fleet/public/components/package_policy_actions_menu.tsx index a7afa4b8681bc..4da1711b28313 100644 --- a/x-pack/plugins/fleet/public/components/package_policy_actions_menu.tsx +++ b/x-pack/plugins/fleet/public/components/package_policy_actions_menu.tsx @@ -49,7 +49,8 @@ export const PackagePolicyActionsMenu: React.FunctionComponent<{ const agentPolicyIsManaged = Boolean(agentPolicy?.is_managed); const isOrphanedPolicy = !agentPolicy && packagePolicy.policy_ids.length === 0; - const isAddAgentVisible = showAddAgent && agentPolicy && !agentPolicyIsManaged; + const isAddAgentVisible = + showAddAgent && agentPolicy && !agentPolicyIsManaged && !agentPolicy?.supports_agentless; const onEnrollmentFlyoutClose = useMemo(() => { return () => setIsEnrollmentFlyoutOpen(false); @@ -110,7 +111,10 @@ export const PackagePolicyActionsMenu: React.FunctionComponent<{ Date: Thu, 12 Sep 2024 13:43:07 -0400 Subject: [PATCH 31/44] fix save object 404 error on agents page --- x-pack/plugins/fleet/server/services/agent_policy.ts | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/x-pack/plugins/fleet/server/services/agent_policy.ts b/x-pack/plugins/fleet/server/services/agent_policy.ts index 81c3d4eca4c6a..d6fabfc57c6de 100644 --- a/x-pack/plugins/fleet/server/services/agent_policy.ts +++ b/x-pack/plugins/fleet/server/services/agent_policy.ts @@ -1143,6 +1143,11 @@ class AgentPolicyService { } if (agentPolicy?.supports_agentless) { + logger.debug(`Starting unenrolling agent from agentless policy ${id}`); + // unenroll offline agents for agentless policies first to avoid 404 Save Object error + await this.triggerAgentPolicyUpdatedEvent(esClient, 'deleted', id, { + spaceId: soClient.getCurrentNamespace(), + }); try { // Deleting agentless deployment await agentlessAgentService.deleteAgentlessAgent(id); @@ -1155,10 +1160,6 @@ class AgentPolicyService { ); logger.error(error); } - // unenroll offline agents for agentless policies - await this.triggerAgentPolicyUpdatedEvent(esClient, 'deleted', id, { - spaceId: soClient.getCurrentNamespace(), - }); } const packagePolicies = await packagePolicyService.findAllForAgentPolicy(soClient, id); From 5ecb5b1bb26283cb10dc3c951e1dd37decd441ab Mon Sep 17 00:00:00 2001 From: Lola Date: Mon, 16 Sep 2024 14:14:56 -0400 Subject: [PATCH 32/44] fix hide multiple agent policies to support ess and serverless --- .../agent_policy/edit_package_policy_page/index.tsx | 7 ++++--- .../agentless/cis_integration_aws.ts | 3 ++- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/edit_package_policy_page/index.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/edit_package_policy_page/index.tsx index cabb2b8c59d7c..7812b0eaa5e1c 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/edit_package_policy_page/index.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/edit_package_policy_page/index.tsx @@ -46,8 +46,6 @@ import { StepConfigurePackagePolicy, StepDefinePackagePolicy, } from '../create_package_policy_page/components'; - -import { AGENTLESS_POLICY_ID } from '../../../../../../common/constants'; import type { AgentPolicy, PackagePolicyEditExtensionComponentProps } from '../../../types'; import { pkgKeyFromPackageInfo } from '../../../services'; @@ -130,7 +128,10 @@ export const EditPackagePolicyForm = memo<{ } = usePackagePolicyWithRelatedData(packagePolicyId, { forceUpgrade, }); - const hasAgentlessAgentPolicy = packagePolicy.policy_ids.includes(AGENTLESS_POLICY_ID); + + const hasAgentlessAgentPolicy = existingAgentPolicies.some( + (policy) => policy.id === policyId && policy.supports_agentless === true + ); const canWriteIntegrationPolicies = useAuthz().integrations.writeIntegrationPolicies; useSetIsReadOnly(!canWriteIntegrationPolicies); diff --git a/x-pack/test_serverless/functional/test_suites/security/ftr/cloud_security_posture/agentless/cis_integration_aws.ts b/x-pack/test_serverless/functional/test_suites/security/ftr/cloud_security_posture/agentless/cis_integration_aws.ts index 35c5b2684f4c6..90991304936ea 100644 --- a/x-pack/test_serverless/functional/test_suites/security/ftr/cloud_security_posture/agentless/cis_integration_aws.ts +++ b/x-pack/test_serverless/functional/test_suites/security/ftr/cloud_security_posture/agentless/cis_integration_aws.ts @@ -115,7 +115,8 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { }); }); - describe('Serverless - Agentless CIS_AWS edit flow', () => { + // TODO: Migrate test after Serverless default agentless policy is deleted. + describe.skip('Serverless - Agentless CIS_AWS edit flow', () => { it(`user should save and edit agentless integration policy`, async () => { const newDirectAccessKeyId = `newDirectAccessKey`; From b1127294ee7d3fc6ba38558c71b83a8386cf760e Mon Sep 17 00:00:00 2001 From: Lola Date: Mon, 16 Sep 2024 14:21:08 -0400 Subject: [PATCH 33/44] fix error messaging --- .../single_page_layout/hooks/form.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 07aa702c1ed79..3375c5137034a 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 @@ -350,7 +350,7 @@ export function useOnSubmit({ notifications.toasts.addError(e, { title: agentlessPolicy?.supports_agentless ? i18n.translate('xpack.fleet.createAgentlessPolicy.errorNotificationTitle', { - defaultMessage: 'Unable to create agentless integration', + defaultMessage: 'Unable to create integration', }) : i18n.translate('xpack.fleet.createAgentPolicy.errorNotificationTitle', { defaultMessage: 'Unable to create agent policy', From a11140599cf290f5ab525d36c028815c1ecb7343 Mon Sep 17 00:00:00 2001 From: Lola Date: Mon, 16 Sep 2024 14:33:28 -0400 Subject: [PATCH 34/44] fix error messaging language --- x-pack/plugins/fleet/server/errors/index.ts | 2 +- x-pack/plugins/fleet/server/services/agent_policy.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/x-pack/plugins/fleet/server/errors/index.ts b/x-pack/plugins/fleet/server/errors/index.ts index caedf038eb7d6..62ed7eafc608d 100644 --- a/x-pack/plugins/fleet/server/errors/index.ts +++ b/x-pack/plugins/fleet/server/errors/index.ts @@ -59,7 +59,7 @@ export class AgentlessAgentCreateError extends FleetError { export class AgentlessPackagePolicyRequestError extends FleetError { constructor(message: string) { - super(`Unable to create agentless integration. ${message}`); + super(`Unable to create integration. ${message}`); } } diff --git a/x-pack/plugins/fleet/server/services/agent_policy.ts b/x-pack/plugins/fleet/server/services/agent_policy.ts index d28dabe6c2f79..b508345651958 100644 --- a/x-pack/plugins/fleet/server/services/agent_policy.ts +++ b/x-pack/plugins/fleet/server/services/agent_policy.ts @@ -441,7 +441,7 @@ class AgentPolicyService { if (givenPolicy?.supports_agentless && !givenPolicy.id) { const integrationName = givenPolicy.name.split(' ').pop(); throw new AgentlessPackagePolicyRequestError( - `${givenPolicy.name} already exist. Please rename ${integrationName} integration.` + `${givenPolicy.name} already exist. Please rename the integration name ${integrationName}.` ); } } From 32726d32cb32183d25f599fbd8751f81061c270f Mon Sep 17 00:00:00 2001 From: Lola Date: Mon, 16 Sep 2024 15:24:27 -0400 Subject: [PATCH 35/44] edit deletion of agent policy messaging --- .../agent_policy/components/agent_policy_delete_provider.tsx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_delete_provider.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_delete_provider.tsx index 8a7e9ec272f33..69dafa40a43e0 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_delete_provider.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_delete_provider.tsx @@ -213,7 +213,10 @@ export const AgentPolicyDeleteProvider: React.FunctionComponent = ({ {agentPolicy?.supports_agentless ? ( {agentPolicy.name}, + }} /> ) : ( Date: Fri, 20 Sep 2024 09:31:19 -0400 Subject: [PATCH 36/44] update tests --- .../edit_package_policy_page/index.tsx | 6 +- .../server/services/agent_policy.test.ts | 4 +- .../apis/agent_policy/agent_policy.ts | 73 +++++++++++++++++++ 3 files changed, 76 insertions(+), 7 deletions(-) diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/edit_package_policy_page/index.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/edit_package_policy_page/index.tsx index 7812b0eaa5e1c..71675db4c6996 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/edit_package_policy_page/index.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/edit_package_policy_page/index.tsx @@ -60,8 +60,6 @@ import { RootPrivilegesCallout } from '../create_package_policy_page/single_page import { StepsWithLessPadding } from '../create_package_policy_page/single_page_layout'; -import { useAgentless } from '../create_package_policy_page/single_page_layout/hooks/setup_technology'; - import { UpgradeStatusCallout } from './components'; import { usePackagePolicyWithRelatedData, useHistoryBlock } from './hooks'; import { getNewSecrets } from './utils'; @@ -104,8 +102,6 @@ export const EditPackagePolicyForm = memo<{ } = useConfig(); const { getHref } = useLink(); const { canUseMultipleAgentPolicies } = useMultipleAgentPolicies(); - const { isAgentlessEnabled } = useAgentless(); - const { // data agentPolicies: existingAgentPolicies, @@ -452,7 +448,7 @@ export const EditPackagePolicyForm = memo<{ onChange={handleExtensionViewOnChange} validationResults={validationResults} isEditPage={true} - isAgentlessEnabled={isAgentlessEnabled} + isAgentlessEnabled={hasAgentlessAgentPolicy} /> ); diff --git a/x-pack/plugins/fleet/server/services/agent_policy.test.ts b/x-pack/plugins/fleet/server/services/agent_policy.test.ts index f4878e7f9f1bc..00bc01aa1f2cb 100644 --- a/x-pack/plugins/fleet/server/services/agent_policy.test.ts +++ b/x-pack/plugins/fleet/server/services/agent_policy.test.ts @@ -363,7 +363,7 @@ describe('Agent policy', () => { ); }); - it('should create a policy without is_managed as true and agentless feature flag is set and in serverless env', async () => { + it('should create a policy agentless feature flag is set and in serverless env', async () => { jest .spyOn(appContextService, 'getExperimentalFeatures') .mockReturnValue({ agentless: true } as any); @@ -401,7 +401,7 @@ describe('Agent policy', () => { }); }); - it('should create a policy without is_managed as true if agentless feature flag is set and in cloud env', async () => { + it('should create a policy if agentless feature flag is set and in cloud env', async () => { jest.spyOn(appContextService, 'getCloud').mockReturnValue({ isCloudEnabled: true } as any); jest.spyOn(appContextService, 'getConfig').mockReturnValue({ agentless: { enabled: true }, diff --git a/x-pack/test/fleet_api_integration/apis/agent_policy/agent_policy.ts b/x-pack/test/fleet_api_integration/apis/agent_policy/agent_policy.ts index 2bc3f68867002..ce231db7ce40a 100644 --- a/x-pack/test/fleet_api_integration/apis/agent_policy/agent_policy.ts +++ b/x-pack/test/fleet_api_integration/apis/agent_policy/agent_policy.ts @@ -1473,6 +1473,79 @@ export default function (providerContext: FtrProviderContext) { await supertest.get(`/api/fleet/agent_policies/${hostedPolicy.id}`).expect(404); }); + it('should allow agentless policies being deleted', async () => { + const { + body: { item: createdPolicy }, + } = await supertest + .post(`/api/fleet/agent_policies`) + .set('kbn-xsrf', 'xxxx') + .send({ + name: 'Agentless policy', + namespace: 'default', + is_managed: false, + support_agentless: true, + }) + .expect(200); + const { + body: { item: agentlessPolicy }, + } = await supertest + .put(`/api/fleet/agent_policies/${createdPolicy.id}`) + .set('kbn-xsrf', 'xxxx') + .send({ + name: 'Agentless policy', + namespace: 'default', + support_agentless: true, + }) + .expect(200); + + const { body } = await supertest + .post('/api/fleet/agent_policies/delete') + .set('kbn-xsrf', 'xxx') + .send({ agentPolicyId: agentlessPolicy.id }); + + expect(body).to.eql({ + id: agentlessPolicy.id, + name: 'Agentless policy', + }); + }); + + it('should allow agentless policies with agents being deleted', async () => { + const { + body: { item: createdPolicy }, + } = await supertest + .post(`/api/fleet/agent_policies`) + .set('kbn-xsrf', 'xxxx') + .send({ + name: 'Agentless policy', + namespace: 'default', + is_managed: false, + support_agentless: true, + }) + .expect(200); + const { + body: { item: agentlessPolicy }, + } = await supertest + .put(`/api/fleet/agent_policies/${createdPolicy.id}`) + .set('kbn-xsrf', 'xxxx') + .send({ + name: 'Agentless policy', + namespace: 'default', + support_agentless: true, + }) + .expect(200); + await generateAgent(providerContext, 'healhty', 'agent-healthy-1', agentlessPolicy.id); + + const { body } = await supertest + .post('/api/fleet/agent_policies/delete') + .set('kbn-xsrf', 'xxx') + .send({ agentPolicyId: agentlessPolicy.id }); + + expect(body).to.eql({ + id: agentlessPolicy.id, + name: 'Agentless policy', + }); + }); + describe('Errors when trying to delete', () => { it('should prevent policies having agents from being deleted', async () => { const { From 6ee67f013e25eba10282d840ef6f4e47badcb21e Mon Sep 17 00:00:00 2001 From: Lola Date: Fri, 20 Sep 2024 15:26:16 -0400 Subject: [PATCH 37/44] add unit test and update FTR for bug fix --- .../edit_package_policy_page/index.test.tsx | 23 +++++++- .../edit_package_policy_page/index.tsx | 12 +++- .../agentless/create_agent.ts | 57 +++++++++++++++++++ .../add_cis_integration_form_page.ts | 7 +++ .../apis/agent_policy/agent_policy.ts | 16 +----- .../agentless/cis_integration_gcp.ts | 2 +- 6 files changed, 98 insertions(+), 19 deletions(-) diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/edit_package_policy_page/index.test.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/edit_package_policy_page/index.test.tsx index 384920b252a5a..94bcf380f7086 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/edit_package_policy_page/index.test.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/edit_package_policy_page/index.test.tsx @@ -495,7 +495,14 @@ describe('edit package policy page', () => { }, }); (sendGetOneAgentPolicy as MockFn).mockResolvedValue({ - data: { item: { id: 'agentless', name: 'Agentless policy', namespace: 'default' } }, + data: { + item: { + id: 'agentless', + name: 'Agentless policy', + namespace: 'default', + supports_agentless: true, + }, + }, }); render(); @@ -514,6 +521,20 @@ describe('edit package policy page', () => { expect(sendUpdatePackagePolicy).toHaveBeenCalled(); }); + it('should hide the multiselect agent policies when agent policy is agentless', async () => { + (useGetAgentPolicies as MockFn).mockReturnValue({ + data: { + items: [{ id: 'agent-policy-1', name: 'Agent policy 1', supports_agentless: true }], + }, + isLoading: false, + }); + + await act(async () => { + render(); + }); + expect(renderResult.queryByTestId('agentPolicyMultiSelect')).not.toBeInTheDocument(); + }); + describe('modify agent policies', () => { beforeEach(() => { useMultipleAgentPoliciesMock.mockReturnValue({ canUseMultipleAgentPolicies: true }); diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/edit_package_policy_page/index.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/edit_package_policy_page/index.tsx index b7287c678a332..e448d1376b2fe 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/edit_package_policy_page/index.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/edit_package_policy_page/index.tsx @@ -60,6 +60,8 @@ import { RootPrivilegesCallout } from '../create_package_policy_page/single_page import { StepsWithLessPadding } from '../create_package_policy_page/single_page_layout'; +import { useAgentless } from '../create_package_policy_page/single_page_layout/hooks/setup_technology'; + import { UpgradeStatusCallout } from './components'; import { usePackagePolicyWithRelatedData, useHistoryBlock } from './hooks'; import { getNewSecrets } from './utils'; @@ -71,7 +73,6 @@ export const EditPackagePolicyPage = memo(() => { } = useRouteMatch<{ policyId: string; packagePolicyId: string }>(); const packagePolicy = useGetOnePackagePolicy(packagePolicyId); - const extensionView = useUIExtension( packagePolicy.data?.item?.package?.name ?? '', 'package-policy-edit' @@ -102,6 +103,7 @@ export const EditPackagePolicyForm = memo<{ } = useConfig(); const { getHref } = useLink(); const { canUseMultipleAgentPolicies } = useMultipleAgentPolicies(); + const { isAgentlessAgentPolicy } = useAgentless(); const { // data agentPolicies: existingAgentPolicies, @@ -125,8 +127,12 @@ export const EditPackagePolicyForm = memo<{ forceUpgrade, }); - const hasAgentlessAgentPolicy = existingAgentPolicies.some( - (policy) => policy.id === policyId && policy.supports_agentless === true + const hasAgentlessAgentPolicy = useMemo( + () => + existingAgentPolicies.length === 1 + ? existingAgentPolicies.some((policy) => isAgentlessAgentPolicy(policy)) + : false, + [existingAgentPolicies, isAgentlessAgentPolicy] ); const canWriteIntegrationPolicies = useAuthz().integrations.writeIntegrationPolicies; diff --git a/x-pack/test/cloud_security_posture_functional/agentless/create_agent.ts b/x-pack/test/cloud_security_posture_functional/agentless/create_agent.ts index 1b1497140875e..bee89c26a1c69 100644 --- a/x-pack/test/cloud_security_posture_functional/agentless/create_agent.ts +++ b/x-pack/test/cloud_security_posture_functional/agentless/create_agent.ts @@ -73,6 +73,63 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { ); }); + it(`should show setup technology selector in edit mode`, async () => { + const integrationPolicyName = `cloud_security_posture-${new Date().toISOString()}`; + await cisIntegration.navigateToAddIntegrationCspmWithVersionPage( + CLOUD_CREDENTIALS_PACKAGE_VERSION + ); + + await cisIntegration.clickOptionButton(CIS_AWS_OPTION_TEST_ID); + await cisIntegration.clickOptionButton(AWS_SINGLE_ACCOUNT_TEST_ID); + + await cisIntegration.inputIntegrationName(integrationPolicyName); + + await cisIntegration.selectSetupTechnology('agentless'); + await cisIntegration.selectAwsCredentials('direct'); + + await pageObjects.header.waitUntilLoadingHasFinished(); + + await cisIntegration.clickSaveButton(); + await pageObjects.header.waitUntilLoadingHasFinished(); + + expect(await cisIntegrationAws.showPostInstallCloudFormationModal()).to.be(false); + + await cisIntegration.navigateToIntegrationCspList(); + await pageObjects.header.waitUntilLoadingHasFinished(); + + await cisIntegration.navigateToEditIntegrationPage(); + await pageObjects.header.waitUntilLoadingHasFinished(); + + expect(await cisIntegration.showSetupTechnologyComponent()).to.be(true); + }); + + it(`should hide setup technology selector in edit mode`, async () => { + const integrationPolicyName = `cloud_security_posture-${new Date().toISOString()}`; + await cisIntegration.navigateToAddIntegrationCspmWithVersionPage( + CLOUD_CREDENTIALS_PACKAGE_VERSION + ); + + await cisIntegration.clickOptionButton(CIS_AWS_OPTION_TEST_ID); + await cisIntegration.clickOptionButton(AWS_SINGLE_ACCOUNT_TEST_ID); + + await cisIntegration.inputIntegrationName(integrationPolicyName); + await cisIntegration.selectSetupTechnology('agent-based'); + await cisIntegration.selectAwsCredentials('direct'); + await pageObjects.header.waitUntilLoadingHasFinished(); + + await cisIntegration.clickSaveButton(); + await pageObjects.header.waitUntilLoadingHasFinished(); + + expect(await cisIntegrationAws.showPostInstallCloudFormationModal()).to.be(false); + + await cisIntegration.navigateToIntegrationCspList(); + await pageObjects.header.waitUntilLoadingHasFinished(); + await cisIntegration.navigateToEditIntegrationPage(); + await pageObjects.header.waitUntilLoadingHasFinished(); + + expect(await cisIntegration.showSetupTechnologyComponent()).to.be(false); + }); + it(`should create default agent-based agent`, async () => { const integrationPolicyName = `cloud_security_posture-${new Date().toISOString()}`; diff --git a/x-pack/test/cloud_security_posture_functional/page_objects/add_cis_integration_form_page.ts b/x-pack/test/cloud_security_posture_functional/page_objects/add_cis_integration_form_page.ts index 8732f0ba5b012..e3ef420055196 100644 --- a/x-pack/test/cloud_security_posture_functional/page_objects/add_cis_integration_form_page.ts +++ b/x-pack/test/cloud_security_posture_functional/page_objects/add_cis_integration_form_page.ts @@ -285,6 +285,11 @@ export function AddCisIntegrationFormPageProvider({ ); await agentOption.click(); }; + + const showSetupTechnologyComponent = async () => { + return await testSubjects.exists(SETUP_TECHNOLOGY_SELECTOR_ACCORDION_TEST_SUBJ); + }; + const selectAwsCredentials = async (credentialType: 'direct' | 'temporary') => { await clickOptionButton(AWS_CREDENTIAL_SELECTOR); await selectValue( @@ -544,5 +549,7 @@ export function AddCisIntegrationFormPageProvider({ getFirstCspmIntegrationPageAgent, getAgentBasedPolicyValue, showSuccessfulToast, + showSetupTechnologyComponent, + navigateToEditIntegrationPage, }; } diff --git a/x-pack/test/fleet_api_integration/apis/agent_policy/agent_policy.ts b/x-pack/test/fleet_api_integration/apis/agent_policy/agent_policy.ts index ce231db7ce40a..f3f929aefcc45 100644 --- a/x-pack/test/fleet_api_integration/apis/agent_policy/agent_policy.ts +++ b/x-pack/test/fleet_api_integration/apis/agent_policy/agent_policy.ts @@ -1486,25 +1486,13 @@ export default function (providerContext: FtrProviderContext) { support_agentless: true, }) .expect(200); - const { - body: { item: agentlessPolicy }, - } = await supertest - .put(`/api/fleet/agent_policies/${createdPolicy.id}`) - .set('kbn-xsrf', 'xxxx') - .send({ - name: 'Agentless policy', - namespace: 'default', - support_agentless: true, - }) - .expect(200); - const { body } = await supertest .post('/api/fleet/agent_policies/delete') .set('kbn-xsrf', 'xxx') - .send({ agentPolicyId: agentlessPolicy.id }); + .send({ agentPolicyId: createdPolicy.id }); expect(body).to.eql({ - id: agentlessPolicy.id, + id: createdPolicy.id, name: 'Agentless policy', }); }); diff --git a/x-pack/test_serverless/functional/test_suites/security/ftr/cloud_security_posture/agentless/cis_integration_gcp.ts b/x-pack/test_serverless/functional/test_suites/security/ftr/cloud_security_posture/agentless/cis_integration_gcp.ts index fbad2e13cb8d3..85a45f67bf9cc 100644 --- a/x-pack/test_serverless/functional/test_suites/security/ftr/cloud_security_posture/agentless/cis_integration_gcp.ts +++ b/x-pack/test_serverless/functional/test_suites/security/ftr/cloud_security_posture/agentless/cis_integration_gcp.ts @@ -100,7 +100,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { }); }); - describe('Serverless - Agentless CIS_GCP edit flow', () => { + describe.skip('Serverless - Agentless CIS_GCP edit flow', () => { it(`user should save and edit agentless integration policy`, async () => { const newCredentialsJSON = 'newJson'; await cisIntegration.createAgentlessIntegration({ From 6a1f96801bcdf6c9a328b6d7aa41f81c8b96fd0b Mon Sep 17 00:00:00 2001 From: Lola Date: Mon, 23 Sep 2024 14:03:41 -0400 Subject: [PATCH 38/44] address pr change and fix tests --- .../agent_policy/components/actions_menu.tsx | 7 +- .../agent_policy_advanced_fields/index.tsx | 36 ++------ .../agent_policy_delete_provider.tsx | 8 +- .../package_policy_delete_provider.tsx | 4 +- .../server/services/agents/agentless_agent.ts | 92 +++++++------------ .../fleet/server/services/utils/agentless.ts | 12 +++ .../agentless/create_agent.ts | 5 +- .../apis/agent_policy/agent_policy.ts | 6 +- 8 files changed, 70 insertions(+), 100 deletions(-) diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/actions_menu.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/actions_menu.tsx index 007220611f079..bfb364abf8a5d 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/actions_menu.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/actions_menu.tsx @@ -186,12 +186,13 @@ export const AgentPolicyActionMenu = memo<{ const agentlessMenuItems = [viewPolicyItem, deletePolicyItem]; let menuItems; + if (agentPolicy?.is_managed) { menuItems = managedMenuItems; - } else if (!agentPolicy?.supports_agentless) { - menuItems = agentBasedMenuItems; - } else { + } else if (agentPolicy?.supports_agentless) { menuItems = agentlessMenuItems; + } else { + menuItems = agentBasedMenuItems; } if ( diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_advanced_fields/index.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_advanced_fields/index.tsx index 49bdab975a4d4..4f02e2c6b5eeb 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_advanced_fields/index.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_advanced_fields/index.tsx @@ -120,6 +120,8 @@ export const AgentPolicyAdvancedOptionsContent: React.FunctionComponent = const licenseService = useLicense(); const [isUninstallCommandFlyoutOpen, setIsUninstallCommandFlyoutOpen] = useState(false); const policyHasElasticDefend = useMemo(() => hasElasticDefend(agentPolicy), [agentPolicy]); + const isManagedorAgentlessPolicy = + agentPolicy.is_managed === true || agentPolicy.supports_agentless === true; const AgentTamperProtectionSectionContent = useMemo( () => ( @@ -408,9 +410,7 @@ export const AgentPolicyAdvancedOptionsContent: React.FunctionComponent = } > = > { @@ -580,11 +576,7 @@ export const AgentPolicyAdvancedOptionsContent: React.FunctionComponent = isInvalid={Boolean(touchedFields.fleet_server_host_id && validation.fleet_server_host_id)} > = isDisabled={disabled} > = isDisabled={disabled} > = > { diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_delete_provider.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_delete_provider.tsx index 69dafa40a43e0..32c350108bccf 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_delete_provider.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_delete_provider.tsx @@ -58,15 +58,15 @@ export const AgentPolicyDeleteProvider: React.FunctionComponent = ({ const { canUseMultipleAgentPolicies } = useMultipleAgentPolicies(); const deleteAgentPolicyPrompt: DeleteAgentPolicy = ( - agentPolicyToDelete, + agentPolicyIdToDelete, onSuccess = () => undefined ) => { - if (!agentPolicyToDelete) { + if (!agentPolicyIdToDelete) { throw new Error('No agent policy specified for deletion'); } setIsModalOpen(true); - setAgentPolicyId(agentPolicyToDelete); - fetchAgentsCount(agentPolicyToDelete); + setAgentPolicyId(agentPolicyIdToDelete); + fetchAgentsCount(agentPolicyIdToDelete); onSuccessCallback.current = onSuccess; }; diff --git a/x-pack/plugins/fleet/public/components/package_policy_delete_provider.tsx b/x-pack/plugins/fleet/public/components/package_policy_delete_provider.tsx index cf72732ace3e4..011568d624221 100644 --- a/x-pack/plugins/fleet/public/components/package_policy_delete_provider.tsx +++ b/x-pack/plugins/fleet/public/components/package_policy_delete_provider.tsx @@ -132,7 +132,9 @@ export const PackagePolicyDeleteProvider: React.FunctionComponent = ({ values: { id: successfulResults[0].name || successfulResults[0].id }, }); - const agentlessPolicy = agentPolicies?.find((policy) => policy.supports_agentless); + const agentlessPolicy = agentPolicies?.find( + (policy) => policy.supports_agentless === true + ); if (!!agentlessPolicy) { try { diff --git a/x-pack/plugins/fleet/server/services/agents/agentless_agent.ts b/x-pack/plugins/fleet/server/services/agents/agentless_agent.ts index 9e4135045ec67..c2a4442a87ded 100644 --- a/x-pack/plugins/fleet/server/services/agents/agentless_agent.ts +++ b/x-pack/plugins/fleet/server/services/agents/agentless_agent.ts @@ -22,6 +22,7 @@ import { appContextService } from '../app_context'; import { listEnrollmentApiKeys } from '../api_keys'; import { listFleetServerHosts } from '../fleet_server_host'; +import type { AgentlessConfig } from '../utils/agentless'; import { prependAgentlessApiBasePathToEndpoint, isAgentlessApiEnabled, @@ -68,14 +69,7 @@ class AgentlessAgentService { logger.debug(`[Agentless API] Creating agentless agent with TLS config with certificate: ${agentlessConfig.api.tls.certificate}, and key: ${agentlessConfig.api.tls.key}`); - const tlsConfig = new SslConfig( - sslSchema.validate({ - enabled: true, - certificate: agentlessConfig.api.tls.certificate, - key: agentlessConfig.api.tls.key, - certificateAuthorities: agentlessConfig.api.tls.ca, - }) - ); + const tlsConfig = this.createTlsConfig(agentlessConfig); const requestConfig: AxiosRequestConfig = { url: prependAgentlessApiBasePathToEndpoint(agentlessConfig, '/deployments'), @@ -96,24 +90,13 @@ class AgentlessAgentService { }), }; + const requestConfigDebug = this.createRequestConfigDebug(requestConfig); + const cloudSetup = appContextService.getCloud(); if (!cloudSetup?.isServerlessEnabled) { requestConfig.data.stack_version = appContextService.getKibanaVersion(); } - const requestConfigDebug = JSON.stringify({ - ...requestConfig, - httpsAgent: { - ...requestConfig.httpsAgent, - options: { - ...requestConfig.httpsAgent.options, - cert: requestConfig.httpsAgent.options.cert ? 'REDACTED' : undefined, - key: requestConfig.httpsAgent.options.key ? 'REDACTED' : undefined, - ca: requestConfig.httpsAgent.options.ca ? 'REDACTED' : undefined, - }, - }, - }); - logger.debug( `[Agentless API] Creating agentless agent with request config ${requestConfigDebug}` ); @@ -170,15 +153,7 @@ class AgentlessAgentService { public async deleteAgentlessAgent(agentlessPolicyId: string) { const logger = appContextService.getLogger(); const agentlessConfig = appContextService.getConfig()?.agentless; - const tlsConfig = new SslConfig( - sslSchema.validate({ - enabled: true, - certificate: agentlessConfig?.api?.tls?.certificate, - key: agentlessConfig?.api?.tls?.key, - certificateAuthorities: agentlessConfig?.api?.tls?.ca, - }) - ); - + const tlsConfig = this.createTlsConfig(agentlessConfig); const requestConfig = { url: getDeletionEndpointPath(agentlessConfig, `/deployments/${agentlessPolicyId}`), method: 'DELETE', @@ -193,19 +168,7 @@ class AgentlessAgentService { }), }; - const requestConfigDebug = JSON.stringify({ - url: getDeletionEndpointPath(agentlessConfig, `/deployments/${agentlessPolicyId}`), - method: 'DELETE', - headers: { - 'Content-type': 'application/json', - }, - httpsAgent: new https.Agent({ - rejectUnauthorized: tlsConfig.rejectUnauthorized, - cert: tlsConfig.certificate, - key: tlsConfig.key, - ca: tlsConfig.certificateAuthorities, - }), - }); + const requestConfigDebug = this.createRequestConfigDebug(requestConfig); logger.debug( `[Agentless API] Start deleting agentless agent for agent policy ${requestConfigDebug}` @@ -224,18 +187,7 @@ class AgentlessAgentService { logger.debug(`[Agentless API] Deleting agentless agent with TLS config with certificate`); logger.debug( - `[Agentless API] Deleting agentless deployment with request config ${JSON.stringify({ - ...requestConfig, - httpsAgent: { - ...requestConfig.httpsAgent, - options: { - ...requestConfig.httpsAgent.options, - cert: requestConfig.httpsAgent.options.cert ? 'REDACTED' : undefined, - key: requestConfig.httpsAgent.options.key ? 'REDACTED' : undefined, - ca: requestConfig.httpsAgent.options.ca ? 'REDACTED' : undefined, - }, - }, - })}` + `[Agentless API] Deleting agentless deployment with request config ${requestConfigDebug}` ); const response = await axios(requestConfig).catch((error: AxiosError) => { @@ -262,9 +214,7 @@ class AgentlessAgentService { ); } else { logger.error( - `[Agentless API] Deleting agentless deployment failed to delete the request ${errorLogCodeCause} ${JSON.stringify( - requestConfigDebug - )}` + `[Agentless API] Deleting agentless deployment failed to delete the request ${errorLogCodeCause} ${requestConfigDebug}` ); } }); @@ -272,6 +222,32 @@ class AgentlessAgentService { return response; } + private createTlsConfig(agentlessConfig: AgentlessConfig | undefined) { + return new SslConfig( + sslSchema.validate({ + enabled: true, + certificate: agentlessConfig?.api?.tls?.certificate, + key: agentlessConfig?.api?.tls?.key, + certificateAuthorities: agentlessConfig?.api?.tls?.ca, + }) + ); + } + + private createRequestConfigDebug(requestConfig: AxiosRequestConfig) { + return JSON.stringify({ + ...requestConfig, + httpsAgent: { + ...requestConfig.httpsAgent, + options: { + ...requestConfig.httpsAgent.options, + cert: requestConfig.httpsAgent.options.cert ? 'REDACTED' : undefined, + key: requestConfig.httpsAgent.options.key ? 'REDACTED' : undefined, + ca: requestConfig.httpsAgent.options.ca ? 'REDACTED' : undefined, + }, + }, + }); + } + private convertCauseErrorsToString = (error: AxiosError) => { if (error.cause instanceof AggregateError) { return error.cause.errors.map((e: Error) => e.message); diff --git a/x-pack/plugins/fleet/server/services/utils/agentless.ts b/x-pack/plugins/fleet/server/services/utils/agentless.ts index 4828bcff3ebb6..52522265cc22a 100644 --- a/x-pack/plugins/fleet/server/services/utils/agentless.ts +++ b/x-pack/plugins/fleet/server/services/utils/agentless.ts @@ -28,6 +28,18 @@ const AGENTLESS_SERVERLESS_API_BASE_PATH = '/api/v1/serverless'; type AgentlessApiEndpoints = '/deployments' | `/deployments/${string}`; +export interface AgentlessConfig { + enabled: boolean; + api: { + url: string; + tls: { + certificate: string; + key: string; + ca: string; + }; + }; +} + export const prependAgentlessApiBasePathToEndpoint = ( agentlessConfig: FleetConfigType['agentless'], endpoint: AgentlessApiEndpoints diff --git a/x-pack/test/cloud_security_posture_functional/agentless/create_agent.ts b/x-pack/test/cloud_security_posture_functional/agentless/create_agent.ts index bee89c26a1c69..2065d1307fbda 100644 --- a/x-pack/test/cloud_security_posture_functional/agentless/create_agent.ts +++ b/x-pack/test/cloud_security_posture_functional/agentless/create_agent.ts @@ -104,7 +104,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { }); it(`should hide setup technology selector in edit mode`, async () => { - const integrationPolicyName = `cloud_security_posture-${new Date().toISOString()}`; + const integrationPolicyName = `cloud_security_posture1-${new Date().toISOString()}`; await cisIntegration.navigateToAddIntegrationCspmWithVersionPage( CLOUD_CREDENTIALS_PACKAGE_VERSION ); @@ -114,13 +114,12 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { await cisIntegration.inputIntegrationName(integrationPolicyName); await cisIntegration.selectSetupTechnology('agent-based'); - await cisIntegration.selectAwsCredentials('direct'); await pageObjects.header.waitUntilLoadingHasFinished(); await cisIntegration.clickSaveButton(); await pageObjects.header.waitUntilLoadingHasFinished(); - expect(await cisIntegrationAws.showPostInstallCloudFormationModal()).to.be(false); + expect(await cisIntegrationAws.showPostInstallCloudFormationModal()).to.be(true); await cisIntegration.navigateToIntegrationCspList(); await pageObjects.header.waitUntilLoadingHasFinished(); diff --git a/x-pack/test/fleet_api_integration/apis/agent_policy/agent_policy.ts b/x-pack/test/fleet_api_integration/apis/agent_policy/agent_policy.ts index f3f929aefcc45..15610f98c62bf 100644 --- a/x-pack/test/fleet_api_integration/apis/agent_policy/agent_policy.ts +++ b/x-pack/test/fleet_api_integration/apis/agent_policy/agent_policy.ts @@ -1483,7 +1483,7 @@ export default function (providerContext: FtrProviderContext) { name: 'Agentless policy', namespace: 'default', is_managed: false, - support_agentless: true, + supports_agentless: true, }) .expect(200); const { body } = await supertest @@ -1507,7 +1507,7 @@ export default function (providerContext: FtrProviderContext) { name: 'Agentless policy', namespace: 'default', is_managed: false, - support_agentless: true, + supports_agentless: true, }) .expect(200); const { @@ -1518,7 +1518,7 @@ export default function (providerContext: FtrProviderContext) { .send({ name: 'Agentless policy', namespace: 'default', - support_agentless: true, + supports_agentless: true, }) .expect(200); await generateAgent(providerContext, 'healhty', 'agent-healthy-1', agentlessPolicy.id); From b124f811c2ec2e283f7b3200cd90be2b3af56667 Mon Sep 17 00:00:00 2001 From: Lola Date: Mon, 23 Sep 2024 15:44:45 -0400 Subject: [PATCH 39/44] update delete messaging --- .../agent_policy_advanced_fields/index.tsx | 2 +- .../package_policy_delete_provider.tsx | 48 ++++++++++++++----- .../apis/agent_policy/agent_policy.ts | 6 +-- 3 files changed, 40 insertions(+), 16 deletions(-) diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_advanced_fields/index.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_advanced_fields/index.tsx index 4f02e2c6b5eeb..ad17a340efb34 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_advanced_fields/index.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_advanced_fields/index.tsx @@ -121,7 +121,7 @@ export const AgentPolicyAdvancedOptionsContent: React.FunctionComponent = const [isUninstallCommandFlyoutOpen, setIsUninstallCommandFlyoutOpen] = useState(false); const policyHasElasticDefend = useMemo(() => hasElasticDefend(agentPolicy), [agentPolicy]); const isManagedorAgentlessPolicy = - agentPolicy.is_managed === true || agentPolicy.supports_agentless === true; + agentPolicy.is_managed === true || agentPolicy?.supports_agentless === true; const AgentTamperProtectionSectionContent = useMemo( () => ( diff --git a/x-pack/plugins/fleet/public/components/package_policy_delete_provider.tsx b/x-pack/plugins/fleet/public/components/package_policy_delete_provider.tsx index 011568d624221..42dcdd74c9ae1 100644 --- a/x-pack/plugins/fleet/public/components/package_policy_delete_provider.tsx +++ b/x-pack/plugins/fleet/public/components/package_policy_delete_provider.tsx @@ -184,6 +184,10 @@ export const PackagePolicyDeleteProvider: React.FunctionComponent = ({ ); const renderModal = () => { + const isAgentlessPolicy = agentPolicies?.find((policy) => policy?.supports_agentless === true); + const packagePolicy = agentPolicies?.[0].package_policies?.find( + (policy) => policy.id === packagePolicies[0] + ); if (!isModalOpen) { return null; } @@ -191,11 +195,18 @@ export const PackagePolicyDeleteProvider: React.FunctionComponent = ({ return ( + isAgentlessPolicy ? ( + + ) : ( + + ) } onCancel={closeModal} onConfirm={deletePackagePolicies} @@ -249,14 +260,16 @@ export const PackagePolicyDeleteProvider: React.FunctionComponent = ({ + !isAgentlessPolicy && ( + + ) } > - {hasMultipleAgentPolicies ? ( + {hasMultipleAgentPolicies && !isAgentlessPolicy && ( = ({ ), }} /> - ) : ( + )}{' '} + {!hasMultipleAgentPolicies && !isAgentlessPolicy && ( = ({ }} /> )} + {!hasMultipleAgentPolicies && isAgentlessPolicy && ( + {packagePolicy?.name}, + }} + /> + )} ) : null} + {!isLoadingAgentsCount && ( Date: Tue, 24 Sep 2024 11:43:53 -0400 Subject: [PATCH 40/44] remove flaky test in build --- .../apis/agent_policy/agent_policy.ts | 24 ------------------- 1 file changed, 24 deletions(-) diff --git a/x-pack/test/fleet_api_integration/apis/agent_policy/agent_policy.ts b/x-pack/test/fleet_api_integration/apis/agent_policy/agent_policy.ts index e313c264a896d..10a496cddc42f 100644 --- a/x-pack/test/fleet_api_integration/apis/agent_policy/agent_policy.ts +++ b/x-pack/test/fleet_api_integration/apis/agent_policy/agent_policy.ts @@ -1473,30 +1473,6 @@ export default function (providerContext: FtrProviderContext) { await supertest.get(`/api/fleet/agent_policies/${hostedPolicy.id}`).expect(404); }); - it('should allow agentless policies being deleted', async () => { - const { - body: { item: createdPolicy }, - } = await supertest - .post(`/api/fleet/agent_policies`) - .set('kbn-xsrf', 'xxxx') - .send({ - name: 'Agentless 1 policy', - namespace: 'default', - supports_agentless: true, - force: true, - }) - .expect(200); - const { body } = await supertest - .post('/api/fleet/agent_policies/delete') - .set('kbn-xsrf', 'xxx') - .send({ agentPolicyId: createdPolicy.id }); - - expect(body).to.eql({ - id: createdPolicy.id, - name: 'Agentless 1 policy', - }); - }); - it('should allow agentless policies with agents being deleted', async () => { const { body: { item: createdPolicy }, From 5997b7ac7401909fb6a139095f7e0d03bdca0e45 Mon Sep 17 00:00:00 2001 From: Lola Date: Tue, 24 Sep 2024 12:58:42 -0400 Subject: [PATCH 41/44] remove flaky test --- .../apis/agent_policy/agent_policy.ts | 37 ------------------- 1 file changed, 37 deletions(-) diff --git a/x-pack/test/fleet_api_integration/apis/agent_policy/agent_policy.ts b/x-pack/test/fleet_api_integration/apis/agent_policy/agent_policy.ts index 0425755df5e4a..f601743e394ec 100644 --- a/x-pack/test/fleet_api_integration/apis/agent_policy/agent_policy.ts +++ b/x-pack/test/fleet_api_integration/apis/agent_policy/agent_policy.ts @@ -1612,43 +1612,6 @@ export default function (providerContext: FtrProviderContext) { await supertest.get(`/api/fleet/agent_policies/${hostedPolicy.id}`).expect(404); }); - it('should allow agentless policies with agents being deleted', async () => { - const { - body: { item: createdPolicy }, - } = await supertest - .post(`/api/fleet/agent_policies`) - .set('kbn-xsrf', 'xxxx') - .send({ - name: 'Agentless policy', - namespace: 'default', - is_managed: false, - supports_agentless: true, - }) - .expect(200); - const { - body: { item: agentlessPolicy }, - } = await supertest - .put(`/api/fleet/agent_policies/${createdPolicy.id}`) - .set('kbn-xsrf', 'xxxx') - .send({ - name: 'Agentless policy', - namespace: 'default', - supports_agentless: true, - }) - .expect(200); - await generateAgent(providerContext, 'healhty', 'agent-healthy-1', agentlessPolicy.id); - - const { body } = await supertest - .post('/api/fleet/agent_policies/delete') - .set('kbn-xsrf', 'xxx') - .send({ agentPolicyId: agentlessPolicy.id }); - - expect(body).to.eql({ - id: agentlessPolicy.id, - name: 'Agentless policy', - }); - }); - describe('Errors when trying to delete', () => { it('should prevent policies having agents from being deleted', async () => { const { From 9d6dcc1f8e54b543dba50eee517fc537acd99a1f Mon Sep 17 00:00:00 2001 From: Lola Date: Wed, 25 Sep 2024 12:11:34 -0400 Subject: [PATCH 42/44] fix unit test --- .../public/components/package_policy_actions_menu.test.tsx | 3 +-- .../fleet/public/components/package_policy_delete_provider.tsx | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/x-pack/plugins/fleet/public/components/package_policy_actions_menu.test.tsx b/x-pack/plugins/fleet/public/components/package_policy_actions_menu.test.tsx index 8436f7c5ba3fb..dbf3969ffc226 100644 --- a/x-pack/plugins/fleet/public/components/package_policy_actions_menu.test.tsx +++ b/x-pack/plugins/fleet/public/components/package_policy_actions_menu.test.tsx @@ -219,8 +219,7 @@ describe('PackagePolicyActionsMenu', () => { }); }); - // Todo: Fix test case when orphan policy fails - it.skip('Should show Edit integration with correct href when there is no agent policy', async () => { + it('Should show Edit integration with correct href when there is no agent policy', async () => { const packagePolicy = createMockPackagePolicy({ policy_ids: [], }); diff --git a/x-pack/plugins/fleet/public/components/package_policy_delete_provider.tsx b/x-pack/plugins/fleet/public/components/package_policy_delete_provider.tsx index 42dcdd74c9ae1..7d71915fda252 100644 --- a/x-pack/plugins/fleet/public/components/package_policy_delete_provider.tsx +++ b/x-pack/plugins/fleet/public/components/package_policy_delete_provider.tsx @@ -185,7 +185,7 @@ export const PackagePolicyDeleteProvider: React.FunctionComponent = ({ const renderModal = () => { const isAgentlessPolicy = agentPolicies?.find((policy) => policy?.supports_agentless === true); - const packagePolicy = agentPolicies?.[0].package_policies?.find( + const packagePolicy = agentPolicies?.[0]?.package_policies?.find( (policy) => policy.id === packagePolicies[0] ); if (!isModalOpen) { From bc99b1df5335a13785fb65170855003d5d353369 Mon Sep 17 00:00:00 2001 From: Lola Date: Wed, 25 Sep 2024 17:32:11 -0400 Subject: [PATCH 43/44] remove agentless policies from multi-select for agent-based integrations --- .../steps/components/agent_policy_options.tsx | 58 ++++++++++--------- 1 file changed, 30 insertions(+), 28 deletions(-) diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/components/steps/components/agent_policy_options.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/components/steps/components/agent_policy_options.tsx index c39466d779548..29722bbc42850 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/components/steps/components/agent_policy_options.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/components/steps/components/agent_policy_options.tsx @@ -127,34 +127,36 @@ export function useAgentPoliciesOptions(packageInfo?: PackageInfo) { const agentPolicyMultiOptions: Array> = useMemo( () => packageInfo && !isOutputLoading && !isAgentPoliciesLoading && !isLoadingPackagePolicies - ? agentPolicies.map((policy) => { - const isLimitedPackageAlreadyInPolicy = - isPackageLimited(packageInfo!) && - packagePoliciesForThisPackageByAgentPolicyId?.[policy.id]; - - const isAPMPackageAndDataOutputIsLogstash = - packageInfo?.name === FLEET_APM_PACKAGE && - getDataOutputForPolicy(policy)?.type === outputType.Logstash; - - return { - append: isAPMPackageAndDataOutputIsLogstash ? ( - - } - > - - - ) : null, - key: policy.id, - label: policy.name, - disabled: isLimitedPackageAlreadyInPolicy || isAPMPackageAndDataOutputIsLogstash, - 'data-test-subj': 'agentPolicyMultiItem', - }; - }) + ? agentPolicies + .filter((policy) => policy.supports_agentless !== true) + .map((policy) => { + const isLimitedPackageAlreadyInPolicy = + isPackageLimited(packageInfo!) && + packagePoliciesForThisPackageByAgentPolicyId?.[policy.id]; + + const isAPMPackageAndDataOutputIsLogstash = + packageInfo?.name === FLEET_APM_PACKAGE && + getDataOutputForPolicy(policy)?.type === outputType.Logstash; + + return { + append: isAPMPackageAndDataOutputIsLogstash ? ( + + } + > + + + ) : null, + key: policy.id, + label: policy.name, + disabled: isLimitedPackageAlreadyInPolicy || isAPMPackageAndDataOutputIsLogstash, + 'data-test-subj': 'agentPolicyMultiItem', + }; + }) : [], [ packageInfo, From b2e2a4eed26c8f29208d20eea770f27598b50d49 Mon Sep 17 00:00:00 2001 From: Lola Date: Tue, 1 Oct 2024 12:29:12 -0400 Subject: [PATCH 44/44] fix error messaging --- x-pack/plugins/fleet/server/errors/handlers.ts | 4 ++++ x-pack/plugins/fleet/server/errors/index.ts | 2 +- x-pack/plugins/fleet/server/services/agent_policy.ts | 4 ++-- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/x-pack/plugins/fleet/server/errors/handlers.ts b/x-pack/plugins/fleet/server/errors/handlers.ts index dfd92951c8919..d8971948397d3 100644 --- a/x-pack/plugins/fleet/server/errors/handlers.ts +++ b/x-pack/plugins/fleet/server/errors/handlers.ts @@ -44,6 +44,7 @@ import { FleetNotFoundError, PackageSavedObjectConflictError, FleetTooManyRequestsError, + AgentlessPolicyExistsRequestError, } from '.'; type IngestErrorHandler = ( @@ -111,6 +112,9 @@ const getHTTPResponseCode = (error: FleetError): number => { if (error instanceof PackageAlreadyInstalledError) { return 409; } + if (error instanceof AgentlessPolicyExistsRequestError) { + return 409; + } // Unsupported Media Type if (error instanceof PackageUnsupportedMediaTypeError) { return 415; diff --git a/x-pack/plugins/fleet/server/errors/index.ts b/x-pack/plugins/fleet/server/errors/index.ts index 62ed7eafc608d..09b387e7a5cee 100644 --- a/x-pack/plugins/fleet/server/errors/index.ts +++ b/x-pack/plugins/fleet/server/errors/index.ts @@ -57,7 +57,7 @@ export class AgentlessAgentCreateError extends FleetError { } } -export class AgentlessPackagePolicyRequestError extends FleetError { +export class AgentlessPolicyExistsRequestError extends AgentPolicyError { constructor(message: string) { super(`Unable to create integration. ${message}`); } diff --git a/x-pack/plugins/fleet/server/services/agent_policy.ts b/x-pack/plugins/fleet/server/services/agent_policy.ts index c4aa2bf49e370..64ae8e1bfe296 100644 --- a/x-pack/plugins/fleet/server/services/agent_policy.ts +++ b/x-pack/plugins/fleet/server/services/agent_policy.ts @@ -84,7 +84,7 @@ import { FleetUnauthorizedError, HostedAgentPolicyRestrictionRelatedError, PackagePolicyRestrictionRelatedError, - AgentlessPackagePolicyRequestError, + AgentlessPolicyExistsRequestError, } from '../errors'; import type { FullAgentConfigMap } from '../../common/types/models/agent_cm'; @@ -440,7 +440,7 @@ class AgentPolicyService { if (givenPolicy?.supports_agentless && !givenPolicy.id) { const integrationName = givenPolicy.name.split(' ').pop(); - throw new AgentlessPackagePolicyRequestError( + throw new AgentlessPolicyExistsRequestError( `${givenPolicy.name} already exist. Please rename the integration name ${integrationName}.` ); }