Skip to content
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

WIP: kernel-install integration #5097

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions docs/treefile.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,10 @@ It supports the following parameters:
* "modules": Kernel data goes just in `/usr/lib/modules`. Use
this for new systems, and systems that don't need to be upgraded
from very old libostree versions.
* "kernel-install": The system is integrated with `/sbin/kernel-install`
from systemd. You likely want to additionally pair this with configuring `layout=ostree`
in `/usr/lib/kernel/install.conf`, and adding a wrapper script to
`/usr/lib/kernel/install.d/05-rpmostree.install`

* `etc-group-members`: Array of strings, optional: Unix groups in this
list will be stored in `/etc/group` instead of `/usr/lib/group`. Use
Expand Down
19 changes: 16 additions & 3 deletions rpmostree-cxxrs.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,8 @@ class Slice final : private detail::copy_assignable_if<std::is_const<T>::value>
Slice () noexcept;
Slice (T *, std::size_t count) noexcept;

template <typename C> explicit Slice (C &c) : Slice (c.data (), c.size ()) {}

Slice &operator= (const Slice<T> &) &noexcept = default;
Slice &operator= (Slice<T> &&) &noexcept = default;

Expand Down Expand Up @@ -1781,6 +1783,7 @@ struct Treefile final : public ::rust::Opaque
bool get_machineid_compat () const noexcept;
::rust::Vec< ::rust::String> get_etc_group_members () const noexcept;
bool get_boot_location_is_modules () const noexcept;
bool use_kernel_install () const noexcept;
bool get_ima () const noexcept;
::rust::String get_releasever () const noexcept;
::rpmostreecxx::RepoMetadataTarget get_repo_metadata_target () const noexcept;
Expand Down Expand Up @@ -2428,7 +2431,8 @@ extern "C"
::rpmostreecxx::TokioEnterGuard *
rpmostreecxx$cxxbridge1$TokioHandle$enter (::rpmostreecxx::TokioHandle const &self) noexcept;

bool rpmostreecxx$cxxbridge1$script_is_ignored (::rust::Str pkg, ::rust::Str script) noexcept;
bool rpmostreecxx$cxxbridge1$script_is_ignored (::rust::Str pkg, ::rust::Str script,
bool use_kernel_install) noexcept;

::rust::repr::PtrLen
rpmostreecxx$cxxbridge1$testutils_entrypoint (::rust::Vec< ::rust::String> *argv) noexcept;
Expand Down Expand Up @@ -2629,6 +2633,9 @@ extern "C"
bool rpmostreecxx$cxxbridge1$Treefile$get_boot_location_is_modules (
::rpmostreecxx::Treefile const &self) noexcept;

bool rpmostreecxx$cxxbridge1$Treefile$use_kernel_install (
::rpmostreecxx::Treefile const &self) noexcept;

bool rpmostreecxx$cxxbridge1$Treefile$get_ima (::rpmostreecxx::Treefile const &self) noexcept;

void rpmostreecxx$cxxbridge1$Treefile$get_releasever (::rpmostreecxx::Treefile const &self,
Expand Down Expand Up @@ -4637,9 +4644,9 @@ TokioHandle::enter () const noexcept
}

bool
script_is_ignored (::rust::Str pkg, ::rust::Str script) noexcept
script_is_ignored (::rust::Str pkg, ::rust::Str script, bool use_kernel_install) noexcept
{
return rpmostreecxx$cxxbridge1$script_is_ignored (pkg, script);
return rpmostreecxx$cxxbridge1$script_is_ignored (pkg, script, use_kernel_install);
}

void
Expand Down Expand Up @@ -5192,6 +5199,12 @@ Treefile::get_boot_location_is_modules () const noexcept
return rpmostreecxx$cxxbridge1$Treefile$get_boot_location_is_modules (*this);
}

bool
Treefile::use_kernel_install () const noexcept
{
return rpmostreecxx$cxxbridge1$Treefile$use_kernel_install (*this);
}

bool
Treefile::get_ima () const noexcept
{
Expand Down
5 changes: 4 additions & 1 deletion rpmostree-cxxrs.h
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,8 @@ class Slice final : private detail::copy_assignable_if<std::is_const<T>::value>
Slice () noexcept;
Slice (T *, std::size_t count) noexcept;

template <typename C> explicit Slice (C &c) : Slice (c.data (), c.size ()) {}

Slice &operator= (const Slice<T> &) &noexcept = default;
Slice &operator= (Slice<T> &&) &noexcept = default;

Expand Down Expand Up @@ -1558,6 +1560,7 @@ struct Treefile final : public ::rust::Opaque
bool get_machineid_compat () const noexcept;
::rust::Vec< ::rust::String> get_etc_group_members () const noexcept;
bool get_boot_location_is_modules () const noexcept;
bool use_kernel_install () const noexcept;
bool get_ima () const noexcept;
::rust::String get_releasever () const noexcept;
::rpmostreecxx::RepoMetadataTarget get_repo_metadata_target () const noexcept;
Expand Down Expand Up @@ -1971,7 +1974,7 @@ void history_prune ();

::rust::Box< ::rpmostreecxx::TokioHandle> tokio_handle_get () noexcept;

bool script_is_ignored (::rust::Str pkg, ::rust::Str script) noexcept;
bool script_is_ignored (::rust::Str pkg, ::rust::Str script, bool use_kernel_install) noexcept;

void testutils_entrypoint (::rust::Vec< ::rust::String> argv);

Expand Down
4 changes: 1 addition & 3 deletions rust/src/cliwrap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ use std::io::prelude::*;
mod cliutil;
mod dracut;
mod grubby;
mod kernel_install;
mod rpm;
mod yumdnf;
use crate::cxxrsutil::CxxResult;
Expand All @@ -29,7 +28,7 @@ pub const CLIWRAP_DESTDIR: &str = "usr/libexec/rpm-ostree/wrapped";
static WRAPPED_BINARIES: &[&str] = &["usr/bin/rpm", "usr/bin/dracut", "usr/sbin/grubby"];

/// Binaries we will wrap, or create if they don't exist.
static MUSTWRAP_BINARIES: &[&str] = &["usr/bin/yum", "usr/bin/dnf", "usr/bin/kernel-install"];
static MUSTWRAP_BINARIES: &[&str] = &["usr/bin/yum", "usr/bin/dnf"];

#[derive(Debug, PartialEq)]
pub(crate) enum RunDisposition {
Expand Down Expand Up @@ -74,7 +73,6 @@ pub fn entrypoint(args: &[&str]) -> Result<()> {
"yum" | "dnf" => Ok(self::yumdnf::main(host_type, args)?),
"dracut" => Ok(self::dracut::main(args)?),
"grubby" => Ok(self::grubby::main(args)?),
"kernel-install" => Ok(self::kernel_install::main(args)?),
_ => Err(anyhow!("Unknown wrapped binary: {}", name)),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This error is triggered now, I am testing with this container file:

FROM quay.io/fedora/fedora-kinoite:40
ADD target/debug/rpm-ostree /usr/bin/rpm-ostree
RUN echo "layout=ostree" > /usr/lib/kernel/install.conf
RUN cat /usr/lib/kernel/install.conf
RUN rpm-ostree override replace https://koji.fedoraproject.org/koji/buildinfo?buildID=2561864

Trying to workaround that next.

}
} else {
Expand Down
62 changes: 0 additions & 62 deletions rust/src/cliwrap/kernel_install.rs

This file was deleted.

5 changes: 2 additions & 3 deletions rust/src/initramfs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
use crate::cxxrsutil::*;
use anyhow::{anyhow, Context, Result};
use camino::Utf8Path;
use cap_std::fs_utf8::Dir as Utf8Dir;
use cap_std::fs::Dir;
use cap_std::io_lifetimes::AsFilelike;
use cap_std_ext::cap_std;
use cap_std_ext::prelude::CapStdExtCommandExt;
Expand Down Expand Up @@ -185,8 +185,7 @@ pub(crate) fn initramfs_overlay_generate(
}

#[context("Running dracut")]
pub(crate) fn run_dracut(kernel_dir: &str) -> Result<()> {
let root_fs = Utf8Dir::open_ambient_dir("/", cap_std::ambient_authority())?;
pub(crate) fn run_dracut(root_fs: &Dir, kernel_dir: &str) -> Result<()> {
let tmp_dir = tempfile::tempdir()?;
let tmp_initramfs_path = tmp_dir.path().join("initramfs.img");

Expand Down
92 changes: 92 additions & 0 deletions rust/src/kernel_install.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
//! Integration with the systemd-owned /sbin/kernel-install tooling.
//!
//! Note that there's two different phases of kernel handling:
//!
//! - build time
//! - deployment time (owned by ostree)
//!
//! This code is wholly concerned with "build time" today. The
//! "deployment time" logic is owned entirely by ostree.
//!

// SPDX-License-Identifier: Apache-2.0 OR MIT

use std::process::Command;

use anyhow::{Context, Result};
use cap_std::fs::Dir;
use cap_std_ext::cap_std;
use cap_std_ext::dirext::CapStdExtDirExt;
use fn_error_context::context;

/// Parsed by kernel-install and set in the environment
const LAYOUT_VAR: &str = "KERNEL_INSTALL_LAYOUT";
/// The value we expect to find for layout
const LAYOUT_OSTREE: &str = "ostree";
/// What we should emit to skip further processing
const SKIP: u8 = 77;
/// The path to the kernel modules
const MODULES: &str = "usr/lib/modules";
/// The default name for the initramfs.
const INITRAMFS: &str = "initramfs.img";

#[context("Adding kernel")]
fn add(root: &Dir, argv: &[&str]) -> Result<()> {
let mut argv_it = argv.iter().copied();
let Some(kver) = argv_it.next() else {
anyhow::bail!("No kernel version provided");
};
println!("Generating initramfs");
crate::initramfs::run_dracut(root, &kver)?;
println!("Running depmod");
let st = Command::new("depmod")
.args(["-a", kver])
.status()
.context("Invoking depmod")?;
if !st.success() {
anyhow::bail!("Failed to run depmod: {st:?}");
}
Ok(())
}

#[context("Removing kernel")]
fn remove(root: &Dir, kver: &str) -> Result<()> {
let kdir = format!("{MODULES}/{kver}");
let Some(kernel_dir) = root.open_dir_optional(&kdir)? else {
return Ok(());
};
// We generate the initramfs, so remove it if it exists.
kernel_dir.remove_file_optional(INITRAMFS)?;
Ok(())
}

/// Primary entrypoint to `/usr/lib/kernel-install.d/05-rpmostree.install`.
#[context("rpm-ostree kernel-install")]
pub fn main(argv: &[&str]) -> Result<u8> {
let Some(layout) = std::env::var_os(LAYOUT_VAR) else {
return Ok(0);
};
if !matches!(layout.to_str(), Some(LAYOUT_OSTREE)) {
return Ok(0);
}
if !ostree_ext::container_utils::is_ostree_container()? {
eprintln!(
"warning: confused state: {LAYOUT_VAR}={LAYOUT_OSTREE} but not in an ostree container"
);
return Ok(0);
}
let root = &Dir::open_ambient_dir("/", cap_std::ambient_authority())?;
match argv {
["add", rest @ ..] => {
add(root, rest)?;
// In the case of adding a new kernel, we intercept everything else
// today. In the future we can try to ensure we reuse what bits are there.
Ok(SKIP)
}
["remove", kver] => {
remove(root, kver)?;
Ok(0)
}
_ => Ok(0),
}
}
4 changes: 3 additions & 1 deletion rust/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -512,7 +512,7 @@ pub mod ffi {

// scripts.rs
extern "Rust" {
fn script_is_ignored(pkg: &str, script: &str) -> bool;
fn script_is_ignored(pkg: &str, script: &str, use_kernel_install: bool) -> bool;
}

// testutils.rs
Expand Down Expand Up @@ -626,6 +626,7 @@ pub mod ffi {
fn get_machineid_compat(&self) -> bool;
fn get_etc_group_members(&self) -> Vec<String>;
fn get_boot_location_is_modules(&self) -> bool;
fn use_kernel_install(&self) -> bool;
fn get_ima(&self) -> bool;
fn get_releasever(&self) -> String;
fn get_repo_metadata_target(&self) -> RepoMetadataTarget;
Expand Down Expand Up @@ -989,6 +990,7 @@ mod initramfs;
pub(crate) use self::initramfs::*;
mod isolation;
mod journal;
pub mod kernel_install;
pub(crate) use self::journal::*;
mod lockfile;
pub(crate) use self::lockfile::*;
Expand Down
1 change: 1 addition & 0 deletions rust/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ async fn inner_async_main(args: Vec<String>) -> Result<i32> {
match *arg {
// Add custom Rust commands here, and also in `libmain.cxx` if user-visible.
"countme" => rpmostree_rust::countme::entrypoint(args).map(|_| 0),
"kernel-install" => rpmostree_rust::kernel_install::main(args).map(Into::into),
"fix-shadow-perms" => rpmostree_rust::passwd::fix_shadow_perms_entrypoint(args).map(|_| 0),
"cliwrap" => rpmostree_rust::cliwrap::entrypoint(args).map(|_| 0),
// A hidden wrapper to intercept some binaries in RPM scriptlets.
Expand Down
Loading
Loading