Can backup vm disks as images
This commit is contained in:
@ -1,6 +1,8 @@
|
||||
use crate::app_config::AppConfig;
|
||||
use crate::constants;
|
||||
use crate::controllers::HttpResult;
|
||||
use crate::controllers::{HttpResult, LibVirtReq};
|
||||
use crate::libvirt_lib_structures::XMLUuid;
|
||||
use crate::libvirt_rest_structures::vm::VMInfo;
|
||||
use crate::utils::file_disks_utils::{DiskFileFormat, DiskFileInfo};
|
||||
use crate::utils::files_utils;
|
||||
use actix_files::NamedFile;
|
||||
@ -107,6 +109,61 @@ pub async fn convert(
|
||||
return Ok(HttpResponse::BadRequest().json("Invalid src file name!"));
|
||||
}
|
||||
|
||||
let src_file_path = AppConfig::get()
|
||||
.disk_images_storage_path()
|
||||
.join(&p.filename);
|
||||
|
||||
let src = DiskFileInfo::load_file(&src_file_path)?;
|
||||
|
||||
handle_convert_request(src, &req).await
|
||||
}
|
||||
|
||||
#[derive(serde::Deserialize)]
|
||||
pub struct BackupVMDiskPath {
|
||||
uid: XMLUuid,
|
||||
diskid: String,
|
||||
}
|
||||
|
||||
/// Perform disk backup
|
||||
pub async fn backup_disk(
|
||||
client: LibVirtReq,
|
||||
path: web::Path<BackupVMDiskPath>,
|
||||
req: web::Json<ConvertDiskImageRequest>,
|
||||
) -> HttpResult {
|
||||
// Get the VM information
|
||||
let info = match client.get_single_domain(path.uid).await {
|
||||
Ok(i) => i,
|
||||
Err(e) => {
|
||||
log::error!("Failed to get domain info! {e}");
|
||||
return Ok(HttpResponse::InternalServerError().json(e.to_string()));
|
||||
}
|
||||
};
|
||||
|
||||
let vm = VMInfo::from_domain(info)?;
|
||||
|
||||
// Load disk information
|
||||
let Some(disk) = vm
|
||||
.file_disks
|
||||
.into_iter()
|
||||
.find(|disk| disk.name == path.diskid)
|
||||
else {
|
||||
return Ok(HttpResponse::NotFound()
|
||||
.json(format!("Disk {} not found for vm {}", path.diskid, vm.name)));
|
||||
};
|
||||
|
||||
let src_path = disk.disk_path(vm.uuid.expect("Missing VM uuid!"));
|
||||
let src_disk = DiskFileInfo::load_file(&src_path)?;
|
||||
|
||||
// Perform conversion
|
||||
handle_convert_request(src_disk, &req).await
|
||||
}
|
||||
|
||||
/// Generic controller code that performs image conversion to create a disk image file
|
||||
pub async fn handle_convert_request(
|
||||
src: DiskFileInfo,
|
||||
req: &ConvertDiskImageRequest,
|
||||
) -> HttpResult {
|
||||
// Check destination file
|
||||
if !files_utils::check_file_name(&req.dest_file_name) {
|
||||
return Ok(HttpResponse::BadRequest().json("Invalid destination file name!"));
|
||||
}
|
||||
@ -119,12 +176,6 @@ pub async fn convert(
|
||||
return Ok(HttpResponse::BadRequest().json("Invalid destination file extension!"));
|
||||
}
|
||||
|
||||
let src_file_path = AppConfig::get()
|
||||
.disk_images_storage_path()
|
||||
.join(&p.filename);
|
||||
|
||||
let src = DiskFileInfo::load_file(&src_file_path)?;
|
||||
|
||||
let dst_file_path = AppConfig::get()
|
||||
.disk_images_storage_path()
|
||||
.join(&req.dest_file_name);
|
||||
@ -141,7 +192,7 @@ pub async fn convert(
|
||||
);
|
||||
}
|
||||
|
||||
Ok(HttpResponse::Ok().json(src))
|
||||
Ok(HttpResponse::Accepted().json("Successfully converted disk file"))
|
||||
}
|
||||
|
||||
/// Delete a disk image
|
||||
|
@ -356,6 +356,10 @@ async fn main() -> std::io::Result<()> {
|
||||
"/api/disk_images/{filename}",
|
||||
web::delete().to(disk_images_controller::delete),
|
||||
)
|
||||
.route(
|
||||
"/api/vm/{uid}/disk/{diskid}/backup",
|
||||
web::post().to(disk_images_controller::backup_disk),
|
||||
)
|
||||
// API tokens controller
|
||||
.route(
|
||||
"/api/token/create",
|
||||
|
@ -93,7 +93,7 @@ impl VMFileDisk {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Get disk path
|
||||
/// Get disk path on file system
|
||||
pub fn disk_path(&self, id: XMLUuid) -> PathBuf {
|
||||
let domain_dir = AppConfig::get().vm_storage_path(id);
|
||||
let file_name = match self.format {
|
||||
|
Reference in New Issue
Block a user