Compare commits
	
		
			44 Commits
		
	
	
		
			20250618
			...
			62a903f565
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 62a903f565 | |||
| b741d79ba7 | |||
| eeda3ca4ec | |||
| 992f91bb8a | |||
| 2f3ad231c7 | |||
| 6e41d3c6df | |||
| f57f3f3c9a | |||
| 34fda42766 | |||
| a9536f4091 | |||
| 7770ad3ca7 | |||
| 02b3373f51 | |||
| 5153af0618 | |||
| d50c3a00a5 | |||
| 4618c2c081 | |||
| 34d78085c8 | |||
| 0381b73635 | |||
| 2e88529e3d | |||
| 84e3f61902 | |||
| 9623493aee | |||
| e5ad7d2fe4 | |||
| 940179ffe5 | |||
| f7b27a527b | |||
| caac7dc1bf | |||
| a0f815534b | |||
| 928c2c5cb4 | |||
| ddc8b65f8a | |||
| 0b67659efa | |||
| 0601d9cad9 | |||
| a1b6ebd9f5 | |||
| b8eedaab51 | |||
| 0afc3252c6 | |||
| 685f1bc502 | |||
| 3e642dd638 | |||
| 22ad68e43e | |||
| 1dd86807fd | |||
| 96747bda89 | |||
| e15514dd4f | |||
| 7556ee2c06 | |||
| 992a902590 | |||
| 100f12e7c1 | |||
| 3de66a5873 | |||
| 49360188f5 | |||
| 35c48ba846 | |||
| 1ad4262086 | 
							
								
								
									
										24
									
								
								virtweb_backend/Cargo.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										24
									
								
								virtweb_backend/Cargo.lock
									
									
									
										generated
									
									
									
								
							@@ -811,9 +811,9 @@ dependencies = [
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "clap"
 | 
			
		||||
version = "4.5.40"
 | 
			
		||||
version = "4.5.41"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "40b6887a1d8685cebccf115538db5c0efe625ccac9696ad45c409d96566e910f"
 | 
			
		||||
checksum = "be92d32e80243a54711e5d7ce823c35c41c9d929dc4ab58e1276f625841aadf9"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "clap_builder",
 | 
			
		||||
 "clap_derive",
 | 
			
		||||
@@ -821,9 +821,9 @@ dependencies = [
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "clap_builder"
 | 
			
		||||
version = "4.5.40"
 | 
			
		||||
version = "4.5.41"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "e0c66c08ce9f0c698cbce5c0279d0bb6ac936d8674174fe48f736533b964f59e"
 | 
			
		||||
checksum = "707eab41e9622f9139419d573eca0900137718000c517d47da73045f54331c3d"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "anstream",
 | 
			
		||||
 "anstyle",
 | 
			
		||||
@@ -833,9 +833,9 @@ dependencies = [
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "clap_derive"
 | 
			
		||||
version = "4.5.40"
 | 
			
		||||
version = "4.5.41"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "d2c7947ae4cc3d851207c1adb5b5e260ff0cca11446b1d6d1423788e442257ce"
 | 
			
		||||
checksum = "ef4f52386a59ca4c860f7393bcf8abd8dfd91ecccc0f774635ff68e92eeef491"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "heck",
 | 
			
		||||
 "proc-macro2",
 | 
			
		||||
@@ -2938,9 +2938,9 @@ checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "reqwest"
 | 
			
		||||
version = "0.12.20"
 | 
			
		||||
version = "0.12.22"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "eabf4c97d9130e2bf606614eb937e86edac8292eaa6f422f995d7e8de1eb1813"
 | 
			
		||||
checksum = "cbc931937e6ca3a06e3b6c0aa7841849b160a90351d6ab467a8b9b9959767531"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "base64 0.22.1",
 | 
			
		||||
 "bytes",
 | 
			
		||||
@@ -3206,9 +3206,9 @@ dependencies = [
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "serde_json"
 | 
			
		||||
version = "1.0.140"
 | 
			
		||||
version = "1.0.141"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373"
 | 
			
		||||
checksum = "30b9eff21ebe718216c6ec64e1d9ac57087aad11efc64e32002bce4a0d4c03d3"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "itoa",
 | 
			
		||||
 "memchr",
 | 
			
		||||
@@ -3421,9 +3421,9 @@ dependencies = [
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "sysinfo"
 | 
			
		||||
version = "0.35.1"
 | 
			
		||||
version = "0.35.2"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "79251336d17c72d9762b8b54be4befe38d2db56fbbc0241396d70f173c39d47a"
 | 
			
		||||
checksum = "3c3ffa3e4ff2b324a57f7aeb3c349656c7b127c3c189520251a648102a92496e"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "libc",
 | 
			
		||||
 "memchr",
 | 
			
		||||
 
 | 
			
		||||
@@ -8,7 +8,7 @@ edition = "2024"
 | 
			
		||||
[dependencies]
 | 
			
		||||
log = "0.4.27"
 | 
			
		||||
env_logger = "0.11.8"
 | 
			
		||||
clap = { version = "4.5.40", features = ["derive", "env"] }
 | 
			
		||||
clap = { version = "4.5.41", features = ["derive", "env"] }
 | 
			
		||||
light-openid = { version = "1.0.4", features = ["crypto-wrapper"] }
 | 
			
		||||
lazy_static = "1.5.0"
 | 
			
		||||
actix = "0.13.5"
 | 
			
		||||
@@ -21,17 +21,17 @@ actix-files = "0.6.6"
 | 
			
		||||
actix-ws = "0.3.0"
 | 
			
		||||
actix-http = "3.11.0"
 | 
			
		||||
serde = { version = "1.0.219", features = ["derive"] }
 | 
			
		||||
serde_json = "1.0.140"
 | 
			
		||||
serde_json = "1.0.141"
 | 
			
		||||
serde_yml = "0.0.12"
 | 
			
		||||
quick-xml = { version = "0.37.5", features = ["serialize", "overlapped-lists"] }
 | 
			
		||||
futures-util = "0.3.31"
 | 
			
		||||
anyhow = "1.0.98"
 | 
			
		||||
actix-multipart = "0.7.2"
 | 
			
		||||
tempfile = "3.20.0"
 | 
			
		||||
reqwest = { version = "0.12.20", features = ["stream"] }
 | 
			
		||||
reqwest = { version = "0.12.22", features = ["stream"] }
 | 
			
		||||
url = "2.5.4"
 | 
			
		||||
virt = "0.4.2"
 | 
			
		||||
sysinfo = { version = "0.35.1", features = ["serde"] }
 | 
			
		||||
sysinfo = { version = "0.35.2", features = ["serde"] }
 | 
			
		||||
uuid = { version = "1.16.0", features = ["v4", "serde"] }
 | 
			
		||||
lazy-regex = "3.4.1"
 | 
			
		||||
thiserror = "2.0.12"
 | 
			
		||||
 
 | 
			
		||||
@@ -27,10 +27,7 @@ impl LibVirtActor {
 | 
			
		||||
    /// Connect to hypervisor
 | 
			
		||||
    pub async fn connect() -> anyhow::Result<Self> {
 | 
			
		||||
        let hypervisor_uri = AppConfig::get().hypervisor_uri.as_deref().unwrap_or("");
 | 
			
		||||
        log::info!(
 | 
			
		||||
            "Will connect to hypvervisor at address '{}'",
 | 
			
		||||
            hypervisor_uri
 | 
			
		||||
        );
 | 
			
		||||
        log::info!("Will connect to hypvervisor at address '{hypervisor_uri}'",);
 | 
			
		||||
        let conn = Connect::open(Some(hypervisor_uri))?;
 | 
			
		||||
 | 
			
		||||
        Ok(Self { m: conn })
 | 
			
		||||
@@ -102,7 +99,7 @@ impl Handler<GetDomainXMLReq> for LibVirtActor {
 | 
			
		||||
        log::debug!("Get domain XML:\n{}", msg.0.as_string());
 | 
			
		||||
        let domain = Domain::lookup_by_uuid_string(&self.m, &msg.0.as_string())?;
 | 
			
		||||
        let xml = domain.get_xml_desc(VIR_DOMAIN_XML_SECURE)?;
 | 
			
		||||
        log::debug!("XML = {}", xml);
 | 
			
		||||
        log::debug!("XML = {xml}");
 | 
			
		||||
        DomainXML::parse_xml(&xml)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -131,7 +128,7 @@ impl Handler<DefineDomainReq> for LibVirtActor {
 | 
			
		||||
    fn handle(&mut self, mut msg: DefineDomainReq, _ctx: &mut Self::Context) -> Self::Result {
 | 
			
		||||
        let xml = msg.1.as_xml()?;
 | 
			
		||||
 | 
			
		||||
        log::debug!("Define domain:\n{}", xml);
 | 
			
		||||
        log::debug!("Define domain:\n{xml}");
 | 
			
		||||
        let domain = Domain::define_xml(&self.m, &xml)?;
 | 
			
		||||
        let uuid = XMLUuid::parse_from_str(&domain.get_uuid_string()?)?;
 | 
			
		||||
 | 
			
		||||
@@ -446,7 +443,7 @@ impl Handler<GetNetworkXMLReq> for LibVirtActor {
 | 
			
		||||
        log::debug!("Get network XML:\n{}", msg.0.as_string());
 | 
			
		||||
        let network = Network::lookup_by_uuid_string(&self.m, &msg.0.as_string())?;
 | 
			
		||||
        let xml = network.get_xml_desc(0)?;
 | 
			
		||||
        log::debug!("XML = {}", xml);
 | 
			
		||||
        log::debug!("XML = {xml}");
 | 
			
		||||
        NetworkXML::parse_xml(&xml)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -602,7 +599,7 @@ impl Handler<GetNWFilterXMLReq> for LibVirtActor {
 | 
			
		||||
        log::debug!("Get network filter XML:\n{}", msg.0.as_string());
 | 
			
		||||
        let filter = NWFilter::lookup_by_uuid_string(&self.m, &msg.0.as_string())?;
 | 
			
		||||
        let xml = filter.get_xml_desc(0)?;
 | 
			
		||||
        log::debug!("XML = {}", xml);
 | 
			
		||||
        log::debug!("XML = {xml}");
 | 
			
		||||
        NetworkFilterXML::parse_xml(xml)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -617,7 +614,7 @@ impl Handler<DefineNWFilterReq> for LibVirtActor {
 | 
			
		||||
    fn handle(&mut self, mut msg: DefineNWFilterReq, _ctx: &mut Self::Context) -> Self::Result {
 | 
			
		||||
        let xml = msg.1.into_xml()?;
 | 
			
		||||
 | 
			
		||||
        log::debug!("Define network filter:\n{}", xml);
 | 
			
		||||
        log::debug!("Define network filter:\n{xml}");
 | 
			
		||||
        let filter = NWFilter::define_xml(&self.m, &xml)?;
 | 
			
		||||
        let uuid = XMLUuid::parse_from_str(&filter.get_uuid_string()?)?;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -280,7 +280,7 @@ impl AppConfig {
 | 
			
		||||
 | 
			
		||||
    /// Get VM vnc sockets path for domain
 | 
			
		||||
    pub fn vnc_socket_for_domain(&self, name: &str) -> PathBuf {
 | 
			
		||||
        self.vnc_sockets_path().join(format!("vnc-{}", name))
 | 
			
		||||
        self.vnc_sockets_path().join(format!("vnc-{name}"))
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Get VM root disks storage directory
 | 
			
		||||
 
 | 
			
		||||
@@ -34,8 +34,7 @@ pub async fn upload(MultipartForm(mut form): MultipartForm<UploadDiskImageForm>)
 | 
			
		||||
    if let Some(mime_type) = file.content_type {
 | 
			
		||||
        if !constants::ALLOWED_DISK_IMAGES_MIME_TYPES.contains(&mime_type.as_ref()) {
 | 
			
		||||
            return Ok(HttpResponse::BadRequest().json(format!(
 | 
			
		||||
                "Unsupported file type for disk upload: {}",
 | 
			
		||||
                mime_type
 | 
			
		||||
                "Unsupported file type for disk upload: {mime_type}"
 | 
			
		||||
            )));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -52,7 +52,7 @@ pub async fn upload_file(MultipartForm(mut form): MultipartForm<UploadIsoForm>)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    let dest_file = AppConfig::get().iso_storage_path().join(file_name);
 | 
			
		||||
    log::info!("Will save ISO file {:?}", dest_file);
 | 
			
		||||
    log::info!("Will save ISO file {dest_file:?}");
 | 
			
		||||
 | 
			
		||||
    if dest_file.exists() {
 | 
			
		||||
        log::error!("Conflict with uploaded iso file name!");
 | 
			
		||||
 
 | 
			
		||||
@@ -43,7 +43,7 @@ impl actix_web::error::ResponseError for HttpErr {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    fn error_response(&self) -> HttpResponse<BoxBody> {
 | 
			
		||||
        log::error!("Error while processing request! {}", self);
 | 
			
		||||
        log::error!("Error while processing request! {self}");
 | 
			
		||||
 | 
			
		||||
        HttpResponse::InternalServerError().body("Failed to execute request!")
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -109,7 +109,7 @@ fn extract_ip_mask<const V: usize>(n: Option<u8>) -> anyhow::Result<Option<u8>>
 | 
			
		||||
fn extract_nw_filter_comment(n: &Option<String>) -> anyhow::Result<Option<String>> {
 | 
			
		||||
    if let Some(comment) = n {
 | 
			
		||||
        if comment.len() > 256 || comment.contains('\"') || comment.contains('\n') {
 | 
			
		||||
            return Err(NetworkFilterExtraction(format!("Invalid comment! {}", comment)).into());
 | 
			
		||||
            return Err(NetworkFilterExtraction(format!("Invalid comment! {comment}")).into());
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -69,8 +69,7 @@ where
 | 
			
		||||
 | 
			
		||||
            if !AppConfig::get().is_allowed_ip(remote_ip.0) {
 | 
			
		||||
                log::error!(
 | 
			
		||||
                    "An attempt to access VirtWeb from an unauthorized network has been intercepted! {:?}",
 | 
			
		||||
                    remote_ip
 | 
			
		||||
                    "An attempt to access VirtWeb from an unauthorized network has been intercepted! {remote_ip:?}"
 | 
			
		||||
                );
 | 
			
		||||
                return Ok(req
 | 
			
		||||
                    .into_response(
 | 
			
		||||
 
 | 
			
		||||
@@ -81,10 +81,10 @@ impl CloudInitConfig {
 | 
			
		||||
        // Process metadata
 | 
			
		||||
        let mut metadatas = vec![];
 | 
			
		||||
        if let Some(inst_id) = &self.instance_id {
 | 
			
		||||
            metadatas.push(format!("instance-id: {}", inst_id));
 | 
			
		||||
            metadatas.push(format!("instance-id: {inst_id}"));
 | 
			
		||||
        }
 | 
			
		||||
        if let Some(local_hostname) = &self.local_hostname {
 | 
			
		||||
            metadatas.push(format!("local-hostname: {}", local_hostname));
 | 
			
		||||
            metadatas.push(format!("local-hostname: {local_hostname}"));
 | 
			
		||||
        }
 | 
			
		||||
        if let Some(dsmode) = &self.dsmode {
 | 
			
		||||
            metadatas.push(format!(
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										907
									
								
								virtweb_frontend/package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										907
									
								
								virtweb_frontend/package-lock.json
									
									
									
										generated
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -11,23 +11,23 @@
 | 
			
		||||
  },
 | 
			
		||||
  "dependencies": {
 | 
			
		||||
    "@emotion/react": "^11.14.0",
 | 
			
		||||
    "@emotion/styled": "^11.14.0",
 | 
			
		||||
    "@emotion/styled": "^11.14.1",
 | 
			
		||||
    "@fontsource/roboto": "^5.2.6",
 | 
			
		||||
    "@mdi/js": "^7.4.47",
 | 
			
		||||
    "@mdi/react": "^1.6.1",
 | 
			
		||||
    "@monaco-editor/react": "^4.7.0",
 | 
			
		||||
    "@mui/icons-material": "^7.1.1",
 | 
			
		||||
    "@mui/material": "^7.1.1",
 | 
			
		||||
    "@mui/icons-material": "^7.2.0",
 | 
			
		||||
    "@mui/material": "^7.2.0",
 | 
			
		||||
    "@mui/x-charts": "^8.3.1",
 | 
			
		||||
    "@mui/x-data-grid": "^8.3.1",
 | 
			
		||||
    "@mui/x-data-grid": "^8.8.0",
 | 
			
		||||
    "date-and-time": "^3.6.0",
 | 
			
		||||
    "filesize": "^10.1.6",
 | 
			
		||||
    "humanize-duration": "^3.32.2",
 | 
			
		||||
    "humanize-duration": "^3.33.0",
 | 
			
		||||
    "monaco-editor": "^0.52.2",
 | 
			
		||||
    "monaco-yaml": "^5.4.0",
 | 
			
		||||
    "react": "^19.1.0",
 | 
			
		||||
    "react-dom": "^19.1.0",
 | 
			
		||||
    "react-router-dom": "^7.6.2",
 | 
			
		||||
    "react-router-dom": "^7.7.0",
 | 
			
		||||
    "react-syntax-highlighter": "^15.6.1",
 | 
			
		||||
    "react-vnc": "^3.1.0",
 | 
			
		||||
    "uuid": "^11.1.0",
 | 
			
		||||
@@ -35,22 +35,22 @@
 | 
			
		||||
    "yaml": "^2.8.0"
 | 
			
		||||
  },
 | 
			
		||||
  "devDependencies": {
 | 
			
		||||
    "@eslint/js": "^9.27.0",
 | 
			
		||||
    "@eslint/js": "^9.31.0",
 | 
			
		||||
    "@types/humanize-duration": "^3.27.4",
 | 
			
		||||
    "@types/jest": "^29.5.14",
 | 
			
		||||
    "@types/react": "^19.1.8",
 | 
			
		||||
    "@types/react-dom": "^19.1.6",
 | 
			
		||||
    "@types/react-syntax-highlighter": "^15.5.13",
 | 
			
		||||
    "@types/uuid": "^10.0.0",
 | 
			
		||||
    "@vitejs/plugin-react": "^4.4.1",
 | 
			
		||||
    "eslint": "^9.27.0",
 | 
			
		||||
    "eslint-plugin-react-dom": "^1.49.0",
 | 
			
		||||
    "@vitejs/plugin-react": "^4.7.0",
 | 
			
		||||
    "eslint": "^9.31.0",
 | 
			
		||||
    "eslint-plugin-react-dom": "^1.52.3",
 | 
			
		||||
    "eslint-plugin-react-hooks": "^5.2.0",
 | 
			
		||||
    "eslint-plugin-react-refresh": "^0.4.20",
 | 
			
		||||
    "eslint-plugin-react-x": "^1.49.0",
 | 
			
		||||
    "globals": "^16.1.0",
 | 
			
		||||
    "eslint-plugin-react-x": "^1.52.3",
 | 
			
		||||
    "globals": "^16.3.0",
 | 
			
		||||
    "typescript": "^5.8.3",
 | 
			
		||||
    "typescript-eslint": "^8.32.1",
 | 
			
		||||
    "typescript-eslint": "^8.37.0",
 | 
			
		||||
    "vite": "^6.3.5"
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -319,7 +319,7 @@ function DiskDetailsTable(p: { disks: DiskInfo[] }): React.ReactElement {
 | 
			
		||||
          {p.disks.map((e, c) => (
 | 
			
		||||
            <TableRow hover key={c}>
 | 
			
		||||
              <TableCell>{e.name}</TableCell>
 | 
			
		||||
              <TableCell>{e.DiskKind}</TableCell>
 | 
			
		||||
              <TableCell>{String(e.DiskKind)}</TableCell>
 | 
			
		||||
              <TableCell>{e.mount_point}</TableCell>
 | 
			
		||||
              <TableCell>{filesize(e.total_space)}</TableCell>
 | 
			
		||||
              <TableCell>{filesize(e.available_space)}</TableCell>
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user