api types: rust fmt
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
This commit is contained in:
parent
4ad118c613
commit
b22d785c18
|
@ -62,18 +62,16 @@ fn as_fingerprint(bytes: &[u8]) -> String {
|
||||||
.as_bytes()
|
.as_bytes()
|
||||||
.chunks(2)
|
.chunks(2)
|
||||||
.map(|v| unsafe { std::str::from_utf8_unchecked(v) }) // it's a hex string
|
.map(|v| unsafe { std::str::from_utf8_unchecked(v) }) // it's a hex string
|
||||||
.collect::<Vec<&str>>().join(":")
|
.collect::<Vec<&str>>()
|
||||||
|
.join(":")
|
||||||
}
|
}
|
||||||
|
|
||||||
pub mod bytes_as_fingerprint {
|
pub mod bytes_as_fingerprint {
|
||||||
use std::mem::MaybeUninit;
|
use std::mem::MaybeUninit;
|
||||||
|
|
||||||
use serde::{Deserialize, Serializer, Deserializer};
|
use serde::{Deserialize, Deserializer, Serializer};
|
||||||
|
|
||||||
pub fn serialize<S>(
|
pub fn serialize<S>(bytes: &[u8; 32], serializer: S) -> Result<S::Ok, S::Error>
|
||||||
bytes: &[u8; 32],
|
|
||||||
serializer: S,
|
|
||||||
) -> Result<S::Ok, S::Error>
|
|
||||||
where
|
where
|
||||||
S: Serializer,
|
S: Serializer,
|
||||||
{
|
{
|
||||||
|
@ -81,9 +79,7 @@ pub mod bytes_as_fingerprint {
|
||||||
serializer.serialize_str(&s)
|
serializer.serialize_str(&s)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deserialize<'de, D>(
|
pub fn deserialize<'de, D>(deserializer: D) -> Result<[u8; 32], D::Error>
|
||||||
deserializer: D,
|
|
||||||
) -> Result<[u8; 32], D::Error>
|
|
||||||
where
|
where
|
||||||
D: Deserializer<'de>,
|
D: Deserializer<'de>,
|
||||||
{
|
{
|
||||||
|
|
|
@ -6,13 +6,12 @@ use proxmox_schema::{
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
PROXMOX_SAFE_ID_FORMAT, SHA256_HEX_REGEX, SINGLE_LINE_COMMENT_SCHEMA, CryptMode, UPID,
|
Authid, CryptMode, Fingerprint, Userid, DATASTORE_NOTIFY_STRING_SCHEMA, GC_SCHEDULE_SCHEMA,
|
||||||
Fingerprint, Userid, Authid,
|
PROXMOX_SAFE_ID_FORMAT, PRUNE_SCHEDULE_SCHEMA, SHA256_HEX_REGEX, SINGLE_LINE_COMMENT_SCHEMA,
|
||||||
GC_SCHEDULE_SCHEMA, DATASTORE_NOTIFY_STRING_SCHEMA, PRUNE_SCHEDULE_SCHEMA,
|
UPID,
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const_regex!{
|
const_regex! {
|
||||||
pub BACKUP_TYPE_REGEX = concat!(r"^(", BACKUP_TYPE_RE!(), r")$");
|
pub BACKUP_TYPE_REGEX = concat!(r"^(", BACKUP_TYPE_RE!(), r")$");
|
||||||
|
|
||||||
pub BACKUP_ID_REGEX = concat!(r"^", BACKUP_ID_RE!(), r"$");
|
pub BACKUP_ID_REGEX = concat!(r"^", BACKUP_ID_RE!(), r"$");
|
||||||
|
@ -81,17 +80,19 @@ pub const DATASTORE_MAP_SCHEMA: Schema = StringSchema::new("Datastore mapping.")
|
||||||
.type_text("(<source>=)?<target>")
|
.type_text("(<source>=)?<target>")
|
||||||
.schema();
|
.schema();
|
||||||
|
|
||||||
pub const DATASTORE_MAP_ARRAY_SCHEMA: Schema = ArraySchema::new(
|
pub const DATASTORE_MAP_ARRAY_SCHEMA: Schema =
|
||||||
"Datastore mapping list.", &DATASTORE_MAP_SCHEMA)
|
ArraySchema::new("Datastore mapping list.", &DATASTORE_MAP_SCHEMA).schema();
|
||||||
.schema();
|
|
||||||
|
|
||||||
pub const DATASTORE_MAP_LIST_SCHEMA: Schema = StringSchema::new(
|
pub const DATASTORE_MAP_LIST_SCHEMA: Schema = StringSchema::new(
|
||||||
"A list of Datastore mappings (or single datastore), comma separated. \
|
"A list of Datastore mappings (or single datastore), comma separated. \
|
||||||
For example 'a=b,e' maps the source datastore 'a' to target 'b and \
|
For example 'a=b,e' maps the source datastore 'a' to target 'b and \
|
||||||
all other sources to the default 'e'. If no default is given, only the \
|
all other sources to the default 'e'. If no default is given, only the \
|
||||||
specified sources are mapped.")
|
specified sources are mapped.",
|
||||||
.format(&ApiStringFormat::PropertyString(&DATASTORE_MAP_ARRAY_SCHEMA))
|
)
|
||||||
.schema();
|
.format(&ApiStringFormat::PropertyString(
|
||||||
|
&DATASTORE_MAP_ARRAY_SCHEMA,
|
||||||
|
))
|
||||||
|
.schema();
|
||||||
|
|
||||||
pub const PRUNE_SCHEMA_KEEP_DAILY: Schema = IntegerSchema::new("Number of daily backups to keep.")
|
pub const PRUNE_SCHEMA_KEEP_DAILY: Schema = IntegerSchema::new("Number of daily backups to keep.")
|
||||||
.minimum(1)
|
.minimum(1)
|
||||||
|
@ -153,17 +154,17 @@ pub const PRUNE_SCHEMA_KEEP_YEARLY: Schema =
|
||||||
#[serde(rename_all = "kebab-case")]
|
#[serde(rename_all = "kebab-case")]
|
||||||
/// Common pruning options
|
/// Common pruning options
|
||||||
pub struct PruneOptions {
|
pub struct PruneOptions {
|
||||||
#[serde(skip_serializing_if="Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub keep_last: Option<u64>,
|
pub keep_last: Option<u64>,
|
||||||
#[serde(skip_serializing_if="Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub keep_hourly: Option<u64>,
|
pub keep_hourly: Option<u64>,
|
||||||
#[serde(skip_serializing_if="Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub keep_daily: Option<u64>,
|
pub keep_daily: Option<u64>,
|
||||||
#[serde(skip_serializing_if="Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub keep_weekly: Option<u64>,
|
pub keep_weekly: Option<u64>,
|
||||||
#[serde(skip_serializing_if="Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub keep_monthly: Option<u64>,
|
pub keep_monthly: Option<u64>,
|
||||||
#[serde(skip_serializing_if="Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub keep_yearly: Option<u64>,
|
pub keep_yearly: Option<u64>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -194,9 +195,10 @@ pub struct DatastoreTuning {
|
||||||
pub chunk_order: Option<ChunkOrder>,
|
pub chunk_order: Option<ChunkOrder>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const DATASTORE_TUNING_STRING_SCHEMA: Schema = StringSchema::new(
|
pub const DATASTORE_TUNING_STRING_SCHEMA: Schema = StringSchema::new("Datastore tuning options")
|
||||||
"Datastore tuning options")
|
.format(&ApiStringFormat::PropertyString(
|
||||||
.format(&ApiStringFormat::PropertyString(&DatastoreTuning::API_SCHEMA))
|
&DatastoreTuning::API_SCHEMA,
|
||||||
|
))
|
||||||
.schema();
|
.schema();
|
||||||
|
|
||||||
#[api(
|
#[api(
|
||||||
|
@ -262,43 +264,43 @@ pub const DATASTORE_TUNING_STRING_SCHEMA: Schema = StringSchema::new(
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
)]
|
)]
|
||||||
#[derive(Serialize,Deserialize,Updater)]
|
#[derive(Serialize, Deserialize, Updater)]
|
||||||
#[serde(rename_all="kebab-case")]
|
#[serde(rename_all = "kebab-case")]
|
||||||
/// Datastore configuration properties.
|
/// Datastore configuration properties.
|
||||||
pub struct DataStoreConfig {
|
pub struct DataStoreConfig {
|
||||||
#[updater(skip)]
|
#[updater(skip)]
|
||||||
pub name: String,
|
pub name: String,
|
||||||
#[updater(skip)]
|
#[updater(skip)]
|
||||||
pub path: String,
|
pub path: String,
|
||||||
#[serde(skip_serializing_if="Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub comment: Option<String>,
|
pub comment: Option<String>,
|
||||||
#[serde(skip_serializing_if="Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub gc_schedule: Option<String>,
|
pub gc_schedule: Option<String>,
|
||||||
#[serde(skip_serializing_if="Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub prune_schedule: Option<String>,
|
pub prune_schedule: Option<String>,
|
||||||
#[serde(skip_serializing_if="Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub keep_last: Option<u64>,
|
pub keep_last: Option<u64>,
|
||||||
#[serde(skip_serializing_if="Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub keep_hourly: Option<u64>,
|
pub keep_hourly: Option<u64>,
|
||||||
#[serde(skip_serializing_if="Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub keep_daily: Option<u64>,
|
pub keep_daily: Option<u64>,
|
||||||
#[serde(skip_serializing_if="Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub keep_weekly: Option<u64>,
|
pub keep_weekly: Option<u64>,
|
||||||
#[serde(skip_serializing_if="Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub keep_monthly: Option<u64>,
|
pub keep_monthly: Option<u64>,
|
||||||
#[serde(skip_serializing_if="Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub keep_yearly: Option<u64>,
|
pub keep_yearly: Option<u64>,
|
||||||
/// If enabled, all backups will be verified right after completion.
|
/// If enabled, all backups will be verified right after completion.
|
||||||
#[serde(skip_serializing_if="Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub verify_new: Option<bool>,
|
pub verify_new: Option<bool>,
|
||||||
/// Send job email notification to this user
|
/// Send job email notification to this user
|
||||||
#[serde(skip_serializing_if="Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub notify_user: Option<Userid>,
|
pub notify_user: Option<Userid>,
|
||||||
/// Send notification only for job errors
|
/// Send notification only for job errors
|
||||||
#[serde(skip_serializing_if="Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub notify: Option<String>,
|
pub notify: Option<String>,
|
||||||
/// Datastore tuning options
|
/// Datastore tuning options
|
||||||
#[serde(skip_serializing_if="Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub tuning: Option<String>,
|
pub tuning: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -375,7 +377,6 @@ pub struct SnapshotVerifyState {
|
||||||
pub state: VerifyState,
|
pub state: VerifyState,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[api(
|
#[api(
|
||||||
properties: {
|
properties: {
|
||||||
"backup-type": {
|
"backup-type": {
|
||||||
|
@ -616,7 +617,7 @@ impl Default for GarbageCollectionStatus {
|
||||||
},
|
},
|
||||||
)]
|
)]
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
#[serde(rename_all="kebab-case")]
|
#[serde(rename_all = "kebab-case")]
|
||||||
/// Overall Datastore status and useful information.
|
/// Overall Datastore status and useful information.
|
||||||
pub struct DataStoreStatus {
|
pub struct DataStoreStatus {
|
||||||
/// Total space (bytes).
|
/// Total space (bytes).
|
||||||
|
@ -626,10 +627,10 @@ pub struct DataStoreStatus {
|
||||||
/// Available space (bytes).
|
/// Available space (bytes).
|
||||||
pub avail: u64,
|
pub avail: u64,
|
||||||
/// Status of last GC
|
/// Status of last GC
|
||||||
#[serde(skip_serializing_if="Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub gc_status: Option<GarbageCollectionStatus>,
|
pub gc_status: Option<GarbageCollectionStatus>,
|
||||||
/// Group/Snapshot counts
|
/// Group/Snapshot counts
|
||||||
#[serde(skip_serializing_if="Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub counts: Option<Counts>,
|
pub counts: Option<Counts>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -649,7 +650,7 @@ pub struct DataStoreStatus {
|
||||||
},
|
},
|
||||||
)]
|
)]
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
#[serde(rename_all="kebab-case")]
|
#[serde(rename_all = "kebab-case")]
|
||||||
/// Status of a Datastore
|
/// Status of a Datastore
|
||||||
pub struct DataStoreStatusListItem {
|
pub struct DataStoreStatusListItem {
|
||||||
pub store: String,
|
pub store: String,
|
||||||
|
@ -660,23 +661,23 @@ pub struct DataStoreStatusListItem {
|
||||||
/// The available bytes of the underlying storage. (-1 on error)
|
/// The available bytes of the underlying storage. (-1 on error)
|
||||||
pub avail: i64,
|
pub avail: i64,
|
||||||
/// A list of usages of the past (last Month).
|
/// A list of usages of the past (last Month).
|
||||||
#[serde(skip_serializing_if="Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub history: Option<Vec<Option<f64>>>,
|
pub history: Option<Vec<Option<f64>>>,
|
||||||
/// History start time (epoch)
|
/// History start time (epoch)
|
||||||
#[serde(skip_serializing_if="Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub history_start: Option<u64>,
|
pub history_start: Option<u64>,
|
||||||
/// History resolution (seconds)
|
/// History resolution (seconds)
|
||||||
#[serde(skip_serializing_if="Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub history_delta: Option<u64>,
|
pub history_delta: Option<u64>,
|
||||||
/// Estimation of the UNIX epoch when the storage will be full.
|
/// Estimation of the UNIX epoch when the storage will be full.
|
||||||
/// This is calculated via a simple Linear Regression (Least
|
/// This is calculated via a simple Linear Regression (Least
|
||||||
/// Squares) of RRD data of the last Month. Missing if there are
|
/// Squares) of RRD data of the last Month. Missing if there are
|
||||||
/// not enough data points yet. If the estimate lies in the past,
|
/// not enough data points yet. If the estimate lies in the past,
|
||||||
/// the usage is decreasing or not changing.
|
/// the usage is decreasing or not changing.
|
||||||
#[serde(skip_serializing_if="Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub estimated_full_date: Option<i64>,
|
pub estimated_full_date: Option<i64>,
|
||||||
/// An error description, for example, when the datastore could not be looked up
|
/// An error description, for example, when the datastore could not be looked up
|
||||||
#[serde(skip_serializing_if="Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub error: Option<String>,
|
pub error: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -685,7 +686,8 @@ pub const ADMIN_DATASTORE_LIST_SNAPSHOTS_RETURN_TYPE: ReturnType = ReturnType {
|
||||||
schema: &ArraySchema::new(
|
schema: &ArraySchema::new(
|
||||||
"Returns the list of snapshots.",
|
"Returns the list of snapshots.",
|
||||||
&SnapshotListItem::API_SCHEMA,
|
&SnapshotListItem::API_SCHEMA,
|
||||||
).schema(),
|
)
|
||||||
|
.schema(),
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const ADMIN_DATASTORE_LIST_SNAPSHOT_FILES_RETURN_TYPE: ReturnType = ReturnType {
|
pub const ADMIN_DATASTORE_LIST_SNAPSHOT_FILES_RETURN_TYPE: ReturnType = ReturnType {
|
||||||
|
@ -693,7 +695,8 @@ pub const ADMIN_DATASTORE_LIST_SNAPSHOT_FILES_RETURN_TYPE: ReturnType = ReturnTy
|
||||||
schema: &ArraySchema::new(
|
schema: &ArraySchema::new(
|
||||||
"Returns the list of archive files inside a backup snapshots.",
|
"Returns the list of archive files inside a backup snapshots.",
|
||||||
&BackupContent::API_SCHEMA,
|
&BackupContent::API_SCHEMA,
|
||||||
).schema(),
|
)
|
||||||
|
.schema(),
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const ADMIN_DATASTORE_LIST_GROUPS_RETURN_TYPE: ReturnType = ReturnType {
|
pub const ADMIN_DATASTORE_LIST_GROUPS_RETURN_TYPE: ReturnType = ReturnType {
|
||||||
|
@ -701,7 +704,8 @@ pub const ADMIN_DATASTORE_LIST_GROUPS_RETURN_TYPE: ReturnType = ReturnType {
|
||||||
schema: &ArraySchema::new(
|
schema: &ArraySchema::new(
|
||||||
"Returns the list of backup groups.",
|
"Returns the list of backup groups.",
|
||||||
&GroupListItem::API_SCHEMA,
|
&GroupListItem::API_SCHEMA,
|
||||||
).schema(),
|
)
|
||||||
|
.schema(),
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const ADMIN_DATASTORE_PRUNE_RETURN_TYPE: ReturnType = ReturnType {
|
pub const ADMIN_DATASTORE_PRUNE_RETURN_TYPE: ReturnType = ReturnType {
|
||||||
|
@ -709,5 +713,6 @@ pub const ADMIN_DATASTORE_PRUNE_RETURN_TYPE: ReturnType = ReturnType {
|
||||||
schema: &ArraySchema::new(
|
schema: &ArraySchema::new(
|
||||||
"Returns the list of snapshots and a flag indicating if there are kept or removed.",
|
"Returns the list of snapshots and a flag indicating if there are kept or removed.",
|
||||||
&PruneListItem::API_SCHEMA,
|
&PruneListItem::API_SCHEMA,
|
||||||
).schema(),
|
)
|
||||||
|
.schema(),
|
||||||
};
|
};
|
||||||
|
|
|
@ -101,7 +101,8 @@ fn strip_unit(v: &str) -> (&str, SizeUnit) {
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut unit = SizeUnit::Byte;
|
let mut unit = SizeUnit::Byte;
|
||||||
(v.strip_suffix(|c: char| match c {
|
#[rustfmt::skip]
|
||||||
|
let value = v.strip_suffix(|c: char| match c {
|
||||||
'k' | 'K' if !binary => { unit = SizeUnit::KByte; true }
|
'k' | 'K' if !binary => { unit = SizeUnit::KByte; true }
|
||||||
'm' | 'M' if !binary => { unit = SizeUnit::MByte; true }
|
'm' | 'M' if !binary => { unit = SizeUnit::MByte; true }
|
||||||
'g' | 'G' if !binary => { unit = SizeUnit::GByte; true }
|
'g' | 'G' if !binary => { unit = SizeUnit::GByte; true }
|
||||||
|
@ -114,7 +115,9 @@ fn strip_unit(v: &str) -> (&str, SizeUnit) {
|
||||||
't' | 'T' if binary => { unit = SizeUnit::Tebi; true }
|
't' | 'T' if binary => { unit = SizeUnit::Tebi; true }
|
||||||
'p' | 'P' if binary => { unit = SizeUnit::Pebi; true }
|
'p' | 'P' if binary => { unit = SizeUnit::Pebi; true }
|
||||||
_ => false
|
_ => false
|
||||||
}).unwrap_or(v).trim_end(), unit)
|
}).unwrap_or(v).trim_end();
|
||||||
|
|
||||||
|
(value, unit)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Byte size which can be displayed in a human friendly way
|
/// Byte size which can be displayed in a human friendly way
|
||||||
|
@ -154,13 +157,19 @@ impl HumanByte {
|
||||||
/// Create a new instance with optimal binary unit computed
|
/// Create a new instance with optimal binary unit computed
|
||||||
pub fn new_binary(size: f64) -> Self {
|
pub fn new_binary(size: f64) -> Self {
|
||||||
let unit = SizeUnit::auto_scale(size, true);
|
let unit = SizeUnit::auto_scale(size, true);
|
||||||
HumanByte { size: size / unit.factor(), unit }
|
HumanByte {
|
||||||
|
size: size / unit.factor(),
|
||||||
|
unit,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a new instance with optimal decimal unit computed
|
/// Create a new instance with optimal decimal unit computed
|
||||||
pub fn new_decimal(size: f64) -> Self {
|
pub fn new_decimal(size: f64) -> Self {
|
||||||
let unit = SizeUnit::auto_scale(size, false);
|
let unit = SizeUnit::auto_scale(size, false);
|
||||||
HumanByte { size: size / unit.factor(), unit }
|
HumanByte {
|
||||||
|
size: size / unit.factor(),
|
||||||
|
unit,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the size as u64 number of bytes
|
/// Returns the size as u64 number of bytes
|
||||||
|
@ -228,7 +237,12 @@ fn test_human_byte_parser() -> Result<(), Error> {
|
||||||
bail!("got unexpected size for '{}' ({} != {})", v, h.size, size);
|
bail!("got unexpected size for '{}' ({} != {})", v, h.size, size);
|
||||||
}
|
}
|
||||||
if h.unit != unit {
|
if h.unit != unit {
|
||||||
bail!("got unexpected unit for '{}' ({:?} != {:?})", v, h.unit, unit);
|
bail!(
|
||||||
|
"got unexpected unit for '{}' ({:?} != {:?})",
|
||||||
|
v,
|
||||||
|
h.unit,
|
||||||
|
unit
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let new = h.to_string();
|
let new = h.to_string();
|
||||||
|
@ -265,7 +279,12 @@ fn test_human_byte_parser() -> Result<(), Error> {
|
||||||
assert_eq!(&format!("{:.7}", h), "1.2345678 B");
|
assert_eq!(&format!("{:.7}", h), "1.2345678 B");
|
||||||
assert_eq!(&format!("{:.8}", h), "1.2345678 B");
|
assert_eq!(&format!("{:.8}", h), "1.2345678 B");
|
||||||
|
|
||||||
assert!(test("987654321", 987654321.0, SizeUnit::Byte, "987654321 B"));
|
assert!(test(
|
||||||
|
"987654321",
|
||||||
|
987654321.0,
|
||||||
|
SizeUnit::Byte,
|
||||||
|
"987654321 B"
|
||||||
|
));
|
||||||
|
|
||||||
assert!(test("1300b", 1300.0, SizeUnit::Byte, "1300 B"));
|
assert!(test("1300b", 1300.0, SizeUnit::Byte, "1300 B"));
|
||||||
assert!(test("1300B", 1300.0, SizeUnit::Byte, "1300 B"));
|
assert!(test("1300B", 1300.0, SizeUnit::Byte, "1300 B"));
|
||||||
|
|
|
@ -7,13 +7,12 @@ use serde::{Deserialize, Serialize};
|
||||||
use proxmox_schema::*;
|
use proxmox_schema::*;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
Userid, Authid, RateLimitConfig,
|
Authid, RateLimitConfig, Userid, BACKUP_GROUP_SCHEMA, BACKUP_TYPE_SCHEMA, DATASTORE_SCHEMA,
|
||||||
REMOTE_ID_SCHEMA, DRIVE_NAME_SCHEMA, MEDIA_POOL_NAME_SCHEMA,
|
DRIVE_NAME_SCHEMA, MEDIA_POOL_NAME_SCHEMA, PROXMOX_SAFE_ID_FORMAT, REMOTE_ID_SCHEMA,
|
||||||
SINGLE_LINE_COMMENT_SCHEMA, PROXMOX_SAFE_ID_FORMAT, DATASTORE_SCHEMA,
|
SINGLE_LINE_COMMENT_SCHEMA,
|
||||||
BACKUP_GROUP_SCHEMA, BACKUP_TYPE_SCHEMA,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const_regex!{
|
const_regex! {
|
||||||
|
|
||||||
/// Regex for verification jobs 'DATASTORE:ACTUAL_JOB_ID'
|
/// Regex for verification jobs 'DATASTORE:ACTUAL_JOB_ID'
|
||||||
pub VERIFICATION_JOB_WORKER_ID_REGEX = concat!(r"^(", PROXMOX_SAFE_ID_REGEX_STR!(), r"):");
|
pub VERIFICATION_JOB_WORKER_ID_REGEX = concat!(r"^(", PROXMOX_SAFE_ID_REGEX_STR!(), r"):");
|
||||||
|
@ -27,34 +26,41 @@ pub const JOB_ID_SCHEMA: Schema = StringSchema::new("Job ID.")
|
||||||
.max_length(32)
|
.max_length(32)
|
||||||
.schema();
|
.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(
|
||||||
.format(&ApiStringFormat::VerifyFn(proxmox_time::verify_calendar_event))
|
proxmox_time::verify_calendar_event,
|
||||||
|
))
|
||||||
.type_text("<calendar-event>")
|
.type_text("<calendar-event>")
|
||||||
.schema();
|
.schema();
|
||||||
|
|
||||||
pub const GC_SCHEDULE_SCHEMA: Schema = StringSchema::new(
|
pub const GC_SCHEDULE_SCHEMA: Schema =
|
||||||
"Run garbage collection job at specified schedule.")
|
StringSchema::new("Run garbage collection job at specified schedule.")
|
||||||
.format(&ApiStringFormat::VerifyFn(proxmox_time::verify_calendar_event))
|
.format(&ApiStringFormat::VerifyFn(
|
||||||
|
proxmox_time::verify_calendar_event,
|
||||||
|
))
|
||||||
.type_text("<calendar-event>")
|
.type_text("<calendar-event>")
|
||||||
.schema();
|
.schema();
|
||||||
|
|
||||||
pub const PRUNE_SCHEDULE_SCHEMA: Schema = StringSchema::new(
|
pub const PRUNE_SCHEDULE_SCHEMA: Schema = StringSchema::new("Run prune job at specified schedule.")
|
||||||
"Run prune job at specified schedule.")
|
.format(&ApiStringFormat::VerifyFn(
|
||||||
.format(&ApiStringFormat::VerifyFn(proxmox_time::verify_calendar_event))
|
proxmox_time::verify_calendar_event,
|
||||||
|
))
|
||||||
.type_text("<calendar-event>")
|
.type_text("<calendar-event>")
|
||||||
.schema();
|
.schema();
|
||||||
|
|
||||||
pub const VERIFICATION_SCHEDULE_SCHEMA: Schema = StringSchema::new(
|
pub const VERIFICATION_SCHEDULE_SCHEMA: Schema =
|
||||||
"Run verify job at specified schedule.")
|
StringSchema::new("Run verify job at specified schedule.")
|
||||||
.format(&ApiStringFormat::VerifyFn(proxmox_time::verify_calendar_event))
|
.format(&ApiStringFormat::VerifyFn(
|
||||||
|
proxmox_time::verify_calendar_event,
|
||||||
|
))
|
||||||
.type_text("<calendar-event>")
|
.type_text("<calendar-event>")
|
||||||
.schema();
|
.schema();
|
||||||
|
|
||||||
pub const REMOVE_VANISHED_BACKUPS_SCHEMA: Schema = BooleanSchema::new(
|
pub const REMOVE_VANISHED_BACKUPS_SCHEMA: Schema = BooleanSchema::new(
|
||||||
"Delete vanished backups. This remove the local copy if the remote backup was deleted.")
|
"Delete vanished backups. This remove the local copy if the remote backup was deleted.",
|
||||||
.default(false)
|
)
|
||||||
.schema();
|
.default(false)
|
||||||
|
.schema();
|
||||||
|
|
||||||
#[api(
|
#[api(
|
||||||
properties: {
|
properties: {
|
||||||
|
@ -80,17 +86,17 @@ pub const REMOVE_VANISHED_BACKUPS_SCHEMA: Schema = BooleanSchema::new(
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
)]
|
)]
|
||||||
#[derive(Serialize,Deserialize,Default)]
|
#[derive(Serialize, Deserialize, Default)]
|
||||||
#[serde(rename_all="kebab-case")]
|
#[serde(rename_all = "kebab-case")]
|
||||||
/// Job Scheduling Status
|
/// Job Scheduling Status
|
||||||
pub struct JobScheduleStatus {
|
pub struct JobScheduleStatus {
|
||||||
#[serde(skip_serializing_if="Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub next_run: Option<i64>,
|
pub next_run: Option<i64>,
|
||||||
#[serde(skip_serializing_if="Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub last_run_state: Option<String>,
|
pub last_run_state: Option<String>,
|
||||||
#[serde(skip_serializing_if="Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub last_run_upid: Option<String>,
|
pub last_run_upid: Option<String>,
|
||||||
#[serde(skip_serializing_if="Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub last_run_endtime: Option<i64>,
|
pub last_run_endtime: Option<i64>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -134,18 +140,21 @@ pub struct DatastoreNotify {
|
||||||
pub sync: Option<Notify>,
|
pub sync: Option<Notify>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const DATASTORE_NOTIFY_STRING_SCHEMA: Schema = StringSchema::new(
|
pub const DATASTORE_NOTIFY_STRING_SCHEMA: Schema =
|
||||||
"Datastore notification setting")
|
StringSchema::new("Datastore notification setting")
|
||||||
.format(&ApiStringFormat::PropertyString(&DatastoreNotify::API_SCHEMA))
|
.format(&ApiStringFormat::PropertyString(
|
||||||
|
&DatastoreNotify::API_SCHEMA,
|
||||||
|
))
|
||||||
.schema();
|
.schema();
|
||||||
|
|
||||||
pub const IGNORE_VERIFIED_BACKUPS_SCHEMA: Schema = BooleanSchema::new(
|
pub const IGNORE_VERIFIED_BACKUPS_SCHEMA: Schema = BooleanSchema::new(
|
||||||
"Do not verify backups that are already verified if their verification is not outdated.")
|
"Do not verify backups that are already verified if their verification is not outdated.",
|
||||||
.default(true)
|
)
|
||||||
.schema();
|
.default(true)
|
||||||
|
.schema();
|
||||||
|
|
||||||
pub const VERIFICATION_OUTDATED_AFTER_SCHEMA: Schema = IntegerSchema::new(
|
pub const VERIFICATION_OUTDATED_AFTER_SCHEMA: Schema =
|
||||||
"Days after that a verification becomes outdated. (0 means always)")
|
IntegerSchema::new("Days after that a verification becomes outdated. (0 means always)")
|
||||||
.minimum(0)
|
.minimum(0)
|
||||||
.schema();
|
.schema();
|
||||||
|
|
||||||
|
@ -175,8 +184,8 @@ pub const VERIFICATION_OUTDATED_AFTER_SCHEMA: Schema = IntegerSchema::new(
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
)]
|
)]
|
||||||
#[derive(Serialize,Deserialize,Updater)]
|
#[derive(Serialize, Deserialize, Updater)]
|
||||||
#[serde(rename_all="kebab-case")]
|
#[serde(rename_all = "kebab-case")]
|
||||||
/// Verification Job
|
/// Verification Job
|
||||||
pub struct VerificationJobConfig {
|
pub struct VerificationJobConfig {
|
||||||
/// unique ID to address this job
|
/// unique ID to address this job
|
||||||
|
@ -184,16 +193,16 @@ pub struct VerificationJobConfig {
|
||||||
pub id: String,
|
pub id: String,
|
||||||
/// the datastore ID this verificaiton job affects
|
/// the datastore ID this verificaiton job affects
|
||||||
pub store: String,
|
pub store: String,
|
||||||
#[serde(skip_serializing_if="Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
/// if not set to false, check the age of the last snapshot verification to filter
|
/// if not set to false, check the age of the last snapshot verification to filter
|
||||||
/// out recent ones, depending on 'outdated_after' configuration.
|
/// out recent ones, depending on 'outdated_after' configuration.
|
||||||
pub ignore_verified: Option<bool>,
|
pub ignore_verified: Option<bool>,
|
||||||
#[serde(skip_serializing_if="Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
/// Reverify snapshots after X days, never if 0. Ignored if 'ignore_verified' is false.
|
/// Reverify snapshots after X days, never if 0. Ignored if 'ignore_verified' is false.
|
||||||
pub outdated_after: Option<i64>,
|
pub outdated_after: Option<i64>,
|
||||||
#[serde(skip_serializing_if="Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub comment: Option<String>,
|
pub comment: Option<String>,
|
||||||
#[serde(skip_serializing_if="Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
/// when to schedule this job in calendar event notation
|
/// when to schedule this job in calendar event notation
|
||||||
pub schedule: Option<String>,
|
pub schedule: Option<String>,
|
||||||
}
|
}
|
||||||
|
@ -208,8 +217,8 @@ pub struct VerificationJobConfig {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
)]
|
)]
|
||||||
#[derive(Serialize,Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
#[serde(rename_all="kebab-case")]
|
#[serde(rename_all = "kebab-case")]
|
||||||
/// Status of Verification Job
|
/// Status of Verification Job
|
||||||
pub struct VerificationJobStatus {
|
pub struct VerificationJobStatus {
|
||||||
#[serde(flatten)]
|
#[serde(flatten)]
|
||||||
|
@ -254,23 +263,23 @@ pub struct VerificationJobStatus {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
)]
|
)]
|
||||||
#[derive(Serialize,Deserialize,Clone,Updater)]
|
#[derive(Serialize, Deserialize, Clone, Updater)]
|
||||||
#[serde(rename_all="kebab-case")]
|
#[serde(rename_all = "kebab-case")]
|
||||||
/// Tape Backup Job Setup
|
/// Tape Backup Job Setup
|
||||||
pub struct TapeBackupJobSetup {
|
pub struct TapeBackupJobSetup {
|
||||||
pub store: String,
|
pub store: String,
|
||||||
pub pool: String,
|
pub pool: String,
|
||||||
pub drive: String,
|
pub drive: String,
|
||||||
#[serde(skip_serializing_if="Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub eject_media: Option<bool>,
|
pub eject_media: Option<bool>,
|
||||||
#[serde(skip_serializing_if="Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub export_media_set: Option<bool>,
|
pub export_media_set: Option<bool>,
|
||||||
#[serde(skip_serializing_if="Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub latest_only: Option<bool>,
|
pub latest_only: Option<bool>,
|
||||||
/// Send job email notification to this user
|
/// Send job email notification to this user
|
||||||
#[serde(skip_serializing_if="Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub notify_user: Option<Userid>,
|
pub notify_user: Option<Userid>,
|
||||||
#[serde(skip_serializing_if="Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub group_filter: Option<Vec<GroupFilter>>,
|
pub group_filter: Option<Vec<GroupFilter>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -292,17 +301,17 @@ pub struct TapeBackupJobSetup {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
)]
|
)]
|
||||||
#[derive(Serialize,Deserialize,Clone,Updater)]
|
#[derive(Serialize, Deserialize, Clone, Updater)]
|
||||||
#[serde(rename_all="kebab-case")]
|
#[serde(rename_all = "kebab-case")]
|
||||||
/// Tape Backup Job
|
/// Tape Backup Job
|
||||||
pub struct TapeBackupJobConfig {
|
pub struct TapeBackupJobConfig {
|
||||||
#[updater(skip)]
|
#[updater(skip)]
|
||||||
pub id: String,
|
pub id: String,
|
||||||
#[serde(flatten)]
|
#[serde(flatten)]
|
||||||
pub setup: TapeBackupJobSetup,
|
pub setup: TapeBackupJobSetup,
|
||||||
#[serde(skip_serializing_if="Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub comment: Option<String>,
|
pub comment: Option<String>,
|
||||||
#[serde(skip_serializing_if="Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub schedule: Option<String>,
|
pub schedule: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -316,8 +325,8 @@ pub struct TapeBackupJobConfig {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
)]
|
)]
|
||||||
#[derive(Serialize,Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
#[serde(rename_all="kebab-case")]
|
#[serde(rename_all = "kebab-case")]
|
||||||
/// Status of Tape Backup Job
|
/// Status of Tape Backup Job
|
||||||
pub struct TapeBackupJobStatus {
|
pub struct TapeBackupJobStatus {
|
||||||
#[serde(flatten)]
|
#[serde(flatten)]
|
||||||
|
@ -325,7 +334,7 @@ pub struct TapeBackupJobStatus {
|
||||||
#[serde(flatten)]
|
#[serde(flatten)]
|
||||||
pub status: JobScheduleStatus,
|
pub status: JobScheduleStatus,
|
||||||
/// Next tape used (best guess)
|
/// Next tape used (best guess)
|
||||||
#[serde(skip_serializing_if="Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub next_media_label: Option<String>,
|
pub next_media_label: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -378,7 +387,8 @@ pub const GROUP_FILTER_SCHEMA: Schema = StringSchema::new(
|
||||||
.type_text("<type:<vm|ct|host>|group:GROUP|regex:RE>")
|
.type_text("<type:<vm|ct|host>|group:GROUP|regex:RE>")
|
||||||
.schema();
|
.schema();
|
||||||
|
|
||||||
pub const GROUP_FILTER_LIST_SCHEMA: Schema = ArraySchema::new("List of group filters.", &GROUP_FILTER_SCHEMA).schema();
|
pub const GROUP_FILTER_LIST_SCHEMA: Schema =
|
||||||
|
ArraySchema::new("List of group filters.", &GROUP_FILTER_SCHEMA).schema();
|
||||||
|
|
||||||
#[api(
|
#[api(
|
||||||
properties: {
|
properties: {
|
||||||
|
@ -419,24 +429,24 @@ pub const GROUP_FILTER_LIST_SCHEMA: Schema = ArraySchema::new("List of group fil
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
)]
|
)]
|
||||||
#[derive(Serialize,Deserialize,Clone,Updater)]
|
#[derive(Serialize, Deserialize, Clone, Updater)]
|
||||||
#[serde(rename_all="kebab-case")]
|
#[serde(rename_all = "kebab-case")]
|
||||||
/// Sync Job
|
/// Sync Job
|
||||||
pub struct SyncJobConfig {
|
pub struct SyncJobConfig {
|
||||||
#[updater(skip)]
|
#[updater(skip)]
|
||||||
pub id: String,
|
pub id: String,
|
||||||
pub store: String,
|
pub store: String,
|
||||||
#[serde(skip_serializing_if="Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub owner: Option<Authid>,
|
pub owner: Option<Authid>,
|
||||||
pub remote: String,
|
pub remote: String,
|
||||||
pub remote_store: String,
|
pub remote_store: String,
|
||||||
#[serde(skip_serializing_if="Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub remove_vanished: Option<bool>,
|
pub remove_vanished: Option<bool>,
|
||||||
#[serde(skip_serializing_if="Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub comment: Option<String>,
|
pub comment: Option<String>,
|
||||||
#[serde(skip_serializing_if="Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub schedule: Option<String>,
|
pub schedule: Option<String>,
|
||||||
#[serde(skip_serializing_if="Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub group_filter: Option<Vec<GroupFilter>>,
|
pub group_filter: Option<Vec<GroupFilter>>,
|
||||||
#[serde(flatten)]
|
#[serde(flatten)]
|
||||||
pub limit: RateLimitConfig,
|
pub limit: RateLimitConfig,
|
||||||
|
@ -452,9 +462,8 @@ pub struct SyncJobConfig {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
)]
|
)]
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
#[derive(Serialize,Deserialize)]
|
#[serde(rename_all = "kebab-case")]
|
||||||
#[serde(rename_all="kebab-case")]
|
|
||||||
/// Status of Sync Job
|
/// Status of Sync Job
|
||||||
pub struct SyncJobStatus {
|
pub struct SyncJobStatus {
|
||||||
#[serde(flatten)]
|
#[serde(flatten)]
|
||||||
|
|
|
@ -39,7 +39,7 @@ impl Default for Kdf {
|
||||||
/// Encryption Key Information
|
/// Encryption Key Information
|
||||||
pub struct KeyInfo {
|
pub struct KeyInfo {
|
||||||
/// Path to key (if stored in a file)
|
/// Path to key (if stored in a file)
|
||||||
#[serde(skip_serializing_if="Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub path: Option<String>,
|
pub path: Option<String>,
|
||||||
pub kdf: Kdf,
|
pub kdf: Kdf,
|
||||||
/// Key creation time
|
/// Key creation time
|
||||||
|
@ -47,10 +47,9 @@ pub struct KeyInfo {
|
||||||
/// Key modification time
|
/// Key modification time
|
||||||
pub modified: i64,
|
pub modified: i64,
|
||||||
/// Key fingerprint
|
/// Key fingerprint
|
||||||
#[serde(skip_serializing_if="Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub fingerprint: Option<String>,
|
pub fingerprint: Option<String>,
|
||||||
/// Password hint
|
/// Password hint
|
||||||
#[serde(skip_serializing_if="Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub hint: Option<String>,
|
pub hint: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@ pub mod common_regex;
|
||||||
pub mod percent_encoding;
|
pub mod percent_encoding;
|
||||||
|
|
||||||
use proxmox_schema::{
|
use proxmox_schema::{
|
||||||
api, const_regex, ApiStringFormat, ApiType, ArraySchema, Schema, StringSchema, ReturnType,
|
api, const_regex, ApiStringFormat, ApiType, ArraySchema, ReturnType, Schema, StringSchema,
|
||||||
};
|
};
|
||||||
use proxmox_time::parse_daily_duration;
|
use proxmox_time::parse_daily_duration;
|
||||||
|
|
||||||
|
@ -68,7 +68,7 @@ pub use user::*;
|
||||||
pub use proxmox_schema::upid::*;
|
pub use proxmox_schema::upid::*;
|
||||||
|
|
||||||
mod crypto;
|
mod crypto;
|
||||||
pub use crypto::{CryptMode, Fingerprint, bytes_as_fingerprint};
|
pub use crypto::{bytes_as_fingerprint, CryptMode, Fingerprint};
|
||||||
|
|
||||||
pub mod file_restore;
|
pub mod file_restore;
|
||||||
|
|
||||||
|
@ -87,7 +87,6 @@ pub use traffic_control::*;
|
||||||
mod zfs;
|
mod zfs;
|
||||||
pub use zfs::*;
|
pub use zfs::*;
|
||||||
|
|
||||||
|
|
||||||
#[rustfmt::skip]
|
#[rustfmt::skip]
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
mod local_macros {
|
mod local_macros {
|
||||||
|
@ -160,14 +159,17 @@ pub const CIDR_FORMAT: ApiStringFormat = ApiStringFormat::Pattern(&CIDR_REGEX);
|
||||||
pub const PVE_CONFIG_DIGEST_FORMAT: ApiStringFormat = ApiStringFormat::Pattern(&SHA256_HEX_REGEX);
|
pub const PVE_CONFIG_DIGEST_FORMAT: ApiStringFormat = ApiStringFormat::Pattern(&SHA256_HEX_REGEX);
|
||||||
pub const PASSWORD_FORMAT: ApiStringFormat = ApiStringFormat::Pattern(&PASSWORD_REGEX);
|
pub const PASSWORD_FORMAT: ApiStringFormat = ApiStringFormat::Pattern(&PASSWORD_REGEX);
|
||||||
pub const UUID_FORMAT: ApiStringFormat = ApiStringFormat::Pattern(&UUID_REGEX);
|
pub const UUID_FORMAT: ApiStringFormat = ApiStringFormat::Pattern(&UUID_REGEX);
|
||||||
pub const BLOCKDEVICE_NAME_FORMAT: ApiStringFormat = ApiStringFormat::Pattern(&BLOCKDEVICE_NAME_REGEX);
|
pub const BLOCKDEVICE_NAME_FORMAT: ApiStringFormat =
|
||||||
pub const SUBSCRIPTION_KEY_FORMAT: ApiStringFormat = ApiStringFormat::Pattern(&SUBSCRIPTION_KEY_REGEX);
|
ApiStringFormat::Pattern(&BLOCKDEVICE_NAME_REGEX);
|
||||||
pub const SYSTEMD_DATETIME_FORMAT: ApiStringFormat = ApiStringFormat::Pattern(&SYSTEMD_DATETIME_REGEX);
|
pub const SUBSCRIPTION_KEY_FORMAT: ApiStringFormat =
|
||||||
|
ApiStringFormat::Pattern(&SUBSCRIPTION_KEY_REGEX);
|
||||||
|
pub const SYSTEMD_DATETIME_FORMAT: ApiStringFormat =
|
||||||
|
ApiStringFormat::Pattern(&SYSTEMD_DATETIME_REGEX);
|
||||||
pub const HOSTNAME_FORMAT: ApiStringFormat = ApiStringFormat::Pattern(&HOSTNAME_REGEX);
|
pub const HOSTNAME_FORMAT: ApiStringFormat = ApiStringFormat::Pattern(&HOSTNAME_REGEX);
|
||||||
pub const OPENSSL_CIPHERS_TLS_FORMAT: ApiStringFormat = ApiStringFormat::Pattern(&OPENSSL_CIPHERS_REGEX);
|
pub const OPENSSL_CIPHERS_TLS_FORMAT: ApiStringFormat =
|
||||||
|
ApiStringFormat::Pattern(&OPENSSL_CIPHERS_REGEX);
|
||||||
|
|
||||||
pub const DNS_ALIAS_FORMAT: ApiStringFormat =
|
pub const DNS_ALIAS_FORMAT: ApiStringFormat = ApiStringFormat::Pattern(&DNS_ALIAS_REGEX);
|
||||||
ApiStringFormat::Pattern(&DNS_ALIAS_REGEX);
|
|
||||||
|
|
||||||
pub const DAILY_DURATION_FORMAT: ApiStringFormat =
|
pub const DAILY_DURATION_FORMAT: ApiStringFormat =
|
||||||
ApiStringFormat::VerifyFn(|s| parse_daily_duration(s).map(drop));
|
ApiStringFormat::VerifyFn(|s| parse_daily_duration(s).map(drop));
|
||||||
|
@ -175,18 +177,15 @@ pub const DAILY_DURATION_FORMAT: ApiStringFormat =
|
||||||
pub const SEARCH_DOMAIN_SCHEMA: Schema =
|
pub const SEARCH_DOMAIN_SCHEMA: Schema =
|
||||||
StringSchema::new("Search domain for host-name lookup.").schema();
|
StringSchema::new("Search domain for host-name lookup.").schema();
|
||||||
|
|
||||||
pub const FIRST_DNS_SERVER_SCHEMA: Schema =
|
pub const FIRST_DNS_SERVER_SCHEMA: Schema = StringSchema::new("First name server IP address.")
|
||||||
StringSchema::new("First name server IP address.")
|
|
||||||
.format(&IP_FORMAT)
|
.format(&IP_FORMAT)
|
||||||
.schema();
|
.schema();
|
||||||
|
|
||||||
pub const SECOND_DNS_SERVER_SCHEMA: Schema =
|
pub const SECOND_DNS_SERVER_SCHEMA: Schema = StringSchema::new("Second name server IP address.")
|
||||||
StringSchema::new("Second name server IP address.")
|
|
||||||
.format(&IP_FORMAT)
|
.format(&IP_FORMAT)
|
||||||
.schema();
|
.schema();
|
||||||
|
|
||||||
pub const THIRD_DNS_SERVER_SCHEMA: Schema =
|
pub const THIRD_DNS_SERVER_SCHEMA: Schema = StringSchema::new("Third name server IP address.")
|
||||||
StringSchema::new("Third name server IP address.")
|
|
||||||
.format(&IP_FORMAT)
|
.format(&IP_FORMAT)
|
||||||
.schema();
|
.schema();
|
||||||
|
|
||||||
|
@ -194,48 +193,47 @@ pub const HOSTNAME_SCHEMA: Schema = StringSchema::new("Hostname (as defined in R
|
||||||
.format(&HOSTNAME_FORMAT)
|
.format(&HOSTNAME_FORMAT)
|
||||||
.schema();
|
.schema();
|
||||||
|
|
||||||
pub const OPENSSL_CIPHERS_TLS_1_2_SCHEMA: Schema = StringSchema::new("OpenSSL cipher list used by the proxy for TLS <= 1.2")
|
pub const OPENSSL_CIPHERS_TLS_1_2_SCHEMA: Schema =
|
||||||
|
StringSchema::new("OpenSSL cipher list used by the proxy for TLS <= 1.2")
|
||||||
.format(&OPENSSL_CIPHERS_TLS_FORMAT)
|
.format(&OPENSSL_CIPHERS_TLS_FORMAT)
|
||||||
.schema();
|
.schema();
|
||||||
|
|
||||||
pub const OPENSSL_CIPHERS_TLS_1_3_SCHEMA: Schema = StringSchema::new("OpenSSL ciphersuites list used by the proxy for TLS 1.3")
|
pub const OPENSSL_CIPHERS_TLS_1_3_SCHEMA: Schema =
|
||||||
|
StringSchema::new("OpenSSL ciphersuites list used by the proxy for TLS 1.3")
|
||||||
.format(&OPENSSL_CIPHERS_TLS_FORMAT)
|
.format(&OPENSSL_CIPHERS_TLS_FORMAT)
|
||||||
.schema();
|
.schema();
|
||||||
|
|
||||||
pub const DNS_NAME_FORMAT: ApiStringFormat =
|
pub const DNS_NAME_FORMAT: ApiStringFormat = ApiStringFormat::Pattern(&DNS_NAME_REGEX);
|
||||||
ApiStringFormat::Pattern(&DNS_NAME_REGEX);
|
|
||||||
|
|
||||||
pub const DNS_NAME_OR_IP_FORMAT: ApiStringFormat =
|
pub const DNS_NAME_OR_IP_FORMAT: ApiStringFormat = ApiStringFormat::Pattern(&DNS_NAME_OR_IP_REGEX);
|
||||||
ApiStringFormat::Pattern(&DNS_NAME_OR_IP_REGEX);
|
|
||||||
|
|
||||||
pub const DNS_NAME_OR_IP_SCHEMA: Schema = StringSchema::new("DNS name or IP address.")
|
pub const DNS_NAME_OR_IP_SCHEMA: Schema = StringSchema::new("DNS name or IP address.")
|
||||||
.format(&DNS_NAME_OR_IP_FORMAT)
|
.format(&DNS_NAME_OR_IP_FORMAT)
|
||||||
.schema();
|
.schema();
|
||||||
|
|
||||||
|
|
||||||
pub const NODE_SCHEMA: Schema = StringSchema::new("Node name (or 'localhost')")
|
pub const NODE_SCHEMA: Schema = StringSchema::new("Node name (or 'localhost')")
|
||||||
.format(&HOSTNAME_FORMAT)
|
.format(&HOSTNAME_FORMAT)
|
||||||
.schema();
|
.schema();
|
||||||
|
|
||||||
pub const TIME_ZONE_SCHEMA: Schema = StringSchema::new(
|
pub const TIME_ZONE_SCHEMA: Schema = StringSchema::new(
|
||||||
"Time zone. The file '/usr/share/zoneinfo/zone.tab' contains the list of valid names.")
|
"Time zone. The file '/usr/share/zoneinfo/zone.tab' contains the list of valid names.",
|
||||||
.format(&SINGLE_LINE_COMMENT_FORMAT)
|
)
|
||||||
.min_length(2)
|
.format(&SINGLE_LINE_COMMENT_FORMAT)
|
||||||
.max_length(64)
|
.min_length(2)
|
||||||
.schema();
|
.max_length(64)
|
||||||
|
.schema();
|
||||||
|
|
||||||
pub const BLOCKDEVICE_NAME_SCHEMA: Schema = StringSchema::new("Block device name (/sys/block/<name>).")
|
pub const BLOCKDEVICE_NAME_SCHEMA: Schema =
|
||||||
|
StringSchema::new("Block device name (/sys/block/<name>).")
|
||||||
.format(&BLOCKDEVICE_NAME_FORMAT)
|
.format(&BLOCKDEVICE_NAME_FORMAT)
|
||||||
.min_length(3)
|
.min_length(3)
|
||||||
.max_length(64)
|
.max_length(64)
|
||||||
.schema();
|
.schema();
|
||||||
|
|
||||||
pub const DISK_ARRAY_SCHEMA: Schema = ArraySchema::new(
|
pub const DISK_ARRAY_SCHEMA: Schema =
|
||||||
"Disk name list.", &BLOCKDEVICE_NAME_SCHEMA)
|
ArraySchema::new("Disk name list.", &BLOCKDEVICE_NAME_SCHEMA).schema();
|
||||||
.schema();
|
|
||||||
|
|
||||||
pub const DISK_LIST_SCHEMA: Schema = StringSchema::new(
|
pub const DISK_LIST_SCHEMA: Schema = StringSchema::new("A list of disk names, comma separated.")
|
||||||
"A list of disk names, comma separated.")
|
|
||||||
.format(&ApiStringFormat::PropertyString(&DISK_ARRAY_SCHEMA))
|
.format(&ApiStringFormat::PropertyString(&DISK_ARRAY_SCHEMA))
|
||||||
.schema();
|
.schema();
|
||||||
|
|
||||||
|
@ -282,15 +280,14 @@ pub const MULTI_LINE_COMMENT_SCHEMA: Schema = StringSchema::new("Comment (multip
|
||||||
.format(&MULTI_LINE_COMMENT_FORMAT)
|
.format(&MULTI_LINE_COMMENT_FORMAT)
|
||||||
.schema();
|
.schema();
|
||||||
|
|
||||||
pub const SUBSCRIPTION_KEY_SCHEMA: Schema = StringSchema::new("Proxmox Backup Server subscription key.")
|
pub const SUBSCRIPTION_KEY_SCHEMA: Schema =
|
||||||
|
StringSchema::new("Proxmox Backup Server subscription key.")
|
||||||
.format(&SUBSCRIPTION_KEY_FORMAT)
|
.format(&SUBSCRIPTION_KEY_FORMAT)
|
||||||
.min_length(15)
|
.min_length(15)
|
||||||
.max_length(16)
|
.max_length(16)
|
||||||
.schema();
|
.schema();
|
||||||
|
|
||||||
pub const SERVICE_ID_SCHEMA: Schema = StringSchema::new("Service ID.")
|
pub const SERVICE_ID_SCHEMA: Schema = StringSchema::new("Service ID.").max_length(256).schema();
|
||||||
.max_length(256)
|
|
||||||
.schema();
|
|
||||||
|
|
||||||
pub const PROXMOX_CONFIG_DIGEST_SCHEMA: Schema = StringSchema::new(
|
pub const PROXMOX_CONFIG_DIGEST_SCHEMA: Schema = StringSchema::new(
|
||||||
"Prevent changes if current configuration file has different \
|
"Prevent changes if current configuration file has different \
|
||||||
|
@ -303,10 +300,8 @@ pub const PROXMOX_CONFIG_DIGEST_SCHEMA: Schema = StringSchema::new(
|
||||||
/// API schema format definition for repository URLs
|
/// API schema format definition for repository URLs
|
||||||
pub const BACKUP_REPO_URL: ApiStringFormat = ApiStringFormat::Pattern(&BACKUP_REPO_URL_REGEX);
|
pub const BACKUP_REPO_URL: ApiStringFormat = ApiStringFormat::Pattern(&BACKUP_REPO_URL_REGEX);
|
||||||
|
|
||||||
|
|
||||||
// Complex type definitions
|
// Complex type definitions
|
||||||
|
|
||||||
|
|
||||||
#[api()]
|
#[api()]
|
||||||
#[derive(Default, Serialize, Deserialize)]
|
#[derive(Default, Serialize, Deserialize)]
|
||||||
/// Storage space usage information.
|
/// Storage space usage information.
|
||||||
|
@ -325,7 +320,6 @@ pub const PASSWORD_HINT_SCHEMA: Schema = StringSchema::new("Password hint.")
|
||||||
.max_length(64)
|
.max_length(64)
|
||||||
.schema();
|
.schema();
|
||||||
|
|
||||||
|
|
||||||
#[api()]
|
#[api()]
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
#[serde(rename_all = "PascalCase")]
|
#[serde(rename_all = "PascalCase")]
|
||||||
|
@ -352,11 +346,10 @@ pub struct APTUpdateInfo {
|
||||||
/// URL under which the package's changelog can be retrieved
|
/// URL under which the package's changelog can be retrieved
|
||||||
pub change_log_url: String,
|
pub change_log_url: String,
|
||||||
/// Custom extra field for additional package information
|
/// Custom extra field for additional package information
|
||||||
#[serde(skip_serializing_if="Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub extra_info: Option<String>,
|
pub extra_info: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[api()]
|
#[api()]
|
||||||
#[derive(Debug, Copy, Clone, PartialEq, Serialize, Deserialize)]
|
#[derive(Debug, Copy, Clone, PartialEq, Serialize, Deserialize)]
|
||||||
#[serde(rename_all = "lowercase")]
|
#[serde(rename_all = "lowercase")]
|
||||||
|
@ -368,7 +361,6 @@ pub enum NodePowerCommand {
|
||||||
Shutdown,
|
Shutdown,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[api()]
|
#[api()]
|
||||||
#[derive(Eq, PartialEq, Debug, Serialize, Deserialize)]
|
#[derive(Eq, PartialEq, Debug, Serialize, Deserialize)]
|
||||||
#[serde(rename_all = "lowercase")]
|
#[serde(rename_all = "lowercase")]
|
||||||
|
@ -407,19 +399,16 @@ pub struct TaskListItem {
|
||||||
/// The authenticated entity who started the task
|
/// The authenticated entity who started the task
|
||||||
pub user: String,
|
pub user: String,
|
||||||
/// The task end time (Epoch)
|
/// The task end time (Epoch)
|
||||||
#[serde(skip_serializing_if="Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub endtime: Option<i64>,
|
pub endtime: Option<i64>,
|
||||||
/// Task end status
|
/// Task end status
|
||||||
#[serde(skip_serializing_if="Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub status: Option<String>,
|
pub status: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const NODE_TASKS_LIST_TASKS_RETURN_TYPE: ReturnType = ReturnType {
|
pub const NODE_TASKS_LIST_TASKS_RETURN_TYPE: ReturnType = ReturnType {
|
||||||
optional: false,
|
optional: false,
|
||||||
schema: &ArraySchema::new(
|
schema: &ArraySchema::new("A list of tasks.", &TaskListItem::API_SCHEMA).schema(),
|
||||||
"A list of tasks.",
|
|
||||||
&TaskListItem::API_SCHEMA,
|
|
||||||
).schema(),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#[api()]
|
#[api()]
|
||||||
|
|
|
@ -3,40 +3,34 @@ use serde::{Deserialize, Serialize};
|
||||||
use proxmox_schema::*;
|
use proxmox_schema::*;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
CIDR_FORMAT, CIDR_V4_FORMAT, CIDR_V6_FORMAT, IP_FORMAT, IP_V4_FORMAT, IP_V6_FORMAT,
|
||||||
PROXMOX_SAFE_ID_REGEX,
|
PROXMOX_SAFE_ID_REGEX,
|
||||||
IP_V4_FORMAT, IP_V6_FORMAT, IP_FORMAT,
|
|
||||||
CIDR_V4_FORMAT, CIDR_V6_FORMAT, CIDR_FORMAT,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const NETWORK_INTERFACE_FORMAT: ApiStringFormat =
|
pub const NETWORK_INTERFACE_FORMAT: ApiStringFormat =
|
||||||
ApiStringFormat::Pattern(&PROXMOX_SAFE_ID_REGEX);
|
ApiStringFormat::Pattern(&PROXMOX_SAFE_ID_REGEX);
|
||||||
|
|
||||||
pub const IP_V4_SCHEMA: Schema =
|
pub const IP_V4_SCHEMA: Schema = StringSchema::new("IPv4 address.")
|
||||||
StringSchema::new("IPv4 address.")
|
|
||||||
.format(&IP_V4_FORMAT)
|
.format(&IP_V4_FORMAT)
|
||||||
.max_length(15)
|
.max_length(15)
|
||||||
.schema();
|
.schema();
|
||||||
|
|
||||||
pub const IP_V6_SCHEMA: Schema =
|
pub const IP_V6_SCHEMA: Schema = StringSchema::new("IPv6 address.")
|
||||||
StringSchema::new("IPv6 address.")
|
|
||||||
.format(&IP_V6_FORMAT)
|
.format(&IP_V6_FORMAT)
|
||||||
.max_length(39)
|
.max_length(39)
|
||||||
.schema();
|
.schema();
|
||||||
|
|
||||||
pub const IP_SCHEMA: Schema =
|
pub const IP_SCHEMA: Schema = StringSchema::new("IP (IPv4 or IPv6) address.")
|
||||||
StringSchema::new("IP (IPv4 or IPv6) address.")
|
|
||||||
.format(&IP_FORMAT)
|
.format(&IP_FORMAT)
|
||||||
.max_length(39)
|
.max_length(39)
|
||||||
.schema();
|
.schema();
|
||||||
|
|
||||||
pub const CIDR_V4_SCHEMA: Schema =
|
pub const CIDR_V4_SCHEMA: Schema = StringSchema::new("IPv4 address with netmask (CIDR notation).")
|
||||||
StringSchema::new("IPv4 address with netmask (CIDR notation).")
|
|
||||||
.format(&CIDR_V4_FORMAT)
|
.format(&CIDR_V4_FORMAT)
|
||||||
.max_length(18)
|
.max_length(18)
|
||||||
.schema();
|
.schema();
|
||||||
|
|
||||||
pub const CIDR_V6_SCHEMA: Schema =
|
pub const CIDR_V6_SCHEMA: Schema = StringSchema::new("IPv6 address with netmask (CIDR notation).")
|
||||||
StringSchema::new("IPv6 address with netmask (CIDR notation).")
|
|
||||||
.format(&CIDR_V6_FORMAT)
|
.format(&CIDR_V6_FORMAT)
|
||||||
.max_length(43)
|
.max_length(43)
|
||||||
.schema();
|
.schema();
|
||||||
|
@ -130,13 +124,14 @@ pub const NETWORK_INTERFACE_NAME_SCHEMA: Schema = StringSchema::new("Network int
|
||||||
.max_length(15) // libc::IFNAMSIZ-1
|
.max_length(15) // libc::IFNAMSIZ-1
|
||||||
.schema();
|
.schema();
|
||||||
|
|
||||||
pub const NETWORK_INTERFACE_ARRAY_SCHEMA: Schema = ArraySchema::new(
|
pub const NETWORK_INTERFACE_ARRAY_SCHEMA: Schema =
|
||||||
"Network interface list.", &NETWORK_INTERFACE_NAME_SCHEMA)
|
ArraySchema::new("Network interface list.", &NETWORK_INTERFACE_NAME_SCHEMA).schema();
|
||||||
.schema();
|
|
||||||
|
|
||||||
pub const NETWORK_INTERFACE_LIST_SCHEMA: Schema = StringSchema::new(
|
pub const NETWORK_INTERFACE_LIST_SCHEMA: Schema =
|
||||||
"A list of network devices, comma separated.")
|
StringSchema::new("A list of network devices, comma separated.")
|
||||||
.format(&ApiStringFormat::PropertyString(&NETWORK_INTERFACE_ARRAY_SCHEMA))
|
.format(&ApiStringFormat::PropertyString(
|
||||||
|
&NETWORK_INTERFACE_ARRAY_SCHEMA,
|
||||||
|
))
|
||||||
.schema();
|
.schema();
|
||||||
|
|
||||||
#[api(
|
#[api(
|
||||||
|
@ -232,48 +227,48 @@ pub struct Interface {
|
||||||
/// Interface type
|
/// Interface type
|
||||||
#[serde(rename = "type")]
|
#[serde(rename = "type")]
|
||||||
pub interface_type: NetworkInterfaceType,
|
pub interface_type: NetworkInterfaceType,
|
||||||
#[serde(skip_serializing_if="Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub method: Option<NetworkConfigMethod>,
|
pub method: Option<NetworkConfigMethod>,
|
||||||
#[serde(skip_serializing_if="Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub method6: Option<NetworkConfigMethod>,
|
pub method6: Option<NetworkConfigMethod>,
|
||||||
#[serde(skip_serializing_if="Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
/// IPv4 address with netmask
|
/// IPv4 address with netmask
|
||||||
pub cidr: Option<String>,
|
pub cidr: Option<String>,
|
||||||
#[serde(skip_serializing_if="Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
/// IPv4 gateway
|
/// IPv4 gateway
|
||||||
pub gateway: Option<String>,
|
pub gateway: Option<String>,
|
||||||
#[serde(skip_serializing_if="Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
/// IPv6 address with netmask
|
/// IPv6 address with netmask
|
||||||
pub cidr6: Option<String>,
|
pub cidr6: Option<String>,
|
||||||
#[serde(skip_serializing_if="Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
/// IPv6 gateway
|
/// IPv6 gateway
|
||||||
pub gateway6: Option<String>,
|
pub gateway6: Option<String>,
|
||||||
|
|
||||||
#[serde(skip_serializing_if="Vec::is_empty")]
|
#[serde(skip_serializing_if = "Vec::is_empty")]
|
||||||
pub options: Vec<String>,
|
pub options: Vec<String>,
|
||||||
#[serde(skip_serializing_if="Vec::is_empty")]
|
#[serde(skip_serializing_if = "Vec::is_empty")]
|
||||||
pub options6: Vec<String>,
|
pub options6: Vec<String>,
|
||||||
|
|
||||||
#[serde(skip_serializing_if="Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub comments: Option<String>,
|
pub comments: Option<String>,
|
||||||
#[serde(skip_serializing_if="Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub comments6: Option<String>,
|
pub comments6: Option<String>,
|
||||||
|
|
||||||
#[serde(skip_serializing_if="Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
/// Maximum Transmission Unit
|
/// Maximum Transmission Unit
|
||||||
pub mtu: Option<u64>,
|
pub mtu: Option<u64>,
|
||||||
|
|
||||||
#[serde(skip_serializing_if="Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub bridge_ports: Option<Vec<String>>,
|
pub bridge_ports: Option<Vec<String>>,
|
||||||
/// Enable bridge vlan support.
|
/// Enable bridge vlan support.
|
||||||
#[serde(skip_serializing_if="Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub bridge_vlan_aware: Option<bool>,
|
pub bridge_vlan_aware: Option<bool>,
|
||||||
|
|
||||||
#[serde(skip_serializing_if="Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub slaves: Option<Vec<String>>,
|
pub slaves: Option<Vec<String>>,
|
||||||
#[serde(skip_serializing_if="Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub bond_mode: Option<LinuxBondMode>,
|
pub bond_mode: Option<LinuxBondMode>,
|
||||||
#[serde(skip_serializing_if="Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
#[serde(rename = "bond-primary")]
|
#[serde(rename = "bond-primary")]
|
||||||
pub bond_primary: Option<String>,
|
pub bond_primary: Option<String>,
|
||||||
pub bond_xmit_hash_policy: Option<BondXmitHashPolicy>,
|
pub bond_xmit_hash_policy: Option<BondXmitHashPolicy>,
|
||||||
|
|
|
@ -1,23 +1,19 @@
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use proxmox_schema::{
|
use proxmox_schema::{api, ApiStringFormat, ArraySchema, Schema, StringSchema, Updater};
|
||||||
api, ApiStringFormat, ArraySchema, Schema, StringSchema, Updater,
|
|
||||||
};
|
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
PROXMOX_SAFE_ID_REGEX, PROXMOX_SAFE_ID_FORMAT, REALM_ID_SCHEMA,
|
PROXMOX_SAFE_ID_FORMAT, PROXMOX_SAFE_ID_REGEX, REALM_ID_SCHEMA, SINGLE_LINE_COMMENT_SCHEMA,
|
||||||
SINGLE_LINE_COMMENT_SCHEMA,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const OPENID_SCOPE_FORMAT: ApiStringFormat =
|
pub const OPENID_SCOPE_FORMAT: ApiStringFormat = ApiStringFormat::Pattern(&PROXMOX_SAFE_ID_REGEX);
|
||||||
ApiStringFormat::Pattern(&PROXMOX_SAFE_ID_REGEX);
|
|
||||||
|
|
||||||
pub const OPENID_SCOPE_SCHEMA: Schema = StringSchema::new("OpenID Scope Name.")
|
pub const OPENID_SCOPE_SCHEMA: Schema = StringSchema::new("OpenID Scope Name.")
|
||||||
.format(&OPENID_SCOPE_FORMAT)
|
.format(&OPENID_SCOPE_FORMAT)
|
||||||
.schema();
|
.schema();
|
||||||
|
|
||||||
pub const OPENID_SCOPE_ARRAY_SCHEMA: Schema = ArraySchema::new(
|
pub const OPENID_SCOPE_ARRAY_SCHEMA: Schema =
|
||||||
"Array of OpenId Scopes.", &OPENID_SCOPE_SCHEMA).schema();
|
ArraySchema::new("Array of OpenId Scopes.", &OPENID_SCOPE_SCHEMA).schema();
|
||||||
|
|
||||||
pub const OPENID_SCOPE_LIST_FORMAT: ApiStringFormat =
|
pub const OPENID_SCOPE_LIST_FORMAT: ApiStringFormat =
|
||||||
ApiStringFormat::PropertyString(&OPENID_SCOPE_ARRAY_SCHEMA);
|
ApiStringFormat::PropertyString(&OPENID_SCOPE_ARRAY_SCHEMA);
|
||||||
|
@ -28,15 +24,15 @@ pub const OPENID_SCOPE_LIST_SCHEMA: Schema = StringSchema::new("OpenID Scope Lis
|
||||||
.default(OPENID_DEFAILT_SCOPE_LIST)
|
.default(OPENID_DEFAILT_SCOPE_LIST)
|
||||||
.schema();
|
.schema();
|
||||||
|
|
||||||
pub const OPENID_ACR_FORMAT: ApiStringFormat =
|
pub const OPENID_ACR_FORMAT: ApiStringFormat = ApiStringFormat::Pattern(&PROXMOX_SAFE_ID_REGEX);
|
||||||
ApiStringFormat::Pattern(&PROXMOX_SAFE_ID_REGEX);
|
|
||||||
|
|
||||||
pub const OPENID_ACR_SCHEMA: Schema = StringSchema::new("OpenID Authentication Context Class Reference.")
|
pub const OPENID_ACR_SCHEMA: Schema =
|
||||||
|
StringSchema::new("OpenID Authentication Context Class Reference.")
|
||||||
.format(&OPENID_SCOPE_FORMAT)
|
.format(&OPENID_SCOPE_FORMAT)
|
||||||
.schema();
|
.schema();
|
||||||
|
|
||||||
pub const OPENID_ACR_ARRAY_SCHEMA: Schema = ArraySchema::new(
|
pub const OPENID_ACR_ARRAY_SCHEMA: Schema =
|
||||||
"Array of OpenId ACRs.", &OPENID_ACR_SCHEMA).schema();
|
ArraySchema::new("Array of OpenId ACRs.", &OPENID_ACR_SCHEMA).schema();
|
||||||
|
|
||||||
pub const OPENID_ACR_LIST_FORMAT: ApiStringFormat =
|
pub const OPENID_ACR_LIST_FORMAT: ApiStringFormat =
|
||||||
ApiStringFormat::PropertyString(&OPENID_ACR_ARRAY_SCHEMA);
|
ApiStringFormat::PropertyString(&OPENID_ACR_ARRAY_SCHEMA);
|
||||||
|
@ -50,10 +46,12 @@ pub const OPENID_USERNAME_CLAIM_SCHEMA: Schema = StringSchema::new(
|
||||||
is up to the identity provider to guarantee the uniqueness. The \
|
is up to the identity provider to guarantee the uniqueness. The \
|
||||||
OpenID specification only guarantees that Subject ('sub') is \
|
OpenID specification only guarantees that Subject ('sub') is \
|
||||||
unique. Also make sure that the user is not allowed to change that \
|
unique. Also make sure that the user is not allowed to change that \
|
||||||
attribute by himself!")
|
attribute by himself!",
|
||||||
.max_length(64)
|
)
|
||||||
.min_length(1)
|
.max_length(64)
|
||||||
.format(&PROXMOX_SAFE_ID_FORMAT) .schema();
|
.min_length(1)
|
||||||
|
.format(&PROXMOX_SAFE_ID_FORMAT)
|
||||||
|
.schema();
|
||||||
|
|
||||||
#[api(
|
#[api(
|
||||||
properties: {
|
properties: {
|
||||||
|
@ -92,7 +90,7 @@ pub const OPENID_USERNAME_CLAIM_SCHEMA: Schema = StringSchema::new(
|
||||||
},
|
},
|
||||||
)]
|
)]
|
||||||
#[derive(Serialize, Deserialize, Updater)]
|
#[derive(Serialize, Deserialize, Updater)]
|
||||||
#[serde(rename_all="kebab-case")]
|
#[serde(rename_all = "kebab-case")]
|
||||||
/// OpenID configuration properties.
|
/// OpenID configuration properties.
|
||||||
pub struct OpenIdRealmConfig {
|
pub struct OpenIdRealmConfig {
|
||||||
#[updater(skip)]
|
#[updater(skip)]
|
||||||
|
@ -101,21 +99,21 @@ pub struct OpenIdRealmConfig {
|
||||||
pub issuer_url: String,
|
pub issuer_url: String,
|
||||||
/// OpenID Client ID
|
/// OpenID Client ID
|
||||||
pub client_id: String,
|
pub client_id: String,
|
||||||
#[serde(skip_serializing_if="Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub scopes: Option<String>,
|
pub scopes: Option<String>,
|
||||||
#[serde(skip_serializing_if="Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub acr_values: Option<String>,
|
pub acr_values: Option<String>,
|
||||||
#[serde(skip_serializing_if="Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub prompt: Option<String>,
|
pub prompt: Option<String>,
|
||||||
/// OpenID Client Key
|
/// OpenID Client Key
|
||||||
#[serde(skip_serializing_if="Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub client_key: Option<String>,
|
pub client_key: Option<String>,
|
||||||
#[serde(skip_serializing_if="Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub comment: Option<String>,
|
pub comment: Option<String>,
|
||||||
/// Automatically create users if they do not exist.
|
/// Automatically create users if they do not exist.
|
||||||
#[serde(skip_serializing_if="Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub autocreate: Option<bool>,
|
pub autocreate: Option<bool>,
|
||||||
#[updater(skip)]
|
#[updater(skip)]
|
||||||
#[serde(skip_serializing_if="Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub username_claim: Option<String>,
|
pub username_claim: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,13 +3,15 @@ use serde::{Deserialize, Serialize};
|
||||||
use super::*;
|
use super::*;
|
||||||
use proxmox_schema::*;
|
use proxmox_schema::*;
|
||||||
|
|
||||||
pub const REMOTE_PASSWORD_SCHEMA: Schema = StringSchema::new("Password or auth token for remote host.")
|
pub const REMOTE_PASSWORD_SCHEMA: Schema =
|
||||||
|
StringSchema::new("Password or auth token for remote host.")
|
||||||
.format(&PASSWORD_FORMAT)
|
.format(&PASSWORD_FORMAT)
|
||||||
.min_length(1)
|
.min_length(1)
|
||||||
.max_length(1024)
|
.max_length(1024)
|
||||||
.schema();
|
.schema();
|
||||||
|
|
||||||
pub const REMOTE_PASSWORD_BASE64_SCHEMA: Schema = StringSchema::new("Password or auth token for remote host (stored as base64 string).")
|
pub const REMOTE_PASSWORD_BASE64_SCHEMA: Schema =
|
||||||
|
StringSchema::new("Password or auth token for remote host (stored as base64 string).")
|
||||||
.format(&PASSWORD_FORMAT)
|
.format(&PASSWORD_FORMAT)
|
||||||
.min_length(1)
|
.min_length(1)
|
||||||
.max_length(1024)
|
.max_length(1024)
|
||||||
|
@ -21,7 +23,6 @@ pub const REMOTE_ID_SCHEMA: Schema = StringSchema::new("Remote ID.")
|
||||||
.max_length(32)
|
.max_length(32)
|
||||||
.schema();
|
.schema();
|
||||||
|
|
||||||
|
|
||||||
#[api(
|
#[api(
|
||||||
properties: {
|
properties: {
|
||||||
comment: {
|
comment: {
|
||||||
|
@ -45,17 +46,17 @@ pub const REMOTE_ID_SCHEMA: Schema = StringSchema::new("Remote ID.")
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
)]
|
)]
|
||||||
#[derive(Serialize,Deserialize,Updater)]
|
#[derive(Serialize, Deserialize, Updater)]
|
||||||
#[serde(rename_all = "kebab-case")]
|
#[serde(rename_all = "kebab-case")]
|
||||||
/// Remote configuration properties.
|
/// Remote configuration properties.
|
||||||
pub struct RemoteConfig {
|
pub struct RemoteConfig {
|
||||||
#[serde(skip_serializing_if="Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub comment: Option<String>,
|
pub comment: Option<String>,
|
||||||
pub host: String,
|
pub host: String,
|
||||||
#[serde(skip_serializing_if="Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub port: Option<u16>,
|
pub port: Option<u16>,
|
||||||
pub auth_id: Authid,
|
pub auth_id: Authid,
|
||||||
#[serde(skip_serializing_if="Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub fingerprint: Option<String>,
|
pub fingerprint: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -72,13 +73,13 @@ pub struct RemoteConfig {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
)]
|
)]
|
||||||
#[derive(Serialize,Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
#[serde(rename_all = "kebab-case")]
|
#[serde(rename_all = "kebab-case")]
|
||||||
/// Remote properties.
|
/// Remote properties.
|
||||||
pub struct Remote {
|
pub struct Remote {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
// Note: The stored password is base64 encoded
|
// Note: The stored password is base64 encoded
|
||||||
#[serde(skip_serializing_if="String::is_empty")]
|
#[serde(skip_serializing_if = "String::is_empty")]
|
||||||
#[serde(with = "proxmox_serde::string_as_base64")]
|
#[serde(with = "proxmox_serde::string_as_base64")]
|
||||||
pub password: String,
|
pub password: String,
|
||||||
#[serde(flatten)]
|
#[serde(flatten)]
|
||||||
|
|
|
@ -3,23 +3,23 @@ use ::serde::{Deserialize, Serialize};
|
||||||
use proxmox_schema::api;
|
use proxmox_schema::api;
|
||||||
|
|
||||||
#[api()]
|
#[api()]
|
||||||
#[derive(Serialize,Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
#[serde(rename_all = "kebab-case")]
|
#[serde(rename_all = "kebab-case")]
|
||||||
/// Optional Device Identification Attributes
|
/// Optional Device Identification Attributes
|
||||||
pub struct OptionalDeviceIdentification {
|
pub struct OptionalDeviceIdentification {
|
||||||
/// Vendor (autodetected)
|
/// Vendor (autodetected)
|
||||||
#[serde(skip_serializing_if="Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub vendor: Option<String>,
|
pub vendor: Option<String>,
|
||||||
/// Model (autodetected)
|
/// Model (autodetected)
|
||||||
#[serde(skip_serializing_if="Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub model: Option<String>,
|
pub model: Option<String>,
|
||||||
/// Serial number (autodetected)
|
/// Serial number (autodetected)
|
||||||
#[serde(skip_serializing_if="Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub serial: Option<String>,
|
pub serial: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[api()]
|
#[api()]
|
||||||
#[derive(Debug,Serialize,Deserialize)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
#[serde(rename_all = "kebab-case")]
|
#[serde(rename_all = "kebab-case")]
|
||||||
/// Kind of device
|
/// Kind of device
|
||||||
pub enum DeviceKind {
|
pub enum DeviceKind {
|
||||||
|
@ -36,7 +36,7 @@ pub enum DeviceKind {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
)]
|
)]
|
||||||
#[derive(Debug,Serialize,Deserialize)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
/// Tape device information
|
/// Tape device information
|
||||||
pub struct TapeDeviceInfo {
|
pub struct TapeDeviceInfo {
|
||||||
pub kind: DeviceKind,
|
pub kind: DeviceKind,
|
||||||
|
|
|
@ -4,13 +4,9 @@ use std::convert::TryFrom;
|
||||||
use anyhow::{bail, Error};
|
use anyhow::{bail, Error};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use proxmox_schema::{api, Schema, IntegerSchema, StringSchema, Updater};
|
use proxmox_schema::{api, IntegerSchema, Schema, StringSchema, Updater};
|
||||||
|
|
||||||
use crate::{
|
use crate::{OptionalDeviceIdentification, CHANGER_NAME_SCHEMA, PROXMOX_SAFE_ID_FORMAT};
|
||||||
PROXMOX_SAFE_ID_FORMAT,
|
|
||||||
CHANGER_NAME_SCHEMA,
|
|
||||||
OptionalDeviceIdentification,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub const DRIVE_NAME_SCHEMA: Schema = StringSchema::new("Drive Identifier.")
|
pub const DRIVE_NAME_SCHEMA: Schema = StringSchema::new("Drive Identifier.")
|
||||||
.format(&PROXMOX_SAFE_ID_FORMAT)
|
.format(&PROXMOX_SAFE_ID_FORMAT)
|
||||||
|
@ -18,12 +14,11 @@ pub const DRIVE_NAME_SCHEMA: Schema = StringSchema::new("Drive Identifier.")
|
||||||
.max_length(32)
|
.max_length(32)
|
||||||
.schema();
|
.schema();
|
||||||
|
|
||||||
pub const LTO_DRIVE_PATH_SCHEMA: Schema = StringSchema::new(
|
pub const LTO_DRIVE_PATH_SCHEMA: Schema =
|
||||||
"The path to a LTO SCSI-generic tape device (i.e. '/dev/sg0')")
|
StringSchema::new("The path to a LTO SCSI-generic tape device (i.e. '/dev/sg0')").schema();
|
||||||
.schema();
|
|
||||||
|
|
||||||
pub const CHANGER_DRIVENUM_SCHEMA: Schema = IntegerSchema::new(
|
pub const CHANGER_DRIVENUM_SCHEMA: Schema =
|
||||||
"Associated changer drive number (requires option changer)")
|
IntegerSchema::new("Associated changer drive number (requires option changer)")
|
||||||
.minimum(0)
|
.minimum(0)
|
||||||
.maximum(255)
|
.maximum(255)
|
||||||
.default(0)
|
.default(0)
|
||||||
|
@ -36,7 +31,7 @@ pub const CHANGER_DRIVENUM_SCHEMA: Schema = IntegerSchema::new(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)]
|
)]
|
||||||
#[derive(Serialize,Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
/// Simulate tape drives (only for test and debug)
|
/// Simulate tape drives (only for test and debug)
|
||||||
#[serde(rename_all = "kebab-case")]
|
#[serde(rename_all = "kebab-case")]
|
||||||
pub struct VirtualTapeDrive {
|
pub struct VirtualTapeDrive {
|
||||||
|
@ -44,7 +39,7 @@ pub struct VirtualTapeDrive {
|
||||||
/// Path to directory
|
/// Path to directory
|
||||||
pub path: String,
|
pub path: String,
|
||||||
/// Virtual tape size
|
/// Virtual tape size
|
||||||
#[serde(skip_serializing_if="Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub max_size: Option<usize>,
|
pub max_size: Option<usize>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -66,16 +61,16 @@ pub struct VirtualTapeDrive {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
)]
|
)]
|
||||||
#[derive(Serialize,Deserialize,Updater)]
|
#[derive(Serialize, Deserialize, Updater)]
|
||||||
#[serde(rename_all = "kebab-case")]
|
#[serde(rename_all = "kebab-case")]
|
||||||
/// Lto SCSI tape driver
|
/// Lto SCSI tape driver
|
||||||
pub struct LtoTapeDrive {
|
pub struct LtoTapeDrive {
|
||||||
#[updater(skip)]
|
#[updater(skip)]
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub path: String,
|
pub path: String,
|
||||||
#[serde(skip_serializing_if="Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub changer: Option<String>,
|
pub changer: Option<String>,
|
||||||
#[serde(skip_serializing_if="Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub changer_drivenum: Option<u64>,
|
pub changer_drivenum: Option<u64>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -89,7 +84,7 @@ pub struct LtoTapeDrive {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
)]
|
)]
|
||||||
#[derive(Serialize,Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
#[serde(rename_all = "kebab-case")]
|
#[serde(rename_all = "kebab-case")]
|
||||||
/// Drive list entry
|
/// Drive list entry
|
||||||
pub struct DriveListEntry {
|
pub struct DriveListEntry {
|
||||||
|
@ -98,12 +93,12 @@ pub struct DriveListEntry {
|
||||||
#[serde(flatten)]
|
#[serde(flatten)]
|
||||||
pub info: OptionalDeviceIdentification,
|
pub info: OptionalDeviceIdentification,
|
||||||
/// the state of the drive if locked
|
/// the state of the drive if locked
|
||||||
#[serde(skip_serializing_if="Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub state: Option<String>,
|
pub state: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[api()]
|
#[api()]
|
||||||
#[derive(Serialize,Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
/// Medium auxiliary memory attributes (MAM)
|
/// Medium auxiliary memory attributes (MAM)
|
||||||
pub struct MamAttribute {
|
pub struct MamAttribute {
|
||||||
/// Attribute id
|
/// Attribute id
|
||||||
|
@ -115,7 +110,7 @@ pub struct MamAttribute {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[api()]
|
#[api()]
|
||||||
#[derive(Serialize,Deserialize,Copy,Clone,Debug)]
|
#[derive(Serialize, Deserialize, Copy, Clone, Debug)]
|
||||||
pub enum TapeDensity {
|
pub enum TapeDensity {
|
||||||
/// Unknown (no media loaded)
|
/// Unknown (no media loaded)
|
||||||
Unknown,
|
Unknown,
|
||||||
|
@ -168,7 +163,7 @@ impl TryFrom<u8> for TapeDensity {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
)]
|
)]
|
||||||
#[derive(Serialize,Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
#[serde(rename_all = "kebab-case")]
|
#[serde(rename_all = "kebab-case")]
|
||||||
/// Drive/Media status for Lto SCSI drives.
|
/// Drive/Media status for Lto SCSI drives.
|
||||||
///
|
///
|
||||||
|
@ -190,35 +185,35 @@ pub struct LtoDriveAndMediaStatus {
|
||||||
/// Tape density
|
/// Tape density
|
||||||
pub density: TapeDensity,
|
pub density: TapeDensity,
|
||||||
/// Media is write protected
|
/// Media is write protected
|
||||||
#[serde(skip_serializing_if="Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub write_protect: Option<bool>,
|
pub write_protect: Option<bool>,
|
||||||
/// Tape Alert Flags
|
/// Tape Alert Flags
|
||||||
#[serde(skip_serializing_if="Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub alert_flags: Option<String>,
|
pub alert_flags: Option<String>,
|
||||||
/// Current file number
|
/// Current file number
|
||||||
#[serde(skip_serializing_if="Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub file_number: Option<u64>,
|
pub file_number: Option<u64>,
|
||||||
/// Current block number
|
/// Current block number
|
||||||
#[serde(skip_serializing_if="Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub block_number: Option<u64>,
|
pub block_number: Option<u64>,
|
||||||
/// Medium Manufacture Date (epoch)
|
/// Medium Manufacture Date (epoch)
|
||||||
#[serde(skip_serializing_if="Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub manufactured: Option<i64>,
|
pub manufactured: Option<i64>,
|
||||||
/// Total Bytes Read in Medium Life
|
/// Total Bytes Read in Medium Life
|
||||||
#[serde(skip_serializing_if="Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub bytes_read: Option<u64>,
|
pub bytes_read: Option<u64>,
|
||||||
/// Total Bytes Written in Medium Life
|
/// Total Bytes Written in Medium Life
|
||||||
#[serde(skip_serializing_if="Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub bytes_written: Option<u64>,
|
pub bytes_written: Option<u64>,
|
||||||
/// Number of mounts for the current volume (i.e., Thread Count)
|
/// Number of mounts for the current volume (i.e., Thread Count)
|
||||||
#[serde(skip_serializing_if="Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub volume_mounts: Option<u64>,
|
pub volume_mounts: Option<u64>,
|
||||||
/// Count of the total number of times the medium has passed over
|
/// Count of the total number of times the medium has passed over
|
||||||
/// the head.
|
/// the head.
|
||||||
#[serde(skip_serializing_if="Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub medium_passes: Option<u64>,
|
pub medium_passes: Option<u64>,
|
||||||
/// Estimated tape wearout factor (assuming max. 16000 end-to-end passes)
|
/// Estimated tape wearout factor (assuming max. 16000 end-to-end passes)
|
||||||
#[serde(skip_serializing_if="Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub medium_wearout: Option<f64>,
|
pub medium_wearout: Option<f64>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,19 +3,15 @@ use ::serde::{Deserialize, Serialize};
|
||||||
use proxmox_schema::*;
|
use proxmox_schema::*;
|
||||||
use proxmox_uuid::Uuid;
|
use proxmox_uuid::Uuid;
|
||||||
|
|
||||||
use crate::{
|
use crate::{MediaLocation, MediaStatus, UUID_FORMAT};
|
||||||
UUID_FORMAT,
|
|
||||||
MediaStatus,
|
|
||||||
MediaLocation,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub const MEDIA_SET_UUID_SCHEMA: Schema =
|
pub const MEDIA_SET_UUID_SCHEMA: Schema = StringSchema::new(
|
||||||
StringSchema::new("MediaSet Uuid (We use the all-zero Uuid to reseve an empty media for a specific pool).")
|
"MediaSet Uuid (We use the all-zero Uuid to reseve an empty media for a specific pool).",
|
||||||
.format(&UUID_FORMAT)
|
)
|
||||||
.schema();
|
.format(&UUID_FORMAT)
|
||||||
|
.schema();
|
||||||
|
|
||||||
pub const MEDIA_UUID_SCHEMA: Schema =
|
pub const MEDIA_UUID_SCHEMA: Schema = StringSchema::new("Media Uuid.")
|
||||||
StringSchema::new("Media Uuid.")
|
|
||||||
.format(&UUID_FORMAT)
|
.format(&UUID_FORMAT)
|
||||||
.schema();
|
.schema();
|
||||||
|
|
||||||
|
@ -26,7 +22,7 @@ pub const MEDIA_UUID_SCHEMA: Schema =
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
)]
|
)]
|
||||||
#[derive(Serialize,Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
#[serde(rename_all = "kebab-case")]
|
#[serde(rename_all = "kebab-case")]
|
||||||
/// Media Set list entry
|
/// Media Set list entry
|
||||||
pub struct MediaSetListEntry {
|
pub struct MediaSetListEntry {
|
||||||
|
@ -56,7 +52,7 @@ pub struct MediaSetListEntry {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
)]
|
)]
|
||||||
#[derive(Serialize,Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
#[serde(rename_all = "kebab-case")]
|
#[serde(rename_all = "kebab-case")]
|
||||||
/// Media list entry
|
/// Media list entry
|
||||||
pub struct MediaListEntry {
|
pub struct MediaListEntry {
|
||||||
|
@ -72,18 +68,18 @@ pub struct MediaListEntry {
|
||||||
/// Catalog status OK
|
/// Catalog status OK
|
||||||
pub catalog: bool,
|
pub catalog: bool,
|
||||||
/// Media set name
|
/// Media set name
|
||||||
#[serde(skip_serializing_if="Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub media_set_name: Option<String>,
|
pub media_set_name: Option<String>,
|
||||||
#[serde(skip_serializing_if="Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub media_set_uuid: Option<Uuid>,
|
pub media_set_uuid: Option<Uuid>,
|
||||||
/// Media set seq_nr
|
/// Media set seq_nr
|
||||||
#[serde(skip_serializing_if="Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub seq_nr: Option<u64>,
|
pub seq_nr: Option<u64>,
|
||||||
/// MediaSet creation time stamp
|
/// MediaSet creation time stamp
|
||||||
#[serde(skip_serializing_if="Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub media_set_ctime: Option<i64>,
|
pub media_set_ctime: Option<i64>,
|
||||||
/// Media Pool
|
/// Media Pool
|
||||||
#[serde(skip_serializing_if="Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub pool: Option<String>,
|
pub pool: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -98,7 +94,7 @@ pub struct MediaListEntry {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
)]
|
)]
|
||||||
#[derive(Serialize,Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
#[serde(rename_all = "kebab-case")]
|
#[serde(rename_all = "kebab-case")]
|
||||||
/// Media label info
|
/// Media label info
|
||||||
pub struct MediaIdFlat {
|
pub struct MediaIdFlat {
|
||||||
|
@ -110,18 +106,18 @@ pub struct MediaIdFlat {
|
||||||
pub ctime: i64,
|
pub ctime: i64,
|
||||||
// All MediaSet properties are optional here
|
// All MediaSet properties are optional here
|
||||||
/// MediaSet Pool
|
/// MediaSet Pool
|
||||||
#[serde(skip_serializing_if="Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub pool: Option<String>,
|
pub pool: Option<String>,
|
||||||
#[serde(skip_serializing_if="Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub media_set_uuid: Option<Uuid>,
|
pub media_set_uuid: Option<Uuid>,
|
||||||
/// MediaSet media sequence number
|
/// MediaSet media sequence number
|
||||||
#[serde(skip_serializing_if="Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub seq_nr: Option<u64>,
|
pub seq_nr: Option<u64>,
|
||||||
/// MediaSet Creation time stamp
|
/// MediaSet Creation time stamp
|
||||||
#[serde(skip_serializing_if="Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub media_set_ctime: Option<i64>,
|
pub media_set_ctime: Option<i64>,
|
||||||
/// Encryption key fingerprint
|
/// Encryption key fingerprint
|
||||||
#[serde(skip_serializing_if="Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub encryption_key_fingerprint: Option<String>,
|
pub encryption_key_fingerprint: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -133,7 +129,7 @@ pub struct MediaIdFlat {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
)]
|
)]
|
||||||
#[derive(Serialize,Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
#[serde(rename_all = "kebab-case")]
|
#[serde(rename_all = "kebab-case")]
|
||||||
/// Label with optional Uuid
|
/// Label with optional Uuid
|
||||||
pub struct LabelUuidMap {
|
pub struct LabelUuidMap {
|
||||||
|
@ -153,7 +149,7 @@ pub struct LabelUuidMap {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
)]
|
)]
|
||||||
#[derive(Serialize,Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
#[serde(rename_all = "kebab-case")]
|
#[serde(rename_all = "kebab-case")]
|
||||||
/// Media content list entry
|
/// Media content list entry
|
||||||
pub struct MediaContentEntry {
|
pub struct MediaContentEntry {
|
||||||
|
|
|
@ -9,14 +9,12 @@ use std::str::FromStr;
|
||||||
use anyhow::Error;
|
use anyhow::Error;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use proxmox_schema::{api, Schema, StringSchema, ApiStringFormat, Updater};
|
use proxmox_schema::{api, ApiStringFormat, Schema, StringSchema, Updater};
|
||||||
|
|
||||||
use proxmox_time::{CalendarEvent, TimeSpan};
|
use proxmox_time::{CalendarEvent, TimeSpan};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
PROXMOX_SAFE_ID_FORMAT,
|
PROXMOX_SAFE_ID_FORMAT, SINGLE_LINE_COMMENT_FORMAT, SINGLE_LINE_COMMENT_SCHEMA,
|
||||||
SINGLE_LINE_COMMENT_FORMAT,
|
|
||||||
SINGLE_LINE_COMMENT_SCHEMA,
|
|
||||||
TAPE_ENCRYPTION_KEY_FINGERPRINT_SCHEMA,
|
TAPE_ENCRYPTION_KEY_FINGERPRINT_SCHEMA,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -27,17 +25,20 @@ pub const MEDIA_POOL_NAME_SCHEMA: Schema = StringSchema::new("Media pool name.")
|
||||||
.schema();
|
.schema();
|
||||||
|
|
||||||
pub const MEDIA_SET_NAMING_TEMPLATE_SCHEMA: Schema = StringSchema::new(
|
pub const MEDIA_SET_NAMING_TEMPLATE_SCHEMA: Schema = StringSchema::new(
|
||||||
"Media set naming template (may contain strftime() time format specifications).")
|
"Media set naming template (may contain strftime() time format specifications).",
|
||||||
.format(&SINGLE_LINE_COMMENT_FORMAT)
|
)
|
||||||
.min_length(2)
|
.format(&SINGLE_LINE_COMMENT_FORMAT)
|
||||||
.max_length(64)
|
.min_length(2)
|
||||||
.schema();
|
.max_length(64)
|
||||||
|
.schema();
|
||||||
|
|
||||||
pub const MEDIA_SET_ALLOCATION_POLICY_FORMAT: ApiStringFormat =
|
pub const MEDIA_SET_ALLOCATION_POLICY_FORMAT: ApiStringFormat = ApiStringFormat::VerifyFn(|s| {
|
||||||
ApiStringFormat::VerifyFn(|s| { MediaSetPolicy::from_str(s)?; Ok(()) });
|
MediaSetPolicy::from_str(s)?;
|
||||||
|
Ok(())
|
||||||
|
});
|
||||||
|
|
||||||
pub const MEDIA_SET_ALLOCATION_POLICY_SCHEMA: Schema = StringSchema::new(
|
pub const MEDIA_SET_ALLOCATION_POLICY_SCHEMA: Schema =
|
||||||
"Media set allocation policy ('continue', 'always', or a calendar event).")
|
StringSchema::new("Media set allocation policy ('continue', 'always', or a calendar event).")
|
||||||
.format(&MEDIA_SET_ALLOCATION_POLICY_FORMAT)
|
.format(&MEDIA_SET_ALLOCATION_POLICY_FORMAT)
|
||||||
.schema();
|
.schema();
|
||||||
|
|
||||||
|
@ -68,11 +69,13 @@ impl std::str::FromStr for MediaSetPolicy {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const MEDIA_RETENTION_POLICY_FORMAT: ApiStringFormat =
|
pub const MEDIA_RETENTION_POLICY_FORMAT: ApiStringFormat = ApiStringFormat::VerifyFn(|s| {
|
||||||
ApiStringFormat::VerifyFn(|s| { RetentionPolicy::from_str(s)?; Ok(()) });
|
RetentionPolicy::from_str(s)?;
|
||||||
|
Ok(())
|
||||||
|
});
|
||||||
|
|
||||||
pub const MEDIA_RETENTION_POLICY_SCHEMA: Schema = StringSchema::new(
|
pub const MEDIA_RETENTION_POLICY_SCHEMA: Schema =
|
||||||
"Media retention policy ('overwrite', 'keep', or time span).")
|
StringSchema::new("Media retention policy ('overwrite', 'keep', or time span).")
|
||||||
.format(&MEDIA_RETENTION_POLICY_FORMAT)
|
.format(&MEDIA_RETENTION_POLICY_FORMAT)
|
||||||
.schema();
|
.schema();
|
||||||
|
|
||||||
|
@ -130,29 +133,29 @@ impl std::str::FromStr for RetentionPolicy {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
)]
|
)]
|
||||||
#[derive(Serialize,Deserialize,Updater)]
|
#[derive(Serialize, Deserialize, Updater)]
|
||||||
/// Media pool configuration
|
/// Media pool configuration
|
||||||
pub struct MediaPoolConfig {
|
pub struct MediaPoolConfig {
|
||||||
/// The pool name
|
/// The pool name
|
||||||
#[updater(skip)]
|
#[updater(skip)]
|
||||||
pub name: String,
|
pub name: String,
|
||||||
/// Media Set allocation policy
|
/// Media Set allocation policy
|
||||||
#[serde(skip_serializing_if="Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub allocation: Option<String>,
|
pub allocation: Option<String>,
|
||||||
/// Media retention policy
|
/// Media retention policy
|
||||||
#[serde(skip_serializing_if="Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub retention: Option<String>,
|
pub retention: Option<String>,
|
||||||
/// Media set naming template (default "%c")
|
/// Media set naming template (default "%c")
|
||||||
///
|
///
|
||||||
/// The template is UTF8 text, and can include strftime time
|
/// The template is UTF8 text, and can include strftime time
|
||||||
/// format specifications.
|
/// format specifications.
|
||||||
#[serde(skip_serializing_if="Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub template: Option<String>,
|
pub template: Option<String>,
|
||||||
/// Encryption key fingerprint
|
/// Encryption key fingerprint
|
||||||
///
|
///
|
||||||
/// If set, encrypt all data using the specified key.
|
/// If set, encrypt all data using the specified key.
|
||||||
#[serde(skip_serializing_if="Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub encrypt: Option<String>,
|
pub encrypt: Option<String>,
|
||||||
#[serde(skip_serializing_if="Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub comment: Option<String>,
|
pub comment: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,28 +24,25 @@ pub use media::*;
|
||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use proxmox_schema::{api, const_regex, Schema, StringSchema, ApiStringFormat};
|
use proxmox_schema::{api, const_regex, ApiStringFormat, Schema, StringSchema};
|
||||||
use proxmox_uuid::Uuid;
|
use proxmox_uuid::Uuid;
|
||||||
|
|
||||||
use crate::{
|
use crate::{BACKUP_ID_SCHEMA, BACKUP_TYPE_SCHEMA, FINGERPRINT_SHA256_FORMAT};
|
||||||
FINGERPRINT_SHA256_FORMAT, BACKUP_ID_SCHEMA, BACKUP_TYPE_SCHEMA,
|
|
||||||
};
|
|
||||||
|
|
||||||
const_regex!{
|
const_regex! {
|
||||||
pub TAPE_RESTORE_SNAPSHOT_REGEX = concat!(r"^", PROXMOX_SAFE_ID_REGEX_STR!(), r":", SNAPSHOT_PATH_REGEX_STR!(), r"$");
|
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 =
|
pub const TAPE_RESTORE_SNAPSHOT_FORMAT: ApiStringFormat =
|
||||||
ApiStringFormat::Pattern(&TAPE_RESTORE_SNAPSHOT_REGEX);
|
ApiStringFormat::Pattern(&TAPE_RESTORE_SNAPSHOT_REGEX);
|
||||||
|
|
||||||
pub const TAPE_ENCRYPTION_KEY_FINGERPRINT_SCHEMA: Schema = StringSchema::new(
|
pub const TAPE_ENCRYPTION_KEY_FINGERPRINT_SCHEMA: Schema =
|
||||||
"Tape encryption key fingerprint (sha256)."
|
StringSchema::new("Tape encryption key fingerprint (sha256).")
|
||||||
)
|
|
||||||
.format(&FINGERPRINT_SHA256_FORMAT)
|
.format(&FINGERPRINT_SHA256_FORMAT)
|
||||||
.schema();
|
.schema();
|
||||||
|
|
||||||
pub const TAPE_RESTORE_SNAPSHOT_SCHEMA: Schema = StringSchema::new(
|
pub const TAPE_RESTORE_SNAPSHOT_SCHEMA: Schema =
|
||||||
"A snapshot in the format: 'store:type/id/time")
|
StringSchema::new("A snapshot in the format: 'store:type/id/time")
|
||||||
.format(&TAPE_RESTORE_SNAPSHOT_FORMAT)
|
.format(&TAPE_RESTORE_SNAPSHOT_FORMAT)
|
||||||
.type_text("store:type/id/time")
|
.type_text("store:type/id/time")
|
||||||
.schema();
|
.schema();
|
||||||
|
@ -78,8 +75,8 @@ pub const TAPE_RESTORE_SNAPSHOT_SCHEMA: Schema = StringSchema::new(
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
)]
|
)]
|
||||||
#[derive(Serialize,Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
#[serde(rename_all="kebab-case")]
|
#[serde(rename_all = "kebab-case")]
|
||||||
/// Content list filter parameters
|
/// Content list filter parameters
|
||||||
pub struct MediaContentListFilter {
|
pub struct MediaContentListFilter {
|
||||||
pub pool: Option<String>,
|
pub pool: Option<String>,
|
||||||
|
|
|
@ -1,14 +1,14 @@
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use proxmox_schema::{api, Schema, IntegerSchema, StringSchema, Updater};
|
use proxmox_schema::{api, IntegerSchema, Schema, StringSchema, Updater};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
HumanByte, CIDR_SCHEMA, DAILY_DURATION_FORMAT,
|
HumanByte, CIDR_SCHEMA, DAILY_DURATION_FORMAT, PROXMOX_SAFE_ID_FORMAT,
|
||||||
PROXMOX_SAFE_ID_FORMAT, SINGLE_LINE_COMMENT_SCHEMA,
|
SINGLE_LINE_COMMENT_SCHEMA,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const TRAFFIC_CONTROL_TIMEFRAME_SCHEMA: Schema = StringSchema::new(
|
pub const TRAFFIC_CONTROL_TIMEFRAME_SCHEMA: Schema =
|
||||||
"Timeframe to specify when the rule is actice.")
|
StringSchema::new("Timeframe to specify when the rule is actice.")
|
||||||
.format(&DAILY_DURATION_FORMAT)
|
.format(&DAILY_DURATION_FORMAT)
|
||||||
.schema();
|
.schema();
|
||||||
|
|
||||||
|
@ -18,13 +18,13 @@ pub const TRAFFIC_CONTROL_ID_SCHEMA: Schema = StringSchema::new("Rule ID.")
|
||||||
.max_length(32)
|
.max_length(32)
|
||||||
.schema();
|
.schema();
|
||||||
|
|
||||||
pub const TRAFFIC_CONTROL_RATE_SCHEMA: Schema = IntegerSchema::new(
|
pub const TRAFFIC_CONTROL_RATE_SCHEMA: Schema =
|
||||||
"Rate limit (for Token bucket filter) in bytes/second.")
|
IntegerSchema::new("Rate limit (for Token bucket filter) in bytes/second.")
|
||||||
.minimum(100_000)
|
.minimum(100_000)
|
||||||
.schema();
|
.schema();
|
||||||
|
|
||||||
pub const TRAFFIC_CONTROL_BURST_SCHEMA: Schema = IntegerSchema::new(
|
pub const TRAFFIC_CONTROL_BURST_SCHEMA: Schema =
|
||||||
"Size of the token bucket (for Token bucket filter) in bytes.")
|
IntegerSchema::new("Size of the token bucket (for Token bucket filter) in bytes.")
|
||||||
.minimum(1000)
|
.minimum(1000)
|
||||||
.schema();
|
.schema();
|
||||||
|
|
||||||
|
@ -48,17 +48,17 @@ pub const TRAFFIC_CONTROL_BURST_SCHEMA: Schema = IntegerSchema::new(
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
)]
|
)]
|
||||||
#[derive(Serialize,Deserialize,Default,Clone,Updater)]
|
#[derive(Serialize, Deserialize, Default, Clone, Updater)]
|
||||||
#[serde(rename_all = "kebab-case")]
|
#[serde(rename_all = "kebab-case")]
|
||||||
/// Rate Limit Configuration
|
/// Rate Limit Configuration
|
||||||
pub struct RateLimitConfig {
|
pub struct RateLimitConfig {
|
||||||
#[serde(skip_serializing_if="Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub rate_in: Option<HumanByte>,
|
pub rate_in: Option<HumanByte>,
|
||||||
#[serde(skip_serializing_if="Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub burst_in: Option<HumanByte>,
|
pub burst_in: Option<HumanByte>,
|
||||||
#[serde(skip_serializing_if="Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub rate_out: Option<HumanByte>,
|
pub rate_out: Option<HumanByte>,
|
||||||
#[serde(skip_serializing_if="Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub burst_out: Option<HumanByte>,
|
pub burst_out: Option<HumanByte>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -100,13 +100,13 @@ impl RateLimitConfig {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
)]
|
)]
|
||||||
#[derive(Serialize,Deserialize, Updater)]
|
#[derive(Serialize, Deserialize, Updater)]
|
||||||
#[serde(rename_all = "kebab-case")]
|
#[serde(rename_all = "kebab-case")]
|
||||||
/// Traffic control rule
|
/// Traffic control rule
|
||||||
pub struct TrafficControlRule {
|
pub struct TrafficControlRule {
|
||||||
#[updater(skip)]
|
#[updater(skip)]
|
||||||
pub name: String,
|
pub name: String,
|
||||||
#[serde(skip_serializing_if="Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub comment: Option<String>,
|
pub comment: Option<String>,
|
||||||
/// Rule applies to Source IPs within this networks
|
/// Rule applies to Source IPs within this networks
|
||||||
pub network: Vec<String>,
|
pub network: Vec<String>,
|
||||||
|
@ -117,6 +117,6 @@ pub struct TrafficControlRule {
|
||||||
// #[serde(skip_serializing_if="Option::is_none")]
|
// #[serde(skip_serializing_if="Option::is_none")]
|
||||||
// pub shared: Option<bool>,
|
// pub shared: Option<bool>,
|
||||||
/// Enable the rule at specific times
|
/// Enable the rule at specific times
|
||||||
#[serde(skip_serializing_if="Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub timeframe: Option<Vec<String>>,
|
pub timeframe: Option<Vec<String>>,
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,22 +1,22 @@
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use proxmox_schema::{
|
use proxmox_schema::{api, BooleanSchema, IntegerSchema, Schema, StringSchema, Updater};
|
||||||
api, BooleanSchema, IntegerSchema, Schema, StringSchema, Updater,
|
|
||||||
};
|
|
||||||
|
|
||||||
use super::{SINGLE_LINE_COMMENT_FORMAT, SINGLE_LINE_COMMENT_SCHEMA};
|
|
||||||
use super::userid::{Authid, Userid, PROXMOX_TOKEN_ID_SCHEMA};
|
use super::userid::{Authid, Userid, PROXMOX_TOKEN_ID_SCHEMA};
|
||||||
|
use super::{SINGLE_LINE_COMMENT_FORMAT, SINGLE_LINE_COMMENT_SCHEMA};
|
||||||
|
|
||||||
pub const ENABLE_USER_SCHEMA: Schema = BooleanSchema::new(
|
pub const ENABLE_USER_SCHEMA: Schema = BooleanSchema::new(
|
||||||
"Enable the account (default). You can set this to '0' to disable the account.")
|
"Enable the account (default). You can set this to '0' to disable the account.",
|
||||||
.default(true)
|
)
|
||||||
.schema();
|
.default(true)
|
||||||
|
.schema();
|
||||||
|
|
||||||
pub const EXPIRE_USER_SCHEMA: Schema = IntegerSchema::new(
|
pub const EXPIRE_USER_SCHEMA: Schema = IntegerSchema::new(
|
||||||
"Account expiration date (seconds since epoch). '0' means no expiration date.")
|
"Account expiration date (seconds since epoch). '0' means no expiration date.",
|
||||||
.default(0)
|
)
|
||||||
.minimum(0)
|
.default(0)
|
||||||
.schema();
|
.minimum(0)
|
||||||
|
.schema();
|
||||||
|
|
||||||
pub const FIRST_NAME_SCHEMA: Schema = StringSchema::new("First name.")
|
pub const FIRST_NAME_SCHEMA: Schema = StringSchema::new("First name.")
|
||||||
.format(&SINGLE_LINE_COMMENT_FORMAT)
|
.format(&SINGLE_LINE_COMMENT_FORMAT)
|
||||||
|
@ -75,23 +75,23 @@ pub const EMAIL_SCHEMA: Schema = StringSchema::new("E-Mail Address.")
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
)]
|
)]
|
||||||
#[derive(Serialize,Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
/// User properties with added list of ApiTokens
|
/// User properties with added list of ApiTokens
|
||||||
pub struct UserWithTokens {
|
pub struct UserWithTokens {
|
||||||
pub userid: Userid,
|
pub userid: Userid,
|
||||||
#[serde(skip_serializing_if="Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub comment: Option<String>,
|
pub comment: Option<String>,
|
||||||
#[serde(skip_serializing_if="Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub enable: Option<bool>,
|
pub enable: Option<bool>,
|
||||||
#[serde(skip_serializing_if="Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub expire: Option<i64>,
|
pub expire: Option<i64>,
|
||||||
#[serde(skip_serializing_if="Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub firstname: Option<String>,
|
pub firstname: Option<String>,
|
||||||
#[serde(skip_serializing_if="Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub lastname: Option<String>,
|
pub lastname: Option<String>,
|
||||||
#[serde(skip_serializing_if="Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub email: Option<String>,
|
pub email: Option<String>,
|
||||||
#[serde(skip_serializing_if="Vec::is_empty", default)]
|
#[serde(skip_serializing_if = "Vec::is_empty", default)]
|
||||||
pub tokens: Vec<ApiToken>,
|
pub tokens: Vec<ApiToken>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -114,15 +114,15 @@ pub struct UserWithTokens {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
)]
|
)]
|
||||||
#[derive(Serialize,Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
/// ApiToken properties.
|
/// ApiToken properties.
|
||||||
pub struct ApiToken {
|
pub struct ApiToken {
|
||||||
pub tokenid: Authid,
|
pub tokenid: Authid,
|
||||||
#[serde(skip_serializing_if="Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub comment: Option<String>,
|
pub comment: Option<String>,
|
||||||
#[serde(skip_serializing_if="Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub enable: Option<bool>,
|
pub enable: Option<bool>,
|
||||||
#[serde(skip_serializing_if="Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub expire: Option<i64>,
|
pub expire: Option<i64>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -172,22 +172,22 @@ impl ApiToken {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
)]
|
)]
|
||||||
#[derive(Serialize,Deserialize,Updater)]
|
#[derive(Serialize, Deserialize, Updater)]
|
||||||
/// User properties.
|
/// User properties.
|
||||||
pub struct User {
|
pub struct User {
|
||||||
#[updater(skip)]
|
#[updater(skip)]
|
||||||
pub userid: Userid,
|
pub userid: Userid,
|
||||||
#[serde(skip_serializing_if="Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub comment: Option<String>,
|
pub comment: Option<String>,
|
||||||
#[serde(skip_serializing_if="Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub enable: Option<bool>,
|
pub enable: Option<bool>,
|
||||||
#[serde(skip_serializing_if="Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub expire: Option<i64>,
|
pub expire: Option<i64>,
|
||||||
#[serde(skip_serializing_if="Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub firstname: Option<String>,
|
pub firstname: Option<String>,
|
||||||
#[serde(skip_serializing_if="Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub lastname: Option<String>,
|
pub lastname: Option<String>,
|
||||||
#[serde(skip_serializing_if="Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub email: Option<String>,
|
pub email: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -39,15 +39,35 @@ use proxmox_schema::{
|
||||||
// slash is not allowed because it is used as pve API delimiter
|
// slash is not allowed because it is used as pve API delimiter
|
||||||
// also see "man useradd"
|
// also see "man useradd"
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! USER_NAME_REGEX_STR { () => (r"(?:[^\s:/[:cntrl:]]+)") }
|
macro_rules! USER_NAME_REGEX_STR {
|
||||||
|
() => {
|
||||||
|
r"(?:[^\s:/[:cntrl:]]+)"
|
||||||
|
};
|
||||||
|
}
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! GROUP_NAME_REGEX_STR { () => (USER_NAME_REGEX_STR!()) }
|
macro_rules! GROUP_NAME_REGEX_STR {
|
||||||
|
() => {
|
||||||
|
USER_NAME_REGEX_STR!()
|
||||||
|
};
|
||||||
|
}
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! TOKEN_NAME_REGEX_STR { () => (PROXMOX_SAFE_ID_REGEX_STR!()) }
|
macro_rules! TOKEN_NAME_REGEX_STR {
|
||||||
|
() => {
|
||||||
|
PROXMOX_SAFE_ID_REGEX_STR!()
|
||||||
|
};
|
||||||
|
}
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! USER_ID_REGEX_STR { () => (concat!(USER_NAME_REGEX_STR!(), r"@", PROXMOX_SAFE_ID_REGEX_STR!())) }
|
macro_rules! USER_ID_REGEX_STR {
|
||||||
|
() => {
|
||||||
|
concat!(USER_NAME_REGEX_STR!(), r"@", PROXMOX_SAFE_ID_REGEX_STR!())
|
||||||
|
};
|
||||||
|
}
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! APITOKEN_ID_REGEX_STR { () => (concat!(USER_ID_REGEX_STR!() , r"!", TOKEN_NAME_REGEX_STR!())) }
|
macro_rules! APITOKEN_ID_REGEX_STR {
|
||||||
|
() => {
|
||||||
|
concat!(USER_ID_REGEX_STR!(), r"!", TOKEN_NAME_REGEX_STR!())
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
const_regex! {
|
const_regex! {
|
||||||
pub PROXMOX_USER_NAME_REGEX = concat!(r"^", USER_NAME_REGEX_STR!(), r"$");
|
pub PROXMOX_USER_NAME_REGEX = concat!(r"^", USER_NAME_REGEX_STR!(), r"$");
|
||||||
|
@ -238,7 +258,8 @@ impl TryFrom<String> for Realm {
|
||||||
type Error = Error;
|
type Error = Error;
|
||||||
|
|
||||||
fn try_from(s: String) -> Result<Self, Error> {
|
fn try_from(s: String) -> Result<Self, Error> {
|
||||||
PROXMOX_AUTH_REALM_STRING_SCHEMA.check_constraints(&s)
|
PROXMOX_AUTH_REALM_STRING_SCHEMA
|
||||||
|
.check_constraints(&s)
|
||||||
.map_err(|_| format_err!("invalid realm"))?;
|
.map_err(|_| format_err!("invalid realm"))?;
|
||||||
|
|
||||||
Ok(Self(s))
|
Ok(Self(s))
|
||||||
|
@ -249,7 +270,8 @@ impl<'a> TryFrom<&'a str> for &'a RealmRef {
|
||||||
type Error = Error;
|
type Error = Error;
|
||||||
|
|
||||||
fn try_from(s: &'a str) -> Result<&'a RealmRef, Error> {
|
fn try_from(s: &'a str) -> Result<&'a RealmRef, Error> {
|
||||||
PROXMOX_AUTH_REALM_STRING_SCHEMA.check_constraints(s)
|
PROXMOX_AUTH_REALM_STRING_SCHEMA
|
||||||
|
.check_constraints(s)
|
||||||
.map_err(|_| format_err!("invalid realm"))?;
|
.map_err(|_| format_err!("invalid realm"))?;
|
||||||
|
|
||||||
Ok(RealmRef::new(s))
|
Ok(RealmRef::new(s))
|
||||||
|
@ -482,7 +504,8 @@ impl std::str::FromStr for Userid {
|
||||||
bail!("invalid user name in user id");
|
bail!("invalid user name in user id");
|
||||||
}
|
}
|
||||||
|
|
||||||
PROXMOX_AUTH_REALM_STRING_SCHEMA.check_constraints(realm)
|
PROXMOX_AUTH_REALM_STRING_SCHEMA
|
||||||
|
.check_constraints(realm)
|
||||||
.map_err(|_| format_err!("invalid realm in user id"))?;
|
.map_err(|_| format_err!("invalid realm in user id"))?;
|
||||||
|
|
||||||
Ok(Self::from((UsernameRef::new(name), RealmRef::new(realm))))
|
Ok(Self::from((UsernameRef::new(name), RealmRef::new(realm))))
|
||||||
|
@ -503,7 +526,8 @@ impl TryFrom<String> for Userid {
|
||||||
bail!("invalid user name in user id");
|
bail!("invalid user name in user id");
|
||||||
}
|
}
|
||||||
|
|
||||||
PROXMOX_AUTH_REALM_STRING_SCHEMA.check_constraints(&data[(name_len + 1)..])
|
PROXMOX_AUTH_REALM_STRING_SCHEMA
|
||||||
|
.check_constraints(&data[(name_len + 1)..])
|
||||||
.map_err(|_| format_err!("invalid realm in user id"))?;
|
.map_err(|_| format_err!("invalid realm in user id"))?;
|
||||||
|
|
||||||
Ok(Self { data, name_len })
|
Ok(Self { data, name_len })
|
||||||
|
@ -532,7 +556,7 @@ impl PartialEq<String> for Userid {
|
||||||
#[derive(Clone, Debug, Eq, PartialEq, Hash, UpdaterType)]
|
#[derive(Clone, Debug, Eq, PartialEq, Hash, UpdaterType)]
|
||||||
pub struct Authid {
|
pub struct Authid {
|
||||||
user: Userid,
|
user: Userid,
|
||||||
tokenname: Option<Tokenname>
|
tokenname: Option<Tokenname>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ApiType for Authid {
|
impl ApiType for Authid {
|
||||||
|
@ -652,7 +676,7 @@ impl TryFrom<String> for Authid {
|
||||||
|
|
||||||
data.truncate(realm_end);
|
data.truncate(realm_end);
|
||||||
|
|
||||||
let user:Userid = data.parse()?;
|
let user: Userid = data.parse()?;
|
||||||
|
|
||||||
Ok(Self { user, tokenname })
|
Ok(Self { user, tokenname })
|
||||||
}
|
}
|
||||||
|
@ -679,7 +703,10 @@ fn test_token_id() {
|
||||||
let token_userid = auth_id.user();
|
let token_userid = auth_id.user();
|
||||||
assert_eq!(&userid, token_userid);
|
assert_eq!(&userid, token_userid);
|
||||||
assert!(auth_id.is_token());
|
assert!(auth_id.is_token());
|
||||||
assert_eq!(auth_id.tokenname().expect("Token has tokenname").as_str(), TokennameRef::new("bar").as_str());
|
assert_eq!(
|
||||||
|
auth_id.tokenname().expect("Token has tokenname").as_str(),
|
||||||
|
TokennameRef::new("bar").as_str()
|
||||||
|
);
|
||||||
assert_eq!(auth_id.to_string(), "test@pam!bar".to_string());
|
assert_eq!(auth_id.to_string(), "test@pam!bar".to_string());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,8 +6,7 @@ const_regex! {
|
||||||
pub ZPOOL_NAME_REGEX = r"^[a-zA-Z][a-z0-9A-Z\-_.:]+$";
|
pub ZPOOL_NAME_REGEX = r"^[a-zA-Z][a-z0-9A-Z\-_.:]+$";
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const ZFS_ASHIFT_SCHEMA: Schema = IntegerSchema::new(
|
pub const ZFS_ASHIFT_SCHEMA: Schema = IntegerSchema::new("Pool sector size exponent.")
|
||||||
"Pool sector size exponent.")
|
|
||||||
.minimum(9)
|
.minimum(9)
|
||||||
.maximum(16)
|
.maximum(16)
|
||||||
.default(12)
|
.default(12)
|
||||||
|
@ -59,7 +58,7 @@ pub enum ZfsRaidLevel {
|
||||||
|
|
||||||
#[api()]
|
#[api()]
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
#[serde(rename_all="kebab-case")]
|
#[serde(rename_all = "kebab-case")]
|
||||||
/// zpool list item
|
/// zpool list item
|
||||||
pub struct ZpoolListItem {
|
pub struct ZpoolListItem {
|
||||||
/// zpool name
|
/// zpool name
|
||||||
|
|
Loading…
Reference in New Issue