[pbs-devel] [PATCH proxmox-backup v6 18/37] datastore: create/delete protected marker file on s3 storage backend
Christian Ebner
c.ebner at proxmox.com
Tue Jul 8 19:00:55 CEST 2025
Commit 8292d3d2 ("api2/admin/datastore: add get/set_protection")
introduced the protected flag for backup snapshots, considering
snapshots as protected based on the presence/absence of the
`.protected` marker file in the corresponding snapshot directory.
To allow independent recovery of a datastore backed by an S3 bucket,
also create/delete the marker file on the object store backend. For
actual checks, still rely on the marker as encountered in the local
cache store.
Signed-off-by: Christian Ebner <c.ebner at proxmox.com>
---
pbs-datastore/src/backup_info.rs | 2 +-
pbs-datastore/src/datastore.rs | 43 +++++++++++++++++++++++++++-----
2 files changed, 38 insertions(+), 7 deletions(-)
diff --git a/pbs-datastore/src/backup_info.rs b/pbs-datastore/src/backup_info.rs
index 46e5b61f0..112d82658 100644
--- a/pbs-datastore/src/backup_info.rs
+++ b/pbs-datastore/src/backup_info.rs
@@ -22,7 +22,7 @@ use crate::manifest::{BackupManifest, MANIFEST_LOCK_NAME};
use crate::{DataBlob, DataStore, DatastoreBackend};
pub const DATASTORE_LOCKS_DIR: &str = "/run/proxmox-backup/locks";
-const PROTECTED_MARKER_FILENAME: &str = ".protected";
+pub const PROTECTED_MARKER_FILENAME: &str = ".protected";
proxmox_schema::const_regex! {
pub BACKUP_FILES_AND_PROTECTED_REGEX = concatcp!(r"^(.*\.([fd]idx|blob)|\", PROTECTED_MARKER_FILENAME, ")$");
diff --git a/pbs-datastore/src/datastore.rs b/pbs-datastore/src/datastore.rs
index 0bc14e31d..099c65ce2 100644
--- a/pbs-datastore/src/datastore.rs
+++ b/pbs-datastore/src/datastore.rs
@@ -29,7 +29,9 @@ use pbs_api_types::{
};
use pbs_config::BackupLockGuard;
-use crate::backup_info::{BackupDir, BackupGroup, BackupInfo, OLD_LOCKING};
+use crate::backup_info::{
+ BackupDir, BackupGroup, BackupInfo, OLD_LOCKING, PROTECTED_MARKER_FILENAME,
+};
use crate::chunk_store::ChunkStore;
use crate::dynamic_index::{DynamicIndexReader, DynamicIndexWriter};
use crate::fixed_index::{FixedIndexReader, FixedIndexWriter};
@@ -1554,12 +1556,41 @@ impl DataStore {
let protected_path = backup_dir.protected_file();
if protection {
- std::fs::File::create(protected_path)
+ std::fs::File::create(&protected_path)
.map_err(|err| format_err!("could not create protection file: {}", err))?;
- } else if let Err(err) = std::fs::remove_file(protected_path) {
- // ignore error for non-existing file
- if err.kind() != std::io::ErrorKind::NotFound {
- bail!("could not remove protection file: {}", err);
+ if let DatastoreBackend::S3(s3_client) = self.backend()? {
+ let object_key = crate::s3::object_key_from_path(
+ &backup_dir.relative_path(),
+ PROTECTED_MARKER_FILENAME,
+ )
+ .context("invalid protected marker object key")?;
+ let _is_duplicate = proxmox_async::runtime::block_on(s3_client.upload_with_retry(
+ object_key,
+ hyper::body::Bytes::from(""),
+ false,
+ ))
+ .context("failed to mark snapshot as protected on s3 backend")?;
+ }
+ } else {
+ if let Err(err) = std::fs::remove_file(&protected_path) {
+ // ignore error for non-existing file
+ if err.kind() != std::io::ErrorKind::NotFound {
+ bail!("could not remove protection file: {err}");
+ }
+ }
+ if let DatastoreBackend::S3(s3_client) = self.backend()? {
+ let object_key = crate::s3::object_key_from_path(
+ &backup_dir.relative_path(),
+ PROTECTED_MARKER_FILENAME,
+ )
+ .context("invalid protected marker object key")?;
+ if let Err(err) =
+ proxmox_async::runtime::block_on(s3_client.delete_object(object_key))
+ {
+ std::fs::File::create(&protected_path)
+ .map_err(|err| format_err!("could not re-create protection file: {err}"))?;
+ return Err(err);
+ }
}
}
--
2.47.2
More information about the pbs-devel
mailing list