From 981bb72a09c770d85d55c169de9dc3706c503733 Mon Sep 17 00:00:00 2001 From: Rob Bradford Date: Wed, 13 Jan 2021 10:06:36 +0000 Subject: [PATCH] vmm: api: Add "power-button" API entry point This will lead to the triggering of an ACPI button inside the guest in order to cleanly shutdown the guest. Signed-off-by: Rob Bradford --- vmm/src/api/http.rs | 4 ++++ vmm/src/api/http_endpoint.rs | 10 +++++++--- vmm/src/api/mod.rs | 17 +++++++++++++++++ vmm/src/lib.rs | 16 ++++++++++++++++ 4 files changed, 44 insertions(+), 3 deletions(-) diff --git a/vmm/src/api/http.rs b/vmm/src/api/http.rs index cd6b51699..915e5a572 100644 --- a/vmm/src/api/http.rs +++ b/vmm/src/api/http.rs @@ -106,6 +106,9 @@ pub enum HttpError { /// Error setting up migration sender VmSendMigration(ApiError), + + /// Error activating power button + VmPowerButton(ApiError), } impl From for HttpError { @@ -210,6 +213,7 @@ lazy_static! { 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.pause"), Box::new(VmActionHandler::new(VmAction::Pause))); + r.routes.insert(endpoint!("/vm.power-button"), Box::new(VmActionHandler::new(VmAction::PowerButton))); r.routes.insert(endpoint!("/vm.reboot"), Box::new(VmActionHandler::new(VmAction::Reboot))); r.routes.insert(endpoint!("/vm.receive-migration"), Box::new(VmActionHandler::new(VmAction::ReceiveMigration(Arc::default())))); r.routes.insert(endpoint!("/vm.remove-device"), Box::new(VmActionHandler::new(VmAction::RemoveDevice(Arc::default())))); diff --git a/vmm/src/api/http_endpoint.rs b/vmm/src/api/http_endpoint.rs index 7c82d54ba..91bf48652 100644 --- a/vmm/src/api/http_endpoint.rs +++ b/vmm/src/api/http_endpoint.rs @@ -6,9 +6,10 @@ use crate::api::http::{error_response, EndpointHandler, HttpError}; use crate::api::{ vm_add_device, vm_add_disk, vm_add_fs, vm_add_net, vm_add_pmem, vm_add_vsock, vm_boot, - vm_counters, vm_create, vm_delete, vm_info, vm_pause, vm_reboot, vm_receive_migration, - vm_remove_device, vm_resize, vm_resize_zone, vm_restore, vm_resume, vm_send_migration, - vm_shutdown, vm_snapshot, vmm_ping, vmm_shutdown, ApiRequest, VmAction, VmConfig, + vm_counters, vm_create, vm_delete, vm_info, vm_pause, vm_power_button, vm_reboot, + vm_receive_migration, vm_remove_device, vm_resize, vm_resize_zone, vm_restore, vm_resume, + vm_send_migration, vm_shutdown, vm_snapshot, vmm_ping, vmm_shutdown, ApiRequest, VmAction, + VmConfig, }; use micro_http::{Body, Method, Request, Response, StatusCode, Version}; use std::sync::mpsc::Sender; @@ -177,6 +178,9 @@ impl EndpointHandler for VmActionHandler { Reboot => vm_reboot(api_notifier, api_sender).map_err(HttpError::VmReboot), Pause => vm_pause(api_notifier, api_sender).map_err(HttpError::VmPause), Resume => vm_resume(api_notifier, api_sender).map_err(HttpError::VmResume), + PowerButton => { + vm_power_button(api_notifier, api_sender).map_err(HttpError::VmPowerButton) + } _ => Err(HttpError::BadRequest), } } diff --git a/vmm/src/api/mod.rs b/vmm/src/api/mod.rs index 6af762350..7fabf8c49 100644 --- a/vmm/src/api/mod.rs +++ b/vmm/src/api/mod.rs @@ -146,6 +146,9 @@ pub enum ApiError { /// Error starting migration sender VmSendMigration(MigratableError), + + /// Error triggering power button + VmPowerButton(VmError), } pub type ApiResult = std::result::Result; @@ -302,6 +305,9 @@ pub enum ApiRequest { /// Outgoing migration VmSendMigration(Arc, Sender), + + // Trigger power button + VmPowerButton(Sender), } pub fn vm_create( @@ -385,6 +391,9 @@ pub enum VmAction { /// Outgoing migration SendMigration(Arc), + + /// Power Button for clean shutdown + PowerButton, } fn vm_action( @@ -416,6 +425,7 @@ fn vm_action( Snapshot(v) => ApiRequest::VmSnapshot(v, response_sender), ReceiveMigration(v) => ApiRequest::VmReceiveMigration(v, response_sender), SendMigration(v) => ApiRequest::VmSendMigration(v, response_sender), + PowerButton => ApiRequest::VmPowerButton(response_sender), }; // Send the VM request. @@ -459,6 +469,13 @@ pub fn vm_counters(api_evt: EventFd, api_sender: Sender) -> ApiResul vm_action(api_evt, api_sender, VmAction::Counters) } +pub fn vm_power_button( + api_evt: EventFd, + api_sender: Sender, +) -> ApiResult> { + vm_action(api_evt, api_sender, VmAction::PowerButton) +} + pub fn vm_receive_migration( api_evt: EventFd, api_sender: Sender, diff --git a/vmm/src/lib.rs b/vmm/src/lib.rs index b0d70f364..53452a74f 100644 --- a/vmm/src/lib.rs +++ b/vmm/src/lib.rs @@ -677,6 +677,14 @@ impl Vmm { } } + fn vm_power_button(&mut self) -> result::Result<(), VmError> { + if let Some(ref mut vm) = self.vm { + vm.power_button() + } else { + Err(VmError::VmNotRunning) + } + } + fn vm_receive_config( &mut self, req: &Request, @@ -1317,6 +1325,14 @@ impl Vmm { .map(|_| ApiResponsePayload::Empty); sender.send(response).map_err(Error::ApiResponseSend)?; } + ApiRequest::VmPowerButton(sender) => { + let response = self + .vm_power_button() + .map_err(ApiError::VmPowerButton) + .map(|_| ApiResponsePayload::Empty); + + sender.send(response).map_err(Error::ApiResponseSend)?; + } } } }