Skip to content

Commit

Permalink
feat(zpool): Add replace_disk. Closes #25 (#67)
Browse files Browse the repository at this point in the history
* Add replace_disk. Closes #25
  • Loading branch information
andoriyu authored Jul 8, 2019
1 parent b276f1e commit c4cfc40
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 3 deletions.
17 changes: 14 additions & 3 deletions src/zpool/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -422,7 +422,7 @@ pub trait ZpoolEngine {
/// Add a ZIL to existing Zpool.
///
/// * `name` - Name of the zpool
/// * `new_zil` - VDEV to use as ZIL
/// * `new_zil` - A VDEV to use as ZIL
/// * `add_mode` - Disable some safety checks
fn add_zil<N: AsRef<str>>(
&self,
Expand All @@ -434,7 +434,7 @@ pub trait ZpoolEngine {
/// Add a cache to existing Zpool.
///
/// * `name` - Name of the zpool
/// * `new_cache` - Disk to use as cache
/// * `new_cache` - A disk to use as cache
/// * `add_mode` - Disable some safety checks
fn add_cache<N: AsRef<str>, D: AsRef<OsStr>>(
&self,
Expand All @@ -446,7 +446,7 @@ pub trait ZpoolEngine {
/// Add a spare to existing Zpool.
///
/// * `name` - Name of the zpool
/// * `new_spare` - Disk to use as spare
/// * `new_spare` - A disk to use as spare
/// * `add_mode` - Disable some safety checks
fn add_spare<N: AsRef<str>, D: AsRef<OsStr>>(
&self,
Expand All @@ -455,6 +455,17 @@ pub trait ZpoolEngine {
add_mode: CreateMode,
) -> ZpoolResult<()>;

/// [Replace](https://docs.oracle.com/cd/E19253-01/819-5461/gazgd/index.html) a device with another.
///
/// * `old_disk` - A disk to be replaced.
/// * `new_disk` - A new disk.
fn replace_disk<N: AsRef<str>, D: AsRef<OsStr>, O: AsRef<OsStr>>(
&self,
name: N,
old_disk: D,
new_disk: O,
) -> ZpoolResult<()>;

/// Remove Spare, Cache or log device
///
/// * `name` - Name of the zpool
Expand Down
20 changes: 20 additions & 0 deletions src/zpool/open3.rs
Original file line number Diff line number Diff line change
Expand Up @@ -483,6 +483,26 @@ impl ZpoolEngine for ZpoolOpen3 {
}
}

fn replace_disk<N: AsRef<str>, D: AsRef<OsStr>, O: AsRef<OsStr>>(
&self,
name: N,
old_disk: D,
new_disk: O,
) -> Result<(), ZpoolError> {
let mut z = self.zpool();
z.arg("replace");
z.arg(name.as_ref());
z.arg(old_disk.as_ref());
z.arg(new_disk.as_ref());
debug!(self.logger, "executing"; "cmd" => format_args!("{:?}", z));
let out = z.output()?;
if out.status.success() {
Ok(())
} else {
Err(ZpoolError::from_stderr(&out.stderr))
}
}

fn remove<N: AsRef<str>, D: AsRef<OsStr>>(&self, name: N, device: D) -> ZpoolResult<()> {
let mut z = self.zpool();
z.arg("remove");
Expand Down
36 changes: 36 additions & 0 deletions tests/test_zpool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -853,3 +853,39 @@ fn test_zpool_add_spare() {
assert_eq!(topo_expected, z);
});
}

#[test]
fn test_zpool_replace_disk() {
use std::{thread, time};

run_test(|name| {
let zpool = ZpoolOpen3::default();
let vdev0_path = setup_vdev("/vdevs/vdev0", &Bytes::MegaBytes(64 + 10));
let vdev1_path = setup_vdev("/vdevs/vdev1", &Bytes::MegaBytes(64 + 10));
let vdev2_path = setup_vdev("/vdevs/vdev2", &Bytes::MegaBytes(64 + 10));
let topo = CreateZpoolRequestBuilder::default()
.name(name.clone())
.create_mode(CreateMode::Force)
.vdev(CreateVdevRequest::Mirror(vec![vdev0_path.clone(), vdev1_path.clone()]))
.build()
.unwrap();
zpool.create(topo.clone()).unwrap();

let result = zpool.replace_disk(&name, &vdev0_path, &vdev2_path);
assert!(result.is_ok());

let topo_expected = CreateZpoolRequestBuilder::default()
.name(name.clone())
.create_mode(CreateMode::Force)
.vdev(CreateVdevRequest::Mirror(vec![vdev2_path.clone(), vdev1_path.clone()]))
.build()
.unwrap();

// otherwise test _might_ fail.
let wait_time = time::Duration::from_secs(13);
thread::sleep(wait_time);

let z = zpool.status(&name).unwrap();
assert_eq!(topo_expected, z);
});
}

0 comments on commit c4cfc40

Please sign in to comment.