Automatically generate cloud disk image when updating domains configuration
	
		
			
	
		
	
	
		
	
		
			All checks were successful
		
		
	
	
		
			
				
	
				continuous-integration/drone/push Build is passing
				
			
		
		
	
	
				
					
				
			
		
			All checks were successful
		
		
	
	continuous-integration/drone/push Build is passing
				
			This commit is contained in:
		@@ -182,6 +182,13 @@ impl Handler<DeleteDomainReq> for LibVirtActor {
 | 
				
			|||||||
            false => sys::VIR_DOMAIN_UNDEFINE_NVRAM,
 | 
					            false => sys::VIR_DOMAIN_UNDEFINE_NVRAM,
 | 
				
			||||||
        })?;
 | 
					        })?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Delete associated cloud init disk
 | 
				
			||||||
 | 
					        let cloud_init_disk = AppConfig::get().cloud_init_disk_path_for_vm(&domain_name);
 | 
				
			||||||
 | 
					        if cloud_init_disk.exists() {
 | 
				
			||||||
 | 
					            std::fs::remove_file(cloud_init_disk)?;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // If requested, delete block storage associated with the VM
 | 
				
			||||||
        if !msg.keep_files {
 | 
					        if !msg.keep_files {
 | 
				
			||||||
            log::info!("Delete storage associated with the domain");
 | 
					            log::info!("Delete storage associated with the domain");
 | 
				
			||||||
            let path = AppConfig::get().vm_storage_path(msg.id);
 | 
					            let path = AppConfig::get().vm_storage_path(msg.id);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -250,6 +250,19 @@ impl AppConfig {
 | 
				
			|||||||
        self.storage_path().join("iso")
 | 
					        self.storage_path().join("iso")
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Get the path where generated cloud init disk image are stored
 | 
				
			||||||
 | 
					    pub fn cloud_init_disk_storage_path(&self) -> PathBuf {
 | 
				
			||||||
 | 
					        self.storage_path().join("cloud_init_disks")
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Get the path where the disk image of a VM is stored
 | 
				
			||||||
 | 
					    pub fn cloud_init_disk_path_for_vm(&self, name: &str) -> PathBuf {
 | 
				
			||||||
 | 
					        self.cloud_init_disk_storage_path().join(format!(
 | 
				
			||||||
 | 
					            "{}-{name}.iso",
 | 
				
			||||||
 | 
					            constants::CLOUD_INIT_IMAGE_PREFIX_NAME
 | 
				
			||||||
 | 
					        ))
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// Get disk images storage directory
 | 
					    /// Get disk images storage directory
 | 
				
			||||||
    pub fn disk_images_storage_path(&self) -> PathBuf {
 | 
					    pub fn disk_images_storage_path(&self) -> PathBuf {
 | 
				
			||||||
        self.storage_path().join("disk_images")
 | 
					        self.storage_path().join("disk_images")
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -57,6 +57,9 @@ pub const DISK_SIZE_MIN: FileSize = FileSize::from_mb(50);
 | 
				
			|||||||
/// Disk size max (B)
 | 
					/// Disk size max (B)
 | 
				
			||||||
pub const DISK_SIZE_MAX: FileSize = FileSize::from_gb(20000);
 | 
					pub const DISK_SIZE_MAX: FileSize = FileSize::from_gb(20000);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Cloud init generated disk image prefix
 | 
				
			||||||
 | 
					pub const CLOUD_INIT_IMAGE_PREFIX_NAME: &str = "virtweb-cloudinit-autogen-image";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Net nat entry comment max size
 | 
					/// Net nat entry comment max size
 | 
				
			||||||
pub const NET_NAT_COMMENT_MAX_SIZE: usize = 250;
 | 
					pub const NET_NAT_COMMENT_MAX_SIZE: usize = 250;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -142,9 +142,22 @@ impl VMInfo {
 | 
				
			|||||||
            return Err(StructureExtraction("Invalid number of vCPU specified!").into());
 | 
					            return Err(StructureExtraction("Invalid number of vCPU specified!").into());
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let mut disks = vec![];
 | 
					        let mut iso_absolute_files = vec![];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Add ISO files
 | 
					        // Process cloud init image
 | 
				
			||||||
 | 
					        if self.cloud_init.attach_config {
 | 
				
			||||||
 | 
					            let cloud_init_disk_path = AppConfig::get().cloud_init_disk_path_for_vm(&self.name);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // Apply latest cloud init configuration
 | 
				
			||||||
 | 
					            std::fs::write(
 | 
				
			||||||
 | 
					                &cloud_init_disk_path,
 | 
				
			||||||
 | 
					                self.cloud_init.generate_nocloud_disk()?,
 | 
				
			||||||
 | 
					            )?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iso_absolute_files.push(cloud_init_disk_path);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Process uploaded ISO files
 | 
				
			||||||
        for iso_file in &self.iso_files {
 | 
					        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,6 +169,13 @@ impl VMInfo {
 | 
				
			|||||||
                return Err(StructureExtraction("Specified ISO file does not exists!").into());
 | 
					                return Err(StructureExtraction("Specified ISO file does not exists!").into());
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iso_absolute_files.push(path);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let mut disks = vec![];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Add ISO disk files
 | 
				
			||||||
 | 
					        for iso_path in iso_absolute_files {
 | 
				
			||||||
            disks.push(DiskXML {
 | 
					            disks.push(DiskXML {
 | 
				
			||||||
                r#type: "file".to_string(),
 | 
					                r#type: "file".to_string(),
 | 
				
			||||||
                device: "cdrom".to_string(),
 | 
					                device: "cdrom".to_string(),
 | 
				
			||||||
@@ -165,7 +185,7 @@ impl VMInfo {
 | 
				
			|||||||
                    cache: "none".to_string(),
 | 
					                    cache: "none".to_string(),
 | 
				
			||||||
                },
 | 
					                },
 | 
				
			||||||
                source: DiskSourceXML {
 | 
					                source: DiskSourceXML {
 | 
				
			||||||
                    file: path.to_string_lossy().to_string(),
 | 
					                    file: iso_path.to_string_lossy().to_string(),
 | 
				
			||||||
                },
 | 
					                },
 | 
				
			||||||
                target: DiskTargetXML {
 | 
					                target: DiskTargetXML {
 | 
				
			||||||
                    dev: format!(
 | 
					                    dev: format!(
 | 
				
			||||||
@@ -182,6 +202,7 @@ impl VMInfo {
 | 
				
			|||||||
            })
 | 
					            })
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Configure VNC access, if requested
 | 
				
			||||||
        let (vnc_graphics, vnc_video) = match self.vnc_access {
 | 
					        let (vnc_graphics, vnc_video) = match self.vnc_access {
 | 
				
			||||||
            true => (
 | 
					            true => (
 | 
				
			||||||
                Some(GraphicsXML {
 | 
					                Some(GraphicsXML {
 | 
				
			||||||
@@ -495,6 +516,7 @@ impl VMInfo {
 | 
				
			|||||||
                .iter()
 | 
					                .iter()
 | 
				
			||||||
                .filter(|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())
 | 
				
			||||||
 | 
					                .filter(|d| !d.starts_with(constants::CLOUD_INIT_IMAGE_PREFIX_NAME))
 | 
				
			||||||
                .collect(),
 | 
					                .collect(),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            file_disks: domain
 | 
					            file_disks: domain
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -61,6 +61,8 @@ async fn main() -> std::io::Result<()> {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    log::debug!("Create required directory, if missing");
 | 
					    log::debug!("Create required directory, if missing");
 | 
				
			||||||
    files_utils::create_directory_if_missing(AppConfig::get().iso_storage_path()).unwrap();
 | 
					    files_utils::create_directory_if_missing(AppConfig::get().iso_storage_path()).unwrap();
 | 
				
			||||||
 | 
					    files_utils::create_directory_if_missing(AppConfig::get().cloud_init_disk_storage_path())
 | 
				
			||||||
 | 
					        .unwrap();
 | 
				
			||||||
    files_utils::create_directory_if_missing(AppConfig::get().disk_images_storage_path()).unwrap();
 | 
					    files_utils::create_directory_if_missing(AppConfig::get().disk_images_storage_path()).unwrap();
 | 
				
			||||||
    files_utils::create_directory_if_missing(AppConfig::get().vnc_sockets_path()).unwrap();
 | 
					    files_utils::create_directory_if_missing(AppConfig::get().vnc_sockets_path()).unwrap();
 | 
				
			||||||
    files_utils::set_file_permission(AppConfig::get().vnc_sockets_path(), 0o777).unwrap();
 | 
					    files_utils::set_file_permission(AppConfig::get().vnc_sockets_path(), 0o777).unwrap();
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,18 +8,18 @@ use std::process::Command;
 | 
				
			|||||||
/// cloud-localds source code: https://github.com/canonical/cloud-utils/blob/main/bin/cloud-localds
 | 
					/// cloud-localds source code: https://github.com/canonical/cloud-utils/blob/main/bin/cloud-localds
 | 
				
			||||||
#[derive(Clone, Debug, serde::Serialize, serde::Deserialize, Default)]
 | 
					#[derive(Clone, Debug, serde::Serialize, serde::Deserialize, Default)]
 | 
				
			||||||
pub struct CloudInitConfig {
 | 
					pub struct CloudInitConfig {
 | 
				
			||||||
    attach_config: bool,
 | 
					    pub attach_config: bool,
 | 
				
			||||||
    /// Main user data
 | 
					    /// Main user data
 | 
				
			||||||
    user_data: String,
 | 
					    pub user_data: String,
 | 
				
			||||||
    /// Instance ID, set in metadata file
 | 
					    /// Instance ID, set in metadata file
 | 
				
			||||||
    #[serde(skip_serializing_if = "Option::is_none")]
 | 
					    #[serde(skip_serializing_if = "Option::is_none")]
 | 
				
			||||||
    instance_id: Option<String>,
 | 
					    pub instance_id: Option<String>,
 | 
				
			||||||
    /// Local hostname, set in metadata file
 | 
					    /// Local hostname, set in metadata file
 | 
				
			||||||
    #[serde(skip_serializing_if = "Option::is_none")]
 | 
					    #[serde(skip_serializing_if = "Option::is_none")]
 | 
				
			||||||
    local_hostname: Option<String>,
 | 
					    pub local_hostname: Option<String>,
 | 
				
			||||||
    /// Network configuration
 | 
					    /// Network configuration
 | 
				
			||||||
    #[serde(skip_serializing_if = "Option::is_none")]
 | 
					    #[serde(skip_serializing_if = "Option::is_none")]
 | 
				
			||||||
    network_configuration: Option<String>,
 | 
					    pub network_configuration: Option<String>,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl CloudInitConfig {
 | 
					impl CloudInitConfig {
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user