tape: simplify media changer implementation - new struct MtxMediaChanger
This commit is contained in:
parent
42967bf185
commit
6fe16039b9
@ -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?
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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(())
|
||||||
}
|
}
|
||||||
|
@ -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();
|
||||||
|
Loading…
Reference in New Issue
Block a user