Skip to content

Commit

Permalink
Bug 1786068, 1786070, 1786091: Fixes kubevirt cdrom bugs
Browse files Browse the repository at this point in the history
  • Loading branch information
glekner committed Jan 13, 2020
1 parent 61f72ff commit 569ba0d
Show file tree
Hide file tree
Showing 4 changed files with 110 additions and 163 deletions.
Expand Up @@ -11,7 +11,6 @@ import { PlusCircleIcon, OutlinedQuestionCircleIcon } from '@patternfly/react-ic
import { k8sPatch } from '@console/internal/module/k8s';
import { ModalFooter } from '../modal/modal-footer';
import { getCDsPatch } from '../../../k8s/patches/vm/vm-cdrom-patches';
import { getRemoveDiskPatches } from '../../../k8s/patches/vm/vm-disk-patches';
import { getVMLikeModel, asVM, isWindows } from '../../../selectors/vm';
import {
getCDRoms,
Expand Down Expand Up @@ -52,7 +51,6 @@ export const CDRomModal = withHandlePromise((props: CDRomModalProps) => {
name,
cdrom,
bootOrder,
isInVM: true,
};
const container = getContainerImageByDisk(vm, name);
if (container) {
Expand Down Expand Up @@ -88,10 +86,12 @@ export const CDRomModal = withHandlePromise((props: CDRomModalProps) => {

const [cds, setCDs] = React.useState<CDMap>(mapCDsToSource(getCDRoms(vm)));
const [showRestartAlert, setShowRestartAlert] = React.useState<boolean>(false);
const [shouldPatch, setShouldPatch] = React.useState<boolean>(false);

const onCDChange = (cdName: string, key: string, value: string) => {
setShowRestartAlert(true);
const cd = { ...cds[cdName], [key]: value, changed: true };
setShouldPatch(true);
const cd = { ...cds[cdName], [key]: value };
if (key === StorageType.URL) {
if (isValidationError(validateURL(value))) {
cd.isURLValid = false;
Expand All @@ -108,33 +108,21 @@ export const CDRomModal = withHandlePromise((props: CDRomModalProps) => {
...initialDisk,
type: StorageType.CONTAINER,
name,
isInVM: false,
changed: true,
newCD: true,
};
setShowRestartAlert(true);
setShouldPatch(true);
setCDs({ ...cds, [name]: newCD });
};

const onCDEject = (cdName: string) =>
setCDs({ ...cds, [cdName]: { ...cds[cdName], ejected: true } });

const onCDDelete = (cdName: string) => {
if (cds[cdName].isInVM) {
const patch = getRemoveDiskPatches(vmLikeEntity, cds[cdName]);
const promise = k8sPatch(getVMLikeModel(vmLikeEntity), vmLikeEntity, patch);
// eslint-disable-next-line promise/catch-or-return
handlePromise(promise).then(() => {
setCDs(_.omit(cds, cdName));
setShowRestartAlert(true);
});
} else {
setCDs(_.omit(cds, cdName));
}
setShouldPatch(true);
setCDs(_.omit(cds, cdName));
};

const submit = async (e) => {
e.preventDefault();
if (Object.values(cds).find((cd) => cd.changed)) {
if (shouldPatch) {
const patch = await getCDsPatch(vmLikeEntity, Object.values(cds));
const promise = k8sPatch(getVMLikeModel(vmLikeEntity), vmLikeEntity, patch);
handlePromise(promise).then(close); // eslint-disable-line promise/catch-or-return
Expand Down Expand Up @@ -178,7 +166,6 @@ export const CDRomModal = withHandlePromise((props: CDRomModalProps) => {
inProgress={inProgress}
onChange={onCDChange}
onDelete={onCDDelete}
onEject={onCDEject}
/>
))
) : (
Expand All @@ -200,6 +187,8 @@ export const CDRomModal = withHandlePromise((props: CDRomModalProps) => {
{_.size(cds) > 1 && (
<Tooltip
position="bottom"
trigger="click mouseenter"
entryDelay={0}
content="You have reached the maximum amount of CD-ROM drives"
>
<OutlinedQuestionCircleIcon />
Expand Down
Expand Up @@ -10,14 +10,13 @@ import {
FormSelectOption,
TextInput,
Button,
InputGroup,
} from '@patternfly/react-core';
import { PersistentVolumeClaimModel, StorageClassModel } from '@console/internal/models';
import { FirehoseResult } from '@console/internal/components/utils';
import { K8sResourceSelectRow } from '../../form/k8s-resource-select-row';
import { VMKind } from '../../../types';
import { FormSelectPlaceholderOption } from '../../form/form-select-placeholder-option';
import { StorageType, sourceDict, CD, CD_SIZE, CD_STORAGE_CLASS } from './constants';
import { StorageType, CD, CD_SIZE, CD_STORAGE_CLASS } from './constants';

export const CDRomRow: React.FC<CDRomRowProps> = ({
cd,
Expand All @@ -26,47 +25,12 @@ export const CDRomRow: React.FC<CDRomRowProps> = ({
storageClasses,
index,
onChange,
onEject,
onDelete,
isWindows,
inProgress,
winToolsContainer,
}) => {
const {
name,
type,
container,
pvc,
url,
windowsTools,
size,
storageClass,
isURLValid,
ejected,
isInVM,
} = cd;

if (isInVM && !ejected)
return (
<div>
<Text component={TextVariants.h4}>{`Drive ${index + 1}: ${sourceDict[type]}`}</Text>
<InputGroup>
<TextInput
isDisabled
type="text"
id={`cdrom-value-${name}`}
value={cd[type]}
aria-label="cdrom-value"
/>
<Button className="vm-cd-eject-btn" variant="secondary" onClick={() => onEject(name)}>
Eject CD-ROM
</Button>
<Button className="vm-cd-delete-btn" onClick={() => onDelete(name)} variant="plain">
<MinusCircleIcon />
</Button>
</InputGroup>
</div>
);
const { name, type, container, pvc, url, windowsTools, size, storageClass, isURLValid } = cd;

return (
<div>
Expand Down Expand Up @@ -210,7 +174,6 @@ export type CDRomRowProps = {
usedPVCs: string[];
index: number;
onChange: (cdName: string, key: string, value: string) => void;
onEject: (cdName: any) => void;
onDelete: (cdName: any) => void;
isWindows: boolean;
inProgress: boolean;
Expand Down
Expand Up @@ -7,8 +7,7 @@ export type CD = {

// UI
changed?: boolean;
ejected?: boolean;
isInVM?: boolean;
newCD?: boolean;
pvc?: string;
container?: string;
type?: string;
Expand Down Expand Up @@ -44,13 +43,6 @@ export const initialDisk = {
changed: false,
};

export const sourceDict = {
container: 'Container',
url: 'URL',
pvc: 'PVC',
windowsTools: 'Windows Tools',
};

export const StorageType = {
WINTOOLS: 'windowsTools',
CONTAINER: 'container',
Expand Down
Expand Up @@ -40,112 +40,115 @@ const assignBootOrderIndex = (vm: VMLikeEntityKind, currDevBootOrder = -1) => {

export const getCDsPatch = async (vm: VMLikeEntityKind, cds: CD[]) => {
let newBootOrder = assignBootOrderIndex(asVM(vm));
let DISKS = getDisks(asVM(vm));
let VOLS = getVolumes(asVM(vm));
let DATATEMPLATES = getDataVolumeTemplates(asVM(vm));
const storageClassConfigMap = await getStorageClassConfigMap({ k8sGet });

cds
.filter((cd) => cd.changed)
.forEach(
({ name, pvc, type, bootOrder, bus, container, windowsTools, url, storageClass, size }) => {
const existingCD = !!bootOrder;
let DISKS = getDisks(asVM(vm)).filter(
(disk) => !disk.cdrom || cds.find((modalCD) => disk.name === modalCD.name || modalCD.newCD),
);
let VOLS = getVolumes(asVM(vm)).filter((v) => DISKS.find((disk) => v.name === disk.name));
let DATATEMPLATES = getDataVolumeTemplates(asVM(vm)).filter((dataVol) =>
VOLS.find((vol) => getVolumeDataVolumeName(vol) === getName(dataVol)),
);
const storageClassConfigMap = await getStorageClassConfigMap({ k8sGet });

const disk: CD = {
cds.forEach(
({ name, pvc, type, bootOrder, bus, container, windowsTools, url, storageClass, size }) => {
const existingCD = !!bootOrder;

const disk: CD = {
name,
bootOrder: existingCD ? bootOrder : newBootOrder,
cdrom: { bus: bus || 'virtio' },
};
let volume: Volume = { name };
let finalDataVolume;

// Patches
if (type === StorageType.PVC) {
volume = {
persistentVolumeClaim: {
claimName: pvc,
},
name,
bootOrder: existingCD ? bootOrder : newBootOrder,
cdrom: { bus: bus || 'virtio' },
};
let volume: Volume = { name };
let finalDataVolume;

// Patches
if (type === StorageType.PVC) {
volume = {
persistentVolumeClaim: {
claimName: pvc,
},
name,
};
}

if (type === StorageType.URL) {
const newDataVolume = {
metadata: {
name: `${getName(vm)}-${name}`,
},
spec: {
pvc: {
accessModes: undefined,
volumeMode: undefined,
resources: {
requests: {
storage: `${size}Gi`,
},
}

if (type === StorageType.URL) {
const newDataVolume = {
metadata: {
name: `${getName(vm)}-${name}`,
},
spec: {
pvc: {
accessModes: undefined,
volumeMode: undefined,
resources: {
requests: {
storage: `${size}Gi`,
},
storageClassName: storageClass,
},
source: { http: { url } },
},
};

const dataVolumeWrapper = DataVolumeWrapper.initialize(newDataVolume);
const storageClassName = dataVolumeWrapper.getStorageClassName();

finalDataVolume = DataVolumeWrapper.mergeWrappers(
DataVolumeWrapper.initializeFromSimpleData({
accessModes: [getDefaultSCAccessMode(storageClassConfigMap, storageClassName)],
volumeMode: getDefaultSCVolumeMode(storageClassConfigMap, storageClassName),
}),
dataVolumeWrapper,
).asResource();

volume = {
name,
dataVolume: {
name: `${getName(vm)}-${name}`,
storageClassName: storageClass,
},
};
}
if (type === StorageType.CONTAINER) {
volume = { name, containerDisk: { image: container } };
}
if (type === StorageType.WINTOOLS) {
volume = { name, containerDisk: { image: windowsTools } };
}

const restOfDisks = DISKS.filter((vol) => vol.name !== name);
const restOfVolumes = VOLS.filter((vol) => vol.name !== name);

let restOfDataTemplates = DATATEMPLATES;
if (type !== StorageType.CONTAINER && VOLS.filter((vol) => !!vol.dataVolume).length > 0) {
const isDataVolume = VOLS.find((vol) => vol.name === name);
if (isDataVolume) {
restOfDataTemplates = DATATEMPLATES.filter(
(vol) => vol.metadata.name !== getVolumeDataVolumeName(isDataVolume),
);
}
}
source: { http: { url } },
},
};

DISKS = [...restOfDisks, disk];
VOLS = [...restOfVolumes, volume];
DATATEMPLATES = restOfDataTemplates;
const dataVolumeWrapper = DataVolumeWrapper.initialize(newDataVolume);
const storageClassName = dataVolumeWrapper.getStorageClassName();

if (finalDataVolume) {
DATATEMPLATES = [...restOfDataTemplates, finalDataVolume];
}
finalDataVolume = DataVolumeWrapper.mergeWrappers(
DataVolumeWrapper.initializeFromSimpleData({
accessModes: [getDefaultSCAccessMode(storageClassConfigMap, storageClassName)],
volumeMode: getDefaultSCVolumeMode(storageClassConfigMap, storageClassName),
}),
dataVolumeWrapper,
).asResource();

if (type !== StorageType.URL) {
// remove unnecessary dataVolumeTemplates
DATATEMPLATES = DATATEMPLATES.filter((dataVol) =>
includes(VOLS.map((vol) => getVolumeDataVolumeName(vol)), dataVol.metadata.name),
volume = {
name,
dataVolume: {
name: `${getName(vm)}-${name}`,
},
};
}
if (type === StorageType.CONTAINER) {
volume = { name, containerDisk: { image: container } };
}
if (type === StorageType.WINTOOLS) {
volume = { name, containerDisk: { image: windowsTools } };
}

const restOfDisks = DISKS.filter((vol) => vol.name !== name);
const restOfVolumes = VOLS.filter((vol) => vol.name !== name);

let restOfDataTemplates = DATATEMPLATES;
if (type !== StorageType.CONTAINER && VOLS.filter((vol) => !!vol.dataVolume).length > 0) {
const isDataVolume = VOLS.find((vol) => vol.name === name);
if (isDataVolume) {
restOfDataTemplates = DATATEMPLATES.filter(
(vol) => vol.metadata.name !== getVolumeDataVolumeName(isDataVolume),
);
}
if (!existingCD) {
newBootOrder++;
}
},
);
}

DISKS = [...restOfDisks, disk];
VOLS = [...restOfVolumes, volume];
DATATEMPLATES = restOfDataTemplates;

if (finalDataVolume) {
DATATEMPLATES = [...restOfDataTemplates, finalDataVolume];
}

if (type !== StorageType.URL) {
// remove unnecessary dataVolumeTemplates
DATATEMPLATES = DATATEMPLATES.filter((dataVol) =>
includes(VOLS.map((vol) => getVolumeDataVolumeName(vol)), dataVol.metadata.name),
);
}
if (!existingCD) {
newBootOrder++;
}
},
);

const patches = [
new PatchBuilder('/spec/template/spec/domain/devices/disks')
Expand Down

0 comments on commit 569ba0d

Please sign in to comment.