tape: add drive status api

This commit is contained in:
Dietmar Maurer 2020-12-22 10:42:22 +01:00
parent ee01737e87
commit cb80d900b3
5 changed files with 173 additions and 40 deletions

View File

@ -1,7 +1,7 @@
use std::path::Path; use std::path::Path;
use std::sync::Arc; use std::sync::Arc;
use anyhow::{bail, Error}; use anyhow::{bail, format_err, Error};
use serde_json::Value; use serde_json::Value;
use proxmox::{ use proxmox::{
@ -35,6 +35,7 @@ use crate::{
MediaIdFlat, MediaIdFlat,
LabelUuidMap, LabelUuidMap,
MamAttribute, MamAttribute,
LinuxDriveStatusFlat,
}, },
server::WorkerTask, server::WorkerTask,
tape::{ tape::{
@ -796,6 +797,33 @@ pub fn cartridge_memory(drive: String) -> Result<Vec<MamAttribute>, Error> {
read_mam_attributes(&drive_config.path) 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<LinuxDriveStatusFlat, Error> {
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] #[sortable]
pub const SUBDIRS: SubdirMap = &sorted!([ pub const SUBDIRS: SubdirMap = &sorted!([
( (
@ -849,6 +877,11 @@ pub const SUBDIRS: SubdirMap = &sorted!([
&Router::new() &Router::new()
.get(&API_METHOD_SCAN_DRIVES) .get(&API_METHOD_SCAN_DRIVES)
), ),
(
"status",
&Router::new()
.get(&API_METHOD_STATUS)
),
( (
"unload", "unload",
&Router::new() &Router::new()

View File

@ -1,5 +1,7 @@
//! Types for tape drive API //! Types for tape drive API
use std::convert::TryFrom;
use anyhow::{bail, Error};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use proxmox::api::{ use proxmox::api::{
@ -111,3 +113,69 @@ pub struct MamAttribute {
/// Attribute value /// Attribute value
pub value: String, 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<u8> for TapeDensity {
type Error = Error;
fn try_from(value: u8) -> Result<Self, Self::Error> {
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,
}

View File

@ -554,6 +554,50 @@ fn cartridge_memory(
Ok(()) 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(&param, &config)?.into();
let output_format = get_output_format(&param);
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( #[api(
input: { input: {
properties: { properties: {
@ -610,6 +654,11 @@ fn main() {
CliCommand::new(&API_METHOD_DEBUG_SCAN) CliCommand::new(&API_METHOD_DEBUG_SCAN)
.completion_cb("drive", complete_drive_name) .completion_cb("drive", complete_drive_name)
) )
.insert(
"status",
CliCommand::new(&API_METHOD_STATUS)
.completion_cb("drive", complete_drive_name)
)
.insert( .insert(
"eod", "eod",
CliCommand::new(&API_METHOD_MOVE_TO_EOM) CliCommand::new(&API_METHOD_MOVE_TO_EOM)

View File

@ -9,6 +9,10 @@ use nix::fcntl::{fcntl, FcntlArg, OFlag};
use proxmox::sys::error::SysResult; use proxmox::sys::error::SysResult;
use crate::{ use crate::{
api2::types::{
TapeDensity,
LinuxDriveStatusFlat,
},
tape::{ tape::{
TapeRead, TapeRead,
TapeWrite, TapeWrite,
@ -31,40 +35,7 @@ use crate::{
}; };
#[derive(Debug)] #[derive(Debug)]
pub enum TapeDensity { pub struct LinuxDriveStatus {
None, // no tape loaded
LTO2,
LTO3,
LTO4,
LTO5,
LTO6,
LTO7,
LTO7M8,
LTO8,
}
impl TryFrom<u8> for TapeDensity {
type Error = Error;
fn try_from(value: u8) -> Result<Self, Self::Error> {
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 blocksize: u32, pub blocksize: u32,
pub density: TapeDensity, pub density: TapeDensity,
pub status: GMTStatusFlags, pub status: GMTStatusFlags,
@ -72,13 +43,25 @@ pub struct DriveStatus {
pub block_number: i32, pub block_number: i32,
} }
impl DriveStatus { impl LinuxDriveStatus {
pub fn tape_is_ready(&self) -> bool { pub fn tape_is_ready(&self) -> bool {
self.status.contains(GMTStatusFlags::ONLINE) && self.status.contains(GMTStatusFlags::ONLINE) &&
!self.status.contains(GMTStatusFlags::DRIVE_OPEN) !self.status.contains(GMTStatusFlags::DRIVE_OPEN)
} }
} }
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
@ -242,7 +225,7 @@ impl LinuxTapeHandle {
} }
/// Get Tape configuration with MTIOCGET ioctl /// Get Tape configuration with MTIOCGET ioctl
pub fn get_drive_status(&self) -> Result<DriveStatus, Error> { pub fn get_drive_status(&self) -> Result<LinuxDriveStatus, Error> {
self.mtnop()?; self.mtnop()?;
@ -268,7 +251,7 @@ impl LinuxTapeHandle {
let density = TapeDensity::try_from(density)?; let density = TapeDensity::try_from(density)?;
Ok(DriveStatus { Ok(LinuxDriveStatus {
blocksize, blocksize,
density, density,
status: gmt, status: gmt,

View File

@ -1,6 +1,6 @@
mod virtual_tape; mod virtual_tape;
mod linux_mtio; mod linux_mtio;
mod linux_tape; pub mod linux_tape;
mod mam; mod mam;
pub use mam::*; pub use mam::*;