Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
bnaecker committed Oct 5, 2023
1 parent d300fb8 commit 28d42ca
Show file tree
Hide file tree
Showing 3 changed files with 701 additions and 14 deletions.
13 changes: 11 additions & 2 deletions illumos-utils/src/running_zone.rs
Original file line number Diff line number Diff line change
Expand Up @@ -391,13 +391,16 @@ pub struct RunningZone {
}

impl RunningZone {
/// The path to the zone's root filesystem (i.e., `/`), within zonepath.
pub const ROOT_FS_PATH: &'static str = "root";

pub fn name(&self) -> &str {
&self.inner.name
}

/// Returns the filesystem path to the zone's root
/// Returns the filesystem path to the zone's root in the GZ.
pub fn root(&self) -> Utf8PathBuf {
self.inner.zonepath.join("root")
self.inner.zonepath.join(Self::ROOT_FS_PATH)
}

pub fn control_interface(&self) -> AddrObject {
Expand Down Expand Up @@ -1006,6 +1009,10 @@ impl RunningZone {
let Some(current) = lines.next() else {
return Ok(None);
};
return Ok(Some((Utf8PathBuf::from(current.trim()), vec![])));

/*
* TODO(ben): Remove this.
// We need to prepend the zonepath root to get the path in the GZ. We
// can do this with `join()`, but that will _replace_ the path if the
// second one is absolute. So trim any prefixed `/` from each path.
Expand Down Expand Up @@ -1038,6 +1045,7 @@ impl RunningZone {
}
Ok(Some((current_log_file, rotated_files)))
*/
}
}

Expand Down Expand Up @@ -1088,6 +1096,7 @@ pub struct ServiceProcess {
pub pid: u32,
/// The path for the current log file.
pub log_file: Utf8PathBuf,
// TODO(ben): remove, we'll do the matching on the snapshot later
/// The paths for any rotated log files.
pub rotated_log_files: Vec<Utf8PathBuf>,
}
Expand Down
135 changes: 135 additions & 0 deletions illumos-utils/src/zfs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,35 @@ pub struct GetValueError {
err: GetValueErrorRaw,
}

#[derive(Debug, thiserror::Error)]
#[error("Failed to list snapshots: {0}")]
pub struct ListSnapshotsError(#[from] crate::ExecutionError);

#[derive(Debug, thiserror::Error)]
#[error("Failed to create snapshot '{snap_name}' from filesystem '{filesystem}': {err}")]
pub struct CreateSnapshotError {
filesystem: String,
snap_name: String,
err: crate::ExecutionError,
}

#[derive(Debug, thiserror::Error)]
#[error("Failed to delete snapshot '{filesystem}@{snap_name}': {err}")]
pub struct DestroySnapshotError {
filesystem: String,
snap_name: String,
err: crate::ExecutionError,
}

#[derive(Debug, thiserror::Error)]
#[error("Failed to create clone '{clone_name}' from snapshot '{filesystem}@{snap_name}': {err}")]
pub struct CloneSnapshotError {
filesystem: String,
snap_name: String,
clone_name: String,
err: crate::ExecutionError,
}

/// Wraps commands for interacting with ZFS.
pub struct Zfs {}

Expand Down Expand Up @@ -181,6 +210,20 @@ impl Zfs {
Ok(filesystems)
}

/// Return the name of a dataset for a ZFS object.
///
/// The object can either be a dataset name, or a path, in which case it
/// will be resolved to the _mounted_ ZFS dataset containing that path.
pub fn get_dataset_name(object: &str) -> Result<String, ListDatasetsError> {
let mut command = std::process::Command::new(ZFS);
let cmd = command.args(&["get", "-Hpo", "name", "name", object]);
execute(cmd)
.map(|output| {
String::from_utf8_lossy(&output.stdout).trim().to_string()
})
.map_err(|err| ListDatasetsError { name: object.to_string(), err })
}

/// Destroys a dataset.
pub fn destroy_dataset(name: &str) -> Result<(), DestroyDatasetError> {
let mut command = std::process::Command::new(PFEXEC);
Expand Down Expand Up @@ -353,6 +396,7 @@ impl Zfs {
}
}

/// Set the value of an Oxide-managed ZFS property.
pub fn set_oxide_value(
filesystem_name: &str,
name: &str,
Expand All @@ -378,6 +422,7 @@ impl Zfs {
Ok(())
}

/// Get the value of an Oxide-managed ZFS property.
pub fn get_oxide_value(
filesystem_name: &str,
name: &str,
Expand Down Expand Up @@ -408,6 +453,96 @@ impl Zfs {
}
Ok(value.to_string())
}

/// List all extant snapshots.
pub fn list_snapshots() -> Result<Vec<Snapshot>, ListSnapshotsError> {
let mut command = std::process::Command::new(ZFS);
let cmd = command.args(&["list", "-H", "-o", "name", "-t", "snapshot"]);
execute(cmd)
.map(|output| {
let stdout = String::from_utf8_lossy(&output.stdout);
stdout
.trim()
.lines()
.map(|line| {
let (filesystem, snap_name) =
line.split_once('@').unwrap();
Snapshot {
filesystem: filesystem.to_string(),
snap_name: snap_name.to_string(),
}
})
.collect()
})
.map_err(ListSnapshotsError::from)
}

/// Create a snapshot of a filesystem.
pub fn create_snapshot(
filesystem: &str,
snap_name: &str,
) -> Result<(), CreateSnapshotError> {
let mut command = std::process::Command::new(ZFS);
let path = format!("{filesystem}@{snap_name}");
let cmd = command.args(&["snapshot", &path]);
execute(cmd).map(|_| ()).map_err(|err| CreateSnapshotError {
filesystem: filesystem.to_string(),
snap_name: snap_name.to_string(),
err,
})
}

/// Destroy a named snapshot of a filesystem.
pub fn destroy_snapshot(
filesystem: &str,
snap_name: &str,
) -> Result<(), DestroySnapshotError> {
let mut command = std::process::Command::new(ZFS);
let path = format!("{filesystem}@{snap_name}");
let cmd = command.args(&["destroy", &path]);
execute(cmd).map(|_| ()).map_err(|err| DestroySnapshotError {
filesystem: filesystem.to_string(),
snap_name: snap_name.to_string(),
err,
})
}

/// Create a clone of a snapshot.
pub fn clone_snapshot(
filesystem: &str,
snap_name: &str,
clone_name: &str,
) -> Result<(), CloneSnapshotError> {
let mut command = std::process::Command::new(ZFS);
let snap_path = format!("{filesystem}@{snap_name}");
let cmd = command.args(&["clone", &snap_path, clone_name]);
execute(cmd).map(|_| ()).map_err(|err| CloneSnapshotError {
filesystem: filesystem.to_string(),
snap_name: snap_name.to_string(),
clone_name: clone_name.to_string(),
err,
})
}
}

/// A read-only snapshot of a ZFS filesystem.
#[derive(Clone, Debug)]
pub struct Snapshot {
pub filesystem: String,
pub snap_name: String,
}

impl fmt::Display for Snapshot {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}@{}", self.filesystem, self.snap_name)
}
}

/// A clone of a ZFS snapshot.
#[derive(Clone, Debug)]
pub struct Clone {
pub snapshot: Snapshot,
pub clone_name: String,
}

/// Returns all datasets managed by Omicron
Expand Down
Loading

0 comments on commit 28d42ca

Please sign in to comment.