tape: cleanup MediaLocation type for direct use with API

This commit is contained in:
Dietmar Maurer 2020-12-16 10:45:58 +01:00
parent 7680525eec
commit c1c2c8f635
7 changed files with 101 additions and 68 deletions

View File

@ -17,32 +17,16 @@ use crate::{
MediaPoolConfig, MediaPoolConfig,
MediaListEntry, MediaListEntry,
MediaStatus, MediaStatus,
MediaLocationKind,
}, },
tape::{ tape::{
TAPE_STATUS_DIR, TAPE_STATUS_DIR,
Inventory, Inventory,
MediaStateDatabase, MediaStateDatabase,
MediaLocation,
MediaPool, MediaPool,
update_online_status, update_online_status,
}, },
}; };
fn split_location(location: &MediaLocation) -> (MediaLocationKind, Option<String>) {
match location {
MediaLocation::Online(changer_name) => {
(MediaLocationKind::Online, Some(changer_name.to_string()))
}
MediaLocation::Offline => {
(MediaLocationKind::Offline, None)
}
MediaLocation::Vault(vault) => {
(MediaLocationKind::Vault, Some(vault.to_string()))
}
}
}
#[api( #[api(
input: { input: {
properties: { properties: {
@ -94,8 +78,6 @@ pub async fn list_media(pool: Option<String>) -> Result<Vec<MediaListEntry>, Err
let current_time = proxmox::tools::time::epoch_i64(); let current_time = proxmox::tools::time::epoch_i64();
for media in pool.list_media() { for media in pool.list_media() {
let (location, location_hint) = split_location(&media.location());
let expired = pool.media_is_expired(&media, current_time); let expired = pool.media_is_expired(&media, current_time);
let media_set_uuid = media.media_set_label().as_ref() let media_set_uuid = media.media_set_label().as_ref()
@ -114,8 +96,7 @@ pub async fn list_media(pool: Option<String>) -> Result<Vec<MediaListEntry>, Err
uuid: media.uuid().to_string(), uuid: media.uuid().to_string(),
changer_id: media.changer_id().to_string(), changer_id: media.changer_id().to_string(),
pool: Some(pool_name.to_string()), pool: Some(pool_name.to_string()),
location, location: media.location().clone(),
location_hint,
status: *media.status(), status: *media.status(),
expired, expired,
media_set_uuid, media_set_uuid,
@ -133,7 +114,6 @@ pub async fn list_media(pool: Option<String>) -> Result<Vec<MediaListEntry>, Err
for media_id in inventory.list_unassigned_media() { for media_id in inventory.list_unassigned_media() {
let (mut status, location) = state_db.status_and_location(&media_id.label.uuid); let (mut status, location) = state_db.status_and_location(&media_id.label.uuid);
let (location, location_hint) = split_location(&location);
if status == MediaStatus::Unknown { if status == MediaStatus::Unknown {
status = MediaStatus::Writable; status = MediaStatus::Writable;
@ -143,7 +123,6 @@ pub async fn list_media(pool: Option<String>) -> Result<Vec<MediaListEntry>, Err
uuid: media_id.label.uuid.to_string(), uuid: media_id.label.uuid.to_string(),
changer_id: media_id.label.changer_id.to_string(), changer_id: media_id.label.changer_id.to_string(),
location, location,
location_hint,
status, status,
expired: false, expired: false,
media_set_uuid: None, media_set_uuid: None,

View File

@ -4,26 +4,13 @@ use proxmox::api::api;
use super::{ use super::{
MediaStatus, MediaStatus,
MediaLocation,
}; };
#[api()]
#[derive(Serialize,Deserialize)]
#[serde(rename_all = "lowercase")]
/// Media location
pub enum MediaLocationKind {
/// Ready for use (inside tape library)
Online,
/// Local available, but need to be mounted (insert into tape
/// drive)
Offline,
/// Media is inside a Vault
Vault,
}
#[api( #[api(
properties: { properties: {
location: { location: {
type: MediaLocationKind, type: MediaLocation,
}, },
status: { status: {
type: MediaStatus, type: MediaStatus,
@ -38,9 +25,7 @@ pub struct MediaListEntry {
pub changer_id: String, pub changer_id: String,
/// Media Uuid /// Media Uuid
pub uuid: String, pub uuid: String,
pub location: MediaLocationKind, pub location: MediaLocation,
/// Media location hint (vault name, changer name)
pub location_hint: Option<String>,
pub status: MediaStatus, pub status: MediaStatus,
/// Expired flag /// Expired flag
pub expired: bool, pub expired: bool,

View File

@ -0,0 +1,91 @@
use anyhow::{bail, Error};
use proxmox::api::{
schema::{
Schema,
StringSchema,
ApiStringFormat,
parse_simple_value,
},
};
use crate::api2::types::{
PROXMOX_SAFE_ID_FORMAT,
CHANGER_NAME_SCHEMA,
};
pub const VAULT_NAME_SCHEMA: Schema = StringSchema::new("Vault name.")
.format(&PROXMOX_SAFE_ID_FORMAT)
.min_length(3)
.max_length(32)
.schema();
#[derive(Debug, PartialEq, Clone)]
/// Media location
pub enum MediaLocation {
/// Ready for use (inside tape library)
Online(String),
/// Local available, but need to be mounted (insert into tape
/// drive)
Offline,
/// Media is inside a Vault
Vault(String),
}
proxmox::forward_deserialize_to_from_str!(MediaLocation);
proxmox::forward_serialize_to_display!(MediaLocation);
impl MediaLocation {
pub const API_SCHEMA: Schema = StringSchema::new(
"Media location (e.g. 'offline', 'online-<changer_name>', 'vault-<vault_name>')")
.format(&ApiStringFormat::VerifyFn(|text| {
let location: MediaLocation = text.parse()?;
match location {
MediaLocation::Online(ref changer) => {
parse_simple_value(changer, &CHANGER_NAME_SCHEMA)?;
}
MediaLocation::Vault(ref vault) => {
parse_simple_value(vault, &VAULT_NAME_SCHEMA)?;
}
MediaLocation::Offline => { /* OK */}
}
Ok(())
}))
.schema();
}
impl std::fmt::Display for MediaLocation {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
MediaLocation::Offline => {
write!(f, "offline")
}
MediaLocation::Online(changer) => {
write!(f, "online-{}", changer)
}
MediaLocation::Vault(vault) => {
write!(f, "vault-{}", vault)
}
}
}
}
impl std::str::FromStr for MediaLocation {
type Err = Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
if s == "offline" {
return Ok(MediaLocation::Offline);
}
if let Some(changer) = s.strip_prefix("online-") {
return Ok(MediaLocation::Online(changer.to_string()));
}
if let Some(vault) = s.strip_prefix("vault-") {
return Ok(MediaLocation::Online(vault.to_string()));
}
bail!("MediaLocation parse error");
}
}

View File

@ -15,5 +15,8 @@ pub use media_pool::*;
mod media_status; mod media_status;
pub use media_status::*; pub use media_status::*;
mod media_location;
pub use media_location::*;
mod media; mod media;
pub use media::*; pub use media::*;

View File

@ -15,7 +15,6 @@ use proxmox_backup::{
self, self,
types::{ types::{
MEDIA_POOL_NAME_SCHEMA, MEDIA_POOL_NAME_SCHEMA,
MediaLocationKind,
MediaStatus, MediaStatus,
MediaListEntry, MediaListEntry,
}, },
@ -72,19 +71,6 @@ async fn list_media(
_ => unreachable!(), _ => unreachable!(),
}; };
fn render_location(_value: &Value, record: &Value) -> Result<String, Error> {
let record: MediaListEntry = serde_json::from_value(record.clone())?;
Ok(match record.location {
MediaLocationKind::Online => {
record.location_hint.unwrap_or(String::from("-"))
}
MediaLocationKind::Offline => String::from("offline"),
MediaLocationKind::Vault => {
format!("V({})", record.location_hint.unwrap_or(String::from("-")))
}
})
}
fn render_status(_value: &Value, record: &Value) -> Result<String, Error> { fn render_status(_value: &Value, record: &Value) -> Result<String, Error> {
let record: MediaListEntry = serde_json::from_value(record.clone())?; let record: MediaListEntry = serde_json::from_value(record.clone())?;
Ok(match record.status { Ok(match record.status {
@ -115,7 +101,7 @@ async fn list_media(
.column(ColumnConfig::new("media-set-name")) .column(ColumnConfig::new("media-set-name"))
.column(ColumnConfig::new("seq-nr")) .column(ColumnConfig::new("seq-nr"))
.column(ColumnConfig::new("status").renderer(render_status)) .column(ColumnConfig::new("status").renderer(render_status))
.column(ColumnConfig::new("location").renderer(render_location)) .column(ColumnConfig::new("location"))
.column(ColumnConfig::new("uuid")) .column(ColumnConfig::new("uuid"))
.column(ColumnConfig::new("media-set-uuid")) .column(ColumnConfig::new("media-set-uuid"))
; ;

View File

@ -16,6 +16,7 @@ use proxmox::tools::Uuid;
use crate::{ use crate::{
api2::types::{ api2::types::{
MediaStatus, MediaStatus,
MediaLocation,
MediaSetPolicy, MediaSetPolicy,
RetentionPolicy, RetentionPolicy,
MediaPoolConfig, MediaPoolConfig,
@ -24,7 +25,6 @@ use crate::{
tape::{ tape::{
MediaId, MediaId,
MediaSet, MediaSet,
MediaLocation,
Inventory, Inventory,
MediaStateDatabase, MediaStateDatabase,
file_formats::{ file_formats::{

View File

@ -21,21 +21,10 @@ use crate::{
}, },
api2::types::{ api2::types::{
MediaStatus, MediaStatus,
MediaLocation,
}, },
}; };
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
/// Media location
pub enum MediaLocation {
/// Ready for use (inside tape library)
Online(String),
/// Local available, but need to be mounted (insert into tape
/// drive)
Offline,
/// Media is inside a Vault
Vault(String),
}
#[derive(Serialize,Deserialize)] #[derive(Serialize,Deserialize)]
struct MediaStateEntry { struct MediaStateEntry {
u: Uuid, u: Uuid,