mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2025-01-03 11:25:20 +00:00
vmm: Implement the VM HTTP endpoint handlers
Implement the vm.create, vm.boot, vm.shutdown and vm.reboot HTTP endpoint handlers. Fixes: #244 Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
This commit is contained in:
parent
8a5e47f989
commit
c505cfae2b
@ -82,4 +82,4 @@ pub use request::{Request, RequestError};
|
||||
pub use response::{Response, StatusCode};
|
||||
|
||||
pub use common::headers::Headers;
|
||||
pub use common::{Body, Version};
|
||||
pub use common::{Body, Method, Version};
|
||||
|
@ -4,9 +4,9 @@
|
||||
//
|
||||
|
||||
extern crate threadpool;
|
||||
extern crate vmm_sys_util;
|
||||
|
||||
use crate::api::ApiRequest;
|
||||
use crate::api::http_endpoint::{VmActionHandler, VmCreate};
|
||||
use crate::api::{ApiRequest, VmAction};
|
||||
use crate::{Error, Result};
|
||||
use micro_http::{HttpConnection, Request, Response, StatusCode, Version};
|
||||
use std::collections::HashMap;
|
||||
@ -50,10 +50,15 @@ macro_rules! endpoint {
|
||||
lazy_static! {
|
||||
/// HTTP_ROUTES contain all the cloud-hypervisor HTTP routes.
|
||||
pub static ref HTTP_ROUTES: HttpRoutes = {
|
||||
let r = HttpRoutes {
|
||||
let mut r = HttpRoutes {
|
||||
routes: HashMap::new(),
|
||||
};
|
||||
|
||||
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.shutdown"), Box::new(VmActionHandler::new(VmAction::Shutdown)));
|
||||
r.routes.insert(endpoint!("/vm.reboot"), Box::new(VmActionHandler::new(VmAction::Reboot)));
|
||||
|
||||
r
|
||||
};
|
||||
}
|
||||
|
126
vmm/src/api/http_endpoint.rs
Normal file
126
vmm/src/api/http_endpoint.rs
Normal file
@ -0,0 +1,126 @@
|
||||
// Copyright © 2019 Intel Corporation
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
use crate::api::http::EndpointHandler;
|
||||
use crate::api::VmConfig;
|
||||
use crate::api::{vm_boot, vm_create, vm_reboot, vm_shutdown, ApiRequest, VmAction};
|
||||
use crate::{Error, Result};
|
||||
use micro_http::{Body, Method, Request, Response, StatusCode, Version};
|
||||
use serde_json::Error as SerdeError;
|
||||
use std::sync::mpsc::Sender;
|
||||
use std::sync::Arc;
|
||||
use vmm_sys_util::eventfd::EventFd;
|
||||
|
||||
/// Errors associated with VMM management
|
||||
#[derive(Debug)]
|
||||
pub enum HttpError {
|
||||
/// API request receive error
|
||||
SerdeJsonDeserialize(SerdeError),
|
||||
|
||||
/// Could not create a VM
|
||||
VmCreate(Error),
|
||||
|
||||
/// Could not boot a VM
|
||||
VmBoot(Error),
|
||||
|
||||
/// Could not shut a VM down
|
||||
VmShutdown(Error),
|
||||
|
||||
/// Could not reboot a VM
|
||||
VmReboot(Error),
|
||||
|
||||
/// Could not act on a VM
|
||||
VmAction(Error),
|
||||
}
|
||||
|
||||
fn error_response(error: HttpError, status: StatusCode) -> Response {
|
||||
let mut response = Response::new(Version::Http11, status);
|
||||
response.set_body(Body::new(format!("{:?}", error)));
|
||||
|
||||
response
|
||||
}
|
||||
|
||||
// /api/v1/vm.create handler
|
||||
pub struct VmCreate {}
|
||||
|
||||
impl EndpointHandler for VmCreate {
|
||||
fn handle_request(
|
||||
&self,
|
||||
req: &Request,
|
||||
api_notifier: EventFd,
|
||||
api_sender: Sender<ApiRequest>,
|
||||
) -> Response {
|
||||
match req.method() {
|
||||
Method::Put => {
|
||||
match &req.body {
|
||||
Some(body) => {
|
||||
// Deserialize into a VmConfig
|
||||
let vm_config: VmConfig = match serde_json::from_slice(body.raw())
|
||||
.map_err(HttpError::SerdeJsonDeserialize)
|
||||
{
|
||||
Ok(config) => config,
|
||||
Err(e) => return error_response(e, StatusCode::BadRequest),
|
||||
};
|
||||
|
||||
// Call vm_create()
|
||||
match vm_create(api_notifier, api_sender, Arc::new(vm_config))
|
||||
.map_err(HttpError::VmCreate)
|
||||
{
|
||||
Ok(_) => Response::new(Version::Http11, StatusCode::OK),
|
||||
Err(e) => error_response(e, StatusCode::InternalServerError),
|
||||
}
|
||||
}
|
||||
|
||||
None => Response::new(Version::Http11, StatusCode::BadRequest),
|
||||
}
|
||||
}
|
||||
|
||||
_ => Response::new(Version::Http11, StatusCode::BadRequest),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Common handler for boot, shutdown and reboot
|
||||
pub struct VmActionHandler {
|
||||
action_fn: VmActionFn,
|
||||
}
|
||||
|
||||
type VmActionFn = Box<dyn Fn(EventFd, Sender<ApiRequest>) -> Result<()> + Send + Sync>;
|
||||
|
||||
impl VmActionHandler {
|
||||
pub fn new(action: VmAction) -> Self {
|
||||
let action_fn = Box::new(match action {
|
||||
VmAction::Boot => vm_boot,
|
||||
VmAction::Shutdown => vm_shutdown,
|
||||
VmAction::Reboot => vm_reboot,
|
||||
});
|
||||
|
||||
VmActionHandler { action_fn }
|
||||
}
|
||||
}
|
||||
|
||||
impl EndpointHandler for VmActionHandler {
|
||||
fn handle_request(
|
||||
&self,
|
||||
req: &Request,
|
||||
api_notifier: EventFd,
|
||||
api_sender: Sender<ApiRequest>,
|
||||
) -> Response {
|
||||
match req.method() {
|
||||
Method::Put => {
|
||||
match (self.action_fn)(api_notifier, api_sender).map_err(|e| match e {
|
||||
Error::ApiVmBoot(_) => HttpError::VmBoot(e),
|
||||
Error::ApiVmShutdown(_) => HttpError::VmShutdown(e),
|
||||
Error::ApiVmReboot(_) => HttpError::VmReboot(e),
|
||||
_ => HttpError::VmAction(e),
|
||||
}) {
|
||||
Ok(_) => Response::new(Version::Http11, StatusCode::OK),
|
||||
Err(e) => error_response(e, StatusCode::InternalServerError),
|
||||
}
|
||||
}
|
||||
_ => Response::new(Version::Http11, StatusCode::BadRequest),
|
||||
}
|
||||
}
|
||||
}
|
@ -34,6 +34,7 @@ extern crate vmm_sys_util;
|
||||
pub use self::http::start_http_thread;
|
||||
|
||||
pub mod http;
|
||||
pub mod http_endpoint;
|
||||
|
||||
use crate::config::VmConfig;
|
||||
use crate::vm::Error as VmError;
|
||||
|
Loading…
Reference in New Issue
Block a user