]> git.proxmox.com Git - proxmox-backup.git/blame - pbs-api-types/src/lib.rs
update to first proxmox crate split
[proxmox-backup.git] / pbs-api-types / src / lib.rs
CommitLineData
155f657f
WB
1//! Basic API types used by most of the PBS code.
2
c23192d3 3use serde::{Deserialize, Serialize};
8cc3760e 4use anyhow::bail;
c23192d3 5
6ef1b649
WB
6use proxmox_schema::{
7 api, const_regex, ApiStringFormat, ApiType, ArraySchema, Schema, StringSchema, ReturnType,
8};
75f83c6a 9use proxmox::{IPRE, IPRE_BRACKET, IPV4OCTET, IPV4RE, IPV6H16, IPV6LS32, IPV6RE};
86fb3877 10
bfff4eaa
WB
11#[rustfmt::skip]
12#[macro_export]
13macro_rules! PROXMOX_SAFE_ID_REGEX_STR { () => { r"(?:[A-Za-z0-9_][A-Za-z0-9._\-]*)" }; }
14
15#[rustfmt::skip]
16#[macro_export]
17macro_rules! BACKUP_ID_RE { () => (r"[A-Za-z0-9_][A-Za-z0-9._\-]*") }
18
19#[rustfmt::skip]
20#[macro_export]
21macro_rules! BACKUP_TYPE_RE { () => (r"(?:host|vm|ct)") }
22
23#[rustfmt::skip]
24#[macro_export]
25macro_rules! BACKUP_TIME_RE { () => (r"[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}Z") }
26
27#[rustfmt::skip]
28#[macro_export]
29macro_rules! SNAPSHOT_PATH_REGEX_STR {
30 () => (
31 concat!(r"(", BACKUP_TYPE_RE!(), ")/(", BACKUP_ID_RE!(), ")/(", BACKUP_TIME_RE!(), r")")
32 );
33}
34
8cc3760e
DM
35mod acl;
36pub use acl::*;
37
38mod datastore;
39pub use datastore::*;
40
e3619d41
DM
41mod jobs;
42pub use jobs::*;
43
45d5d873
DM
44mod key_derivation;
45pub use key_derivation::{Kdf, KeyInfo};
46
6f422880
DM
47mod network;
48pub use network::*;
49
751f6b61
WB
50#[macro_use]
51mod userid;
52pub use userid::Authid;
53pub use userid::Userid;
54pub use userid::{Realm, RealmRef};
55pub use userid::{Tokenname, TokennameRef};
56pub use userid::{Username, UsernameRef};
57pub use userid::{PROXMOX_GROUP_ID_SCHEMA, PROXMOX_TOKEN_ID_SCHEMA, PROXMOX_TOKEN_NAME_SCHEMA};
58
2b7f8dd5
WB
59#[macro_use]
60mod user;
b65dfff5 61pub use user::*;
2b7f8dd5 62
6ef1b649 63pub use proxmox_schema::upid::*;
95f9d67c 64
ea584a75
WB
65mod crypto;
66pub use crypto::{CryptMode, Fingerprint};
67
013b1e8b
WB
68pub mod file_restore;
69
6afdda88
DM
70mod remote;
71pub use remote::*;
72
1ce8e905
DM
73mod tape;
74pub use tape::*;
75
8cc3760e
DM
76mod zfs;
77pub use zfs::*;
78
79
75f83c6a
WB
80#[rustfmt::skip]
81#[macro_use]
82mod local_macros {
83 macro_rules! DNS_LABEL { () => (r"(?:[a-zA-Z0-9](?:[a-zA-Z0-9\-]*[a-zA-Z0-9])?)") }
84 macro_rules! DNS_NAME { () => (concat!(r"(?:(?:", DNS_LABEL!() , r"\.)*", DNS_LABEL!(), ")")) }
85 macro_rules! CIDR_V4_REGEX_STR { () => (concat!(r"(?:", IPV4RE!(), r"/\d{1,2})$")) }
86 macro_rules! CIDR_V6_REGEX_STR { () => (concat!(r"(?:", IPV6RE!(), r"/\d{1,3})$")) }
87 macro_rules! DNS_ALIAS_LABEL { () => (r"(?:[a-zA-Z0-9_](?:[a-zA-Z0-9\-]*[a-zA-Z0-9])?)") }
88 macro_rules! DNS_ALIAS_NAME {
89 () => (concat!(r"(?:(?:", DNS_ALIAS_LABEL!() , r"\.)*", DNS_ALIAS_LABEL!(), ")"))
90 }
91}
92
86fb3877 93const_regex! {
75f83c6a
WB
94 pub IP_V4_REGEX = concat!(r"^", IPV4RE!(), r"$");
95 pub IP_V6_REGEX = concat!(r"^", IPV6RE!(), r"$");
96 pub IP_REGEX = concat!(r"^", IPRE!(), r"$");
97 pub CIDR_V4_REGEX = concat!(r"^", CIDR_V4_REGEX_STR!(), r"$");
98 pub CIDR_V6_REGEX = concat!(r"^", CIDR_V6_REGEX_STR!(), r"$");
99 pub CIDR_REGEX = concat!(r"^(?:", CIDR_V4_REGEX_STR!(), "|", CIDR_V6_REGEX_STR!(), r")$");
100 pub HOSTNAME_REGEX = r"^(?:[a-zA-Z0-9](?:[a-zA-Z0-9\-]*[a-zA-Z0-9])?)$";
101 pub DNS_NAME_REGEX = concat!(r"^", DNS_NAME!(), r"$");
102 pub DNS_ALIAS_REGEX = concat!(r"^", DNS_ALIAS_NAME!(), r"$");
103 pub DNS_NAME_OR_IP_REGEX = concat!(r"^(?:", DNS_NAME!(), "|", IPRE!(), r")$");
104
105 pub SHA256_HEX_REGEX = r"^[a-f0-9]{64}$"; // fixme: define in common_regex ?
106
107 pub PASSWORD_REGEX = r"^[[:^cntrl:]]*$"; // everything but control characters
108
109 pub UUID_REGEX = r"^[0-9a-f]{8}(?:-[0-9a-f]{4}){3}-[0-9a-f]{12}$";
110
8cc3760e 111 pub SYSTEMD_DATETIME_REGEX = r"^\d{4}-\d{2}-\d{2}( \d{2}:\d{2}(:\d{2})?)?$"; // fixme: define in common_regex ?
bfff4eaa 112
86fb3877 113 pub FINGERPRINT_SHA256_REGEX = r"^(?:[0-9a-fA-F][0-9a-fA-F])(?::[0-9a-fA-F][0-9a-fA-F]){31}$";
3c430e9a
WB
114
115 /// Regex for safe identifiers.
116 ///
117 /// This
118 /// [article](https://dwheeler.com/essays/fixing-unix-linux-filenames.html)
119 /// contains further information why it is reasonable to restict
120 /// names this way. This is not only useful for filenames, but for
121 /// any identifier command line tools work with.
122 pub PROXMOX_SAFE_ID_REGEX = concat!(r"^", PROXMOX_SAFE_ID_REGEX_STR!(), r"$");
123
124 pub SINGLE_LINE_COMMENT_REGEX = r"^[[:^cntrl:]]*$";
75f83c6a
WB
125
126 pub BACKUP_REPO_URL_REGEX = concat!(
127 r"^^(?:(?:(",
128 USER_ID_REGEX_STR!(), "|", APITOKEN_ID_REGEX_STR!(),
129 ")@)?(",
130 DNS_NAME!(), "|", IPRE_BRACKET!(),
131 "):)?(?:([0-9]{1,5}):)?(", PROXMOX_SAFE_ID_REGEX_STR!(), r")$"
132 );
4c1b7761
WB
133
134 pub BLOCKDEVICE_NAME_REGEX = r"^(:?(:?h|s|x?v)d[a-z]+)|(:?nvme\d+n\d+)$";
8cc3760e 135 pub SUBSCRIPTION_KEY_REGEX = concat!(r"^pbs(?:[cbsp])-[0-9a-f]{10}$");
86fb3877
WB
136}
137
75f83c6a
WB
138pub const IP_V4_FORMAT: ApiStringFormat = ApiStringFormat::Pattern(&IP_V4_REGEX);
139pub const IP_V6_FORMAT: ApiStringFormat = ApiStringFormat::Pattern(&IP_V6_REGEX);
140pub const IP_FORMAT: ApiStringFormat = ApiStringFormat::Pattern(&IP_REGEX);
141pub const CIDR_V4_FORMAT: ApiStringFormat = ApiStringFormat::Pattern(&CIDR_V4_REGEX);
142pub const CIDR_V6_FORMAT: ApiStringFormat = ApiStringFormat::Pattern(&CIDR_V6_REGEX);
143pub const CIDR_FORMAT: ApiStringFormat = ApiStringFormat::Pattern(&CIDR_REGEX);
8cc3760e
DM
144pub const PVE_CONFIG_DIGEST_FORMAT: ApiStringFormat = ApiStringFormat::Pattern(&SHA256_HEX_REGEX);
145pub const PASSWORD_FORMAT: ApiStringFormat = ApiStringFormat::Pattern(&PASSWORD_REGEX);
146pub const UUID_FORMAT: ApiStringFormat = ApiStringFormat::Pattern(&UUID_REGEX);
147pub const BLOCKDEVICE_NAME_FORMAT: ApiStringFormat = ApiStringFormat::Pattern(&BLOCKDEVICE_NAME_REGEX);
148pub const SUBSCRIPTION_KEY_FORMAT: ApiStringFormat = ApiStringFormat::Pattern(&SUBSCRIPTION_KEY_REGEX);
149pub const SYSTEMD_DATETIME_FORMAT: ApiStringFormat = ApiStringFormat::Pattern(&SYSTEMD_DATETIME_REGEX);
150pub const HOSTNAME_FORMAT: ApiStringFormat = ApiStringFormat::Pattern(&HOSTNAME_REGEX);
151
152pub const DNS_ALIAS_FORMAT: ApiStringFormat =
153 ApiStringFormat::Pattern(&DNS_ALIAS_REGEX);
154
155pub const SEARCH_DOMAIN_SCHEMA: Schema =
156 StringSchema::new("Search domain for host-name lookup.").schema();
157
158pub const FIRST_DNS_SERVER_SCHEMA: Schema =
159 StringSchema::new("First name server IP address.")
160 .format(&IP_FORMAT)
161 .schema();
162
163pub const SECOND_DNS_SERVER_SCHEMA: Schema =
164 StringSchema::new("Second name server IP address.")
165 .format(&IP_FORMAT)
166 .schema();
167
168pub const THIRD_DNS_SERVER_SCHEMA: Schema =
169 StringSchema::new("Third name server IP address.")
170 .format(&IP_FORMAT)
171 .schema();
172
173pub const HOSTNAME_SCHEMA: Schema = StringSchema::new("Hostname (as defined in RFC1123).")
174 .format(&HOSTNAME_FORMAT)
175 .schema();
75f83c6a 176
6afdda88
DM
177pub const DNS_NAME_FORMAT: ApiStringFormat =
178 ApiStringFormat::Pattern(&DNS_NAME_REGEX);
179
180pub const DNS_NAME_OR_IP_FORMAT: ApiStringFormat =
181 ApiStringFormat::Pattern(&DNS_NAME_OR_IP_REGEX);
182
183pub const DNS_NAME_OR_IP_SCHEMA: Schema = StringSchema::new("DNS name or IP address.")
184 .format(&DNS_NAME_OR_IP_FORMAT)
185 .schema();
186
8cc3760e
DM
187pub const NODE_SCHEMA: Schema = StringSchema::new("Node name (or 'localhost')")
188 .format(&ApiStringFormat::VerifyFn(|node| {
189 if node == "localhost" || node == proxmox::tools::nodename() {
190 Ok(())
191 } else {
192 bail!("no such node '{}'", node);
193 }
194 }))
ea584a75 195 .schema();
8cc3760e
DM
196
197pub const TIME_ZONE_SCHEMA: Schema = StringSchema::new(
198 "Time zone. The file '/usr/share/zoneinfo/zone.tab' contains the list of valid names.")
199 .format(&SINGLE_LINE_COMMENT_FORMAT)
200 .min_length(2)
201 .max_length(64)
ea584a75
WB
202 .schema();
203
8cc3760e
DM
204pub const BLOCKDEVICE_NAME_SCHEMA: Schema = StringSchema::new("Block device name (/sys/block/<name>).")
205 .format(&BLOCKDEVICE_NAME_FORMAT)
ea584a75 206 .min_length(3)
8cc3760e
DM
207 .max_length(64)
208 .schema();
209
210pub const DISK_ARRAY_SCHEMA: Schema = ArraySchema::new(
211 "Disk name list.", &BLOCKDEVICE_NAME_SCHEMA)
212 .schema();
213
214pub const DISK_LIST_SCHEMA: Schema = StringSchema::new(
215 "A list of disk names, comma separated.")
216 .format(&ApiStringFormat::PropertyString(&DISK_ARRAY_SCHEMA))
217 .schema();
218
219pub const PASSWORD_SCHEMA: Schema = StringSchema::new("Password.")
220 .format(&PASSWORD_FORMAT)
221 .min_length(1)
222 .max_length(1024)
223 .schema();
224
225pub const PBS_PASSWORD_SCHEMA: Schema = StringSchema::new("User Password.")
226 .format(&PASSWORD_FORMAT)
227 .min_length(5)
228 .max_length(64)
ea584a75
WB
229 .schema();
230
21211748
DM
231pub const REALM_ID_SCHEMA: Schema = StringSchema::new("Realm name.")
232 .format(&PROXMOX_SAFE_ID_FORMAT)
233 .min_length(2)
234 .max_length(32)
235 .schema();
236
86fb3877
WB
237pub const FINGERPRINT_SHA256_FORMAT: ApiStringFormat =
238 ApiStringFormat::Pattern(&FINGERPRINT_SHA256_REGEX);
239
240pub const CERT_FINGERPRINT_SHA256_SCHEMA: Schema =
241 StringSchema::new("X509 certificate fingerprint (sha256).")
242 .format(&FINGERPRINT_SHA256_FORMAT)
243 .schema();
3c430e9a
WB
244
245pub const PROXMOX_SAFE_ID_FORMAT: ApiStringFormat =
246 ApiStringFormat::Pattern(&PROXMOX_SAFE_ID_REGEX);
247
248pub const SINGLE_LINE_COMMENT_FORMAT: ApiStringFormat =
249 ApiStringFormat::Pattern(&SINGLE_LINE_COMMENT_REGEX);
250
251pub const SINGLE_LINE_COMMENT_SCHEMA: Schema = StringSchema::new("Comment (single line).")
252 .format(&SINGLE_LINE_COMMENT_FORMAT)
253 .schema();
bfff4eaa 254
8cc3760e
DM
255pub const SUBSCRIPTION_KEY_SCHEMA: Schema = StringSchema::new("Proxmox Backup Server subscription key.")
256 .format(&SUBSCRIPTION_KEY_FORMAT)
257 .min_length(15)
258 .max_length(16)
259 .schema();
260
261pub const SERVICE_ID_SCHEMA: Schema = StringSchema::new("Service ID.")
262 .max_length(256)
263 .schema();
264
2b7f8dd5
WB
265pub const PROXMOX_CONFIG_DIGEST_SCHEMA: Schema = StringSchema::new(
266 "Prevent changes if current configuration file has different \
267 SHA256 digest. This can be used to prevent concurrent \
268 modifications.",
269)
270.format(&PVE_CONFIG_DIGEST_FORMAT)
271.schema();
272
75f83c6a
WB
273/// API schema format definition for repository URLs
274pub const BACKUP_REPO_URL: ApiStringFormat = ApiStringFormat::Pattern(&BACKUP_REPO_URL_REGEX);
275
75f83c6a 276
ea584a75
WB
277// Complex type definitions
278
51ec8a3c
WB
279
280#[api()]
281#[derive(Default, Serialize, Deserialize)]
282/// Storage space usage information.
283pub struct StorageStatus {
284 /// Total space (bytes).
285 pub total: u64,
286 /// Used space (bytes).
287 pub used: u64,
288 /// Available space (bytes).
289 pub avail: u64,
290}
291
eb5e0ae6
WB
292pub const PASSWORD_HINT_SCHEMA: Schema = StringSchema::new("Password hint.")
293 .format(&SINGLE_LINE_COMMENT_FORMAT)
294 .min_length(1)
295 .max_length(64)
296 .schema();
297
298
299#[api]
300#[derive(Deserialize, Serialize)]
301/// RSA public key information
302pub struct RsaPubKeyInfo {
303 /// Path to key (if stored in a file)
304 #[serde(skip_serializing_if="Option::is_none")]
305 pub path: Option<String>,
306 /// RSA exponent
307 pub exponent: String,
308 /// Hex-encoded RSA modulus
309 pub modulus: String,
310 /// Key (modulus) length in bits
311 pub length: usize,
312}
313
314impl std::convert::TryFrom<openssl::rsa::Rsa<openssl::pkey::Public>> for RsaPubKeyInfo {
315 type Error = anyhow::Error;
316
317 fn try_from(value: openssl::rsa::Rsa<openssl::pkey::Public>) -> Result<Self, Self::Error> {
318 let modulus = value.n().to_hex_str()?.to_string();
319 let exponent = value.e().to_dec_str()?.to_string();
320 let length = value.size() as usize * 8;
321
322 Ok(Self {
323 path: None,
324 exponent,
325 modulus,
326 length,
327 })
328 }
329}
7b570c17 330
e3619d41
DM
331#[api()]
332#[derive(Debug, Clone, Serialize, Deserialize)]
333#[serde(rename_all = "PascalCase")]
334/// Describes a package for which an update is available.
335pub struct APTUpdateInfo {
336 /// Package name
337 pub package: String,
338 /// Package title
339 pub title: String,
340 /// Package architecture
341 pub arch: String,
342 /// Human readable package description
343 pub description: String,
344 /// New version to be updated to
345 pub version: String,
346 /// Old version currently installed
347 pub old_version: String,
348 /// Package origin
349 pub origin: String,
350 /// Package priority in human-readable form
351 pub priority: String,
352 /// Package section
353 pub section: String,
354 /// URL under which the package's changelog can be retrieved
355 pub change_log_url: String,
356 /// Custom extra field for additional package information
357 #[serde(skip_serializing_if="Option::is_none")]
358 pub extra_info: Option<String>,
359}
8cc3760e 360
8cc3760e
DM
361
362#[api()]
363#[derive(Debug, Copy, Clone, PartialEq, Serialize, Deserialize)]
364#[serde(rename_all = "lowercase")]
365/// Node Power command type.
366pub enum NodePowerCommand {
367 /// Restart the server
368 Reboot,
369 /// Shutdown the server
370 Shutdown,
371}
81867f05
DM
372
373
374#[api()]
375#[derive(Eq, PartialEq, Debug, Serialize, Deserialize)]
376#[serde(rename_all = "lowercase")]
377pub enum TaskStateType {
378 /// Ok
379 OK,
380 /// Warning
381 Warning,
382 /// Error
383 Error,
384 /// Unknown
385 Unknown,
386}
387
388#[api(
389 properties: {
390 upid: { schema: UPID::API_SCHEMA },
391 },
392)]
393#[derive(Serialize, Deserialize)]
394/// Task properties.
395pub struct TaskListItem {
396 pub upid: String,
397 /// The node name where the task is running on.
398 pub node: String,
399 /// The Unix PID
400 pub pid: i64,
401 /// The task start time (Epoch)
402 pub pstart: u64,
403 /// The task start time (Epoch)
404 pub starttime: i64,
405 /// Worker type (arbitrary ASCII string)
406 pub worker_type: String,
407 /// Worker ID (arbitrary ASCII string)
408 pub worker_id: Option<String>,
409 /// The authenticated entity who started the task
410 pub user: String,
411 /// The task end time (Epoch)
412 #[serde(skip_serializing_if="Option::is_none")]
413 pub endtime: Option<i64>,
414 /// Task end status
415 #[serde(skip_serializing_if="Option::is_none")]
416 pub status: Option<String>,
417}
418
419pub const NODE_TASKS_LIST_TASKS_RETURN_TYPE: ReturnType = ReturnType {
420 optional: false,
421 schema: &ArraySchema::new(
422 "A list of tasks.",
423 &TaskListItem::API_SCHEMA,
424 ).schema(),
425};
d1c3bc53
DM
426
427pub use proxmox_rrd_api_types::{RRDMode, RRDTimeFrameResolution};