mirror of
https://git.proxmox.com/git/proxmox-backup
synced 2025-08-07 02:33:23 +00:00
fix #4719: wait for tape to be available in changer
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@proxmox.com>
This commit is contained in:
parent
2ebe7bb54a
commit
bdce7fa154
@ -540,27 +540,34 @@ pub fn send_tape_backup_status(
|
|||||||
|
|
||||||
/// Send email to a person to request a manual media change
|
/// Send email to a person to request a manual media change
|
||||||
pub fn send_load_media_email(
|
pub fn send_load_media_email(
|
||||||
drive: &str,
|
changer: bool,
|
||||||
|
device: &str,
|
||||||
label_text: &str,
|
label_text: &str,
|
||||||
to: &str,
|
to: &str,
|
||||||
reason: Option<String>,
|
reason: Option<String>,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
use std::fmt::Write as _;
|
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();
|
let mut text = String::new();
|
||||||
|
|
||||||
if let Some(reason) = reason {
|
if let Some(reason) = reason {
|
||||||
let _ = write!(
|
let _ = write!(
|
||||||
text,
|
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");
|
if changer {
|
||||||
|
text.push_str("Please insert the requested media into the changer.\n\n");
|
||||||
let _ = writeln!(text, "Drive: {drive}");
|
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}");
|
let _ = writeln!(text, "Media: {label_text}");
|
||||||
|
|
||||||
send_job_status_mail(to, &subject, &text)
|
send_job_status_mail(to, &subject, &text)
|
||||||
|
@ -298,6 +298,7 @@ enum TapeRequestError {
|
|||||||
OpenFailed(String),
|
OpenFailed(String),
|
||||||
WrongLabel(String),
|
WrongLabel(String),
|
||||||
ReadFailed(String),
|
ReadFailed(String),
|
||||||
|
LoadingFailed(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::fmt::Display for TapeRequestError {
|
impl std::fmt::Display for TapeRequestError {
|
||||||
@ -321,6 +322,9 @@ impl std::fmt::Display for TapeRequestError {
|
|||||||
TapeRequestError::ReadFailed(reason) => {
|
TapeRequestError::ReadFailed(reason) => {
|
||||||
write!(f, "tape read failed - {}", 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();
|
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 mut last_error = TapeRequestError::None;
|
||||||
|
|
||||||
|
let changer = &drive_config.changer;
|
||||||
|
|
||||||
let update_and_log_request_error =
|
let update_and_log_request_error =
|
||||||
|old: &mut TapeRequestError, new: TapeRequestError| -> Result<(), Error> {
|
|old: &mut TapeRequestError, new: TapeRequestError| -> Result<(), Error> {
|
||||||
if new != *old {
|
if new != *old {
|
||||||
task_log!(worker, "{}", new);
|
task_log!(worker, "{}", new);
|
||||||
|
let (device_type, device) = if let Some(changer) = changer {
|
||||||
|
("changer", changer.as_str())
|
||||||
|
} else {
|
||||||
|
("drive", drive)
|
||||||
|
};
|
||||||
|
|
||||||
task_log!(
|
task_log!(
|
||||||
worker,
|
worker,
|
||||||
"Please insert media '{}' into drive '{}'",
|
"Please insert media '{}' into {} '{}'",
|
||||||
label_text,
|
label_text,
|
||||||
drive
|
device_type,
|
||||||
|
device
|
||||||
);
|
);
|
||||||
if let Some(to) = notify_email {
|
if let Some(to) = notify_email {
|
||||||
send_load_media_email(
|
send_load_media_email(
|
||||||
drive,
|
changer.is_some(),
|
||||||
|
device,
|
||||||
&label_text,
|
&label_text,
|
||||||
to,
|
to,
|
||||||
Some(new.to_string()),
|
Some(new.to_string()),
|
||||||
@ -427,13 +422,31 @@ pub fn request_and_load_media(
|
|||||||
worker.check_abort()?;
|
worker.check_abort()?;
|
||||||
std::thread::sleep(std::time::Duration::from_millis(100));
|
std::thread::sleep(std::time::Duration::from_millis(100));
|
||||||
}
|
}
|
||||||
} else {
|
} else if drive_config.changer.is_none() {
|
||||||
task_log!(
|
task_log!(
|
||||||
worker,
|
worker,
|
||||||
"Checking for media '{}' in drive '{}'",
|
"Checking for media '{}' in drive '{}'",
|
||||||
label_text,
|
label_text,
|
||||||
drive
|
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) {
|
let mut handle = match open_lto_tape_drive(&drive_config) {
|
||||||
|
Loading…
Reference in New Issue
Block a user