Skip to content

Commit f7b41cc

Browse files
committed
cli: Fix switch --mutate-in-place to work outside booted environment
Move the --mutate-in-place handling before get_storage() so it doesn't require a fully booted ostree environment. This enables use cases like Anaconda where we're chrooted into a non-booted system. Closes: #1854 Assisted-by: OpenCode (claude-sonnet-4-20250514) Signed-off-by: Colin Walters <walters@verbum.org>
1 parent 39b64e1 commit f7b41cc

File tree

4 files changed

+50
-19
lines changed

4 files changed

+50
-19
lines changed

crates/lib/src/cli.rs

Lines changed: 17 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1206,31 +1206,29 @@ async fn switch_ostree(
12061206
/// Implementation of the `bootc switch` CLI command.
12071207
#[context("Switching")]
12081208
async fn switch(opts: SwitchOpts) -> Result<()> {
1209+
// If we're doing an in-place mutation, we shortcut most of the rest of the work here
1210+
// TODO: what we really want here is Storage::detect_from_root() that also handles
1211+
// composefs. But for now this just assumes ostree.
1212+
if opts.mutate_in_place {
1213+
let target = imgref_for_switch(&opts)?;
1214+
let deployid = {
1215+
// Clone to pass into helper thread
1216+
let target = target.clone();
1217+
let root = cap_std::fs::Dir::open_ambient_dir("/", cap_std::ambient_authority())?;
1218+
tokio::task::spawn_blocking(move || {
1219+
crate::deploy::switch_origin_inplace(&root, &target)
1220+
})
1221+
.await??
1222+
};
1223+
println!("Updated {deployid} to pull from {target}");
1224+
return Ok(());
1225+
}
12091226
let storage = &get_storage().await?;
12101227
match storage.kind()? {
12111228
BootedStorageKind::Ostree(booted_ostree) => {
1212-
// If we're doing an in-place mutation, we shortcut most of the rest of the work here
1213-
if opts.mutate_in_place {
1214-
let target = imgref_for_switch(&opts)?;
1215-
let deployid = {
1216-
// Clone to pass into helper thread
1217-
let target = target.clone();
1218-
let root =
1219-
cap_std::fs::Dir::open_ambient_dir("/", cap_std::ambient_authority())?;
1220-
tokio::task::spawn_blocking(move || {
1221-
crate::deploy::switch_origin_inplace(&root, &target)
1222-
})
1223-
.await??
1224-
};
1225-
println!("Updated {deployid} to pull from {target}");
1226-
return Ok(());
1227-
}
12281229
switch_ostree(opts, storage, &booted_ostree).await
12291230
}
12301231
BootedStorageKind::Composefs(booted_cfs) => {
1231-
if opts.mutate_in_place {
1232-
anyhow::bail!("--mutate-in-place is not yet supported for composefs backend");
1233-
}
12341232
switch_composefs(opts, storage, &booted_cfs).await
12351233
}
12361234
}

tmt/plans/integration.fmf

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,4 +140,11 @@ execute:
140140
how: fmf
141141
test:
142142
- /tmt/tests/tests/test-31-switch-to-unified
143+
144+
/plan-31-switch-mutate-in-place:
145+
summary: switch --mutate-in-place
146+
discover:
147+
how: fmf
148+
test:
149+
- /tmt/tests/tests/test-31-switch-mutate-in-place
143150
# END GENERATED PLANS
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# number: 31
2+
# tmt:
3+
# summary: switch --mutate-in-place
4+
# duration: 30m
5+
#
6+
use std assert
7+
use tap.nu
8+
use bootc_testlib.nu
9+
10+
# See https://github.com/bootc-dev/bootc/issues/1854
11+
12+
let st = bootc status --json | from json
13+
let is_composefs = ($st.status.booted.composefs? != null)
14+
if not $is_composefs {
15+
# This is aiming to reproduce an environment closer to the Anaconda case
16+
# where we're chrooted into a non-booted system. TODO: What we really want
17+
# is to add `bootc switch --sysroot` too.
18+
mv /run/ostree-booted /run/ostree-booted.orig
19+
unshare -m /bin/sh -c 'mount -o remount,rw /sysroot && bootc switch --mutate-in-place quay.io/nosuchimage/image-to-test-switch'
20+
tap ok
21+
}

tmt/tests/tests.fmf

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,3 +74,8 @@
7474
summary: Onboard to unified storage, build derived image, and switch to it
7575
duration: 30m
7676
test: nu booted/test-switch-to-unified.nu
77+
78+
/test-31-switch-mutate-in-place:
79+
summary: switch --mutate-in-place
80+
duration: 30m
81+
test: nu booted/test-switch-mutate-in-place.nu

0 commit comments

Comments
 (0)