[pbs-devel] [PATCH proxmox-backup v9 19/46] datastore: create/delete protected marker file on s3 storage backend
Christian Ebner
c.ebner at proxmox.com
Sat Jul 19 14:50:08 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>
---
changes since version 8:
- use upload_no_replace_with_retry
pbs-datastore/src/backup_info.rs | 2 +-
pbs-datastore/src/datastore.rs | 42 +++++++++++++++++++++++++++-----
2 files changed, 37 insertions(+), 7 deletions(-)
diff --git a/pbs-datastore/src/backup_info.rs b/pbs-datastore/src/backup_info.rs
index a4bf958cf..26f03a0ae 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 5bb4e1777..fb6e14a35 100644
--- a/pbs-datastore/src/datastore.rs
+++ b/pbs-datastore/src/datastore.rs
@@ -31,7 +31,9 @@ use pbs_api_types::{
use pbs_config::s3::{S3_CFG_TYPE_ID, S3_SECRETS_CFG_TYPE_ID};
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};
@@ -1576,12 +1578,40 @@ 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_no_replace_with_retry(object_key, hyper::body::Bytes::from("")),
+ )
+ .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