From b766db88c0cfbbfe56c8a6c347ccb244747d8cae Mon Sep 17 00:00:00 2001 From: Colin Walters Date: Fri, 2 Feb 2024 15:01:27 -0500 Subject: [PATCH] Add suggestion for `LABEL containers.bootc 1` As we aim to slowly move away from ostree, let's add a bootc label that we expect to be used. For now, this is just a warning. I will change rpm-ostree to add this by default if we take this. But this one is also an important step for if we ever add the flow of simply deriving from an existing application base image. Signed-off-by: Colin Walters --- docs/bootc-images.md | 10 ++++++++++ lib/Cargo.toml | 1 + lib/src/cli.rs | 1 + lib/src/deploy.rs | 28 ++++++++++++++++++++++++++++ lib/src/journal.rs | 36 ++++++++++++++++++++++++++++++++++++ lib/src/lib.rs | 2 ++ lib/src/metadata.rs | 4 ++++ 7 files changed, 82 insertions(+) create mode 100644 lib/src/journal.rs create mode 100644 lib/src/metadata.rs diff --git a/docs/bootc-images.md b/docs/bootc-images.md index 8a3355634..afa1470c3 100644 --- a/docs/bootc-images.md +++ b/docs/bootc-images.md @@ -50,6 +50,16 @@ The requirement for both methods is that your initial treefile/manifest However, the ostree usage is an implementation detail and the requirement on this will be lifted in the future. +## Standard metadata for bootc compatible images + +It is strongly recommended to do: + +```dockerfile +LABEL containers.bootc 1 +``` + +This will signal that this image is intended to be usable with `bootc`. + # Deriving from existing base images It's important to emphasize that from one diff --git a/lib/Cargo.toml b/lib/Cargo.toml index b81b576a3..270db168f 100644 --- a/lib/Cargo.toml +++ b/lib/Cargo.toml @@ -26,6 +26,7 @@ gvariant = "0.4.0" indicatif = "0.17.0" libc = "^0.2" liboverdrop = "0.1.0" +libsystemd = "0.7" once_cell = "1.9" openssl = "^0.10" # TODO drop this in favor of rustix diff --git a/lib/src/cli.rs b/lib/src/cli.rs index da4441bab..77154fcb7 100644 --- a/lib/src/cli.rs +++ b/lib/src/cli.rs @@ -341,6 +341,7 @@ async fn upgrade(opts: UpgradeOpts) -> Result<()> { println!("No changes in: {}", imgref); } PrepareResult::Ready(r) => { + crate::deploy::check_bootc_label(&r.config); println!("Update available for: {}", imgref); if let Some(version) = r.version() { println!(" Version: {version}"); diff --git a/lib/src/deploy.rs b/lib/src/deploy.rs index 6b4373983..82e481daf 100644 --- a/lib/src/deploy.rs +++ b/lib/src/deploy.rs @@ -19,6 +19,7 @@ use ostree_ext::sysroot::SysrootLock; use crate::spec::HostSpec; use crate::spec::ImageReference; +use crate::status::labels_of_config; // TODO use https://github.com/ostreedev/ostree-rs-ext/pull/493/commits/afc1837ff383681b947de30c0cefc70080a4f87a const BASE_IMAGE_PREFIX: &str = "ostree/container/baseimage/bootc"; @@ -84,6 +85,32 @@ pub(crate) async fn new_importer( Ok(imp) } +pub(crate) fn check_bootc_label(config: &ostree_ext::oci_spec::image::ImageConfiguration) { + if let Some(label) = + labels_of_config(config).and_then(|labels| labels.get(crate::metadata::BOOTC_COMPAT_LABEL)) + { + match label.as_str() { + crate::metadata::COMPAT_LABEL_V1 => {} + o => crate::journal::journal_print( + libsystemd::logging::Priority::Warning, + &format!( + "notice: Unknown {} value {}", + crate::metadata::BOOTC_COMPAT_LABEL, + o + ), + ), + } + } else { + crate::journal::journal_print( + libsystemd::logging::Priority::Warning, + &format!( + "notice: Image is missing label: {}", + crate::metadata::BOOTC_COMPAT_LABEL + ), + ) + } +} + /// Wrapper for pulling a container image, wiring up status output. #[context("Pulling")] pub(crate) async fn pull( @@ -101,6 +128,7 @@ pub(crate) async fn pull( } PrepareResult::Ready(p) => p, }; + check_bootc_label(&prep.config); if let Some(warning) = prep.deprecated_warning() { ostree_ext::cli::print_deprecated_warning(warning).await; } diff --git a/lib/src/journal.rs b/lib/src/journal.rs new file mode 100644 index 000000000..bed50ec62 --- /dev/null +++ b/lib/src/journal.rs @@ -0,0 +1,36 @@ +//! Thin wrapper for systemd journaling; these APIs are no-ops +//! when not running under systemd. Only use them when + +use std::collections::HashMap; +use std::sync::atomic::{AtomicBool, Ordering}; + +/// Set to true if we failed to write to the journal once +static EMITTED_JOURNAL_ERROR: AtomicBool = AtomicBool::new(false); + +/// Wrapper for structured logging which is an explicit no-op +/// when systemd is not in use (e.g. in a container). +pub(crate) fn journal_send( + priority: libsystemd::logging::Priority, + msg: &str, + vars: impl Iterator, +) where + K: AsRef, + V: AsRef, +{ + if !libsystemd::daemon::booted() { + return; + } + if let Err(e) = libsystemd::logging::journal_send(priority, msg, vars) { + if !EMITTED_JOURNAL_ERROR.swap(true, Ordering::SeqCst) { + eprintln!("failed to write to journal: {e}"); + } + } +} + +/// Wrapper for writing to systemd journal which is an explicit no-op +/// when systemd is not in use (e.g. in a container). +#[allow(dead_code)] +pub(crate) fn journal_print(priority: libsystemd::logging::Priority, msg: &str) { + let vars: HashMap<&str, &str> = HashMap::new(); + journal_send(priority, msg, vars.into_iter()) +} diff --git a/lib/src/lib.rs b/lib/src/lib.rs index fafdd991e..aad5d95b2 100644 --- a/lib/src/lib.rs +++ b/lib/src/lib.rs @@ -19,7 +19,9 @@ pub mod cli; pub(crate) mod deploy; +pub(crate) mod journal; mod lsm; +pub(crate) mod metadata; mod reboot; mod reexec; mod status; diff --git a/lib/src/metadata.rs b/lib/src/metadata.rs new file mode 100644 index 000000000..4db5758bf --- /dev/null +++ b/lib/src/metadata.rs @@ -0,0 +1,4 @@ +/// This label is expected to be present on compatible base images. +pub(crate) const BOOTC_COMPAT_LABEL: &str = "containers.bootc"; +/// The current single well-known value for the label. +pub(crate) const COMPAT_LABEL_V1: &str = "1";