vmm: Implement the /api/v1/vm.delete endpoint

Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
This commit is contained in:
Samuel Ortiz 2019-10-01 17:24:39 +02:00
parent f9daf2e247
commit 7328ecdb3b
4 changed files with 46 additions and 15 deletions

View File

@ -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.delete"), Box::new(VmActionHandler::new(VmAction::Delete)));
r.routes.insert(endpoint!("/vm.info"), Box::new(VmInfo {})); 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)));

View File

@ -5,8 +5,8 @@
use crate::api::http::EndpointHandler; use crate::api::http::EndpointHandler;
use crate::api::{ use crate::api::{
vm_boot, vm_create, vm_info, vm_reboot, vm_shutdown, ApiError, ApiRequest, ApiResult, VmAction, vm_boot, vm_create, vm_delete, vm_info, vm_reboot, vm_shutdown, ApiError, ApiRequest,
VmConfig, ApiResult, VmAction, VmConfig,
}; };
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;
@ -97,6 +97,7 @@ impl VmActionHandler {
pub fn new(action: VmAction) -> Self { pub fn new(action: VmAction) -> Self {
let action_fn = Box::new(match action { let action_fn = Box::new(match action {
VmAction::Boot => vm_boot, VmAction::Boot => vm_boot,
VmAction::Delete => vm_delete,
VmAction::Shutdown => vm_shutdown, VmAction::Shutdown => vm_shutdown,
VmAction::Reboot => vm_reboot, VmAction::Reboot => vm_reboot,
}); });

View File

@ -67,6 +67,9 @@ pub enum ApiError {
/// The VM could not be created. /// The VM could not be created.
VmCreate(VmError), VmCreate(VmError),
/// The VM could not be deleted.
VmDelete(VmError),
/// The VM info is not available. /// The VM info is not available.
VmInfo(VmError), VmInfo(VmError),
@ -117,6 +120,12 @@ pub enum ApiRequest {
/// VmBoot error back. /// VmBoot error back.
VmBoot(Sender<ApiResponse>), VmBoot(Sender<ApiResponse>),
/// Delete the previously created virtual machine.
/// If the VM was not previously created, the VMM API server will send a
/// VmDelete error back.
/// If the VM is booted, we shut it down first.
VmDelete(Sender<ApiResponse>),
/// Request the VM information. /// Request the VM information.
VmInfo(Sender<ApiResponse>), VmInfo(Sender<ApiResponse>),
@ -156,6 +165,9 @@ pub enum VmAction {
/// Boot a VM /// Boot a VM
Boot, Boot,
/// Delete a VM
Delete,
/// Shut a VM down /// Shut a VM down
Shutdown, Shutdown,
@ -168,6 +180,7 @@ fn vm_action(api_evt: EventFd, api_sender: Sender<ApiRequest>, action: VmAction)
let request = match action { let request = match action {
VmAction::Boot => ApiRequest::VmBoot(response_sender), VmAction::Boot => ApiRequest::VmBoot(response_sender),
VmAction::Delete => ApiRequest::VmDelete(response_sender),
VmAction::Shutdown => ApiRequest::VmShutdown(response_sender), VmAction::Shutdown => ApiRequest::VmShutdown(response_sender),
VmAction::Reboot => ApiRequest::VmReboot(response_sender), VmAction::Reboot => ApiRequest::VmReboot(response_sender),
}; };
@ -176,19 +189,7 @@ fn vm_action(api_evt: EventFd, api_sender: Sender<ApiRequest>, action: VmAction)
api_sender.send(request).map_err(ApiError::RequestSend)?; api_sender.send(request).map_err(ApiError::RequestSend)?;
api_evt.write(1).map_err(ApiError::EventFdWrite)?; api_evt.write(1).map_err(ApiError::EventFdWrite)?;
match action { response_receiver.recv().map_err(ApiError::ResponseRecv)??;
VmAction::Boot => {
response_receiver.recv().map_err(ApiError::ResponseRecv)??;
}
VmAction::Shutdown => {
response_receiver.recv().map_err(ApiError::ResponseRecv)??;
}
VmAction::Reboot => {
response_receiver.recv().map_err(ApiError::ResponseRecv)??;
}
}
Ok(()) Ok(())
} }
@ -197,6 +198,10 @@ pub fn vm_boot(api_evt: EventFd, api_sender: Sender<ApiRequest>) -> ApiResult<()
vm_action(api_evt, api_sender, VmAction::Boot) vm_action(api_evt, api_sender, VmAction::Boot)
} }
pub fn vm_delete(api_evt: EventFd, api_sender: Sender<ApiRequest>) -> ApiResult<()> {
vm_action(api_evt, api_sender, VmAction::Delete)
}
pub fn vm_shutdown(api_evt: EventFd, api_sender: Sender<ApiRequest>) -> ApiResult<()> { pub fn vm_shutdown(api_evt: EventFd, api_sender: Sender<ApiRequest>) -> ApiResult<()> {
vm_action(api_evt, api_sender, VmAction::Shutdown) vm_action(api_evt, api_sender, VmAction::Shutdown)
} }

View File

@ -307,6 +307,22 @@ impl Vmm {
} }
} }
fn vm_delete(&mut self) -> result::Result<(), VmError> {
if self.vm_config.is_none() {
return Ok(());
}
self.vm_config = None;
// First we shut the current VM down if necessary.
if let Some(ref mut vm) = self.vm {
vm.shutdown()?;
self.vm = None;
}
Ok(())
}
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;
@ -377,6 +393,14 @@ impl Vmm {
sender.send(response).map_err(Error::ApiResponseSend)?; sender.send(response).map_err(Error::ApiResponseSend)?;
} }
ApiRequest::VmDelete(sender) => {
let response = match self.vm_delete() {
Ok(_) => Ok(ApiResponsePayload::Empty),
Err(e) => Err(ApiError::VmDelete(e)),
};
sender.send(response).map_err(Error::ApiResponseSend)?;
}
ApiRequest::VmBoot(sender) => { ApiRequest::VmBoot(sender) => {
// If we don't have a config, we can not boot a VM. // If we don't have a config, we can not boot a VM.
if self.vm_config.is_none() { if self.vm_config.is_none() {