-
Notifications
You must be signed in to change notification settings - Fork 14
Allow passing absolute paths to initrd and vmlinuz #121
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
Allow passing absolute paths to initrd and vmlinuz #121
Conversation
8d44bd2
to
7115f34
Compare
Not by default, but we definitely can to be clear. |
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.
Per previous debate overall I just really do not like this idea of mutating bootloader entries shipped in the image and would prefer that we generate them client side. This logic would need to fundamentally change for that (and look more similar to what kernel-install
and ostree
to today).
But from my PoV that isn't blocking experimentation.
src/bootloader.rs
Outdated
// the file into the given 'entry_id' pathname and rename the entry file itself to | ||
// "{entry_id}.conf". | ||
pub fn relocate(&mut self, entry_id: &str) { | ||
pub fn relocate(&mut self, entry_id: &str, abs_entry_path: Option<&str>) -> Result<()> { |
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.
I think it'd be more consistent if this was Option<&Path>
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.
Yeah, std::Path
would've been a better choice here. Unsure why we went with &str
, maybe because of Rust shenanigans? @allisonkarlitskaya
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.
It's because it's a string in the boot loader file, which is the thing that causes us to go fetch these files in the first place. It's not possible for us to have non-utf8 boot resources...
resisting camino urges intensifies
src/bootloader.rs
Outdated
let new = format!("/{entry_id}/{basename}"); | ||
let new_entry_path = Path::new(&new); |
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.
Except yeah, above we have a string and so...this is where camino makes sense. It's honestly also one of the reasons I just ended up strictly denying non-UTF8 filenames in ostree, dealing with it is just a giant pain and there's so many file formats which reference filenames that just don't support non-UTF8 filenames, or would be extremely awkward to do.
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.
The first patch should absolutely just go in as-is. That's clearly an oversight on my part. We might even add the relocation step to the write_type1 function to save a bit of repetition (which is what ultimately led to the bug).
For the second one, I think the issue here is that it's not clear what "bootdir" refers to. Up to now (in my brain, at least) bootdir was one thing: the root of the boot partition. Now we have the possibility of not having a separate boot partition but rather /boot/ inside of another partition. I think this is a violation of the bootloader spec, but let's set that aside.
How about we rather do something like having two parameters:
- an absolute path to the partition which contains the boot stuff
- an optional relative path to the boot directory within that partition
So for a bootc system this would look like "/sysroot"
and Some("boot")
respectively. For the examples it would look like "/boot"
and None
.
That would allow us to:
- properly locate our
loader/entries/
directory - properly place our boot resources inside of a subdir
- properly refer to those boot resources in our loader entry file relative to the root of the partition
- not have any redundancy in the path components we provide
src/bootloader.rs
Outdated
// the file into the given 'entry_id' pathname and rename the entry file itself to | ||
// "{entry_id}.conf". | ||
pub fn relocate(&mut self, entry_id: &str) { | ||
pub fn relocate(&mut self, entry_id: &str, abs_entry_path: Option<&str>) -> Result<()> { |
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.
It's because it's a string in the boot loader file, which is the thing that causes us to go fetch these files in the first place. It's not possible for us to have non-utf8 boot resources...
resisting camino urges intensifies
That sort of thing requires a citation, so here we go:
https://uapi-group.org/specifications/specs/boot_loader_specification/ |
Yes, the status quo with at least Fedora derivatives using grub and ostree (at least) is that it isn't set up matching the BLS. That's 100% something we'd like to fix (ostreedev/ostree#3359 is one notable ingredient). |
7115f34
to
57e3a8d
Compare
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.
I'm very sorry. I thought I posted this review earlier today. It's the same as we discussed on matrix, though...
src/write_boot.rs
Outdated
/// * entry_id - In case of a BLS entry, the name of file to be generated in `loader/entries` | ||
/// * boot_subdir - If `Some(path)`, the path is prepended to `initrd` and `linux` keys in the BLS entry | ||
/// | ||
/// For example, if `boot_subdir = Some("/boot/1")` and `boot_partition = "/boot"`, |
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.
I think this is what I was trying to avoid.
I rather think that in this case we'd have:
boot_partition
:/boot
boot_subdir
:Some("1")
So in the BLS-compliant case where the boot directory is rooted in its own filesystem, we'd pass None
for boot_subdir
. We should think about this less in terms of mechanics like ("prepended to paths in the entry file") and more about what the user sees in terms of their config.
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.
But again, we want absolute "boot" path. If the "boot" dir is mounted at /run/bootc/mounts/rootfs/boot
we have no way of knowing what the "final" absolute path is going to be. It could be /rootfs/boot
or it could just be /boot
, and this is the crux of the issue.
I didn't like the idea of just assuming that the "final" directory in the boot_partition
will be the actual one.
b92ace4
to
ea4d3a7
Compare
/// * entry_id - In case of a BLS entry, the name of file to be generated in `loader/entries` | ||
/// * boot_subdir - If `Some(path)`, the path is prepended to `initrd` and `linux` keys in the BLS entry | ||
/// | ||
/// For example, if `boot_subdir = Some("/boot/1")` and `boot_partition = "/boot"`, |
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.
The repetition of /boot
is the thing that I'm objecting to. The path to the files contained in the entry should consist of concatenating boot_partition + boot_subdir + entry_id. I think we should talk about this in a call :)
Signed-off-by: Pragyan Poudyal <[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.
Looking better thanks, but I think with the args defined the way that they are defined now, we don't need to make things so complicated...
// the file into the given 'entry_id' pathname and rename the entry file itself to | ||
// "{entry_id}.conf". | ||
pub fn relocate(&mut self, entry_id: &str) { | ||
pub fn relocate(&mut self, entry_id: &str, boot_subdir: Option<&str>) -> Result<()> { |
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.
Same nags as before: try to keep these in the order that they get pasted back together... so when they appear, they are always in the order of: boot_partition, boot_subdir, entry_id.
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.
Also: with the arguments defined as they are now, I don't think this function needs to be failable anymore...
|
||
let final_path = if let Some(boot_subdir) = boot_subdir { | ||
Path::new(boot_subdir) | ||
.join(new_entry_path.strip_prefix("/").unwrap_or(new_entry_path)) | ||
} else { | ||
new_entry_path.to_path_buf() | ||
}; | ||
|
||
let final_path = final_path | ||
.to_str() | ||
.ok_or_else(|| anyhow!("Failed to convert Path '{final_path:?}' to string"))?; | ||
|
||
line.replace_range(range, final_path); |
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 seems really too complicated. Should just be something like:
let new = match boot_subdir {
Some(subdir) => format!("/{subdir}/{entry_id}/{basename}"),
None => format!("/{entry_id}/{basename}"),
};
or so, no?
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.
So, new
here is where the loader file is created relative to the /boot directory and final is the final concatenated path in the loader/entries/<entry_id>
They have to be separate
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.
The naming is what's weird here :)
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.
ah sure. I failed to notice that we use new
for both things. But even still, you could let new_entry_path = match ...
as per the previous comment, no?
bootdir: &Path, | ||
boot_partition: &Path, | ||
entry_id: Option<&str>, | ||
boot_subdir: Option<&str>, |
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.
Order again: boot_partition, boot_subdir, entry_id.
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 correct, no?
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.
Yes. I think I wrote that to a previous iteration.
t1.relocate(name, boot_subdir)?; | ||
} | ||
write_t1_simple(t1, bootdir, root_id, cmdline_extra, repo)?; | ||
write_t1_simple(t1, boot_partition, root_id, cmdline_extra, repo)?; |
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.
Feels like that's gonna fail? boot_partition.join(boot_subdir), no? Or just pass both arguments through.
You might actually consider doing the relocation inside of the write code as well (it would reduce a small amount of duplication).
It might also pay to get gibbity to write some tests for you... |
2cc49ea
to
49ab4c8
Compare
// the file into the given 'entry_id' pathname and rename the entry file itself to | ||
// "{entry_id}.conf". | ||
pub fn relocate(&mut self, entry_id: &str) { | ||
pub fn relocate(&mut self, boot_subdir: Option<&str>, entry_id: &str) -> Result<()> { |
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.
Drop the Result<()> please
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.
my bad, forgot to remove after refactor
bootdir: &Path, | ||
boot_partition: &Path, | ||
entry_id: Option<&str>, | ||
boot_subdir: Option<&str>, |
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.
Yes. I think I wrote that to a previous iteration.
let final_entry_path = if let Some(boot_subdir) = boot_subdir { | ||
format!("/{boot_subdir}{new}") | ||
} else { | ||
new.clone() |
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.
I guess you could just move (and duplicate) the line.replace_range()
into the if to avoid the clone if it bothers you ;)
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.
duplication bothers me a bit more than a String clone :)
49ab4c8
to
47e5df8
Compare
Grub needs absolute paths to initrd and vmlinuz if we do not have `/boot` in a boot partition, which we do not in bootc. Add param `boot_subdir` which acts like a subdirectory in the boot directory in case the boot partition is mounted in another directory. Signed-off-by: Pragyan Poudyal <[email protected]>
47e5df8
to
f8f9323
Compare
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 all the iterations. Looks good now!
Grub needs absolute paths to initrd and vmlinuz if we do not have
/boot
in a boot partition, which we do not in bootc.