tape: cleanup MediaLocation type for direct use with API
This commit is contained in:
parent
7680525eec
commit
c1c2c8f635
|
@ -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,
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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");
|
||||||
|
}
|
||||||
|
}
|
|
@ -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::*;
|
||||||
|
|
|
@ -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"))
|
||||||
;
|
;
|
||||||
|
|
|
@ -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::{
|
||||||
|
|
|
@ -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,
|
||||||
|
|
Loading…
Reference in New Issue