mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 01:13:23 -04:00
[Fleet] Do not break UI and API on orphaned package policies (#137107)
This commit is contained in:
parent
becaec81e1
commit
616f7be237
6 changed files with 65 additions and 24 deletions
|
@ -15,6 +15,7 @@ import {
|
|||
EuiFlexItem,
|
||||
EuiText,
|
||||
EuiButton,
|
||||
EuiIcon,
|
||||
} from '@elastic/eui';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { FormattedRelative, FormattedMessage } from '@kbn/i18n-react';
|
||||
|
@ -47,7 +48,7 @@ interface PackagePoliciesPanelProps {
|
|||
|
||||
interface InMemoryPackagePolicyAndAgentPolicy {
|
||||
packagePolicy: InMemoryPackagePolicy;
|
||||
agentPolicy: GetAgentPoliciesResponseItem;
|
||||
agentPolicy?: GetAgentPoliciesResponseItem;
|
||||
}
|
||||
|
||||
const IntegrationDetailsLink = memo<{
|
||||
|
@ -68,6 +69,17 @@ const IntegrationDetailsLink = memo<{
|
|||
);
|
||||
});
|
||||
|
||||
const AgentPolicyNotFound = () => (
|
||||
<EuiText color="subdued" size="xs" className="eui-textNoWrap">
|
||||
<EuiIcon size="m" type="alert" color="warning" />
|
||||
|
||||
<FormattedMessage
|
||||
id="xpack.fleet.epm.packageDetails.integrationList.agentPolicyDeletedWarning"
|
||||
defaultMessage="Policy not found"
|
||||
/>
|
||||
</EuiText>
|
||||
);
|
||||
|
||||
export const PackagePoliciesPage = ({ name, version }: PackagePoliciesPanelProps) => {
|
||||
const { search } = useLocation();
|
||||
const history = useHistory();
|
||||
|
@ -101,7 +113,7 @@ export const PackagePoliciesPage = ({ name, version }: PackagePoliciesPanelProps
|
|||
const canWriteIntegrationPolicies = useAuthz().integrations.writeIntegrationPolicies;
|
||||
|
||||
const packageAndAgentPolicies = useMemo((): Array<{
|
||||
agentPolicy: GetAgentPoliciesResponseItem;
|
||||
agentPolicy?: GetAgentPoliciesResponseItem;
|
||||
packagePolicy: InMemoryPackagePolicy;
|
||||
}> => {
|
||||
if (!data?.items) {
|
||||
|
@ -131,7 +143,7 @@ export const PackagePoliciesPage = ({ name, version }: PackagePoliciesPanelProps
|
|||
}, [data?.items, updatableIntegrations]);
|
||||
|
||||
const showAddAgentHelpForPackagePolicyId = packageAndAgentPolicies.find(
|
||||
({ agentPolicy }) => agentPolicy.id === showAddAgentHelpForPolicyId
|
||||
({ agentPolicy }) => agentPolicy?.id === showAddAgentHelpForPolicyId
|
||||
)?.packagePolicy?.id;
|
||||
// Handle the "add agent" link displayed in post-installation toast notifications in the case
|
||||
// where a user is clicking the link while on the package policies listing page
|
||||
|
@ -187,7 +199,7 @@ export const PackagePoliciesPage = ({ name, version }: PackagePoliciesPanelProps
|
|||
</EuiText>
|
||||
</EuiFlexItem>
|
||||
|
||||
{packagePolicy.hasUpgrade && (
|
||||
{agentPolicy && packagePolicy.hasUpgrade && (
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiButton
|
||||
size="s"
|
||||
|
@ -217,7 +229,11 @@ export const PackagePoliciesPage = ({ name, version }: PackagePoliciesPanelProps
|
|||
}),
|
||||
truncateText: true,
|
||||
render(id, { agentPolicy }) {
|
||||
return <AgentPolicySummaryLine policy={agentPolicy} />;
|
||||
return agentPolicy ? (
|
||||
<AgentPolicySummaryLine policy={agentPolicy} />
|
||||
) : (
|
||||
<AgentPolicyNotFound />
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@ -250,6 +266,9 @@ export const PackagePoliciesPage = ({ name, version }: PackagePoliciesPanelProps
|
|||
defaultMessage: 'Agents',
|
||||
}),
|
||||
render({ agentPolicy, packagePolicy }: InMemoryPackagePolicyAndAgentPolicy) {
|
||||
if (!agentPolicy) {
|
||||
return null;
|
||||
}
|
||||
return (
|
||||
<PackagePolicyAgentsCell
|
||||
agentPolicy={agentPolicy}
|
||||
|
@ -273,10 +292,14 @@ export const PackagePoliciesPage = ({ name, version }: PackagePoliciesPanelProps
|
|||
agentPolicy={agentPolicy}
|
||||
packagePolicy={packagePolicy}
|
||||
showAddAgent={true}
|
||||
upgradePackagePolicyHref={`${getHref('upgrade_package_policy', {
|
||||
policyId: agentPolicy.id,
|
||||
packagePolicyId: packagePolicy.id,
|
||||
})}?from=integrations-policy-list`}
|
||||
upgradePackagePolicyHref={
|
||||
agentPolicy
|
||||
? `${getHref('upgrade_package_policy', {
|
||||
policyId: agentPolicy.id,
|
||||
packagePolicyId: packagePolicy.id,
|
||||
})}?from=integrations-policy-list`
|
||||
: undefined
|
||||
}
|
||||
/>
|
||||
);
|
||||
},
|
||||
|
@ -311,7 +334,7 @@ export const PackagePoliciesPage = ({ name, version }: PackagePoliciesPanelProps
|
|||
);
|
||||
}
|
||||
const selectedPolicies = packageAndAgentPolicies.find(
|
||||
({ agentPolicy: policy }) => policy.id === flyoutOpenForPolicyId
|
||||
({ agentPolicy: policy }) => policy?.id === flyoutOpenForPolicyId
|
||||
);
|
||||
const agentPolicy = selectedPolicies?.agentPolicy;
|
||||
const packagePolicy = selectedPolicies?.packagePolicy;
|
||||
|
|
|
@ -32,7 +32,7 @@ function renderMenu({
|
|||
agentPolicy={agentPolicy}
|
||||
packagePolicy={packagePolicy}
|
||||
showAddAgent={showAddAgent}
|
||||
upgradePackagePolicyHref=""
|
||||
upgradePackagePolicyHref="/test/upgrade-link"
|
||||
defaultIsOpen={defaultIsOpen}
|
||||
key="test1"
|
||||
/>
|
||||
|
@ -95,8 +95,9 @@ test('Should enable upgrade button if package has upgrade', async () => {
|
|||
const agentPolicy = createMockAgentPolicy();
|
||||
const packagePolicy = createMockPackagePolicy({ hasUpgrade: true });
|
||||
const { utils } = renderMenu({ agentPolicy, packagePolicy });
|
||||
|
||||
await act(async () => {
|
||||
const upgradeButton = utils.getByText('Upgrade integration policy').closest('button');
|
||||
const upgradeButton = utils.getByTestId('PackagePolicyActionsUpgradeItem');
|
||||
expect(upgradeButton).not.toBeDisabled();
|
||||
});
|
||||
});
|
||||
|
|
|
@ -19,11 +19,11 @@ import { DangerEuiContextMenuItem } from './danger_eui_context_menu_item';
|
|||
import { PackagePolicyDeleteProvider } from './package_policy_delete_provider';
|
||||
|
||||
export const PackagePolicyActionsMenu: React.FunctionComponent<{
|
||||
agentPolicy: AgentPolicy;
|
||||
agentPolicy?: AgentPolicy;
|
||||
packagePolicy: InMemoryPackagePolicy;
|
||||
showAddAgent?: boolean;
|
||||
defaultIsOpen?: boolean;
|
||||
upgradePackagePolicyHref: string;
|
||||
upgradePackagePolicyHref?: string;
|
||||
}> = ({
|
||||
agentPolicy,
|
||||
packagePolicy,
|
||||
|
@ -38,6 +38,9 @@ export const PackagePolicyActionsMenu: React.FunctionComponent<{
|
|||
const [isActionsMenuOpen, setIsActionsMenuOpen] = useState(defaultIsOpen);
|
||||
|
||||
const isManaged = Boolean(packagePolicy.is_managed);
|
||||
const agentPolicyIsManaged = Boolean(agentPolicy?.is_managed);
|
||||
|
||||
const isAddAgentVisible = showAddAgent && agentPolicy && !agentPolicyIsManaged;
|
||||
|
||||
const onEnrollmentFlyoutClose = useMemo(() => {
|
||||
return () => setIsEnrollmentFlyoutOpen(false);
|
||||
|
@ -55,7 +58,7 @@ export const PackagePolicyActionsMenu: React.FunctionComponent<{
|
|||
// defaultMessage="View integration"
|
||||
// />
|
||||
// </EuiContextMenuItem>,
|
||||
...(showAddAgent && !agentPolicy.is_managed
|
||||
...(isAddAgentVisible
|
||||
? [
|
||||
<EuiContextMenuItem
|
||||
data-test-subj="PackagePolicyActionsAddAgentItem"
|
||||
|
@ -75,7 +78,7 @@ export const PackagePolicyActionsMenu: React.FunctionComponent<{
|
|||
: []),
|
||||
<EuiContextMenuItem
|
||||
data-test-subj="PackagePolicyActionsEditItem"
|
||||
disabled={!canWriteIntegrationPolicies}
|
||||
disabled={!canWriteIntegrationPolicies || !agentPolicy}
|
||||
icon="pencil"
|
||||
href={getHref('integration_policy_edit', {
|
||||
packagePolicyId: packagePolicy.id,
|
||||
|
@ -89,7 +92,9 @@ export const PackagePolicyActionsMenu: React.FunctionComponent<{
|
|||
</EuiContextMenuItem>,
|
||||
<EuiContextMenuItem
|
||||
data-test-subj="PackagePolicyActionsUpgradeItem"
|
||||
disabled={!packagePolicy.hasUpgrade || !canWriteIntegrationPolicies}
|
||||
disabled={
|
||||
!packagePolicy.hasUpgrade || !canWriteIntegrationPolicies || !upgradePackagePolicyHref
|
||||
}
|
||||
icon="refresh"
|
||||
href={upgradePackagePolicyHref}
|
||||
key="packagePolicyUpgrade"
|
||||
|
@ -108,7 +113,7 @@ export const PackagePolicyActionsMenu: React.FunctionComponent<{
|
|||
// </EuiContextMenuItem>,
|
||||
];
|
||||
|
||||
if (!agentPolicy.is_managed) {
|
||||
if (!agentPolicy || !agentPolicyIsManaged) {
|
||||
menuItems.push(
|
||||
<PackagePolicyDeleteProvider agentPolicy={agentPolicy} key="packagePolicyDelete">
|
||||
{(deletePackagePoliciesPrompt) => {
|
||||
|
|
|
@ -15,7 +15,7 @@ import { AGENT_API_ROUTES, AGENTS_PREFIX } from '../../common/constants';
|
|||
import type { AgentPolicy } from '../types';
|
||||
|
||||
interface Props {
|
||||
agentPolicy: AgentPolicy;
|
||||
agentPolicy?: AgentPolicy;
|
||||
children: (deletePackagePoliciesPrompt: DeletePackagePoliciesPrompt) => React.ReactElement;
|
||||
}
|
||||
|
||||
|
@ -43,7 +43,7 @@ export const PackagePolicyDeleteProvider: React.FunctionComponent<Props> = ({
|
|||
|
||||
const fetchAgentsCount = useMemo(
|
||||
() => async () => {
|
||||
if (isLoadingAgentsCount || !isFleetEnabled) {
|
||||
if (isLoadingAgentsCount || !isFleetEnabled || !agentPolicy) {
|
||||
return;
|
||||
}
|
||||
setIsLoadingAgentsCount(true);
|
||||
|
@ -59,7 +59,7 @@ export const PackagePolicyDeleteProvider: React.FunctionComponent<Props> = ({
|
|||
setAgentsCount(data?.total || 0);
|
||||
setIsLoadingAgentsCount(false);
|
||||
},
|
||||
[agentPolicy.id, isFleetEnabled, isLoadingAgentsCount]
|
||||
[agentPolicy, isFleetEnabled, isLoadingAgentsCount]
|
||||
);
|
||||
|
||||
const deletePackagePoliciesPrompt = useMemo(
|
||||
|
@ -200,7 +200,7 @@ export const PackagePolicyDeleteProvider: React.FunctionComponent<Props> = ({
|
|||
id="xpack.fleet.deletePackagePolicy.confirmModal.affectedAgentsMessage"
|
||||
defaultMessage="Fleet has detected that {agentPolicyName} is already in use by some of your agents."
|
||||
values={{
|
||||
agentPolicyName: <strong>{agentPolicy.name}</strong>,
|
||||
agentPolicyName: <strong>{agentPolicy?.name}</strong>,
|
||||
}}
|
||||
/>
|
||||
</EuiCallOut>
|
||||
|
|
|
@ -613,7 +613,7 @@ class AgentPolicyService {
|
|||
id: string,
|
||||
packagePolicyIds: string[],
|
||||
options?: { user?: AuthenticatedUser; force?: boolean }
|
||||
): Promise<AgentPolicy> {
|
||||
) {
|
||||
const oldAgentPolicy = await this.get(soClient, id, false);
|
||||
|
||||
if (!oldAgentPolicy) {
|
||||
|
|
|
@ -484,7 +484,19 @@ class PackagePolicyService implements PackagePolicyServiceInterface {
|
|||
throw new PackagePolicyRestrictionRelatedError(`Cannot delete package policy ${id}`);
|
||||
}
|
||||
|
||||
if (!options?.skipUnassignFromAgentPolicies) {
|
||||
const agentPolicy = await agentPolicyService
|
||||
.get(soClient, packagePolicy.policy_id)
|
||||
.catch((err) => {
|
||||
if (soClient.errors.isNotFoundError(err)) {
|
||||
appContextService
|
||||
.getLogger()
|
||||
.warn(`Agent policy ${packagePolicy.policy_id} not found`);
|
||||
return null;
|
||||
}
|
||||
throw err;
|
||||
});
|
||||
|
||||
if (agentPolicy && !options?.skipUnassignFromAgentPolicies) {
|
||||
await agentPolicyService.unassignPackagePolicies(
|
||||
soClient,
|
||||
esClient,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue