tape: implement drive clean
This commit is contained in:
parent
25d3965769
commit
df69a4fc59
@ -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()
|
||||
|
@ -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(¶m, &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)
|
||||
|
@ -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(())
|
||||
}
|
||||
}
|
||||
|
@ -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>;
|
||||
}
|
||||
|
@ -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(())
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user