[pbs-devel] [PATCH proxmox-backup] fix #4719: wait for tape to be available in changer

Dominik Csapak d.csapak at proxmox.com
Mon May 8 13:03:41 CEST 2023


instead of aborting. If the tape is currently e.g. offline, in an
import/export slot or in the wrong drive, this gives the user the chance to
manually move it/insert it, so that the backup job can continue.

Send an e-mail like we do on a standalone drive, but adapt the messages
to contain the changer instead of the drive.

This can help when not all tapes are currently available in the changer.

Signed-off-by: Dominik Csapak <d.csapak at proxmox.com>
---
 src/server/email_notifications.rs | 19 ++++++----
 src/tape/drive/mod.rs             | 59 +++++++++++++++++++------------
 2 files changed, 49 insertions(+), 29 deletions(-)

diff --git a/src/server/email_notifications.rs b/src/server/email_notifications.rs
index 1224191c..27b638bb 100644
--- a/src/server/email_notifications.rs
+++ b/src/server/email_notifications.rs
@@ -540,27 +540,34 @@ pub fn send_tape_backup_status(
 
 /// Send email to a person to request a manual media change
 pub fn send_load_media_email(
-    drive: &str,
+    changer: bool,
+    device: &str,
     label_text: &str,
     to: &str,
     reason: Option<String>,
 ) -> Result<(), Error> {
     use std::fmt::Write as _;
 
-    let subject = format!("Load Media '{label_text}' request for drive '{drive}'");
+    let device_type = if changer { "changer" } else { "drive" };
+
+    let subject = format!("Load Media '{label_text}' request for {device_type} '{device}'");
 
     let mut text = String::new();
 
     if let Some(reason) = reason {
         let _ = write!(
             text,
-            "The drive has the wrong or no tape inserted. Error:\n{reason}\n\n"
+            "The {device_type} has the wrong or no tape(s) inserted. Error:\n{reason}\n\n"
         );
     }
 
-    text.push_str("Please insert the requested media into the backup drive.\n\n");
-
-    let _ = writeln!(text, "Drive: {drive}");
+    if changer {
+        text.push_str("Please insert the requested media into the changer.\n\n");
+        let _ = writeln!(text, "Changer: {device}");
+    } else {
+        text.push_str("Please insert the requested media into the backup drive.\n\n");
+        let _ = writeln!(text, "Drive: {device}");
+    }
     let _ = writeln!(text, "Media: {label_text}");
 
     send_job_status_mail(to, &subject, &text)
diff --git a/src/tape/drive/mod.rs b/src/tape/drive/mod.rs
index c69ebc63..86f01201 100644
--- a/src/tape/drive/mod.rs
+++ b/src/tape/drive/mod.rs
@@ -298,6 +298,7 @@ enum TapeRequestError {
     OpenFailed(String),
     WrongLabel(String),
     ReadFailed(String),
+    LoadingFailed(String),
 }
 
 impl std::fmt::Display for TapeRequestError {
@@ -321,6 +322,9 @@ impl std::fmt::Display for TapeRequestError {
             TapeRequestError::ReadFailed(reason) => {
                 write!(f, "tape read failed - {}", reason)
             }
+            TapeRequestError::LoadingFailed(reason) => {
+                write!(f, "could not load tape into drive - {}", reason)
+            }
         }
     }
 }
@@ -374,40 +378,31 @@ pub fn request_and_load_media(
 
                     let label_text = label.label_text.clone();
 
-                    if drive_config.changer.is_some() {
-                        task_log!(
-                            worker,
-                            "loading media '{}' into drive '{}'",
-                            label_text,
-                            drive
-                        );
-
-                        let mut changer = MtxMediaChanger::with_drive_config(&drive_config)?;
-                        changer.load_media(&label_text)?;
-
-                        let mut handle: Box<dyn TapeDriver> =
-                            Box::new(open_lto_tape_drive(&drive_config)?);
-
-                        let media_id = check_label(handle.as_mut(), &label.uuid)?;
-
-                        return Ok((handle, media_id));
-                    }
-
                     let mut last_error = TapeRequestError::None;
 
+                    let changer = &drive_config.changer;
+
                     let update_and_log_request_error =
                         |old: &mut TapeRequestError, new: TapeRequestError| -> Result<(), Error> {
                             if new != *old {
                                 task_log!(worker, "{}", new);
+                                let (device_type, device) = if let Some(changer) = changer {
+                                    ("changer", changer.as_str())
+                                } else {
+                                    ("drive", drive)
+                                };
+
                                 task_log!(
                                     worker,
-                                    "Please insert media '{}' into drive '{}'",
+                                    "Please insert media '{}' into {} '{}'",
                                     label_text,
-                                    drive
+                                    device_type,
+                                    device
                                 );
                                 if let Some(to) = notify_email {
                                     send_load_media_email(
-                                        drive,
+                                        changer.is_some(),
+                                        device,
                                         &label_text,
                                         to,
                                         Some(new.to_string()),
@@ -427,13 +422,31 @@ pub fn request_and_load_media(
                                 worker.check_abort()?;
                                 std::thread::sleep(std::time::Duration::from_millis(100));
                             }
-                        } else {
+                        } else if drive_config.changer.is_none() {
                             task_log!(
                                 worker,
                                 "Checking for media '{}' in drive '{}'",
                                 label_text,
                                 drive
                             );
+                        } else {
+                            task_log!(
+                                worker,
+                                "trying to load media '{}' into drive '{}'",
+                                label_text,
+                                drive
+                            );
+                        }
+
+                        if drive_config.changer.is_some() {
+                            let mut changer = MtxMediaChanger::with_drive_config(&drive_config)?;
+                            if let Err(err) = changer.load_media(&label_text) {
+                                update_and_log_request_error(
+                                    &mut last_error,
+                                    TapeRequestError::LoadingFailed(err.to_string()),
+                                )?;
+                                continue;
+                            }
                         }
 
                         let mut handle = match open_lto_tape_drive(&drive_config) {
-- 
2.30.2






More information about the pbs-devel mailing list