mirror of
https://github.com/Start9Labs/start-os.git
synced 2026-03-30 04:01:58 +00:00
Backups Rework (#698)
* wip: Backup al * wip: Backup * backup code complete * wip * wip * update types * wip * fix errors * Backups wizard (#699) * backup adjustments * fix endpoint arg * Update prod-key-modal.page.ts Co-authored-by: Drew Ansbacher <drew.ansbacher@spiredigital.com> Co-authored-by: Aiden McClelland <me@drbonez.dev> * build errs addressed * working * update backup command input, nix, and apk add * add ecryptfs-utils * fix build * wip * fixes for macos * more mac magic * fix typo * working * fixes after rebase * chore: remove unused imports Co-authored-by: Justin Miller <dragondef@gmail.com> Co-authored-by: Drew Ansbacher <drew.ansbacher@gmail.com> Co-authored-by: Drew Ansbacher <drew.ansbacher@spiredigital.com> Co-authored-by: Lucy Cifferello <12953208+elvece@users.noreply.github.com>
This commit is contained in:
30
system-images/compat/Cargo.lock
generated
30
system-images/compat/Cargo.lock
generated
@@ -212,9 +212,9 @@ checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.2.1"
|
||||
version = "1.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
|
||||
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||
|
||||
[[package]]
|
||||
name = "bitvec"
|
||||
@@ -461,7 +461,7 @@ dependencies = [
|
||||
"lazy_static",
|
||||
"linear-map",
|
||||
"log",
|
||||
"nix 0.22.1",
|
||||
"nix 0.23.0",
|
||||
"pest",
|
||||
"pest_derive",
|
||||
"rand 0.7.3",
|
||||
@@ -860,6 +860,7 @@ dependencies = [
|
||||
"hex",
|
||||
"hmac",
|
||||
"http",
|
||||
"hyper",
|
||||
"hyper-ws-listener",
|
||||
"indexmap",
|
||||
"isocountry",
|
||||
@@ -868,7 +869,7 @@ dependencies = [
|
||||
"lazy_static",
|
||||
"libc",
|
||||
"log",
|
||||
"nix 0.22.1",
|
||||
"nix 0.23.0",
|
||||
"num",
|
||||
"openssh-keys",
|
||||
"openssl",
|
||||
@@ -1366,9 +1367,9 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
|
||||
|
||||
[[package]]
|
||||
name = "hyper"
|
||||
version = "0.14.12"
|
||||
version = "0.14.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "13f67199e765030fa08fe0bd581af683f0d5bc04ea09c2b1102012c5fb90e7fd"
|
||||
checksum = "15d1cfb9e4f68655fa04c01f59edb405b6074a0f7118ea881e5026e4a1cd8593"
|
||||
dependencies = [
|
||||
"bytes 1.1.0",
|
||||
"futures-channel",
|
||||
@@ -1807,9 +1808,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nix"
|
||||
version = "0.22.1"
|
||||
version = "0.23.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e7555d6c7164cc913be1ce7f95cbecdabda61eb2ccd89008524af306fb7f5031"
|
||||
checksum = "f305c2c2e4c39a82f7bf0bf65fb557f9070ce06781d4f2454295cc34b1c43188"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"cc",
|
||||
@@ -2072,14 +2073,15 @@ dependencies = [
|
||||
"json-patch",
|
||||
"json-ptr",
|
||||
"lazy_static",
|
||||
"log",
|
||||
"nix 0.22.1",
|
||||
"nix 0.23.0",
|
||||
"patch-db-macro",
|
||||
"serde",
|
||||
"serde_cbor 0.11.1",
|
||||
"serde_json",
|
||||
"thiserror",
|
||||
"tokio 1.12.0",
|
||||
"tracing",
|
||||
"tracing-error",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3677,9 +3679,9 @@ checksum = "360dfd1d6d30e05fda32ace2c8c70e9c0a9da713275777f5a4dbb8a1893930c6"
|
||||
|
||||
[[package]]
|
||||
name = "tracing"
|
||||
version = "0.1.26"
|
||||
version = "0.1.29"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "09adeb8c97449311ccd28a427f96fb563e7fd31aabf994189879d9da2394b89d"
|
||||
checksum = "375a639232caf30edfc78e8d89b2d4c375515393e7af7e16f01cd96917fb2105"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"pin-project-lite 0.2.7",
|
||||
@@ -3700,9 +3702,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tracing-core"
|
||||
version = "0.1.19"
|
||||
version = "0.1.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2ca517f43f0fb96e0c3072ed5c275fe5eece87e8cb52f4a77b69226d3b1c9df8"
|
||||
checksum = "1f4ed65637b8390770814083d20756f87bfa2c21bf2f110babdc5438351746e4"
|
||||
dependencies = [
|
||||
"lazy_static",
|
||||
]
|
||||
|
||||
@@ -18,7 +18,7 @@ itertools = "0.10.0"
|
||||
lazy_static = "1.4"
|
||||
linear-map = { version = "1.2", features = ["serde_impl"] }
|
||||
log = "0.4.11"
|
||||
nix = "0.22.0"
|
||||
nix = "0.23.0"
|
||||
pest = "2.1"
|
||||
pest_derive = "2.1"
|
||||
rand = "0.7"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
FROM alpine:latest
|
||||
|
||||
RUN apk update && apk add duplicity && apk add curl
|
||||
RUN apk update && apk add duplicity curl
|
||||
ADD ./target/aarch64-unknown-linux-musl/release/compat /usr/local/bin/compat
|
||||
|
||||
ENTRYPOINT ["compat"]
|
||||
|
||||
@@ -1,74 +1,63 @@
|
||||
use std::path::Path;
|
||||
use std::{path::Path, process::Stdio};
|
||||
|
||||
pub fn create_backup<P: AsRef<Path>>(
|
||||
mountpoint: P,
|
||||
data_path: P,
|
||||
app_id: &str,
|
||||
pub fn create_backup(
|
||||
mountpoint: impl AsRef<Path>,
|
||||
data_path: impl AsRef<Path>,
|
||||
) -> Result<(), anyhow::Error> {
|
||||
let path = std::fs::canonicalize(mountpoint)?;
|
||||
let volume_path = Path::new(embassy::VOLUMES).join(app_id);
|
||||
let mountpoint = std::fs::canonicalize(mountpoint)?;
|
||||
let data_path = std::fs::canonicalize(data_path)?;
|
||||
|
||||
let exclude = if volume_path.is_dir() {
|
||||
let ignore_path = volume_path.join(".backupignore");
|
||||
if ignore_path.is_file() {
|
||||
std::fs::read(ignore_path)?
|
||||
} else {
|
||||
Vec::new()
|
||||
}
|
||||
let ignore_path = data_path.join(".backupignore");
|
||||
let exclude = if ignore_path.is_file() {
|
||||
std::fs::read_to_string(ignore_path)?
|
||||
} else {
|
||||
return Err(anyhow::anyhow!("Volume For {} Does Not Exist", app_id))
|
||||
String::new()
|
||||
};
|
||||
|
||||
let mut data_cmd = std::process::Command::new("duplicity");
|
||||
for exclude in exclude {
|
||||
for exclude in exclude.lines().map(|s| s.trim()).filter(|s| !s.is_empty()) {
|
||||
if exclude.to_string().starts_with('!') {
|
||||
data_cmd.arg(format!(
|
||||
"--include={}",
|
||||
volume_path.join(exclude.to_string().trim_start_matches('!')).display()
|
||||
data_path
|
||||
.join(exclude.to_string().trim_start_matches('!'))
|
||||
.display()
|
||||
));
|
||||
} else {
|
||||
data_cmd.arg(format!("--exclude={}", volume_path.join(exclude.to_string()).display()));
|
||||
data_cmd.arg(format!(
|
||||
"--exclude={}",
|
||||
data_path.join(exclude.to_string()).display()
|
||||
));
|
||||
}
|
||||
}
|
||||
let data_res = data_cmd
|
||||
.arg(volume_path)
|
||||
.arg(format!("file://{}", data_path.as_ref().display().to_string()))
|
||||
.arg(data_path)
|
||||
.arg(format!("file://{}", mountpoint.display().to_string()))
|
||||
.output();
|
||||
data_res?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn restore_backup<P: AsRef<Path>>(
|
||||
path: P,
|
||||
data_path: P,
|
||||
app_id: &str,
|
||||
pub fn restore_backup(
|
||||
mountpoint: impl AsRef<Path>,
|
||||
data_path: impl AsRef<Path>,
|
||||
) -> Result<(), anyhow::Error> {
|
||||
let path = std::fs::canonicalize(path)?;
|
||||
if !path.is_dir() {
|
||||
anyhow::anyhow!("Backup Path Must Be Directory");
|
||||
}
|
||||
let metadata_path = path.join("metadata.yaml");
|
||||
let volume_path = Path::new(embassy::VOLUMES).join(app_id);
|
||||
let mountpoint = std::fs::canonicalize(mountpoint)?;
|
||||
let data_path = std::fs::canonicalize(data_path)?;
|
||||
|
||||
let mut data_cmd = std::process::Command::new("duplicity");
|
||||
data_cmd
|
||||
let data_output = std::process::Command::new("duplicity")
|
||||
.arg("--force")
|
||||
.arg(format!("file://{:#?}", data_path.as_ref().display().to_string()))
|
||||
.arg(&volume_path);
|
||||
|
||||
let data_output = data_cmd.status()?;
|
||||
if !data_output.success() {
|
||||
return Err(anyhow::anyhow!("duplicity error for {}", app_id))
|
||||
.arg(format!("file://{}", mountpoint.display().to_string()))
|
||||
.arg(&data_path)
|
||||
.stderr(Stdio::piped())
|
||||
.output()?;
|
||||
if !data_output.status.success() {
|
||||
return Err(anyhow::anyhow!(
|
||||
"duplicity error: {}",
|
||||
String::from_utf8(data_output.stderr).unwrap()
|
||||
));
|
||||
}
|
||||
|
||||
std::fs::copy(
|
||||
metadata_path,
|
||||
Path::new(embassy::VOLUMES)
|
||||
.join(app_id)
|
||||
.join("start9")
|
||||
.join("restore.yaml"),
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -125,11 +125,6 @@ fn inner_main() -> Result<(), anyhow::Error> {
|
||||
SubCommand::with_name("duplicity")
|
||||
.subcommand(
|
||||
SubCommand::with_name("create")
|
||||
.arg(
|
||||
Arg::with_name("package-id")
|
||||
.help("The `id` field from the manifest file")
|
||||
.required(true),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("mountpoint")
|
||||
.help("The backups mount point")
|
||||
@@ -143,11 +138,6 @@ fn inner_main() -> Result<(), anyhow::Error> {
|
||||
)
|
||||
.subcommand(
|
||||
SubCommand::with_name("restore")
|
||||
.arg(
|
||||
Arg::with_name("package-id")
|
||||
.help("The `id` field from the manifest file")
|
||||
.required(true),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("mountpoint")
|
||||
.help("The backups mount point")
|
||||
@@ -271,7 +261,6 @@ fn inner_main() -> Result<(), anyhow::Error> {
|
||||
let res = create_backup(
|
||||
sub_m.value_of("mountpoint").unwrap(),
|
||||
sub_m.value_of("datapath").unwrap(),
|
||||
sub_m.value_of("package-id").unwrap(),
|
||||
);
|
||||
match res {
|
||||
Ok(r) => {
|
||||
@@ -283,9 +272,8 @@ fn inner_main() -> Result<(), anyhow::Error> {
|
||||
}
|
||||
("restore", Some(sub_m)) => {
|
||||
let res = restore_backup(
|
||||
sub_m.value_of("package-id").unwrap(),
|
||||
sub_m.value_of("datapath").unwrap(),
|
||||
sub_m.value_of("mountpoint").unwrap(),
|
||||
sub_m.value_of("datapath").unwrap(),
|
||||
);
|
||||
match res {
|
||||
Ok(r) => {
|
||||
|
||||
Reference in New Issue
Block a user