tape: return media usage info with status command
This commit is contained in:
		@ -35,7 +35,7 @@ use crate::{
 | 
			
		||||
        MediaIdFlat,
 | 
			
		||||
        LabelUuidMap,
 | 
			
		||||
        MamAttribute,
 | 
			
		||||
        LinuxDriveStatusFlat,
 | 
			
		||||
        LinuxDriveAndMediaStatus,
 | 
			
		||||
    },
 | 
			
		||||
    server::WorkerTask,
 | 
			
		||||
    tape::{
 | 
			
		||||
@ -51,6 +51,7 @@ use crate::{
 | 
			
		||||
        open_drive,
 | 
			
		||||
        media_changer,
 | 
			
		||||
        update_changer_online_status,
 | 
			
		||||
        mam_extract_media_usage,
 | 
			
		||||
        file_formats::{
 | 
			
		||||
            MediaLabel,
 | 
			
		||||
            MediaSetLabel,
 | 
			
		||||
@ -807,22 +808,37 @@ pub fn cartridge_memory(drive: String) -> Result<Vec<MamAttribute>, Error> {
 | 
			
		||||
        },
 | 
			
		||||
    },
 | 
			
		||||
    returns: {
 | 
			
		||||
        type: LinuxDriveStatusFlat,
 | 
			
		||||
        type: LinuxDriveAndMediaStatus,
 | 
			
		||||
    },
 | 
			
		||||
)]
 | 
			
		||||
/// Get drive status
 | 
			
		||||
pub fn status(drive: String) -> Result<LinuxDriveStatusFlat, Error> {
 | 
			
		||||
/// Get drive/media status
 | 
			
		||||
pub fn status(drive: String) -> Result<LinuxDriveAndMediaStatus, Error> {
 | 
			
		||||
 | 
			
		||||
    let (config, _digest) = config::drive::config()?;
 | 
			
		||||
 | 
			
		||||
    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))?;
 | 
			
		||||
 | 
			
		||||
    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]
 | 
			
		||||
 | 
			
		||||
@ -166,8 +166,8 @@ impl TryFrom<u8> for TapeDensity {
 | 
			
		||||
)]
 | 
			
		||||
#[derive(Serialize,Deserialize)]
 | 
			
		||||
#[serde(rename_all = "kebab-case")]
 | 
			
		||||
/// Drive status for Linux SCSI drives.
 | 
			
		||||
pub struct LinuxDriveStatusFlat {
 | 
			
		||||
/// Drive/Media status for Linux SCSI drives.
 | 
			
		||||
pub struct LinuxDriveAndMediaStatus {
 | 
			
		||||
    /// Block size (0 is variable size)
 | 
			
		||||
    pub blocksize: u32,
 | 
			
		||||
    /// Tape density
 | 
			
		||||
@ -178,4 +178,10 @@ pub struct LinuxDriveStatusFlat {
 | 
			
		||||
    pub file_number: i32,
 | 
			
		||||
    /// Current block number
 | 
			
		||||
    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::{
 | 
			
		||||
        HumanByte,
 | 
			
		||||
        render_epoch,
 | 
			
		||||
        render_bytes_human_readable,
 | 
			
		||||
    },
 | 
			
		||||
    server::{
 | 
			
		||||
        UPID,
 | 
			
		||||
@ -568,7 +569,7 @@ fn cartridge_memory(
 | 
			
		||||
        },
 | 
			
		||||
    },
 | 
			
		||||
)]
 | 
			
		||||
/// Get drive status
 | 
			
		||||
/// Get drive/media status
 | 
			
		||||
fn status(
 | 
			
		||||
    mut param: Value,
 | 
			
		||||
    rpcenv: &mut dyn RpcEnvironment,
 | 
			
		||||
@ -592,6 +593,9 @@ fn status(
 | 
			
		||||
        .column(ColumnConfig::new("status"))
 | 
			
		||||
        .column(ColumnConfig::new("file-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);
 | 
			
		||||
 | 
			
		||||
@ -11,7 +11,6 @@ use proxmox::sys::error::SysResult;
 | 
			
		||||
use crate::{
 | 
			
		||||
    api2::types::{
 | 
			
		||||
        TapeDensity,
 | 
			
		||||
        LinuxDriveStatusFlat,
 | 
			
		||||
        MamAttribute,
 | 
			
		||||
    },
 | 
			
		||||
    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 {
 | 
			
		||||
 | 
			
		||||
    /// This needs to lock the drive
 | 
			
		||||
 | 
			
		||||
@ -178,3 +178,46 @@ fn decode_mam_attributes(data: &[u8]) -> Result<Vec<MamAttribute>, Error> {
 | 
			
		||||
    }
 | 
			
		||||
    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 })
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user