Skip to content

Commit

Permalink
fix(vmm): code cleanup (#46)
Browse files Browse the repository at this point in the history
* fix(vmm): code cleanup

Signed-off-by: Muriel Paraire <[email protected]>

* fix: lint

Signed-off-by: Muriel Paraire <[email protected]>

---------

Signed-off-by: Muriel Paraire <[email protected]>
  • Loading branch information
MurielParaire authored May 3, 2024
1 parent 1f46bc7 commit 1e6e7c7
Show file tree
Hide file tree
Showing 4 changed files with 132 additions and 116 deletions.
6 changes: 3 additions & 3 deletions src/vmm/src/core/vmm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -339,7 +339,7 @@ impl VMM {
&mut self,
num_vcpus: u8,
mem_size_mb: u32,
kernel_path: &Path,
kernel_path: PathBuf,
initramfs_path: &Option<PathBuf>,
) -> Result<()> {
let cmdline_extra_parameters = &mut Vec::new();
Expand All @@ -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,
)?;
Expand Down
239 changes: 127 additions & 112 deletions src/vmm/src/grpc/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -34,13 +35,120 @@ impl From<VmmErrors> 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")
}
}
}
}

#[derive(Default)]
pub struct VmmService;

impl VmmService {
pub fn get_initramfs(
&self,
language: &str,
curr_dir: &OsStr,
) -> std::result::Result<PathBuf, VmmErrors> {
// 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<PathBuf, VmmErrors> {
// 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 =
Expand All @@ -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)?;

Expand All @@ -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) => {
Expand Down
1 change: 1 addition & 0 deletions src/vmm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,5 @@ pub enum VmmErrors {
VmmNew(core::Error),
VmmConfigure(core::Error),
VmmRun(core::Error),
VmmBuildEnvironment(std::io::Error),
}
2 changes: 1 addition & 1 deletion src/vmm/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
vmm.configure(
cli_args.cpus,
cli_args.memory,
&cli_args.kernel,
cli_args.kernel,
&cli_args.initramfs,
)
.map_err(VmmErrors::VmmConfigure)
Expand Down

0 comments on commit 1e6e7c7

Please sign in to comment.