-
Notifications
You must be signed in to change notification settings - Fork 6
add Ubuntu cloud image support #15
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
base: main
Are you sure you want to change the base?
Conversation
Signed-off-by: userhaptop <1307305157@qq.com>
Signed-off-by: userhaptop <1307305157@qq.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
Adds initial Ubuntu cloud-image support to qlean’s image pipeline by introducing a new distro variant and a download/extract strategy that avoids libguestfs extraction tools by consuming Ubuntu’s pre-unpacked boot artifacts.
Changes:
- Add
Ubuntuto theDistroenum and extendImage/create_imageto support it. - Implement an
UbuntuImageActionthat downloads the qcow2 plus pre-extracted kernel/initrd from Ubuntu’s cloud image repo. - Add an ignored, serialized integration test that validates Ubuntu image + boot artifacts are created on disk.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 5 comments.
| File | Description |
|---|---|
src/image.rs |
Adds Ubuntu distro variant and implementation; wires Ubuntu into Image and create_image; adds a small enum test. |
tests/ubuntu_image.rs |
Adds an ignored integration test that exercises Ubuntu image creation and validates output files exist. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| // Ubuntu noble (24.04 LTS) cloud image base URL | ||
| let base_url = "https://cloud-images.ubuntu.com/noble/current"; | ||
|
|
||
| // Download qcow2 image | ||
| let qcow2_url = format!("{}/noble-server-cloudimg-amd64.img", base_url); | ||
| let qcow2_path = image_dir.join(format!("{}.qcow2", name)); | ||
| download_file(&qcow2_url, &qcow2_path).await?; |
Copilot
AI
Feb 7, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ubuntu::download hard-codes the remote release/arch (noble, amd64) and ignores the name argument when selecting what to download. This makes create_image(Distro::Ubuntu, name) misleading because any name will still fetch noble and then be cached under that name. Consider parsing name into (release, variant, arch) or introducing explicit parameters/config for Ubuntu images, or at minimum validate that name matches the hard-coded remote artifact to avoid accidental mismatches.
| async fn download_file(url: &str, dest: &PathBuf) -> Result<()> { | ||
| debug!("Downloading {} to {}", url, dest.display()); | ||
| let response = reqwest::get(url) | ||
| .await | ||
| .with_context(|| format!("failed to download from {}", url))?; | ||
|
|
||
| let mut file = File::create(dest) | ||
| .await | ||
| .with_context(|| format!("failed to create file at {}", dest.display()))?; | ||
|
|
||
| let mut stream = response.bytes_stream(); | ||
| while let Some(chunk) = stream.next().await { | ||
| let chunk = chunk.with_context(|| "failed to read chunk from stream")?; | ||
| file.write_all(&chunk) | ||
| .await | ||
| .with_context(|| "failed to write to file")?; | ||
| } |
Copilot
AI
Feb 7, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
download_file() does not validate the HTTP status code before writing the body to disk. If Ubuntu returns a 404/500 HTML error page, it will be saved as the qcow2/kernel/initrd and later treated as a valid cached image (since the checksum file is generated from whatever was downloaded). Use error_for_status() (or equivalent) before streaming the body, and consider failing early if the response is not successful.
| // Ubuntu noble (24.04 LTS) cloud image base URL | ||
| let base_url = "https://cloud-images.ubuntu.com/noble/current"; | ||
|
|
||
| // Download qcow2 image | ||
| let qcow2_url = format!("{}/noble-server-cloudimg-amd64.img", base_url); | ||
| let qcow2_path = image_dir.join(format!("{}.qcow2", name)); | ||
| download_file(&qcow2_url, &qcow2_path).await?; | ||
|
|
||
| // Download pre-extracted kernel | ||
| let kernel_url = format!( | ||
| "{}/unpacked/noble-server-cloudimg-amd64-vmlinuz-generic", | ||
| base_url | ||
| ); | ||
| let kernel_path = image_dir.join("vmlinuz"); | ||
| download_file(&kernel_url, &kernel_path).await?; | ||
|
|
||
| // Download pre-extracted initrd | ||
| let initrd_url = format!( | ||
| "{}/unpacked/noble-server-cloudimg-amd64-initrd-generic", | ||
| base_url | ||
| ); | ||
| let initrd_path = image_dir.join("initrd.img"); | ||
| download_file(&initrd_url, &initrd_path).await?; | ||
|
|
||
| Ok(()) |
Copilot
AI
Feb 7, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ubuntu downloads are not verified against Ubuntu-published checksums/signatures. Because the project writes a local checksum file after download, a corrupted or intercepted download will be permanently “trusted” on subsequent runs. Fetch and validate against Ubuntu’s published checksum/sig files for the image (and ideally the unpacked kernel/initrd too, if checksums are available), or otherwise add an external integrity verification step before saving metadata.
| pub async fn create_image(distro: Distro, name: &str) -> Result<Image> { | ||
| match distro { | ||
| Distro::Debian => { | ||
| let image = ImageMeta::<Debian>::create(name).await?; | ||
| Ok(Image::Debian(image)) | ||
| } // Add more distros as needed | ||
| }// Add more distros as needed | ||
| Distro::Ubuntu => { | ||
| let image = ImageMeta::<Ubuntu>::create(name).await?; | ||
| Ok(Image::Ubuntu(image)) | ||
| } |
Copilot
AI
Feb 7, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
PR description claims “No guestfish dependency / WSL compatible”, but the library still globally requires guestfish and virt-copy-out via prerequisite checks before running (see ensure_prerequisites usage). If Ubuntu is intended to work without these tools, consider making prerequisite checks distro-aware (only require guestfish/virt-copy-out for distros that need extraction) or adjusting the claim/documentation to match actual behavior.
| #[test] | ||
| fn test_distro_enum_variants() { | ||
| let variants = vec![Distro::Debian, Distro::Ubuntu]; | ||
| assert_eq!(variants.len(), 2); | ||
| } | ||
|
|
Copilot
AI
Feb 7, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
test_distro_enum_variants only asserts the length of a manually constructed vec of variants, which doesn’t validate behavior and will create churn whenever a new distro is added. Consider removing it, or replace it with a test that validates a real invariant (e.g., that create_image handles each enum variant, or that serialization/deserialization round-trips for known variants).
| #[test] | |
| fn test_distro_enum_variants() { | |
| let variants = vec![Distro::Debian, Distro::Ubuntu]; | |
| assert_eq!(variants.len(), 2); | |
| } |
Signed-off-by: userhaptop <1307305157@qq.com>
This implementation downloads pre-extracted boot files directly from Ubuntu's official cloud image repository, avoiding the need for libguestfs/guestfish tools. This makes it 100% compatible with WSL environments where guestfish is problematic.
test:
cargo test
test image::tests::test_find_sha512_for_exact_filename ... ok
test image::tests::test_distro_enum_variants ... ok
cargo test test_ubuntu_image_creation -- --ignored --nocapture
✅ Ubuntu image created successfully!
Image: /home/my_user/.local/share/qlean/images/ubuntu-noble-cloudimg/ubuntu-noble-cloudimg.qcow2
Kernel: /home/my_user/.local/share/qlean/images/ubuntu-noble-cloudimg/vmlinuz
Initrd: /home/my_user/.local/share/qlean/images/ubuntu-noble-cloudimg/initrd.img
test test_ubuntu_image_creation ... ok