diff --git a/x-pack/plugins/fleet/common/types/rest_spec/agent.ts b/x-pack/plugins/fleet/common/types/rest_spec/agent.ts
index 7a8b7b918c1e3..886730d38f831 100644
--- a/x-pack/plugins/fleet/common/types/rest_spec/agent.ts
+++ b/x-pack/plugins/fleet/common/types/rest_spec/agent.ts
@@ -89,6 +89,7 @@ export interface PostBulkAgentUpgradeRequest {
agents: string[] | string;
source_uri?: string;
version: string;
+ rollout_duration_seconds?: number;
};
}
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 44e87d7fb4e63..239afe6c7e330 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
@@ -70,7 +70,6 @@ export const AgentDetailsActionMenu: React.FunctionComponent<{
{
setIsUpgradeModalOpen(false);
refreshAgent();
diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/bulk_actions.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/bulk_actions.tsx
index a2515b51814ee..e27c647e25f70 100644
--- a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/bulk_actions.tsx
+++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/bulk_actions.tsx
@@ -24,7 +24,6 @@ import {
AgentUnenrollAgentModal,
AgentUpgradeAgentModal,
} from '../../components';
-import { useKibanaVersion } from '../../../../hooks';
import type { SelectionMode } from './types';
@@ -48,11 +47,10 @@ export const AgentBulkActions: React.FunctionComponent = ({
selectedAgents,
refreshAgents,
}) => {
- const kibanaVersion = useKibanaVersion();
// Bulk actions menu states
const [isMenuOpen, setIsMenuOpen] = useState(false);
const closeMenu = () => setIsMenuOpen(false);
- const openMenu = () => setIsMenuOpen(true);
+ const onClickMenu = () => setIsMenuOpen(!isMenuOpen);
// Actions states
const [isReassignFlyoutOpen, setIsReassignFlyoutOpen] = useState(false);
@@ -150,7 +148,6 @@ export const AgentBulkActions: React.FunctionComponent = ({
{isUpgradeModalOpen && (
{
@@ -172,7 +169,7 @@ export const AgentBulkActions: React.FunctionComponent = ({
fill
iconType="arrowDown"
iconSide="right"
- onClick={openMenu}
+ onClick={onClickMenu}
data-test-subj="agentBulkActionsButton"
>
= () => {
fetchData();
refreshUpgrades();
}}
- version={kibanaVersion}
/>
)}
diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/components/agent_upgrade_modal/constants.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/components/agent_upgrade_modal/constants.tsx
new file mode 100644
index 0000000000000..b5d8cd8f4d72d
--- /dev/null
+++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/components/agent_upgrade_modal/constants.tsx
@@ -0,0 +1,32 @@
+/*
+ * 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.
+ */
+
+// Available versions for the upgrade of the Elastic Agent
+// These versions are only intended to be used as a fallback
+// in the event that the updated versions cannot be retrieved from the endpoint
+
+export const FALLBACK_VERSIONS = [
+ '8.2.0',
+ '8.1.3',
+ '8.1.2',
+ '8.1.1',
+ '8.1.0',
+ '8.0.1',
+ '8.0.0',
+ '7.9.3',
+ '7.9.2',
+ '7.9.1',
+ '7.9.0',
+ '7.8.1',
+ '7.8.0',
+ '7.17.3',
+ '7.17.2',
+ '7.17.1',
+ '7.17.0',
+];
+
+export const MAINTAINANCE_VALUES = [1, 2, 4, 8, 12, 24, 48];
diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/components/agent_upgrade_modal/index.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/components/agent_upgrade_modal/index.tsx
index 72ca7a5b80fd7..2122abb5e2785 100644
--- a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/components/agent_upgrade_modal/index.tsx
+++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/components/agent_upgrade_modal/index.tsx
@@ -7,34 +7,89 @@
import React, { useState } from 'react';
import { i18n } from '@kbn/i18n';
-import { EuiConfirmModal, EuiBetaBadge, EuiFlexGroup, EuiFlexItem } from '@elastic/eui';
+import {
+ EuiConfirmModal,
+ EuiComboBox,
+ EuiFormRow,
+ EuiSpacer,
+ EuiToolTip,
+ EuiIcon,
+ EuiFlexGroup,
+ EuiFlexItem,
+ EuiCallOut,
+} from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n-react';
+import type { EuiComboBoxOptionOption } from '@elastic/eui';
+
import type { Agent } from '../../../../types';
import {
sendPostAgentUpgrade,
sendPostBulkAgentUpgrade,
useStartServices,
+ useKibanaVersion,
} from '../../../../hooks';
+import { FALLBACK_VERSIONS, MAINTAINANCE_VALUES } from './constants';
+
interface Props {
onClose: () => void;
agents: Agent[] | string;
agentCount: number;
- version: string;
}
+const getVersion = (version: Array>) => version[0].value as string;
+
export const AgentUpgradeAgentModal: React.FunctionComponent = ({
onClose,
agents,
agentCount,
- version,
}) => {
const { notifications } = useStartServices();
+ const kibanaVersion = useKibanaVersion();
const [isSubmitting, setIsSubmitting] = useState(false);
+ const [errors, setErrors] = useState();
+
const isSingleAgent = Array.isArray(agents) && agents.length === 1;
+ const isSmallBatch = Array.isArray(agents) && agents.length > 1 && agents.length <= 10;
const isAllAgents = agents === '';
+
+ const fallbackVersions = [kibanaVersion].concat(FALLBACK_VERSIONS);
+ const fallbackOptions: Array> = fallbackVersions.map(
+ (option) => ({
+ label: option,
+ value: option,
+ })
+ );
+ const maintainanceWindows = isSmallBatch ? [0].concat(MAINTAINANCE_VALUES) : MAINTAINANCE_VALUES;
+ const maintainanceOptions: Array> = maintainanceWindows.map(
+ (option) => ({
+ label:
+ option === 0
+ ? i18n.translate('xpack.fleet.upgradeAgents.noMaintainanceWindowOption', {
+ defaultMessage: 'Immediately',
+ })
+ : i18n.translate('xpack.fleet.upgradeAgents.hourLabel', {
+ defaultMessage: '{option} {count, plural, one {hour} other {hours}}',
+ values: { option, count: option === 1 },
+ }),
+ value: option === 0 ? 0 : option * 3600,
+ })
+ );
+ const [selectedVersion, setSelectedVersion] = useState([fallbackOptions[0]]);
+ const [selectedMantainanceWindow, setSelectedMantainanceWindow] = useState([
+ maintainanceOptions[0],
+ ]);
+
async function onSubmit() {
+ const version = getVersion(selectedVersion);
+ const rolloutOptions =
+ selectedMantainanceWindow.length > 0 && (selectedMantainanceWindow[0]?.value as number) > 0
+ ? {
+ rollout_duration_seconds: selectedMantainanceWindow[0].value,
+ }
+ : {};
+
try {
setIsSubmitting(true);
const { data, error } = isSingleAgent
@@ -42,10 +97,14 @@ export const AgentUpgradeAgentModal: React.FunctionComponent = ({
version,
})
: await sendPostBulkAgentUpgrade({
- agents: Array.isArray(agents) ? agents.map((agent) => agent.id) : agents,
version,
+ agents: Array.isArray(agents) ? agents.map((agent) => agent.id) : agents,
+ ...rolloutOptions,
});
if (error) {
+ if (error?.statusCode === 400) {
+ setErrors(error?.message);
+ }
throw error;
}
@@ -114,39 +173,20 @@ export const AgentUpgradeAgentModal: React.FunctionComponent = ({
-
- {isSingleAgent ? (
-
- ) : (
-
- )}
-
-
-
- }
- tooltipContent={
-
- }
+ <>
+ {isSingleAgent ? (
+
+ ) : (
+
-
-
+ )}
+ >
}
onCancel={onClose}
onConfirm={onSubmit}
@@ -179,17 +219,88 @@ export const AgentUpgradeAgentModal: React.FunctionComponent = ({
defaultMessage="This action will upgrade the agent running on '{hostName}' to version {version}. This action can not be undone. Are you sure you wish to continue?"
values={{
hostName: ((agents[0] as Agent).local_metadata.host as any).hostname,
- version,
+ version: getVersion(selectedVersion),
}}
/>
) : (
)}
+
+
+ >) => {
+ setSelectedVersion(selected);
+ }}
+ />
+
+
+ {!isSingleAgent ? (
+
+
+ {i18n.translate('xpack.fleet.upgradeAgents.maintainanceAvailableLabel', {
+ defaultMessage: 'Maintainance window available',
+ })}
+
+
+
+
+
+
+
+
+ }
+ fullWidth
+ >
+ >) => {
+ setSelectedMantainanceWindow(selected);
+ }}
+ />
+
+ ) : null}
+ {errors ? (
+ <>
+
+ >
+ ) : null}
);
};
diff --git a/x-pack/plugins/translations/translations/fr-FR.json b/x-pack/plugins/translations/translations/fr-FR.json
index f211cc9fede8e..8bd7308a27a70 100644
--- a/x-pack/plugins/translations/translations/fr-FR.json
+++ b/x-pack/plugins/translations/translations/fr-FR.json
@@ -13071,8 +13071,6 @@
"xpack.fleet.upgradeAgents.cancelButtonLabel": "Annuler",
"xpack.fleet.upgradeAgents.confirmMultipleButtonLabel": "Mettre à niveau {count, plural, one {l'agent} other {{count} agents} =true {tous les agents sélectionnés}}",
"xpack.fleet.upgradeAgents.confirmSingleButtonLabel": "Mettre à niveau l'agent",
- "xpack.fleet.upgradeAgents.experimentalLabel": "Expérimental",
- "xpack.fleet.upgradeAgents.experimentalLabelTooltip": "Une modification ou une suppression de la mise à niveau de l'agent peut intervenir dans une version ultérieure. La mise à niveau n'est pas soumise à l'accord de niveau de service du support technique.",
"xpack.fleet.upgradeAgents.fatalErrorNotificationTitle": "Erreur lors de la mise à niveau de {count, plural, one {l'agent} other {{count} agents} =true {tous les agents sélectionnés}}",
"xpack.fleet.upgradeAgents.successMultiNotificationTitle": "{isMixed, select, true {{success} agents sur {total}} other {{isAllAgents, select, true {Tous les agents sélectionnés} other {{success}} }}} mis à niveau",
"xpack.fleet.upgradeAgents.successSingleNotificationTitle": "{count} agent mis à niveau",
diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json
index eec41bfb71c81..12300057ca7ff 100644
--- a/x-pack/plugins/translations/translations/ja-JP.json
+++ b/x-pack/plugins/translations/translations/ja-JP.json
@@ -13178,8 +13178,6 @@
"xpack.fleet.upgradeAgents.cancelButtonLabel": "キャンセル",
"xpack.fleet.upgradeAgents.confirmMultipleButtonLabel": "{count, plural, other {{count}個のエージェント} =true {すべての選択されたエージェント}}をアップグレード",
"xpack.fleet.upgradeAgents.confirmSingleButtonLabel": "エージェントをアップグレード",
- "xpack.fleet.upgradeAgents.experimentalLabel": "実験的",
- "xpack.fleet.upgradeAgents.experimentalLabelTooltip": "アップグレードエージェントは今後のリリースで変更または削除される可能性があり、SLA のサポート対象になりません。",
"xpack.fleet.upgradeAgents.fatalErrorNotificationTitle": "{count, plural, other {{count}個のエージェント} =true {すべての選択されたエージェント}}のアップグレードエラー",
"xpack.fleet.upgradeAgents.successMultiNotificationTitle": "{isMixed, select, true {{success}/{total}個の} other {{isAllAgents, select, true {すべての選択された} other {{success}} }}}エージェントをアップグレードしました",
"xpack.fleet.upgradeAgents.successSingleNotificationTitle": "{count}個のエージェントをアップグレードしました",
diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json
index 2d7566bdd8c87..5953802b0a0a5 100644
--- a/x-pack/plugins/translations/translations/zh-CN.json
+++ b/x-pack/plugins/translations/translations/zh-CN.json
@@ -13202,8 +13202,6 @@
"xpack.fleet.upgradeAgents.cancelButtonLabel": "取消",
"xpack.fleet.upgradeAgents.confirmMultipleButtonLabel": "升级{count, plural, one {代理} other { {count} 个代理} =true {所有选定代理}}",
"xpack.fleet.upgradeAgents.confirmSingleButtonLabel": "升级代理",
- "xpack.fleet.upgradeAgents.experimentalLabel": "实验性",
- "xpack.fleet.upgradeAgents.experimentalLabelTooltip": "在未来的版本中可能会更改或移除升级代理,其不受支持 SLA 的约束。",
"xpack.fleet.upgradeAgents.fatalErrorNotificationTitle": "升级{count, plural, one {代理} other { {count} 个代理} =true {所有选定代理}}时出错",
"xpack.fleet.upgradeAgents.successMultiNotificationTitle": "已升级{isMixed, select, true { {success} 个(共 {total} 个)} other {{isAllAgents, select, true {所有选定} other { {success} 个} }}}代理",
"xpack.fleet.upgradeAgents.successSingleNotificationTitle": "已升级 {count} 个代理",