From 1e6e7c75b82868e36bd77a10c209f541dbc6071a Mon Sep 17 00:00:00 2001 From: Muriel Paraire <72733662+MurielParaire@users.noreply.github.com> Date: Fri, 3 May 2024 22:21:55 +0200 Subject: [PATCH] fix(vmm): code cleanup (#46) * fix(vmm): code cleanup Signed-off-by: Muriel Paraire <72733662+MurielParaire@users.noreply.github.com> * fix: lint Signed-off-by: Muriel Paraire <72733662+MurielParaire@users.noreply.github.com> --------- Signed-off-by: Muriel Paraire <72733662+MurielParaire@users.noreply.github.com> --- src/vmm/src/core/vmm.rs | 6 +- src/vmm/src/grpc/server.rs | 239 ++++++++++++++++++++----------------- src/vmm/src/lib.rs | 1 + src/vmm/src/main.rs | 2 +- 4 files changed, 132 insertions(+), 116 deletions(-) diff --git a/src/vmm/src/core/vmm.rs b/src/vmm/src/core/vmm.rs index 4eb2ce6..d3e6ca5 100644 --- a/src/vmm/src/core/vmm.rs +++ b/src/vmm/src/core/vmm.rs @@ -13,7 +13,7 @@ use std::io::{self, stdout, Stdout}; use std::net::Ipv4Addr; use std::os::unix::io::AsRawFd; use std::os::unix::prelude::RawFd; -use std::path::{Path, PathBuf}; +use std::path::PathBuf; use std::sync::{Arc, Mutex}; use std::thread; use tracing::info; @@ -339,7 +339,7 @@ impl VMM { &mut self, num_vcpus: u8, mem_size_mb: u32, - kernel_path: &Path, + kernel_path: PathBuf, initramfs_path: &Option, ) -> Result<()> { let cmdline_extra_parameters = &mut Vec::new(); @@ -350,7 +350,7 @@ impl VMM { let kernel_load = kernel::kernel_setup( &self.guest_memory, - kernel_path.to_path_buf(), + kernel_path, initramfs_path.clone(), cmdline_extra_parameters, )?; diff --git a/src/vmm/src/grpc/server.rs b/src/vmm/src/grpc/server.rs index e5c6919..a478656 100644 --- a/src/vmm/src/grpc/server.rs +++ b/src/vmm/src/grpc/server.rs @@ -4,6 +4,7 @@ use self::vmmorchestrator::{ use crate::grpc::client::agent::ExecuteRequest; use crate::VmmErrors; use crate::{core::vmm::VMM, grpc::client::WorkloadClient}; +use std::ffi::OsStr; use std::time::Duration; use std::{ convert::From, @@ -34,6 +35,9 @@ impl From for Status { VmmErrors::VmmNew(_) => Status::internal("Error creating VMM"), VmmErrors::VmmConfigure(_) => Status::internal("Error configuring VMM"), VmmErrors::VmmRun(_) => Status::internal("Error running VMM"), + VmmErrors::VmmBuildEnvironment(_) => { + Status::internal("Error while compiling the necessary files for the VMM") + } } } } @@ -41,6 +45,110 @@ impl From for Status { #[derive(Default)] pub struct VmmService; +impl VmmService { + pub fn get_initramfs( + &self, + language: &str, + curr_dir: &OsStr, + ) -> std::result::Result { + // define initramfs file placement + let mut initramfs_entire_file_path = curr_dir.to_os_string(); + initramfs_entire_file_path.push(&format!("/tools/rootfs/{language}.img")); + // set image name + let image = format!("{language}:alpine"); + + // check if an initramfs already exists + let rootfs_exists = Path::new(&initramfs_entire_file_path) + .try_exists() + .map_err(VmmErrors::VmmBuildEnvironment)?; + if !rootfs_exists { + // build the agent + let agent_file_name = self.get_path( + curr_dir, + "/target/x86_64-unknown-linux-musl/release/agent", + "cargo", + vec![ + "build", + "--release", + "--bin", + "agent", + "--target=x86_64-unknown-linux-musl", + ], + )?; + // build initramfs + info!("Building initramfs"); + let _ = self + .run_command( + "sh", + vec![ + "./tools/rootfs/mkrootfs.sh", + &image, + &agent_file_name.to_str().unwrap(), + &initramfs_entire_file_path.to_str().unwrap(), + ], + ) + .map_err(VmmErrors::VmmBuildEnvironment); + } + Ok(PathBuf::from(&initramfs_entire_file_path)) + } + + pub fn run_command( + &self, + command_type: &str, + args: Vec<&str>, + ) -> std::result::Result<(), std::io::Error> { + // Execute the script using sh and capture output and error streams + Command::new(command_type) + .args(args) + .stdout(Stdio::inherit()) + .stderr(Stdio::inherit()) + .output() + .expect("Failed to execute the script"); + Ok(()) + } + + pub fn get_path( + &self, + curr_dir: &OsStr, + end_path: &str, + command_type: &str, + args: Vec<&str>, + ) -> std::result::Result { + // define file path + let mut entire_path = curr_dir.to_os_string(); + entire_path.push(end_path); + + // Check if the file is on the system, else build it + let exists = Path::new(&entire_path) + .try_exists() + .map_err(VmmErrors::VmmBuildEnvironment)?; + + if !exists { + info!("File {:?} not found, building it", &entire_path); + let _ = self + .run_command(command_type, args) + .map_err(VmmErrors::VmmBuildEnvironment); + info!("File {:?} successfully build", &entire_path); + }; + Ok(PathBuf::from(&entire_path)) + } + + pub fn get_agent_request( + &self, + vmm_request: RunVmmRequest, + language: String, + ) -> ExecuteRequest { + // Send the grpc request to start the agent + ExecuteRequest { + workload_name: vmm_request.workload_name, + language, + action: 2, // Prepare and run + code: vmm_request.code, + config_str: "[build]\nrelease = true".to_string(), + } + } +} + #[tonic::async_trait] impl VmmServiceTrait for VmmService { type RunStream = @@ -54,108 +162,26 @@ impl VmmServiceTrait for VmmService { const GUEST_IP: Ipv4Addr = Ipv4Addr::new(172, 29, 0, 2); // get current directory - let mut curr_dir = - current_dir().expect("Need to be able to access current directory path."); - - // define kernel path - let mut kernel_entire_path = curr_dir.as_os_str().to_owned(); - kernel_entire_path - .push("/tools/kernel/linux-cloud-hypervisor/arch/x86/boot/compressed/vmlinux.bin"); - - // Check if the kernel is on the system, else build it - let kernel_exists = Path::new(&kernel_entire_path) - .try_exists() - .unwrap_or_else(|_| panic!("Could not access folder {:?}", &kernel_entire_path)); - - if !kernel_exists { - info!("Kernel not found, building kernel"); - // Execute the script using sh and capture output and error streams - let output = Command::new("sh") - .arg("./tools/kernel/mkkernel.sh") - .stdout(Stdio::piped()) - .stderr(Stdio::piped()) - .output() - .expect("Failed to execute the kernel build script"); - - // Print output and error streams - info!("Script output: {}", String::from_utf8_lossy(&output.stdout)); - error!("Script errors: {}", String::from_utf8_lossy(&output.stderr)); - }; - let kernel_path = Path::new(&kernel_entire_path); - - // define initramfs file placement - let mut initramfs_entire_file_path = curr_dir.as_os_str().to_owned(); - initramfs_entire_file_path.push("/tools/rootfs/"); + let curr_dir = current_dir() + .map_err(VmmErrors::VmmBuildEnvironment)? + .into_os_string(); + + // build kernel if necessary + let kernel_path: PathBuf = self.get_path( + &curr_dir, + "/tools/kernel/linux-cloud-hypervisor/arch/x86/boot/compressed/vmlinux.bin", + "sh", + vec!["./tools/kernel/mkkernel.sh"], + )?; // get request with the language let vmm_request = request.into_inner(); - let language: Language = - Language::from_i32(vmm_request.language).expect("Unknown language"); - - let image = match language { - Language::Rust => { - initramfs_entire_file_path.push("rust.img"); - "rust:alpine" - } - Language::Python => { - initramfs_entire_file_path.push("python.img"); - "python:alpine" - } - Language::Node => { - initramfs_entire_file_path.push("node.img"); - "node:alpine" - } - }; - - let rootfs_exists = Path::new(&initramfs_entire_file_path) - .try_exists() - .unwrap_or_else(|_| { - panic!("Could not access folder {:?}", &initramfs_entire_file_path) - }); - if !rootfs_exists { - // check if agent binary exists - let agent_file_name = curr_dir.as_mut_os_string(); - agent_file_name.push("/target/x86_64-unknown-linux-musl/release/agent"); - - // if agent hasn't been build, build it - let agent_exists = Path::new(&agent_file_name) - .try_exists() - .unwrap_or_else(|_| panic!("Could not access folder {:?}", &agent_file_name)); - if !agent_exists { - //build agent - info!("Building agent binary"); - // Execute the script using sh and capture output and error streams - let output = Command::new("just") - .arg("build-musl-agent") - .stdout(Stdio::piped()) - .stderr(Stdio::piped()) - .output() - .expect("Failed to execute the just build script for the agent"); - - // Print output and error streams - info!("Script output: {}", String::from_utf8_lossy(&output.stdout)); - error!("Script errors: {}", String::from_utf8_lossy(&output.stderr)); - info!("Agent binary successfully built.") - } + let language: String = Language::from_i32(vmm_request.language) + .expect("Unknown language") + .as_str_name() + .to_lowercase(); - info!("Building initramfs"); - // Execute the script using sh and capture output and error streams - let output = Command::new("sh") - .arg("./tools/rootfs/mkrootfs.sh") - .arg(image) - .arg(&agent_file_name) - .arg(&initramfs_entire_file_path) - .stdout(Stdio::piped()) - .stderr(Stdio::piped()) - .output() - .expect("Failed to execute the initramfs build script"); - - // Print output and error streams - info!("Script output: {}", String::from_utf8_lossy(&output.stdout)); - error!("Script errors: {}", String::from_utf8_lossy(&output.stderr)); - info!("Initramfs successfully built.") - } - let initramfs_path = PathBuf::from(&initramfs_entire_file_path); + let initramfs_path = self.get_initramfs(&language, curr_dir.as_os_str())?; let mut vmm = VMM::new(HOST_IP, HOST_NETMASK, GUEST_IP).map_err(VmmErrors::VmmNew)?; @@ -171,29 +197,18 @@ impl VmmServiceTrait for VmmService { } }); + // run the grpc client let grpc_client = tokio::spawn(async move { // Wait 2 seconds tokio::time::sleep(Duration::from_secs(2)).await; - println!("Connecting to Agent service"); + info!("Connecting to Agent service"); WorkloadClient::new(GUEST_IP, 50051).await }) .await .unwrap(); - // Send the grpc request to start the agent - let agent_request = ExecuteRequest { - workload_name: vmm_request.workload_name, - language: match vmm_request.language { - 0 => "rust".to_string(), - 1 => "python".to_string(), - 2 => "node".to_string(), - _ => unreachable!("Invalid language"), - }, - action: 2, // Prepare and run - code: vmm_request.code, - config_str: "[build]\nrelease = true".to_string(), - }; + let agent_request = self.get_agent_request(vmm_request, language); match grpc_client { Ok(mut client) => { diff --git a/src/vmm/src/lib.rs b/src/vmm/src/lib.rs index c4b00ad..ba51a25 100644 --- a/src/vmm/src/lib.rs +++ b/src/vmm/src/lib.rs @@ -9,4 +9,5 @@ pub enum VmmErrors { VmmNew(core::Error), VmmConfigure(core::Error), VmmRun(core::Error), + VmmBuildEnvironment(std::io::Error), } diff --git a/src/vmm/src/main.rs b/src/vmm/src/main.rs index 7f6a748..36f8b9f 100644 --- a/src/vmm/src/main.rs +++ b/src/vmm/src/main.rs @@ -51,7 +51,7 @@ async fn main() -> Result<(), Box> { vmm.configure( cli_args.cpus, cli_args.memory, - &cli_args.kernel, + cli_args.kernel, &cli_args.initramfs, ) .map_err(VmmErrors::VmmConfigure)