diff --git a/appmgr/src/lib.rs b/appmgr/src/lib.rs index 3bbf73f0c..4d7f4e9ec 100644 --- a/appmgr/src/lib.rs +++ b/appmgr/src/lib.rs @@ -27,6 +27,7 @@ pub mod middleware; pub mod migration; pub mod net; pub mod properties; +pub mod recovery; pub mod s9pk; pub mod setup; pub mod shutdown; @@ -62,7 +63,8 @@ pub fn echo(#[arg] message: String) -> Result { auth::auth, db::db, ssh::ssh, - net::wifi::wifi + net::wifi::wifi, + disk::disk, ))] pub fn main_api() -> Result<(), RpcError> { Ok(()) @@ -103,12 +105,12 @@ pub fn portable_api() -> Result<(), RpcError> { Ok(()) } -#[command(subcommands(version::git_info, echo,))] +#[command(subcommands(version::git_info, echo, recovery::recovery))] pub fn recovery_api() -> Result<(), RpcError> { Ok(()) } -#[command(subcommands(version::git_info, echo,))] +#[command(subcommands(version::git_info, echo, setup::setup))] pub fn setup_api() -> Result<(), RpcError> { Ok(()) } diff --git a/appmgr/src/recovery.rs b/appmgr/src/recovery.rs new file mode 100644 index 000000000..2bf5568c2 --- /dev/null +++ b/appmgr/src/recovery.rs @@ -0,0 +1,40 @@ +use std::sync::Arc; + +use rpc_toolkit::command; +use rpc_toolkit::yajrc::RpcError; + +use crate::context::RecoveryContext; +use crate::logs::{display_logs, fetch_logs, LogResponse, LogSource}; +use crate::Error; + +pub const SYSTEMD_UNIT: &'static str = "embassy-init"; + +#[command(subcommands(error, logs, exit))] +pub fn recovery() -> Result<(), Error> { + Ok(()) +} + +#[command] +pub fn error(#[context] ctx: RecoveryContext) -> Result, Error> { + Ok(ctx.error.clone()) +} + +#[command(display(display_logs))] +pub async fn logs( + #[arg] limit: Option, + #[arg] cursor: Option, + #[arg] before_flag: Option, +) -> Result { + Ok(fetch_logs( + LogSource::Service(SYSTEMD_UNIT), + limit, + cursor, + before_flag.unwrap_or(false), + ) + .await?) +} + +#[command] +pub fn exit(#[context] ctx: RecoveryContext) -> Result<(), Error> { + ctx.shutdown.send(()).expect("receiver dropped"); +} diff --git a/appmgr/src/setup.rs b/appmgr/src/setup.rs index 718417ace..312593945 100644 --- a/appmgr/src/setup.rs +++ b/appmgr/src/setup.rs @@ -1,15 +1,18 @@ use std::path::PathBuf; +use std::time::Duration; use rpc_toolkit::command; use serde::{Deserialize, Serialize}; +use tokio::process::Command; use torut::onion::TorSecretKeyV3; use crate::context::SetupContext; use crate::disk::disk; use crate::disk::main::DEFAULT_PASSWORD; +use crate::util::Invoke; use crate::{Error, ResultExt}; -#[command(subcommands(status, disk))] +#[command(subcommands(status, disk, execute))] pub fn setup() -> Result<(), Error> { Ok(()) } @@ -44,6 +47,21 @@ pub async fn execute( let guid = crate::disk::main::create(&ctx.zfs_pool_name, [embassy_logicalname], DEFAULT_PASSWORD) .await?; + let mut ctr = 0; + while { + ctr += 1; + ctr < 30 // 30s timeout + } && String::from_utf8( + Command::new("zpool") + .arg("import") + .invoke(crate::ErrorKind::Zfs) + .await?, + )? + .trim() + == "no pools available to import" + { + tokio::time::sleep(Duration::from_secs(1)).await; + } crate::disk::main::load(&guid, &ctx.zfs_pool_name, &ctx.datadir, DEFAULT_PASSWORD).await?; let password = argon2::hash_encoded( embassy_password.as_bytes(),