diff --git a/appmgr/src/bin/embassy-init.rs b/appmgr/src/bin/embassy-init.rs index f0351c977..a09019590 100644 --- a/appmgr/src/bin/embassy-init.rs +++ b/appmgr/src/bin/embassy-init.rs @@ -2,12 +2,12 @@ use std::path::Path; use std::sync::Arc; use embassy::context::rpc::RpcContextConfig; -use embassy::context::{RecoveryContext, SetupContext}; +use embassy::context::{DiagnosticContext, SetupContext}; use embassy::disk::main::DEFAULT_PASSWORD; use embassy::hostname::get_product_key; use embassy::middleware::cors::cors; +use embassy::middleware::diagnostic::diagnostic; use embassy::middleware::encrypt::encrypt; -use embassy::middleware::recovery::recovery; use embassy::net::mdns::MdnsController; use embassy::sound::MARIO_COIN; use embassy::util::Invoke; @@ -172,7 +172,7 @@ async fn inner_main(cfg_path: Option<&str>) -> Result<(), Error> { let mdns = MdnsController::init(); tokio::fs::write( "/etc/nginx/sites-available/default", - include_str!("../nginx/recovery-ui.conf"), + include_str!("../nginx/diagnostic-ui.conf"), ) .await .with_ctx(|_| { @@ -186,14 +186,14 @@ async fn inner_main(cfg_path: Option<&str>) -> Result<(), Error> { .arg("nginx") .invoke(embassy::ErrorKind::Nginx) .await?; - let ctx = RecoveryContext::init(cfg_path, e).await?; + let ctx = DiagnosticContext::init(cfg_path, e).await?; rpc_server!({ - command: embassy::recovery_api, + command: embassy::diagnostic_api, context: ctx.clone(), status: status_fn, middleware: [ cors, - recovery, + diagnostic, ] }) .with_graceful_shutdown({ diff --git a/appmgr/src/bin/embassyd.rs b/appmgr/src/bin/embassyd.rs index b013c1675..57ab8b1f4 100644 --- a/appmgr/src/bin/embassyd.rs +++ b/appmgr/src/bin/embassyd.rs @@ -1,11 +1,11 @@ use std::time::Duration; use anyhow::anyhow; -use embassy::context::{RecoveryContext, RpcContext}; +use embassy::context::{DiagnosticContext, RpcContext}; use embassy::db::subscribe; use embassy::middleware::auth::auth; use embassy::middleware::cors::cors; -use embassy::middleware::recovery::recovery; +use embassy::middleware::diagnostic::diagnostic; use embassy::net::tor::tor_health_check; use embassy::shutdown::Shutdown; use embassy::status::{check_all, synchronize_all}; @@ -275,14 +275,14 @@ fn main() { log::error!("{}", e.source); log::debug!("{}", e.source); embassy::sound::BEETHOVEN.play().await?; - let ctx = RecoveryContext::init(cfg_path, e).await?; + let ctx = DiagnosticContext::init(cfg_path, e).await?; rpc_server!({ - command: embassy::recovery_api, + command: embassy::diagnostic_api, context: ctx.clone(), status: status_fn, middleware: [ cors, - recovery, + diagnostic, ] }) .with_graceful_shutdown({ diff --git a/appmgr/src/context/recovery.rs b/appmgr/src/context/diagnostic.rs similarity index 80% rename from appmgr/src/context/recovery.rs rename to appmgr/src/context/diagnostic.rs index 0c53b11f6..34988ba3f 100644 --- a/appmgr/src/context/recovery.rs +++ b/appmgr/src/context/diagnostic.rs @@ -16,10 +16,10 @@ use crate::{Error, ResultExt}; #[derive(Debug, Default, Deserialize)] #[serde(rename_all = "kebab-case")] -pub struct RecoveryContextConfig { +pub struct DiagnosticContextConfig { pub bind_rpc: Option, } -impl RecoveryContextConfig { +impl DiagnosticContextConfig { pub async fn load>(path: Option

) -> Result { let cfg_path = path .as_ref() @@ -36,21 +36,21 @@ impl RecoveryContextConfig { } } -pub struct RecoveryContextSeed { +pub struct DiagnosticContextSeed { pub bind_rpc: SocketAddr, pub shutdown: Sender<()>, pub error: Arc, } #[derive(Clone)] -pub struct RecoveryContext(Arc); -impl RecoveryContext { +pub struct DiagnosticContext(Arc); +impl DiagnosticContext { pub async fn init>(path: Option

, error: Error) -> Result { - let cfg = RecoveryContextConfig::load(path).await?; + let cfg = DiagnosticContextConfig::load(path).await?; let (shutdown, _) = tokio::sync::broadcast::channel(1); - Ok(Self(Arc::new(RecoveryContextSeed { + Ok(Self(Arc::new(DiagnosticContextSeed { bind_rpc: cfg.bind_rpc.unwrap_or(([127, 0, 0, 1], 5959).into()), shutdown, error: Arc::new(error.into()), @@ -58,7 +58,7 @@ impl RecoveryContext { } } -impl Context for RecoveryContext { +impl Context for DiagnosticContext { fn host(&self) -> Host<&str> { match self.0.bind_rpc.ip() { IpAddr::V4(a) => Host::Ipv4(a), @@ -69,8 +69,8 @@ impl Context for RecoveryContext { self.0.bind_rpc.port() } } -impl Deref for RecoveryContext { - type Target = RecoveryContextSeed; +impl Deref for DiagnosticContext { + type Target = DiagnosticContextSeed; fn deref(&self) -> &Self::Target { &*self.0 } diff --git a/appmgr/src/context/mod.rs b/appmgr/src/context/mod.rs index 28175f7f1..c094c50ab 100644 --- a/appmgr/src/context/mod.rs +++ b/appmgr/src/context/mod.rs @@ -1,10 +1,10 @@ pub mod cli; -pub mod recovery; +pub mod diagnostic; pub mod rpc; pub mod setup; pub use cli::CliContext; -pub use recovery::RecoveryContext; +pub use diagnostic::DiagnosticContext; pub use rpc::RpcContext; pub use setup::SetupContext; @@ -13,8 +13,8 @@ impl From for () { () } } -impl From for () { - fn from(_: RecoveryContext) -> Self { +impl From for () { + fn from(_: DiagnosticContext) -> Self { () } } diff --git a/appmgr/src/db/model.rs b/appmgr/src/db/model.rs index 0545527cd..365bee50f 100644 --- a/appmgr/src/db/model.rs +++ b/appmgr/src/db/model.rs @@ -37,7 +37,7 @@ impl Database { tor_address: format!("http://{}", tor_key.public().get_onion_address()) .parse() .unwrap(), - status: ServerStatus::Running, + status: ServerStatus::Running {}, eos_marketplace: "https://beta-registry-0-3.start9labs.com".parse().unwrap(), package_marketplace: None, wifi: WifiInfo { @@ -72,26 +72,38 @@ impl DatabaseModel { #[derive(Debug, Deserialize, Serialize, HasModel)] #[serde(rename_all = "kebab-case")] pub struct ServerInfo { - id: String, - version: Version, - lan_address: Url, - tor_address: Url, - status: ServerStatus, - eos_marketplace: Url, - package_marketplace: Option, - wifi: WifiInfo, - unread_notification_count: u64, - specs: ServerSpecs, - connection_addresses: ConnectionAddresses, - share_stats: bool, + pub id: String, + pub version: Version, + pub lan_address: Url, + pub tor_address: Url, + #[serde(flatten)] + pub status: ServerStatus, + pub eos_marketplace: Url, + pub package_marketplace: Option, + pub wifi: WifiInfo, + pub unread_notification_count: u64, + pub specs: ServerSpecs, + pub connection_addresses: ConnectionAddresses, + pub share_stats: bool, } #[derive(Debug, Deserialize, Serialize)] #[serde(rename_all = "kebab-case")] +#[serde(tag = "status")] pub enum ServerStatus { - Running, - Updating, - BackingUp, + Running {}, + #[serde(rename_all = "kebab-case")] + Updating { + update_progress: UpdateProgress, + }, + BackingUp {}, +} + +#[derive(Debug, Deserialize, Serialize)] +#[serde(rename_all = "kebab-case")] +pub struct UpdateProgress { + pub size: u64, + pub downloaded: u64, } #[derive(Debug, Deserialize, Serialize)] diff --git a/appmgr/src/recovery.rs b/appmgr/src/diagnostic.rs similarity index 77% rename from appmgr/src/recovery.rs rename to appmgr/src/diagnostic.rs index ddd1978e0..057a5c1b9 100644 --- a/appmgr/src/recovery.rs +++ b/appmgr/src/diagnostic.rs @@ -3,7 +3,7 @@ use std::sync::Arc; use rpc_toolkit::command; use rpc_toolkit::yajrc::RpcError; -use crate::context::RecoveryContext; +use crate::context::DiagnosticContext; use crate::logs::{display_logs, fetch_logs, LogResponse, LogSource}; use crate::util::display_none; use crate::Error; @@ -11,12 +11,12 @@ use crate::Error; pub const SYSTEMD_UNIT: &'static str = "embassy-init"; #[command(subcommands(error, logs, exit))] -pub fn recovery() -> Result<(), Error> { +pub fn diagnostic() -> Result<(), Error> { Ok(()) } #[command] -pub fn error(#[context] ctx: RecoveryContext) -> Result, Error> { +pub fn error(#[context] ctx: DiagnosticContext) -> Result, Error> { Ok(ctx.error.clone()) } @@ -36,7 +36,7 @@ pub async fn logs( } #[command(display(display_none))] -pub fn exit(#[context] ctx: RecoveryContext) -> Result<(), Error> { +pub fn exit(#[context] ctx: DiagnosticContext) -> Result<(), Error> { ctx.shutdown.send(()).expect("receiver dropped"); Ok(()) } diff --git a/appmgr/src/disk/main.rs b/appmgr/src/disk/main.rs index 06b9c143c..6ee70d74f 100644 --- a/appmgr/src/disk/main.rs +++ b/appmgr/src/disk/main.rs @@ -8,6 +8,8 @@ use crate::{Error, ResultExt}; pub const PASSWORD_PATH: &'static str = "/etc/embassy/password"; pub const DEFAULT_PASSWORD: &'static str = "password"; +// TODO: use IncorrectDisk / DiskNotAvailable / DiskCorrupted + pub async fn create, P: AsRef>( pool_name: &str, disks: I, diff --git a/appmgr/src/error.rs b/appmgr/src/error.rs index 252834466..50356d83d 100644 --- a/appmgr/src/error.rs +++ b/appmgr/src/error.rs @@ -20,17 +20,17 @@ pub enum ErrorKind { Deserialization = 12, Utf8 = 13, ParseVersion = 14, - Duplicity = 15, // REMOVE + IncorrectDisk = 15, Nginx = 16, Dependency = 17, ParseS9pk = 18, ParseUrl = 19, - GParted = 20, // REMOVE + DiskNotAvailable = 20, BlockDevice = 21, InvalidOnionAddress = 22, Pack = 23, ValidateS9pk = 24, - OpenSSL = 25, // REMOVE + DiskCorrupted = 25, Tor = 26, ConfigGen = 27, ParseNumber = 28, @@ -56,7 +56,7 @@ pub enum ErrorKind { Zfs = 48, OpenSsl = 49, PasswordHashGeneration = 50, - RecoveryMode = 51, + DiagnosticMode = 51, ParseDbField = 52, } impl ErrorKind { @@ -77,17 +77,17 @@ impl ErrorKind { Deserialization => "Deserialization Error", Utf8 => "UTF-8 Parse Error", ParseVersion => "Version Parsing Error", - Duplicity => "Duplicity Error", + IncorrectDisk => "Incorrect Disk", Nginx => "Nginx Error", Dependency => "Dependency Error", ParseS9pk => "S9PK Parsing Error", ParseUrl => "URL Parsing Error", - GParted => "GNU Parted Error", + DiskNotAvailable => "Disk Not Available", BlockDevice => "Block Device Error", InvalidOnionAddress => "Invalid Onion Address", Pack => "Pack Error", ValidateS9pk => "S9PK Validation Error", - OpenSSL => "OpenSSL Error", // Remove + DiskCorrupted => "Disk Corrupted", // Remove Tor => "Tor Daemon Error", ConfigGen => "Config Generation Error", ParseNumber => "Number Parsing Error", @@ -113,7 +113,7 @@ impl ErrorKind { Zfs => "ZFS Error", OpenSsl => "OpenSSL Internal Error", PasswordHashGeneration => "Password Hash Generation Error", - RecoveryMode => "Embassy is in Recovery Mode", + DiagnosticMode => "Embassy is in Diagnostic Mode", ParseDbField => "Database Field Parse Error", } } diff --git a/appmgr/src/lib.rs b/appmgr/src/lib.rs index 737c5009b..95cc998ec 100644 --- a/appmgr/src/lib.rs +++ b/appmgr/src/lib.rs @@ -15,6 +15,7 @@ pub mod control; pub mod db; pub mod dependencies; pub mod developer; +pub mod diagnostic; pub mod disk; pub mod error; pub mod hostname; @@ -28,7 +29,6 @@ pub mod migration; pub mod net; pub mod notifications; pub mod properties; -pub mod recovery; pub mod s9pk; pub mod setup; pub mod shutdown; @@ -106,8 +106,8 @@ pub fn portable_api() -> Result<(), RpcError> { Ok(()) } -#[command(subcommands(version::git_info, echo, recovery::recovery))] -pub fn recovery_api() -> Result<(), RpcError> { +#[command(subcommands(version::git_info, echo, diagnostic::diagnostic))] +pub fn diagnostic_api() -> Result<(), RpcError> { Ok(()) } diff --git a/appmgr/src/middleware/recovery.rs b/appmgr/src/middleware/diagnostic.rs similarity index 77% rename from appmgr/src/middleware/recovery.rs rename to appmgr/src/middleware/diagnostic.rs index 8dd5c33d9..9f978680e 100644 --- a/appmgr/src/middleware/recovery.rs +++ b/appmgr/src/middleware/diagnostic.rs @@ -7,7 +7,7 @@ use rpc_toolkit::Metadata; use crate::Error; -pub async fn recovery( +pub async fn diagnostic( _req: &mut Request, _metadata: M, ) -> Result>, HttpError> { @@ -19,8 +19,11 @@ pub async fn recovery( if let Err(e) = rpc_res { if e.code == -32601 { *e = Error::new( - anyhow::anyhow!("{} is not available on the Recovery API", method), - crate::ErrorKind::RecoveryMode, + anyhow::anyhow!( + "{} is not available on the Diagnostic API", + method + ), + crate::ErrorKind::DiagnosticMode, ) .into(); } diff --git a/appmgr/src/middleware/mod.rs b/appmgr/src/middleware/mod.rs index f349363b8..0cc0b7bf8 100644 --- a/appmgr/src/middleware/mod.rs +++ b/appmgr/src/middleware/mod.rs @@ -1,4 +1,4 @@ pub mod auth; pub mod cors; +pub mod diagnostic; pub mod encrypt; -pub mod recovery; diff --git a/appmgr/src/nginx/recovery-ui.conf b/appmgr/src/nginx/diagnostic-ui.conf similarity index 92% rename from appmgr/src/nginx/recovery-ui.conf rename to appmgr/src/nginx/diagnostic-ui.conf index 10acc657b..e83593507 100644 --- a/appmgr/src/nginx/recovery-ui.conf +++ b/appmgr/src/nginx/diagnostic-ui.conf @@ -2,7 +2,7 @@ server { listen 80 default_server; listen [::]:80 default_server; - root /var/www/html/recovery; + root /var/www/html/diagnostic; index index.html index.htm index.nginx-debian.html;