diff --git a/src/api2/tape/drive.rs b/src/api2/tape/drive.rs index 1f12c4cb..6ad1136c 100644 --- a/src/api2/tape/drive.rs +++ b/src/api2/tape/drive.rs @@ -8,6 +8,7 @@ use crate::{ config, api2::types::{ DRIVE_ID_SCHEMA, + MEDIA_LABEL_SCHEMA, LinuxTapeDrive, ScsiTapeChanger, TapeDeviceInfo, @@ -56,6 +57,32 @@ pub fn load_slot( mtx_load(&changer.path, slot, drivenum) } +#[api( + input: { + properties: { + drive: { + schema: DRIVE_ID_SCHEMA, + }, + "changer-id": { + schema: MEDIA_LABEL_SCHEMA, + }, + }, + }, +)] +/// Load media with specified label +/// +/// Issue a media load request to the associated changer device. +pub fn load_media(drive: String, changer_id: String) -> Result<(), Error> { + + let (config, _digest) = config::drive::config()?; + + let (mut changer, _) = media_changer(&config, &drive, false)?; + + changer.load_media(&changer_id)?; + + Ok(()) +} + #[api( input: { properties: { diff --git a/src/api2/types/tape/drive.rs b/src/api2/types/tape/drive.rs index f9029db5..de046fbe 100644 --- a/src/api2/types/tape/drive.rs +++ b/src/api2/types/tape/drive.rs @@ -29,6 +29,12 @@ pub const SCSI_CHANGER_PATH_SCHEMA: Schema = StringSchema::new( "Path to Linux generic SCSI device (i.e. '/dev/sg4')") .schema(); +pub const MEDIA_LABEL_SCHEMA: Schema = StringSchema::new("Media Label/Barcode.") + .format(&PROXMOX_SAFE_ID_FORMAT) + .min_length(3) + .max_length(32) + .schema(); + #[api( properties: { name: { @@ -128,6 +134,10 @@ pub enum MtxEntryKind { "entry-kind": { type: MtxEntryKind, }, + "changer-id": { + schema: MEDIA_LABEL_SCHEMA, + optional: true, + }, }, )] #[derive(Serialize,Deserialize)] diff --git a/src/bin/proxmox-tape.rs b/src/bin/proxmox-tape.rs index 0bf1a5da..1df64ab4 100644 --- a/src/bin/proxmox-tape.rs +++ b/src/bin/proxmox-tape.rs @@ -16,12 +16,16 @@ use proxmox_backup::{ self, types::{ DRIVE_ID_SCHEMA, + MEDIA_LABEL_SCHEMA, }, }, config::{ self, drive::complete_drive_name, }, + tape::{ + complete_media_changer_id, + }, }; mod proxmox_tape; @@ -153,6 +157,39 @@ fn eject_media( Ok(()) } +#[api( + input: { + properties: { + drive: { + schema: DRIVE_ID_SCHEMA, + optional: true, + }, + "changer-id": { + schema: MEDIA_LABEL_SCHEMA, + }, + }, + }, +)] +/// Load media +fn load_media( + mut param: Value, + rpcenv: &mut dyn RpcEnvironment, +) -> Result<(), Error> { + + let (config, _digest) = config::drive::config()?; + + param["drive"] = lookup_drive_name(¶m, &config)?.into(); + + let info = &api2::tape::drive::API_METHOD_LOAD_MEDIA; + + match info.handler { + ApiHandler::Sync(handler) => (handler)(param, info, rpcenv)?, + _ => unreachable!(), + }; + + Ok(()) +} + fn main() { let cmd_def = CliCommandMap::new() @@ -173,6 +210,13 @@ fn main() { ) .insert("changer", changer_commands()) .insert("drive", drive_commands()) + .insert( + "load-media", + CliCommand::new(&API_METHOD_LOAD_MEDIA) + .arg_param(&["changer-id"]) + .completion_cb("drive", complete_drive_name) + .completion_cb("changer-id", complete_media_changer_id) + ) ; let mut rpcenv = CliEnvironment::new();