Skip to content

Commit

Permalink
feat(vmm): add grpc server to handle api requests (#26)
Browse files Browse the repository at this point in the history
* feat: grpc and cli in lumper

Signed-off-by: Mauran <[email protected]>

---------

Signed-off-by: Mauran <[email protected]>
  • Loading branch information
thomas-mauran authored Apr 24, 2024
1 parent e3bd31d commit 2338841
Show file tree
Hide file tree
Showing 6 changed files with 166 additions and 31 deletions.
6 changes: 6 additions & 0 deletions src/vmm/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,16 @@ linux-loader = { version = "0.11.0", features = ["bzimage", "elf"] }
log = "0.4.20"
nix = { version = "0.28.0", features = ["term"] }
openpty = "0.2.0"
prost = "0.11"
tonic = "0.9"
tracing = "0.1.40"
tracing-subscriber = "0.3.18"
virtio-bindings = "0.2.2"
vm-device = "0.1.0"
vm-memory = { version = "0.14.0", features = ["backend-mmap"] }
vm-superio = "0.7.0"
vmm-sys-util = "0.12.1"
tokio = { version= "1.37.0", features= ["full"]}

[build-dependencies]
tonic-build = "0.9"
4 changes: 4 additions & 0 deletions src/vmm/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
fn main() -> Result<(), Box<dyn std::error::Error>> {
tonic_build::compile_protos("../../proto/vmm.proto")?;
Ok(())
}
27 changes: 21 additions & 6 deletions src/vmm/src/args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,31 @@ use clap::Parser;
use clap_verbosity_flag::{InfoLevel, Verbosity};
use tracing::level_filters;

/// The Virtual Machine Manager for the Cloudlet serverless runtime.
#[derive(Parser, Debug)]
#[command(author, version, about, long_about = None)]
#[command(version, about)]
pub struct CliArgs {
#[command(subcommand)]
pub command: Commands,
}

#[derive(Parser, Debug)]
pub enum Commands {
#[command(about = "Run a VMM instance.")]
Cli(CliArguments),
#[command(about = "Run a GRPC server listening for incoming requests.")]
Grpc,
}

/// Run a VMM instance.
#[derive(Parser, Debug)]
#[command(author, version, about)]
pub struct CliArguments {
/// Path to the image of the Linux kernel to boot.
#[arg(short, long, env)]
#[arg(short, long, env, required = true)]
pub kernel: PathBuf,

/// Path to the cpio archive to use as the initramfs.
#[arg(short, long, env)]
#[arg(short, long, env, required = true)]
pub initramfs: Option<PathBuf>,

/// Number of virtual CPUs assigned to the guest.
Expand All @@ -26,11 +41,11 @@ pub struct CliArguments {
pub memory: u32,

/// IPv4 address of the host tap interface.
#[clap(long, env)]
#[clap(long, env, required = true)]
pub network_host_ip: Ipv4Addr,

/// Subnet mask of the host tap interface.
#[clap(long, env)]
#[clap(long, env, required = true)]
pub network_host_netmask: Ipv4Addr,

/// Verbosity level.
Expand Down
8 changes: 8 additions & 0 deletions src/vmm/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1 +1,9 @@
pub mod core;
pub mod service;

#[derive(Debug)]
pub enum VmmErrors {
VmmNew(core::Error),
VmmConfigure(core::Error),
VmmRun(core::Error),
}
70 changes: 45 additions & 25 deletions src/vmm/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,40 +1,60 @@
use crate::args::CliArguments;
use crate::args::{CliArgs, Commands};
use clap::Parser;
use tonic::transport::Server;
use tracing::info;
use vmm::core::{self, vmm::VMM};

use vmm::{
core::vmm::VMM,
service::{vmmorchestrator, VmmService},
VmmErrors,
};
mod args;

#[derive(Debug)]
pub enum Error {
VmmNew(core::Error),
VmmConfigure(core::Error),
VmmRun(core::Error),
}

/// The application entry point.
fn main() -> Result<(), Error> {
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Parse the configuration and configure logger verbosity
let args = CliArguments::parse();
tracing_subscriber::fmt()
.with_max_level(args.convert_log_to_tracing())
.init();
let args = CliArgs::parse();

info!(
app_name = env!("CARGO_PKG_NAME"),
app_version = env!("CARGO_PKG_VERSION"),
"Starting application",
);

// Create a new VMM
let mut vmm =
VMM::new(args.network_host_ip, args.network_host_netmask).map_err(Error::VmmNew)?;

vmm.configure(args.cpus, args.memory, &args.kernel, &args.initramfs)
.map_err(Error::VmmConfigure)?;

// Run the VMM
vmm.run().map_err(Error::VmmRun)?;
let addr = "[::1]:50051".parse().unwrap();
let vmm_service = VmmService;

// check if the args is grpc or command
match args.command {
Commands::Grpc => {
Server::builder()
.add_service(vmmorchestrator::vmm_service_server::VmmServiceServer::new(
vmm_service,
))
.serve(addr)
.await?;
}
Commands::Cli(cli_args) => {
tracing_subscriber::fmt()
.with_max_level(cli_args.convert_log_to_tracing())
.init();
// Create a new VMM
let mut vmm = VMM::new(cli_args.network_host_ip, cli_args.network_host_netmask)
.map_err(VmmErrors::VmmNew)
.unwrap();

vmm.configure(
cli_args.cpus,
cli_args.memory,
&cli_args.kernel,
&cli_args.initramfs,
)
.map_err(VmmErrors::VmmConfigure)
.unwrap();

// Run the VMM
vmm.run().map_err(VmmErrors::VmmRun).unwrap();
}
}

Ok(())
}
82 changes: 82 additions & 0 deletions src/vmm/src/service.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
use self::vmmorchestrator::{
vmm_service_server::VmmService as VmmServiceTrait, RunVmmRequest, RunVmmResponse,
};
use crate::core::vmm::VMM;
use crate::VmmErrors;
use std::{
convert::From,
net::Ipv4Addr,
path::{Path, PathBuf},
process::{Command, Stdio},
};
use tonic::{Request, Response, Status};
use tracing::{error, info};

pub mod vmmorchestrator {
tonic::include_proto!("vmmorchestrator");
}

// Implement the From trait for VmmErrors into Status
impl From<VmmErrors> for Status {
fn from(error: VmmErrors) -> Self {
// You can create a custom Status variant based on the error
match error {
VmmErrors::VmmNew(_) => Status::internal("Error creating VMM"),
VmmErrors::VmmConfigure(_) => Status::internal("Error configuring VMM"),
VmmErrors::VmmRun(_) => Status::internal("Error running VMM"),
}
}
}

#[derive(Default)]
pub struct VmmService;

#[tonic::async_trait]
impl VmmServiceTrait for VmmService {
async fn run(
&self,
_request: Request<RunVmmRequest>,
) -> Result<Response<RunVmmResponse>, Status> {
let response = vmmorchestrator::RunVmmResponse {};

const HOST_IP: Ipv4Addr = Ipv4Addr::new(172, 29, 0, 1);
const HOST_NETMASK: Ipv4Addr = Ipv4Addr::new(255, 255, 0, 0);

// Check if the kernel is on the system, else build it
if !Path::new("./tools/kernel/linux-cloud-hypervisor/arch/x86/boot/compressed/vmlinux.bin")
.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
error!("Script output: {}", String::from_utf8_lossy(&output.stdout));
error!("Script errors: {}", String::from_utf8_lossy(&output.stderr));
};

let kernel_path = &Path::new(
"./tools/kernel/linux-cloud-hypervisor/arch/x86/boot/compressed/vmlinux.bin",
);
let mut initramfs_path: PathBuf = PathBuf::new();

// Todo - Check if the initramfs for the specified language is on the system, else build it
initramfs_path.push("./tools/rootfs/initramfs.img");

// // Create a new VMM
let mut vmm = VMM::new(HOST_IP, HOST_NETMASK).map_err(VmmErrors::VmmNew)?;

// Configure the VMM parameters might need to be calculated rather than hardcoded
vmm.configure(1, 512, kernel_path, &Some(initramfs_path))
.map_err(VmmErrors::VmmConfigure)?;
// Run the VMM
vmm.run().map_err(VmmErrors::VmmRun)?;

Ok(Response::new(response))
}
}

0 comments on commit 2338841

Please sign in to comment.