changer.load_media(&changer_id)
}).await?
}
+
#[api(
input: {
properties: {
}).await?
}
+#[api(
+ input: {
+ properties: {
+ drive: {
+ schema: DRIVE_NAME_SCHEMA,
+ },
+ "changer-id": {
+ schema: MEDIA_LABEL_SCHEMA,
+ },
+ },
+ },
+ returns: {
+ description: "The import-export slot number the media was transfered to.",
+ type: u64,
+ minimum: 1,
+ },
+)]
+/// Export media with specified label
+pub async fn export_media(drive: String, changer_id: String) -> Result<u64, Error> {
+
+ let (config, _digest) = config::drive::config()?;
+
+ tokio::task::spawn_blocking(move || {
+ let (mut changer, changer_name) = required_media_changer(&config, &drive)?;
+ match changer.export_media(&changer_id)? {
+ Some(slot) => Ok(slot),
+ None => bail!("media '{}' is not online (via changer '{}')", changer_id, changer_name),
+ }
+ }).await?
+}
+
#[api(
input: {
properties: {
Ok(())
}
+#[api(
+ input: {
+ properties: {
+ drive: {
+ schema: DRIVE_NAME_SCHEMA,
+ optional: true,
+ },
+ "changer-id": {
+ schema: MEDIA_LABEL_SCHEMA,
+ },
+ },
+ },
+)]
+/// Export media with specified label
+async fn export_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_EXPORT_MEDIA;
+
+ match info.handler {
+ ApiHandler::Async(handler) => (handler)(param, info, rpcenv).await?,
+ _ => unreachable!(),
+ };
+
+ Ok(())
+}
+
#[api(
input: {
properties: {
CliCommand::new(&API_METHOD_UNLOAD_MEDIA)
.completion_cb("drive", complete_drive_name)
)
+ .insert(
+ "export-media",
+ CliCommand::new(&API_METHOD_EXPORT_MEDIA)
+ .arg_param(&["changer-id"])
+ .completion_cb("drive", complete_drive_name)
+ .completion_cb("changer-id", complete_media_changer_id)
+ )
;
let mut rpcenv = CliEnvironment::new();
mod mtx;
pub use mtx::*;
-use anyhow::{bail, Error};
+use anyhow::Error;
/// Interface to media change devices
pub trait MediaChange {
/// By moving the media to an empty import-export slot. Returns
/// Some(slot) if the media was exported. Returns None if the media is
/// not online (already exported).
- fn export_media(&mut self, changer_id: &str) -> Result<Option<u64>, Error> {
- let status = self.status()?;
-
- let mut from = None;
- let mut to = None;
-
- for (i, (import_export, element_status)) in status.slots.iter().enumerate() {
- if *import_export {
- if to.is_some() { continue; }
- if let ElementStatus::Empty = element_status {
- to = Some(i as u64 + 1);
- }
- } else {
- if let ElementStatus::VolumeTag(ref tag) = element_status {
- if tag == changer_id {
- from = Some(i as u64 + 1);
- }
- }
- }
- }
- match (from, to) {
- (Some(from), Some(to)) => {
- self.transfer_media(from, to)?;
- Ok(Some(to))
- }
- (Some(_from), None) => bail!("unable to find free export slot"),
- (None, _) => Ok(None), // not online
- }
- }
-
+ fn export_media(&mut self, changer_id: &str) -> Result<Option<u64>, Error>;
}
}
let drive_status = &status.drives[drivenum as usize];
if let Some(slot) = drive_status.loaded_slot {
+ // fixme: check if slot is free
mtx_unload(path, slot, drivenum)
} else {
let mut free_slot = None;
Ok(())
}
+
+ fn export_media(&mut self, changer_id: &str) -> Result<Option<u64>, Error> {
+ let status = self.status()?;
+
+ let mut from_drive = None;
+ if let Some(drive_status) = status.drives.get(self.drivenum as usize) {
+ if let ElementStatus::VolumeTag(ref tag) = drive_status.status {
+ if tag == changer_id {
+ from_drive = Some(self.drivenum);
+ }
+ }
+ }
+
+ let mut from = None;
+ let mut to = None;
+
+ for (i, (import_export, element_status)) in status.slots.iter().enumerate() {
+ if *import_export {
+ if to.is_some() { continue; }
+ if let ElementStatus::Empty = element_status {
+ to = Some(i as u64 + 1);
+ }
+ } else {
+ if let ElementStatus::VolumeTag(ref tag) = element_status {
+ if tag == changer_id {
+ from = Some(i as u64 + 1);
+ }
+ }
+ }
+ }
+
+ if let Some(drivenum) = from_drive {
+ match to {
+ Some(to) => {
+ mtx_unload(&self.config.path, to, drivenum)?;
+ Ok(Some(to))
+ }
+ None => bail!("unable to find free export slot"),
+ }
+ } else {
+ match (from, to) {
+ (Some(from), Some(to)) => {
+ self.transfer_media(from, to)?;
+ Ok(Some(to))
+ }
+ (Some(_from), None) => bail!("unable to find free export slot"),
+ (None, _) => Ok(None), // not online
+ }
+ }
+ }
}
}
fn transfer_media(&mut self, _from: u64, _to: u64) -> Result<(), Error> {
- bail!("medfia tranfer is not implemented!");
+ bail!("media tranfer is not implemented!");
+ }
+
+ fn export_media(&mut self, _changer_id: &str) -> Result<Option<u64>, Error> {
+ bail!("media export is not implemented!");
}
fn load_media_from_slot(&mut self, slot: u64) -> Result<(), Error> {
handle.transfer_media(from, to)
}
+ fn export_media(&mut self, changer_id: &str) -> Result<Option<u64>, Error> {
+ let mut handle = self.open()?;
+ handle.export_media(changer_id)
+ }
+
fn load_media_from_slot(&mut self, slot: u64) -> Result<(), Error> {
let mut handle = self.open()?;
handle.load_media_from_slot(slot)