Split file_disks_utils into two files
	
		
			
	
		
	
	
		
	
		
			Some checks failed
		
		
	
	
		
			
				
	
				continuous-integration/drone/push Build is failing
				
			
		
		
	
	
				
					
				
			
		
			Some checks failed
		
		
	
	continuous-integration/drone/push Build is failing
				
			This commit is contained in:
		@@ -4,9 +4,9 @@ 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::utils::file_disks_utils::{VMDiskFormat, VMFileDisk};
 | 
			
		||||
use crate::utils::files_utils;
 | 
			
		||||
use crate::utils::files_utils::convert_size_unit_to_mb;
 | 
			
		||||
use crate::utils::vm_file_disks_utils::{VMDiskFormat, VMFileDisk};
 | 
			
		||||
use lazy_regex::regex;
 | 
			
		||||
use num::Integer;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,10 +1,6 @@
 | 
			
		||||
use crate::app_config::AppConfig;
 | 
			
		||||
use crate::constants;
 | 
			
		||||
use crate::libvirt_lib_structures::XMLUuid;
 | 
			
		||||
use crate::utils::files_utils;
 | 
			
		||||
use lazy_regex::regex;
 | 
			
		||||
use std::os::linux::fs::MetadataExt;
 | 
			
		||||
use std::path::{Path, PathBuf};
 | 
			
		||||
use std::path::Path;
 | 
			
		||||
use std::process::Command;
 | 
			
		||||
use std::time::UNIX_EPOCH;
 | 
			
		||||
 | 
			
		||||
@@ -12,173 +8,6 @@ use std::time::UNIX_EPOCH;
 | 
			
		||||
enum DisksError {
 | 
			
		||||
    #[error("DiskParseError: {0}")]
 | 
			
		||||
    Parse(&'static str),
 | 
			
		||||
    #[error("DiskConfigError: {0}")]
 | 
			
		||||
    Config(&'static str),
 | 
			
		||||
    #[error("DiskCreateError")]
 | 
			
		||||
    Create,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Type of disk allocation
 | 
			
		||||
#[derive(Copy, Clone, Debug, serde::Serialize, serde::Deserialize)]
 | 
			
		||||
pub enum VMDiskAllocType {
 | 
			
		||||
    Fixed,
 | 
			
		||||
    Sparse,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Disk allocation type
 | 
			
		||||
#[derive(serde::Serialize, serde::Deserialize)]
 | 
			
		||||
#[serde(tag = "format")]
 | 
			
		||||
pub enum VMDiskFormat {
 | 
			
		||||
    Raw {
 | 
			
		||||
        /// Type of disk allocation
 | 
			
		||||
        alloc_type: VMDiskAllocType,
 | 
			
		||||
    },
 | 
			
		||||
    QCow2,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(serde::Serialize, serde::Deserialize)]
 | 
			
		||||
pub struct VMFileDisk {
 | 
			
		||||
    /// Disk name
 | 
			
		||||
    pub name: String,
 | 
			
		||||
    /// Disk size, in bytes
 | 
			
		||||
    pub size: usize,
 | 
			
		||||
    /// Disk format
 | 
			
		||||
    #[serde(flatten)]
 | 
			
		||||
    pub format: VMDiskFormat,
 | 
			
		||||
    /// Set this variable to true to delete the disk
 | 
			
		||||
    pub delete: bool,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl VMFileDisk {
 | 
			
		||||
    pub fn load_from_file(path: &str) -> anyhow::Result<Self> {
 | 
			
		||||
        let file = Path::new(path);
 | 
			
		||||
 | 
			
		||||
        let info = DiskFileInfo::load_file(file)?;
 | 
			
		||||
 | 
			
		||||
        Ok(Self {
 | 
			
		||||
            name: info.name,
 | 
			
		||||
 | 
			
		||||
            // Get only the virtual size of the file
 | 
			
		||||
            size: match info.format {
 | 
			
		||||
                DiskFileFormat::Raw { .. } => info.file_size,
 | 
			
		||||
                DiskFileFormat::QCow2 { virtual_size } => virtual_size,
 | 
			
		||||
                _ => anyhow::bail!("Unsupported image format: {:?}", info.format),
 | 
			
		||||
            },
 | 
			
		||||
 | 
			
		||||
            format: match info.format {
 | 
			
		||||
                DiskFileFormat::Raw { is_sparse } => VMDiskFormat::Raw {
 | 
			
		||||
                    alloc_type: match is_sparse {
 | 
			
		||||
                        true => VMDiskAllocType::Sparse,
 | 
			
		||||
                        false => VMDiskAllocType::Fixed,
 | 
			
		||||
                    },
 | 
			
		||||
                },
 | 
			
		||||
                DiskFileFormat::QCow2 { .. } => VMDiskFormat::QCow2,
 | 
			
		||||
                _ => anyhow::bail!("Unsupported image format: {:?}", info.format),
 | 
			
		||||
            },
 | 
			
		||||
            delete: false,
 | 
			
		||||
        })
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn check_config(&self) -> anyhow::Result<()> {
 | 
			
		||||
        if constants::DISK_NAME_MIN_LEN > self.name.len()
 | 
			
		||||
            || constants::DISK_NAME_MAX_LEN < self.name.len()
 | 
			
		||||
        {
 | 
			
		||||
            return Err(DisksError::Config("Disk name length is invalid").into());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if !regex!("^[a-zA-Z0-9]+$").is_match(&self.name) {
 | 
			
		||||
            return Err(DisksError::Config("Disk name contains invalid characters!").into());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Check disk size
 | 
			
		||||
        if !(constants::DISK_SIZE_MIN..=constants::DISK_SIZE_MAX).contains(&self.size) {
 | 
			
		||||
            return Err(DisksError::Config("Disk size is invalid!").into());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        Ok(())
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Get disk path
 | 
			
		||||
    pub fn disk_path(&self, id: XMLUuid) -> PathBuf {
 | 
			
		||||
        let domain_dir = AppConfig::get().vm_storage_path(id);
 | 
			
		||||
        let file_name = match self.format {
 | 
			
		||||
            VMDiskFormat::Raw { .. } => self.name.to_string(),
 | 
			
		||||
            VMDiskFormat::QCow2 => format!("{}.qcow2", self.name),
 | 
			
		||||
        };
 | 
			
		||||
        domain_dir.join(&file_name)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Apply disk configuration
 | 
			
		||||
    pub fn apply_config(&self, id: XMLUuid) -> anyhow::Result<()> {
 | 
			
		||||
        self.check_config()?;
 | 
			
		||||
 | 
			
		||||
        let file = self.disk_path(id);
 | 
			
		||||
        files_utils::create_directory_if_missing(file.parent().unwrap())?;
 | 
			
		||||
 | 
			
		||||
        // Delete file if requested
 | 
			
		||||
        if self.delete {
 | 
			
		||||
            if !file.exists() {
 | 
			
		||||
                log::debug!("File {file:?} does not exists, so it was not deleted");
 | 
			
		||||
                return Ok(());
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            log::info!("Deleting {file:?}");
 | 
			
		||||
            std::fs::remove_file(file)?;
 | 
			
		||||
            return Ok(());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if file.exists() {
 | 
			
		||||
            log::debug!("File {file:?} does not exists, so it was not touched");
 | 
			
		||||
            return Ok(());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Prepare command to create file
 | 
			
		||||
        let res = match self.format {
 | 
			
		||||
            VMDiskFormat::Raw { alloc_type } => {
 | 
			
		||||
                let mut cmd = Command::new("/usr/bin/dd");
 | 
			
		||||
                cmd.arg("if=/dev/zero")
 | 
			
		||||
                    .arg(format!("of={}", file.to_string_lossy()))
 | 
			
		||||
                    .arg("bs=1M");
 | 
			
		||||
 | 
			
		||||
                match alloc_type {
 | 
			
		||||
                    VMDiskAllocType::Fixed => cmd.arg(format!("count={}", self.size_mb())),
 | 
			
		||||
                    VMDiskAllocType::Sparse => {
 | 
			
		||||
                        cmd.arg(format!("seek={}", self.size_mb())).arg("count=0")
 | 
			
		||||
                    }
 | 
			
		||||
                };
 | 
			
		||||
 | 
			
		||||
                cmd.output()?
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            VMDiskFormat::QCow2 => {
 | 
			
		||||
                let mut cmd = Command::new(constants::QEMU_IMAGE_PROGRAM);
 | 
			
		||||
                cmd.arg("create")
 | 
			
		||||
                    .arg("-f")
 | 
			
		||||
                    .arg("qcow2")
 | 
			
		||||
                    .arg(file)
 | 
			
		||||
                    .arg(format!("{}M", self.size_mb()));
 | 
			
		||||
 | 
			
		||||
                cmd.output()?
 | 
			
		||||
            }
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        // Execute Linux command
 | 
			
		||||
        if !res.status.success() {
 | 
			
		||||
            log::error!(
 | 
			
		||||
                "Failed to create disk! stderr={} stdout={}",
 | 
			
		||||
                String::from_utf8_lossy(&res.stderr),
 | 
			
		||||
                String::from_utf8_lossy(&res.stdout)
 | 
			
		||||
            );
 | 
			
		||||
            return Err(DisksError::Create.into());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        Ok(())
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Get the size of file disk in megabytes
 | 
			
		||||
    pub fn size_mb(&self) -> usize {
 | 
			
		||||
        self.size / (1000 * 1000)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, serde::Serialize)]
 | 
			
		||||
@@ -193,12 +22,12 @@ pub enum DiskFileFormat {
 | 
			
		||||
/// Disk file information
 | 
			
		||||
#[derive(serde::Serialize)]
 | 
			
		||||
pub struct DiskFileInfo {
 | 
			
		||||
    file_size: usize,
 | 
			
		||||
    pub file_size: usize,
 | 
			
		||||
    #[serde(flatten)]
 | 
			
		||||
    format: DiskFileFormat,
 | 
			
		||||
    file_name: String,
 | 
			
		||||
    name: String,
 | 
			
		||||
    created: u64,
 | 
			
		||||
    pub format: DiskFileFormat,
 | 
			
		||||
    pub file_name: String,
 | 
			
		||||
    pub name: String,
 | 
			
		||||
    pub created: u64,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl DiskFileInfo {
 | 
			
		||||
 
 | 
			
		||||
@@ -5,3 +5,4 @@ pub mod net_utils;
 | 
			
		||||
pub mod rand_utils;
 | 
			
		||||
pub mod time_utils;
 | 
			
		||||
pub mod url_utils;
 | 
			
		||||
pub mod vm_file_disks_utils;
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										179
									
								
								virtweb_backend/src/utils/vm_file_disks_utils.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										179
									
								
								virtweb_backend/src/utils/vm_file_disks_utils.rs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,179 @@
 | 
			
		||||
use crate::app_config::AppConfig;
 | 
			
		||||
use crate::constants;
 | 
			
		||||
use crate::libvirt_lib_structures::XMLUuid;
 | 
			
		||||
use crate::utils::file_disks_utils::{DiskFileFormat, DiskFileInfo};
 | 
			
		||||
use crate::utils::files_utils;
 | 
			
		||||
use lazy_regex::regex;
 | 
			
		||||
use std::path::{Path, PathBuf};
 | 
			
		||||
use std::process::Command;
 | 
			
		||||
 | 
			
		||||
#[derive(thiserror::Error, Debug)]
 | 
			
		||||
enum VMDisksError {
 | 
			
		||||
    #[error("DiskConfigError: {0}")]
 | 
			
		||||
    Config(&'static str),
 | 
			
		||||
    #[error("DiskCreateError")]
 | 
			
		||||
    Create,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Type of disk allocation
 | 
			
		||||
#[derive(Copy, Clone, Debug, serde::Serialize, serde::Deserialize)]
 | 
			
		||||
pub enum VMDiskAllocType {
 | 
			
		||||
    Fixed,
 | 
			
		||||
    Sparse,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Disk allocation type
 | 
			
		||||
#[derive(serde::Serialize, serde::Deserialize)]
 | 
			
		||||
#[serde(tag = "format")]
 | 
			
		||||
pub enum VMDiskFormat {
 | 
			
		||||
    Raw {
 | 
			
		||||
        /// Type of disk allocation
 | 
			
		||||
        alloc_type: VMDiskAllocType,
 | 
			
		||||
    },
 | 
			
		||||
    QCow2,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(serde::Serialize, serde::Deserialize)]
 | 
			
		||||
pub struct VMFileDisk {
 | 
			
		||||
    /// Disk name
 | 
			
		||||
    pub name: String,
 | 
			
		||||
    /// Disk size, in bytes
 | 
			
		||||
    pub size: usize,
 | 
			
		||||
    /// Disk format
 | 
			
		||||
    #[serde(flatten)]
 | 
			
		||||
    pub format: VMDiskFormat,
 | 
			
		||||
    /// Set this variable to true to delete the disk
 | 
			
		||||
    pub delete: bool,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl VMFileDisk {
 | 
			
		||||
    pub fn load_from_file(path: &str) -> anyhow::Result<Self> {
 | 
			
		||||
        let file = Path::new(path);
 | 
			
		||||
 | 
			
		||||
        let info = DiskFileInfo::load_file(file)?;
 | 
			
		||||
 | 
			
		||||
        Ok(Self {
 | 
			
		||||
            name: info.name,
 | 
			
		||||
 | 
			
		||||
            // Get only the virtual size of the file
 | 
			
		||||
            size: match info.format {
 | 
			
		||||
                DiskFileFormat::Raw { .. } => info.file_size,
 | 
			
		||||
                DiskFileFormat::QCow2 { virtual_size } => virtual_size,
 | 
			
		||||
                _ => anyhow::bail!("Unsupported image format: {:?}", info.format),
 | 
			
		||||
            },
 | 
			
		||||
 | 
			
		||||
            format: match info.format {
 | 
			
		||||
                DiskFileFormat::Raw { is_sparse } => VMDiskFormat::Raw {
 | 
			
		||||
                    alloc_type: match is_sparse {
 | 
			
		||||
                        true => VMDiskAllocType::Sparse,
 | 
			
		||||
                        false => VMDiskAllocType::Fixed,
 | 
			
		||||
                    },
 | 
			
		||||
                },
 | 
			
		||||
                DiskFileFormat::QCow2 { .. } => VMDiskFormat::QCow2,
 | 
			
		||||
                _ => anyhow::bail!("Unsupported image format: {:?}", info.format),
 | 
			
		||||
            },
 | 
			
		||||
            delete: false,
 | 
			
		||||
        })
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn check_config(&self) -> anyhow::Result<()> {
 | 
			
		||||
        if constants::DISK_NAME_MIN_LEN > self.name.len()
 | 
			
		||||
            || constants::DISK_NAME_MAX_LEN < self.name.len()
 | 
			
		||||
        {
 | 
			
		||||
            return Err(VMDisksError::Config("Disk name length is invalid").into());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if !regex!("^[a-zA-Z0-9]+$").is_match(&self.name) {
 | 
			
		||||
            return Err(VMDisksError::Config("Disk name contains invalid characters!").into());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Check disk size
 | 
			
		||||
        if !(constants::DISK_SIZE_MIN..=constants::DISK_SIZE_MAX).contains(&self.size) {
 | 
			
		||||
            return Err(VMDisksError::Config("Disk size is invalid!").into());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        Ok(())
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Get disk path
 | 
			
		||||
    pub fn disk_path(&self, id: XMLUuid) -> PathBuf {
 | 
			
		||||
        let domain_dir = AppConfig::get().vm_storage_path(id);
 | 
			
		||||
        let file_name = match self.format {
 | 
			
		||||
            VMDiskFormat::Raw { .. } => self.name.to_string(),
 | 
			
		||||
            VMDiskFormat::QCow2 => format!("{}.qcow2", self.name),
 | 
			
		||||
        };
 | 
			
		||||
        domain_dir.join(&file_name)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Apply disk configuration
 | 
			
		||||
    pub fn apply_config(&self, id: XMLUuid) -> anyhow::Result<()> {
 | 
			
		||||
        self.check_config()?;
 | 
			
		||||
 | 
			
		||||
        let file = self.disk_path(id);
 | 
			
		||||
        files_utils::create_directory_if_missing(file.parent().unwrap())?;
 | 
			
		||||
 | 
			
		||||
        // Delete file if requested
 | 
			
		||||
        if self.delete {
 | 
			
		||||
            if !file.exists() {
 | 
			
		||||
                log::debug!("File {file:?} does not exists, so it was not deleted");
 | 
			
		||||
                return Ok(());
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            log::info!("Deleting {file:?}");
 | 
			
		||||
            std::fs::remove_file(file)?;
 | 
			
		||||
            return Ok(());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if file.exists() {
 | 
			
		||||
            log::debug!("File {file:?} does not exists, so it was not touched");
 | 
			
		||||
            return Ok(());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Prepare command to create file
 | 
			
		||||
        let res = match self.format {
 | 
			
		||||
            VMDiskFormat::Raw { alloc_type } => {
 | 
			
		||||
                let mut cmd = Command::new("/usr/bin/dd");
 | 
			
		||||
                cmd.arg("if=/dev/zero")
 | 
			
		||||
                    .arg(format!("of={}", file.to_string_lossy()))
 | 
			
		||||
                    .arg("bs=1M");
 | 
			
		||||
 | 
			
		||||
                match alloc_type {
 | 
			
		||||
                    VMDiskAllocType::Fixed => cmd.arg(format!("count={}", self.size_mb())),
 | 
			
		||||
                    VMDiskAllocType::Sparse => {
 | 
			
		||||
                        cmd.arg(format!("seek={}", self.size_mb())).arg("count=0")
 | 
			
		||||
                    }
 | 
			
		||||
                };
 | 
			
		||||
 | 
			
		||||
                cmd.output()?
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            VMDiskFormat::QCow2 => {
 | 
			
		||||
                let mut cmd = Command::new(constants::QEMU_IMAGE_PROGRAM);
 | 
			
		||||
                cmd.arg("create")
 | 
			
		||||
                    .arg("-f")
 | 
			
		||||
                    .arg("qcow2")
 | 
			
		||||
                    .arg(file)
 | 
			
		||||
                    .arg(format!("{}M", self.size_mb()));
 | 
			
		||||
 | 
			
		||||
                cmd.output()?
 | 
			
		||||
            }
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        // Execute Linux command
 | 
			
		||||
        if !res.status.success() {
 | 
			
		||||
            log::error!(
 | 
			
		||||
                "Failed to create disk! stderr={} stdout={}",
 | 
			
		||||
                String::from_utf8_lossy(&res.stderr),
 | 
			
		||||
                String::from_utf8_lossy(&res.stdout)
 | 
			
		||||
            );
 | 
			
		||||
            return Err(VMDisksError::Create.into());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        Ok(())
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Get the size of file disk in megabytes
 | 
			
		||||
    pub fn size_mb(&self) -> usize {
 | 
			
		||||
        self.size / (1000 * 1000)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user