tape: implement drive clean

This commit is contained in:
Dietmar Maurer 2021-01-08 11:32:56 +01:00
parent 25d3965769
commit df69a4fc59
5 changed files with 148 additions and 0 deletions

View File

@ -480,6 +480,53 @@ pub async fn read_label(drive: String) -> Result<MediaIdFlat, Error> {
}).await?
}
#[api(
input: {
properties: {
drive: {
schema: DRIVE_NAME_SCHEMA,
},
},
},
returns: {
schema: UPID_SCHEMA,
},
)]
/// Clean drive
pub fn clean_drive(
drive: String,
rpcenv: &mut dyn RpcEnvironment,
) -> Result<Value, Error> {
let (config, _digest) = config::drive::config()?;
check_drive_exists(&config, &drive)?; // early check before starting worker
let auth_id: Authid = rpcenv.get_auth_id().unwrap().parse()?;
let to_stdout = if rpcenv.env_type() == RpcEnvironmentType::CLI { true } else { false };
let upid_str = WorkerTask::new_thread(
"clean-drive",
Some(drive.clone()),
auth_id,
to_stdout,
move |worker| {
let (mut changer, _changer_name) = required_media_changer(&config, &drive)?;
worker.log("Starting drive clean");
changer.clean_drive()?;
worker.log("Drive cleaned sucessfully");
Ok(())
})?;
Ok(upid_str.into())
}
#[api(
input: {
properties: {
@ -643,6 +690,7 @@ pub fn update_inventory(
inventory.store(media_id, false)?;
}
}
changer.unload_media(None)?;
}
Ok(())
}
@ -940,6 +988,11 @@ pub const SUBDIRS: SubdirMap = &sorted!([
&Router::new()
.put(&API_METHOD_CATALOG_MEDIA)
),
(
"clean",
&Router::new()
.put(&API_METHOD_CLEAN_DRIVE)
),
(
"eject-media",
&Router::new()

View File

@ -677,6 +677,38 @@ fn status(
Ok(())
}
#[api(
input: {
properties: {
drive: {
schema: DRIVE_NAME_SCHEMA,
optional: true,
},
},
},
)]
/// Clean drive
async fn clean_drive(
mut param: Value,
rpcenv: &mut dyn RpcEnvironment,
) -> Result<(), Error> {
let (config, _digest) = config::drive::config()?;
param["drive"] = lookup_drive_name(&param, &config)?.into();
let info = &api2::tape::drive::API_METHOD_CLEAN_DRIVE;
let result = match info.handler {
ApiHandler::Sync(handler) => (handler)(param, info, rpcenv)?,
_ => unreachable!(),
};
wait_for_local_worker(result.as_str().unwrap()).await?;
Ok(())
}
#[api(
input: {
properties: {
@ -856,6 +888,11 @@ fn main() {
CliCommand::new(&API_METHOD_CARTRIDGE_MEMORY)
.completion_cb("drive", complete_drive_name)
)
.insert(
"clean",
CliCommand::new(&API_METHOD_CLEAN_DRIVE)
.completion_cb("drive", complete_drive_name)
)
.insert(
"label",
CliCommand::new(&API_METHOD_LABEL_MEDIA)

View File

@ -145,4 +145,47 @@ impl MediaChange for LinuxTapeDrive {
fn eject_on_unload(&self) -> bool {
true
}
fn clean_drive(&mut self) -> Result<(), Error> {
let (config, _digest) = crate::config::drive::config()?;
let changer: ScsiTapeChanger = match self.changer {
Some(ref changer) => config.lookup("changer", changer)?,
None => bail!("unable to load cleaning cartridge - no associated changer device"),
};
let drivenum = self.changer_drive_id.unwrap_or(0);
let status = mtx_status(&changer)?;
let mut cleaning_cartridge_slot = None;
for (i, (import_export, element_status)) in status.slots.iter().enumerate() {
if *import_export { continue; }
if let ElementStatus::VolumeTag(ref tag) = element_status {
if tag.starts_with("CLN") {
cleaning_cartridge_slot = Some(i + 1);
break;
}
}
}
let cleaning_cartridge_slot = match cleaning_cartridge_slot {
None => bail!("clean failed - unable to find cleaning cartridge"),
Some(cleaning_cartridge_slot) => cleaning_cartridge_slot as u64,
};
if let Some(drive_status) = status.drives.get(drivenum as usize) {
match drive_status.status {
ElementStatus::Empty => { /* OK */ },
_ => unload_to_free_slot(&self.name, &changer.path, &status, drivenum)?,
}
}
mtx_load(&changer.path, cleaning_cartridge_slot, drivenum)?;
mtx_unload(&changer.path, cleaning_cartridge_slot, drivenum)?;
Ok(())
}
}

View File

@ -63,4 +63,10 @@ pub trait MediaChange {
Ok(list)
}
/// Load/Unload cleaning cartridge
///
/// This fail if there is no cleaning cartridge online. Any media
/// inside the drive is automatically unloaded.
fn clean_drive(&mut self) -> Result<(), Error>;
}

View File

@ -439,6 +439,10 @@ impl MediaChange for VirtualTapeHandle {
fn eject_on_unload(&self) -> bool {
true
}
fn clean_drive(&mut self) -> Result<(), Error> {
Ok(())
}
}
impl MediaChange for VirtualTapeDrive {
@ -472,4 +476,9 @@ impl MediaChange for VirtualTapeDrive {
let handle = self.open()?;
handle.online_media_changer_ids()
}
fn clean_drive(&mut self) -> Result<(), Error> {
Ok(())
}
}