Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Fleet] add setup technology selector to add integration page #189612

Merged
merged 10 commits into from
Aug 2, 2024
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

import React from 'react';

import { FormattedMessage } from '@kbn/i18n-react';
import { EuiBetaBadge, EuiFormRow, EuiSpacer, EuiSuperSelect, EuiText } from '@elastic/eui';

import { SetupTechnology } from '../../../../../types';

export const SETUP_TECHNOLOGY_SELECTOR_TEST_SUBJ = 'setup-technology-selector';

export const SetupTechnologySelector = ({
disabled,
setupTechnology,
onSetupTechnologyChange,
}: {
disabled: boolean;
setupTechnology: SetupTechnology;
onSetupTechnologyChange: (value: SetupTechnology) => void;
}) => {
const options = [
{
value: SetupTechnology.AGENTLESS,
inputDisplay: (
<>
<FormattedMessage
id="xpack.fleet.setupTechnology.agentlessInputDisplay"
defaultMessage="Agentless"
/>
&nbsp;
<EuiBetaBadge
label="Beta"
size="s"
tooltipContent="This module is not GA. Please help us by reporting any bugs."
juliaElastic marked this conversation as resolved.
Show resolved Hide resolved
/>
</>
),
dropdownDisplay: (
<>
<strong>
<FormattedMessage
id="xpack.fleet.setupTechnology.agentlessDrowpownDisplay"
defaultMessage="Agentless"
/>
</strong>
&nbsp;
<EuiBetaBadge
label="Beta"
size="s"
tooltipContent="This module is not GA. Please help us by reporting any bugs."
/>
<EuiText size="s" color="subdued">
<p>
<FormattedMessage
id="xpack.fleet.setupTechnology.agentlessDrowpownDescription"
defaultMessage="Set up the integration without an agent"
/>
</p>
</EuiText>
</>
),
},
{
value: SetupTechnology.AGENT_BASED,
inputDisplay: (
<FormattedMessage
id="xpack.fleet.setupTechnology.agentbasedInputDisplay"
defaultMessage="Agent-based"
/>
),
dropdownDisplay: (
<>
<strong>
<FormattedMessage
id="xpack.fleet.setupTechnology.agentbasedDrowpownDisplay"
defaultMessage="Agent-based"
/>
</strong>
<EuiText size="s" color="subdued">
<p>
<FormattedMessage
id="xpack.fleet.setupTechnology.agentbasedDrowpownDescription"
defaultMessage="Set up the integration with an agent"
/>
</p>
</EuiText>
</>
),
},
];

return (
<>
<EuiSpacer size="l" />
<EuiFormRow
fullWidth
label={
<FormattedMessage
id="xpack.fleet.setupTechnology.setupTechnologyLabel"
defaultMessage="Setup technology"
/>
}
>
<EuiSuperSelect
disabled={disabled}
options={options}
valueOfSelected={setupTechnology}
placeholder={
<FormattedMessage
id="xpack.fleet.setupTechnology.setupTechnologyPlaceholder"
defaultMessage="Select the setup technology"
/>
}
onChange={onSetupTechnologyChange}
itemLayoutAlign="top"
hasDividers
fullWidth
data-test-subj={SETUP_TECHNOLOGY_SELECTOR_TEST_SUBJ}
/>
</EuiFormRow>
</>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -92,12 +92,8 @@ export function useSetupTechnology({
isEditPage?: boolean;
}) {
const { cloud } = useStartServices();
const {
isAgentlessEnabled,
isAgentlessIntegration,
isAgentlessCloudEnabled,
isAgentlessServerlessEnabled,
} = useAgentless();
const { isAgentlessEnabled, isAgentlessCloudEnabled, isAgentlessServerlessEnabled } =
useAgentless();

// this is a placeholder for the new agent-BASED policy that will be used when the user switches from agentless to agent-based and back
const newAgentBasedPolicy = useRef<NewAgentPolicy>(newAgentPolicy);
Expand All @@ -107,6 +103,7 @@ export function useSetupTechnology({
const [newAgentlessPolicy, setNewAgentlessPolicy] = useState<AgentPolicy | NewAgentPolicy>(
generateNewAgentPolicyWithDefaults({
supports_agentless: true,
monitoring_enabled: [],
})
);

Expand Down Expand Up @@ -135,12 +132,6 @@ export function useSetupTechnology({
setNewAgentPolicy,
]);

useEffect(() => {
if (isAgentlessEnabled && packageInfo && isAgentlessIntegration(packageInfo)) {
setSelectedSetupTechnology(SetupTechnology.AGENTLESS);
}
}, [isAgentlessEnabled, isAgentlessIntegration, packageInfo]);

// tech debt: remove this useEffect when Serverless uses the Agentless API
// https://github.com/elastic/security-team/issues/9781
useEffect(() => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ import { PostInstallGoogleCloudShellModal } from './components/cloud_security_po
import { PostInstallAzureArmTemplateModal } from './components/cloud_security_posture/post_install_azure_arm_template_modal';
import { RootPrivilegesCallout } from './root_callout';
import { useAgentless } from './hooks/setup_technology';
import { SetupTechnologySelector } from './components/setup_technology_selector';

export const StepsWithLessPadding = styled(EuiSteps)`
.euiStep__content {
Expand Down Expand Up @@ -349,7 +350,7 @@ export const CreatePackagePolicySinglePage: CreatePackagePolicyParams = ({
"'package-policy-create' and 'package-policy-replace-define-step' cannot both be registered as UI extensions"
);
}
const { isAgentlessEnabled } = useAgentless();
const { isAgentlessEnabled, isAgentlessIntegration } = useAgentless();
const { handleSetupTechnologyChange, selectedSetupTechnology } = useSetupTechnology({
newAgentPolicy,
setNewAgentPolicy,
Expand Down Expand Up @@ -397,6 +398,19 @@ export const CreatePackagePolicySinglePage: CreatePackagePolicyParams = ({
submitAttempted={formState === 'INVALID'}
/>

{/* TODO move SetupTechnologySelector out of extensionView */}
{!extensionView && isAgentlessIntegration(packageInfo) && (
<SetupTechnologySelector
disabled={false}
setupTechnology={selectedSetupTechnology}
onSetupTechnologyChange={(value) => {
handleSetupTechnologyChange(value);
// agentless doesn't need system integration
setWithSysMonitoring(value === SetupTechnology.AGENT_BASED);
}}
/>
)}

{/* Only show the out-of-box configuration step if a UI extension is NOT registered */}
{!extensionView && (
<StepConfigurePackagePolicy
Expand Down Expand Up @@ -435,6 +449,9 @@ export const CreatePackagePolicySinglePage: CreatePackagePolicyParams = ({
extensionView,
handleExtensionViewOnChange,
spaceSettings?.allowedNamespacePrefixes,
handleSetupTechnologyChange,
isAgentlessIntegration,
selectedSetupTechnology,
]
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -119,8 +119,7 @@ export const PackagePoliciesTable: React.FunctionComponent<Props> = ({
<EuiFlexGroup gutterSize="s" alignItems="center">
<EuiFlexItem data-test-subj="PackagePoliciesTableName" grow={false}>
<EuiLink
title={value}
{...(canReadIntegrationPolicies
{...(canReadIntegrationPolicies && !agentPolicy.supports_agentless
? {
href: getHref('edit_integration', {
policyId: agentPolicy.id,
Expand All @@ -129,7 +128,20 @@ export const PackagePoliciesTable: React.FunctionComponent<Props> = ({
}
: { disabled: true })}
>
<span className="eui-textTruncate" title={value}>
<span
className="eui-textTruncate"
title={
agentPolicy.supports_agentless
? i18n.translate(
'xpack.fleet.policyDetails.packagePoliciesTable.disabledEditTitle',
{
defaultMessage:
'It is not allowed to edit an agentless integration. Please add a new integration if needed.',
juliaElastic marked this conversation as resolved.
Show resolved Hide resolved
}
)
: value
}
>
{value}
</span>
{packagePolicy.description ? (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,16 +58,31 @@ interface InMemoryPackagePolicyAndAgentPolicy {

const IntegrationDetailsLink = memo<{
packagePolicy: InMemoryPackagePolicyAndAgentPolicy['packagePolicy'];
}>(({ packagePolicy }) => {
agentPolicies: InMemoryPackagePolicyAndAgentPolicy['agentPolicies'];
}>(({ packagePolicy, agentPolicies }) => {
const { getHref } = useLink();
const policySupportsAgentless = agentPolicies?.some((policy) => policy.supports_agentless);
return (
<EuiLink
className="eui-textTruncate"
data-test-subj="integrationNameLink"
title={packagePolicy.name}
href={getHref('integration_policy_edit', {
packagePolicyId: packagePolicy.id,
})}
{...(policySupportsAgentless
? {
disabled: true,
title: i18n.translate(
'xpack.fleet.epm.packageDetails.integrationList.disabledEditTitle',
{
defaultMessage:
'It is not allowed to edit an agentless integration. Please add a new integration if needed.',
}
),
}
: {
href: getHref('integration_policy_edit', {
packagePolicyId: packagePolicy.id,
}),
title: packagePolicy.name,
})}
>
{packagePolicy.name}
</EuiLink>
Expand Down Expand Up @@ -182,8 +197,10 @@ export const PackagePoliciesPage = ({ name, version }: PackagePoliciesPanelProps
name: i18n.translate('xpack.fleet.epm.packageDetails.integrationList.name', {
defaultMessage: 'Integration policy',
}),
render(_, { packagePolicy }) {
return <IntegrationDetailsLink packagePolicy={packagePolicy} />;
render(_, { agentPolicies, packagePolicy }) {
return (
<IntegrationDetailsLink packagePolicy={packagePolicy} agentPolicies={agentPolicies} />
);
},
},
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,11 @@ import { EuiContextMenuItem, EuiPortal } from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n-react';

import type { AgentPolicy, InMemoryPackagePolicy } from '../types';
import { useAgentPolicyRefresh, useAuthz, useLink } from '../hooks';
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';
Expand All @@ -36,6 +38,9 @@ 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;
Expand Down Expand Up @@ -87,13 +92,23 @@ export const PackagePolicyActionsMenu: React.FunctionComponent<{
: []),
<EuiContextMenuItem
data-test-subj="PackagePolicyActionsEditItem"
disabled={!canWriteIntegrationPolicies || !agentPolicy}
disabled={
!canWriteIntegrationPolicies || !agentPolicy || (agentPolicy?.supports_agentless ?? false)
}
icon="pencil"
href={`${getHref('edit_integration', {
policyId: agentPolicy?.id ?? '',
packagePolicyId: packagePolicy.id,
})}${from ? `?from=${from}` : ''}`}
key="packagePolicyEdit"
toolTipContent={
(agentPolicy?.supports_agentless ?? false) && (
<FormattedMessage
id="xpack.fleet.epm.packageDetails.integrationList.editIntegrationAgentlessTooltip"
defaultMessage="It is not allowed to edit an agentless integration. Please add a new integration if needed."
/>
)
}
>
<FormattedMessage
id="xpack.fleet.policyDetails.packagePoliciesTable.editActionTitle"
Expand Down Expand Up @@ -123,7 +138,7 @@ export const PackagePolicyActionsMenu: React.FunctionComponent<{
// </EuiContextMenuItem>,
];

if (!agentPolicy || !agentPolicyIsManaged) {
if (!agentPolicy || !agentPolicyIsManaged || agentPolicy.supports_agentless) {
juliaElastic marked this conversation as resolved.
Show resolved Hide resolved
const ContextMenuItem = canWriteIntegrationPolicies
? DangerEuiContextMenuItem
: EuiContextMenuItem;
Expand All @@ -138,7 +153,12 @@ export const PackagePolicyActionsMenu: React.FunctionComponent<{
onClick={() => {
deletePackagePoliciesPrompt([packagePolicy.id], () => {
setIsActionsMenuOpen(false);
refreshAgentPolicy();
if (agentPolicy?.supports_agentless) {
// go back to all agent policies
navigateToApp(PLUGIN_ID, { path: pagePathGetters.policies_list()[1] });
} else {
refreshAgentPolicy();
}
});
}}
>
Expand Down
Loading