SHA256
Huge refactor, quicksave
This commit is contained in:
+251
-12
@@ -22,9 +22,26 @@ use nix;
|
||||
use std::fs;
|
||||
use std::process::Command;
|
||||
|
||||
// timeout for block deices population
|
||||
/// timeout for block deices population
|
||||
const WAIT_FOR_BLK_DEVS: u64 = 5u64;
|
||||
|
||||
/// list of subvolumes to move from current system to snapshoot when being restored
|
||||
const SBUVOL_TO_MOVE: [(&str, &str); 1] = [("var", "/tmp")];
|
||||
|
||||
const TMP_ROOT: &str = "/mnt/bee-root";
|
||||
const TMP_ROOT_SNAPS: &str = "/mnt/bee-root/bzz-snaps";
|
||||
const TMP_ROOT_USR: &str = "/mnt/bee-root/usr";
|
||||
const TMP_ROOT_VAR: &str = "/mnt/bee-root/var";
|
||||
|
||||
/// Path where /usr subvolume got moved on snapshot restore
|
||||
const TMP_ROOT_SNAPS_USR: &str = "/mnt/bee-root/bzz-snaps/tmp_usr";
|
||||
/// Path where /var subvolume got moved on snapshot restore
|
||||
const TMP_ROOT_SNAPS_VAR: &str = "/mnt/bee-root/bzz-snaps/tmp_var";
|
||||
|
||||
const TMP_ROOT_SNAPS_PREFIX: &str = "/mnt/bee-root/bzz-snaps/tmp_";
|
||||
|
||||
const PAC_LOCK_FILE: &str = "/var/lib/hive-up/pac-lock";
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct CommandFailed {
|
||||
pub stderr: Vec<u8>,
|
||||
@@ -249,13 +266,17 @@ pub fn bzzpss_dev_encrypted(dev_name: &str) -> Result<bool, ExecCommandError> {
|
||||
}
|
||||
}
|
||||
|
||||
//const TMP_ROOT: &str = "/mnt/bee-root";
|
||||
///
|
||||
/// Looking for snapshots in snaps_dir for usr and var
|
||||
/// And return list of date-time part of filename if both snapshots exists
|
||||
///
|
||||
pub fn list_bzzpss_snaps(snaps_dir: &str) -> Result<Vec<String>, ExecCommandError> {
|
||||
use regex_lite::Regex;
|
||||
use std::path::Path;
|
||||
|
||||
// root snapshoot in a form of bzz-yyyy-mm-ddTHH-MM-SS
|
||||
let re = Regex::new(r"^bzz-[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}-[0-9]{2}-[0-9]{2}$").unwrap();
|
||||
// usr or var snapshoot in a form of bzz-usr|var-yyyy-mm-ddTHH-MM-SS
|
||||
let re = Regex::new(r"^bzz-(usr|var)-([0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}-[0-9]{2}-[0-9]{2})$")
|
||||
.unwrap();
|
||||
|
||||
let mut res: Vec<String> = Vec::new();
|
||||
// if snaps dir path do not exist return empty list
|
||||
@@ -263,19 +284,231 @@ pub fn list_bzzpss_snaps(snaps_dir: &str) -> Result<Vec<String>, ExecCommandErro
|
||||
return Ok(res);
|
||||
}
|
||||
|
||||
// contains only date-time part
|
||||
let mut usr_snaps: Vec<String> = Vec::new();
|
||||
let mut var_snaps: Vec<String> = Vec::new();
|
||||
|
||||
// collect snapshots date-time
|
||||
for maybe_entry in fs::read_dir(snaps_dir)? {
|
||||
let entry = maybe_entry?;
|
||||
if entry.file_type()?.is_dir() {
|
||||
if let Some(dir_name) = entry.file_name().to_str()
|
||||
&& re.is_match(dir_name)
|
||||
{
|
||||
res.push(dir_name.to_string());
|
||||
if let Some(dir_name) = entry.file_name().to_str() {
|
||||
if let Some(captured) = re.captures(&dir_name) {
|
||||
let subvol_name = &captured[1];
|
||||
let date_time = captured[2].to_string();
|
||||
if subvol_name == "usr" {
|
||||
usr_snaps.push(date_time);
|
||||
} else {
|
||||
var_snaps.push(date_time);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// now we need to make sure snapshots of /usr and /var both exist
|
||||
// just fools safe, may reconsider in future
|
||||
usr_snaps.sort();
|
||||
for snap_time in usr_snaps {
|
||||
if var_snaps.contains(&snap_time) {
|
||||
res.push(snap_time);
|
||||
}
|
||||
}
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
///
|
||||
/// creates rw snapshot of "subvolume" and places it into "target"
|
||||
/// bcachefs subvolume snapshot --rw /subvolume /target
|
||||
///
|
||||
pub fn snapshot_rw(subvolume: &str, target: &str) -> Result<(), ExecCommandError> {
|
||||
exec_command(
|
||||
"bcachefs",
|
||||
&vec!["subvolume", "snapshot", "--rw", subvolume, target],
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
///
|
||||
/// bcachefs subvolume delete shortcut
|
||||
///
|
||||
pub fn subvolume_delete(subvolume: &str) -> Result<(), ExecCommandError> {
|
||||
exec_command("bcachefs", &vec!["subvolume", "delete", subvolume])?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
///
|
||||
/// Helper function to get snapshot names in form of "bzz-(usr|var)-date-time"
|
||||
/// vol: "usr" or "var"
|
||||
/// dt: datetime
|
||||
///
|
||||
fn snap_name_from_dt(vol: &str, dt: &str) -> String {
|
||||
format!("bzz-{}-{}", vol, dt)
|
||||
}
|
||||
|
||||
///
|
||||
///
|
||||
/// // Stable Rust example using from_fn
|
||||
fn first_n(n: u64) -> impl Iterator<Item = u64> {
|
||||
let mut count = 0;
|
||||
std::iter::from_fn(move || {
|
||||
if count < n {
|
||||
let val = count;
|
||||
count += 1;
|
||||
Some(val)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
enum RollbackStates {
|
||||
Start,
|
||||
RenameUsrVarAct,
|
||||
ChangeToRw,
|
||||
MoveSubvolums,
|
||||
RemoveOldVols,
|
||||
ClearSnaps,
|
||||
Finish,
|
||||
Err,
|
||||
}
|
||||
|
||||
pub fn roll_back_snap(
|
||||
snaps_list: &Vec<String>,
|
||||
target_snap: &str,
|
||||
) -> impl Iterator<Item = Result<String, ExecCommandError>> {
|
||||
let usr_ro_snap_path = format!("{}/bzz-{}-{}", TMP_ROOT_SNAPS, "usr", target_snap);
|
||||
let var_ro_snap_path = format!("{}/bzz-{}-{}", TMP_ROOT_SNAPS, "usr", target_snap);
|
||||
|
||||
let mut roll_state = RollbackStates::Start;
|
||||
|
||||
std::iter::from_fn(move || match roll_state {
|
||||
RollbackStates::Start => {
|
||||
roll_state = RollbackStates::RenameUsrVarAct;
|
||||
Some(Ok("Move usr and var to temporary location".into()))
|
||||
}
|
||||
RollbackStates::RenameUsrVarAct => {
|
||||
let move_res = fs::rename(TMP_ROOT_USR, TMP_ROOT_SNAPS_USR)
|
||||
.and_then(|_| fs::rename(TMP_ROOT_VAR, TMP_ROOT_SNAPS_VAR));
|
||||
if let Err(ex) = move_res {
|
||||
roll_state = RollbackStates::Err;
|
||||
Some(Err(ex.into()))
|
||||
} else {
|
||||
roll_state = RollbackStates::ChangeToRw;
|
||||
Some(Ok("Setting snapshot as current system ...".into()))
|
||||
}
|
||||
}
|
||||
RollbackStates::ChangeToRw => {
|
||||
let rw_res = snapshot_rw(&usr_ro_snap_path, TMP_ROOT_USR)
|
||||
.and_then(|_| snapshot_rw(&var_ro_snap_path, TMP_ROOT_VAR));
|
||||
if let Err(ex) = rw_res {
|
||||
roll_state = RollbackStates::Err;
|
||||
Some(Err(ex))
|
||||
} else {
|
||||
roll_state = RollbackStates::MoveSubvolums;
|
||||
Some(Ok(
|
||||
"Moving subvolumes from old /usr and /var to new one".into()
|
||||
))
|
||||
}
|
||||
}
|
||||
RollbackStates::MoveSubvolums => {
|
||||
let mut mv_res = Some(Ok("Removing old /usr and /var".into()));
|
||||
for (vol, svol_path) in SBUVOL_TO_MOVE {
|
||||
let v_from = format!("{}{}{}", TMP_ROOT_SNAPS_PREFIX, vol, svol_path);
|
||||
let v_dest = format!("{}/{}{}", TMP_ROOT, vol, svol_path);
|
||||
if let Err(ex) = fs::rename(v_from, v_dest) {
|
||||
roll_state = RollbackStates::Err;
|
||||
mv_res = Some(Err(ex.into()));
|
||||
break;
|
||||
}
|
||||
}
|
||||
roll_state = RollbackStates::RemoveOldVols;
|
||||
mv_res
|
||||
}
|
||||
RollbackStates::RemoveOldVols => {
|
||||
let rem_old_res = subvolume_delete(TMP_ROOT_SNAPS_USR)
|
||||
.and_then(|_| subvolume_delete(TMP_ROOT_SNAPS_VAR));
|
||||
if let Err(ex) = rem_old_res {
|
||||
roll_state = RollbackStates::Err;
|
||||
Some(Err(ex))
|
||||
} else {
|
||||
roll_state = RollbackStates::ClearSnaps;
|
||||
Some(Ok("Clearing snapshots...".into()))
|
||||
}
|
||||
}
|
||||
RollbackStates::ClearSnaps => {
|
||||
let mut clr_snap_res = Some(Ok("All done!".into()));
|
||||
for snap_date_time in snaps_list.iter().rev() {
|
||||
let usr_snap = format!("{}/bzz-{}-{}", TMP_ROOT_SNAPS, "usr", snap_date_time);
|
||||
let var_snap = format!("{}/bzz-{}-{}", TMP_ROOT_SNAPS, "usr", snap_date_time);
|
||||
if let Err(ex) =
|
||||
subvolume_delete(&usr_snap).and_then(|_| subvolume_delete(&var_snap))
|
||||
{
|
||||
clr_snap_res = Some(Err(ex));
|
||||
roll_state = RollbackStates::Err;
|
||||
break;
|
||||
}
|
||||
if snap_date_time == target_snap {
|
||||
break;
|
||||
}
|
||||
}
|
||||
clr_snap_res
|
||||
}
|
||||
RollbackStates::Finish => None,
|
||||
RollbackStates::Err => None,
|
||||
})
|
||||
|
||||
// 1. Rename usr and var to TMP_ROOT_SNAPS/tmp_var|usr
|
||||
// fs::rename(TMP_ROOT_USR, TMP_ROOT_SNAPS_USR)?;
|
||||
// fs::rename(TMP_ROOT_VAR, TMP_ROOT_SNAPS_VAR)?;
|
||||
|
||||
// 2. snapshot desired snaps as RW to /usr and /var
|
||||
// snapshot_rw(&usr_ro_snap_path, TMP_ROOT_USR)?;
|
||||
// snapshot_rw(&var_ro_snap_path, TMP_ROOT_VAR)?;
|
||||
|
||||
// 3. move subvolumes from old /usr and /var
|
||||
// for (vol, svol_path) in SBUVOL_TO_MOVE {
|
||||
// let v_from = format!("{}{}{}", TMP_ROOT_SNAPS_PREFIX, vol, svol_path);
|
||||
// let v_dest = format!("{}/{}{}",TMP_ROOT,vol,svol_path);
|
||||
// fs::rename(v_from, v_dest)?;
|
||||
// }
|
||||
|
||||
// 4. removing tmp /usr /var
|
||||
// subvolume_delete(TMP_ROOT_SNAPS_USR)?;
|
||||
// subvolume_delete(TMP_ROOT_SNAPS_VAR)?;
|
||||
|
||||
// 5. Removing all snapshoots made after one we restored, including inself
|
||||
// Iterate in reverse untill we get to target_snap in snaps list
|
||||
// for snap_date_time in snaps_list.iter().rev() {
|
||||
// let usr_snap = format!("{}/bzz-{}-{}", TMP_ROOT_SNAPS, "usr", snap_date_time);
|
||||
// let var_snap = format!("{}/bzz-{}-{}", TMP_ROOT_SNAPS, "usr", snap_date_time);
|
||||
// subvolume_delete(&usr_snap)?;
|
||||
// subvolume_delete(&var_snap)?;
|
||||
// if snap_date_time == target_snap {
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
|
||||
// Ok(())
|
||||
}
|
||||
|
||||
///
|
||||
/// Checks if pac_lock file exist and returns date-time from it if it does,
|
||||
/// Otherwise return None
|
||||
///
|
||||
pub fn check_pac_lock() -> Result<Option<String>, ExecCommandError> {
|
||||
use std::path::Path;
|
||||
let pac_lock_path = Path::new(PAC_LOCK_FILE);
|
||||
if pac_lock_path.exists() {
|
||||
let snap_dt = fs::read_to_string(pac_lock_path)?;
|
||||
Ok(Some(snap_dt.trim().into()))
|
||||
}
|
||||
else {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
// pulls /sys/class/block
|
||||
fn wait_for_block_devices(timeout_secs: u64) -> bool {
|
||||
use std::path::Path;
|
||||
@@ -300,7 +533,6 @@ fn wait_for_block_devices(timeout_secs: u64) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
|
||||
// mounting process
|
||||
//# Mount essential virtual filesystems
|
||||
// mount -t proc none /proc
|
||||
@@ -351,7 +583,8 @@ pub fn prepare_env() -> Result<(), ExecCommandError> {
|
||||
.map_err(|ex| format!("Error mounting /dev: {}", ex.to_string()))?;
|
||||
|
||||
//mount -t tmpfs -o nosuid,nodev,noexec,mode=0755 none /run
|
||||
let run_mount_flags = MsFlags::MS_NOSUID | MsFlags::MS_NODEV | MsFlags::MS_NOEXEC | MsFlags::MS_RELATIME;
|
||||
let run_mount_flags =
|
||||
MsFlags::MS_NOSUID | MsFlags::MS_NODEV | MsFlags::MS_NOEXEC | MsFlags::MS_RELATIME;
|
||||
mount(
|
||||
Some("run"),
|
||||
"/run",
|
||||
@@ -367,7 +600,6 @@ pub fn prepare_env() -> Result<(), ExecCommandError> {
|
||||
// Creating dir for udev so this little shit wont hang
|
||||
// fs::create_dir("/run/udev")?;
|
||||
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -412,7 +644,14 @@ pub fn mount_bee_root(dev_name: &str, mount_point: &str) -> Result<(), ExecComma
|
||||
root_mount_flags,
|
||||
None::<&str>,
|
||||
)
|
||||
.map_err(|ex| format!("Error mounting root {} to {} :\n{}",dev_name, mount_point, ex.to_string()))?;
|
||||
.map_err(|ex| {
|
||||
format!(
|
||||
"Error mounting root {} to {} :\n{}",
|
||||
dev_name,
|
||||
mount_point,
|
||||
ex.to_string()
|
||||
)
|
||||
})?;
|
||||
// exec_command("/usr/bin/mount", &vec!["-o", "ro", dev_name, mount_point])?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user