From 03380db560537f4cf92d6ba60822e464df7d8247 Mon Sep 17 00:00:00 2001 From: Dominik Csapak Date: Wed, 26 May 2021 15:48:04 +0200 Subject: [PATCH] api2/tape: add api call to list media sets we want a 'media-set' selector in the gui, this makes it very easy to do and is not as costly as reusing the media list, since we do not need to iterate over all media (e.g. unassigned) Signed-off-by: Dominik Csapak --- src/api2/tape/media.rs | 75 ++++++++++++++++++++++++++++++++++++ src/api2/types/tape/media.rs | 20 ++++++++++ 2 files changed, 95 insertions(+) diff --git a/src/api2/tape/media.rs b/src/api2/tape/media.rs index 683c74b8..8351b2be 100644 --- a/src/api2/tape/media.rs +++ b/src/api2/tape/media.rs @@ -1,4 +1,5 @@ use std::path::Path; +use std::collections::HashSet; use anyhow::{bail, format_err, Error}; use serde::{Serialize, Deserialize}; @@ -28,6 +29,7 @@ use crate::{ CHANGER_NAME_SCHEMA, MediaPoolConfig, MediaListEntry, + MediaSetListEntry, MediaStatus, MediaContentEntry, VAULT_NAME_SCHEMA, @@ -44,6 +46,74 @@ use crate::{ }, }; +#[api( + returns: { + description: "List of media sets.", + type: Array, + items: { + type: MediaSetListEntry, + }, + }, + access: { + description: "List of media sets filtered by Tape.Audit privileges on pool", + permission: &Permission::Anybody, + }, +)] +/// List Media sets +pub async fn list_media_sets( + rpcenv: &mut dyn RpcEnvironment, +) -> Result, Error> { + let auth_id: Authid = rpcenv.get_auth_id().unwrap().parse()?; + let user_info = CachedUserInfo::new()?; + + let (config, _digest) = config::media_pool::config()?; + + let status_path = Path::new(TAPE_STATUS_DIR); + + let mut media_sets: HashSet = HashSet::new(); + let mut list = Vec::new(); + + for (_section_type, data) in config.sections.values() { + let pool_name = match data["name"].as_str() { + None => continue, + Some(name) => name, + }; + + let privs = user_info.lookup_privs(&auth_id, &["tape", "pool", pool_name]); + if (privs & PRIV_TAPE_AUDIT) == 0 { + continue; + } + + let config: MediaPoolConfig = config.lookup("pool", pool_name)?; + + let changer_name = None; // assume standalone drive + let pool = MediaPool::with_config(status_path, &config, changer_name, true)?; + + for media in pool.list_media() { + if let Some(label) = media.media_set_label() { + if media_sets.contains(&label.uuid) { + continue; + } + + let media_set_uuid = label.uuid.clone(); + let media_set_ctime = label.ctime; + let media_set_name = pool + .generate_media_set_name(&media_set_uuid, config.template.clone()) + .unwrap_or_else(|_| media_set_uuid.to_string()); + + media_sets.insert(media_set_uuid.clone()); + list.push(MediaSetListEntry { + media_set_name, + media_set_uuid, + media_set_ctime, + pool: pool_name.to_string(), + }); + } + } + } + + Ok(list) +} #[api( input: { properties: { @@ -546,6 +616,11 @@ const SUBDIRS: SubdirMap = &[ .get(&API_METHOD_DESTROY_MEDIA) ), ( "list", &MEDIA_LIST_ROUTER ), + ( + "media-sets", + &Router::new() + .get(&API_METHOD_LIST_MEDIA_SETS) + ), ( "move", &Router::new() diff --git a/src/api2/types/tape/media.rs b/src/api2/types/tape/media.rs index 554efa7a..b53ce28b 100644 --- a/src/api2/types/tape/media.rs +++ b/src/api2/types/tape/media.rs @@ -12,6 +12,26 @@ use crate::api2::types::{ MediaLocation, }; +#[api( + properties: { + "media-set-uuid": { + schema: MEDIA_SET_UUID_SCHEMA, + }, + }, +)] +#[derive(Serialize,Deserialize)] +#[serde(rename_all = "kebab-case")] +/// Media Set list entry +pub struct MediaSetListEntry { + /// Media set name + pub media_set_name: String, + pub media_set_uuid: Uuid, + /// MediaSet creation time stamp + pub media_set_ctime: i64, + /// Media Pool + pub pool: String, +} + #[api( properties: { location: {