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:
Samuel Ortiz 2019-09-27 01:37:06 +02:00
parent 8a5e47f989
commit c505cfae2b
4 changed files with 136 additions and 4 deletions

View File

@ -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};

View File

@ -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
};
}

View 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),
}
}
}

View File

@ -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;