Skip to content

Commit

Permalink
add /usr/lib/bootc/kargs.d support
Browse files Browse the repository at this point in the history
Fixes #255. Allows users to
create files within /usr/lib/bootc/kargs.d with kernel arguments. These
arguments can now be applied on a switch, upgrade, or edit.

General process:
- use ostree commit of fetched container image to return
the file tree
- navigate to /usr/lib/bootc/kargs.d
- read each file within the directory
- push the contents of each file (kargs) into a vector containing all
the desired kargs
- pass the kargs to the stage() function

Signed-off-by: Luke Yang <luyang@redhat.com>
  • Loading branch information
lukewarmtemp committed Mar 20, 2024
1 parent 5390a98 commit c31108a
Show file tree
Hide file tree
Showing 2 changed files with 71 additions and 4 deletions.
25 changes: 22 additions & 3 deletions lib/src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -357,6 +357,7 @@ async fn upgrade(opts: UpgradeOpts) -> Result<()> {
}
} else {
let fetched = crate::deploy::pull(sysroot, imgref, opts.quiet).await?;
let mut kargs = crate::deploy::get_kargs(repo, fetched.as_ref())?;
let staged_digest = staged_image.as_ref().map(|s| s.image_digest.as_str());
let fetched_digest = fetched.manifest_digest.as_str();
tracing::debug!("staged: {staged_digest:?}");
Expand All @@ -378,7 +379,12 @@ async fn upgrade(opts: UpgradeOpts) -> Result<()> {
println!("No update available.")
} else {
let osname = booted_deployment.osname();
crate::deploy::stage(sysroot, &osname, &fetched, &spec).await?;
let mut opts = ostree::SysrootDeployTreeOpts::default();
let mut kargs: Vec<&str> = kargs.iter_mut().map(|s| { let s = s.trim(); s }).collect();
kargs.sort();
kargs.dedup();
opts.override_kernel_argv = Some(kargs.as_slice());
crate::deploy::stage(sysroot, &osname, &fetched, &spec, Some(opts)).await?;
changed = true;
if let Some(prev) = booted_image.as_ref() {
if let Some(fetched_manifest) = fetched.get_manifest(repo)? {
Expand Down Expand Up @@ -451,6 +457,7 @@ async fn switch(opts: SwitchOpts) -> Result<()> {
let new_spec = RequiredHostSpec::from_spec(&new_spec)?;

let fetched = crate::deploy::pull(sysroot, &target, opts.quiet).await?;
let mut kargs = crate::deploy::get_kargs(repo, fetched.as_ref())?;

if !opts.retain {
// By default, we prune the previous ostree ref so it will go away after later upgrades
Expand All @@ -464,7 +471,12 @@ async fn switch(opts: SwitchOpts) -> Result<()> {
}

let stateroot = booted_deployment.osname();
crate::deploy::stage(sysroot, &stateroot, &fetched, &new_spec).await?;
let mut opts = ostree::SysrootDeployTreeOpts::default();
let mut kargs: Vec<&str> = kargs.iter_mut().map(|s| { let s = s.trim(); s }).collect();
kargs.sort();
kargs.dedup();
opts.override_kernel_argv = Some(kargs.as_slice());
crate::deploy::stage(sysroot, &stateroot, &fetched, &new_spec, Some(opts)).await?;

Ok(())
}
Expand Down Expand Up @@ -493,11 +505,18 @@ async fn edit(opts: EditOpts) -> Result<()> {
}
let new_spec = RequiredHostSpec::from_spec(&new_host.spec)?;
let fetched = crate::deploy::pull(sysroot, new_spec.image, opts.quiet).await?;
let repo = &sysroot.repo();
let mut kargs = crate::deploy::get_kargs(repo, fetched.as_ref())?;

// TODO gc old layers here

let stateroot = booted_deployment.osname();
crate::deploy::stage(sysroot, &stateroot, &fetched, &new_spec).await?;
let mut opts = ostree::SysrootDeployTreeOpts::default();
let mut kargs: Vec<&str> = kargs.iter_mut().map(|s| { let s = s.trim(); s }).collect();
kargs.sort();
kargs.dedup();
opts.override_kernel_argv = Some(kargs.as_slice());
crate::deploy::stage(sysroot, &stateroot, &fetched, &new_spec, Some(opts)).await?;

Ok(())
}
Expand Down
50 changes: 49 additions & 1 deletion lib/src/deploy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ use ostree_ext::container::store::PrepareResult;
use ostree_ext::ostree;
use ostree_ext::ostree::Deployment;
use ostree_ext::sysroot::SysrootLock;
use ostree_ext::prelude::FileExt;
use ostree_ext::prelude::Cast;
use ostree_ext::prelude::FileEnumeratorExt;

use crate::spec::HostSpec;
use crate::spec::ImageReference;
Expand Down Expand Up @@ -219,16 +222,18 @@ async fn deploy(
stateroot: &str,
image: &ImageState,
origin: &glib::KeyFile,
opts: Option<ostree::SysrootDeployTreeOpts<'_>>,
) -> Result<()> {
let stateroot = Some(stateroot);
let opts = opts.unwrap_or(Default::default());
// Copy to move into thread
let cancellable = gio::Cancellable::NONE;
let _new_deployment = sysroot.stage_tree_with_options(
stateroot,
image.ostree_commit.as_str(),
Some(origin),
merge_deployment,
&Default::default(),
&opts,
cancellable,
)?;
Ok(())
Expand All @@ -253,6 +258,7 @@ pub(crate) async fn stage(
stateroot: &str,
image: &ImageState,
spec: &RequiredHostSpec<'_>,
opts: Option<ostree::SysrootDeployTreeOpts<'_>>,
) -> Result<()> {
let merge_deployment = sysroot.merge_deployment(Some(stateroot));
let origin = origin_from_imageref(spec.image)?;
Expand All @@ -262,6 +268,7 @@ pub(crate) async fn stage(
stateroot,
image,
&origin,
opts,
)
.await?;
crate::deploy::cleanup(sysroot).await?;
Expand Down Expand Up @@ -340,6 +347,47 @@ pub(crate) fn switch_origin_inplace(root: &Dir, imgref: &ImageReference) -> Resu
Ok(newest_deployment)
}

pub fn get_kargs(repo: &ostree::Repo, fetched: &ImageState) -> Result<Vec<String>> {
let cancellable = gio::Cancellable::NONE;
let (fetched_tree, _) = repo.read_commit(fetched.ostree_commit.as_str(), cancellable)?;
let fetched_tree = fetched_tree.resolve_relative_path("/usr/lib/bootc/kargs.d");
let fetched_tree = fetched_tree.downcast::<ostree::RepoFile>().expect("downcast");
match fetched_tree.query_exists(cancellable) {
true => {}
false => {
return Ok(vec![]);
}
}

let mut kargs = vec![];
let queryattrs = "standard::name,standard::type";
let queryflags = gio::FileQueryInfoFlags::NOFOLLOW_SYMLINKS;
let fetched_iter = fetched_tree.enumerate_children(queryattrs, queryflags, cancellable)?;
while let Some(fetched_info) = fetched_iter.next_file(cancellable)? {
let fetched_child = fetched_iter.child(&fetched_info);
let fetched_child = fetched_child.downcast::<ostree::RepoFile>().expect("downcast");
fetched_child.ensure_resolved()?;
let fetched_contents_checksum = fetched_child.checksum();
let f = ostree::Repo::load_file(repo, fetched_contents_checksum.as_str(), cancellable)?;
let file_content = f.0;
let mut buffer = vec![];
let mut reader = ostree_ext::prelude::InputStreamExtManual::into_read(file_content.unwrap());
let _ = std::io::Read::read_to_end(&mut reader, &mut buffer);
let s = std::string::String::from_utf8(buffer)?;
kargs.push(s);
}

let existing_kargs = ostree::KernelArgs::new();
ostree::KernelArgs::append_proc_cmdline(
&existing_kargs,
cancellable,
)?;
let mut existing_kargs = existing_kargs.to_strv().iter().map(|s| { s.as_str().to_string() }).collect();
kargs.append(&mut existing_kargs);

Ok(kargs)
}

#[test]
fn test_switch_inplace() -> Result<()> {
use cap_std::fs::DirBuilderExt;
Expand Down

0 comments on commit c31108a

Please sign in to comment.