diff --git a/vmm/src/api/mod.rs b/vmm/src/api/mod.rs index e176f309a..ca5add44f 100644 --- a/vmm/src/api/mod.rs +++ b/vmm/src/api/mod.rs @@ -98,6 +98,9 @@ pub enum ApiError { /// The VM could not be snapshotted. VmSnapshot(VmError), + /// The VM could not restored. + VmRestore(VmError), + /// The VMM could not shutdown. VmmShutdown(VmError), @@ -155,6 +158,13 @@ pub struct VmSnapshotConfig { pub destination_url: String, } +#[derive(Clone, Deserialize, Serialize)] +pub struct VmRestoreConfig { + /// The snapshot restore source URL. + /// This is where the VMM is going to get its snapshot to restore itself from. + pub source_url: String, +} + pub enum ApiResponsePayload { /// No data is sent on the channel. Empty, @@ -235,6 +245,9 @@ pub enum ApiRequest { /// Take a VM snapshot VmSnapshot(Arc, Sender), + + /// Restore from a VM snapshot + VmRestore(Arc, Sender), } pub fn vm_create( @@ -341,6 +354,24 @@ pub fn vm_snapshot( Ok(()) } +pub fn vm_restore( + api_evt: EventFd, + api_sender: Sender, + data: Arc, +) -> ApiResult<()> { + let (response_sender, response_receiver) = channel(); + + // Send the VM restore request. + api_sender + .send(ApiRequest::VmRestore(data, response_sender)) + .map_err(ApiError::RequestSend)?; + api_evt.write(1).map_err(ApiError::EventFdWrite)?; + + response_receiver.recv().map_err(ApiError::ResponseRecv)??; + + Ok(()) +} + pub fn vm_info(api_evt: EventFd, api_sender: Sender) -> ApiResult { let (response_sender, response_receiver) = channel(); diff --git a/vmm/src/lib.rs b/vmm/src/lib.rs index 4eb37b279..a0dcc13e2 100644 --- a/vmm/src/lib.rs +++ b/vmm/src/lib.rs @@ -292,6 +292,10 @@ impl Vmm { Ok(()) } + fn vm_restore(&mut self, _source_url: &str) -> result::Result<(), VmError> { + Ok(()) + } + fn vm_shutdown(&mut self) -> result::Result<(), VmError> { if let Some(ref mut vm) = self.vm.take() { vm.shutdown() @@ -601,6 +605,14 @@ impl Vmm { sender.send(response).map_err(Error::ApiResponseSend)?; } + ApiRequest::VmRestore(snapshot_data, sender) => { + let response = self + .vm_restore(&snapshot_data.source_url) + .map_err(ApiError::VmRestore) + .map(|_| ApiResponsePayload::Empty); + + sender.send(response).map_err(Error::ApiResponseSend)?; + } ApiRequest::VmmShutdown(sender) => { let response = self .vmm_shutdown() diff --git a/vmm/src/migration.rs b/vmm/src/migration.rs index a3408dc6b..decc9f93b 100644 --- a/vmm/src/migration.rs +++ b/vmm/src/migration.rs @@ -2,10 +2,13 @@ // // SPDX-License-Identifier: Apache-2.0 +use crate::config::VmConfig; +use crate::vm::{VmSnapshot, VM_SNAPSHOT_ID}; use anyhow::anyhow; use std::fs::File; use std::io::BufReader; use std::path::PathBuf; +use std::sync::{Arc, Mutex}; use url::Url; use vm_migration::{MigratableError, Snapshot}; @@ -59,3 +62,23 @@ pub fn recv_vm_snapshot(source_url: &str) -> std::result::Result std::result::Result>, MigratableError> { + if let Some(vm_section) = snapshot + .snapshot_data + .get(&format!("{}-section", VM_SNAPSHOT_ID)) + { + let vm_snapshot: VmSnapshot = + serde_json::from_slice(&vm_section.snapshot).map_err(|e| { + MigratableError::Restore(anyhow!("Could not deserialize VM snapshot {}", e)) + })?; + + return Ok(vm_snapshot.config); + } + + Err(MigratableError::Restore(anyhow!( + "Could not find VM config snapshot section" + ))) +} diff --git a/vmm/src/vm.rs b/vmm/src/vm.rs index 125c70f88..3d31a189d 100755 --- a/vmm/src/vm.rs +++ b/vmm/src/vm.rs @@ -139,6 +139,9 @@ pub enum Error { /// VM is not created VmNotCreated, + /// VM is already created + VmAlreadyCreated, + /// VM is not running VmNotRunning, @@ -184,6 +187,9 @@ pub enum Error { /// Cannot snapshot VM Snapshot(MigratableError), + /// Cannot restore VM + Restore(MigratableError), + /// Cannot send VM snapshot SnapshotSend(MigratableError), }