diff --git a/src/api2/tape/drive.rs b/src/api2/tape/drive.rs index 25b03bf9..a9372975 100644 --- a/src/api2/tape/drive.rs +++ b/src/api2/tape/drive.rs @@ -44,7 +44,6 @@ use crate::{ tape::{ TAPE_STATUS_DIR, TapeDriver, - MediaChange, MediaPool, Inventory, MediaCatalog, @@ -138,10 +137,9 @@ pub async fn unload( let (config, _digest) = config::drive::config()?; - let mut drive_config: LinuxTapeDrive = config.lookup("linux", &drive)?; - tokio::task::spawn_blocking(move || { - drive_config.unload_media(target_slot) + let (mut changer, _) = required_media_changer(&config, &drive)?; + changer.unload_media(target_slot) }).await? } diff --git a/src/tape/changer/linux_tape.rs b/src/tape/changer/linux_tape.rs index 068955d2..f21bd1a3 100644 --- a/src/tape/changer/linux_tape.rs +++ b/src/tape/changer/linux_tape.rs @@ -15,6 +15,30 @@ use crate::{ }, }; +/// Implements MediaChange using 'mtx' linux cli tool +pub struct MtxMediaChanger { + drive_name: String, // used for error messages + drivenum: u64, + config: ScsiTapeChanger, +} + +impl MtxMediaChanger { + + pub fn with_drive_config(drive_config: &LinuxTapeDrive) -> Result { + let (config, _digest) = crate::config::drive::config()?; + let changer_config: ScsiTapeChanger = match drive_config.changer { + Some(ref changer) => config.lookup("changer", changer)?, + None => bail!("drive '{}' has no associated changer", drive_config.name), + }; + + Ok(Self { + drive_name: drive_config.name.clone(), + drivenum: drive_config.changer_drive_id.unwrap_or(0), + config: changer_config, + }) + } +} + fn unload_to_free_slot(drive_name: &str, path: &str, status: &MtxStatus, drivenum: u64) -> Result<(), Error> { if drivenum >= status.drives.len() as u64 { @@ -41,30 +65,14 @@ fn unload_to_free_slot(drive_name: &str, path: &str, status: &MtxStatus, drivenu } } -impl MediaChange for LinuxTapeDrive { +impl MediaChange for MtxMediaChanger { fn status(&mut self) -> Result { - let (config, _digest) = crate::config::drive::config()?; - - let changer: ScsiTapeChanger = match self.changer { - Some(ref changer) => config.lookup("changer", changer)?, - None => bail!("drive '{}' has no associated changer", self.name), - }; - - mtx_status(&changer) + mtx_status(&self.config) } fn load_media_from_slot(&mut self, slot: u64) -> Result<(), Error> { - let (config, _digest) = crate::config::drive::config()?; - - let changer: ScsiTapeChanger = match self.changer { - Some(ref changer) => config.lookup("changer", changer)?, - None => bail!("drive '{}' has no associated changer", self.name), - }; - - let drivenum = self.changer_drive_id.unwrap_or(0); - - mtx_load(&changer.path, slot, drivenum as u64) + mtx_load(&self.config.path, slot, self.drivenum) } fn load_media(&mut self, changer_id: &str) -> Result<(), Error> { @@ -73,32 +81,23 @@ impl MediaChange for LinuxTapeDrive { bail!("unable to load media '{}' (seems top be a a cleaning units)", changer_id); } - let (config, _digest) = crate::config::drive::config()?; + let status = self.status()?; - let changer: ScsiTapeChanger = match self.changer { - Some(ref changer) => config.lookup("changer", changer)?, - None => bail!("drive '{}' has no associated changer", self.name), - }; - - let status = mtx_status(&changer)?; - - let drivenum = self.changer_drive_id.unwrap_or(0); - - // already loaded? + // already loaded? for (i, drive_status) in status.drives.iter().enumerate() { if let ElementStatus::VolumeTag(ref tag) = drive_status.status { if *tag == changer_id { - if i as u64 != drivenum { + if i as u64 != self.drivenum { bail!("unable to load media '{}' - media in wrong drive ({} != {})", - changer_id, i, drivenum); + changer_id, i, self.drivenum); } return Ok(()) } } - if i as u64 == drivenum { - match drive_status.status { + if i as u64 == self.drivenum { + match drive_status.status { ElementStatus::Empty => { /* OK */ }, - _ => unload_to_free_slot(&self.name, &changer.path, &status, drivenum as u64)?, + _ => unload_to_free_slot(&self.drive_name, &self.config.path, &status, self.drivenum)?, } } } @@ -121,24 +120,15 @@ impl MediaChange for LinuxTapeDrive { Some(slot) => slot, }; - mtx_load(&changer.path, slot as u64, drivenum as u64) + mtx_load(&self.config.path, slot as u64, self.drivenum) } fn unload_media(&mut self, target_slot: Option) -> Result<(), Error> { - let (config, _digest) = crate::config::drive::config()?; - - let changer: ScsiTapeChanger = match self.changer { - Some(ref changer) => config.lookup("changer", changer)?, - None => return Ok(()), - }; - - let drivenum = self.changer_drive_id.unwrap_or(0); - if let Some(target_slot) = target_slot { - mtx_unload(&changer.path, target_slot, drivenum) + mtx_unload(&self.config.path, target_slot, self.drivenum) } else { - let status = mtx_status(&changer)?; - unload_to_free_slot(&self.name, &changer.path, &status, drivenum) + let status = self.status()?; + unload_to_free_slot(&self.drive_name, &self.config.path, &status, self.drivenum) } } @@ -147,16 +137,7 @@ impl MediaChange for LinuxTapeDrive { } fn clean_drive(&mut self) -> Result<(), Error> { - let (config, _digest) = crate::config::drive::config()?; - - let changer: ScsiTapeChanger = match self.changer { - Some(ref changer) => config.lookup("changer", changer)?, - None => bail!("unable to load cleaning cartridge - no associated changer device"), - }; - - let drivenum = self.changer_drive_id.unwrap_or(0); - - let status = mtx_status(&changer)?; + let status = self.status()?; let mut cleaning_cartridge_slot = None; @@ -175,16 +156,16 @@ impl MediaChange for LinuxTapeDrive { Some(cleaning_cartridge_slot) => cleaning_cartridge_slot as u64, }; - if let Some(drive_status) = status.drives.get(drivenum as usize) { + if let Some(drive_status) = status.drives.get(self.drivenum as usize) { match drive_status.status { ElementStatus::Empty => { /* OK */ }, - _ => unload_to_free_slot(&self.name, &changer.path, &status, drivenum)?, + _ => unload_to_free_slot(&self.drive_name, &self.config.path, &status, self.drivenum)?, } } - mtx_load(&changer.path, cleaning_cartridge_slot, drivenum)?; + mtx_load(&self.config.path, cleaning_cartridge_slot, self.drivenum)?; - mtx_unload(&changer.path, cleaning_cartridge_slot, drivenum)?; + mtx_unload(&self.config.path, cleaning_cartridge_slot, self.drivenum)?; Ok(()) } diff --git a/src/tape/drive/mod.rs b/src/tape/drive/mod.rs index 7f059313..566b184f 100644 --- a/src/tape/drive/mod.rs +++ b/src/tape/drive/mod.rs @@ -31,6 +31,7 @@ use crate::{ TapeWrite, TapeRead, MediaId, + MtxMediaChanger, file_formats::{ PROXMOX_BACKUP_MEDIA_LABEL_MAGIC_1_0, PROXMOX_BACKUP_MEDIA_SET_LABEL_MAGIC_1_0, @@ -181,11 +182,12 @@ pub fn media_changer( Ok(Some((Box::new(tape), drive.to_string()))) } "linux" => { - let tape = LinuxTapeDrive::deserialize(config)?; - match tape.changer { + let drive_config = LinuxTapeDrive::deserialize(config)?; + match drive_config.changer { Some(ref changer_name) => { + let changer = MtxMediaChanger::with_drive_config(&drive_config)?; let changer_name = changer_name.to_string(); - Ok(Some((Box::new(tape), changer_name))) + Ok(Some((Box::new(changer), changer_name))) } None => Ok(None), } @@ -294,15 +296,16 @@ pub fn request_and_load_media( return Ok((handle, media_id)); } "linux" => { - let mut tape = LinuxTapeDrive::deserialize(config)?; + let drive_config = LinuxTapeDrive::deserialize(config)?; let changer_id = label.changer_id.clone(); - if tape.changer.is_some() { + if drive_config.changer.is_some() { - tape.load_media(&changer_id)?; + let mut changer = MtxMediaChanger::with_drive_config(&drive_config)?; + changer.load_media(&changer_id)?; - let mut handle: Box = Box::new(tape.open()?); + let mut handle: Box = Box::new(drive_config.open()?); let media_id = check_label(handle.as_mut(), &label.uuid)?; @@ -319,7 +322,7 @@ pub fn request_and_load_media( let mut last_error = None; loop { - let mut handle = match tape.open() { + let mut handle = match drive_config.open() { Ok(handle) => handle, Err(err) => { let err = err.to_string();