From mboxrd@z Thu Jan  1 00:00:00 1970
Return-Path: <d.csapak@proxmox.com>
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 <pbs-devel@lists.proxmox.com>; 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 <pbs-devel@lists.proxmox.com>; 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 <pbs-devel@lists.proxmox.com>; 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 <pbs-devel@lists.proxmox.com>; Mon,  8 Mar 2021 14:10:53 +0100 (CET)
From: Dominik Csapak <d.csapak@proxmox.com>
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
 <pbs-devel.lists.proxmox.com>
List-Unsubscribe: <https://lists.proxmox.com/cgi-bin/mailman/options/pbs-devel>, 
 <mailto:pbs-devel-request@lists.proxmox.com?subject=unsubscribe>
List-Archive: <http://lists.proxmox.com/pipermail/pbs-devel/>
List-Post: <mailto:pbs-devel@lists.proxmox.com>
List-Help: <mailto:pbs-devel-request@lists.proxmox.com?subject=help>
List-Subscribe: <https://lists.proxmox.com/cgi-bin/mailman/listinfo/pbs-devel>, 
 <mailto:pbs-devel-request@lists.proxmox.com?subject=subscribe>
X-List-Received-Date: Mon, 08 Mar 2021 13:11:24 -0000

Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
---
 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<DataStore>,
     pool_config: &MediaPoolConfig,
     setup: &TapeBackupJobSetup,
+    email: Option<String>,
 ) -> 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:
+
+<https://{{fqdn}}:{{port}}/#DataStore-{{job.store}}>
+
+"###;
+
+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:
+
+<https://{{fqdn}}:{{port}}/#pbsServerAdministration:tasks>
+
+"###;
 
 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