tape: cleanup MediaLocation type for direct use with API
This commit is contained in:
		@ -17,32 +17,16 @@ use crate::{
 | 
			
		||||
        MediaPoolConfig,
 | 
			
		||||
        MediaListEntry,
 | 
			
		||||
        MediaStatus,
 | 
			
		||||
        MediaLocationKind,
 | 
			
		||||
    },
 | 
			
		||||
    tape::{
 | 
			
		||||
        TAPE_STATUS_DIR,
 | 
			
		||||
        Inventory,
 | 
			
		||||
        MediaStateDatabase,
 | 
			
		||||
        MediaLocation,
 | 
			
		||||
        MediaPool,
 | 
			
		||||
        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(
 | 
			
		||||
    input: {
 | 
			
		||||
        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();
 | 
			
		||||
 | 
			
		||||
        for media in pool.list_media() {
 | 
			
		||||
            let (location, location_hint) = split_location(&media.location());
 | 
			
		||||
 | 
			
		||||
            let expired = pool.media_is_expired(&media, current_time);
 | 
			
		||||
 | 
			
		||||
            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(),
 | 
			
		||||
                changer_id: media.changer_id().to_string(),
 | 
			
		||||
                pool: Some(pool_name.to_string()),
 | 
			
		||||
                location,
 | 
			
		||||
                location_hint,
 | 
			
		||||
                location: media.location().clone(),
 | 
			
		||||
                status: *media.status(),
 | 
			
		||||
                expired,
 | 
			
		||||
                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() {
 | 
			
		||||
 | 
			
		||||
            let (mut status, location) = state_db.status_and_location(&media_id.label.uuid);
 | 
			
		||||
            let (location, location_hint) = split_location(&location);
 | 
			
		||||
 | 
			
		||||
            if status == MediaStatus::Unknown {
 | 
			
		||||
                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(),
 | 
			
		||||
                changer_id: media_id.label.changer_id.to_string(),
 | 
			
		||||
                location,
 | 
			
		||||
                location_hint,
 | 
			
		||||
                status,
 | 
			
		||||
                expired: false,
 | 
			
		||||
                media_set_uuid: None,
 | 
			
		||||
 | 
			
		||||
@ -4,26 +4,13 @@ use proxmox::api::api;
 | 
			
		||||
 | 
			
		||||
use super::{
 | 
			
		||||
    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(
 | 
			
		||||
    properties: {
 | 
			
		||||
        location: {
 | 
			
		||||
            type: MediaLocationKind,
 | 
			
		||||
            type: MediaLocation,
 | 
			
		||||
        },
 | 
			
		||||
        status: {
 | 
			
		||||
            type: MediaStatus,
 | 
			
		||||
@ -38,9 +25,7 @@ pub struct MediaListEntry {
 | 
			
		||||
    pub changer_id: String,
 | 
			
		||||
    /// Media Uuid
 | 
			
		||||
    pub uuid: String,
 | 
			
		||||
    pub location: MediaLocationKind,
 | 
			
		||||
    /// Media location hint (vault name, changer name)
 | 
			
		||||
    pub location_hint: Option<String>,
 | 
			
		||||
    pub location: MediaLocation,
 | 
			
		||||
    pub status: MediaStatus,
 | 
			
		||||
    /// Expired flag
 | 
			
		||||
    pub expired: bool,
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										91
									
								
								src/api2/types/tape/media_location.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										91
									
								
								src/api2/types/tape/media_location.rs
									
									
									
									
									
										Normal 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");
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -15,5 +15,8 @@ pub use media_pool::*;
 | 
			
		||||
mod media_status;
 | 
			
		||||
pub use media_status::*;
 | 
			
		||||
 | 
			
		||||
mod media_location;
 | 
			
		||||
pub use media_location::*;
 | 
			
		||||
 | 
			
		||||
mod media;
 | 
			
		||||
pub use media::*;
 | 
			
		||||
 | 
			
		||||
@ -15,7 +15,6 @@ use proxmox_backup::{
 | 
			
		||||
        self,
 | 
			
		||||
        types::{
 | 
			
		||||
            MEDIA_POOL_NAME_SCHEMA,
 | 
			
		||||
            MediaLocationKind,
 | 
			
		||||
            MediaStatus,
 | 
			
		||||
            MediaListEntry,
 | 
			
		||||
        },
 | 
			
		||||
@ -72,19 +71,6 @@ async fn list_media(
 | 
			
		||||
        _ => 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> {
 | 
			
		||||
        let record: MediaListEntry = serde_json::from_value(record.clone())?;
 | 
			
		||||
        Ok(match record.status {
 | 
			
		||||
@ -115,7 +101,7 @@ async fn list_media(
 | 
			
		||||
        .column(ColumnConfig::new("media-set-name"))
 | 
			
		||||
        .column(ColumnConfig::new("seq-nr"))
 | 
			
		||||
        .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("media-set-uuid"))
 | 
			
		||||
        ;
 | 
			
		||||
 | 
			
		||||
@ -16,6 +16,7 @@ use proxmox::tools::Uuid;
 | 
			
		||||
use crate::{
 | 
			
		||||
    api2::types::{
 | 
			
		||||
        MediaStatus,
 | 
			
		||||
        MediaLocation,
 | 
			
		||||
        MediaSetPolicy,
 | 
			
		||||
        RetentionPolicy,
 | 
			
		||||
        MediaPoolConfig,
 | 
			
		||||
@ -24,7 +25,6 @@ use crate::{
 | 
			
		||||
    tape::{
 | 
			
		||||
        MediaId,
 | 
			
		||||
        MediaSet,
 | 
			
		||||
        MediaLocation,
 | 
			
		||||
        Inventory,
 | 
			
		||||
        MediaStateDatabase,
 | 
			
		||||
        file_formats::{
 | 
			
		||||
 | 
			
		||||
@ -21,21 +21,10 @@ use crate::{
 | 
			
		||||
    },
 | 
			
		||||
    api2::types::{
 | 
			
		||||
        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)]
 | 
			
		||||
struct MediaStateEntry {
 | 
			
		||||
    u: Uuid,
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user