tape: changer - add export-slot config

This commit is contained in:
Dietmar Maurer 2021-01-06 11:06:50 +01:00
parent a174854a0d
commit 38ae42b11a
3 changed files with 98 additions and 3 deletions

View File

@ -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)?;

View File

@ -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()]

View File

@ -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);