Can attach multiple ISOs to the same domain at the same time
This commit is contained in:
		@@ -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
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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: [],
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -16,22 +16,47 @@ 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) {
 | 
					  return (
 | 
				
			||||||
    const iso = p.isoList.find((d) => d.filename === p.value);
 | 
					    <>
 | 
				
			||||||
 | 
					      <SelectInput
 | 
				
			||||||
 | 
					        label="Attach an ISO file"
 | 
				
			||||||
 | 
					        editable={p.editable}
 | 
				
			||||||
 | 
					        value={undefined}
 | 
				
			||||||
 | 
					        onValueChange={(v) => {
 | 
				
			||||||
 | 
					          if (v) {
 | 
				
			||||||
 | 
					            p.attachedISOs.push(v);
 | 
				
			||||||
 | 
					            p.onChange(p.attachedISOs);
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        }}
 | 
				
			||||||
 | 
					        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 (
 | 
					        return (
 | 
				
			||||||
          <ListItem
 | 
					          <ListItem
 | 
				
			||||||
 | 
					            key={num}
 | 
				
			||||||
            secondaryAction={
 | 
					            secondaryAction={
 | 
				
			||||||
              p.editable && (
 | 
					              p.editable && (
 | 
				
			||||||
                <IconButton
 | 
					                <IconButton
 | 
				
			||||||
                  edge="end"
 | 
					                  edge="end"
 | 
				
			||||||
              aria-label="detach iso file"
 | 
					                  aria-label="Detach iso file"
 | 
				
			||||||
                  onClick={() => {
 | 
					                  onClick={() => {
 | 
				
			||||||
                p.onChange(undefined);
 | 
					                    p.attachedISOs.splice(num, 1);
 | 
				
			||||||
 | 
					                    p.onChange(p.attachedISOs);
 | 
				
			||||||
                  }}
 | 
					                  }}
 | 
				
			||||||
                >
 | 
					                >
 | 
				
			||||||
                  <Tooltip title="Detach ISO file">
 | 
					                  <Tooltip title="Detach ISO file">
 | 
				
			||||||
@@ -52,23 +77,7 @@ export function VMSelectIsoInput(p: {
 | 
				
			|||||||
            />
 | 
					            />
 | 
				
			||||||
          </ListItem>
 | 
					          </ListItem>
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
  }
 | 
					      })}
 | 
				
			||||||
 | 
					    </>
 | 
				
			||||||
  return (
 | 
					 | 
				
			||||||
    <SelectInput
 | 
					 | 
				
			||||||
      label="ISO file"
 | 
					 | 
				
			||||||
      editable={p.editable}
 | 
					 | 
				
			||||||
      value={p.value}
 | 
					 | 
				
			||||||
      onValueChange={p.onChange}
 | 
					 | 
				
			||||||
      options={[
 | 
					 | 
				
			||||||
        { label: "None", value: undefined },
 | 
					 | 
				
			||||||
        ...p.isoList.map((i) => {
 | 
					 | 
				
			||||||
          return {
 | 
					 | 
				
			||||||
            label: `${i.filename} ${filesize(i.size)}`,
 | 
					 | 
				
			||||||
            value: i.filename,
 | 
					 | 
				
			||||||
          };
 | 
					 | 
				
			||||||
        }),
 | 
					 | 
				
			||||||
      ]}
 | 
					 | 
				
			||||||
    />
 | 
					 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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?.();
 | 
				
			||||||
          }}
 | 
					          }}
 | 
				
			||||||
        />
 | 
					        />
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user