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