Feature/backup+restore (#2613)

* feat: Implementation on the backup for the service.

* wip: Getting the flow of backup/restore

* feat: Recover

* Feature: Commit the full pass on the backup restore.

* use special type for backup instead of special id (#2614)

* fix: Allow compat docker style to run again

* fix: Backup for the js side

* chore: Update some of the callbacks

---------

Co-authored-by: Aiden McClelland <3732071+dr-bonez@users.noreply.github.com>
This commit is contained in:
Jade
2024-05-06 15:46:36 -06:00
committed by GitHub
parent 9b14d714ca
commit 30aabe255b
21 changed files with 415 additions and 102 deletions

View File

@@ -1 +1,94 @@
use std::path::PathBuf;
use futures::FutureExt;
use models::ProcedureName;
use super::TempDesiredRestore;
use crate::disk::mount::filesystem::ReadWrite;
use crate::prelude::*;
use crate::service::config::GetConfig;
use crate::service::dependencies::DependencyConfig;
use crate::service::transition::{TransitionKind, TransitionState};
use crate::service::ServiceActor;
use crate::util::actor::background::BackgroundJobQueue;
use crate::util::actor::{ConflictBuilder, Handler};
use crate::util::future::RemoteCancellable;
pub(in crate::service) struct Backup {
pub path: PathBuf,
}
impl Handler<Backup> for ServiceActor {
type Response = Result<(), Error>;
fn conflicts_with(_: &Backup) -> ConflictBuilder<Self> {
ConflictBuilder::everything()
.except::<GetConfig>()
.except::<DependencyConfig>()
}
async fn handle(&mut self, backup: Backup, jobs: &BackgroundJobQueue) -> Self::Response {
// So Need a handle to just a single field in the state
let temp: TempDesiredRestore = TempDesiredRestore::new(&self.0.persistent_container.state);
let mut current = self.0.persistent_container.state.subscribe();
let path = backup.path.clone();
let seed = self.0.clone();
let state = self.0.persistent_container.state.clone();
let transition = RemoteCancellable::new(
async move {
temp.stop();
current
.wait_for(|s| s.running_status.is_none())
.await
.with_kind(ErrorKind::Unknown)?;
let backup_guard = seed
.persistent_container
.mount_backup(path, ReadWrite)
.await?;
seed.persistent_container
.execute(ProcedureName::CreateBackup, Value::Null, None)
.await?;
backup_guard.unmount(true).await?;
if temp.restore().is_start() {
current
.wait_for(|s| s.running_status.is_some())
.await
.with_kind(ErrorKind::Unknown)?;
}
drop(temp);
state.send_modify(|s| {
s.transition_state.take();
});
Ok::<_, Error>(())
}
.map(|x| {
if let Err(err) = dbg!(x) {
tracing::debug!("{:?}", err);
tracing::warn!("{}", err);
}
}),
);
let cancel_handle = transition.cancellation_handle();
let transition = transition.shared();
let job_transition = transition.clone();
jobs.add_job(job_transition.map(|_| ()));
let mut old = None;
self.0.persistent_container.state.send_modify(|s| {
old = std::mem::replace(
&mut s.transition_state,
Some(TransitionState {
kind: TransitionKind::BackingUp,
cancel_handle,
}),
)
});
if let Some(t) = old {
t.abort().await;
}
match transition.await {
None => Err(Error::new(eyre!("Backup canceled"), ErrorKind::Unknown)),
Some(x) => Ok(x),
}
}
}