diff --git a/src/quardle/mod.rs b/src/quardle/mod.rs index fb0480f..6b74145 100644 --- a/src/quardle/mod.rs +++ b/src/quardle/mod.rs @@ -3,9 +3,12 @@ use flate2::Compression; use flate2::write::GzEncoder; use serde::{Deserialize, Serialize}; use serde_json; +use std::process::Command; /// Constances declarations -const QUARDLE_BUILD_DIR: &str = "/tmp/quark/builds/"; +const QUARK_BUILD_DIR: &str = "/tmp/quark/builds/"; +const QUARK_CONFIG_DIR: &str = "/opt/quark/"; + const QUARDLE_KERNEL: &str = "bzImage"; const QUARDLE_INITRD: &str = "rootfs/"; const QUARDLE_KERNEL_CMDLINE: &str = "/proc/cmdline"; @@ -40,14 +43,17 @@ impl Quardle { /// Build a quardle from instance variables /// If delete is true, delete the quardle temporary files after building pub fn build(&self, delete_after: Option) -> Result<()> { - // creating working directory at /tmp/quark/builds/ + // creating working directory create_dir_all(self.clone().get_work_dir()).unwrap(); - // Creating the quardle self + .setup() + .add_kernel() + .add_init_rd() + .add_kaps() .add_config_file() .make_archive()?; - + // Deleting temporary files used to build the quardle if delete_after.unwrap_or(false) { self.delete().unwrap(); @@ -73,7 +79,142 @@ impl Quardle { /// /tmp/quark/builds// /// Used to create temporary files used to build quardle fn get_work_dir(self) -> String { - format!("{}{}/", QUARDLE_BUILD_DIR, self.name) + format!("{}{}/", QUARK_BUILD_DIR, self.name) + } + + /// Setup default quark configuration + /// Create a `quark` directory in /opt + fn setup(&self) -> &Quardle { + // Create the quark configuration directory + if !std::path::Path::new(&format!("{}", QUARK_CONFIG_DIR)).exists() { + println!("Quark configuration directory does not exist, creating it !"); + Command::new("mkdir") + .arg("/opt/quark") + .output() + .expect("failed to setup quark"); + } + + // Install kaps sources + if !std::path::Path::new(&format!("{}kaps", QUARK_CONFIG_DIR)).exists() { + println!("Kaps not found, installing it !"); + Command::new("git") + .args(["clone", "https://github.com/virt-do/kaps.git"]) // Using https protocol because it seems not supporting ssh + .current_dir(format!("{}", QUARK_CONFIG_DIR)) + .output() + .expect("failed to fetch kaps"); + } + + // Install a default kernel configuration file + if !std::path::Path::new(&format!("{}linux-config-x86_64", QUARK_CONFIG_DIR)).exists() { + println!("Kernel config file not found, installing it !"); + Command::new("curl") + .arg("https://raw.githubusercontent.com/virt-do/lab/main/do-vmm/kernel/linux-config-x86_64") + .arg("-O") + .current_dir(format!("{}", QUARK_CONFIG_DIR)) + .output() + .expect("failed to fetch kernel config file"); + } + + // Install a script to build kernel + if !std::path::Path::new(&format!("{}kernel", QUARK_CONFIG_DIR)).exists() { + println!("Kernel not found, installing and building it !"); + Command::new("git") + .arg("clone") + .args(["--depth", "1"]) + .arg("https://github.com/cloud-hypervisor/linux.git") // Using https protocol because it seems not supporting ssh + .args(["-b", "ch-5.14"]) + .arg("kernel") + .current_dir(format!("{}", QUARK_CONFIG_DIR)) + .output() + .expect("failed to download kernel builder"); + // Use our config file + Command::new("cp") + .arg(format!("{}linux-config-x86_64", QUARK_CONFIG_DIR)) + .arg(format!("{}kernel/.config", QUARK_CONFIG_DIR)) + .output() + .expect("failed to copy kernel config"); + + // Building kernel binary + // FIXME: It seems that the build process is not working properly, command is stopped during build process + Command::new("make") + .arg("bzImage") + .args(["-j", "nproc"]) + .current_dir(format!("{}kernel", QUARK_CONFIG_DIR)) + .status() // Here we are using status because we have to wait the command to finish + .expect("failed to build kernel binary"); + } + + self + } + + /// Append kernel configuration + /// Fetch automated script if isn't already installed, and use some bash script to build it + fn add_kernel(&self) -> &Quardle { + println!("Installing kernel binary !"); + Command::new("cp") + .arg(format!("{}arch/x86/boot/bzImage", QUARK_CONFIG_DIR)) + .arg(format!("{}/", self.clone().get_work_dir())) + .spawn() + .expect("failed to copy kernel"); + self + } + + /// Append basic rootfs + /// Fetch automated script if isn't already installed, and use some bash script to build it + fn add_init_rd(&self) -> &Quardle { + println!("Installing initRamFS"); + Command::new("curl") + .arg("https://dl-cdn.alpinelinux.org/alpine/v3.14/releases/x86_64/alpine-minirootfs-3.14.2-x86_64.tar.gz") + .arg("-O") + .current_dir(self.clone().get_work_dir()) + .output() + .expect("failed to download alpine image"); + Command::new("mkdir") + .arg(QUARDLE_INITRD) + .current_dir(self.clone().get_work_dir()) + .output() + .expect("failed to create rootfs folder"); + Command::new("tar") + .arg("-xf") + .arg("alpine-minirootfs-3.14.2-x86_64.tar.gz") + .args(["-C", QUARDLE_INITRD]) + .current_dir(self.clone().get_work_dir()) + .output() + .expect("failed to untar alpine image"); + Command::new("rm") + .arg("-f") + .arg("alpine-minirootfs-3.14.2-x86_64.tar.gz") + .current_dir(self.clone().get_work_dir()) + .output() + .expect("failed to delete downloaded archive"); + Command::new("runc") + .arg("spec") + .arg("--rootless") + .current_dir(self.clone().get_work_dir()) + .output() + .expect("failed to generate runtime spec"); + self + } + + /// Append kaps binary to builded image + /// Fetch kaps source code if isn't already installed, build it from source and copy it to the working directory + fn add_kaps(&self) -> &Quardle { + Command::new("cargo") + .current_dir(format!("{}kaps", QUARK_CONFIG_DIR)) + .arg("build") + .arg("--release") + // .arg("--out-dir") //TODO: outdir is only available on nightly for now, should be used later + // .arg(format!("{}/rootfs/usr/bin/kaps",self.clone().get_work_dir())) + .output() + .expect("failed to build kaps"); + + Command::new("cp") + .arg(format!("{}kaps/target/release/kaps", QUARK_CONFIG_DIR)) + .arg(format!("{}/rootfs/usr/bin/kaps",self.clone().get_work_dir())) + .output() + .expect("failed to copy kaps"); + + self } /// Generate the config file of the quardle @@ -110,7 +251,7 @@ impl Quardle { #[cfg(test)] mod tests { - use super::*; + use super::*; #[test] fn quardle_new() {