From cb80d900b3d73c46aeec5448b809c55dcee92319 Mon Sep 17 00:00:00 2001 From: Dietmar Maurer Date: Tue, 22 Dec 2020 10:42:22 +0100 Subject: [PATCH] tape: add drive status api --- src/api2/tape/drive.rs | 37 ++++++++++++++++++-- src/api2/types/tape/drive.rs | 68 ++++++++++++++++++++++++++++++++++++ src/bin/proxmox-tape.rs | 49 ++++++++++++++++++++++++++ src/tape/drive/linux_tape.rs | 57 +++++++++++------------------- src/tape/drive/mod.rs | 2 +- 5 files changed, 173 insertions(+), 40 deletions(-) diff --git a/src/api2/tape/drive.rs b/src/api2/tape/drive.rs index 639f8ed8..2ce64ef6 100644 --- a/src/api2/tape/drive.rs +++ b/src/api2/tape/drive.rs @@ -1,7 +1,7 @@ use std::path::Path; use std::sync::Arc; -use anyhow::{bail, Error}; +use anyhow::{bail, format_err, Error}; use serde_json::Value; use proxmox::{ @@ -35,6 +35,7 @@ use crate::{ MediaIdFlat, LabelUuidMap, MamAttribute, + LinuxDriveStatusFlat, }, server::WorkerTask, tape::{ @@ -51,7 +52,7 @@ use crate::{ open_drive, media_changer, update_changer_online_status, - file_formats::{ + file_formats::{ MediaLabel, MediaSetLabel, }, @@ -796,6 +797,33 @@ pub fn cartridge_memory(drive: String) -> Result, Error> { read_mam_attributes(&drive_config.path) } +#[api( + input: { + properties: { + drive: { + schema: DRIVE_NAME_SCHEMA, + }, + }, + }, + returns: { + type: LinuxDriveStatusFlat, + }, +)] +/// Get drive status +pub fn status(drive: String) -> Result { + + let (config, _digest) = config::drive::config()?; + + let drive_config: LinuxTapeDrive = config.lookup("linux", &drive)?; + + let 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()) +} + #[sortable] pub const SUBDIRS: SubdirMap = &sorted!([ ( @@ -849,6 +877,11 @@ pub const SUBDIRS: SubdirMap = &sorted!([ &Router::new() .get(&API_METHOD_SCAN_DRIVES) ), + ( + "status", + &Router::new() + .get(&API_METHOD_STATUS) + ), ( "unload", &Router::new() diff --git a/src/api2/types/tape/drive.rs b/src/api2/types/tape/drive.rs index aff3373e..db33967c 100644 --- a/src/api2/types/tape/drive.rs +++ b/src/api2/types/tape/drive.rs @@ -1,5 +1,7 @@ //! Types for tape drive API +use std::convert::TryFrom; +use anyhow::{bail, Error}; use serde::{Deserialize, Serialize}; use proxmox::api::{ @@ -111,3 +113,69 @@ pub struct MamAttribute { /// Attribute value pub value: String, } + +#[api()] +#[derive(Serialize,Deserialize,Debug)] +pub enum TapeDensity { + /// No tape loaded + None, + /// LTO2 + LTO2, + /// LTO3 + LTO3, + /// LTO4 + LTO4, + /// LTO5 + LTO5, + /// LTO6 + LTO6, + /// LTO7 + LTO7, + /// LTO7M8 + LTO7M8, + /// LTO8 + LTO8, +} + +impl TryFrom for TapeDensity { + type Error = Error; + + fn try_from(value: u8) -> Result { + let density = match value { + 0x00 => TapeDensity::None, + 0x42 => TapeDensity::LTO2, + 0x44 => TapeDensity::LTO3, + 0x46 => TapeDensity::LTO4, + 0x58 => TapeDensity::LTO5, + 0x5a => TapeDensity::LTO6, + 0x5c => TapeDensity::LTO7, + 0x5d => TapeDensity::LTO7M8, + 0x5e => TapeDensity::LTO8, + _ => bail!("unknown tape density code 0x{:02x}", value), + }; + Ok(density) + } +} + +#[api( + properties: { + density: { + type: TapeDensity, + }, + }, +)] +#[derive(Serialize,Deserialize)] +#[serde(rename_all = "kebab-case")] +/// Drive status for Linux SCSI drives. +pub struct LinuxDriveStatusFlat { + /// Block size (0 is variable size) + pub blocksize: u32, + /// Tape density + pub density: TapeDensity, + /// Status flags + pub status: String, + /// Current file number + pub file_number: i32, + /// Current block number + pub block_number: i32, +} diff --git a/src/bin/proxmox-tape.rs b/src/bin/proxmox-tape.rs index fdfc058d..32dd516b 100644 --- a/src/bin/proxmox-tape.rs +++ b/src/bin/proxmox-tape.rs @@ -554,6 +554,50 @@ fn cartridge_memory( Ok(()) } +#[api( + input: { + properties: { + drive: { + schema: DRIVE_NAME_SCHEMA, + optional: true, + }, + "output-format": { + schema: OUTPUT_FORMAT, + optional: true, + }, + }, + }, +)] +/// Get drive status +fn status( + mut param: Value, + rpcenv: &mut dyn RpcEnvironment, +) -> Result<(), Error> { + + let (config, _digest) = config::drive::config()?; + + param["drive"] = lookup_drive_name(¶m, &config)?.into(); + + let output_format = get_output_format(¶m); + let info = &api2::tape::drive::API_METHOD_STATUS; + + let mut data = match info.handler { + ApiHandler::Sync(handler) => (handler)(param, info, rpcenv)?, + _ => unreachable!(), + }; + + let options = default_table_format_options() + .column(ColumnConfig::new("blocksize")) + .column(ColumnConfig::new("density")) + .column(ColumnConfig::new("status")) + .column(ColumnConfig::new("file-number")) + .column(ColumnConfig::new("block-number")) + ; + + format_and_print_result_full(&mut data, &info.returns, &output_format, &options); + Ok(()) +} + #[api( input: { properties: { @@ -610,6 +654,11 @@ fn main() { CliCommand::new(&API_METHOD_DEBUG_SCAN) .completion_cb("drive", complete_drive_name) ) + .insert( + "status", + CliCommand::new(&API_METHOD_STATUS) + .completion_cb("drive", complete_drive_name) + ) .insert( "eod", CliCommand::new(&API_METHOD_MOVE_TO_EOM) diff --git a/src/tape/drive/linux_tape.rs b/src/tape/drive/linux_tape.rs index 84c17a0b..630fd9e5 100644 --- a/src/tape/drive/linux_tape.rs +++ b/src/tape/drive/linux_tape.rs @@ -9,6 +9,10 @@ use nix::fcntl::{fcntl, FcntlArg, OFlag}; use proxmox::sys::error::SysResult; use crate::{ + api2::types::{ + TapeDensity, + LinuxDriveStatusFlat, + }, tape::{ TapeRead, TapeWrite, @@ -31,40 +35,7 @@ use crate::{ }; #[derive(Debug)] -pub enum TapeDensity { - None, // no tape loaded - LTO2, - LTO3, - LTO4, - LTO5, - LTO6, - LTO7, - LTO7M8, - LTO8, -} - -impl TryFrom for TapeDensity { - type Error = Error; - - fn try_from(value: u8) -> Result { - let density = match value { - 0x00 => TapeDensity::None, - 0x42 => TapeDensity::LTO2, - 0x44 => TapeDensity::LTO3, - 0x46 => TapeDensity::LTO4, - 0x58 => TapeDensity::LTO5, - 0x5a => TapeDensity::LTO6, - 0x5c => TapeDensity::LTO7, - 0x5d => TapeDensity::LTO7M8, - 0x5e => TapeDensity::LTO8, - _ => bail!("unknown tape density code 0x{:02x}", value), - }; - Ok(density) - } -} - -#[derive(Debug)] -pub struct DriveStatus { +pub struct LinuxDriveStatus { pub blocksize: u32, pub density: TapeDensity, pub status: GMTStatusFlags, @@ -72,13 +43,25 @@ pub struct DriveStatus { pub block_number: i32, } -impl DriveStatus { +impl LinuxDriveStatus { pub fn tape_is_ready(&self) -> bool { self.status.contains(GMTStatusFlags::ONLINE) && !self.status.contains(GMTStatusFlags::DRIVE_OPEN) } } +impl From 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 @@ -242,7 +225,7 @@ impl LinuxTapeHandle { } /// Get Tape configuration with MTIOCGET ioctl - pub fn get_drive_status(&self) -> Result { + pub fn get_drive_status(&self) -> Result { self.mtnop()?; @@ -268,7 +251,7 @@ impl LinuxTapeHandle { let density = TapeDensity::try_from(density)?; - Ok(DriveStatus { + Ok(LinuxDriveStatus { blocksize, density, status: gmt, diff --git a/src/tape/drive/mod.rs b/src/tape/drive/mod.rs index 883ce51d..cd3e8829 100644 --- a/src/tape/drive/mod.rs +++ b/src/tape/drive/mod.rs @@ -1,6 +1,6 @@ mod virtual_tape; mod linux_mtio; -mod linux_tape; +pub mod linux_tape; mod mam; pub use mam::*;