src/backup/manifest.rs: new class to generate/parse index.json
This commit is contained in:
		@ -103,7 +103,6 @@
 | 
				
			|||||||
//!
 | 
					//!
 | 
				
			||||||
//! Not sure if this is better. TODO
 | 
					//! Not sure if this is better. TODO
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub const MANIFEST_BLOB_NAME: &str = "index.json.blob";
 | 
					 | 
				
			||||||
pub const CATALOG_BLOB_NAME: &str = "catalog.blob";
 | 
					pub const CATALOG_BLOB_NAME: &str = "catalog.blob";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[macro_export]
 | 
					#[macro_export]
 | 
				
			||||||
@ -119,6 +118,9 @@ macro_rules! PROXMOX_BACKUP_READER_PROTOCOL_ID_V1 {
 | 
				
			|||||||
mod file_formats;
 | 
					mod file_formats;
 | 
				
			||||||
pub use file_formats::*;
 | 
					pub use file_formats::*;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					mod manifest;
 | 
				
			||||||
 | 
					pub use manifest::*;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
mod crypt_config;
 | 
					mod crypt_config;
 | 
				
			||||||
pub use crypt_config::*;
 | 
					pub use crypt_config::*;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										65
									
								
								src/backup/manifest.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										65
									
								
								src/backup/manifest.rs
									
									
									
									
									
										Normal file
									
								
							@ -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<FileInfo>,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					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<Value> for BackupManifest {
 | 
				
			||||||
 | 
					    type Error = Error;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn try_from(data: Value) -> Result<Self, Error> {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        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 })
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -732,7 +732,8 @@ fn create_backup(
 | 
				
			|||||||
            verbose,
 | 
					            verbose,
 | 
				
			||||||
        ).await?;
 | 
					        ).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?
 | 
					        // fixme: encrypt/sign catalog?
 | 
				
			||||||
         let catalog_file = std::fs::OpenOptions::new()
 | 
					         let catalog_file = std::fs::OpenOptions::new()
 | 
				
			||||||
@ -751,14 +752,14 @@ fn create_backup(
 | 
				
			|||||||
                    let stats = client
 | 
					                    let stats = client
 | 
				
			||||||
                        .upload_blob_from_file(&filename, &target, crypt_config.clone(), true)
 | 
					                        .upload_blob_from_file(&filename, &target, crypt_config.clone(), true)
 | 
				
			||||||
                        .await?;
 | 
					                        .await?;
 | 
				
			||||||
                    file_list.push((target, stats));
 | 
					                    manifest.add_file(target, stats.size, stats.csum);
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                BackupType::LOGFILE => { // fixme: remove - not needed anymore ?
 | 
					                BackupType::LOGFILE => { // fixme: remove - not needed anymore ?
 | 
				
			||||||
                    println!("Upload log file '{}' to '{:?}' as {}", filename, repo, target);
 | 
					                    println!("Upload log file '{}' to '{:?}' as {}", filename, repo, target);
 | 
				
			||||||
                    let stats = client
 | 
					                    let stats = client
 | 
				
			||||||
                        .upload_blob_from_file(&filename, &target, crypt_config.clone(), true)
 | 
					                        .upload_blob_from_file(&filename, &target, crypt_config.clone(), true)
 | 
				
			||||||
                        .await?;
 | 
					                        .await?;
 | 
				
			||||||
                    file_list.push((target, stats));
 | 
					                    manifest.add_file(target, stats.size, stats.csum);
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                BackupType::PXAR => {
 | 
					                BackupType::PXAR => {
 | 
				
			||||||
                    upload_catalog = true;
 | 
					                    upload_catalog = true;
 | 
				
			||||||
@ -775,7 +776,7 @@ fn create_backup(
 | 
				
			|||||||
                        crypt_config.clone(),
 | 
					                        crypt_config.clone(),
 | 
				
			||||||
                        catalog.clone(),
 | 
					                        catalog.clone(),
 | 
				
			||||||
                    ).await?;
 | 
					                    ).await?;
 | 
				
			||||||
                    file_list.push((target, stats));
 | 
					                    manifest.add_file(target, stats.size, stats.csum);
 | 
				
			||||||
                    catalog.lock().unwrap().end_directory()?;
 | 
					                    catalog.lock().unwrap().end_directory()?;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                BackupType::IMAGE => {
 | 
					                BackupType::IMAGE => {
 | 
				
			||||||
@ -789,7 +790,7 @@ fn create_backup(
 | 
				
			|||||||
                        verbose,
 | 
					                        verbose,
 | 
				
			||||||
                        crypt_config.clone(),
 | 
					                        crypt_config.clone(),
 | 
				
			||||||
                    ).await?;
 | 
					                    ).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))?;
 | 
					            catalog_file.seek(SeekFrom::Start(0))?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            let stats = client.upload_blob(catalog_file, target).await?;
 | 
					            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 {
 | 
					        if let Some(rsa_encrypted_key) = rsa_encrypted_key {
 | 
				
			||||||
@ -814,7 +815,7 @@ fn create_backup(
 | 
				
			|||||||
            let stats = client
 | 
					            let stats = client
 | 
				
			||||||
                .upload_blob_from_data(rsa_encrypted_key, target, None, false, false)
 | 
					                .upload_blob_from_data(rsa_encrypted_key, target, None, false, false)
 | 
				
			||||||
                .await?;
 | 
					                .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
 | 
					            // openssl rsautl -decrypt -inkey master-private.pem -in rsa-encrypted.key -out t
 | 
				
			||||||
            /*
 | 
					            /*
 | 
				
			||||||
@ -826,28 +827,13 @@ fn create_backup(
 | 
				
			|||||||
             */
 | 
					             */
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // create index.json
 | 
					        // create manifest (index.json)
 | 
				
			||||||
        let file_list = file_list.iter()
 | 
					        let manifest = manifest.into_json();
 | 
				
			||||||
            .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,
 | 
					 | 
				
			||||||
        });
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        println!("Upload index.json to '{:?}'", repo);
 | 
					        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
 | 
					        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?;
 | 
					            .await?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        client.finish().await?;
 | 
					        client.finish().await?;
 | 
				
			||||||
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user