From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: <pbs-devel-bounces@lists.proxmox.com> Received: from firstgate.proxmox.com (firstgate.proxmox.com [IPv6:2a01:7e0:0:424::9]) by lore.proxmox.com (Postfix) with ESMTPS id 57B851FF17F for <inbox@lore.proxmox.com>; Mon, 19 May 2025 13:47:49 +0200 (CEST) Received: from firstgate.proxmox.com (localhost [127.0.0.1]) by firstgate.proxmox.com (Proxmox) with ESMTP id 64975887B; Mon, 19 May 2025 13:47:38 +0200 (CEST) From: Christian Ebner <c.ebner@proxmox.com> To: pbs-devel@lists.proxmox.com Date: Mon, 19 May 2025 13:46:08 +0200 Message-Id: <20250519114640.303640-8-c.ebner@proxmox.com> X-Mailer: git-send-email 2.39.5 In-Reply-To: <20250519114640.303640-1-c.ebner@proxmox.com> References: <20250519114640.303640-1-c.ebner@proxmox.com> MIME-Version: 1.0 X-SPAM-LEVEL: Spam detection results: 0 AWL 0.029 Adjusted score from AWL reputation of From: address BAYES_00 -1.9 Bayes spam probability is 0 to 1% DMARC_MISSING 0.1 Missing DMARC policy KAM_DMARC_STATUS 0.01 Test Rule for DKIM or SPF Failure with Strict Alignment SPF_HELO_NONE 0.001 SPF: HELO does not publish an SPF Record SPF_PASS -0.001 SPF: sender matches SPF record Subject: [pbs-devel] [RFC proxmox-backup 07/39] s3 client: add dedicated type for s3 object keys X-BeenThere: pbs-devel@lists.proxmox.com X-Mailman-Version: 2.1.29 Precedence: list List-Id: Proxmox Backup Server development discussion <pbs-devel.lists.proxmox.com> List-Unsubscribe: <https://lists.proxmox.com/cgi-bin/mailman/options/pbs-devel>, <mailto:pbs-devel-request@lists.proxmox.com?subject=unsubscribe> List-Archive: <http://lists.proxmox.com/pipermail/pbs-devel/> List-Post: <mailto:pbs-devel@lists.proxmox.com> List-Help: <mailto:pbs-devel-request@lists.proxmox.com?subject=help> List-Subscribe: <https://lists.proxmox.com/cgi-bin/mailman/listinfo/pbs-devel>, <mailto:pbs-devel-request@lists.proxmox.com?subject=subscribe> Reply-To: Proxmox Backup Server development discussion <pbs-devel@lists.proxmox.com> Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Errors-To: pbs-devel-bounces@lists.proxmox.com Sender: "pbs-devel" <pbs-devel-bounces@lists.proxmox.com> S3 objects are uniquely identified within a bucket by their object key [0]. Implements conversion and utility traits to easily convert and encode a string or a chunk digest as corresponding object key for the S3 storage backend. Adds type checking for s3 client operations requiring an object key. [0] https://docs.aws.amazon.com/AmazonS3/latest/userguide/object-keys.html Signed-off-by: Christian Ebner <c.ebner@proxmox.com> --- pbs-s3-client/src/lib.rs | 2 ++ pbs-s3-client/src/object_key.rs | 64 +++++++++++++++++++++++++++++++++ 2 files changed, 66 insertions(+) create mode 100644 pbs-s3-client/src/object_key.rs diff --git a/pbs-s3-client/src/lib.rs b/pbs-s3-client/src/lib.rs index 5a60b92ec..a4081df15 100644 --- a/pbs-s3-client/src/lib.rs +++ b/pbs-s3-client/src/lib.rs @@ -1,3 +1,5 @@ mod aws_sign_v4; mod client; pub use client::{S3Client, S3ClientOptions}; +mod object_key; +pub use object_key::{S3ObjectKey, S3_CONTENT_PREFIX}; diff --git a/pbs-s3-client/src/object_key.rs b/pbs-s3-client/src/object_key.rs new file mode 100644 index 000000000..362c0cd55 --- /dev/null +++ b/pbs-s3-client/src/object_key.rs @@ -0,0 +1,64 @@ +use crate::aws_sign_v4::aws_sign_v4_uri_encode; + +pub const S3_CONTENT_PREFIX: &str = ".content"; + +#[derive(Clone)] +pub struct S3ObjectKey { + object_key: String, +} + +// All regular keys (non-digests) get prefixed by a `/.contents`, so that +// content listing without all the chunks can be done by that prefix. +impl core::convert::From<&str> for S3ObjectKey { + fn from(object_key: &str) -> Self { + let object_key = object_key.strip_prefix("/").unwrap_or(object_key); + let object_key = format!( + "/{S3_CONTENT_PREFIX}/{object_key}", + object_key = aws_sign_v4_uri_encode(object_key, true) + ); + + Self { object_key } + } +} + +impl core::convert::From<&[u8; 32]> for S3ObjectKey { + fn from(digest: &[u8; 32]) -> Self { + // Use the same layout as on regular PBS datastores, including the 4 hex digit prefix + let object_key = hex::encode(digest); + let prefix = &object_key[..4]; + Self { + object_key: format!("/.chunks/{prefix}/{object_key}"), + } + } +} + +impl core::convert::From<[u8; 32]> for S3ObjectKey { + fn from(digest: [u8; 32]) -> Self { + Self::from(&digest) + } +} + +impl std::ops::Deref for S3ObjectKey { + type Target = str; + + fn deref(&self) -> &Self::Target { + &self.object_key + } +} + +impl std::fmt::Display for S3ObjectKey { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.object_key) + } +} + +impl S3ObjectKey { + /// Generate source key for copy object operations given the source bucket. + pub fn to_copy_source_key(&self, source_bucket: &str) -> Self { + Self { + // object key already contains the required separator slash in-between source bucket + // and source object key. + object_key: format!("{source_bucket}{}", self.object_key), + } + } +} -- 2.39.5 _______________________________________________ pbs-devel mailing list pbs-devel@lists.proxmox.com https://lists.proxmox.com/cgi-bin/mailman/listinfo/pbs-devel