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

Christian Ebner c.ebner at proxmox.com
Thu May 29 16:31:53 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 | 22 +++++++++++++++++++++-
 1 file changed, 21 insertions(+), 1 deletion(-)

diff --git a/pbs-datastore/src/datastore.rs b/pbs-datastore/src/datastore.rs
index 42d27d249..ab5c22501 100644
--- a/pbs-datastore/src/datastore.rs
+++ b/pbs-datastore/src/datastore.rs
@@ -8,7 +8,7 @@ use std::time::Duration;
 
 use anyhow::{bail, format_err, Context, Error};
 use nix::unistd::{unlinkat, UnlinkatFlags};
-use pbs_s3_client::{S3Client, S3ClientOptions};
+use pbs_s3_client::{PutObjectResponse, S3Client, S3ClientOptions};
 use pbs_tools::lru_cache::LruCache;
 use tracing::{info, warn};
 
@@ -42,6 +42,8 @@ use crate::DataBlob;
 static DATASTORE_MAP: LazyLock<Mutex<HashMap<String, Arc<DataStoreImpl>>>> =
     LazyLock::new(|| Mutex::new(HashMap::new()));
 
+const NAMESPACE_MARKER_FILENAME: &str = ".namespace";
+
 /// checks if auth_id is owner, or, if owner is a token, if
 /// auth_id is the user of the token
 pub fn check_backup_owner(owner: &Authid, auth_id: &Authid) -> Result<(), Error> {
@@ -590,6 +592,24 @@ 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 marker = ns.path().join(NAMESPACE_MARKER_FILENAME);
+            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());
 
-- 
2.39.5





More information about the pbs-devel mailing list