tape: simplify media changer implementation - new struct MtxMediaChanger

This commit is contained in:
Dietmar Maurer 2021-01-10 10:02:01 +01:00
parent 42967bf185
commit 6fe16039b9
3 changed files with 56 additions and 74 deletions

View File

@ -44,7 +44,6 @@ use crate::{
tape::{ tape::{
TAPE_STATUS_DIR, TAPE_STATUS_DIR,
TapeDriver, TapeDriver,
MediaChange,
MediaPool, MediaPool,
Inventory, Inventory,
MediaCatalog, MediaCatalog,
@ -138,10 +137,9 @@ pub async fn unload(
let (config, _digest) = config::drive::config()?; let (config, _digest) = config::drive::config()?;
let mut drive_config: LinuxTapeDrive = config.lookup("linux", &drive)?;
tokio::task::spawn_blocking(move || { 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? }).await?
} }

View File

@ -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<Self, Error> {
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> { fn unload_to_free_slot(drive_name: &str, path: &str, status: &MtxStatus, drivenum: u64) -> Result<(), Error> {
if drivenum >= status.drives.len() as u64 { 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<MtxStatus, Error> { fn status(&mut self) -> Result<MtxStatus, Error> {
let (config, _digest) = crate::config::drive::config()?; mtx_status(&self.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)
} }
fn load_media_from_slot(&mut self, slot: u64) -> Result<(), Error> { fn load_media_from_slot(&mut self, slot: u64) -> Result<(), Error> {
let (config, _digest) = crate::config::drive::config()?; mtx_load(&self.config.path, slot, self.drivenum)
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)
} }
fn load_media(&mut self, changer_id: &str) -> Result<(), Error> { 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); 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 { // already loaded?
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?
for (i, drive_status) in status.drives.iter().enumerate() { for (i, drive_status) in status.drives.iter().enumerate() {
if let ElementStatus::VolumeTag(ref tag) = drive_status.status { if let ElementStatus::VolumeTag(ref tag) = drive_status.status {
if *tag == changer_id { if *tag == changer_id {
if i as u64 != drivenum { if i as u64 != self.drivenum {
bail!("unable to load media '{}' - media in wrong drive ({} != {})", bail!("unable to load media '{}' - media in wrong drive ({} != {})",
changer_id, i, drivenum); changer_id, i, self.drivenum);
} }
return Ok(()) return Ok(())
} }
} }
if i as u64 == drivenum { if i as u64 == self.drivenum {
match drive_status.status { match drive_status.status {
ElementStatus::Empty => { /* OK */ }, 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, 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<u64>) -> Result<(), Error> { fn unload_media(&mut self, target_slot: Option<u64>) -> 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 { if let Some(target_slot) = target_slot {
mtx_unload(&changer.path, target_slot, drivenum) mtx_unload(&self.config.path, target_slot, self.drivenum)
} else { } else {
let status = mtx_status(&changer)?; let status = self.status()?;
unload_to_free_slot(&self.name, &changer.path, &status, drivenum) 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> { fn clean_drive(&mut self) -> Result<(), Error> {
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!("unable to load cleaning cartridge - no associated changer device"),
};
let drivenum = self.changer_drive_id.unwrap_or(0);
let status = mtx_status(&changer)?;
let mut cleaning_cartridge_slot = None; let mut cleaning_cartridge_slot = None;
@ -175,16 +156,16 @@ impl MediaChange for LinuxTapeDrive {
Some(cleaning_cartridge_slot) => cleaning_cartridge_slot as u64, 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 { match drive_status.status {
ElementStatus::Empty => { /* OK */ }, 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(()) Ok(())
} }

View File

@ -31,6 +31,7 @@ use crate::{
TapeWrite, TapeWrite,
TapeRead, TapeRead,
MediaId, MediaId,
MtxMediaChanger,
file_formats::{ file_formats::{
PROXMOX_BACKUP_MEDIA_LABEL_MAGIC_1_0, PROXMOX_BACKUP_MEDIA_LABEL_MAGIC_1_0,
PROXMOX_BACKUP_MEDIA_SET_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()))) Ok(Some((Box::new(tape), drive.to_string())))
} }
"linux" => { "linux" => {
let tape = LinuxTapeDrive::deserialize(config)?; let drive_config = LinuxTapeDrive::deserialize(config)?;
match tape.changer { match drive_config.changer {
Some(ref changer_name) => { Some(ref changer_name) => {
let changer = MtxMediaChanger::with_drive_config(&drive_config)?;
let changer_name = changer_name.to_string(); let changer_name = changer_name.to_string();
Ok(Some((Box::new(tape), changer_name))) Ok(Some((Box::new(changer), changer_name)))
} }
None => Ok(None), None => Ok(None),
} }
@ -294,15 +296,16 @@ pub fn request_and_load_media(
return Ok((handle, media_id)); return Ok((handle, media_id));
} }
"linux" => { "linux" => {
let mut tape = LinuxTapeDrive::deserialize(config)?; let drive_config = LinuxTapeDrive::deserialize(config)?;
let changer_id = label.changer_id.clone(); 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<dyn TapeDriver> = Box::new(tape.open()?); let mut handle: Box<dyn TapeDriver> = Box::new(drive_config.open()?);
let media_id = check_label(handle.as_mut(), &label.uuid)?; 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; let mut last_error = None;
loop { loop {
let mut handle = match tape.open() { let mut handle = match drive_config.open() {
Ok(handle) => handle, Ok(handle) => handle,
Err(err) => { Err(err) => {
let err = err.to_string(); let err = err.to_string();