-use anyhow::{bail, Error};
use ::serde::{Deserialize, Serialize};
-use serde_json::Value;
+use anyhow::Error;
use hex::FromHex;
+use serde_json::Value;
-use proxmox_router::{Router, RpcEnvironment, Permission};
-use proxmox_schema::{api, parse_property_string};
+use proxmox_router::{http_bail, Permission, Router, RpcEnvironment};
+use proxmox_schema::{api, param_bail};
use pbs_api_types::{
- Authid, ScsiTapeChanger, ScsiTapeChangerUpdater, LtoTapeDrive,
- PROXMOX_CONFIG_DIGEST_SCHEMA, CHANGER_NAME_SCHEMA, SLOT_ARRAY_SCHEMA,
- PRIV_TAPE_AUDIT, PRIV_TAPE_MODIFY,
+ Authid, LtoTapeDrive, ScsiTapeChanger, ScsiTapeChangerUpdater, CHANGER_NAME_SCHEMA,
+ PRIV_TAPE_AUDIT, PRIV_TAPE_MODIFY, PROXMOX_CONFIG_DIGEST_SCHEMA, SLOT_ARRAY_SCHEMA,
};
use pbs_config::CachedUserInfo;
-use pbs_tape::linux_list_drives::{linux_tape_changer_list, check_drive_path};
+use pbs_tape::linux_list_drives::{check_drive_path, linux_tape_changer_list};
#[api(
protected: true,
)]
/// Create a new changer device
pub fn create_changer(config: ScsiTapeChanger) -> Result<(), Error> {
-
let _lock = pbs_config::drive::lock()?;
let (mut section_config, _digest) = pbs_config::drive::config()?;
+ if section_config.sections.get(&config.name).is_some() {
+ param_bail!("name", "Entry '{}' already exists", config.name);
+ }
+
let linux_changers = linux_tape_changer_list();
check_drive_path(&linux_changers, &config.path)?;
let existing: Vec<ScsiTapeChanger> = section_config.convert_to_typed_array("changer")?;
for changer in existing {
- if changer.name == config.name {
- bail!("Entry '{}' already exists", config.name);
- }
-
if changer.path == config.path {
- bail!("Path '{}' already in use by '{}'", config.path, changer.name);
+ param_bail!(
+ "path",
+ "Path '{}' already in use by '{}'",
+ config.path,
+ changer.name
+ );
}
}
pub fn get_config(
name: String,
_param: Value,
- mut rpcenv: &mut dyn RpcEnvironment,
+ rpcenv: &mut dyn RpcEnvironment,
) -> Result<ScsiTapeChanger, Error> {
-
let (config, digest) = pbs_config::drive::config()?;
let data: ScsiTapeChanger = config.lookup("changer", &name)?;
- rpcenv["digest"] = hex::encode(&digest).into();
+ rpcenv["digest"] = hex::encode(digest).into();
Ok(data)
}
/// List changers
pub fn list_changers(
_param: Value,
- mut rpcenv: &mut dyn RpcEnvironment,
+ rpcenv: &mut dyn RpcEnvironment,
) -> Result<Vec<ScsiTapeChanger>, Error> {
let auth_id: Authid = rpcenv.get_auth_id().unwrap().parse()?;
let user_info = CachedUserInfo::new()?;
})
.collect();
- rpcenv["digest"] = hex::encode(&digest).into();
+ rpcenv["digest"] = hex::encode(digest).into();
Ok(list)
}
#[api()]
#[derive(Serialize, Deserialize)]
-#[allow(non_camel_case_types)]
#[serde(rename_all = "kebab-case")]
/// Deletable property name
pub enum DeletableProperty {
/// Delete export-slots.
- export_slots,
+ ExportSlots,
+ /// Delete eject-before-unload.
+ EjectBeforeUnload,
}
#[api(
digest: Option<String>,
_param: Value,
) -> Result<(), Error> {
-
let _lock = pbs_config::drive::lock()?;
let (mut config, expected_digest) = pbs_config::drive::config()?;
if let Some(delete) = delete {
for delete_prop in delete {
match delete_prop {
- DeletableProperty::export_slots => {
+ DeletableProperty::ExportSlots => {
data.export_slots = None;
}
+ DeletableProperty::EjectBeforeUnload => {
+ data.eject_before_unload = None;
+ }
}
}
}
}
if let Some(export_slots) = update.export_slots {
- let slots: Value = parse_property_string(
- &export_slots, &SLOT_ARRAY_SCHEMA
- )?;
+ let slots: Value = SLOT_ARRAY_SCHEMA.parse_property_string(&export_slots)?;
let mut slots: Vec<String> = slots
.as_array()
.unwrap()
}
}
+ if let Some(eject_before_unload) = update.eject_before_unload {
+ data.eject_before_unload = Some(eject_before_unload);
+ }
+
config.set_data(&name, "changer", &data)?;
pbs_config::drive::save_config(&config)?;
)]
/// Delete a tape changer configuration
pub fn delete_changer(name: String, _param: Value) -> Result<(), Error> {
-
let _lock = pbs_config::drive::lock()?;
let (mut config, _digest) = pbs_config::drive::config()?;
match config.sections.get(&name) {
Some((section_type, _)) => {
if section_type != "changer" {
- bail!("Entry '{}' exists, but is not a changer device", name);
+ param_bail!(
+ "name",
+ "Entry '{}' exists, but is not a changer device",
+ name
+ );
}
config.sections.remove(&name);
- },
- None => bail!("Delete changer '{}' failed - no such entry", name),
+ }
+ None => http_bail!(
+ NOT_FOUND,
+ "Delete changer '{}' failed - no such entry",
+ name
+ ),
}
let drive_list: Vec<LtoTapeDrive> = config.convert_to_typed_array("lto")?;
for drive in drive_list {
if let Some(changer) = drive.changer {
if changer == name {
- bail!("Delete changer '{}' failed - used by drive '{}'", name, drive.name);
+ param_bail!(
+ "name",
+ "Delete changer '{}' failed - used by drive '{}'",
+ name,
+ drive.name
+ );
}
}
}
.put(&API_METHOD_UPDATE_CHANGER)
.delete(&API_METHOD_DELETE_CHANGER);
-
pub const ROUTER: Router = Router::new()
.get(&API_METHOD_LIST_CHANGERS)
.post(&API_METHOD_CREATE_CHANGER)