From 2091abeea23dc8009b0e565cbb0920e553290d97 Mon Sep 17 00:00:00 2001 From: Aiden McClelland <3732071+dr-bonez@users.noreply.github.com> Date: Wed, 30 Oct 2024 12:55:36 -0600 Subject: [PATCH] persist hostname in config overlay (#2769) * persist hostname * add migration * fix version mismatch * remove dmesg logging from build --- Makefile | 2 +- core/Cargo.lock | 2 +- core/startos/Cargo.toml | 2 +- core/startos/src/context/setup.rs | 4 + core/startos/src/diagnostic.rs | 7 +- core/startos/src/os_install/mod.rs | 17 +--- core/startos/src/setup.rs | 7 ++ core/startos/src/util/io.rs | 14 ++++ core/startos/src/version/mod.rs | 5 +- core/startos/src/version/v0_3_6_alpha_0.rs | 83 +++++++++---------- core/startos/src/version/v0_3_6_alpha_7.rs | 13 +++ image-recipe/build.sh | 13 +-- sdk/base/lib/osBindings/SetupResult.ts | 1 + web/package.json | 2 +- web/patchdb-ui-seed.json | 2 +- .../src/app/services/api/mock-api.service.ts | 2 + .../modals/os-welcome/os-welcome.page.html | 2 +- 17 files changed, 105 insertions(+), 73 deletions(-) diff --git a/Makefile b/Makefile index d7ff9ec6c..c13beef94 100644 --- a/Makefile +++ b/Makefile @@ -213,7 +213,7 @@ emulate-reflash: $(ALL_TARGETS) @if [ -z "$(REMOTE)" ]; then >&2 echo "Must specify REMOTE" && false; fi $(call ssh,'sudo /usr/lib/startos/scripts/chroot-and-upgrade --create') $(MAKE) install REMOTE=$(REMOTE) SSHPASS=$(SSHPASS) DESTDIR=/media/startos/next PLATFORM=$(PLATFORM) - $(call ssh,'sudo rm -f /media/startos/config/disk.guid') + $(call ssh,'sudo rm -f /media/startos/config/disk.guid /media/startos/config/overlay/etc/hostname') $(call ssh,'sudo /media/startos/next/usr/lib/startos/scripts/chroot-and-upgrade --no-sync "apt-get install -y $(shell cat ./build/lib/depends)"') upload-ota: results/$(BASENAME).squashfs diff --git a/core/Cargo.lock b/core/Cargo.lock index cfa00f33f..acd2ceb32 100644 --- a/core/Cargo.lock +++ b/core/Cargo.lock @@ -5051,7 +5051,7 @@ dependencies = [ [[package]] name = "start-os" -version = "0.3.6-alpha.6" +version = "0.3.6-alpha.7" dependencies = [ "aes", "async-compression", diff --git a/core/startos/Cargo.toml b/core/startos/Cargo.toml index 99384345d..77a710df7 100644 --- a/core/startos/Cargo.toml +++ b/core/startos/Cargo.toml @@ -14,7 +14,7 @@ keywords = [ name = "start-os" readme = "README.md" repository = "https://github.com/Start9Labs/start-os" -version = "0.3.6-alpha.6" +version = "0.3.6-alpha.7" license = "MIT" [lib] diff --git a/core/startos/src/context/setup.rs b/core/startos/src/context/setup.rs index 999154977..96ec07700 100644 --- a/core/startos/src/context/setup.rs +++ b/core/startos/src/context/setup.rs @@ -21,6 +21,7 @@ use crate::account::AccountInfo; use crate::context::config::ServerConfig; use crate::context::RpcContext; use crate::disk::OsPartitionInfo; +use crate::hostname::Hostname; use crate::init::init_postgres; use crate::prelude::*; use crate::progress::FullProgressTracker; @@ -42,6 +43,8 @@ lazy_static::lazy_static! { pub struct SetupResult { pub tor_address: String, #[ts(type = "string")] + pub hostname: Hostname, + #[ts(type = "string")] pub lan_address: InternedString, pub root_ca: String, } @@ -50,6 +53,7 @@ impl TryFrom<&AccountInfo> for SetupResult { fn try_from(value: &AccountInfo) -> Result { Ok(Self { tor_address: format!("https://{}", value.tor_key.public().get_onion_address()), + hostname: value.hostname.clone(), lan_address: value.hostname.lan_address(), root_ca: String::from_utf8(value.root_ca_cert.to_pem()?)?, }) diff --git a/core/startos/src/diagnostic.rs b/core/startos/src/diagnostic.rs index 3eab3b16b..f0c142706 100644 --- a/core/startos/src/diagnostic.rs +++ b/core/startos/src/diagnostic.rs @@ -9,6 +9,7 @@ use rpc_toolkit::{ use crate::context::{CliContext, DiagnosticContext, RpcContext}; use crate::init::SYSTEM_REBUILD_PATH; use crate::shutdown::Shutdown; +use crate::util::io::delete_file; use crate::Error; pub fn diagnostic() -> ParentHandler { @@ -95,9 +96,7 @@ pub fn disk() -> ParentHandler { } pub async fn forget_disk(_: C) -> Result<(), Error> { - let disk_guid = Path::new("/media/startos/config/disk.guid"); - if tokio::fs::metadata(disk_guid).await.is_ok() { - tokio::fs::remove_file(disk_guid).await?; - } + delete_file("/media/startos/config/overlay/etc/hostname").await?; + delete_file("/media/startos/config/disk.guid").await?; Ok(()) } diff --git a/core/startos/src/os_install/mod.rs b/core/startos/src/os_install/mod.rs index a87a71209..4cd8aac2d 100644 --- a/core/startos/src/os_install/mod.rs +++ b/core/startos/src/os_install/mod.rs @@ -21,7 +21,7 @@ use crate::disk::OsPartitionInfo; use crate::net::utils::find_eth_iface; use crate::prelude::*; use crate::s9pk::merkle_archive::source::multi_cursor_file::MultiCursorFile; -use crate::util::io::{open_file, TmpDir}; +use crate::util::io::{delete_file, open_file, TmpDir}; use crate::util::serde::IoFormat; use crate::util::Invoke; use crate::ARCH; @@ -180,18 +180,9 @@ pub async fn execute( { if let Err(e) = async { // cp -r ${guard}/config /tmp/config - if tokio::fs::metadata(guard.path().join("config/upgrade")) - .await - .is_ok() - { - tokio::fs::remove_file(guard.path().join("config/upgrade")).await?; - } - if tokio::fs::metadata(guard.path().join("config/disk.guid")) - .await - .is_ok() - { - tokio::fs::remove_file(guard.path().join("config/disk.guid")).await?; - } + delete_file(guard.path().join("config/upgrade")).await?; + delete_file(guard.path().join("config/overlay/etc/hostname")).await?; + delete_file(guard.path().join("config/disk.guid")).await?; Command::new("cp") .arg("-r") .arg(guard.path().join("config")) diff --git a/core/startos/src/setup.rs b/core/startos/src/setup.rs index 642dd5476..1319ffae4 100644 --- a/core/startos/src/setup.rs +++ b/core/startos/src/setup.rs @@ -10,6 +10,7 @@ use rpc_toolkit::yajrc::RpcError; use rpc_toolkit::{from_fn_async, Context, HandlerExt, ParentHandler}; use serde::{Deserialize, Serialize}; use tokio::io::AsyncWriteExt; +use tokio::process::Command; use tokio::try_join; use tracing::instrument; use ts_rs::TS; @@ -36,6 +37,7 @@ use crate::progress::{FullProgress, PhaseProgressTrackerHandle}; use crate::rpc_continuations::Guid; use crate::util::crypto::EncryptedWire; use crate::util::io::{create_file, dir_copy, dir_size, Counter}; +use crate::util::Invoke; use crate::{Error, ErrorKind, ResultExt}; pub fn setup() -> ParentHandler { @@ -336,6 +338,11 @@ pub async fn complete(ctx: SetupContext) -> Result { let mut guid_file = create_file("/media/startos/config/disk.guid").await?; guid_file.write_all(ctx.disk_guid.as_bytes()).await?; guid_file.sync_all().await?; + Command::new("systemd-firstboot") + .arg("--root=/media/startos/config/overlay/") + .arg(format!("--hostname={}", res.hostname.0)) + .invoke(ErrorKind::ParseSysInfo) + .await?; Ok(res.clone()) } Some(Err(e)) => Err(e.clone_output()), diff --git a/core/startos/src/util/io.rs b/core/startos/src/util/io.rs index c3bf83d00..0e7aada54 100644 --- a/core/startos/src/util/io.rs +++ b/core/startos/src/util/io.rs @@ -923,6 +923,20 @@ pub async fn create_file(path: impl AsRef) -> Result { .with_ctx(|_| (ErrorKind::Filesystem, lazy_format!("create {path:?}"))) } +pub async fn delete_file(path: impl AsRef) -> Result<(), Error> { + let path = path.as_ref(); + tokio::fs::remove_file(path) + .await + .or_else(|e| { + if e.kind() == std::io::ErrorKind::NotFound { + Ok(()) + } else { + Err(e) + } + }) + .with_ctx(|_| (ErrorKind::Filesystem, lazy_format!("delete {path:?}"))) +} + pub async fn rename(src: impl AsRef, dst: impl AsRef) -> Result<(), Error> { let src = src.as_ref(); let dst = dst.as_ref(); diff --git a/core/startos/src/version/mod.rs b/core/startos/src/version/mod.rs index bc8deea17..10a02d63b 100644 --- a/core/startos/src/version/mod.rs +++ b/core/startos/src/version/mod.rs @@ -306,7 +306,10 @@ where Ok(()) } /// MUST be idempotent, and is run after *all* db migrations - fn post_up(self, ctx: &RpcContext) -> impl Future> + Send + 'static { + fn post_up<'a>( + self, + ctx: &'a RpcContext, + ) -> impl Future> + Send + 'a { async { Ok(()) } } fn down(self, db: &mut Value) -> Result<(), Error> { diff --git a/core/startos/src/version/v0_3_6_alpha_0.rs b/core/startos/src/version/v0_3_6_alpha_0.rs index 2f4b141b4..7a6045a3a 100644 --- a/core/startos/src/version/v0_3_6_alpha_0.rs +++ b/core/startos/src/version/v0_3_6_alpha_0.rs @@ -19,6 +19,10 @@ use torut::onion::TorSecretKeyV3; use super::v0_3_5::V0_3_0_COMPAT; use super::{v0_3_5_2, VersionT}; +use crate::account::AccountInfo; +use crate::auth::Sessions; +use crate::backup::target::cifs::CifsTargets; +use crate::context::RpcContext; use crate::db::model::Database; use crate::disk::mount::filesystem::cifs::Cifs; use crate::disk::mount::util::unmount; @@ -26,19 +30,15 @@ use crate::hostname::Hostname; use crate::net::forward::AvailablePorts; use crate::net::keys::KeyStore; use crate::net::ssl::CertStore; +use crate::net::tor; use crate::net::tor::OnionStore; use crate::notifications::{Notification, Notifications}; use crate::prelude::*; +use crate::s9pk::merkle_archive::source::multi_cursor_file::MultiCursorFile; use crate::ssh::{SshKeys, SshPubKey}; use crate::util::crypto::ed25519_expand_key; use crate::util::serde::{Pem, PemEncoding}; use crate::util::Invoke; -use crate::{account::AccountInfo, net::tor}; -use crate::{auth::Sessions, context::RpcContext}; -use crate::{ - backup::target::cifs::CifsTargets, - s9pk::merkle_archive::source::multi_cursor_file::MultiCursorFile, -}; lazy_static::lazy_static! { static ref V0_3_6_alpha_0: exver::Version = exver::Version::new( @@ -328,61 +328,58 @@ impl VersionT for Version { #[instrument(skip(self, ctx))] /// MUST be idempotent, and is run after *all* db migrations - fn post_up(self, ctx: &RpcContext) -> impl Future> + Send + 'static { - let ctx = ctx.clone(); - async move { - let path = Path::new("/embassy-data/package-data/archive/"); + async fn post_up(self, ctx: &RpcContext) -> Result<(), Error> { + let path = Path::new("/embassy-data/package-data/archive/"); + if !path.is_dir() { + return Err(Error::new( + eyre!( + "expected path ({}) to be a directory", + path.to_string_lossy() + ), + ErrorKind::Filesystem, + )); + } + // Should be the name of the package + let mut paths = tokio::fs::read_dir(path).await?; + while let Some(path) = paths.next_entry().await? { + let path = path.path(); if !path.is_dir() { - return Err(Error::new( - eyre!( - "expected path ({}) to be a directory", - path.to_string_lossy() - ), - ErrorKind::Filesystem, - )); + continue; } - // Should be the name of the package + // Should be the version of the package let mut paths = tokio::fs::read_dir(path).await?; while let Some(path) = paths.next_entry().await? { let path = path.path(); if !path.is_dir() { continue; } - // Should be the version of the package + + // Should be s9pk let mut paths = tokio::fs::read_dir(path).await?; while let Some(path) = paths.next_entry().await? { let path = path.path(); - if !path.is_dir() { + if path.is_dir() { continue; } - // Should be s9pk - let mut paths = tokio::fs::read_dir(path).await?; - while let Some(path) = paths.next_entry().await? { - let path = path.path(); - if path.is_dir() { - continue; - } + let package_s9pk = tokio::fs::File::open(path).await?; + let file = MultiCursorFile::open(&package_s9pk).await?; - let package_s9pk = tokio::fs::File::open(path).await?; - let file = MultiCursorFile::open(&package_s9pk).await?; - - let key = ctx.db.peek().await.into_private().into_compat_s9pk_key(); - ctx.services - .install( - ctx.clone(), - || crate::s9pk::load(file.clone(), || Ok(key.de()?.0), None), - None::, - None, - ) - .await? - .await? - .await?; - } + let key = ctx.db.peek().await.into_private().into_compat_s9pk_key(); + ctx.services + .install( + ctx.clone(), + || crate::s9pk::load(file.clone(), || Ok(key.de()?.0), None), + None::, + None, + ) + .await? + .await? + .await?; } } - Ok(()) } + Ok(()) } } diff --git a/core/startos/src/version/v0_3_6_alpha_7.rs b/core/startos/src/version/v0_3_6_alpha_7.rs index 75c0af72f..bbf9468ff 100644 --- a/core/startos/src/version/v0_3_6_alpha_7.rs +++ b/core/startos/src/version/v0_3_6_alpha_7.rs @@ -1,9 +1,11 @@ use exver::{PreReleaseSegment, VersionRange}; use imbl_value::{json, InOMap}; +use tokio::process::Command; use super::v0_3_5::V0_3_0_COMPAT; use super::{v0_3_6_alpha_6, VersionT}; use crate::prelude::*; +use crate::util::Invoke; lazy_static::lazy_static! { static ref V0_3_6_alpha_7: exver::Version = exver::Version::new( @@ -44,6 +46,17 @@ impl VersionT for Version { } Ok(()) } + async fn post_up(self, ctx: &crate::context::RpcContext) -> Result<(), Error> { + Command::new("systemd-firstboot") + .arg("--root=/media/startos/config/overlay/") + .arg(format!( + "--hostname={}", + ctx.account.read().await.hostname.0 + )) + .invoke(ErrorKind::ParseSysInfo) + .await?; + Ok(()) + } fn down(self, _db: &mut Value) -> Result<(), Error> { Ok(()) } diff --git a/image-recipe/build.sh b/image-recipe/build.sh index ea88824d0..ae1831704 100755 --- a/image-recipe/build.sh +++ b/image-recipe/build.sh @@ -57,13 +57,14 @@ if [ "$NON_FREE" = 1 ]; then fi fi -PLATFORM_CONFIG_EXTRAS= +PLATFORM_CONFIG_EXTRAS=() if [ "${IB_TARGET_PLATFORM}" = "raspberrypi" ]; then - PLATFORM_CONFIG_EXTRAS="$PLATFORM_CONFIG_EXTRAS --firmware-binary false" - PLATFORM_CONFIG_EXTRAS="$PLATFORM_CONFIG_EXTRAS --firmware-chroot false" - PLATFORM_CONFIG_EXTRAS="$PLATFORM_CONFIG_EXTRAS --linux-flavours rpi-v8" + PLATFORM_CONFIG_EXTRAS+=( --firmware-binary false ) + PLATFORM_CONFIG_EXTRAS+=( --firmware-chroot false ) + PLATFORM_CONFIG_EXTRAS+=( --linux-packages linux-image-6.6.51+rpt ) + PLATFORM_CONFIG_EXTRAS+=( --linux-flavours "rpi-v8 rpi-2712" ) elif [ "${IB_TARGET_PLATFORM}" = "rockchip64" ]; then - PLATFORM_CONFIG_EXTRAS="$PLATFORM_CONFIG_EXTRAS --linux-flavours rockchip64" + PLATFORM_CONFIG_EXTRAS+=( --linux-flavours rockchip64 ) fi @@ -87,7 +88,7 @@ lb config \ --bootstrap-qemu-arch ${IB_TARGET_ARCH} \ --bootstrap-qemu-static /usr/bin/qemu-${QEMU_ARCH}-static \ --archive-areas "${ARCHIVE_AREAS}" \ - $PLATFORM_CONFIG_EXTRAS + ${PLATFORM_CONFIG_EXTRAS[@]} # Overlays diff --git a/sdk/base/lib/osBindings/SetupResult.ts b/sdk/base/lib/osBindings/SetupResult.ts index 464aeb4b7..d81c7f039 100644 --- a/sdk/base/lib/osBindings/SetupResult.ts +++ b/sdk/base/lib/osBindings/SetupResult.ts @@ -2,6 +2,7 @@ export type SetupResult = { torAddress: string + hostname: string lanAddress: string rootCa: string } diff --git a/web/package.json b/web/package.json index e900277c4..f1146118d 100644 --- a/web/package.json +++ b/web/package.json @@ -1,6 +1,6 @@ { "name": "startos-ui", - "version": "0.3.6-alpha.6", + "version": "0.3.6-alpha.7", "author": "Start9 Labs, Inc", "homepage": "https://start9.com/", "license": "MIT", diff --git a/web/patchdb-ui-seed.json b/web/patchdb-ui-seed.json index 5862c6f83..3256bb87c 100644 --- a/web/patchdb-ui-seed.json +++ b/web/patchdb-ui-seed.json @@ -21,5 +21,5 @@ "ackInstructions": {}, "theme": "Dark", "widgets": [], - "ack-welcome": "0.3.6-alpha.6" + "ack-welcome": "0.3.6-alpha.7" } diff --git a/web/projects/setup-wizard/src/app/services/api/mock-api.service.ts b/web/projects/setup-wizard/src/app/services/api/mock-api.service.ts index a5757b010..a17f56a0c 100644 --- a/web/projects/setup-wizard/src/app/services/api/mock-api.service.ts +++ b/web/projects/setup-wizard/src/app/services/api/mock-api.service.ts @@ -137,6 +137,7 @@ export class MockApiService extends ApiService { return { status: 'complete', torAddress: 'https://asdafsadasdasasdasdfasdfasdf.onion', + hostname: 'adjective-noun', lanAddress: 'https://adjective-noun.local', rootCa: encodeBase64(rootCA), } @@ -283,6 +284,7 @@ export class MockApiService extends ApiService { await pauseFor(1000) return { torAddress: 'https://asdafsadasdasasdasdfasdfasdf.onion', + hostname: 'adjective-noun', lanAddress: 'https://adjective-noun.local', rootCa: encodeBase64(rootCA), } diff --git a/web/projects/ui/src/app/modals/os-welcome/os-welcome.page.html b/web/projects/ui/src/app/modals/os-welcome/os-welcome.page.html index 2a43292ad..3e4fe52f3 100644 --- a/web/projects/ui/src/app/modals/os-welcome/os-welcome.page.html +++ b/web/projects/ui/src/app/modals/os-welcome/os-welcome.page.html @@ -12,7 +12,7 @@

This Release

-

0.3.6-alpha.6

+

0.3.6-alpha.7

This is an ALPHA release! DO NOT use for production data!
Expect that any data you create or store on this version of the OS can be