From: Christian Ebner <c.ebner@proxmox.com>
To: pbs-devel@lists.proxmox.com
Subject: [PATCH proxmox-backup] pbs-config: refactor and move helper to detect config digest changes
Date: Thu, 2 Apr 2026 15:41:10 +0200 [thread overview]
Message-ID: <20260402134110.848575-1-c.ebner@proxmox.com> (raw)
This is such a common pattern for a huge number of API handlers that
refactoring it into a common helper is waranted. As a positive side
effect, direct dependencies on the hex crate for the API handlers are
reduced.
By moving the helper to pbs-config it can be used also from within
pbs-config, which will be used to detect config changes for encrypton
keys in the future.
In that particular case, keeping all the locking and digest
change detection logic inside that crate makes sense since the keys
are stored separately, which is an implementation detail the API
handler should not be concerned with.
No functional changes intended.
Signed-off-by: Christian Ebner <c.ebner@proxmox.com>
---
While encountered when working on the config api for encrypted push
sync jobs, this touches so many API handlers that sending this as
dedicated patch for independent review already.
pbs-config/Cargo.toml | 1 +
pbs-config/src/lib.rs | 19 +++++++++++++++++-
src/api2/access/acl.rs | 6 +-----
src/api2/access/user.rs | 26 +++++--------------------
src/api2/config/access/ad.rs | 6 +-----
src/api2/config/access/ldap.rs | 11 ++---------
src/api2/config/access/openid.rs | 11 ++---------
src/api2/config/access/pam.rs | 6 +-----
src/api2/config/access/pbs.rs | 6 +-----
src/api2/config/access/tfa.rs | 12 ++++--------
src/api2/config/changer.rs | 6 +-----
src/api2/config/datastore.rs | 11 ++---------
src/api2/config/drive.rs | 6 +-----
src/api2/config/metrics/influxdbhttp.rs | 11 ++---------
src/api2/config/metrics/influxdbudp.rs | 11 ++---------
src/api2/config/prune.rs | 11 ++---------
src/api2/config/remote.rs | 11 ++---------
src/api2/config/s3.rs | 11 ++---------
src/api2/config/sync.rs | 11 ++---------
src/api2/config/tape_backup_job.rs | 11 ++---------
src/api2/config/tape_encryption_keys.rs | 11 ++---------
src/api2/config/traffic_control.rs | 11 ++---------
src/api2/config/verify.rs | 11 ++---------
src/api2/node/config.rs | 4 +---
src/api2/node/network.rs | 11 ++---------
src/tools/mod.rs | 13 -------------
26 files changed, 63 insertions(+), 202 deletions(-)
diff --git a/pbs-config/Cargo.toml b/pbs-config/Cargo.toml
index eb81ce004..c3f1660f6 100644
--- a/pbs-config/Cargo.toml
+++ b/pbs-config/Cargo.toml
@@ -9,6 +9,7 @@ rust-version.workspace = true
[dependencies]
anyhow.workspace = true
const_format.workspace = true
+hex.workspace = true
libc.workspace = true
nix.workspace = true
once_cell.workspace = true
diff --git a/pbs-config/src/lib.rs b/pbs-config/src/lib.rs
index 1ed472385..8b900e11c 100644
--- a/pbs-config/src/lib.rs
+++ b/pbs-config/src/lib.rs
@@ -20,7 +20,8 @@ pub mod verify;
mod config_version_cache;
pub use config_version_cache::ConfigVersionCache;
-use anyhow::{format_err, Error};
+use anyhow::{bail, format_err, Error};
+use hex::FromHex;
use nix::unistd::{Gid, Group, Uid, User};
use proxmox_sys::fs::DirLockGuard;
use std::os::unix::prelude::AsRawFd;
@@ -148,3 +149,19 @@ pub fn replace_secret_config<P: AsRef<std::path::Path>>(path: P, data: &[u8]) ->
Ok(())
}
+
+/// Detect modified configuration files
+///
+/// This function fails with a reasonable error message if checksums do not match.
+pub fn detect_modified_configuration_file<T: AsRef<str>>(
+ digest_str: Option<T>,
+ expected_digest: &[u8; 32],
+) -> Result<(), Error> {
+ if let Some(digest_str) = digest_str {
+ let digest = <[u8; 32]>::from_hex(digest_str.as_ref())?;
+ if &digest != expected_digest {
+ bail!("detected modified configuration - file changed by other user? Try again.");
+ }
+ }
+ Ok(())
+}
diff --git a/src/api2/access/acl.rs b/src/api2/access/acl.rs
index ee474754a..adcb799e8 100644
--- a/src/api2/access/acl.rs
+++ b/src/api2/access/acl.rs
@@ -1,7 +1,6 @@
//! Manage Access Control Lists
use anyhow::{bail, Error};
-use hex::FromHex;
use proxmox_router::{Permission, Router, RpcEnvironment};
use proxmox_schema::api;
@@ -218,10 +217,7 @@ pub fn update_acl(
let (mut tree, expected_digest) = pbs_config::acl::config()?;
- if let Some(ref digest) = digest {
- let digest = <[u8; 32]>::from_hex(digest)?;
- crate::tools::detect_modified_configuration_file(&digest, &expected_digest)?;
- }
+ pbs_config::detect_modified_configuration_file(digest, &expected_digest)?;
let propagate = propagate.unwrap_or(true);
diff --git a/src/api2/access/user.rs b/src/api2/access/user.rs
index 3b4cf1214..0ad2ed569 100644
--- a/src/api2/access/user.rs
+++ b/src/api2/access/user.rs
@@ -1,7 +1,6 @@
//! User Management
use anyhow::{bail, format_err, Error};
-use hex::FromHex;
use serde::{Deserialize, Serialize};
use serde_json::{json, Value};
use std::collections::HashMap;
@@ -269,10 +268,7 @@ pub async fn update_user(
let (mut config, expected_digest) = pbs_config::user::config()?;
- if let Some(ref digest) = digest {
- let digest = <[u8; 32]>::from_hex(digest)?;
- crate::tools::detect_modified_configuration_file(&digest, &expected_digest)?;
- }
+ pbs_config::detect_modified_configuration_file(digest, &expected_digest)?;
let mut data: User = config.lookup("user", userid.as_str())?;
@@ -358,10 +354,7 @@ pub fn delete_user(userid: Userid, digest: Option<String>) -> Result<(), Error>
let (mut config, expected_digest) = pbs_config::user::config()?;
- if let Some(ref digest) = digest {
- let digest = <[u8; 32]>::from_hex(digest)?;
- crate::tools::detect_modified_configuration_file(&digest, &expected_digest)?;
- }
+ pbs_config::detect_modified_configuration_file(digest, &expected_digest)?;
if config.sections.remove(userid.as_str()).is_none() {
bail!("user '{}' does not exist.", userid);
@@ -496,10 +489,7 @@ pub fn generate_token(
let (mut config, expected_digest) = pbs_config::user::config()?;
- if let Some(ref digest) = digest {
- let digest = <[u8; 32]>::from_hex(digest)?;
- crate::tools::detect_modified_configuration_file(&digest, &expected_digest)?;
- }
+ pbs_config::detect_modified_configuration_file(digest, &expected_digest)?;
let tokenid = Authid::from((userid.clone(), Some(token_name.clone())));
let tokenid_string = tokenid.to_string();
@@ -613,10 +603,7 @@ pub fn update_token(
let (mut config, expected_digest) = pbs_config::user::config()?;
- if let Some(ref digest) = digest {
- let digest = <[u8; 32]>::from_hex(digest)?;
- crate::tools::detect_modified_configuration_file(&digest, &expected_digest)?;
- }
+ pbs_config::detect_modified_configuration_file(digest, &expected_digest)?;
let tokenid = Authid::from((userid, Some(token_name)));
let tokenid_string = tokenid.to_string();
@@ -699,10 +686,7 @@ pub fn delete_token(
let (mut user_config, expected_digest) = pbs_config::user::config()?;
- if let Some(ref digest) = digest {
- let digest = <[u8; 32]>::from_hex(digest)?;
- crate::tools::detect_modified_configuration_file(&digest, &expected_digest)?;
- }
+ pbs_config::detect_modified_configuration_file(digest, &expected_digest)?;
let (mut acl_config, _digest) = pbs_config::acl::config()?;
do_delete_token(token_name, &userid, &mut user_config, &mut acl_config)?;
diff --git a/src/api2/config/access/ad.rs b/src/api2/config/access/ad.rs
index 2afb16b86..d45ab448e 100644
--- a/src/api2/config/access/ad.rs
+++ b/src/api2/config/access/ad.rs
@@ -1,5 +1,4 @@
use anyhow::{bail, format_err, Error};
-use hex::FromHex;
use serde::{Deserialize, Serialize};
use serde_json::Value;
@@ -207,10 +206,7 @@ pub async fn update_ad_realm(
let (mut domains, expected_digest) = domains::config()?;
- if let Some(ref digest) = digest {
- let digest = <[u8; 32]>::from_hex(digest)?;
- crate::tools::detect_modified_configuration_file(&digest, &expected_digest)?;
- }
+ pbs_config::detect_modified_configuration_file(digest, &expected_digest)?;
let mut config: AdRealmConfig = domains.lookup("ad", &realm)?;
diff --git a/src/api2/config/access/ldap.rs b/src/api2/config/access/ldap.rs
index 6a93ece22..c4029d70c 100644
--- a/src/api2/config/access/ldap.rs
+++ b/src/api2/config/access/ldap.rs
@@ -1,7 +1,6 @@
use crate::auth::LdapAuthenticator;
use ::serde::{Deserialize, Serialize};
use anyhow::{format_err, Error};
-use hex::FromHex;
use serde_json::Value;
use proxmox_ldap::Connection;
@@ -119,10 +118,7 @@ pub fn delete_ldap_realm(
let (mut domains, expected_digest) = domains::config()?;
- if let Some(ref digest) = digest {
- let digest = <[u8; 32]>::from_hex(digest)?;
- crate::tools::detect_modified_configuration_file(&digest, &expected_digest)?;
- }
+ pbs_config::detect_modified_configuration_file(digest, &expected_digest)?;
if domains.sections.remove(&realm).is_none() {
http_bail!(NOT_FOUND, "realm '{}' does not exist.", realm);
@@ -242,10 +238,7 @@ pub fn update_ldap_realm(
let (mut domains, expected_digest) = domains::config()?;
- if let Some(ref digest) = digest {
- let digest = <[u8; 32]>::from_hex(digest)?;
- crate::tools::detect_modified_configuration_file(&digest, &expected_digest)?;
- }
+ pbs_config::detect_modified_configuration_file(digest, &expected_digest)?;
let mut config: LdapRealmConfig = domains.lookup("ldap", &realm)?;
diff --git a/src/api2/config/access/openid.rs b/src/api2/config/access/openid.rs
index 5b767fcca..ab05bfb68 100644
--- a/src/api2/config/access/openid.rs
+++ b/src/api2/config/access/openid.rs
@@ -1,7 +1,6 @@
use ::serde::{Deserialize, Serialize};
/// Configure OpenId realms
use anyhow::Error;
-use hex::FromHex;
use serde_json::Value;
use proxmox_router::{http_bail, Permission, Router, RpcEnvironment};
@@ -103,10 +102,7 @@ pub fn delete_openid_realm(
let (mut domains, expected_digest) = domains::config()?;
- if let Some(ref digest) = digest {
- let digest = <[u8; 32]>::from_hex(digest)?;
- crate::tools::detect_modified_configuration_file(&digest, &expected_digest)?;
- }
+ pbs_config::detect_modified_configuration_file(digest, &expected_digest)?;
if domains.sections.remove(&realm).is_none() {
http_bail!(NOT_FOUND, "realm '{}' does not exist.", realm);
@@ -207,10 +203,7 @@ pub fn update_openid_realm(
let (mut domains, expected_digest) = domains::config()?;
- if let Some(ref digest) = digest {
- let digest = <[u8; 32]>::from_hex(digest)?;
- crate::tools::detect_modified_configuration_file(&digest, &expected_digest)?;
- }
+ pbs_config::detect_modified_configuration_file(digest, &expected_digest)?;
let mut config: OpenIdRealmConfig = domains.lookup("openid", &realm)?;
diff --git a/src/api2/config/access/pam.rs b/src/api2/config/access/pam.rs
index 04ae616b9..40a7b522d 100644
--- a/src/api2/config/access/pam.rs
+++ b/src/api2/config/access/pam.rs
@@ -1,6 +1,5 @@
use ::serde::{Deserialize, Serialize};
use anyhow::Error;
-use hex::FromHex;
use proxmox_router::{Permission, Router, RpcEnvironment};
use proxmox_schema::api;
@@ -82,10 +81,7 @@ pub fn update_pam_realm(
let (mut domains, expected_digest) = domains::config()?;
- if let Some(ref digest) = digest {
- let digest = <[u8; 32]>::from_hex(digest)?;
- crate::tools::detect_modified_configuration_file(&digest, &expected_digest)?;
- }
+ pbs_config::detect_modified_configuration_file(digest, &expected_digest)?;
let mut config: PamRealmConfig = domains.lookup("pam", "pam")?;
diff --git a/src/api2/config/access/pbs.rs b/src/api2/config/access/pbs.rs
index 2873eabbb..536e8c854 100644
--- a/src/api2/config/access/pbs.rs
+++ b/src/api2/config/access/pbs.rs
@@ -1,6 +1,5 @@
use ::serde::{Deserialize, Serialize};
use anyhow::Error;
-use hex::FromHex;
use proxmox_router::{Permission, Router, RpcEnvironment};
use proxmox_schema::api;
@@ -82,10 +81,7 @@ pub fn update_pbs_realm(
let (mut domains, expected_digest) = domains::config()?;
- if let Some(ref digest) = digest {
- let digest = <[u8; 32]>::from_hex(digest)?;
- crate::tools::detect_modified_configuration_file(&digest, &expected_digest)?;
- }
+ pbs_config::detect_modified_configuration_file(digest, &expected_digest)?;
let mut config: PbsRealmConfig = domains.lookup("pbs", "pbs")?;
diff --git a/src/api2/config/access/tfa.rs b/src/api2/config/access/tfa.rs
index 5cb17bba0..19824298b 100644
--- a/src/api2/config/access/tfa.rs
+++ b/src/api2/config/access/tfa.rs
@@ -2,7 +2,6 @@
//! If we add more, it should be moved into a sub module.
use anyhow::{format_err, Error};
-use hex::FromHex;
use serde::{Deserialize, Serialize};
use proxmox_router::list_subdirs_api_method;
@@ -94,13 +93,10 @@ pub fn update_webauthn_config(
let mut tfa = tfa::read()?;
if let Some(wa) = &mut tfa.webauthn {
- if let Some(ref digest) = digest {
- let digest = <[u8; 32]>::from_hex(digest)?;
- crate::tools::detect_modified_configuration_file(
- &digest,
- &crate::config::tfa::webauthn_config_digest(wa)?,
- )?;
- }
+ pbs_config::detect_modified_configuration_file(
+ digest,
+ &crate::config::tfa::webauthn_config_digest(wa)?,
+ )?;
if let Some(delete) = delete {
for delete in delete {
diff --git a/src/api2/config/changer.rs b/src/api2/config/changer.rs
index 31a15abab..f827c2b52 100644
--- a/src/api2/config/changer.rs
+++ b/src/api2/config/changer.rs
@@ -1,6 +1,5 @@
use ::serde::{Deserialize, Serialize};
use anyhow::Error;
-use hex::FromHex;
use serde_json::Value;
use proxmox_router::{http_bail, Permission, Router, RpcEnvironment};
@@ -183,10 +182,7 @@ pub fn update_changer(
let (mut config, expected_digest) = pbs_config::drive::config()?;
- if let Some(ref digest) = digest {
- let digest = <[u8; 32]>::from_hex(digest)?;
- crate::tools::detect_modified_configuration_file(&digest, &expected_digest)?;
- }
+ pbs_config::detect_modified_configuration_file(digest, &expected_digest)?;
let mut data: ScsiTapeChanger = config.lookup("changer", &name)?;
diff --git a/src/api2/config/datastore.rs b/src/api2/config/datastore.rs
index f845fe2d0..2c5472444 100644
--- a/src/api2/config/datastore.rs
+++ b/src/api2/config/datastore.rs
@@ -3,7 +3,6 @@ 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};
@@ -479,10 +478,7 @@ pub fn update_datastore(
// pass/compare digest
let (mut config, expected_digest) = pbs_config::datastore::config()?;
- if let Some(ref digest) = digest {
- let digest = <[u8; 32]>::from_hex(digest)?;
- crate::tools::detect_modified_configuration_file(&digest, &expected_digest)?;
- }
+ pbs_config::detect_modified_configuration_file(digest, &expected_digest)?;
let mut data: DataStoreConfig = config.lookup("datastore", &name)?;
@@ -696,10 +692,7 @@ pub async fn delete_datastore(
let (config, expected_digest) = pbs_config::datastore::config()?;
- if let Some(ref digest) = digest {
- let digest = <[u8; 32]>::from_hex(digest)?;
- crate::tools::detect_modified_configuration_file(&digest, &expected_digest)?;
- }
+ pbs_config::detect_modified_configuration_file(digest, &expected_digest)?;
if !config.sections.contains_key(&name) {
http_bail!(NOT_FOUND, "datastore '{}' does not exist.", name);
diff --git a/src/api2/config/drive.rs b/src/api2/config/drive.rs
index 1222ab200..6f198acdd 100644
--- a/src/api2/config/drive.rs
+++ b/src/api2/config/drive.rs
@@ -1,6 +1,5 @@
use ::serde::{Deserialize, Serialize};
use anyhow::{format_err, Error};
-use hex::FromHex;
use serde_json::Value;
use proxmox_router::{http_bail, Permission, Router, RpcEnvironment};
@@ -185,10 +184,7 @@ pub fn update_drive(
let (mut config, expected_digest) = pbs_config::drive::config()?;
- if let Some(ref digest) = digest {
- let digest = <[u8; 32]>::from_hex(digest)?;
- crate::tools::detect_modified_configuration_file(&digest, &expected_digest)?;
- }
+ pbs_config::detect_modified_configuration_file(digest, &expected_digest)?;
let mut data: LtoTapeDrive = config.lookup("lto", &name)?;
diff --git a/src/api2/config/metrics/influxdbhttp.rs b/src/api2/config/metrics/influxdbhttp.rs
index bed292600..6df4569b4 100644
--- a/src/api2/config/metrics/influxdbhttp.rs
+++ b/src/api2/config/metrics/influxdbhttp.rs
@@ -1,5 +1,4 @@
use anyhow::{bail, format_err, Error};
-use hex::FromHex;
use serde::{Deserialize, Serialize};
use serde_json::Value;
@@ -122,10 +121,7 @@ pub fn delete_influxdb_http_server(
let (mut metrics, expected_digest) = metrics::config()?;
- if let Some(ref digest) = digest {
- let digest = <[u8; 32]>::from_hex(digest)?;
- crate::tools::detect_modified_configuration_file(&digest, &expected_digest)?;
- }
+ pbs_config::detect_modified_configuration_file(digest, &expected_digest)?;
if metrics.sections.remove(&name).is_none() {
bail!("name '{}' does not exist.", name);
@@ -227,10 +223,7 @@ pub async fn update_influxdb_http_server(
let (mut metrics, expected_digest) = metrics::config()?;
- if let Some(ref digest) = digest {
- let digest = <[u8; 32]>::from_hex(digest)?;
- crate::tools::detect_modified_configuration_file(&digest, &expected_digest)?;
- }
+ pbs_config::detect_modified_configuration_file(digest, &expected_digest)?;
let mut config: InfluxDbHttp = metrics.lookup("influxdb-http", &name)?;
diff --git a/src/api2/config/metrics/influxdbudp.rs b/src/api2/config/metrics/influxdbudp.rs
index c47a4e191..60ae8a1b7 100644
--- a/src/api2/config/metrics/influxdbudp.rs
+++ b/src/api2/config/metrics/influxdbudp.rs
@@ -1,5 +1,4 @@
use anyhow::{bail, format_err, Error};
-use hex::FromHex;
use serde::{Deserialize, Serialize};
use serde_json::Value;
@@ -109,10 +108,7 @@ pub fn delete_influxdb_udp_server(
let (mut metrics, expected_digest) = metrics::config()?;
- if let Some(ref digest) = digest {
- let digest = <[u8; 32]>::from_hex(digest)?;
- crate::tools::detect_modified_configuration_file(&digest, &expected_digest)?;
- }
+ pbs_config::detect_modified_configuration_file(digest, &expected_digest)?;
if metrics.sections.remove(&name).is_none() {
bail!("name '{}' does not exist.", name);
@@ -204,10 +200,7 @@ pub async fn update_influxdb_udp_server(
let (mut metrics, expected_digest) = metrics::config()?;
- if let Some(ref digest) = digest {
- let digest = <[u8; 32]>::from_hex(digest)?;
- crate::tools::detect_modified_configuration_file(&digest, &expected_digest)?;
- }
+ pbs_config::detect_modified_configuration_file(digest, &expected_digest)?;
let mut config: InfluxDbUdp = metrics.lookup("influxdb-udp", &name)?;
diff --git a/src/api2/config/prune.rs b/src/api2/config/prune.rs
index b433c248a..2f846fdf0 100644
--- a/src/api2/config/prune.rs
+++ b/src/api2/config/prune.rs
@@ -1,5 +1,4 @@
use anyhow::Error;
-use hex::FromHex;
use serde::{Deserialize, Serialize};
use serde_json::Value;
@@ -224,10 +223,7 @@ pub fn update_prune_job(
// pass/compare digest
let (mut config, expected_digest) = prune::config()?;
- if let Some(ref digest) = digest {
- let digest = <[u8; 32]>::from_hex(digest)?;
- crate::tools::detect_modified_configuration_file(&digest, &expected_digest)?;
- }
+ pbs_config::detect_modified_configuration_file(digest, &expected_digest)?;
let mut data: PruneJobConfig = config.lookup("prune", &id)?;
@@ -369,10 +365,7 @@ pub fn delete_prune_job(
user_info.check_privs(&auth_id, &job.acl_path(), PRIV_DATASTORE_MODIFY, true)?;
- if let Some(ref digest) = digest {
- let digest = <[u8; 32]>::from_hex(digest)?;
- crate::tools::detect_modified_configuration_file(&digest, &expected_digest)?;
- }
+ pbs_config::detect_modified_configuration_file(digest, &expected_digest)?;
if config.sections.remove(&id).is_none() {
http_bail!(NOT_FOUND, "job '{}' does not exist.", id);
diff --git a/src/api2/config/remote.rs b/src/api2/config/remote.rs
index 1996ee91b..f6cbca977 100644
--- a/src/api2/config/remote.rs
+++ b/src/api2/config/remote.rs
@@ -1,6 +1,5 @@
use ::serde::{Deserialize, Serialize};
use anyhow::{bail, format_err, Error};
-use hex::FromHex;
use pbs_api_types::BackupNamespace;
use pbs_api_types::NamespaceListItem;
use proxmox_router::list_subdirs_api_method;
@@ -192,10 +191,7 @@ pub fn update_remote(
let (mut config, expected_digest) = pbs_config::remote::config()?;
- if let Some(ref digest) = digest {
- let digest = <[u8; 32]>::from_hex(digest)?;
- crate::tools::detect_modified_configuration_file(&digest, &expected_digest)?;
- }
+ pbs_config::detect_modified_configuration_file(digest, &expected_digest)?;
let mut data: Remote = config.lookup("remote", &name)?;
@@ -292,10 +288,7 @@ pub fn delete_remote(name: String, digest: Option<String>) -> Result<(), Error>
let (mut config, expected_digest) = pbs_config::remote::config()?;
- if let Some(ref digest) = digest {
- let digest = <[u8; 32]>::from_hex(digest)?;
- crate::tools::detect_modified_configuration_file(&digest, &expected_digest)?;
- }
+ pbs_config::detect_modified_configuration_file(digest, &expected_digest)?;
if config.sections.remove(&name).is_none() {
http_bail!(NOT_FOUND, "remote '{}' does not exist.", name);
diff --git a/src/api2/config/s3.rs b/src/api2/config/s3.rs
index 29ac1038a..7a338bc83 100644
--- a/src/api2/config/s3.rs
+++ b/src/api2/config/s3.rs
@@ -1,6 +1,5 @@
use ::serde::{Deserialize, Serialize};
use anyhow::{bail, Context, Error};
-use hex::FromHex;
use serde_json::Value;
use proxmox_router::{http_bail, Permission, Router, RpcEnvironment};
@@ -200,10 +199,7 @@ pub fn update_s3_client_config(
let (mut config, expected_digest) = s3::config()?;
// Secrets are not included in digest concurrent changes therefore not detected.
- if let Some(ref digest) = digest {
- let digest = <[u8; 32]>::from_hex(digest)?;
- crate::tools::detect_modified_configuration_file(&digest, &expected_digest)?;
- }
+ pbs_config::detect_modified_configuration_file(digest, &expected_digest)?;
let mut data: S3ClientConf = config.lookup(S3_CFG_TYPE_ID, &id)?;
@@ -311,10 +307,7 @@ pub fn delete_s3_client_config(
let _lock = s3::lock_config()?;
let (mut config, expected_digest) = s3::config()?;
- if let Some(ref digest) = digest {
- let digest = <[u8; 32]>::from_hex(digest)?;
- crate::tools::detect_modified_configuration_file(&digest, &expected_digest)?;
- }
+ pbs_config::detect_modified_configuration_file(digest, &expected_digest)?;
if let Some(datastore) =
s3_client_in_use(&id).context("failed to check if s3 client is in-use")?
diff --git a/src/api2/config/sync.rs b/src/api2/config/sync.rs
index dff447cb6..67fa3182c 100644
--- a/src/api2/config/sync.rs
+++ b/src/api2/config/sync.rs
@@ -1,6 +1,5 @@
use ::serde::{Deserialize, Serialize};
use anyhow::{bail, Error};
-use hex::FromHex;
use pbs_api_types::SyncDirection;
use serde_json::Value;
@@ -398,10 +397,7 @@ pub fn update_sync_job(
let (mut config, expected_digest) = sync::config()?;
- if let Some(ref digest) = digest {
- let digest = <[u8; 32]>::from_hex(digest)?;
- crate::tools::detect_modified_configuration_file(&digest, &expected_digest)?;
- }
+ pbs_config::detect_modified_configuration_file(digest, &expected_digest)?;
let mut data: SyncJobConfig = config.lookup("sync", &id)?;
@@ -617,10 +613,7 @@ pub fn delete_sync_job(
let (mut config, expected_digest) = sync::config()?;
- if let Some(ref digest) = digest {
- let digest = <[u8; 32]>::from_hex(digest)?;
- crate::tools::detect_modified_configuration_file(&digest, &expected_digest)?;
- }
+ pbs_config::detect_modified_configuration_file(digest, &expected_digest)?;
match config.lookup("sync", &id) {
Ok(job) => {
diff --git a/src/api2/config/tape_backup_job.rs b/src/api2/config/tape_backup_job.rs
index 38dbe9747..e69ab99bf 100644
--- a/src/api2/config/tape_backup_job.rs
+++ b/src/api2/config/tape_backup_job.rs
@@ -1,6 +1,5 @@
use ::serde::{Deserialize, Serialize};
use anyhow::Error;
-use hex::FromHex;
use serde_json::Value;
use proxmox_router::{http_bail, Permission, Router, RpcEnvironment};
@@ -193,10 +192,7 @@ pub fn update_tape_backup_job(
let mut data: TapeBackupJobConfig = config.lookup("backup", &id)?;
- if let Some(ref digest) = digest {
- let digest = <[u8; 32]>::from_hex(digest)?;
- crate::tools::detect_modified_configuration_file(&digest, &expected_digest)?;
- }
+ pbs_config::detect_modified_configuration_file(digest, &expected_digest)?;
if let Some(delete) = delete {
for delete_prop in delete {
@@ -328,10 +324,7 @@ pub fn delete_tape_backup_job(
let (mut config, expected_digest) = pbs_config::tape_job::config()?;
- if let Some(ref digest) = digest {
- let digest = <[u8; 32]>::from_hex(digest)?;
- crate::tools::detect_modified_configuration_file(&digest, &expected_digest)?;
- }
+ pbs_config::detect_modified_configuration_file(digest, &expected_digest)?;
match config.lookup::<TapeBackupJobConfig>("backup", &id) {
Ok(_job) => {
diff --git a/src/api2/config/tape_encryption_keys.rs b/src/api2/config/tape_encryption_keys.rs
index 788ed0e7b..a450bf435 100644
--- a/src/api2/config/tape_encryption_keys.rs
+++ b/src/api2/config/tape_encryption_keys.rs
@@ -1,5 +1,4 @@
use anyhow::{bail, format_err, Error};
-use hex::FromHex;
use serde_json::Value;
use proxmox_router::{http_bail, ApiMethod, Permission, Router, RpcEnvironment};
@@ -115,10 +114,7 @@ pub fn change_passphrase(
let (mut config_map, expected_digest) = load_key_configs()?;
- if let Some(ref digest) = digest {
- let digest = <[u8; 32]>::from_hex(digest)?;
- crate::tools::detect_modified_configuration_file(&digest, &expected_digest)?;
- }
+ pbs_config::detect_modified_configuration_file(digest, &expected_digest)?;
let key_config = match config_map.get(&fingerprint) {
Some(key_config) => key_config,
@@ -313,10 +309,7 @@ pub fn delete_key(
let (mut config_map, expected_digest) = load_key_configs()?;
let (mut key_map, _) = load_keys()?;
- if let Some(ref digest) = digest {
- let digest = <[u8; 32]>::from_hex(digest)?;
- crate::tools::detect_modified_configuration_file(&digest, &expected_digest)?;
- }
+ pbs_config::detect_modified_configuration_file(digest, &expected_digest)?;
match config_map.get(&fingerprint) {
Some(_) => {
diff --git a/src/api2/config/traffic_control.rs b/src/api2/config/traffic_control.rs
index 49b1267e9..1b18c8b03 100644
--- a/src/api2/config/traffic_control.rs
+++ b/src/api2/config/traffic_control.rs
@@ -1,6 +1,5 @@
use ::serde::{Deserialize, Serialize};
use anyhow::Error;
-use hex::FromHex;
use serde_json::Value;
use proxmox_router::{http_bail, ApiMethod, Permission, Router, RpcEnvironment};
@@ -161,10 +160,7 @@ pub fn update_traffic_control(
let (mut config, expected_digest) = pbs_config::traffic_control::config()?;
- if let Some(ref digest) = digest {
- let digest = <[u8; 32]>::from_hex(digest)?;
- crate::tools::detect_modified_configuration_file(&digest, &expected_digest)?;
- }
+ pbs_config::detect_modified_configuration_file(digest, &expected_digest)?;
let mut data: TrafficControlRule = config.lookup("rule", &name)?;
@@ -261,10 +257,7 @@ pub fn delete_traffic_control(name: String, digest: Option<String>) -> Result<()
let (mut config, expected_digest) = pbs_config::traffic_control::config()?;
- if let Some(ref digest) = digest {
- let digest = <[u8; 32]>::from_hex(digest)?;
- crate::tools::detect_modified_configuration_file(&digest, &expected_digest)?;
- }
+ pbs_config::detect_modified_configuration_file(digest, &expected_digest)?;
if config.sections.remove(&name).is_none() {
http_bail!(NOT_FOUND, "traffic control rule '{}' does not exist.", name);
diff --git a/src/api2/config/verify.rs b/src/api2/config/verify.rs
index a88a3c322..90b2236ac 100644
--- a/src/api2/config/verify.rs
+++ b/src/api2/config/verify.rs
@@ -1,6 +1,5 @@
use ::serde::{Deserialize, Serialize};
use anyhow::Error;
-use hex::FromHex;
use serde_json::Value;
use proxmox_router::{http_bail, Permission, Router, RpcEnvironment};
@@ -202,10 +201,7 @@ pub fn update_verification_job(
// pass/compare digest
let (mut config, expected_digest) = verify::config()?;
- if let Some(ref digest) = digest {
- let digest = <[u8; 32]>::from_hex(digest)?;
- crate::tools::detect_modified_configuration_file(&digest, &expected_digest)?;
- }
+ pbs_config::detect_modified_configuration_file(digest, &expected_digest)?;
let mut data: VerificationJobConfig = config.lookup("verification", &id)?;
@@ -331,10 +327,7 @@ pub fn delete_verification_job(
let job: VerificationJobConfig = config.lookup("verification", &id)?;
user_info.check_privs(&auth_id, &job.acl_path(), PRIV_DATASTORE_VERIFY, true)?;
- if let Some(ref digest) = digest {
- let digest = <[u8; 32]>::from_hex(digest)?;
- crate::tools::detect_modified_configuration_file(&digest, &expected_digest)?;
- }
+ pbs_config::detect_modified_configuration_file(digest, &expected_digest)?;
match config.sections.get(&id) {
Some(_) => {
diff --git a/src/api2/node/config.rs b/src/api2/node/config.rs
index 19ede24b7..10682bdf5 100644
--- a/src/api2/node/config.rs
+++ b/src/api2/node/config.rs
@@ -1,6 +1,5 @@
use ::serde::{Deserialize, Serialize};
use anyhow::Error;
-use hex::FromHex;
use proxmox_router::{Permission, Router, RpcEnvironment};
use proxmox_schema::api;
@@ -110,8 +109,7 @@ pub fn update_node_config(
if let Some(digest) = digest {
// FIXME: GUI doesn't handle our non-inlined digest part here properly...
if !digest.is_empty() {
- let digest = <[u8; 32]>::from_hex(&digest)?;
- crate::tools::detect_modified_configuration_file(&digest, &expected_digest)?;
+ pbs_config::detect_modified_configuration_file(Some(digest), &expected_digest)?;
}
}
diff --git a/src/api2/node/network.rs b/src/api2/node/network.rs
index d0a04e59d..edae5064a 100644
--- a/src/api2/node/network.rs
+++ b/src/api2/node/network.rs
@@ -1,5 +1,4 @@
use anyhow::{bail, Error};
-use hex::FromHex;
use serde::{Deserialize, Serialize};
use serde_json::{to_value, Value};
@@ -612,10 +611,7 @@ pub fn update_interface(
let (mut config, expected_digest) = network::config()?;
- if let Some(ref digest) = digest {
- let digest = <[u8; 32]>::from_hex(digest)?;
- crate::tools::detect_modified_configuration_file(&digest, &expected_digest)?;
- }
+ pbs_config::detect_modified_configuration_file(digest, &expected_digest)?;
if gateway.is_some() {
check_duplicate_gateway_v4(&config, &iface)?;
@@ -824,10 +820,7 @@ pub fn delete_interface(iface: String, digest: Option<String>) -> Result<(), Err
let (mut config, expected_digest) = network::config()?;
- if let Some(ref digest) = digest {
- let digest = <[u8; 32]>::from_hex(digest)?;
- crate::tools::detect_modified_configuration_file(&digest, &expected_digest)?;
- }
+ pbs_config::detect_modified_configuration_file(digest, &expected_digest)?;
let _interface = config.lookup(&iface)?; // check if interface exists
diff --git a/src/tools/mod.rs b/src/tools/mod.rs
index 6a975bde2..51d9ad777 100644
--- a/src/tools/mod.rs
+++ b/src/tools/mod.rs
@@ -29,19 +29,6 @@ pub fn assert_if_modified(digest1: &str, digest2: &str) -> Result<(), Error> {
Ok(())
}
-/// Detect modified configuration files
-///
-/// This function fails with a reasonable error message if checksums do not match.
-pub fn detect_modified_configuration_file(
- digest1: &[u8; 32],
- digest2: &[u8; 32],
-) -> Result<(), Error> {
- if digest1 != digest2 {
- bail!("detected modified configuration - file changed by other user? Try again.");
- }
- Ok(())
-}
-
/// The default 2 hours are far too long for PBS
pub const PROXMOX_BACKUP_TCP_KEEPALIVE_TIME: u32 = 120;
pub const DEFAULT_USER_AGENT_STRING: &str = "proxmox-backup-client/1.0";
--
2.47.3
reply other threads:[~2026-04-02 13:41 UTC|newest]
Thread overview: [no followups] expand[flat|nested] mbox.gz Atom feed
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260402134110.848575-1-c.ebner@proxmox.com \
--to=c.ebner@proxmox.com \
--cc=pbs-devel@lists.proxmox.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.