From c505cfae2bccfd11c3da6ffb1762cb88057010f8 Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Fri, 27 Sep 2019 01:37:06 +0200 Subject: [PATCH] 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 --- micro_http/src/lib.rs | 2 +- vmm/src/api/http.rs | 11 ++- vmm/src/api/http_endpoint.rs | 126 +++++++++++++++++++++++++++++++++++ vmm/src/api/mod.rs | 1 + 4 files changed, 136 insertions(+), 4 deletions(-) create mode 100644 vmm/src/api/http_endpoint.rs diff --git a/micro_http/src/lib.rs b/micro_http/src/lib.rs index aec3a16c1..69a75246c 100644 --- a/micro_http/src/lib.rs +++ b/micro_http/src/lib.rs @@ -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}; diff --git a/vmm/src/api/http.rs b/vmm/src/api/http.rs index 930eebca3..db919f543 100644 --- a/vmm/src/api/http.rs +++ b/vmm/src/api/http.rs @@ -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 }; } diff --git a/vmm/src/api/http_endpoint.rs b/vmm/src/api/http_endpoint.rs new file mode 100644 index 000000000..f26a044de --- /dev/null +++ b/vmm/src/api/http_endpoint.rs @@ -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, + ) -> 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) -> 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, + ) -> 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), + } + } +} diff --git a/vmm/src/api/mod.rs b/vmm/src/api/mod.rs index dbc0064ab..63b17138f 100644 --- a/vmm/src/api/mod.rs +++ b/vmm/src/api/mod.rs @@ -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;