diff --git a/vmm/src/api/http.rs b/vmm/src/api/http.rs index 4006b136e..0dfc560cf 100644 --- a/vmm/src/api/http.rs +++ b/vmm/src/api/http.rs @@ -4,7 +4,8 @@ // use crate::api::http_endpoint::{ - VmActionHandler, VmAddDevice, VmCreate, VmInfo, VmRemoveDevice, VmResize, VmmPing, VmmShutdown, + VmActionHandler, VmAddDevice, VmAddDisk, VmCreate, VmInfo, VmRemoveDevice, VmResize, VmmPing, + VmmShutdown, }; use crate::api::{ApiRequest, VmAction}; use crate::seccomp_filters::{get_seccomp_filter, Thread}; @@ -66,6 +67,7 @@ lazy_static! { r.routes.insert(endpoint!("/vm.resize"), Box::new(VmResize {})); r.routes.insert(endpoint!("/vm.add-device"), Box::new(VmAddDevice {})); r.routes.insert(endpoint!("/vm.remove-device"), Box::new(VmRemoveDevice {})); + r.routes.insert(endpoint!("/vm.add-disk"), Box::new(VmAddDisk {})); r }; diff --git a/vmm/src/api/http_endpoint.rs b/vmm/src/api/http_endpoint.rs index 019ab8f39..81c88ca6b 100644 --- a/vmm/src/api/http_endpoint.rs +++ b/vmm/src/api/http_endpoint.rs @@ -5,9 +5,10 @@ use crate::api::http::EndpointHandler; use crate::api::{ - vm_add_device, vm_boot, vm_create, vm_delete, vm_info, vm_pause, vm_reboot, vm_remove_device, - vm_resize, vm_resume, vm_shutdown, vmm_ping, vmm_shutdown, ApiError, ApiRequest, ApiResult, - DeviceConfig, VmAction, VmConfig, VmRemoveDeviceData, VmResizeData, + vm_add_device, vm_add_disk, vm_boot, vm_create, vm_delete, vm_info, vm_pause, vm_reboot, + vm_remove_device, vm_resize, vm_resume, vm_shutdown, vmm_ping, vmm_shutdown, ApiError, + ApiRequest, ApiResult, DeviceConfig, DiskConfig, VmAction, VmConfig, VmRemoveDeviceData, + VmResizeData, }; use micro_http::{Body, Method, Request, Response, StatusCode, Version}; use serde_json::Error as SerdeError; @@ -59,6 +60,9 @@ pub enum HttpError { /// Could not handle VMM ping VmmPing(ApiError), + + /// Could not add a disk to a VM + VmAddDisk(ApiError), } fn error_response(error: HttpError, status: StatusCode) -> Response { @@ -352,3 +356,42 @@ impl EndpointHandler for VmRemoveDevice { } } } + +// /api/v1/vm.add-disk handler +pub struct VmAddDisk {} + +impl EndpointHandler for VmAddDisk { + 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 DiskConfig + let vm_add_disk_data: DiskConfig = match serde_json::from_slice(body.raw()) + .map_err(HttpError::SerdeJsonDeserialize) + { + Ok(config) => config, + Err(e) => return error_response(e, StatusCode::BadRequest), + }; + + // Call vm_add_device() + match vm_add_disk(api_notifier, api_sender, Arc::new(vm_add_disk_data)) + .map_err(HttpError::VmAddDisk) + { + Ok(_) => Response::new(Version::Http11, StatusCode::NoContent), + Err(e) => error_response(e, StatusCode::InternalServerError), + } + } + + None => Response::new(Version::Http11, StatusCode::BadRequest), + } + } + _ => Response::new(Version::Http11, StatusCode::BadRequest), + } + } +} diff --git a/vmm/src/api/mod.rs b/vmm/src/api/mod.rs index 7a6d3ba7a..8166234d9 100644 --- a/vmm/src/api/mod.rs +++ b/vmm/src/api/mod.rs @@ -36,7 +36,7 @@ pub use self::http::start_http_thread; pub mod http; pub mod http_endpoint; -use crate::config::{DeviceConfig, VmConfig}; +use crate::config::{DeviceConfig, DiskConfig, VmConfig}; use crate::vm::{Error as VmError, VmState}; use std::io; use std::sync::mpsc::{channel, RecvError, SendError, Sender}; @@ -111,6 +111,9 @@ pub enum ApiError { /// Cannot apply seccomp filter ApplySeccompFilter(seccomp::Error), + + /// The device could not be added to the VM. + VmAddDisk(VmError), } pub type ApiResult = std::result::Result; @@ -204,6 +207,9 @@ pub enum ApiRequest { /// Remove a device from the VM. VmRemoveDevice(Arc, Sender), + + /// Add a disk to the VM. + VmAddDisk(Arc, Sender), } pub fn vm_create( @@ -392,3 +398,21 @@ pub fn vm_remove_device( Ok(()) } + +pub fn vm_add_disk( + api_evt: EventFd, + api_sender: Sender, + data: Arc, +) -> ApiResult<()> { + let (response_sender, response_receiver) = channel(); + + // Send the VM add-disk request. + api_sender + .send(ApiRequest::VmAddDisk(data, response_sender)) + .map_err(ApiError::RequestSend)?; + api_evt.write(1).map_err(ApiError::EventFdWrite)?; + + response_receiver.recv().map_err(ApiError::ResponseRecv)??; + + Ok(()) +} diff --git a/vmm/src/lib.rs b/vmm/src/lib.rs index 7ebfc41a4..aa7aed8b5 100644 --- a/vmm/src/lib.rs +++ b/vmm/src/lib.rs @@ -16,7 +16,7 @@ extern crate tempfile; extern crate vmm_sys_util; use crate::api::{ApiError, ApiRequest, ApiResponse, ApiResponsePayload, VmInfo, VmmPingResponse}; -use crate::config::{DeviceConfig, VmConfig}; +use crate::config::{DeviceConfig, DiskConfig, VmConfig}; use crate::seccomp_filters::{get_seccomp_filter, Thread}; use crate::vm::{Error as VmError, Vm, VmState}; use libc::EFD_NONBLOCK; @@ -415,6 +415,19 @@ impl Vmm { } } + fn vm_add_disk(&mut self, disk_cfg: DiskConfig) -> result::Result<(), VmError> { + if let Some(ref mut vm) = self.vm { + if let Err(e) = vm.add_disk(disk_cfg) { + error!("Error when adding new disk to the VM: {:?}", e); + Err(e) + } else { + Ok(()) + } + } else { + Err(VmError::VmNotRunning) + } + } + fn control_loop(&mut self, api_receiver: Arc>) -> Result<()> { const EPOLL_EVENTS_LEN: usize = 100; @@ -584,6 +597,13 @@ impl Vmm { .map(|_| ApiResponsePayload::Empty); sender.send(response).map_err(Error::ApiResponseSend)?; } + ApiRequest::VmAddDisk(add_disk_data, sender) => { + let response = self + .vm_add_disk(add_disk_data.as_ref().clone()) + .map_err(ApiError::VmAddDisk) + .map(|_| ApiResponsePayload::Empty); + sender.send(response).map_err(Error::ApiResponseSend)?; + } } } }