Skip to content

Commit 07faf7d

Browse files
committed
store: Add support for composefs
This is prep for wider usage of it in this project. Like the containers-image: storage, it is only initialized on demand right now. (An obvious next step is to redo things so the ostree storage is also on-demand) - This is hardcoded to SHA512 right now...but we clearly want a way to configure that or maybe we just really default to 512? - We explicitly bridge between the ostree fsverity enablement to the composefs verity enablement - Right now the usage is just a stub but I plan to expose more here Signed-off-by: Colin Walters <[email protected]>
1 parent 88dd963 commit 07faf7d

File tree

3 files changed

+94
-4
lines changed

3 files changed

+94
-4
lines changed

crates/lib/src/cli.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ use ostree::gio;
1919
use ostree_container::store::PrepareResult;
2020
use ostree_ext::composefs::fsverity;
2121
use ostree_ext::composefs::fsverity::FsVerityHashValue;
22+
use ostree_ext::composefs::splitstream::SplitStreamWriter;
2223
use ostree_ext::container as ostree_container;
2324
use ostree_ext::container_utils::ostree_booted;
2425
use ostree_ext::keyfileext::KeyFileExt;
@@ -462,6 +463,8 @@ pub(crate) enum InternalsOpts {
462463
#[clap(allow_hyphen_values = true)]
463464
args: Vec<OsString>,
464465
},
466+
/// Ensure that a composefs repository is initialized
467+
TestComposefs,
465468
/// Loopback device cleanup helper (internal use only)
466469
LoopbackCleanupHelper {
467470
/// Device path to clean up
@@ -1226,6 +1229,18 @@ async fn run_from_opt(opt: Opt) -> Result<()> {
12261229
)
12271230
.await
12281231
}
1232+
InternalsOpts::TestComposefs => {
1233+
// This is a stub to be replaced
1234+
let storage = get_storage().await?;
1235+
let cfs = storage.get_ensure_composefs()?;
1236+
let testdata = b"some test data";
1237+
let testdata_digest = openssl::sha::sha256(testdata);
1238+
let mut w = SplitStreamWriter::new(&cfs, None, Some(testdata_digest));
1239+
w.write_inline(testdata);
1240+
let object = cfs.write_stream(w, Some("testobject"))?.to_hex();
1241+
assert_eq!(object, "5d94ceb0b2bb3a78237e0a74bc030a262239ab5f47754a5eb2e42941056b64cb21035d64a8f7c2f156e34b820802fa51884de2b1f7dc3a41b9878fc543cd9b07");
1242+
Ok(())
1243+
}
12291244
// We don't depend on fsverity-utils today, so re-expose some helpful CLI tools.
12301245
InternalsOpts::Fsverity(args) => match args {
12311246
FsverityOpts::Measure { path } => {

crates/lib/src/store/mod.rs

Lines changed: 71 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,58 @@
11
use std::cell::OnceCell;
22
use std::env;
33
use std::ops::Deref;
4+
use std::sync::Arc;
45

56
use anyhow::{Context, Result};
67
use cap_std_ext::cap_std;
7-
use cap_std_ext::cap_std::fs::Dir;
8+
use cap_std_ext::cap_std::fs::{Dir, DirBuilder, DirBuilderExt as _};
89
use cap_std_ext::dirext::CapStdExtDirExt;
910
use clap::ValueEnum;
1011
use fn_error_context::context;
1112

1213
use ostree_ext::container::OstreeImageReference;
1314
use ostree_ext::keyfileext::KeyFileExt;
14-
use ostree_ext::ostree;
1515
use ostree_ext::sysroot::SysrootLock;
16+
use ostree_ext::{composefs, ostree};
17+
use rustix::fs::Mode;
1618

1719
use crate::lsm;
1820
use crate::spec::ImageStatus;
1921
use crate::utils::deployment_fd;
2022

2123
mod ostree_container;
2224

25+
/// See https://github.com/containers/composefs-rs/issues/159
26+
pub type ComposefsRepository =
27+
composefs::repository::Repository<composefs::fsverity::Sha512HashValue>;
28+
29+
/// Path to the physical root
30+
pub const SYSROOT: &str = "sysroot";
31+
32+
/// The toplevel composefs directory path
33+
pub const COMPOSEFS: &str = "composefs";
34+
pub const COMPOSEFS_MODE: Mode = Mode::from_raw_mode(0o700);
35+
2336
/// The path to the bootc root directory, relative to the physical
2437
/// system root
2538
pub(crate) const BOOTC_ROOT: &str = "ostree/bootc";
2639

2740
pub(crate) struct Storage {
41+
/// Directory holding the physical root
42+
pub physical_root: Dir,
43+
44+
/// The OSTree storage
2845
pub sysroot: SysrootLock,
29-
run: Dir,
46+
/// The composefs storage
47+
pub composefs: OnceCell<Arc<ComposefsRepository>>,
48+
/// The containers-image storage used foR LBIs
3049
imgstore: OnceCell<crate::imgstorage::Storage>,
50+
51+
/// Our runtime state
52+
run: Dir,
53+
54+
/// This is a stub abstraction that tries to hide ostree
55+
/// that we aren't really using right now
3156
pub store: Box<dyn ContainerImageStoreImpl>,
3257
}
3358

@@ -71,12 +96,29 @@ impl Storage {
7196
}),
7297
Err(_) => crate::spec::Store::default(),
7398
};
74-
7599
let store = load(store);
76100

101+
// ostree has historically always relied on
102+
// having ostree -> sysroot/ostree as a symlink in the image to
103+
// make it so that code doesn't need to distinguish between booted
104+
// vs offline target. The ostree code all just looks at the ostree/
105+
// directory, and will follow the link in the booted case.
106+
//
107+
// For composefs we aren't going to do a similar thing, so here
108+
// we need to explicitly distinguish the two and the storage
109+
// here hence holds a reference to the physical root.
110+
let ostree_sysroot_dir = crate::utils::sysroot_dir(&sysroot)?;
111+
let physical_root = if sysroot.is_booted() {
112+
ostree_sysroot_dir.open_dir(SYSROOT)?
113+
} else {
114+
ostree_sysroot_dir
115+
};
116+
77117
Ok(Self {
118+
physical_root,
78119
sysroot,
79120
run,
121+
composefs: Default::default(),
80122
store,
81123
imgstore: Default::default(),
82124
})
@@ -111,6 +153,31 @@ impl Storage {
111153
Ok(self.imgstore.get_or_init(|| imgstore))
112154
}
113155

156+
pub(crate) fn get_ensure_composefs(&self) -> Result<Arc<ComposefsRepository>> {
157+
if let Some(composefs) = self.composefs.get() {
158+
return Ok(Arc::clone(composefs));
159+
}
160+
161+
let mut db = DirBuilder::new();
162+
db.mode(COMPOSEFS_MODE.as_raw_mode());
163+
self.physical_root.ensure_dir_with(COMPOSEFS, &db)?;
164+
165+
let mut composefs =
166+
ComposefsRepository::open_path(&self.physical_root.open_dir(COMPOSEFS)?, ".")?;
167+
168+
// Bootstrap verity off of the ostree state. In practice this means disabled by
169+
// default right now.
170+
let ostree_repo = &self.sysroot.repo();
171+
let ostree_verity = ostree_ext::fsverity::is_verity_enabled(ostree_repo)?;
172+
if !ostree_verity.enabled {
173+
tracing::debug!("Setting insecure mode for composefs repo");
174+
composefs.set_insecure(true);
175+
}
176+
let composefs = Arc::new(composefs);
177+
let r = Arc::clone(self.composefs.get_or_init(|| composefs));
178+
Ok(r)
179+
}
180+
114181
/// Update the mtime on the storage root directory
115182
#[context("Updating storage root mtime")]
116183
pub(crate) fn update_mtime(&self) -> Result<()> {
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
use std assert
2+
use tap.nu
3+
4+
tap begin "composefs integration smoke test"
5+
6+
bootc internals test-composefs
7+
8+
tap ok

0 commit comments

Comments
 (0)