tape: return media usage info with status command
This commit is contained in:
parent
dbe7e556b0
commit
5ae86dfaa1
|
@ -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]
|
||||||
|
|
|
@ -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,
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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 })
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue