Skip to content
Open
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
22 changes: 17 additions & 5 deletions crates/initramfs/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,7 @@ fn overlay_state(
state: impl AsFd,
source: &str,
mode: Option<rustix::fs::Mode>,
mount_attr_flags: Option<MountAttrFlags>,
) -> Result<()> {
let upper = ensure_dir(state.as_fd(), "upper", mode)?;
let work = ensure_dir(state.as_fd(), "work", mode)?;
Expand All @@ -230,16 +231,26 @@ fn overlay_state(
let fs = fsmount(
overlayfs.as_fd(),
FsMountFlags::FSMOUNT_CLOEXEC,
MountAttrFlags::empty(),
mount_attr_flags.unwrap_or(MountAttrFlags::empty()),
)?;

mount_at_wrapper(fs, base, ".").context("Moving mount")
}

/// Mounts a transient overlayfs with passed in fd as the lowerdir
#[context("Mounting transient overlayfs")]
pub fn overlay_transient(base: impl AsFd, mode: Option<rustix::fs::Mode>) -> Result<()> {
overlay_state(base, prepare_mount(mount_tmpfs()?)?, "transient", mode)
pub fn overlay_transient(
base: impl AsFd,
mode: Option<rustix::fs::Mode>,
mount_attr_flags: Option<MountAttrFlags>,
) -> Result<()> {
overlay_state(
base,
prepare_mount(mount_tmpfs()?)?,
"transient",
mode,
mount_attr_flags,
)
}

#[context("Opening rootfs")]
Expand Down Expand Up @@ -307,8 +318,9 @@ pub fn mount_subdir(
open_dir(&state, subdir)?,
"overlay",
None,
None,
),
MountType::Transient => overlay_transient(open_dir(&new_root, subdir)?, None),
MountType::Transient => overlay_transient(open_dir(&new_root, subdir)?, None, None),
}
}

Expand Down Expand Up @@ -371,7 +383,7 @@ pub fn setup_root(args: Args) -> Result<()> {
}

if config.root.transient {
overlay_transient(&new_root, None)?;
overlay_transient(&new_root, None, None)?;
}

match composefs::mount::mount_at(&sysroot_clone, &new_root, "sysroot") {
Expand Down
12 changes: 9 additions & 3 deletions crates/lib/src/bootc_composefs/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ use ostree_ext::container::deploy::ORIGIN_CONTAINER;
use rustix::{
fd::AsFd,
fs::{Mode, OFlags, StatVfsMountFlags, open},
mount::MountAttrFlags,
path::Arg,
};

Expand Down Expand Up @@ -329,7 +330,7 @@ pub(crate) async fn write_composefs_state(
Ok(())
}

pub(crate) fn composefs_usr_overlay() -> Result<()> {
pub(crate) fn composefs_usr_overlay(access_mode: FilesystemOverlayAccessMode) -> Result<()> {
let status = get_composefs_usr_overlay_status()?;
if status.is_some() {
println!("An overlayfs is already mounted on /usr");
Expand All @@ -342,9 +343,14 @@ pub(crate) fn composefs_usr_overlay() -> Result<()> {
let usr_metadata = usr.metadata(".").context("Getting /usr metadata")?;
let usr_mode = Mode::from_raw_mode(usr_metadata.permissions().mode());

overlay_transient(usr, Some(usr_mode))?;
let mount_attr_flags = match access_mode {
FilesystemOverlayAccessMode::ReadOnly => Some(MountAttrFlags::MOUNT_ATTR_RDONLY),
FilesystemOverlayAccessMode::ReadWrite => None,
};

println!("A writeable overlayfs is now mounted on /usr");
overlay_transient(usr, Some(usr_mode), mount_attr_flags)?;

println!("A {} overlayfs is now mounted on /usr", access_mode);
println!("All changes there will be discarded on reboot.");

Ok(())
Expand Down
39 changes: 29 additions & 10 deletions crates/lib/src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ use crate::bootc_composefs::{
use crate::deploy::{MergeState, RequiredHostSpec};
use crate::podstorage::set_additional_image_store;
use crate::progress_jsonl::{ProgressWriter, RawProgressFd};
use crate::spec::FilesystemOverlayAccessMode;
use crate::spec::Host;
use crate::spec::ImageReference;
use crate::status::get_host;
Expand Down Expand Up @@ -261,6 +262,16 @@ pub(crate) struct StatusOpts {
pub(crate) verbose: bool,
}

/// Add a transient overlayfs on /usr
#[derive(Debug, Parser, PartialEq, Eq)]
pub(crate) struct UsrOverlayOpts {
/// Mount the overlayfs as read-only. A read-only overlayfs is useful since it may be remounted
/// as read/write in a private mount namespace and written to while the mount point remains
/// read-only to the rest of the system.
#[clap(long)]
pub(crate) read_only: bool,
}

#[derive(Debug, clap::Subcommand, PartialEq, Eq)]
pub(crate) enum InstallOpts {
/// Install to the target block device.
Expand Down Expand Up @@ -741,11 +752,11 @@ pub(crate) enum Opt {
///
/// Shows bootc system state. Outputs YAML by default, human-readable if terminal detected.
Status(StatusOpts),
/// Add a transient writable overlayfs on `/usr`.
/// Add a transient overlayfs on `/usr`.
///
/// Allows temporary package installation that will be discarded on reboot.
#[clap(alias = "usroverlay")]
UsrOverlay,
UsrOverlay(UsrOverlayOpts),
/// Install the running container to a target.
///
/// Takes a container image and installs it to disk in a bootable format.
Expand Down Expand Up @@ -1402,13 +1413,16 @@ async fn edit(opts: EditOpts) -> Result<()> {
}

/// Implementation of `bootc usroverlay`
async fn usroverlay() -> Result<()> {
async fn usroverlay(access_mode: FilesystemOverlayAccessMode) -> Result<()> {
// This is just a pass-through today. At some point we may make this a libostree API
// or even oxidize it.
Err(Command::new("ostree")
.args(["admin", "unlock"])
.exec()
.into())
let args = match access_mode {
// In this context, "--transient" means "read-only overlay"
FilesystemOverlayAccessMode::ReadOnly => ["admin", "unlock", "--transient"].as_slice(),

FilesystemOverlayAccessMode::ReadWrite => ["admin", "unlock"].as_slice(),
};
Comment on lines +1419 to +1424
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

This match statement can be simplified into an if/else expression to make it more concise.

Suggested change
let args = match access_mode {
// In this context, "--transient" means "read-only overlay"
FilesystemOverlayAccessMode::ReadOnly => ["admin", "unlock", "--transient"].as_slice(),
FilesystemOverlayAccessMode::ReadWrite => ["admin", "unlock"].as_slice(),
};
let args: &[&str] = if access_mode == FilesystemOverlayAccessMode::ReadOnly {
// In this context, "--transient" means "read-only overlay"
&["admin", "unlock", "--transient"]
} else {
&["admin", "unlock"]
};

Err(Command::new("ostree").args(args).exec().into())
}

/// Perform process global initialization. This should be called as early as possible
Expand Down Expand Up @@ -1519,12 +1533,17 @@ async fn run_from_opt(opt: Opt) -> Result<()> {
Ok(())
}
Opt::Edit(opts) => edit(opts).await,
Opt::UsrOverlay => {
Opt::UsrOverlay(opts) => {
use crate::store::Environment;
let env = Environment::detect()?;
let access_mode = if opts.read_only {
FilesystemOverlayAccessMode::ReadOnly
} else {
FilesystemOverlayAccessMode::ReadWrite
};
match env {
Environment::OstreeBooted => usroverlay().await,
Environment::ComposefsBooted(_) => composefs_usr_overlay(),
Environment::OstreeBooted => usroverlay(access_mode).await,
Environment::ComposefsBooted(_) => composefs_usr_overlay(access_mode),
_ => anyhow::bail!("usroverlay only applies on booted hosts"),
}
}
Expand Down
62 changes: 61 additions & 1 deletion docs/src/host-v1.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@
"rollback": null,
"rollbackQueued": false,
"staged": null,
"type": null
"type": null,
"usrOverlay": null
}
}
},
Expand Down Expand Up @@ -220,6 +221,54 @@
}
]
},
"FilesystemOverlay": {
"description": "Details of an overlay filesystem: read-only or read/write, persistent or transient.",
"type": "object",
"properties": {
"accessMode": {
"description": "Whether the overlay is read-only or read/write",
"$ref": "#/$defs/FilesystemOverlayAccessMode"
},
"persistence": {
"description": "Whether the overlay will persist across reboots",
"$ref": "#/$defs/FilesystemOverlayPersistence"
}
},
"required": [
"accessMode",
"persistence"
]
},
"FilesystemOverlayAccessMode": {
"description": "The permissions mode of a /usr overlay",
"oneOf": [
{
"description": "The overlay is mounted read-only",
"type": "string",
"const": "readOnly"
},
{
"description": "The overlay is mounted read/write",
"type": "string",
"const": "readWrite"
}
]
},
"FilesystemOverlayPersistence": {
"description": "The persistence mode of a /usr overlay",
"oneOf": [
{
"description": "Changes are temporary and will be lost on reboot",
"type": "string",
"const": "transient"
},
{
"description": "Changes persist across reboots",
"type": "string",
"const": "persistent"
}
]
},
"HostSpec": {
"description": "The host specification",
"type": "object",
Expand Down Expand Up @@ -301,6 +350,17 @@
"type": "null"
}
]
},
"usrOverlay": {
"description": "The state of the overlay mounted on /usr",
"anyOf": [
{
"$ref": "#/$defs/FilesystemOverlay"
},
{
"type": "null"
}
]
}
}
},
Expand Down
4 changes: 4 additions & 0 deletions docs/src/man/bootc-container-ukify.8.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ Any additional arguments after `--` are passed through to ukify unchanged.

Default: /

**--allow-missing-verity**

Make fs-verity validation optional in case the filesystem doesn't support it

<!-- END GENERATED OPTIONS -->

# EXAMPLES
Expand Down
2 changes: 1 addition & 1 deletion docs/src/man/bootc-install-to-disk.8.md
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ its DPS type GUID, without requiring an explicit `root=` kernel argument.

Default: false

**--insecure**
**--allow-missing-verity**

Make fs-verity validation optional in case the filesystem doesn't support it

Expand Down
2 changes: 1 addition & 1 deletion docs/src/man/bootc-install-to-existing-root.8.md
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,7 @@ of migrating the fstab entries. See the "Injecting kernel arguments" section abo

Default: false

**--insecure**
**--allow-missing-verity**

Make fs-verity validation optional in case the filesystem doesn't support it

Expand Down
2 changes: 1 addition & 1 deletion docs/src/man/bootc-install-to-filesystem.8.md
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ is currently expected to be empty by default.

Default: false

**--insecure**
**--allow-missing-verity**

Make fs-verity validation optional in case the filesystem doesn't support it

Expand Down
14 changes: 10 additions & 4 deletions docs/src/man/bootc-usr-overlay.8.md
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
# NAME

bootc-usr-overlay - Adds a transient writable overlayfs on `/usr` that
will be discarded on reboot
bootc-usr-overlay - Adds a transient overlayfs on `/usr` that will be discarded
on reboot

# SYNOPSIS

**bootc usr-overlay** \[*OPTIONS...*\]
Copy link
Collaborator

Choose a reason for hiding this comment

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

just update-generated should resync the new options

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done in a separate commit


# DESCRIPTION

Adds a transient writable overlayfs on `/usr` that will be discarded
on reboot.
Adds a transient overlayfs on `/usr` that will be discarded on reboot. The
overlayfs is read/write by default.

## USE CASES

Expand All @@ -31,7 +31,13 @@ Almost always, a system process will hold a reference to the open mount
point. You can however invoke `umount -l /usr` to perform a "lazy
unmount".

# OPTIONS

<!-- BEGIN GENERATED OPTIONS -->
**--read-only**

Mount the overlayfs as read-only. A read-only overlayfs is useful since it may be remounted as read/write in a private mount namespace and written to while the mount point remains read-only to the rest of the system

<!-- END GENERATED OPTIONS -->

# VERSION
Expand Down
2 changes: 1 addition & 1 deletion docs/src/man/bootc.8.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ pulled and `bootc upgrade`.
| **bootc rollback** | Change the bootloader entry ordering; the deployment under `rollback` will be queued for the next boot, and the current will become rollback. If there is a `staged` entry (an unapplied, queued upgrade) then it will be discarded |
| **bootc edit** | Apply full changes to the host specification |
| **bootc status** | Display status |
| **bootc usr-overlay** | Add a transient writable overlayfs on `/usr` |
| **bootc usr-overlay** | Add a transient overlayfs on `/usr` |
| **bootc install** | Install the running container to a target |
| **bootc container** | Operations which can be executed as part of a container build |
| **bootc composefs-finalize-staged** | |
Expand Down
9 changes: 8 additions & 1 deletion tmt/plans/integration.fmf
Original file line number Diff line number Diff line change
Expand Up @@ -182,8 +182,15 @@ execute:
test:
- /tmt/tests/tests/test-34-user-agent

/plan-35-upgrade-preflight-disk-check:
Copy link
Collaborator

Choose a reason for hiding this comment

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

not a huge deal but I think these tmt/* changes belong in the previous commit that adds the test code

summary: Verify pre-flight disk space check rejects images with inflated layer sizes
discover:
how: fmf
test:
- /tmt/tests/tests/test-35-upgrade-preflight-disk-check
Copy link
Collaborator

Choose a reason for hiding this comment

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

I think this might have been a bad rebase? I believe this should point to the new test-usroverlay.nu file from the previous commit

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Hmm, just tried just update-generated again over f8eef4a and got an identical diff. Maybe update-generated was not run after #2022 or #1995?

Copy link
Collaborator

Choose a reason for hiding this comment

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

Yeah we have #1891 to hopefully gate on update-generated so we don't continue getting into this state where things are out of date. Known problem unfortunately ☹️


/plan-36-rollback:
summary: Test bootc rollback functionality through image switch and rollback cycle
summary: Test bootc rollback functionality
discover:
how: fmf
test:
Expand Down
Loading
Loading