Skip to content

Commit

Permalink
install: Add support for pulling LBIs during install
Browse files Browse the repository at this point in the history
Solves containers#846

This adds a new `--pull` option to `bootc install` which will pull
all LBIs into the target's container storage, even if they are not
available in the source root container storage.
  • Loading branch information
omertuc committed Oct 31, 2024
1 parent b469332 commit c6cd8a3
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 15 deletions.
8 changes: 6 additions & 2 deletions lib/src/boundimage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ pub(crate) struct ResolvedBoundImage {
/// Given a deployment, pull all container images it references.
pub(crate) async fn pull_bound_images(sysroot: &Storage, deployment: &Deployment) -> Result<()> {
let bound_images = query_bound_images_for_deployment(sysroot, deployment)?;
pull_images(sysroot, bound_images).await
pull_images(sysroot, &bound_images).await
}

#[context("Querying bound images")]
Expand Down Expand Up @@ -108,6 +108,7 @@ pub(crate) fn query_bound_images(root: &Dir) -> Result<Vec<BoundImage>> {

#[cfg(feature = "install")]
impl ResolvedBoundImage {
#[context("resolving bound image {}", src.image)]
pub(crate) async fn from_image(src: &BoundImage) -> Result<Self> {
let proxy = containers_image_proxy::ImageProxy::new().await?;
let img = proxy
Expand Down Expand Up @@ -148,7 +149,10 @@ fn parse_container_file(file_contents: &tini::Ini) -> Result<BoundImage> {
}

#[context("Pulling bound images")]
pub(crate) async fn pull_images(sysroot: &Storage, bound_images: Vec<BoundImage>) -> Result<()> {
pub(crate) async fn pull_images(
sysroot: &Storage,
bound_images: &[crate::boundimage::BoundImage],
) -> Result<()> {
tracing::debug!("Pulling bound images: {}", bound_images.len());
// Yes, the usage of NonZeroUsize here is...maybe odd looking, but I find
// it an elegant way to divide (empty vector, non empty vector) since
Expand Down
47 changes: 35 additions & 12 deletions lib/src/install.rs
Original file line number Diff line number Diff line change
Expand Up @@ -165,11 +165,16 @@ pub(crate) struct InstallConfigOpts {
#[serde(default)]
pub(crate) generic_image: bool,

/// Do not pull any "logically bound" images at install time.
/// Do not resolve any "logically bound" images at install time.
#[clap(long, hide = true)]
#[serde(default)]
pub(crate) skip_bound_images: bool,

/// Pull "logically bound" images at install time.
#[clap(long)]
#[serde(default)]
pub(crate) pull: bool,

/// The stateroot name to use. Defaults to `default`.
#[clap(long)]
pub(crate) stateroot: Option<String>,
Expand Down Expand Up @@ -1271,7 +1276,8 @@ async fn install_with_sysroot(
rootfs: &RootSetup,
sysroot: &Storage,
boot_uuid: &str,
bound_images: &[crate::boundimage::ResolvedBoundImage],
bound_images: &[crate::boundimage::BoundImage],
resolved_bound_images: &[crate::boundimage::ResolvedBoundImage],
) -> Result<()> {
// And actually set up the container in that root, returning a deployment and
// the aleph state (see below).
Expand All @@ -1298,13 +1304,20 @@ async fn install_with_sysroot(
tracing::debug!("Installed bootloader");

tracing::debug!("Perfoming post-deployment operations");
// Note that we *always* initialize this container storage, even
// if there are no bound images today.
let imgstore = sysroot.get_ensure_imgstore()?;
// Now copy each bound image from the host's container storage into the target.
for image in bound_images {
let image = image.image.as_str();
imgstore.pull_from_host_storage(image).await?;

if state.config_opts.pull {
crate::boundimage::pull_images(sysroot, bound_images)
.await
.context("pulling bound images")?;
} else {
// Note that we *always* initialize this container storage, even
// if there are no bound images today.
let imgstore = sysroot.get_ensure_imgstore()?;
// Now copy each bound image from the host's container storage into the target.
for image in resolved_bound_images {
let image = image.image.as_str();
imgstore.pull_from_host_storage(image).await?;
}
}

Ok(())
Expand Down Expand Up @@ -1344,9 +1357,11 @@ async fn install_to_filesystem_impl(state: &State, rootfs: &mut RootSetup) -> Re
tracing::debug!("bound images={bound_images:?}");

// Verify each bound image is present in the container storage
let bound_images = {
let resolved_bound_images = if state.config_opts.pull {
Vec::new()
} else {
let mut r = Vec::with_capacity(bound_images.len());
for image in bound_images {
for image in &bound_images {
let resolved = crate::boundimage::ResolvedBoundImage::from_image(&image).await?;
tracing::debug!("Resolved {}: {}", resolved.image, resolved.digest);
r.push(resolved)
Expand All @@ -1357,7 +1372,15 @@ async fn install_to_filesystem_impl(state: &State, rootfs: &mut RootSetup) -> Re
// Initialize the ostree sysroot (repo, stateroot, etc.)
{
let sysroot = initialize_ostree_root(state, rootfs).await?;
install_with_sysroot(state, rootfs, &sysroot, &boot_uuid, &bound_images).await?;
install_with_sysroot(
state,
rootfs,
&sysroot,
&boot_uuid,
&bound_images,
&resolved_bound_images,
)
.await?;
// We must drop the sysroot here in order to close any open file
// descriptors.
}
Expand Down
2 changes: 1 addition & 1 deletion lib/src/install/baseline.rs
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ pub(crate) fn install_create_rootfs(
crate::blockdev::wipefs(dev)?;
} else if device.has_children() {
anyhow::bail!(
"Detected existing partitions on {}; use e.g. `wipefs` if you intend to overwrite",
"Detected existing partitions on {}; use e.g. `wipefs` or --wipe if you intend to overwrite",
opts.device
);
}
Expand Down

0 comments on commit c6cd8a3

Please sign in to comment.