diff --git a/crates/lib/src/install.rs b/crates/lib/src/install.rs index bada00301..2e6302877 100644 --- a/crates/lib/src/install.rs +++ b/crates/lib/src/install.rs @@ -6,6 +6,7 @@ // This sub-module is the "basic" installer that handles creating basic block device // and filesystem setup. +mod aleph; #[cfg(feature = "install-to-disk")] pub(crate) mod baseline; pub(crate) mod completion; @@ -23,6 +24,7 @@ use std::str::FromStr; use std::sync::Arc; use std::time::Duration; +use aleph::InstallAleph; use anyhow::{anyhow, ensure, Context, Result}; use bootc_utils::CommandRunExt; use camino::Utf8Path; @@ -35,11 +37,9 @@ use cap_std_ext::cap_std::fs_utf8::DirEntry as DirEntryUtf8; use cap_std_ext::cap_tempfile::TempDir; use cap_std_ext::cmdext::CapStdExtCommandExt; use cap_std_ext::prelude::CapStdExtDirExt; -use chrono::prelude::*; use clap::ValueEnum; use fn_error_context::context; use ostree::gio; -use ostree_ext::oci_spec; use ostree_ext::ostree; use ostree_ext::ostree_prepareroot::{ComposefsState, Tristate}; use ostree_ext::prelude::Cast; @@ -417,27 +417,6 @@ impl State { } } -/// Path to initially deployed version information -const BOOTC_ALEPH_PATH: &str = ".bootc-aleph.json"; - -/// The "aleph" version information is injected into /root/.bootc-aleph.json -/// and contains the image ID that was initially used to install. This can -/// be used to trace things like the specific version of `mkfs.ext4` or -/// kernel version that was used. -#[derive(Debug, Serialize)] -struct InstallAleph { - /// Digested pull spec for installed image - image: String, - /// The version number - version: Option, - /// The timestamp - timestamp: Option>, - /// The `uname -r` of the kernel doing the installation - kernel: String, - /// The state of SELinux at install time - selinux: String, -} - /// A mount specification is a subset of a line in `/etc/fstab`. /// /// There are 3 (ASCII) whitespace separated values: @@ -529,32 +508,6 @@ impl FromStr for MountSpec { } } -impl InstallAleph { - #[context("Creating aleph data")] - pub(crate) fn new( - src_imageref: &ostree_container::OstreeImageReference, - imgstate: &ostree_container::store::LayeredImageState, - selinux_state: &SELinuxFinalState, - ) -> Result { - let uname = rustix::system::uname(); - let labels = crate::status::labels_of_config(&imgstate.configuration); - let timestamp = labels - .and_then(|l| { - l.get(oci_spec::image::ANNOTATION_CREATED) - .map(|s| s.as_str()) - }) - .and_then(bootc_utils::try_deserialize_timestamp); - let r = InstallAleph { - image: src_imageref.imgref.name.clone(), - version: imgstate.version().as_ref().map(|s| s.to_string()), - timestamp, - kernel: uname.release().to_str()?.to_string(), - selinux: selinux_state.to_aleph().to_string(), - }; - Ok(r) - } -} - impl SourceInfo { // Inspect container information and convert it to an ostree image reference // that pulls from containers-storage. @@ -1346,12 +1299,7 @@ async fn install_with_sysroot( // the aleph state (see below). let (deployment, aleph) = install_container(state, rootfs, &sysroot, has_ostree).await?; // Write the aleph data that captures the system state at the time of provisioning for aid in future debugging. - rootfs - .physical_root - .atomic_replace_with(BOOTC_ALEPH_PATH, |f| { - anyhow::Ok(aleph.to_canon_json_writer(f)?) - }) - .context("Writing aleph version")?; + aleph.write_to(&rootfs.physical_root)?; let deployment_path = sysroot.deployment_dirpath(&deployment); diff --git a/crates/lib/src/install/aleph.rs b/crates/lib/src/install/aleph.rs new file mode 100644 index 000000000..5983513da --- /dev/null +++ b/crates/lib/src/install/aleph.rs @@ -0,0 +1,63 @@ +use anyhow::{Context as _, Result}; +use canon_json::CanonJsonSerialize as _; +use cap_std_ext::{cap_std::fs::Dir, dirext::CapStdExtDirExt as _}; +use fn_error_context::context; +use ostree_ext::{container as ostree_container, oci_spec}; +use serde::Serialize; + +use super::SELinuxFinalState; + +/// Path to initially deployed version information +pub(crate) const BOOTC_ALEPH_PATH: &str = ".bootc-aleph.json"; + +/// The "aleph" version information is injected into /root/.bootc-aleph.json +/// and contains the image ID that was initially used to install. This can +/// be used to trace things like the specific version of `mkfs.ext4` or +/// kernel version that was used. +#[derive(Debug, Serialize)] +pub(crate) struct InstallAleph { + /// Digested pull spec for installed image + pub(crate) image: String, + /// The version number + pub(crate) version: Option, + /// The timestamp + pub(crate) timestamp: Option>, + /// The `uname -r` of the kernel doing the installation + pub(crate) kernel: String, + /// The state of SELinux at install time + pub(crate) selinux: String, +} + +impl InstallAleph { + #[context("Creating aleph data")] + pub(crate) fn new( + src_imageref: &ostree_container::OstreeImageReference, + imgstate: &ostree_container::store::LayeredImageState, + selinux_state: &SELinuxFinalState, + ) -> Result { + let uname = rustix::system::uname(); + let labels = crate::status::labels_of_config(&imgstate.configuration); + let timestamp = labels + .and_then(|l| { + l.get(oci_spec::image::ANNOTATION_CREATED) + .map(|s| s.as_str()) + }) + .and_then(bootc_utils::try_deserialize_timestamp); + let r = InstallAleph { + image: src_imageref.imgref.name.clone(), + version: imgstate.version().as_ref().map(|s| s.to_string()), + timestamp, + kernel: uname.release().to_str()?.to_string(), + selinux: selinux_state.to_aleph().to_string(), + }; + Ok(r) + } + + /// Serialize to a file in the target root. + pub(crate) fn write_to(&self, root: &Dir) -> Result<()> { + root.atomic_replace_with(BOOTC_ALEPH_PATH, |f| { + anyhow::Ok(self.to_canon_json_writer(f)?) + }) + .context("Writing aleph version") + } +}