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