Prepare, configure, and manage Firecracker microVMs in seconds!
virtualization
linux
microvm
firecracker
1use std::{process, thread};
2
3use anyhow::Error;
4use fire_config::read_config;
5use firecracker_state::repo;
6use firecracker_vm::types::VmOptions;
7use owo_colors::OwoColorize;
8
9use crate::command::run_command;
10
11pub async fn up(options: VmOptions) -> Result<(), Error> {
12 check_kvm_support()?;
13
14 let mut options = match read_config() {
15 Ok(config) => VmOptions::from(config),
16 Err(_) => options.clone(),
17 };
18
19 let current_dir = std::env::current_dir()?;
20 let fire_toml = current_dir.join("fire.toml");
21 let mut vm_id = None;
22 let pool = firecracker_state::create_connection_pool().await?;
23 let vm = repo::virtual_machine::find_by_api_socket(&pool, &options.api_socket).await?;
24
25 if let Some(vm) = vm {
26 vm_id = Some(vm.id.clone());
27 }
28
29 if fire_toml.exists() {
30 let vm =
31 repo::virtual_machine::find_by_project_dir(&pool, ¤t_dir.display().to_string())
32 .await?;
33
34 if let Some(vm) = vm {
35 options.api_socket = vm.api_socket.clone();
36 vm_id = Some(vm.id.clone());
37 }
38 }
39
40 let vms = repo::virtual_machine::all(&pool).await?;
41 if options.tap.is_empty() {
42 let vms = vms
43 .into_iter()
44 .filter(|vm| vm.tap.starts_with("tap"))
45 .collect::<Vec<_>>();
46 options.tap = format!("tap{}", vms.len());
47
48 while vms.iter().any(|vm| vm.tap == options.tap) {
49 let tap_num: u32 = options
50 .tap
51 .trim_start_matches("tap")
52 .parse::<u32>()
53 .unwrap_or(0)
54 .checked_add(1)
55 .unwrap_or(0);
56 options.tap = format!("tap{}", tap_num);
57 }
58 } else {
59 if vms
60 .iter()
61 .any(|vm| vm.tap == options.tap && vm.api_socket != options.api_socket)
62 {
63 println!(
64 "[!] Tap device name {} is already in use. Please choose a different name.",
65 options.tap.cyan()
66 );
67 process::exit(1);
68 }
69 }
70
71 let pid = firecracker_process::start(&options).await?;
72
73 loop {
74 thread::sleep(std::time::Duration::from_secs(1));
75 if firecracker_process::is_running() {
76 println!("[+] Firecracker is running.");
77 break;
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
90pub fn check_kvm_support() -> Result<(), Error> {
91 print!("[+] Checking for kvm support... ");
92
93 if !run_command("sh", &["-c", "lsmod | grep kvm"], false)
94 .map(|output| output.status.success())
95 .unwrap_or(false)
96 {
97 return Err(anyhow::anyhow!(
98 "KVM is not available. Please ensure KVM is enabled in your system."
99 ));
100 }
101
102 println!("{}", "[✓] OK".bright_green());
103
104 Ok(())
105}