bootc_lib/install/
aleph.rs1use std::collections::BTreeMap;
2
3use anyhow::{Context as _, Result};
4use canon_json::CanonJsonSerialize as _;
5use cap_std_ext::{cap_std::fs::Dir, dirext::CapStdExtDirExt as _};
6use fn_error_context::context;
7use ostree_ext::{container as ostree_container, oci_spec};
8use serde::Serialize;
9
10use super::SELinuxFinalState;
11
12pub(crate) const BOOTC_ALEPH_PATH: &str = ".bootc-aleph.json";
14
15#[derive(Debug, Serialize)]
20#[serde(rename_all = "kebab-case")]
21pub(crate) struct InstallAleph {
22 #[serde(skip_serializing_if = "Option::is_none")]
24 pub(crate) image: Option<String>,
25 pub(crate) digest: String,
27 #[serde(rename = "target-image")]
29 pub(crate) target_image: String,
30 #[serde(skip_serializing_if = "BTreeMap::is_empty")]
32 pub(crate) labels: BTreeMap<String, String>,
33 pub(crate) version: Option<String>,
35 pub(crate) timestamp: Option<chrono::DateTime<chrono::Utc>>,
37 pub(crate) kernel: String,
39 pub(crate) selinux: String,
41}
42
43impl InstallAleph {
44 #[context("Creating aleph data")]
45 pub(crate) fn new(
46 src_imageref: &ostree_container::OstreeImageReference,
47 target_imgref: &ostree_container::OstreeImageReference,
48 imgstate: &ostree_container::store::LayeredImageState,
49 selinux_state: &SELinuxFinalState,
50 ) -> Result<Self> {
51 let uname = rustix::system::uname();
52 let oci_labels = crate::status::labels_of_config(&imgstate.configuration);
53 let timestamp = oci_labels
54 .and_then(|l| {
55 l.get(oci_spec::image::ANNOTATION_CREATED)
56 .map(|s| s.as_str())
57 })
58 .and_then(bootc_utils::try_deserialize_timestamp);
59 let labels: BTreeMap<String, String> = oci_labels
60 .map(|l| l.iter().map(|(k, v)| (k.clone(), v.clone())).collect())
61 .unwrap_or_default();
62 let image = if src_imageref.imgref.name.starts_with("/tmp") {
65 tracing::debug!("Not serializing the source imageref as it's a local temporary image.");
66 None
67 } else {
68 Some(src_imageref.imgref.name.clone())
69 };
70 let r = InstallAleph {
71 image,
72 target_image: target_imgref.imgref.name.clone(),
73 digest: imgstate.manifest_digest.to_string(),
74 labels,
75 version: imgstate.version().as_ref().map(|s| s.to_string()),
76 timestamp,
77 kernel: uname.release().to_str()?.to_string(),
78 selinux: selinux_state.to_aleph().to_string(),
79 };
80 Ok(r)
81 }
82
83 pub(crate) fn write_to(&self, root: &Dir) -> Result<()> {
85 root.atomic_replace_with(BOOTC_ALEPH_PATH, |f| {
86 anyhow::Ok(self.to_canon_json_writer(f)?)
87 })
88 .context("Writing aleph version")
89 }
90}