Skip to content

install: Add to-existing-root #382

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

Merged
merged 1 commit into from
Mar 9, 2024
Merged
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
3 changes: 1 addition & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -143,6 +143,5 @@ jobs:
sudo chattr -i /ostree/deploy/default/deploy/*
sudo rm /ostree/deploy/default -rf
sudo podman run --rm -ti --privileged --env BOOTC_SKIP_SELINUX_HOST_CHECK=1 --env RUST_LOG=debug -v /:/target -v /var/lib/containers:/var/lib/containers -v ./usr/bin/bootc:/usr/bin/bootc --pid=host --security-opt label=disable \
quay.io/centos-bootc/centos-bootc-dev:stream9 bootc install to-filesystem \
--replace=alongside /target
quay.io/centos-bootc/centos-bootc-dev:stream9 bootc install to-existing-root
sudo ls -ldZ / /ostree/deploy/default/deploy/* /ostree/deploy/default/deploy/*/etc
20 changes: 15 additions & 5 deletions docs/src/bootc-install.md
Original file line number Diff line number Diff line change
@@ -225,7 +225,7 @@ podman run --rm --privileged --pid=host --security-opt label=type:unconfined_t

Notice that we use `--generic-image` for this use case.

### Using `bootc install to-filesystem --replace=alongside`
### Using `bootc install to-existing-root`

This is a variant of `install to-filesystem`, which maximizes convenience for using
an existing Linux system, converting it into the target container image. Note that
@@ -241,13 +241,23 @@ The core command should look like this (root/elevated permission required):
podman run --rm --privileged -v /var/lib/containers:/var/lib/containers -v /:/target \
--pid=host --security-opt label=type:unconfined_t \
<image> \
bootc install to-filesystem --replace=alongside /target
bootc install to-existing-root
```

At the current time, leftover data in `/` is **NOT** automatically cleaned up. This can
It is assumed in this command that the target rootfs is pased via `-v /:/target` at this time.

As noted above, the data in `/boot` will be wiped, but everything else in the existing
operating `/` is **NOT** automatically cleaned up. This can
be useful, because it allows the new image to automatically import data from the previous
host system! For example, things like SSH keys or container images can be copied
and then deleted from the original.
host system! For example, container images, database, user home directory data, config
files in `/etc` are all available after the subsequent reboot in `/sysroot` (which
is the "physical root").

A special case of this trick is using the `--root-ssh-authorized-keys` flag to inherit
root's SSH keys (which may have been injected from e.g. cloud instance userdata
via a tool like `cloud-init`). To do this, just add
`--root-ssh-authorized-keys /target/root/.ssh/authorized_keys`
to the above.

### Using `bootc install to-filesystem --source-imgref <imgref>`

4 changes: 4 additions & 0 deletions lib/src/cli.rs
Original file line number Diff line number Diff line change
@@ -118,6 +118,7 @@ pub(crate) enum InstallOpts {
ToDisk(crate::install::InstallToDiskOpts),
/// Install to the target filesystem
ToFilesystem(crate::install::InstallToFilesystemOpts),
ToExistingRoot(crate::install::InstallToExistingRootOpts),
/// Output JSON to stdout that contains the merged installation configuration
/// as it may be relevant to calling processes using `install to-filesystem`
/// that want to honor e.g. `root-fs-type`.
@@ -533,6 +534,9 @@ async fn run_from_opt(opt: Opt) -> Result<()> {
Opt::Install(opts) => match opts {
InstallOpts::ToDisk(opts) => crate::install::install_to_disk(opts).await,
InstallOpts::ToFilesystem(opts) => crate::install::install_to_filesystem(opts).await,
InstallOpts::ToExistingRoot(opts) => {
crate::install::install_to_existing_root(opts).await
}
InstallOpts::PrintConfiguration => crate::install::print_configuration(),
},
#[cfg(feature = "install")]
38 changes: 38 additions & 0 deletions lib/src/install.rs
Original file line number Diff line number Diff line change
@@ -249,6 +249,28 @@ pub(crate) struct InstallToFilesystemOpts {
pub(crate) config_opts: InstallConfigOpts,
}

/// Perform an installation to the host root filesystem.
#[derive(Debug, Clone, clap::Parser)]
pub(crate) struct InstallToExistingRootOpts {
/// Configure how existing data is treated.
#[clap(long, default_value = "alongside")]
pub(crate) replace: Option<ReplaceMode>,

#[clap(flatten)]
pub(crate) source_opts: InstallSourceOpts,

#[clap(flatten)]
pub(crate) target_opts: InstallTargetOpts,

#[clap(flatten)]
pub(crate) config_opts: InstallConfigOpts,

/// Path to the mounted root; it's expected to invoke podman with
/// `-v /:/target`, then supplying this argument is unnecessary.
#[clap(default_value = "/target")]
pub(crate) root_path: Utf8PathBuf,
}

/// Global state captured from the container.
#[derive(Debug, Clone)]
pub(crate) struct SourceInfo {
@@ -1355,6 +1377,22 @@ pub(crate) async fn install_to_filesystem(opts: InstallToFilesystemOpts) -> Resu
Ok(())
}

pub(crate) async fn install_to_existing_root(opts: InstallToExistingRootOpts) -> Result<()> {
let opts = InstallToFilesystemOpts {
filesystem_opts: InstallTargetFilesystemOpts {
root_path: opts.root_path,
root_mount_spec: None,
boot_mount_spec: None,
replace: opts.replace,
},
source_opts: opts.source_opts,
target_opts: opts.target_opts,
config_opts: opts.config_opts,
};

install_to_filesystem(opts).await
}

#[test]
fn install_opts_serializable() {
let c: InstallToDiskOpts = serde_json::from_value(serde_json::json!({
2 changes: 1 addition & 1 deletion tests/integration/playbooks/install.yaml
Original file line number Diff line number Diff line change
@@ -72,7 +72,7 @@
-v /var/lib/containers:/var/lib/containers \
--security-opt label=type:unconfined_t \
{{ test_image_url }} \
bootc install to-filesystem --replace=alongside /target"
bootc install to-existing-root"
become: true

- name: Reboot to deploy new system