From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from firstgate.proxmox.com (firstgate.proxmox.com [212.224.123.68]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by lists.proxmox.com (Postfix) with ESMTPS id 98B17912B7 for ; Thu, 6 Oct 2022 11:08:16 +0200 (CEST) Received: from firstgate.proxmox.com (localhost [127.0.0.1]) by firstgate.proxmox.com (Proxmox) with ESMTP id 81A7B1AB8B for ; Thu, 6 Oct 2022 11:08:16 +0200 (CEST) Received: from proxmox-new.maurer-it.com (proxmox-new.maurer-it.com [94.136.29.106]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by firstgate.proxmox.com (Proxmox) with ESMTPS for ; Thu, 6 Oct 2022 11:08:14 +0200 (CEST) Received: from proxmox-new.maurer-it.com (localhost.localdomain [127.0.0.1]) by proxmox-new.maurer-it.com (Proxmox) with ESMTP id 244D44416B for ; Thu, 6 Oct 2022 11:08:14 +0200 (CEST) From: Dominik Csapak To: pbs-devel@lists.proxmox.com Date: Thu, 6 Oct 2022 11:08:12 +0200 Message-Id: <20221006090812.1491248-1-d.csapak@proxmox.com> X-Mailer: git-send-email 2.30.2 MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-SPAM-LEVEL: Spam detection results: 0 AWL 0.069 Adjusted score from AWL reputation of From: address BAYES_00 -1.9 Bayes spam probability is 0 to 1% KAM_DMARC_STATUS 0.01 Test Rule for DKIM or SPF Failure with Strict Alignment SPF_HELO_NONE 0.001 SPF: HELO does not publish an SPF Record SPF_PASS -0.001 SPF: sender matches SPF record URIBL_BLOCKED 0.001 ADMINISTRATOR NOTICE: The query to URIBL was blocked. See http://wiki.apache.org/spamassassin/DnsBlocklists#dnsbl-block for more information. [jobs.rs, datastore.rs] Subject: [pbs-devel] [PATCH proxmox-backup v2] fix #4274: implement prune notifications X-BeenThere: pbs-devel@lists.proxmox.com X-Mailman-Version: 2.1.29 Precedence: list List-Id: Proxmox Backup Server development discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 06 Oct 2022 09:08:16 -0000 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 --- 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, /// 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]; } -- 2.30.2