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)) (No client certificate requested) by lists.proxmox.com (Postfix) with ESMTPS id E249C6B0E0 for ; Mon, 8 Mar 2021 14:11:24 +0100 (CET) Received: from firstgate.proxmox.com (localhost [127.0.0.1]) by firstgate.proxmox.com (Proxmox) with ESMTP id BFCB01EC01 for ; Mon, 8 Mar 2021 14:10:54 +0100 (CET) Received: from proxmox-new.maurer-it.com (proxmox-new.maurer-it.com [212.186.127.180]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits)) (No client certificate requested) by firstgate.proxmox.com (Proxmox) with ESMTPS id 841E01EBE3 for ; Mon, 8 Mar 2021 14:10:53 +0100 (CET) Received: from proxmox-new.maurer-it.com (localhost.localdomain [127.0.0.1]) by proxmox-new.maurer-it.com (Proxmox) with ESMTP id 5151C41DCC for ; Mon, 8 Mar 2021 14:10:53 +0100 (CET) From: Dominik Csapak To: pbs-devel@lists.proxmox.com Date: Mon, 8 Mar 2021 14:10:49 +0100 Message-Id: <20210308131051.11767-1-d.csapak@proxmox.com> X-Mailer: git-send-email 2.20.1 MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-SPAM-LEVEL: Spam detection results: 0 AWL 0.195 Adjusted score from AWL reputation of From: address KAM_DMARC_STATUS 0.01 Test Rule for DKIM or SPF Failure with Strict Alignment RCVD_IN_DNSWL_MED -2.3 Sender listed at https://www.dnswl.org/, medium trust SPF_HELO_NONE 0.001 SPF: HELO does not publish an SPF Record SPF_PASS -0.001 SPF: sender matches SPF record Subject: [pbs-devel] [PATCH proxmox-backup 1/3] tape/backup: add success/error 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: Mon, 08 Mar 2021 13:11:24 -0000 Signed-off-by: Dominik Csapak --- src/api2/tape/backup.rs | 40 ++++++++++++-- src/server/email_notifications.rs | 92 +++++++++++++++++++++++++++++++ 2 files changed, 126 insertions(+), 6 deletions(-) diff --git a/src/api2/tape/backup.rs b/src/api2/tape/backup.rs index 06f75f92..e8ae887c 100644 --- a/src/api2/tape/backup.rs +++ b/src/api2/tape/backup.rs @@ -193,15 +193,30 @@ pub fn do_tape_backup_job( task_log!(worker,"task triggered by schedule '{}'", event_str); } + let notify_user = setup.notify_user.as_ref().unwrap_or_else(|| &Userid::root_userid()); + let email = lookup_user_email(notify_user); + let job_result = backup_worker( &worker, datastore, &pool_config, &setup, + email.clone(), ); let status = worker.create_state(&job_result); + if let Some(email) = email { + if let Err(err) = crate::server::send_tape_backup_status( + &email, + Some(job.jobname()), + &setup, + &job_result, + ) { + eprintln!("send tape backup notification failed: {}", err); + } + } + if let Err(err) = job.finish(status) { eprintln!( "could not finish job state for {}: {}", @@ -312,6 +327,9 @@ pub fn backup( let job_id = format!("{}:{}:{}", setup.store, setup.pool, setup.drive); + let notify_user = setup.notify_user.as_ref().unwrap_or_else(|| &Userid::root_userid()); + let email = lookup_user_email(notify_user); + let upid_str = WorkerTask::new_thread( "tape-backup", Some(job_id), @@ -320,16 +338,28 @@ pub fn backup( move |worker| { let _drive_lock = drive_lock; // keep lock guard set_tape_device_state(&setup.drive, &worker.upid().to_string())?; - backup_worker( + let job_result = backup_worker( &worker, datastore, &pool_config, &setup, - )?; + email.clone(), + ); + + if let Some(email) = email { + if let Err(err) = crate::server::send_tape_backup_status( + &email, + None, + &setup, + &job_result, + ) { + eprintln!("send tape backup notification failed: {}", err); + } + } // ignore errors let _ = set_tape_device_state(&setup.drive, ""); - Ok(()) + job_result } )?; @@ -341,6 +371,7 @@ fn backup_worker( datastore: Arc, pool_config: &MediaPoolConfig, setup: &TapeBackupJobSetup, + email: Option, ) -> Result<(), Error> { let status_path = Path::new(TAPE_STATUS_DIR); @@ -352,9 +383,6 @@ fn backup_worker( let pool = MediaPool::with_config(status_path, &pool_config, changer_name)?; - let notify_user = setup.notify_user.as_ref().unwrap_or_else(|| &Userid::root_userid()); - let email = lookup_user_email(notify_user); - let mut pool_writer = PoolWriter::new(pool, &setup.drive, worker, email)?; let mut group_list = BackupInfo::list_backup_groups(&datastore.base_path())?; diff --git a/src/server/email_notifications.rs b/src/server/email_notifications.rs index 3ff1be7c..f09a8931 100644 --- a/src/server/email_notifications.rs +++ b/src/server/email_notifications.rs @@ -10,6 +10,7 @@ use crate::{ config::datastore::DataStoreConfig, config::verify::VerificationJobConfig, config::sync::SyncJobConfig, + config::tape_job::TapeBackupJobSetup, api2::types::{ APTUpdateInfo, GarbageCollectionStatus, @@ -138,6 +139,43 @@ To upgrade visit the web interface: "###; +const TAPE_BACKUP_OK_TEMPLATE: &str = r###" + +{{#if id ~}} +Job ID: {{id}} +{{/if~}} +Datastore: {{job.store}} +Tape Pool: {{job.pool}} +Tape Drive: {{job.drive}} + + +Tape Backup successful. + + +Please visit the web interface for futher details: + + + +"###; + +const TAPE_BACKUP_ERR_TEMPLATE: &str = r###" + +{{#if id ~}} +Job ID: {{id}} +{{/if~}} +Datastore: {{job.store}} +Tape Pool: {{job.pool}} +Tape Drive: {{job.drive}} + + +Tape Backup failed: {{error}} + + +Please visit the web interface for futher details: + + + +"###; lazy_static::lazy_static!{ @@ -158,6 +196,9 @@ lazy_static::lazy_static!{ hb.register_template_string("sync_ok_template", SYNC_OK_TEMPLATE).unwrap(); hb.register_template_string("sync_err_template", SYNC_ERR_TEMPLATE).unwrap(); + hb.register_template_string("tape_backup_ok_template", TAPE_BACKUP_OK_TEMPLATE).unwrap(); + hb.register_template_string("tape_backup_err_template", TAPE_BACKUP_ERR_TEMPLATE).unwrap(); + hb.register_template_string("package_update_template", PACKAGE_UPDATES_TEMPLATE).unwrap(); hb @@ -356,6 +397,57 @@ pub fn send_sync_status( Ok(()) } +pub fn send_tape_backup_status( + email: &str, + id: Option<&str>, + job: &TapeBackupJobSetup, + result: &Result<(), Error>, +) -> Result<(), Error> { + + let (fqdn, port) = get_server_url(); + let mut data = json!({ + "job": job, + "fqdn": fqdn, + "port": port, + "id": id, + }); + + let text = match result { + Ok(()) => { + HANDLEBARS.render("tape_backup_ok_template", &data)? + } + Err(err) => { + data["error"] = err.to_string().into(); + HANDLEBARS.render("tape_backup_err_template", &data)? + } + }; + + let subject = match (result, id) { + (Ok(()), Some(id)) => format!( + "Tape Backup '{}' datastore '{}' successful", + id, + job.store, + ), + (Ok(()), None) => format!( + "Tape Backup datastore '{}' successful", + job.store, + ), + (Err(_), Some(id)) => format!( + "Tape Backup '{}' datastore '{}' failed", + id, + job.store, + ), + (Err(_), None) => format!( + "Tape Backup datastore '{}' failed", + job.store, + ), + }; + + send_job_status_mail(email, &subject, &text)?; + + Ok(()) +} + fn get_server_url() -> (String, usize) { // user will surely request that they can change this -- 2.20.1