};
use crate::{
+ backup::KeyConfig,
tape::{
TapeWrite,
TapeRead,
- MtxStatus,
- DriveStatus,
- ElementStatus,
- changer::MediaChange,
+ changer::{
+ MediaChange,
+ MtxStatus,
+ DriveStatus,
+ ElementStatus,
+ StorageElementStatus,
+ },
drive::{
VirtualTapeDrive,
TapeDriver,
MediaSetLabel,
MediaContentHeader,
PROXMOX_BACKUP_MEDIA_SET_LABEL_MAGIC_1_0,
+ BlockedReader,
+ BlockedWriter,
},
helpers::{
EmulateTapeReader,
EmulateTapeWriter,
- BlockedReader,
- BlockedWriter,
},
},
};
/// This needs to lock the drive
pub fn open(&self) -> Result<VirtualTapeHandle, Error> {
- let mut lock_path = std::path::PathBuf::from(&self.path);
- lock_path.push(".drive.lck");
+ proxmox::try_block!({
+ let mut lock_path = std::path::PathBuf::from(&self.path);
+ lock_path.push(".drive.lck");
- let timeout = std::time::Duration::new(10, 0);
- let lock = proxmox::tools::fs::open_file_locked(&lock_path, timeout, true)?;
+ let timeout = std::time::Duration::new(10, 0);
+ let lock = proxmox::tools::fs::open_file_locked(&lock_path, timeout, true)?;
- Ok(VirtualTapeHandle {
- _lock: lock,
- max_size: self.max_size.unwrap_or(64*1024*1024),
- path: std::path::PathBuf::from(&self.path),
- })
+ Ok(VirtualTapeHandle {
+ _lock: lock,
+ drive_name: self.name.clone(),
+ max_size: self.max_size.unwrap_or(64*1024*1024),
+ path: std::path::PathBuf::from(&self.path),
+ })
+ }).map_err(|err: Error| format_err!("open drive '{}' ({}) failed - {}", self.name, self.path, err))
}
}
}
pub struct VirtualTapeHandle {
+ drive_name: String,
path: std::path::PathBuf,
max_size: usize,
_lock: File,
Ok(())
}
- fn online_media_changer_ids(&self) -> Result<Vec<String>, Error> {
+ fn online_media_label_texts(&self) -> Result<Vec<String>, Error> {
let mut list = Vec::new();
for entry in std::fs::read_dir(&self.path)? {
let entry = entry?;
if path.is_file() && path.extension() == Some(std::ffi::OsStr::new("json")) {
if let Some(name) = path.file_stem() {
if let Some(name) = name.to_str() {
- if name.starts_with("tape-") {
- list.push(name[5..].to_string());
+ if let Some(label) = name.strip_prefix("tape-") {
+ list.push(label.to_string());
}
}
}
}
}
- fn write_media_set_label(&mut self, media_set_label: &MediaSetLabel) -> Result<(), Error> {
+ fn write_media_set_label(
+ &mut self,
+ media_set_label: &MediaSetLabel,
+ key_config: Option<&KeyConfig>,
+ ) -> Result<(), Error> {
+
+ self.set_encryption(None)?;
+
+ if key_config.is_some() {
+ bail!("encryption is not implemented - internal error");
+ }
let mut status = self.load_status()?;
match status.current_tape {
impl MediaChange for VirtualTapeHandle {
+ fn drive_number(&self) -> u64 {
+ 0
+ }
+
+ fn drive_name(&self) -> &str {
+ &self.drive_name
+ }
+
fn status(&mut self) -> Result<MtxStatus, Error> {
let drive_status = self.load_status()?;
drives.push(DriveStatus {
loaded_slot: None,
status: ElementStatus::VolumeTag(current_tape.name.clone()),
- });
+ drive_serial_number: None,
+ vendor: None,
+ model: None,
+ element_address: 0,
+ });
}
// This implementation is lame, because we do not have fixed
// slot-assignment here.
let mut slots = Vec::new();
- let changer_ids = self.online_media_changer_ids()?;
- let max_slots = ((changer_ids.len() + 7)/8) * 8;
+ let label_texts = self.online_media_label_texts()?;
+ let max_slots = ((label_texts.len() + 7)/8) * 8;
for i in 0..max_slots {
- if let Some(changer_id) = changer_ids.get(i) {
- slots.push((false, ElementStatus::VolumeTag(changer_id.clone())));
+ let status = if let Some(label_text) = label_texts.get(i) {
+ ElementStatus::VolumeTag(label_text.clone())
} else {
- slots.push((false, ElementStatus::Empty));
- }
+ ElementStatus::Empty
+ };
+ slots.push(StorageElementStatus {
+ import_export: false,
+ status,
+ element_address: (i + 1) as u16,
+ });
}
- Ok(MtxStatus { drives, slots })
+ Ok(MtxStatus { drives, slots, transports: Vec::new() })
+ }
+
+ fn transfer_media(&mut self, _from: u64, _to: u64) -> Result<MtxStatus, Error> {
+ bail!("media transfer is not implemented!");
}
- fn transfer(&mut self, from: u64, to: u64) -> Result<(), Error> {
- bail!("medfia tranfer is not implemented!");
+ fn export_media(&mut self, _label_text: &str) -> Result<Option<u64>, Error> {
+ bail!("media export is not implemented!");
}
- fn load_media_from_slot(&mut self, slot: u64) -> Result<(), Error> {
+ fn load_media_from_slot(&mut self, slot: u64) -> Result<MtxStatus, Error> {
if slot < 1 {
bail!("invalid slot ID {}", slot);
}
- let changer_ids = self.online_media_changer_ids()?;
+ let label_texts = self.online_media_label_texts()?;
- if slot > changer_ids.len() as u64 {
+ if slot > label_texts.len() as u64 {
bail!("slot {} is empty", slot);
}
- self.load_media(&changer_ids[slot as usize - 1])
+ self.load_media(&label_texts[slot as usize - 1])
}
/// Try to load media
///
/// We automatically create an empty virtual tape here (if it does
/// not exist already)
- fn load_media(&mut self, label: &str) -> Result<(), Error> {
+ fn load_media(&mut self, label: &str) -> Result<MtxStatus, Error> {
let name = format!("tape-{}.json", label);
let mut path = self.path.clone();
path.push(&name);
pos: 0,
}),
};
- self.store_status(&status)
+ self.store_status(&status)?;
+
+ self.status()
}
- fn unload_media(&mut self, _target_slot: Option<u64>) -> Result<(), Error> {
+ fn unload_media(&mut self, _target_slot: Option<u64>) -> Result<MtxStatus, Error> {
// Note: we currently simply ignore target_slot
self.eject_media()?;
- Ok(())
+ self.status()
}
- fn eject_on_unload(&self) -> bool {
- true
- }
-
- fn clean_drive(&mut self) -> Result<(), Error> {
- Ok(())
+ fn clean_drive(&mut self) -> Result<MtxStatus, Error> {
+ // do nothing
+ self.status()
}
}
impl MediaChange for VirtualTapeDrive {
+ fn drive_number(&self) -> u64 {
+ 0
+ }
+
+ fn drive_name(&self) -> &str {
+ &self.name
+ }
+
fn status(&mut self) -> Result<MtxStatus, Error> {
let mut handle = self.open()?;
handle.status()
}
- fn transfer(&mut self, from: u64, to: u64) -> Result<(), Error> {
+ fn transfer_media(&mut self, from: u64, to: u64) -> Result<MtxStatus, Error> {
let mut handle = self.open()?;
- handle.transfer(from, to)
+ handle.transfer_media(from, to)
}
- fn load_media_from_slot(&mut self, slot: u64) -> Result<(), Error> {
+ fn export_media(&mut self, label_text: &str) -> Result<Option<u64>, Error> {
let mut handle = self.open()?;
- handle.load_media_from_slot(slot)
+ handle.export_media(label_text)
}
- fn load_media(&mut self, changer_id: &str) -> Result<(), Error> {
+ fn load_media_from_slot(&mut self, slot: u64) -> Result<MtxStatus, Error> {
let mut handle = self.open()?;
- handle.load_media(changer_id)
+ handle.load_media_from_slot(slot)
}
- fn unload_media(&mut self, target_slot: Option<u64>) -> Result<(), Error> {
+ fn load_media(&mut self, label_text: &str) -> Result<MtxStatus, Error> {
let mut handle = self.open()?;
- handle.unload_media(target_slot)?;
- Ok(())
+ handle.load_media(label_text)
}
- fn eject_on_unload(&self) -> bool {
- true
+ fn unload_media(&mut self, target_slot: Option<u64>) -> Result<MtxStatus, Error> {
+ let mut handle = self.open()?;
+ handle.unload_media(target_slot)
}
- fn online_media_changer_ids(&mut self) -> Result<Vec<String>, Error> {
+ fn online_media_label_texts(&mut self) -> Result<Vec<String>, Error> {
let handle = self.open()?;
- handle.online_media_changer_ids()
+ handle.online_media_label_texts()
}
- fn clean_drive(&mut self) -> Result<(), Error> {
- Ok(())
+ fn clean_drive(&mut self) -> Result<MtxStatus, Error> {
+ let mut handle = self.open()?;
+ handle.clean_drive()
}
-
}