diff --git a/src/api2/tape/backup.rs b/src/api2/tape/backup.rs index 581f98de..4ae03059 100644 --- a/src/api2/tape/backup.rs +++ b/src/api2/tape/backup.rs @@ -51,6 +51,11 @@ use crate::{ pool: { schema: MEDIA_POOL_NAME_SCHEMA, }, + "eject-media": { + description: "Eject media upon job completion.", + type: bool, + optional: true, + }, }, }, returns: { @@ -61,6 +66,7 @@ use crate::{ pub fn backup( store: String, pool: String, + eject_media: Option, rpcenv: &mut dyn RpcEnvironment, ) -> Result { @@ -77,20 +83,20 @@ pub fn backup( let to_stdout = if rpcenv.env_type() == RpcEnvironmentType::CLI { true } else { false }; + let eject_media = eject_media.unwrap_or(false); + let upid_str = WorkerTask::new_thread( "tape-backup", Some(store.clone()), auth_id, to_stdout, move |worker| { - backup_worker(&worker, datastore, &pool_config)?; + backup_worker(&worker, datastore, &pool_config, eject_media)?; Ok(()) } )?; Ok(upid_str.into()) - - } pub const ROUTER: Router = Router::new() @@ -101,6 +107,7 @@ fn backup_worker( worker: &WorkerTask, datastore: Arc, pool_config: &MediaPoolConfig, + eject_media: bool, ) -> Result<(), Error> { let status_path = Path::new(TAPE_STATUS_DIR); @@ -135,6 +142,11 @@ fn backup_worker( pool_writer.commit()?; + if eject_media { + worker.log(format!("ejection backup media")); + pool_writer.eject_media()?; + } + Ok(()) } diff --git a/src/bin/proxmox-tape.rs b/src/bin/proxmox-tape.rs index 1c06f334..76c40d76 100644 --- a/src/bin/proxmox-tape.rs +++ b/src/bin/proxmox-tape.rs @@ -718,6 +718,11 @@ async fn clean_drive( pool: { schema: MEDIA_POOL_NAME_SCHEMA, }, + "eject-media": { + description: "Eject media upon job completion.", + type: bool, + optional: true, + }, }, }, )] diff --git a/src/tape/pool_writer.rs b/src/tape/pool_writer.rs index 13b6caf8..616b0fcd 100644 --- a/src/tape/pool_writer.rs +++ b/src/tape/pool_writer.rs @@ -26,6 +26,7 @@ use crate::{ tape_write_snapshot_archive, request_and_load_media, tape_alert_flags_critical, + media_changer, file_formats::MediaSetLabel, }, }; @@ -106,6 +107,24 @@ impl PoolWriter { self.media_set_catalog.contains_snapshot(snapshot) } + /// Eject media and drop PoolWriterState (close drive) + pub fn eject_media(&mut self) -> Result<(), Error> { + let mut status = match self.status.take() { + Some(status) => status, + None => return Ok(()), // no media loaded + }; + + let (drive_config, _digest) = crate::config::drive::config()?; + + if let Some((mut changer, _)) = media_changer(&drive_config, &self.drive_name)? { + changer.unload_media(None)?; + } else { + status.drive.eject_media()?; + } + + Ok(()) + } + /// commit changes to tape and catalog /// /// This is done automatically during a backupsession, but needs to