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

Configure Feed

Select the types of activity you want to include in your feed.

refactors firecracker prepare

+275 -236
+255 -213
crates/firecracker-prepare/src/lib.rs
··· 13 13 14 14 pub const GUEST_IP: &str = "172.16.0.2"; 15 15 16 - #[derive(Default, Clone)] 17 - pub struct PrepareOptions { 18 - pub debian: Option<bool>, 19 - pub alpine: Option<bool>, 20 - pub ubuntu: Option<bool>, 21 - pub nixos: Option<bool>, 16 + #[derive(Clone, Copy, PartialEq)] 17 + pub enum Distro { 18 + Debian, 19 + Alpine, 20 + Ubuntu, 21 + NixOS, 22 22 } 23 23 24 - pub fn prepare(options: PrepareOptions) -> Result<()> { 25 - let arch = command::run_command("uname", &["-m"], false)?.stdout; 26 - let arch = String::from_utf8_lossy(&arch).trim().to_string(); 24 + pub trait RootfsPreparer { 25 + fn prepare(&self, arch: &str, app_dir: &str) -> Result<(String, String, String)>; 26 + fn name(&self) -> &'static str; 27 + } 27 28 28 - println!("[+] Detected architecture: {}", arch.bright_green()); 29 + pub struct DebianPreparer; 30 + pub struct AlpinePreparer; 31 + pub struct UbuntuPreparer; 32 + pub struct NixOSPreparer; 29 33 30 - let (kernel_file, ext4_file, ssh_key_file) = match ( 31 - options.debian, 32 - options.alpine, 33 - options.ubuntu, 34 - options.nixos, 35 - ) { 36 - (Some(true), _, _, _) => prepare_debian(&arch)?, 37 - (_, Some(true), _, _) => prepare_alpine(&arch)?, 38 - (_, _, _, Some(true)) => prepare_nixos(&arch)?, 39 - (_, _, Some(true), _) => prepare_ubuntu(&arch)?, 40 - _ => { 41 - return Err(anyhow::anyhow!("No valid rootfs option provided.")); 42 - } 43 - }; 34 + impl RootfsPreparer for DebianPreparer { 35 + fn name(&self) -> &'static str { 36 + "Debian" 37 + } 44 38 45 - println!("[✓] Kernel: {}", kernel_file.bright_green()); 46 - println!("[✓] Rootfs: {}", ext4_file.bright_green()); 47 - println!("[✓] SSH Key: {}", ssh_key_file.bright_green()); 39 + fn prepare(&self, arch: &str, app_dir: &str) -> Result<(String, String, String)> { 40 + println!( 41 + "[+] Preparing {} rootfs for {}...", 42 + self.name(), 43 + arch.bright_green() 44 + ); 45 + let kernel_file = downloader::download_kernel(arch)?; 46 + let debootstrap_dir = format!("{}/debootstrap", app_dir); 48 47 49 - Ok(()) 50 - } 48 + let arch = match arch { 49 + "x86_64" => "amd64", 50 + "aarch64" => "arm64", 51 + _ => arch, 52 + }; 51 53 52 - pub fn prepare_ubuntu(arch: &str) -> Result<(String, String, String)> { 53 - println!("[+] Preparing Ubuntu rootfs for {}...", arch.bright_green()); 54 - let (kernel_file, ubuntu_file, ubuntu_version) = downloader::download_files(arch)?; 54 + if !std::path::Path::new(&debootstrap_dir).exists() { 55 + fs::create_dir_all(&debootstrap_dir)?; 56 + run_command_with_stdout_inherit( 57 + "debootstrap", 58 + &[ 59 + &format!("--arch={}", arch), 60 + "stable", 61 + &debootstrap_dir, 62 + "http://deb.debian.org/debian/", 63 + ], 64 + true, 65 + )?; 66 + } 55 67 56 - let app_dir = config::get_config_dir()?; 57 - let squashfs_root_dir = format!("{}/squashfs_root", app_dir); 68 + let ssh_key_name = "id_rsa"; 69 + run_command( 70 + "mkdir", 71 + &["-p", &format!("{}/root/.ssh", debootstrap_dir)], 72 + true, 73 + )?; 74 + ssh::generate_and_copy_ssh_key(&ssh_key_name, &debootstrap_dir)?; 58 75 59 - rootfs::extract_squashfs(&ubuntu_file, &squashfs_root_dir)?; 76 + if !run_command("chroot", &[&debootstrap_dir, "which", "sshd"], true) 77 + .map(|output| output.status.success()) 78 + .unwrap_or(false) 79 + { 80 + run_command_with_stdout_inherit( 81 + "chroot", 82 + &[&debootstrap_dir, "apt-get", "update"], 83 + true, 84 + )?; 85 + run_command_with_stdout_inherit( 86 + "chroot", 87 + &[ 88 + &debootstrap_dir, 89 + "apt-get", 90 + "install", 91 + "-y", 92 + "openssh-server", 93 + ], 94 + true, 95 + )?; 96 + run_command( 97 + "chroot", 98 + &[&debootstrap_dir, "systemctl", "enable", "ssh"], 99 + true, 100 + )?; 101 + } 60 102 61 - let ssh_key_name = "id_rsa"; 62 - ssh::generate_and_copy_ssh_key(&ssh_key_name, &squashfs_root_dir)?; 103 + let ext4_file = format!("{}/debian-{}.ext4", app_dir, arch); 104 + if !std::path::Path::new(&ext4_file).exists() { 105 + rootfs::create_ext4_filesystem(&debootstrap_dir, &ext4_file, 600)?; 106 + } 63 107 64 - let ext4_file = format!("{}/ubuntu-{}.ext4", app_dir, ubuntu_version); 108 + let ssh_key_file = format!("{}/{}", app_dir, ssh_key_name); 65 109 66 - if !std::path::Path::new(&ext4_file).exists() { 67 - rootfs::create_ext4_filesystem(&squashfs_root_dir, &ext4_file, 400)?; 68 - } else { 69 - println!( 70 - "[!] {} already exists, skipping ext4 creation.", 71 - ext4_file.bright_yellow() 72 - ); 110 + Ok((kernel_file, ext4_file, ssh_key_file)) 73 111 } 74 - 75 - let ssh_key_file = format!("{}/{}", app_dir, ssh_key_name); 76 - 77 - Ok((kernel_file, ext4_file, ssh_key_file)) 78 112 } 79 113 80 - pub fn prepare_debian(arch: &str) -> Result<(String, String, String)> { 81 - println!("[+] Preparing Debian rootfs for {}...", arch.bright_green()); 82 - let kernel_file = downloader::download_kernel(arch)?; 83 - let app_dir = config::get_config_dir()?; 84 - let debootstrap_dir: &str = &format!("{}/debootstrap", app_dir); 114 + impl RootfsPreparer for AlpinePreparer { 115 + fn name(&self) -> &'static str { 116 + "Alpine" 117 + } 85 118 86 - let arch = match arch { 87 - "x86_64" => "amd64", 88 - "aarch64" => "arm64", 89 - _ => arch, 90 - }; 119 + fn prepare(&self, arch: &str, app_dir: &str) -> Result<(String, String, String)> { 120 + println!( 121 + "[+] Preparing {} rootfs for {}...", 122 + self.name(), 123 + arch.bright_green() 124 + ); 125 + let kernel_file = downloader::download_kernel(arch)?; 126 + let minirootfs = format!("{}/minirootfs", app_dir); 127 + downloader::download_alpine_rootfs(&minirootfs, arch)?; 91 128 92 - if !std::path::Path::new(debootstrap_dir).exists() { 93 - fs::create_dir_all(debootstrap_dir)?; 94 - run_command_with_stdout_inherit( 95 - "debootstrap", 129 + run_command( 130 + "sh", 96 131 &[ 97 - &format!("--arch={}", arch), 98 - "stable", 99 - debootstrap_dir, 100 - "http://deb.debian.org/debian/", 132 + "-c", 133 + &format!("echo 'nameserver 8.8.8.8' > {}/etc/resolv.conf", minirootfs), 101 134 ], 102 135 true, 103 136 )?; 104 - } 137 + if !run_command("chroot", &[&minirootfs, "which", "sshd"], true) 138 + .map(|output| output.status.success()) 139 + .unwrap_or(false) 140 + { 141 + run_command_with_stdout_inherit("chroot", &[&minirootfs, "apk", "update"], true)?; 142 + run_command_with_stdout_inherit( 143 + "chroot", 144 + &[ 145 + &minirootfs, 146 + "apk", 147 + "add", 148 + "alpine-base", 149 + "util-linux", 150 + "linux-virt", 151 + "haveged", 152 + "openssh", 153 + ], 154 + true, 155 + )?; 156 + } 105 157 106 - let ssh_key_name = "id_rsa"; 107 - run_command( 108 - "mkdir", 109 - &["-p", &format!("{}/root/.ssh", debootstrap_dir)], 110 - true, 111 - )?; 112 - ssh::generate_and_copy_ssh_key(&ssh_key_name, &debootstrap_dir)?; 113 - 114 - if !run_command("chroot", &[debootstrap_dir, "which", "sshd"], true) 115 - .map(|output| output.status.success()) 116 - .unwrap_or(false) 117 - { 118 - run_command_with_stdout_inherit("chroot", &[debootstrap_dir, "apt-get", "update"], true)?; 119 158 run_command_with_stdout_inherit( 120 159 "chroot", 160 + &[&minirootfs, "rc-update", "add", "haveged"], 161 + true, 162 + )?; 163 + run_command( 164 + "chroot", 121 165 &[ 122 - debootstrap_dir, 123 - "apt-get", 124 - "install", 125 - "-y", 126 - "openssh-server", 166 + &minirootfs, 167 + "sh", 168 + "-c", 169 + "for svc in devfs procfs sysfs; do ln -fs /etc/init.d/$svc /etc/runlevels/boot; done", 127 170 ], 128 171 true, 129 172 )?; 173 + if !run_command( 174 + "chroot", 175 + &[ 176 + &minirootfs, 177 + "ln", 178 + "-s", 179 + "agetty", 180 + "/etc/init.d/agetty.ttyS0", 181 + ], 182 + true, 183 + ) 184 + .map(|output| output.status.success()) 185 + .unwrap_or(false) 186 + { 187 + println!("[!] Failed to create symlink for agetty.ttyS0, please check manually."); 188 + } 189 + run_command_with_stdout_inherit( 190 + "chroot", 191 + &[&minirootfs, "sh", "-c", "echo ttyS0 > /etc/securetty"], 192 + true, 193 + )?; 130 194 run_command( 131 195 "chroot", 132 - &[debootstrap_dir, "systemctl", "enable", "ssh"], 196 + &[&minirootfs, "rc-update", "add", "agetty.ttyS0", "default"], 133 197 true, 134 198 )?; 135 - } 136 199 137 - let ext4_file = format!("{}/debian-{}.ext4", app_dir, arch); 138 - if !std::path::Path::new(&ext4_file).exists() { 139 - rootfs::create_ext4_filesystem(debootstrap_dir, &ext4_file, 600)?; 140 - } 141 - 142 - let ssh_key_file = format!("{}/{}", app_dir, ssh_key_name); 143 - 144 - Ok((kernel_file, ext4_file, ssh_key_file)) 145 - } 200 + run_command("chroot", &[&minirootfs, "rc-update", "add", "sshd"], true)?; 201 + run_command( 202 + "chroot", 203 + &[&minirootfs, "rc-update", "add", "networking", "boot"], 204 + true, 205 + )?; 206 + run_command( 207 + "chroot", 208 + &[&minirootfs, "mkdir", "-p", "/root/.ssh", "/etc/network"], 209 + true, 210 + )?; 146 211 147 - pub fn prepare_alpine(arch: &str) -> Result<(String, String, String)> { 148 - println!("[+] Preparing Alpine rootfs for {}...", arch.bright_green()); 149 - let kernel_file = downloader::download_kernel(arch)?; 150 - let app_dir = config::get_config_dir()?; 151 - let minirootfs = format!("{}/minirootfs", app_dir); 152 - downloader::download_alpine_rootfs(&minirootfs, arch)?; 153 - 154 - run_command( 155 - "sh", 156 - &[ 157 - "-c", 158 - &format!("echo 'nameserver 8.8.8.8' > {}/etc/resolv.conf", minirootfs), 159 - ], 160 - true, 161 - )?; 162 - if !run_command("chroot", &[&minirootfs, "which", "sshd"], true) 163 - .map(|output| output.status.success()) 164 - .unwrap_or(false) 165 - { 166 - run_command_with_stdout_inherit("chroot", &[&minirootfs, "apk", "update"], true)?; 167 - run_command_with_stdout_inherit( 212 + run_command( 168 213 "chroot", 169 214 &[ 170 215 &minirootfs, 171 - "apk", 172 - "add", 173 - "alpine-base", 174 - "util-linux", 175 - "linux-virt", 176 - "haveged", 177 - "openssh", 216 + "sh", 217 + "-c", 218 + &format!("echo 'auto eth0\niface eth0 inet static\n address {}\n netmask 255.255.255.0\n gateway 172.16.0.1\n' > /etc/network/interfaces", GUEST_IP), 178 219 ], 179 220 true, 180 221 )?; 222 + 223 + let ssh_key_name = "id_rsa"; 224 + ssh::generate_and_copy_ssh_key(&ssh_key_name, &minirootfs)?; 225 + 226 + let ext4_file = format!("{}/alpine-{}.ext4", app_dir, arch); 227 + if !std::path::Path::new(&ext4_file).exists() { 228 + rootfs::create_ext4_filesystem(&minirootfs, &ext4_file, 500)?; 229 + } 230 + 231 + let ssh_key_file = format!("{}/{}", app_dir, ssh_key_name); 232 + 233 + Ok((kernel_file, ext4_file, ssh_key_file)) 181 234 } 235 + } 182 236 183 - run_command_with_stdout_inherit( 184 - "chroot", 185 - &[&minirootfs, "rc-update", "add", "haveged"], 186 - true, 187 - )?; 188 - run_command( 189 - "chroot", 190 - &[ 191 - &minirootfs, 192 - "sh", 193 - "-c", 194 - "for svc in devfs procfs sysfs; do ln -fs /etc/init.d/$svc /etc/runlevels/boot; done", 195 - ], 196 - true, 197 - )?; 198 - if !run_command( 199 - "chroot", 200 - &[ 201 - &minirootfs, 202 - "ln", 203 - "-s", 204 - "agetty", 205 - "/etc/init.d/agetty.ttyS0", 206 - ], 207 - true, 208 - ) 209 - .map(|output| output.status.success()) 210 - .unwrap_or(false) 211 - { 212 - println!("[!] Failed to create symlink for agetty.ttyS0, please check manually."); 237 + impl RootfsPreparer for UbuntuPreparer { 238 + fn name(&self) -> &'static str { 239 + "Ubuntu" 213 240 } 214 - run_command_with_stdout_inherit( 215 - "chroot", 216 - &[&minirootfs, "sh", "-c", "echo ttyS0 > /etc/securetty"], 217 - true, 218 - )?; 219 - run_command( 220 - "chroot", 221 - &[&minirootfs, "rc-update", "add", "agetty.ttyS0", "default"], 222 - true, 223 - )?; 224 241 225 - run_command("chroot", &[&minirootfs, "rc-update", "add", "sshd"], true)?; 226 - run_command( 227 - "chroot", 228 - &[&minirootfs, "rc-update", "add", "networking", "boot"], 229 - true, 230 - )?; 231 - run_command( 232 - "chroot", 233 - &[&minirootfs, "mkdir", "-p", "/root/.ssh", "/etc/network"], 234 - true, 235 - )?; 242 + fn prepare(&self, arch: &str, app_dir: &str) -> Result<(String, String, String)> { 243 + println!( 244 + "[+] Preparing {} rootfs for {}...", 245 + self.name(), 246 + arch.bright_green() 247 + ); 248 + let (kernel_file, ubuntu_file, ubuntu_version) = downloader::download_files(arch)?; 249 + 250 + let squashfs_root_dir = format!("{}/squashfs_root", app_dir); 251 + rootfs::extract_squashfs(&ubuntu_file, &squashfs_root_dir)?; 252 + 253 + let ssh_key_name = "id_rsa"; 254 + ssh::generate_and_copy_ssh_key(&ssh_key_name, &squashfs_root_dir)?; 255 + 256 + let ext4_file = format!("{}/ubuntu-{}.ext4", app_dir, ubuntu_version); 257 + if !std::path::Path::new(&ext4_file).exists() { 258 + rootfs::create_ext4_filesystem(&squashfs_root_dir, &ext4_file, 400)?; 259 + } else { 260 + println!( 261 + "[!] {} already exists, skipping ext4 creation.", 262 + ext4_file.bright_yellow() 263 + ); 264 + } 236 265 237 - run_command( 238 - "chroot", 239 - &[ 240 - &minirootfs, 241 - "sh", 242 - "-c", 243 - &format!("echo 'auto eth0\niface eth0 inet static\n address {}\n netmask 255.255.255.0\n gateway 172.16.0.1\n' > /etc/network/interfaces", GUEST_IP), 244 - ], 245 - true, 246 - )?; 266 + let ssh_key_file = format!("{}/{}", app_dir, ssh_key_name); 247 267 248 - let ssh_key_name = "id_rsa"; 249 - ssh::generate_and_copy_ssh_key(&ssh_key_name, &minirootfs)?; 268 + Ok((kernel_file, ext4_file, ssh_key_file)) 269 + } 270 + } 250 271 251 - let ext4_file = format!("{}/alpine-{}.ext4", app_dir, arch); 252 - if !std::path::Path::new(&ext4_file).exists() { 253 - rootfs::create_ext4_filesystem(&minirootfs, &ext4_file, 500)?; 272 + impl RootfsPreparer for NixOSPreparer { 273 + fn name(&self) -> &'static str { 274 + "NixOS" 254 275 } 255 276 256 - let ssh_key_file = format!("{}/{}", app_dir, ssh_key_name); 277 + fn prepare(&self, arch: &str, app_dir: &str) -> Result<(String, String, String)> { 278 + println!( 279 + "[+] Preparing {} rootfs for {}...", 280 + self.name(), 281 + arch.bright_green() 282 + ); 283 + let kernel_file = downloader::download_kernel(arch)?; 284 + let nixos_rootfs = format!("{}/nixosrootfs", app_dir); 285 + let squashfs_file = format!("{}/nixos-rootfs.squashfs", app_dir); 257 286 258 - Ok((kernel_file, ext4_file, ssh_key_file)) 259 - } 287 + downloader::download_nixos_rootfs(arch)?; 288 + rootfs::extract_squashfs(&squashfs_file, &nixos_rootfs)?; 260 289 261 - pub fn prepare_nixos(arch: &str) -> Result<(String, String, String)> { 262 - println!("[+] Preparing NixOS rootfs for {}...", arch.bright_green()); 290 + let ssh_key_name = "id_rsa"; 291 + ssh::generate_and_copy_ssh_key_nixos(&ssh_key_name, &nixos_rootfs)?; 263 292 264 - let kernel_file = downloader::download_kernel(arch)?; 265 - let app_dir = config::get_config_dir()?; 266 - let nixos_rootfs = format!("{}/nixosrootfs", app_dir); 267 - let squashfs_file = format!("{}/nixos-rootfs.squashfs", app_dir); 293 + let ext4_file = format!("{}/nixos-rootfs.ext4", app_dir); 294 + if !std::path::Path::new(&ext4_file).exists() { 295 + rootfs::create_ext4_filesystem(&nixos_rootfs, &ext4_file, 5120)?; 296 + } 268 297 269 - downloader::download_nixos_rootfs(arch)?; 270 - rootfs::extract_squashfs(&squashfs_file, &nixos_rootfs)?; 298 + let ssh_key_file = format!("{}/{}", app_dir, ssh_key_name); 271 299 272 - let ssh_key_name = "id_rsa"; 273 - ssh::generate_and_copy_ssh_key_nixos(&ssh_key_name, &nixos_rootfs)?; 300 + println!( 301 + "[+] {} rootfs prepared at: {}", 302 + self.name(), 303 + nixos_rootfs.bright_green() 304 + ); 274 305 275 - let ext4_file = format!("{}/{}", app_dir, "nixos-rootfs.ext4"); 276 - if !std::path::Path::new(&ext4_file).exists() { 277 - rootfs::create_ext4_filesystem(&nixos_rootfs, &ext4_file, 5120)?; 306 + Ok((kernel_file, ext4_file, ssh_key_file)) 278 307 } 308 + } 279 309 280 - let ssh_key_file = format!("{}/{}", app_dir, ssh_key_name); 310 + pub fn prepare(distro: Distro) -> Result<()> { 311 + let arch = run_command("uname", &["-m"], false)?.stdout; 312 + let arch = String::from_utf8_lossy(&arch).trim().to_string(); 313 + println!("[+] Detected architecture: {}", arch.bright_green()); 314 + 315 + let app_dir = config::get_config_dir()?; 316 + let preparer: Box<dyn RootfsPreparer> = match distro { 317 + Distro::Debian => Box::new(DebianPreparer), 318 + Distro::Alpine => Box::new(AlpinePreparer), 319 + Distro::Ubuntu => Box::new(UbuntuPreparer), 320 + Distro::NixOS => Box::new(NixOSPreparer), 321 + }; 281 322 282 - println!( 283 - "[+] NixOS rootfs prepared at: {}", 284 - nixos_rootfs.bright_green() 285 - ); 323 + let (kernel_file, ext4_file, ssh_key_file) = preparer.prepare(&arch, &app_dir)?; 286 324 287 - Ok((kernel_file, ext4_file.into(), ssh_key_file)) 325 + println!("[✓] Kernel: {}", kernel_file.bright_green()); 326 + println!("[✓] Rootfs: {}", ext4_file.bright_green()); 327 + println!("[✓] SSH Key: {}", ssh_key_file.bright_green()); 328 + 329 + Ok(()) 288 330 }
+13 -8
crates/firecracker-up/src/cmd/up.rs
··· 1 1 use std::thread; 2 2 3 3 use anyhow::Error; 4 - use firecracker_prepare::PrepareOptions; 4 + use firecracker_prepare::Distro; 5 5 use owo_colors::OwoColorize; 6 6 7 7 use crate::command::run_command; ··· 14 14 pub nixos: Option<bool>, 15 15 } 16 16 17 - impl Into<PrepareOptions> for UpOptions { 18 - fn into(self) -> PrepareOptions { 19 - PrepareOptions { 20 - debian: self.debian, 21 - alpine: self.alpine, 22 - ubuntu: self.ubuntu, 23 - nixos: self.nixos, 17 + impl Into<Distro> for UpOptions { 18 + fn into(self) -> Distro { 19 + if self.debian.unwrap_or(false) { 20 + Distro::Debian 21 + } else if self.alpine.unwrap_or(false) { 22 + Distro::Alpine 23 + } else if self.nixos.unwrap_or(false) { 24 + Distro::NixOS 25 + } else if self.ubuntu.unwrap_or(true) { 26 + Distro::Ubuntu 27 + } else { 28 + panic!("No valid distribution option provided."); 24 29 } 25 30 } 26 31 }
+7 -15
crates/firecracker-vm/src/lib.rs
··· 1 1 use anyhow::{anyhow, Context, Result}; 2 - use firecracker_prepare::PrepareOptions; 2 + use firecracker_prepare::Distro; 3 3 use owo_colors::OwoColorize; 4 4 use std::fs; 5 5 ··· 12 12 mod guest; 13 13 mod network; 14 14 15 - pub fn setup(options: PrepareOptions) -> Result<()> { 15 + pub fn setup(distro: Distro) -> Result<()> { 16 16 let app_dir = get_config_dir().with_context(|| "Failed to get configuration directory")?; 17 17 18 18 let logfile = format!("{}/firecracker.log", app_dir); ··· 34 34 .display() 35 35 .to_string(); 36 36 37 - let ext4_file = match ( 38 - options.debian, 39 - options.alpine, 40 - options.ubuntu, 41 - options.nixos, 42 - ) { 43 - (Some(true), _, _, _) => format!("{}/debian*.ext4", app_dir), 44 - (_, Some(true), _, _) => format!("{}/alpine*.ext4", app_dir), 45 - (_, _, _, Some(true)) => format!("{}/nixos*.ext4", app_dir), 46 - (_, _, Some(true), _) => format!("{}/ubuntu*.ext4", app_dir), 47 - _ => { 48 - return Err(anyhow::anyhow!("No valid rootfs option provided.")); 49 - } 37 + let ext4_file = match distro { 38 + Distro::Debian => format!("{}/debian*.ext4", app_dir), 39 + Distro::Alpine => format!("{}/alpine*.ext4", app_dir), 40 + Distro::NixOS => format!("{}/nixos*.ext4", app_dir), 41 + Distro::Ubuntu => format!("{}/ubuntu*.ext4", app_dir), 50 42 }; 51 43 52 44 let rootfs = glob::glob(&ext4_file)