Skip to content

Commit

Permalink
[Fleet] When deleting an agent policy, only delete integration polici…
Browse files Browse the repository at this point in the history
…es if no other agent policies use it (#186601)

Closes #182222

## Summary
- If `enableReusableIntegrationPolicies` is enabled, the
`agentPolicyService.delete` method finds the integration policies that
are shared with other agent policies and doesn't delete them.
-  Updated the UI so that the modal shows an info box to the user:

![Screenshot 2024-06-24 at 10 20
53](https://github.com/elastic/kibana/assets/16084106/6db8f225-bfc7-47cf-a49c-adc0e0b794ac)


### Checklist

- [ ] Any text added follows [EUI's writing
guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses
sentence case text and includes [i18n
support](https://github.com/elastic/kibana/blob/main/packages/kbn-i18n/README.md)
- [ ]
[Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html)
was added for features that require explanation or tutorials
- [ ] [Unit or functional
tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)
were updated or added to match the most common scenarios

---------

Co-authored-by: Kibana Machine <[email protected]>
  • Loading branch information
criamico and kibanamachine authored Jun 24, 2024
1 parent 5d6b0f8 commit 8bd7124
Show file tree
Hide file tree
Showing 4 changed files with 294 additions and 89 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@ export const AgentPolicyActionMenu = memo<{
<AgentPolicyDeleteProvider
hasFleetServer={policyHasFleetServer(agentPolicy as AgentPolicy)}
key="deletePolicy"
packagePolicies={agentPolicy.package_policies}
>
{(deleteAgentPolicyPrompt) => (
<EuiContextMenuItem
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,15 @@
* 2.0.
*/

import React, { Fragment, useRef, useState } from 'react';
import { EuiConfirmModal, EuiCallOut } from '@elastic/eui';
import React, { Fragment, useCallback, useMemo, useRef, useState } from 'react';
import { EuiConfirmModal, EuiCallOut, EuiSpacer } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n-react';

import { useHistory } from 'react-router-dom';

import { SO_SEARCH_LIMIT } from '../../../../../constants';
import { ExperimentalFeaturesService } from '../../../services';

import {
useStartServices,
Expand All @@ -22,9 +23,12 @@ import {
sendGetAgents,
} from '../../../hooks';

import type { PackagePolicy } from '../../../types';

interface Props {
children: (deleteAgentPolicy: DeleteAgentPolicy) => React.ReactElement;
hasFleetServer: boolean;
packagePolicies?: PackagePolicy[];
}

export type DeleteAgentPolicy = (agentPolicy: string, onSuccess?: OnSuccessCallback) => void;
Expand All @@ -34,6 +38,7 @@ type OnSuccessCallback = (agentPolicyDeleted: string) => void;
export const AgentPolicyDeleteProvider: React.FunctionComponent<Props> = ({
children,
hasFleetServer,
packagePolicies,
}) => {
const { notifications } = useStartServices();
const {
Expand All @@ -48,6 +53,7 @@ export const AgentPolicyDeleteProvider: React.FunctionComponent<Props> = ({
const { getPath } = useLink();
const history = useHistory();
const deleteAgentPolicyMutation = useDeleteAgentPolicyMutation();
const { enableReusableIntegrationPolicies } = ExperimentalFeaturesService.get();

const deleteAgentPolicyPrompt: DeleteAgentPolicy = (
agentPolicyToDelete,
Expand Down Expand Up @@ -106,20 +112,31 @@ export const AgentPolicyDeleteProvider: React.FunctionComponent<Props> = ({
history.push(getPath('policies_list'));
};

const fetchAgentsCount = async (agentPolicyToCheck: string) => {
if (!isFleetEnabled || isLoadingAgentsCount) {
return;
const fetchAgentsCount = useCallback(
async (agentPolicyToCheck: string) => {
if (!isFleetEnabled || isLoadingAgentsCount) {
return;
}
setIsLoadingAgentsCount(true);
// filtering out the unenrolled agents assigned to this policy
const agents = await sendGetAgents({
showInactive: true,
kuery: `policy_id:"${agentPolicyToCheck}" and not status: unenrolled`,
perPage: SO_SEARCH_LIMIT,
});
setAgentsCount(agents.data?.total ?? 0);
setIsLoadingAgentsCount(false);
},
[isFleetEnabled, isLoadingAgentsCount]
);

const packagePoliciesWithMultiplePolicies = useMemo(() => {
// Find if there are package policies that have multiple agent policies
if (packagePolicies && enableReusableIntegrationPolicies) {
return packagePolicies.some((policy) => policy?.policy_ids.length > 1);
}
setIsLoadingAgentsCount(true);
// filtering out the unenrolled agents assigned to this policy
const agents = await sendGetAgents({
showInactive: true,
kuery: `policy_id:"${agentPolicyToCheck}" and not status: unenrolled`,
perPage: SO_SEARCH_LIMIT,
});
setAgentsCount(agents.data?.total ?? 0);
setIsLoadingAgentsCount(false);
};
return false;
}, [enableReusableIntegrationPolicies, packagePolicies]);

const renderModal = () => {
if (!isModalOpen) {
Expand Down Expand Up @@ -158,6 +175,21 @@ export const AgentPolicyDeleteProvider: React.FunctionComponent<Props> = ({
buttonColor="danger"
confirmButtonDisabled={isLoading || isLoadingAgentsCount || !!agentsCount}
>
{packagePoliciesWithMultiplePolicies && (
<>
<EuiCallOut
color="primary"
iconType="iInCircle"
title={
<FormattedMessage
id="xpack.fleet.deleteAgentPolicy.confirmModal.warningSharedIntegrationPolicies"
defaultMessage="Fleet has detected that this policy contains integration policies shared by multiple agent policies. These integration policies won't be deleted."
/>
}
/>
<EuiSpacer size="m" />
</>
)}
{isLoadingAgentsCount ? (
<FormattedMessage
id="xpack.fleet.deleteAgentPolicy.confirmModal.loadingAgentsCountMessage"
Expand Down
Loading

0 comments on commit 8bd7124

Please sign in to comment.