[pbs-devel] [RFC proxmox-backup 39/39] datastore: create namespace marker in S3 backend

Christian Ebner c.ebner at proxmox.com
Mon May 19 13:46:40 CEST 2025


The S3 object store only allows to store objects, referenced by their
key. For backup namespaces datastores however use directories, so
they cannot be represented as one to one mapping.

Instead, create an empty marker file for each namespace and operate
based on that.

Signed-off-by: Christian Ebner <c.ebner at proxmox.com>
---
 pbs-datastore/src/datastore.rs | 32 ++++++++++++++++++++++++++++++++
 1 file changed, 32 insertions(+)

diff --git a/pbs-datastore/src/datastore.rs b/pbs-datastore/src/datastore.rs
index 9c8b7de03..a45b21413 100644
--- a/pbs-datastore/src/datastore.rs
+++ b/pbs-datastore/src/datastore.rs
@@ -635,6 +635,25 @@ impl DataStore {
         // construct ns before mkdir to enforce max-depth and name validity
         let ns = BackupNamespace::from_parent_ns(parent, name)?;
 
+        if let DatastoreBackend::S3(s3_client) = self.backend()? {
+            let mut marker = ns.path();
+            marker.push(".namespace");
+            let namespace_marker = marker
+                .to_str()
+                .ok_or_else(|| format_err!("unexpected namespace path"))?;
+
+            let response = proxmox_async::runtime::block_on(
+                s3_client.put_object(namespace_marker.into(), hyper::body::Body::empty()),
+            )?;
+            match response {
+                PutObjectResponse::NeedsRetry => bail!("failed to create namespace, needs retry"),
+                PutObjectResponse::PreconditionFailed => {
+                    bail!("failed to create namespace, precondition failed")
+                }
+                PutObjectResponse::Success(_) => (),
+            }
+        }
+
         let mut ns_full_path = self.base_path();
         ns_full_path.push(ns.path());
 
@@ -645,6 +664,19 @@ impl DataStore {
 
     /// Returns if the given namespace exists on the datastore
     pub fn namespace_exists(&self, ns: &BackupNamespace) -> bool {
+        if let DatastoreBackend::S3(s3_client) = self.backend().unwrap() {
+            let mut marker = ns.path();
+            marker.push(".namespace");
+            let namespace_marker = marker
+                .to_str()
+                .ok_or_else(|| format_err!("unexpected namespace path"))
+                .unwrap();
+
+            let response =
+                proxmox_async::runtime::block_on(s3_client.head_object(namespace_marker.into()))
+                    .unwrap();
+            return response.is_some();
+        }
         let mut path = self.base_path();
         path.push(ns.path());
         path.exists()
-- 
2.39.5





More information about the pbs-devel mailing list