Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat(api): add support grpc client #21

Merged
merged 6 commits into from
Apr 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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