Can attach multiple ISOs to the same domain at the same time

This commit is contained in:
Pierre HUBERT 2023-12-08 17:12:19 +01:00
parent f05ae9fd52
commit 64eb90c0a4
4 changed files with 79 additions and 65 deletions

View File

@ -87,8 +87,8 @@ pub struct VMInfo {
pub number_vcpu: usize, pub number_vcpu: usize,
/// Enable VNC access through admin console /// Enable VNC access through admin console
pub vnc_access: bool, pub vnc_access: bool,
/// Attach an ISO file /// Attach ISO file(s)
pub iso_file: Option<String>, pub iso_files: Vec<String>,
/// Storage - https://access.redhat.com/documentation/fr-fr/red_hat_enterprise_linux/6/html/virtualization_administration_guide/sect-virtualization-virtualized_block_devices-adding_storage_devices_to_guests#sect-Virtualization-Adding_storage_devices_to_guests-Adding_file_based_storage_to_a_guest /// Storage - https://access.redhat.com/documentation/fr-fr/red_hat_enterprise_linux/6/html/virtualization_administration_guide/sect-virtualization-virtualized_block_devices-adding_storage_devices_to_guests#sect-Virtualization-Adding_storage_devices_to_guests-Adding_file_based_storage_to_a_guest
pub disks: Vec<Disk>, pub disks: Vec<Disk>,
/// Network cards /// Network cards
@ -133,7 +133,7 @@ impl VMInfo {
let mut disks = vec![]; let mut disks = vec![];
if let Some(iso_file) = &self.iso_file { for iso_file in &self.iso_files {
if !files_utils::check_file_name(iso_file) { if !files_utils::check_file_name(iso_file) {
return Err(StructureExtraction("ISO filename is invalid!").into()); return Err(StructureExtraction("ISO filename is invalid!").into());
} }
@ -156,12 +156,15 @@ impl VMInfo {
file: path.to_string_lossy().to_string(), file: path.to_string_lossy().to_string(),
}, },
target: DiskTargetXML { target: DiskTargetXML {
dev: "hdc".to_string(), dev: format!(
"hd{}",
["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l"][disks.len()]
),
bus: "usb".to_string(), bus: "usb".to_string(),
}, },
readonly: Some(DiskReadOnlyXML {}), readonly: Some(DiskReadOnlyXML {}),
boot: DiskBootXML { boot: DiskBootXML {
order: "1".to_string(), order: (disks.len() + 1).to_string(),
}, },
address: None, address: None,
}) })
@ -182,7 +185,7 @@ impl VMInfo {
// Check disks name for duplicates // Check disks name for duplicates
for disk in &self.disks { for disk in &self.disks {
if self.disks.iter().filter(|d| d.name == disk.name).count() > 1 { if self.disks.iter().filter(|d| d.name == disk.name).count() > 1 {
return Err(StructureExtraction("Two differents disks have the same name!").into()); return Err(StructureExtraction("Two different disks have the same name!").into());
} }
} }
@ -328,12 +331,13 @@ impl VMInfo {
number_vcpu: domain.vcpu.body, number_vcpu: domain.vcpu.body,
memory: convert_to_mb(&domain.memory.unit, domain.memory.memory)?, memory: convert_to_mb(&domain.memory.unit, domain.memory.memory)?,
vnc_access: domain.devices.graphics.is_some(), vnc_access: domain.devices.graphics.is_some(),
iso_file: domain iso_files: domain
.devices .devices
.disks .disks
.iter() .iter()
.find(|d| d.device == "cdrom") .filter(|d| d.device == "cdrom")
.map(|d| d.source.file.rsplit_once('/').unwrap().1.to_string()), .map(|d| d.source.file.rsplit_once('/').unwrap().1.to_string())
.collect(),
disks: domain disks: domain
.devices .devices

View File

@ -52,7 +52,7 @@ interface VMInfoInterface {
memory: number; memory: number;
number_vcpu: number; number_vcpu: number;
vnc_access: boolean; vnc_access: boolean;
iso_file?: string; iso_files: string[];
disks: VMDisk[]; disks: VMDisk[];
networks: VMNetInterface[]; networks: VMNetInterface[];
} }
@ -68,7 +68,7 @@ export class VMInfo implements VMInfoInterface {
number_vcpu: number; number_vcpu: number;
memory: number; memory: number;
vnc_access: boolean; vnc_access: boolean;
iso_file?: string; iso_files: string[];
disks: VMDisk[]; disks: VMDisk[];
networks: VMNetInterface[]; networks: VMNetInterface[];
@ -83,7 +83,7 @@ export class VMInfo implements VMInfoInterface {
this.number_vcpu = int.number_vcpu; this.number_vcpu = int.number_vcpu;
this.memory = int.memory; this.memory = int.memory;
this.vnc_access = int.vnc_access; this.vnc_access = int.vnc_access;
this.iso_file = int.iso_file; this.iso_files = int.iso_files;
this.disks = int.disks; this.disks = int.disks;
this.networks = int.networks; this.networks = int.networks;
} }
@ -96,6 +96,7 @@ export class VMInfo implements VMInfoInterface {
memory: 1024, memory: 1024,
number_vcpu: 1, number_vcpu: 1,
vnc_access: true, vnc_access: true,
iso_files: [],
disks: [], disks: [],
networks: [], networks: [],
}); });

View File

@ -16,59 +16,68 @@ import Icon from "@mdi/react";
export function VMSelectIsoInput(p: { export function VMSelectIsoInput(p: {
editable: boolean; editable: boolean;
isoList: IsoFile[]; isoList: IsoFile[];
value?: string; attachedISOs: string[];
onChange: (newVal?: string) => void; onChange: (newVal: string[]) => void;
}): React.ReactElement { }): React.ReactElement {
if (!p.value && !p.editable) return <></>; if (!p.attachedISOs && !p.editable) return <></>;
if (p.value) {
const iso = p.isoList.find((d) => d.filename === p.value);
return (
<ListItem
secondaryAction={
p.editable && (
<IconButton
edge="end"
aria-label="detach iso file"
onClick={() => {
p.onChange(undefined);
}}
>
<Tooltip title="Detach ISO file">
<DeleteIcon />
</Tooltip>
</IconButton>
)
}
>
<ListItemAvatar>
<Avatar>
<Icon path={mdiDisc} />
</Avatar>
</ListItemAvatar>
<ListItemText
primary={iso?.filename}
secondary={filesize(iso?.size ?? 0)}
/>
</ListItem>
);
}
return ( return (
<SelectInput <>
label="ISO file" <SelectInput
editable={p.editable} label="Attach an ISO file"
value={p.value} editable={p.editable}
onValueChange={p.onChange} value={undefined}
options={[ onValueChange={(v) => {
{ label: "None", value: undefined }, if (v) {
...p.isoList.map((i) => { p.attachedISOs.push(v);
return { p.onChange(p.attachedISOs);
label: `${i.filename} ${filesize(i.size)}`, }
value: i.filename, }}
}; options={[
}), { label: "None", value: undefined },
]} ...p.isoList.map((i) => {
/> return {
label: `${i.filename} ${filesize(i.size)}`,
value: i.filename,
};
}),
]}
/>
{p.attachedISOs.map((isoName, num) => {
const iso = p.isoList.find((d) => d.filename === isoName);
return (
<ListItem
key={num}
secondaryAction={
p.editable && (
<IconButton
edge="end"
aria-label="Detach iso file"
onClick={() => {
p.attachedISOs.splice(num, 1);
p.onChange(p.attachedISOs);
}}
>
<Tooltip title="Detach ISO file">
<DeleteIcon />
</Tooltip>
</IconButton>
)
}
>
<ListItemAvatar>
<Avatar>
<Icon path={mdiDisc} />
</Avatar>
</ListItemAvatar>
<ListItemText
primary={iso?.filename}
secondary={filesize(iso?.size ?? 0)}
/>
</ListItem>
);
})}
</>
); );
} }

View File

@ -203,9 +203,9 @@ function VMDetailsInner(
<VMSelectIsoInput <VMSelectIsoInput
editable={p.editable} editable={p.editable}
isoList={p.isoList} isoList={p.isoList}
value={p.vm.iso_file} attachedISOs={p.vm.iso_files}
onChange={(v) => { onChange={(v) => {
p.vm.iso_file = v; p.vm.iso_files = v;
p.onChange?.(); p.onChange?.();
}} }}
/> />