Feature/backup fs (#2665)

* port 040 config, WIP

* update fixtures

* use taiga modal for backups too

* fix: update Taiga UI and refactor everything to work

* chore: package-lock

* fix interfaces and mocks for interfaces

* better mocks

* function to transform old spec to new

* delete unused fns

* delete unused FE config utils

* fix exports from sdk

* reorganize exports

* functions to translate config

* rename unionSelectKey and unionValueKey

* new backup fs

* update sdk types

* change types, include fuse module

* fix casing

* rework setup wiz

* rework UI

* only fuse3

* fix arm build

* misc fixes

* fix duplicate server select

* fix: fix throwing inside dialog

---------

Co-authored-by: Matt Hill <mattnine@protonmail.com>
Co-authored-by: waterplea <alexander@inkin.ru>
Co-authored-by: Matt Hill <MattDHill@users.noreply.github.com>
This commit is contained in:
Aiden McClelland
2024-07-11 11:32:46 -06:00
committed by GitHub
parent f2a02b392e
commit 87322744d4
67 changed files with 880 additions and 563 deletions

View File

@@ -1,3 +1,4 @@
use std::collections::BTreeMap;
use std::path::{Path, PathBuf};
use std::sync::Arc;
use std::time::Duration;
@@ -25,7 +26,7 @@ use crate::disk::main::DEFAULT_PASSWORD;
use crate::disk::mount::filesystem::cifs::Cifs;
use crate::disk::mount::filesystem::ReadWrite;
use crate::disk::mount::guard::{GenericMountGuard, TmpMountGuard};
use crate::disk::util::{pvscan, recovery_info, DiskInfo, EmbassyOsRecoveryInfo};
use crate::disk::util::{pvscan, recovery_info, DiskInfo, StartOsRecoveryInfo};
use crate::disk::REPAIR_DISK_PATH;
use crate::init::{init, InitPhases, InitResult};
use crate::net::net_controller::PreInitNetController;
@@ -237,7 +238,7 @@ pub async fn verify_cifs(
username,
password,
}: VerifyCifsParams,
) -> Result<EmbassyOsRecoveryInfo, Error> {
) -> Result<BTreeMap<String, StartOsRecoveryInfo>, Error> {
let password: Option<String> = password.map(|x| x.decrypt(&ctx)).flatten();
let guard = TmpMountGuard::mount(
&Cifs {
@@ -251,15 +252,28 @@ pub async fn verify_cifs(
.await?;
let start_os = recovery_info(guard.path()).await?;
guard.unmount().await?;
start_os.ok_or_else(|| Error::new(eyre!("No Backup Found"), crate::ErrorKind::NotFound))
if start_os.is_empty() {
return Err(Error::new(
eyre!("No Backup Found"),
crate::ErrorKind::NotFound,
));
}
Ok(start_os)
}
#[derive(Debug, Deserialize, Serialize, TS)]
#[serde(tag = "type")]
#[serde(rename_all = "camelCase")]
pub enum RecoverySource {
Migrate { guid: String },
Backup { target: BackupTargetFS },
#[serde(rename_all_fields = "camelCase")]
pub enum RecoverySource<Password> {
Migrate {
guid: String,
},
Backup {
target: BackupTargetFS,
password: Password,
server_id: String,
},
}
#[derive(Deserialize, Serialize, TS)]
@@ -268,8 +282,7 @@ pub enum RecoverySource {
pub struct SetupExecuteParams {
start_os_logicalname: PathBuf,
start_os_password: EncryptedWire,
recovery_source: Option<RecoverySource>,
recovery_password: Option<EncryptedWire>,
recovery_source: Option<RecoverySource<EncryptedWire>>,
}
// #[command(rpc_only)]
@@ -279,7 +292,6 @@ pub async fn execute(
start_os_logicalname,
start_os_password,
recovery_source,
recovery_password,
}: SetupExecuteParams,
) -> Result<SetupProgress, Error> {
let start_os_password = match start_os_password.decrypt(&ctx) {
@@ -291,29 +303,27 @@ pub async fn execute(
))
}
};
let recovery_password: Option<String> = match recovery_password {
Some(a) => match a.decrypt(&ctx) {
Some(a) => Some(a),
None => {
return Err(Error::new(
let recovery = match recovery_source {
Some(RecoverySource::Backup {
target,
password,
server_id,
}) => Some(RecoverySource::Backup {
target,
password: password.decrypt(&ctx).ok_or_else(|| {
Error::new(
color_eyre::eyre::eyre!("Couldn't decode recoveryPassword"),
crate::ErrorKind::Unknown,
))
}
},
)
})?,
server_id,
}),
Some(RecoverySource::Migrate { guid }) => Some(RecoverySource::Migrate { guid }),
None => None,
};
let setup_ctx = ctx.clone();
ctx.run_setup(|| {
execute_inner(
setup_ctx,
start_os_logicalname,
start_os_password,
recovery_source,
recovery_password,
)
})?;
ctx.run_setup(|| execute_inner(setup_ctx, start_os_logicalname, start_os_password, recovery))?;
Ok(ctx.progress().await)
}
@@ -348,12 +358,11 @@ pub async fn execute_inner(
ctx: SetupContext,
start_os_logicalname: PathBuf,
start_os_password: String,
recovery_source: Option<RecoverySource>,
recovery_password: Option<String>,
recovery_source: Option<RecoverySource<String>>,
) -> Result<(SetupResult, RpcContext), Error> {
let progress = &ctx.progress;
let mut disk_phase = progress.add_phase("Formatting data drive".into(), Some(10));
let restore_phase = match &recovery_source {
let restore_phase = match recovery_source.as_ref() {
Some(RecoverySource::Backup { .. }) => {
Some(progress.add_phase("Restoring backup".into(), Some(100)))
}
@@ -396,13 +405,18 @@ pub async fn execute_inner(
};
match recovery_source {
Some(RecoverySource::Backup { target }) => {
Some(RecoverySource::Backup {
target,
password,
server_id,
}) => {
recover(
&ctx,
guid,
start_os_password,
target,
recovery_password,
server_id,
password,
progress,
)
.await
@@ -448,7 +462,8 @@ async fn recover(
guid: Arc<String>,
start_os_password: String,
recovery_source: BackupTargetFS,
recovery_password: Option<String>,
server_id: String,
recovery_password: String,
progress: SetupExecuteProgress,
) -> Result<(SetupResult, RpcContext), Error> {
let recovery_source = TmpMountGuard::mount(&recovery_source, ReadWrite).await?;
@@ -457,7 +472,8 @@ async fn recover(
guid.clone(),
start_os_password,
recovery_source,
recovery_password,
&server_id,
&recovery_password,
progress,
)
.await