tape: correctly parse mtx import/export slots

This commit is contained in:
Dietmar Maurer 2020-12-28 13:32:56 +01:00
parent df3a74d7e0
commit e0362b0d0f
6 changed files with 29 additions and 13 deletions

View File

@ -82,9 +82,13 @@ pub async fn get_status(name: String) -> Result<Vec<MtxStatusEntry>, Error> {
list.push(entry); list.push(entry);
} }
for (id, slot_status) in status.slots.iter().enumerate() { for (id, (import_export, slot_status)) in status.slots.iter().enumerate() {
let entry = MtxStatusEntry { let entry = MtxStatusEntry {
entry_kind: MtxEntryKind::Slot, entry_kind: if *import_export {
MtxEntryKind::ImportExport
} else {
MtxEntryKind::Slot
},
entry_id: id as u64 + 1, entry_id: id as u64 + 1,
changer_id: match &slot_status { changer_id: match &slot_status {
ElementStatus::Empty => None, ElementStatus::Empty => None,

View File

@ -44,13 +44,15 @@ pub struct ScsiTapeChanger {
#[api()] #[api()]
#[derive(Serialize,Deserialize)] #[derive(Serialize,Deserialize)]
#[serde(rename_all = "lowercase")] #[serde(rename_all = "kebab-case")]
/// Mtx Entry Kind /// Mtx Entry Kind
pub enum MtxEntryKind { pub enum MtxEntryKind {
/// Drive /// Drive
Drive, Drive,
/// Slot /// Slot
Slot, Slot,
/// Import/Export Slot
ImportExport,
} }
#[api( #[api(

View File

@ -207,6 +207,8 @@ async fn get_status(
}; };
let options = default_table_format_options() let options = default_table_format_options()
.sortby("entry-kind", false)
.sortby("entry-id", false)
.column(ColumnConfig::new("entry-kind")) .column(ColumnConfig::new("entry-kind"))
.column(ColumnConfig::new("entry-id")) .column(ColumnConfig::new("entry-id"))
.column(ColumnConfig::new("changer-id")) .column(ColumnConfig::new("changer-id"))

View File

@ -27,7 +27,8 @@ fn unload_to_free_slot(drive_name: &str, path: &str, status: &MtxStatus, drivenu
} else { } else {
let mut free_slot = None; let mut free_slot = None;
for i in 0..status.slots.len() { for i in 0..status.slots.len() {
if let ElementStatus::Empty = status.slots[i] { if status.slots[i].0 { continue; } // skip import/export slots
if let ElementStatus::Empty = status.slots[i].1 {
free_slot = Some((i+1) as u64); free_slot = Some((i+1) as u64);
break; break;
} }
@ -79,9 +80,12 @@ impl MediaChange for LinuxTapeDrive {
} }
let mut slot = None; let mut slot = None;
for (i, element_status) in status.slots.iter().enumerate() { for (i, (import_export, element_status)) in status.slots.iter().enumerate() {
if let ElementStatus::VolumeTag(tag) = element_status { if let ElementStatus::VolumeTag(tag) = element_status {
if *tag == changer_id { if *tag == changer_id {
if *import_export {
bail!("unable to load media '{}' - inside import/export slot", changer_id);
}
slot = Some(i+1); slot = Some(i+1);
break; break;
} }
@ -134,7 +138,8 @@ impl MediaChange for LinuxTapeDrive {
} }
} }
for element_status in status.slots.iter() { for (import_export, element_status) in status.slots.iter() {
if *import_export { continue; }
if let ElementStatus::VolumeTag(ref tag) = element_status { if let ElementStatus::VolumeTag(ref tag) = element_status {
list.push(tag.clone()); list.push(tag.clone());
} }

View File

@ -87,7 +87,8 @@ pub fn mtx_status_to_online_set(status: &MtxStatus, inventory: &Inventory) -> Ha
} }
} }
for slot_status in status.slots.iter() { for (import_export, slot_status) in status.slots.iter() {
if *import_export { continue; }
if let ElementStatus::VolumeTag(ref changer_id) = slot_status { if let ElementStatus::VolumeTag(ref changer_id) = slot_status {
if let Some(media_id) = inventory.find_media_by_changer_id(changer_id) { if let Some(media_id) = inventory.find_media_by_changer_id(changer_id) {
online_set.insert(media_id.label.uuid.clone()); online_set.insert(media_id.label.uuid.clone());

View File

@ -31,8 +31,8 @@ pub struct DriveStatus {
pub struct MtxStatus { pub struct MtxStatus {
/// List of known drives /// List of known drives
pub drives: Vec<DriveStatus>, pub drives: Vec<DriveStatus>,
/// List of known slots /// List of known slots, the boolean attribute marks import/export slots
pub slots: Vec<ElementStatus>, pub slots: Vec<(bool, ElementStatus)>,
} }
// Recognizes one line // Recognizes one line
@ -122,17 +122,19 @@ fn parse_data_transfer_element(i: &str) -> IResult<&str, (u64, DriveStatus)> {
Ok((i, (id, element_status))) Ok((i, (id, element_status)))
} }
fn parse_storage_element(i: &str) -> IResult<&str, (u64, ElementStatus)> { fn parse_storage_element(i: &str) -> IResult<&str, (u64, bool, ElementStatus)> {
let (i, _) = multispace1(i)?; let (i, _) = multispace1(i)?;
let (i, _) = tag("Storage Element")(i)?; let (i, _) = tag("Storage Element")(i)?;
let (i, _) = multispace1(i)?; let (i, _) = multispace1(i)?;
let (i, id) = parse_u64(i)?; let (i, id) = parse_u64(i)?;
let (i, opt_ie) = nom::combinator::opt(tag(" IMPORT/EXPORT"))(i)?;
let import_export = opt_ie.is_some();
let (i, _) = nom::character::complete::char(':')(i)?; let (i, _) = nom::character::complete::char(':')(i)?;
let (i, element_status) = parse_slot_status(i)?; let (i, element_status) = parse_slot_status(i)?;
let (i, _) = nom::character::complete::newline(i)?; let (i, _) = nom::character::complete::newline(i)?;
Ok((i, (id, element_status))) Ok((i, (id, import_export, element_status)))
} }
fn parse_status(i: &str) -> IResult<&str, MtxStatus> { fn parse_status(i: &str) -> IResult<&str, MtxStatus> {
@ -149,12 +151,12 @@ fn parse_status(i: &str) -> IResult<&str, MtxStatus> {
} }
let mut slots = Vec::new(); let mut slots = Vec::new();
while let Ok((n, (id, element_status))) = parse_storage_element(i) { while let Ok((n, (id, import_export, element_status))) = parse_storage_element(i) {
if id != (slots.len() as u64 + 1) { if id != (slots.len() as u64 + 1) {
return Err(parse_failure(i, "unexpected slot number")); return Err(parse_failure(i, "unexpected slot number"));
} }
i = n; i = n;
slots.push(element_status); slots.push((import_export, element_status));
} }
let status = MtxStatus { drives, slots }; let status = MtxStatus { drives, slots };