aboutsummaryrefslogtreecommitdiffstats
path: root/zone_zfs/src/file_system.rs
diff options
context:
space:
mode:
Diffstat (limited to 'zone_zfs/src/file_system.rs')
-rw-r--r--zone_zfs/src/file_system.rs157
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()
+ }
+}