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