211 lines
6.4 KiB
Rust

use crate::controllers::{HttpResult, LibVirtReq};
use crate::libvirt_lib_structures::{DomainState, DomainXMLUuid};
use crate::libvirt_rest_structures::VMInfo;
use actix_web::{web, HttpResponse};
#[derive(serde::Serialize)]
struct VMInfoAndState {
#[serde(flatten)]
info: VMInfo,
state: DomainState,
}
#[derive(serde::Serialize)]
struct VMUuid {
uuid: DomainXMLUuid,
}
/// Create a new VM
pub async fn create(client: LibVirtReq, req: web::Json<VMInfo>) -> HttpResult {
let domain = match req.0.to_domain() {
Ok(d) => d,
Err(e) => {
log::error!("Failed to extract domain info! {e}");
return Ok(HttpResponse::BadRequest().body(e.to_string()));
}
};
let id = client.update_domain(domain).await?;
Ok(HttpResponse::Ok().json(VMUuid { uuid: id }))
}
/// Get the list of domains
pub async fn list_all(client: LibVirtReq) -> HttpResult {
let list = client.get_full_list().await?;
let mut out = Vec::with_capacity(list.len());
for entry in list {
let info = VMInfo::from_domain(entry)?;
out.push(VMInfoAndState {
state: client
.get_domain_state(info.uuid.expect("Domain without UUID !"))
.await?,
info,
})
}
Ok(HttpResponse::Ok().json(out))
}
#[derive(serde::Deserialize)]
pub struct SingleVMUUidReq {
uid: DomainXMLUuid,
}
/// Get the information about a single VM
pub async fn get_single(client: LibVirtReq, id: web::Path<SingleVMUUidReq>) -> HttpResult {
let info = match client.get_single_domain(id.uid).await {
Ok(i) => i,
Err(e) => {
log::error!("Failed to get domain info! {e}");
return Ok(HttpResponse::InternalServerError().json(e.to_string()));
}
};
let state = client.get_domain_state(id.uid).await?;
Ok(HttpResponse::Ok().json(VMInfoAndState {
info: VMInfo::from_domain(info)?,
state,
}))
}
/// Update a VM information
pub async fn update(
client: LibVirtReq,
id: web::Path<SingleVMUUidReq>,
req: web::Json<VMInfo>,
) -> HttpResult {
let mut domain = req.0.to_domain().map_err(|e| {
log::error!("Failed to extract domain info! {e}");
HttpResponse::BadRequest().body(e.to_string())
})?;
domain.uuid = Some(id.uid);
client.update_domain(domain).await?;
Ok(HttpResponse::Ok().finish())
}
#[derive(serde::Deserialize)]
pub struct DeleteVMQuery {
keep_files: bool,
}
/// Delete a VM
pub async fn delete(
client: LibVirtReq,
id: web::Path<SingleVMUUidReq>,
req: web::Json<DeleteVMQuery>,
) -> HttpResult {
if let Err(e) = client.kill_domain(id.uid).await {
log::info!("Failed to kill domain before deleting it: {e}");
}
client
.delete_domain(id.uid, req.keep_files)
.await
.map_err(|e| {
log::error!("Failed to delete domain! {e}");
HttpResponse::InternalServerError().body(e.to_string())
})?;
Ok(HttpResponse::Ok().finish())
}
/// Start a VM
pub async fn start(client: LibVirtReq, id: web::Path<SingleVMUUidReq>) -> HttpResult {
Ok(match client.start_domain(id.uid).await {
Ok(_) => HttpResponse::Ok().json("Domain started"),
Err(e) => {
log::error!("Failed to start domain {:?} ! {e}", id.uid);
HttpResponse::InternalServerError().json("Failed to start domain!")
}
})
}
/// Shutdown a VM
pub async fn shutdown(client: LibVirtReq, id: web::Path<SingleVMUUidReq>) -> HttpResult {
Ok(match client.shutdown_domain(id.uid).await {
Ok(_) => HttpResponse::Ok().json("Domain shutdown"),
Err(e) => {
log::error!("Failed to shutdown domain {:?} ! {e}", id.uid);
HttpResponse::InternalServerError().json("Failed to shutdown domain!")
}
})
}
/// Kill a VM
pub async fn kill(client: LibVirtReq, id: web::Path<SingleVMUUidReq>) -> HttpResult {
Ok(match client.kill_domain(id.uid).await {
Ok(_) => HttpResponse::Ok().json("Domain killed"),
Err(e) => {
log::error!("Failed to kill domain {:?} ! {e}", id.uid);
HttpResponse::InternalServerError().json("Failed to kill domain!")
}
})
}
/// Reset a VM
pub async fn reset(client: LibVirtReq, id: web::Path<SingleVMUUidReq>) -> HttpResult {
Ok(match client.reset_domain(id.uid).await {
Ok(_) => HttpResponse::Ok().json("Domain reseted"),
Err(e) => {
log::error!("Failed to reset domain {:?} ! {e}", id.uid);
HttpResponse::InternalServerError().json("Failed to reset domain!")
}
})
}
/// Suspend a VM
pub async fn suspend(client: LibVirtReq, id: web::Path<SingleVMUUidReq>) -> HttpResult {
Ok(match client.suspend_domain(id.uid).await {
Ok(_) => HttpResponse::Ok().json("Domain suspended"),
Err(e) => {
log::error!("Failed to suspend domain {:?} ! {e}", id.uid);
HttpResponse::InternalServerError().json("Failed to suspend domain!")
}
})
}
/// Resume a VM
pub async fn resume(client: LibVirtReq, id: web::Path<SingleVMUUidReq>) -> HttpResult {
Ok(match client.resume_domain(id.uid).await {
Ok(_) => HttpResponse::Ok().json("Domain resumed"),
Err(e) => {
log::error!("Failed to resume domain {:?} ! {e}", id.uid);
HttpResponse::InternalServerError().json("Failed to resume domain!")
}
})
}
#[derive(serde::Serialize)]
struct DomainStateRes {
state: DomainState,
}
/// Get the state of a VM
pub async fn state(client: LibVirtReq, id: web::Path<SingleVMUUidReq>) -> HttpResult {
Ok(match client.get_domain_state(id.uid).await {
Ok(s) => HttpResponse::Ok().json(DomainStateRes { state: s }),
Err(e) => {
log::error!("Failed to get domain state {:?} ! {e}", id.uid);
HttpResponse::InternalServerError().json("Failed to get domain state!")
}
})
}
/// Take a screenshot of a VM
pub async fn screenshot(client: LibVirtReq, id: web::Path<SingleVMUUidReq>) -> HttpResult {
Ok(match client.screenshot_domain(id.uid).await {
Ok(b) => HttpResponse::Ok().content_type("image/png").body(b),
Err(e) => {
log::error!(
"Failed to take the screenshot of a domain {:?} ! {e}",
id.uid
);
HttpResponse::InternalServerError().json("Failed to take the screenshot of the domain!")
}
})
}