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

🐾 Add a plan details item to edit boot disk #1205

Merged
merged 1 commit into from
Jun 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,13 @@
"Assessment": "Assessment",
"Authentication type": "Authentication type",
"Bandwidth": "Bandwidth",
"Boot from first root device": "Boot from first root device",
"Boot from the first hard drive": "Boot from the first hard drive",
"Boot from the first partition on the first hard drive": "Boot from the first partition on the first hard drive",
"Boot from the first partition on the second hard drive": "Boot from the first partition on the second hard drive",
"Boot from the second hard drive": "Boot from the second hard drive",
"Boot from the second partition on the first hard drive": "Boot from the second partition on the first hard drive",
"Boot from the second partition on the second hard drive": "Boot from the second partition on the second hard drive",
"CA certificate": "CA certificate",
"CA certificate - disabled when 'Skip certificate validation' is selected": "CA certificate - disabled when 'Skip certificate validation' is selected",
"CA certificate - leave empty to use system CA certificates": "CA certificate - leave empty to use system CA certificates",
Expand All @@ -60,6 +67,7 @@
"Cannot retrieve certificate": "Cannot retrieve certificate",
"Category": "Category",
"Certificate change detected": "Certificate change detected",
"Choose the root filesystem to be converted.": "Choose the root filesystem to be converted.",
"Clear all filters": "Clear all filters",
"Click the pencil for setting provider web UI link": "Click the pencil for setting provider web UI link",
"Click the update credentials button to save your changes, button is disabled until a change is detected.": "Click the update credentials button to save your changes, button is disabled until a change is detected.",
Expand Down Expand Up @@ -142,6 +150,7 @@
"Edit Provider Credentials": "Edit Provider Credentials",
"Edit provider credentials.\n Use this link to edit the providers credentials instead of editing the secret directly.": "Edit provider credentials.\n Use this link to edit the providers credentials instead of editing the secret directly.",
"Edit provider web UI link": "Edit provider web UI link",
"Edit root device": "Edit root device",
"Edit Snapshot polling interval (seconds)": "Edit Snapshot polling interval (seconds)",
"Edit StorageMap": "Edit StorageMap",
"Edit target namespace": "Edit target namespace",
Expand Down Expand Up @@ -179,6 +188,7 @@
"Filter by template": "Filter by template",
"Filter by tenant": "Filter by tenant",
"Filter provider": "Filter provider",
"First root device": "First root device",
"Flavor": "Flavor",
"Folder": "Folder",
"GPUs/Host Devices": "GPUs/Host Devices",
Expand Down Expand Up @@ -382,6 +392,7 @@
"Restore default columns": "Restore default columns",
"Return to the providers list page": "Return to the providers list page",
"Reveal values": "Reveal values",
"Root device": "Root device",
"Run the migration plan.": "Run the migration plan.",
"Running": "Running",
"Running virtual machines": "Running virtual machines",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -147,4 +147,8 @@
.forklift-page-plan-resources-td-fractional {
text-align: left;
display: inline-block;
}
}

.forklift-page-plan-settings-icon {
padding-right: var(--pf-global--spacer--sm);
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { DescriptionList } from '@patternfly/react-core';
import {
PreserveClusterCpuModelDetailsItem,
PreserveStaticIPsDetailsItem,
RootDiskDetailsItem,
SetLUKSEncryptionPasswordsDetailsItem,
TargetNamespaceDetailsItem,
TransferNetworkDetailsItem,
Expand Down Expand Up @@ -75,6 +76,10 @@ export const SettingsSectionInternal: React.FC<SettingsSectionProps> = ({ obj, p
{['vsphere'].includes(sourceProvider?.spec?.type) && (
<SetLUKSEncryptionPasswordsDetailsItem resource={obj} canPatch={permissions.canPatch} />
)}

{['vsphere'].includes(sourceProvider?.spec?.type) && (
<RootDiskDetailsItem resource={obj} canPatch={permissions.canPatch} />
)}
</DescriptionList>
</>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import React from 'react';
import { useModal } from 'src/modules/Providers/modals';
import { DetailsItem } from 'src/modules/Providers/utils';
import { useForkliftTranslation } from 'src/utils/i18n';

import { Label, Tooltip } from '@patternfly/react-core';
import { ExclamationTriangleIcon } from '@patternfly/react-icons';

import { PlanDetailsItemProps } from '../../DetailsSection';
import { VIRT_V2V_HELP_LINK } from '../modals';
import { getRootDiskLabelByKey } from '../modals/EditRootDisk';
import { EditRootDisk } from '../modals/EditRootDisk/EditRootDisk';

export const RootDiskDetailsItem: React.FC<PlanDetailsItemProps> = ({
resource,
canPatch,
helpContent,
}) => {
const { t } = useForkliftTranslation();
const { showModal } = useModal();

const defaultHelpContent = t(`Choose the root filesystem to be converted.`);

const rootDisk = resource?.spec?.vms?.[0].rootDisk;

return (
<DetailsItem
title={t('Root device')}
content={getDiskLabel(rootDisk)}
helpContent={helpContent ?? defaultHelpContent}
moreInfoLink={VIRT_V2V_HELP_LINK}
crumbs={['spec', 'vms', 'rootDisk']}
onEdit={canPatch && (() => showModal(<EditRootDisk resource={resource} />))}
/>
);
};

/**
* Generates a label component for the given disk key.
* @param {string} diskKey - The key representing the disk option.
* @returns {JSX.Element} The label component for the disk.
*/
const getDiskLabel = (diskKey: string) => {
const diskLabel = getRootDiskLabelByKey(diskKey);

// First boot disk, color green
if (!diskKey) {
return (
<Label isCompact color={'green'}>
{diskLabel}
</Label>
);
}

// Known boot disk format, color grey.
if (diskKey.startsWith('/dev/sd')) {
return (
<Label isCompact color={'grey'}>
{diskLabel}
</Label>
);
}

// Unknown boot disk format.
return (
<Tooltip
content={
'Root filesystem format should start with "/dev/sd[X]", see documentation for more information.'
}
>
<Label isCompact color={'orange'}>
<span className="forklift-page-plan-settings-icon">
<ExclamationTriangleIcon color="orange" />
</span>
{diskLabel}
</Label>
</Tooltip>
);
};
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// @index(['./*', /style/g], f => `export * from '${f.path}';`)
export * from './PreserveClusterCpuModelDetailsItem';
export * from './PreserveStaticIPsDetailsItem';
export * from './RootDiskDetailsItem';
export * from './SetLUKSEncryptionPasswordsDetailsItem';
export * from './TargetNamespaceDetailsItem';
export * from './TransferNetworkDetailsItem';
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
import React from 'react';
import { FilterableSelect } from 'src/components/FilterableSelect/FilterableSelect';
import {
EditModal,
EditModalProps,
ModalInputComponentType,
OnConfirmHookType,
} from 'src/modules/Providers/modals';
import { useForkliftTranslation } from 'src/utils/i18n';

import { Modify, PlanModel, V1beta1Plan } from '@kubev2v/types';
import { K8sModel, k8sPatch } from '@openshift-console/dynamic-plugin-sdk';
import { HelperText, HelperTextItem, Text } from '@patternfly/react-core';

import { editRootDiskModalAlert } from './editRootDiskModalAlert';
import { editRootDiskModalBody } from './editRootDiskModalBody';
import { diskOptions, getRootDiskLabelByKey } from './getRootDiskLabelByKey';

const onConfirm: OnConfirmHookType = async ({ resource, model, newValue }) => {
const plan = resource as V1beta1Plan;

const resourceValue = plan?.spec?.vms;
const op = resourceValue ? 'replace' : 'add';
const newVMs = resourceValue.map((vm) => ({
...vm,
rootDisk: newValue || undefined,
}));

const obj = await k8sPatch({
model: model,
resource: resource,
data: [
{
op,
path: '/spec/vms',
value: newVMs || undefined,
},
],
});

return obj;
};

interface DropdownRendererProps {
value: string | number;
onChange: (string) => void;
}

const RootDiskInputFactory: () => ModalInputComponentType = () => {
const DropdownRenderer: React.FC<DropdownRendererProps> = ({ value, onChange }) => {
const { t } = useForkliftTranslation();
const options = diskOptions(t);

const dropdownItems = options.map((option) => ({
itemId: option.key,
children: (
<>
<Text>{getRootDiskLabelByKey(option.key)}</Text>
{option.description && (
<HelperText>
<HelperTextItem variant="indeterminate">{option.description}</HelperTextItem>
</HelperText>
)}
</>
),
}));

return (
<FilterableSelect
selectOptions={dropdownItems}
value={value as string}
onSelect={onChange}
canCreate
placeholder={t('First root device')}
></FilterableSelect>
);
};

return DropdownRenderer;
};

export const EditRootDisk: React.FC<EditRootDiskProps> = (props) => {
const { t } = useForkliftTranslation();

const plan = props.resource;
const rootDisk = plan.spec.vms?.[0]?.rootDisk;
const allVMsHasMatchingRootDisk = plan.spec.vms.every((vm) => vm?.rootDisk === rootDisk);

return (
<EditModal
{...props}
jsonPath={(obj: V1beta1Plan) => obj?.spec?.vms?.[0]?.rootDisk}
title={props?.title || t('Edit root device')}
label={props?.label || t('Root device')}
model={PlanModel}
onConfirmHook={onConfirm}
body={
<>
{editRootDiskModalBody}
{!allVMsHasMatchingRootDisk && editRootDiskModalAlert}
</>
}
InputComponent={RootDiskInputFactory()}
/>
);
};

export type EditRootDiskProps = Modify<
EditModalProps,
{
resource: V1beta1Plan;
title?: string;
label?: string;
model?: K8sModel;
jsonPath?: string | string[];
}
>;
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import React from 'react';
import { AlertMessageForModals } from 'src/modules/Providers/modals';

export const editRootDiskModalAlert = (
<AlertMessageForModals
variant="warning"
title={'The plan rootDisk keys was manually configured'}
message={
<>
<p>Warning: not all virtual machines are configures using the same root disk number,</p>
<p>updating the root disk number will override the current configuration.</p>
</>
}
/>
);
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import React from 'react';
import { ForkliftTrans } from 'src/utils';

import { ExternalLink } from '@kubev2v/common';

import { VIRT_V2V_HELP_LINK } from '../EditLUKSEncryptionPasswords';

export const editRootDiskModalBody = (
<>
<ForkliftTrans>
<p>Choose the root filesystem to be converted.</p>
<br />
<p>
Default behavior is to choose the first root device in the case of a multi-boot operating
system. Since this is a heuristic, it may sometimes choose the wrong one.
</p>
<br />
<p>
When using a multi-boot VM, you can also name a specific root device, eg.{' '}
<strong>/dev/sda2</strong> would mean to use the second partition on the first hard drive.
If the named root device does not exist or was not detected as a root device, the migration
will fail.{' '}
<ExternalLink isInline href={VIRT_V2V_HELP_LINK}>
Learn more
</ExternalLink>
.
</p>
</ForkliftTrans>
</>
);
Loading