Skip to content

Commit 72f9013

Browse files
authored
Merge pull request #648 from cgwalters/kargs-cleanup-2
kargs: A few more minor cleanups and test improvements
2 parents 591e998 + 6000633 commit 72f9013

File tree

1 file changed

+145
-36
lines changed

1 file changed

+145
-36
lines changed

lib/src/kargs.rs

Lines changed: 145 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,24 @@ use serde::Deserialize;
1313

1414
use crate::deploy::ImageState;
1515

16+
/// The kargs.d configuration file.
1617
#[derive(Deserialize)]
1718
#[serde(rename_all = "kebab-case", deny_unknown_fields)]
1819
struct Config {
20+
/// Ordered list of kernel arguments.
1921
kargs: Vec<String>,
22+
/// Optional list of architectures (using the Rust naming conventions);
23+
/// if present and the current architecture doesn't match, the file is skipped.
2024
match_architectures: Option<Vec<String>>,
2125
}
2226

27+
impl Config {
28+
/// Return true if the filename is one we should parse.
29+
fn filename_matches(name: &str) -> bool {
30+
matches!(Utf8Path::new(name).extension(), Some("toml"))
31+
}
32+
}
33+
2334
/// Load and parse all bootc kargs.d files in the specified root, returning
2435
/// a combined list.
2536
pub(crate) fn get_kargs_in_root(d: &Dir, sys_arch: &str) -> Result<Vec<String>> {
@@ -39,7 +50,7 @@ pub(crate) fn get_kargs_in_root(d: &Dir, sys_arch: &str) -> Result<Vec<String>>
3950
let name = name
4051
.to_str()
4152
.ok_or_else(|| anyhow::anyhow!("Invalid non-UTF8 filename: {name:?}"))?;
42-
if !matches!(Utf8Path::new(name).extension(), Some("toml")) {
53+
if !Config::filename_matches(name) {
4354
continue;
4455
}
4556
let buf = d.read_to_string(name)?;
@@ -49,6 +60,47 @@ pub(crate) fn get_kargs_in_root(d: &Dir, sys_arch: &str) -> Result<Vec<String>>
4960
Ok(ret)
5061
}
5162

63+
/// Load kargs.d files from the target ostree commit root
64+
fn get_kargs_from_ostree(
65+
repo: &ostree::Repo,
66+
fetched_tree: &ostree::RepoFile,
67+
sys_arch: &str,
68+
) -> Result<Vec<String>> {
69+
let cancellable = gio::Cancellable::NONE;
70+
let queryattrs = "standard::name,standard::type";
71+
let queryflags = gio::FileQueryInfoFlags::NOFOLLOW_SYMLINKS;
72+
let fetched_iter = fetched_tree.enumerate_children(queryattrs, queryflags, cancellable)?;
73+
let mut ret = Vec::new();
74+
while let Some(fetched_info) = fetched_iter.next_file(cancellable)? {
75+
// only read and parse the file if it is a toml file
76+
let name = fetched_info.name();
77+
let name = if let Some(name) = name.to_str() {
78+
name
79+
} else {
80+
continue;
81+
};
82+
if !Config::filename_matches(name) {
83+
continue;
84+
}
85+
86+
let fetched_child = fetched_iter.child(&fetched_info);
87+
let fetched_child = fetched_child
88+
.downcast::<ostree::RepoFile>()
89+
.expect("downcast");
90+
fetched_child.ensure_resolved()?;
91+
let fetched_contents_checksum = fetched_child.checksum();
92+
let f = ostree::Repo::load_file(repo, fetched_contents_checksum.as_str(), cancellable)?;
93+
let file_content = f.0;
94+
let mut reader =
95+
ostree_ext::prelude::InputStreamExtManual::into_read(file_content.unwrap());
96+
let s = std::io::read_to_string(&mut reader)?;
97+
let parsed_kargs =
98+
parse_kargs_toml(&s, sys_arch).with_context(|| format!("Parsing {name}"))?;
99+
ret.extend(parsed_kargs);
100+
}
101+
Ok(ret)
102+
}
103+
52104
/// Compute the kernel arguments for the new deployment. This starts from the booted
53105
/// karg, but applies the diff between the bootc karg files in /usr/lib/bootc/kargs.d
54106
/// between the booted deployment and the new one.
@@ -86,33 +138,8 @@ pub(crate) fn get_kargs(
86138
return Ok(kargs);
87139
}
88140

89-
let mut remote_kargs: Vec<String> = vec![];
90-
let queryattrs = "standard::name,standard::type";
91-
let queryflags = gio::FileQueryInfoFlags::NOFOLLOW_SYMLINKS;
92-
let fetched_iter = fetched_tree.enumerate_children(queryattrs, queryflags, cancellable)?;
93-
while let Some(fetched_info) = fetched_iter.next_file(cancellable)? {
94-
// only read and parse the file if it is a toml file
95-
let name = fetched_info.name();
96-
if let Some(name) = name.to_str() {
97-
if name.ends_with(".toml") {
98-
let fetched_child = fetched_iter.child(&fetched_info);
99-
let fetched_child = fetched_child
100-
.downcast::<ostree::RepoFile>()
101-
.expect("downcast");
102-
fetched_child.ensure_resolved()?;
103-
let fetched_contents_checksum = fetched_child.checksum();
104-
let f =
105-
ostree::Repo::load_file(repo, fetched_contents_checksum.as_str(), cancellable)?;
106-
let file_content = f.0;
107-
let mut reader =
108-
ostree_ext::prelude::InputStreamExtManual::into_read(file_content.unwrap());
109-
let s = std::io::read_to_string(&mut reader)?;
110-
let mut parsed_kargs =
111-
parse_kargs_toml(&s, sys_arch).with_context(|| format!("Parsing {name}"))?;
112-
remote_kargs.append(&mut parsed_kargs);
113-
}
114-
}
115-
}
141+
// Fetch the kernel arguments from the new root
142+
let remote_kargs = get_kargs_from_ostree(repo, &fetched_tree, sys_arch)?;
116143

117144
// get the diff between the existing and remote kargs
118145
let mut added_kargs: Vec<String> = remote_kargs
@@ -156,6 +183,9 @@ fn parse_kargs_toml(contents: &str, sys_arch: &str) -> Result<Vec<String>> {
156183

157184
#[cfg(test)]
158185
mod tests {
186+
use fn_error_context::context;
187+
use rustix::fd::{AsFd, AsRawFd};
188+
159189
use super::*;
160190

161191
#[test]
@@ -208,6 +238,20 @@ match-architectures = ["x86_64", "aarch64"]
208238
assert!(parse_kargs_toml(test_missing, "x86_64").is_err());
209239
}
210240

241+
#[context("writing test kargs")]
242+
fn write_test_kargs(td: &Dir) -> Result<()> {
243+
td.write(
244+
"usr/lib/bootc/kargs.d/01-foo.toml",
245+
r##"kargs = ["console=tty0", "nosmt"]"##,
246+
)?;
247+
td.write(
248+
"usr/lib/bootc/kargs.d/02-bar.toml",
249+
r##"kargs = ["console=ttyS1"]"##,
250+
)?;
251+
252+
Ok(())
253+
}
254+
211255
#[test]
212256
fn test_get_kargs_in_root() -> Result<()> {
213257
let td = cap_std_ext::cap_tempfile::TempDir::new(cap_std::ambient_authority())?;
@@ -220,18 +264,83 @@ match-architectures = ["x86_64", "aarch64"]
220264
// Non-toml file
221265
td.write("usr/lib/bootc/kargs.d/somegarbage", "garbage")?;
222266
assert_eq!(get_kargs_in_root(&td, "x86_64").unwrap().len(), 0);
223-
td.write(
224-
"usr/lib/bootc/kargs.d/01-foo.toml",
225-
r##"kargs = ["console=tty0", "nosmt"]"##,
226-
)?;
227-
td.write(
228-
"usr/lib/bootc/kargs.d/02-bar.toml",
229-
r##"kargs = ["console=ttyS1"]"##,
230-
)?;
267+
268+
write_test_kargs(&td)?;
231269

232270
let args = get_kargs_in_root(&td, "x86_64").unwrap();
233271
similar_asserts::assert_eq!(args, ["console=tty0", "nosmt", "console=ttyS1"]);
234272

235273
Ok(())
236274
}
275+
276+
#[context("ostree commit")]
277+
fn ostree_commit(
278+
repo: &ostree::Repo,
279+
d: &Dir,
280+
path: &Utf8Path,
281+
ostree_ref: &str,
282+
) -> Result<()> {
283+
let cancellable = gio::Cancellable::NONE;
284+
let txn = repo.auto_transaction(cancellable)?;
285+
286+
let mt = ostree::MutableTree::new();
287+
repo.write_dfd_to_mtree(d.as_fd().as_raw_fd(), path.as_str(), &mt, None, cancellable)
288+
.context("Writing merged filesystem to mtree")?;
289+
290+
let merged_root = repo
291+
.write_mtree(&mt, cancellable)
292+
.context("Writing mtree")?;
293+
let merged_root = merged_root.downcast::<ostree::RepoFile>().unwrap();
294+
let merged_commit = repo
295+
.write_commit(None, None, None, None, &merged_root, cancellable)
296+
.context("Writing commit")?;
297+
repo.transaction_set_ref(None, &ostree_ref, Some(merged_commit.as_str()));
298+
txn.commit(cancellable)?;
299+
Ok(())
300+
}
301+
302+
#[test]
303+
fn test_get_kargs_in_ostree() -> Result<()> {
304+
let cancellable = gio::Cancellable::NONE;
305+
let td = cap_std_ext::cap_tempfile::TempDir::new(cap_std::ambient_authority())?;
306+
307+
td.create_dir("repo")?;
308+
let repo = &ostree::Repo::create_at(
309+
td.as_fd().as_raw_fd(),
310+
"repo",
311+
ostree::RepoMode::Bare,
312+
None,
313+
gio::Cancellable::NONE,
314+
)?;
315+
316+
td.create_dir("rootfs")?;
317+
let test_rootfs = &td.open_dir("rootfs")?;
318+
319+
ostree_commit(repo, &test_rootfs, ".".into(), "testref")?;
320+
// Helper closure to read the kargs
321+
let get_kargs = |sys_arch: &str| -> Result<Vec<String>> {
322+
let rootfs = repo.read_commit("testref", cancellable)?.0;
323+
let rootfs = rootfs.downcast_ref::<ostree::RepoFile>().unwrap();
324+
let fetched_tree = rootfs.resolve_relative_path("/usr/lib/bootc/kargs.d");
325+
let fetched_tree = fetched_tree
326+
.downcast::<ostree::RepoFile>()
327+
.expect("downcast");
328+
if !fetched_tree.query_exists(cancellable) {
329+
return Ok(Default::default());
330+
}
331+
get_kargs_from_ostree(repo, &fetched_tree, sys_arch)
332+
};
333+
334+
// rootfs is empty
335+
assert_eq!(get_kargs("x86_64").unwrap().len(), 0);
336+
337+
test_rootfs.create_dir_all("usr/lib/bootc/kargs.d")?;
338+
write_test_kargs(&test_rootfs).unwrap();
339+
ostree_commit(repo, &test_rootfs, ".".into(), "testref")?;
340+
341+
let args = get_kargs("x86_64").unwrap();
342+
similar_asserts::assert_eq!(args, ["console=tty0", "nosmt", "console=ttyS1"]);
343+
344+
Ok(())
345+
}
237346
}

0 commit comments

Comments
 (0)