feat: load bundled migration images and log progress during os migration

Load pre-saved container images from /usr/lib/startos/migration-images
before migrating packages, removing the need for internet access during
the v1→v2 s9pk conversion.  Add a periodic progress logger so the user
can see which package is being migrated.
This commit is contained in:
Aiden McClelland
2026-03-24 19:16:28 -06:00
parent ecc4703ae7
commit e0f27281d1
2 changed files with 47 additions and 0 deletions

View File

@@ -1721,6 +1721,14 @@ lxc.mod.cleaned-up-containers:
fr_FR: "Conteneurs LXC orphelins nettoyés avec succès"
pl_PL: "Pomyślnie wyczyszczono wiszące kontenery LXC"
# version/v0_3_6_alpha_0.rs
migration.migrating-package:
en_US: "Migrating package %{package}..."
de_DE: "Paket %{package} wird migriert..."
es_ES: "Migrando paquete %{package}..."
fr_FR: "Migration du paquet %{package}..."
pl_PL: "Migracja pakietu %{package}..."
# registry/admin.rs
registry.admin.unknown-signer:
en_US: "Unknown signer"

View File

@@ -27,6 +27,7 @@ use crate::net::keys::KeyStore;
use crate::notifications::Notifications;
use crate::prelude::*;
use crate::s9pk::merkle_archive::source::multi_cursor_file::MultiCursorFile;
use crate::s9pk::v2::pack::CONTAINER_TOOL;
use crate::ssh::{SshKeys, SshPubKey};
use crate::util::Invoke;
use crate::util::serde::Pem;
@@ -326,7 +327,41 @@ impl VersionT for Version {
.await?;
}
// Load bundled migration images (start9/compat, start9/utils,
// tonistiigi/binfmt) so the v1->v2 s9pk conversion doesn't need
// internet access.
let migration_images_dir = Path::new("/usr/lib/startos/migration-images");
if let Ok(mut entries) = tokio::fs::read_dir(migration_images_dir).await {
while let Some(entry) = entries.next_entry().await? {
let path = entry.path();
if path.extension() == Some(OsStr::new("tar")) {
tracing::info!("Loading migration image: {}", path.display());
Command::new(*CONTAINER_TOOL)
.arg("load")
.arg("-i")
.arg(&path)
.invoke(crate::ErrorKind::Docker)
.await?;
}
}
}
// Should be the name of the package
let current_package: std::sync::Arc<tokio::sync::watch::Sender<Option<PackageId>>> =
std::sync::Arc::new(tokio::sync::watch::channel(None).0);
let progress_logger = {
let current_package = current_package.clone();
tokio::spawn(async move {
let mut interval = tokio::time::interval(std::time::Duration::from_secs(30));
interval.tick().await; // skip immediate first tick
loop {
interval.tick().await;
if let Some(ref id) = *current_package.borrow() {
tracing::info!("{}", t!("migration.migrating-package", package = id.to_string()));
}
}
})
};
let mut paths = tokio::fs::read_dir(path).await?;
while let Some(path) = paths.next_entry().await? {
let Ok(id) = path.file_name().to_string_lossy().parse::<PackageId>() else {
@@ -367,6 +402,9 @@ impl VersionT for Version {
false
};
tracing::info!("{}", t!("migration.migrating-package", package = id.to_string()));
current_package.send_replace(Some(id.clone()));
if let Err(e) = async {
let package_s9pk = tokio::fs::File::open(path).await?;
let file = MultiCursorFile::open(&package_s9pk).await?;
@@ -411,6 +449,7 @@ impl VersionT for Version {
}
}
}
progress_logger.abort();
Ok(())
}
}