Can get the list of VM of a group
This commit is contained in:
parent
bcf6e8a33b
commit
9f8e2e9dc2
@ -1,4 +1,6 @@
|
|||||||
use crate::controllers::{HttpResult, LibVirtReq};
|
use crate::controllers::{HttpResult, LibVirtReq};
|
||||||
|
use crate::extractors::group_vm_id_extractor::GroupVmIdExtractor;
|
||||||
|
use crate::libvirt_rest_structures::vm::VMInfo;
|
||||||
use actix_web::HttpResponse;
|
use actix_web::HttpResponse;
|
||||||
|
|
||||||
/// Get the list of groups
|
/// Get the list of groups
|
||||||
@ -14,3 +16,12 @@ pub async fn list(client: LibVirtReq) -> HttpResult {
|
|||||||
|
|
||||||
Ok(HttpResponse::Ok().json(groups))
|
Ok(HttpResponse::Ok().json(groups))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get information about a VM
|
||||||
|
pub async fn vm_info(vms_ids: GroupVmIdExtractor) -> HttpResult {
|
||||||
|
let mut vms = Vec::new();
|
||||||
|
for vm in vms_ids.0 {
|
||||||
|
vms.push(VMInfo::from_domain(vm)?)
|
||||||
|
}
|
||||||
|
Ok(HttpResponse::Ok().json(vms))
|
||||||
|
}
|
||||||
|
66
virtweb_backend/src/extractors/group_vm_id_extractor.rs
Normal file
66
virtweb_backend/src/extractors/group_vm_id_extractor.rs
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
use crate::controllers::LibVirtReq;
|
||||||
|
use crate::libvirt_lib_structures::domain::DomainXML;
|
||||||
|
use crate::libvirt_lib_structures::XMLUuid;
|
||||||
|
use crate::libvirt_rest_structures::vm::VMGroupId;
|
||||||
|
use actix_http::Payload;
|
||||||
|
use actix_web::error::ErrorBadRequest;
|
||||||
|
use actix_web::web::Query;
|
||||||
|
use actix_web::{web, Error, FromRequest, HttpRequest};
|
||||||
|
use std::future::Future;
|
||||||
|
use std::pin::Pin;
|
||||||
|
|
||||||
|
pub struct GroupVmIdExtractor(pub Vec<DomainXML>);
|
||||||
|
|
||||||
|
#[derive(serde::Deserialize)]
|
||||||
|
struct GroupIDInPath {
|
||||||
|
gid: VMGroupId,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(serde::Deserialize)]
|
||||||
|
struct FilterVM {
|
||||||
|
vm_id: Option<XMLUuid>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromRequest for GroupVmIdExtractor {
|
||||||
|
type Error = Error;
|
||||||
|
type Future = Pin<Box<dyn Future<Output = Result<Self, Self::Error>>>>;
|
||||||
|
|
||||||
|
fn from_request(req: &HttpRequest, _payload: &mut Payload) -> Self::Future {
|
||||||
|
let req = req.clone();
|
||||||
|
|
||||||
|
Box::pin(async move {
|
||||||
|
let Ok(group_id) =
|
||||||
|
web::Path::<GroupIDInPath>::from_request(&req, &mut Payload::None).await
|
||||||
|
else {
|
||||||
|
return Err(ErrorBadRequest("Group ID not specified in path!"));
|
||||||
|
};
|
||||||
|
let group_id = group_id.into_inner().gid;
|
||||||
|
|
||||||
|
let filter_vm = match Query::<FilterVM>::from_request(&req, &mut Payload::None).await {
|
||||||
|
Ok(v) => v,
|
||||||
|
Err(e) => {
|
||||||
|
log::error!("Failed to extract VM id from request! {e}");
|
||||||
|
return Err(ErrorBadRequest("Failed to extract VM id from request!"));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let Ok(client) = LibVirtReq::from_request(&req, &mut Payload::None).await else {
|
||||||
|
return Err(ErrorBadRequest("Failed to extract client handle!"));
|
||||||
|
};
|
||||||
|
|
||||||
|
let vms = match client.get_full_group_vm_list(&group_id).await {
|
||||||
|
Ok(vms) => vms,
|
||||||
|
Err(e) => {
|
||||||
|
log::error!("Failed to get the VM of the group {group_id:?}: {e}");
|
||||||
|
return Err(ErrorBadRequest("Failed to get the VM of the group!"));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Filter (if requested by the user)
|
||||||
|
Ok(GroupVmIdExtractor(match filter_vm.vm_id {
|
||||||
|
None => vms,
|
||||||
|
Some(id) => vms.into_iter().filter(|vms| vms.uuid == Some(id)).collect(),
|
||||||
|
}))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
@ -1,3 +1,4 @@
|
|||||||
pub mod api_auth_extractor;
|
pub mod api_auth_extractor;
|
||||||
pub mod auth_extractor;
|
pub mod auth_extractor;
|
||||||
|
pub mod group_vm_id_extractor;
|
||||||
pub mod local_auth_extractor;
|
pub mod local_auth_extractor;
|
||||||
|
@ -122,6 +122,21 @@ impl LibVirtClient {
|
|||||||
Ok(out)
|
Ok(out)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the full list of VMs of a given group
|
||||||
|
pub async fn get_full_group_vm_list(
|
||||||
|
&self,
|
||||||
|
group: &VMGroupId,
|
||||||
|
) -> anyhow::Result<Vec<DomainXML>> {
|
||||||
|
let vms = self.get_full_domains_list().await?;
|
||||||
|
let mut out = Vec::new();
|
||||||
|
for vm in vms {
|
||||||
|
if VMInfo::from_domain(vm.clone())?.group == Some(group.clone()) {
|
||||||
|
out.push(vm);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(out)
|
||||||
|
}
|
||||||
|
|
||||||
/// Update a network configuration
|
/// Update a network configuration
|
||||||
pub async fn update_network(
|
pub async fn update_network(
|
||||||
&self,
|
&self,
|
||||||
|
@ -19,7 +19,7 @@ pub struct DomainMetadataXML {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// OS information
|
/// OS information
|
||||||
#[derive(Debug, serde::Serialize, serde::Deserialize)]
|
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
||||||
#[serde(rename = "os")]
|
#[serde(rename = "os")]
|
||||||
pub struct OSXML {
|
pub struct OSXML {
|
||||||
#[serde(rename = "@firmware", default)]
|
#[serde(rename = "@firmware", default)]
|
||||||
@ -29,7 +29,7 @@ pub struct OSXML {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// OS Type information
|
/// OS Type information
|
||||||
#[derive(Debug, serde::Serialize, serde::Deserialize)]
|
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
||||||
#[serde(rename = "os")]
|
#[serde(rename = "os")]
|
||||||
pub struct OSTypeXML {
|
pub struct OSTypeXML {
|
||||||
#[serde(rename = "@arch")]
|
#[serde(rename = "@arch")]
|
||||||
@ -41,7 +41,7 @@ pub struct OSTypeXML {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// OS Loader information
|
/// OS Loader information
|
||||||
#[derive(Debug, serde::Serialize, serde::Deserialize)]
|
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
||||||
#[serde(rename = "loader")]
|
#[serde(rename = "loader")]
|
||||||
pub struct OSLoaderXML {
|
pub struct OSLoaderXML {
|
||||||
#[serde(rename = "@secure")]
|
#[serde(rename = "@secure")]
|
||||||
@ -49,39 +49,39 @@ pub struct OSLoaderXML {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Hypervisor features
|
/// Hypervisor features
|
||||||
#[derive(serde::Serialize, serde::Deserialize, Default, Debug)]
|
#[derive(serde::Serialize, serde::Deserialize, Clone, Default, Debug)]
|
||||||
#[serde(rename = "features")]
|
#[serde(rename = "features")]
|
||||||
pub struct FeaturesXML {
|
pub struct FeaturesXML {
|
||||||
pub acpi: ACPIXML,
|
pub acpi: ACPIXML,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// ACPI feature
|
/// ACPI feature
|
||||||
#[derive(serde::Serialize, serde::Deserialize, Default, Debug)]
|
#[derive(serde::Serialize, serde::Deserialize, Clone, Default, Debug)]
|
||||||
#[serde(rename = "acpi")]
|
#[serde(rename = "acpi")]
|
||||||
pub struct ACPIXML {}
|
pub struct ACPIXML {}
|
||||||
|
|
||||||
#[derive(Debug, serde::Serialize, serde::Deserialize)]
|
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
||||||
#[serde(rename = "mac")]
|
#[serde(rename = "mac")]
|
||||||
pub struct NetMacAddress {
|
pub struct NetMacAddress {
|
||||||
#[serde(rename = "@address")]
|
#[serde(rename = "@address")]
|
||||||
pub address: String,
|
pub address: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, serde::Serialize, serde::Deserialize)]
|
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
||||||
#[serde(rename = "source")]
|
#[serde(rename = "source")]
|
||||||
pub struct NetIntSourceXML {
|
pub struct NetIntSourceXML {
|
||||||
#[serde(rename = "@network")]
|
#[serde(rename = "@network")]
|
||||||
pub network: String,
|
pub network: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, serde::Serialize, serde::Deserialize)]
|
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
||||||
#[serde(rename = "model")]
|
#[serde(rename = "model")]
|
||||||
pub struct NetIntModelXML {
|
pub struct NetIntModelXML {
|
||||||
#[serde(rename = "@type")]
|
#[serde(rename = "@type")]
|
||||||
pub r#type: String,
|
pub r#type: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, serde::Serialize, serde::Deserialize)]
|
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
||||||
#[serde(rename = "filterref")]
|
#[serde(rename = "filterref")]
|
||||||
pub struct NetIntFilterParameterXML {
|
pub struct NetIntFilterParameterXML {
|
||||||
#[serde(rename = "@name")]
|
#[serde(rename = "@name")]
|
||||||
@ -90,7 +90,7 @@ pub struct NetIntFilterParameterXML {
|
|||||||
pub value: String,
|
pub value: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, serde::Serialize, serde::Deserialize)]
|
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
||||||
#[serde(rename = "filterref")]
|
#[serde(rename = "filterref")]
|
||||||
pub struct NetIntfilterRefXML {
|
pub struct NetIntfilterRefXML {
|
||||||
#[serde(rename = "@filter")]
|
#[serde(rename = "@filter")]
|
||||||
@ -99,7 +99,7 @@ pub struct NetIntfilterRefXML {
|
|||||||
pub parameters: Vec<NetIntFilterParameterXML>,
|
pub parameters: Vec<NetIntFilterParameterXML>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, serde::Serialize, serde::Deserialize)]
|
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
||||||
#[serde(rename = "interface")]
|
#[serde(rename = "interface")]
|
||||||
pub struct DomainNetInterfaceXML {
|
pub struct DomainNetInterfaceXML {
|
||||||
#[serde(rename = "@type")]
|
#[serde(rename = "@type")]
|
||||||
@ -113,14 +113,14 @@ pub struct DomainNetInterfaceXML {
|
|||||||
pub filterref: Option<NetIntfilterRefXML>,
|
pub filterref: Option<NetIntfilterRefXML>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, serde::Serialize, serde::Deserialize)]
|
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
||||||
#[serde(rename = "input")]
|
#[serde(rename = "input")]
|
||||||
pub struct DomainInputXML {
|
pub struct DomainInputXML {
|
||||||
#[serde(rename = "@type")]
|
#[serde(rename = "@type")]
|
||||||
pub r#type: String,
|
pub r#type: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, serde::Serialize, serde::Deserialize)]
|
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
||||||
#[serde(rename = "backend")]
|
#[serde(rename = "backend")]
|
||||||
pub struct TPMBackendXML {
|
pub struct TPMBackendXML {
|
||||||
#[serde(rename = "@type")]
|
#[serde(rename = "@type")]
|
||||||
@ -130,7 +130,7 @@ pub struct TPMBackendXML {
|
|||||||
pub r#version: String,
|
pub r#version: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, serde::Serialize, serde::Deserialize)]
|
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
||||||
#[serde(rename = "tpm")]
|
#[serde(rename = "tpm")]
|
||||||
pub struct TPMDeviceXML {
|
pub struct TPMDeviceXML {
|
||||||
#[serde(rename = "@model")]
|
#[serde(rename = "@model")]
|
||||||
@ -139,7 +139,7 @@ pub struct TPMDeviceXML {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Devices information
|
/// Devices information
|
||||||
#[derive(Debug, serde::Serialize, serde::Deserialize)]
|
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
||||||
#[serde(rename = "devices")]
|
#[serde(rename = "devices")]
|
||||||
pub struct DevicesXML {
|
pub struct DevicesXML {
|
||||||
/// Graphics (used for VNC)
|
/// Graphics (used for VNC)
|
||||||
@ -168,7 +168,7 @@ pub struct DevicesXML {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Graphics information
|
/// Graphics information
|
||||||
#[derive(Debug, serde::Serialize, serde::Deserialize)]
|
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
||||||
#[serde(rename = "graphics")]
|
#[serde(rename = "graphics")]
|
||||||
pub struct GraphicsXML {
|
pub struct GraphicsXML {
|
||||||
#[serde(rename = "@type")]
|
#[serde(rename = "@type")]
|
||||||
@ -178,14 +178,14 @@ pub struct GraphicsXML {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Video device information
|
/// Video device information
|
||||||
#[derive(Debug, serde::Serialize, serde::Deserialize)]
|
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
||||||
#[serde(rename = "video")]
|
#[serde(rename = "video")]
|
||||||
pub struct VideoXML {
|
pub struct VideoXML {
|
||||||
pub model: VideoModelXML,
|
pub model: VideoModelXML,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Video model device information
|
/// Video model device information
|
||||||
#[derive(Debug, serde::Serialize, serde::Deserialize)]
|
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
||||||
#[serde(rename = "model")]
|
#[serde(rename = "model")]
|
||||||
pub struct VideoModelXML {
|
pub struct VideoModelXML {
|
||||||
#[serde(rename = "@type")]
|
#[serde(rename = "@type")]
|
||||||
@ -193,7 +193,7 @@ pub struct VideoModelXML {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Disk information
|
/// Disk information
|
||||||
#[derive(Debug, serde::Serialize, serde::Deserialize)]
|
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
||||||
#[serde(rename = "disk")]
|
#[serde(rename = "disk")]
|
||||||
pub struct DiskXML {
|
pub struct DiskXML {
|
||||||
#[serde(rename = "@type")]
|
#[serde(rename = "@type")]
|
||||||
@ -211,7 +211,7 @@ pub struct DiskXML {
|
|||||||
pub address: Option<DiskAddressXML>,
|
pub address: Option<DiskAddressXML>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, serde::Serialize, serde::Deserialize)]
|
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
||||||
#[serde(rename = "driver")]
|
#[serde(rename = "driver")]
|
||||||
pub struct DiskDriverXML {
|
pub struct DiskDriverXML {
|
||||||
#[serde(rename = "@name")]
|
#[serde(rename = "@name")]
|
||||||
@ -222,14 +222,14 @@ pub struct DiskDriverXML {
|
|||||||
pub r#cache: String,
|
pub r#cache: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, serde::Serialize, serde::Deserialize)]
|
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
||||||
#[serde(rename = "source")]
|
#[serde(rename = "source")]
|
||||||
pub struct DiskSourceXML {
|
pub struct DiskSourceXML {
|
||||||
#[serde(rename = "@file")]
|
#[serde(rename = "@file")]
|
||||||
pub file: String,
|
pub file: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, serde::Serialize, serde::Deserialize)]
|
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
||||||
#[serde(rename = "target")]
|
#[serde(rename = "target")]
|
||||||
pub struct DiskTargetXML {
|
pub struct DiskTargetXML {
|
||||||
#[serde(rename = "@dev")]
|
#[serde(rename = "@dev")]
|
||||||
@ -238,18 +238,18 @@ pub struct DiskTargetXML {
|
|||||||
pub bus: String,
|
pub bus: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, serde::Serialize, serde::Deserialize)]
|
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
||||||
#[serde(rename = "readonly")]
|
#[serde(rename = "readonly")]
|
||||||
pub struct DiskReadOnlyXML {}
|
pub struct DiskReadOnlyXML {}
|
||||||
|
|
||||||
#[derive(Debug, serde::Serialize, serde::Deserialize)]
|
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
||||||
#[serde(rename = "boot")]
|
#[serde(rename = "boot")]
|
||||||
pub struct DiskBootXML {
|
pub struct DiskBootXML {
|
||||||
#[serde(rename = "@order")]
|
#[serde(rename = "@order")]
|
||||||
pub order: String,
|
pub order: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, serde::Serialize, serde::Deserialize)]
|
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
||||||
#[serde(rename = "address")]
|
#[serde(rename = "address")]
|
||||||
pub struct DiskAddressXML {
|
pub struct DiskAddressXML {
|
||||||
#[serde(rename = "@type")]
|
#[serde(rename = "@type")]
|
||||||
@ -269,7 +269,7 @@ pub struct DiskAddressXML {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Domain RAM information
|
/// Domain RAM information
|
||||||
#[derive(Debug, serde::Serialize, serde::Deserialize)]
|
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
||||||
#[serde(rename = "memory")]
|
#[serde(rename = "memory")]
|
||||||
pub struct DomainMemoryXML {
|
pub struct DomainMemoryXML {
|
||||||
#[serde(rename = "@unit")]
|
#[serde(rename = "@unit")]
|
||||||
@ -279,7 +279,7 @@ pub struct DomainMemoryXML {
|
|||||||
pub memory: usize,
|
pub memory: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, serde::Serialize, serde::Deserialize)]
|
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
||||||
#[serde(rename = "topology")]
|
#[serde(rename = "topology")]
|
||||||
pub struct DomainCPUTopology {
|
pub struct DomainCPUTopology {
|
||||||
#[serde(rename = "@sockets")]
|
#[serde(rename = "@sockets")]
|
||||||
@ -290,14 +290,14 @@ pub struct DomainCPUTopology {
|
|||||||
pub threads: usize,
|
pub threads: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, serde::Serialize, serde::Deserialize)]
|
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
||||||
#[serde(rename = "cpu")]
|
#[serde(rename = "cpu")]
|
||||||
pub struct DomainVCPUXML {
|
pub struct DomainVCPUXML {
|
||||||
#[serde(rename = "$value")]
|
#[serde(rename = "$value")]
|
||||||
pub body: usize,
|
pub body: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, serde::Serialize, serde::Deserialize)]
|
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
||||||
#[serde(rename = "cpu")]
|
#[serde(rename = "cpu")]
|
||||||
pub struct DomainCPUXML {
|
pub struct DomainCPUXML {
|
||||||
#[serde(rename = "@mode")]
|
#[serde(rename = "@mode")]
|
||||||
@ -306,7 +306,7 @@ pub struct DomainCPUXML {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Domain information, see https://libvirt.org/formatdomain.html
|
/// Domain information, see https://libvirt.org/formatdomain.html
|
||||||
#[derive(Debug, serde::Serialize, serde::Deserialize)]
|
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
||||||
#[serde(rename = "domain")]
|
#[serde(rename = "domain")]
|
||||||
pub struct DomainXML {
|
pub struct DomainXML {
|
||||||
/// Domain type (kvm)
|
/// Domain type (kvm)
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
#[derive(serde::Serialize, serde::Deserialize, Clone, Copy, Debug)]
|
#[derive(serde::Serialize, serde::Deserialize, Clone, Copy, Debug, Eq, PartialEq)]
|
||||||
pub struct XMLUuid(pub uuid::Uuid);
|
pub struct XMLUuid(pub uuid::Uuid);
|
||||||
|
|
||||||
impl XMLUuid {
|
impl XMLUuid {
|
||||||
|
@ -212,7 +212,10 @@ async fn main() -> std::io::Result<()> {
|
|||||||
.route("/api/vnc", web::get().to(vm_controller::vnc))
|
.route("/api/vnc", web::get().to(vm_controller::vnc))
|
||||||
// Groups controller
|
// Groups controller
|
||||||
.route("/api/group/list", web::get().to(groups_controller::list))
|
.route("/api/group/list", web::get().to(groups_controller::list))
|
||||||
// TODO list VM
|
.route(
|
||||||
|
"/api/group/{gid}/vm/info",
|
||||||
|
web::get().to(groups_controller::vm_info),
|
||||||
|
)
|
||||||
// TODO start VM
|
// TODO start VM
|
||||||
// TODO stop VM
|
// TODO stop VM
|
||||||
// TODO suspend VM
|
// TODO suspend VM
|
||||||
|
Loading…
Reference in New Issue
Block a user