mirror of
https://github.com/Start9Labs/start-os.git
synced 2026-03-30 20:14:49 +00:00
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:
@@ -164,7 +164,7 @@ pub async fn backup_all(
|
||||
.decrypt(&ctx)?;
|
||||
let password = password.decrypt(&ctx)?;
|
||||
|
||||
let ((fs, package_ids), status_guard) = (
|
||||
let ((fs, package_ids, server_id), status_guard) = (
|
||||
ctx.db
|
||||
.mutate(|db| {
|
||||
check_password_against_db(db, &password)?;
|
||||
@@ -181,7 +181,11 @@ pub async fn backup_all(
|
||||
.collect()
|
||||
};
|
||||
assure_backing_up(db, &package_ids)?;
|
||||
Ok((fs, package_ids))
|
||||
Ok((
|
||||
fs,
|
||||
package_ids,
|
||||
db.as_public().as_server_info().as_id().de()?,
|
||||
))
|
||||
})
|
||||
.await?,
|
||||
BackupStatusGuard::new(ctx.db.clone()),
|
||||
@@ -189,6 +193,7 @@ pub async fn backup_all(
|
||||
|
||||
let mut backup_guard = BackupMountGuard::mount(
|
||||
TmpMountGuard::mount(&fs, ReadWrite).await?,
|
||||
&server_id,
|
||||
&old_password_decrypted,
|
||||
)
|
||||
.await?;
|
||||
@@ -298,11 +303,11 @@ async fn perform_backup(
|
||||
let ui = ctx.db.peek().await.into_public().into_ui().de()?;
|
||||
|
||||
let mut os_backup_file =
|
||||
AtomicFile::new(backup_guard.path().join("os-backup.cbor"), None::<PathBuf>)
|
||||
AtomicFile::new(backup_guard.path().join("os-backup.json"), None::<PathBuf>)
|
||||
.await
|
||||
.with_kind(ErrorKind::Filesystem)?;
|
||||
os_backup_file
|
||||
.write_all(&IoFormat::Cbor.to_vec(&OsBackup {
|
||||
.write_all(&IoFormat::Json.to_vec(&OsBackup {
|
||||
account: ctx.account.read().await.clone(),
|
||||
ui,
|
||||
})?)
|
||||
@@ -325,22 +330,23 @@ async fn perform_backup(
|
||||
dir_copy(luks_folder, &luks_folder_bak, None).await?;
|
||||
}
|
||||
|
||||
let timestamp = Some(Utc::now());
|
||||
let timestamp = Utc::now();
|
||||
|
||||
backup_guard.unencrypted_metadata.version = crate::version::Current::new().semver().into();
|
||||
backup_guard.unencrypted_metadata.full = true;
|
||||
backup_guard.unencrypted_metadata.hostname = ctx.account.read().await.hostname.clone();
|
||||
backup_guard.unencrypted_metadata.timestamp = timestamp.clone();
|
||||
backup_guard.metadata.version = crate::version::Current::new().semver().into();
|
||||
backup_guard.metadata.timestamp = timestamp;
|
||||
backup_guard.metadata.timestamp = Some(timestamp);
|
||||
backup_guard.metadata.package_backups = package_backups;
|
||||
|
||||
backup_guard.save().await?;
|
||||
backup_guard.save_and_unmount().await?;
|
||||
|
||||
ctx.db
|
||||
.mutate(|v| {
|
||||
v.as_public_mut()
|
||||
.as_server_info_mut()
|
||||
.as_last_backup_mut()
|
||||
.ser(×tamp)
|
||||
.ser(&Some(timestamp))
|
||||
})
|
||||
.await?;
|
||||
|
||||
|
||||
@@ -44,9 +44,14 @@ pub async fn restore_packages_rpc(
|
||||
password,
|
||||
}: RestorePackageParams,
|
||||
) -> Result<(), Error> {
|
||||
let fs = target_id.load(&ctx.db.peek().await)?;
|
||||
let backup_guard =
|
||||
BackupMountGuard::mount(TmpMountGuard::mount(&fs, ReadWrite).await?, &password).await?;
|
||||
let peek = ctx.db.peek().await;
|
||||
let fs = target_id.load(&peek)?;
|
||||
let backup_guard = BackupMountGuard::mount(
|
||||
TmpMountGuard::mount(&fs, ReadWrite).await?,
|
||||
&peek.as_public().as_server_info().as_id().de()?,
|
||||
&password,
|
||||
)
|
||||
.await?;
|
||||
|
||||
let tasks = restore_packages(&ctx, backup_guard, ids).await?;
|
||||
|
||||
@@ -73,7 +78,8 @@ pub async fn recover_full_embassy(
|
||||
disk_guid: Arc<String>,
|
||||
start_os_password: String,
|
||||
recovery_source: TmpMountGuard,
|
||||
recovery_password: Option<String>,
|
||||
server_id: &str,
|
||||
recovery_password: &str,
|
||||
SetupExecuteProgress {
|
||||
init_phases,
|
||||
restore_phase,
|
||||
@@ -82,14 +88,11 @@ pub async fn recover_full_embassy(
|
||||
) -> Result<(SetupResult, RpcContext), Error> {
|
||||
let mut restore_phase = restore_phase.or_not_found("restore progress")?;
|
||||
|
||||
let backup_guard = BackupMountGuard::mount(
|
||||
recovery_source,
|
||||
recovery_password.as_deref().unwrap_or_default(),
|
||||
)
|
||||
.await?;
|
||||
let backup_guard =
|
||||
BackupMountGuard::mount(recovery_source, server_id, recovery_password).await?;
|
||||
|
||||
let os_backup_path = backup_guard.path().join("os-backup.cbor");
|
||||
let mut os_backup: OsBackup = IoFormat::Cbor.from_slice(
|
||||
let os_backup_path = backup_guard.path().join("os-backup.json");
|
||||
let mut os_backup: OsBackup = IoFormat::Json.from_slice(
|
||||
&tokio::fs::read(&os_backup_path)
|
||||
.await
|
||||
.with_ctx(|_| (ErrorKind::Filesystem, os_backup_path.display().to_string()))?,
|
||||
|
||||
@@ -14,7 +14,7 @@ use crate::db::model::DatabaseModel;
|
||||
use crate::disk::mount::filesystem::cifs::Cifs;
|
||||
use crate::disk::mount::filesystem::ReadOnly;
|
||||
use crate::disk::mount::guard::{GenericMountGuard, TmpMountGuard};
|
||||
use crate::disk::util::{recovery_info, EmbassyOsRecoveryInfo};
|
||||
use crate::disk::util::{recovery_info, StartOsRecoveryInfo};
|
||||
use crate::prelude::*;
|
||||
use crate::util::serde::KeyVal;
|
||||
|
||||
@@ -43,7 +43,7 @@ pub struct CifsBackupTarget {
|
||||
path: PathBuf,
|
||||
username: String,
|
||||
mountable: bool,
|
||||
start_os: Option<EmbassyOsRecoveryInfo>,
|
||||
start_os: BTreeMap<String, StartOsRecoveryInfo>,
|
||||
}
|
||||
|
||||
pub fn cifs<C: Context>() -> ParentHandler<C> {
|
||||
@@ -239,7 +239,7 @@ pub async fn list(db: &DatabaseModel) -> Result<Vec<(u32, CifsBackupTarget)>, Er
|
||||
path: mount_info.path,
|
||||
username: mount_info.username,
|
||||
mountable: start_os.is_ok(),
|
||||
start_os: start_os.ok().and_then(|a| a),
|
||||
start_os: start_os.ok().unwrap_or_default(),
|
||||
},
|
||||
));
|
||||
}
|
||||
|
||||
@@ -157,6 +157,16 @@ pub fn target<C: Context>() -> ParentHandler<C> {
|
||||
})
|
||||
.with_call_remote::<CliContext>(),
|
||||
)
|
||||
.subcommand(
|
||||
"mount",
|
||||
from_fn_async(mount).with_call_remote::<CliContext>(),
|
||||
)
|
||||
.subcommand(
|
||||
"umount",
|
||||
from_fn_async(umount)
|
||||
.no_display()
|
||||
.with_call_remote::<CliContext>(),
|
||||
)
|
||||
}
|
||||
|
||||
// #[command(display(display_serializable))]
|
||||
@@ -250,6 +260,7 @@ fn display_backup_info(params: WithIoFormat<InfoParams>, info: BackupInfo) {
|
||||
#[command(rename_all = "kebab-case")]
|
||||
pub struct InfoParams {
|
||||
target_id: BackupTargetId,
|
||||
server_id: String,
|
||||
password: String,
|
||||
}
|
||||
|
||||
@@ -258,11 +269,13 @@ pub async fn info(
|
||||
ctx: RpcContext,
|
||||
InfoParams {
|
||||
target_id,
|
||||
server_id,
|
||||
password,
|
||||
}: InfoParams,
|
||||
) -> Result<BackupInfo, Error> {
|
||||
let guard = BackupMountGuard::mount(
|
||||
TmpMountGuard::mount(&target_id.load(&ctx.db.peek().await)?, ReadWrite).await?,
|
||||
&server_id,
|
||||
&password,
|
||||
)
|
||||
.await?;
|
||||
@@ -284,6 +297,7 @@ lazy_static::lazy_static! {
|
||||
#[command(rename_all = "kebab-case")]
|
||||
pub struct MountParams {
|
||||
target_id: BackupTargetId,
|
||||
server_id: String,
|
||||
password: String,
|
||||
}
|
||||
|
||||
@@ -292,6 +306,7 @@ pub async fn mount(
|
||||
ctx: RpcContext,
|
||||
MountParams {
|
||||
target_id,
|
||||
server_id,
|
||||
password,
|
||||
}: MountParams,
|
||||
) -> Result<String, Error> {
|
||||
@@ -303,6 +318,7 @@ pub async fn mount(
|
||||
|
||||
let guard = BackupMountGuard::mount(
|
||||
TmpMountGuard::mount(&target_id.clone().load(&ctx.db.peek().await)?, ReadWrite).await?,
|
||||
&server_id,
|
||||
&password,
|
||||
)
|
||||
.await?;
|
||||
|
||||
Reference in New Issue
Block a user