Skip to content

Commit 88ba172

Browse files
committed
install: Support being passed --filesystem with no install config
This fixes a logical bug where for base images that don't have any install configuration at all, we errored out even if we were explicitly passed `--filesystem`. This is just about making it easier to test base images that don't have an install config. Signed-off-by: Colin Walters <[email protected]>
1 parent 36e70da commit 88ba172

File tree

4 files changed

+79
-24
lines changed

4 files changed

+79
-24
lines changed

.github/workflows/ci.yml

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,3 +148,42 @@ jobs:
148148
sudo podman run --rm -ti --privileged --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 \
149149
${image} bootc install to-existing-root
150150
sudo podman run --rm -ti --privileged -v /:/target -v ./usr/bin/bootc:/usr/bin/bootc --pid=host --security-opt label=disable ${image} bootc internal-tests verify-selinux /target/ostree --warn
151+
install-to-existing-root:
152+
name: "Test install-to-existing-root"
153+
needs: [build-c9s]
154+
runs-on: ubuntu-latest
155+
steps:
156+
- name: Download
157+
uses: actions/download-artifact@v4
158+
with:
159+
name: bootc-c9s.tar.zst
160+
- name: Install
161+
run: tar -xvf bootc.tar.zst
162+
- name: Integration tests
163+
run: |
164+
set -xeuo pipefail
165+
# We should be able to install to-existing-root with no install config,
166+
# so we bind mount an empty directory over /usr/lib/bootc/install.
167+
empty=$(mktemp -d)
168+
image=quay.io/centos-bootc/centos-bootc-dev:stream9
169+
sudo podman run --rm -ti --privileged --env RUST_LOG=debug -v /:/target -v /var/lib/containers:/var/lib/containers -v ./usr/bin/bootc:/usr/bin/bootc -v ${empty}:/usr/lib/bootc/install --pid=host --security-opt label=disable \
170+
${image} bootc install to-existing-root
171+
install-to-loopback:
172+
name: "Test install to-disk --via-loopback"
173+
needs: [build-c9s]
174+
runs-on: ubuntu-latest
175+
steps:
176+
- name: Download
177+
uses: actions/download-artifact@v4
178+
with:
179+
name: bootc-c9s.tar.zst
180+
- name: Install
181+
run: tar -xvf bootc.tar.zst
182+
- name: Integration tests
183+
run: |
184+
set -xeuo pipefail
185+
image=quay.io/centos-bootc/centos-bootc-dev:stream9
186+
tmpdisk=$(mktemp -p /var/tmp)
187+
truncate -s 20G ${tmpdisk}
188+
sudo podman run --rm -ti --privileged --env RUST_LOG=debug -v /dev:/dev -v /:/target -v /var/lib/containers:/var/lib/containers -v ./usr/bin/bootc:/usr/bin/bootc --pid=host --security-opt label=disable \
189+
-v ${tmpdisk}:/disk ${image} bootc install to-disk --via-loopback /disk

lib/src/install.rs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -298,7 +298,7 @@ pub(crate) struct State {
298298
#[allow(dead_code)]
299299
pub(crate) config_opts: InstallConfigOpts,
300300
pub(crate) target_imgref: ostree_container::OstreeImageReference,
301-
pub(crate) install_config: config::InstallConfiguration,
301+
pub(crate) install_config: Option<config::InstallConfiguration>,
302302
/// The parsed contents of the authorized_keys (not the file path)
303303
pub(crate) root_ssh_authorized_keys: Option<String>,
304304
}
@@ -515,7 +515,7 @@ impl SourceInfo {
515515
}
516516

517517
pub(crate) fn print_configuration() -> Result<()> {
518-
let mut install_config = config::load_config()?;
518+
let mut install_config = config::load_config()?.unwrap_or_default();
519519
install_config.filter_to_external();
520520
let stdout = std::io::stdout().lock();
521521
serde_json::to_writer(stdout, &install_config).map_err(Into::into)
@@ -1128,7 +1128,11 @@ async fn prepare_install(
11281128
}
11291129

11301130
let install_config = config::load_config()?;
1131-
tracing::debug!("Loaded install configuration");
1131+
if install_config.is_some() {
1132+
tracing::debug!("Loaded install configuration");
1133+
} else {
1134+
tracing::debug!("No install configuration found");
1135+
}
11321136

11331137
// Eagerly read the file now to ensure we error out early if e.g. it doesn't exist,
11341138
// instead of much later after we're 80% of the way through an install.

lib/src/install/baseline.rs

Lines changed: 29 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,15 @@ pub(crate) fn install_create_rootfs(
146146
opts: InstallBlockDeviceOpts,
147147
) -> Result<RootSetup> {
148148
let luks_name = "root";
149+
// Ensure we have a root filesystem upfront
150+
let root_filesystem = opts
151+
.filesystem
152+
.or(state
153+
.install_config
154+
.as_ref()
155+
.and_then(|c| c.filesystem_root())
156+
.and_then(|r| r.fstype))
157+
.ok_or_else(|| anyhow::anyhow!("No root filesystem specified"))?;
149158
// Verify that the target is empty (if not already wiped in particular, but it's
150159
// also good to verify that the wipe worked)
151160
let device = crate::blockdev::list_dev(&opts.device)?;
@@ -296,9 +305,18 @@ pub(crate) fn install_create_rootfs(
296305
};
297306

298307
let base_rootdev = findpart(ROOTPN)?;
299-
let block_setup = state
300-
.install_config
301-
.get_block_setup(opts.block_setup.as_ref().copied())?;
308+
// Use the install configuration to find the block setup, if we have one
309+
let block_setup = if let Some(config) = state.install_config.as_ref() {
310+
config.get_block_setup(opts.block_setup.as_ref().copied())?
311+
} else if opts.filesystem.is_some() {
312+
// Otherwise, if a filesystem is specified then we default to whatever was
313+
// specified via --block-setup, or the default
314+
opts.block_setup.unwrap_or_default()
315+
} else {
316+
// If there was no default filesystem, then there's no default block setup,
317+
// and we need to error out.
318+
anyhow::bail!("No install configuration found, and no filesystem specified")
319+
};
302320
let (rootdev, root_blockdev_kargs) = match block_setup {
303321
BlockSetup::Direct => (base_rootdev, None),
304322
BlockSetup::Tpm2Luks => {
@@ -342,13 +360,6 @@ pub(crate) fn install_create_rootfs(
342360
let boot_uuid = mkfs(bootdev, bootfs_type, Some("boot"), []).context("Initializing /boot")?;
343361

344362
// Initialize rootfs
345-
let root_filesystem = opts
346-
.filesystem
347-
.or(state
348-
.install_config
349-
.filesystem_root()
350-
.and_then(|r| r.fstype))
351-
.ok_or_else(|| anyhow::anyhow!("No root filesystem specified"))?;
352363
let root_uuid = mkfs(&rootdev, root_filesystem, Some("root"), [])?;
353364
let rootarg = format!("root=UUID={root_uuid}");
354365
let bootsrc = format!("UUID={boot_uuid}");
@@ -359,18 +370,18 @@ pub(crate) fn install_create_rootfs(
359370
fstype: MountSpec::AUTO.into(),
360371
options: Some("ro".into()),
361372
};
373+
let install_config_kargs = state
374+
.install_config
375+
.as_ref()
376+
.and_then(|c| c.kargs.as_ref())
377+
.into_iter()
378+
.flatten()
379+
.map(ToOwned::to_owned);
362380
let kargs = root_blockdev_kargs
363381
.into_iter()
364382
.flatten()
365383
.chain([rootarg, RW_KARG.to_string(), bootarg].into_iter())
366-
.chain(
367-
state
368-
.install_config
369-
.kargs
370-
.iter()
371-
.flatten()
372-
.map(ToOwned::to_owned),
373-
)
384+
.chain(install_config_kargs)
374385
.collect::<Vec<_>>();
375386

376387
mount::mount(&rootdev, &rootfs)?;

lib/src/install/config.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,7 @@ impl InstallConfiguration {
153153

154154
#[context("Loading configuration")]
155155
/// Load the install configuration, merging all found configuration files.
156-
pub(crate) fn load_config() -> Result<InstallConfiguration> {
156+
pub(crate) fn load_config() -> Result<Option<InstallConfiguration>> {
157157
const SYSTEMD_CONVENTIONAL_BASES: &[&str] = &["/usr/lib", "/usr/local/lib", "/etc", "/run"];
158158
let fragments = liboverdrop::scan(SYSTEMD_CONVENTIONAL_BASES, "bootc/install", &["toml"], true);
159159
let mut config: Option<InstallConfiguration> = None;
@@ -177,8 +177,9 @@ pub(crate) fn load_config() -> Result<InstallConfiguration> {
177177
config = c.install;
178178
}
179179
}
180-
let mut config = config.ok_or_else(|| anyhow::anyhow!("No bootc/install config found; this operating system must define a default configuration to be installable"))?;
181-
config.canonicalize();
180+
if let Some(config) = config.as_mut() {
181+
config.canonicalize();
182+
}
182183
Ok(config)
183184
}
184185

0 commit comments

Comments
 (0)