diff options
Diffstat (limited to 'zone_zfs/src/file_system.rs')
-rw-r--r-- | zone_zfs/src/file_system.rs | 157 |
1 files changed, 157 insertions, 0 deletions
diff --git a/zone_zfs/src/file_system.rs b/zone_zfs/src/file_system.rs new file mode 100644 index 0000000..390c00d --- /dev/null +++ b/zone_zfs/src/file_system.rs @@ -0,0 +1,157 @@ +use anyhow::{anyhow, Context, Result}; +use zone_core::{Container, ContainerStatus}; +use std::{ + ffi::{OsStr, OsString}, + fmt::Display, + path::PathBuf, + process::{Command, Output}, +}; + +use super::snapshot::Snapshot; + +#[derive(Debug)] +pub struct FileSystem { + pub(crate) value: OsString, + pub(crate) mountpoint: Option<PathBuf>, +} + +impl Display for FileSystem { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.value.to_string_lossy()) + } +} + +// pool/000.0/nkollack-1 +impl TryFrom<OsString> for FileSystem { + type Error = anyhow::Error; + + fn try_from(value: OsString) -> Result<Self, Self::Error> { + Ok(FileSystem { + value, + mountpoint: None, + }) + } +} + +impl TryFrom<&str> for FileSystem { + type Error = anyhow::Error; + + fn try_from(value: &str) -> Result<Self, Self::Error> { + value.try_into() + } +} + +impl AsRef<OsStr> for FileSystem { + fn as_ref(&self) -> &OsStr { + self.value.as_ref() + } +} + +impl From<FileSystem> for PathBuf { + fn from(val: FileSystem) -> Self { + PathBuf::from(val.value) + } +} + +impl From<FileSystem> for String { + fn from(val: FileSystem) -> Self { + val.value.to_string_lossy().to_string() + } +} + +impl From<FileSystem> for Container { + fn from(file_system: FileSystem) -> Self { + let path_buf = PathBuf::from(&file_system) + .file_name() + .expect("Invalid FileSystem path") + .to_string_lossy() + .into_owned(); + + let (user, id) = path_buf.rsplit_once("-").expect("Invalid FileSystem name!"); + + Container { + id: id + .parse() + .expect("Failed to parse ID from FileSystem name!"), + template: PathBuf::from(file_system) + .parent() + .expect("Base path has no parent!") + .to_string_lossy() + .into_owned(), + user: user.to_string(), + status: ContainerStatus::default(), + } + } +} + +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")? + .to_string_lossy() + .into_owned()) + } + + fn set_quota(&self) -> Result<()> { + match Command::new("zfs") + .arg("set") + .arg(format!("quota={}", "")) + .arg(&self.value) + .status()? + .success() + { + true => Ok(()), + false => Err(anyhow!("Failed to set a quota: {:?}", self)), + } + } + + pub(super) fn get_snapshots(&self) -> Result<Vec<Snapshot>> { + let stdout = Command::new("zfs") + .arg("list") + .arg("-H") + .arg("-o") + .arg("name") + .arg("-t") + .arg("snapshot") + .arg(self) + .output()? + .stdout; + + String::from_utf8(stdout)? + .split_whitespace() + .map(|s| s.try_into()) + .collect() + } + + pub(super) fn get_latest_snapshot(&self) -> Result<Option<Snapshot>> { + // pool/447.0@210119221709 + Ok(self + .get_snapshots()? + .into_iter() + .max_by_key(|s| s.timestamp)) + } + + pub(super) fn get_file_systems() -> Result<Vec<FileSystem>> { + let output = Command::new("zfs") + .arg("list") + .arg("-H") + .arg("-o") + .arg("name") + .output()? + .stdout; + + std::str::from_utf8(&output)? + .split_whitespace() + .map(|fs| fs.try_into()) + .collect() + } +} |