move drive config to pbs_config workspace
Also moved the tape type definitions to pbs_api_types.
This commit is contained in:
parent
ccb3b45e18
commit
1ce8e905ea
|
@ -61,6 +61,9 @@ pub mod file_restore;
|
||||||
mod remote;
|
mod remote;
|
||||||
pub use remote::*;
|
pub use remote::*;
|
||||||
|
|
||||||
|
mod tape;
|
||||||
|
pub use tape::*;
|
||||||
|
|
||||||
#[rustfmt::skip]
|
#[rustfmt::skip]
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
mod local_macros {
|
mod local_macros {
|
||||||
|
|
|
@ -13,7 +13,7 @@ use proxmox::api::{
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::api2::types::{
|
use crate::{
|
||||||
PROXMOX_SAFE_ID_FORMAT,
|
PROXMOX_SAFE_ID_FORMAT,
|
||||||
OptionalDeviceIdentification,
|
OptionalDeviceIdentification,
|
||||||
};
|
};
|
|
@ -9,7 +9,7 @@ use proxmox::api::{
|
||||||
schema::{Schema, IntegerSchema, StringSchema, Updater},
|
schema::{Schema, IntegerSchema, StringSchema, Updater},
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::api2::types::{
|
use crate::{
|
||||||
PROXMOX_SAFE_ID_FORMAT,
|
PROXMOX_SAFE_ID_FORMAT,
|
||||||
CHANGER_NAME_SCHEMA,
|
CHANGER_NAME_SCHEMA,
|
||||||
OptionalDeviceIdentification,
|
OptionalDeviceIdentification,
|
|
@ -1,17 +1,26 @@
|
||||||
use ::serde::{Deserialize, Serialize};
|
use ::serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use proxmox::{
|
use proxmox::{
|
||||||
api::api,
|
api::{api, schema::*},
|
||||||
tools::Uuid,
|
tools::Uuid,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::api2::types::{
|
use crate::{
|
||||||
MEDIA_UUID_SCHEMA,
|
UUID_FORMAT,
|
||||||
MEDIA_SET_UUID_SCHEMA,
|
|
||||||
MediaStatus,
|
MediaStatus,
|
||||||
MediaLocation,
|
MediaLocation,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub const MEDIA_SET_UUID_SCHEMA: Schema =
|
||||||
|
StringSchema::new("MediaSet Uuid (We use the all-zero Uuid to reseve an empty media for a specific pool).")
|
||||||
|
.format(&UUID_FORMAT)
|
||||||
|
.schema();
|
||||||
|
|
||||||
|
pub const MEDIA_UUID_SCHEMA: Schema =
|
||||||
|
StringSchema::new("Media Uuid.")
|
||||||
|
.format(&UUID_FORMAT)
|
||||||
|
.schema();
|
||||||
|
|
||||||
#[api(
|
#[api(
|
||||||
properties: {
|
properties: {
|
||||||
"media-set-uuid": {
|
"media-set-uuid": {
|
|
@ -9,7 +9,7 @@ use proxmox::api::{
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::api2::types::{
|
use crate::{
|
||||||
PROXMOX_SAFE_ID_FORMAT,
|
PROXMOX_SAFE_ID_FORMAT,
|
||||||
CHANGER_NAME_SCHEMA,
|
CHANGER_NAME_SCHEMA,
|
||||||
};
|
};
|
|
@ -16,7 +16,7 @@ use proxmox::api::{
|
||||||
|
|
||||||
use pbs_systemd::time::{parse_calendar_event, parse_time_span, CalendarEvent, TimeSpan};
|
use pbs_systemd::time::{parse_calendar_event, parse_time_span, CalendarEvent, TimeSpan};
|
||||||
|
|
||||||
use crate::api2::types::{
|
use crate::{
|
||||||
PROXMOX_SAFE_ID_FORMAT,
|
PROXMOX_SAFE_ID_FORMAT,
|
||||||
SINGLE_LINE_COMMENT_FORMAT,
|
SINGLE_LINE_COMMENT_FORMAT,
|
||||||
SINGLE_LINE_COMMENT_SCHEMA,
|
SINGLE_LINE_COMMENT_SCHEMA,
|
|
@ -0,0 +1,94 @@
|
||||||
|
//! Types for tape backup API
|
||||||
|
|
||||||
|
mod device;
|
||||||
|
pub use device::*;
|
||||||
|
|
||||||
|
mod changer;
|
||||||
|
pub use changer::*;
|
||||||
|
|
||||||
|
mod drive;
|
||||||
|
pub use drive::*;
|
||||||
|
|
||||||
|
mod media_pool;
|
||||||
|
pub use media_pool::*;
|
||||||
|
|
||||||
|
mod media_status;
|
||||||
|
pub use media_status::*;
|
||||||
|
|
||||||
|
mod media_location;
|
||||||
|
|
||||||
|
pub use media_location::*;
|
||||||
|
|
||||||
|
mod media;
|
||||||
|
pub use media::*;
|
||||||
|
|
||||||
|
use ::serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
use proxmox::api::api;
|
||||||
|
use proxmox::api::schema::{Schema, StringSchema, ApiStringFormat};
|
||||||
|
use proxmox::tools::Uuid;
|
||||||
|
|
||||||
|
use proxmox::const_regex;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
FINGERPRINT_SHA256_FORMAT, BACKUP_ID_SCHEMA, BACKUP_TYPE_SCHEMA,
|
||||||
|
};
|
||||||
|
|
||||||
|
const_regex!{
|
||||||
|
pub TAPE_RESTORE_SNAPSHOT_REGEX = concat!(r"^", PROXMOX_SAFE_ID_REGEX_STR!(), r":", SNAPSHOT_PATH_REGEX_STR!(), r"$");
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const TAPE_RESTORE_SNAPSHOT_FORMAT: ApiStringFormat =
|
||||||
|
ApiStringFormat::Pattern(&TAPE_RESTORE_SNAPSHOT_REGEX);
|
||||||
|
|
||||||
|
pub const TAPE_ENCRYPTION_KEY_FINGERPRINT_SCHEMA: Schema = StringSchema::new(
|
||||||
|
"Tape encryption key fingerprint (sha256)."
|
||||||
|
)
|
||||||
|
.format(&FINGERPRINT_SHA256_FORMAT)
|
||||||
|
.schema();
|
||||||
|
|
||||||
|
pub const TAPE_RESTORE_SNAPSHOT_SCHEMA: Schema = StringSchema::new(
|
||||||
|
"A snapshot in the format: 'store:type/id/time")
|
||||||
|
.format(&TAPE_RESTORE_SNAPSHOT_FORMAT)
|
||||||
|
.type_text("store:type/id/time")
|
||||||
|
.schema();
|
||||||
|
|
||||||
|
#[api(
|
||||||
|
properties: {
|
||||||
|
pool: {
|
||||||
|
schema: MEDIA_POOL_NAME_SCHEMA,
|
||||||
|
optional: true,
|
||||||
|
},
|
||||||
|
"label-text": {
|
||||||
|
schema: MEDIA_LABEL_SCHEMA,
|
||||||
|
optional: true,
|
||||||
|
},
|
||||||
|
"media": {
|
||||||
|
schema: MEDIA_UUID_SCHEMA,
|
||||||
|
optional: true,
|
||||||
|
},
|
||||||
|
"media-set": {
|
||||||
|
schema: MEDIA_SET_UUID_SCHEMA,
|
||||||
|
optional: true,
|
||||||
|
},
|
||||||
|
"backup-type": {
|
||||||
|
schema: BACKUP_TYPE_SCHEMA,
|
||||||
|
optional: true,
|
||||||
|
},
|
||||||
|
"backup-id": {
|
||||||
|
schema: BACKUP_ID_SCHEMA,
|
||||||
|
optional: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)]
|
||||||
|
#[derive(Serialize,Deserialize)]
|
||||||
|
#[serde(rename_all="kebab-case")]
|
||||||
|
/// Content list filter parameters
|
||||||
|
pub struct MediaContentListFilter {
|
||||||
|
pub pool: Option<String>,
|
||||||
|
pub label_text: Option<String>,
|
||||||
|
pub media: Option<Uuid>,
|
||||||
|
pub media_set: Option<Uuid>,
|
||||||
|
pub backup_type: Option<String>,
|
||||||
|
pub backup_id: Option<String>,
|
||||||
|
}
|
|
@ -27,17 +27,13 @@ use proxmox::{
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
use pbs_config::{open_backup_lockfile, BackupLockGuard};
|
use crate::{open_backup_lockfile, replace_backup_config, BackupLockGuard};
|
||||||
|
|
||||||
use crate::{
|
use pbs_api_types::{
|
||||||
api2::types::{
|
DRIVE_NAME_SCHEMA, VirtualTapeDrive, LtoTapeDrive, ScsiTapeChanger,
|
||||||
DRIVE_NAME_SCHEMA,
|
|
||||||
VirtualTapeDrive,
|
|
||||||
LtoTapeDrive,
|
|
||||||
ScsiTapeChanger,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
/// Static [`SectionConfig`] to access parser/writer functions.
|
/// Static [`SectionConfig`] to access parser/writer functions.
|
||||||
pub static ref CONFIG: SectionConfig = init();
|
pub static ref CONFIG: SectionConfig = init();
|
||||||
|
@ -94,7 +90,7 @@ pub fn config() -> Result<(SectionConfigData, [u8;32]), Error> {
|
||||||
/// Save the configuration file
|
/// Save the configuration file
|
||||||
pub fn save_config(config: &SectionConfigData) -> Result<(), Error> {
|
pub fn save_config(config: &SectionConfigData) -> Result<(), Error> {
|
||||||
let raw = CONFIG.write(DRIVE_CFG_FILENAME, &config)?;
|
let raw = CONFIG.write(DRIVE_CFG_FILENAME, &config)?;
|
||||||
pbs_config::replace_backup_config(DRIVE_CFG_FILENAME, raw.as_bytes())
|
replace_backup_config(DRIVE_CFG_FILENAME, raw.as_bytes())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check if the specified drive name exists in the config.
|
/// Check if the specified drive name exists in the config.
|
|
@ -1,4 +1,5 @@
|
||||||
pub mod domains;
|
pub mod domains;
|
||||||
|
pub mod drive;
|
||||||
pub mod remote;
|
pub mod remote;
|
||||||
|
|
||||||
use anyhow::{format_err, Error};
|
use anyhow::{format_err, Error};
|
||||||
|
|
|
@ -10,25 +10,25 @@ use proxmox::api::{
|
||||||
schema::parse_property_string,
|
schema::parse_property_string,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use pbs_api_types::{
|
||||||
|
Authid,
|
||||||
|
PROXMOX_CONFIG_DIGEST_SCHEMA,
|
||||||
|
CHANGER_NAME_SCHEMA,
|
||||||
|
SCSI_CHANGER_PATH_SCHEMA,
|
||||||
|
SLOT_ARRAY_SCHEMA,
|
||||||
|
EXPORT_SLOT_LIST_SCHEMA,
|
||||||
|
ScsiTapeChanger,
|
||||||
|
LtoTapeDrive,
|
||||||
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
config::{
|
config::{
|
||||||
self,
|
|
||||||
cached_user_info::CachedUserInfo,
|
cached_user_info::CachedUserInfo,
|
||||||
acl::{
|
acl::{
|
||||||
PRIV_TAPE_AUDIT,
|
PRIV_TAPE_AUDIT,
|
||||||
PRIV_TAPE_MODIFY,
|
PRIV_TAPE_MODIFY,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
api2::types::{
|
|
||||||
Authid,
|
|
||||||
PROXMOX_CONFIG_DIGEST_SCHEMA,
|
|
||||||
CHANGER_NAME_SCHEMA,
|
|
||||||
SCSI_CHANGER_PATH_SCHEMA,
|
|
||||||
SLOT_ARRAY_SCHEMA,
|
|
||||||
EXPORT_SLOT_LIST_SCHEMA,
|
|
||||||
ScsiTapeChanger,
|
|
||||||
LtoTapeDrive,
|
|
||||||
},
|
|
||||||
tape::{
|
tape::{
|
||||||
linux_tape_changer_list,
|
linux_tape_changer_list,
|
||||||
check_drive_path,
|
check_drive_path,
|
||||||
|
@ -62,9 +62,9 @@ pub fn create_changer(
|
||||||
export_slots: Option<String>,
|
export_slots: Option<String>,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
|
|
||||||
let _lock = config::drive::lock()?;
|
let _lock = pbs_config::drive::lock()?;
|
||||||
|
|
||||||
let (mut config, _digest) = config::drive::config()?;
|
let (mut config, _digest) = pbs_config::drive::config()?;
|
||||||
|
|
||||||
let linux_changers = linux_tape_changer_list();
|
let linux_changers = linux_tape_changer_list();
|
||||||
|
|
||||||
|
@ -90,7 +90,7 @@ pub fn create_changer(
|
||||||
|
|
||||||
config.set_data(&name, "changer", &item)?;
|
config.set_data(&name, "changer", &item)?;
|
||||||
|
|
||||||
config::drive::save_config(&config)?;
|
pbs_config::drive::save_config(&config)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -117,7 +117,7 @@ pub fn get_config(
|
||||||
mut rpcenv: &mut dyn RpcEnvironment,
|
mut rpcenv: &mut dyn RpcEnvironment,
|
||||||
) -> Result<ScsiTapeChanger, Error> {
|
) -> Result<ScsiTapeChanger, Error> {
|
||||||
|
|
||||||
let (config, digest) = config::drive::config()?;
|
let (config, digest) = pbs_config::drive::config()?;
|
||||||
|
|
||||||
let data: ScsiTapeChanger = config.lookup("changer", &name)?;
|
let data: ScsiTapeChanger = config.lookup("changer", &name)?;
|
||||||
|
|
||||||
|
@ -150,7 +150,7 @@ pub fn list_changers(
|
||||||
let auth_id: Authid = rpcenv.get_auth_id().unwrap().parse()?;
|
let auth_id: Authid = rpcenv.get_auth_id().unwrap().parse()?;
|
||||||
let user_info = CachedUserInfo::new()?;
|
let user_info = CachedUserInfo::new()?;
|
||||||
|
|
||||||
let (config, digest) = config::drive::config()?;
|
let (config, digest) = pbs_config::drive::config()?;
|
||||||
|
|
||||||
let list: Vec<ScsiTapeChanger> = config.convert_to_typed_array("changer")?;
|
let list: Vec<ScsiTapeChanger> = config.convert_to_typed_array("changer")?;
|
||||||
|
|
||||||
|
@ -219,9 +219,9 @@ pub fn update_changer(
|
||||||
_param: Value,
|
_param: Value,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
|
|
||||||
let _lock = config::drive::lock()?;
|
let _lock = pbs_config::drive::lock()?;
|
||||||
|
|
||||||
let (mut config, expected_digest) = config::drive::config()?;
|
let (mut config, expected_digest) = pbs_config::drive::config()?;
|
||||||
|
|
||||||
if let Some(ref digest) = digest {
|
if let Some(ref digest) = digest {
|
||||||
let digest = proxmox::tools::hex_to_digest(digest)?;
|
let digest = proxmox::tools::hex_to_digest(digest)?;
|
||||||
|
@ -268,7 +268,7 @@ pub fn update_changer(
|
||||||
|
|
||||||
config.set_data(&name, "changer", &data)?;
|
config.set_data(&name, "changer", &data)?;
|
||||||
|
|
||||||
config::drive::save_config(&config)?;
|
pbs_config::drive::save_config(&config)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -289,9 +289,9 @@ pub fn update_changer(
|
||||||
/// Delete a tape changer configuration
|
/// Delete a tape changer configuration
|
||||||
pub fn delete_changer(name: String, _param: Value) -> Result<(), Error> {
|
pub fn delete_changer(name: String, _param: Value) -> Result<(), Error> {
|
||||||
|
|
||||||
let _lock = config::drive::lock()?;
|
let _lock = pbs_config::drive::lock()?;
|
||||||
|
|
||||||
let (mut config, _digest) = config::drive::config()?;
|
let (mut config, _digest) = pbs_config::drive::config()?;
|
||||||
|
|
||||||
match config.sections.get(&name) {
|
match config.sections.get(&name) {
|
||||||
Some((section_type, _)) => {
|
Some((section_type, _)) => {
|
||||||
|
@ -312,7 +312,7 @@ pub fn delete_changer(name: String, _param: Value) -> Result<(), Error> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
config::drive::save_config(&config)?;
|
pbs_config::drive::save_config(&config)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,23 +4,23 @@ use serde_json::Value;
|
||||||
|
|
||||||
use proxmox::api::{api, Router, RpcEnvironment, Permission};
|
use proxmox::api::{api, Router, RpcEnvironment, Permission};
|
||||||
|
|
||||||
|
use pbs_api_types::{
|
||||||
|
Authid,
|
||||||
|
PROXMOX_CONFIG_DIGEST_SCHEMA,
|
||||||
|
DRIVE_NAME_SCHEMA,
|
||||||
|
LtoTapeDrive,
|
||||||
|
LtoTapeDriveUpdater,
|
||||||
|
ScsiTapeChanger,
|
||||||
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
config::{
|
config::{
|
||||||
self,
|
|
||||||
cached_user_info::CachedUserInfo,
|
cached_user_info::CachedUserInfo,
|
||||||
acl::{
|
acl::{
|
||||||
PRIV_TAPE_AUDIT,
|
PRIV_TAPE_AUDIT,
|
||||||
PRIV_TAPE_MODIFY,
|
PRIV_TAPE_MODIFY,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
api2::types::{
|
|
||||||
Authid,
|
|
||||||
PROXMOX_CONFIG_DIGEST_SCHEMA,
|
|
||||||
DRIVE_NAME_SCHEMA,
|
|
||||||
LtoTapeDrive,
|
|
||||||
LtoTapeDriveUpdater,
|
|
||||||
ScsiTapeChanger,
|
|
||||||
},
|
|
||||||
tape::{
|
tape::{
|
||||||
lto_tape_device_list,
|
lto_tape_device_list,
|
||||||
check_drive_path,
|
check_drive_path,
|
||||||
|
@ -44,9 +44,9 @@ use crate::{
|
||||||
/// Create a new drive
|
/// Create a new drive
|
||||||
pub fn create_drive(config: LtoTapeDrive) -> Result<(), Error> {
|
pub fn create_drive(config: LtoTapeDrive) -> Result<(), Error> {
|
||||||
|
|
||||||
let _lock = config::drive::lock()?;
|
let _lock = pbs_config::drive::lock()?;
|
||||||
|
|
||||||
let (mut section_config, _digest) = config::drive::config()?;
|
let (mut section_config, _digest) = pbs_config::drive::config()?;
|
||||||
|
|
||||||
let lto_drives = lto_tape_device_list();
|
let lto_drives = lto_tape_device_list();
|
||||||
|
|
||||||
|
@ -65,7 +65,7 @@ pub fn create_drive(config: LtoTapeDrive) -> Result<(), Error> {
|
||||||
|
|
||||||
section_config.set_data(&config.name, "lto", &config)?;
|
section_config.set_data(&config.name, "lto", &config)?;
|
||||||
|
|
||||||
config::drive::save_config(§ion_config)?;
|
pbs_config::drive::save_config(§ion_config)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -92,7 +92,7 @@ pub fn get_config(
|
||||||
mut rpcenv: &mut dyn RpcEnvironment,
|
mut rpcenv: &mut dyn RpcEnvironment,
|
||||||
) -> Result<LtoTapeDrive, Error> {
|
) -> Result<LtoTapeDrive, Error> {
|
||||||
|
|
||||||
let (config, digest) = config::drive::config()?;
|
let (config, digest) = pbs_config::drive::config()?;
|
||||||
|
|
||||||
let data: LtoTapeDrive = config.lookup("lto", &name)?;
|
let data: LtoTapeDrive = config.lookup("lto", &name)?;
|
||||||
|
|
||||||
|
@ -125,7 +125,7 @@ pub fn list_drives(
|
||||||
let auth_id: Authid = rpcenv.get_auth_id().unwrap().parse()?;
|
let auth_id: Authid = rpcenv.get_auth_id().unwrap().parse()?;
|
||||||
let user_info = CachedUserInfo::new()?;
|
let user_info = CachedUserInfo::new()?;
|
||||||
|
|
||||||
let (config, digest) = config::drive::config()?;
|
let (config, digest) = pbs_config::drive::config()?;
|
||||||
|
|
||||||
let drive_list: Vec<LtoTapeDrive> = config.convert_to_typed_array("lto")?;
|
let drive_list: Vec<LtoTapeDrive> = config.convert_to_typed_array("lto")?;
|
||||||
|
|
||||||
|
@ -192,9 +192,9 @@ pub fn update_drive(
|
||||||
_param: Value,
|
_param: Value,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
|
|
||||||
let _lock = config::drive::lock()?;
|
let _lock = pbs_config::drive::lock()?;
|
||||||
|
|
||||||
let (mut config, expected_digest) = config::drive::config()?;
|
let (mut config, expected_digest) = pbs_config::drive::config()?;
|
||||||
|
|
||||||
if let Some(ref digest) = digest {
|
if let Some(ref digest) = digest {
|
||||||
let digest = proxmox::tools::hex_to_digest(digest)?;
|
let digest = proxmox::tools::hex_to_digest(digest)?;
|
||||||
|
@ -239,7 +239,7 @@ pub fn update_drive(
|
||||||
|
|
||||||
config.set_data(&name, "lto", &data)?;
|
config.set_data(&name, "lto", &data)?;
|
||||||
|
|
||||||
config::drive::save_config(&config)?;
|
pbs_config::drive::save_config(&config)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -260,9 +260,9 @@ pub fn update_drive(
|
||||||
/// Delete a drive configuration
|
/// Delete a drive configuration
|
||||||
pub fn delete_drive(name: String, _param: Value) -> Result<(), Error> {
|
pub fn delete_drive(name: String, _param: Value) -> Result<(), Error> {
|
||||||
|
|
||||||
let _lock = config::drive::lock()?;
|
let _lock = pbs_config::drive::lock()?;
|
||||||
|
|
||||||
let (mut config, _digest) = config::drive::config()?;
|
let (mut config, _digest) = pbs_config::drive::config()?;
|
||||||
|
|
||||||
match config.sections.get(&name) {
|
match config.sections.get(&name) {
|
||||||
Some((section_type, _)) => {
|
Some((section_type, _)) => {
|
||||||
|
@ -274,7 +274,7 @@ pub fn delete_drive(name: String, _param: Value) -> Result<(), Error> {
|
||||||
None => bail!("Delete drive '{}' failed - no such drive", name),
|
None => bail!("Delete drive '{}' failed - no such drive", name),
|
||||||
}
|
}
|
||||||
|
|
||||||
config::drive::save_config(&config)?;
|
pbs_config::drive::save_config(&config)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -123,7 +123,7 @@ pub fn list_tape_backup_jobs(
|
||||||
|
|
||||||
let (job_config, digest) = config::tape_job::config()?;
|
let (job_config, digest) = config::tape_job::config()?;
|
||||||
let (pool_config, _pool_digest) = config::media_pool::config()?;
|
let (pool_config, _pool_digest) = config::media_pool::config()?;
|
||||||
let (drive_config, _digest) = config::drive::config()?;
|
let (drive_config, _digest) = pbs_config::drive::config()?;
|
||||||
|
|
||||||
let job_list_iter = job_config
|
let job_list_iter = job_config
|
||||||
.convert_to_typed_array("backup")?
|
.convert_to_typed_array("backup")?
|
||||||
|
@ -194,7 +194,7 @@ pub fn do_tape_backup_job(
|
||||||
let (config, _digest) = config::media_pool::config()?;
|
let (config, _digest) = config::media_pool::config()?;
|
||||||
let pool_config: MediaPoolConfig = config.lookup("pool", &setup.pool)?;
|
let pool_config: MediaPoolConfig = config.lookup("pool", &setup.pool)?;
|
||||||
|
|
||||||
let (drive_config, _digest) = config::drive::config()?;
|
let (drive_config, _digest) = pbs_config::drive::config()?;
|
||||||
|
|
||||||
// for scheduled jobs we acquire the lock later in the worker
|
// for scheduled jobs we acquire the lock later in the worker
|
||||||
let drive_lock = if schedule.is_some() {
|
let drive_lock = if schedule.is_some() {
|
||||||
|
@ -373,7 +373,7 @@ pub fn backup(
|
||||||
let (config, _digest) = config::media_pool::config()?;
|
let (config, _digest) = config::media_pool::config()?;
|
||||||
let pool_config: MediaPoolConfig = config.lookup("pool", &setup.pool)?;
|
let pool_config: MediaPoolConfig = config.lookup("pool", &setup.pool)?;
|
||||||
|
|
||||||
let (drive_config, _digest) = config::drive::config()?;
|
let (drive_config, _digest) = pbs_config::drive::config()?;
|
||||||
|
|
||||||
// early check/lock before starting worker
|
// early check/lock before starting worker
|
||||||
let drive_lock = lock_tape_device(&drive_config, &setup.drive)?;
|
let drive_lock = lock_tape_device(&drive_config, &setup.drive)?;
|
||||||
|
@ -578,7 +578,7 @@ fn backup_worker(
|
||||||
// Try to update the the media online status
|
// Try to update the the media online status
|
||||||
fn update_media_online_status(drive: &str) -> Result<Option<String>, Error> {
|
fn update_media_online_status(drive: &str) -> Result<Option<String>, Error> {
|
||||||
|
|
||||||
let (config, _digest) = config::drive::config()?;
|
let (config, _digest) = pbs_config::drive::config()?;
|
||||||
|
|
||||||
if let Ok(Some((mut changer, changer_name))) = media_changer(&config, drive) {
|
if let Ok(Some((mut changer, changer_name))) = media_changer(&config, drive) {
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,6 @@ use proxmox::list_subdirs_api_method;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
config::{
|
config::{
|
||||||
self,
|
|
||||||
cached_user_info::CachedUserInfo,
|
cached_user_info::CachedUserInfo,
|
||||||
acl::{
|
acl::{
|
||||||
PRIV_TAPE_AUDIT,
|
PRIV_TAPE_AUDIT,
|
||||||
|
@ -71,7 +70,7 @@ pub async fn get_status(
|
||||||
cache: bool,
|
cache: bool,
|
||||||
) -> Result<Vec<MtxStatusEntry>, Error> {
|
) -> Result<Vec<MtxStatusEntry>, Error> {
|
||||||
|
|
||||||
let (config, _digest) = config::drive::config()?;
|
let (config, _digest) = pbs_config::drive::config()?;
|
||||||
|
|
||||||
let mut changer_config: ScsiTapeChanger = config.lookup("changer", &name)?;
|
let mut changer_config: ScsiTapeChanger = config.lookup("changer", &name)?;
|
||||||
|
|
||||||
|
@ -171,7 +170,7 @@ pub async fn transfer(
|
||||||
to: u64,
|
to: u64,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
|
|
||||||
let (config, _digest) = config::drive::config()?;
|
let (config, _digest) = pbs_config::drive::config()?;
|
||||||
|
|
||||||
let mut changer_config: ScsiTapeChanger = config.lookup("changer", &name)?;
|
let mut changer_config: ScsiTapeChanger = config.lookup("changer", &name)?;
|
||||||
|
|
||||||
|
@ -205,7 +204,7 @@ pub fn list_changers(
|
||||||
let auth_id: Authid = rpcenv.get_auth_id().unwrap().parse()?;
|
let auth_id: Authid = rpcenv.get_auth_id().unwrap().parse()?;
|
||||||
let user_info = CachedUserInfo::new()?;
|
let user_info = CachedUserInfo::new()?;
|
||||||
|
|
||||||
let (config, _digest) = config::drive::config()?;
|
let (config, _digest) = pbs_config::drive::config()?;
|
||||||
|
|
||||||
let linux_changers = linux_tape_changer_list();
|
let linux_changers = linux_tape_changer_list();
|
||||||
|
|
||||||
|
|
|
@ -75,6 +75,7 @@ use crate::{
|
||||||
TapeDriver,
|
TapeDriver,
|
||||||
LtoTapeHandle,
|
LtoTapeHandle,
|
||||||
open_lto_tape_device,
|
open_lto_tape_device,
|
||||||
|
open_lto_tape_drive,
|
||||||
media_changer,
|
media_changer,
|
||||||
required_media_changer,
|
required_media_changer,
|
||||||
open_drive,
|
open_drive,
|
||||||
|
@ -101,7 +102,7 @@ where
|
||||||
+ FnOnce(Arc<WorkerTask>, SectionConfigData) -> Result<(), Error>,
|
+ FnOnce(Arc<WorkerTask>, SectionConfigData) -> Result<(), Error>,
|
||||||
{
|
{
|
||||||
// early check/lock before starting worker
|
// early check/lock before starting worker
|
||||||
let (config, _digest) = config::drive::config()?;
|
let (config, _digest) = pbs_config::drive::config()?;
|
||||||
let lock_guard = lock_tape_device(&config, &drive)?;
|
let lock_guard = lock_tape_device(&config, &drive)?;
|
||||||
|
|
||||||
let auth_id: Authid = rpcenv.get_auth_id().unwrap().parse()?;
|
let auth_id: Authid = rpcenv.get_auth_id().unwrap().parse()?;
|
||||||
|
@ -125,7 +126,7 @@ where
|
||||||
R: Send + 'static,
|
R: Send + 'static,
|
||||||
{
|
{
|
||||||
// early check/lock before starting worker
|
// early check/lock before starting worker
|
||||||
let (config, _digest) = config::drive::config()?;
|
let (config, _digest) = pbs_config::drive::config()?;
|
||||||
let lock_guard = lock_tape_device(&config, &drive)?;
|
let lock_guard = lock_tape_device(&config, &drive)?;
|
||||||
tokio::task::spawn_blocking(move || {
|
tokio::task::spawn_blocking(move || {
|
||||||
let _lock_guard = lock_guard;
|
let _lock_guard = lock_guard;
|
||||||
|
@ -1140,7 +1141,7 @@ pub async fn cartridge_memory(drive: String) -> Result<Vec<MamAttribute>, Error>
|
||||||
"reading cartridge memory".to_string(),
|
"reading cartridge memory".to_string(),
|
||||||
move |config| {
|
move |config| {
|
||||||
let drive_config: LtoTapeDrive = config.lookup("lto", &drive)?;
|
let drive_config: LtoTapeDrive = config.lookup("lto", &drive)?;
|
||||||
let mut handle = drive_config.open()?;
|
let mut handle = open_lto_tape_drive(&drive_config)?;
|
||||||
|
|
||||||
handle.cartridge_memory()
|
handle.cartridge_memory()
|
||||||
}
|
}
|
||||||
|
@ -1170,7 +1171,7 @@ pub async fn volume_statistics(drive: String) -> Result<Lp17VolumeStatistics, Er
|
||||||
"reading volume statistics".to_string(),
|
"reading volume statistics".to_string(),
|
||||||
move |config| {
|
move |config| {
|
||||||
let drive_config: LtoTapeDrive = config.lookup("lto", &drive)?;
|
let drive_config: LtoTapeDrive = config.lookup("lto", &drive)?;
|
||||||
let mut handle = drive_config.open()?;
|
let mut handle = open_lto_tape_drive(&drive_config)?;
|
||||||
|
|
||||||
handle.volume_statistics()
|
handle.volume_statistics()
|
||||||
}
|
}
|
||||||
|
@ -1376,7 +1377,7 @@ pub fn list_drives(
|
||||||
let auth_id: Authid = rpcenv.get_auth_id().unwrap().parse()?;
|
let auth_id: Authid = rpcenv.get_auth_id().unwrap().parse()?;
|
||||||
let user_info = CachedUserInfo::new()?;
|
let user_info = CachedUserInfo::new()?;
|
||||||
|
|
||||||
let (config, _) = config::drive::config()?;
|
let (config, _) = pbs_config::drive::config()?;
|
||||||
|
|
||||||
let lto_drives = lto_tape_device_list();
|
let lto_drives = lto_tape_device_list();
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,6 @@ use std::path::Path;
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
|
|
||||||
use anyhow::{bail, format_err, Error};
|
use anyhow::{bail, format_err, Error};
|
||||||
use serde::{Serialize, Deserialize};
|
|
||||||
|
|
||||||
use proxmox::{
|
use proxmox::{
|
||||||
api::{api, Router, SubdirMap, RpcEnvironment, Permission},
|
api::{api, Router, SubdirMap, RpcEnvironment, Permission},
|
||||||
|
@ -11,6 +10,11 @@ use proxmox::{
|
||||||
};
|
};
|
||||||
|
|
||||||
use pbs_datastore::backup_info::BackupDir;
|
use pbs_datastore::backup_info::BackupDir;
|
||||||
|
use pbs_api_types::{
|
||||||
|
MEDIA_POOL_NAME_SCHEMA, MEDIA_LABEL_SCHEMA, MEDIA_UUID_SCHEMA, CHANGER_NAME_SCHEMA,
|
||||||
|
VAULT_NAME_SCHEMA, Authid, MediaPoolConfig, MediaListEntry, MediaSetListEntry,
|
||||||
|
MediaStatus, MediaContentEntry, MediaContentListFilter,
|
||||||
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
config::{
|
config::{
|
||||||
|
@ -20,23 +24,7 @@ use crate::{
|
||||||
PRIV_TAPE_AUDIT,
|
PRIV_TAPE_AUDIT,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
api2::types::{
|
tape::{
|
||||||
Authid,
|
|
||||||
BACKUP_ID_SCHEMA,
|
|
||||||
BACKUP_TYPE_SCHEMA,
|
|
||||||
MEDIA_POOL_NAME_SCHEMA,
|
|
||||||
MEDIA_LABEL_SCHEMA,
|
|
||||||
MEDIA_UUID_SCHEMA,
|
|
||||||
MEDIA_SET_UUID_SCHEMA,
|
|
||||||
CHANGER_NAME_SCHEMA,
|
|
||||||
MediaPoolConfig,
|
|
||||||
MediaListEntry,
|
|
||||||
MediaSetListEntry,
|
|
||||||
MediaStatus,
|
|
||||||
MediaContentEntry,
|
|
||||||
VAULT_NAME_SCHEMA,
|
|
||||||
},
|
|
||||||
tape::{
|
|
||||||
TAPE_STATUS_DIR,
|
TAPE_STATUS_DIR,
|
||||||
Inventory,
|
Inventory,
|
||||||
MediaPool,
|
MediaPool,
|
||||||
|
@ -393,46 +381,6 @@ pub fn destroy_media(label_text: String, force: Option<bool>,) -> Result<(), Err
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[api(
|
|
||||||
properties: {
|
|
||||||
pool: {
|
|
||||||
schema: MEDIA_POOL_NAME_SCHEMA,
|
|
||||||
optional: true,
|
|
||||||
},
|
|
||||||
"label-text": {
|
|
||||||
schema: MEDIA_LABEL_SCHEMA,
|
|
||||||
optional: true,
|
|
||||||
},
|
|
||||||
"media": {
|
|
||||||
schema: MEDIA_UUID_SCHEMA,
|
|
||||||
optional: true,
|
|
||||||
},
|
|
||||||
"media-set": {
|
|
||||||
schema: MEDIA_SET_UUID_SCHEMA,
|
|
||||||
optional: true,
|
|
||||||
},
|
|
||||||
"backup-type": {
|
|
||||||
schema: BACKUP_TYPE_SCHEMA,
|
|
||||||
optional: true,
|
|
||||||
},
|
|
||||||
"backup-id": {
|
|
||||||
schema: BACKUP_ID_SCHEMA,
|
|
||||||
optional: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
)]
|
|
||||||
#[derive(Serialize,Deserialize)]
|
|
||||||
#[serde(rename_all="kebab-case")]
|
|
||||||
/// Content list filter parameters
|
|
||||||
pub struct MediaContentListFilter {
|
|
||||||
pub pool: Option<String>,
|
|
||||||
pub label_text: Option<String>,
|
|
||||||
pub media: Option<Uuid>,
|
|
||||||
pub media_set: Option<Uuid>,
|
|
||||||
pub backup_type: Option<String>,
|
|
||||||
pub backup_id: Option<String>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[api(
|
#[api(
|
||||||
input: {
|
input: {
|
||||||
properties: {
|
properties: {
|
||||||
|
|
|
@ -49,7 +49,6 @@ use crate::{
|
||||||
TAPE_RESTORE_SNAPSHOT_SCHEMA,
|
TAPE_RESTORE_SNAPSHOT_SCHEMA,
|
||||||
},
|
},
|
||||||
config::{
|
config::{
|
||||||
self,
|
|
||||||
cached_user_info::CachedUserInfo,
|
cached_user_info::CachedUserInfo,
|
||||||
acl::{
|
acl::{
|
||||||
PRIV_DATASTORE_BACKUP,
|
PRIV_DATASTORE_BACKUP,
|
||||||
|
@ -271,7 +270,7 @@ pub fn restore(
|
||||||
bail!("no permissions on /tape/pool/{}", pool);
|
bail!("no permissions on /tape/pool/{}", pool);
|
||||||
}
|
}
|
||||||
|
|
||||||
let (drive_config, _digest) = config::drive::config()?;
|
let (drive_config, _digest) = pbs_config::drive::config()?;
|
||||||
|
|
||||||
// early check/lock before starting worker
|
// early check/lock before starting worker
|
||||||
let drive_lock = lock_tape_device(&drive_config, &drive)?;
|
let drive_lock = lock_tape_device(&drive_config, &drive)?;
|
||||||
|
|
|
@ -8,9 +8,6 @@ use proxmox::const_regex;
|
||||||
|
|
||||||
use crate::config::acl::Role;
|
use crate::config::acl::Role;
|
||||||
|
|
||||||
mod tape;
|
|
||||||
pub use tape::*;
|
|
||||||
|
|
||||||
mod acme;
|
mod acme;
|
||||||
pub use acme::*;
|
pub use acme::*;
|
||||||
|
|
||||||
|
@ -43,7 +40,6 @@ const_regex!{
|
||||||
|
|
||||||
pub DATASTORE_MAP_REGEX = concat!(r"(:?", PROXMOX_SAFE_ID_REGEX_STR!(), r"=)?", PROXMOX_SAFE_ID_REGEX_STR!());
|
pub DATASTORE_MAP_REGEX = concat!(r"(:?", PROXMOX_SAFE_ID_REGEX_STR!(), r"=)?", PROXMOX_SAFE_ID_REGEX_STR!());
|
||||||
|
|
||||||
pub TAPE_RESTORE_SNAPSHOT_REGEX = concat!(r"^", PROXMOX_SAFE_ID_REGEX_STR!(), r":", SNAPSHOT_PATH_REGEX_STR!(), r"$");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const SYSTEMD_DATETIME_FORMAT: ApiStringFormat =
|
pub const SYSTEMD_DATETIME_FORMAT: ApiStringFormat =
|
||||||
|
@ -70,9 +66,6 @@ pub const BLOCKDEVICE_NAME_FORMAT: ApiStringFormat =
|
||||||
pub const DATASTORE_MAP_FORMAT: ApiStringFormat =
|
pub const DATASTORE_MAP_FORMAT: ApiStringFormat =
|
||||||
ApiStringFormat::Pattern(&DATASTORE_MAP_REGEX);
|
ApiStringFormat::Pattern(&DATASTORE_MAP_REGEX);
|
||||||
|
|
||||||
pub const TAPE_RESTORE_SNAPSHOT_FORMAT: ApiStringFormat =
|
|
||||||
ApiStringFormat::Pattern(&TAPE_RESTORE_SNAPSHOT_REGEX);
|
|
||||||
|
|
||||||
pub const PASSWORD_SCHEMA: Schema = StringSchema::new("Password.")
|
pub const PASSWORD_SCHEMA: Schema = StringSchema::new("Password.")
|
||||||
.format(&PASSWORD_FORMAT)
|
.format(&PASSWORD_FORMAT)
|
||||||
.min_length(1)
|
.min_length(1)
|
||||||
|
@ -85,12 +78,6 @@ pub const PBS_PASSWORD_SCHEMA: Schema = StringSchema::new("User Password.")
|
||||||
.max_length(64)
|
.max_length(64)
|
||||||
.schema();
|
.schema();
|
||||||
|
|
||||||
pub const TAPE_ENCRYPTION_KEY_FINGERPRINT_SCHEMA: Schema = StringSchema::new(
|
|
||||||
"Tape encryption key fingerprint (sha256)."
|
|
||||||
)
|
|
||||||
.format(&FINGERPRINT_SHA256_FORMAT)
|
|
||||||
.schema();
|
|
||||||
|
|
||||||
pub const CHUNK_DIGEST_SCHEMA: Schema = StringSchema::new("Chunk digest (SHA256).")
|
pub const CHUNK_DIGEST_SCHEMA: Schema = StringSchema::new("Chunk digest (SHA256).")
|
||||||
.format(&CHUNK_DIGEST_FORMAT)
|
.format(&CHUNK_DIGEST_FORMAT)
|
||||||
.schema();
|
.schema();
|
||||||
|
@ -238,22 +225,6 @@ pub const DATASTORE_MAP_LIST_SCHEMA: Schema = StringSchema::new(
|
||||||
.format(&ApiStringFormat::PropertyString(&DATASTORE_MAP_ARRAY_SCHEMA))
|
.format(&ApiStringFormat::PropertyString(&DATASTORE_MAP_ARRAY_SCHEMA))
|
||||||
.schema();
|
.schema();
|
||||||
|
|
||||||
pub const TAPE_RESTORE_SNAPSHOT_SCHEMA: Schema = StringSchema::new(
|
|
||||||
"A snapshot in the format: 'store:type/id/time")
|
|
||||||
.format(&TAPE_RESTORE_SNAPSHOT_FORMAT)
|
|
||||||
.type_text("store:type/id/time")
|
|
||||||
.schema();
|
|
||||||
|
|
||||||
pub const MEDIA_SET_UUID_SCHEMA: Schema =
|
|
||||||
StringSchema::new("MediaSet Uuid (We use the all-zero Uuid to reseve an empty media for a specific pool).")
|
|
||||||
.format(&UUID_FORMAT)
|
|
||||||
.schema();
|
|
||||||
|
|
||||||
pub const MEDIA_UUID_SCHEMA: Schema =
|
|
||||||
StringSchema::new("Media Uuid.")
|
|
||||||
.format(&UUID_FORMAT)
|
|
||||||
.schema();
|
|
||||||
|
|
||||||
pub const SYNC_SCHEDULE_SCHEMA: Schema = StringSchema::new(
|
pub const SYNC_SCHEDULE_SCHEMA: Schema = StringSchema::new(
|
||||||
"Run sync job at specified schedule.")
|
"Run sync job at specified schedule.")
|
||||||
.format(&ApiStringFormat::VerifyFn(pbs_systemd::time::verify_calendar_event))
|
.format(&ApiStringFormat::VerifyFn(pbs_systemd::time::verify_calendar_event))
|
||||||
|
|
|
@ -1,22 +0,0 @@
|
||||||
//! Types for tape backup API
|
|
||||||
|
|
||||||
mod device;
|
|
||||||
pub use device::*;
|
|
||||||
|
|
||||||
mod changer;
|
|
||||||
pub use changer::*;
|
|
||||||
|
|
||||||
mod drive;
|
|
||||||
pub use drive::*;
|
|
||||||
|
|
||||||
mod media_pool;
|
|
||||||
pub use media_pool::*;
|
|
||||||
|
|
||||||
mod media_status;
|
|
||||||
pub use media_status::*;
|
|
||||||
|
|
||||||
mod media_location;
|
|
||||||
pub use media_location::*;
|
|
||||||
|
|
||||||
mod media;
|
|
||||||
pub use media::*;
|
|
|
@ -55,7 +55,7 @@ fn main() -> Result<(), Error> {
|
||||||
let text = match arg.as_ref() {
|
let text = match arg.as_ref() {
|
||||||
"apidata.js" => generate_api_tree(),
|
"apidata.js" => generate_api_tree(),
|
||||||
"datastore.cfg" => dump_section_config(&config::datastore::CONFIG),
|
"datastore.cfg" => dump_section_config(&config::datastore::CONFIG),
|
||||||
"tape.cfg" => dump_section_config(&config::drive::CONFIG),
|
"tape.cfg" => dump_section_config(&pbs_config::drive::CONFIG),
|
||||||
"tape-job.cfg" => dump_section_config(&config::tape_job::CONFIG),
|
"tape-job.cfg" => dump_section_config(&config::tape_job::CONFIG),
|
||||||
"user.cfg" => dump_section_config(&config::user::CONFIG),
|
"user.cfg" => dump_section_config(&config::user::CONFIG),
|
||||||
"remote.cfg" => dump_section_config(&pbs_config::remote::CONFIG),
|
"remote.cfg" => dump_section_config(&pbs_config::remote::CONFIG),
|
||||||
|
|
|
@ -30,6 +30,23 @@ use proxmox::{
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use pbs_api_types::{
|
||||||
|
LTO_DRIVE_PATH_SCHEMA, DRIVE_NAME_SCHEMA, LtoTapeDrive,
|
||||||
|
};
|
||||||
|
use pbs_config::drive::complete_drive_name;
|
||||||
|
|
||||||
|
use proxmox_backup::{
|
||||||
|
tape::{
|
||||||
|
complete_drive_path,
|
||||||
|
lto_tape_device_list,
|
||||||
|
drive::{
|
||||||
|
TapeDriver,
|
||||||
|
LtoTapeHandle,
|
||||||
|
open_lto_tape_device,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
pub const FILE_MARK_COUNT_SCHEMA: Schema =
|
pub const FILE_MARK_COUNT_SCHEMA: Schema =
|
||||||
IntegerSchema::new("File mark count.")
|
IntegerSchema::new("File mark count.")
|
||||||
.minimum(1)
|
.minimum(1)
|
||||||
|
@ -57,31 +74,10 @@ pub const DRIVE_OPTION_LIST_SCHEMA: Schema =
|
||||||
.min_length(1)
|
.min_length(1)
|
||||||
.schema();
|
.schema();
|
||||||
|
|
||||||
use proxmox_backup::{
|
|
||||||
config::{
|
|
||||||
self,
|
|
||||||
drive::complete_drive_name,
|
|
||||||
},
|
|
||||||
api2::types::{
|
|
||||||
LTO_DRIVE_PATH_SCHEMA,
|
|
||||||
DRIVE_NAME_SCHEMA,
|
|
||||||
LtoTapeDrive,
|
|
||||||
},
|
|
||||||
tape::{
|
|
||||||
complete_drive_path,
|
|
||||||
lto_tape_device_list,
|
|
||||||
drive::{
|
|
||||||
TapeDriver,
|
|
||||||
LtoTapeHandle,
|
|
||||||
open_lto_tape_device,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
fn get_tape_handle(param: &Value) -> Result<LtoTapeHandle, Error> {
|
fn get_tape_handle(param: &Value) -> Result<LtoTapeHandle, Error> {
|
||||||
|
|
||||||
if let Some(name) = param["drive"].as_str() {
|
if let Some(name) = param["drive"].as_str() {
|
||||||
let (config, _digest) = config::drive::config()?;
|
let (config, _digest) = pbs_config::drive::config()?;
|
||||||
let drive: LtoTapeDrive = config.lookup("lto", &name)?;
|
let drive: LtoTapeDrive = config.lookup("lto", &name)?;
|
||||||
eprintln!("using device {}", drive.path);
|
eprintln!("using device {}", drive.path);
|
||||||
return LtoTapeHandle::new(open_lto_tape_device(&drive.path)?);
|
return LtoTapeHandle::new(open_lto_tape_device(&drive.path)?);
|
||||||
|
@ -93,7 +89,7 @@ fn get_tape_handle(param: &Value) -> Result<LtoTapeHandle, Error> {
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Ok(name) = std::env::var("PROXMOX_TAPE_DRIVE") {
|
if let Ok(name) = std::env::var("PROXMOX_TAPE_DRIVE") {
|
||||||
let (config, _digest) = config::drive::config()?;
|
let (config, _digest) = pbs_config::drive::config()?;
|
||||||
let drive: LtoTapeDrive = config.lookup("lto", &name)?;
|
let drive: LtoTapeDrive = config.lookup("lto", &name)?;
|
||||||
eprintln!("using device {}", drive.path);
|
eprintln!("using device {}", drive.path);
|
||||||
return LtoTapeHandle::new(open_lto_tape_device(&drive.path)?);
|
return LtoTapeHandle::new(open_lto_tape_device(&drive.path)?);
|
||||||
|
@ -104,7 +100,7 @@ fn get_tape_handle(param: &Value) -> Result<LtoTapeHandle, Error> {
|
||||||
return LtoTapeHandle::new(open_lto_tape_device(&device)?);
|
return LtoTapeHandle::new(open_lto_tape_device(&device)?);
|
||||||
}
|
}
|
||||||
|
|
||||||
let (config, _digest) = config::drive::config()?;
|
let (config, _digest) = pbs_config::drive::config()?;
|
||||||
|
|
||||||
let mut drive_names = Vec::new();
|
let mut drive_names = Vec::new();
|
||||||
for (name, (section_type, _)) in config.sections.iter() {
|
for (name, (section_type, _)) in config.sections.iter() {
|
||||||
|
|
|
@ -25,6 +25,8 @@ use proxmox::{
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use pbs_config::drive::complete_changer_name;
|
||||||
|
|
||||||
use proxmox_backup::{
|
use proxmox_backup::{
|
||||||
tools::sgutils2::{
|
tools::sgutils2::{
|
||||||
scsi_inquiry,
|
scsi_inquiry,
|
||||||
|
@ -43,18 +45,12 @@ use proxmox_backup::{
|
||||||
sg_pt_changer,
|
sg_pt_changer,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
config::{
|
|
||||||
self,
|
|
||||||
drive::{
|
|
||||||
complete_changer_name,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
fn get_changer_handle(param: &Value) -> Result<File, Error> {
|
fn get_changer_handle(param: &Value) -> Result<File, Error> {
|
||||||
|
|
||||||
if let Some(name) = param["changer"].as_str() {
|
if let Some(name) = param["changer"].as_str() {
|
||||||
let (config, _digest) = config::drive::config()?;
|
let (config, _digest) = pbs_config::drive::config()?;
|
||||||
let changer_config: ScsiTapeChanger = config.lookup("changer", &name)?;
|
let changer_config: ScsiTapeChanger = config.lookup("changer", &name)?;
|
||||||
eprintln!("using device {}", changer_config.path);
|
eprintln!("using device {}", changer_config.path);
|
||||||
return sg_pt_changer::open(&changer_config.path);
|
return sg_pt_changer::open(&changer_config.path);
|
||||||
|
@ -66,7 +62,7 @@ fn get_changer_handle(param: &Value) -> Result<File, Error> {
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Ok(name) = std::env::var("PROXMOX_TAPE_DRIVE") {
|
if let Ok(name) = std::env::var("PROXMOX_TAPE_DRIVE") {
|
||||||
let (config, _digest) = config::drive::config()?;
|
let (config, _digest) = pbs_config::drive::config()?;
|
||||||
let drive: LtoTapeDrive = config.lookup("lto", &name)?;
|
let drive: LtoTapeDrive = config.lookup("lto", &name)?;
|
||||||
if let Some(changer) = drive.changer {
|
if let Some(changer) = drive.changer {
|
||||||
let changer_config: ScsiTapeChanger = config.lookup("changer", &changer)?;
|
let changer_config: ScsiTapeChanger = config.lookup("changer", &changer)?;
|
||||||
|
|
|
@ -21,6 +21,8 @@ use pbs_tools::format::{
|
||||||
render_bytes_human_readable,
|
render_bytes_human_readable,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use pbs_config::drive::complete_drive_name;
|
||||||
|
|
||||||
use proxmox_backup::{
|
use proxmox_backup::{
|
||||||
api2::{
|
api2::{
|
||||||
self,
|
self,
|
||||||
|
@ -36,9 +38,7 @@ use proxmox_backup::{
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
config::{
|
config::{
|
||||||
self,
|
|
||||||
datastore::complete_datastore_name,
|
datastore::complete_datastore_name,
|
||||||
drive::complete_drive_name,
|
|
||||||
media_pool::complete_pool_name,
|
media_pool::complete_pool_name,
|
||||||
},
|
},
|
||||||
tape::{
|
tape::{
|
||||||
|
@ -121,7 +121,7 @@ async fn format_media(mut param: Value) -> Result<(), Error> {
|
||||||
|
|
||||||
let output_format = extract_output_format(&mut param);
|
let output_format = extract_output_format(&mut param);
|
||||||
|
|
||||||
let (config, _digest) = config::drive::config()?;
|
let (config, _digest) = pbs_config::drive::config()?;
|
||||||
|
|
||||||
let drive = extract_drive_name(&mut param, &config)?;
|
let drive = extract_drive_name(&mut param, &config)?;
|
||||||
|
|
||||||
|
@ -154,7 +154,7 @@ async fn rewind(mut param: Value) -> Result<(), Error> {
|
||||||
|
|
||||||
let output_format = extract_output_format(&mut param);
|
let output_format = extract_output_format(&mut param);
|
||||||
|
|
||||||
let (config, _digest) = config::drive::config()?;
|
let (config, _digest) = pbs_config::drive::config()?;
|
||||||
|
|
||||||
let drive = extract_drive_name(&mut param, &config)?;
|
let drive = extract_drive_name(&mut param, &config)?;
|
||||||
|
|
||||||
|
@ -187,7 +187,7 @@ async fn eject_media(mut param: Value) -> Result<(), Error> {
|
||||||
|
|
||||||
let output_format = extract_output_format(&mut param);
|
let output_format = extract_output_format(&mut param);
|
||||||
|
|
||||||
let (config, _digest) = config::drive::config()?;
|
let (config, _digest) = pbs_config::drive::config()?;
|
||||||
|
|
||||||
let drive = extract_drive_name(&mut param, &config)?;
|
let drive = extract_drive_name(&mut param, &config)?;
|
||||||
|
|
||||||
|
@ -223,7 +223,7 @@ async fn load_media(mut param: Value) -> Result<(), Error> {
|
||||||
|
|
||||||
let output_format = extract_output_format(&mut param);
|
let output_format = extract_output_format(&mut param);
|
||||||
|
|
||||||
let (config, _digest) = config::drive::config()?;
|
let (config, _digest) = pbs_config::drive::config()?;
|
||||||
|
|
||||||
let drive = extract_drive_name(&mut param, &config)?;
|
let drive = extract_drive_name(&mut param, &config)?;
|
||||||
|
|
||||||
|
@ -253,7 +253,7 @@ async fn load_media(mut param: Value) -> Result<(), Error> {
|
||||||
/// Export media with specified label
|
/// Export media with specified label
|
||||||
async fn export_media(mut param: Value) -> Result<(), Error> {
|
async fn export_media(mut param: Value) -> Result<(), Error> {
|
||||||
|
|
||||||
let (config, _digest) = config::drive::config()?;
|
let (config, _digest) = pbs_config::drive::config()?;
|
||||||
|
|
||||||
let drive = extract_drive_name(&mut param, &config)?;
|
let drive = extract_drive_name(&mut param, &config)?;
|
||||||
|
|
||||||
|
@ -283,7 +283,7 @@ async fn export_media(mut param: Value) -> Result<(), Error> {
|
||||||
/// Load media from the specified slot
|
/// Load media from the specified slot
|
||||||
async fn load_media_from_slot(mut param: Value) -> Result<(), Error> {
|
async fn load_media_from_slot(mut param: Value) -> Result<(), Error> {
|
||||||
|
|
||||||
let (config, _digest) = config::drive::config()?;
|
let (config, _digest) = pbs_config::drive::config()?;
|
||||||
|
|
||||||
let drive = extract_drive_name(&mut param, &config)?;
|
let drive = extract_drive_name(&mut param, &config)?;
|
||||||
|
|
||||||
|
@ -320,7 +320,7 @@ async fn unload_media(mut param: Value) -> Result<(), Error> {
|
||||||
|
|
||||||
let output_format = extract_output_format(&mut param);
|
let output_format = extract_output_format(&mut param);
|
||||||
|
|
||||||
let (config, _digest) = config::drive::config()?;
|
let (config, _digest) = pbs_config::drive::config()?;
|
||||||
|
|
||||||
let drive = extract_drive_name(&mut param, &config)?;
|
let drive = extract_drive_name(&mut param, &config)?;
|
||||||
|
|
||||||
|
@ -360,7 +360,7 @@ async fn label_media(mut param: Value) -> Result<(), Error> {
|
||||||
|
|
||||||
let output_format = extract_output_format(&mut param);
|
let output_format = extract_output_format(&mut param);
|
||||||
|
|
||||||
let (config, _digest) = config::drive::config()?;
|
let (config, _digest) = pbs_config::drive::config()?;
|
||||||
|
|
||||||
let drive = extract_drive_name(&mut param, &config)?;
|
let drive = extract_drive_name(&mut param, &config)?;
|
||||||
|
|
||||||
|
@ -398,7 +398,7 @@ async fn read_label(mut param: Value) -> Result<(), Error> {
|
||||||
|
|
||||||
let output_format = extract_output_format(&mut param);
|
let output_format = extract_output_format(&mut param);
|
||||||
|
|
||||||
let (config, _digest) = config::drive::config()?;
|
let (config, _digest) = pbs_config::drive::config()?;
|
||||||
|
|
||||||
let drive = extract_drive_name(&mut param, &config)?;
|
let drive = extract_drive_name(&mut param, &config)?;
|
||||||
|
|
||||||
|
@ -458,7 +458,7 @@ async fn inventory(
|
||||||
|
|
||||||
let output_format = extract_output_format(&mut param);
|
let output_format = extract_output_format(&mut param);
|
||||||
|
|
||||||
let (config, _digest) = config::drive::config()?;
|
let (config, _digest) = pbs_config::drive::config()?;
|
||||||
let drive = extract_drive_name(&mut param, &config)?;
|
let drive = extract_drive_name(&mut param, &config)?;
|
||||||
|
|
||||||
let do_read = read_labels.unwrap_or(false) || read_all_labels.unwrap_or(false);
|
let do_read = read_labels.unwrap_or(false) || read_all_labels.unwrap_or(false);
|
||||||
|
@ -516,7 +516,7 @@ async fn barcode_label_media(mut param: Value) -> Result<(), Error> {
|
||||||
|
|
||||||
let output_format = extract_output_format(&mut param);
|
let output_format = extract_output_format(&mut param);
|
||||||
|
|
||||||
let (config, _digest) = config::drive::config()?;
|
let (config, _digest) = pbs_config::drive::config()?;
|
||||||
|
|
||||||
let drive = extract_drive_name(&mut param, &config)?;
|
let drive = extract_drive_name(&mut param, &config)?;
|
||||||
|
|
||||||
|
@ -543,7 +543,7 @@ async fn barcode_label_media(mut param: Value) -> Result<(), Error> {
|
||||||
/// Move to end of media (MTEOM, used to debug)
|
/// Move to end of media (MTEOM, used to debug)
|
||||||
fn move_to_eom(mut param: Value) -> Result<(), Error> {
|
fn move_to_eom(mut param: Value) -> Result<(), Error> {
|
||||||
|
|
||||||
let (config, _digest) = config::drive::config()?;
|
let (config, _digest) = pbs_config::drive::config()?;
|
||||||
|
|
||||||
let drive = extract_drive_name(&mut param, &config)?;
|
let drive = extract_drive_name(&mut param, &config)?;
|
||||||
|
|
||||||
|
@ -573,7 +573,7 @@ fn move_to_eom(mut param: Value) -> Result<(), Error> {
|
||||||
/// method is expected to fails when we reach EOT.
|
/// method is expected to fails when we reach EOT.
|
||||||
fn debug_scan(mut param: Value) -> Result<(), Error> {
|
fn debug_scan(mut param: Value) -> Result<(), Error> {
|
||||||
|
|
||||||
let (config, _digest) = config::drive::config()?;
|
let (config, _digest) = pbs_config::drive::config()?;
|
||||||
|
|
||||||
let drive = extract_drive_name(&mut param, &config)?;
|
let drive = extract_drive_name(&mut param, &config)?;
|
||||||
|
|
||||||
|
@ -655,7 +655,7 @@ async fn cartridge_memory(mut param: Value) -> Result<(), Error> {
|
||||||
|
|
||||||
let output_format = extract_output_format(&mut param);
|
let output_format = extract_output_format(&mut param);
|
||||||
|
|
||||||
let (config, _digest) = config::drive::config()?;
|
let (config, _digest) = pbs_config::drive::config()?;
|
||||||
|
|
||||||
let drive = extract_drive_name(&mut param, &config)?;
|
let drive = extract_drive_name(&mut param, &config)?;
|
||||||
|
|
||||||
|
@ -696,7 +696,7 @@ async fn volume_statistics(mut param: Value) -> Result<(), Error> {
|
||||||
|
|
||||||
let output_format = extract_output_format(&mut param);
|
let output_format = extract_output_format(&mut param);
|
||||||
|
|
||||||
let (config, _digest) = config::drive::config()?;
|
let (config, _digest) = pbs_config::drive::config()?;
|
||||||
|
|
||||||
let drive = extract_drive_name(&mut param, &config)?;
|
let drive = extract_drive_name(&mut param, &config)?;
|
||||||
|
|
||||||
|
@ -734,7 +734,7 @@ async fn status(mut param: Value) -> Result<(), Error> {
|
||||||
|
|
||||||
let output_format = extract_output_format(&mut param);
|
let output_format = extract_output_format(&mut param);
|
||||||
|
|
||||||
let (config, _digest) = config::drive::config()?;
|
let (config, _digest) = pbs_config::drive::config()?;
|
||||||
|
|
||||||
let drive = extract_drive_name(&mut param, &config)?;
|
let drive = extract_drive_name(&mut param, &config)?;
|
||||||
|
|
||||||
|
@ -794,7 +794,7 @@ async fn clean_drive(mut param: Value) -> Result<(), Error> {
|
||||||
|
|
||||||
let output_format = extract_output_format(&mut param);
|
let output_format = extract_output_format(&mut param);
|
||||||
|
|
||||||
let (config, _digest) = config::drive::config()?;
|
let (config, _digest) = pbs_config::drive::config()?;
|
||||||
|
|
||||||
let drive = extract_drive_name(&mut param, &config)?;
|
let drive = extract_drive_name(&mut param, &config)?;
|
||||||
|
|
||||||
|
@ -855,7 +855,7 @@ async fn backup(mut param: Value) -> Result<(), Error> {
|
||||||
|
|
||||||
let output_format = extract_output_format(&mut param);
|
let output_format = extract_output_format(&mut param);
|
||||||
|
|
||||||
let (config, _digest) = config::drive::config()?;
|
let (config, _digest) = pbs_config::drive::config()?;
|
||||||
|
|
||||||
param["drive"] = extract_drive_name(&mut param, &config)?.into();
|
param["drive"] = extract_drive_name(&mut param, &config)?.into();
|
||||||
|
|
||||||
|
@ -910,7 +910,7 @@ async fn restore(mut param: Value) -> Result<(), Error> {
|
||||||
|
|
||||||
let output_format = extract_output_format(&mut param);
|
let output_format = extract_output_format(&mut param);
|
||||||
|
|
||||||
let (config, _digest) = config::drive::config()?;
|
let (config, _digest) = pbs_config::drive::config()?;
|
||||||
|
|
||||||
param["drive"] = extract_drive_name(&mut param, &config)?.into();
|
param["drive"] = extract_drive_name(&mut param, &config)?.into();
|
||||||
|
|
||||||
|
@ -957,7 +957,7 @@ async fn catalog_media(mut param: Value) -> Result<(), Error> {
|
||||||
|
|
||||||
let output_format = extract_output_format(&mut param);
|
let output_format = extract_output_format(&mut param);
|
||||||
|
|
||||||
let (config, _digest) = config::drive::config()?;
|
let (config, _digest) = pbs_config::drive::config()?;
|
||||||
|
|
||||||
let drive = extract_drive_name(&mut param, &config)?;
|
let drive = extract_drive_name(&mut param, &config)?;
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,11 @@ use proxmox::{
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use pbs_config::drive::{
|
||||||
|
complete_drive_name,
|
||||||
|
complete_changer_name,
|
||||||
|
};
|
||||||
|
|
||||||
use proxmox_backup::{
|
use proxmox_backup::{
|
||||||
api2::{
|
api2::{
|
||||||
self,
|
self,
|
||||||
|
@ -20,16 +25,7 @@ use proxmox_backup::{
|
||||||
},
|
},
|
||||||
tape::{
|
tape::{
|
||||||
complete_changer_path,
|
complete_changer_path,
|
||||||
drive::{
|
drive::media_changer,
|
||||||
media_changer,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
config::{
|
|
||||||
self,
|
|
||||||
drive::{
|
|
||||||
complete_drive_name,
|
|
||||||
complete_changer_name,
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -232,7 +228,7 @@ async fn get_status(
|
||||||
rpcenv: &mut dyn RpcEnvironment,
|
rpcenv: &mut dyn RpcEnvironment,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
|
|
||||||
let (config, _digest) = config::drive::config()?;
|
let (config, _digest) = pbs_config::drive::config()?;
|
||||||
|
|
||||||
param["name"] = lookup_changer_name(¶m, &config)?.into();
|
param["name"] = lookup_changer_name(¶m, &config)?.into();
|
||||||
|
|
||||||
|
@ -295,7 +291,7 @@ pub async fn transfer(
|
||||||
rpcenv: &mut dyn RpcEnvironment,
|
rpcenv: &mut dyn RpcEnvironment,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
|
|
||||||
let (config, _digest) = config::drive::config()?;
|
let (config, _digest) = pbs_config::drive::config()?;
|
||||||
|
|
||||||
param["name"] = lookup_changer_name(¶m, &config)?.into();
|
param["name"] = lookup_changer_name(¶m, &config)?.into();
|
||||||
|
|
||||||
|
|
|
@ -10,21 +10,16 @@ use proxmox::{
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
use proxmox_backup::{
|
use pbs_api_types::DRIVE_NAME_SCHEMA;
|
||||||
api2::{
|
|
||||||
self,
|
use pbs_config::drive::{
|
||||||
types::{
|
complete_drive_name,
|
||||||
DRIVE_NAME_SCHEMA,
|
complete_changer_name,
|
||||||
},
|
complete_lto_drive_name,
|
||||||
},
|
|
||||||
tape::complete_drive_path,
|
|
||||||
config::drive::{
|
|
||||||
complete_drive_name,
|
|
||||||
complete_changer_name,
|
|
||||||
complete_lto_drive_name,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use proxmox_backup::{api2, tape::complete_drive_path};
|
||||||
|
|
||||||
pub fn drive_commands() -> CommandLineInterface {
|
pub fn drive_commands() -> CommandLineInterface {
|
||||||
|
|
||||||
let cmd_def = CliCommandMap::new()
|
let cmd_def = CliCommandMap::new()
|
||||||
|
|
|
@ -16,7 +16,6 @@ use pbs_datastore::Kdf;
|
||||||
use pbs_datastore::paperkey::{PaperkeyFormat, generate_paper_key};
|
use pbs_datastore::paperkey::{PaperkeyFormat, generate_paper_key};
|
||||||
|
|
||||||
use proxmox_backup::{
|
use proxmox_backup::{
|
||||||
config,
|
|
||||||
api2::{
|
api2::{
|
||||||
self,
|
self,
|
||||||
types::{
|
types::{
|
||||||
|
@ -208,7 +207,7 @@ async fn restore_key(
|
||||||
rpcenv: &mut dyn RpcEnvironment,
|
rpcenv: &mut dyn RpcEnvironment,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
|
|
||||||
let (config, _digest) = config::drive::config()?;
|
let (config, _digest) = pbs_config::drive::config()?;
|
||||||
param["drive"] = crate::extract_drive_name(&mut param, &config)?.into();
|
param["drive"] = crate::extract_drive_name(&mut param, &config)?.into();
|
||||||
|
|
||||||
if !tty::stdin_isatty() {
|
if !tty::stdin_isatty() {
|
||||||
|
|
|
@ -10,18 +10,14 @@ use proxmox::{
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use pbs_api_types::{
|
||||||
|
MEDIA_POOL_NAME_SCHEMA, CHANGER_NAME_SCHEMA, MediaStatus, MediaListEntry,
|
||||||
|
MediaContentListFilter,
|
||||||
|
};
|
||||||
|
use pbs_config::drive::complete_changer_name;
|
||||||
|
|
||||||
use proxmox_backup::{
|
use proxmox_backup::{
|
||||||
api2::{
|
api2,
|
||||||
self,
|
|
||||||
types::{
|
|
||||||
MEDIA_POOL_NAME_SCHEMA,
|
|
||||||
CHANGER_NAME_SCHEMA,
|
|
||||||
MediaStatus,
|
|
||||||
MediaListEntry,
|
|
||||||
},
|
|
||||||
tape::media::MediaContentListFilter,
|
|
||||||
},
|
|
||||||
config::drive::complete_changer_name,
|
|
||||||
tape::{
|
tape::{
|
||||||
complete_media_label_text,
|
complete_media_label_text,
|
||||||
complete_media_uuid,
|
complete_media_uuid,
|
||||||
|
|
|
@ -18,22 +18,18 @@ use proxmox::{
|
||||||
tools::Uuid,
|
tools::Uuid,
|
||||||
};
|
};
|
||||||
|
|
||||||
use pbs_api_types::Fingerprint;
|
use pbs_api_types::{
|
||||||
|
Fingerprint, LTO_DRIVE_PATH_SCHEMA, DRIVE_NAME_SCHEMA, TAPE_ENCRYPTION_KEY_FINGERPRINT_SCHEMA,
|
||||||
|
MEDIA_SET_UUID_SCHEMA, LtoTapeDrive,
|
||||||
|
};
|
||||||
|
|
||||||
use proxmox_backup::{
|
use proxmox_backup::{
|
||||||
config,
|
|
||||||
api2::types::{
|
|
||||||
LTO_DRIVE_PATH_SCHEMA,
|
|
||||||
DRIVE_NAME_SCHEMA,
|
|
||||||
TAPE_ENCRYPTION_KEY_FINGERPRINT_SCHEMA,
|
|
||||||
MEDIA_SET_UUID_SCHEMA,
|
|
||||||
LtoTapeDrive,
|
|
||||||
},
|
|
||||||
tape::{
|
tape::{
|
||||||
drive::{
|
drive::{
|
||||||
TapeDriver,
|
TapeDriver,
|
||||||
LtoTapeHandle,
|
LtoTapeHandle,
|
||||||
open_lto_tape_device,
|
open_lto_tape_device,
|
||||||
|
open_lto_tape_drive,
|
||||||
check_tape_is_lto_tape_device,
|
check_tape_is_lto_tape_device,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -42,10 +38,10 @@ use proxmox_backup::{
|
||||||
fn get_tape_handle(param: &Value) -> Result<LtoTapeHandle, Error> {
|
fn get_tape_handle(param: &Value) -> Result<LtoTapeHandle, Error> {
|
||||||
|
|
||||||
let handle = if let Some(name) = param["drive"].as_str() {
|
let handle = if let Some(name) = param["drive"].as_str() {
|
||||||
let (config, _digest) = config::drive::config()?;
|
let (config, _digest) = pbs_config::drive::config()?;
|
||||||
let drive: LtoTapeDrive = config.lookup("lto", &name)?;
|
let drive: LtoTapeDrive = config.lookup("lto", &name)?;
|
||||||
eprintln!("using device {}", drive.path);
|
eprintln!("using device {}", drive.path);
|
||||||
drive.open()?
|
open_lto_tape_drive(&drive)?
|
||||||
} else if let Some(device) = param["device"].as_str() {
|
} else if let Some(device) = param["device"].as_str() {
|
||||||
eprintln!("using device {}", device);
|
eprintln!("using device {}", device);
|
||||||
LtoTapeHandle::new(open_lto_tape_device(&device)?)?
|
LtoTapeHandle::new(open_lto_tape_device(&device)?)?
|
||||||
|
@ -56,12 +52,12 @@ fn get_tape_handle(param: &Value) -> Result<LtoTapeHandle, Error> {
|
||||||
check_tape_is_lto_tape_device(&file)?;
|
check_tape_is_lto_tape_device(&file)?;
|
||||||
LtoTapeHandle::new(file)?
|
LtoTapeHandle::new(file)?
|
||||||
} else if let Ok(name) = std::env::var("PROXMOX_TAPE_DRIVE") {
|
} else if let Ok(name) = std::env::var("PROXMOX_TAPE_DRIVE") {
|
||||||
let (config, _digest) = config::drive::config()?;
|
let (config, _digest) = pbs_config::drive::config()?;
|
||||||
let drive: LtoTapeDrive = config.lookup("lto", &name)?;
|
let drive: LtoTapeDrive = config.lookup("lto", &name)?;
|
||||||
eprintln!("using device {}", drive.path);
|
eprintln!("using device {}", drive.path);
|
||||||
drive.open()?
|
open_lto_tape_drive(&drive)?
|
||||||
} else {
|
} else {
|
||||||
let (config, _digest) = config::drive::config()?;
|
let (config, _digest) = pbs_config::drive::config()?;
|
||||||
|
|
||||||
let mut drive_names = Vec::new();
|
let mut drive_names = Vec::new();
|
||||||
for (name, (section_type, _)) in config.sections.iter() {
|
for (name, (section_type, _)) in config.sections.iter() {
|
||||||
|
@ -73,7 +69,7 @@ fn get_tape_handle(param: &Value) -> Result<LtoTapeHandle, Error> {
|
||||||
let name = drive_names[0];
|
let name = drive_names[0];
|
||||||
let drive: LtoTapeDrive = config.lookup("lto", &name)?;
|
let drive: LtoTapeDrive = config.lookup("lto", &name)?;
|
||||||
eprintln!("using device {}", drive.path);
|
eprintln!("using device {}", drive.path);
|
||||||
drive.open()?
|
open_lto_tape_drive(&drive)?
|
||||||
} else {
|
} else {
|
||||||
bail!("no drive/device specified");
|
bail!("no drive/device specified");
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,7 +25,6 @@ pub mod tfa;
|
||||||
pub mod token_shadow;
|
pub mod token_shadow;
|
||||||
pub mod user;
|
pub mod user;
|
||||||
pub mod verify;
|
pub mod verify;
|
||||||
pub mod drive;
|
|
||||||
pub mod media_pool;
|
pub mod media_pool;
|
||||||
pub mod tape_encryption_keys;
|
pub mod tape_encryption_keys;
|
||||||
pub mod tape_job;
|
pub mod tape_job;
|
||||||
|
|
|
@ -524,7 +524,7 @@ pub struct MtxMediaChanger {
|
||||||
impl MtxMediaChanger {
|
impl MtxMediaChanger {
|
||||||
|
|
||||||
pub fn with_drive_config(drive_config: &LtoTapeDrive) -> Result<Self, Error> {
|
pub fn with_drive_config(drive_config: &LtoTapeDrive) -> Result<Self, Error> {
|
||||||
let (config, _digest) = crate::config::drive::config()?;
|
let (config, _digest) = pbs_config::drive::config()?;
|
||||||
let changer_config: ScsiTapeChanger = match drive_config.changer {
|
let changer_config: ScsiTapeChanger = match drive_config.changer {
|
||||||
Some(ref changer) => config.lookup("changer", changer)?,
|
Some(ref changer) => config.lookup("changer", changer)?,
|
||||||
None => bail!("drive '{}' has no associated changer", drive_config.name),
|
None => bail!("drive '{}' has no associated changer", drive_config.name),
|
||||||
|
|
|
@ -125,7 +125,7 @@ pub fn mtx_status_to_online_set(status: &MtxStatus, inventory: &Inventory) -> Ha
|
||||||
/// For a single 'changer', or else simply ask all changer devices.
|
/// For a single 'changer', or else simply ask all changer devices.
|
||||||
pub fn update_online_status(state_path: &Path, changer: Option<&str>) -> Result<OnlineStatusMap, Error> {
|
pub fn update_online_status(state_path: &Path, changer: Option<&str>) -> Result<OnlineStatusMap, Error> {
|
||||||
|
|
||||||
let (config, _digest) = crate::config::drive::config()?;
|
let (config, _digest) = pbs_config::drive::config()?;
|
||||||
|
|
||||||
let mut inventory = Inventory::load(state_path)?;
|
let mut inventory = Inventory::load(state_path)?;
|
||||||
|
|
||||||
|
|
|
@ -54,37 +54,34 @@ use crate::{
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
impl LtoTapeDrive {
|
/// Open a tape device
|
||||||
|
///
|
||||||
|
/// This does additional checks:
|
||||||
|
///
|
||||||
|
/// - check if it is a non-rewinding tape device
|
||||||
|
/// - check if drive is ready (tape loaded)
|
||||||
|
/// - check block size
|
||||||
|
/// - for autoloader only, try to reload ejected tapes
|
||||||
|
pub fn open_lto_tape_drive(config: &LtoTapeDrive) -> Result<LtoTapeHandle, Error> {
|
||||||
|
|
||||||
/// Open a tape device
|
proxmox::try_block!({
|
||||||
///
|
let file = open_lto_tape_device(&config.path)?;
|
||||||
/// This does additional checks:
|
|
||||||
///
|
|
||||||
/// - check if it is a non-rewinding tape device
|
|
||||||
/// - check if drive is ready (tape loaded)
|
|
||||||
/// - check block size
|
|
||||||
/// - for autoloader only, try to reload ejected tapes
|
|
||||||
pub fn open(&self) -> Result<LtoTapeHandle, Error> {
|
|
||||||
|
|
||||||
proxmox::try_block!({
|
let mut handle = LtoTapeHandle::new(file)?;
|
||||||
let file = open_lto_tape_device(&self.path)?;
|
|
||||||
|
|
||||||
let mut handle = LtoTapeHandle::new(file)?;
|
if !handle.sg_tape.test_unit_ready().is_ok() {
|
||||||
|
// for autoloader only, try to reload ejected tapes
|
||||||
if !handle.sg_tape.test_unit_ready().is_ok() {
|
if config.changer.is_some() {
|
||||||
// for autoloader only, try to reload ejected tapes
|
let _ = handle.sg_tape.load(); // just try, ignore error
|
||||||
if self.changer.is_some() {
|
|
||||||
let _ = handle.sg_tape.load(); // just try, ignore error
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
handle.sg_tape.wait_until_ready()?;
|
handle.sg_tape.wait_until_ready()?;
|
||||||
|
|
||||||
handle.set_default_options()?;
|
handle.set_default_options()?;
|
||||||
|
|
||||||
Ok(handle)
|
Ok(handle)
|
||||||
}).map_err(|err: Error| format_err!("open drive '{}' ({}) failed - {}", self.name, self.path, err))
|
}).map_err(|err: Error| format_err!("open drive '{}' ({}) failed - {}", config.name, config.path, err))
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Lto Tape device handle
|
/// Lto Tape device handle
|
||||||
|
|
|
@ -32,12 +32,9 @@ use pbs_api_types::Fingerprint;
|
||||||
use pbs_datastore::key_derivation::KeyConfig;
|
use pbs_datastore::key_derivation::KeyConfig;
|
||||||
use pbs_datastore::task::TaskState;
|
use pbs_datastore::task::TaskState;
|
||||||
use pbs_datastore::task_log;
|
use pbs_datastore::task_log;
|
||||||
|
use pbs_api_types::{VirtualTapeDrive, LtoTapeDrive};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
api2::types::{
|
|
||||||
VirtualTapeDrive,
|
|
||||||
LtoTapeDrive,
|
|
||||||
},
|
|
||||||
server::{
|
server::{
|
||||||
send_load_media_email,
|
send_load_media_email,
|
||||||
WorkerTask,
|
WorkerTask,
|
||||||
|
@ -47,7 +44,10 @@ use crate::{
|
||||||
TapeRead,
|
TapeRead,
|
||||||
BlockReadError,
|
BlockReadError,
|
||||||
MediaId,
|
MediaId,
|
||||||
drive::lto::TapeAlertFlags,
|
drive::{
|
||||||
|
virtual_tape::open_virtual_tape_drive,
|
||||||
|
lto::TapeAlertFlags,
|
||||||
|
},
|
||||||
file_formats::{
|
file_formats::{
|
||||||
PROXMOX_BACKUP_MEDIA_LABEL_MAGIC_1_0,
|
PROXMOX_BACKUP_MEDIA_LABEL_MAGIC_1_0,
|
||||||
PROXMOX_BACKUP_MEDIA_SET_LABEL_MAGIC_1_0,
|
PROXMOX_BACKUP_MEDIA_SET_LABEL_MAGIC_1_0,
|
||||||
|
@ -305,12 +305,12 @@ pub fn open_drive(
|
||||||
match section_type_name.as_ref() {
|
match section_type_name.as_ref() {
|
||||||
"virtual" => {
|
"virtual" => {
|
||||||
let tape = VirtualTapeDrive::deserialize(config)?;
|
let tape = VirtualTapeDrive::deserialize(config)?;
|
||||||
let handle = tape.open()?;
|
let handle = open_virtual_tape_drive(&tape)?;
|
||||||
Ok(Box::new(handle))
|
Ok(Box::new(handle))
|
||||||
}
|
}
|
||||||
"lto" => {
|
"lto" => {
|
||||||
let tape = LtoTapeDrive::deserialize(config)?;
|
let tape = LtoTapeDrive::deserialize(config)?;
|
||||||
let handle = tape.open()?;
|
let handle = open_lto_tape_drive(&tape)?;
|
||||||
Ok(Box::new(handle))
|
Ok(Box::new(handle))
|
||||||
}
|
}
|
||||||
_ => bail!("unknown drive type '{}' - internal error"),
|
_ => bail!("unknown drive type '{}' - internal error"),
|
||||||
|
@ -395,7 +395,7 @@ pub fn request_and_load_media(
|
||||||
|
|
||||||
tape.load_media(&label_text)?;
|
tape.load_media(&label_text)?;
|
||||||
|
|
||||||
let mut handle: Box<dyn TapeDriver> = Box::new(tape.open()?);
|
let mut handle: Box<dyn TapeDriver> = Box::new(open_virtual_tape_drive(&tape)?);
|
||||||
|
|
||||||
let media_id = check_label(handle.as_mut(), &label.uuid)?;
|
let media_id = check_label(handle.as_mut(), &label.uuid)?;
|
||||||
|
|
||||||
|
@ -413,7 +413,7 @@ pub fn request_and_load_media(
|
||||||
let mut changer = MtxMediaChanger::with_drive_config(&drive_config)?;
|
let mut changer = MtxMediaChanger::with_drive_config(&drive_config)?;
|
||||||
changer.load_media(&label_text)?;
|
changer.load_media(&label_text)?;
|
||||||
|
|
||||||
let mut handle: Box<dyn TapeDriver> = Box::new(drive_config.open()?);
|
let mut handle: Box<dyn TapeDriver> = Box::new(open_lto_tape_drive(&drive_config)?);
|
||||||
|
|
||||||
let media_id = check_label(handle.as_mut(), &label.uuid)?;
|
let media_id = check_label(handle.as_mut(), &label.uuid)?;
|
||||||
|
|
||||||
|
@ -463,7 +463,7 @@ pub fn request_and_load_media(
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut handle = match drive_config.open() {
|
let mut handle = match open_lto_tape_drive(&drive_config) {
|
||||||
Ok(handle) => handle,
|
Ok(handle) => handle,
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
update_and_log_request_error(
|
update_and_log_request_error(
|
||||||
|
|
|
@ -42,26 +42,23 @@ use crate::{
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
impl VirtualTapeDrive {
|
/// This needs to lock the drive
|
||||||
|
pub fn open_virtual_tape_drive(config: &VirtualTapeDrive) -> Result<VirtualTapeHandle, Error> {
|
||||||
|
proxmox::try_block!({
|
||||||
|
let mut lock_path = std::path::PathBuf::from(&config.path);
|
||||||
|
lock_path.push(".drive.lck");
|
||||||
|
|
||||||
/// This needs to lock the drive
|
let options = CreateOptions::new();
|
||||||
pub fn open(&self) -> Result<VirtualTapeHandle, Error> {
|
let timeout = std::time::Duration::new(10, 0);
|
||||||
proxmox::try_block!({
|
let lock = proxmox::tools::fs::open_file_locked(&lock_path, timeout, true, options)?;
|
||||||
let mut lock_path = std::path::PathBuf::from(&self.path);
|
|
||||||
lock_path.push(".drive.lck");
|
|
||||||
|
|
||||||
let options = CreateOptions::new();
|
Ok(VirtualTapeHandle {
|
||||||
let timeout = std::time::Duration::new(10, 0);
|
_lock: lock,
|
||||||
let lock = proxmox::tools::fs::open_file_locked(&lock_path, timeout, true, options)?;
|
drive_name: config.name.clone(),
|
||||||
|
max_size: config.max_size.unwrap_or(64*1024*1024),
|
||||||
Ok(VirtualTapeHandle {
|
path: std::path::PathBuf::from(&config.path),
|
||||||
_lock: lock,
|
})
|
||||||
drive_name: self.name.clone(),
|
}).map_err(|err: Error| format_err!("open drive '{}' ({}) failed - {}", config.name, config.path, err))
|
||||||
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))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize,Deserialize)]
|
#[derive(Serialize,Deserialize)]
|
||||||
|
@ -583,42 +580,42 @@ impl MediaChange for VirtualTapeDrive {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn status(&mut self) -> Result<MtxStatus, Error> {
|
fn status(&mut self) -> Result<MtxStatus, Error> {
|
||||||
let mut handle = self.open()?;
|
let mut handle = open_virtual_tape_drive(self)?;
|
||||||
handle.status()
|
handle.status()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn transfer_media(&mut self, from: u64, to: u64) -> Result<MtxStatus, Error> {
|
fn transfer_media(&mut self, from: u64, to: u64) -> Result<MtxStatus, Error> {
|
||||||
let mut handle = self.open()?;
|
let mut handle = open_virtual_tape_drive(self)?;
|
||||||
handle.transfer_media(from, to)
|
handle.transfer_media(from, to)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn export_media(&mut self, label_text: &str) -> Result<Option<u64>, Error> {
|
fn export_media(&mut self, label_text: &str) -> Result<Option<u64>, Error> {
|
||||||
let mut handle = self.open()?;
|
let mut handle = open_virtual_tape_drive(self)?;
|
||||||
handle.export_media(label_text)
|
handle.export_media(label_text)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load_media_from_slot(&mut self, slot: u64) -> Result<MtxStatus, Error> {
|
fn load_media_from_slot(&mut self, slot: u64) -> Result<MtxStatus, Error> {
|
||||||
let mut handle = self.open()?;
|
let mut handle = open_virtual_tape_drive(self)?;
|
||||||
handle.load_media_from_slot(slot)
|
handle.load_media_from_slot(slot)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load_media(&mut self, label_text: &str) -> Result<MtxStatus, Error> {
|
fn load_media(&mut self, label_text: &str) -> Result<MtxStatus, Error> {
|
||||||
let mut handle = self.open()?;
|
let mut handle = open_virtual_tape_drive(self)?;
|
||||||
handle.load_media(label_text)
|
handle.load_media(label_text)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn unload_media(&mut self, target_slot: Option<u64>) -> Result<MtxStatus, Error> {
|
fn unload_media(&mut self, target_slot: Option<u64>) -> Result<MtxStatus, Error> {
|
||||||
let mut handle = self.open()?;
|
let mut handle = open_virtual_tape_drive(self)?;
|
||||||
handle.unload_media(target_slot)
|
handle.unload_media(target_slot)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn online_media_label_texts(&mut self) -> Result<Vec<String>, Error> {
|
fn online_media_label_texts(&mut self) -> Result<Vec<String>, Error> {
|
||||||
let handle = self.open()?;
|
let handle = open_virtual_tape_drive(self)?;
|
||||||
handle.online_media_label_texts()
|
handle.online_media_label_texts()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn clean_drive(&mut self) -> Result<MtxStatus, Error> {
|
fn clean_drive(&mut self) -> Result<MtxStatus, Error> {
|
||||||
let mut handle = self.open()?;
|
let mut handle = open_virtual_tape_drive(self)?;
|
||||||
handle.clean_drive()
|
handle.clean_drive()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -133,7 +133,7 @@ impl PoolWriter {
|
||||||
None => return Ok(()), // no media loaded
|
None => return Ok(()), // no media loaded
|
||||||
};
|
};
|
||||||
|
|
||||||
let (drive_config, _digest) = crate::config::drive::config()?;
|
let (drive_config, _digest) = pbs_config::drive::config()?;
|
||||||
|
|
||||||
if let Some((mut changer, _)) = media_changer(&drive_config, &self.drive_name)? {
|
if let Some((mut changer, _)) = media_changer(&drive_config, &self.drive_name)? {
|
||||||
worker.log("eject media");
|
worker.log("eject media");
|
||||||
|
@ -153,7 +153,7 @@ impl PoolWriter {
|
||||||
pub fn export_media_set(&mut self, worker: &WorkerTask) -> Result<(), Error> {
|
pub fn export_media_set(&mut self, worker: &WorkerTask) -> Result<(), Error> {
|
||||||
let mut status = self.status.take();
|
let mut status = self.status.take();
|
||||||
|
|
||||||
let (drive_config, _digest) = crate::config::drive::config()?;
|
let (drive_config, _digest) = pbs_config::drive::config()?;
|
||||||
|
|
||||||
if let Some((mut changer, _)) = media_changer(&drive_config, &self.drive_name)? {
|
if let Some((mut changer, _)) = media_changer(&drive_config, &self.drive_name)? {
|
||||||
|
|
||||||
|
@ -226,7 +226,7 @@ impl PoolWriter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let (drive_config, _digest) = crate::config::drive::config()?;
|
let (drive_config, _digest) = pbs_config::drive::config()?;
|
||||||
|
|
||||||
let (mut drive, old_media_id) =
|
let (mut drive, old_media_id) =
|
||||||
request_and_load_media(worker, &drive_config, &self.drive_name, media.label(), &self.notify_email)?;
|
request_and_load_media(worker, &drive_config, &self.drive_name, media.label(), &self.notify_email)?;
|
||||||
|
|
Loading…
Reference in New Issue