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 #[serde(skip_serializing_if = "Option::is_none")]
35 pub(crate) version: Option<String>,
36 #[serde(skip_serializing_if = "Option::is_none")]
38 pub(crate) timestamp: Option<chrono::DateTime<chrono::Utc>>,
39 pub(crate) kernel: String,
41 pub(crate) selinux: String,
43}
44
45impl InstallAleph {
46 #[context("Creating aleph data")]
47 pub(crate) fn new(
48 src_imageref: &ostree_container::OstreeImageReference,
49 target_imgref: &ostree_container::OstreeImageReference,
50 imgstate: &ostree_container::store::LayeredImageState,
51 selinux_state: &SELinuxFinalState,
52 ) -> Result<Self> {
53 let uname = rustix::system::uname();
54 let oci_labels = crate::status::labels_of_config(&imgstate.configuration);
55 let timestamp = oci_labels
56 .and_then(|l| {
57 l.get(oci_spec::image::ANNOTATION_CREATED)
58 .map(|s| s.as_str())
59 })
60 .and_then(bootc_utils::try_deserialize_timestamp);
61 let labels: BTreeMap<String, String> = oci_labels
62 .map(|l| l.iter().map(|(k, v)| (k.clone(), v.clone())).collect())
63 .unwrap_or_default();
64 let image = if src_imageref.imgref.name.starts_with("/tmp") {
67 tracing::debug!("Not serializing the source imageref as it's a local temporary image.");
68 None
69 } else {
70 Some(src_imageref.imgref.name.clone())
71 };
72 let r = InstallAleph {
73 image,
74 target_image: target_imgref.imgref.name.clone(),
75 digest: imgstate.manifest_digest.to_string(),
76 labels,
77 version: imgstate.version().as_ref().map(|s| s.to_string()),
78 timestamp,
79 kernel: uname.release().to_str()?.to_string(),
80 selinux: selinux_state.to_aleph().to_string(),
81 };
82 Ok(r)
83 }
84
85 pub(crate) fn write_to(&self, root: &Dir) -> Result<()> {
87 root.atomic_replace_with(BOOTC_ALEPH_PATH, |f| {
88 anyhow::Ok(self.to_canon_json_writer(f)?)
89 })
90 .context("Writing aleph version")
91 }
92}