Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
383 changes: 205 additions & 178 deletions Cargo.lock

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,9 @@ clap = "4.5.4"
clap_mangen = { version = "0.2.20" }
# Reviewers (including AI tools): The composefs-rs git revision is duplicated for each crate.
# If adding/removing crates here, also update docs/Dockerfile.mdbook and docs/src/internals.md.
composefs = { git = "https://github.com/containers/composefs-rs", rev = "1498349e11d0e4bd545feab533f0b7ab5294ae9a", package = "composefs", features = ["rhel9"] }
composefs-boot = { git = "https://github.com/containers/composefs-rs", rev = "1498349e11d0e4bd545feab533f0b7ab5294ae9a", package = "composefs-boot" }
composefs-oci = { git = "https://github.com/containers/composefs-rs", rev = "1498349e11d0e4bd545feab533f0b7ab5294ae9a", package = "composefs-oci" }
composefs = { git = "https://github.com/containers/composefs-rs", rev = "49d4f50d6ba338edca26d799145a1283185f2466", package = "composefs", features = ["rhel9"] }
composefs-boot = { git = "https://github.com/containers/composefs-rs", rev = "49d4f50d6ba338edca26d799145a1283185f2466", package = "composefs-boot" }
composefs-oci = { git = "https://github.com/containers/composefs-rs", rev = "49d4f50d6ba338edca26d799145a1283185f2466", package = "composefs-oci" }
fn-error-context = "0.2.1"
hex = "0.4.3"
indicatif = "0.18.0"
Expand Down
32 changes: 13 additions & 19 deletions crates/lib/src/bootc_composefs/export.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,15 @@ use std::{fs::File, os::fd::AsRawFd};
use anyhow::{Context, Result};
use cap_std_ext::cap_std::{ambient_authority, fs::Dir};
use composefs::splitstream::SplitStreamData;
use composefs_oci::open_config;
use ocidir::{oci_spec::image::Platform, OciDir};
use ostree_ext::container::skopeo;
use ostree_ext::{container::Transport, oci_spec::image::ImageConfiguration};
use ostree_ext::container::Transport;
use tar::EntryType;

use crate::image::get_imgrefs_for_copy;
use crate::{
bootc_composefs::{
status::{get_composefs_status, get_imginfo},
update::str_to_sha256digest,
},
bootc_composefs::status::{get_composefs_status, get_imginfo},
store::{BootedComposefs, Storage},
};

Expand Down Expand Up @@ -52,21 +50,17 @@ pub async fn export_repo_to_image(

let imginfo = get_imginfo(storage, &depl_verity, None).await?;

let config_name = &imginfo.manifest.config().digest().digest();
let config_name = str_to_sha256digest(config_name)?;
let config_digest = imginfo.manifest.config().digest().digest();

let var_tmp =
Dir::open_ambient_dir("/var/tmp", ambient_authority()).context("Opening /var/tmp")?;

let tmpdir = cap_std_ext::cap_tempfile::tempdir_in(&var_tmp)?;
let oci_dir = OciDir::ensure(tmpdir.try_clone()?).context("Opening OCI")?;

let mut config_stream = booted_cfs
.repo
.open_stream(&hex::encode(config_name), None)
.context("Opening config stream")?;

let config = ImageConfiguration::from_reader(&mut config_stream)?;
// Use composefs_oci::open_config to get the config and layer map
let (config, layer_map) =
open_config(&*booted_cfs.repo, config_digest, None).context("Opening config")?;

// We can't guarantee that we'll get the same tar stream as the container image
// So we create new config and manifest
Expand All @@ -82,12 +76,12 @@ pub async fn export_repo_to_image(
let total_layers = config.rootfs().diff_ids().len();

for (idx, old_diff_id) in config.rootfs().diff_ids().iter().enumerate() {
let layer_sha256 = str_to_sha256digest(old_diff_id)?;
let layer_verity = config_stream.lookup(&layer_sha256)?;
// Look up the layer verity from the map
let layer_verity = layer_map
.get(old_diff_id.as_str())
.ok_or_else(|| anyhow::anyhow!("Layer {old_diff_id} not found in config"))?;

let mut layer_stream = booted_cfs
.repo
.open_stream(&hex::encode(layer_sha256), Some(layer_verity))?;
let mut layer_stream = booted_cfs.repo.open_stream("", Some(layer_verity), None)?;

let mut layer_writer = oci_dir.create_layer(None)?;
layer_writer.follow_symlinks(false);
Expand Down Expand Up @@ -120,7 +114,7 @@ pub async fn export_repo_to_image(

let size = header.entry_size()?;

match layer_stream.read_exact(size as usize, ((size + 511) & !511) as usize)? {
match layer_stream.read_exact(size as usize, ((size as usize) + 511) & !511)? {
SplitStreamData::External(obj_id) => match header.entry_type() {
EntryType::Regular | EntryType::Continuous => {
let file = File::from(booted_cfs.repo.open_object(&obj_id)?);
Expand Down
11 changes: 4 additions & 7 deletions crates/lib/src/bootc_composefs/repo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,7 @@ use std::sync::Arc;

use anyhow::{Context, Result};

use ostree_ext::composefs::{
fsverity::{FsVerityHashValue, Sha512HashValue},
util::Sha256Digest,
};
use ostree_ext::composefs::fsverity::{FsVerityHashValue, Sha512HashValue};
use ostree_ext::composefs_boot::{bootloader::BootEntry as ComposefsBootEntry, BootOps};
use ostree_ext::composefs_oci::{
image::create_filesystem as create_composefs_filesystem, pull as composefs_oci_pull,
Expand All @@ -26,7 +23,7 @@ pub(crate) fn open_composefs_repo(rootfs_dir: &Dir) -> Result<crate::store::Comp
pub(crate) async fn initialize_composefs_repository(
state: &State,
root_setup: &RootSetup,
) -> Result<(Sha256Digest, impl FsVerityHashValue)> {
) -> Result<(String, impl FsVerityHashValue)> {
let rootfs_dir = &root_setup.physical_root;

rootfs_dir
Expand Down Expand Up @@ -94,11 +91,11 @@ pub(crate) async fn pull_composefs_repo(
.await
.context("Pulling composefs repo")?;

tracing::info!("ID: {}, Verity: {}", hex::encode(id), verity.to_hex());
tracing::info!("ID: {id}, Verity: {}", verity.to_hex());

let repo = open_composefs_repo(&rootfs_dir)?;
let mut fs: crate::store::ComposefsFilesystem =
create_composefs_filesystem(&repo, &hex::encode(id), None)
create_composefs_filesystem(&repo, &id, None)
.context("Failed to create composefs filesystem")?;

let entries = fs.transform_for_boot(&repo)?;
Expand Down
16 changes: 3 additions & 13 deletions crates/lib/src/bootc_composefs/update.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
use anyhow::{Context, Result};
use camino::Utf8PathBuf;
use cap_std_ext::cap_std::fs::Dir;
use composefs::{
fsverity::{FsVerityHashValue, Sha512HashValue},
util::{parse_sha256, Sha256Digest},
};
use composefs::fsverity::{FsVerityHashValue, Sha512HashValue};
use composefs_boot::BootOps;
use composefs_oci::image::create_filesystem;
use fn_error_context::context;
Expand All @@ -28,12 +25,6 @@ use crate::{
store::{BootedComposefs, ComposefsRepository, Storage},
};

#[context("Getting SHA256 Digest for {id}")]
pub fn str_to_sha256digest(id: &str) -> Result<Sha256Digest> {
let id = id.strip_prefix("sha256:").unwrap_or(id);
Ok(parse_sha256(&id)?)
}

/// Checks if a container image has been pulled to the local composefs repository.
///
/// This function verifies whether the specified container image exists in the local
Expand Down Expand Up @@ -61,10 +52,9 @@ pub(crate) async fn is_image_pulled(
let img_config_manifest = get_container_manifest_and_config(&imgref_repr).await?;

let img_digest = img_config_manifest.manifest.config().digest().digest();
let img_sha256 = str_to_sha256digest(&img_digest)?;

// check_stream is expensive to run, but probably a good idea
let container_pulled = repo.check_stream(&img_sha256).context("Checking stream")?;
// NB: add deep checking?
let container_pulled = repo.has_stream(img_digest).context("Checking stream")?;

Ok((container_pulled, img_config_manifest))
}
Expand Down
Loading
Loading