summaryrefslogtreecommitdiff
path: root/src/image.rs
blob: 7b7c2ce856f3f3e4ff78f25cfe01320ba5c7a3fb (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
//! Virtual machine image handling.

use std::fs::copy;
use std::path::{Path, PathBuf};
use std::process::Command;
use std::result::Result;

/// Errors from this module.
#[derive(Debug, thiserror::Error)]
pub enum ImageError {
    /// Error resizing image.
    #[error("qemu-img resize failed: {0}")]
    ResizeError(String),

    /// Base image copy error.
    #[error("could not copy base image {0} to {1}")]
    BaseImageCopy(PathBuf, PathBuf, #[source] std::io::Error),

    /// Could not execute command.
    #[error("couldn't execute {0}: {1}")]
    CommandError(String, #[source] std::io::Error),

    /// Error parsing a string as UTF8.
    #[error(transparent)]
    StringError(#[from] std::string::FromUtf8Error),
}

/// A virtual machine image.
#[derive(Debug, Clone)]
pub struct VirtualMachineImage {
    filename: PathBuf,
}

impl VirtualMachineImage {
    /// Create new image from a base image.
    pub fn new_from_base(base_image: &Path, image: &Path) -> Result<Self, ImageError> {
        copy(base_image, image).map_err(|err| {
            ImageError::BaseImageCopy(base_image.to_path_buf(), image.to_path_buf(), err)
        })?;
        Ok(Self {
            filename: image.to_path_buf(),
        })
    }

    /// Filename of the image.
    pub fn filename(&self) -> &Path {
        &self.filename
    }

    /// Change size of image.
    pub fn resize(&self, new_size: u64) -> Result<(), ImageError> {
        let r = Command::new("qemu-img")
            .arg("resize")
            .arg(self.filename())
            .arg(format!("{}", new_size))
            .output()
            .map_err(|err| ImageError::CommandError("qemu-img resize".to_string(), err))?;
        if !r.status.success() {
            let stderr = String::from_utf8(r.stderr)?;
            return Err(ImageError::ResizeError(stderr));
        }
        Ok(())
    }
}