From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from firstgate.proxmox.com (firstgate.proxmox.com [212.224.123.68]) by lore.proxmox.com (Postfix) with ESMTPS id B928D1FF185 for ; Mon, 21 Jul 2025 18:44:42 +0200 (CEST) Received: from firstgate.proxmox.com (localhost [127.0.0.1]) by firstgate.proxmox.com (Proxmox) with ESMTP id AF62F164D9; Mon, 21 Jul 2025 18:45:40 +0200 (CEST) From: Christian Ebner To: pbs-devel@lists.proxmox.com Date: Mon, 21 Jul 2025 18:45:04 +0200 Message-ID: <20250721164507.1045869-47-c.ebner@proxmox.com> X-Mailer: git-send-email 2.47.2 In-Reply-To: <20250721164507.1045869-1-c.ebner@proxmox.com> References: <20250721164507.1045869-1-c.ebner@proxmox.com> MIME-Version: 1.0 X-Bm-Milter-Handled: 55990f41-d878-4baa-be0a-ee34c49e34d2 X-Bm-Transport-Timestamp: 1753116314646 X-SPAM-LEVEL: Spam detection results: 0 AWL 0.046 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] [PATCH proxmox-backup v10 43/46] datastore: mark store as in-use by setting marker on s3 backend X-BeenThere: pbs-devel@lists.proxmox.com X-Mailman-Version: 2.1.29 Precedence: list List-Id: Proxmox Backup Server development discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: Proxmox Backup Server development discussion Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Errors-To: pbs-devel-bounces@lists.proxmox.com Sender: "pbs-devel" Adds an in-use marker on the S3 store to protect from accidental reuse of the same datastore by multiple Proxmox Backup Server instances. Set the marker file on store creation. The local cache folder is however always assumed to be empty and needs creation on datastore creation to guarantee consistency. Signed-off-by: Christian Ebner --- changes since version 9: - adapt to `try_from` for S3ObjectKey generation src/api2/config/datastore.rs | 46 +++++++++++++++++++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) diff --git a/src/api2/config/datastore.rs b/src/api2/config/datastore.rs index 9b87e01f2..98ef28a31 100644 --- a/src/api2/config/datastore.rs +++ b/src/api2/config/datastore.rs @@ -4,6 +4,7 @@ use std::sync::Arc; use ::serde::{Deserialize, Serialize}; use anyhow::{bail, format_err, Context, Error}; use hex::FromHex; +use http_body_util::BodyExt; use serde_json::Value; use tracing::{info, warn}; @@ -35,10 +36,20 @@ use pbs_config::CachedUserInfo; use pbs_datastore::get_datastore_mount_status; use proxmox_rest_server::WorkerTask; +use proxmox_s3_client::S3ObjectKey; use crate::server::jobstate; use crate::tools::disks::unmount_by_mountpoint; +const S3_DATASTORE_IN_USE_MARKER: &str = ".in-use"; + +#[derive(Default, serde::Deserialize, serde::Serialize)] +#[serde(rename_all = "kebab-case")] +struct InUseContent { + #[serde(skip_serializing_if = "Option::is_none")] + hostname: Option, +} + #[api( input: { properties: {}, @@ -153,6 +164,24 @@ pub(crate) fn do_create_datastore( // Fine to block since this runs in worker task proxmox_async::runtime::block_on(s3_client.head_bucket()) .context("failed to access bucket")?; + + let object_key = S3ObjectKey::try_from(S3_DATASTORE_IN_USE_MARKER) + .context("failed to generate s3 object key")?; + if let Some(response) = + proxmox_async::runtime::block_on(s3_client.get_object(object_key.clone())) + .context("failed to get in-use marker from bucket")? + { + let content = proxmox_async::runtime::block_on(response.content.collect()) + .unwrap_or_default(); + let content = + String::from_utf8(content.to_bytes().to_vec()).unwrap_or_default(); + let in_use: InUseContent = serde_json::from_str(&content).unwrap_or_default(); + if let Some(hostname) = in_use.hostname { + bail!("Bucket already contains datastore in use by host {hostname}"); + } else { + bail!("Bucket already contains datastore in use"); + } + } backend_s3_client = Some(Arc::new(s3_client)); } } @@ -165,7 +194,7 @@ pub(crate) fn do_create_datastore( UnmountGuard::new(None) }; - let chunk_store = if reuse_datastore { + let chunk_store = if reuse_datastore && backend_s3_client.is_none() { ChunkStore::verify_chunkstore(&path).and_then(|_| { // Must be the only instance accessing and locking the chunk store, // dropping will close all other locks from this process on the lockfile as well. @@ -195,6 +224,21 @@ pub(crate) fn do_create_datastore( )? }; + if let Some(ref s3_client) = backend_s3_client { + let object_key = S3ObjectKey::try_from(S3_DATASTORE_IN_USE_MARKER) + .context("failed to generate s3 object key")?; + let content = serde_json::to_string(&InUseContent { + hostname: Some(proxmox_sys::nodename().to_string()), + }) + .context("failed to encode hostname")?; + proxmox_async::runtime::block_on(s3_client.put_object( + object_key, + hyper::body::Bytes::from(content).into(), + true, + )) + .context("failed to upload in-use marker for datastore")?; + } + if tuning.gc_atime_safety_check.unwrap_or(true) { chunk_store .check_fs_atime_updates(true, backend_s3_client) -- 2.47.2 _______________________________________________ pbs-devel mailing list pbs-devel@lists.proxmox.com https://lists.proxmox.com/cgi-bin/mailman/listinfo/pbs-devel