tape: return media usage info with status command

This commit is contained in:
Dietmar Maurer 2020-12-23 11:24:34 +01:00
parent dbe7e556b0
commit 5ae86dfaa1
5 changed files with 78 additions and 22 deletions

View File

@ -35,7 +35,7 @@ use crate::{
MediaIdFlat, MediaIdFlat,
LabelUuidMap, LabelUuidMap,
MamAttribute, MamAttribute,
LinuxDriveStatusFlat, LinuxDriveAndMediaStatus,
}, },
server::WorkerTask, server::WorkerTask,
tape::{ tape::{
@ -51,6 +51,7 @@ use crate::{
open_drive, open_drive,
media_changer, media_changer,
update_changer_online_status, update_changer_online_status,
mam_extract_media_usage,
file_formats::{ file_formats::{
MediaLabel, MediaLabel,
MediaSetLabel, MediaSetLabel,
@ -807,22 +808,37 @@ pub fn cartridge_memory(drive: String) -> Result<Vec<MamAttribute>, Error> {
}, },
}, },
returns: { returns: {
type: LinuxDriveStatusFlat, type: LinuxDriveAndMediaStatus,
}, },
)] )]
/// Get drive status /// Get drive/media status
pub fn status(drive: String) -> Result<LinuxDriveStatusFlat, Error> { pub fn status(drive: String) -> Result<LinuxDriveAndMediaStatus, Error> {
let (config, _digest) = config::drive::config()?; let (config, _digest) = config::drive::config()?;
let drive_config: LinuxTapeDrive = config.lookup("linux", &drive)?; let drive_config: LinuxTapeDrive = config.lookup("linux", &drive)?;
let handle = drive_config.open() let mut handle = drive_config.open()
.map_err(|err| format_err!("open drive '{}' ({}) failed - {}", drive, drive_config.path, err))?; .map_err(|err| format_err!("open drive '{}' ({}) failed - {}", drive, drive_config.path, err))?;
let drive_status = handle.get_drive_status()?; let drive_status = handle.get_drive_status()?;
Ok(drive_status.into()) let mam = handle.cartridge_memory()?;
let usage = mam_extract_media_usage(&mam)?;
let status = LinuxDriveAndMediaStatus {
blocksize: drive_status.blocksize,
density: drive_status.density,
status: format!("{:?}", drive_status.status),
file_number: drive_status.file_number,
block_number: drive_status.block_number,
manufactured: usage.manufactured,
bytes_read: usage.bytes_read,
bytes_written: usage.bytes_written,
};
Ok(status)
} }
#[sortable] #[sortable]

View File

@ -166,8 +166,8 @@ impl TryFrom<u8> for TapeDensity {
)] )]
#[derive(Serialize,Deserialize)] #[derive(Serialize,Deserialize)]
#[serde(rename_all = "kebab-case")] #[serde(rename_all = "kebab-case")]
/// Drive status for Linux SCSI drives. /// Drive/Media status for Linux SCSI drives.
pub struct LinuxDriveStatusFlat { pub struct LinuxDriveAndMediaStatus {
/// Block size (0 is variable size) /// Block size (0 is variable size)
pub blocksize: u32, pub blocksize: u32,
/// Tape density /// Tape density
@ -178,4 +178,10 @@ pub struct LinuxDriveStatusFlat {
pub file_number: i32, pub file_number: i32,
/// Current block number /// Current block number
pub block_number: i32, pub block_number: i32,
/// Medium Manufacture Date (epoch)
pub manufactured: i64,
/// Total Bytes Read in Medium Life
pub bytes_read: u64,
/// Total Bytes Written in Medium Life
pub bytes_written: u64,
} }

View File

@ -19,6 +19,7 @@ use proxmox_backup::{
tools::format::{ tools::format::{
HumanByte, HumanByte,
render_epoch, render_epoch,
render_bytes_human_readable,
}, },
server::{ server::{
UPID, UPID,
@ -568,7 +569,7 @@ fn cartridge_memory(
}, },
}, },
)] )]
/// Get drive status /// Get drive/media status
fn status( fn status(
mut param: Value, mut param: Value,
rpcenv: &mut dyn RpcEnvironment, rpcenv: &mut dyn RpcEnvironment,
@ -592,6 +593,9 @@ fn status(
.column(ColumnConfig::new("status")) .column(ColumnConfig::new("status"))
.column(ColumnConfig::new("file-number")) .column(ColumnConfig::new("file-number"))
.column(ColumnConfig::new("block-number")) .column(ColumnConfig::new("block-number"))
.column(ColumnConfig::new("manufactured").renderer(render_epoch))
.column(ColumnConfig::new("bytes-written").renderer(render_bytes_human_readable))
.column(ColumnConfig::new("bytes-read").renderer(render_bytes_human_readable))
; ;
format_and_print_result_full(&mut data, &info.returns, &output_format, &options); format_and_print_result_full(&mut data, &info.returns, &output_format, &options);

View File

@ -11,7 +11,6 @@ use proxmox::sys::error::SysResult;
use crate::{ use crate::{
api2::types::{ api2::types::{
TapeDensity, TapeDensity,
LinuxDriveStatusFlat,
MamAttribute, MamAttribute,
}, },
tape::{ tape::{
@ -52,18 +51,6 @@ impl LinuxDriveStatus {
} }
} }
impl From<LinuxDriveStatus> for LinuxDriveStatusFlat {
fn from(status: LinuxDriveStatus) -> Self {
LinuxDriveStatusFlat {
blocksize: status.blocksize,
density: status.density,
status: format!("{:?}", status.status),
file_number: status.file_number,
block_number: status.block_number,
}
}
}
impl LinuxTapeDrive { impl LinuxTapeDrive {
/// This needs to lock the drive /// This needs to lock the drive

View File

@ -178,3 +178,46 @@ fn decode_mam_attributes(data: &[u8]) -> Result<Vec<MamAttribute>, Error> {
} }
Ok(list) Ok(list)
} }
/// Media Usage Information from Cartridge Memory
pub struct MediaUsageInfo {
pub manufactured: i64,
pub bytes_read: u64,
pub bytes_written: u64,
}
/// Extract Media Usage Information from Cartridge Memory
pub fn mam_extract_media_usage(mam: &[MamAttribute]) -> Result<MediaUsageInfo, Error> {
let manufactured: i64 = match mam.iter().find(|v| v.id == 0x04_06).map(|v| v.value.clone()) {
Some(date_str) => {
if date_str.len() != 8 {
bail!("unable to parse 'Medium Manufacture Date' - wrong length");
}
let year: i32 = date_str[..4].parse()?;
let mon: i32 = date_str[4..6].parse()?;
let mday: i32 = date_str[6..8].parse()?;
use proxmox::tools::time::TmEditor;
let mut t = TmEditor::new(true);
t.set_year(year)?;
t.set_mon(mon)?;
t.set_mday(mday)?;
t.into_epoch()?
}
None => bail!("unable to read MAM 'Medium Manufacture Date'"),
};
let bytes_written: u64 = match mam.iter().find(|v| v.id == 0x02_20).map(|v| v.value.clone()) {
Some(read_str) => read_str.parse::<u64>()? * 1024*1024,
None => bail!("unable to read MAM 'Total MBytes Written In Medium Life'"),
};
let bytes_read: u64 = match mam.iter().find(|v| v.id == 0x02_21).map(|v| v.value.clone()) {
Some(read_str) => read_str.parse::<u64>()? * 1024*1024,
None => bail!("unable to read MAM 'Total MBytes Read In Medium Life'"),
};
Ok(MediaUsageInfo { manufactured, bytes_written, bytes_read })
}