Skip to content

Commit

Permalink
Merge pull request #21 from charley04310/feat/api-support-grpc-client
Browse files Browse the repository at this point in the history
Feat(api): add support grpc client
  • Loading branch information
charley04310 authored Apr 21, 2024
2 parents f844cff + e3aee5d commit 4d3293f
Show file tree
Hide file tree
Showing 16 changed files with 204 additions and 119 deletions.
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -224,3 +224,7 @@ $RECYCLE.BIN/
*.lnk

# End of https://www.toptal.com/developers/gitignore/api/windows,macos,linux,vim,intellij+all,rust,rust-analyzer,visualstudiocode

# RooFs and Kernel
kernel/*
rootfs/*
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
[workspace]
members = [ "src/api","src/vmm", "src/cli"]
members = ["src/api", "src/vmm", "src/cli"]
resolver = "2"
32 changes: 32 additions & 0 deletions proto/vmm.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
syntax = "proto3";

package vmmorchestrator;

enum Language {
PYTHON = 0;
NODE = 1;
RUST = 2;
}

enum LogLevel {
DEBUG = 0;
INFO = 1;
WARN = 2;
ERROR = 3;
}

service VmmService {
rpc Run (RunVmmRequest) returns (RunVmmResponse);
}

message RunVmmRequest {

Language language = 1;
string code = 2;
string env = 3;
LogLevel log_level = 4;

}

message RunVmmResponse {
}
6 changes: 6 additions & 0 deletions src/api/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,9 @@ edition = "2021"
[dependencies]
actix-web = "4.5.1"
serde = "1.0.197"
tonic = "0.9"
prost = "0.11"
shared_models = { path="../shared-models" }

[build-dependencies]
tonic-build = "0.9"
4 changes: 4 additions & 0 deletions src/api/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(())
}
26 changes: 26 additions & 0 deletions src/api/src/client.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
use tonic::transport::Channel;
use vmmorchestrator::vmm_service_client::VmmServiceClient;

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

pub struct VmmClient {
client: VmmServiceClient<Channel>,
}

impl VmmClient {
pub async fn new() -> Result<Self, tonic::transport::Error> {
let client = VmmServiceClient::connect("http://[::1]:50051")
.await
.expect("Failed to connect to VMM service");

Ok(VmmClient { client })
}

pub async fn run_vmm(&mut self, request: vmmorchestrator::RunVmmRequest) {
let request = tonic::Request::new(request);
let response = self.client.run(request).await.unwrap();
println!("RESPONSE={:?}", response);
}
}
1 change: 1 addition & 0 deletions src/api/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
pub mod client;
pub mod services;
17 changes: 5 additions & 12 deletions src/api/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,20 +1,13 @@
use actix_web::{App, HttpServer};
use api::services::{configuration, logs, metrics, run, shutdown};
use api::services::{run, shutdown};

#[actix_web::main]
async fn main() -> std::io::Result<()> {
let port = 3000;

println!("Starting server on port: {}", port);
HttpServer::new(|| {
App::new()
.service(configuration)
.service(run)
.service(logs)
.service(metrics)
.service(shutdown)
})
.bind(("127.0.0.1", port))?
.run()
.await
HttpServer::new(|| App::new().service(run).service(shutdown))
.bind(("127.0.0.1", port))?
.run()
.await
}
43 changes: 22 additions & 21 deletions src/api/src/services.rs
Original file line number Diff line number Diff line change
@@ -1,28 +1,29 @@
use actix_web::{get, post, web, HttpResponse, Responder};

#[post("/configuration")]
pub async fn configuration(req_body: String) -> impl Responder {
// TODO: Use the body to create the vm configuration
HttpResponse::Ok().body(req_body)
}
use crate::client::vmmorchestrator::RunVmmRequest;
use crate::client::VmmClient;
use actix_web::{post, web, HttpResponse, Responder};
use shared_models::CloudletDtoRequest;

#[post("/run")]
pub async fn run(req_body: String) -> impl Responder {
// TODO: Use the body id to start the fm
HttpResponse::Ok().body(req_body)
}

#[get("/logs/{id}")]
pub async fn logs(id: web::Path<String>) -> HttpResponse {
// TODO: maybe not close the stream and keep sending the logs
HttpResponse::Ok().body(format!("Logs here: {}", &id))
}
pub async fn run(req_body: web::Json<CloudletDtoRequest>) -> impl Responder {
let req = req_body.into_inner();
let grpc_client = VmmClient::new().await;

#[get("/metrics/{id}")]
pub async fn metrics(id: web::Path<String>) -> HttpResponse {
// TODO: Get the metrics for a VM with the given ID
let vmm_request = RunVmmRequest {
code: req.code,
env: req.env,
language: req.language as i32,
log_level: req.log_level as i32,
};

HttpResponse::Ok().body(format!("Metrics here: {}", &id))
match grpc_client {
Ok(mut client) => {
println!("Successfully connected to VMM service");
client.run_vmm(vmm_request).await;
HttpResponse::Ok().body("Successfully ran VMM")
}
Err(e) => HttpResponse::InternalServerError()
.body("Failed to connect to VMM service with error: ".to_string() + &e.to_string()),
}
}

#[post("/shutdown")]
Expand Down
1 change: 1 addition & 0 deletions src/cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,4 @@ serde_yaml = "0.9.34"
schemars = "0.8.16"
serde_json = "1.0.115"
reqwest = "0.12.3"
shared_models = { path="../shared-models" }
29 changes: 9 additions & 20 deletions src/cli/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
use clap::Parser;

use args::{CliArgs, Commands};
use request::run_request;
use request::HttpRunRequest;
use shared_models::YamlClientConfigFile;

use services::CloudletClient;
use std::io::{self};
use types::Config;
use utils::{load_config, read_file};
use utils::ConfigFileHandler;

mod args;
mod request;
mod types;
mod services;
mod utils;

#[tokio::main]
Expand All @@ -18,20 +17,10 @@ async fn main() -> io::Result<()> {

match args.command {
Commands::Run { config_path } => {
let yaml_config: Config =
load_config(&config_path).expect("Error while loading the configuration file");

let code =
read_file(&yaml_config.code_path).expect("Error while reading the code file");
println!("Code from file: \n{}", code);

let env =
read_file(&yaml_config.env_path).expect("Error while reading the environment file");
println!("Env from file : \n{}", env);
println!("Configuration from YAML file: \n {:#?}", yaml_config);

let body = HttpRunRequest::new(yaml_config.language, env, code, yaml_config.log_level);
let response = run_request(body).await;
let yaml_config: YamlClientConfigFile = ConfigFileHandler::load_config(&config_path)
.expect("Error while loading the configuration file");
let body = CloudletClient::new_cloudlet_config(yaml_config);
let response = CloudletClient::run(body).await;

match response {
Ok(_) => println!("Request successful"),
Expand Down
41 changes: 0 additions & 41 deletions src/cli/src/request.rs

This file was deleted.

39 changes: 39 additions & 0 deletions src/cli/src/services.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
use crate::utils::ConfigFileHandler;
use reqwest::Client;
use shared_models::{CloudletDtoRequest, YamlClientConfigFile};
use std::error::Error;
pub struct CloudletClient {}

impl CloudletClient {
pub fn new_cloudlet_config(config: YamlClientConfigFile) -> CloudletDtoRequest {
let code: String = ConfigFileHandler::read_file(&config.code_path)
.expect("Error while reading the code file");
let env = ConfigFileHandler::read_file(&config.env_path)
.expect("Error while reading the environment file");
let language = config.language;
let log_level = config.log_level;
CloudletDtoRequest {
language,
env,
code,
log_level,
}
}

pub async fn run(request: CloudletDtoRequest) -> Result<(), Box<dyn Error>> {
let client = Client::new();
let json = serde_json::to_string(&request)?;
println!("REQUEST : {:?}", request);
let res = client
.post("http://127.0.0.1:3000/run")
.header(reqwest::header::CONTENT_TYPE, "application/json")
.body(json)
.send()
.await?;

match res.status().as_u16() {
200 => Ok(()),
_ => Err("Error while making the request".into()),
}
}
}
32 changes: 18 additions & 14 deletions src/cli/src/utils.rs
Original file line number Diff line number Diff line change
@@ -1,20 +1,24 @@
use crate::types::Config;
use shared_models::YamlClientConfigFile;
use std::fs::File;
use std::io::{self, Read};
use std::path::PathBuf;

pub fn load_config(config_path: &PathBuf) -> io::Result<Config> {
let mut file = File::open(config_path)?;
let mut contents = String::new();
file.read_to_string(&mut contents)?;
let config: Config = serde_yaml::from_str(&contents)
.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
Ok(config)
}
pub struct ConfigFileHandler {}

impl ConfigFileHandler {
pub fn load_config(config_path: &PathBuf) -> io::Result<YamlClientConfigFile> {
let mut file = File::open(config_path)?;
let mut contents = String::new();
file.read_to_string(&mut contents)?;
let config: YamlClientConfigFile = serde_yaml::from_str(&contents)
.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
Ok(config)
}

pub fn read_file(file_path: &str) -> io::Result<String> {
let mut file = File::open(file_path)?;
let mut contents = String::new();
file.read_to_string(&mut contents)?;
Ok(contents)
pub fn read_file(file_path: &PathBuf) -> io::Result<String> {
let mut file = File::open(file_path)?;
let mut contents = String::new();
file.read_to_string(&mut contents)?;
Ok(contents)
}
}
16 changes: 16 additions & 0 deletions src/shared-models/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
[package]
name = "shared_models"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
clap = { version = "4.5.3", features = ["derive"] }
serde = { version = "1.0.197", features = ["derive"] }
serde_yaml = "0.9.34"
serde_json = "1.0.115"

[lib]
name = "shared_models"
path = "src/lib.rs"
Loading

0 comments on commit 4d3293f

Please sign in to comment.