diff options
Diffstat (limited to 'zone_zfs/src')
-rw-r--r-- | zone_zfs/src/file_system.rs | 73 | ||||
-rw-r--r-- | zone_zfs/src/lib.rs | 62 | ||||
-rw-r--r-- | zone_zfs/src/snapshot.rs | 25 |
3 files changed, 82 insertions, 78 deletions
diff --git a/zone_zfs/src/file_system.rs b/zone_zfs/src/file_system.rs index 50e3c56..83164c9 100644 --- a/zone_zfs/src/file_system.rs +++ b/zone_zfs/src/file_system.rs @@ -1,12 +1,11 @@ -use anyhow::{anyhow, Context, Result}; use std::{ ffi::{OsStr, OsString}, fmt::Display, path::PathBuf, - process::{Command, Output}, + process::Command, }; -use super::snapshot::Snapshot; +use crate::{snapshot::Snapshot, Error, Result}; #[derive(Debug)] pub struct FileSystem { @@ -22,9 +21,9 @@ impl Display for FileSystem { // pool/000.0/nkollack-1 impl TryFrom<OsString> for FileSystem { - type Error = anyhow::Error; + type Error = Error; - fn try_from(value: OsString) -> Result<Self, Self::Error> { + fn try_from(value: OsString) -> Result<Self> { Ok(FileSystem { value, mountpoint: None, @@ -33,9 +32,9 @@ impl TryFrom<OsString> for FileSystem { } impl TryFrom<&str> for FileSystem { - type Error = anyhow::Error; + type Error = Error; - fn try_from(value: &str) -> Result<Self, Self::Error> { + fn try_from(value: &str) -> Result<Self> { value.try_into() } } @@ -58,34 +57,24 @@ impl From<FileSystem> for String { } } -impl TryFrom<Output> for FileSystem { - type Error = anyhow::Error; - - fn try_from(value: Output) -> Result<Self, Self::Error> { - std::str::from_utf8(&value.stdout)?.try_into() - } -} - impl FileSystem { pub(super) fn get_name(&self) -> Result<String> { Ok(PathBuf::from(self.value.clone()) .file_name() - .context("Invalid path for filesystem")? + .ok_or_else(|| Error::FileSystem(format!("Invalid path for filesystem: {:?}", self)))? .to_string_lossy() .into_owned()) } pub(super) fn set_quota(&self, quota: &str) -> Result<()> { - match Command::new("zfs") + Command::new("zfs") .arg("set") .arg(format!("quota={}", quota)) .arg(&self.value) .status()? .success() - { - true => Ok(()), - false => Err(anyhow!("Failed to set a quota: {:?}", self)), - } + .then(|| ()) + .ok_or_else(|| Error::FileSystem(format!("Failed to set quota: {:?}", self))) } pub(super) fn get_snapshots(&self) -> Result<Vec<Snapshot>> { @@ -100,7 +89,8 @@ impl FileSystem { .output()? .stdout; - String::from_utf8(stdout)? + String::from_utf8(stdout) + .map_err(|err| Error::FileSystem(format!("Failed to parse command output: {:?}", err)))? .split_whitespace() .map(|s| s.try_into()) .collect() @@ -115,7 +105,7 @@ impl FileSystem { } pub(super) fn get_file_systems() -> Result<Vec<FileSystem>> { - let output = Command::new("zfs") + let stdout = Command::new("zfs") .arg("list") .arg("-H") .arg("-o") @@ -123,34 +113,31 @@ impl FileSystem { .output()? .stdout; - std::str::from_utf8(&output)? + String::from_utf8(stdout) + .map_err(|err| Error::FileSystem(format!("Failed to parse command output: {:?}", err)))? .split_whitespace() - .map(|fs| fs.try_into()) + .map(|s| s.try_into()) .collect() } pub fn mount(&self) -> Result<()> { - match Command::new("zfs") + Command::new("zfs") .arg("mount") .arg(&self.value) .status()? .success() - { - true => Ok(()), - false => Err(anyhow!("Failed to mount the filesystem: {:?}", self)), - } + .then(|| ()) + .ok_or_else(|| Error::FileSystem(format!("Failed to mount: {:?}", self))) } pub fn unmount(&self) -> Result<()> { - match Command::new("zfs") + Command::new("zfs") .arg("unmount") .arg(&self.value) .status()? .success() - { - true => Ok(()), - false => Err(anyhow!("Failed to unmount the filesystem: {:?}", self)), - } + .then(|| ()) + .ok_or_else(|| Error::FileSystem(format!("Failed to unmount: {:?}", self))) } pub fn destroy(&self, force: bool) -> Result<()> { @@ -161,14 +148,12 @@ impl FileSystem { } args.push(&self.value); - match Command::new("zfs") - .arg("destroy") - .args(args) - .status()? - .success() - { - true => Ok(()), - false => Err(anyhow!("Failed to destroy the filesystem: {:?}", self)), - } + Command::new("zfs") + .arg("destroy") + .args(args) + .status()? + .success() + .then(|| ()) + .ok_or_else(|| Error::FileSystem(format!("Failed to destroy: {:?}", self))) } } diff --git a/zone_zfs/src/lib.rs b/zone_zfs/src/lib.rs index 53947a6..c430cba 100644 --- a/zone_zfs/src/lib.rs +++ b/zone_zfs/src/lib.rs @@ -1,13 +1,32 @@ use self::file_system::FileSystem; -use anyhow::Result; -use figment::{providers::{Serialized, Toml, Env, Format}, Figment, Metadata, Profile, Provider}; +use figment::{ + providers::{Env, Format, Serialized, Toml}, + Figment, Metadata, Profile, Provider, +}; use serde::{Deserialize, Serialize}; -use std::path::PathBuf; +use std::{io, path::PathBuf, result}; pub mod file_system; pub mod snapshot; +type Result<T> = result::Result<T, Error>; + +#[derive(thiserror::Error, Debug)] +pub enum Error { + #[error("ZFS error")] + ZFS(String), + + #[error("Snapshot Error: {0:?}")] + Snapshot(String), + + #[error("File System Error: {0:?}")] + FileSystem(String), + + #[error("IO Error: Failed to run command")] + IO(#[from] io::Error), +} + #[derive(Debug, Deserialize, Serialize)] pub struct Config { pub quota: String, @@ -22,11 +41,10 @@ impl Default for Config { } impl Config { - pub fn from<T: Provider>(provider: T) -> Result<Config, figment::Error> { + pub fn from<T: Provider>(provider: T) -> result::Result<Config, figment::Error> { Figment::from(provider).extract() } - // Provide a default provider, a `Figment`. pub fn figment() -> Figment { Figment::from(Config::default()) .merge(Toml::file(Env::var_or("ZFS_CONFIG", "ZFS.toml")).nested()) @@ -39,7 +57,9 @@ impl Provider for Config { Metadata::named("ZFS Config") } - fn data(&self) -> Result<figment::value::Map<Profile, figment::value::Dict>, figment::Error> { + fn data( + &self, + ) -> result::Result<figment::value::Map<Profile, figment::value::Dict>, figment::Error> { Serialized::defaults(Config::default()).data() } } @@ -49,33 +69,27 @@ pub fn create_file_system( name: String, config: &Config, ) -> Result<FileSystem> { - let fs = FileSystem::get_file_systems() - .unwrap() + let fs = FileSystem::get_file_systems()? .into_iter() - .find(|fs| match fs.get_name() { - Ok(name) => name == base_fs_name, - Err(_) => false, + .find_map(|fs| match fs.get_name() { + Ok(n) if n == base_fs_name => Some(fs), + _ => None, }) - .unwrap_or_else(|| todo!("Handle!")); + .ok_or_else(|| Error::FileSystem("No ".to_string()))?; let snapshot = fs - .get_latest_snapshot() - .expect("No snapshot found") - .unwrap(); + .get_latest_snapshot()? + .ok_or_else(|| Error::Snapshot("No snapshot found".to_string()))?; let mut mountpoint = fs.value; mountpoint.push(name); - let cloned_fs = snapshot - .clone_into_file_system( - snapshot.file_system.get_name()?, - Some(PathBuf::from(mountpoint)), - ) - .unwrap(); + let cloned_fs = snapshot.clone_into_file_system( + snapshot.file_system.get_name()?, + Some(PathBuf::from(mountpoint)), + )?; - cloned_fs - .set_quota(&config.quota) - .expect("Failed to set quota"); + cloned_fs.set_quota(&config.quota)?; Ok(cloned_fs) } diff --git a/zone_zfs/src/snapshot.rs b/zone_zfs/src/snapshot.rs index 48faa68..14fafb4 100644 --- a/zone_zfs/src/snapshot.rs +++ b/zone_zfs/src/snapshot.rs @@ -1,11 +1,10 @@ -use anyhow::{anyhow, Result}; use chrono::{DateTime, Utc}; use std::{ffi::OsString, path::PathBuf, process::Command}; use tracing::warn; -use super::file_system::FileSystem; +use crate::{file_system::FileSystem, Error, Result}; -#[derive()] +#[derive(Debug)] pub struct Snapshot { // pool/000.0@00000000000 pub value: OsString, @@ -15,9 +14,9 @@ pub struct Snapshot { impl TryFrom<&str> for Snapshot { // <file_system>@<timestamp> - type Error = anyhow::Error; + type Error = Error; - fn try_from(value: &str) -> Result<Self, Self::Error> { + fn try_from(value: &str) -> Result<Self> { match value.split('@').collect::<Vec<&str>>()[..] { [file_system, name] => Ok(Snapshot { file_system: FileSystem::try_from(file_system)?, @@ -30,7 +29,10 @@ impl TryFrom<&str> for Snapshot { chrono::MIN_DATETIME }), }), - _ => Err(anyhow!("Failed to parse snapshot: {}", value)), + _ => Err(Error::Snapshot(format!( + "Failed to parse snapshot: {:?}", + value + ))), } } } @@ -56,9 +58,12 @@ impl Snapshot { .arg(format!("mountpoint={}", mp.to_string_lossy())); }; - match command.arg(&self.value).arg(&new_fs).status()?.success() { - true => Ok(new_fs), - false => Err(anyhow!("Failed to clone snapshot: {:?}", new_fs)), - } + command + .arg(&self.value) + .arg(&new_fs) + .status()? + .success() + .then(|| new_fs) + .ok_or_else(|| Error::Snapshot(format!("Failed to clone snapshot: {:?}", self))) } } |