Prepare, configure, and manage Firecracker microVMs in seconds!
virtualization linux microvm firecracker
at main 132 lines 4.8 kB view raw
1use std::fs; 2 3use anyhow::anyhow; 4use anyhow::Context; 5use anyhow::Error; 6use firecracker_prepare::command::run_command_with_stdout_inherit; 7 8use crate::types::VmOptions; 9 10pub fn setup_tailscale(name: &str, config: &VmOptions) -> Result<(), Error> { 11 if let Some(tailscale) = &config.tailscale { 12 if let Some(auth_key) = &tailscale.auth_key { 13 let len = auth_key.len(); 14 let display_key = if len > 16 { 15 format!("{}****{}", &auth_key[..16], &auth_key[len - 4..]) 16 } else { 17 return Err(anyhow!("Tailscale auth key is too short")); 18 }; 19 println!("[+] Setting up Tailscale with auth key: {}", display_key); 20 let key_path = 21 get_private_key_path().with_context(|| "Failed to get SSH private key path")?; 22 23 let guest_ip = format!("{}.firecracker", name); 24 25 if config.nixos.unwrap_or(false) { 26 run_ssh_command( 27 &key_path, 28 &guest_ip, 29 &format!("tailscale up --auth-key {} --hostname {}", auth_key, name), 30 )?; 31 run_ssh_command(&key_path, &guest_ip, "systemctl status tailscaled || true")?; 32 run_ssh_command(&key_path, &guest_ip, "tailscale status || true")?; 33 println!("[+] Tailscale setup completed."); 34 return Ok(()); 35 } 36 37 run_ssh_command(&key_path, &guest_ip, "rm -f /etc/security/namespace.init")?; 38 39 if config.alpine.unwrap_or(false) { 40 run_ssh_command(&key_path, &guest_ip, "apk add openrc")?; 41 } 42 43 if config.gentoo.unwrap_or(false) { 44 run_ssh_command(&key_path, &guest_ip, "emerge --sync")?; 45 run_ssh_command(&key_path, &guest_ip, "emerge net-misc/curl")?; 46 } 47 48 if config.slackware.unwrap_or(false) { 49 // run_ssh_command(&key_path, &guest_ip, "slackpkg update")?; 50 run_ssh_command( 51 &key_path, 52 &guest_ip, 53 "yes | slackpkg install nghttp2 brotli zstd libidn2 libpsl cyrus-sasl perl", 54 )?; 55 run_ssh_command(&key_path, &guest_ip, "update-ca-certificates --fresh")?; 56 } 57 58 run_ssh_command( 59 &key_path, 60 &guest_ip, 61 "type tailscaled || curl -fsSL https://tailscale.com/install.sh | sh", 62 )?; 63 64 if config.alpine.unwrap_or(false) || config.slackware.unwrap_or(false) { 65 run_ssh_command( 66 &key_path, 67 &guest_ip, 68 &format!("tailscale up --auth-key {} --hostname {}", auth_key, name), 69 )?; 70 run_ssh_command(&key_path, &guest_ip, "rc-status")?; 71 } else { 72 run_ssh_command( 73 &key_path, 74 &guest_ip, 75 "systemctl enable tailscaled && systemctl start tailscaled || true", 76 )?; 77 run_ssh_command( 78 &key_path, 79 &guest_ip, 80 &format!("tailscale up --auth-key {} --hostname {}", auth_key, name), 81 )?; 82 run_ssh_command(&key_path, &guest_ip, "systemctl status tailscaled || true")?; 83 } 84 85 run_ssh_command(&key_path, &guest_ip, "tailscale status || true")?; 86 87 println!("[+] Tailscale setup completed."); 88 return Ok(()); 89 } 90 } 91 92 println!("[+] Tailscale auth key not provided, skipping Tailscale setup."); 93 Ok(()) 94} 95 96fn run_ssh_command(key_path: &str, guest_ip: &str, command: &str) -> Result<(), Error> { 97 run_command_with_stdout_inherit( 98 "ssh", 99 &[ 100 "-i", 101 key_path, 102 "-o", 103 "StrictHostKeyChecking=no", 104 "-o", 105 "UserKnownHostsFile=/dev/null", 106 &format!("root@{}", guest_ip), 107 command, 108 ], 109 false, 110 )?; 111 Ok(()) 112} 113 114fn get_private_key_path() -> Result<String, Error> { 115 let home_dir = dirs::home_dir().ok_or_else(|| anyhow!("Failed to get home directory"))?; 116 let app_dir = format!("{}/.fireup", home_dir.display()); 117 let key_name = glob::glob(format!("{}/id_rsa", app_dir).as_str()) 118 .with_context(|| "Failed to glob ssh key files")? 119 .last() 120 .ok_or_else(|| anyhow!("No SSH key file found"))? 121 .with_context(|| "Failed to get SSH key path")?; 122 let key_name = fs::canonicalize(&key_name) 123 .with_context(|| { 124 format!( 125 "Failed to resolve absolute path for SSH key: {}", 126 key_name.display() 127 ) 128 })? 129 .display() 130 .to_string(); 131 Ok(key_name) 132}