tape: show catalog status in media list
This commit is contained in:
		@ -58,12 +58,15 @@ pub async fn list_media(pool: Option<String>) -> Result<Vec<MediaListEntry>, Err
 | 
			
		||||
 | 
			
		||||
    let status_path = Path::new(TAPE_STATUS_DIR);
 | 
			
		||||
 | 
			
		||||
    tokio::task::spawn_blocking(move || {
 | 
			
		||||
    let catalogs = tokio::task::spawn_blocking(move || {
 | 
			
		||||
        // update online media status
 | 
			
		||||
        if let Err(err) = update_online_status(status_path) {
 | 
			
		||||
            eprintln!("{}", err);
 | 
			
		||||
            eprintln!("update online media status failed - using old state");
 | 
			
		||||
        }
 | 
			
		||||
    }).await?;
 | 
			
		||||
        // test what catalog files we have
 | 
			
		||||
        MediaCatalog::media_with_catalogs(status_path)
 | 
			
		||||
    }).await??;
 | 
			
		||||
 | 
			
		||||
    let mut list = Vec::new();
 | 
			
		||||
 | 
			
		||||
@ -100,12 +103,20 @@ pub async fn list_media(pool: Option<String>) -> Result<Vec<MediaListEntry>, Err
 | 
			
		||||
                        .unwrap_or_else(|_| set.uuid.to_string())
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
            let catalog_ok = if media.media_set_label().is_none() {
 | 
			
		||||
                // Media is empty, we need no catalog
 | 
			
		||||
                true
 | 
			
		||||
            } else {
 | 
			
		||||
                catalogs.contains(media.uuid())
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            list.push(MediaListEntry {
 | 
			
		||||
                uuid: media.uuid().to_string(),
 | 
			
		||||
                changer_id: media.changer_id().to_string(),
 | 
			
		||||
                pool: Some(pool_name.to_string()),
 | 
			
		||||
                location: media.location().clone(),
 | 
			
		||||
                status: *media.status(),
 | 
			
		||||
                catalog: catalog_ok,
 | 
			
		||||
                expired,
 | 
			
		||||
                media_set_uuid,
 | 
			
		||||
                media_set_name,
 | 
			
		||||
@ -131,6 +142,7 @@ pub async fn list_media(pool: Option<String>) -> Result<Vec<MediaListEntry>, Err
 | 
			
		||||
                changer_id: media_id.label.changer_id.to_string(),
 | 
			
		||||
                location,
 | 
			
		||||
                status,
 | 
			
		||||
                catalog: true, // empty, so we do not need a catalog
 | 
			
		||||
                expired: false,
 | 
			
		||||
                media_set_uuid: None,
 | 
			
		||||
                media_set_name: None,
 | 
			
		||||
 | 
			
		||||
@ -29,6 +29,8 @@ pub struct MediaListEntry {
 | 
			
		||||
    pub status: MediaStatus,
 | 
			
		||||
    /// Expired flag
 | 
			
		||||
    pub expired: bool,
 | 
			
		||||
    /// Catalog status OK
 | 
			
		||||
    pub catalog: bool,
 | 
			
		||||
    /// Media set name
 | 
			
		||||
    #[serde(skip_serializing_if="Option::is_none")]
 | 
			
		||||
    pub media_set_name: Option<String>,
 | 
			
		||||
 | 
			
		||||
@ -104,6 +104,14 @@ async fn list_media(
 | 
			
		||||
        })
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn catalog_status(value: &Value, _record: &Value) -> Result<String, Error> {
 | 
			
		||||
        let catalog_ok = value.as_bool().unwrap();
 | 
			
		||||
        if catalog_ok {
 | 
			
		||||
            Ok(String::from("ok"))
 | 
			
		||||
        } else {
 | 
			
		||||
            Ok(String::from("missing"))
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    let options = default_table_format_options()
 | 
			
		||||
        .sortby("pool", false)
 | 
			
		||||
        .sortby("media-set-uuid", false)
 | 
			
		||||
@ -115,6 +123,7 @@ async fn list_media(
 | 
			
		||||
        .column(ColumnConfig::new("seq-nr"))
 | 
			
		||||
        .column(ColumnConfig::new("status").renderer(render_status))
 | 
			
		||||
        .column(ColumnConfig::new("location"))
 | 
			
		||||
        .column(ColumnConfig::new("catalog").renderer(catalog_status))
 | 
			
		||||
        .column(ColumnConfig::new("uuid"))
 | 
			
		||||
        .column(ColumnConfig::new("media-set-uuid"))
 | 
			
		||||
        ;
 | 
			
		||||
 | 
			
		||||
@ -3,7 +3,7 @@ use std::fs::File;
 | 
			
		||||
use std::io::{Write, Read, BufReader, Seek, SeekFrom};
 | 
			
		||||
use std::os::unix::io::AsRawFd;
 | 
			
		||||
use std::path::Path;
 | 
			
		||||
use std::collections::HashMap;
 | 
			
		||||
use std::collections::{HashSet, HashMap};
 | 
			
		||||
 | 
			
		||||
use anyhow::{bail, format_err, Error};
 | 
			
		||||
use endian_trait::Endian;
 | 
			
		||||
@ -22,6 +22,7 @@ use proxmox::tools::{
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
use crate::{
 | 
			
		||||
    tools::fs::read_subdir,
 | 
			
		||||
    backup::BackupDir,
 | 
			
		||||
    tape::{
 | 
			
		||||
        MediaId,
 | 
			
		||||
@ -58,6 +59,22 @@ pub struct MediaCatalog  {
 | 
			
		||||
 | 
			
		||||
impl MediaCatalog {
 | 
			
		||||
 | 
			
		||||
    /// List media with catalogs
 | 
			
		||||
    pub fn media_with_catalogs(base_path: &Path) -> Result<HashSet<Uuid>, Error> {
 | 
			
		||||
        let mut catalogs = HashSet::new();
 | 
			
		||||
 | 
			
		||||
        for entry in read_subdir(libc::AT_FDCWD, base_path)? {
 | 
			
		||||
            let entry = entry?;
 | 
			
		||||
            let name = unsafe { entry.file_name_utf8_unchecked() };
 | 
			
		||||
            if !name.ends_with(".log") { continue; }
 | 
			
		||||
            if let Ok(uuid) = Uuid::parse_str(&name[..(name.len()-4)]) {
 | 
			
		||||
                catalogs.insert(uuid);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        Ok(catalogs)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Test if a catalog exists
 | 
			
		||||
    pub fn exists(base_path: &Path, uuid: &Uuid) -> bool {
 | 
			
		||||
        let mut path = base_path.to_owned();
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user