From 14c95ac4f7ee6fb97123bc6cdca195b64bdd0185 Mon Sep 17 00:00:00 2001 From: Pierre HUBERT Date: Fri, 3 May 2024 21:07:30 +0200 Subject: [PATCH] Add routes to manipulate VM --- .../src/controllers/vm_controller.rs | 58 ++++++++++++++- remote_backend/src/main.rs | 17 +++++ remote_backend/src/virtweb_client.rs | 72 +++++++++++++++++-- 3 files changed, 138 insertions(+), 9 deletions(-) diff --git a/remote_backend/src/controllers/vm_controller.rs b/remote_backend/src/controllers/vm_controller.rs index e821a29..4d5e264 100644 --- a/remote_backend/src/controllers/vm_controller.rs +++ b/remote_backend/src/controllers/vm_controller.rs @@ -3,7 +3,7 @@ use crate::controllers::HttpResult; use crate::virtweb_client; use crate::virtweb_client::VMUuid; -use actix_web::HttpResponse; +use actix_web::{web, HttpResponse}; #[derive(Debug, serde::Serialize)] pub struct VMInfoAndCaps { @@ -27,7 +27,7 @@ pub async fn list() -> HttpResult { let mut res = vec![]; for v in rights.list_vm() { - let vm_info = virtweb_client::get_vm_info(v).await?; + let vm_info = virtweb_client::vm_info(v).await?; res.push(VMInfoAndCaps { uiid: vm_info.uuid, @@ -46,3 +46,57 @@ pub async fn list() -> HttpResult { Ok(HttpResponse::Ok().json(res)) } + +#[derive(serde::Deserialize)] +pub struct ReqPath { + uid: VMUuid, +} + +/// Get the state of a VM +pub async fn state(path: web::Path) -> HttpResult { + Ok(HttpResponse::Ok().json(virtweb_client::vm_state(path.uid).await?)) +} + +/// Start a VM +pub async fn start(path: web::Path) -> HttpResult { + virtweb_client::vm_start(path.uid).await?; + Ok(HttpResponse::Ok().finish()) +} + +/// Shutdown a VM +pub async fn shutdown(path: web::Path) -> HttpResult { + virtweb_client::vm_shutdown(path.uid).await?; + Ok(HttpResponse::Ok().finish()) +} + +/// Kill a VM +pub async fn kill(path: web::Path) -> HttpResult { + virtweb_client::vm_kill(path.uid).await?; + Ok(HttpResponse::Ok().finish()) +} + +/// Reset a VM +pub async fn reset(path: web::Path) -> HttpResult { + virtweb_client::vm_reset(path.uid).await?; + Ok(HttpResponse::Ok().finish()) +} + +/// Suspend a VM +pub async fn suspend(path: web::Path) -> HttpResult { + virtweb_client::vm_suspend(path.uid).await?; + Ok(HttpResponse::Ok().finish()) +} + +/// Resume a VM +pub async fn resume(path: web::Path) -> HttpResult { + virtweb_client::vm_resume(path.uid).await?; + Ok(HttpResponse::Ok().finish()) +} + +/// Take the screenshot of a VM +pub async fn screenshot(path: web::Path) -> HttpResult { + let screenshot = virtweb_client::vm_screenshot(path.uid).await?; + Ok(HttpResponse::Ok() + .insert_header(("content-type", "image/png")) + .body(screenshot)) +} diff --git a/remote_backend/src/main.rs b/remote_backend/src/main.rs index 6b35070..6cc3568 100644 --- a/remote_backend/src/main.rs +++ b/remote_backend/src/main.rs @@ -80,6 +80,23 @@ async fn main() -> std::io::Result<()> { web::get().to(auth_controller::sign_out), ) .route("/api/vm/list", web::get().to(vm_controller::list)) + .route("/api/vm/{uid}/state", web::get().to(vm_controller::state)) + .route("/api/vm/{uid}/start", web::get().to(vm_controller::start)) + .route( + "/api/vm/{uid}/shutdown", + web::get().to(vm_controller::shutdown), + ) + .route("/api/vm/{uid}/kill", web::get().to(vm_controller::kill)) + .route("/api/vm/{uid}/reset", web::get().to(vm_controller::reset)) + .route( + "/api/vm/{uid}/suspend", + web::get().to(vm_controller::suspend), + ) + .route("/api/vm/{uid}/resume", web::get().to(vm_controller::resume)) + .route( + "/api/vm/{uid}/screenshot", + web::get().to(vm_controller::screenshot), + ) }) .bind(&AppConfig::get().listen_address)? .run() diff --git a/remote_backend/src/virtweb_client.rs b/remote_backend/src/virtweb_client.rs index 26d5190..656780e 100644 --- a/remote_backend/src/virtweb_client.rs +++ b/remote_backend/src/virtweb_client.rs @@ -76,6 +76,11 @@ pub struct VMInfo { pub description: Option, } +#[derive(serde::Deserialize, serde::Serialize, Debug)] +pub struct VMState { + pub state: String, +} + #[derive(serde::Deserialize, Debug)] pub struct TokenRight { verb: String, @@ -129,7 +134,7 @@ impl TokenInfo { } /// Perform a request on the API -async fn request(uri: D) -> anyhow::Result { +async fn request(uri: D) -> anyhow::Result { let url = format!("{}{}", AppConfig::get().virtweb_base_url, uri); log::debug!("Will query {uri}..."); @@ -154,20 +159,73 @@ async fn request(uri: D) -> anyhow:: return Err(VirtWebClientError::InvalidStatusCode(res.status().as_u16()).into()); } - Ok(res.json().await?) + Ok(res) +} + +/// Perform a request on the API +async fn json_request(uri: D) -> anyhow::Result { + Ok(request(uri).await?.json().await?) } /// Get current token information pub async fn get_token_info() -> anyhow::Result { let res: TokenInfo = - request(format!("/api/token/{}", AppConfig::get().virtweb_token_id)).await?; + json_request(format!("/api/token/{}", AppConfig::get().virtweb_token_id)).await?; Ok(res) } /// Get a vm information -pub async fn get_vm_info(id: VMUuid) -> anyhow::Result { - let res: VMInfo = request(format!("/api/vm/{}", id.0)).await?; - - Ok(res) +pub async fn vm_info(id: VMUuid) -> anyhow::Result { + json_request(id.route_info()).await +} + +/// Get a vm information +pub async fn vm_state(id: VMUuid) -> anyhow::Result { + json_request(id.route_state()).await +} + +/// Start a vm +pub async fn vm_start(id: VMUuid) -> anyhow::Result<()> { + request(id.route_start()).await?; + Ok(()) +} + +/// Shutdown a vm +pub async fn vm_shutdown(id: VMUuid) -> anyhow::Result<()> { + request(id.route_shutdown()).await?; + Ok(()) +} + +/// Kill a vm +pub async fn vm_kill(id: VMUuid) -> anyhow::Result<()> { + request(id.route_kill()).await?; + Ok(()) +} + +/// Reset a vm +pub async fn vm_reset(id: VMUuid) -> anyhow::Result<()> { + request(id.route_reset()).await?; + Ok(()) +} + +/// Suspend a vm +pub async fn vm_suspend(id: VMUuid) -> anyhow::Result<()> { + request(id.route_suspend()).await?; + Ok(()) +} + +/// Resume a vm +pub async fn vm_resume(id: VMUuid) -> anyhow::Result<()> { + request(id.route_resume()).await?; + Ok(()) +} + +/// Resume a vm +pub async fn vm_screenshot(id: VMUuid) -> anyhow::Result> { + Ok(request(id.route_screenshot()) + .await? + .bytes() + .await? + .to_vec()) }