mirror of
https://github.com/Start9Labs/start-os.git
synced 2026-03-26 10:21:52 +00:00
start consolidating
This commit is contained in:
9
Makefile
9
Makefile
@@ -12,8 +12,8 @@ RUST_ARCH := $(shell if [ "$(ARCH)" = "riscv64" ]; then echo riscv64gc; else ech
|
||||
REGISTRY_BASENAME := $(shell PROJECT=start-registry PLATFORM=$(ARCH) ./build/env/basename.sh)
|
||||
TUNNEL_BASENAME := $(shell PROJECT=start-tunnel PLATFORM=$(ARCH) ./build/env/basename.sh)
|
||||
IMAGE_TYPE=$(shell if [ "$(PLATFORM)" = raspberrypi ]; then echo img; else echo iso; fi)
|
||||
WEB_UIS := web/dist/raw/ui/index.html web/dist/raw/setup-wizard/index.html web/dist/raw/install-wizard/index.html
|
||||
COMPRESSED_WEB_UIS := web/dist/static/ui/index.html web/dist/static/setup-wizard/index.html web/dist/static/install-wizard/index.html
|
||||
WEB_UIS := web/dist/raw/ui/index.html web/dist/raw/setup-wizard/index.html
|
||||
COMPRESSED_WEB_UIS := web/dist/static/ui/index.html web/dist/static/setup-wizard/index.html
|
||||
FIRMWARE_ROMS := build/lib/firmware/$(PLATFORM) $(shell jq --raw-output '.[] | select(.platform[] | contains("$(PLATFORM)")) | "./build/lib/firmware/$(PLATFORM)/" + .id + ".rom.gz"' build/lib/firmware.json)
|
||||
BUILD_SRC := $(call ls-files, build/lib) build/lib/depends build/lib/conflicts $(FIRMWARE_ROMS)
|
||||
IMAGE_RECIPE_SRC := $(call ls-files, build/image-recipe/)
|
||||
@@ -22,7 +22,6 @@ CORE_SRC := $(call ls-files, core) $(shell git ls-files --recurse-submodules pat
|
||||
WEB_SHARED_SRC := $(call ls-files, web/projects/shared) $(call ls-files, web/projects/marketplace) $(shell ls -p web/ | grep -v / | sed 's/^/web\//g') web/node_modules/.package-lock.json web/config.json patch-db/client/dist/index.js sdk/baseDist/package.json web/patchdb-ui-seed.json sdk/dist/package.json
|
||||
WEB_UI_SRC := $(call ls-files, web/projects/ui)
|
||||
WEB_SETUP_WIZARD_SRC := $(call ls-files, web/projects/setup-wizard)
|
||||
WEB_INSTALL_WIZARD_SRC := $(call ls-files, web/projects/install-wizard)
|
||||
WEB_START_TUNNEL_SRC := $(call ls-files, web/projects/start-tunnel)
|
||||
PATCH_DB_CLIENT_SRC := $(shell git ls-files --recurse-submodules patch-db/client)
|
||||
GZIP_BIN := $(shell which pigz || which gzip)
|
||||
@@ -333,10 +332,6 @@ web/dist/raw/setup-wizard/index.html: $(WEB_SETUP_WIZARD_SRC) $(WEB_SHARED_SRC)
|
||||
npm --prefix web run build:setup
|
||||
touch web/dist/raw/setup-wizard/index.html
|
||||
|
||||
web/dist/raw/install-wizard/index.html: $(WEB_INSTALL_WIZARD_SRC) $(WEB_SHARED_SRC) web/.angular/.updated
|
||||
npm --prefix web run build:install
|
||||
touch web/dist/raw/install-wizard/index.html
|
||||
|
||||
web/dist/raw/start-tunnel/index.html: $(WEB_START_TUNNEL_SRC) $(WEB_SHARED_SRC) web/.angular/.updated
|
||||
npm --prefix web run build:tunnel
|
||||
touch web/dist/raw/start-tunnel/index.html
|
||||
|
||||
@@ -75,9 +75,9 @@ pub async fn restore_packages_rpc(
|
||||
}
|
||||
|
||||
#[instrument(skip_all)]
|
||||
pub async fn recover_full_embassy(
|
||||
pub async fn recover_full_server(
|
||||
ctx: &SetupContext,
|
||||
disk_guid: Arc<String>,
|
||||
disk_guid: InternedString,
|
||||
start_os_password: String,
|
||||
recovery_source: TmpMountGuard,
|
||||
server_id: &str,
|
||||
@@ -116,11 +116,13 @@ pub async fn recover_full_embassy(
|
||||
.await?;
|
||||
drop(db);
|
||||
|
||||
let init_result = init(&ctx.webserver, &ctx.config, init_phases).await?;
|
||||
let config = ctx.config.peek(|c| c.clone());
|
||||
|
||||
let init_result = init(&ctx.webserver, &config, init_phases).await?;
|
||||
|
||||
let rpc_ctx = RpcContext::init(
|
||||
&ctx.webserver,
|
||||
&ctx.config,
|
||||
&config,
|
||||
disk_guid.clone(),
|
||||
Some(init_result),
|
||||
rpc_ctx_phases,
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use tokio::process::Command;
|
||||
use tracing::instrument;
|
||||
|
||||
use crate::context::config::ServerConfig;
|
||||
use crate::context::rpc::InitRpcContextPhases;
|
||||
use crate::context::{DiagnosticContext, InitContext, InstallContext, RpcContext, SetupContext};
|
||||
use crate::context::{DiagnosticContext, InitContext, RpcContext, SetupContext};
|
||||
use crate::disk::REPAIR_DISK_PATH;
|
||||
use crate::disk::fsck::RepairStrategy;
|
||||
use crate::disk::main::DEFAULT_PASSWORD;
|
||||
@@ -79,40 +77,11 @@ async fn setup_or_init(
|
||||
.invoke(crate::ErrorKind::OpenSsl)
|
||||
.await?;
|
||||
|
||||
if tokio::fs::metadata("/run/live/medium").await.is_ok() {
|
||||
Command::new("sed")
|
||||
.arg("-i")
|
||||
.arg("s/PasswordAuthentication no/PasswordAuthentication yes/g")
|
||||
.arg("/etc/ssh/sshd_config")
|
||||
.invoke(crate::ErrorKind::Filesystem)
|
||||
.await?;
|
||||
Command::new("systemctl")
|
||||
.arg("reload")
|
||||
.arg("ssh")
|
||||
.invoke(crate::ErrorKind::OpenSsh)
|
||||
.await?;
|
||||
|
||||
let ctx = InstallContext::init().await?;
|
||||
|
||||
server.serve_ui_for(ctx.clone());
|
||||
|
||||
ctx.shutdown
|
||||
.subscribe()
|
||||
.recv()
|
||||
.await
|
||||
.expect("context dropped");
|
||||
|
||||
return Ok(Err(Shutdown {
|
||||
disk_guid: None,
|
||||
restart: true,
|
||||
}));
|
||||
}
|
||||
|
||||
if tokio::fs::metadata("/media/startos/config/disk.guid")
|
||||
.await
|
||||
.is_err()
|
||||
{
|
||||
let ctx = SetupContext::init(server, config)?;
|
||||
let ctx = SetupContext::init(server, config.clone())?;
|
||||
|
||||
server.serve_ui_for(ctx.clone());
|
||||
|
||||
@@ -156,9 +125,9 @@ async fn setup_or_init(
|
||||
disk_phase.start();
|
||||
let guid_string = tokio::fs::read_to_string("/media/startos/config/disk.guid") // unique identifier for volume group - keeps track of the disk that goes with your embassy
|
||||
.await?;
|
||||
let disk_guid = Arc::new(String::from(guid_string.trim()));
|
||||
let disk_guid = InternedString::intern(guid_string.trim());
|
||||
let requires_reboot = crate::disk::main::import(
|
||||
&**disk_guid,
|
||||
&*disk_guid,
|
||||
DATA_DIR,
|
||||
if tokio::fs::metadata(REPAIR_DISK_PATH).await.is_ok() {
|
||||
RepairStrategy::Aggressive
|
||||
@@ -236,11 +205,10 @@ pub async fn main(
|
||||
.await
|
||||
.is_ok()
|
||||
{
|
||||
Some(Arc::new(
|
||||
Some(InternedString::intern(
|
||||
tokio::fs::read_to_string("/media/startos/config/disk.guid") // unique identifier for volume group - keeps track of the disk that goes with your embassy
|
||||
.await?
|
||||
.trim()
|
||||
.to_owned(),
|
||||
.trim(),
|
||||
))
|
||||
} else {
|
||||
None
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
use std::cmp::max;
|
||||
use std::ffi::OsString;
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
|
||||
use clap::Parser;
|
||||
@@ -15,11 +14,11 @@ use crate::context::{DiagnosticContext, InitContext, RpcContext};
|
||||
use crate::net::gateway::{BindTcp, SelfContainedNetworkInterfaceListener, UpgradableListener};
|
||||
use crate::net::static_server::refresher;
|
||||
use crate::net::web_server::{Acceptor, WebServer};
|
||||
use crate::prelude::*;
|
||||
use crate::shutdown::Shutdown;
|
||||
use crate::system::launch_metrics_task;
|
||||
use crate::util::io::append_file;
|
||||
use crate::util::logger::LOGGER;
|
||||
use crate::{Error, ErrorKind, ResultExt};
|
||||
|
||||
#[instrument(skip_all)]
|
||||
async fn inner_main(
|
||||
@@ -53,11 +52,10 @@ async fn inner_main(
|
||||
let ctx = RpcContext::init(
|
||||
&server.acceptor_setter(),
|
||||
config,
|
||||
Arc::new(
|
||||
InternedString::intern(
|
||||
tokio::fs::read_to_string("/media/startos/config/disk.guid") // unique identifier for volume group - keeps track of the disk that goes with your embassy
|
||||
.await?
|
||||
.trim()
|
||||
.to_owned(),
|
||||
.trim(),
|
||||
),
|
||||
None,
|
||||
rpc_ctx_phases,
|
||||
@@ -167,11 +165,10 @@ pub fn main(args: impl IntoIterator<Item = OsString>) {
|
||||
.await
|
||||
.is_ok()
|
||||
{
|
||||
Some(Arc::new(
|
||||
Some(InternedString::intern(
|
||||
tokio::fs::read_to_string("/media/startos/config/disk.guid") // unique identifier for volume group - keeps track of the disk that goes with your embassy
|
||||
.await?
|
||||
.trim()
|
||||
.to_owned(),
|
||||
.trim(),
|
||||
))
|
||||
} else {
|
||||
None
|
||||
|
||||
@@ -23,7 +23,7 @@ use tracing::instrument;
|
||||
|
||||
use super::setup::CURRENT_SECRET;
|
||||
use crate::context::config::{ClientConfig, local_config_path};
|
||||
use crate::context::{DiagnosticContext, InitContext, InstallContext, RpcContext, SetupContext};
|
||||
use crate::context::{DiagnosticContext, InitContext, RpcContext, SetupContext};
|
||||
use crate::developer::{OS_DEVELOPER_KEY_PATH, default_developer_key_path};
|
||||
use crate::middleware::auth::local::LocalAuthContext;
|
||||
use crate::prelude::*;
|
||||
@@ -394,22 +394,3 @@ impl CallRemote<SetupContext> for CliContext {
|
||||
.await
|
||||
}
|
||||
}
|
||||
impl CallRemote<InstallContext> for CliContext {
|
||||
async fn call_remote(
|
||||
&self,
|
||||
method: &str,
|
||||
_: OrdMap<&'static str, Value>,
|
||||
params: Value,
|
||||
_: Empty,
|
||||
) -> Result<Value, RpcError> {
|
||||
crate::middleware::auth::signature::call_remote(
|
||||
self,
|
||||
self.rpc_url.clone(),
|
||||
HeaderMap::new(),
|
||||
self.rpc_url.host_str(),
|
||||
method,
|
||||
params,
|
||||
)
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
@@ -111,8 +111,6 @@ impl ClientConfig {
|
||||
pub struct ServerConfig {
|
||||
#[arg(short, long)]
|
||||
pub config: Option<PathBuf>,
|
||||
#[arg(long)]
|
||||
pub ethernet_interface: Option<String>,
|
||||
#[arg(skip)]
|
||||
pub os_partitions: Option<OsPartitionInfo>,
|
||||
#[arg(long)]
|
||||
@@ -131,7 +129,6 @@ impl ContextConfig for ServerConfig {
|
||||
self.config.take()
|
||||
}
|
||||
fn merge_with(&mut self, other: Self) {
|
||||
self.ethernet_interface = self.ethernet_interface.take().or(other.ethernet_interface);
|
||||
self.os_partitions = self.os_partitions.take().or(other.os_partitions);
|
||||
self.socks_listen = self.socks_listen.take().or(other.socks_listen);
|
||||
self.revision_cache_size = self
|
||||
|
||||
@@ -6,15 +6,15 @@ use rpc_toolkit::yajrc::RpcError;
|
||||
use tokio::sync::broadcast::Sender;
|
||||
use tracing::instrument;
|
||||
|
||||
use crate::Error;
|
||||
use crate::context::config::ServerConfig;
|
||||
use crate::prelude::*;
|
||||
use crate::rpc_continuations::RpcContinuations;
|
||||
use crate::shutdown::Shutdown;
|
||||
|
||||
pub struct DiagnosticContextSeed {
|
||||
pub shutdown: Sender<Shutdown>,
|
||||
pub error: Arc<RpcError>,
|
||||
pub disk_guid: Option<Arc<String>>,
|
||||
pub disk_guid: Option<InternedString>,
|
||||
pub rpc_continuations: RpcContinuations,
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ impl DiagnosticContext {
|
||||
#[instrument(skip_all)]
|
||||
pub fn init(
|
||||
_config: &ServerConfig,
|
||||
disk_guid: Option<Arc<String>>,
|
||||
disk_guid: Option<InternedString>,
|
||||
error: Error,
|
||||
) -> Result<Self, Error> {
|
||||
tracing::error!("Error: {}: Starting diagnostic UI", error);
|
||||
|
||||
@@ -1,44 +0,0 @@
|
||||
use std::ops::Deref;
|
||||
use std::sync::Arc;
|
||||
|
||||
use rpc_toolkit::Context;
|
||||
use tokio::sync::broadcast::Sender;
|
||||
use tracing::instrument;
|
||||
|
||||
use crate::Error;
|
||||
use crate::net::utils::find_eth_iface;
|
||||
use crate::rpc_continuations::RpcContinuations;
|
||||
|
||||
pub struct InstallContextSeed {
|
||||
pub ethernet_interface: String,
|
||||
pub shutdown: Sender<()>,
|
||||
pub rpc_continuations: RpcContinuations,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct InstallContext(Arc<InstallContextSeed>);
|
||||
impl InstallContext {
|
||||
#[instrument(skip_all)]
|
||||
pub async fn init() -> Result<Self, Error> {
|
||||
let (shutdown, _) = tokio::sync::broadcast::channel(1);
|
||||
Ok(Self(Arc::new(InstallContextSeed {
|
||||
ethernet_interface: find_eth_iface().await?,
|
||||
shutdown,
|
||||
rpc_continuations: RpcContinuations::new(),
|
||||
})))
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<RpcContinuations> for InstallContext {
|
||||
fn as_ref(&self) -> &RpcContinuations {
|
||||
&self.rpc_continuations
|
||||
}
|
||||
}
|
||||
|
||||
impl Context for InstallContext {}
|
||||
impl Deref for InstallContext {
|
||||
type Target = InstallContextSeed;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&*self.0
|
||||
}
|
||||
}
|
||||
@@ -2,13 +2,11 @@ pub mod cli;
|
||||
pub mod config;
|
||||
pub mod diagnostic;
|
||||
pub mod init;
|
||||
pub mod install;
|
||||
pub mod rpc;
|
||||
pub mod setup;
|
||||
|
||||
pub use cli::CliContext;
|
||||
pub use diagnostic::DiagnosticContext;
|
||||
pub use init::InitContext;
|
||||
pub use install::InstallContext;
|
||||
pub use rpc::RpcContext;
|
||||
pub use setup::SetupContext;
|
||||
|
||||
@@ -60,7 +60,7 @@ pub struct RpcContextSeed {
|
||||
pub os_partitions: OsPartitionInfo,
|
||||
pub wifi_interface: Option<String>,
|
||||
pub ethernet_interface: String,
|
||||
pub disk_guid: Arc<String>,
|
||||
pub disk_guid: InternedString,
|
||||
pub ephemeral_sessions: SyncMutex<Sessions>,
|
||||
pub db: TypedPatchDb<Database>,
|
||||
pub sync_db: watch::Sender<u64>,
|
||||
@@ -134,7 +134,7 @@ impl RpcContext {
|
||||
pub async fn init(
|
||||
webserver: &WebServerAcceptorSetter<UpgradableListener>,
|
||||
config: &ServerConfig,
|
||||
disk_guid: Arc<String>,
|
||||
disk_guid: InternedString,
|
||||
init_result: Option<InitResult>,
|
||||
InitRpcContextPhases {
|
||||
mut load_db,
|
||||
@@ -340,11 +340,7 @@ impl RpcContext {
|
||||
)
|
||||
})?,
|
||||
wifi_interface: wifi_interface.clone(),
|
||||
ethernet_interface: if let Some(eth) = config.ethernet_interface.clone() {
|
||||
eth
|
||||
} else {
|
||||
find_eth_iface().await?
|
||||
},
|
||||
ethernet_interface: find_eth_iface().await?,
|
||||
disk_guid,
|
||||
ephemeral_sessions: SyncMutex::new(Sessions::new()),
|
||||
sync_db: watch::Sender::new(db.sequence().await),
|
||||
|
||||
@@ -18,7 +18,7 @@ use crate::MAIN_DATA;
|
||||
use crate::account::AccountInfo;
|
||||
use crate::context::RpcContext;
|
||||
use crate::context::config::ServerConfig;
|
||||
use crate::disk::OsPartitionInfo;
|
||||
use crate::disk::mount::guard::TmpMountGuard;
|
||||
use crate::hostname::Hostname;
|
||||
use crate::net::gateway::UpgradableListener;
|
||||
use crate::net::web_server::{WebServer, WebServerAcceptorSetter};
|
||||
@@ -28,6 +28,7 @@ use crate::rpc_continuations::{Guid, RpcContinuation, RpcContinuations};
|
||||
use crate::setup::SetupProgress;
|
||||
use crate::shutdown::Shutdown;
|
||||
use crate::util::future::NonDetachingJoinHandle;
|
||||
use crate::util::sync::SyncMutex;
|
||||
|
||||
lazy_static::lazy_static! {
|
||||
pub static ref CURRENT_SECRET: Jwk = Jwk::generate_ec_key(josekit::jwk::alg::ec::EcCurve::P256).unwrap_or_else(|e| {
|
||||
@@ -66,15 +67,15 @@ impl TryFrom<&AccountInfo> for SetupResult {
|
||||
|
||||
pub struct SetupContextSeed {
|
||||
pub webserver: WebServerAcceptorSetter<UpgradableListener>,
|
||||
pub config: ServerConfig,
|
||||
pub os_partitions: OsPartitionInfo,
|
||||
pub config: SyncMutex<ServerConfig>,
|
||||
pub disable_encryption: bool,
|
||||
pub progress: FullProgressTracker,
|
||||
pub task: OnceCell<NonDetachingJoinHandle<()>>,
|
||||
pub result: OnceCell<Result<(SetupResult, RpcContext), Error>>,
|
||||
pub disk_guid: OnceCell<Arc<String>>,
|
||||
pub disk_guid: OnceCell<InternedString>,
|
||||
pub shutdown: Sender<Option<Shutdown>>,
|
||||
pub rpc_continuations: RpcContinuations,
|
||||
pub install_rootfs: SyncMutex<Option<TmpMountGuard>>,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
@@ -83,27 +84,22 @@ impl SetupContext {
|
||||
#[instrument(skip_all)]
|
||||
pub fn init(
|
||||
webserver: &WebServer<UpgradableListener>,
|
||||
config: &ServerConfig,
|
||||
config: ServerConfig,
|
||||
) -> Result<Self, Error> {
|
||||
let (shutdown, _) = tokio::sync::broadcast::channel(1);
|
||||
let mut progress = FullProgressTracker::new();
|
||||
progress.enable_logging(true);
|
||||
Ok(Self(Arc::new(SetupContextSeed {
|
||||
webserver: webserver.acceptor_setter(),
|
||||
config: config.clone(),
|
||||
os_partitions: config.os_partitions.clone().ok_or_else(|| {
|
||||
Error::new(
|
||||
eyre!("missing required configuration: `os-partitions`"),
|
||||
ErrorKind::NotFound,
|
||||
)
|
||||
})?,
|
||||
disable_encryption: config.disable_encryption.unwrap_or(false),
|
||||
config: SyncMutex::new(config),
|
||||
progress,
|
||||
task: OnceCell::new(),
|
||||
result: OnceCell::new(),
|
||||
disk_guid: OnceCell::new(),
|
||||
shutdown,
|
||||
rpc_continuations: RpcContinuations::new(),
|
||||
install_rootfs: SyncMutex::new(None),
|
||||
})))
|
||||
}
|
||||
#[instrument(skip_all)]
|
||||
|
||||
@@ -2,6 +2,7 @@ use std::collections::BTreeMap;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use color_eyre::eyre::eyre;
|
||||
use imbl_value::InternedString;
|
||||
use tokio::process::Command;
|
||||
use tracing::instrument;
|
||||
|
||||
@@ -20,10 +21,10 @@ pub const MAIN_FS_SIZE: FsSize = FsSize::Gigabytes(8);
|
||||
#[instrument(skip_all)]
|
||||
pub async fn create<I, P>(
|
||||
disks: &I,
|
||||
pvscan: &BTreeMap<PathBuf, Option<String>>,
|
||||
pvscan: &BTreeMap<PathBuf, Option<InternedString>>,
|
||||
datadir: impl AsRef<Path>,
|
||||
password: Option<&str>,
|
||||
) -> Result<String, Error>
|
||||
) -> Result<InternedString, Error>
|
||||
where
|
||||
for<'a> &'a I: IntoIterator<Item = &'a P>,
|
||||
P: AsRef<Path>,
|
||||
@@ -37,9 +38,9 @@ where
|
||||
#[instrument(skip_all)]
|
||||
pub async fn create_pool<I, P>(
|
||||
disks: &I,
|
||||
pvscan: &BTreeMap<PathBuf, Option<String>>,
|
||||
pvscan: &BTreeMap<PathBuf, Option<InternedString>>,
|
||||
encrypted: bool,
|
||||
) -> Result<String, Error>
|
||||
) -> Result<InternedString, Error>
|
||||
where
|
||||
for<'a> &'a I: IntoIterator<Item = &'a P>,
|
||||
P: AsRef<Path>,
|
||||
@@ -79,7 +80,7 @@ where
|
||||
cmd.arg(disk.as_ref());
|
||||
}
|
||||
cmd.invoke(crate::ErrorKind::DiskManagement).await?;
|
||||
Ok(guid)
|
||||
Ok(guid.into())
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
|
||||
@@ -25,6 +25,8 @@ pub struct OsPartitionInfo {
|
||||
pub bios: Option<PathBuf>,
|
||||
pub boot: PathBuf,
|
||||
pub root: PathBuf,
|
||||
#[serde(skip)] // internal use only
|
||||
pub data: Option<PathBuf>,
|
||||
}
|
||||
impl OsPartitionInfo {
|
||||
pub fn contains(&self, logicalname: impl AsRef<Path>) -> bool {
|
||||
|
||||
@@ -20,9 +20,9 @@ use super::mount::guard::TmpMountGuard;
|
||||
use crate::disk::OsPartitionInfo;
|
||||
use crate::disk::mount::guard::GenericMountGuard;
|
||||
use crate::hostname::Hostname;
|
||||
use crate::prelude::*;
|
||||
use crate::util::Invoke;
|
||||
use crate::util::serde::IoFormat;
|
||||
use crate::{Error, ResultExt as _};
|
||||
|
||||
#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
@@ -40,7 +40,7 @@ pub struct DiskInfo {
|
||||
pub model: Option<String>,
|
||||
pub partitions: Vec<PartitionInfo>,
|
||||
pub capacity: u64,
|
||||
pub guid: Option<String>,
|
||||
pub guid: Option<InternedString>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||
@@ -51,7 +51,7 @@ pub struct PartitionInfo {
|
||||
pub capacity: u64,
|
||||
pub used: Option<u64>,
|
||||
pub start_os: BTreeMap<String, StartOsRecoveryInfo>,
|
||||
pub guid: Option<String>,
|
||||
pub guid: Option<InternedString>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, Deserialize, Serialize)]
|
||||
@@ -215,7 +215,7 @@ pub async fn get_percentage<P: AsRef<Path>>(path: P) -> Result<u64, Error> {
|
||||
}
|
||||
|
||||
#[instrument(skip_all)]
|
||||
pub async fn pvscan() -> Result<BTreeMap<PathBuf, Option<String>>, Error> {
|
||||
pub async fn pvscan() -> Result<BTreeMap<PathBuf, Option<InternedString>>, Error> {
|
||||
let pvscan_out = Command::new("pvscan")
|
||||
.invoke(crate::ErrorKind::DiskManagement)
|
||||
.await?;
|
||||
@@ -448,7 +448,7 @@ async fn part_info(part: PathBuf) -> PartitionInfo {
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_pvscan_output(pvscan_output: &str) -> BTreeMap<PathBuf, Option<String>> {
|
||||
fn parse_pvscan_output(pvscan_output: &str) -> BTreeMap<PathBuf, Option<InternedString>> {
|
||||
fn parse_line(line: &str) -> IResult<&str, (&str, Option<&str>)> {
|
||||
let pv_parse = preceded(
|
||||
tag(" PV "),
|
||||
@@ -471,7 +471,7 @@ fn parse_pvscan_output(pvscan_output: &str) -> BTreeMap<PathBuf, Option<String>>
|
||||
for entry in entries {
|
||||
match parse_line(entry) {
|
||||
Ok((_, (pv, vg))) => {
|
||||
ret.insert(PathBuf::from(pv), vg.map(|s| s.to_owned()));
|
||||
ret.insert(PathBuf::from(pv), vg.map(InternedString::intern));
|
||||
}
|
||||
Err(_) => {
|
||||
tracing::warn!("Failed to parse pvscan output line: {}", entry);
|
||||
|
||||
@@ -242,12 +242,7 @@ pub fn main_api<C: Context>() -> ParentHandler<C> {
|
||||
.with_about("Commands to display logs, restart the server, etc"),
|
||||
)
|
||||
.subcommand("init", init::init_api::<C>())
|
||||
.subcommand("setup", setup::setup::<C>())
|
||||
.subcommand(
|
||||
"install",
|
||||
os_install::install::<C>()
|
||||
.with_about("Commands to list disk info, install StartOS, and reboot"),
|
||||
);
|
||||
.subcommand("setup", setup::setup::<C>());
|
||||
if &*PLATFORM != "raspberrypi" {
|
||||
api = api.subcommand("kiosk", kiosk::<C>());
|
||||
}
|
||||
|
||||
@@ -11,11 +11,6 @@ fn main() {
|
||||
"$CARGO_MANIFEST_DIR/../web/dist/static/setup-wizard"
|
||||
))
|
||||
.ok();
|
||||
startos::net::static_server::INSTALL_WIZARD_CELL
|
||||
.set(include_dir::include_dir!(
|
||||
"$CARGO_MANIFEST_DIR/../web/dist/static/install-wizard"
|
||||
))
|
||||
.ok();
|
||||
#[cfg(not(feature = "beta"))]
|
||||
startos::db::model::public::DB_UI_SEED_CELL
|
||||
.set(include_str!(concat!(
|
||||
|
||||
@@ -30,7 +30,7 @@ use tokio::io::{AsyncRead, AsyncReadExt, AsyncSeekExt, BufReader};
|
||||
use tokio_util::io::ReaderStream;
|
||||
use url::Url;
|
||||
|
||||
use crate::context::{DiagnosticContext, InitContext, InstallContext, RpcContext, SetupContext};
|
||||
use crate::context::{DiagnosticContext, InitContext, RpcContext, SetupContext};
|
||||
use crate::hostname::Hostname;
|
||||
use crate::middleware::auth::Auth;
|
||||
use crate::middleware::auth::session::ValidSessionToken;
|
||||
@@ -178,20 +178,6 @@ impl UiContext for SetupContext {
|
||||
}
|
||||
}
|
||||
|
||||
pub static INSTALL_WIZARD_CELL: OnceLock<Dir<'static>> = OnceLock::new();
|
||||
|
||||
impl UiContext for InstallContext {
|
||||
fn ui_dir() -> &'static Dir<'static> {
|
||||
INSTALL_WIZARD_CELL.get().unwrap_or(&EMPTY_DIR)
|
||||
}
|
||||
fn api() -> ParentHandler<Self> {
|
||||
main_api()
|
||||
}
|
||||
fn middleware(server: Server<Self>) -> HttpServer<Self> {
|
||||
server.middleware(Cors::new())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn rpc_router<C: Context + Clone + AsRef<RpcContinuations>>(
|
||||
ctx: C,
|
||||
server: HttpServer<C>,
|
||||
|
||||
@@ -9,7 +9,7 @@ use crate::os_install::partition_for;
|
||||
use crate::prelude::*;
|
||||
|
||||
pub async fn partition(disk: &DiskInfo, overwrite: bool) -> Result<OsPartitionInfo, Error> {
|
||||
let efi = {
|
||||
let (efi, data_part) = {
|
||||
let disk = disk.clone();
|
||||
tokio::task::spawn_blocking(move || {
|
||||
let use_efi = Path::new("/sys/firmware/efi").exists();
|
||||
@@ -93,6 +93,7 @@ pub async fn partition(disk: &DiskInfo, overwrite: bool) -> Result<OsPartitionIn
|
||||
None,
|
||||
)?;
|
||||
|
||||
let mut data_part = None;
|
||||
if overwrite {
|
||||
gpt.add_partition(
|
||||
"data",
|
||||
@@ -110,6 +111,10 @@ pub async fn partition(disk: &DiskInfo, overwrite: bool) -> Result<OsPartitionIn
|
||||
0,
|
||||
None,
|
||||
)?;
|
||||
data_part = gpt
|
||||
.partitions()
|
||||
.last_key_value()
|
||||
.map(|(num, _)| partition_for(&disk.logicalname, *num));
|
||||
} else if let Some(guid_part) = guid_part {
|
||||
let mut parts = gpt.partitions().clone();
|
||||
parts.insert(
|
||||
@@ -119,11 +124,15 @@ pub async fn partition(disk: &DiskInfo, overwrite: bool) -> Result<OsPartitionIn
|
||||
guid_part,
|
||||
);
|
||||
gpt.update_partitions(parts)?;
|
||||
data_part = gpt
|
||||
.partitions()
|
||||
.last_key_value()
|
||||
.map(|(num, _)| partition_for(&disk.logicalname, *num));
|
||||
}
|
||||
|
||||
gpt.write()?;
|
||||
|
||||
Ok(efi)
|
||||
Ok((efi, data_part))
|
||||
})
|
||||
.await
|
||||
.unwrap()?
|
||||
@@ -134,5 +143,6 @@ pub async fn partition(disk: &DiskInfo, overwrite: bool) -> Result<OsPartitionIn
|
||||
bios: (!efi).then(|| partition_for(&disk.logicalname, 1)),
|
||||
boot: partition_for(&disk.logicalname, 2),
|
||||
root: partition_for(&disk.logicalname, 3),
|
||||
data: data_part,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ use crate::disk::util::DiskInfo;
|
||||
use crate::os_install::partition_for;
|
||||
|
||||
pub async fn partition(disk: &DiskInfo, overwrite: bool) -> Result<OsPartitionInfo, Error> {
|
||||
{
|
||||
let data_part = {
|
||||
let sectors = (disk.capacity / 512) as u32;
|
||||
let disk = disk.clone();
|
||||
tokio::task::spawn_blocking(move || {
|
||||
@@ -59,6 +59,7 @@ pub async fn partition(disk: &DiskInfo, overwrite: bool) -> Result<OsPartitionIn
|
||||
sectors: 33556480 - 2099200,
|
||||
};
|
||||
|
||||
let mut data_part = true;
|
||||
if overwrite {
|
||||
mbr[3] = MBRPartitionEntry {
|
||||
boot: 0,
|
||||
@@ -70,19 +71,22 @@ pub async fn partition(disk: &DiskInfo, overwrite: bool) -> Result<OsPartitionIn
|
||||
}
|
||||
} else if let Some(guid_part) = guid_part {
|
||||
mbr[3] = guid_part;
|
||||
} else {
|
||||
data_part = false;
|
||||
}
|
||||
mbr.write_into(&mut file)?;
|
||||
|
||||
Ok(())
|
||||
Ok(data_part)
|
||||
})
|
||||
.await
|
||||
.unwrap()?;
|
||||
}
|
||||
.unwrap()?
|
||||
};
|
||||
|
||||
Ok(OsPartitionInfo {
|
||||
efi: None,
|
||||
bios: None,
|
||||
boot: partition_for(&disk.logicalname, 1),
|
||||
root: partition_for(&disk.logicalname, 2),
|
||||
data: data_part.then(|| partition_for(&disk.logicalname, 3)),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -2,13 +2,12 @@ use std::path::{Path, PathBuf};
|
||||
|
||||
use clap::Parser;
|
||||
use color_eyre::eyre::eyre;
|
||||
use rpc_toolkit::{Context, HandlerExt, ParentHandler, from_fn_async};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tokio::process::Command;
|
||||
use ts_rs::TS;
|
||||
|
||||
use crate::context::SetupContext;
|
||||
use crate::context::config::ServerConfig;
|
||||
use crate::context::{CliContext, InstallContext};
|
||||
use crate::disk::OsPartitionInfo;
|
||||
use crate::disk::mount::filesystem::bind::Bind;
|
||||
use crate::disk::mount::filesystem::block_dev::BlockDev;
|
||||
@@ -17,80 +16,18 @@ use crate::disk::mount::filesystem::overlayfs::OverlayFs;
|
||||
use crate::disk::mount::filesystem::{MountType, ReadWrite};
|
||||
use crate::disk::mount::guard::{GenericMountGuard, MountGuard, TmpMountGuard};
|
||||
use crate::disk::util::{DiskInfo, PartitionTable};
|
||||
use crate::net::utils::find_eth_iface;
|
||||
use crate::prelude::*;
|
||||
use crate::s9pk::merkle_archive::source::multi_cursor_file::MultiCursorFile;
|
||||
use crate::setup::SetupInfo;
|
||||
use crate::util::Invoke;
|
||||
use crate::util::io::{TmpDir, delete_file, open_file};
|
||||
use crate::util::io::{TmpDir, delete_file, open_file, write_file_atomic};
|
||||
use crate::util::serde::IoFormat;
|
||||
use crate::{ARCH, Error};
|
||||
|
||||
mod gpt;
|
||||
mod mbr;
|
||||
|
||||
pub fn install<C: Context>() -> ParentHandler<C> {
|
||||
ParentHandler::new()
|
||||
.subcommand("disk", disk::<C>().with_about("Command to list disk info"))
|
||||
.subcommand(
|
||||
"execute",
|
||||
from_fn_async(execute::<InstallContext>)
|
||||
.no_display()
|
||||
.with_about("Install StartOS over existing version")
|
||||
.with_call_remote::<CliContext>(),
|
||||
)
|
||||
.subcommand(
|
||||
"reboot",
|
||||
from_fn_async(reboot)
|
||||
.no_display()
|
||||
.with_about("Restart the server")
|
||||
.with_call_remote::<CliContext>(),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn disk<C: Context>() -> ParentHandler<C> {
|
||||
ParentHandler::new().subcommand(
|
||||
"list",
|
||||
from_fn_async(list)
|
||||
.no_display()
|
||||
.with_about("List disk info")
|
||||
.with_call_remote::<CliContext>(),
|
||||
)
|
||||
}
|
||||
|
||||
pub async fn list(_: InstallContext) -> Result<Vec<DiskInfo>, Error> {
|
||||
let skip = match async {
|
||||
Ok::<_, Error>(
|
||||
Path::new(
|
||||
&String::from_utf8(
|
||||
Command::new("grub-probe-default")
|
||||
.arg("-t")
|
||||
.arg("disk")
|
||||
.arg("/run/live/medium")
|
||||
.invoke(crate::ErrorKind::Grub)
|
||||
.await?,
|
||||
)?
|
||||
.trim(),
|
||||
)
|
||||
.to_owned(),
|
||||
)
|
||||
}
|
||||
.await
|
||||
{
|
||||
Ok(a) => Some(a),
|
||||
Err(e) => {
|
||||
tracing::error!("Could not determine live usb device: {}", e);
|
||||
tracing::debug!("{:?}", e);
|
||||
None
|
||||
}
|
||||
};
|
||||
Ok(crate::disk::util::list(&Default::default())
|
||||
.await?
|
||||
.into_iter()
|
||||
.filter(|i| Some(&*i.logicalname) != skip.as_deref())
|
||||
.collect())
|
||||
}
|
||||
|
||||
pub fn partition_for(disk: impl AsRef<Path>, idx: usize) -> PathBuf {
|
||||
pub fn partition_for(disk: impl AsRef<Path>, idx: u32) -> PathBuf {
|
||||
let disk_path = disk.as_ref();
|
||||
let (root, leaf) = if let (Some(root), Some(leaf)) = (
|
||||
disk_path.parent(),
|
||||
@@ -122,34 +59,52 @@ async fn partition(disk: &mut DiskInfo, overwrite: bool) -> Result<OsPartitionIn
|
||||
#[derive(Deserialize, Serialize, Parser, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[command(rename_all = "kebab-case")]
|
||||
pub struct ExecuteParams {
|
||||
logicalname: PathBuf,
|
||||
#[arg(short = 'o')]
|
||||
overwrite: bool,
|
||||
pub struct InstallOsParams {
|
||||
os_drive: PathBuf,
|
||||
#[command(flatten)]
|
||||
data_drive: Option<DataDrive>,
|
||||
}
|
||||
|
||||
pub async fn execute<C: Context>(
|
||||
_: C,
|
||||
ExecuteParams {
|
||||
logicalname,
|
||||
mut overwrite,
|
||||
}: ExecuteParams,
|
||||
) -> Result<(), Error> {
|
||||
let mut disk = crate::disk::util::list(&Default::default())
|
||||
.await?
|
||||
.into_iter()
|
||||
.find(|d| &d.logicalname == &logicalname)
|
||||
#[derive(Deserialize, Serialize, Parser, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[command(rename_all = "kebab-case")]
|
||||
struct DataDrive {
|
||||
#[arg(long = "data-drive")]
|
||||
logicalname: PathBuf,
|
||||
#[arg(long)]
|
||||
wipe: bool,
|
||||
}
|
||||
|
||||
pub async fn install_os(
|
||||
ctx: SetupContext,
|
||||
InstallOsParams {
|
||||
os_drive,
|
||||
data_drive,
|
||||
}: InstallOsParams,
|
||||
) -> Result<SetupInfo, Error> {
|
||||
let mut disks = crate::disk::util::list(&Default::default()).await?;
|
||||
let disk = disks
|
||||
.iter_mut()
|
||||
.find(|d| &d.logicalname == &os_drive)
|
||||
.ok_or_else(|| {
|
||||
Error::new(
|
||||
eyre!("Unknown disk {}", logicalname.display()),
|
||||
eyre!("Unknown disk {}", os_drive.display()),
|
||||
crate::ErrorKind::DiskManagement,
|
||||
)
|
||||
})?;
|
||||
let eth_iface = find_eth_iface().await?;
|
||||
|
||||
overwrite |= disk.guid.is_none() && disk.partitions.iter().all(|p| p.guid.is_none());
|
||||
let overwrite = if let Some(data_drive) = &data_drive {
|
||||
data_drive.wipe
|
||||
|| ((disk.guid.is_none() || disk.logicalname != data_drive.logicalname)
|
||||
&& disk
|
||||
.partitions
|
||||
.iter()
|
||||
.all(|p| p.guid.is_none() || p.logicalname != data_drive.logicalname))
|
||||
} else {
|
||||
true
|
||||
};
|
||||
|
||||
let part_info = partition(&mut disk, overwrite).await?;
|
||||
let part_info = partition(disk, overwrite).await?;
|
||||
|
||||
if let Some(efi) = &part_info.efi {
|
||||
Command::new("mkfs.vfat")
|
||||
@@ -271,11 +226,12 @@ pub async fn execute<C: Context>(
|
||||
rootfs.path().join("config/config.yaml"),
|
||||
IoFormat::Yaml.to_vec(&ServerConfig {
|
||||
os_partitions: Some(part_info.clone()),
|
||||
ethernet_interface: Some(eth_iface),
|
||||
..Default::default()
|
||||
})?,
|
||||
)
|
||||
.await?;
|
||||
ctx.config
|
||||
.mutate(|c| c.os_partitions = Some(part_info.clone()));
|
||||
|
||||
let lower = TmpMountGuard::mount(&BlockDev::new(&image_path), MountType::ReadOnly).await?;
|
||||
let work = config_path.join("work");
|
||||
@@ -396,15 +352,47 @@ pub async fn execute<C: Context>(
|
||||
tokio::fs::remove_dir_all(&work).await?;
|
||||
lower.unmount().await?;
|
||||
|
||||
rootfs.unmount().await?;
|
||||
let mut setup_info = SetupInfo::default();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
if let Some(data_drive) = data_drive {
|
||||
let mut logicalname = &*data_drive.logicalname;
|
||||
if logicalname == &os_drive {
|
||||
logicalname = part_info.data.as_deref().ok_or_else(|| {
|
||||
Error::new(
|
||||
eyre!("not enough room on OS drive for data"),
|
||||
ErrorKind::InvalidRequest,
|
||||
)
|
||||
})?;
|
||||
}
|
||||
if let Some(guid) = disks.iter().find_map(|d| {
|
||||
d.guid
|
||||
.as_ref()
|
||||
.filter(|_| &d.logicalname == logicalname)
|
||||
.cloned()
|
||||
.or_else(|| {
|
||||
d.partitions.iter().find_map(|p| {
|
||||
p.guid
|
||||
.as_ref()
|
||||
.filter(|_| &p.logicalname == logicalname)
|
||||
.cloned()
|
||||
})
|
||||
})
|
||||
}) {
|
||||
setup_info.guid = Some(guid);
|
||||
setup_info.attach = true;
|
||||
} else {
|
||||
let guid = crate::setup::setup_data_drive(&ctx, logicalname).await?;
|
||||
setup_info.guid = Some(guid);
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn reboot(ctx: InstallContext) -> Result<(), Error> {
|
||||
Command::new("sync")
|
||||
.invoke(crate::ErrorKind::Filesystem)
|
||||
.await?;
|
||||
ctx.shutdown.send(()).unwrap();
|
||||
Ok(())
|
||||
write_file_atomic(
|
||||
rootfs.path().join("config/setup.json"),
|
||||
IoFormat::JsonPretty.to_vec(&setup_info)?,
|
||||
)
|
||||
.await?;
|
||||
|
||||
ctx.install_rootfs.replace(Some(rootfs));
|
||||
|
||||
Ok(setup_info)
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
use std::collections::BTreeMap;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
|
||||
use color_eyre::eyre::eyre;
|
||||
@@ -18,7 +17,7 @@ use ts_rs::TS;
|
||||
|
||||
use crate::account::AccountInfo;
|
||||
use crate::auth::write_shadow;
|
||||
use crate::backup::restore::recover_full_embassy;
|
||||
use crate::backup::restore::recover_full_server;
|
||||
use crate::backup::target::BackupTargetFS;
|
||||
use crate::context::rpc::InitRpcContextPhases;
|
||||
use crate::context::setup::SetupResult;
|
||||
@@ -40,7 +39,8 @@ use crate::shutdown::Shutdown;
|
||||
use crate::system::sync_kiosk;
|
||||
use crate::util::Invoke;
|
||||
use crate::util::crypto::EncryptedWire;
|
||||
use crate::util::io::{Counter, create_file, dir_copy, dir_size};
|
||||
use crate::util::io::{Counter, create_file, dir_copy, dir_size, read_file_to_string};
|
||||
use crate::util::serde::IoFormat;
|
||||
use crate::{DATA_DIR, Error, ErrorKind, MAIN_DATA, PACKAGE_DATA, PLATFORM, ResultExt};
|
||||
|
||||
pub fn setup<C: Context>() -> ParentHandler<C> {
|
||||
@@ -53,6 +53,10 @@ pub fn setup<C: Context>() -> ParentHandler<C> {
|
||||
)
|
||||
.subcommand("disk", disk::<C>())
|
||||
.subcommand("attach", from_fn_async(attach).no_cli())
|
||||
.subcommand(
|
||||
"install-os",
|
||||
from_fn_async(crate::os_install::install_os).no_cli(),
|
||||
)
|
||||
.subcommand("execute", from_fn_async(execute).no_cli())
|
||||
.subcommand("cifs", cifs::<C>())
|
||||
.subcommand("complete", from_fn_async(complete).no_cli())
|
||||
@@ -81,7 +85,12 @@ pub fn disk<C: Context>() -> ParentHandler<C> {
|
||||
}
|
||||
|
||||
pub async fn list_disks(ctx: SetupContext) -> Result<Vec<DiskInfo>, Error> {
|
||||
crate::disk::util::list(&ctx.os_partitions).await
|
||||
crate::disk::util::list(
|
||||
&ctx.config
|
||||
.peek(|c| c.os_partitions.clone())
|
||||
.unwrap_or_default(),
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
#[instrument(skip_all)]
|
||||
@@ -91,7 +100,7 @@ async fn setup_init(
|
||||
kiosk: Option<bool>,
|
||||
init_phases: InitPhases,
|
||||
) -> Result<(AccountInfo, InitResult), Error> {
|
||||
let init_result = init(&ctx.webserver, &ctx.config, init_phases).await?;
|
||||
let init_result = init(&ctx.webserver, &ctx.config.peek(|c| c.clone()), init_phases).await?;
|
||||
|
||||
let account = init_result
|
||||
.net_ctrl
|
||||
@@ -127,10 +136,10 @@ async fn setup_init(
|
||||
#[ts(export)]
|
||||
pub struct AttachParams {
|
||||
#[serde(rename = "startOsPassword")]
|
||||
password: Option<EncryptedWire>,
|
||||
guid: Arc<String>,
|
||||
pub password: Option<EncryptedWire>,
|
||||
pub guid: InternedString,
|
||||
#[ts(optional)]
|
||||
kiosk: Option<bool>,
|
||||
pub kiosk: Option<bool>,
|
||||
}
|
||||
|
||||
#[instrument(skip_all)]
|
||||
@@ -193,7 +202,7 @@ pub async fn attach(
|
||||
|
||||
let (account, net_ctrl) = setup_init(&setup_ctx, password, kiosk, init_phases).await?;
|
||||
|
||||
let rpc_ctx = RpcContext::init(&setup_ctx.webserver, &setup_ctx.config, disk_guid, Some(net_ctrl), rpc_ctx_phases).await?;
|
||||
let rpc_ctx = RpcContext::init(&setup_ctx.webserver, &setup_ctx.config.peek(|c| c.clone()), disk_guid, Some(net_ctrl), rpc_ctx_phases).await?;
|
||||
|
||||
Ok(((&account).try_into()?, rpc_ctx))
|
||||
})?;
|
||||
@@ -206,8 +215,17 @@ pub async fn attach(
|
||||
#[ts(export)]
|
||||
#[serde(tag = "status")]
|
||||
pub enum SetupStatusRes {
|
||||
Complete(SetupResult),
|
||||
NeedsInstall,
|
||||
Incomplete(SetupInfo),
|
||||
Running(SetupProgress),
|
||||
Complete(SetupResult),
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Deserialize, Serialize, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SetupInfo {
|
||||
pub guid: Option<InternedString>,
|
||||
pub attach: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize, TS)]
|
||||
@@ -218,17 +236,30 @@ pub struct SetupProgress {
|
||||
pub guid: Guid,
|
||||
}
|
||||
|
||||
pub async fn status(ctx: SetupContext) -> Result<Option<SetupStatusRes>, Error> {
|
||||
pub async fn status(ctx: SetupContext) -> Result<SetupStatusRes, Error> {
|
||||
if let Some(res) = ctx.result.get() {
|
||||
match res {
|
||||
Ok((res, _)) => Ok(Some(SetupStatusRes::Complete(res.clone()))),
|
||||
Ok((res, _)) => Ok(SetupStatusRes::Complete(res.clone())),
|
||||
Err(e) => Err(e.clone_output()),
|
||||
}
|
||||
} else {
|
||||
if ctx.task.initialized() {
|
||||
Ok(Some(SetupStatusRes::Running(ctx.progress().await)))
|
||||
Ok(SetupStatusRes::Running(ctx.progress().await))
|
||||
} else {
|
||||
Ok(None)
|
||||
let path = if tokio::fs::metadata("/run/live/medium").await.is_ok() {
|
||||
let Some(path) = ctx
|
||||
.install_rootfs
|
||||
.peek(|fs| fs.as_ref().map(|fs| fs.path().join("config/setup.json")))
|
||||
else {
|
||||
return Ok(SetupStatusRes::NeedsInstall);
|
||||
};
|
||||
path
|
||||
} else {
|
||||
Path::new("/media/startos/config/setup.json").to_path_buf()
|
||||
};
|
||||
IoFormat::Json
|
||||
.from_slice(read_file_to_string(path).await?.as_bytes())
|
||||
.map(SetupStatusRes::Incomplete)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -304,6 +335,28 @@ pub enum RecoverySource<Password> {
|
||||
},
|
||||
}
|
||||
|
||||
pub async fn setup_data_drive(
|
||||
ctx: &SetupContext,
|
||||
logicalname: &Path,
|
||||
) -> Result<InternedString, Error> {
|
||||
let encryption_password = if ctx.disable_encryption {
|
||||
None
|
||||
} else {
|
||||
Some(DEFAULT_PASSWORD)
|
||||
};
|
||||
let guid = crate::disk::main::create(
|
||||
&[logicalname],
|
||||
&pvscan().await?,
|
||||
DATA_DIR,
|
||||
encryption_password,
|
||||
)
|
||||
.await?;
|
||||
let _ = crate::disk::main::import(&*guid, DATA_DIR, RepairStrategy::Preen, encryption_password)
|
||||
.await?;
|
||||
let _ = ctx.disk_guid.set(guid.clone());
|
||||
Ok(guid)
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export)]
|
||||
@@ -432,23 +485,7 @@ pub async fn execute_inner(
|
||||
let rpc_ctx_phases = InitRpcContextPhases::new(&progress);
|
||||
|
||||
disk_phase.start();
|
||||
let encryption_password = if ctx.disable_encryption {
|
||||
None
|
||||
} else {
|
||||
Some(DEFAULT_PASSWORD)
|
||||
};
|
||||
let guid = Arc::new(
|
||||
crate::disk::main::create(
|
||||
&[start_os_logicalname],
|
||||
&pvscan().await?,
|
||||
DATA_DIR,
|
||||
encryption_password,
|
||||
)
|
||||
.await?,
|
||||
);
|
||||
let _ = crate::disk::main::import(&*guid, DATA_DIR, RepairStrategy::Preen, encryption_password)
|
||||
.await?;
|
||||
let _ = ctx.disk_guid.set(guid.clone());
|
||||
let guid = setup_data_drive(&ctx, &start_os_logicalname).await?;
|
||||
disk_phase.complete();
|
||||
|
||||
let progress = SetupExecuteProgress {
|
||||
@@ -490,7 +527,7 @@ pub struct SetupExecuteProgress {
|
||||
|
||||
async fn fresh_setup(
|
||||
ctx: &SetupContext,
|
||||
guid: Arc<String>,
|
||||
guid: InternedString,
|
||||
start_os_password: &str,
|
||||
kiosk: Option<bool>,
|
||||
SetupExecuteProgress {
|
||||
@@ -506,11 +543,13 @@ async fn fresh_setup(
|
||||
db.put(&ROOT, &Database::init(&account, kiosk)?).await?;
|
||||
drop(db);
|
||||
|
||||
let init_result = init(&ctx.webserver, &ctx.config, init_phases).await?;
|
||||
let config = ctx.config.peek(|c| c.clone());
|
||||
|
||||
let init_result = init(&ctx.webserver, &config, init_phases).await?;
|
||||
|
||||
let rpc_ctx = RpcContext::init(
|
||||
&ctx.webserver,
|
||||
&ctx.config,
|
||||
&config,
|
||||
guid,
|
||||
Some(init_result),
|
||||
rpc_ctx_phases,
|
||||
@@ -525,7 +564,7 @@ async fn fresh_setup(
|
||||
#[instrument(skip_all)]
|
||||
async fn recover(
|
||||
ctx: &SetupContext,
|
||||
guid: Arc<String>,
|
||||
guid: InternedString,
|
||||
start_os_password: String,
|
||||
recovery_source: BackupTargetFS,
|
||||
server_id: String,
|
||||
@@ -534,7 +573,7 @@ async fn recover(
|
||||
progress: SetupExecuteProgress,
|
||||
) -> Result<(SetupResult, RpcContext), Error> {
|
||||
let recovery_source = TmpMountGuard::mount(&recovery_source, ReadWrite).await?;
|
||||
recover_full_embassy(
|
||||
recover_full_server(
|
||||
ctx,
|
||||
guid.clone(),
|
||||
start_os_password,
|
||||
@@ -550,7 +589,7 @@ async fn recover(
|
||||
#[instrument(skip_all)]
|
||||
async fn migrate(
|
||||
ctx: &SetupContext,
|
||||
guid: Arc<String>,
|
||||
guid: InternedString,
|
||||
old_guid: &str,
|
||||
start_os_password: String,
|
||||
kiosk: Option<bool>,
|
||||
@@ -636,7 +675,7 @@ async fn migrate(
|
||||
|
||||
let rpc_ctx = RpcContext::init(
|
||||
&ctx.webserver,
|
||||
&ctx.config,
|
||||
&ctx.config.peek(|c| c.clone()),
|
||||
guid,
|
||||
Some(net_ctrl),
|
||||
rpc_ctx_phases,
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::PLATFORM;
|
||||
use crate::context::RpcContext;
|
||||
use crate::disk::main::export;
|
||||
@@ -10,7 +8,7 @@ use crate::util::Invoke;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Shutdown {
|
||||
pub disk_guid: Option<Arc<String>>,
|
||||
pub disk_guid: Option<InternedString>,
|
||||
pub restart: bool,
|
||||
}
|
||||
impl Shutdown {
|
||||
|
||||
Reference in New Issue
Block a user