From 59e9ba01c631608f8241d349cdf51690e17f9e3c Mon Sep 17 00:00:00 2001 From: Dietmar Maurer Date: Sat, 12 Oct 2019 17:58:08 +0200 Subject: [PATCH] src/backup/manifest.rs: new class to generate/parse index.json --- src/backup.rs | 4 +- src/backup/manifest.rs | 65 ++++++++++++++++++++++++++++++++ src/bin/proxmox-backup-client.rs | 38 ++++++------------- 3 files changed, 80 insertions(+), 27 deletions(-) create mode 100644 src/backup/manifest.rs diff --git a/src/backup.rs b/src/backup.rs index 5deaf73b..905f60b7 100644 --- a/src/backup.rs +++ b/src/backup.rs @@ -103,7 +103,6 @@ //! //! Not sure if this is better. TODO -pub const MANIFEST_BLOB_NAME: &str = "index.json.blob"; pub const CATALOG_BLOB_NAME: &str = "catalog.blob"; #[macro_export] @@ -119,6 +118,9 @@ macro_rules! PROXMOX_BACKUP_READER_PROTOCOL_ID_V1 { mod file_formats; pub use file_formats::*; +mod manifest; +pub use manifest::*; + mod crypt_config; pub use crypt_config::*; diff --git a/src/backup/manifest.rs b/src/backup/manifest.rs new file mode 100644 index 00000000..8d5d4488 --- /dev/null +++ b/src/backup/manifest.rs @@ -0,0 +1,65 @@ +use failure::*; +use std::convert::TryFrom; + +use serde_json::{json, Value}; + +use crate::backup::BackupDir; + +pub const MANIFEST_BLOB_NAME: &str = "index.json.blob"; + +struct FileInfo { + filename: String, + size: u64, + csum: [u8; 32], +} + +pub struct BackupManifest { + snapshot: BackupDir, + files: Vec, +} + +impl BackupManifest { + + pub fn new(snapshot: BackupDir) -> Self { + Self { files: Vec::new(), snapshot } + } + + pub fn add_file(&mut self, filename: String, size: u64, csum: [u8; 32]) { + self.files.push(FileInfo { filename, size, csum }); + } + + pub fn into_json(self) -> Value { + json!({ + "backup-type": self.snapshot.group().backup_type(), + "backup-id": self.snapshot.group().backup_id(), + "backup-time": self.snapshot.backup_time().timestamp(), + "files": self.files.iter() + .fold(Vec::new(), |mut acc, info| { + acc.push(json!({ + "filename": info.filename, + "size": info.size, + "csum": proxmox::tools::digest_to_hex(&info.csum), + })); + acc + }) + }) + } + +} + +impl TryFrom for BackupManifest { + type Error = Error; + + fn try_from(data: Value) -> Result { + + let backup_type = data["backup_type"].as_str().unwrap(); + let backup_id = data["backup_id"].as_str().unwrap(); + let backup_time = data["backup_time"].as_i64().unwrap(); + + let snapshot = BackupDir::new(backup_type, backup_id, backup_time); + + let files = Vec::new(); + + Ok(Self { files, snapshot }) + } +} diff --git a/src/bin/proxmox-backup-client.rs b/src/bin/proxmox-backup-client.rs index ce0866d2..a669de2a 100644 --- a/src/bin/proxmox-backup-client.rs +++ b/src/bin/proxmox-backup-client.rs @@ -732,7 +732,8 @@ fn create_backup( verbose, ).await?; - let mut file_list = vec![]; + let snapshot = BackupDir::new(backup_type, backup_id, backup_time.timestamp()); + let mut manifest = BackupManifest::new(snapshot); // fixme: encrypt/sign catalog? let catalog_file = std::fs::OpenOptions::new() @@ -751,14 +752,14 @@ fn create_backup( let stats = client .upload_blob_from_file(&filename, &target, crypt_config.clone(), true) .await?; - file_list.push((target, stats)); + manifest.add_file(target, stats.size, stats.csum); } BackupType::LOGFILE => { // fixme: remove - not needed anymore ? println!("Upload log file '{}' to '{:?}' as {}", filename, repo, target); let stats = client .upload_blob_from_file(&filename, &target, crypt_config.clone(), true) .await?; - file_list.push((target, stats)); + manifest.add_file(target, stats.size, stats.csum); } BackupType::PXAR => { upload_catalog = true; @@ -775,7 +776,7 @@ fn create_backup( crypt_config.clone(), catalog.clone(), ).await?; - file_list.push((target, stats)); + manifest.add_file(target, stats.size, stats.csum); catalog.lock().unwrap().end_directory()?; } BackupType::IMAGE => { @@ -789,7 +790,7 @@ fn create_backup( verbose, crypt_config.clone(), ).await?; - file_list.push((target, stats)); + manifest.add_file(target, stats.size, stats.csum); } } } @@ -805,7 +806,7 @@ fn create_backup( catalog_file.seek(SeekFrom::Start(0))?; let stats = client.upload_blob(catalog_file, target).await?; - file_list.push((target.to_owned(), stats)); + manifest.add_file(target.to_owned(), stats.size, stats.csum); } if let Some(rsa_encrypted_key) = rsa_encrypted_key { @@ -814,7 +815,7 @@ fn create_backup( let stats = client .upload_blob_from_data(rsa_encrypted_key, target, None, false, false) .await?; - file_list.push((format!("{}.blob", target), stats)); + manifest.add_file(format!("{}.blob", target), stats.size, stats.csum); // openssl rsautl -decrypt -inkey master-private.pem -in rsa-encrypted.key -out t /* @@ -826,28 +827,13 @@ fn create_backup( */ } - // create index.json - let file_list = file_list.iter() - .fold(vec![], |mut acc, (filename, stats)| { - acc.push(json!({ - "filename": filename, - "size": stats.size, - "csum": proxmox::tools::digest_to_hex(&stats.csum), - })); - acc - }); - - let index = json!({ - "backup-type": backup_type, - "backup-id": backup_id, - "backup-time": backup_time.timestamp(), - "files": file_list, - }); + // create manifest (index.json) + let manifest = manifest.into_json(); println!("Upload index.json to '{:?}'", repo); - let index_data = serde_json::to_string_pretty(&index)?.into(); + let manifest = serde_json::to_string_pretty(&manifest)?.into(); client - .upload_blob_from_data(index_data, "index.json.blob", crypt_config.clone(), true, true) + .upload_blob_from_data(manifest, MANIFEST_BLOB_NAME, crypt_config.clone(), true, true) .await?; client.finish().await?;