[PATCH proxmox-backup v7 25/34] api: config: update notification thresholds for config and counters

Christian Ebner
2026-04-01T13:48:49Z

Allow users to update or clear notification threshold values stored
in the datastore configuration via api or cli.

At the same time, also load and update the threshold values for the
shared request counters so they are applied immediately.

To achieve this without duplicating code, move the request counter
loading and updating of the thresholds into dedicated helpers.

Signed-off-by: Christian Ebner <c.ebner@proxmox.com>
Reviewed-by: Hannes Laimer <h.laimer@proxmox.com>
Tested-by: Hannes Laimer <h.laimer@proxmox.com>
---
pbs-datastore/src/datastore.rs | 27 ++++++++++++++++++++++++---
src/api2/config/datastore.rs | 33 +++++++++++++++++++++++++++++----
2 files changed, 53 insertions(+), 7 deletions(-)

diff --git a/pbs-datastore/src/datastore.rs b/pbs-datastore/src/datastore.rs
index 71ff0fa3a..2d63f7527 100644
--- a/pbs-datastore/src/datastore.rs
+++ b/pbs-datastore/src/datastore.rs
@@ -18,8 +18,8 @@ use tracing::{info, warn};

use proxmox_human_byte::HumanByte;
use proxmox_s3_client::{
- S3Client, S3ClientConf, S3ClientOptions, S3ObjectKey, S3PathPrefix, S3RateLimiterOptions,
- S3RequestCounterConfig, SharedRequestCounters,
+ RequestCounterThresholds, S3Client, S3ClientConf, S3ClientOptions, S3ObjectKey, S3PathPrefix,
+ S3RateLimiterOptions, S3RequestCounterConfig, SharedRequestCounters,
};
use proxmox_schema::ApiType;

@@ -706,7 +706,10 @@ impl DataStore {
);

let cache = LocalDatastoreLruCache::new(cache_capacity, chunk_store.clone());
- let request_counters = Self::request_counters(&config, &backend_config)?;
+
+ let mut request_counters = Self::request_counters(&config, &backend_config)?;
+
+ Self::update_notification_thresholds(&mut request_counters, &config)?;

(Some(cache), Some(Arc::new(request_counters)))
} else {
@@ -756,6 +759,24 @@ impl DataStore {
Ok(request_counters)
}

+ /// Update the notification threshold values on the counters by given config
+ pub fn update_notification_thresholds(
+ counters: &mut SharedRequestCounters,
+ config: &DataStoreConfig,
+ ) -> Result<(), Error> {
+ let thresholds: RequestCounterThresholds =
+ if let Some(thresholds) = &config.notification_thresholds {
+ serde_json::from_value(
+ RequestCounterThresholds::API_SCHEMA.parse_property_string(thresholds)?,
+ )?
+ } else {
+ RequestCounterThresholds::default()
+ };
+
+ counters.update_thresholds(&thresholds);
+ Ok(())
+ }
+
// Requires obtaining a shared chunk store lock beforehand
pub fn create_fixed_writer<P: AsRef<Path>>(
&self,
diff --git a/src/api2/config/datastore.rs b/src/api2/config/datastore.rs
index f845fe2d0..d51c60f43 100644
--- a/src/api2/config/datastore.rs
+++ b/src/api2/config/datastore.rs
@@ -14,10 +14,11 @@ use proxmox_section_config::SectionConfigData;
use proxmox_uuid::Uuid;

use pbs_api_types::{
- Authid, DataStoreConfig, DataStoreConfigUpdater, DatastoreBackendType, DatastoreNotify,
- DatastoreTuning, KeepOptions, MaintenanceMode, MaintenanceType, PruneJobConfig,
- PruneJobOptions, DATASTORE_SCHEMA, PRIV_DATASTORE_ALLOCATE, PRIV_DATASTORE_AUDIT,
- PRIV_DATASTORE_MODIFY, PRIV_SYS_MODIFY, PROXMOX_CONFIG_DIGEST_SCHEMA, UPID_SCHEMA,
+ Authid, DataStoreConfig, DataStoreConfigUpdater, DatastoreBackendConfig, DatastoreBackendType,
+ DatastoreNotify, DatastoreTuning, KeepOptions, MaintenanceMode, MaintenanceType,
+ PruneJobConfig, PruneJobOptions, DATASTORE_SCHEMA, PRIV_DATASTORE_ALLOCATE,
+ PRIV_DATASTORE_AUDIT, PRIV_DATASTORE_MODIFY, PRIV_SYS_MODIFY, PROXMOX_CONFIG_DIGEST_SCHEMA,
+ UPID_SCHEMA,
};
use pbs_config::BackupLockGuard;
use pbs_datastore::chunk_store::ChunkStore;
@@ -436,6 +437,8 @@ pub enum DeletableProperty {
Tuning,
/// Delete the maintenance-mode property
MaintenanceMode,
+ /// Delete the notification-thresholds property
+ NotificationThresholds,
}

#[api(
@@ -534,6 +537,10 @@ pub fn update_datastore(
DeletableProperty::MaintenanceMode => {
data.set_maintenance_mode(None)?;
}
+ DeletableProperty::NotificationThresholds => {
+ data.notification_thresholds = None;
+ update_thresholds(&data)?;
+ }
}
}
}
@@ -619,6 +626,11 @@ pub fn update_datastore(
data.set_maintenance_mode(maintenance_mode)?;
}

+ if update.notification_thresholds.is_some() {
+ data.notification_thresholds = update.notification_thresholds;
+ update_thresholds(&data)?;
+ }
+
config.set_data(&name, "datastore", &data)?;

pbs_config::datastore::save_config(&config)?;
@@ -651,6 +663,19 @@ pub fn update_datastore(
Ok(())
}

+fn update_thresholds(config: &DataStoreConfig) -> Result<(), Error> {
+ let backend_config: DatastoreBackendConfig = serde_json::from_value(
+ DatastoreBackendConfig::API_SCHEMA
+ .parse_property_string(config.backend.as_deref().unwrap_or(""))?,
+ )?;
+ if backend_config.ty.unwrap_or_default() == DatastoreBackendType::S3 {
+ let mut request_counters =
+ pbs_datastore::DataStore::request_counters(config, &backend_config)?;
+ pbs_datastore::DataStore::update_notification_thresholds(&mut request_counters, config)?;
+ }
+ Ok(())
+}
+
#[api(
protected: true,
input: {
--
2.47.3