Skip to content

Commit 06c693c

Browse files
committed
WIP: Add osbuild-disk
This mirrors `to-disk`, except instead of having the bootc container install itself, we're adding osbuild/bib in the middle. I think this is pretty close to working, but right now it dies deep in the osbuild stack failing to fetch the image. But this all works with `to-disk` where bootc-in-container fetches it. Assisted-by: Claude Code Signed-off-by: Colin Walters <[email protected]>
1 parent 88b787d commit 06c693c

File tree

4 files changed

+668
-0
lines changed

4 files changed

+668
-0
lines changed

crates/integration-tests/src/main.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ mod tests {
1515
pub mod libvirt_upload_disk;
1616
pub mod libvirt_verb;
1717
pub mod mount_feature;
18+
pub mod osbuild_disk;
1819
pub mod run_ephemeral;
1920
pub mod run_ephemeral_ssh;
2021
pub mod to_disk;
@@ -243,6 +244,18 @@ fn main() {
243244
tests::to_disk::test_to_disk_caching();
244245
Ok(())
245246
}),
247+
Trial::test("osbuild_disk_qcow2", || {
248+
tests::osbuild_disk::test_osbuild_disk_qcow2();
249+
Ok(())
250+
}),
251+
Trial::test("osbuild_disk_with_config", || {
252+
tests::osbuild_disk::test_osbuild_disk_with_config();
253+
Ok(())
254+
}),
255+
Trial::test("osbuild_disk_raw", || {
256+
tests::osbuild_disk::test_osbuild_disk_raw();
257+
Ok(())
258+
}),
246259
Trial::test("libvirt_list_functionality", || {
247260
tests::libvirt_verb::test_libvirt_list_functionality();
248261
Ok(())
Lines changed: 231 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,231 @@
1+
//! Integration tests for osbuild-disk command
2+
//!
3+
//! ⚠️ **CRITICAL INTEGRATION TEST POLICY** ⚠️
4+
//!
5+
//! INTEGRATION TESTS MUST NEVER "warn and continue" ON FAILURES!
6+
//!
7+
//! If something is not working:
8+
//! - Use `todo!("reason why this doesn't work yet")`
9+
//! - Use `panic!("clear error message")`
10+
//! - Use `assert!()` and `unwrap()` to fail hard
11+
//!
12+
//! NEVER use patterns like:
13+
//! - "Note: test failed - likely due to..."
14+
//! - "This is acceptable in CI/testing environments"
15+
//! - Warning and continuing on failures
16+
17+
use camino::Utf8PathBuf;
18+
use std::process::Command;
19+
use tempfile::TempDir;
20+
21+
use crate::{run_bcvk, INTEGRATION_TEST_LABEL};
22+
23+
/// Test building a qcow2 disk image with bootc-image-builder
24+
pub fn test_osbuild_disk_qcow2() {
25+
let temp_dir = TempDir::new().expect("Failed to create temp directory");
26+
let output_dir =
27+
Utf8PathBuf::try_from(temp_dir.path().to_path_buf()).expect("temp path is not UTF-8");
28+
29+
let output = run_bcvk(&[
30+
"osbuild-disk",
31+
"--label",
32+
INTEGRATION_TEST_LABEL,
33+
"quay.io/centos-bootc/centos-bootc:stream10",
34+
output_dir.as_str(),
35+
])
36+
.expect("Failed to run bcvk osbuild-disk");
37+
38+
assert!(
39+
output.success(),
40+
"osbuild-disk failed with exit code: {:?}. stdout: {}, stderr: {}",
41+
output.exit_code(),
42+
output.stdout,
43+
output.stderr
44+
);
45+
46+
// Verify output directory contains qcow2 subdirectory
47+
let qcow2_dir = output_dir.join("qcow2");
48+
assert!(
49+
qcow2_dir.exists(),
50+
"qcow2 output directory not found at {}",
51+
qcow2_dir
52+
);
53+
54+
// Verify disk.qcow2 file exists
55+
let disk_path = qcow2_dir.join("disk.qcow2");
56+
assert!(
57+
disk_path.exists(),
58+
"disk.qcow2 file not found at {}",
59+
disk_path
60+
);
61+
62+
let metadata = std::fs::metadata(&disk_path).expect("Failed to get disk metadata");
63+
assert!(metadata.len() > 0, "Disk image is empty");
64+
65+
// Verify the file is actually qcow2 format using qemu-img info
66+
let qemu_img_output = Command::new("qemu-img")
67+
.args(["info", disk_path.as_str()])
68+
.output()
69+
.expect("Failed to run qemu-img info");
70+
71+
let qemu_img_stdout = String::from_utf8_lossy(&qemu_img_output.stdout);
72+
73+
assert!(
74+
qemu_img_output.status.success(),
75+
"qemu-img info failed with exit code: {:?}",
76+
qemu_img_output.status.code()
77+
);
78+
79+
assert!(
80+
qemu_img_stdout.contains("file format: qcow2"),
81+
"qemu-img info doesn't show qcow2 format. Output was:\n{}",
82+
qemu_img_stdout
83+
);
84+
85+
assert!(
86+
output.stdout.contains("Build completed successfully!")
87+
|| output.stderr.contains("Build completed successfully!"),
88+
"No 'Build completed successfully!' message found in output. stdout: {}, stderr: {}",
89+
output.stdout,
90+
output.stderr
91+
);
92+
}
93+
94+
/// Test building with a custom config file
95+
pub fn test_osbuild_disk_with_config() {
96+
let temp_dir = TempDir::new().expect("Failed to create temp directory");
97+
let output_dir =
98+
Utf8PathBuf::try_from(temp_dir.path().join("output")).expect("temp path is not UTF-8");
99+
std::fs::create_dir_all(&output_dir).expect("Failed to create output directory");
100+
101+
// Create a simple config file with user customization
102+
let config_path = temp_dir.path().join("config.toml");
103+
let config_content = r#"
104+
[[customizations.user]]
105+
name = "testuser"
106+
password = "testpass"
107+
groups = ["wheel"]
108+
"#;
109+
std::fs::write(&config_path, config_content).expect("Failed to write config file");
110+
111+
let config_path_str = config_path.to_str().expect("Config path is not UTF-8");
112+
113+
let output = run_bcvk(&[
114+
"osbuild-disk",
115+
"--label",
116+
INTEGRATION_TEST_LABEL,
117+
"--config",
118+
config_path_str,
119+
"quay.io/centos-bootc/centos-bootc:stream10",
120+
output_dir.as_str(),
121+
])
122+
.expect("Failed to run bcvk osbuild-disk with config");
123+
124+
assert!(
125+
output.success(),
126+
"osbuild-disk with config failed with exit code: {:?}. stdout: {}, stderr: {}",
127+
output.exit_code(),
128+
output.stdout,
129+
output.stderr
130+
);
131+
132+
// Verify output directory contains qcow2 subdirectory
133+
let qcow2_dir = output_dir.join("qcow2");
134+
assert!(
135+
qcow2_dir.exists(),
136+
"qcow2 output directory not found at {}",
137+
qcow2_dir
138+
);
139+
140+
// Verify disk.qcow2 file exists
141+
let disk_path = qcow2_dir.join("disk.qcow2");
142+
assert!(
143+
disk_path.exists(),
144+
"disk.qcow2 file not found at {}",
145+
disk_path
146+
);
147+
148+
let metadata = std::fs::metadata(&disk_path).expect("Failed to get disk metadata");
149+
assert!(metadata.len() > 0, "Disk image is empty");
150+
151+
assert!(
152+
output.stdout.contains("Build completed successfully!")
153+
|| output.stderr.contains("Build completed successfully!"),
154+
"No 'Build completed successfully!' message found in output. stdout: {}, stderr: {}",
155+
output.stdout,
156+
output.stderr
157+
);
158+
}
159+
160+
/// Test building a raw disk image
161+
pub fn test_osbuild_disk_raw() {
162+
let temp_dir = TempDir::new().expect("Failed to create temp directory");
163+
let output_dir =
164+
Utf8PathBuf::try_from(temp_dir.path().to_path_buf()).expect("temp path is not UTF-8");
165+
166+
let output = run_bcvk(&[
167+
"osbuild-disk",
168+
"--label",
169+
INTEGRATION_TEST_LABEL,
170+
"--type",
171+
"raw",
172+
"quay.io/centos-bootc/centos-bootc:stream10",
173+
output_dir.as_str(),
174+
])
175+
.expect("Failed to run bcvk osbuild-disk with raw format");
176+
177+
assert!(
178+
output.success(),
179+
"osbuild-disk with raw format failed with exit code: {:?}. stdout: {}, stderr: {}",
180+
output.exit_code(),
181+
output.stdout,
182+
output.stderr
183+
);
184+
185+
// Verify output directory contains image subdirectory (raw images go here)
186+
let image_dir = output_dir.join("image");
187+
assert!(
188+
image_dir.exists(),
189+
"image output directory not found at {}",
190+
image_dir
191+
);
192+
193+
// Verify disk.raw file exists
194+
let disk_path = image_dir.join("disk.raw");
195+
assert!(
196+
disk_path.exists(),
197+
"disk.raw file not found at {}",
198+
disk_path
199+
);
200+
201+
let metadata = std::fs::metadata(&disk_path).expect("Failed to get disk metadata");
202+
assert!(metadata.len() > 0, "Disk image is empty");
203+
204+
// Verify the file is raw format using qemu-img info
205+
let qemu_img_output = Command::new("qemu-img")
206+
.args(["info", disk_path.as_str()])
207+
.output()
208+
.expect("Failed to run qemu-img info");
209+
210+
let qemu_img_stdout = String::from_utf8_lossy(&qemu_img_output.stdout);
211+
212+
assert!(
213+
qemu_img_output.status.success(),
214+
"qemu-img info failed with exit code: {:?}",
215+
qemu_img_output.status.code()
216+
);
217+
218+
assert!(
219+
qemu_img_stdout.contains("file format: raw"),
220+
"qemu-img info doesn't show raw format. Output was:\n{}",
221+
qemu_img_stdout
222+
);
223+
224+
assert!(
225+
output.stdout.contains("Build completed successfully!")
226+
|| output.stderr.contains("Build completed successfully!"),
227+
"No 'Build completed successfully!' message found in output. stdout: {}, stderr: {}",
228+
output.stdout,
229+
output.stderr
230+
);
231+
}

crates/kit/src/main.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ mod images;
1919
mod install_options;
2020
mod libvirt;
2121
mod libvirt_upload_disk;
22+
mod osbuild_disk;
2223
#[allow(dead_code)]
2324
mod podman;
2425
#[allow(dead_code)]
@@ -113,6 +114,10 @@ enum Commands {
113114
#[clap(name = "to-disk")]
114115
ToDisk(to_disk::ToDiskOpts),
115116

117+
/// Build disk images using bootc-image-builder
118+
#[clap(name = "osbuild-disk")]
119+
OsbuildDisk(osbuild_disk::OsbuildDiskOpts),
120+
116121
/// Manage libvirt integration for bootc containers
117122
Libvirt {
118123
/// Hypervisor connection URI (e.g., qemu:///system, qemu+ssh://host/system)
@@ -187,6 +192,9 @@ fn main() -> Result<(), Report> {
187192
Commands::ToDisk(opts) => {
188193
to_disk::run(opts)?;
189194
}
195+
Commands::OsbuildDisk(opts) => {
196+
osbuild_disk::run(opts)?;
197+
}
190198
Commands::Libvirt { connect, command } => {
191199
let options = libvirt::LibvirtOptions { connect };
192200
match command {

0 commit comments

Comments
 (0)