Skip to content

Commit

Permalink
Pass the oci_dir and tag in the format <oci_dir>:<tag>
Browse files Browse the repository at this point in the history
This will support passing puzzlefs as a mount helper in the lxc oci
template [1].

[1] lxc/lxc@1a2da75

Signed-off-by: Ariel Miculas-Trif <[email protected]>
  • Loading branch information
ariel-miculas committed Sep 18, 2024
1 parent 9b32174 commit 24d7d44
Show file tree
Hide file tree
Showing 4 changed files with 39 additions and 36 deletions.
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ $ tree /tmp/example-rootfs

Then run:
```
$ cargo run --release -- build /tmp/example-rootfs /tmp/puzzlefs-image puzzlefs_example
$ cargo run --release -- build /tmp/example-rootfs /tmp/puzzlefs-image:puzzlefs_example
puzzlefs image manifest digest: 9ac9abc098870c55cc61431dae8635806273d8f61274d34bec062560e79dc2f5
```
This builds a puzzlefs image with the above root filesystem in `/tmp/puzzlefs-image`, with the tag `puzzlefs_example`.
Expand All @@ -107,13 +107,13 @@ It also outputs the image's manifest digest, which is useful for verifying the i
For additional build options, run `puzzlefs build -h`.

### Mounting a puzzlefs image
To mount the above puzlefs image, first we need to create a mountpoint:
To mount the above puzzlefs image, first we need to create a mountpoint:
```
mkdir /tmp/mounted-image
```
Then run `puzzlefs mount` with the location of the puzzlefs image, the image tag and the mountpoint:
```
$ cargo run --release -- mount /tmp/puzzlefs-image puzzlefs_example /tmp/mounted-image
$ cargo run --release -- mount /tmp/puzzlefs-image:puzzlefs_example /tmp/mounted-image
```

If everything was successful, you will see a `fuse` entry in the output of `mount`:
Expand Down Expand Up @@ -145,7 +145,7 @@ For additional mount options, run `cargo run -- mount -h`.
### Mounting with fs-verity enabled
If you want to mount the filesystem with `fs-verity` authenticity protection, first enable `fs-verity` by running:
```
$ cargo run --release -- enable-fs-verity /tmp/puzzlefs-image puzzlefs_example 9ac9abc098870c55cc61431dae8635806273d8f61274d34bec062560e79dc2f5
$ cargo run --release -- enable-fs-verity /tmp/puzzlefs-image:puzzlefs_example 9ac9abc098870c55cc61431dae8635806273d8f61274d34bec062560e79dc2f5
```
This makes the data and metadata files readonly. Any reads of corrupted data will fail.

Expand Down
41 changes: 25 additions & 16 deletions exe/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@ enum SubCommand {
struct Build {
rootfs: String,
oci_dir: String,
tag: String,
#[arg(short, long, value_name = "base-layer")]
base_layer: Option<String>,
#[arg(short, long, value_name = "compressed")]
Expand All @@ -48,7 +47,6 @@ struct Build {
#[derive(Args)]
struct Mount {
oci_dir: String,
tag: String,
mountpoint: String,
#[arg(short, long)]
foreground: bool,
Expand All @@ -63,14 +61,12 @@ struct Mount {
#[derive(Args)]
struct Extract {
oci_dir: String,
tag: String,
extract_dir: String,
}

#[derive(Args)]
struct FsVerity {
oci_dir: String,
tag: String,
root_hash: String,
}

Expand Down Expand Up @@ -148,32 +144,42 @@ fn mount_background(
Ok(())
}

fn parse_oci_dir(oci_dir: &str) -> anyhow::Result<(&str, &str)> {
let components: Vec<&str> = oci_dir.split_terminator(":").collect();
if components.len() != 2 {
anyhow::bail!("Expected oci_dir in the following format <oci_dir>:<tag> ")
}

Ok((components[0], components[1]))
}

fn main() -> anyhow::Result<()> {
let opts: Opts = Opts::parse();
match opts.subcmd {
SubCommand::Build(b) => {
let rootfs = Path::new(&b.rootfs);
let oci_dir = Path::new(&b.oci_dir);
let (oci_dir, tag) = parse_oci_dir(&b.oci_dir)?;
let oci_dir = Path::new(oci_dir);
let image = Image::new(oci_dir)?;
let new_image = match b.base_layer {
Some(base_layer) => {
let (_desc, image) = if b.compression {
add_rootfs_delta::<Zstd>(rootfs, image, &b.tag, &base_layer)?
add_rootfs_delta::<Zstd>(rootfs, image, tag, &base_layer)?
} else {
add_rootfs_delta::<Noop>(rootfs, image, &b.tag, &base_layer)?
add_rootfs_delta::<Noop>(rootfs, image, tag, &base_layer)?
};
image
}
None => {
if b.compression {
build_initial_rootfs::<Zstd>(rootfs, &image, &b.tag)?
build_initial_rootfs::<Zstd>(rootfs, &image, tag)?
} else {
build_initial_rootfs::<Noop>(rootfs, &image, &b.tag)?
build_initial_rootfs::<Noop>(rootfs, &image, tag)?
};
Arc::new(image)
}
};
let mut manifest_fd = new_image.get_image_manifest_fd(&b.tag)?;
let mut manifest_fd = new_image.get_image_manifest_fd(tag)?;
let mut read_buffer = Vec::new();
manifest_fd.read_to_end(&mut read_buffer)?;
let manifest_digest = get_fs_verity_digest(&read_buffer)?;
Expand All @@ -191,7 +197,8 @@ fn main() -> anyhow::Result<()> {
init_syslog(log_level)?;
}

let oci_dir = Path::new(&m.oci_dir);
let (oci_dir, tag) = parse_oci_dir(&m.oci_dir)?;
let oci_dir = Path::new(oci_dir);
let oci_dir = fs::canonicalize(oci_dir)?;
let image = Image::open(&oci_dir)?;
let mountpoint = Path::new(&m.mountpoint);
Expand All @@ -213,7 +220,7 @@ fn main() -> anyhow::Result<()> {
let named_pipe = m.init_pipe.map(PathBuf::from);
let result = spawn_mount(
image,
&m.tag,
tag,
&mountpoint,
&m.options.unwrap_or_default(),
named_pipe.clone().map(PipeDescriptor::NamedPipe),
Expand Down Expand Up @@ -244,7 +251,7 @@ fn main() -> anyhow::Result<()> {

if let Err(e) = mount_background(
image,
&m.tag,
tag,
&mountpoint,
m.options,
manifest_verity,
Expand All @@ -262,14 +269,16 @@ fn main() -> anyhow::Result<()> {
Ok(())
}
SubCommand::Extract(e) => {
let (oci_dir, tag) = parse_oci_dir(&e.oci_dir)?;
init_logging("info");
extract_rootfs(&e.oci_dir, &e.tag, &e.extract_dir)
extract_rootfs(oci_dir, tag, &e.extract_dir)
}
SubCommand::EnableFsVerity(v) => {
let oci_dir = Path::new(&v.oci_dir);
let (oci_dir, tag) = parse_oci_dir(&v.oci_dir)?;
let oci_dir = Path::new(oci_dir);
let oci_dir = fs::canonicalize(oci_dir)?;
let image = Image::open(&oci_dir)?;
enable_fs_verity(image, &v.tag, &v.root_hash)?;
enable_fs_verity(image, tag, &v.root_hash)?;
Ok(())
}
}
Expand Down
8 changes: 4 additions & 4 deletions exe/tests/extract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,18 @@ fn build_and_extract_is_noop() -> anyhow::Result<()> {

// TODO: figure out a better way to do all this osstr stuff...
let oci = dir.path().join("oci");
let mut oci_arg = oci.into_os_string();
oci_arg.push(OsStr::new(":test"));
puzzlefs([
OsStr::new("build"),
ubuntu_rootfs.as_ref(),
oci.as_ref(),
OsStr::new("test"),
oci_arg.as_ref(),
])?;

let extracted = dir.path().join("extracted");
puzzlefs([
OsStr::new("extract"),
oci.as_os_str(),
OsStr::new("test"),
oci_arg.as_os_str(),
extracted.as_os_str(),
])?;
assert!(!dir_diff::is_different(ubuntu_rootfs, extracted).unwrap());
Expand Down
18 changes: 6 additions & 12 deletions exe/tests/verity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,12 +81,9 @@ fn test_fs_verity() -> anyhow::Result<()> {
let rootfs = Path::new("../puzzlefs-lib/src/builder/test/test-1/");

let oci = mount_path.join("oci");
let output = puzzlefs([
OsStr::new("build"),
rootfs.as_ref(),
oci.as_ref(),
OsStr::new("test"),
])?;
let mut oci_arg = oci.clone().into_os_string();
oci_arg.push(OsStr::new(":test"));
let output = puzzlefs([OsStr::new("build"), rootfs.as_ref(), oci_arg.as_ref()])?;

let tokens = output.split_whitespace().collect::<Vec<_>>();

Expand All @@ -101,8 +98,7 @@ fn test_fs_verity() -> anyhow::Result<()> {

puzzlefs([
OsStr::new("enable-fs-verity"),
oci.as_ref(),
OsStr::new("test"),
oci_arg.as_ref(),
OsStr::new(digest),
])?;

Expand All @@ -118,8 +114,7 @@ fn test_fs_verity() -> anyhow::Result<()> {
OsStr::new("-f"),
OsStr::new("-d"),
OsStr::new(RANDOM_DIGEST),
oci.as_ref(),
OsStr::new("test"),
oci_arg.as_ref(),
OsStr::new(&puzzlefs_mountpoint),
]);

Expand All @@ -133,8 +128,7 @@ fn test_fs_verity() -> anyhow::Result<()> {
OsStr::new("mount"),
OsStr::new("-d"),
OsStr::new(digest),
oci.as_ref(),
OsStr::new("test"),
oci_arg.as_ref(),
OsStr::new(&puzzlefs_mountpoint),
])?;

Expand Down

0 comments on commit 24d7d44

Please sign in to comment.