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_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?
}

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> {
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> {
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<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 {
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(())
}

View File

@ -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<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)?;
@ -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();