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