-
Notifications
You must be signed in to change notification settings - Fork 129
Initial implementation for /etc merge #1485
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: composefs-backend
Are you sure you want to change the base?
Initial implementation for /etc merge #1485
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code Review
This pull request introduces a new crate etc-merge
for calculating differences between /etc
directories. The initial implementation provides a compute_diff
function and related helpers. My review focuses on correctness issues, such as a typo in a key data structure and an incomplete hashing function that misses file permissions. I've also pointed out an unused variable that indicates incomplete logic, and suggested improvements to test data and assertions for better maintainability.
crates/etc-merge/src/lib.rs
Outdated
assert_eq!(res.added.len(), new_files.len()); | ||
assert!(res.added.iter().all(|file| new_files | ||
.iter() | ||
.find(|x| PathBuf::from(*x) == *file) | ||
.is_some())); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This assertion logic is a bit complex. A simpler and more idiomatic way to compare two collections for equality regardless of order is to sort them and then compare the sorted collections. This pattern is repeated for modified and removed files as well.
assert_eq!(res.added.len(), new_files.len()); | |
assert!(res.added.iter().all(|file| new_files | |
.iter() | |
.find(|x| PathBuf::from(*x) == *file) | |
.is_some())); | |
let mut res_added = res.added; | |
res_added.sort(); | |
let mut expected_added: Vec<_> = new_files.iter().map(PathBuf::from).collect(); | |
expected_added.sort(); | |
assert_eq!(res_added, expected_added); |
ede5599
to
37d6b19
Compare
I've tested the output of this implementation with |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
General question, not something specific about this PR (this looks great BTW!)
Would Bootc's ostree backend be refactored to make use of this crate in time, or is the plan for ostree to remain mostly separate? Obviously the implementation would be completely separate PR to this anyway.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a good question indeed. I've been really tempted to basically vendor+rewrite some of the ostree-sysroot stuff in this project. However, it has a ton of implications.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for working on this!
crates/etc-merge/src/lib.rs
Outdated
let mut buf = vec![0u8; entry.metadata()?.size() as usize]; | ||
|
||
let mut file = entry.open().context(format!("Opening entry {path:?}"))?; | ||
file.read_exact(&mut buf) | ||
.context(format!("Reading {path:?}. Buf: {buf:?}"))?; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Two key things here. First I think we should incremental hashing instead of reading the whole thing into memory and then hashing the memory buffer.
But second a nice optimization to make here is handling the case where the file has fsverity enabled. Then we can efficiently just query its fsverity hash to do a diff.
It won't be the default for files in a mutable /etc
to have fsverity enabled but it makes sense to do so (dir is mutable, so the write-tmpfile-then-rename pattern continues to work) and we should make things faster for those who do use it.
37d6b19
to
3d6c8c3
Compare
crates/etc-merge/src/lib.rs
Outdated
|
||
path.pop(); | ||
|
||
// file has fs-verity enabled. We don't need to check the content/metadata |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note that fsverity only covers file contents, not metadata. It's totally allowed to do e.g. chmod
or chown
on such a file...which we probably want to have tracked as modified right?
Eh sorry...I guess maybe this fsverity suggestion is adding too much complexity at the moment for a non-default corner case.
Let's I guess just leave it as a // TODO consider also using fsverity here if available
?
7d596fe
to
d9b384d
Compare
dc635c5
to
0faabae
Compare
Signed-off-by: Johan-Liebert1 <[email protected]>
Test for whether the file has fs-verity enabled or not, and if it does we simply check the verity. Incrementally compute hash for files rather than reading the entire file in memory. Signed-off-by: Johan-Liebert1 <[email protected]>
Signed-off-by: Johan-Liebert1 <[email protected]>
Signed-off-by: Johan-Liebert1 <[email protected]>
Signed-off-by: Johan-Liebert1 <[email protected]>
Merge added, modified, removed files from the current etc into the new etc directory, following the rules 1. If file is removed from current_etc, it will be removed from new_etc 2. If file is modified in current_etc, it will be copied to the new_etc overwriting any existing files 3. If a file is added in current_etc, then the above modification rule applies Modification includes change in content/permissions. Changed in Xattrs and/or ownership is not handled yet. Signed-off-by: Johan-Liebert1 <[email protected]>
Signed-off-by: Johan-Liebert1 <[email protected]>
Signed-off-by: Johan-Liebert1 <[email protected]>
b2f05a1
to
eafc75f
Compare
Signed-off-by: Johan-Liebert1 <[email protected]>
eafc75f
to
f1c87a7
Compare
Hmm... tests failed because we can't chown unless we're root. And some issue with |
Yeah, some of this stuff really needs privileged integration tests, not unit tests. In the short term what I think is easiest is to add an option to the core logic to ignore uid/gid + xattrs and that's what we do in unit tests. For integration tests what we have in some other places is exposing the core functionality via Line 1237 in 8ed1134
(actually that's not so good an example because the command hardcodes the test, which bloats production binaries) This one is maybe a bit better: Line 1291 in 8ed1134
There's the tests-integration crate which is also intended to hold stuff like this. |
Signed-off-by: Johan-Liebert1 <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ugh I reviewed but forgot to click submit
composefs = { git = "https://github.com/containers/composefs-rs", rev = "28d4721f77f973f0e394d60d6a69d9b39cb38d7f", package = "composefs", features = ["rhel9"] } | ||
composefs-boot = { git = "https://github.com/containers/composefs-rs", rev = "28d4721f77f973f0e394d60d6a69d9b39cb38d7f", package = "composefs-boot" } | ||
composefs-oci = { git = "https://github.com/containers/composefs-rs", rev = "28d4721f77f973f0e394d60d6a69d9b39cb38d7f", package = "composefs-oci" } | ||
composefs = { git = "https://github.com/containers/composefs-rs", rev = "8d1e570275621531d39b8f01681584bcc85ce01c", package = "composefs", features = ["rhel9"] } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In order to reduce conflicts let's do separate PRs for bumping crate dependencies.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done in #1503
Very initial iteration for
/etc
merge