diff --git a/vmm/src/api/http.rs b/vmm/src/api/http.rs index d0c85aa11..cd6b51699 100644 --- a/vmm/src/api/http.rs +++ b/vmm/src/api/http.rs @@ -100,6 +100,12 @@ pub enum HttpError { /// Could not get counters from VM VmCounters(ApiError), + + /// Error setting up migration received + VmReceiveMigration(ApiError), + + /// Error setting up migration sender + VmSendMigration(ApiError), } impl From for HttpError { @@ -205,11 +211,13 @@ lazy_static! { 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.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())))); r.routes.insert(endpoint!("/vm.resize"), Box::new(VmActionHandler::new(VmAction::Resize(Arc::default())))); r.routes.insert(endpoint!("/vm.resize-zone"), Box::new(VmActionHandler::new(VmAction::ResizeZone(Arc::default())))); r.routes.insert(endpoint!("/vm.restore"), Box::new(VmActionHandler::new(VmAction::Restore(Arc::default())))); r.routes.insert(endpoint!("/vm.resume"), Box::new(VmActionHandler::new(VmAction::Resume))); + r.routes.insert(endpoint!("/vm.send-migration"), Box::new(VmActionHandler::new(VmAction::SendMigration(Arc::default())))); r.routes.insert(endpoint!("/vm.shutdown"), Box::new(VmActionHandler::new(VmAction::Shutdown))); r.routes.insert(endpoint!("/vm.snapshot"), Box::new(VmActionHandler::new(VmAction::Snapshot(Arc::default())))); r.routes.insert(endpoint!("/vmm.ping"), Box::new(VmmPing {})); diff --git a/vmm/src/api/http_endpoint.rs b/vmm/src/api/http_endpoint.rs index 2bc6a9463..7c82d54ba 100644 --- a/vmm/src/api/http_endpoint.rs +++ b/vmm/src/api/http_endpoint.rs @@ -6,9 +6,9 @@ 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_remove_device, vm_resize, - vm_resize_zone, vm_restore, vm_resume, vm_shutdown, vm_snapshot, vmm_ping, vmm_shutdown, - ApiRequest, VmAction, VmConfig, + 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, }; use micro_http::{Body, Method, Request, Response, StatusCode, Version}; use std::sync::mpsc::Sender; @@ -153,6 +153,20 @@ impl EndpointHandler for VmActionHandler { ) .map_err(HttpError::VmSnapshot), + ReceiveMigration(_) => vm_receive_migration( + api_notifier, + api_sender, + Arc::new(serde_json::from_slice(body.raw())?), + ) + .map_err(HttpError::VmReceiveMigration), + + SendMigration(_) => vm_send_migration( + api_notifier, + api_sender, + Arc::new(serde_json::from_slice(body.raw())?), + ) + .map_err(HttpError::VmSendMigration), + _ => Err(HttpError::BadRequest), } } else { diff --git a/vmm/src/api/mod.rs b/vmm/src/api/mod.rs index 36583f334..9684e3c46 100644 --- a/vmm/src/api/mod.rs +++ b/vmm/src/api/mod.rs @@ -44,6 +44,7 @@ use micro_http::Body; use std::io; use std::sync::mpsc::{channel, RecvError, SendError, Sender}; use std::sync::{Arc, Mutex}; +use vm_migration::MigratableError; use vmm_sys_util::eventfd::EventFd; /// API errors are sent back from the VMM API server through the ApiResponse. @@ -138,6 +139,12 @@ pub enum ApiError { /// The vsock device could not be added to the VM. VmAddVsock(VmError), + + /// Error starting migration receiever + VmReceiveMigration(MigratableError), + + /// Error starting migration sender + VmSendMigration(MigratableError), } pub type ApiResult = std::result::Result; @@ -177,6 +184,18 @@ pub struct VmSnapshotConfig { pub destination_url: String, } +#[derive(Clone, Deserialize, Serialize, Default)] +pub struct VmReceiveMigrationData { + /// URL for the reception of migration state + pub receiver_url: String, +} + +#[derive(Clone, Deserialize, Serialize, Default)] +pub struct VmSendMigrationData { + /// URL to migrate the VM to + pub destination_url: String, +} + pub enum ApiResponsePayload { /// No data is sent on the channel. Empty, @@ -275,6 +294,12 @@ pub enum ApiRequest { /// Restore from a VM snapshot VmRestore(Arc, Sender), + + /// Incoming migration + VmReceiveMigration(Arc, Sender), + + /// Outgoing migration + VmSendMigration(Arc, Sender), } pub fn vm_create( @@ -352,6 +377,12 @@ pub enum VmAction { /// Snapshot VM Snapshot(Arc), + + /// Incoming migration + ReceiveMigration(Arc), + + /// Outgoing migration + SendMigration(Arc), } fn vm_action( @@ -381,6 +412,8 @@ fn vm_action( ResizeZone(v) => ApiRequest::VmResizeZone(v, response_sender), Restore(v) => ApiRequest::VmRestore(v, response_sender), Snapshot(v) => ApiRequest::VmSnapshot(v, response_sender), + ReceiveMigration(v) => ApiRequest::VmReceiveMigration(v, response_sender), + SendMigration(v) => ApiRequest::VmSendMigration(v, response_sender), }; // Send the VM request. @@ -424,6 +457,22 @@ pub fn vm_counters(api_evt: EventFd, api_sender: Sender) -> ApiResul vm_action(api_evt, api_sender, VmAction::Counters) } +pub fn vm_receive_migration( + api_evt: EventFd, + api_sender: Sender, + data: Arc, +) -> ApiResult> { + vm_action(api_evt, api_sender, VmAction::ReceiveMigration(data)) +} + +pub fn vm_send_migration( + api_evt: EventFd, + api_sender: Sender, + data: Arc, +) -> ApiResult> { + vm_action(api_evt, api_sender, VmAction::SendMigration(data)) +} + pub fn vm_snapshot( api_evt: EventFd, api_sender: Sender, diff --git a/vmm/src/lib.rs b/vmm/src/lib.rs index 5e01da9e5..7f83c1185 100644 --- a/vmm/src/lib.rs +++ b/vmm/src/lib.rs @@ -22,7 +22,10 @@ extern crate vmm_sys_util; #[macro_use] extern crate credibility; -use crate::api::{ApiError, ApiRequest, ApiResponse, ApiResponsePayload, VmInfo, VmmPingResponse}; +use crate::api::{ + ApiError, ApiRequest, ApiResponse, ApiResponsePayload, VmInfo, VmReceiveMigrationData, + VmSendMigrationData, VmmPingResponse, +}; use crate::config::{ DeviceConfig, DiskConfig, FsConfig, NetConfig, PmemConfig, RestoreConfig, VmConfig, VsockConfig, }; @@ -39,7 +42,7 @@ use std::sync::mpsc::{Receiver, RecvError, SendError, Sender}; use std::sync::{Arc, Mutex}; use std::{result, thread}; use thiserror::Error; -use vm_migration::{Pausable, Snapshottable, Transportable}; +use vm_migration::{MigratableError, Pausable, Snapshottable, Transportable}; use vmm_sys_util::eventfd::EventFd; pub mod api; @@ -639,6 +642,25 @@ impl Vmm { } } + fn vm_receive_migration( + &mut self, + receive_data_migration: VmReceiveMigrationData, + ) -> result::Result<(), MigratableError> { + info!( + "Migration Receiver: {}", + receive_data_migration.receiver_url + ); + Ok(()) + } + + fn vm_send_migration( + &mut self, + send_data_migration: VmSendMigrationData, + ) -> result::Result<(), MigratableError> { + info!("Migration Sender: {}", send_data_migration.destination_url); + Ok(()) + } + fn control_loop(&mut self, api_receiver: Arc>) -> Result<()> { const EPOLL_EVENTS_LEN: usize = 100; @@ -878,6 +900,22 @@ impl Vmm { sender.send(response).map_err(Error::ApiResponseSend)?; } + ApiRequest::VmReceiveMigration(receive_migration_data, sender) => { + let response = self + .vm_receive_migration( + receive_migration_data.as_ref().clone(), + ) + .map_err(ApiError::VmReceiveMigration) + .map(|_| ApiResponsePayload::Empty); + sender.send(response).map_err(Error::ApiResponseSend)?; + } + ApiRequest::VmSendMigration(send_migration_data, sender) => { + let response = self + .vm_send_migration(send_migration_data.as_ref().clone()) + .map_err(ApiError::VmSendMigration) + .map(|_| ApiResponsePayload::Empty); + sender.send(response).map_err(Error::ApiResponseSend)?; + } } } }