From f70d8091d31cf77fd11f8cff7e99377e38077b91 Mon Sep 17 00:00:00 2001 From: Dietmar Maurer Date: Thu, 10 Dec 2020 09:09:06 +0100 Subject: [PATCH] tape: implement option changer-drive-id --- src/api2/config/drive.rs | 30 +++++++++++++++++++++++++++++- src/api2/tape/drive.rs | 12 ++++++------ src/api2/types/tape/drive.rs | 19 ++++++++++++++++--- src/bin/proxmox_tape/drive.rs | 1 + src/tape/changer/linux_tape.rs | 8 ++++---- 5 files changed, 56 insertions(+), 14 deletions(-) diff --git a/src/api2/config/drive.rs b/src/api2/config/drive.rs index 0403f791..a99d94cb 100644 --- a/src/api2/config/drive.rs +++ b/src/api2/config/drive.rs @@ -10,6 +10,7 @@ use crate::{ PROXMOX_CONFIG_DIGEST_SCHEMA, DRIVE_ID_SCHEMA, CHANGER_ID_SCHEMA, + CHANGER_DRIVE_ID_SCHEMA, LINUX_DRIVE_PATH_SCHEMA, DriveListEntry, LinuxTapeDrive, @@ -36,6 +37,10 @@ use crate::{ schema: CHANGER_ID_SCHEMA, optional: true, }, + "changer-drive-id": { + schema: CHANGER_DRIVE_ID_SCHEMA, + optional: true, + }, }, }, )] @@ -142,10 +147,13 @@ pub fn list_drives( #[api()] #[derive(Serialize, Deserialize)] #[allow(non_camel_case_types)] +#[serde(rename_all = "kebab-case")] /// Deletable property name pub enum DeletableProperty { /// Delete the changer property. changer, + /// Delete the changer-drive-id property. + changer_drive_id, } #[api( @@ -163,6 +171,10 @@ pub enum DeletableProperty { schema: CHANGER_ID_SCHEMA, optional: true, }, + "changer-drive-id": { + schema: CHANGER_DRIVE_ID_SCHEMA, + optional: true, + }, delete: { description: "List of properties to delete.", type: Array, @@ -183,6 +195,7 @@ pub fn update_drive( name: String, path: Option, changer: Option, + changer_drive_id: Option, delete: Option>, digest: Option, _param: Value, @@ -202,7 +215,11 @@ pub fn update_drive( if let Some(delete) = delete { for delete_prop in delete { match delete_prop { - DeletableProperty::changer => { data.changer = None; }, + DeletableProperty::changer => { + data.changer = None; + data.changer_drive_id = None; + }, + DeletableProperty::changer_drive_id => { data.changer_drive_id = None; }, } } } @@ -218,6 +235,17 @@ pub fn update_drive( data.changer = Some(changer); } + if let Some(changer_drive_id) = changer_drive_id { + if changer_drive_id == 0 { + data.changer_drive_id = None; + } else { + if data.changer.is_none() { + bail!("Option 'changer-drive-id' requires option 'changer'."); + } + data.changer_drive_id = Some(changer_drive_id); + } + } + config.set_data(&name, "linux", &data)?; config::drive::save_config(&config)?; diff --git a/src/api2/tape/drive.rs b/src/api2/tape/drive.rs index ef3e3c35..81e234b4 100644 --- a/src/api2/tape/drive.rs +++ b/src/api2/tape/drive.rs @@ -52,7 +52,7 @@ pub fn load_slot( None => bail!("drive '{}' has no associated changer", drive), }; - let drivenum = 0; + let drivenum = drive_config.changer_drive_id.unwrap_or(0); mtx_load(&changer.path, slot, drivenum) } @@ -217,11 +217,6 @@ pub fn eject_media(drive: String) -> Result<(), Error> { } pub const SUBDIRS: SubdirMap = &[ - ( - "rewind", - &Router::new() - .put(&API_METHOD_REWIND) - ), ( "erase-media", &Router::new() @@ -237,6 +232,11 @@ pub const SUBDIRS: SubdirMap = &[ &Router::new() .put(&API_METHOD_LOAD_SLOT) ), + ( + "rewind", + &Router::new() + .put(&API_METHOD_REWIND) + ), ( "scan", &Router::new() diff --git a/src/api2/types/tape/drive.rs b/src/api2/types/tape/drive.rs index de046fbe..11fa9914 100644 --- a/src/api2/types/tape/drive.rs +++ b/src/api2/types/tape/drive.rs @@ -4,7 +4,7 @@ use serde::{Deserialize, Serialize}; use proxmox::api::{ api, - schema::{Schema, StringSchema}, + schema::{Schema, IntegerSchema, StringSchema}, }; use crate::api2::types::PROXMOX_SAFE_ID_FORMAT; @@ -35,6 +35,13 @@ pub const MEDIA_LABEL_SCHEMA: Schema = StringSchema::new("Media Label/Barcode.") .max_length(32) .schema(); +pub const CHANGER_DRIVE_ID_SCHEMA: Schema = IntegerSchema::new( + "Associated changer drive number (requires option changer)") + .minimum(0) + .maximum(8) + .default(0) + .schema(); + #[api( properties: { name: { @@ -65,17 +72,23 @@ pub struct VirtualTapeDrive { changer: { schema: CHANGER_ID_SCHEMA, optional: true, - } + }, + "changer-drive-id": { + schema: CHANGER_DRIVE_ID_SCHEMA, + optional: true, + }, } )] #[derive(Serialize,Deserialize)] +#[serde(rename_all = "kebab-case")] /// Linux SCSI tape driver pub struct LinuxTapeDrive { pub name: String, pub path: String, - /// Associated changer device #[serde(skip_serializing_if="Option::is_none")] pub changer: Option, + #[serde(skip_serializing_if="Option::is_none")] + pub changer_drive_id: Option, } #[api( diff --git a/src/bin/proxmox_tape/drive.rs b/src/bin/proxmox_tape/drive.rs index 8442c35d..6a181641 100644 --- a/src/bin/proxmox_tape/drive.rs +++ b/src/bin/proxmox_tape/drive.rs @@ -179,6 +179,7 @@ fn get_config( .column(ColumnConfig::new("name")) .column(ColumnConfig::new("path")) .column(ColumnConfig::new("changer")) + .column(ColumnConfig::new("changer-drive-id")) ; format_and_print_result_full(&mut data, info.returns, &output_format, &options); diff --git a/src/tape/changer/linux_tape.rs b/src/tape/changer/linux_tape.rs index e2a4a404..56983984 100644 --- a/src/tape/changer/linux_tape.rs +++ b/src/tape/changer/linux_tape.rs @@ -57,20 +57,20 @@ impl MediaChange for LinuxTapeDrive { let status = mtx_status(&changer.path)?; - let drivenum = 0; // fixme: read from drive config + let drivenum = self.changer_drive_id.unwrap_or(0); // 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 != drivenum { + if i as u64 != drivenum { bail!("unable to load media '{}' - media in wrong drive ({} != {})", changer_id, i, drivenum); } return Ok(()) } } - if i == drivenum { + if i as u64 == drivenum { match drive_status.status { ElementStatus::Empty => { /* OK */ }, _ => unload_to_free_slot(&self.name, &changer.path, &status, drivenum as u64)?, @@ -105,7 +105,7 @@ impl MediaChange for LinuxTapeDrive { None => return Ok(()), }; - let drivenum: u64 = 0; + let drivenum = self.changer_drive_id.unwrap_or(0); let status = mtx_status(&changer.path)?;