tape: implement destroy_media

This commit is contained in:
Dietmar Maurer 2020-12-14 08:58:40 +01:00
parent fba0b77469
commit fb657d8ee5
4 changed files with 81 additions and 3 deletions

View File

@ -1,9 +1,11 @@
use std::path::Path; use std::path::Path;
use anyhow::Error; use anyhow::{bail, format_err, Error};
use proxmox::api::{api, Router, SubdirMap}; use proxmox::{
use proxmox::list_subdirs_api_method; api::{api, Router, SubdirMap},
list_subdirs_api_method,
};
use crate::{ use crate::{
config::{ config::{
@ -11,6 +13,7 @@ use crate::{
}, },
api2::types::{ api2::types::{
MEDIA_POOL_NAME_SCHEMA, MEDIA_POOL_NAME_SCHEMA,
MEDIA_LABEL_SCHEMA,
MediaPoolConfig, MediaPoolConfig,
MediaListEntry, MediaListEntry,
MediaStatus, MediaStatus,
@ -154,7 +157,57 @@ pub async fn list_media(pool: Option<String>) -> Result<Vec<MediaListEntry>, Err
Ok(list) Ok(list)
} }
#[api(
input: {
properties: {
"changer-id": {
schema: MEDIA_LABEL_SCHEMA,
},
force: {
description: "Force removal (even if media is used in a media set).",
type: bool,
optional: true,
},
},
},
)]
/// Destroy media (completely remove from database)
pub fn destroy_media(changer_id: String, force: Option<bool>,) -> Result<(), Error> {
let force = force.unwrap_or(false);
let status_path = Path::new(TAPE_STATUS_DIR);
let mut inventory = Inventory::load(status_path)?;
let media_id = inventory.find_media_by_changer_id(&changer_id)
.ok_or_else(|| format_err!("no such media '{}'", changer_id))?;
if !force {
if let Some(ref set) = media_id.media_set_label {
let is_empty = set.uuid.as_ref() == [0u8;16];
if !is_empty {
bail!("media '{}' contains data (please use 'force' flag to remove.", changer_id);
}
}
}
let uuid = media_id.label.uuid.clone();
drop(media_id);
inventory.remove_media(&uuid)?;
let mut state_db = MediaStateDatabase::load(status_path)?;
state_db.remove_media(&uuid)?;
Ok(())
}
const SUBDIRS: SubdirMap = &[ const SUBDIRS: SubdirMap = &[
(
"destroy",
&Router::new()
.get(&API_METHOD_DESTROY_MEDIA)
),
( (
"list", "list",
&Router::new() &Router::new()

View File

@ -20,6 +20,7 @@ use proxmox_backup::{
MediaListEntry, MediaListEntry,
}, },
}, },
tape::complete_media_changer_id,
config::{ config::{
media_pool::complete_pool_name, media_pool::complete_pool_name,
}, },
@ -33,6 +34,12 @@ pub fn media_commands() -> CommandLineInterface {
CliCommand::new(&API_METHOD_LIST_MEDIA) CliCommand::new(&API_METHOD_LIST_MEDIA)
.completion_cb("pool", complete_pool_name) .completion_cb("pool", complete_pool_name)
) )
.insert(
"destroy-media",
CliCommand::new(&api2::tape::media::API_METHOD_DESTROY_MEDIA)
.arg_param(&["changer-id"])
.completion_cb("changer-id", complete_media_changer_id)
)
; ;
cmd_def.into() cmd_def.into()

View File

@ -251,6 +251,16 @@ impl Inventory {
Ok(()) Ok(())
} }
/// Remove a single media persistently
pub fn remove_media(&mut self, uuid: &Uuid) -> Result<(), Error> {
let _lock = self.lock()?;
self.map = Self::load_media_db(&self.inventory_path)?;
self.map.remove(uuid);
self.update_helpers();
self.replace_file()?;
Ok(())
}
/// Lookup media /// Lookup media
pub fn lookup_media(&self, uuid: &Uuid) -> Option<&MediaId> { pub fn lookup_media(&self, uuid: &Uuid) -> Option<&MediaId> {
self.map.get(uuid) self.map.get(uuid)

View File

@ -201,6 +201,14 @@ impl MediaStateDatabase {
self.store() self.store()
} }
/// Lock database, reload database, remove media, store database
pub fn remove_media(&mut self, uuid: &Uuid) -> Result<(), Error> {
let _lock = self.lock()?;
self.map = Self::load_media_db(&self.database_path)?;
self.map.remove(uuid);
self.store()
}
fn store(&self) -> Result<(), Error> { fn store(&self) -> Result<(), Error> {
let mut list = Vec::new(); let mut list = Vec::new();