Skip to content

Commit

Permalink
feat: shutdown vm
Browse files Browse the repository at this point in the history
  • Loading branch information
Hunh0w committed May 2, 2024
1 parent d1d1f47 commit a3ec2af
Show file tree
Hide file tree
Showing 10 changed files with 145 additions and 12 deletions.
8 changes: 8 additions & 0 deletions proto/vmm.proto
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ message ExecuteResponse {
}

service VmmService {
rpc Shutdown (ShutdownVmRequest) returns (ShutdownVmResponse) {};
rpc Run (RunVmmRequest) returns (stream ExecuteResponse) {};
}

Expand All @@ -45,3 +46,10 @@ message RunVmmRequest {

message RunVmmResponse {
}

message ShutdownVmRequest {
}

message ShutdownVmResponse {
bool success = 1;
}
15 changes: 15 additions & 0 deletions src/api/src/client.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use std::time::Duration;

use tonic::{transport::Channel, Streaming};
use vmmorchestrator::vmm_service_client::VmmServiceClient;

Expand Down Expand Up @@ -27,4 +29,17 @@ impl VmmClient {

Ok(response_stream)
}

pub async fn shutdown_vm(
&mut self,
request: vmmorchestrator::ShutdownVmRequest,
) -> Result<vmmorchestrator::ShutdownVmResponse, tonic::Status> {
let mut request = tonic::Request::new(request);
request.set_timeout(Duration::from_secs(5));
let response = self.client.shutdown(request).await?.into_inner();

println!("shutdown response: {:?}", response);

Ok(response)
}
}
43 changes: 38 additions & 5 deletions src/api/src/service.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use crate::client::{
vmmorchestrator::{ExecuteResponse, RunVmmRequest},
vmmorchestrator::{ExecuteResponse, RunVmmRequest, ShutdownVmRequest, ShutdownVmResponse},
VmmClient,
};
use actix_web::{post, web, HttpResponse, Responder};
use actix_web::{post, web, HttpRequest, HttpResponse, Responder};
use actix_web_lab::sse;
use async_stream::stream;
use serde::Serialize;
Expand Down Expand Up @@ -65,7 +65,40 @@ impl From<ExecuteResponse> for ExecuteJsonResponse {
}

#[post("/shutdown")]
pub async fn shutdown(req_body: String) -> impl Responder {
// TODO: Get the id from the body and shutdown the vm
HttpResponse::Ok().body(req_body)
pub async fn shutdown(request: HttpRequest) -> impl Responder {
let req = request;

let mut client = VmmClient::new().await.unwrap();

println!("Request: {:?}", req);

let shutdown_request = ShutdownVmRequest{};
let response_result = client.shutdown_vm(shutdown_request).await;

match response_result {
Ok(response) => {
let json_response: ShutdownJsonResponse = response.into();
return HttpResponse::Ok().body(serde_json::to_string(&json_response).unwrap());
}
Err(_) => {
let json_response: ShutdownJsonResponse = ShutdownJsonResponse {
success: false
};
return HttpResponse::Ok().body(serde_json::to_string(&json_response).unwrap());
}
}

}

#[derive(Debug, Serialize)]
pub struct ShutdownJsonResponse {
pub success: bool,
}

impl From<ShutdownVmResponse> for ShutdownJsonResponse {
fn from(value: ShutdownVmResponse) -> Self {
Self {
success: value.success
}
}
}
1 change: 1 addition & 0 deletions src/cli/src/args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,5 @@ pub enum Commands {
#[arg(short, long)]
config_path: PathBuf,
},
Shutdown {},
}
10 changes: 10 additions & 0 deletions src/cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,16 @@ async fn main() -> io::Result<()> {
Ok(_) => println!("Request successful {:?}", response),
Err(e) => eprintln!("Error while making the request: {}", e),
}
},
Commands::Shutdown {} => {
let response = CloudletClient::shutdown().await;
match response {
Ok(bool) => {
if bool { println!("Shutdown Request successful !")}
else { println!("Shutdown Request Failed")}
},
Err(()) => println!("Cannot send shutdown Request"),
}
}
}

Expand Down
15 changes: 13 additions & 2 deletions src/cli/src/services.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::utils::ConfigFileHandler;
use reqwest::Client;
use serde::Deserialize;
use shared_models::{BuildConfig, CloudletDtoRequest, Language, ServerConfig};
use shared_models::{BuildConfig, CloudletDtoRequest, Language, ServerConfig, CloudletShutdownResponse};
use std::error::Error;

#[derive(Deserialize, Debug)]
Expand Down Expand Up @@ -50,4 +50,15 @@ impl CloudletClient {
println!("Response: {:?}", res.text().await?);
Ok(())
}
}

pub async fn shutdown() -> Result<bool, ()> {
let client = Client::new();
let response = client.post("http://127.0.0.1:3000/shutdown")
.send()
.await;

let shutdown_response: CloudletShutdownResponse = response.unwrap().json::<CloudletShutdownResponse>().await.unwrap();

Ok(shutdown_response.success)
}
}
5 changes: 5 additions & 0 deletions src/shared-models/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,11 @@ pub struct CloudletDtoRequest {
pub build: BuildConfig,
}

#[derive(Debug, Deserialize)]
pub struct CloudletShutdownResponse {
pub success: bool
}

#[derive(Serialize, Deserialize, Debug)]
pub struct ServerConfig {
pub address: String,
Expand Down
1 change: 1 addition & 0 deletions src/vmm/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ vm-memory = { version = "0.14.1", features = ["backend-mmap"] }
vm-superio = "0.7.0"
vmm-sys-util = "0.12.1"
tokio-stream = "0.1.15"
hyper = "1.3.1"

[build-dependencies]
tonic-build = "0.9"
32 changes: 28 additions & 4 deletions src/vmm/src/grpc/client.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
use self::agent::{workload_runner_client::WorkloadRunnerClient, ExecuteRequest};
use self::agent::{workload_runner_client::WorkloadRunnerClient, ExecuteRequest, SignalRequest};
use log::error;
use std::{net::Ipv4Addr, time::Duration};
use tonic::{transport::Channel, Streaming};
use std::{error::Error, net::Ipv4Addr, time::Duration};
use tonic::{transport::Channel, IntoRequest, Streaming};
use super::server::vmmorchestrator::{ShutdownVmRequest, ShutdownVmResponse};

pub mod agent {
tonic::include_proto!("cloudlet.agent");
Expand Down Expand Up @@ -34,7 +35,30 @@ impl WorkloadClient {
) -> Result<Streaming<agent::ExecuteResponse>, tonic::Status> {
let request = tonic::Request::new(request);
let response_stream = self.client.execute(request).await?.into_inner();

Ok(response_stream)
}

pub async fn shutdown(
&mut self,
_request: ShutdownVmRequest,
) -> Result<ShutdownVmResponse, tonic::Status> {
const BROKEN_PIPE_ERROR: &str = "stream closed because of a broken pipe";

let signal_request = SignalRequest::default();
let response = self.client.signal(signal_request).await;

if let Err(status) = response {
let error = status.source().unwrap().source().unwrap().source().unwrap();
if error.to_string().as_str().eq(BROKEN_PIPE_ERROR) {
return Ok(ShutdownVmResponse {
success: true
});
}
}

Ok(ShutdownVmResponse {
success: false
})
}
}
27 changes: 26 additions & 1 deletion src/vmm/src/grpc/server.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use self::vmmorchestrator::{vmm_service_server::VmmService as VmmServiceTrait, RunVmmRequest};
use self::vmmorchestrator::{vmm_service_server::VmmService as VmmServiceTrait, RunVmmRequest, ShutdownVmRequest, ShutdownVmResponse};
use crate::grpc::client::agent::ExecuteRequest;
use crate::VmmErrors;
use crate::{core::vmm::VMM, grpc::client::WorkloadClient};
Expand Down Expand Up @@ -43,6 +43,31 @@ impl VmmServiceTrait for VmmService {
type RunStream =
ReceiverStream<std::result::Result<vmmorchestrator::ExecuteResponse, tonic::Status>>;

async fn shutdown(&self, request: Request<ShutdownVmRequest>) -> Result<ShutdownVmResponse> {
const GUEST_IP: Ipv4Addr = Ipv4Addr::new(172, 29, 0, 2);

let grpc_client = tokio::spawn(async move {
// Wait 2 seconds
tokio::time::sleep(Duration::from_secs(2)).await;
println!("Connecting to Agent service");

WorkloadClient::new(GUEST_IP, 50051).await
})
.await
.unwrap();

if let Ok(mut client) = grpc_client {
info!("Attempting to shutdown the VM...");

let response = client.shutdown(request.into_inner()).await.unwrap();

return Ok(Response::new(response));
}else if let Err(e) = grpc_client {
error!("ERROR {:?}", e);
}
return Err(Status::internal("Failed to shutdown the VM"));
}

async fn run(&self, request: Request<RunVmmRequest>) -> Result<Self::RunStream> {
let (tx, rx) = tokio::sync::mpsc::channel(4);

Expand Down

0 comments on commit a3ec2af

Please sign in to comment.