Skip to content

Commit 1b4e264

Browse files
committed
examples: Add example that injects arbitrary tar as OCI
I wanted to test out how container runtimes behaved with a tarball that had a filled in user/group name. For convenience of testing arbitrary tarballs in container images, add this example which takes an externally generated tar and just wraps it with OCI metadata. Signed-off-by: Colin Walters <[email protected]>
1 parent 2be18fd commit 1b4e264

File tree

1 file changed

+80
-0
lines changed

1 file changed

+80
-0
lines changed

examples/ocidir-import-tar.rs

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
//! # Import a pre-generated tarball, wrapping with OCI metadata into an OCI directory.
2+
//!
3+
//! This little exmaple shows a bit of how to use the ocidir API. But it has a use case
4+
//! for low-level testing of OCI runtimes by injecting arbitrary tarballs.
5+
6+
use std::io::BufReader;
7+
use std::{fs::File, path::Path};
8+
9+
use anyhow::Context;
10+
use cap_tempfile::cap_std;
11+
use chrono::Utc;
12+
use oci_spec::image::{MediaType, Platform};
13+
use ocidir::OciDir;
14+
15+
fn import(oci_dir: &OciDir, name: &str, src: File) -> anyhow::Result<()> {
16+
let mtime = src.metadata()?.modified()?;
17+
let mut input_tar = BufReader::new(src);
18+
let created = chrono::DateTime::<Utc>::from(mtime);
19+
20+
let mut manifest = oci_dir.new_empty_manifest().unwrap().build().unwrap();
21+
let mut config = ocidir::oci_spec::image::ImageConfigurationBuilder::default()
22+
.build()
23+
.unwrap();
24+
25+
// Add the src as a layer
26+
let mut writer = oci_dir.create_blob().unwrap();
27+
std::io::copy(&mut input_tar, &mut writer)?;
28+
29+
let blob = writer.complete()?;
30+
let descriptor = blob
31+
.descriptor()
32+
.media_type(MediaType::ImageLayer)
33+
.build()
34+
.unwrap();
35+
let blob_digest = descriptor.digest().to_string();
36+
manifest.layers_mut().push(descriptor);
37+
let mut rootfs = config.rootfs().clone();
38+
rootfs.diff_ids_mut().push(blob_digest);
39+
config.set_rootfs(rootfs);
40+
let h = oci_spec::image::HistoryBuilder::default()
41+
.created(created.to_rfc3339_opts(chrono::SecondsFormat::Secs, true))
42+
.created_by(name.to_string())
43+
.build()
44+
.unwrap();
45+
config.history_mut().push(h);
46+
47+
println!(
48+
"Created image with manifest: {}",
49+
manifest.to_string_pretty().unwrap()
50+
);
51+
52+
// Add the image manifest
53+
let _descriptor = oci_dir
54+
.insert_manifest_and_config(
55+
manifest.clone(),
56+
config,
57+
Some("latest"),
58+
Platform::default(),
59+
)
60+
.unwrap();
61+
62+
Ok(())
63+
}
64+
65+
fn main() -> anyhow::Result<()> {
66+
let args = std::env::args().collect::<Vec<_>>();
67+
let ocidir = args[1].as_str();
68+
let path = Path::new(args[2].as_str());
69+
let Some(name) = path.file_stem().and_then(|v| v.to_str()) else {
70+
anyhow::bail!("Invalid path: {path:?}");
71+
};
72+
let f = File::open(path).with_context(|| format!("Opening {path:?}"))?;
73+
74+
let dir = &cap_std::fs::Dir::open_ambient_dir(ocidir, cap_std::ambient_authority())
75+
.with_context(|| format!("Opening {ocidir}"))?;
76+
let oci_dir = OciDir::ensure(dir.try_clone()?)?;
77+
78+
import(&oci_dir, name, f)?;
79+
Ok(())
80+
}

0 commit comments

Comments
 (0)