diff --git a/lib/src/cli.rs b/lib/src/cli.rs index 456f517e..b031d0a7 100644 --- a/lib/src/cli.rs +++ b/lib/src/cli.rs @@ -17,7 +17,8 @@ use ostree::{gio, glib}; use std::borrow::Cow; use std::collections::BTreeMap; use std::ffi::OsString; -use std::io::{BufWriter, Write}; +use std::fs::File; +use std::io::{BufReader, BufWriter, Write}; use std::path::PathBuf; use std::process::Command; use tokio::sync::mpsc::Receiver; @@ -138,6 +139,11 @@ pub(crate) enum ContainerOpts { /// Path to Docker-formatted authentication file. authfile: Option, + /// Path to a JSON-formatted serialized container configuration; this is the + /// `config` property of https://github.com/opencontainers/image-spec/blob/main/config.md + #[clap(long)] + config: Option, + /// Propagate an OSTree commit metadata key to container label #[clap(name = "copymeta", long)] copy_meta_keys: Vec, @@ -660,6 +666,7 @@ async fn container_export( authfile: Option, copy_meta_keys: Vec, copy_meta_opt_keys: Vec, + container_config: Option, cmd: Option>, compression_fast: bool, ) -> Result<()> { @@ -667,9 +674,15 @@ async fn container_export( labels: Some(labels), cmd, }; + let container_config = if let Some(container_config) = container_config { + serde_json::from_reader(File::open(container_config).map(BufReader::new)?)? + } else { + None + }; let opts = crate::container::ExportOpts { copy_meta_keys, copy_meta_opt_keys, + container_config, authfile, skip_compression: compression_fast, // TODO rename this in the struct at the next semver break ..Default::default() @@ -896,6 +909,7 @@ async fn run_from_opt(opt: Opt) -> Result<()> { authfile, copy_meta_keys, copy_meta_opt_keys, + config, cmd, compression_fast, } => { @@ -917,6 +931,7 @@ async fn run_from_opt(opt: Opt) -> Result<()> { authfile, copy_meta_keys, copy_meta_opt_keys, + config, cmd, compression_fast, ) diff --git a/lib/src/container/encapsulate.rs b/lib/src/container/encapsulate.rs index 75758eb8..d9cd9e62 100644 --- a/lib/src/container/encapsulate.rs +++ b/lib/src/container/encapsulate.rs @@ -214,7 +214,7 @@ fn build_oci( let commit_meta = &commit_v.child_value(0); let commit_meta = glib::VariantDict::new(Some(commit_meta)); - let mut ctrcfg = oci_image::Config::default(); + let mut ctrcfg = opts.container_config.clone().unwrap_or_default(); let mut imgcfg = oci_image::ImageConfiguration::default(); imgcfg.set_created(Some( commit_timestamp.format("%Y-%m-%dT%H:%M:%SZ").to_string(), @@ -381,6 +381,8 @@ pub struct ExportOpts<'m, 'o> { // TODO semver-break: remove this /// Use only the standard OCI version label pub no_legacy_version_label: bool, + /// Image runtime configuration that will be used as a base + pub container_config: Option, /// A reference to the metadata for a previous build; used to optimize /// the packing structure. pub prior_build: Option<&'m oci_image::ImageManifest>, diff --git a/lib/tests/it/main.rs b/lib/tests/it/main.rs index b42e91d7..29e5f55c 100644 --- a/lib/tests/it/main.rs +++ b/lib/tests/it/main.rs @@ -454,10 +454,15 @@ async fn impl_test_container_import_export(chunked: bool) -> Result<()> { }) .transpose()?; let mut opts = ExportOpts::default(); + let container_config = oci_spec::image::ConfigBuilder::default() + .stop_signal("SIGRTMIN+3") + .build() + .unwrap(); opts.copy_meta_keys = vec!["buildsys.checksum".to_string()]; opts.copy_meta_opt_keys = vec!["nosuchvalue".to_string()]; opts.max_layers = std::num::NonZeroU32::new(PKGS_V0_LEN as u32); opts.contentmeta = contentmeta.as_ref(); + opts.container_config = Some(container_config); let digest = ostree_ext::container::encapsulate( fixture.srcrepo(), fixture.testref(), @@ -483,11 +488,10 @@ async fn impl_test_container_import_export(chunked: bool) -> Result<()> { let creation_time = chrono::NaiveDateTime::parse_from_str(cfg.created().as_deref().unwrap(), "%+").unwrap(); assert_eq!(creation_time.timestamp(), 872879442); + let found_cfg = cfg.config().as_ref().unwrap(); // unwrap. Unwrap. UnWrap. UNWRAP!!!!!!! assert_eq!( - cfg.config() - .as_ref() - .unwrap() + found_cfg .cmd() .as_ref() .unwrap() @@ -497,6 +501,7 @@ async fn impl_test_container_import_export(chunked: bool) -> Result<()> { .as_str(), "/usr/bin/bash" ); + assert_eq!(found_cfg.stop_signal().as_deref().unwrap(), "SIGRTMIN+3"); let n_chunks = if chunked { LAYERS_V0_LEN } else { 1 }; assert_eq!(cfg.rootfs().diff_ids().len(), n_chunks);