mirror of
https://github.com/elastic/kibana.git
synced 2025-04-25 02:09:32 -04:00
[Fleet] Changes to agent upgrade modal to allow for rolling upgrades (#132421)
* [Fleet] Changes to agent upgrade modal to allow for rolling upgrades * Update the onSubmit logic and handle case with single agent * Fix check * [CI] Auto-commit changed files from 'node scripts/eslint --no-cache --fix' * Add option to upgrade immediately; minor fixes * [CI] Auto-commit changed files from 'node scripts/precommit_hook.js --ref HEAD~1..HEAD --fix' * Add callout in modal for 400 errors * Linter fixes * Fix i18n error * Address code review comments Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
parent
473141f58b
commit
aa4c389ed2
9 changed files with 184 additions and 51 deletions
|
@ -89,6 +89,7 @@ export interface PostBulkAgentUpgradeRequest {
|
|||
agents: string[] | string;
|
||||
source_uri?: string;
|
||||
version: string;
|
||||
rollout_duration_seconds?: number;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -70,7 +70,6 @@ export const AgentDetailsActionMenu: React.FunctionComponent<{
|
|||
<AgentUpgradeAgentModal
|
||||
agents={[agent]}
|
||||
agentCount={1}
|
||||
version={kibanaVersion}
|
||||
onClose={() => {
|
||||
setIsUpgradeModalOpen(false);
|
||||
refreshAgent();
|
||||
|
|
|
@ -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<Props> = ({
|
|||
selectedAgents,
|
||||
refreshAgents,
|
||||
}) => {
|
||||
const kibanaVersion = useKibanaVersion();
|
||||
// Bulk actions menu states
|
||||
const [isMenuOpen, setIsMenuOpen] = useState<boolean>(false);
|
||||
const closeMenu = () => setIsMenuOpen(false);
|
||||
const openMenu = () => setIsMenuOpen(true);
|
||||
const onClickMenu = () => setIsMenuOpen(!isMenuOpen);
|
||||
|
||||
// Actions states
|
||||
const [isReassignFlyoutOpen, setIsReassignFlyoutOpen] = useState<boolean>(false);
|
||||
|
@ -150,7 +148,6 @@ export const AgentBulkActions: React.FunctionComponent<Props> = ({
|
|||
{isUpgradeModalOpen && (
|
||||
<EuiPortal>
|
||||
<AgentUpgradeAgentModal
|
||||
version={kibanaVersion}
|
||||
agents={agents}
|
||||
agentCount={agentCount}
|
||||
onClose={() => {
|
||||
|
@ -172,7 +169,7 @@ export const AgentBulkActions: React.FunctionComponent<Props> = ({
|
|||
fill
|
||||
iconType="arrowDown"
|
||||
iconSide="right"
|
||||
onClick={openMenu}
|
||||
onClick={onClickMenu}
|
||||
data-test-subj="agentBulkActionsButton"
|
||||
>
|
||||
<FormattedMessage
|
||||
|
|
|
@ -505,7 +505,6 @@ export const AgentListPage: React.FunctionComponent<{}> = () => {
|
|||
fetchData();
|
||||
refreshUpgrades();
|
||||
}}
|
||||
version={kibanaVersion}
|
||||
/>
|
||||
</EuiPortal>
|
||||
)}
|
||||
|
|
|
@ -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];
|
|
@ -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<EuiComboBoxOptionOption<string>>) => version[0].value as string;
|
||||
|
||||
export const AgentUpgradeAgentModal: React.FunctionComponent<Props> = ({
|
||||
onClose,
|
||||
agents,
|
||||
agentCount,
|
||||
version,
|
||||
}) => {
|
||||
const { notifications } = useStartServices();
|
||||
const kibanaVersion = useKibanaVersion();
|
||||
const [isSubmitting, setIsSubmitting] = useState(false);
|
||||
const [errors, setErrors] = useState<string | undefined>();
|
||||
|
||||
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<EuiComboBoxOptionOption<string>> = fallbackVersions.map(
|
||||
(option) => ({
|
||||
label: option,
|
||||
value: option,
|
||||
})
|
||||
);
|
||||
const maintainanceWindows = isSmallBatch ? [0].concat(MAINTAINANCE_VALUES) : MAINTAINANCE_VALUES;
|
||||
const maintainanceOptions: Array<EuiComboBoxOptionOption<number>> = 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<Props> = ({
|
|||
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,8 +173,7 @@ export const AgentUpgradeAgentModal: React.FunctionComponent<Props> = ({
|
|||
<EuiConfirmModal
|
||||
data-test-subj="agentUpgradeModal"
|
||||
title={
|
||||
<EuiFlexGroup alignItems="center" gutterSize="s">
|
||||
<EuiFlexItem grow={false}>
|
||||
<>
|
||||
{isSingleAgent ? (
|
||||
<FormattedMessage
|
||||
id="xpack.fleet.upgradeAgents.upgradeSingleTitle"
|
||||
|
@ -128,25 +186,7 @@ export const AgentUpgradeAgentModal: React.FunctionComponent<Props> = ({
|
|||
values={{ count: isAllAgents || agentCount }}
|
||||
/>
|
||||
)}
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiBetaBadge
|
||||
iconType="beaker"
|
||||
label={
|
||||
<FormattedMessage
|
||||
id="xpack.fleet.upgradeAgents.experimentalLabel"
|
||||
defaultMessage="Experimental"
|
||||
/>
|
||||
}
|
||||
tooltipContent={
|
||||
<FormattedMessage
|
||||
id="xpack.fleet.upgradeAgents.experimentalLabelTooltip"
|
||||
defaultMessage="Upgrade agent might change or be removed in a future release and is not subject to the support SLA."
|
||||
/>
|
||||
}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</>
|
||||
}
|
||||
onCancel={onClose}
|
||||
onConfirm={onSubmit}
|
||||
|
@ -179,17 +219,88 @@ export const AgentUpgradeAgentModal: React.FunctionComponent<Props> = ({
|
|||
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),
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<FormattedMessage
|
||||
id="xpack.fleet.upgradeAgents.upgradeMultipleDescription"
|
||||
defaultMessage="This action will upgrade multiple agents to version {version}. This action can not be undone. Are you sure you wish to continue?"
|
||||
values={{ version }}
|
||||
values={{ version: getVersion(selectedVersion) }}
|
||||
/>
|
||||
)}
|
||||
</p>
|
||||
<EuiSpacer size="m" />
|
||||
<EuiFormRow
|
||||
label={i18n.translate('xpack.fleet.upgradeAgents.chooseVersionLabel', {
|
||||
defaultMessage: 'Upgrade version',
|
||||
})}
|
||||
fullWidth
|
||||
>
|
||||
<EuiComboBox
|
||||
data-test-subj="agentUpgradeModal.VersionCombobox"
|
||||
fullWidth
|
||||
singleSelection={{ asPlainText: true }}
|
||||
options={fallbackOptions}
|
||||
selectedOptions={selectedVersion}
|
||||
onChange={(selected: Array<EuiComboBoxOptionOption<string>>) => {
|
||||
setSelectedVersion(selected);
|
||||
}}
|
||||
/>
|
||||
</EuiFormRow>
|
||||
<EuiSpacer size="m" />
|
||||
{!isSingleAgent ? (
|
||||
<EuiFormRow
|
||||
label={
|
||||
<EuiFlexGroup gutterSize="s">
|
||||
<EuiFlexItem grow={false}>
|
||||
{i18n.translate('xpack.fleet.upgradeAgents.maintainanceAvailableLabel', {
|
||||
defaultMessage: 'Maintainance window available',
|
||||
})}
|
||||
</EuiFlexItem>
|
||||
<EuiSpacer size="xs" />
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiToolTip
|
||||
position="top"
|
||||
content={i18n.translate(
|
||||
'xpack.fleet.upgradeAgents.maintainanceAvailableTooltip',
|
||||
{
|
||||
defaultMessage:
|
||||
'Defines the duration of time available to perform the upgrade. The agent upgrades are spread uniformly across this duration in order to avoid exhausting network resources.',
|
||||
}
|
||||
)}
|
||||
>
|
||||
<EuiIcon type="iInCircle" title="TooltipIcon" />
|
||||
</EuiToolTip>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
}
|
||||
fullWidth
|
||||
>
|
||||
<EuiComboBox
|
||||
data-test-subj="agentUpgradeModal.MaintainanceCombobox"
|
||||
fullWidth
|
||||
singleSelection={{ asPlainText: true }}
|
||||
options={maintainanceOptions}
|
||||
selectedOptions={selectedMantainanceWindow}
|
||||
onChange={(selected: Array<EuiComboBoxOptionOption<number>>) => {
|
||||
setSelectedMantainanceWindow(selected);
|
||||
}}
|
||||
/>
|
||||
</EuiFormRow>
|
||||
) : null}
|
||||
{errors ? (
|
||||
<>
|
||||
<EuiCallOut
|
||||
color="danger"
|
||||
title={i18n.translate('xpack.fleet.upgradeAgents.warningCallout', {
|
||||
defaultMessage:
|
||||
'Error upgrading the selected {count, plural, one {agent} other {{count} agents}}',
|
||||
values: { count: isSingleAgent },
|
||||
})}
|
||||
/>
|
||||
</>
|
||||
) : null}
|
||||
</EuiConfirmModal>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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}個のエージェントをアップグレードしました",
|
||||
|
|
|
@ -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} 个代理",
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue