src/client/backup_writer.rs - upload_stream: add crypt_mode

This commit is contained in:
Dietmar Maurer 2020-07-08 10:42:20 +02:00
parent 24be37e3f6
commit 3bad3e6e52
3 changed files with 39 additions and 16 deletions

View File

@ -1,4 +1,4 @@
use anyhow::{bail, Error}; use anyhow::{bail, format_err, Error};
use std::convert::TryInto; use std::convert::TryInto;
use proxmox::tools::io::{ReadExt, WriteExt}; use proxmox::tools::io::{ReadExt, WriteExt};
@ -362,6 +362,7 @@ impl DataBlob {
/// we always compute the correct one. /// we always compute the correct one.
pub struct DataChunkBuilder<'a, 'b> { pub struct DataChunkBuilder<'a, 'b> {
config: Option<&'b CryptConfig>, config: Option<&'b CryptConfig>,
crypt_mode: CryptMode,
orig_data: &'a [u8], orig_data: &'a [u8],
digest_computed: bool, digest_computed: bool,
digest: [u8; 32], digest: [u8; 32],
@ -375,6 +376,7 @@ impl <'a, 'b> DataChunkBuilder<'a, 'b> {
Self { Self {
orig_data, orig_data,
config: None, config: None,
crypt_mode: CryptMode::None,
digest_computed: false, digest_computed: false,
digest: [0u8; 32], digest: [0u8; 32],
compress: true, compress: true,
@ -391,12 +393,18 @@ impl <'a, 'b> DataChunkBuilder<'a, 'b> {
/// Set encryption Configuration /// Set encryption Configuration
/// ///
/// If set, chunks are encrypted. /// If set, chunks are encrypted or signed
pub fn crypt_config(mut self, value: &'b CryptConfig) -> Self { pub fn crypt_config(mut self, value: &'b CryptConfig, crypt_mode: CryptMode) -> Self {
if self.digest_computed { if self.digest_computed {
panic!("unable to set crypt_config after compute_digest()."); panic!("unable to set crypt_config after compute_digest().");
} }
if crypt_mode == CryptMode::None {
self.config = None;
} else {
self.config = Some(value); self.config = Some(value);
}
self.crypt_mode = crypt_mode;
self self
} }
@ -430,11 +438,17 @@ impl <'a, 'b> DataChunkBuilder<'a, 'b> {
self.compute_digest(); self.compute_digest();
} }
let chunk = DataBlob::encode( let chunk = match self.crypt_mode {
CryptMode::None | CryptMode::Encrypt => {
DataBlob::encode(self.orig_data, self.config, self.compress)?
}
CryptMode::SignOnly => DataBlob::create_signed(
self.orig_data, self.orig_data,
self.config, self.config
.ok_or_else(|| format_err!("cannot sign without crypt config"))?,
self.compress, self.compress,
)?; )?,
};
Ok((chunk, self.digest)) Ok((chunk, self.digest))
} }
@ -442,6 +456,7 @@ impl <'a, 'b> DataChunkBuilder<'a, 'b> {
/// Create a chunk filled with zeroes /// Create a chunk filled with zeroes
pub fn build_zero_chunk( pub fn build_zero_chunk(
crypt_config: Option<&CryptConfig>, crypt_config: Option<&CryptConfig>,
crypt_mode: CryptMode,
chunk_size: usize, chunk_size: usize,
compress: bool, compress: bool,
) -> Result<(DataBlob, [u8; 32]), Error> { ) -> Result<(DataBlob, [u8; 32]), Error> {
@ -450,7 +465,7 @@ impl <'a, 'b> DataChunkBuilder<'a, 'b> {
zero_bytes.resize(chunk_size, 0u8); zero_bytes.resize(chunk_size, 0u8);
let mut chunk_builder = DataChunkBuilder::new(&zero_bytes).compress(compress); let mut chunk_builder = DataChunkBuilder::new(&zero_bytes).compress(compress);
if let Some(ref crypt_config) = crypt_config { if let Some(ref crypt_config) = crypt_config {
chunk_builder = chunk_builder.crypt_config(crypt_config); chunk_builder = chunk_builder.crypt_config(crypt_config, crypt_mode);
} }
chunk_builder.build() chunk_builder.build()

View File

@ -256,6 +256,7 @@ pub async fn api_datastore_latest_snapshot(
async fn backup_directory<P: AsRef<Path>>( async fn backup_directory<P: AsRef<Path>>(
client: &BackupWriter, client: &BackupWriter,
crypt_mode: CryptMode,
previous_manifest: Option<Arc<BackupManifest>>, previous_manifest: Option<Arc<BackupManifest>>,
dir_path: P, dir_path: P,
archive_name: &str, archive_name: &str,
@ -292,7 +293,7 @@ async fn backup_directory<P: AsRef<Path>>(
}); });
let stats = client let stats = client
.upload_stream(previous_manifest, archive_name, stream, "dynamic", None) .upload_stream(crypt_mode, previous_manifest, archive_name, stream, "dynamic", None)
.await?; .await?;
Ok(stats) Ok(stats)
@ -300,6 +301,7 @@ async fn backup_directory<P: AsRef<Path>>(
async fn backup_image<P: AsRef<Path>>( async fn backup_image<P: AsRef<Path>>(
client: &BackupWriter, client: &BackupWriter,
crypt_mode: CryptMode,
previous_manifest: Option<Arc<BackupManifest>>, previous_manifest: Option<Arc<BackupManifest>>,
image_path: P, image_path: P,
archive_name: &str, archive_name: &str,
@ -318,7 +320,7 @@ async fn backup_image<P: AsRef<Path>>(
let stream = FixedChunkStream::new(stream, chunk_size.unwrap_or(4*1024*1024)); let stream = FixedChunkStream::new(stream, chunk_size.unwrap_or(4*1024*1024));
let stats = client let stats = client
.upload_stream(previous_manifest, archive_name, stream, "fixed", Some(image_size)) .upload_stream(crypt_mode, previous_manifest, archive_name, stream, "fixed", Some(image_size))
.await?; .await?;
Ok(stats) Ok(stats)
@ -628,7 +630,8 @@ async fn start_garbage_collection(param: Value) -> Result<Value, Error> {
} }
fn spawn_catalog_upload( fn spawn_catalog_upload(
client: Arc<BackupWriter> client: Arc<BackupWriter>,
crypt_mode: CryptMode,
) -> Result< ) -> Result<
( (
Arc<Mutex<CatalogWriter<crate::tools::StdChannelWriter>>>, Arc<Mutex<CatalogWriter<crate::tools::StdChannelWriter>>>,
@ -646,7 +649,7 @@ fn spawn_catalog_upload(
tokio::spawn(async move { tokio::spawn(async move {
let catalog_upload_result = client let catalog_upload_result = client
.upload_stream(None, CATALOG_NAME, catalog_chunk_stream, "dynamic", None) .upload_stream(crypt_mode, None, CATALOG_NAME, catalog_chunk_stream, "dynamic", None)
.await; .await;
if let Err(ref err) = catalog_upload_result { if let Err(ref err) = catalog_upload_result {
@ -956,7 +959,7 @@ async fn create_backup(
BackupSpecificationType::PXAR => { BackupSpecificationType::PXAR => {
// start catalog upload on first use // start catalog upload on first use
if catalog.is_none() { if catalog.is_none() {
let (cat, res) = spawn_catalog_upload(client.clone())?; let (cat, res) = spawn_catalog_upload(client.clone(), crypt_mode)?;
catalog = Some(cat); catalog = Some(cat);
catalog_result_tx = Some(res); catalog_result_tx = Some(res);
} }
@ -966,6 +969,7 @@ async fn create_backup(
catalog.lock().unwrap().start_directory(std::ffi::CString::new(target.as_str())?.as_c_str())?; catalog.lock().unwrap().start_directory(std::ffi::CString::new(target.as_str())?.as_c_str())?;
let stats = backup_directory( let stats = backup_directory(
&client, &client,
crypt_mode,
previous_manifest.clone(), previous_manifest.clone(),
&filename, &filename,
&target, &target,
@ -984,6 +988,7 @@ async fn create_backup(
println!("Upload image '{}' to '{:?}' as {}", filename, repo, target); println!("Upload image '{}' to '{:?}' as {}", filename, repo, target);
let stats = backup_image( let stats = backup_image(
&client, &client,
crypt_mode,
previous_manifest.clone(), previous_manifest.clone(),
&filename, &filename,
&target, &target,

View File

@ -210,6 +210,7 @@ impl BackupWriter {
pub async fn upload_stream( pub async fn upload_stream(
&self, &self,
crypt_mode: CryptMode,
previous_manifest: Option<Arc<BackupManifest>>, previous_manifest: Option<Arc<BackupManifest>>,
archive_name: &str, archive_name: &str,
stream: impl Stream<Item = Result<bytes::BytesMut, Error>>, stream: impl Stream<Item = Result<bytes::BytesMut, Error>>,
@ -249,6 +250,7 @@ impl BackupWriter {
&prefix, &prefix,
known_chunks.clone(), known_chunks.clone(),
self.crypt_config.clone(), self.crypt_config.clone(),
crypt_mode,
self.verbose, self.verbose,
) )
.await?; .await?;
@ -474,6 +476,7 @@ impl BackupWriter {
prefix: &str, prefix: &str,
known_chunks: Arc<Mutex<HashSet<[u8;32]>>>, known_chunks: Arc<Mutex<HashSet<[u8;32]>>>,
crypt_config: Option<Arc<CryptConfig>>, crypt_config: Option<Arc<CryptConfig>>,
crypt_mode: CryptMode,
verbose: bool, verbose: bool,
) -> impl Future<Output = Result<(usize, usize, std::time::Duration, usize, [u8; 32]), Error>> { ) -> impl Future<Output = Result<(usize, usize, std::time::Duration, usize, [u8; 32]), Error>> {
@ -507,7 +510,7 @@ impl BackupWriter {
.compress(true); .compress(true);
if let Some(ref crypt_config) = crypt_config { if let Some(ref crypt_config) = crypt_config {
chunk_builder = chunk_builder.crypt_config(crypt_config); chunk_builder = chunk_builder.crypt_config(crypt_config, crypt_mode);
} }
let mut known_chunks = known_chunks.lock().unwrap(); let mut known_chunks = known_chunks.lock().unwrap();