xref: /cloud-hypervisor/vmm/src/migration.rs (revision 3ce0fef7fd546467398c914dbc74d8542e45cf6f)
1 // Copyright © 2020 Intel Corporation
2 //
3 // SPDX-License-Identifier: Apache-2.0
4 
5 #[cfg(all(target_arch = "x86_64", feature = "guest_debug"))]
6 use crate::coredump::GuestDebuggableError;
7 use crate::{config::VmConfig, vm::VmSnapshot};
8 use anyhow::anyhow;
9 use std::fs::File;
10 use std::io::Read;
11 use std::path::PathBuf;
12 use vm_migration::{MigratableError, Snapshot};
13 
14 pub const SNAPSHOT_STATE_FILE: &str = "state.json";
15 pub const SNAPSHOT_CONFIG_FILE: &str = "config.json";
16 
17 pub fn url_to_path(url: &str) -> std::result::Result<PathBuf, MigratableError> {
18     let path: PathBuf = url
19         .strip_prefix("file://")
20         .ok_or_else(|| {
21             MigratableError::MigrateSend(anyhow!("Could not extract path from URL: {}", url))
22         })
23         .map(|s| s.into())?;
24 
25     if !path.is_dir() {
26         return Err(MigratableError::MigrateSend(anyhow!(
27             "Destination is not a directory"
28         )));
29     }
30 
31     Ok(path)
32 }
33 
34 #[cfg(all(target_arch = "x86_64", feature = "guest_debug"))]
35 pub fn url_to_file(url: &str) -> std::result::Result<PathBuf, GuestDebuggableError> {
36     let file: PathBuf = url
37         .strip_prefix("file://")
38         .ok_or_else(|| {
39             GuestDebuggableError::Coredump(anyhow!("Could not extract file from URL: {}", url))
40         })
41         .map(|s| s.into())?;
42 
43     Ok(file)
44 }
45 
46 pub fn recv_vm_config(source_url: &str) -> std::result::Result<VmConfig, MigratableError> {
47     let mut vm_config_path = url_to_path(source_url)?;
48 
49     vm_config_path.push(SNAPSHOT_CONFIG_FILE);
50 
51     // Try opening the snapshot file
52     let mut vm_config_file =
53         File::open(vm_config_path).map_err(|e| MigratableError::MigrateReceive(e.into()))?;
54     let mut bytes = Vec::new();
55     vm_config_file
56         .read_to_end(&mut bytes)
57         .map_err(|e| MigratableError::MigrateReceive(e.into()))?;
58 
59     serde_json::from_slice(&bytes).map_err(|e| MigratableError::MigrateReceive(e.into()))
60 }
61 
62 pub fn recv_vm_state(source_url: &str) -> std::result::Result<Snapshot, MigratableError> {
63     let mut vm_state_path = url_to_path(source_url)?;
64 
65     vm_state_path.push(SNAPSHOT_STATE_FILE);
66 
67     // Try opening the snapshot file
68     let mut vm_state_file =
69         File::open(vm_state_path).map_err(|e| MigratableError::MigrateReceive(e.into()))?;
70     let mut bytes = Vec::new();
71     vm_state_file
72         .read_to_end(&mut bytes)
73         .map_err(|e| MigratableError::MigrateReceive(e.into()))?;
74 
75     serde_json::from_slice(&bytes).map_err(|e| MigratableError::MigrateReceive(e.into()))
76 }
77 
78 pub fn get_vm_snapshot(snapshot: &Snapshot) -> std::result::Result<VmSnapshot, MigratableError> {
79     if let Some(snapshot_data) = snapshot.snapshot_data.as_ref() {
80         return snapshot_data.to_state();
81     }
82 
83     Err(MigratableError::Restore(anyhow!(
84         "Could not find VM config snapshot section"
85     )))
86 }
87