]> git.proxmox.com Git - proxmox-backup.git/blame - pbs-api-types/src/lib.rs
changer config cleanup: use Updater
[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
WB
3use serde::{Deserialize, Serialize};
4
5use proxmox::api::api;
7b570c17
WB
6use proxmox::api::schema::{
7 ApiStringFormat, ApiType, ArraySchema, EnumEntry, IntegerSchema, ReturnType, Schema,
8 StringSchema,
9};
86fb3877 10use proxmox::const_regex;
75f83c6a 11use proxmox::{IPRE, IPRE_BRACKET, IPV4OCTET, IPV4RE, IPV6H16, IPV6LS32, IPV6RE};
86fb3877 12
bfff4eaa
WB
13#[rustfmt::skip]
14#[macro_export]
15macro_rules! PROXMOX_SAFE_ID_REGEX_STR { () => { r"(?:[A-Za-z0-9_][A-Za-z0-9._\-]*)" }; }
16
17#[rustfmt::skip]
18#[macro_export]
19macro_rules! BACKUP_ID_RE { () => (r"[A-Za-z0-9_][A-Za-z0-9._\-]*") }
20
21#[rustfmt::skip]
22#[macro_export]
23macro_rules! BACKUP_TYPE_RE { () => (r"(?:host|vm|ct)") }
24
25#[rustfmt::skip]
26#[macro_export]
27macro_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") }
28
29#[rustfmt::skip]
30#[macro_export]
31macro_rules! SNAPSHOT_PATH_REGEX_STR {
32 () => (
33 concat!(r"(", BACKUP_TYPE_RE!(), ")/(", BACKUP_ID_RE!(), ")/(", BACKUP_TIME_RE!(), r")")
34 );
35}
36
e3619d41
DM
37mod jobs;
38pub use jobs::*;
39
45d5d873
DM
40mod key_derivation;
41pub use key_derivation::{Kdf, KeyInfo};
42
751f6b61
WB
43#[macro_use]
44mod userid;
45pub use userid::Authid;
46pub use userid::Userid;
47pub use userid::{Realm, RealmRef};
48pub use userid::{Tokenname, TokennameRef};
49pub use userid::{Username, UsernameRef};
50pub use userid::{PROXMOX_GROUP_ID_SCHEMA, PROXMOX_TOKEN_ID_SCHEMA, PROXMOX_TOKEN_NAME_SCHEMA};
51
2b7f8dd5
WB
52#[macro_use]
53mod user;
54pub use user::{ApiToken, User, UserWithTokens};
55pub use user::{
56 EMAIL_SCHEMA, ENABLE_USER_SCHEMA, EXPIRE_USER_SCHEMA, FIRST_NAME_SCHEMA, LAST_NAME_SCHEMA,
57};
58
95f9d67c 59pub mod upid;
c23192d3 60pub use upid::UPID;
95f9d67c 61
ea584a75
WB
62mod crypto;
63pub use crypto::{CryptMode, Fingerprint};
64
013b1e8b
WB
65pub mod file_restore;
66
6afdda88
DM
67mod remote;
68pub use remote::*;
69
1ce8e905
DM
70mod tape;
71pub use tape::*;
72
75f83c6a
WB
73#[rustfmt::skip]
74#[macro_use]
75mod local_macros {
76 macro_rules! DNS_LABEL { () => (r"(?:[a-zA-Z0-9](?:[a-zA-Z0-9\-]*[a-zA-Z0-9])?)") }
77 macro_rules! DNS_NAME { () => (concat!(r"(?:(?:", DNS_LABEL!() , r"\.)*", DNS_LABEL!(), ")")) }
78 macro_rules! CIDR_V4_REGEX_STR { () => (concat!(r"(?:", IPV4RE!(), r"/\d{1,2})$")) }
79 macro_rules! CIDR_V6_REGEX_STR { () => (concat!(r"(?:", IPV6RE!(), r"/\d{1,3})$")) }
80 macro_rules! DNS_ALIAS_LABEL { () => (r"(?:[a-zA-Z0-9_](?:[a-zA-Z0-9\-]*[a-zA-Z0-9])?)") }
81 macro_rules! DNS_ALIAS_NAME {
82 () => (concat!(r"(?:(?:", DNS_ALIAS_LABEL!() , r"\.)*", DNS_ALIAS_LABEL!(), ")"))
83 }
84}
85
86fb3877 86const_regex! {
75f83c6a
WB
87 pub IP_V4_REGEX = concat!(r"^", IPV4RE!(), r"$");
88 pub IP_V6_REGEX = concat!(r"^", IPV6RE!(), r"$");
89 pub IP_REGEX = concat!(r"^", IPRE!(), r"$");
90 pub CIDR_V4_REGEX = concat!(r"^", CIDR_V4_REGEX_STR!(), r"$");
91 pub CIDR_V6_REGEX = concat!(r"^", CIDR_V6_REGEX_STR!(), r"$");
92 pub CIDR_REGEX = concat!(r"^(?:", CIDR_V4_REGEX_STR!(), "|", CIDR_V6_REGEX_STR!(), r")$");
93 pub HOSTNAME_REGEX = r"^(?:[a-zA-Z0-9](?:[a-zA-Z0-9\-]*[a-zA-Z0-9])?)$";
94 pub DNS_NAME_REGEX = concat!(r"^", DNS_NAME!(), r"$");
95 pub DNS_ALIAS_REGEX = concat!(r"^", DNS_ALIAS_NAME!(), r"$");
96 pub DNS_NAME_OR_IP_REGEX = concat!(r"^(?:", DNS_NAME!(), "|", IPRE!(), r")$");
97
98 pub SHA256_HEX_REGEX = r"^[a-f0-9]{64}$"; // fixme: define in common_regex ?
99
100 pub PASSWORD_REGEX = r"^[[:^cntrl:]]*$"; // everything but control characters
101
102 pub UUID_REGEX = r"^[0-9a-f]{8}(?:-[0-9a-f]{4}){3}-[0-9a-f]{12}$";
103
bfff4eaa
WB
104 pub BACKUP_TYPE_REGEX = concat!(r"^(", BACKUP_TYPE_RE!(), r")$");
105
106 pub BACKUP_ID_REGEX = concat!(r"^", BACKUP_ID_RE!(), r"$");
107
108 pub BACKUP_DATE_REGEX = concat!(r"^", BACKUP_TIME_RE!() ,r"$");
109
110 pub GROUP_PATH_REGEX = concat!(r"^(", BACKUP_TYPE_RE!(), ")/(", BACKUP_ID_RE!(), r")$");
111
112 pub BACKUP_FILE_REGEX = r"^.*\.([fd]idx|blob)$";
113
114 pub SNAPSHOT_PATH_REGEX = concat!(r"^", SNAPSHOT_PATH_REGEX_STR!(), r"$");
115
86fb3877 116 pub FINGERPRINT_SHA256_REGEX = r"^(?:[0-9a-fA-F][0-9a-fA-F])(?::[0-9a-fA-F][0-9a-fA-F]){31}$";
3c430e9a
WB
117
118 /// Regex for safe identifiers.
119 ///
120 /// This
121 /// [article](https://dwheeler.com/essays/fixing-unix-linux-filenames.html)
122 /// contains further information why it is reasonable to restict
123 /// names this way. This is not only useful for filenames, but for
124 /// any identifier command line tools work with.
125 pub PROXMOX_SAFE_ID_REGEX = concat!(r"^", PROXMOX_SAFE_ID_REGEX_STR!(), r"$");
126
127 pub SINGLE_LINE_COMMENT_REGEX = r"^[[:^cntrl:]]*$";
75f83c6a
WB
128
129 pub BACKUP_REPO_URL_REGEX = concat!(
130 r"^^(?:(?:(",
131 USER_ID_REGEX_STR!(), "|", APITOKEN_ID_REGEX_STR!(),
132 ")@)?(",
133 DNS_NAME!(), "|", IPRE_BRACKET!(),
134 "):)?(?:([0-9]{1,5}):)?(", PROXMOX_SAFE_ID_REGEX_STR!(), r")$"
135 );
4c1b7761
WB
136
137 pub BLOCKDEVICE_NAME_REGEX = r"^(:?(:?h|s|x?v)d[a-z]+)|(:?nvme\d+n\d+)$";
86fb3877
WB
138}
139
75f83c6a
WB
140pub const IP_V4_FORMAT: ApiStringFormat = ApiStringFormat::Pattern(&IP_V4_REGEX);
141pub const IP_V6_FORMAT: ApiStringFormat = ApiStringFormat::Pattern(&IP_V6_REGEX);
142pub const IP_FORMAT: ApiStringFormat = ApiStringFormat::Pattern(&IP_REGEX);
143pub const CIDR_V4_FORMAT: ApiStringFormat = ApiStringFormat::Pattern(&CIDR_V4_REGEX);
144pub const CIDR_V6_FORMAT: ApiStringFormat = ApiStringFormat::Pattern(&CIDR_V6_REGEX);
145pub const CIDR_FORMAT: ApiStringFormat = ApiStringFormat::Pattern(&CIDR_REGEX);
146
6afdda88
DM
147pub const DNS_NAME_FORMAT: ApiStringFormat =
148 ApiStringFormat::Pattern(&DNS_NAME_REGEX);
149
150pub const DNS_NAME_OR_IP_FORMAT: ApiStringFormat =
151 ApiStringFormat::Pattern(&DNS_NAME_OR_IP_REGEX);
152
153pub const DNS_NAME_OR_IP_SCHEMA: Schema = StringSchema::new("DNS name or IP address.")
154 .format(&DNS_NAME_OR_IP_FORMAT)
155 .schema();
156
ea584a75
WB
157pub const BACKUP_ID_SCHEMA: Schema = StringSchema::new("Backup ID.")
158 .format(&BACKUP_ID_FORMAT)
159 .schema();
160pub const BACKUP_TYPE_SCHEMA: Schema = StringSchema::new("Backup type.")
161 .format(&ApiStringFormat::Enum(&[
162 EnumEntry::new("vm", "Virtual Machine Backup"),
163 EnumEntry::new("ct", "Container Backup"),
164 EnumEntry::new("host", "Host Backup"),
165 ]))
166 .schema();
167pub const BACKUP_TIME_SCHEMA: Schema = IntegerSchema::new("Backup time (Unix epoch.)")
168 .minimum(1_547_797_308)
169 .schema();
170
171pub const DATASTORE_SCHEMA: Schema = StringSchema::new("Datastore name.")
172 .format(&PROXMOX_SAFE_ID_FORMAT)
173 .min_length(3)
174 .max_length(32)
175 .schema();
176
21211748
DM
177pub const REALM_ID_SCHEMA: Schema = StringSchema::new("Realm name.")
178 .format(&PROXMOX_SAFE_ID_FORMAT)
179 .min_length(2)
180 .max_length(32)
181 .schema();
182
86fb3877
WB
183pub const FINGERPRINT_SHA256_FORMAT: ApiStringFormat =
184 ApiStringFormat::Pattern(&FINGERPRINT_SHA256_REGEX);
185
186pub const CERT_FINGERPRINT_SHA256_SCHEMA: Schema =
187 StringSchema::new("X509 certificate fingerprint (sha256).")
188 .format(&FINGERPRINT_SHA256_FORMAT)
189 .schema();
3c430e9a 190
2b7f8dd5 191pub const PRUNE_SCHEMA_KEEP_DAILY: Schema = IntegerSchema::new("Number of daily backups to keep.")
ced69458
DC
192 .minimum(1)
193 .schema();
194
2b7f8dd5
WB
195pub const PRUNE_SCHEMA_KEEP_HOURLY: Schema =
196 IntegerSchema::new("Number of hourly backups to keep.")
197 .minimum(1)
198 .schema();
ced69458 199
2b7f8dd5 200pub const PRUNE_SCHEMA_KEEP_LAST: Schema = IntegerSchema::new("Number of backups to keep.")
ced69458
DC
201 .minimum(1)
202 .schema();
203
2b7f8dd5
WB
204pub const PRUNE_SCHEMA_KEEP_MONTHLY: Schema =
205 IntegerSchema::new("Number of monthly backups to keep.")
206 .minimum(1)
207 .schema();
ced69458 208
2b7f8dd5
WB
209pub const PRUNE_SCHEMA_KEEP_WEEKLY: Schema =
210 IntegerSchema::new("Number of weekly backups to keep.")
211 .minimum(1)
212 .schema();
ced69458 213
2b7f8dd5
WB
214pub const PRUNE_SCHEMA_KEEP_YEARLY: Schema =
215 IntegerSchema::new("Number of yearly backups to keep.")
216 .minimum(1)
217 .schema();
ced69458 218
3c430e9a
WB
219pub const PROXMOX_SAFE_ID_FORMAT: ApiStringFormat =
220 ApiStringFormat::Pattern(&PROXMOX_SAFE_ID_REGEX);
221
222pub const SINGLE_LINE_COMMENT_FORMAT: ApiStringFormat =
223 ApiStringFormat::Pattern(&SINGLE_LINE_COMMENT_REGEX);
224
225pub const SINGLE_LINE_COMMENT_SCHEMA: Schema = StringSchema::new("Comment (single line).")
226 .format(&SINGLE_LINE_COMMENT_FORMAT)
227 .schema();
bfff4eaa 228
2b7f8dd5
WB
229pub const PROXMOX_CONFIG_DIGEST_SCHEMA: Schema = StringSchema::new(
230 "Prevent changes if current configuration file has different \
231 SHA256 digest. This can be used to prevent concurrent \
232 modifications.",
233)
234.format(&PVE_CONFIG_DIGEST_FORMAT)
235.schema();
236
bfff4eaa 237pub const BACKUP_ID_FORMAT: ApiStringFormat = ApiStringFormat::Pattern(&BACKUP_ID_REGEX);
c23192d3 238
75f83c6a
WB
239/// API schema format definition for repository URLs
240pub const BACKUP_REPO_URL: ApiStringFormat = ApiStringFormat::Pattern(&BACKUP_REPO_URL_REGEX);
241
c23192d3
WB
242#[api(
243 properties: {
244 "upid": {
245 optional: true,
246 type: UPID,
247 },
248 },
249)]
250#[derive(Clone, Serialize, Deserialize)]
251#[serde(rename_all = "kebab-case")]
252/// Garbage collection status.
253pub struct GarbageCollectionStatus {
254 pub upid: Option<String>,
255 /// Number of processed index files.
256 pub index_file_count: usize,
257 /// Sum of bytes referred by index files.
258 pub index_data_bytes: u64,
259 /// Bytes used on disk.
260 pub disk_bytes: u64,
261 /// Chunks used on disk.
262 pub disk_chunks: usize,
263 /// Sum of removed bytes.
264 pub removed_bytes: u64,
265 /// Number of removed chunks.
266 pub removed_chunks: usize,
267 /// Sum of pending bytes (pending removal - kept for safety).
268 pub pending_bytes: u64,
269 /// Number of pending chunks (pending removal - kept for safety).
270 pub pending_chunks: usize,
271 /// Number of chunks marked as .bad by verify that have been removed by GC.
272 pub removed_bad: usize,
273 /// Number of chunks still marked as .bad after garbage collection.
274 pub still_bad: usize,
275}
276
277impl Default for GarbageCollectionStatus {
278 fn default() -> Self {
279 GarbageCollectionStatus {
280 upid: None,
281 index_file_count: 0,
282 index_data_bytes: 0,
283 disk_bytes: 0,
284 disk_chunks: 0,
285 removed_bytes: 0,
286 removed_chunks: 0,
287 pending_bytes: 0,
288 pending_chunks: 0,
289 removed_bad: 0,
290 still_bad: 0,
291 }
292 }
293}
75f83c6a
WB
294
295pub const PVE_CONFIG_DIGEST_FORMAT: ApiStringFormat = ApiStringFormat::Pattern(&SHA256_HEX_REGEX);
296pub const CHUNK_DIGEST_FORMAT: ApiStringFormat = ApiStringFormat::Pattern(&SHA256_HEX_REGEX);
297
298pub const PASSWORD_FORMAT: ApiStringFormat = ApiStringFormat::Pattern(&PASSWORD_REGEX);
299
300pub const UUID_FORMAT: ApiStringFormat = ApiStringFormat::Pattern(&UUID_REGEX);
ea584a75
WB
301
302pub const BACKUP_ARCHIVE_NAME_SCHEMA: Schema = StringSchema::new("Backup archive name.")
303 .format(&PROXMOX_SAFE_ID_FORMAT)
304 .schema();
305
306// Complex type definitions
307
308#[api(
309 properties: {
310 "filename": {
311 schema: BACKUP_ARCHIVE_NAME_SCHEMA,
312 },
313 "crypt-mode": {
314 type: CryptMode,
315 optional: true,
316 },
317 },
318)]
319#[derive(Serialize, Deserialize)]
320#[serde(rename_all = "kebab-case")]
321/// Basic information about archive files inside a backup snapshot.
322pub struct BackupContent {
323 pub filename: String,
324 /// Info if file is encrypted, signed, or neither.
325 #[serde(skip_serializing_if = "Option::is_none")]
326 pub crypt_mode: Option<CryptMode>,
327 /// Archive size (from backup manifest).
328 #[serde(skip_serializing_if = "Option::is_none")]
329 pub size: Option<u64>,
330}
331
332#[api()]
333#[derive(Debug, Copy, Clone, PartialEq, Serialize, Deserialize)]
334#[serde(rename_all = "lowercase")]
335/// Result of a verify operation.
336pub enum VerifyState {
337 /// Verification was successful
338 Ok,
339 /// Verification reported one or more errors
340 Failed,
341}
342
343#[api(
344 properties: {
345 upid: {
346 type: UPID,
347 },
348 state: {
349 type: VerifyState,
350 },
351 },
352)]
353#[derive(Serialize, Deserialize)]
354/// Task properties.
355pub struct SnapshotVerifyState {
356 /// UPID of the verify task
357 pub upid: UPID,
358 /// State of the verification. Enum.
359 pub state: VerifyState,
360}
361
362#[api(
363 properties: {
364 "backup-type": {
365 schema: BACKUP_TYPE_SCHEMA,
366 },
367 "backup-id": {
368 schema: BACKUP_ID_SCHEMA,
369 },
370 "backup-time": {
371 schema: BACKUP_TIME_SCHEMA,
372 },
373 comment: {
374 schema: SINGLE_LINE_COMMENT_SCHEMA,
375 optional: true,
376 },
377 verification: {
378 type: SnapshotVerifyState,
379 optional: true,
380 },
381 fingerprint: {
382 type: String,
383 optional: true,
384 },
385 files: {
386 items: {
387 schema: BACKUP_ARCHIVE_NAME_SCHEMA
388 },
389 },
390 owner: {
391 type: Authid,
392 optional: true,
393 },
394 },
395)]
396#[derive(Serialize, Deserialize)]
397#[serde(rename_all = "kebab-case")]
398/// Basic information about backup snapshot.
399pub struct SnapshotListItem {
400 pub backup_type: String, // enum
401 pub backup_id: String,
402 pub backup_time: i64,
403 /// The first line from manifest "notes"
404 #[serde(skip_serializing_if = "Option::is_none")]
405 pub comment: Option<String>,
406 /// The result of the last run verify task
407 #[serde(skip_serializing_if = "Option::is_none")]
408 pub verification: Option<SnapshotVerifyState>,
409 /// Fingerprint of encryption key
410 #[serde(skip_serializing_if = "Option::is_none")]
411 pub fingerprint: Option<Fingerprint>,
412 /// List of contained archive files.
413 pub files: Vec<BackupContent>,
414 /// Overall snapshot size (sum of all archive sizes).
415 #[serde(skip_serializing_if = "Option::is_none")]
416 pub size: Option<u64>,
417 /// The owner of the snapshots group
418 #[serde(skip_serializing_if = "Option::is_none")]
419 pub owner: Option<Authid>,
420}
421
422#[api(
423 properties: {
424 "backup-type": {
425 schema: BACKUP_TYPE_SCHEMA,
426 },
427 "backup-id": {
428 schema: BACKUP_ID_SCHEMA,
429 },
430 "last-backup": {
431 schema: BACKUP_TIME_SCHEMA,
432 },
433 "backup-count": {
434 type: Integer,
435 },
436 files: {
437 items: {
438 schema: BACKUP_ARCHIVE_NAME_SCHEMA
439 },
440 },
441 owner: {
442 type: Authid,
443 optional: true,
444 },
445 },
446)]
447#[derive(Serialize, Deserialize)]
448#[serde(rename_all = "kebab-case")]
449/// Basic information about a backup group.
450pub struct GroupListItem {
451 pub backup_type: String, // enum
452 pub backup_id: String,
453 pub last_backup: i64,
454 /// Number of contained snapshots
455 pub backup_count: u64,
456 /// List of contained archive files.
457 pub files: Vec<String>,
458 /// The owner of group
459 #[serde(skip_serializing_if = "Option::is_none")]
460 pub owner: Option<Authid>,
d6688884 461 /// The first line from group "notes"
2b7f8dd5 462 #[serde(skip_serializing_if = "Option::is_none")]
d6688884 463 pub comment: Option<String>,
ea584a75
WB
464}
465
466#[api(
467 properties: {
468 store: {
469 schema: DATASTORE_SCHEMA,
470 },
471 comment: {
472 optional: true,
473 schema: SINGLE_LINE_COMMENT_SCHEMA,
474 },
475 },
476)]
477#[derive(Serialize, Deserialize)]
478#[serde(rename_all = "kebab-case")]
479/// Basic information about a datastore.
480pub struct DataStoreListItem {
481 pub store: String,
482 pub comment: Option<String>,
483}
484
485#[api(
486 properties: {
487 "backup-type": {
488 schema: BACKUP_TYPE_SCHEMA,
489 },
490 "backup-id": {
491 schema: BACKUP_ID_SCHEMA,
492 },
493 "backup-time": {
494 schema: BACKUP_TIME_SCHEMA,
495 },
496 },
497)]
498#[derive(Serialize, Deserialize)]
499#[serde(rename_all = "kebab-case")]
500/// Prune result.
501pub struct PruneListItem {
502 pub backup_type: String, // enum
503 pub backup_id: String,
504 pub backup_time: i64,
505 /// Keep snapshot
506 pub keep: bool,
507}
51ec8a3c
WB
508
509#[api()]
510#[derive(Default, Serialize, Deserialize)]
511/// Storage space usage information.
512pub struct StorageStatus {
513 /// Total space (bytes).
514 pub total: u64,
515 /// Used space (bytes).
516 pub used: u64,
517 /// Available space (bytes).
518 pub avail: u64,
519}
520
521#[api()]
522#[derive(Serialize, Deserialize, Default)]
523/// Backup Type group/snapshot counts.
524pub struct TypeCounts {
525 /// The number of groups of the type.
526 pub groups: u64,
527 /// The number of snapshots of the type.
528 pub snapshots: u64,
529}
530
531#[api(
532 properties: {
533 ct: {
534 type: TypeCounts,
535 optional: true,
536 },
537 host: {
538 type: TypeCounts,
539 optional: true,
540 },
541 vm: {
542 type: TypeCounts,
543 optional: true,
544 },
545 other: {
546 type: TypeCounts,
547 optional: true,
548 },
549 },
550)]
551#[derive(Serialize, Deserialize, Default)]
552/// Counts of groups/snapshots per BackupType.
553pub struct Counts {
554 /// The counts for CT backups
555 pub ct: Option<TypeCounts>,
556 /// The counts for Host backups
557 pub host: Option<TypeCounts>,
558 /// The counts for VM backups
559 pub vm: Option<TypeCounts>,
560 /// The counts for other backup types
561 pub other: Option<TypeCounts>,
562}
eb5e0ae6
WB
563
564pub const PASSWORD_HINT_SCHEMA: Schema = StringSchema::new("Password hint.")
565 .format(&SINGLE_LINE_COMMENT_FORMAT)
566 .min_length(1)
567 .max_length(64)
568 .schema();
569
570
571#[api]
572#[derive(Deserialize, Serialize)]
573/// RSA public key information
574pub struct RsaPubKeyInfo {
575 /// Path to key (if stored in a file)
576 #[serde(skip_serializing_if="Option::is_none")]
577 pub path: Option<String>,
578 /// RSA exponent
579 pub exponent: String,
580 /// Hex-encoded RSA modulus
581 pub modulus: String,
582 /// Key (modulus) length in bits
583 pub length: usize,
584}
585
586impl std::convert::TryFrom<openssl::rsa::Rsa<openssl::pkey::Public>> for RsaPubKeyInfo {
587 type Error = anyhow::Error;
588
589 fn try_from(value: openssl::rsa::Rsa<openssl::pkey::Public>) -> Result<Self, Self::Error> {
590 let modulus = value.n().to_hex_str()?.to_string();
591 let exponent = value.e().to_dec_str()?.to_string();
592 let length = value.size() as usize * 8;
593
594 Ok(Self {
595 path: None,
596 exponent,
597 modulus,
598 length,
599 })
600 }
601}
7b570c17
WB
602
603#[api(
604 properties: {
605 upid: { schema: UPID::API_SCHEMA },
606 },
607)]
608#[derive(Serialize, Deserialize)]
609/// Task properties.
610pub struct TaskListItem {
611 pub upid: String,
612 /// The node name where the task is running on.
613 pub node: String,
614 /// The Unix PID
615 pub pid: i64,
616 /// The task start time (Epoch)
617 pub pstart: u64,
618 /// The task start time (Epoch)
619 pub starttime: i64,
620 /// Worker type (arbitrary ASCII string)
621 pub worker_type: String,
622 /// Worker ID (arbitrary ASCII string)
623 pub worker_id: Option<String>,
624 /// The authenticated entity who started the task
625 pub user: Authid,
626 /// The task end time (Epoch)
627 #[serde(skip_serializing_if="Option::is_none")]
628 pub endtime: Option<i64>,
629 /// Task end status
630 #[serde(skip_serializing_if="Option::is_none")]
631 pub status: Option<String>,
632}
633
634pub const ADMIN_DATASTORE_LIST_SNAPSHOTS_RETURN_TYPE: ReturnType = ReturnType {
635 optional: false,
636 schema: &ArraySchema::new(
637 "Returns the list of snapshots.",
638 &SnapshotListItem::API_SCHEMA,
639 ).schema(),
640};
641
642pub const ADMIN_DATASTORE_LIST_SNAPSHOT_FILES_RETURN_TYPE: ReturnType = ReturnType {
643 optional: false,
644 schema: &ArraySchema::new(
645 "Returns the list of archive files inside a backup snapshots.",
646 &BackupContent::API_SCHEMA,
647 ).schema(),
648};
649
650pub const ADMIN_DATASTORE_LIST_GROUPS_RETURN_TYPE: ReturnType = ReturnType {
651 optional: false,
652 schema: &ArraySchema::new(
653 "Returns the list of backup groups.",
654 &GroupListItem::API_SCHEMA,
655 ).schema(),
656};
657
658pub const ADMIN_DATASTORE_PRUNE_RETURN_TYPE: ReturnType = ReturnType {
659 optional: false,
660 schema: &ArraySchema::new(
661 "Returns the list of snapshots and a flag indicating if there are kept or removed.",
662 &PruneListItem::API_SCHEMA,
663 ).schema(),
664};
665
666pub const NODE_TASKS_LIST_TASKS_RETURN_TYPE: ReturnType = ReturnType {
667 optional: false,
668 schema: &ArraySchema::new(
669 "A list of tasks.",
670 &TaskListItem::API_SCHEMA,
671 ).schema(),
672};
e3619d41
DM
673
674#[api()]
675#[derive(Debug, Clone, Serialize, Deserialize)]
676#[serde(rename_all = "PascalCase")]
677/// Describes a package for which an update is available.
678pub struct APTUpdateInfo {
679 /// Package name
680 pub package: String,
681 /// Package title
682 pub title: String,
683 /// Package architecture
684 pub arch: String,
685 /// Human readable package description
686 pub description: String,
687 /// New version to be updated to
688 pub version: String,
689 /// Old version currently installed
690 pub old_version: String,
691 /// Package origin
692 pub origin: String,
693 /// Package priority in human-readable form
694 pub priority: String,
695 /// Package section
696 pub section: String,
697 /// URL under which the package's changelog can be retrieved
698 pub change_log_url: String,
699 /// Custom extra field for additional package information
700 #[serde(skip_serializing_if="Option::is_none")]
701 pub extra_info: Option<String>,
702}