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, /// Sync job setting pub sync: Option, + /// Prune job setting + pub prune: Option, } 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: + + + +"###; + +const PRUNE_OK_TEMPLATE: &str = r###" + +Job ID: {{jobname}} +Datastore: {{store}} + +Pruning successful. + + +Please visit the web interface for further details: + + + +"###; + +const PRUNE_ERR_TEMPLATE: &str = r###" + +Job ID: {{jobname}} +Datastore: {{store}} + +Pruning failed: {{error}} + + Please visit the web interface for further details: @@ -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, 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]; }