Skip to content

Commit 3b41d81

Browse files
authored
Merge pull request #1289 from ckyrouac/to-existing-cleanup
Add alongside-cleanup systemd service
2 parents b1fb35c + b6300d8 commit 3b41d81

File tree

6 files changed

+73
-6
lines changed

6 files changed

+73
-6
lines changed

Makefile

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,13 @@ install:
3737
# Copy dracut and systemd config files
3838
cp -Prf baseimage/dracut $(DESTDIR)$(prefix)/share/doc/bootc/baseimage/dracut
3939
cp -Prf baseimage/systemd $(DESTDIR)$(prefix)/share/doc/bootc/baseimage/systemd
40+
# Install fedora-bootc-destructive-cleanup in fedora derivatives
41+
ID=$$(. /usr/lib/os-release && echo $$ID); \
42+
ID_LIKE=$$(. /usr/lib/os-release && echo $$ID_LIKE); \
43+
if [ "$$ID" = "fedora" ] || [[ "$$ID_LIKE" == *"fedora"* ]]; then \
44+
ln -s ../bootc-destructive-cleanup.service $(DESTDIR)/$(prefix)/lib/systemd/system/multi-user.target.wants/bootc-destructive-cleanup.service; \
45+
install -D -m 0755 -t $(DESTDIR)/$(prefix)/lib/bootc contrib/scripts/fedora-bootc-destructive-cleanup; \
46+
fi
4047

4148
# Run this to also take over the functionality of `ostree container` for example.
4249
# Only needed for OS/distros that have callers invoking `ostree container` and not bootc.
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
#!/bin/bash
2+
# An implementation of --cleanup for bootc installs on Fedora derivatives
3+
4+
set -xeuo pipefail
5+
6+
# Remove all RPMs installed in the physical root (i.e. the previous OS)
7+
mount -o remount,rw /sysroot
8+
rpm -qa --root=/sysroot --dbpath=/usr/lib/sysimage/rpm | xargs rpm -e --root=/sysroot --dbpath=/usr/lib/sysimage/rpm
9+
10+
# Remove all container images (including the one that was used to install)
11+
# Note that this does not remove stopped containers, and so some storage
12+
# may leak. This may change in the future.
13+
mount --bind -o rw /sysroot/var/lib/containers /var/lib/containers
14+
podman system prune --all -f

lib/src/cli.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1154,7 +1154,8 @@ async fn run_from_opt(opt: Opt) -> Result<()> {
11541154
#[cfg(feature = "install-to-disk")]
11551155
InstallOpts::ToDisk(opts) => crate::install::install_to_disk(opts).await,
11561156
InstallOpts::ToFilesystem(opts) => {
1157-
crate::install::install_to_filesystem(opts, false).await
1157+
crate::install::install_to_filesystem(opts, false, crate::install::Cleanup::Skip)
1158+
.await
11581159
}
11591160
InstallOpts::ToExistingRoot(opts) => {
11601161
crate::install::install_to_existing_root(opts).await

lib/src/install.rs

Lines changed: 35 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,8 @@ const BOOT: &str = "boot";
6969
const RUN_BOOTC: &str = "/run/bootc";
7070
/// The default path for the host rootfs
7171
const ALONGSIDE_ROOT_MOUNT: &str = "/target";
72+
/// Global flag to signal the booted system was provisioned via an alongside bootc install
73+
const DESTRUCTIVE_CLEANUP: &str = "bootc-destructive-cleanup";
7274
/// This is an ext4 special directory we need to ignore.
7375
const LOST_AND_FOUND: &str = "lost+found";
7476
/// The filename of the composefs EROFS superblock; TODO move this into ostree
@@ -335,6 +337,11 @@ pub(crate) struct InstallToExistingRootOpts {
335337
#[clap(long)]
336338
pub(crate) acknowledge_destructive: bool,
337339

340+
/// Add the bootc-destructive-cleanup systemd service to delete files from
341+
/// the previous install on first boot
342+
#[clap(long)]
343+
pub(crate) cleanup: bool,
344+
338345
/// Path to the mounted root; this is now not necessary to provide.
339346
/// Historically it was necessary to ensure the host rootfs was mounted at here
340347
/// via e.g. `-v /:/target`.
@@ -1460,7 +1467,11 @@ impl BoundImages {
14601467
}
14611468
}
14621469

1463-
async fn install_to_filesystem_impl(state: &State, rootfs: &mut RootSetup) -> Result<()> {
1470+
async fn install_to_filesystem_impl(
1471+
state: &State,
1472+
rootfs: &mut RootSetup,
1473+
cleanup: Cleanup,
1474+
) -> Result<()> {
14641475
if matches!(state.selinux_state, SELinuxFinalState::ForceTargetDisabled) {
14651476
rootfs.kargs.push("selinux=0".to_string());
14661477
}
@@ -1489,6 +1500,7 @@ async fn install_to_filesystem_impl(state: &State, rootfs: &mut RootSetup) -> Re
14891500
let bound_images = BoundImages::from_state(state).await?;
14901501

14911502
// Initialize the ostree sysroot (repo, stateroot, etc.)
1503+
14921504
{
14931505
let (sysroot, has_ostree, imgstore) = initialize_ostree_root(state, rootfs).await?;
14941506

@@ -1502,9 +1514,16 @@ async fn install_to_filesystem_impl(state: &State, rootfs: &mut RootSetup) -> Re
15021514
&imgstore,
15031515
)
15041516
.await?;
1517+
1518+
if matches!(cleanup, Cleanup::TriggerOnNextBoot) {
1519+
let sysroot_dir = crate::utils::sysroot_dir(&sysroot)?;
1520+
tracing::debug!("Writing {DESTRUCTIVE_CLEANUP}");
1521+
sysroot_dir.atomic_write(format!("etc/{}", DESTRUCTIVE_CLEANUP), b"")?;
1522+
}
1523+
15051524
// We must drop the sysroot here in order to close any open file
15061525
// descriptors.
1507-
}
1526+
};
15081527

15091528
// Run this on every install as the penultimate step
15101529
install_finalize(&rootfs.physical_root_path).await?;
@@ -1570,7 +1589,7 @@ pub(crate) async fn install_to_disk(mut opts: InstallToDiskOpts) -> Result<()> {
15701589
(rootfs, loopback_dev)
15711590
};
15721591

1573-
install_to_filesystem_impl(&state, &mut rootfs).await?;
1592+
install_to_filesystem_impl(&state, &mut rootfs, Cleanup::Skip).await?;
15741593

15751594
// Drop all data about the root except the bits we need to ensure any file descriptors etc. are closed.
15761595
let (root_path, luksdev) = rootfs.into_storage();
@@ -1740,11 +1759,17 @@ fn warn_on_host_root(rootfs_fd: &Dir) -> Result<()> {
17401759
Ok(())
17411760
}
17421761

1762+
pub enum Cleanup {
1763+
Skip,
1764+
TriggerOnNextBoot,
1765+
}
1766+
17431767
/// Implementation of the `bootc install to-filsystem` CLI command.
17441768
#[context("Installing to filesystem")]
17451769
pub(crate) async fn install_to_filesystem(
17461770
opts: InstallToFilesystemOpts,
17471771
targeting_host_root: bool,
1772+
cleanup: Cleanup,
17481773
) -> Result<()> {
17491774
// Gather global state, destructuring the provided options.
17501775
// IMPORTANT: We might re-execute the current process in this function (for SELinux among other things)
@@ -1950,7 +1975,7 @@ pub(crate) async fn install_to_filesystem(
19501975
skip_finalize,
19511976
};
19521977

1953-
install_to_filesystem_impl(&state, &mut rootfs).await?;
1978+
install_to_filesystem_impl(&state, &mut rootfs, cleanup).await?;
19541979

19551980
// Drop all data about the root except the path to ensure any file descriptors etc. are closed.
19561981
drop(rootfs);
@@ -1961,6 +1986,11 @@ pub(crate) async fn install_to_filesystem(
19611986
}
19621987

19631988
pub(crate) async fn install_to_existing_root(opts: InstallToExistingRootOpts) -> Result<()> {
1989+
let cleanup = match opts.cleanup {
1990+
true => Cleanup::TriggerOnNextBoot,
1991+
false => Cleanup::Skip,
1992+
};
1993+
19641994
let opts = InstallToFilesystemOpts {
19651995
filesystem_opts: InstallTargetFilesystemOpts {
19661996
root_path: opts.root_path,
@@ -1975,7 +2005,7 @@ pub(crate) async fn install_to_existing_root(opts: InstallToExistingRootOpts) ->
19752005
config_opts: opts.config_opts,
19762006
};
19772007

1978-
install_to_filesystem(opts, true).await
2008+
install_to_filesystem(opts, true, cleanup).await
19792009
}
19802010

19812011
/// Implementation of `bootc install finalize`.

system-reinstall-bootc/src/podman.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,9 @@ pub(crate) fn reinstall_command(image: &str, ssh_key_file: &str) -> Command {
4444
// The image is always pulled first, so let's avoid requiring the credentials to be baked
4545
// in the image for this check.
4646
"--skip-fetch-check",
47+
// Always enable the systemd service to cleanup the previous install after booting into the
48+
// bootc system for the first time
49+
"--cleanup",
4750
]
4851
.map(String::from)
4952
.to_vec();
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
[Unit]
2+
Description=Cleanup previous the installation after an alongside installation
3+
Documentation=man:bootc(8)
4+
ConditionPathExists=/sysroot/etc/bootc-destructive-cleanup
5+
6+
[Service]
7+
Type=oneshot
8+
ExecStart=/usr/lib/bootc/fedora-bootc-destructive-cleanup
9+
PrivateMounts=true
10+
11+
[Install]
12+
WantedBy=multi-user.target

0 commit comments

Comments
 (0)