diff --git a/src/api2/tape/backup.rs b/src/api2/tape/backup.rs index bd709394..d455cb94 100644 --- a/src/api2/tape/backup.rs +++ b/src/api2/tape/backup.rs @@ -178,7 +178,7 @@ pub fn backup_snapshot( break; } - let uuid = pool_writer.load_writable_media()?; + let uuid = pool_writer.load_writable_media(worker)?; let (leom, _bytes) = pool_writer.append_chunk_archive(&datastore, &mut chunk_iter)?; @@ -187,7 +187,7 @@ pub fn backup_snapshot( } } - let uuid = pool_writer.load_writable_media()?; + let uuid = pool_writer.load_writable_media(worker)?; let (done, _bytes) = pool_writer.append_snapshot_archive(&snapshot_reader)?; @@ -195,7 +195,7 @@ pub fn backup_snapshot( // does not fit on tape, so we try on next volume pool_writer.set_media_status_full(&uuid)?; - pool_writer.load_writable_media()?; + pool_writer.load_writable_media(worker)?; let (done, _bytes) = pool_writer.append_snapshot_archive(&snapshot_reader)?; if !done { diff --git a/src/api2/tape/restore.rs b/src/api2/tape/restore.rs index 6d7c5e25..445c103d 100644 --- a/src/api2/tape/restore.rs +++ b/src/api2/tape/restore.rs @@ -67,7 +67,7 @@ pub fn request_and_restore_media( Some(ref set) => &set.uuid, }; - let (mut drive, info) = request_and_load_media(&drive_config, &drive_name, &media_id.label)?; + let (mut drive, info) = request_and_load_media(worker, &drive_config, &drive_name, &media_id.label)?; match info.media_set_label { None => { diff --git a/src/tape/drive/mod.rs b/src/tape/drive/mod.rs index cd3e8829..81261647 100644 --- a/src/tape/drive/mod.rs +++ b/src/tape/drive/mod.rs @@ -19,6 +19,7 @@ use crate::{ VirtualTapeDrive, LinuxTapeDrive, }, + server::WorkerTask, tape::{ TapeWrite, TapeRead, @@ -223,6 +224,7 @@ pub fn open_drive( /// /// Returns a handle to the opened drive and the media labels. pub fn request_and_load_media( + worker: &WorkerTask, config: &SectionConfigData, drive: &str, label: &MediaLabel, @@ -231,51 +233,97 @@ pub fn request_and_load_media( MediaId, ), Error> { + let check_label = |handle: &mut dyn TapeDriver, uuid: &proxmox::tools::Uuid| { + if let Ok(Some(media_id)) = handle.read_label() { + println!("found media label {} ({})", media_id.label.changer_id, media_id.label.uuid.to_string()); + if media_id.label.uuid == *uuid { + return Ok(media_id); + } + } + bail!("read label failed (please label all tapes first)"); + }; + match config.sections.get(drive) { Some((section_type_name, config)) => { match section_type_name.as_ref() { "virtual" => { - let mut drive = VirtualTapeDrive::deserialize(config)?; + let mut tape = VirtualTapeDrive::deserialize(config)?; let changer_id = label.changer_id.clone(); - drive.load_media(&changer_id)?; + tape.load_media(&changer_id)?; - let mut handle = drive.open()?; + let mut handle: Box = Box::new(tape.open()?); - if let Ok(Some(media_id)) = handle.read_label() { - println!("found media label {} ({})", media_id.label.changer_id, media_id.label.uuid.to_string()); - if media_id.label.uuid == label.uuid { - return Ok((Box::new(handle), media_id)); - } - } - bail!("read label failed (label all tapes first)"); + let media_id = check_label(handle.as_mut(), &label.uuid)?; + + return Ok((handle, media_id)); } "linux" => { - let tape = LinuxTapeDrive::deserialize(config)?; + let mut tape = LinuxTapeDrive::deserialize(config)?; - let id = label.changer_id.clone(); + let changer_id = label.changer_id.clone(); - println!("Please insert media '{}' into drive '{}'", id, drive); + if tape.changer.is_some() { + + tape.load_media(&changer_id)?; + + let mut handle: Box = Box::new(tape.open()?); + + let media_id = check_label(handle.as_mut(), &label.uuid)?; + + return Ok((handle, media_id)); + } + + worker.log(format!("Please insert media '{}' into drive '{}'", changer_id, drive)); + + let to = "root@localhost"; // fixme + let mut changer = ChangeMediaEmail::new(drive, to); + + changer.load_media(&changer_id)?; // semd email + + let mut last_media_uuid = None; loop { let mut handle = match tape.open() { Ok(handle) => handle, Err(_) => { - eprintln!("tape open failed - test again in 5 secs"); + //eprintln!("tape open failed - test again in 5 secs"); std::thread::sleep(std::time::Duration::from_millis(5_000)); continue; } }; - if let Ok(Some(media_id)) = handle.read_label() { - println!("found media label {} ({})", media_id.label.changer_id, media_id.label.uuid.to_string()); - if media_id.label.uuid == label.uuid { - return Ok((Box::new(handle), media_id)); + match handle.read_label() { + Ok(Some(media_id)) => { + if media_id.label.uuid == label.uuid { + worker.log(format!( + "found media label {} ({})", + media_id.label.changer_id, + media_id.label.uuid.to_string(), + )); + return Ok((Box::new(handle), media_id)); + } else { + if Some(media_id.label.uuid.clone()) != last_media_uuid { + worker.log(format!( + "wrong media label {} ({})", + media_id.label.changer_id, + media_id.label.uuid.to_string(), + )); + last_media_uuid = Some(media_id.label.uuid); + } + } } + Ok(None) => { + if last_media_uuid.is_some() { + worker.log(format!("found empty media without label (please label all tapes first)")); + last_media_uuid = None; + } + } + Err(_) => { /* test again */ } } - println!("read label failed - test again in 5 secs"); + // eprintln!("read label failed - test again in 5 secs"); std::thread::sleep(std::time::Duration::from_millis(5_000)); } } diff --git a/src/tape/pool_writer.rs b/src/tape/pool_writer.rs index ce118445..6be4a31f 100644 --- a/src/tape/pool_writer.rs +++ b/src/tape/pool_writer.rs @@ -12,6 +12,7 @@ use crate::{ backup::{ DataStore, }, + server::WorkerTask, tape::{ TAPE_STATUS_DIR, MAX_CHUNK_ARCHIVE_SIZE, @@ -118,7 +119,7 @@ impl PoolWriter { } /// Load a writable media into the drive - pub fn load_writable_media(&mut self) -> Result { + pub fn load_writable_media(&mut self, worker: &WorkerTask) -> Result { let last_media_uuid = match self.status { Some(PoolWriterState { ref catalog, .. }) => Some(catalog.uuid().clone()), None => None, @@ -147,7 +148,7 @@ impl PoolWriter { } let (drive_config, _digest) = crate::config::drive::config()?; - let (drive, catalog) = drive_load_and_label_media(&drive_config, &self.drive_name, &media.id())?; + let (drive, catalog) = drive_load_and_label_media(worker, &drive_config, &self.drive_name, &media.id())?; self.status = Some(PoolWriterState { drive, catalog, at_eom: false, bytes_written: 0 }); Ok(media_uuid) @@ -333,13 +334,14 @@ fn write_chunk_archive<'a>( // set label. If the tabe is empty, or the existing set label does not // match the expected media set, overwrite the media set label. fn drive_load_and_label_media( + worker: &WorkerTask, drive_config: &SectionConfigData, drive_name: &str, media_id: &MediaId, ) -> Result<(Box, MediaCatalog), Error> { let (mut tmp_drive, info) = - request_and_load_media(&drive_config, &drive_name, &media_id.label)?; + request_and_load_media(worker, &drive_config, &drive_name, &media_id.label)?; let media_catalog;