Skip to content

Commit a3708d0

Browse files
committed
to-disk: Fix cross-device link errors with AlmaLinux and similar images
Closes: #125 Switch to bind-mounting /var/tmp from the outer VM into the inner podman container. I think we fixed this in newer bootc, but this ensures compatibility with older versions. Also add AlmaLinux to the test matrix and creates a parameterized integration test that validates to-disk works across all supported bootc images. Deduplicates disk validation logic into a shared helper function. Assisted-by: Claude Code (Sonnet 4.5) Signed-off-by: Colin Walters <walters@verbum.org>
1 parent d870f45 commit a3708d0

3 files changed

Lines changed: 90 additions & 42 deletions

File tree

Justfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
PRIMARY_IMAGE := "quay.io/centos-bootc/centos-bootc:stream10"
2-
ALL_BASE_IMAGES := "quay.io/fedora/fedora-bootc:42 quay.io/centos-bootc/centos-bootc:stream9 quay.io/centos-bootc/centos-bootc:stream10"
2+
ALL_BASE_IMAGES := "quay.io/fedora/fedora-bootc:42 quay.io/centos-bootc/centos-bootc:stream9 quay.io/centos-bootc/centos-bootc:stream10 quay.io/almalinuxorg/almalinux-bootc:9.6"
33

44
# Build the native binary
55
build:

crates/integration-tests/src/tests/to_disk.rs

Lines changed: 87 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -16,38 +16,27 @@
1616
1717
use camino::Utf8PathBuf;
1818
use color_eyre::Result;
19-
use integration_tests::integration_test;
19+
use integration_tests::{integration_test, parameterized_integration_test};
2020
use linkme::distributed_slice;
2121

2222
use std::process::Command;
2323
use tempfile::TempDir;
2424

25-
use crate::{get_test_image, run_bcvk, INTEGRATION_TEST_LABEL};
26-
27-
/// Test actual bootc installation to a disk image
28-
fn test_to_disk() -> Result<()> {
29-
let temp_dir = TempDir::new().expect("Failed to create temp directory");
30-
let disk_path = Utf8PathBuf::try_from(temp_dir.path().join("test-disk.img"))
31-
.expect("temp path is not UTF-8");
32-
33-
let output = run_bcvk(&[
34-
"to-disk",
35-
"--label",
36-
INTEGRATION_TEST_LABEL,
37-
&get_test_image(),
38-
disk_path.as_str(),
39-
])?;
40-
41-
assert!(
42-
output.success(),
43-
"to-disk failed with exit code: {:?}. stdout: {}, stderr: {}",
44-
output.exit_code(),
45-
output.stdout,
46-
output.stderr
47-
);
48-
49-
let metadata = std::fs::metadata(&disk_path).expect("Failed to get disk metadata");
50-
assert!(metadata.len() > 0);
25+
use crate::{get_test_image, run_bcvk, CapturedOutput, INTEGRATION_TEST_LABEL};
26+
27+
/// Validate that a disk image was created successfully with proper bootc installation
28+
///
29+
/// This helper function verifies:
30+
/// - The disk image file exists and has non-zero size
31+
/// - The disk has valid partition table (using sfdisk)
32+
/// - The installation completed successfully (from output messages)
33+
fn validate_disk_image(
34+
disk_path: &Utf8PathBuf,
35+
output: &CapturedOutput,
36+
context: &str,
37+
) -> Result<()> {
38+
let metadata = std::fs::metadata(disk_path).expect("Failed to get disk metadata");
39+
assert!(metadata.len() > 0, "{}: Disk image is empty", context);
5140

5241
// Verify the disk has partitions using sfdisk -l
5342
let sfdisk_output = Command::new("sfdisk")
@@ -60,14 +49,16 @@ fn test_to_disk() -> Result<()> {
6049

6150
assert!(
6251
sfdisk_output.status.success(),
63-
"sfdisk failed with exit code: {:?}",
52+
"{}: sfdisk failed with exit code: {:?}",
53+
context,
6454
sfdisk_output.status.code()
6555
);
6656

6757
assert!(
6858
sfdisk_stdout.contains("Disk ")
6959
&& (sfdisk_stdout.contains("sectors") || sfdisk_stdout.contains("bytes")),
70-
"sfdisk output doesn't show expected disk information"
60+
"{}: sfdisk output doesn't show expected disk information",
61+
context
7162
);
7263

7364
let has_partitions = sfdisk_stdout.lines().any(|line| {
@@ -76,15 +67,43 @@ fn test_to_disk() -> Result<()> {
7667

7768
assert!(
7869
has_partitions,
79-
"No bootc partitions found in sfdisk output. Output was:\n{}",
80-
sfdisk_stdout
70+
"{}: No bootc partitions found in sfdisk output. Output was:\n{}",
71+
context, sfdisk_stdout
8172
);
8273

8374
assert!(
8475
output.stdout.contains("Installation complete") || output.stderr.contains("Installation complete"),
85-
"No 'Installation complete' message found in output. This indicates bootc install did not complete successfully. stdout: {}, stderr: {}",
76+
"{}: No 'Installation complete' message found in output. This indicates bootc install did not complete successfully. stdout: {}, stderr: {}",
77+
context,
8678
output.stdout, output.stderr
8779
);
80+
81+
Ok(())
82+
}
83+
84+
/// Test actual bootc installation to a disk image
85+
fn test_to_disk() -> Result<()> {
86+
let temp_dir = TempDir::new().expect("Failed to create temp directory");
87+
let disk_path = Utf8PathBuf::try_from(temp_dir.path().join("test-disk.img"))
88+
.expect("temp path is not UTF-8");
89+
90+
let output = run_bcvk(&[
91+
"to-disk",
92+
"--label",
93+
INTEGRATION_TEST_LABEL,
94+
&get_test_image(),
95+
disk_path.as_str(),
96+
])?;
97+
98+
assert!(
99+
output.success(),
100+
"to-disk failed with exit code: {:?}. stdout: {}, stderr: {}",
101+
output.exit_code(),
102+
output.stdout,
103+
output.stderr
104+
);
105+
106+
validate_disk_image(&disk_path, &output, "test_to_disk")?;
88107
Ok(())
89108
}
90109
integration_test!(test_to_disk);
@@ -112,9 +131,6 @@ fn test_to_disk_qcow2() -> Result<()> {
112131
output.stderr
113132
);
114133

115-
let metadata = std::fs::metadata(&disk_path).expect("Failed to get disk metadata");
116-
assert!(metadata.len() > 0);
117-
118134
// Verify the file is actually qcow2 format using qemu-img info
119135
let qemu_img_output = Command::new("qemu-img")
120136
.args(["info", disk_path.as_str()])
@@ -135,11 +151,7 @@ fn test_to_disk_qcow2() -> Result<()> {
135151
qemu_img_stdout
136152
);
137153

138-
assert!(
139-
output.stdout.contains("Installation complete") || output.stderr.contains("Installation complete"),
140-
"No 'Installation complete' message found in output. This indicates bootc install did not complete successfully. stdout: {}, stderr: {}",
141-
output.stdout, output.stderr
142-
);
154+
validate_disk_image(&disk_path, &output, "test_to_disk_qcow2")?;
143155
Ok(())
144156
}
145157
integration_test!(test_to_disk_qcow2);
@@ -215,3 +227,38 @@ fn test_to_disk_caching() -> Result<()> {
215227
Ok(())
216228
}
217229
integration_test!(test_to_disk_caching);
230+
231+
/// Test to-disk with various bootc images to ensure compatibility
232+
///
233+
/// This parameterized test runs to-disk with multiple container images,
234+
/// particularly testing AlmaLinux which had cross-device link issues (issue #125)
235+
fn test_to_disk_multi_image(image: &str) -> Result<()> {
236+
let temp_dir = TempDir::new().expect("Failed to create temp directory");
237+
let disk_path = Utf8PathBuf::try_from(temp_dir.path().join("test-disk.img"))
238+
.expect("temp path is not UTF-8");
239+
240+
let output = run_bcvk(&[
241+
"to-disk",
242+
"--label",
243+
INTEGRATION_TEST_LABEL,
244+
image,
245+
disk_path.as_str(),
246+
])?;
247+
248+
assert!(
249+
output.success(),
250+
"to-disk with image {} failed with exit code: {:?}. stdout: {}, stderr: {}",
251+
image,
252+
output.exit_code(),
253+
output.stdout,
254+
output.stderr
255+
);
256+
257+
validate_disk_image(
258+
&disk_path,
259+
&output,
260+
&format!("test_to_disk_multi_image({})", image),
261+
)?;
262+
Ok(())
263+
}
264+
parameterized_integration_test!(test_to_disk_multi_image);

crates/kit/src/to_disk.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -245,9 +245,10 @@ impl ToDiskOpts {
245245
246246
# Execute bootc installation, having the outer podman pull from
247247
# the virtiofs store on the host, as well as the inner bootc.
248+
# Mount /var/tmp into inner container to avoid cross-device link errors (issue #125)
248249
export STORAGE_OPTS=additionalimagestore=${AIS}
249250
podman run --rm -i ${tty} --privileged --pid=host --net=none -v /sys:/sys:ro \
250-
-v /var/lib/containers:/var/lib/containers -v /dev:/dev -v ${AIS}:${AIS} --security-opt label=type:unconfined_t \
251+
-v /var/lib/containers:/var/lib/containers -v /var/tmp:/var/tmp -v /dev:/dev -v ${AIS}:${AIS} --security-opt label=type:unconfined_t \
251252
--env=STORAGE_OPTS \
252253
{INSTALL_LOG} \
253254
{SOURCE_IMGREF} \

0 commit comments

Comments
 (0)