tape: API type cleanup, use serde flatten to derive types

This commit is contained in:
Dietmar Maurer 2021-01-30 09:36:54 +01:00
parent 9586ce2f46
commit b5b99a52cd
8 changed files with 97 additions and 81 deletions

View File

@ -17,7 +17,6 @@ use crate::{
LINUX_DRIVE_PATH_SCHEMA, LINUX_DRIVE_PATH_SCHEMA,
SLOT_ARRAY_SCHEMA, SLOT_ARRAY_SCHEMA,
EXPORT_SLOT_LIST_SCHEMA, EXPORT_SLOT_LIST_SCHEMA,
DriveListEntry,
ScsiTapeChanger, ScsiTapeChanger,
LinuxTapeDrive, LinuxTapeDrive,
}, },
@ -121,7 +120,7 @@ pub fn get_config(
description: "The list of configured changers (with config digest).", description: "The list of configured changers (with config digest).",
type: Array, type: Array,
items: { items: {
type: DriveListEntry, type: ScsiTapeChanger,
}, },
}, },
)] )]
@ -129,27 +128,14 @@ pub fn get_config(
pub fn list_changers( pub fn list_changers(
_param: Value, _param: Value,
mut rpcenv: &mut dyn RpcEnvironment, mut rpcenv: &mut dyn RpcEnvironment,
) -> Result<Vec<DriveListEntry>, Error> { ) -> Result<Vec<ScsiTapeChanger>, Error> {
let (config, digest) = config::drive::config()?; let (config, digest) = config::drive::config()?;
let changer_list: Vec<ScsiTapeChanger> = config.convert_to_typed_array("changer")?; let list: Vec<ScsiTapeChanger> = 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,
});
}
rpcenv["digest"] = proxmox::tools::digest_to_hex(&digest).into(); rpcenv["digest"] = proxmox::tools::digest_to_hex(&digest).into();
Ok(list) Ok(list)
} }
#[api()] #[api()]

View File

@ -12,7 +12,6 @@ use crate::{
CHANGER_NAME_SCHEMA, CHANGER_NAME_SCHEMA,
CHANGER_DRIVENUM_SCHEMA, CHANGER_DRIVENUM_SCHEMA,
LINUX_DRIVE_PATH_SCHEMA, LINUX_DRIVE_PATH_SCHEMA,
DriveListEntry,
LinuxTapeDrive, LinuxTapeDrive,
ScsiTapeChanger, ScsiTapeChanger,
}, },
@ -110,7 +109,7 @@ pub fn get_config(
description: "The list of configured drives (with config digest).", description: "The list of configured drives (with config digest).",
type: Array, type: Array,
items: { items: {
type: DriveListEntry, type: LinuxTapeDrive,
}, },
}, },
)] )]
@ -125,6 +124,7 @@ pub fn list_drives(
let drive_list: Vec<LinuxTapeDrive> = config.convert_to_typed_array("linux")?; let drive_list: Vec<LinuxTapeDrive> = config.convert_to_typed_array("linux")?;
rpcenv["digest"] = proxmox::tools::digest_to_hex(&digest).into(); rpcenv["digest"] = proxmox::tools::digest_to_hex(&digest).into();
Ok(drive_list) Ok(drive_list)
} }

View File

@ -10,7 +10,7 @@ use crate::{
config, config,
api2::types::{ api2::types::{
CHANGER_NAME_SCHEMA, CHANGER_NAME_SCHEMA,
DriveListEntry, ChangerListEntry,
MtxEntryKind, MtxEntryKind,
MtxStatusEntry, MtxStatusEntry,
ScsiTapeChanger, ScsiTapeChanger,
@ -25,7 +25,7 @@ use crate::{
ScsiMediaChange, ScsiMediaChange,
mtx_status_to_online_set, 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.", description: "The list of configured changers with model information.",
type: Array, type: Array,
items: { items: {
type: DriveListEntry, type: ChangerListEntry,
}, },
}, },
)] )]
/// List changers /// List changers
pub fn list_changers( pub fn list_changers(
_param: Value, _param: Value,
) -> Result<Vec<DriveListEntry>, Error> { ) -> Result<Vec<ChangerListEntry>, Error> {
let (config, _digest) = config::drive::config()?; let (config, _digest) = config::drive::config()?;
@ -162,21 +162,8 @@ pub fn list_changers(
let mut list = Vec::new(); let mut list = Vec::new();
for changer in changer_list { for changer in changer_list {
let mut entry = DriveListEntry { let info = lookup_device_identification(&linux_changers, &changer.path);
name: changer.name, let entry = ChangerListEntry { config: changer, info };
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());
}
list.push(entry); list.push(entry);
} }
Ok(list) Ok(list)

View File

@ -49,7 +49,7 @@ use crate::{
MediaCatalog, MediaCatalog,
MediaId, MediaId,
linux_tape_device_list, linux_tape_device_list,
lookup_drive, lookup_device_identification,
file_formats::{ file_formats::{
MediaLabel, MediaLabel,
MediaSetLabel, MediaSetLabel,
@ -1133,21 +1133,8 @@ pub fn list_drives(
continue; continue;
} }
let mut entry = DriveListEntry { let info = lookup_device_identification(&linux_drives, &drive.path);
name: drive.name, let entry = DriveListEntry { config: drive, info };
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());
}
list.push(entry); list.push(entry);
} }

View File

@ -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.") pub const CHANGER_NAME_SCHEMA: Schema = StringSchema::new("Tape Changer Identifier.")
.format(&PROXMOX_SAFE_ID_FORMAT) .format(&PROXMOX_SAFE_ID_FORMAT)
@ -69,6 +72,26 @@ pub struct ScsiTapeChanger {
pub export_slots: Option<String>, pub export_slots: Option<String>,
} }
#[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()] #[api()]
#[derive(Serialize,Deserialize)] #[derive(Serialize,Deserialize)]
#[serde(rename_all = "kebab-case")] #[serde(rename_all = "kebab-case")]

View File

@ -2,6 +2,22 @@ use ::serde::{Deserialize, Serialize};
use proxmox::api::api; 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<String>,
/// Model (autodetected)
#[serde(skip_serializing_if="Option::is_none")]
pub model: Option<String>,
/// Serial number (autodetected)
#[serde(skip_serializing_if="Option::is_none")]
pub serial: Option<String>,
}
#[api()] #[api()]
#[derive(Debug,Serialize,Deserialize)] #[derive(Debug,Serialize,Deserialize)]
#[serde(rename_all = "kebab-case")] #[serde(rename_all = "kebab-case")]

View File

@ -12,6 +12,7 @@ use proxmox::api::{
use crate::api2::types::{ use crate::api2::types::{
PROXMOX_SAFE_ID_FORMAT, PROXMOX_SAFE_ID_FORMAT,
CHANGER_NAME_SCHEMA, CHANGER_NAME_SCHEMA,
OptionalDeviceIdentification,
}; };
pub const DRIVE_NAME_SCHEMA: Schema = StringSchema::new("Drive Identifier.") pub const DRIVE_NAME_SCHEMA: Schema = StringSchema::new("Drive Identifier.")
@ -80,30 +81,24 @@ pub struct LinuxTapeDrive {
pub changer_drivenum: Option<u64>, pub changer_drivenum: Option<u64>,
} }
#[api()] #[api(
properties: {
config: {
type: LinuxTapeDrive,
},
info: {
type: OptionalDeviceIdentification,
},
},
)]
#[derive(Serialize,Deserialize)] #[derive(Serialize,Deserialize)]
#[serde(rename_all = "kebab-case")] #[serde(rename_all = "kebab-case")]
/// Drive list entry /// Drive list entry
pub struct DriveListEntry { pub struct DriveListEntry {
/// Drive name #[serde(flatten)]
pub name: String, pub config: LinuxTapeDrive,
/// Path to the linux device node #[serde(flatten)]
pub path: String, pub info: OptionalDeviceIdentification,
/// Associated changer device
#[serde(skip_serializing_if="Option::is_none")]
pub changer: Option<String>,
/// Drive number in associated changer device
#[serde(skip_serializing_if="Option::is_none")]
pub changer_drivenum: Option<u64>,
/// Vendor (autodetected)
#[serde(skip_serializing_if="Option::is_none")]
pub vendor: Option<String>,
/// Model (autodetected)
#[serde(skip_serializing_if="Option::is_none")]
pub model: Option<String>,
/// Serial number (autodetected)
#[serde(skip_serializing_if="Option::is_none")]
pub serial: Option<String>,
} }
#[api()] #[api()]

View File

@ -6,6 +6,7 @@ use anyhow::{bail, Error};
use crate::{ use crate::{
api2::types::{ api2::types::{
DeviceKind, DeviceKind,
OptionalDeviceIdentification,
TapeDeviceInfo, TapeDeviceInfo,
}, },
tools::fs::scan_subdir, tools::fs::scan_subdir,
@ -191,9 +192,9 @@ pub fn linux_tape_device_list() -> Vec<TapeDeviceInfo> {
list list
} }
/// Test if path is a linux tape device /// Test if a device exists, and returns associated `TapeDeviceInfo`
pub fn lookup_drive<'a>( pub fn lookup_device<'a>(
drives: &'a[TapeDeviceInfo], devices: &'a[TapeDeviceInfo],
path: &str, path: &str,
) -> Option<&'a TapeDeviceInfo> { ) -> Option<&'a TapeDeviceInfo> {
@ -202,18 +203,39 @@ pub fn lookup_drive<'a>(
let major = unsafe { libc::major(stat.st_rdev) }; let major = unsafe { libc::major(stat.st_rdev) };
let minor = unsafe { libc::minor(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 { } else {
None 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 /// Make sure path is a linux tape device
pub fn check_drive_path( pub fn check_drive_path(
drives: &[TapeDeviceInfo], drives: &[TapeDeviceInfo],
path: &str, path: &str,
) -> Result<(), Error> { ) -> 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); bail!("path '{}' is not a linux (non-rewinding) tape device", path);
} }
Ok(()) Ok(())