[pbs-devel] [PATCH proxmox-backup 1/9] cli: manager: move update-to-prune-jobs command to new migrate-config sub-command

Lukas Wagner l.wagner at proxmox.com
Mon Jun 23 16:13:07 CEST 2025


The new subcommand is introduced so that we have a common name space for
any config migration tasks which are triggered by d/postinst (or potentially
by hand).

No functional changes.

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

Notes:
    I guess at this point we could also drop this code entirely?

 debian/postinst                               |  2 +-
 src/bin/proxmox-backup-manager.rs             |  6 +-
 .../proxmox_backup_manager/migrate_config.rs  | 98 +++++++++++++++++++
 src/bin/proxmox_backup_manager/mod.rs         |  1 +
 src/bin/proxmox_backup_manager/prune.rs       | 87 +---------------
 5 files changed, 104 insertions(+), 90 deletions(-)
 create mode 100644 src/bin/proxmox_backup_manager/migrate_config.rs

diff --git a/debian/postinst b/debian/postinst
index f38a8c66..7f4c57cc 100644
--- a/debian/postinst
+++ b/debian/postinst
@@ -35,7 +35,7 @@ case "$1" in
 
 		if dpkg --compare-versions "$2" 'lt' '2.2.2~'; then
 			echo "moving prune schedule from datacenter config to new prune job config"
-			proxmox-backup-manager update-to-prune-jobs-config \
+			proxmox-backup-manager migrate-config update-to-prune-jobs-config \
 			    || echo "Failed to move prune jobs, please check manually"
 			true
 		fi
diff --git a/src/bin/proxmox-backup-manager.rs b/src/bin/proxmox-backup-manager.rs
index d4363e71..378c5c7f 100644
--- a/src/bin/proxmox-backup-manager.rs
+++ b/src/bin/proxmox-backup-manager.rs
@@ -712,9 +712,9 @@ async fn run() -> Result<(), Error> {
         .insert("report", CliCommand::new(&API_METHOD_REPORT))
         .insert("versions", CliCommand::new(&API_METHOD_GET_VERSIONS));
 
-    let args: Vec<String> = std::env::args().take(2).collect();
-    if args.len() >= 2 && args[1] == "update-to-prune-jobs-config" {
-        return update_to_prune_jobs_config();
+    let args: Vec<String> = std::env::args().take(3).collect();
+    if args.len() >= 3 && args[1] == "migrate-config" {
+        return migrate_config::handle_command(&args[2]);
     }
     let avoid_init = args.len() >= 2 && (args[1] == "bashcomplete" || args[1] == "printdoc");
 
diff --git a/src/bin/proxmox_backup_manager/migrate_config.rs b/src/bin/proxmox_backup_manager/migrate_config.rs
new file mode 100644
index 00000000..214c8d71
--- /dev/null
+++ b/src/bin/proxmox_backup_manager/migrate_config.rs
@@ -0,0 +1,98 @@
+use anyhow::{bail, Error};
+use serde::Deserialize;
+
+use pbs_api_types::{DataStoreConfig, PruneJobConfig, PruneJobOptions};
+use pbs_config::prune;
+
+/// Handle a 'migrate-config' command.
+pub fn handle_command(command: &str) -> Result<(), Error> {
+    match command {
+        "update-to-prune-jobs-config" => return update_to_prune_jobs_config(),
+        _ => bail!("invalid fixup command: {command}"),
+    }
+}
+
+/// Migrate a datastore's prune setting to a prune job.
+pub(crate) fn update_to_prune_jobs_config() -> Result<(), Error> {
+    use pbs_config::datastore;
+
+    let _prune_lock = prune::lock_config()?;
+    let _datastore_lock = datastore::lock_config()?;
+
+    let (mut data, _digest) = prune::config()?;
+    let (mut storeconfig, _digest) = datastore::config()?;
+
+    for (store, entry) in storeconfig.sections.iter_mut() {
+        let ty = &entry.0;
+
+        if ty != "datastore" {
+            continue;
+        }
+
+        let mut config = match DataStoreConfig::deserialize(&entry.1) {
+            Ok(c) => c,
+            Err(err) => {
+                eprintln!("failed to parse config of store {store}: {err}");
+                continue;
+            }
+        };
+
+        let options = PruneJobOptions {
+            keep: std::mem::take(&mut config.keep),
+            ..Default::default()
+        };
+
+        let schedule = config.prune_schedule.take();
+
+        entry.1 = serde_json::to_value(config)?;
+
+        let schedule = match schedule {
+            Some(s) => s,
+            None => {
+                if options.keeps_something() {
+                    eprintln!(
+                        "dropping prune job without schedule from datastore '{store}' in datastore.cfg"
+                    );
+                } else {
+                    eprintln!("ignoring empty prune job of datastore '{store}' in datastore.cfg");
+                }
+                continue;
+            }
+        };
+
+        let mut id = format!("storeconfig-{store}");
+        id.truncate(32);
+        if data.sections.contains_key(&id) {
+            eprintln!("skipping existing converted prune job for datastore '{store}': {id}");
+            continue;
+        }
+
+        if !options.keeps_something() {
+            eprintln!("dropping empty prune job of datastore '{store}' in datastore.cfg");
+            continue;
+        }
+
+        let prune_config = PruneJobConfig {
+            id: id.clone(),
+            store: store.clone(),
+            disable: false,
+            comment: None,
+            schedule,
+            options,
+        };
+
+        let prune_config = serde_json::to_value(prune_config)?;
+
+        data.sections
+            .insert(id, ("prune".to_string(), prune_config));
+
+        eprintln!(
+            "migrating prune job of datastore '{store}' from datastore.cfg to prune.cfg jobs"
+        );
+    }
+
+    prune::save_config(&data)?;
+    datastore::save_config(&storeconfig)?;
+
+    Ok(())
+}
diff --git a/src/bin/proxmox_backup_manager/mod.rs b/src/bin/proxmox_backup_manager/mod.rs
index 11fb6dd3..14bd729e 100644
--- a/src/bin/proxmox_backup_manager/mod.rs
+++ b/src/bin/proxmox_backup_manager/mod.rs
@@ -36,3 +36,4 @@ mod openid;
 pub use openid::*;
 mod traffic_control;
 pub use traffic_control::*;
+pub mod migrate_config;
diff --git a/src/bin/proxmox_backup_manager/prune.rs b/src/bin/proxmox_backup_manager/prune.rs
index 923eb6f5..eb06608b 100644
--- a/src/bin/proxmox_backup_manager/prune.rs
+++ b/src/bin/proxmox_backup_manager/prune.rs
@@ -1,13 +1,12 @@
 use std::collections::HashMap;
 
 use anyhow::Error;
-use serde::Deserialize;
 use serde_json::Value;
 
 use proxmox_router::{cli::*, ApiHandler, RpcEnvironment};
 use proxmox_schema::api;
 
-use pbs_api_types::{DataStoreConfig, PruneJobConfig, PruneJobOptions, JOB_ID_SCHEMA};
+use pbs_api_types::{PruneJobConfig, JOB_ID_SCHEMA};
 use pbs_config::prune;
 
 use proxmox_backup::api2;
@@ -180,87 +179,3 @@ fn get_prune_job(id: &str) -> Result<PruneJobConfig, Error> {
 
     config.lookup("prune", id)
 }
-
-pub(crate) fn update_to_prune_jobs_config() -> Result<(), Error> {
-    use pbs_config::datastore;
-
-    let _prune_lock = prune::lock_config()?;
-    let _datastore_lock = datastore::lock_config()?;
-
-    let (mut data, _digest) = prune::config()?;
-    let (mut storeconfig, _digest) = datastore::config()?;
-
-    for (store, entry) in storeconfig.sections.iter_mut() {
-        let ty = &entry.0;
-
-        if ty != "datastore" {
-            continue;
-        }
-
-        let mut config = match DataStoreConfig::deserialize(&entry.1) {
-            Ok(c) => c,
-            Err(err) => {
-                eprintln!("failed to parse config of store {store}: {err}");
-                continue;
-            }
-        };
-
-        let options = PruneJobOptions {
-            keep: std::mem::take(&mut config.keep),
-            ..Default::default()
-        };
-
-        let schedule = config.prune_schedule.take();
-
-        entry.1 = serde_json::to_value(config)?;
-
-        let schedule = match schedule {
-            Some(s) => s,
-            None => {
-                if options.keeps_something() {
-                    eprintln!(
-                        "dropping prune job without schedule from datastore '{store}' in datastore.cfg"
-                    );
-                } else {
-                    eprintln!("ignoring empty prune job of datastore '{store}' in datastore.cfg");
-                }
-                continue;
-            }
-        };
-
-        let mut id = format!("storeconfig-{store}");
-        id.truncate(32);
-        if data.sections.contains_key(&id) {
-            eprintln!("skipping existing converted prune job for datastore '{store}': {id}");
-            continue;
-        }
-
-        if !options.keeps_something() {
-            eprintln!("dropping empty prune job of datastore '{store}' in datastore.cfg");
-            continue;
-        }
-
-        let prune_config = PruneJobConfig {
-            id: id.clone(),
-            store: store.clone(),
-            disable: false,
-            comment: None,
-            schedule,
-            options,
-        };
-
-        let prune_config = serde_json::to_value(prune_config)?;
-
-        data.sections
-            .insert(id, ("prune".to_string(), prune_config));
-
-        eprintln!(
-            "migrating prune job of datastore '{store}' from datastore.cfg to prune.cfg jobs"
-        );
-    }
-
-    prune::save_config(&data)?;
-    datastore::save_config(&storeconfig)?;
-
-    Ok(())
-}
-- 
2.39.5





More information about the pbs-devel mailing list