Generalize disk file creation logic
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:
@ -1,4 +1,5 @@
|
||||
use crate::constants;
|
||||
use crate::utils::file_size_utils::FileSize;
|
||||
use std::os::linux::fs::MetadataExt;
|
||||
use std::path::Path;
|
||||
use std::process::Command;
|
||||
@ -8,13 +9,15 @@ use std::time::UNIX_EPOCH;
|
||||
enum DisksError {
|
||||
#[error("DiskParseError: {0}")]
|
||||
Parse(&'static str),
|
||||
#[error("DiskCreateError")]
|
||||
Create,
|
||||
}
|
||||
|
||||
#[derive(Debug, serde::Serialize)]
|
||||
#[serde(tag = "format")]
|
||||
pub enum DiskFileFormat {
|
||||
Raw { is_sparse: bool },
|
||||
QCow2 { virtual_size: usize },
|
||||
QCow2 { virtual_size: FileSize },
|
||||
CompressedRaw,
|
||||
CompressedQCow2,
|
||||
}
|
||||
@ -22,7 +25,7 @@ pub enum DiskFileFormat {
|
||||
/// Disk file information
|
||||
#[derive(serde::Serialize)]
|
||||
pub struct DiskFileInfo {
|
||||
pub file_size: usize,
|
||||
pub file_size: FileSize,
|
||||
#[serde(flatten)]
|
||||
pub format: DiskFileFormat,
|
||||
pub file_name: String,
|
||||
@ -64,7 +67,7 @@ impl DiskFileInfo {
|
||||
|
||||
Ok(Self {
|
||||
name,
|
||||
file_size: metadata.len() as usize,
|
||||
file_size: FileSize::from_bytes(metadata.len() as usize),
|
||||
format,
|
||||
file_name: file
|
||||
.file_name()
|
||||
@ -78,6 +81,50 @@ impl DiskFileInfo {
|
||||
.as_secs(),
|
||||
})
|
||||
}
|
||||
|
||||
/// Create a new empty disk
|
||||
pub fn create(file: &Path, format: DiskFileFormat, size: FileSize) -> anyhow::Result<()> {
|
||||
// Prepare command to create file
|
||||
let res = match format {
|
||||
DiskFileFormat::Raw { is_sparse } => {
|
||||
let mut cmd = Command::new("/usr/bin/dd");
|
||||
cmd.arg("if=/dev/zero")
|
||||
.arg(format!("of={}", file.to_string_lossy()))
|
||||
.arg("bs=1M");
|
||||
|
||||
match is_sparse {
|
||||
false => cmd.arg(format!("count={}", size.as_mb())),
|
||||
true => cmd.arg(format!("seek={}", size.as_mb())).arg("count=0"),
|
||||
};
|
||||
|
||||
cmd.output()?
|
||||
}
|
||||
|
||||
DiskFileFormat::QCow2 { virtual_size } => {
|
||||
let mut cmd = Command::new(constants::QEMU_IMAGE_PROGRAM);
|
||||
cmd.arg("create")
|
||||
.arg("-f")
|
||||
.arg("qcow2")
|
||||
.arg(file)
|
||||
.arg(format!("{}M", virtual_size.as_mb()));
|
||||
|
||||
cmd.output()?
|
||||
}
|
||||
_ => anyhow::bail!("Cannot create disk file image of this format: {format:?}!"),
|
||||
};
|
||||
|
||||
// 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(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(serde::Deserialize)]
|
||||
@ -87,7 +134,7 @@ struct QCowInfoOutput {
|
||||
}
|
||||
|
||||
/// Get QCow2 virtual size
|
||||
fn qcow_virt_size(path: &Path) -> anyhow::Result<usize> {
|
||||
fn qcow_virt_size(path: &Path) -> anyhow::Result<FileSize> {
|
||||
// Run qemu-img
|
||||
let mut cmd = Command::new(constants::QEMU_IMAGE_PROGRAM);
|
||||
cmd.args([
|
||||
@ -110,5 +157,5 @@ fn qcow_virt_size(path: &Path) -> anyhow::Result<usize> {
|
||||
|
||||
// Decode JSON
|
||||
let decoded: QCowInfoOutput = serde_json::from_str(&res_json)?;
|
||||
Ok(decoded.virtual_size)
|
||||
Ok(FileSize::from_bytes(decoded.virtual_size))
|
||||
}
|
||||
|
Reference in New Issue
Block a user