Add routes to manipulate VM

This commit is contained in:
Pierre HUBERT 2024-05-03 21:07:30 +02:00
parent 50600e4e56
commit 14c95ac4f7
3 changed files with 138 additions and 9 deletions

View File

@ -3,7 +3,7 @@
use crate::controllers::HttpResult; use crate::controllers::HttpResult;
use crate::virtweb_client; use crate::virtweb_client;
use crate::virtweb_client::VMUuid; use crate::virtweb_client::VMUuid;
use actix_web::HttpResponse; use actix_web::{web, HttpResponse};
#[derive(Debug, serde::Serialize)] #[derive(Debug, serde::Serialize)]
pub struct VMInfoAndCaps { pub struct VMInfoAndCaps {
@ -27,7 +27,7 @@ pub async fn list() -> HttpResult {
let mut res = vec![]; let mut res = vec![];
for v in rights.list_vm() { 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 { res.push(VMInfoAndCaps {
uiid: vm_info.uuid, uiid: vm_info.uuid,
@ -46,3 +46,57 @@ pub async fn list() -> HttpResult {
Ok(HttpResponse::Ok().json(res)) 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<ReqPath>) -> HttpResult {
Ok(HttpResponse::Ok().json(virtweb_client::vm_state(path.uid).await?))
}
/// Start a VM
pub async fn start(path: web::Path<ReqPath>) -> HttpResult {
virtweb_client::vm_start(path.uid).await?;
Ok(HttpResponse::Ok().finish())
}
/// Shutdown a VM
pub async fn shutdown(path: web::Path<ReqPath>) -> HttpResult {
virtweb_client::vm_shutdown(path.uid).await?;
Ok(HttpResponse::Ok().finish())
}
/// Kill a VM
pub async fn kill(path: web::Path<ReqPath>) -> HttpResult {
virtweb_client::vm_kill(path.uid).await?;
Ok(HttpResponse::Ok().finish())
}
/// Reset a VM
pub async fn reset(path: web::Path<ReqPath>) -> HttpResult {
virtweb_client::vm_reset(path.uid).await?;
Ok(HttpResponse::Ok().finish())
}
/// Suspend a VM
pub async fn suspend(path: web::Path<ReqPath>) -> HttpResult {
virtweb_client::vm_suspend(path.uid).await?;
Ok(HttpResponse::Ok().finish())
}
/// Resume a VM
pub async fn resume(path: web::Path<ReqPath>) -> 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<ReqPath>) -> HttpResult {
let screenshot = virtweb_client::vm_screenshot(path.uid).await?;
Ok(HttpResponse::Ok()
.insert_header(("content-type", "image/png"))
.body(screenshot))
}

View File

@ -80,6 +80,23 @@ async fn main() -> std::io::Result<()> {
web::get().to(auth_controller::sign_out), web::get().to(auth_controller::sign_out),
) )
.route("/api/vm/list", web::get().to(vm_controller::list)) .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)? .bind(&AppConfig::get().listen_address)?
.run() .run()

View File

@ -76,6 +76,11 @@ pub struct VMInfo {
pub description: Option<String>, pub description: Option<String>,
} }
#[derive(serde::Deserialize, serde::Serialize, Debug)]
pub struct VMState {
pub state: String,
}
#[derive(serde::Deserialize, Debug)] #[derive(serde::Deserialize, Debug)]
pub struct TokenRight { pub struct TokenRight {
verb: String, verb: String,
@ -129,7 +134,7 @@ impl TokenInfo {
} }
/// Perform a request on the API /// Perform a request on the API
async fn request<D: Display, E: serde::de::DeserializeOwned>(uri: D) -> anyhow::Result<E> { async fn request<D: Display>(uri: D) -> anyhow::Result<reqwest::Response> {
let url = format!("{}{}", AppConfig::get().virtweb_base_url, uri); let url = format!("{}{}", AppConfig::get().virtweb_base_url, uri);
log::debug!("Will query {uri}..."); log::debug!("Will query {uri}...");
@ -154,20 +159,73 @@ async fn request<D: Display, E: serde::de::DeserializeOwned>(uri: D) -> anyhow::
return Err(VirtWebClientError::InvalidStatusCode(res.status().as_u16()).into()); 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<D: Display, E: serde::de::DeserializeOwned>(uri: D) -> anyhow::Result<E> {
Ok(request(uri).await?.json().await?)
} }
/// Get current token information /// Get current token information
pub async fn get_token_info() -> anyhow::Result<TokenInfo> { pub async fn get_token_info() -> anyhow::Result<TokenInfo> {
let res: TokenInfo = 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) Ok(res)
} }
/// Get a vm information /// Get a vm information
pub async fn get_vm_info(id: VMUuid) -> anyhow::Result<VMInfo> { pub async fn vm_info(id: VMUuid) -> anyhow::Result<VMInfo> {
let res: VMInfo = request(format!("/api/vm/{}", id.0)).await?; json_request(id.route_info()).await
}
Ok(res)
/// Get a vm information
pub async fn vm_state(id: VMUuid) -> anyhow::Result<VMState> {
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<Vec<u8>> {
Ok(request(id.route_screenshot())
.await?
.bytes()
.await?
.to_vec())
} }