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