tape: add drive status api
This commit is contained in:
parent
ee01737e87
commit
cb80d900b3
|
@ -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::{
|
||||||
|
@ -51,7 +52,7 @@ use crate::{
|
||||||
open_drive,
|
open_drive,
|
||||||
media_changer,
|
media_changer,
|
||||||
update_changer_online_status,
|
update_changer_online_status,
|
||||||
file_formats::{
|
file_formats::{
|
||||||
MediaLabel,
|
MediaLabel,
|
||||||
MediaSetLabel,
|
MediaSetLabel,
|
||||||
},
|
},
|
||||||
|
@ -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()
|
||||||
|
|
|
@ -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,
|
||||||
|
}
|
||||||
|
|
|
@ -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(¶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(
|
#[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)
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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::*;
|
||||||
|
|
Loading…
Reference in New Issue