Prepare, configure, and manage Firecracker microVMs in seconds!
virtualization linux microvm firecracker

Merge pull request #13 from tsirysndr/feat/default-vmlinux

feat: update kernel handling in microvm and downloader services

authored by tsiry-sandratraina.com and committed by

GitHub a8fd32b4 462bb085

+51 -30
+3 -2
crates/fire-server/src/services/microvm.rs
··· 160 } 161 } 162 163 - firecracker_prepare::prepare(options.clone().into(), options.vmlinux.clone(), ssh_keys)?; 164 - let vm_id = firecracker_vm::setup(&options, pid, vm_id).await?; 165 let vm = repo::virtual_machine::find(&pool, &vm_id) 166 .await? 167 .ok_or_else(|| Error::msg("Failed to retrieve the created VM"))?;
··· 160 } 161 } 162 163 + let kernel_file = 164 + firecracker_prepare::prepare(options.clone().into(), options.vmlinux.clone(), ssh_keys)?; 165 + let vm_id = firecracker_vm::setup(&options, pid, vm_id, &kernel_file).await?; 166 let vm = repo::virtual_machine::find(&pool, &vm_id) 167 .await? 168 .ok_or_else(|| Error::msg("Failed to retrieve the created VM"))?;
+19 -4
crates/firecracker-prepare/src/downloader.rs
··· 3 use regex::Regex; 4 use std::path::Path; 5 6 - use crate::command::{run_command, run_command_with_stdout_inherit}; 7 8 pub fn download_files(arch: &str) -> Result<(String, String, String)> { 9 let app_dir = 10 crate::config::get_config_dir().with_context(|| "Failed to get configuration directory")?; 11 - let kernel_file = download_kernel(arch)?; 12 13 let ci_version = get_ci_version().with_context(|| "Failed to get CI version")?; 14 ··· 73 Ok(ci_version.to_string()) 74 } 75 76 - pub fn download_kernel(arch: &str) -> Result<String> { 77 let app_dir = 78 crate::config::get_config_dir().with_context(|| "Failed to get configuration directory")?; 79 let ci_version = ··· 99 Ok(kernel_file) 100 } 101 102 fn get_latest_key(url: &str, prefix: &str) -> Result<String> { 103 let output = run_command( 104 "curl", ··· 157 return Ok(()); 158 } 159 println!("Downloading: {}", output.bright_green()); 160 - run_command_with_stdout_inherit("wget", &["-O", output, url], false)?; 161 Ok(()) 162 } 163
··· 3 use regex::Regex; 4 use std::path::Path; 5 6 + use crate::{ 7 + command::{run_command, run_command_with_stdout_inherit}, 8 + get_kernel_version, 9 + }; 10 11 pub fn download_files(arch: &str) -> Result<(String, String, String)> { 12 let app_dir = 13 crate::config::get_config_dir().with_context(|| "Failed to get configuration directory")?; 14 + let kernel_file = download_kernel(&get_kernel_version(), arch)?; 15 16 let ci_version = get_ci_version().with_context(|| "Failed to get CI version")?; 17 ··· 76 Ok(ci_version.to_string()) 77 } 78 79 + pub fn download_kernel_from_firecracker(arch: &str) -> Result<String> { 80 let app_dir = 81 crate::config::get_config_dir().with_context(|| "Failed to get configuration directory")?; 82 let ci_version = ··· 102 Ok(kernel_file) 103 } 104 105 + pub fn download_kernel(version: &str, arch: &str) -> Result<String> { 106 + let app_dir = 107 + crate::config::get_config_dir().with_context(|| "Failed to get configuration directory")?; 108 + let kernel_file = format!("{}/vmlinux-{}.{}", app_dir, version, arch); 109 + let kernel_url = &format!( 110 + "https://github.com/tsirysndr/vmlinux-builder/releases/download/{}/vmlinux-{}.{}", 111 + version, version, arch, 112 + ); 113 + download_file(kernel_url, &kernel_file)?; 114 + Ok(kernel_file) 115 + } 116 + 117 fn get_latest_key(url: &str, prefix: &str) -> Result<String> { 118 let output = run_command( 119 "curl", ··· 172 return Ok(()); 173 } 174 println!("Downloading: {}", output.bright_green()); 175 + run_command_with_stdout_inherit("curl", &["-L", "-o", output, url], false)?; 176 Ok(()) 177 } 178
+19 -14
crates/firecracker-prepare/src/lib.rs
··· 1 - use std::fs; 2 3 use anyhow::Result; 4 use owo_colors::OwoColorize; ··· 19 20 const BRIDGE_IP: &str = "172.16.0.1"; 21 22 #[derive(Clone, Copy, PartialEq, Serialize, Deserialize, Debug)] 23 pub enum Distro { 24 Debian, ··· 58 distro: Distro, 59 kernel_file: Option<String>, 60 ssh_keys: Option<Vec<String>>, 61 - ) -> Result<()> { 62 let arch = run_command("uname", &["-m"], false)?.stdout; 63 let arch = String::from_utf8_lossy(&arch).trim().to_string(); 64 println!("[+] Detected architecture: {}", arch.bright_green()); ··· 102 Some(ssh_key_file) => println!("[✓] SSH Key: {}", ssh_key_file.bright_green()), 103 } 104 105 - Ok(()) 106 } 107 108 pub trait RootfsPreparer { ··· 149 150 let kernel_file = match kernel_file { 151 Some(k) => fs::canonicalize(k)?.to_str().unwrap().to_string(), 152 - None => downloader::download_kernel(arch)?, 153 }; 154 let debootstrap_dir = format!("{}/debian-rootfs", app_dir); 155 156 let arch = match arch { ··· 288 289 let kernel_file = match kernel_file { 290 Some(k) => fs::canonicalize(k)?.to_str().unwrap().to_string(), 291 - None => downloader::download_kernel(arch)?, 292 }; 293 let minirootfs = format!("{}/minirootfs", app_dir); 294 downloader::download_alpine_rootfs(&minirootfs, arch)?; ··· 513 ); 514 let kernel_file = match kernel_file { 515 Some(k) => fs::canonicalize(k)?.to_str().unwrap().to_string(), 516 - None => downloader::download_kernel(arch)?, 517 }; 518 let nixos_rootfs = format!("{}/nixos-rootfs", app_dir); 519 let squashfs_file = format!("{}/nixos-rootfs.squashfs", app_dir); ··· 573 574 let kernel_file = match kernel_file { 575 Some(k) => fs::canonicalize(k)?.to_str().unwrap().to_string(), 576 - None => downloader::download_kernel(arch)?, 577 }; 578 let fedora_rootfs = format!("{}/fedora-rootfs", app_dir); 579 let squashfs_file = format!("{}/fedora-rootfs.squashfs", app_dir); ··· 639 640 let kernel_file = match kernel_file { 641 Some(k) => fs::canonicalize(k)?.to_str().unwrap().to_string(), 642 - None => downloader::download_kernel(arch)?, 643 }; 644 645 let gentoo_rootfs = format!("{}/gentoo-rootfs", app_dir); ··· 701 702 let kernel_file = match kernel_file { 703 Some(k) => fs::canonicalize(k)?.to_str().unwrap().to_string(), 704 - None => downloader::download_kernel(arch)?, 705 }; 706 707 let slackware_rootfs = format!("{}/slackware-rootfs", app_dir); ··· 768 769 let kernel_file = match kernel_file { 770 Some(k) => fs::canonicalize(k)?.to_str().unwrap().to_string(), 771 - None => downloader::download_kernel(arch)?, 772 }; 773 774 let opensuse_rootfs = format!("{}/opensuse-rootfs", app_dir); ··· 829 830 let kernel_file = match kernel_file { 831 Some(k) => fs::canonicalize(k)?.to_str().unwrap().to_string(), 832 - None => downloader::download_kernel(arch)?, 833 }; 834 835 let almalinux_rootfs = format!("{}/almalinux-rootfs", app_dir); ··· 884 885 let kernel_file = match kernel_file { 886 Some(k) => fs::canonicalize(k)?.to_str().unwrap().to_string(), 887 - None => downloader::download_kernel(arch)?, 888 }; 889 890 let rockylinux_rootfs = format!("{}/rockylinux-rootfs", app_dir); ··· 938 939 let kernel_file = match kernel_file { 940 Some(k) => fs::canonicalize(k)?.to_str().unwrap().to_string(), 941 - None => downloader::download_kernel(arch)?, 942 }; 943 let archlinux_rootfs = format!("{}/archlinux-rootfs", app_dir); 944 let squashfs_file = format!("{}/archlinux-rootfs.squashfs", app_dir); ··· 1003 1004 let kernel_file = match kernel_file { 1005 Some(k) => fs::canonicalize(k)?.to_str().unwrap().to_string(), 1006 - None => downloader::download_kernel(arch)?, 1007 }; 1008 1009 let opensuse_rootfs = format!("{}/opensuse-tumbleweed-rootfs", app_dir);
··· 1 + use std::{env, fs}; 2 3 use anyhow::Result; 4 use owo_colors::OwoColorize; ··· 19 20 const BRIDGE_IP: &str = "172.16.0.1"; 21 22 + fn get_kernel_version() -> String { 23 + env::var("KERNEL_VERSION").unwrap_or_else(|_| "6.16.7".to_string()) 24 + } 25 + 26 #[derive(Clone, Copy, PartialEq, Serialize, Deserialize, Debug)] 27 pub enum Distro { 28 Debian, ··· 62 distro: Distro, 63 kernel_file: Option<String>, 64 ssh_keys: Option<Vec<String>>, 65 + ) -> Result<String> { 66 let arch = run_command("uname", &["-m"], false)?.stdout; 67 let arch = String::from_utf8_lossy(&arch).trim().to_string(); 68 println!("[+] Detected architecture: {}", arch.bright_green()); ··· 106 Some(ssh_key_file) => println!("[✓] SSH Key: {}", ssh_key_file.bright_green()), 107 } 108 109 + Ok(kernel_file) 110 } 111 112 pub trait RootfsPreparer { ··· 153 154 let kernel_file = match kernel_file { 155 Some(k) => fs::canonicalize(k)?.to_str().unwrap().to_string(), 156 + None => downloader::download_kernel(&get_kernel_version(), arch)?, 157 }; 158 + 159 let debootstrap_dir = format!("{}/debian-rootfs", app_dir); 160 161 let arch = match arch { ··· 293 294 let kernel_file = match kernel_file { 295 Some(k) => fs::canonicalize(k)?.to_str().unwrap().to_string(), 296 + None => downloader::download_kernel(&get_kernel_version(), arch)?, 297 }; 298 let minirootfs = format!("{}/minirootfs", app_dir); 299 downloader::download_alpine_rootfs(&minirootfs, arch)?; ··· 518 ); 519 let kernel_file = match kernel_file { 520 Some(k) => fs::canonicalize(k)?.to_str().unwrap().to_string(), 521 + None => downloader::download_kernel(&get_kernel_version(), arch)?, 522 }; 523 let nixos_rootfs = format!("{}/nixos-rootfs", app_dir); 524 let squashfs_file = format!("{}/nixos-rootfs.squashfs", app_dir); ··· 578 579 let kernel_file = match kernel_file { 580 Some(k) => fs::canonicalize(k)?.to_str().unwrap().to_string(), 581 + None => downloader::download_kernel(&get_kernel_version(), arch)?, 582 }; 583 let fedora_rootfs = format!("{}/fedora-rootfs", app_dir); 584 let squashfs_file = format!("{}/fedora-rootfs.squashfs", app_dir); ··· 644 645 let kernel_file = match kernel_file { 646 Some(k) => fs::canonicalize(k)?.to_str().unwrap().to_string(), 647 + None => downloader::download_kernel(&get_kernel_version(), arch)?, 648 }; 649 650 let gentoo_rootfs = format!("{}/gentoo-rootfs", app_dir); ··· 706 707 let kernel_file = match kernel_file { 708 Some(k) => fs::canonicalize(k)?.to_str().unwrap().to_string(), 709 + None => downloader::download_kernel(&get_kernel_version(), arch)?, 710 }; 711 712 let slackware_rootfs = format!("{}/slackware-rootfs", app_dir); ··· 773 774 let kernel_file = match kernel_file { 775 Some(k) => fs::canonicalize(k)?.to_str().unwrap().to_string(), 776 + None => downloader::download_kernel(&get_kernel_version(), arch)?, 777 }; 778 779 let opensuse_rootfs = format!("{}/opensuse-rootfs", app_dir); ··· 834 835 let kernel_file = match kernel_file { 836 Some(k) => fs::canonicalize(k)?.to_str().unwrap().to_string(), 837 + None => downloader::download_kernel(&get_kernel_version(), arch)?, 838 }; 839 840 let almalinux_rootfs = format!("{}/almalinux-rootfs", app_dir); ··· 889 890 let kernel_file = match kernel_file { 891 Some(k) => fs::canonicalize(k)?.to_str().unwrap().to_string(), 892 + None => downloader::download_kernel(&get_kernel_version(), arch)?, 893 }; 894 895 let rockylinux_rootfs = format!("{}/rockylinux-rootfs", app_dir); ··· 943 944 let kernel_file = match kernel_file { 945 Some(k) => fs::canonicalize(k)?.to_str().unwrap().to_string(), 946 + None => downloader::download_kernel(&get_kernel_version(), arch)?, 947 }; 948 let archlinux_rootfs = format!("{}/archlinux-rootfs", app_dir); 949 let squashfs_file = format!("{}/archlinux-rootfs.squashfs", app_dir); ··· 1008 1009 let kernel_file = match kernel_file { 1010 Some(k) => fs::canonicalize(k)?.to_str().unwrap().to_string(), 1011 + None => downloader::download_kernel(&get_kernel_version(), arch)?, 1012 }; 1013 1014 let opensuse_rootfs = format!("{}/opensuse-tumbleweed-rootfs", app_dir);
+2 -2
crates/firecracker-up/src/cmd/up.rs
··· 78 } 79 } 80 81 - firecracker_prepare::prepare( 82 options.clone().into(), 83 options.vmlinux.clone(), 84 options.ssh_keys.clone(), 85 )?; 86 - firecracker_vm::setup(&options, pid, vm_id).await?; 87 Ok(()) 88 } 89
··· 78 } 79 } 80 81 + let kernel_file = firecracker_prepare::prepare( 82 options.clone().into(), 83 options.vmlinux.clone(), 84 options.ssh_keys.clone(), 85 )?; 86 + firecracker_vm::setup(&options, pid, vm_id, &kernel_file).await?; 87 Ok(()) 88 } 89
+8 -8
crates/firecracker-vm/src/lib.rs
··· 19 mod network; 20 pub mod types; 21 22 - pub async fn setup(options: &VmOptions, pid: u32, vm_id: Option<String>) -> Result<String> { 23 let distro: Distro = options.clone().into(); 24 let app_dir = get_config_dir().with_context(|| "Failed to get configuration directory")?; 25 ··· 43 fs::File::create(&logfile) 44 .with_context(|| format!("Failed to create log file: {}", logfile))?; 45 46 - let kernel = glob::glob(format!("{}/vmlinux*", app_dir).as_str()) 47 - .with_context(|| "Failed to glob kernel files")? 48 - .last() 49 - .ok_or_else(|| anyhow!("No kernel file found"))? 50 - .with_context(|| "Failed to get kernel path")?; 51 - let kernel = fs::canonicalize(&kernel) 52 .with_context(|| { 53 format!( 54 "Failed to resolve absolute path for kernel: {}", 55 - kernel.display() 56 ) 57 })? 58 .display()
··· 19 mod network; 20 pub mod types; 21 22 + pub async fn setup( 23 + options: &VmOptions, 24 + pid: u32, 25 + vm_id: Option<String>, 26 + kernel_file: &str, 27 + ) -> Result<String> { 28 let distro: Distro = options.clone().into(); 29 let app_dir = get_config_dir().with_context(|| "Failed to get configuration directory")?; 30 ··· 48 fs::File::create(&logfile) 49 .with_context(|| format!("Failed to create log file: {}", logfile))?; 50 51 + let kernel = fs::canonicalize(kernel_file) 52 .with_context(|| { 53 format!( 54 "Failed to resolve absolute path for kernel: {}", 55 + kernel_file 56 ) 57 })? 58 .display()