1
0
mirror of https://github.com/containers/bootc.git synced 2026-02-05 06:45:13 +01:00

lib: Remove composefs-backend feature gate

While composefs is still experimental, after looking at this
I think the feature gating we're doing has a pretty high "pain:gain"
ratio - in other words, the risk we're mitigating by having it
off is very low.

Since composefs is a focus of development, let's just remove
the feature gate. We have good CI coverage for the non-composefs
case.

Assisted-by: Claude Code (Sonnet 4.5)
Signed-off-by: Colin Walters <walters@verbum.org>
This commit is contained in:
Colin Walters
2025-10-28 08:33:48 -04:00
parent 37fa085be9
commit d42d5b7ade
11 changed files with 5 additions and 104 deletions

View File

@@ -74,13 +74,11 @@ similar-asserts = { workspace = true }
static_assertions = { workspace = true }
[features]
default = ["install-to-disk", "composefs-backend"]
default = ["install-to-disk"]
# This feature enables `bootc install to-disk`, which is considered just a "demo"
# or reference installer; we expect most nontrivial use cases to be using
# `bootc install to-filesystem`.
install-to-disk = []
# Enable support for the composefs native backend
composefs-backend = []
# This featuares enables `bootc internals publish-rhsm-facts` to integrate with
# Red Hat Subscription Manager
rhsm = []

View File

@@ -8,7 +8,6 @@ use fn_error_context::context;
use bootc_blockdev::{Partition, PartitionTable};
use bootc_mount as mount;
#[cfg(any(feature = "composefs-backend", feature = "install-to-disk"))]
use crate::bootc_composefs::boot::mount_esp;
use crate::{discoverable_partition_specification, utils};
@@ -72,7 +71,6 @@ pub(crate) fn install_via_bootupd(
}
#[context("Installing bootloader")]
#[cfg(any(feature = "composefs-backend", feature = "install-to-disk"))]
pub(crate) fn install_systemd_boot(
device: &PartitionTable,
_rootfs: &Utf8Path,

View File

@@ -33,7 +33,6 @@ use schemars::schema_for;
use serde::{Deserialize, Serialize};
use tempfile::tempdir_in;
#[cfg(feature = "composefs-backend")]
use crate::bootc_composefs::{
finalize::{composefs_backend_finalize, get_etc_diff},
rollback::composefs_rollback,
@@ -667,9 +666,7 @@ pub(crate) enum Opt {
#[clap(subcommand)]
#[clap(hide = true)]
Internals(InternalsOpts),
#[cfg(feature = "composefs-backend")]
ComposefsFinalizeStaged,
#[cfg(feature = "composefs-backend")]
/// Diff current /etc configuration versus default
ConfigDiff,
}
@@ -1263,38 +1260,26 @@ async fn run_from_opt(opt: Opt) -> Result<()> {
let root = &Dir::open_ambient_dir("/", cap_std::ambient_authority())?;
match opt {
Opt::Upgrade(opts) => {
#[cfg(feature = "composefs-backend")]
if composefs_booted()?.is_some() {
upgrade_composefs(opts).await
} else {
upgrade(opts).await
}
#[cfg(not(feature = "composefs-backend"))]
upgrade(opts).await
}
Opt::Switch(opts) => {
#[cfg(feature = "composefs-backend")]
if composefs_booted()?.is_some() {
switch_composefs(opts).await
} else {
switch(opts).await
}
#[cfg(not(feature = "composefs-backend"))]
switch(opts).await
}
Opt::Rollback(opts) => {
#[cfg(feature = "composefs-backend")]
if composefs_booted()?.is_some() {
composefs_rollback().await?
} else {
rollback(&opts).await?
}
#[cfg(not(feature = "composefs-backend"))]
rollback(&opts).await?;
if opts.apply {
crate::reboot::reboot()?;
}
@@ -1303,15 +1288,11 @@ async fn run_from_opt(opt: Opt) -> Result<()> {
}
Opt::Edit(opts) => edit(opts).await,
Opt::UsrOverlay => {
#[cfg(feature = "composefs-backend")]
if composefs_booted()?.is_some() {
composefs_usr_overlay()
} else {
usroverlay().await
}
#[cfg(not(feature = "composefs-backend"))]
usroverlay().await
}
Opt::Container(opts) => match opts {
ContainerOpts::Lint {
@@ -1604,10 +1585,8 @@ async fn run_from_opt(opt: Opt) -> Result<()> {
}
},
#[cfg(feature = "composefs-backend")]
Opt::ComposefsFinalizeStaged => composefs_backend_finalize().await,
#[cfg(feature = "composefs-backend")]
Opt::ConfigDiff => get_etc_diff().await,
}
}

View File

@@ -53,7 +53,6 @@ use serde::{Deserialize, Serialize};
#[cfg(feature = "install-to-disk")]
use self::baseline::InstallBlockDeviceOpts;
#[cfg(feature = "composefs-backend")]
use crate::bootc_composefs::{boot::setup_composefs_boot, repo::initialize_composefs_repository};
use crate::boundimage::{BoundImage, ResolvedBoundImage};
use crate::containerenv::ContainerExecutionInfo;
@@ -66,7 +65,6 @@ use crate::task::Task;
use crate::utils::sigpolicy_from_opt;
use bootc_kernel_cmdline::{bytes, utf8, INITRD_ARG_PREFIX, ROOTFLAGS};
use bootc_mount::Filesystem;
#[cfg(feature = "composefs-backend")]
use composefs::fsverity::FsVerityHashValue;
/// The toplevel boot directory
@@ -275,7 +273,6 @@ pub(crate) struct InstallToDiskOpts {
#[clap(flatten)]
#[serde(flatten)]
#[cfg(feature = "composefs-backend")]
pub(crate) composefs_opts: InstallComposefsOpts,
}
@@ -353,7 +350,6 @@ pub(crate) struct InstallToFilesystemOpts {
#[clap(flatten)]
pub(crate) config_opts: InstallConfigOpts,
#[cfg(feature = "composefs-backend")]
#[clap(flatten)]
pub(crate) composefs_opts: InstallComposefsOpts,
}
@@ -388,7 +384,6 @@ pub(crate) struct InstallToExistingRootOpts {
#[clap(default_value = ALONGSIDE_ROOT_MOUNT)]
pub(crate) root_path: Utf8PathBuf,
#[cfg(feature = "composefs-backend")]
#[clap(flatten)]
pub(crate) composefs_opts: InstallComposefsOpts,
}
@@ -431,7 +426,6 @@ pub(crate) struct State {
pub(crate) composefs_required: bool,
// If Some, then --composefs_native is passed
#[cfg(feature = "composefs-backend")]
pub(crate) composefs_options: InstallComposefsOpts,
/// Detected bootloader type for the target system
@@ -562,7 +556,7 @@ impl FromStr for MountSpec {
}
}
#[cfg(all(feature = "install-to-disk", feature = "composefs-backend"))]
#[cfg(feature = "install-to-disk")]
impl InstallToDiskOpts {
pub(crate) fn validate(&self) -> Result<()> {
if !self.composefs_opts.composefs_backend {
@@ -1218,11 +1212,7 @@ async fn verify_target_fetch(
}
fn root_has_uki(root: &Dir) -> Result<bool> {
#[cfg(feature = "composefs-backend")]
return crate::bootc_composefs::boot::container_root_has_uki(root);
#[cfg(not(feature = "composefs-backend"))]
Ok(false)
crate::bootc_composefs::boot::container_root_has_uki(root)
}
/// Preparation for an install; validates and prepares some (thereafter immutable) global state.
@@ -1230,7 +1220,7 @@ async fn prepare_install(
config_opts: InstallConfigOpts,
source_opts: InstallSourceOpts,
target_opts: InstallTargetOpts,
#[cfg(feature = "composefs-backend")] mut composefs_options: InstallComposefsOpts,
mut composefs_options: InstallComposefsOpts,
) -> Result<Arc<State>> {
tracing::trace!("Preparing install");
let rootfs = cap_std::fs::Dir::open_ambient_dir("/", cap_std::ambient_authority())
@@ -1305,7 +1295,6 @@ async fn prepare_install(
tracing::debug!("Composefs required: {composefs_required}");
#[cfg(feature = "composefs-backend")]
if composefs_required {
composefs_options.composefs_backend = true;
}
@@ -1378,7 +1367,6 @@ async fn prepare_install(
// Determine bootloader type for the target system
// Priority: user-specified > bootupd availability > systemd-boot fallback
#[cfg(feature = "composefs-backend")]
let detected_bootloader = {
if let Some(bootloader) = composefs_options.bootloader.clone() {
bootloader
@@ -1390,8 +1378,6 @@ async fn prepare_install(
}
}
};
#[cfg(not(feature = "composefs-backend"))]
let detected_bootloader = crate::spec::Bootloader::Grub;
println!("Bootloader: {detected_bootloader}");
// Create our global (read-only) state which gets wrapped in an Arc
@@ -1410,7 +1396,6 @@ async fn prepare_install(
host_is_container,
composefs_required,
detected_bootloader,
#[cfg(feature = "composefs-backend")]
composefs_options,
});
@@ -1582,7 +1567,6 @@ async fn install_to_filesystem_impl(
}
}
#[cfg(feature = "composefs-backend")]
if state.composefs_options.composefs_backend {
// Load a fd for the mounted target physical root
@@ -1593,9 +1577,6 @@ async fn install_to_filesystem_impl(
ostree_install(state, rootfs, cleanup).await?;
}
#[cfg(not(feature = "composefs-backend"))]
ostree_install(state, rootfs, cleanup).await?;
// Finalize mounted filesystems
if !rootfs.skip_finalize {
let bootfs = rootfs.boot.as_ref().map(|_| ("boot", "boot"));
@@ -1615,7 +1596,6 @@ fn installation_complete() {
#[context("Installing to disk")]
#[cfg(feature = "install-to-disk")]
pub(crate) async fn install_to_disk(mut opts: InstallToDiskOpts) -> Result<()> {
#[cfg(feature = "composefs-backend")]
opts.validate()?;
// Log the disk installation operation to systemd journal
@@ -1664,7 +1644,6 @@ pub(crate) async fn install_to_disk(mut opts: InstallToDiskOpts) -> Result<()> {
opts.config_opts,
opts.source_opts,
opts.target_opts,
#[cfg(feature = "composefs-backend")]
opts.composefs_opts,
)
.await?;
@@ -1902,7 +1881,6 @@ pub(crate) async fn install_to_filesystem(
opts.config_opts,
opts.source_opts,
opts.target_opts,
#[cfg(feature = "composefs-backend")]
opts.composefs_opts,
)
.await?;
@@ -2174,7 +2152,6 @@ pub(crate) async fn install_to_existing_root(opts: InstallToExistingRootOpts) ->
source_opts: opts.source_opts,
target_opts: opts.target_opts,
config_opts: opts.config_opts,
#[cfg(feature = "composefs-backend")]
composefs_opts: opts.composefs_opts,
};

View File

@@ -4,7 +4,6 @@
//! to provide a fully "container native" tool for using
//! bootable container images.
#[cfg(feature = "composefs-backend")]
mod bootc_composefs;
pub(crate) mod bootc_kargs;
mod bootloader;

View File

@@ -27,7 +27,6 @@ use linkme::distributed_slice;
use ostree_ext::ostree_prepareroot;
use serde::Serialize;
#[cfg(feature = "composefs-backend")]
use crate::bootc_composefs::boot::EFI_LINUX;
/// Reference to embedded default baseimage content that should exist.
@@ -770,7 +769,6 @@ fn check_boot(root: &Dir, config: &LintExecutionConfig) -> LintResult {
})
.collect();
let mut entries = entries?;
#[cfg(feature = "composefs-backend")]
{
// Work around https://github.com/containers/composefs-rs/issues/131
let efidir = Utf8Path::new(EFI_LINUX)

View File

@@ -11,7 +11,6 @@ use ostree_ext::{container::OstreeImageReference, oci_spec};
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
#[cfg(feature = "composefs-backend")]
use crate::bootc_composefs::boot::BootType;
use crate::{k8sapitypes, status::Slot};
@@ -201,7 +200,6 @@ impl FromStr for Bootloader {
/// A bootable entry
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
#[serde(rename_all = "camelCase")]
#[cfg(feature = "composefs-backend")]
pub struct BootEntryComposefs {
/// The erofs verity
pub verity: String,
@@ -232,7 +230,6 @@ pub struct BootEntry {
/// If this boot entry is ostree based, the corresponding state
pub ostree: Option<BootEntryOstree>,
/// If this boot entry is composefs based, the corresponding state
#[cfg(feature = "composefs-backend")]
pub composefs: Option<BootEntryComposefs>,
}
@@ -305,7 +302,6 @@ impl Host {
}
}
#[cfg(feature = "composefs-backend")]
pub(crate) fn require_composefs_booted(&self) -> anyhow::Result<&BootEntryComposefs> {
let cfs = self
.status
@@ -588,7 +584,6 @@ mod tests {
pinned: false,
store: None,
ostree: None,
#[cfg(feature = "composefs-backend")]
composefs: None,
}
}

View File

@@ -19,7 +19,6 @@ use ostree_ext::sysroot::SysrootLock;
use ostree_ext::ostree;
#[cfg(feature = "composefs-backend")]
use crate::bootc_composefs::status::{composefs_booted, composefs_deployment_status};
use crate::cli::OutputFormat;
use crate::spec::ImageStatus;
@@ -210,7 +209,6 @@ fn boot_entry_from_deployment(
deploy_serial: deployment.deployserial().try_into().unwrap(),
stateroot: deployment.stateroot().into(),
}),
#[cfg(feature = "composefs-backend")]
composefs: None,
};
Ok(r)
@@ -340,7 +338,6 @@ pub(crate) fn get_status(
Ok((deployments, host))
}
#[cfg(feature = "composefs-backend")]
async fn get_host() -> Result<Host> {
let host = if ostree_booted()? {
let sysroot = super::cli::get_storage().await?;
@@ -357,21 +354,6 @@ async fn get_host() -> Result<Host> {
Ok(host)
}
#[cfg(not(feature = "composefs-backend"))]
async fn get_host() -> Result<Host> {
let host = if ostree_booted()? {
let sysroot = super::cli::get_storage().await?;
let ostree = sysroot.get_ostree()?;
let booted_deployment = ostree.booted_deployment();
let (_deployments, host) = get_status(&ostree, booted_deployment.as_ref())?;
host
} else {
Default::default()
};
Ok(host)
}
/// Implementation of the `bootc status` CLI command.
#[context("Status")]
pub(crate) async fn status(opts: super::cli::StatusOpts) -> Result<()> {
@@ -515,7 +497,6 @@ fn human_render_slot(
writeln!(out, "{digest} ({arch})")?;
// Write the EROFS verity if present
#[cfg(feature = "composefs-backend")]
if let Some(composefs) = &entry.composefs {
write_row_name(&mut out, "Verity", prefix_len)?;
writeln!(out, "{}", composefs.verity)?;
@@ -622,7 +603,6 @@ fn human_render_slot_ostree(
}
/// Output a rendering of a non-container composefs boot entry.
#[cfg(feature = "composefs-backend")]
fn human_render_slot_composefs(
mut out: impl Write,
slot: Slot,
@@ -657,7 +637,6 @@ fn human_readable_output_booted(mut out: impl Write, host: &Host, verbose: bool)
writeln!(out)?;
}
#[cfg(feature = "composefs-backend")]
if let Some(image) = &host_status.image {
human_render_slot(&mut out, Some(slot_name), host_status, image, verbose)?;
} else if let Some(ostree) = host_status.ostree.as_ref() {
@@ -673,21 +652,6 @@ fn human_readable_output_booted(mut out: impl Write, host: &Host, verbose: bool)
} else {
writeln!(out, "Current {slot_name} state is unknown")?;
}
#[cfg(not(feature = "composefs-backend"))]
if let Some(image) = &host_status.image {
human_render_slot(&mut out, Some(slot_name), host_status, image, verbose)?;
} else if let Some(ostree) = host_status.ostree.as_ref() {
human_render_slot_ostree(
&mut out,
Some(slot_name),
host_status,
&ostree.checksum,
verbose,
)?;
} else {
writeln!(out, "Current {slot_name} state is unknown")?;
}
}
}

View File

@@ -37,7 +37,6 @@ use crate::utils::deployment_fd;
/// See https://github.com/containers/composefs-rs/issues/159
pub type ComposefsRepository =
composefs::repository::Repository<composefs::fsverity::Sha512HashValue>;
#[cfg(feature = "composefs-backend")]
pub type ComposefsFilesystem = composefs::tree::FileSystem<composefs::fsverity::Sha512HashValue>;
/// Path to the physical root

View File

@@ -1,7 +1,6 @@
use std::future::Future;
use std::io::Write;
use std::os::fd::BorrowedFd;
#[cfg(feature = "composefs-backend")]
use std::path::{Component, Path, PathBuf};
use std::process::Command;
use std::time::Duration;
@@ -202,7 +201,6 @@ pub(crate) fn digested_pullspec(image: &str, digest: &str) -> String {
format!("{image}@{digest}")
}
#[cfg(feature = "composefs-backend")]
#[derive(Debug)]
pub enum EfiError {
SystemNotUEFI,
@@ -213,14 +211,12 @@ pub enum EfiError {
Io(std::io::Error),
}
#[cfg(feature = "composefs-backend")]
impl From<std::io::Error> for EfiError {
fn from(e: std::io::Error) -> Self {
EfiError::Io(e)
}
}
#[cfg(feature = "composefs-backend")]
pub fn read_uefi_var(var_name: &str) -> Result<String, EfiError> {
use crate::install::EFIVARFS;
use cap_std_ext::cap_std::ambient_authority;
@@ -262,7 +258,6 @@ pub fn read_uefi_var(var_name: &str) -> Result<String, EfiError> {
/// Computes a relative path from `from` to `to`.
///
/// Both `from` and `to` must be absolute paths.
#[cfg(feature = "composefs-backend")]
pub(crate) fn path_relative_to(from: &Path, to: &Path) -> Result<PathBuf> {
if !from.is_absolute() || !to.is_absolute() {
anyhow::bail!("Paths must be absolute");
@@ -321,7 +316,6 @@ mod tests {
}
#[test]
#[cfg(feature = "composefs-backend")]
fn test_relative_path() {
let from = Path::new("/sysroot/state/deploy/image_id");
let to = Path::new("/sysroot/state/os/default/var");

View File

@@ -9,7 +9,7 @@ Tracking issue: <https://github.com/bootc-dev/bootc/issues/1190>
The composefs backend is an experimental alternative storage backend that uses [composefs-rs](https://github.com/containers/composefs-rs) instead of ostree for storing and managing bootc system deployments.
**Status**: Experimental. The composefs backend is under active development and not yet suitable for production use. The feature is currently gated behind the `composefs-backend` compile-time feature flag, which in current git main is enabled by default.
**Status**: Experimental. The composefs backend is under active development and not yet suitable for production use. The feature is always compiled in as of bootc v1.10.1.
## Key Benefits