Skip to content

Commit

Permalink
CNV-52394: Add storage migration status modal
Browse files Browse the repository at this point in the history
  • Loading branch information
upalatucci committed Jan 21, 2025
1 parent 8dd30ca commit 59b4dde
Show file tree
Hide file tree
Showing 8 changed files with 346 additions and 55 deletions.
7 changes: 7 additions & 0 deletions locales/en/plugin__kubevirt-plugin.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
"{{time}} seconds": "{{time}} seconds",
"{{timestampPluralized}} ago": "{{timestampPluralized}} ago",
"{{tolerations}} Toleration rules": "{{tolerations}} Toleration rules",
"{t('Select')} <2>{t('Rollback')}</2> {t('to return any completed migration to the original StorageClass.')}": "{t('Select')} <2>{t('Rollback')}</2> {t('to return any completed migration to the original StorageClass.')}",
"<0><0>Bridge binding</0>: Connects the VirtualMachine to the selected network, which is ideal for L2 devices.</0><1><0>SR-IOV binding</0>: Attaches a virtual function network device to the VirtualMachine for high performance.</1>": "<0><0>Bridge binding</0>: Connects the VirtualMachine to the selected network, which is ideal for L2 devices.</0><1><0>SR-IOV binding</0>: Attaches a virtual function network device to the VirtualMachine for high performance.</1>",
"<0><0>WARNING:</0> this PVC is used as a base operating system image. New VMs will not be able to clone this image</0>": "<0><0>WARNING:</0> this PVC is used as a base operating system image. New VMs will not be able to clone this image</0>",
"<0>Autounattend.xml</0><1>Autounattend will be picked up automatically during windows installation. it can be used with destructive actions such as disk formatting. Autounattend will only be used once during installation.</1><2><0>{t('Learn more')}</0></2>": "<0>Autounattend.xml</0><1>Autounattend will be picked up automatically during windows installation. it can be used with destructive actions such as disk formatting. Autounattend will only be used once during installation.</1><2><0>{t('Learn more')}</0></2>",
Expand Down Expand Up @@ -154,6 +155,7 @@
"Are you sure you want to cancel?": "Are you sure you want to cancel?",
"Are you sure you want to leave this page?": "Are you sure you want to leave this page?",
"Are you sure you want to restore {{vmName}} from snapshot {{snapshotName}}?<6><0>Note: </0>Data from the last snapshot taken will be lost. To prevent losing current data, take another snapshot before restoring from this one.</6>": "Are you sure you want to restore {{vmName}} from snapshot {{snapshotName}}?<6><0>Note: </0>Data from the last snapshot taken will be lost. To prevent losing current data, take another snapshot before restoring from this one.</6>",
"Are you sure you want to stop the VirtualMachine workloads?": "Are you sure you want to stop the VirtualMachine workloads?",
"As a default, the VirtualMachine CPU uses sockets to enable hotplug. You can also define the topology manually": "As a default, the VirtualMachine CPU uses sockets to enable hotplug. You can also define the topology manually",
"As new versions of a DataSource become available older versions will be replaced": "As new versions of a DataSource become available older versions will be replaced",
"Ask your cluster administrator for access permissions.": "Ask your cluster administrator for access permissions.",
Expand Down Expand Up @@ -307,6 +309,7 @@
"Container Image": "Container Image",
"Container is required.": "Container is required.",
"Content from container registry": "Content from container registry",
"Continue": "Continue",
"Copied": "Copied",
"Copy SSH command": "Copy SSH command",
"Copy template's boot source disk": "Copy template's boot source disk",
Expand Down Expand Up @@ -1029,6 +1032,7 @@
"Retain revisions": "Retain revisions",
"Review": "Review",
"RHEL download page ": "RHEL download page ",
"Rollback": "Rollback",
"Rules with \"Preferred\" condition will stack with an \"AND\" relation between them.": "Rules with \"Preferred\" condition will stack with an \"AND\" relation between them.",
"Rules with \"Required\" condition will stack with an \"OR\" relation between them.": "Rules with \"Required\" condition will stack with an \"OR\" relation between them.",
"Run": "Run",
Expand Down Expand Up @@ -1193,6 +1197,8 @@
"Status conditions": "Status conditions",
"Step {{current}}/{{size}}": "Step {{current}}/{{size}}",
"Stop": "Stop",
"Stop migration": "Stop migration",
"Stopping the migration will cancel any remaining migrations that are scheduled or currently in progress": "Stopping the migration will cancel any remaining migrations that are scheduled or currently in progress",
"Storage": "Storage",
"Storage ({{disks}})": "Storage ({{disks}})",
"Storage checkup": "Storage checkup",
Expand Down Expand Up @@ -1302,6 +1308,7 @@
"To gain unlimited bandwidth, set to 0": "To gain unlimited bandwidth, set to 0",
"To get started, install permissions and then run a checkup": "To get started, install permissions and then run a checkup",
"To perform this action you must get permission from your Organization Administrator.": "To perform this action you must get permission from your Organization Administrator.",
"to return any completed migration to the original StorageClass.": "to return any completed migration to the original StorageClass.",
"To see the vCPU metric, you must set the schedstats=enable kernel argument in the MachineConfig object.": "To see the vCPU metric, you must set the schedstats=enable kernel argument in the MachineConfig object.",
"Today": "Today",
"Tolerations": "Tolerations",
Expand Down
4 changes: 4 additions & 0 deletions src/utils/resources/vmim/selectors.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { V1VirtualMachineInstanceMigration } from '@kubevirt-ui/kubevirt-api/kubevirt';

export const getMigrationPod = (vmim: V1VirtualMachineInstanceMigration) =>
vmim?.status?.migrationState?.sourcePod;
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import VirtualMachineMigrationDestinationTab from './tabs/VirtualMachineMigratio
import VirtualMachineMigrationDetails from './tabs/VirtualMachineMigrationDetails';
import VirtualMachineMigrationReviewTab from './tabs/VirtualMachineMigrationReviewTab';
import { entireVMSelected, migrateVM } from './utils';
import VirtualMachineMigrationStatus from './VirtualMachineMigrationStatus';

import './virtual-machine-migration-modal.scss';

Expand All @@ -34,6 +35,8 @@ const VirtualMachineMigrateModal: FC<VirtualMachineMigrateModalProps> = ({
const [selectedStorageClass, setSelectedStorageClass] = useState('');
const [migrationError, setMigrationError] = useState<Error | null>(null);
const [migrationLoading, setMigrationLoading] = useState(false);
const [migrationStarted, setMigrationStarted] = useState(false);

const [selectedPVCs, setSelectedPVCs] = useState<IoK8sApiCoreV1PersistentVolumeClaim[] | null>(
null,
);
Expand All @@ -60,7 +63,7 @@ const VirtualMachineMigrateModal: FC<VirtualMachineMigrateModalProps> = ({
try {
await migrateVM(vm, pvcsToMigrate, destinationStorageClass);

onClose();
setMigrationStarted(true);
} catch (apiError) {
setMigrationError(apiError);
}
Expand All @@ -79,60 +82,64 @@ const VirtualMachineMigrateModal: FC<VirtualMachineMigrateModalProps> = ({
variant="large"
>
<StateHandler error={loadingError} loaded>
<Wizard
header={
<WizardHeader
closeButtonAriaLabel={t('Close header')}
description={t('Migrate VirtualMachine storage to a different StorageClass.')}
onClose={onClose}
title={t('Migrate VirtualMachine storage')}
/>
}
onClose={onClose}
onSave={onSubmit}
title={t('Migrate VirtualMachine storage')}
>
<WizardStep
footer={{ isNextDisabled: nothingSelected }}
id="wizard-migration-details"
name={t('Migration details')}
{migrationStarted ? (
<VirtualMachineMigrationStatus onClose={onClose} vm={vm} />
) : (
<Wizard
header={
<WizardHeader
closeButtonAriaLabel={t('Close header')}
description={t('Migrate VirtualMachine storage to a different StorageClass.')}
onClose={onClose}
title={t('Migrate VirtualMachine storage')}
/>
}
onClose={onClose}
onSave={onSubmit}
title={t('Migrate VirtualMachine storage')}
>
{loaded && scLoaded ? (
<VirtualMachineMigrationDetails
pvcs={pvcs}
selectedPVCs={selectedPVCs}
setSelectedPVCs={setSelectedPVCs}
<WizardStep
footer={{ isNextDisabled: nothingSelected }}
id="wizard-migration-details"
name={t('Migration details')}
>
{loaded && scLoaded ? (
<VirtualMachineMigrationDetails
pvcs={pvcs}
selectedPVCs={selectedPVCs}
setSelectedPVCs={setSelectedPVCs}
vm={vm}
/>
) : (
<Loading />
)}
</WizardStep>
<WizardStep id="wizard-migrate-destination" name={t('Destination StorageClass')}>
<VirtualMachineMigrationDestinationTab
defaultStorageClassName={defaultStorageClassName}
destinationStorageClass={destinationStorageClass}
setSelectedStorageClass={setSelectedStorageClass}
sortedStorageClasses={sortedStorageClasses}
/>
</WizardStep>
<WizardStep
footer={{
isNextDisabled: migrationLoading,
nextButtonText: t('Migrate VirtualMachine storage'),
}}
id="wizard-migrate-review"
name={t('Review')}
>
<VirtualMachineMigrationReviewTab
defaultStorageClassName={defaultStorageClassName}
destinationStorageClass={destinationStorageClass}
migrationError={migrationError}
pvcs={pvcsToMigrate}
vm={vm}
/>
) : (
<Loading />
)}
</WizardStep>
<WizardStep id="wizard-migrate-destination" name={t('Destination StorageClass')}>
<VirtualMachineMigrationDestinationTab
defaultStorageClassName={defaultStorageClassName}
destinationStorageClass={destinationStorageClass}
setSelectedStorageClass={setSelectedStorageClass}
sortedStorageClasses={sortedStorageClasses}
/>
</WizardStep>
<WizardStep
footer={{
isNextDisabled: migrationLoading,
nextButtonText: t('Migrate VirtualMachine storage'),
}}
id="wizard-migrate-review"
name={t('Review')}
>
<VirtualMachineMigrationReviewTab
defaultStorageClassName={defaultStorageClassName}
destinationStorageClass={destinationStorageClass}
migrationError={migrationError}
pvcs={pvcsToMigrate}
vm={vm}
/>
</WizardStep>
</Wizard>
</WizardStep>
</Wizard>
)}
</StateHandler>
</Modal>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
import React, { FC, useState } from 'react';
import { Trans } from 'react-i18next';

import { V1VirtualMachine } from '@kubevirt-ui/kubevirt-api/kubevirt';
import { useKubevirtTranslation } from '@kubevirt-utils/hooks/useKubevirtTranslation';
import {
ActionList,
ActionListItem,
Alert,
AlertVariant,
Button,
ButtonVariant,
Text,
Title,
} from '@patternfly/react-core';
import { CloseIcon, WarningTriangleIcon } from '@patternfly/react-icons';
import { rollbackStorageMigration } from '@virtualmachines/actions/actions';

type VirtualMachineMigrationRollbackProps = {
onClose: () => void;
onContinue: () => void;
vm: V1VirtualMachine;
};

const VirtualMachineMigrationRollback: FC<VirtualMachineMigrationRollbackProps> = ({
onClose,
onContinue,
vm,
}) => {
const { t } = useKubevirtTranslation();
const [loadingRollback, setLoadingRollback] = useState(false);
const [errorRollback, setErrorRollback] = useState<Error>();

const rollback = async () => {
setLoadingRollback(true);

try {
await rollbackStorageMigration(vm);
onClose();
} catch (apiError) {
setErrorRollback(errorRollback);
} finally {
setLoadingRollback(false);
}
};

return (
<div className="pf-v5-c-wizard migration-status">
<div className="pf-v5-c-wizard__header">
<div className="pf-v5-c-wizard__close">
<Button aria-label={t('Close')} onClick={onClose} variant={ButtonVariant.plain}>
<CloseIcon />
</Button>
</div>
<div className="pf-v5-c-wizard__title">
<h2 className="pf-v5-c-wizard__title-text">{t('Migrate VirtualMachine storage')}</h2>
</div>
<div className="pf-v5-c-wizard__description">
{t('Migrate VirtualMachine storage to a different StorageClass.')}
</div>
</div>

<div className="migration-status__body">
<Title headingLevel="h2">
<WarningTriangleIcon color="var(--pf-global--warning-color--100)" /> {t('Stop migration')}
</Title>

<Text>{t('Are you sure you want to stop the VirtualMachine workloads?')}</Text>
<Text>
{t(
'Stopping the migration will cancel any remaining migrations that are scheduled or currently in progress',
)}
</Text>

<Text>
<Trans t={t}>
{t('Select')} <strong>{t('Rollback')}</strong>{' '}
{t('to return any completed migration to the original StorageClass.')}
</Trans>
</Text>

{errorRollback && (
<Alert isInline title={t('Error')} variant={AlertVariant.danger}>
{errorRollback?.message}
</Alert>
)}
</div>
<ActionList>
<ActionListItem>
<Button isLoading={loadingRollback} onClick={rollback}>
{t('Rollback')}
</Button>
</ActionListItem>
<ActionListItem>
<Button onClick={onContinue} variant={ButtonVariant.link}>
{t('Continue')}
</Button>
</ActionListItem>
</ActionList>
</div>
);
};

export default VirtualMachineMigrationRollback;
Loading

0 comments on commit 59b4dde

Please sign in to comment.