Skip to content

Commit 4db6f0b

Browse files
committed
Add support for storage migration for multiple namespaces
1 parent 123c9e1 commit 4db6f0b

17 files changed

+148
-80
lines changed

locales/en/plugin__kubevirt-plugin.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,7 @@
171171
"An error occurred": "An error occurred",
172172
"An error occurred during the cloning process": "An error occurred during the cloning process",
173173
"An error occurred during the upload process": "An error occurred during the upload process",
174+
"An existing MigPlan for these namespaces was found.": "An existing MigPlan for these namespaces was found.",
174175
"An existing MigPlan for this namespace was found. ": "An existing MigPlan for this namespace was found. ",
175176
"An InstanceType must be selected": "An InstanceType must be selected",
176177
"An OpenShift project is an alternative representation of a Kubernetes namespace.": "An OpenShift project is an alternative representation of a Kubernetes namespace.",

locales/es/plugin__kubevirt-plugin.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,7 @@
176176
"An error occurred": "Ocurrió un error",
177177
"An error occurred during the cloning process": "Ocurrió un error durante el proceso de clonación",
178178
"An error occurred during the upload process": "Ocurrió un error durante el proceso de carga",
179+
"An existing MigPlan for these namespaces was found.": "An existing MigPlan for these namespaces was found.",
179180
"An existing MigPlan for this namespace was found. ": "Se encontró un MigPlan existente para este espacio de nombre. ",
180181
"An InstanceType must be selected": "Se debe seleccionar un InstanceType",
181182
"An OpenShift project is an alternative representation of a Kubernetes namespace.": "Un proyecto OpenShift es una representación alternativa de un espacio de nombres de Kubernetes.",

locales/fr/plugin__kubevirt-plugin.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,7 @@
176176
"An error occurred": "Une erreur s’est produite",
177177
"An error occurred during the cloning process": "Une erreur s'est produite lors du processus de clonage",
178178
"An error occurred during the upload process": "Une erreur s'est produite lors du processus de téléchargement",
179+
"An existing MigPlan for these namespaces was found.": "An existing MigPlan for these namespaces was found.",
179180
"An existing MigPlan for this namespace was found. ": "Un MigPlan existant pour cet espace de noms a été trouvé. ",
180181
"An InstanceType must be selected": "Un InstanceType doit être sélectionné",
181182
"An OpenShift project is an alternative representation of a Kubernetes namespace.": "Un projet OpenShift est une représentation alternative d’un espace de noms Kubernetes.",

locales/ja/plugin__kubevirt-plugin.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,7 @@
171171
"An error occurred": "エラーが発生しました",
172172
"An error occurred during the cloning process": "クローン作成中にエラーが発生しました",
173173
"An error occurred during the upload process": "アップロード中にエラーが発生しました",
174+
"An existing MigPlan for these namespaces was found.": "An existing MigPlan for these namespaces was found.",
174175
"An existing MigPlan for this namespace was found. ": "このnamespace の既存の MigPlan が見つかりました。",
175176
"An InstanceType must be selected": "InstanceType を選択する必要があります",
176177
"An OpenShift project is an alternative representation of a Kubernetes namespace.": "OpenShift プロジェクトは、Kubernetes namespace を別の形で表現したものです。",

locales/ko/plugin__kubevirt-plugin.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,7 @@
171171
"An error occurred": "오류가 발생했습니다",
172172
"An error occurred during the cloning process": "복제 프로세스 중 오류가 발생했습니다.",
173173
"An error occurred during the upload process": "업로드 프로세스 중 오류 발생",
174+
"An existing MigPlan for these namespaces was found.": "An existing MigPlan for these namespaces was found.",
174175
"An existing MigPlan for this namespace was found. ": "이 네임스페이스의 기존 MigPlan이 발견되었습니다. ",
175176
"An InstanceType must be selected": "InstanceType을 선택해야 합니다.",
176177
"An OpenShift project is an alternative representation of a Kubernetes namespace.": "OpenShift 프로젝트는 Kubernetes 네임스페이스의 대체 표현입니다.",

locales/zh/plugin__kubevirt-plugin.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,7 @@
171171
"An error occurred": "发生错误",
172172
"An error occurred during the cloning process": "克隆过程中出现错误",
173173
"An error occurred during the upload process": "上传过程中出现错误",
174+
"An existing MigPlan for these namespaces was found.": "An existing MigPlan for these namespaces was found.",
174175
"An existing MigPlan for this namespace was found. ": "找到用于此命名空间的现有 MigPlan。",
175176
"An InstanceType must be selected": "必须选择一个 InstanceType",
176177
"An OpenShift project is an alternative representation of a Kubernetes namespace.": "OpenShift 项目是 Kubernetes 命名空间的一个替代表示。",

src/utils/resources/migrations/constants.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ export type PersistentVolumesMigPlan = {
3636
export type MigPlan = K8sResourceCommon & {
3737
spec: {
3838
[key: string]: any;
39+
namespaces?: string[];
3940
persistentVolumes?: PersistentVolumesMigPlan[];
4041
};
4142
status?: { conditions: K8sResourceCondition[]; suffix: string };

src/utils/utils/utils.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,3 +237,5 @@ export const isIPV6LinkLocal = (ip: string): boolean => {
237237

238238
export const removeLinkLocalIPV6 = (ipAddress: IPAddress[]) =>
239239
ipAddress.filter((item) => !isIPV6LinkLocal(item?.ip?.trim()));
240+
241+
export const removeDuplicates = (array: any[]) => Array.from(new Set(array));

src/views/virtualmachines/actions/components/VirtualMachineMigration/VirtualMachineMigrationModal.tsx

Lines changed: 34 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -8,36 +8,34 @@ import Loading from '@kubevirt-utils/components/Loading/Loading';
88
import StateHandler from '@kubevirt-utils/components/StateHandler/StateHandler';
99
import useDefaultStorageClass from '@kubevirt-utils/hooks/useDefaultStorage/useDefaultStorageClass';
1010
import { useKubevirtTranslation } from '@kubevirt-utils/hooks/useKubevirtTranslation';
11-
import {
12-
modelToGroupVersionKind,
13-
modelToRef,
14-
PersistentVolumeClaimModel,
15-
} from '@kubevirt-utils/models';
11+
import { modelToRef } from '@kubevirt-utils/models';
1612
import {
1713
DEFAULT_MIGRATION_NAMESPACE,
1814
MigPlanModel,
1915
} from '@kubevirt-utils/resources/migrations/constants';
2016
import { getName, getNamespace } from '@kubevirt-utils/resources/shared';
21-
import { isEmpty } from '@kubevirt-utils/utils/utils';
17+
import { isEmpty, removeDuplicates } from '@kubevirt-utils/utils/utils';
2218
import { getCluster } from '@multicluster/helpers/selectors';
23-
import useK8sWatchData from '@multicluster/hooks/useK8sWatchData';
2419
import { k8sDelete } from '@openshift-console/dynamic-plugin-sdk';
2520
import {
2621
Alert,
2722
AlertVariant,
23+
List,
24+
ListItem,
2825
Modal,
2926
ModalBody,
3027
Wizard,
3128
WizardHeader,
3229
WizardStep,
3330
} from '@patternfly/react-core';
31+
import useMigrationNamespacesPVCs from '@virtualmachines/actions/components/VirtualMachineMigration/hooks/useMigrationNamespacesPVCs';
32+
import VirtualMachineMigrationDestinationTab from '@virtualmachines/actions/components/VirtualMachineMigration/tabs/VirtualMachineMigrationDestinationTab';
33+
import VirtualMachineMigrationDetails from '@virtualmachines/actions/components/VirtualMachineMigration/tabs/VirtualMachineMigrationDetails';
34+
import VirtualMachineMigrationReviewTab from '@virtualmachines/actions/components/VirtualMachineMigration/tabs/VirtualMachineMigrationReviewTab';
3435

3536
import useCreateEmptyMigPlan from './hooks/useCreateEmptyMigPlan';
36-
import useExistingMigrationPlan from './hooks/useExistingMigrationPlan';
37+
import useExistingMigPlanConflicts from './hooks/useExistingMigPlanConflicts';
3738
import useMigrationState from './hooks/useMigrationState';
38-
import VirtualMachineMigrationDestinationTab from './tabs/VirtualMachineMigrationDestinationTab';
39-
import VirtualMachineMigrationDetails from './tabs/VirtualMachineMigrationDetails';
40-
import VirtualMachineMigrationReviewTab from './tabs/VirtualMachineMigrationReviewTab';
4139
import { entireVMSelected, getMigratableVMPVCs } from './utils/utils';
4240
import VirtualMachineMigrationStatus from './VirtualMachineMigrationStatus';
4341

@@ -55,36 +53,29 @@ const VirtualMachineMigrateModal: FC<VirtualMachineMigrateModalProps> = ({
5553
vms,
5654
}) => {
5755
const { t } = useKubevirtTranslation();
56+
const vmNamespaces = removeDuplicates(vms?.map((vm) => getNamespace(vm)));
5857

59-
const migrationNamespace = getNamespace(vms?.[0]);
6058
const cluster = getCluster(vms?.[0]);
6159
const [selectedStorageClass, setSelectedStorageClass] = useState('');
6260

6361
const [currentMigPlanCreation, migPlanCreationLoaded, migPlanCreationError] =
64-
useCreateEmptyMigPlan(migrationNamespace, cluster);
62+
useCreateEmptyMigPlan(vmNamespaces, cluster);
6563

66-
const [existingMigPlan, migrationPlansLoaded] = useExistingMigrationPlan(
64+
const { migPlansLoaded, namespaceConflicts } = useExistingMigPlanConflicts(
6765
currentMigPlanCreation,
68-
migrationNamespace,
66+
vmNamespaces,
6967
cluster,
7068
);
7169

7270
const [selectedPVCs, setSelectedPVCs] = useState<IoK8sApiCoreV1PersistentVolumeClaim[] | null>(
7371
null,
7472
);
7573

76-
const [namespacePVCs, loaded, loadingError] = useK8sWatchData<
77-
IoK8sApiCoreV1PersistentVolumeClaim[]
78-
>({
79-
cluster,
80-
groupVersionKind: modelToGroupVersionKind(PersistentVolumeClaimModel),
81-
isList: true,
82-
namespace: migrationNamespace,
83-
});
74+
const [pvcsInNamespaces, loaded, loadError] = useMigrationNamespacesPVCs(cluster, vmNamespaces);
8475

8576
const vmsPVCs = useMemo(
86-
() => vms.map((vm) => getMigratableVMPVCs(vm, namespacePVCs)).flat(),
87-
[vms, namespacePVCs],
77+
() => vms.map((vm) => getMigratableVMPVCs(vm, pvcsInNamespaces)).flat(),
78+
[vms, pvcsInNamespaces],
8879
);
8980

9081
const [{ clusterDefaultStorageClass, sortedStorageClasses }, scLoaded] =
@@ -108,7 +99,7 @@ const VirtualMachineMigrateModal: FC<VirtualMachineMigrateModalProps> = ({
10899
const { migMigration, migrationError, migrationLoading, migrationStarted, onSubmit } =
109100
useMigrationState(
110101
currentMigPlanCreation,
111-
namespacePVCs,
102+
pvcsInNamespaces,
112103
pvcsToMigrate,
113104
destinationStorageClass,
114105
);
@@ -130,7 +121,8 @@ const VirtualMachineMigrateModal: FC<VirtualMachineMigrateModalProps> = ({
130121
});
131122
}, [onClose, migrationStarted, currentMigPlanCreation]);
132123

133-
const disableForExistingMigPlan = !isEmpty(existingMigPlan) || !migrationPlansLoaded;
124+
const disableForExistingMigPlan = !isEmpty(namespaceConflicts) || !migPlansLoaded;
125+
134126
return (
135127
<Modal
136128
className="virtual-machine-migration-modal"
@@ -139,7 +131,7 @@ const VirtualMachineMigrateModal: FC<VirtualMachineMigrateModalProps> = ({
139131
variant="large"
140132
>
141133
<ModalBody>
142-
<StateHandler error={loadingError || migPlanCreationError} hasData loaded>
134+
<StateHandler error={loadError || migPlanCreationError} hasData loaded>
143135
{migrationStarted ? (
144136
<VirtualMachineMigrationStatus
145137
migMigration={migMigration}
@@ -170,11 +162,22 @@ const VirtualMachineMigrateModal: FC<VirtualMachineMigrateModalProps> = ({
170162
id="wizard-migration-details"
171163
name={t('Migration details')}
172164
>
173-
{!isEmpty(existingMigPlan) && (
165+
{!isEmpty(namespaceConflicts) && (
174166
<Alert
175-
title={t('An existing MigPlan for this namespace was found. ')}
167+
title={
168+
namespaceConflicts.length === 1
169+
? t('An existing MigPlan for this namespace was found. ')
170+
: t('An existing MigPlan for these namespaces was found.')
171+
}
176172
variant={AlertVariant.danger}
177173
>
174+
{namespaceConflicts.length > 1 && (
175+
<List className="pf-v6-u-my-sm">
176+
{namespaceConflicts.map((ns) => (
177+
<ListItem key={ns}>{ns}</ListItem>
178+
))}
179+
</List>
180+
)}
178181
<Trans ns="plugin__kubevirt-plugin" t={t}>
179182
Click{' '}
180183
<Link
@@ -188,7 +191,7 @@ const VirtualMachineMigrateModal: FC<VirtualMachineMigrateModalProps> = ({
188191
</Alert>
189192
)}
190193

191-
{isEmpty(existingMigPlan) && loaded && scLoaded && (
194+
{isEmpty(namespaceConflicts) && loaded && scLoaded && (
192195
<VirtualMachineMigrationDetails
193196
pvcs={vmsPVCs}
194197
selectedPVCs={selectedPVCs}

src/views/virtualmachines/actions/components/VirtualMachineMigration/VirtualMachineMigrationStatus.tsx

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,12 @@ import { Link } from 'react-router-dom-v5-compat';
44
import ErrorAlert from '@kubevirt-utils/components/ErrorAlert/ErrorAlert';
55
import { useKubevirtTranslation } from '@kubevirt-utils/hooks/useKubevirtTranslation';
66
import { modelToRef } from '@kubevirt-utils/models';
7+
import {
8+
DEFAULT_MIGRATION_NAMESPACE,
9+
MigMigration,
10+
MigMigrationStatuses,
11+
MigPlanModel,
12+
} from '@kubevirt-utils/resources/migrations/constants';
713
import { Timestamp } from '@openshift-console/dynamic-plugin-sdk';
814
import {
915
ActionList,
@@ -17,13 +23,6 @@ import {
1723
} from '@patternfly/react-core';
1824
import { CloseIcon } from '@patternfly/react-icons';
1925

20-
import {
21-
DEFAULT_MIGRATION_NAMESPACE,
22-
MigMigration,
23-
MigMigrationStatuses,
24-
MigPlanModel,
25-
} from '../../../../../utils/resources/migrations/constants';
26-
2726
import useProgressMigration from './hooks/useProgressMigration';
2827
import { getMigMigrationStatusLabel } from './utils/utils';
2928
import VirtualMachineMigrationRollback from './VirtualMachineMigrationRollback';

0 commit comments

Comments
 (0)