Managed to insert an ISO file
This commit is contained in:
parent
b007826710
commit
d93a2b857a
@ -60,8 +60,13 @@ pub struct ACPIXML {}
|
||||
#[derive(serde::Serialize, serde::Deserialize)]
|
||||
#[serde(rename = "devices")]
|
||||
pub struct DevicesXML {
|
||||
/// Graphics (used for VNC
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub graphics: Option<GraphicsXML>,
|
||||
|
||||
/// Disks (used for storage)
|
||||
#[serde(default, rename = "disk")]
|
||||
pub disks: Option<DiskXML>, // TODO : change to vec
|
||||
}
|
||||
|
||||
/// Screen information
|
||||
@ -74,6 +79,74 @@ pub struct GraphicsXML {
|
||||
pub socket: String,
|
||||
}
|
||||
|
||||
/// Disk information
|
||||
#[derive(serde::Serialize, serde::Deserialize)]
|
||||
#[serde(rename = "disk")]
|
||||
pub struct DiskXML {
|
||||
#[serde(rename(serialize = "@type"))]
|
||||
pub r#type: String,
|
||||
#[serde(rename(serialize = "@device"))]
|
||||
pub r#device: String,
|
||||
|
||||
pub driver: DiskDriverXML,
|
||||
pub source: DiskSourceXML,
|
||||
pub target: DiskTargetXML,
|
||||
pub readonly: DiskReadOnlyXML,
|
||||
pub boot: DiskBootXML,
|
||||
pub address: DiskAddressXML,
|
||||
}
|
||||
|
||||
#[derive(serde::Serialize, serde::Deserialize)]
|
||||
#[serde(rename = "driver")]
|
||||
pub struct DiskDriverXML {
|
||||
#[serde(rename(serialize = "@name"))]
|
||||
pub name: String,
|
||||
#[serde(rename(serialize = "@type"))]
|
||||
pub r#type: String,
|
||||
}
|
||||
|
||||
#[derive(serde::Serialize, serde::Deserialize)]
|
||||
#[serde(rename = "source")]
|
||||
pub struct DiskSourceXML {
|
||||
#[serde(rename(serialize = "@file"))]
|
||||
pub file: String,
|
||||
}
|
||||
|
||||
#[derive(serde::Serialize, serde::Deserialize)]
|
||||
#[serde(rename = "target")]
|
||||
pub struct DiskTargetXML {
|
||||
#[serde(rename(serialize = "@dev"))]
|
||||
pub dev: String,
|
||||
#[serde(rename(serialize = "@bus"))]
|
||||
pub bus: String,
|
||||
}
|
||||
|
||||
#[derive(serde::Serialize, serde::Deserialize)]
|
||||
#[serde(rename = "readonly")]
|
||||
pub struct DiskReadOnlyXML {}
|
||||
|
||||
#[derive(serde::Serialize, serde::Deserialize)]
|
||||
#[serde(rename = "boot")]
|
||||
pub struct DiskBootXML {
|
||||
#[serde(rename(serialize = "@order"))]
|
||||
pub order: String,
|
||||
}
|
||||
|
||||
#[derive(serde::Serialize, serde::Deserialize)]
|
||||
#[serde(rename = "address")]
|
||||
pub struct DiskAddressXML {
|
||||
#[serde(rename(serialize = "@type"))]
|
||||
pub r#type: String,
|
||||
#[serde(rename(serialize = "@controller"))]
|
||||
pub r#controller: String,
|
||||
#[serde(rename(serialize = "@bus"))]
|
||||
pub r#bus: String,
|
||||
#[serde(rename(serialize = "@target"))]
|
||||
pub r#target: String,
|
||||
#[serde(rename(serialize = "@unit"))]
|
||||
pub r#unit: String,
|
||||
}
|
||||
|
||||
/// Domain RAM information
|
||||
#[derive(serde::Serialize, serde::Deserialize)]
|
||||
#[serde(rename = "memory")]
|
||||
|
@ -1,10 +1,12 @@
|
||||
use crate::app_config::AppConfig;
|
||||
use crate::constants;
|
||||
use crate::libvirt_lib_structures::{
|
||||
DevicesXML, DomainMemoryXML, DomainXML, DomainXMLUuid, FeaturesXML, GraphicsXML, OSLoaderXML,
|
||||
OSTypeXML, ACPIXML, OSXML,
|
||||
DevicesXML, DiskAddressXML, DiskBootXML, DiskDriverXML, DiskReadOnlyXML, DiskSourceXML,
|
||||
DiskTargetXML, DiskXML, DomainMemoryXML, DomainXML, DomainXMLUuid, FeaturesXML, GraphicsXML,
|
||||
OSLoaderXML, OSTypeXML, ACPIXML, OSXML,
|
||||
};
|
||||
use crate::libvirt_rest_structures::LibVirtStructError::StructureExtraction;
|
||||
use crate::utils::files_utils;
|
||||
use lazy_regex::regex;
|
||||
use std::ops::{Div, Mul};
|
||||
|
||||
@ -70,8 +72,9 @@ pub struct VMInfo {
|
||||
pub memory: usize,
|
||||
/// Enable VNC access through admin console
|
||||
pub vnc_access: bool,
|
||||
/// Attach an ISO file
|
||||
pub iso_file: Option<String>,
|
||||
// TODO : storage
|
||||
// TODO : iso
|
||||
// TODO : autostart
|
||||
// TODO : network interface
|
||||
}
|
||||
@ -105,6 +108,47 @@ impl VMInfo {
|
||||
return Err(StructureExtraction("VM memory is invalid!").into());
|
||||
}
|
||||
|
||||
let mut disks = vec![];
|
||||
|
||||
if let Some(iso_file) = &self.iso_file {
|
||||
if !files_utils::check_file_name(iso_file) {
|
||||
return Err(StructureExtraction("ISO filename is invalid!").into());
|
||||
}
|
||||
|
||||
let path = AppConfig::get().iso_storage_path().join(iso_file);
|
||||
|
||||
if !path.exists() {
|
||||
return Err(StructureExtraction("Specified ISO file does not exists!").into());
|
||||
}
|
||||
|
||||
disks.push(DiskXML {
|
||||
r#type: "file".to_string(),
|
||||
device: "cdrom".to_string(),
|
||||
driver: DiskDriverXML {
|
||||
name: "qemu".to_string(),
|
||||
r#type: "raw".to_string(),
|
||||
},
|
||||
source: DiskSourceXML {
|
||||
file: path.to_string_lossy().to_string(),
|
||||
},
|
||||
target: DiskTargetXML {
|
||||
dev: "hdc".to_string(),
|
||||
bus: "ide".to_string(),
|
||||
},
|
||||
readonly: DiskReadOnlyXML {},
|
||||
boot: DiskBootXML {
|
||||
order: "1".to_string(),
|
||||
},
|
||||
address: DiskAddressXML {
|
||||
r#type: "drive".to_string(),
|
||||
controller: "0".to_string(),
|
||||
bus: "1".to_string(),
|
||||
target: "0".to_string(),
|
||||
unit: "0".to_string(),
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
let vnc_graphics = match self.vnc_access {
|
||||
true => Some(GraphicsXML {
|
||||
r#type: "vnc".to_string(),
|
||||
@ -147,6 +191,7 @@ impl VMInfo {
|
||||
|
||||
devices: DevicesXML {
|
||||
graphics: vnc_graphics,
|
||||
disks: disks.into_iter().next(),
|
||||
},
|
||||
|
||||
memory: DomainMemoryXML {
|
||||
@ -187,6 +232,12 @@ impl VMInfo {
|
||||
},
|
||||
memory: convert_to_mb(&domain.memory.unit, domain.memory.memory)?,
|
||||
vnc_access: domain.devices.graphics.is_some(),
|
||||
iso_file: domain
|
||||
.devices
|
||||
.disks
|
||||
.iter()
|
||||
.find(|d| d.device == "cdrom")
|
||||
.map(|d| d.source.file.rsplit_once('/').unwrap().1.to_string()),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -27,6 +27,7 @@ interface VMInfoInterface {
|
||||
architecture: "i686" | "x86_64";
|
||||
memory: number;
|
||||
vnc_access: boolean;
|
||||
iso_file?: string;
|
||||
}
|
||||
|
||||
export class VMInfo implements VMInfoInterface {
|
||||
@ -39,6 +40,7 @@ export class VMInfo implements VMInfoInterface {
|
||||
architecture: "i686" | "x86_64";
|
||||
memory: number;
|
||||
vnc_access: boolean;
|
||||
iso_file?: string;
|
||||
|
||||
constructor(int: VMInfoInterface) {
|
||||
this.name = int.name;
|
||||
@ -50,6 +52,7 @@ export class VMInfo implements VMInfoInterface {
|
||||
this.architecture = int.architecture;
|
||||
this.memory = int.memory;
|
||||
this.vnc_access = int.vnc_access;
|
||||
this.iso_file = int.iso_file;
|
||||
}
|
||||
|
||||
static NewEmpty(): VMInfo {
|
||||
|
@ -2,7 +2,7 @@ import { FormControl, InputLabel, MenuItem, Select } from "@mui/material";
|
||||
import { TextInput } from "./TextInput";
|
||||
|
||||
export interface SelectOption {
|
||||
value: string;
|
||||
value?: string;
|
||||
label: string;
|
||||
}
|
||||
|
||||
|
@ -7,13 +7,38 @@ import { CheckboxInput } from "../forms/CheckboxInput";
|
||||
import { SelectInput } from "../forms/SelectInput";
|
||||
import { TextInput } from "../forms/TextInput";
|
||||
import { VMScreenshot } from "./VMScreenshot";
|
||||
import { IsoFile, IsoFilesApi } from "../../api/IsoFilesApi";
|
||||
import { AsyncWidget } from "../AsyncWidget";
|
||||
import React from "react";
|
||||
import { filesize } from "filesize";
|
||||
|
||||
export function VMDetails(p: {
|
||||
interface DetailsProps {
|
||||
vm: VMInfo;
|
||||
editable: boolean;
|
||||
onChange?: () => void;
|
||||
screenshot?: boolean;
|
||||
}): React.ReactElement {
|
||||
}
|
||||
|
||||
export function VMDetails(p: DetailsProps): React.ReactElement {
|
||||
const [list, setList] = React.useState<IsoFile[] | any>();
|
||||
|
||||
const load = async () => {
|
||||
setList(await IsoFilesApi.GetList());
|
||||
};
|
||||
|
||||
return (
|
||||
<AsyncWidget
|
||||
loadKey={"1"}
|
||||
load={load}
|
||||
errMsg="Failed to load the list of ISO files"
|
||||
build={() => <VMDetailsInner iso={list!} {...p} />}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
function VMDetailsInner(
|
||||
p: DetailsProps & { iso: IsoFile[] }
|
||||
): React.ReactElement {
|
||||
return (
|
||||
<Grid container spacing={2}>
|
||||
{
|
||||
@ -128,6 +153,28 @@ export function VMDetails(p: {
|
||||
}}
|
||||
/>
|
||||
</EditSection>
|
||||
|
||||
{/* Storage section */}
|
||||
<EditSection title="Storage">
|
||||
<SelectInput
|
||||
label="ISO file"
|
||||
editable={p.editable}
|
||||
value={p.vm.iso_file}
|
||||
onValueChange={(v) => {
|
||||
p.vm.iso_file = v;
|
||||
p.onChange?.();
|
||||
}}
|
||||
options={[
|
||||
{ label: "None", value: undefined },
|
||||
...p.iso.map((i) => {
|
||||
return {
|
||||
label: `${i.filename} ${filesize(i.size)}`,
|
||||
value: i.filename,
|
||||
};
|
||||
}),
|
||||
]}
|
||||
/>
|
||||
</EditSection>
|
||||
</Grid>
|
||||
);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user