From f9edff8bf469261c56ca640b703af8eaeb32c881 Mon Sep 17 00:00:00 2001 From: Aiden McClelland Date: Tue, 26 Mar 2024 16:21:57 -0600 Subject: [PATCH] handle todos --- core/startos/src/auth.rs | 1 - core/startos/src/backup/mod.rs | 9 + core/startos/src/backup/restore.rs | 1 - core/startos/src/config/mod.rs | 1 - core/startos/src/context/rpc.rs | 34 ---- core/startos/src/db/model/package.rs | 37 ++-- core/startos/src/dependencies.rs | 2 - core/startos/src/lib.rs | 2 +- core/startos/src/net/ssl.rs | 1 - core/startos/src/net/tor.rs | 2 +- core/startos/src/s9pk/rpc.rs | 2 +- core/startos/src/s9pk/v1/manifest.rs | 5 +- core/startos/src/s9pk/v2/compat.rs | 7 +- .../src/service/service_effect_handler.rs | 44 +++-- core/startos/src/service/service_map.rs | 1 - core/startos/src/volume.rs | 183 ------------------ .../src/app/services/patch-db/data-model.ts | 4 +- 17 files changed, 58 insertions(+), 278 deletions(-) diff --git a/core/startos/src/auth.rs b/core/startos/src/auth.rs index 4d3c20bd1..7adce72bc 100644 --- a/core/startos/src/auth.rs +++ b/core/startos/src/auth.rs @@ -93,7 +93,6 @@ pub fn auth() -> ParentHandler { from_fn_async(logout) .with_metadata("get-session", Value::Bool(true)) .with_remote_cli::() - // TODO @dr-bonez .no_display(), ) .subcommand("session", session()) diff --git a/core/startos/src/backup/mod.rs b/core/startos/src/backup/mod.rs index de2dfbf7d..c963118c4 100644 --- a/core/startos/src/backup/mod.rs +++ b/core/startos/src/backup/mod.rs @@ -45,6 +45,15 @@ pub fn backup() -> ParentHandler { .subcommand("target", target::target()) } +pub fn package_backup() -> ParentHandler { + ParentHandler::new().subcommand( + "restore", + from_fn_async(restore::restore_packages_rpc) + .no_display() + .with_remote_cli::(), + ) +} + #[derive(Deserialize, Serialize)] struct BackupMetadata { pub timestamp: DateTime, diff --git a/core/startos/src/backup/restore.rs b/core/startos/src/backup/restore.rs index 0cdd24aba..70695b42e 100644 --- a/core/startos/src/backup/restore.rs +++ b/core/startos/src/backup/restore.rs @@ -33,7 +33,6 @@ pub struct RestorePackageParams { pub password: String, } -// TODO dr Why doesn't anything use this // #[command(rename = "restore", display(display_none))] #[instrument(skip(ctx, password))] pub async fn restore_packages_rpc( diff --git a/core/startos/src/config/mod.rs b/core/startos/src/config/mod.rs index bcd44193b..18f67b05a 100644 --- a/core/startos/src/config/mod.rs +++ b/core/startos/src/config/mod.rs @@ -165,7 +165,6 @@ pub struct SetParams { pub config: StdinDeserializable>, } -// TODO Dr Why isn't this used? // #[command( // subcommands(self(set_impl(async, context(RpcContext))), set_dry), // display(display_none), diff --git a/core/startos/src/context/rpc.rs b/core/startos/src/context/rpc.rs index f987ffbf4..6450eb561 100644 --- a/core/startos/src/context/rpc.rs +++ b/core/startos/src/context/rpc.rs @@ -19,7 +19,6 @@ use super::setup::CURRENT_SECRET; use crate::account::AccountInfo; use crate::context::config::ServerConfig; use crate::core::rpc_continuations::{RequestGuid, RestHandler, RpcContinuation, WebSocketHandler}; -use crate::db::model::package::CurrentDependents; use crate::db::prelude::PatchDbExt; use crate::dependencies::compute_dependency_config_errs; use crate::disk::OsPartitionInfo; @@ -207,39 +206,6 @@ impl RpcContext { #[instrument(skip(self))] pub async fn cleanup_and_initialize(&self) -> Result<(), Error> { - self.db - .mutate(|f| { - let mut current_dependents = f - .as_public_mut() - .as_package_data() - .keys()? - .into_iter() - .map(|k| (k.clone(), BTreeMap::new())) - .collect::>(); - for (package_id, package) in - f.as_public_mut().as_package_data_mut().as_entries_mut()? - { - for (k, v) in package.clone().into_current_dependencies().into_entries()? { - let mut entry: BTreeMap<_, _> = - current_dependents.remove(&k).unwrap_or_default(); - entry.insert(package_id.clone(), v.de()?); - current_dependents.insert(k, entry); - } - } - for (package_id, current_dependents) in current_dependents { - if let Some(deps) = f - .as_public_mut() - .as_package_data_mut() - .as_idx_mut(&package_id) - .map(|i| i.as_current_dependents_mut()) - { - deps.ser(&CurrentDependents(current_dependents))?; - } - } - Ok(()) - }) - .await?; - self.services.init(&self).await?; tracing::info!("Initialized Package Managers"); diff --git a/core/startos/src/db/model/package.rs b/core/startos/src/db/model/package.rs index 7e2bf2769..05d6e73b7 100644 --- a/core/startos/src/db/model/package.rs +++ b/core/startos/src/db/model/package.rs @@ -1,6 +1,7 @@ use std::collections::{BTreeMap, BTreeSet}; use chrono::{DateTime, Utc}; +use emver::VersionRange; use imbl_value::InternedString; use models::{DataUrl, HealthCheckId, HostId, PackageId}; use patch_db::json_ptr::JsonPointer; @@ -299,7 +300,6 @@ pub struct PackageDataEntry { pub icon: DataUrl<'static>, pub last_backup: Option>, pub dependency_info: BTreeMap, - pub current_dependents: CurrentDependents, pub current_dependencies: CurrentDependencies, pub interface_addresses: InterfaceAddressMap, pub hosts: HostInfo, @@ -357,29 +357,6 @@ impl Default for ExposedUI { } } -#[derive(Debug, Clone, Default, Deserialize, Serialize)] -pub struct CurrentDependents(pub BTreeMap); -impl CurrentDependents { - pub fn map( - mut self, - transform: impl Fn( - BTreeMap, - ) -> BTreeMap, - ) -> Self { - self.0 = transform(self.0); - self - } -} -impl Map for CurrentDependents { - type Key = PackageId; - type Value = CurrentDependencyInfo; - fn key_str(key: &Self::Key) -> Result, Error> { - Ok(key) - } - fn key_string(key: &Self::Key) -> Result { - Ok(key.clone().into()) - } -} #[derive(Debug, Clone, Default, Deserialize, Serialize)] pub struct CurrentDependencies(pub BTreeMap); impl CurrentDependencies { @@ -416,9 +393,19 @@ pub struct StaticDependencyInfo { #[serde(rename_all = "camelCase")] #[serde(tag = "kind")] pub enum CurrentDependencyInfo { - Exists, + #[serde(rename_all = "camelCase")] + Exists { + #[ts(type = "string")] + url: Url, + #[ts(type = "string")] + version_spec: VersionRange, + }, #[serde(rename_all = "camelCase")] Running { + #[ts(type = "string")] + url: Url, + #[ts(type = "string")] + version_spec: VersionRange, #[serde(default)] #[ts(type = "string[]")] health_checks: BTreeSet, diff --git a/core/startos/src/dependencies.rs b/core/startos/src/dependencies.rs index 168713f61..ca40bf432 100644 --- a/core/startos/src/dependencies.rs +++ b/core/startos/src/dependencies.rs @@ -56,8 +56,6 @@ pub struct DepInfo { pub version: VersionRange, pub requirement: DependencyRequirement, pub description: Option, - #[serde(default)] - pub config: Option, // TODO: remove } #[derive(Deserialize, Serialize, Parser)] diff --git a/core/startos/src/lib.rs b/core/startos/src/lib.rs index d19f9c61a..0b3336783 100644 --- a/core/startos/src/lib.rs +++ b/core/startos/src/lib.rs @@ -236,7 +236,7 @@ pub fn package() -> ParentHandler { .with_remote_cli::(), ) .subcommand("dependency", dependencies::dependency()) - .subcommand("package-backup", backup::backup()) + .subcommand("backup", backup::package_backup()) .subcommand("connect", from_fn_async(service::connect_rpc).no_cli()) .subcommand( "connect", diff --git a/core/startos/src/net/ssl.rs b/core/startos/src/net/ssl.rs index 0756114c5..245881c55 100644 --- a/core/startos/src/net/ssl.rs +++ b/core/startos/src/net/ssl.rs @@ -183,7 +183,6 @@ pub async fn root_ca_start_time() -> Result { const EC_CURVE_NAME: nid::Nid = nid::Nid::X9_62_PRIME256V1; lazy_static::lazy_static! { static ref EC_GROUP: EcGroup = EcGroup::from_curve_name(EC_CURVE_NAME).unwrap(); - static ref SSL_MUTEX: Mutex<()> = Mutex::new(()); // TODO: make thread safe } pub async fn export_key(key: &PKey, target: &Path) -> Result<(), Error> { diff --git a/core/startos/src/net/tor.rs b/core/startos/src/net/tor.rs index 72b05e2aa..c87f506dc 100644 --- a/core/startos/src/net/tor.rs +++ b/core/startos/src/net/tor.rs @@ -768,7 +768,7 @@ async fn test() { let mut conn = torut::control::UnauthenticatedConn::new( TcpStream::connect(SocketAddr::from(([127, 0, 0, 1], 9051))) .await - .unwrap(), // TODO + .unwrap(), ); let auth = conn .load_protocol_info() diff --git a/core/startos/src/s9pk/rpc.rs b/core/startos/src/s9pk/rpc.rs index e11faa2ff..3a98da02b 100644 --- a/core/startos/src/s9pk/rpc.rs +++ b/core/startos/src/s9pk/rpc.rs @@ -132,7 +132,7 @@ async fn add_image( Command::new("bash") .arg("-c") .arg(format!( - "{CONTAINER_TOOL} export {container_id} | mksquashfs - {sqfs} -tar -force-uid 100000 -force-gid 100000", // TODO: real uid mapping + "{CONTAINER_TOOL} export {container_id} | mksquashfs - {sqfs} -tar", container_id = container_id.trim(), sqfs = sqfs_path.display() )) diff --git a/core/startos/src/s9pk/v1/manifest.rs b/core/startos/src/s9pk/v1/manifest.rs index 381a446fe..813ad11a6 100644 --- a/core/startos/src/s9pk/v1/manifest.rs +++ b/core/startos/src/s9pk/v1/manifest.rs @@ -1,7 +1,9 @@ +use std::collections::BTreeMap; use std::path::{Path, PathBuf}; use imbl_value::InOMap; pub use models::PackageId; +use models::VolumeId; use serde::{Deserialize, Serialize}; use url::Url; @@ -11,7 +13,6 @@ use crate::prelude::*; use crate::s9pk::manifest::{Alerts, Description, HardwareRequirements}; use crate::util::Version; use crate::version::{Current, VersionT}; -use crate::volume::Volumes; fn current_version() -> Version { Current::new().semver().into() @@ -40,7 +41,7 @@ pub struct Manifest { pub donation_url: Option, #[serde(default)] pub alerts: Alerts, - pub volumes: Volumes, + pub volumes: BTreeMap, #[serde(default)] pub dependencies: Dependencies, pub config: Option>, diff --git a/core/startos/src/s9pk/v2/compat.rs b/core/startos/src/s9pk/v2/compat.rs index e2ef8bdbb..423491e7a 100644 --- a/core/startos/src/s9pk/v2/compat.rs +++ b/core/startos/src/s9pk/v2/compat.rs @@ -19,7 +19,6 @@ use crate::s9pk::v1::reader::S9pkReader; use crate::s9pk::v2::S9pk; use crate::util::io::TmpDir; use crate::util::Invoke; -use crate::volume::Volume; use crate::ARCH; pub const MAGIC_AND_VERSION: &[u8] = &[0x3b, 0x3b, 0x01]; @@ -254,7 +253,7 @@ impl S9pk> { for (asset_id, _) in manifest .volumes .iter() - .filter(|(_, v)| matches!(v, Volume::Assets { .. })) + .filter(|(_, v)| v.get("type").and_then(|v| v.as_str()) == Some("assets")) { let assets_path = asset_dir.join(&asset_id); let sqfs_path = assets_path.with_extension("squashfs"); @@ -338,13 +337,13 @@ impl From for Manifest { assets: value .volumes .iter() - .filter(|(_, v)| matches!(v, &&Volume::Assets { .. })) + .filter(|(_, v)| v.get("type").and_then(|v| v.as_str()) == Some("assets")) .map(|(id, _)| id.clone()) .collect(), volumes: value .volumes .iter() - .filter(|(_, v)| matches!(v, &&Volume::Data { .. })) + .filter(|(_, v)| v.get("type").and_then(|v| v.as_str()) == Some("data")) .map(|(id, _)| id.clone()) .collect(), alerts: value.alerts, diff --git a/core/startos/src/service/service_effect_handler.rs b/core/startos/src/service/service_effect_handler.rs index f791b6458..b3eaf365c 100644 --- a/core/startos/src/service/service_effect_handler.rs +++ b/core/startos/src/service/service_effect_handler.rs @@ -8,6 +8,7 @@ use std::sync::{Arc, Weak}; use clap::builder::ValueParserFactory; use clap::Parser; +use emver::VersionRange; use imbl::OrdMap; use imbl_value::{json, InternedString}; use models::{ActionId, HealthCheckId, ImageId, PackageId, VolumeId}; @@ -16,6 +17,7 @@ use rpc_toolkit::{from_fn, from_fn_async, AnyContext, Context, Empty, HandlerExt use serde::{Deserialize, Serialize}; use tokio::process::Command; use ts_rs::TS; +use url::Url; use crate::db::model::package::{ CurrentDependencies, CurrentDependencyInfo, ExposedUI, StoreExposedUI, @@ -1096,15 +1098,19 @@ enum DependencyRequirement { id: PackageId, #[ts(type = "string[]")] health_checks: BTreeSet, - version_spec: String, - url: String, + #[ts(type = "string")] + version_spec: VersionRange, + #[ts(type = "string")] + url: Url, }, #[serde(rename_all = "camelCase")] Exists { #[ts(type = "string")] id: PackageId, - version_spec: String, - url: String, + #[ts(type = "string")] + version_spec: VersionRange, + #[ts(type = "string")] + url: Url, }, } // filebrowser:exists,bitcoind:running:foo+bar+baz @@ -1114,8 +1120,8 @@ impl FromStr for DependencyRequirement { match s.split_once(':') { Some((id, "e")) | Some((id, "exists")) => Ok(Self::Exists { id: id.parse()?, - url: "".to_string(), - version_spec: "*".to_string(), + url: "".parse()?, // TODO + version_spec: "*".parse()?, // TODO }), Some((id, rest)) => { let health_checks = match rest.split_once(':') { @@ -1138,15 +1144,15 @@ impl FromStr for DependencyRequirement { Ok(Self::Running { id: id.parse()?, health_checks, - url: "".to_string(), - version_spec: "*".to_string(), + url: "".parse()?, // TODO + version_spec: "*".parse()?, // TODO }) } None => Ok(Self::Running { id: s.parse()?, health_checks: BTreeSet::new(), - url: "".to_string(), - version_spec: "*".to_string(), + url: "".parse()?, // TODO + version_spec: "*".parse()?, // TODO }), } } @@ -1183,23 +1189,23 @@ async fn set_dependencies( id, url, version_spec, - } => (id, CurrentDependencyInfo::Exists), + } => (id, CurrentDependencyInfo::Exists { url, version_spec }), DependencyRequirement::Running { id, health_checks, url, version_spec, - } => (id, CurrentDependencyInfo::Running { health_checks }), + } => ( + id, + CurrentDependencyInfo::Running { + url, + version_spec, + health_checks, + }, + ), }) .collect(), ); - for (dep, entry) in db.as_public_mut().as_package_data_mut().as_entries_mut()? { - if let Some(info) = dependencies.0.get(&dep) { - entry.as_current_dependents_mut().insert(id, info)?; - } else { - entry.as_current_dependents_mut().remove(id)?; - } - } db.as_public_mut() .as_package_data_mut() .as_idx_mut(id) diff --git a/core/startos/src/service/service_map.rs b/core/startos/src/service/service_map.rs index 23e1bb540..1a9d2342c 100644 --- a/core/startos/src/service/service_map.rs +++ b/core/startos/src/service/service_map.rs @@ -171,7 +171,6 @@ impl ServiceMap { icon, last_backup: None, dependency_info: Default::default(), - current_dependents: Default::default(), // TODO: initialize current_dependencies: Default::default(), interface_addresses: Default::default(), hosts: Default::default(), diff --git a/core/startos/src/volume.rs b/core/startos/src/volume.rs index a631e68e6..593422a67 100644 --- a/core/startos/src/volume.rs +++ b/core/startos/src/volume.rs @@ -1,15 +1,9 @@ -use std::collections::BTreeMap; -use std::ops::{Deref, DerefMut}; use std::path::{Path, PathBuf}; pub use helpers::script_dir; -use imbl_value::InternedString; pub use models::VolumeId; use models::{HostId, PackageId}; -use serde::{Deserialize, Serialize}; -use tracing::instrument; -use crate::context::RpcContext; use crate::net::PACKAGE_CERT_PATH; use crate::prelude::*; use crate::util::Version; @@ -17,72 +11,6 @@ use crate::util::Version; pub const PKG_VOLUME_DIR: &str = "package-data/volumes"; pub const BACKUP_DIR: &str = "/media/embassy/backups"; -#[derive(Clone, Debug, Default, Deserialize, Serialize)] -pub struct Volumes(BTreeMap); -impl Volumes { - #[instrument(skip_all)] - pub async fn install( - &self, - ctx: &RpcContext, - pkg_id: &PackageId, - version: &Version, - ) -> Result<(), Error> { - for (volume_id, volume) in &self.0 { - volume - .install(&ctx.datadir, pkg_id, version, volume_id) - .await?; // TODO: concurrent? - } - Ok(()) - } - pub fn get_path_for( - &self, - path: &PathBuf, - pkg_id: &PackageId, - version: &Version, - volume_id: &VolumeId, - ) -> Option { - self.0 - .get(volume_id) - .map(|volume| volume.path_for(path, pkg_id, version, volume_id)) - } - pub fn to_readonly(&self) -> Self { - Volumes( - self.0 - .iter() - .map(|(id, volume)| { - let mut volume = volume.clone(); - volume.set_readonly(); - (id.clone(), volume) - }) - .collect(), - ) - } -} -impl Deref for Volumes { - type Target = BTreeMap; - fn deref(&self) -> &Self::Target { - &self.0 - } -} -impl DerefMut for Volumes { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.0 - } -} -impl Map for Volumes { - type Key = VolumeId; - type Value = Volume; - fn key_str(key: &Self::Key) -> Result, Error> { - Ok(key) - } - fn key_string(key: &Self::Key) -> Result { - match key { - VolumeId::Custom(id) => Ok(id.clone().into()), - _ => Self::key_str(key).map(|s| InternedString::intern(s.as_ref())), - } - } -} - pub fn data_dir>(datadir: P, pkg_id: &PackageId, volume_id: &VolumeId) -> PathBuf { datadir .as_ref() @@ -108,114 +36,3 @@ pub fn backup_dir(pkg_id: &PackageId) -> PathBuf { pub fn cert_dir(pkg_id: &PackageId, host_id: &HostId) -> PathBuf { Path::new(PACKAGE_CERT_PATH).join(pkg_id).join(host_id) } - -#[derive(Clone, Debug, Deserialize, Serialize)] -#[serde(tag = "type")] -#[serde(rename_all = "camelCase")] -pub enum Volume { - #[serde(rename_all = "camelCase")] - Data { - #[serde(skip)] - readonly: bool, - }, - #[serde(rename_all = "camelCase")] - Assets {}, - #[serde(rename_all = "camelCase")] - Pointer { - package_id: PackageId, - volume_id: VolumeId, - path: PathBuf, - readonly: bool, - }, - #[serde(rename_all = "camelCase")] - Certificate { interface_id: HostId }, - #[serde(rename_all = "camelCase")] - Backup { readonly: bool }, -} -impl Volume { - pub async fn install( - &self, - path: &PathBuf, - pkg_id: &PackageId, - version: &Version, - volume_id: &VolumeId, - ) -> Result<(), Error> { - match self { - Volume::Data { .. } => { - tokio::fs::create_dir_all(self.path_for(path, pkg_id, version, volume_id)).await?; - } - _ => (), - } - Ok(()) - } - pub fn path_for( - &self, - data_dir_path: impl AsRef, - pkg_id: &PackageId, - version: &Version, - volume_id: &VolumeId, - ) -> PathBuf { - match self { - Volume::Data { .. } => data_dir(&data_dir_path, pkg_id, volume_id), - Volume::Assets {} => asset_dir(&data_dir_path, pkg_id, version).join(volume_id), - Volume::Pointer { - package_id, - volume_id, - path, - .. - } => data_dir(&data_dir_path, package_id, volume_id).join(if path.is_absolute() { - path.strip_prefix("/").unwrap() - } else { - path.as_ref() - }), - Volume::Certificate { interface_id } => cert_dir(pkg_id, &interface_id), - Volume::Backup { .. } => backup_dir(pkg_id), - } - } - - pub fn pointer_path(&self, data_dir_path: impl AsRef) -> Option { - if let Volume::Pointer { - path, - package_id, - volume_id, - .. - } = self - { - Some( - data_dir(data_dir_path.as_ref(), package_id, volume_id).join( - if path.is_absolute() { - path.strip_prefix("/").unwrap() - } else { - path.as_ref() - }, - ), - ) - } else { - None - } - } - - pub fn set_readonly(&mut self) { - match self { - Volume::Data { readonly } => { - *readonly = true; - } - Volume::Pointer { readonly, .. } => { - *readonly = true; - } - Volume::Backup { readonly } => { - *readonly = true; - } - _ => (), - } - } - pub fn readonly(&self) -> bool { - match self { - Volume::Data { readonly } => *readonly, - Volume::Assets {} => true, - Volume::Pointer { readonly, .. } => *readonly, - Volume::Certificate { .. } => true, - Volume::Backup { readonly } => *readonly, - } - } -} diff --git a/web/projects/ui/src/app/services/patch-db/data-model.ts b/web/projects/ui/src/app/services/patch-db/data-model.ts index 537e15329..c1d46ece2 100644 --- a/web/projects/ui/src/app/services/patch-db/data-model.ts +++ b/web/projects/ui/src/app/services/patch-db/data-model.ts @@ -139,7 +139,9 @@ export enum PackageState { } export interface CurrentDependencyInfo { - versionRange: string + kind: 'exists' | 'running' + url: string + versionSpec: string healthChecks: string[] // array of health check IDs }