Skip to content

Commit

Permalink
Fix up output a bit, add troubleshooting to readme
Browse files Browse the repository at this point in the history
  • Loading branch information
jssblck committed Dec 12, 2024
1 parent 9d3a711 commit 217875f
Show file tree
Hide file tree
Showing 4 changed files with 45 additions and 11 deletions.
22 changes: 22 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,3 +94,25 @@ The other options are:
> The `separate` option also writes a `layers.json` file in the target directory,
> which is a JSON-encoded array of layer directory names.
> This array specifies the order of layer application in the image.
## troubleshooting

Set `RUST_LOG=debug` to get more detailed logs, and `RUST_LOG=trace` to get extremely detailed logs.
You can also filter to logs in a specific module (such as `circe` or `circe_lib`)
by setting `RUST_LOG=circe=debug` or `RUST_LOG=circe_lib=debug`.

> [!TIP]
> In macOS and Linux, you can apply environment variables to a command without changing your environment;
> for example: `RUST_LOG=trace circe ...`.
### future improvements

These are somewhat "known issues", but mostly "things to keep in mind" when using `circe`.
Ideally we'll fix these in the future; feel free to make a contribution or open an issue letting us know if one of these is blocking you.

- [ ] circe does not currently download layers concurrently.
Since network transfer is effectively always the bottleneck, adding concurrent downloads would likely speed up `circe` significantly.
That being said, as of our tests today `circe` is already about as fast as `docker pull && docker save`.
- [ ] symlinks are unpacked with the same destination as written in the actual container.
This means e.g. they can link to files outside of the output directory
(the example case I found was files in `usr/bin`, linking to `/bin/`).
19 changes: 12 additions & 7 deletions bin/src/extract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@ use circe_lib::{registry::Registry, LayerDescriptor, Platform, Reference};
use clap::{Parser, ValueEnum};
use color_eyre::eyre::{bail, Context, Result};
use std::{path::PathBuf, str::FromStr};
use tap::Pipe;
use tracing::info;
use tracing::{debug, info};

#[derive(Debug, Parser)]
pub struct Options {
Expand Down Expand Up @@ -63,7 +62,7 @@ pub enum Mode {

#[tracing::instrument]
pub async fn main(opts: Options) -> Result<()> {
info!("Extracting image");
info!("extracting image");

let output = canonicalize_output_dir(&opts.output_dir, opts.overwrite)?;
let registry = Registry::builder()
Expand Down Expand Up @@ -92,6 +91,7 @@ async fn squash(
info!("enumerated {count} {}", plural(count, "layer", "layers"));

for (descriptor, layer) in layers.zip(1usize..) {
debug!(?descriptor, layer, count, "applying layer");
if count > 0 {
info!(layer = %descriptor, "applying layer {layer} of {count}");
} else {
Expand All @@ -104,6 +104,7 @@ async fn squash(
.with_context(|| format!("apply layer {descriptor} to {output:?}"))?;
}

info!("finished applying layers");
Ok(())
}

Expand All @@ -117,6 +118,7 @@ async fn separate(
info!("enumerated {count} {}", plural(count, "layer", "layers"));

for (descriptor, layer) in layers.iter().zip(1usize..) {
debug!(?descriptor, layer, count, "applying layer");
let output = output.join(descriptor.digest.as_hex());
if count > 0 {
info!(layer = %descriptor, "applying layer {layer} of {count}");
Expand All @@ -130,16 +132,19 @@ async fn separate(
.with_context(|| format!("apply layer {descriptor} to {output:?}"))?;
}

info!("finished applying layers");
let index_destination = output.join("layers.json");
let index = layers
.into_iter()
.map(|l| l.digest.as_hex())
.collect::<Vec<_>>()
.pipe_ref(serde_json::to_string_pretty)
.context("serialize layer index")?;
.collect::<Vec<_>>();

tokio::fs::write(output.join("layers.json"), index)
debug!(?index, ?index_destination, "serializing layer index");
let index = serde_json::to_string_pretty(&index).context("serialize layer index")?;
tokio::fs::write(&index_destination, index)
.await
.context("write layer index")
.inspect(|_| info!(path = ?index_destination, "layer index written"))
}

/// Given a (probably relative) path to a directory, canonicalize it to an absolute path.
Expand Down
3 changes: 2 additions & 1 deletion bin/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ async fn main() -> Result<()> {
tracing_tree::HierarchicalLayer::default()
.with_indent_lines(true)
.with_indent_amount(2)
.with_thread_ids(true)
.with_thread_ids(false)
.with_thread_names(false)
.with_verbose_exit(false)
.with_verbose_entry(false)
.with_deferred_spans(true)
Expand Down
12 changes: 9 additions & 3 deletions lib/src/registry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ use oci_client::{
use os_str_bytes::OsStrBytesExt;
use tokio_tar::Archive;
use tokio_util::io::StreamReader;
use tracing::{info, warn};
use tracing::{debug, warn};

use crate::{
ext::PriorityFind,
Expand Down Expand Up @@ -244,10 +244,16 @@ async fn apply_tarball(stream: impl Stream<Item = Chunk> + Unpin, output: &Path)
// Whiteout files delete the file from the filesystem.
if let Some(path) = is_whiteout(&path) {
unwrap_warn!(tokio::fs::remove_file(&path).await, "whiteout: {path:?}");
info!(?path, "whiteout");
debug!(?path, "whiteout");
continue;
}

// Future improvement: symlinks are unpacked with the same destination as written in the actual container;
// this means e.g. they can link to files outside of the output directory
// (the example case I found was in `usr/bin`, linking to `/bin/`).
// I don't _think_ this matters for now given how we're using this today, but it's technically incorrect.
// To fix this we need to re-implement the logic in `unpack_in` to rewrite symlink destinations.

// Otherwise, apply the file as normal.
// Both _new_ and _changed_ files are handled the same way:
// the layer contains the entire file content, so we just overwrite the file.
Expand All @@ -256,7 +262,7 @@ async fn apply_tarball(stream: impl Stream<Item = Chunk> + Unpin, output: &Path)
continue;
}

info!(?path, "apply");
debug!(?path, "apply");
}

Ok(())
Expand Down

0 comments on commit 217875f

Please sign in to comment.