diff --git a/lib/Cargo.toml b/lib/Cargo.toml index a059910d..1de87671 100644 --- a/lib/Cargo.toml +++ b/lib/Cargo.toml @@ -10,7 +10,7 @@ version = "0.4.0" [dependencies] anyhow = "1.0" -containers-image-proxy = "0.2" +containers-image-proxy = "0.3" async-compression = { version = "0.3", features = ["gzip", "tokio"] } bytes = "1.0.1" bitflags = "1" diff --git a/lib/src/cli.rs b/lib/src/cli.rs index 644c6ae1..b53fed12 100644 --- a/lib/src/cli.rs +++ b/lib/src/cli.rs @@ -125,6 +125,18 @@ enum ContainerOpts { Image(ContainerImageOpts), } +/// Options for container image fetching. +#[derive(Debug, StructOpt)] +struct ContainerProxyOpts { + #[structopt(long)] + /// Path to Docker-formatted authentication file. + authfile: Option, + + #[structopt(long)] + /// Skip TLS verification. + insecure_skip_tls_verification: bool, +} + /// Options for import/export to tar archives. #[derive(Debug, StructOpt)] enum ContainerImageOpts { @@ -144,6 +156,9 @@ enum ContainerImageOpts { /// Image reference, e.g. ostree-remote-image:someremote:registry:quay.io/exampleos/exampleos:latest #[structopt(parse(try_from_str = parse_imgref))] imgref: OstreeImageReference, + + #[structopt(flatten)] + proxyopts: ContainerProxyOpts, }, /// Copy a pulled container image from one repo to another. @@ -176,6 +191,9 @@ enum ContainerImageOpts { #[structopt(parse(try_from_str = parse_imgref))] imgref: OstreeImageReference, + #[structopt(flatten)] + proxyopts: ContainerProxyOpts, + /// Target image reference, e.g. ostree-remote-image:someremote:registry:quay.io/exampleos/exampleos:latest /// /// If specified, `--imgref` will be used as a source, but this reference will be emitted into the origin @@ -220,6 +238,15 @@ enum Opt { ImaSign(ImaSignOpts), } +impl Into for ContainerProxyOpts { + fn into(self) -> ostree_container::store::ImageProxyConfig { + ostree_container::store::ImageProxyConfig { + authfile: self.authfile, + insecure_skip_tls_verification: Some(self.insecure_skip_tls_verification), + } + } +} + /// Import a tar archive containing an ostree commit. async fn tar_import(opts: &ImportOpts) -> Result<()> { let repo = &ostree::Repo::open_at(libc::AT_FDCWD, opts.repo.as_str(), gio::NONE_CANCELLABLE)?; @@ -331,9 +358,13 @@ async fn container_info(imgref: &OstreeImageReference) -> Result<()> { } /// Write a layered container image into an OSTree commit. -async fn container_store(repo: &str, imgref: &OstreeImageReference) -> Result<()> { +async fn container_store( + repo: &str, + imgref: &OstreeImageReference, + proxyopts: ContainerProxyOpts, +) -> Result<()> { let repo = &ostree::Repo::open_at(libc::AT_FDCWD, repo, gio::NONE_CANCELLABLE)?; - let mut imp = LayeredImageImporter::new(repo, imgref).await?; + let mut imp = LayeredImageImporter::new(repo, imgref, proxyopts.into()).await?; let prep = match imp.prepare().await? { PrepareResult::AlreadyPresent(c) => { println!("No changes in {} => {}", imgref, c.merge_commit); @@ -444,7 +475,11 @@ where } Ok(()) } - ContainerImageOpts::Pull { repo, imgref } => container_store(&repo, &imgref).await, + ContainerImageOpts::Pull { + repo, + imgref, + proxyopts, + } => container_store(&repo, &imgref, proxyopts).await, ContainerImageOpts::Copy { src_repo, dest_repo, @@ -462,6 +497,7 @@ where imgref, target_imgref, karg, + proxyopts, } => { let sysroot = &ostree::Sysroot::new(Some(&gio::File::for_path(&sysroot))); sysroot.load(gio::NONE_CANCELLABLE)?; @@ -473,6 +509,7 @@ where let options = crate::container::deploy::DeployOpts { kargs: kargs.as_deref(), target_imgref: target_imgref.as_ref(), + proxy_cfg: Some(proxyopts.into()), }; crate::container::deploy::deploy(sysroot, &stateroot, &imgref, Some(options)) .await diff --git a/lib/src/container/deploy.rs b/lib/src/container/deploy.rs index d7f69527..020657e5 100644 --- a/lib/src/container/deploy.rs +++ b/lib/src/container/deploy.rs @@ -22,6 +22,9 @@ pub struct DeployOpts<'a> { /// /// To implement this, use this option for the latter `:latest` tag. pub target_imgref: Option<&'a OstreeImageReference>, + + /// Configuration for fetching containers. + pub proxy_cfg: Option, } /// Write a container image to an OSTree deployment. @@ -36,7 +39,12 @@ pub async fn deploy( let cancellable = ostree::gio::NONE_CANCELLABLE; let options = options.unwrap_or_default(); let repo = &sysroot.repo().unwrap(); - let mut imp = super::store::LayeredImageImporter::new(repo, imgref).await?; + let mut imp = super::store::LayeredImageImporter::new( + repo, + imgref, + options.proxy_cfg.unwrap_or_default(), + ) + .await?; if let Some(target) = options.target_imgref { imp.set_target(target); } diff --git a/lib/src/container/store.rs b/lib/src/container/store.rs index 7bcfb237..c973f270 100644 --- a/lib/src/container/store.rs +++ b/lib/src/container/store.rs @@ -16,6 +16,12 @@ use ostree::{gio, glib}; use std::collections::HashMap; use std::iter::FromIterator; +/// Configuration for the proxy. +/// +/// We re-export this rather than inventing our own wrapper +/// in the interest of avoiding duplication. +pub use containers_image_proxy::ImageProxyConfig; + /// The ostree ref prefix for blobs. const LAYER_PREFIX: &str = "ostree/container/blob"; /// The ostree ref prefix for image references. @@ -167,8 +173,12 @@ pub fn manifest_digest_from_commit(commit: &glib::Variant) -> Result { impl LayeredImageImporter { /// Create a new importer. - pub async fn new(repo: &ostree::Repo, imgref: &OstreeImageReference) -> Result { - let mut proxy = ImageProxy::new().await?; + pub async fn new( + repo: &ostree::Repo, + imgref: &OstreeImageReference, + config: ImageProxyConfig, + ) -> Result { + let proxy = ImageProxy::new_with_config(config).await?; let proxy_img = proxy.open_image(&imgref.imgref.to_string()).await?; let repo = repo.clone(); Ok(LayeredImageImporter { diff --git a/lib/src/container/unencapsulate.rs b/lib/src/container/unencapsulate.rs index 07f4c5b9..979ab189 100644 --- a/lib/src/container/unencapsulate.rs +++ b/lib/src/container/unencapsulate.rs @@ -92,7 +92,7 @@ impl AsyncRead for ProgressReader { pub async fn fetch_manifest( imgref: &OstreeImageReference, ) -> Result<(oci_spec::image::ImageManifest, String)> { - let mut proxy = ImageProxy::new().await?; + let proxy = ImageProxy::new().await?; let oi = &proxy.open_image(&imgref.imgref.to_string()).await?; let (digest, raw_manifest) = proxy.fetch_manifest(oi).await?; proxy.close_image(oi).await?; diff --git a/lib/tests/it/main.rs b/lib/tests/it/main.rs index fac3d623..bc6015a0 100644 --- a/lib/tests/it/main.rs +++ b/lib/tests/it/main.rs @@ -431,9 +431,12 @@ async fn test_container_write_derive() -> Result<()> { assert!(images.is_empty()); // Pull a derived image - two layers, new base plus one layer. - let mut imp = - ostree_ext::container::store::LayeredImageImporter::new(&fixture.destrepo, &exampleos_ref) - .await?; + let mut imp = ostree_ext::container::store::LayeredImageImporter::new( + &fixture.destrepo, + &exampleos_ref, + Default::default(), + ) + .await?; let prep = match imp.prepare().await? { PrepareResult::AlreadyPresent(_) => panic!("should not be already imported"), PrepareResult::Ready(r) => r, @@ -465,9 +468,12 @@ async fn test_container_write_derive() -> Result<()> { )?; // Import again, but there should be no changes. - let mut imp = - ostree_ext::container::store::LayeredImageImporter::new(&fixture.destrepo, &exampleos_ref) - .await?; + let mut imp = ostree_ext::container::store::LayeredImageImporter::new( + &fixture.destrepo, + &exampleos_ref, + Default::default(), + ) + .await?; let already_present = match imp.prepare().await? { PrepareResult::AlreadyPresent(c) => c, PrepareResult::Ready(_) => { @@ -478,9 +484,12 @@ async fn test_container_write_derive() -> Result<()> { // Test upgrades; replace the oci-archive with new content. std::fs::write(exampleos_path, EXAMPLEOS_DERIVED_V2_OCI)?; - let mut imp = - ostree_ext::container::store::LayeredImageImporter::new(&fixture.destrepo, &exampleos_ref) - .await?; + let mut imp = ostree_ext::container::store::LayeredImageImporter::new( + &fixture.destrepo, + &exampleos_ref, + Default::default(), + ) + .await?; let prep = match imp.prepare().await? { PrepareResult::AlreadyPresent(_) => panic!("should not be already imported"), PrepareResult::Ready(r) => r, @@ -512,9 +521,12 @@ async fn test_container_write_derive() -> Result<()> { )?; // And there should be no changes on upgrade again. - let mut imp = - ostree_ext::container::store::LayeredImageImporter::new(&fixture.destrepo, &exampleos_ref) - .await?; + let mut imp = ostree_ext::container::store::LayeredImageImporter::new( + &fixture.destrepo, + &exampleos_ref, + Default::default(), + ) + .await?; let already_present = match imp.prepare().await? { PrepareResult::AlreadyPresent(c) => c, PrepareResult::Ready(_) => {