Prepare, configure, and manage Firecracker microVMs in seconds!
virtualization linux microvm firecracker
at main 113 lines 3.2 kB view raw
1use std::{process, thread}; 2 3use anyhow::Result; 4use firecracker_state::repo; 5use firecracker_vm::types::VmOptions; 6use owo_colors::OwoColorize; 7 8use crate::command::{run_command, run_command_in_background}; 9 10pub mod command; 11 12pub async fn start(config: &VmOptions) -> Result<u32> { 13 let name = config 14 .api_socket 15 .trim_start_matches("/tmp/firecracker-") 16 .trim_end_matches(".sock") 17 .to_string(); 18 19 stop(Some(name)).await?; 20 println!("[+] Starting Firecracker..."); 21 let pid = run_command_in_background("firecracker", &["--api-sock", &config.api_socket], true)?; 22 23 let mut attempts = 0; 24 while !std::path::Path::new(&config.api_socket).exists() { 25 if attempts >= 100 { 26 println!("[!] Timed out waiting for Firecracker to start. Please check the logs."); 27 process::exit(1); 28 } 29 attempts += 1; 30 thread::sleep(std::time::Duration::from_millis(500)); 31 } 32 33 Ok(pid) 34} 35 36pub async fn stop(name: Option<String>) -> Result<()> { 37 if name.is_none() { 38 return stop_all().await; 39 } 40 41 let name = name.unwrap(); 42 43 if !vm_is_running(&name).await? { 44 println!("[!] {} is not running.", name.cyan()); 45 return Ok(()); 46 } 47 48 let config = VmOptions { 49 api_socket: format!("/tmp/firecracker-{}.sock", name), 50 ..Default::default() 51 }; 52 53 let pool = firecracker_state::create_connection_pool().await?; 54 55 let vm = repo::virtual_machine::find(&pool, &name).await?; 56 if vm.is_none() { 57 println!( 58 "[!] No virtual machine found with name or id '{}'.", 59 name.cyan() 60 ); 61 process::exit(1); 62 } 63 64 let vm = vm.unwrap(); 65 if let Some(pid) = vm.pid { 66 if run_command("kill", &["-s", "KILL", &pid.to_string()], true).is_err() { 67 println!("[!] Failed to kill process with PID {}.", pid); 68 } 69 } 70 71 run_command("rm", &["-rf", &config.api_socket], true)?; 72 println!("[+] {} has been stopped.", name.cyan()); 73 74 repo::virtual_machine::update_status(&pool, &name, "STOPPED").await?; 75 76 Ok(()) 77} 78 79pub async fn vm_is_running(name: &str) -> Result<bool> { 80 let pool = firecracker_state::create_connection_pool().await?; 81 let vm = repo::virtual_machine::find(&pool, name).await?; 82 83 if let Some(vm) = vm { 84 if std::path::Path::new(&vm.api_socket).exists() { 85 return Ok(true); 86 } 87 repo::virtual_machine::update_status(&pool, name, "STOPPED").await?; 88 } 89 90 Ok(false) 91} 92 93pub fn is_running() -> bool { 94 match run_command("pgrep", &["-x", "firecracker"], false) { 95 Ok(output) => output.status.success(), 96 Err(_) => false, 97 } 98} 99 100pub async fn stop_all() -> Result<()> { 101 if !is_running() { 102 println!("[!] No Firecracker process is running."); 103 return Ok(()); 104 } 105 106 run_command("pkill", &["-x", "firecracker"], true)?; 107 run_command("bash", &["-c", "rm -rf /tmp/firecracker-*.sock"], true)?; 108 println!("[+] All Firecracker processes have been stopped."); 109 110 let pool = firecracker_state::create_connection_pool().await?; 111 repo::virtual_machine::update_all_status(&pool, "STOPPED").await?; 112 Ok(()) 113}