1 // Copyright © 2020 Intel Corporation 2 // 3 // SPDX-License-Identifier: Apache-2.0 4 5 #[cfg(feature = "guest_debug")] 6 use crate::coredump::GuestDebuggableError; 7 use crate::{ 8 config::VmConfig, 9 vm::{VmSnapshot, VM_SNAPSHOT_ID}, 10 }; 11 use anyhow::anyhow; 12 use std::fs::File; 13 use std::io::BufReader; 14 use std::path::PathBuf; 15 use vm_migration::{MigratableError, Snapshot}; 16 17 pub const SNAPSHOT_STATE_FILE: &str = "state.json"; 18 pub const SNAPSHOT_CONFIG_FILE: &str = "config.json"; 19 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(feature = "guest_debug")] 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 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 vm_config_file = 56 File::open(vm_config_path).map_err(|e| MigratableError::MigrateSend(e.into()))?; 57 let vm_config_reader = BufReader::new(vm_config_file); 58 serde_json::from_reader(vm_config_reader).map_err(|e| MigratableError::MigrateReceive(e.into())) 59 } 60 61 pub fn recv_vm_state(source_url: &str) -> std::result::Result<Snapshot, MigratableError> { 62 let mut vm_state_path = url_to_path(source_url)?; 63 64 vm_state_path.push(SNAPSHOT_STATE_FILE); 65 66 // Try opening the snapshot file 67 let vm_state_file = 68 File::open(vm_state_path).map_err(|e| MigratableError::MigrateSend(e.into()))?; 69 let vm_state_reader = BufReader::new(vm_state_file); 70 serde_json::from_reader(vm_state_reader).map_err(|e| MigratableError::MigrateReceive(e.into())) 71 } 72 73 pub fn get_vm_snapshot(snapshot: &Snapshot) -> std::result::Result<VmSnapshot, MigratableError> { 74 if let Some(vm_section) = snapshot 75 .snapshot_data 76 .get(&format!("{}-section", VM_SNAPSHOT_ID)) 77 { 78 return serde_json::from_slice(&vm_section.snapshot).map_err(|e| { 79 MigratableError::Restore(anyhow!("Could not deserialize VM snapshot {}", e)) 80 }); 81 } 82 83 Err(MigratableError::Restore(anyhow!( 84 "Could not find VM config snapshot section" 85 ))) 86 } 87