diff --git a/virtweb_backend/Cargo.lock b/virtweb_backend/Cargo.lock index 66d3308..6516a15 100644 --- a/virtweb_backend/Cargo.lock +++ b/virtweb_backend/Cargo.lock @@ -1982,6 +1982,16 @@ dependencies = [ "cc", ] +[[package]] +name = "libyml" +version = "0.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3302702afa434ffa30847a83305f0a69d6abd74293b6554c18ec85c7ef30c980" +dependencies = [ + "anyhow", + "version_check", +] + [[package]] name = "light-openid" version = "1.0.4" @@ -3093,6 +3103,21 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_yml" +version = "0.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59e2dd588bf1597a252c3b920e0143eb99b0f76e4e082f4c92ce34fbc9e71ddd" +dependencies = [ + "indexmap", + "itoa", + "libyml", + "memchr", + "ryu", + "serde", + "version_check", +] + [[package]] name = "sha1" version = "0.10.6" @@ -3754,6 +3779,7 @@ dependencies = [ "rust-embed", "serde", "serde_json", + "serde_yml", "sysinfo", "tempfile", "thiserror 2.0.12", diff --git a/virtweb_backend/Cargo.toml b/virtweb_backend/Cargo.toml index 9c75bd0..ee19a16 100644 --- a/virtweb_backend/Cargo.toml +++ b/virtweb_backend/Cargo.toml @@ -22,6 +22,7 @@ actix-ws = "0.3.0" actix-http = "3.10.0" serde = { version = "1.0.219", features = ["derive"] } serde_json = "1.0.140" +serde_yml = "0.0.12" quick-xml = { version = "0.37.5", features = ["serialize", "overlapped-lists"] } futures-util = "0.3.31" anyhow = "1.0.98" diff --git a/virtweb_backend/src/libvirt_rest_structures/mod.rs b/virtweb_backend/src/libvirt_rest_structures/mod.rs index 8984e81..cdbbcd1 100644 --- a/virtweb_backend/src/libvirt_rest_structures/mod.rs +++ b/virtweb_backend/src/libvirt_rest_structures/mod.rs @@ -13,4 +13,6 @@ enum LibVirtStructError { ParseFilteringChain(String), #[error("NetworkFilterExtractionError: {0}")] NetworkFilterExtraction(String), + #[error("CloudInitConfigurationError: {0}")] + CloudInitConfiguration(String), } diff --git a/virtweb_backend/src/libvirt_rest_structures/vm.rs b/virtweb_backend/src/libvirt_rest_structures/vm.rs index 68f10f1..8042aa7 100644 --- a/virtweb_backend/src/libvirt_rest_structures/vm.rs +++ b/virtweb_backend/src/libvirt_rest_structures/vm.rs @@ -3,7 +3,9 @@ use crate::constants; use crate::libvirt_lib_structures::XMLUuid; use crate::libvirt_lib_structures::domain::*; use crate::libvirt_rest_structures::LibVirtStructError; -use crate::libvirt_rest_structures::LibVirtStructError::StructureExtraction; +use crate::libvirt_rest_structures::LibVirtStructError::{ + CloudInitConfiguration, StructureExtraction, +}; use crate::utils::cloud_init_utils::CloudInitConfig; use crate::utils::file_size_utils::FileSize; use crate::utils::files_utils; @@ -142,6 +144,10 @@ impl VMInfo { return Err(StructureExtraction("Invalid number of vCPU specified!").into()); } + if let Some(e) = self.cloud_init.check_error() { + return Err(CloudInitConfiguration(e).into()); + } + let mut iso_absolute_files = vec![]; // Process cloud init image diff --git a/virtweb_backend/src/utils/cloud_init_utils.rs b/virtweb_backend/src/utils/cloud_init_utils.rs index d689b1a..8891035 100644 --- a/virtweb_backend/src/utils/cloud_init_utils.rs +++ b/virtweb_backend/src/utils/cloud_init_utils.rs @@ -35,6 +35,27 @@ pub struct CloudInitConfig { } impl CloudInitConfig { + /// Check cloud init configuration + pub fn check_error(&self) -> Option { + if !self.user_data.is_empty() { + // Check YAML content + if let Err(e) = serde_yml::from_str::(&self.user_data) { + return Some(format!( + "user data is an invalid YAML file! Deserialization error: {e}" + )); + } + + // Check first line + if !self.user_data.starts_with("#cloud-config\n") { + return Some( + "user data file MUST start with '#cloud-config' as first line!".to_string(), + ); + } + } + + None + } + /// Generate disk image for nocloud usage pub fn generate_nocloud_disk(&self) -> anyhow::Result> { let temp_path = tempfile::tempdir_in(&AppConfig::get().temp_dir)?;