diff --git a/src/api2/config/changer.rs b/src/api2/config/changer.rs index 8404d20b..b099427a 100644 --- a/src/api2/config/changer.rs +++ b/src/api2/config/changer.rs @@ -17,7 +17,6 @@ use crate::{ LINUX_DRIVE_PATH_SCHEMA, SLOT_ARRAY_SCHEMA, EXPORT_SLOT_LIST_SCHEMA, - DriveListEntry, ScsiTapeChanger, LinuxTapeDrive, }, @@ -121,7 +120,7 @@ pub fn get_config( description: "The list of configured changers (with config digest).", type: Array, items: { - type: DriveListEntry, + type: ScsiTapeChanger, }, }, )] @@ -129,27 +128,14 @@ pub fn get_config( pub fn list_changers( _param: Value, mut rpcenv: &mut dyn RpcEnvironment, -) -> Result, Error> { +) -> Result, Error> { let (config, digest) = config::drive::config()?; - let changer_list: Vec = config.convert_to_typed_array("changer")?; - - let mut list = Vec::new(); - - for changer in changer_list { - list.push(DriveListEntry { - name: changer.name, - path: changer.path.clone(), - changer: None, - changer_drivenum: None, - vendor: None, - model: None, - serial: None, - }); - } + let list: Vec = config.convert_to_typed_array("changer")?; rpcenv["digest"] = proxmox::tools::digest_to_hex(&digest).into(); + Ok(list) } #[api()] diff --git a/src/api2/config/drive.rs b/src/api2/config/drive.rs index 8255d445..3e0c7194 100644 --- a/src/api2/config/drive.rs +++ b/src/api2/config/drive.rs @@ -12,7 +12,6 @@ use crate::{ CHANGER_NAME_SCHEMA, CHANGER_DRIVENUM_SCHEMA, LINUX_DRIVE_PATH_SCHEMA, - DriveListEntry, LinuxTapeDrive, ScsiTapeChanger, }, @@ -110,7 +109,7 @@ pub fn get_config( description: "The list of configured drives (with config digest).", type: Array, items: { - type: DriveListEntry, + type: LinuxTapeDrive, }, }, )] @@ -125,6 +124,7 @@ pub fn list_drives( let drive_list: Vec = config.convert_to_typed_array("linux")?; rpcenv["digest"] = proxmox::tools::digest_to_hex(&digest).into(); + Ok(drive_list) } diff --git a/src/api2/tape/changer.rs b/src/api2/tape/changer.rs index 84030f8e..dc98d85b 100644 --- a/src/api2/tape/changer.rs +++ b/src/api2/tape/changer.rs @@ -10,7 +10,7 @@ use crate::{ config, api2::types::{ CHANGER_NAME_SCHEMA, - DriveListEntry, + ChangerListEntry, MtxEntryKind, MtxStatusEntry, ScsiTapeChanger, @@ -25,7 +25,7 @@ use crate::{ ScsiMediaChange, mtx_status_to_online_set, }, - lookup_drive, + lookup_device_identification, }, }; @@ -144,14 +144,14 @@ pub async fn transfer( description: "The list of configured changers with model information.", type: Array, items: { - type: DriveListEntry, + type: ChangerListEntry, }, }, )] /// List changers pub fn list_changers( _param: Value, -) -> Result, Error> { +) -> Result, Error> { let (config, _digest) = config::drive::config()?; @@ -162,21 +162,8 @@ pub fn list_changers( let mut list = Vec::new(); for changer in changer_list { - let mut entry = DriveListEntry { - name: changer.name, - path: changer.path.clone(), - changer: None, - changer_drivenum: None, - vendor: None, - model: None, - serial: None, - }; - if let Some(info) = lookup_drive(&linux_changers, &changer.path) { - entry.vendor = Some(info.vendor.clone()); - entry.model = Some(info.model.clone()); - entry.serial = Some(info.serial.clone()); - } - + let info = lookup_device_identification(&linux_changers, &changer.path); + let entry = ChangerListEntry { config: changer, info }; list.push(entry); } Ok(list) diff --git a/src/api2/tape/drive.rs b/src/api2/tape/drive.rs index 9811762d..494f28aa 100644 --- a/src/api2/tape/drive.rs +++ b/src/api2/tape/drive.rs @@ -49,7 +49,7 @@ use crate::{ MediaCatalog, MediaId, linux_tape_device_list, - lookup_drive, + lookup_device_identification, file_formats::{ MediaLabel, MediaSetLabel, @@ -1133,21 +1133,8 @@ pub fn list_drives( continue; } - let mut entry = DriveListEntry { - name: drive.name, - path: drive.path.clone(), - changer: drive.changer, - changer_drivenum: drive.changer_drivenum, - vendor: None, - model: None, - serial: None, - }; - if let Some(info) = lookup_drive(&linux_drives, &drive.path) { - entry.vendor = Some(info.vendor.clone()); - entry.model = Some(info.model.clone()); - entry.serial = Some(info.serial.clone()); - } - + let info = lookup_device_identification(&linux_drives, &drive.path); + let entry = DriveListEntry { config: drive, info }; list.push(entry); } diff --git a/src/api2/types/tape/changer.rs b/src/api2/types/tape/changer.rs index dccaea6a..f9d30acd 100644 --- a/src/api2/types/tape/changer.rs +++ b/src/api2/types/tape/changer.rs @@ -13,7 +13,10 @@ use proxmox::api::{ }, }; -use crate::api2::types::PROXMOX_SAFE_ID_FORMAT; +use crate::api2::types::{ + PROXMOX_SAFE_ID_FORMAT, + OptionalDeviceIdentification, +}; pub const CHANGER_NAME_SCHEMA: Schema = StringSchema::new("Tape Changer Identifier.") .format(&PROXMOX_SAFE_ID_FORMAT) @@ -69,6 +72,26 @@ pub struct ScsiTapeChanger { pub export_slots: Option, } +#[api( + properties: { + config: { + type: ScsiTapeChanger, + }, + info: { + type: OptionalDeviceIdentification, + }, + }, +)] +#[derive(Serialize,Deserialize)] +#[serde(rename_all = "kebab-case")] +/// Changer config with optional device identification attributes +pub struct ChangerListEntry { + #[serde(flatten)] + pub config: ScsiTapeChanger, + #[serde(flatten)] + pub info: OptionalDeviceIdentification, +} + #[api()] #[derive(Serialize,Deserialize)] #[serde(rename_all = "kebab-case")] diff --git a/src/api2/types/tape/device.rs b/src/api2/types/tape/device.rs index 11495b88..811cd36f 100644 --- a/src/api2/types/tape/device.rs +++ b/src/api2/types/tape/device.rs @@ -2,6 +2,22 @@ use ::serde::{Deserialize, Serialize}; use proxmox::api::api; +#[api()] +#[derive(Serialize,Deserialize)] +#[serde(rename_all = "kebab-case")] +/// Optional Device Identification Attributes +pub struct OptionalDeviceIdentification { + /// Vendor (autodetected) + #[serde(skip_serializing_if="Option::is_none")] + pub vendor: Option, + /// Model (autodetected) + #[serde(skip_serializing_if="Option::is_none")] + pub model: Option, + /// Serial number (autodetected) + #[serde(skip_serializing_if="Option::is_none")] + pub serial: Option, +} + #[api()] #[derive(Debug,Serialize,Deserialize)] #[serde(rename_all = "kebab-case")] diff --git a/src/api2/types/tape/drive.rs b/src/api2/types/tape/drive.rs index 9d9b0591..19eb57fb 100644 --- a/src/api2/types/tape/drive.rs +++ b/src/api2/types/tape/drive.rs @@ -12,6 +12,7 @@ use proxmox::api::{ use crate::api2::types::{ PROXMOX_SAFE_ID_FORMAT, CHANGER_NAME_SCHEMA, + OptionalDeviceIdentification, }; pub const DRIVE_NAME_SCHEMA: Schema = StringSchema::new("Drive Identifier.") @@ -80,30 +81,24 @@ pub struct LinuxTapeDrive { pub changer_drivenum: Option, } -#[api()] +#[api( + properties: { + config: { + type: LinuxTapeDrive, + }, + info: { + type: OptionalDeviceIdentification, + }, + }, +)] #[derive(Serialize,Deserialize)] #[serde(rename_all = "kebab-case")] /// Drive list entry pub struct DriveListEntry { - /// Drive name - pub name: String, - /// Path to the linux device node - pub path: String, - /// Associated changer device - #[serde(skip_serializing_if="Option::is_none")] - pub changer: Option, - /// Drive number in associated changer device - #[serde(skip_serializing_if="Option::is_none")] - pub changer_drivenum: Option, - /// Vendor (autodetected) - #[serde(skip_serializing_if="Option::is_none")] - pub vendor: Option, - /// Model (autodetected) - #[serde(skip_serializing_if="Option::is_none")] - pub model: Option, - /// Serial number (autodetected) - #[serde(skip_serializing_if="Option::is_none")] - pub serial: Option, + #[serde(flatten)] + pub config: LinuxTapeDrive, + #[serde(flatten)] + pub info: OptionalDeviceIdentification, } #[api()] diff --git a/src/tape/linux_list_drives.rs b/src/tape/linux_list_drives.rs index e3ab9524..dacbda2c 100644 --- a/src/tape/linux_list_drives.rs +++ b/src/tape/linux_list_drives.rs @@ -6,6 +6,7 @@ use anyhow::{bail, Error}; use crate::{ api2::types::{ DeviceKind, + OptionalDeviceIdentification, TapeDeviceInfo, }, tools::fs::scan_subdir, @@ -191,9 +192,9 @@ pub fn linux_tape_device_list() -> Vec { list } -/// Test if path is a linux tape device -pub fn lookup_drive<'a>( - drives: &'a[TapeDeviceInfo], +/// Test if a device exists, and returns associated `TapeDeviceInfo` +pub fn lookup_device<'a>( + devices: &'a[TapeDeviceInfo], path: &str, ) -> Option<&'a TapeDeviceInfo> { @@ -202,18 +203,39 @@ pub fn lookup_drive<'a>( let major = unsafe { libc::major(stat.st_rdev) }; let minor = unsafe { libc::minor(stat.st_rdev) }; - drives.iter().find(|d| d.major == major && d.minor == minor) + devices.iter().find(|d| d.major == major && d.minor == minor) } else { None } } +/// Lookup optional drive identification attributes +pub fn lookup_device_identification<'a>( + devices: &'a[TapeDeviceInfo], + path: &str, +) -> OptionalDeviceIdentification { + + if let Some(info) = lookup_device(devices, path) { + OptionalDeviceIdentification { + vendor: Some(info.vendor.clone()), + model: Some(info.model.clone()), + serial: Some(info.serial.clone()), + } + } else { + OptionalDeviceIdentification { + vendor: None, + model: None, + serial: None, + } + } +} + /// Make sure path is a linux tape device pub fn check_drive_path( drives: &[TapeDeviceInfo], path: &str, ) -> Result<(), Error> { - if lookup_drive(drives, path).is_none() { + if lookup_device(drives, path).is_none() { bail!("path '{}' is not a linux (non-rewinding) tape device", path); } Ok(())