mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2025-02-22 11:22:26 +00:00
vmm: Implement the /api/v1/vm.info endpoint
This, for now, returns the VM config and its state. Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
This commit is contained in:
parent
27af983ec9
commit
42758244a0
@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
extern crate threadpool;
|
extern crate threadpool;
|
||||||
|
|
||||||
use crate::api::http_endpoint::{VmActionHandler, VmCreate};
|
use crate::api::http_endpoint::{VmActionHandler, VmCreate, VmInfo};
|
||||||
use crate::api::{ApiRequest, VmAction};
|
use crate::api::{ApiRequest, VmAction};
|
||||||
use crate::{Error, Result};
|
use crate::{Error, Result};
|
||||||
use micro_http::{HttpConnection, Request, Response, StatusCode, Version};
|
use micro_http::{HttpConnection, Request, Response, StatusCode, Version};
|
||||||
@ -56,6 +56,7 @@ lazy_static! {
|
|||||||
|
|
||||||
r.routes.insert(endpoint!("/vm.create"), Box::new(VmCreate {}));
|
r.routes.insert(endpoint!("/vm.create"), Box::new(VmCreate {}));
|
||||||
r.routes.insert(endpoint!("/vm.boot"), Box::new(VmActionHandler::new(VmAction::Boot)));
|
r.routes.insert(endpoint!("/vm.boot"), Box::new(VmActionHandler::new(VmAction::Boot)));
|
||||||
|
r.routes.insert(endpoint!("/vm.info"), Box::new(VmInfo {}));
|
||||||
r.routes.insert(endpoint!("/vm.shutdown"), Box::new(VmActionHandler::new(VmAction::Shutdown)));
|
r.routes.insert(endpoint!("/vm.shutdown"), Box::new(VmActionHandler::new(VmAction::Shutdown)));
|
||||||
r.routes.insert(endpoint!("/vm.reboot"), Box::new(VmActionHandler::new(VmAction::Reboot)));
|
r.routes.insert(endpoint!("/vm.reboot"), Box::new(VmActionHandler::new(VmAction::Reboot)));
|
||||||
|
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
use crate::api::http::EndpointHandler;
|
use crate::api::http::EndpointHandler;
|
||||||
use crate::api::VmConfig;
|
use crate::api::VmConfig;
|
||||||
use crate::api::{vm_boot, vm_create, vm_reboot, vm_shutdown, ApiRequest, VmAction};
|
use crate::api::{vm_boot, vm_create, vm_info, vm_reboot, vm_shutdown, ApiRequest, VmAction};
|
||||||
use crate::{Error, Result};
|
use crate::{Error, Result};
|
||||||
use micro_http::{Body, Method, Request, Response, StatusCode, Version};
|
use micro_http::{Body, Method, Request, Response, StatusCode, Version};
|
||||||
use serde_json::Error as SerdeError;
|
use serde_json::Error as SerdeError;
|
||||||
@ -25,6 +25,9 @@ pub enum HttpError {
|
|||||||
/// Could not boot a VM
|
/// Could not boot a VM
|
||||||
VmBoot(Error),
|
VmBoot(Error),
|
||||||
|
|
||||||
|
/// Could not get the VM information
|
||||||
|
VmInfo(Error),
|
||||||
|
|
||||||
/// Could not shut a VM down
|
/// Could not shut a VM down
|
||||||
VmShutdown(Error),
|
VmShutdown(Error),
|
||||||
|
|
||||||
@ -124,3 +127,29 @@ impl EndpointHandler for VmActionHandler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// /api/v1/vm.info handler
|
||||||
|
pub struct VmInfo {}
|
||||||
|
|
||||||
|
impl EndpointHandler for VmInfo {
|
||||||
|
fn handle_request(
|
||||||
|
&self,
|
||||||
|
req: &Request,
|
||||||
|
api_notifier: EventFd,
|
||||||
|
api_sender: Sender<ApiRequest>,
|
||||||
|
) -> Response {
|
||||||
|
match req.method() {
|
||||||
|
Method::Get => match vm_info(api_notifier, api_sender).map_err(HttpError::VmInfo) {
|
||||||
|
Ok(info) => {
|
||||||
|
let mut response = Response::new(Version::Http11, StatusCode::OK);
|
||||||
|
let info_serialized = serde_json::to_string(&info).unwrap();
|
||||||
|
|
||||||
|
response.set_body(Body::new(info_serialized));
|
||||||
|
response
|
||||||
|
}
|
||||||
|
Err(e) => error_response(e, StatusCode::InternalServerError),
|
||||||
|
},
|
||||||
|
_ => Response::new(Version::Http11, StatusCode::BadRequest),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -37,7 +37,7 @@ pub mod http;
|
|||||||
pub mod http_endpoint;
|
pub mod http_endpoint;
|
||||||
|
|
||||||
use crate::config::VmConfig;
|
use crate::config::VmConfig;
|
||||||
use crate::vm::Error as VmError;
|
use crate::vm::{Error as VmError, VmState};
|
||||||
use crate::{Error, Result};
|
use crate::{Error, Result};
|
||||||
use std::sync::mpsc::{channel, Sender};
|
use std::sync::mpsc::{channel, Sender};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
@ -55,6 +55,9 @@ pub enum ApiError {
|
|||||||
/// The VM is already created.
|
/// The VM is already created.
|
||||||
VmAlreadyCreated,
|
VmAlreadyCreated,
|
||||||
|
|
||||||
|
/// The VM info is not available.
|
||||||
|
VmInfo,
|
||||||
|
|
||||||
/// The VM config is missing.
|
/// The VM config is missing.
|
||||||
VmMissingConfig,
|
VmMissingConfig,
|
||||||
|
|
||||||
@ -71,9 +74,18 @@ pub enum ApiError {
|
|||||||
VmReboot,
|
VmReboot,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Deserialize, Serialize)]
|
||||||
|
pub struct VmInfo {
|
||||||
|
pub config: Arc<VmConfig>,
|
||||||
|
pub state: VmState,
|
||||||
|
}
|
||||||
|
|
||||||
pub enum ApiResponsePayload {
|
pub enum ApiResponsePayload {
|
||||||
/// No data is sent on the channel.
|
/// No data is sent on the channel.
|
||||||
Empty,
|
Empty,
|
||||||
|
|
||||||
|
/// Virtual machine information
|
||||||
|
VmInfo(VmInfo),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This is the response sent by the VMM API server through the mpsc channel.
|
/// This is the response sent by the VMM API server through the mpsc channel.
|
||||||
@ -92,6 +104,9 @@ pub enum ApiRequest {
|
|||||||
/// VmBoot error back.
|
/// VmBoot error back.
|
||||||
VmBoot(Sender<ApiResponse>),
|
VmBoot(Sender<ApiResponse>),
|
||||||
|
|
||||||
|
/// Request the VM information.
|
||||||
|
VmInfo(Sender<ApiResponse>),
|
||||||
|
|
||||||
/// Shut the previously booted virtual machine down.
|
/// Shut the previously booted virtual machine down.
|
||||||
/// If the VM was not previously booted or created, the VMM API server
|
/// If the VM was not previously booted or created, the VMM API server
|
||||||
/// will send a VmShutdown error back.
|
/// will send a VmShutdown error back.
|
||||||
@ -188,3 +203,23 @@ pub fn vm_shutdown(api_evt: EventFd, api_sender: Sender<ApiRequest>) -> Result<(
|
|||||||
pub fn vm_reboot(api_evt: EventFd, api_sender: Sender<ApiRequest>) -> Result<()> {
|
pub fn vm_reboot(api_evt: EventFd, api_sender: Sender<ApiRequest>) -> Result<()> {
|
||||||
vm_action(api_evt, api_sender, VmAction::Reboot)
|
vm_action(api_evt, api_sender, VmAction::Reboot)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn vm_info(api_evt: EventFd, api_sender: Sender<ApiRequest>) -> Result<VmInfo> {
|
||||||
|
let (response_sender, response_receiver) = channel();
|
||||||
|
|
||||||
|
// Send the VM request.
|
||||||
|
api_sender
|
||||||
|
.send(ApiRequest::VmInfo(response_sender))
|
||||||
|
.map_err(Error::ApiRequestSend)?;
|
||||||
|
api_evt.write(1).map_err(Error::EventFdWrite)?;
|
||||||
|
|
||||||
|
let vm_info = response_receiver
|
||||||
|
.recv()
|
||||||
|
.map_err(Error::ApiResponseRecv)?
|
||||||
|
.map_err(|_| Error::ApiVmInfo)?;
|
||||||
|
|
||||||
|
match vm_info {
|
||||||
|
ApiResponsePayload::VmInfo(info) => Ok(info),
|
||||||
|
_ => Err(Error::ApiVmInfo),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -14,9 +14,9 @@ extern crate serde_derive;
|
|||||||
extern crate serde_json;
|
extern crate serde_json;
|
||||||
extern crate vmm_sys_util;
|
extern crate vmm_sys_util;
|
||||||
|
|
||||||
use crate::api::{ApiError, ApiRequest, ApiResponse, ApiResponsePayload};
|
use crate::api::{ApiError, ApiRequest, ApiResponse, ApiResponsePayload, VmInfo};
|
||||||
use crate::config::VmConfig;
|
use crate::config::VmConfig;
|
||||||
use crate::vm::{Error as VmError, ExitBehaviour, Vm};
|
use crate::vm::{Error as VmError, ExitBehaviour, Vm, VmState};
|
||||||
use libc::EFD_NONBLOCK;
|
use libc::EFD_NONBLOCK;
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::os::unix::io::{AsRawFd, RawFd};
|
use std::os::unix::io::{AsRawFd, RawFd};
|
||||||
@ -52,6 +52,9 @@ pub enum Error {
|
|||||||
/// Cannot boot a VM from the API
|
/// Cannot boot a VM from the API
|
||||||
ApiVmBoot(ApiError),
|
ApiVmBoot(ApiError),
|
||||||
|
|
||||||
|
/// Cannot get the VM info
|
||||||
|
ApiVmInfo,
|
||||||
|
|
||||||
/// Cannot shut a VM down from the API
|
/// Cannot shut a VM down from the API
|
||||||
ApiVmShutdown(ApiError),
|
ApiVmShutdown(ApiError),
|
||||||
|
|
||||||
@ -88,6 +91,9 @@ pub enum Error {
|
|||||||
/// Cannot boot a VM
|
/// Cannot boot a VM
|
||||||
VmBoot(VmError),
|
VmBoot(VmError),
|
||||||
|
|
||||||
|
/// Cannot fetch the VM information
|
||||||
|
VmInfo,
|
||||||
|
|
||||||
/// The Vm is not created
|
/// The Vm is not created
|
||||||
VmNotCreated,
|
VmNotCreated,
|
||||||
|
|
||||||
@ -289,6 +295,23 @@ impl Vmm {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn vm_info(&self) -> Result<VmInfo> {
|
||||||
|
match &self.vm_config {
|
||||||
|
Some(config) => {
|
||||||
|
let state = match &self.vm {
|
||||||
|
Some(vm) => vm.get_state().unwrap(),
|
||||||
|
None => VmState::Created,
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(VmInfo {
|
||||||
|
config: Arc::clone(config),
|
||||||
|
state,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
None => Err(Error::VmNotCreated),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn control_loop(&mut self, api_receiver: Arc<Receiver<ApiRequest>>) -> Result<ExitBehaviour> {
|
fn control_loop(&mut self, api_receiver: Arc<Receiver<ApiRequest>>) -> Result<ExitBehaviour> {
|
||||||
const EPOLL_EVENTS_LEN: usize = 100;
|
const EPOLL_EVENTS_LEN: usize = 100;
|
||||||
|
|
||||||
@ -429,6 +452,14 @@ impl Vmm {
|
|||||||
Err(_) => Err(ApiError::VmReboot),
|
Err(_) => Err(ApiError::VmReboot),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
sender.send(response).map_err(Error::ApiResponseSend)?;
|
||||||
|
}
|
||||||
|
ApiRequest::VmInfo(sender) => {
|
||||||
|
let response = match self.vm_info() {
|
||||||
|
Ok(info) => Ok(ApiResponsePayload::VmInfo(info)),
|
||||||
|
Err(_) => Err(ApiError::VmInfo),
|
||||||
|
};
|
||||||
|
|
||||||
sender.send(response).map_err(Error::ApiResponseSend)?;
|
sender.send(response).map_err(Error::ApiResponseSend)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user