use BackupSetup for ProxmoxRestore::new()

This commit is contained in:
Dietmar Maurer 2020-02-19 12:31:27 +01:00
parent 76381310d3
commit aca3c6a306
4 changed files with 84 additions and 69 deletions

View File

@ -9,37 +9,10 @@ use serde_json::{json, Value};
use proxmox_backup::backup::*; use proxmox_backup::backup::*;
use proxmox_backup::client::*; use proxmox_backup::client::*;
use chrono::{Utc, DateTime}; use super::BackupSetup;
use crate::capi_types::*; use crate::capi_types::*;
use crate::upload_queue::*; use crate::upload_queue::*;
#[derive(Clone)]
pub(crate) struct BackupSetup {
pub host: String,
pub store: String,
pub user: String,
pub chunk_size: u64,
pub backup_id: String,
pub backup_time: DateTime<Utc>,
pub password: Option<String>,
pub keyfile: Option<std::path::PathBuf>,
pub key_password: Option<String>,
pub fingerprint: Option<String>,
}
impl BackupSetup {
pub(crate) async fn connect(&self) -> Result<Arc<BackupWriter>, Error> {
let options = HttpClientOptions::new()
.fingerprint(self.fingerprint.clone())
.password(self.password.clone());
let client = HttpClient::new(&self.host, &self.user, options)?;
BackupWriter::start(client, &self.store, "vm", &self.backup_id, self.backup_time, false).await
}
}
struct ImageUploadInfo { struct ImageUploadInfo {
wid: u64, wid: u64,
device_name: String, device_name: String,

View File

@ -5,10 +5,9 @@ use std::os::raw::{c_uchar, c_char, c_int, c_void};
use std::sync::{Mutex, Condvar}; use std::sync::{Mutex, Condvar};
use proxmox::try_block; use proxmox::try_block;
use proxmox_backup::backup::*;
use proxmox_backup::client::BackupRepository; use proxmox_backup::client::BackupRepository;
use chrono::{Utc, TimeZone}; use chrono::{DateTime, Utc, TimeZone};
mod capi_types; mod capi_types;
use capi_types::*; use capi_types::*;
@ -16,7 +15,6 @@ use capi_types::*;
mod upload_queue; mod upload_queue;
mod commands; mod commands;
use commands::*;
mod worker_task; mod worker_task;
use worker_task::*; use worker_task::*;
@ -55,6 +53,20 @@ macro_rules! raise_error_int {
}} }}
} }
#[derive(Clone)]
pub(crate) struct BackupSetup {
pub host: String,
pub store: String,
pub user: String,
pub chunk_size: u64,
pub backup_id: String,
pub backup_time: DateTime<Utc>,
pub password: Option<String>,
pub keyfile: Option<std::path::PathBuf>,
pub key_password: Option<String>,
pub fingerprint: Option<String>,
}
// helper class to implement synchrounous interface // helper class to implement synchrounous interface
struct GotResultCondition { struct GotResultCondition {
lock: Mutex<bool>, lock: Mutex<bool>,
@ -665,14 +677,27 @@ pub extern "C" fn proxmox_backup_disconnect(handle: *mut ProxmoxBackupHandle) {
#[allow(clippy::not_unsafe_ptr_arg_deref)] #[allow(clippy::not_unsafe_ptr_arg_deref)]
pub extern "C" fn proxmox_restore_connect( pub extern "C" fn proxmox_restore_connect(
repo: *const c_char, repo: *const c_char,
snapshot: *const c_char, backup_id: *const c_char,
backup_time: u64,
password: *const c_char,
keyfile: *const c_char, keyfile: *const c_char,
key_password: *const c_char,
fingerprint: *const c_char,
error: * mut * mut c_char, error: * mut * mut c_char,
) -> *mut ProxmoxRestoreHandle { ) -> *mut ProxmoxRestoreHandle {
let result: Result<_, Error> = try_block!({ let result: Result<_, Error> = try_block!({
let repo = unsafe { CStr::from_ptr(repo).to_str()?.to_owned() }; let repo = unsafe { CStr::from_ptr(repo).to_str()?.to_owned() };
let repo: BackupRepository = repo.parse()?; let repo: BackupRepository = repo.parse()?;
let backup_id = unsafe { CStr::from_ptr(backup_id).to_str()?.to_owned() };
let backup_time = Utc.timestamp(backup_time as i64, 0);
let password = if password.is_null() {
None
} else {
Some(unsafe { CStr::from_ptr(password).to_str()?.to_owned() })
};
let keyfile = if keyfile.is_null() { let keyfile = if keyfile.is_null() {
None None
@ -680,10 +705,32 @@ pub extern "C" fn proxmox_restore_connect(
Some(unsafe { CStr::from_ptr(keyfile).to_str().map(std::path::PathBuf::from)? }) Some(unsafe { CStr::from_ptr(keyfile).to_str().map(std::path::PathBuf::from)? })
}; };
let snapshot = unsafe { CStr::from_ptr(snapshot).to_string_lossy().into_owned() }; let key_password = if key_password.is_null() {
let snapshot = BackupDir::parse(&snapshot)?; None
} else {
Some(unsafe { CStr::from_ptr(key_password).to_str()?.to_owned() })
};
ProxmoxRestore::new(repo, snapshot, keyfile) let fingerprint = if fingerprint.is_null() {
None
} else {
Some(unsafe { CStr::from_ptr(fingerprint).to_str()?.to_owned() })
};
let setup = BackupSetup {
host: repo.host().to_owned(),
user: repo.user().to_owned(),
store: repo.store().to_owned(),
chunk_size: PROXMOX_BACKUP_DEFAULT_CHUNK_SIZE, // not used by restore
backup_id,
password,
backup_time,
keyfile,
key_password,
fingerprint,
};
ProxmoxRestore::new(setup)
}); });
match result { match result {

View File

@ -4,7 +4,9 @@ use std::os::unix::fs::OpenOptionsExt;
use proxmox_backup::tools::runtime::block_on; use proxmox_backup::tools::runtime::block_on;
use proxmox_backup::backup::*; use proxmox_backup::backup::*;
use proxmox_backup::client::{HttpClient, HttpClientOptions, BackupReader, BackupRepository, RemoteChunkReader}; use proxmox_backup::client::{HttpClient, HttpClientOptions, BackupReader, RemoteChunkReader};
use super::BackupSetup;
pub(crate) struct ProxmoxRestore { pub(crate) struct ProxmoxRestore {
pub client: Arc<BackupReader>, pub client: Arc<BackupReader>,
@ -14,31 +16,28 @@ pub(crate) struct ProxmoxRestore {
impl ProxmoxRestore { impl ProxmoxRestore {
pub fn new( pub fn new(setup: BackupSetup) -> Result<Self, Error> {
repo: BackupRepository,
snapshot: BackupDir,
keyfile: Option<std::path::PathBuf>,
) -> Result<Self, Error> {
let host = repo.host().to_owned(); let crypt_config = match setup.keyfile {
let user = repo.user().to_owned();
let store = repo.store().to_owned();
let backup_type = snapshot.group().backup_type();
let backup_id = snapshot.group().backup_id().to_owned();
let backup_time = snapshot.backup_time();
if backup_type != "vm" {
bail!("wrong backup type ({} != vm)", backup_type);
}
let crypt_config = match keyfile {
None => None, None => None,
Some(path) => { Some(ref path) => {
let (key, _) = load_and_decrypt_key(&path, &get_encryption_key_password)?; let (key, _) = load_and_decrypt_key(path, & || {
match setup.key_password {
Some(ref key_password) => Ok(key_password.as_bytes().to_vec()),
None => bail!("no key_password specified"),
}
})?;
Some(Arc::new(CryptConfig::new(key)?)) Some(Arc::new(CryptConfig::new(key)?))
} }
}; };
let host = setup.host;
let user = setup.user;
let store = setup.store;
let backup_type = String::from("vm");
let backup_id = setup.backup_id;
let backup_time = setup.backup_time;
let result: Result<_, Error> = block_on(async { let result: Result<_, Error> = block_on(async {
let options = HttpClientOptions::new(); let options = HttpClientOptions::new();
@ -174,15 +173,3 @@ impl ProxmoxRestore {
Ok(()) Ok(())
} }
} }
// helper to get encrtyption key password
fn get_encryption_key_password() -> Result<Vec<u8>, Error> {
use std::env::VarError::*;
match std::env::var("PBS_ENCRYPTION_PASSWORD") {
Ok(p) => Ok(p.as_bytes().to_vec()),
Err(NotUnicode(_)) => bail!("PBS_ENCRYPTION_PASSWORD contains bad characters"),
Err(NotPresent) => {
bail!("env PBS_ENCRYPTION_PASSWORD not set");
}
}
}

View File

@ -10,7 +10,9 @@ use futures::future::{Future, Either, FutureExt};
use proxmox_backup::tools::BroadcastFuture; use proxmox_backup::tools::BroadcastFuture;
use proxmox_backup::backup::{CryptConfig, load_and_decrypt_key}; use proxmox_backup::backup::{CryptConfig, load_and_decrypt_key};
use proxmox_backup::client::{HttpClient, HttpClientOptions, BackupWriter};
use super::BackupSetup;
use crate::capi_types::*; use crate::capi_types::*;
use crate::commands::*; use crate::commands::*;
@ -141,11 +143,17 @@ fn backup_worker_task(
match msg { match msg {
BackupMessage::Connect { callback_info } => { BackupMessage::Connect { callback_info } => {
let client = client.clone();
let setup = setup.clone(); let setup = setup.clone();
let client = client.clone();
let command_future = async move { let command_future = async move {
let writer = setup.connect().await?; let options = HttpClientOptions::new()
.fingerprint(setup.fingerprint.clone())
.password(setup.password.clone());
let http = HttpClient::new(&setup.host, &setup.user, options)?;
let writer = BackupWriter::start(http, &setup.store, "vm", &setup.backup_id, setup.backup_time, false).await?;
let mut guard = client.lock().unwrap(); let mut guard = client.lock().unwrap();
*guard = Some(writer); *guard = Some(writer);
Ok(0) Ok(0)