tape: changer - add export-slot config
This commit is contained in:
parent
a174854a0d
commit
38ae42b11a
@ -1,7 +1,13 @@
|
|||||||
use anyhow::{bail, Error};
|
use anyhow::{bail, Error};
|
||||||
|
use ::serde::{Deserialize, Serialize};
|
||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
|
|
||||||
use proxmox::api::{api, Router, RpcEnvironment};
|
use proxmox::api::{
|
||||||
|
api,
|
||||||
|
Router,
|
||||||
|
RpcEnvironment,
|
||||||
|
schema::parse_property_string,
|
||||||
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
config,
|
config,
|
||||||
@ -9,6 +15,8 @@ use crate::{
|
|||||||
PROXMOX_CONFIG_DIGEST_SCHEMA,
|
PROXMOX_CONFIG_DIGEST_SCHEMA,
|
||||||
CHANGER_NAME_SCHEMA,
|
CHANGER_NAME_SCHEMA,
|
||||||
LINUX_DRIVE_PATH_SCHEMA,
|
LINUX_DRIVE_PATH_SCHEMA,
|
||||||
|
SLOT_ARRAY_SCHEMA,
|
||||||
|
EXPORT_SLOT_LIST_SCHEMA,
|
||||||
DriveListEntry,
|
DriveListEntry,
|
||||||
ScsiTapeChanger,
|
ScsiTapeChanger,
|
||||||
LinuxTapeDrive,
|
LinuxTapeDrive,
|
||||||
@ -30,6 +38,10 @@ use crate::{
|
|||||||
path: {
|
path: {
|
||||||
schema: LINUX_DRIVE_PATH_SCHEMA,
|
schema: LINUX_DRIVE_PATH_SCHEMA,
|
||||||
},
|
},
|
||||||
|
"export-slots": {
|
||||||
|
schema: EXPORT_SLOT_LIST_SCHEMA,
|
||||||
|
optional: true,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
)]
|
)]
|
||||||
@ -37,6 +49,7 @@ use crate::{
|
|||||||
pub fn create_changer(
|
pub fn create_changer(
|
||||||
name: String,
|
name: String,
|
||||||
path: String,
|
path: String,
|
||||||
|
export_slots: Option<String>,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
|
|
||||||
let _lock = config::drive::lock()?;
|
let _lock = config::drive::lock()?;
|
||||||
@ -54,6 +67,7 @@ pub fn create_changer(
|
|||||||
let item = ScsiTapeChanger {
|
let item = ScsiTapeChanger {
|
||||||
name: name.clone(),
|
name: name.clone(),
|
||||||
path,
|
path,
|
||||||
|
export_slots,
|
||||||
};
|
};
|
||||||
|
|
||||||
config.set_data(&name, "changer", &item)?;
|
config.set_data(&name, "changer", &item)?;
|
||||||
@ -139,6 +153,15 @@ pub fn list_changers(
|
|||||||
rpcenv["digest"] = proxmox::tools::digest_to_hex(&digest).into();
|
rpcenv["digest"] = proxmox::tools::digest_to_hex(&digest).into();
|
||||||
Ok(list)
|
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,
|
||||||
|
}
|
||||||
|
|
||||||
#[api(
|
#[api(
|
||||||
protected: true,
|
protected: true,
|
||||||
@ -151,6 +174,18 @@ pub fn list_changers(
|
|||||||
schema: LINUX_DRIVE_PATH_SCHEMA,
|
schema: LINUX_DRIVE_PATH_SCHEMA,
|
||||||
optional: true,
|
optional: true,
|
||||||
},
|
},
|
||||||
|
"export-slots": {
|
||||||
|
schema: EXPORT_SLOT_LIST_SCHEMA,
|
||||||
|
optional: true,
|
||||||
|
},
|
||||||
|
delete: {
|
||||||
|
description: "List of properties to delete.",
|
||||||
|
type: Array,
|
||||||
|
optional: true,
|
||||||
|
items: {
|
||||||
|
type: DeletableProperty,
|
||||||
|
},
|
||||||
|
},
|
||||||
digest: {
|
digest: {
|
||||||
schema: PROXMOX_CONFIG_DIGEST_SCHEMA,
|
schema: PROXMOX_CONFIG_DIGEST_SCHEMA,
|
||||||
optional: true,
|
optional: true,
|
||||||
@ -162,6 +197,8 @@ pub fn list_changers(
|
|||||||
pub fn update_changer(
|
pub fn update_changer(
|
||||||
name: String,
|
name: String,
|
||||||
path: Option<String>,
|
path: Option<String>,
|
||||||
|
export_slots: Option<String>,
|
||||||
|
delete: Option<Vec<DeletableProperty>>,
|
||||||
digest: Option<String>,
|
digest: Option<String>,
|
||||||
_param: Value,
|
_param: Value,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
@ -177,12 +214,42 @@ pub fn update_changer(
|
|||||||
|
|
||||||
let mut data: ScsiTapeChanger = config.lookup("changer", &name)?;
|
let mut data: ScsiTapeChanger = config.lookup("changer", &name)?;
|
||||||
|
|
||||||
|
if let Some(delete) = delete {
|
||||||
|
for delete_prop in delete {
|
||||||
|
match delete_prop {
|
||||||
|
DeletableProperty::export_slots => {
|
||||||
|
data.export_slots = None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if let Some(path) = path {
|
if let Some(path) = path {
|
||||||
let changers = linux_tape_changer_list();
|
let changers = linux_tape_changer_list();
|
||||||
check_drive_path(&changers, &path)?;
|
check_drive_path(&changers, &path)?;
|
||||||
data.path = path;
|
data.path = path;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let Some(export_slots) = export_slots {
|
||||||
|
let slots: Value = parse_property_string(
|
||||||
|
&export_slots, &SLOT_ARRAY_SCHEMA
|
||||||
|
)?;
|
||||||
|
let mut slots: Vec<String> = slots
|
||||||
|
.as_array()
|
||||||
|
.unwrap()
|
||||||
|
.iter()
|
||||||
|
.map(|v| v.to_string())
|
||||||
|
.collect();
|
||||||
|
slots.sort();
|
||||||
|
|
||||||
|
if slots.is_empty() {
|
||||||
|
data.export_slots = None;
|
||||||
|
} else {
|
||||||
|
let slots = slots.join(",");
|
||||||
|
data.export_slots = Some(slots);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
config.set_data(&name, "changer", &data)?;
|
config.set_data(&name, "changer", &data)?;
|
||||||
|
|
||||||
config::drive::save_config(&config)?;
|
config::drive::save_config(&config)?;
|
||||||
|
@ -4,7 +4,13 @@ use serde::{Deserialize, Serialize};
|
|||||||
|
|
||||||
use proxmox::api::{
|
use proxmox::api::{
|
||||||
api,
|
api,
|
||||||
schema::{Schema, StringSchema},
|
schema::{
|
||||||
|
Schema,
|
||||||
|
ApiStringFormat,
|
||||||
|
ArraySchema,
|
||||||
|
IntegerSchema,
|
||||||
|
StringSchema,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::api2::types::PROXMOX_SAFE_ID_FORMAT;
|
use crate::api2::types::PROXMOX_SAFE_ID_FORMAT;
|
||||||
@ -25,6 +31,20 @@ pub const MEDIA_LABEL_SCHEMA: Schema = StringSchema::new("Media Label/Barcode.")
|
|||||||
.max_length(32)
|
.max_length(32)
|
||||||
.schema();
|
.schema();
|
||||||
|
|
||||||
|
pub const SLOT_ARRAY_SCHEMA: Schema = ArraySchema::new(
|
||||||
|
"Slot list.", &IntegerSchema::new("Slot number")
|
||||||
|
.minimum(1)
|
||||||
|
.schema())
|
||||||
|
.schema();
|
||||||
|
|
||||||
|
pub const EXPORT_SLOT_LIST_SCHEMA: Schema = StringSchema::new(r###"\
|
||||||
|
A list of slot numbers, comma separated. Those slots are reserved for
|
||||||
|
Import/Export, i.e. any media in those slots are considered to be
|
||||||
|
'offline'.
|
||||||
|
"###)
|
||||||
|
.format(&ApiStringFormat::PropertyString(&SLOT_ARRAY_SCHEMA))
|
||||||
|
.schema();
|
||||||
|
|
||||||
#[api(
|
#[api(
|
||||||
properties: {
|
properties: {
|
||||||
name: {
|
name: {
|
||||||
@ -33,13 +53,20 @@ pub const MEDIA_LABEL_SCHEMA: Schema = StringSchema::new("Media Label/Barcode.")
|
|||||||
path: {
|
path: {
|
||||||
schema: SCSI_CHANGER_PATH_SCHEMA,
|
schema: SCSI_CHANGER_PATH_SCHEMA,
|
||||||
},
|
},
|
||||||
}
|
"export-slots": {
|
||||||
|
schema: EXPORT_SLOT_LIST_SCHEMA,
|
||||||
|
optional: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
)]
|
)]
|
||||||
#[derive(Serialize,Deserialize)]
|
#[derive(Serialize,Deserialize)]
|
||||||
|
#[serde(rename_all = "kebab-case")]
|
||||||
/// SCSI tape changer
|
/// SCSI tape changer
|
||||||
pub struct ScsiTapeChanger {
|
pub struct ScsiTapeChanger {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub path: String,
|
pub path: String,
|
||||||
|
#[serde(skip_serializing_if="Option::is_none")]
|
||||||
|
pub export_slots: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[api()]
|
#[api()]
|
||||||
|
@ -173,6 +173,7 @@ fn get_config(
|
|||||||
let options = default_table_format_options()
|
let options = default_table_format_options()
|
||||||
.column(ColumnConfig::new("name"))
|
.column(ColumnConfig::new("name"))
|
||||||
.column(ColumnConfig::new("path"))
|
.column(ColumnConfig::new("path"))
|
||||||
|
.column(ColumnConfig::new("export-slots"))
|
||||||
;
|
;
|
||||||
|
|
||||||
format_and_print_result_full(&mut data, &info.returns, &output_format, &options);
|
format_and_print_result_full(&mut data, &info.returns, &output_format, &options);
|
||||||
|
Loading…
Reference in New Issue
Block a user