[pbs-devel] [PATCH proxmox-backup v8 06/45] datastore: allow to get the backend for a datastore

Lukas Wagner l.wagner at proxmox.com
Fri Jul 18 09:52:41 CEST 2025


With my feedback addressed:

Reviewed-by: Lukas Wagner <l.wagner at proxmox.com>


On  2025-07-15 14:52, Christian Ebner wrote:
> Implements an enum with variants Filesystem and S3 to distinguish
> between available backends. Filesystem will be used as default, if no
> backend is configured in the datastores configuration. If the
> datastore has an s3 backend configured, the backend method will
> instantiate and s3 client and return it with the S3 variant.
> 
> This allows to instantiate the client once, keeping and reusing the
> same open connection to the api for the lifetime of task or job, e.g.
> in the backup writer/readers runtime environment.
> 
> Signed-off-by: Christian Ebner <c.ebner at proxmox.com>
> ---
> changes since version 7:
> - no changes
> 
>  pbs-datastore/src/datastore.rs | 52 ++++++++++++++++++++++++++++++++--
>  pbs-datastore/src/lib.rs       |  1 +
>  2 files changed, 51 insertions(+), 2 deletions(-)
> 
> diff --git a/pbs-datastore/src/datastore.rs b/pbs-datastore/src/datastore.rs
> index 924d8cf9c..90ab80005 100644
> --- a/pbs-datastore/src/datastore.rs
> +++ b/pbs-datastore/src/datastore.rs
> @@ -12,6 +12,7 @@ use pbs_tools::lru_cache::LruCache;
>  use tracing::{info, warn};
>  
>  use proxmox_human_byte::HumanByte;
> +use proxmox_s3_client::{S3Client, S3ClientConfig, S3ClientOptions, S3ClientSecretsConfig};
>  use proxmox_schema::ApiType;
>  
>  use proxmox_sys::error::SysError;
> @@ -23,8 +24,8 @@ use proxmox_worker_task::WorkerTaskContext;
>  
>  use pbs_api_types::{
>      ArchiveType, Authid, BackupGroupDeleteStats, BackupNamespace, BackupType, ChunkOrder,
> -    DataStoreConfig, DatastoreFSyncLevel, DatastoreTuning, GarbageCollectionStatus,
> -    MaintenanceMode, MaintenanceType, Operation, UPID,
> +    DataStoreConfig, DatastoreBackendConfig, DatastoreBackendType, DatastoreFSyncLevel,
> +    DatastoreTuning, GarbageCollectionStatus, MaintenanceMode, MaintenanceType, Operation, UPID,
>  };
>  use pbs_config::BackupLockGuard;
>  
> @@ -127,6 +128,7 @@ pub struct DataStoreImpl {
>      chunk_order: ChunkOrder,
>      last_digest: Option<[u8; 32]>,
>      sync_level: DatastoreFSyncLevel,
> +    backend_config: DatastoreBackendConfig,
>  }
>  
>  impl DataStoreImpl {
> @@ -141,6 +143,7 @@ impl DataStoreImpl {
>              chunk_order: Default::default(),
>              last_digest: None,
>              sync_level: Default::default(),
> +            backend_config: Default::default(),
>          })
>      }
>  }
> @@ -196,6 +199,12 @@ impl Drop for DataStore {
>      }
>  }
>  
> +#[derive(Clone)]
> +pub enum DatastoreBackend {
> +    Filesystem,
> +    S3(Arc<S3Client>),
> +}
> +

Missing doc comments for this public enum

>  impl DataStore {
>      // This one just panics on everything
>      #[doc(hidden)]
> @@ -206,6 +215,39 @@ impl DataStore {
>          })
>      }
>  
> +    /// Get the backend for this datastore based on it's configuration
> +    pub fn backend(&self) -> Result<DatastoreBackend, Error> {
> +        let backend_type = match self.inner.backend_config.ty.unwrap_or_default() {
> +            DatastoreBackendType::Filesystem => DatastoreBackend::Filesystem,
> +            DatastoreBackendType::S3 => {
> +                let s3_client_id = self
> +                    .inner
> +                    .backend_config
> +                    .client
> +                    .as_ref()
> +                    .ok_or_else(|| format_err!("missing client for s3 backend"))?;
> +                let bucket = self
> +                    .inner
> +                    .backend_config
> +                    .bucket
> +                    .clone()
> +                    .ok_or_else(|| format_err!("missing bucket for s3 backend"))?;
> +
> +                let (config, _config_digest) = pbs_config::s3::config()?;
> +                let (secrets, _secrets_digest) = pbs_config::s3::secrets_config()?;
> +                let config: S3ClientConfig = config.lookup("s3client", s3_client_id)?;
> +                let secrets: S3ClientSecretsConfig = secrets.lookup("s3secrets", s3_client_id)?;

Same thing here with regards to the hard-coded section type names.

> +
> +                let options =
> +                    S3ClientOptions::from_config(config, secrets, bucket, self.name().to_owned());
> +                let s3_client = S3Client::new(options)?;
> +                DatastoreBackend::S3(Arc::new(s3_client))
> +            }
> +        };
> +
> +        Ok(backend_type)
> +    }
> +
>      pub fn lookup_datastore(
>          name: &str,
>          operation: Option<Operation>,
> @@ -383,6 +425,11 @@ impl DataStore {
>                  .parse_property_string(config.tuning.as_deref().unwrap_or(""))?,
>          )?;
>  
> +        let backend_config: DatastoreBackendConfig = serde_json::from_value(
> +            DatastoreBackendConfig::API_SCHEMA
> +                .parse_property_string(config.backend.as_deref().unwrap_or(""))?,
> +        )?;
> +
>          Ok(DataStoreImpl {
>              chunk_store,
>              gc_mutex: Mutex::new(()),
> @@ -391,6 +438,7 @@ impl DataStore {
>              chunk_order: tuning.chunk_order.unwrap_or_default(),
>              last_digest,
>              sync_level: tuning.sync_level.unwrap_or_default(),
> +            backend_config,
>          })
>      }
>  
> diff --git a/pbs-datastore/src/lib.rs b/pbs-datastore/src/lib.rs
> index ffd0d91b2..ca6fdb7d8 100644
> --- a/pbs-datastore/src/lib.rs
> +++ b/pbs-datastore/src/lib.rs
> @@ -204,6 +204,7 @@ pub use store_progress::StoreProgress;
>  mod datastore;
>  pub use datastore::{
>      check_backup_owner, ensure_datastore_is_mounted, get_datastore_mount_status, DataStore,
> +    DatastoreBackend,
>  };
>  
>  mod hierarchy;

-- 
- Lukas





More information about the pbs-devel mailing list