tape: implement destroy_media
This commit is contained in:
		@ -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()
 | 
				
			||||||
 | 
				
			|||||||
@ -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()
 | 
				
			||||||
 | 
				
			|||||||
@ -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)
 | 
				
			||||||
 | 
				
			|||||||
@ -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();
 | 
				
			||||||
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user