Prepare, configure, and manage Firecracker microVMs in seconds!
virtualization
linux
microvm
firecracker
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}