diagnostic mode changes

This commit is contained in:
Aiden McClelland
2021-09-15 12:03:29 -06:00
parent 14c7540738
commit 2fd97b323c
12 changed files with 78 additions and 61 deletions

View File

@@ -2,12 +2,12 @@ use std::path::Path;
use std::sync::Arc; use std::sync::Arc;
use embassy::context::rpc::RpcContextConfig; use embassy::context::rpc::RpcContextConfig;
use embassy::context::{RecoveryContext, SetupContext}; use embassy::context::{DiagnosticContext, SetupContext};
use embassy::disk::main::DEFAULT_PASSWORD; use embassy::disk::main::DEFAULT_PASSWORD;
use embassy::hostname::get_product_key; use embassy::hostname::get_product_key;
use embassy::middleware::cors::cors; use embassy::middleware::cors::cors;
use embassy::middleware::diagnostic::diagnostic;
use embassy::middleware::encrypt::encrypt; use embassy::middleware::encrypt::encrypt;
use embassy::middleware::recovery::recovery;
use embassy::net::mdns::MdnsController; use embassy::net::mdns::MdnsController;
use embassy::sound::MARIO_COIN; use embassy::sound::MARIO_COIN;
use embassy::util::Invoke; use embassy::util::Invoke;
@@ -172,7 +172,7 @@ async fn inner_main(cfg_path: Option<&str>) -> Result<(), Error> {
let mdns = MdnsController::init(); let mdns = MdnsController::init();
tokio::fs::write( tokio::fs::write(
"/etc/nginx/sites-available/default", "/etc/nginx/sites-available/default",
include_str!("../nginx/recovery-ui.conf"), include_str!("../nginx/diagnostic-ui.conf"),
) )
.await .await
.with_ctx(|_| { .with_ctx(|_| {
@@ -186,14 +186,14 @@ async fn inner_main(cfg_path: Option<&str>) -> Result<(), Error> {
.arg("nginx") .arg("nginx")
.invoke(embassy::ErrorKind::Nginx) .invoke(embassy::ErrorKind::Nginx)
.await?; .await?;
let ctx = RecoveryContext::init(cfg_path, e).await?; let ctx = DiagnosticContext::init(cfg_path, e).await?;
rpc_server!({ rpc_server!({
command: embassy::recovery_api, command: embassy::diagnostic_api,
context: ctx.clone(), context: ctx.clone(),
status: status_fn, status: status_fn,
middleware: [ middleware: [
cors, cors,
recovery, diagnostic,
] ]
}) })
.with_graceful_shutdown({ .with_graceful_shutdown({

View File

@@ -1,11 +1,11 @@
use std::time::Duration; use std::time::Duration;
use anyhow::anyhow; use anyhow::anyhow;
use embassy::context::{RecoveryContext, RpcContext}; use embassy::context::{DiagnosticContext, RpcContext};
use embassy::db::subscribe; use embassy::db::subscribe;
use embassy::middleware::auth::auth; use embassy::middleware::auth::auth;
use embassy::middleware::cors::cors; use embassy::middleware::cors::cors;
use embassy::middleware::recovery::recovery; use embassy::middleware::diagnostic::diagnostic;
use embassy::net::tor::tor_health_check; use embassy::net::tor::tor_health_check;
use embassy::shutdown::Shutdown; use embassy::shutdown::Shutdown;
use embassy::status::{check_all, synchronize_all}; use embassy::status::{check_all, synchronize_all};
@@ -275,14 +275,14 @@ fn main() {
log::error!("{}", e.source); log::error!("{}", e.source);
log::debug!("{}", e.source); log::debug!("{}", e.source);
embassy::sound::BEETHOVEN.play().await?; embassy::sound::BEETHOVEN.play().await?;
let ctx = RecoveryContext::init(cfg_path, e).await?; let ctx = DiagnosticContext::init(cfg_path, e).await?;
rpc_server!({ rpc_server!({
command: embassy::recovery_api, command: embassy::diagnostic_api,
context: ctx.clone(), context: ctx.clone(),
status: status_fn, status: status_fn,
middleware: [ middleware: [
cors, cors,
recovery, diagnostic,
] ]
}) })
.with_graceful_shutdown({ .with_graceful_shutdown({

View File

@@ -16,10 +16,10 @@ use crate::{Error, ResultExt};
#[derive(Debug, Default, Deserialize)] #[derive(Debug, Default, Deserialize)]
#[serde(rename_all = "kebab-case")] #[serde(rename_all = "kebab-case")]
pub struct RecoveryContextConfig { pub struct DiagnosticContextConfig {
pub bind_rpc: Option<SocketAddr>, pub bind_rpc: Option<SocketAddr>,
} }
impl RecoveryContextConfig { impl DiagnosticContextConfig {
pub async fn load<P: AsRef<Path>>(path: Option<P>) -> Result<Self, Error> { pub async fn load<P: AsRef<Path>>(path: Option<P>) -> Result<Self, Error> {
let cfg_path = path let cfg_path = path
.as_ref() .as_ref()
@@ -36,21 +36,21 @@ impl RecoveryContextConfig {
} }
} }
pub struct RecoveryContextSeed { pub struct DiagnosticContextSeed {
pub bind_rpc: SocketAddr, pub bind_rpc: SocketAddr,
pub shutdown: Sender<()>, pub shutdown: Sender<()>,
pub error: Arc<RpcError>, pub error: Arc<RpcError>,
} }
#[derive(Clone)] #[derive(Clone)]
pub struct RecoveryContext(Arc<RecoveryContextSeed>); pub struct DiagnosticContext(Arc<DiagnosticContextSeed>);
impl RecoveryContext { impl DiagnosticContext {
pub async fn init<P: AsRef<Path>>(path: Option<P>, error: Error) -> Result<Self, Error> { pub async fn init<P: AsRef<Path>>(path: Option<P>, error: Error) -> Result<Self, Error> {
let cfg = RecoveryContextConfig::load(path).await?; let cfg = DiagnosticContextConfig::load(path).await?;
let (shutdown, _) = tokio::sync::broadcast::channel(1); 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()), bind_rpc: cfg.bind_rpc.unwrap_or(([127, 0, 0, 1], 5959).into()),
shutdown, shutdown,
error: Arc::new(error.into()), error: Arc::new(error.into()),
@@ -58,7 +58,7 @@ impl RecoveryContext {
} }
} }
impl Context for RecoveryContext { impl Context for DiagnosticContext {
fn host(&self) -> Host<&str> { fn host(&self) -> Host<&str> {
match self.0.bind_rpc.ip() { match self.0.bind_rpc.ip() {
IpAddr::V4(a) => Host::Ipv4(a), IpAddr::V4(a) => Host::Ipv4(a),
@@ -69,8 +69,8 @@ impl Context for RecoveryContext {
self.0.bind_rpc.port() self.0.bind_rpc.port()
} }
} }
impl Deref for RecoveryContext { impl Deref for DiagnosticContext {
type Target = RecoveryContextSeed; type Target = DiagnosticContextSeed;
fn deref(&self) -> &Self::Target { fn deref(&self) -> &Self::Target {
&*self.0 &*self.0
} }

View File

@@ -1,10 +1,10 @@
pub mod cli; pub mod cli;
pub mod recovery; pub mod diagnostic;
pub mod rpc; pub mod rpc;
pub mod setup; pub mod setup;
pub use cli::CliContext; pub use cli::CliContext;
pub use recovery::RecoveryContext; pub use diagnostic::DiagnosticContext;
pub use rpc::RpcContext; pub use rpc::RpcContext;
pub use setup::SetupContext; pub use setup::SetupContext;
@@ -13,8 +13,8 @@ impl From<CliContext> for () {
() ()
} }
} }
impl From<RecoveryContext> for () { impl From<DiagnosticContext> for () {
fn from(_: RecoveryContext) -> Self { fn from(_: DiagnosticContext) -> Self {
() ()
} }
} }

View File

@@ -37,7 +37,7 @@ impl Database {
tor_address: format!("http://{}", tor_key.public().get_onion_address()) tor_address: format!("http://{}", tor_key.public().get_onion_address())
.parse() .parse()
.unwrap(), .unwrap(),
status: ServerStatus::Running, status: ServerStatus::Running {},
eos_marketplace: "https://beta-registry-0-3.start9labs.com".parse().unwrap(), eos_marketplace: "https://beta-registry-0-3.start9labs.com".parse().unwrap(),
package_marketplace: None, package_marketplace: None,
wifi: WifiInfo { wifi: WifiInfo {
@@ -72,26 +72,38 @@ impl DatabaseModel {
#[derive(Debug, Deserialize, Serialize, HasModel)] #[derive(Debug, Deserialize, Serialize, HasModel)]
#[serde(rename_all = "kebab-case")] #[serde(rename_all = "kebab-case")]
pub struct ServerInfo { pub struct ServerInfo {
id: String, pub id: String,
version: Version, pub version: Version,
lan_address: Url, pub lan_address: Url,
tor_address: Url, pub tor_address: Url,
status: ServerStatus, #[serde(flatten)]
eos_marketplace: Url, pub status: ServerStatus,
package_marketplace: Option<Url>, pub eos_marketplace: Url,
wifi: WifiInfo, pub package_marketplace: Option<Url>,
unread_notification_count: u64, pub wifi: WifiInfo,
specs: ServerSpecs, pub unread_notification_count: u64,
connection_addresses: ConnectionAddresses, pub specs: ServerSpecs,
share_stats: bool, pub connection_addresses: ConnectionAddresses,
pub share_stats: bool,
} }
#[derive(Debug, Deserialize, Serialize)] #[derive(Debug, Deserialize, Serialize)]
#[serde(rename_all = "kebab-case")] #[serde(rename_all = "kebab-case")]
#[serde(tag = "status")]
pub enum ServerStatus { pub enum ServerStatus {
Running, Running {},
Updating, #[serde(rename_all = "kebab-case")]
BackingUp, 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)] #[derive(Debug, Deserialize, Serialize)]

View File

@@ -3,7 +3,7 @@ use std::sync::Arc;
use rpc_toolkit::command; use rpc_toolkit::command;
use rpc_toolkit::yajrc::RpcError; use rpc_toolkit::yajrc::RpcError;
use crate::context::RecoveryContext; use crate::context::DiagnosticContext;
use crate::logs::{display_logs, fetch_logs, LogResponse, LogSource}; use crate::logs::{display_logs, fetch_logs, LogResponse, LogSource};
use crate::util::display_none; use crate::util::display_none;
use crate::Error; use crate::Error;
@@ -11,12 +11,12 @@ use crate::Error;
pub const SYSTEMD_UNIT: &'static str = "embassy-init"; pub const SYSTEMD_UNIT: &'static str = "embassy-init";
#[command(subcommands(error, logs, exit))] #[command(subcommands(error, logs, exit))]
pub fn recovery() -> Result<(), Error> { pub fn diagnostic() -> Result<(), Error> {
Ok(()) Ok(())
} }
#[command] #[command]
pub fn error(#[context] ctx: RecoveryContext) -> Result<Arc<RpcError>, Error> { pub fn error(#[context] ctx: DiagnosticContext) -> Result<Arc<RpcError>, Error> {
Ok(ctx.error.clone()) Ok(ctx.error.clone())
} }
@@ -36,7 +36,7 @@ pub async fn logs(
} }
#[command(display(display_none))] #[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"); ctx.shutdown.send(()).expect("receiver dropped");
Ok(()) Ok(())
} }

View File

@@ -8,6 +8,8 @@ use crate::{Error, ResultExt};
pub const PASSWORD_PATH: &'static str = "/etc/embassy/password"; pub const PASSWORD_PATH: &'static str = "/etc/embassy/password";
pub const DEFAULT_PASSWORD: &'static str = "password"; pub const DEFAULT_PASSWORD: &'static str = "password";
// TODO: use IncorrectDisk / DiskNotAvailable / DiskCorrupted
pub async fn create<I: IntoIterator<Item = P>, P: AsRef<Path>>( pub async fn create<I: IntoIterator<Item = P>, P: AsRef<Path>>(
pool_name: &str, pool_name: &str,
disks: I, disks: I,

View File

@@ -20,17 +20,17 @@ pub enum ErrorKind {
Deserialization = 12, Deserialization = 12,
Utf8 = 13, Utf8 = 13,
ParseVersion = 14, ParseVersion = 14,
Duplicity = 15, // REMOVE IncorrectDisk = 15,
Nginx = 16, Nginx = 16,
Dependency = 17, Dependency = 17,
ParseS9pk = 18, ParseS9pk = 18,
ParseUrl = 19, ParseUrl = 19,
GParted = 20, // REMOVE DiskNotAvailable = 20,
BlockDevice = 21, BlockDevice = 21,
InvalidOnionAddress = 22, InvalidOnionAddress = 22,
Pack = 23, Pack = 23,
ValidateS9pk = 24, ValidateS9pk = 24,
OpenSSL = 25, // REMOVE DiskCorrupted = 25,
Tor = 26, Tor = 26,
ConfigGen = 27, ConfigGen = 27,
ParseNumber = 28, ParseNumber = 28,
@@ -56,7 +56,7 @@ pub enum ErrorKind {
Zfs = 48, Zfs = 48,
OpenSsl = 49, OpenSsl = 49,
PasswordHashGeneration = 50, PasswordHashGeneration = 50,
RecoveryMode = 51, DiagnosticMode = 51,
ParseDbField = 52, ParseDbField = 52,
} }
impl ErrorKind { impl ErrorKind {
@@ -77,17 +77,17 @@ impl ErrorKind {
Deserialization => "Deserialization Error", Deserialization => "Deserialization Error",
Utf8 => "UTF-8 Parse Error", Utf8 => "UTF-8 Parse Error",
ParseVersion => "Version Parsing Error", ParseVersion => "Version Parsing Error",
Duplicity => "Duplicity Error", IncorrectDisk => "Incorrect Disk",
Nginx => "Nginx Error", Nginx => "Nginx Error",
Dependency => "Dependency Error", Dependency => "Dependency Error",
ParseS9pk => "S9PK Parsing Error", ParseS9pk => "S9PK Parsing Error",
ParseUrl => "URL Parsing Error", ParseUrl => "URL Parsing Error",
GParted => "GNU Parted Error", DiskNotAvailable => "Disk Not Available",
BlockDevice => "Block Device Error", BlockDevice => "Block Device Error",
InvalidOnionAddress => "Invalid Onion Address", InvalidOnionAddress => "Invalid Onion Address",
Pack => "Pack Error", Pack => "Pack Error",
ValidateS9pk => "S9PK Validation Error", ValidateS9pk => "S9PK Validation Error",
OpenSSL => "OpenSSL Error", // Remove DiskCorrupted => "Disk Corrupted", // Remove
Tor => "Tor Daemon Error", Tor => "Tor Daemon Error",
ConfigGen => "Config Generation Error", ConfigGen => "Config Generation Error",
ParseNumber => "Number Parsing Error", ParseNumber => "Number Parsing Error",
@@ -113,7 +113,7 @@ impl ErrorKind {
Zfs => "ZFS Error", Zfs => "ZFS Error",
OpenSsl => "OpenSSL Internal Error", OpenSsl => "OpenSSL Internal Error",
PasswordHashGeneration => "Password Hash Generation Error", PasswordHashGeneration => "Password Hash Generation Error",
RecoveryMode => "Embassy is in Recovery Mode", DiagnosticMode => "Embassy is in Diagnostic Mode",
ParseDbField => "Database Field Parse Error", ParseDbField => "Database Field Parse Error",
} }
} }

View File

@@ -15,6 +15,7 @@ pub mod control;
pub mod db; pub mod db;
pub mod dependencies; pub mod dependencies;
pub mod developer; pub mod developer;
pub mod diagnostic;
pub mod disk; pub mod disk;
pub mod error; pub mod error;
pub mod hostname; pub mod hostname;
@@ -28,7 +29,6 @@ pub mod migration;
pub mod net; pub mod net;
pub mod notifications; pub mod notifications;
pub mod properties; pub mod properties;
pub mod recovery;
pub mod s9pk; pub mod s9pk;
pub mod setup; pub mod setup;
pub mod shutdown; pub mod shutdown;
@@ -106,8 +106,8 @@ pub fn portable_api() -> Result<(), RpcError> {
Ok(()) Ok(())
} }
#[command(subcommands(version::git_info, echo, recovery::recovery))] #[command(subcommands(version::git_info, echo, diagnostic::diagnostic))]
pub fn recovery_api() -> Result<(), RpcError> { pub fn diagnostic_api() -> Result<(), RpcError> {
Ok(()) Ok(())
} }

View File

@@ -7,7 +7,7 @@ use rpc_toolkit::Metadata;
use crate::Error; use crate::Error;
pub async fn recovery<M: Metadata>( pub async fn diagnostic<M: Metadata>(
_req: &mut Request<Body>, _req: &mut Request<Body>,
_metadata: M, _metadata: M,
) -> Result<Result<DynMiddlewareStage2, Response<Body>>, HttpError> { ) -> Result<Result<DynMiddlewareStage2, Response<Body>>, HttpError> {
@@ -19,8 +19,11 @@ pub async fn recovery<M: Metadata>(
if let Err(e) = rpc_res { if let Err(e) = rpc_res {
if e.code == -32601 { if e.code == -32601 {
*e = Error::new( *e = Error::new(
anyhow::anyhow!("{} is not available on the Recovery API", method), anyhow::anyhow!(
crate::ErrorKind::RecoveryMode, "{} is not available on the Diagnostic API",
method
),
crate::ErrorKind::DiagnosticMode,
) )
.into(); .into();
} }

View File

@@ -1,4 +1,4 @@
pub mod auth; pub mod auth;
pub mod cors; pub mod cors;
pub mod diagnostic;
pub mod encrypt; pub mod encrypt;
pub mod recovery;

View File

@@ -2,7 +2,7 @@ server {
listen 80 default_server; listen 80 default_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; index index.html index.htm index.nginx-debian.html;