[pbs-devel] [PATCH proxmox-backup v2] fix #4274: implement prune notifications

Dominik Csapak d.csapak at proxmox.com
Thu Oct 6 11:08:12 CEST 2022


we converted the prune settings of datastores to prune-jobs, but did
not actually implement the notifications for them, even though
we had the notification options in the gui (they did not work).

implement the basic ok/error notification for prune jobs

Signed-off-by: Dominik Csapak <d.csapak at proxmox.com>
---
changes from v1:
* include 'fix #' in the commit subject
* call lookup_datastore_notify_settings directly in the send helper
* fix compilation errors
* rebase on master
 pbs-api-types/src/jobs.rs         |  6 +++
 src/api2/config/datastore.rs      |  1 +
 src/server/email_notifications.rs | 77 +++++++++++++++++++++++++++++++
 src/server/prune_job.rs           |  7 ++-
 www/datastore/OptionView.js       |  2 +-
 www/window/NotifyOptions.js       |  2 +-
 6 files changed, 91 insertions(+), 4 deletions(-)

diff --git a/pbs-api-types/src/jobs.rs b/pbs-api-types/src/jobs.rs
index e4be03f0..7f029af7 100644
--- a/pbs-api-types/src/jobs.rs
+++ b/pbs-api-types/src/jobs.rs
@@ -128,6 +128,10 @@ pub enum Notify {
             type: Notify,
             optional: true,
         },
+        prune: {
+            type: Notify,
+            optional: true,
+        },
     },
 )]
 #[derive(Debug, Serialize, Deserialize)]
@@ -139,6 +143,8 @@ pub struct DatastoreNotify {
     pub verify: Option<Notify>,
     /// Sync job setting
     pub sync: Option<Notify>,
+    /// Prune job setting
+    pub prune: Option<Notify>,
 }
 
 pub const DATASTORE_NOTIFY_STRING_SCHEMA: Schema =
diff --git a/src/api2/config/datastore.rs b/src/api2/config/datastore.rs
index 2d769722..08adf7c9 100644
--- a/src/api2/config/datastore.rs
+++ b/src/api2/config/datastore.rs
@@ -331,6 +331,7 @@ pub fn update_datastore(
             gc: None,
             verify: None,
             sync: None,
+            prune: None,
         } = notify
         {
             data.notify = None;
diff --git a/src/server/email_notifications.rs b/src/server/email_notifications.rs
index f60acc64..8d97623a 100644
--- a/src/server/email_notifications.rs
+++ b/src/server/email_notifications.rs
@@ -113,6 +113,34 @@ Remote Store: {{job.remote-store}}
 Synchronization failed: {{error}}
 
 
+Please visit the web interface for further details:
+
+<https://{{fqdn}}:{{port}}/#pbsServerAdministration:tasks>
+
+"###;
+
+const PRUNE_OK_TEMPLATE: &str = r###"
+
+Job ID:       {{jobname}}
+Datastore:    {{store}}
+
+Pruning successful.
+
+
+Please visit the web interface for further details:
+
+<https://{{fqdn}}:{{port}}/#DataStore-{{store}}>
+
+"###;
+
+const PRUNE_ERR_TEMPLATE: &str = r###"
+
+Job ID:       {{jobname}}
+Datastore:    {{store}}
+
+Pruning failed: {{error}}
+
+
 Please visit the web interface for further details:
 
 <https://{{fqdn}}:{{port}}/#pbsServerAdministration:tasks>
@@ -227,6 +255,9 @@ lazy_static::lazy_static! {
             hb.register_template_string("sync_ok_template", SYNC_OK_TEMPLATE)?;
             hb.register_template_string("sync_err_template", SYNC_ERR_TEMPLATE)?;
 
+            hb.register_template_string("prune_ok_template", PRUNE_OK_TEMPLATE)?;
+            hb.register_template_string("prune_err_template", PRUNE_ERR_TEMPLATE)?;
+
             hb.register_template_string("tape_backup_ok_template", TAPE_BACKUP_OK_TEMPLATE)?;
             hb.register_template_string("tape_backup_err_template", TAPE_BACKUP_ERR_TEMPLATE)?;
 
@@ -384,6 +415,51 @@ pub fn send_verify_status(
     Ok(())
 }
 
+pub fn send_prune_status(
+    store: &str,
+    jobname: &str,
+    result: &Result<(), Error>,
+) -> Result<(), Error> {
+    let (email, notify) = match lookup_datastore_notify_settings(&store) {
+        (Some(email), notify) => (email, notify),
+        (None, _) => return Ok(()),
+    };
+
+    match notify.prune {
+        None => { /* send notifications by default */ }
+        Some(notify) => {
+            if notify == Notify::Never || (result.is_ok() && notify == Notify::Error) {
+                return Ok(());
+            }
+        }
+    }
+
+    let (fqdn, port) = get_server_url();
+    let mut data = json!({
+        "jobname": jobname,
+        "store": store,
+        "fqdn": fqdn,
+        "port": port,
+    });
+
+    let text = match result {
+        Ok(()) => HANDLEBARS.render("prune_ok_template", &data)?,
+        Err(err) => {
+            data["error"] = err.to_string().into();
+            HANDLEBARS.render("prune_err_template", &data)?
+        }
+    };
+
+    let subject = match result {
+        Ok(()) => format!("Pruning datastore '{}' successful", store,),
+        Err(_) => format!("Pruning datastore '{}' failed", store,),
+    };
+
+    send_job_status_mail(&email, &subject, &text)?;
+
+    Ok(())
+}
+
 pub fn send_sync_status(
     email: &str,
     notify: DatastoreNotify,
@@ -584,6 +660,7 @@ pub fn lookup_datastore_notify_settings(store: &str) -> (Option<String>, Datasto
         gc: None,
         verify: None,
         sync: None,
+        prune: None,
     };
 
     let (config, _digest) = match pbs_config::datastore::config() {
diff --git a/src/server/prune_job.rs b/src/server/prune_job.rs
index 4e261b48..0a8e1d19 100644
--- a/src/server/prune_job.rs
+++ b/src/server/prune_job.rs
@@ -164,9 +164,9 @@ pub fn do_prune_job(
     let worker_type = job.jobtype().to_string();
     let auth_id = auth_id.clone();
     let worker_id = match &prune_options.ns {
-        Some(ns) if ns.is_root() => store,
+        Some(ns) if ns.is_root() => store.clone(),
         Some(ns) => format!("{store}:{ns}"),
-        None => store,
+        None => store.clone(),
     };
 
     let upid_str = WorkerTask::new_thread(
@@ -191,6 +191,9 @@ pub fn do_prune_job(
                 eprintln!("could not finish job state for {}: {}", job.jobtype(), err);
             }
 
+            if let Err(err) = crate::server::send_prune_status(&store, job.jobname(), &result) {
+                log::error!("send prune notification failed: {}", err);
+            }
             result
         },
     )?;
diff --git a/www/datastore/OptionView.js b/www/datastore/OptionView.js
index 4cfafccf..eb335979 100644
--- a/www/datastore/OptionView.js
+++ b/www/datastore/OptionView.js
@@ -110,7 +110,7 @@ Ext.define('PBS.Datastore.Options', {
 	    renderer: (value) => {
 		let notify = PBS.Utils.parsePropertyString(value);
 		let res = [];
-		for (const k of ['Verify', 'Sync', 'GC']) {
+		for (const k of ['Verify', 'Sync', 'GC', 'Prune']) {
 		    let v = Ext.String.capitalize(notify[k.toLowerCase()]) || 'Always';
 		    res.push(`${k}=${v}`);
 		}
diff --git a/www/window/NotifyOptions.js b/www/window/NotifyOptions.js
index 924bbb8b..7c7e6489 100644
--- a/www/window/NotifyOptions.js
+++ b/www/window/NotifyOptions.js
@@ -36,7 +36,7 @@ Ext.define('PBS.window.NotifyOptions', {
 	xtype: 'inputpanel',
 	onGetValues: function(values) {
 	    let notify = {};
-	    for (const k of ['verify', 'sync', 'gc']) {
+	    for (const k of ['verify', 'sync', 'gc', 'prune']) {
 		notify[k] = values[k];
 		delete values[k];
 	    }
-- 
2.30.2






More information about the pbs-devel mailing list