1 //! API Type Definitions
4 use serde
::{Deserialize, Serialize}
;
6 use proxmox
::api
::{api, schema::*}
;
7 use proxmox
::const_regex
;
9 use crate::config
::acl
::Role
;
14 pub use pbs_api_types
::*;
16 // File names: may not contain slashes, may not start with "."
17 pub const FILENAME_FORMAT
: ApiStringFormat
= ApiStringFormat
::VerifyFn(|name
| {
18 if name
.starts_with('
.'
) {
19 bail
!("file names may not start with '.'");
21 if name
.contains('
/'
) {
22 bail
!("file names may not contain slashes");
28 pub SYSTEMD_DATETIME_REGEX
= r
"^\d{4}-\d{2}-\d{2}( \d{2}:\d{2}(:\d{2})?)?$"; // fixme: define in common_regex ?
30 /// Regex for verification jobs 'DATASTORE:ACTUAL_JOB_ID'
31 pub VERIFICATION_JOB_WORKER_ID_REGEX
= concat
!(r
"^(", PROXMOX_SAFE_ID_REGEX_STR
!(), r
"):");
32 /// Regex for sync jobs 'REMOTE:REMOTE_DATASTORE:LOCAL_DATASTORE:ACTUAL_JOB_ID'
33 pub SYNC_JOB_WORKER_ID_REGEX
= concat
!(r
"^(", PROXMOX_SAFE_ID_REGEX_STR
!(), r
"):(", PROXMOX_SAFE_ID_REGEX_STR
!(), r
"):(", PROXMOX_SAFE_ID_REGEX_STR
!(), r
"):");
35 pub ACL_PATH_REGEX
= concat
!(r
"^(?:/|", r
"(?:/", PROXMOX_SAFE_ID_REGEX_STR
!(), ")+", r
")$");
37 pub SUBSCRIPTION_KEY_REGEX
= concat
!(r
"^pbs(?:[cbsp])-[0-9a-f]{10}$");
39 pub ZPOOL_NAME_REGEX
= r
"^[a-zA-Z][a-z0-9A-Z\-_.:]+$";
41 pub DATASTORE_MAP_REGEX
= concat
!(r
"(:?", PROXMOX_SAFE_ID_REGEX_STR
!(), r
"=)?", PROXMOX_SAFE_ID_REGEX_STR
!());
45 pub const SYSTEMD_DATETIME_FORMAT
: ApiStringFormat
=
46 ApiStringFormat
::Pattern(&SYSTEMD_DATETIME_REGEX
);
48 pub const HOSTNAME_FORMAT
: ApiStringFormat
=
49 ApiStringFormat
::Pattern(&HOSTNAME_REGEX
);
51 pub const DNS_ALIAS_FORMAT
: ApiStringFormat
=
52 ApiStringFormat
::Pattern(&DNS_ALIAS_REGEX
);
54 pub const ACL_PATH_FORMAT
: ApiStringFormat
=
55 ApiStringFormat
::Pattern(&ACL_PATH_REGEX
);
57 pub const NETWORK_INTERFACE_FORMAT
: ApiStringFormat
=
58 ApiStringFormat
::Pattern(&PROXMOX_SAFE_ID_REGEX
);
60 pub const SUBSCRIPTION_KEY_FORMAT
: ApiStringFormat
=
61 ApiStringFormat
::Pattern(&SUBSCRIPTION_KEY_REGEX
);
63 pub const BLOCKDEVICE_NAME_FORMAT
: ApiStringFormat
=
64 ApiStringFormat
::Pattern(&BLOCKDEVICE_NAME_REGEX
);
66 pub const DATASTORE_MAP_FORMAT
: ApiStringFormat
=
67 ApiStringFormat
::Pattern(&DATASTORE_MAP_REGEX
);
69 pub const PASSWORD_SCHEMA
: Schema
= StringSchema
::new("Password.")
70 .format(&PASSWORD_FORMAT
)
75 pub const PBS_PASSWORD_SCHEMA
: Schema
= StringSchema
::new("User Password.")
76 .format(&PASSWORD_FORMAT
)
81 pub const CHUNK_DIGEST_SCHEMA
: Schema
= StringSchema
::new("Chunk digest (SHA256).")
82 .format(&CHUNK_DIGEST_FORMAT
)
85 pub const NODE_SCHEMA
: Schema
= StringSchema
::new("Node name (or 'localhost')")
86 .format(&ApiStringFormat
::VerifyFn(|node
| {
87 if node
== "localhost" || node
== proxmox
::tools
::nodename() {
90 bail
!("no such node '{}'", node
);
95 pub const SEARCH_DOMAIN_SCHEMA
: Schema
=
96 StringSchema
::new("Search domain for host-name lookup.").schema();
98 pub const FIRST_DNS_SERVER_SCHEMA
: Schema
=
99 StringSchema
::new("First name server IP address.")
103 pub const SECOND_DNS_SERVER_SCHEMA
: Schema
=
104 StringSchema
::new("Second name server IP address.")
108 pub const THIRD_DNS_SERVER_SCHEMA
: Schema
=
109 StringSchema
::new("Third name server IP address.")
113 pub const IP_V4_SCHEMA
: Schema
=
114 StringSchema
::new("IPv4 address.")
115 .format(&IP_V4_FORMAT
)
119 pub const IP_V6_SCHEMA
: Schema
=
120 StringSchema
::new("IPv6 address.")
121 .format(&IP_V6_FORMAT
)
125 pub const IP_SCHEMA
: Schema
=
126 StringSchema
::new("IP (IPv4 or IPv6) address.")
131 pub const CIDR_V4_SCHEMA
: Schema
=
132 StringSchema
::new("IPv4 address with netmask (CIDR notation).")
133 .format(&CIDR_V4_FORMAT
)
137 pub const CIDR_V6_SCHEMA
: Schema
=
138 StringSchema
::new("IPv6 address with netmask (CIDR notation).")
139 .format(&CIDR_V6_FORMAT
)
143 pub const CIDR_SCHEMA
: Schema
=
144 StringSchema
::new("IP address (IPv4 or IPv6) with netmask (CIDR notation).")
145 .format(&CIDR_FORMAT
)
149 pub const TIME_ZONE_SCHEMA
: Schema
= StringSchema
::new(
150 "Time zone. The file '/usr/share/zoneinfo/zone.tab' contains the list of valid names.")
151 .format(&SINGLE_LINE_COMMENT_FORMAT
)
156 pub const ACL_PATH_SCHEMA
: Schema
= StringSchema
::new(
157 "Access control path.")
158 .format(&ACL_PATH_FORMAT
)
163 pub const ACL_PROPAGATE_SCHEMA
: Schema
= BooleanSchema
::new(
164 "Allow to propagate (inherit) permissions.")
168 pub const ACL_UGID_TYPE_SCHEMA
: Schema
= StringSchema
::new(
169 "Type of 'ugid' property.")
170 .format(&ApiStringFormat
::Enum(&[
171 EnumEntry
::new("user", "User"),
172 EnumEntry
::new("group", "Group")]))
178 schema
: ACL_PROPAGATE_SCHEMA
,
181 schema
: ACL_PATH_SCHEMA
,
184 schema
: ACL_UGID_TYPE_SCHEMA
,
188 description
: "User or Group ID.",
195 #[derive(Serialize, Deserialize)]
197 pub struct AclListItem
{
200 pub ugid_type
: String
,
205 pub const UPID_SCHEMA
: Schema
= StringSchema
::new("Unique Process/Task ID.")
209 pub const DATASTORE_MAP_SCHEMA
: Schema
= StringSchema
::new("Datastore mapping.")
210 .format(&DATASTORE_MAP_FORMAT
)
213 .type_text("(<source>=)?<target>")
216 pub const DATASTORE_MAP_ARRAY_SCHEMA
: Schema
= ArraySchema
::new(
217 "Datastore mapping list.", &DATASTORE_MAP_SCHEMA
)
220 pub const DATASTORE_MAP_LIST_SCHEMA
: Schema
= StringSchema
::new(
221 "A list of Datastore mappings (or single datastore), comma separated. \
222 For example 'a=b,e' maps the source datastore 'a' to target 'b and \
223 all other sources to the default 'e'. If no default is given, only the \
224 specified sources are mapped.")
225 .format(&ApiStringFormat
::PropertyString(&DATASTORE_MAP_ARRAY_SCHEMA
))
228 pub const SYNC_SCHEDULE_SCHEMA
: Schema
= StringSchema
::new(
229 "Run sync job at specified schedule.")
230 .format(&ApiStringFormat
::VerifyFn(pbs_systemd
::time
::verify_calendar_event
))
231 .type_text("<calendar-event>")
234 pub const GC_SCHEDULE_SCHEMA
: Schema
= StringSchema
::new(
235 "Run garbage collection job at specified schedule.")
236 .format(&ApiStringFormat
::VerifyFn(pbs_systemd
::time
::verify_calendar_event
))
237 .type_text("<calendar-event>")
240 pub const PRUNE_SCHEDULE_SCHEMA
: Schema
= StringSchema
::new(
241 "Run prune job at specified schedule.")
242 .format(&ApiStringFormat
::VerifyFn(pbs_systemd
::time
::verify_calendar_event
))
243 .type_text("<calendar-event>")
246 pub const VERIFICATION_SCHEDULE_SCHEMA
: Schema
= StringSchema
::new(
247 "Run verify job at specified schedule.")
248 .format(&ApiStringFormat
::VerifyFn(pbs_systemd
::time
::verify_calendar_event
))
249 .type_text("<calendar-event>")
252 pub const JOB_ID_SCHEMA
: Schema
= StringSchema
::new("Job ID.")
253 .format(&PROXMOX_SAFE_ID_FORMAT
)
258 pub const REMOVE_VANISHED_BACKUPS_SCHEMA
: Schema
= BooleanSchema
::new(
259 "Delete vanished backups. This remove the local copy if the remote backup was deleted.")
263 pub const IGNORE_VERIFIED_BACKUPS_SCHEMA
: Schema
= BooleanSchema
::new(
264 "Do not verify backups that are already verified if their verification is not outdated.")
268 pub const VERIFICATION_OUTDATED_AFTER_SCHEMA
: Schema
= IntegerSchema
::new(
269 "Days after that a verification becomes outdated")
273 pub const HOSTNAME_SCHEMA
: Schema
= StringSchema
::new("Hostname (as defined in RFC1123).")
274 .format(&HOSTNAME_FORMAT
)
277 pub const SUBSCRIPTION_KEY_SCHEMA
: Schema
= StringSchema
::new("Proxmox Backup Server subscription key.")
278 .format(&SUBSCRIPTION_KEY_FORMAT
)
283 pub const BLOCKDEVICE_NAME_SCHEMA
: Schema
= StringSchema
::new("Block device name (/sys/block/<name>).")
284 .format(&BLOCKDEVICE_NAME_FORMAT
)
289 // Complex type definitions
294 type: GarbageCollectionStatus
,
303 #[derive(Serialize, Deserialize)]
304 #[serde(rename_all="kebab-case")]
305 /// Overall Datastore status and useful information.
306 pub struct DataStoreStatus
{
307 /// Total space (bytes).
309 /// Used space (bytes).
311 /// Available space (bytes).
313 /// Status of last GC
314 #[serde(skip_serializing_if="Option::is_none")]
315 pub gc_status
: Option
<GarbageCollectionStatus
>,
316 /// Group/Snapshot counts
317 #[serde(skip_serializing_if="Option::is_none")]
318 pub counts
: Option
<Counts
>,
322 #[derive(Eq, PartialEq, Debug, Serialize, Deserialize)]
323 #[serde(rename_all = "lowercase")]
324 pub enum TaskStateType
{
336 #[derive(Debug, Copy, Clone, PartialEq, Serialize, Deserialize)]
337 #[serde(rename_all = "lowercase")]
338 /// Node Power command type.
339 pub enum NodePowerCommand
{
340 /// Restart the server
342 /// Shutdown the server
347 #[derive(Debug, Copy, Clone, PartialEq, Serialize, Deserialize)]
348 #[serde(rename_all = "lowercase")]
349 /// Interface configuration method
350 pub enum NetworkConfigMethod
{
351 /// Configuration is done manually using other tools
353 /// Define interfaces with statically allocated addresses.
355 /// Obtain an address via DHCP
357 /// Define the loopback interface.
362 #[derive(Debug, Copy, Clone, PartialEq, Serialize, Deserialize)]
363 #[serde(rename_all = "kebab-case")]
364 #[allow(non_camel_case_types)]
367 pub enum LinuxBondMode
{
368 /// Round-robin policy
370 /// Active-backup policy
376 /// IEEE 802.3ad Dynamic link aggregation
377 #[serde(rename = "802.3ad")]
379 /// Adaptive transmit load balancing
381 /// Adaptive load balancing
386 #[derive(Debug, Copy, Clone, PartialEq, Serialize, Deserialize)]
387 #[serde(rename_all = "kebab-case")]
388 #[allow(non_camel_case_types)]
390 /// Bond Transmit Hash Policy for LACP (802.3ad)
391 pub enum BondXmitHashPolicy
{
395 #[serde(rename = "layer2+3")]
398 #[serde(rename = "layer3+4")]
403 #[derive(Debug, Copy, Clone, PartialEq, Serialize, Deserialize)]
404 #[serde(rename_all = "lowercase")]
405 /// Network interface type
406 pub enum NetworkInterfaceType
{
409 /// Physical Ethernet device
415 /// Linux VLAN (eth.10)
417 /// Interface Alias (eth:1)
419 /// Unknown interface type
423 pub const NETWORK_INTERFACE_NAME_SCHEMA
: Schema
= StringSchema
::new("Network interface name.")
424 .format(&NETWORK_INTERFACE_FORMAT
)
426 .max_length(libc
::IFNAMSIZ
-1)
429 pub const NETWORK_INTERFACE_ARRAY_SCHEMA
: Schema
= ArraySchema
::new(
430 "Network interface list.", &NETWORK_INTERFACE_NAME_SCHEMA
)
433 pub const NETWORK_INTERFACE_LIST_SCHEMA
: Schema
= StringSchema
::new(
434 "A list of network devices, comma separated.")
435 .format(&ApiStringFormat
::PropertyString(&NETWORK_INTERFACE_ARRAY_SCHEMA
))
441 schema
: NETWORK_INTERFACE_NAME_SCHEMA
,
444 type: NetworkInterfaceType
,
447 type: NetworkConfigMethod
,
451 type: NetworkConfigMethod
,
455 schema
: CIDR_V4_SCHEMA
,
459 schema
: CIDR_V6_SCHEMA
,
463 schema
: IP_V4_SCHEMA
,
467 schema
: IP_V6_SCHEMA
,
471 description
: "Option list (inet)",
474 description
: "Optional attribute line.",
479 description
: "Option list (inet6)",
482 description
: "Optional attribute line.",
487 description
: "Comments (inet, may span multiple lines)",
492 description
: "Comments (inet6, may span multiple lines)",
497 schema
: NETWORK_INTERFACE_ARRAY_SCHEMA
,
501 schema
: NETWORK_INTERFACE_ARRAY_SCHEMA
,
509 schema
: NETWORK_INTERFACE_NAME_SCHEMA
,
512 bond_xmit_hash_policy
: {
513 type: BondXmitHashPolicy
,
518 #[derive(Debug, Serialize, Deserialize)]
519 /// Network Interface configuration
520 pub struct Interface
{
521 /// Autostart interface
522 #[serde(rename = "autostart")]
524 /// Interface is active (UP)
529 #[serde(rename = "type")]
530 pub interface_type
: NetworkInterfaceType
,
531 #[serde(skip_serializing_if="Option::is_none")]
532 pub method
: Option
<NetworkConfigMethod
>,
533 #[serde(skip_serializing_if="Option::is_none")]
534 pub method6
: Option
<NetworkConfigMethod
>,
535 #[serde(skip_serializing_if="Option::is_none")]
536 /// IPv4 address with netmask
537 pub cidr
: Option
<String
>,
538 #[serde(skip_serializing_if="Option::is_none")]
540 pub gateway
: Option
<String
>,
541 #[serde(skip_serializing_if="Option::is_none")]
542 /// IPv6 address with netmask
543 pub cidr6
: Option
<String
>,
544 #[serde(skip_serializing_if="Option::is_none")]
546 pub gateway6
: Option
<String
>,
548 #[serde(skip_serializing_if="Vec::is_empty")]
549 pub options
: Vec
<String
>,
550 #[serde(skip_serializing_if="Vec::is_empty")]
551 pub options6
: Vec
<String
>,
553 #[serde(skip_serializing_if="Option::is_none")]
554 pub comments
: Option
<String
>,
555 #[serde(skip_serializing_if="Option::is_none")]
556 pub comments6
: Option
<String
>,
558 #[serde(skip_serializing_if="Option::is_none")]
559 /// Maximum Transmission Unit
560 pub mtu
: Option
<u64>,
562 #[serde(skip_serializing_if="Option::is_none")]
563 pub bridge_ports
: Option
<Vec
<String
>>,
564 /// Enable bridge vlan support.
565 #[serde(skip_serializing_if="Option::is_none")]
566 pub bridge_vlan_aware
: Option
<bool
>,
568 #[serde(skip_serializing_if="Option::is_none")]
569 pub slaves
: Option
<Vec
<String
>>,
570 #[serde(skip_serializing_if="Option::is_none")]
571 pub bond_mode
: Option
<LinuxBondMode
>,
572 #[serde(skip_serializing_if="Option::is_none")]
573 #[serde(rename = "bond-primary")]
574 pub bond_primary
: Option
<String
>,
575 pub bond_xmit_hash_policy
: Option
<BondXmitHashPolicy
>,
581 fn test_cert_fingerprint_schema() -> Result
<(), anyhow
::Error
> {
583 let schema
= CERT_FINGERPRINT_SHA256_SCHEMA
;
585 let invalid_fingerprints
= [
586 "86:88:7c:be:26:77:a5:62:67:d9:06:f5:e4::61:3e:20:dc:cd:43:92:07:7f:fb:65:54:6c:ff:d2:96:36:f8",
587 "88:7C:BE:26:77:a5:62:67:D9:06:f5:e4:14:61:3e:20:dc:cd:43:92:07:7f:fb:65:54:6c:ff:d2:96:36:f8",
588 "86:88:7c:be:26:77:a5:62:67:d9:06:f5:e4::14:61:3e:20:dc:cd:43:92:07:7f:fb:65:54:6c:ff:d2:96:36:f8:ff",
589 "XX:88:7c:be:26:77:a5:62:67:d9:06:f5:e4::14:61:3e:20:dc:cd:43:92:07:7f:fb:65:54:6c:ff:d2:96:36:f8",
590 "86:88:Y4:be:26:77:a5:62:67:d9:06:f5:e4:14:61:3e:20:dc:cd:43:92:07:7f:fb:65:54:6c:ff:d2:96:36:f8",
591 "86:88:0:be:26:77:a5:62:67:d9:06:f5:e4:14:61:3e:20:dc:cd:43:92:07:7f:fb:65:54:6c:ff:d2:96:36:f8",
594 for fingerprint
in invalid_fingerprints
.iter() {
595 if parse_simple_value(fingerprint
, &schema
).is_ok() {
596 bail
!("test fingerprint '{}' failed - got Ok() while exception an error.", fingerprint
);
600 let valid_fingerprints
= [
601 "86:88:7c:be:26:77:a5:62:67:d9:06:f5:e4:14:61:3e:20:dc:cd:43:92:07:7f:fb:65:54:6c:ff:d2:96:36:f8",
602 "86:88:7C:BE:26:77:a5:62:67:D9:06:f5:e4:14:61:3e:20:dc:cd:43:92:07:7f:fb:65:54:6c:ff:d2:96:36:f8",
605 for fingerprint
in valid_fingerprints
.iter() {
606 let v
= match parse_simple_value(fingerprint
, &schema
) {
609 bail
!("unable to parse fingerprint '{}' - {}", fingerprint
, err
);
613 if v
!= serde_json
::json
!(fingerprint
) {
614 bail
!("unable to parse fingerprint '{}' - got wrong value {:?}", fingerprint
, v
);
622 fn test_proxmox_user_id_schema() -> Result
<(), anyhow
::Error
> {
623 let invalid_user_ids
= [
628 "xx x@test", // contains space
629 "xx\nx@test", // contains control character
630 "x:xx@test", // contains collon
631 "xx/x@test", // contains slash
632 "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx@test", // too long
635 for name
in invalid_user_ids
.iter() {
636 if parse_simple_value(name
, &Userid
::API_SCHEMA
).is_ok() {
637 bail
!("test userid '{}' failed - got Ok() while exception an error.", name
);
641 let valid_user_ids
= [
645 "xxx@_T_E_S_T-it.com",
646 "x_x-x.x@test-it.com",
649 for name
in valid_user_ids
.iter() {
650 let v
= match parse_simple_value(name
, &Userid
::API_SCHEMA
) {
653 bail
!("unable to parse userid '{}' - {}", name
, err
);
657 if v
!= serde_json
::json
!(name
) {
658 bail
!("unable to parse userid '{}' - got wrong value {:?}", name
, v
);
666 #[derive(Copy, Clone, Serialize, Deserialize)]
667 #[serde(rename_all = "UPPERCASE")]
678 #[derive(Copy, Clone, Serialize, Deserialize)]
679 #[serde(rename_all = "lowercase")]
680 pub enum RRDTimeFrameResolution
{
681 /// 1 min => last 70 minutes
683 /// 30 min => last 35 hours
685 /// 3 hours => about 8 days
687 /// 12 hours => last 35 days
689 /// 1 week => last 490 days
694 #[derive(Debug, Clone, Serialize, Deserialize)]
695 #[serde(rename_all = "PascalCase")]
696 /// Describes a package for which an update is available.
697 pub struct APTUpdateInfo
{
702 /// Package architecture
704 /// Human readable package description
705 pub description
: String
,
706 /// New version to be updated to
708 /// Old version currently installed
709 pub old_version
: String
,
712 /// Package priority in human-readable form
713 pub priority
: String
,
716 /// URL under which the package's changelog can be retrieved
717 pub change_log_url
: String
,
718 /// Custom extra field for additional package information
719 #[serde(skip_serializing_if="Option::is_none")]
720 pub extra_info
: Option
<String
>,
724 #[derive(Debug, Copy, Clone, PartialEq, Serialize, Deserialize)]
725 #[serde(rename_all = "lowercase")]
726 /// When do we send notifications
728 /// Never send notification
730 /// Send notifications for failed and successful jobs
732 /// Send notifications for failed jobs only
752 #[derive(Debug, Serialize, Deserialize)]
753 /// Datastore notify settings
754 pub struct DatastoreNotify
{
755 /// Garbage collection settings
756 pub gc
: Option
<Notify
>,
757 /// Verify job setting
758 pub verify
: Option
<Notify
>,
760 pub sync
: Option
<Notify
>,
763 pub const DATASTORE_NOTIFY_STRING_SCHEMA
: Schema
= StringSchema
::new(
764 "Datastore notification setting")
765 .format(&ApiStringFormat
::PropertyString(&DatastoreNotify
::API_SCHEMA
))
772 description
: "Estimated time of the next run (UNIX epoch).",
777 description
: "Result of the last run.",
782 description
: "Task UPID of the last run.",
786 "last-run-endtime": {
787 description
: "Endtime of the last run.",
793 #[derive(Serialize,Deserialize,Default)]
794 #[serde(rename_all="kebab-case")]
795 /// Job Scheduling Status
796 pub struct JobScheduleStatus
{
797 #[serde(skip_serializing_if="Option::is_none")]
798 pub next_run
: Option
<i64>,
799 #[serde(skip_serializing_if="Option::is_none")]
800 pub last_run_state
: Option
<String
>,
801 #[serde(skip_serializing_if="Option::is_none")]
802 pub last_run_upid
: Option
<String
>,
803 #[serde(skip_serializing_if="Option::is_none")]
804 pub last_run_endtime
: Option
<i64>,
808 #[derive(Serialize, Deserialize, Default)]
809 #[serde(rename_all = "kebab-case")]
810 /// Node memory usage counters
811 pub struct NodeMemoryCounters
{
821 #[derive(Serialize, Deserialize, Default)]
822 #[serde(rename_all = "kebab-case")]
823 /// Node swap usage counters
824 pub struct NodeSwapCounters
{
834 #[derive(Serialize,Deserialize,Default)]
835 #[serde(rename_all = "kebab-case")]
836 /// Contains general node information such as the fingerprint`
837 pub struct NodeInformation
{
838 /// The SSL Fingerprint
839 pub fingerprint
: String
,
843 #[derive(Serialize, Deserialize, Default)]
844 #[serde(rename_all = "kebab-case")]
845 /// Information about the CPU
846 pub struct NodeCpuInformation
{
849 /// The number of CPU sockets
851 /// The number of CPU cores (incl. threads)
858 type: NodeMemoryCounters
,
864 type: NodeSwapCounters
,
870 description
: "the load",
874 type: NodeCpuInformation
,
877 type: NodeInformation
,
881 #[derive(Serialize, Deserialize, Default)]
882 #[serde(rename_all = "kebab-case")]
884 pub struct NodeStatus
{
885 pub memory
: NodeMemoryCounters
,
886 pub root
: StorageStatus
,
887 pub swap
: NodeSwapCounters
,
888 /// The current uptime of the server.
890 /// Load for 1, 5 and 15 minutes.
891 pub loadavg
: [f64; 3],
892 /// The current kernel version.
893 pub kversion
: String
,
894 /// Total CPU usage since last query.
896 /// Total IO wait since last query.
898 pub cpuinfo
: NodeCpuInformation
,
899 pub info
: NodeInformation
,
902 pub const HTTP_PROXY_SCHEMA
: Schema
= StringSchema
::new(
903 "HTTP proxy configuration [http://]<host>[:port]")
904 .format(&ApiStringFormat
::VerifyFn(|s
| {
905 proxmox_http
::ProxyConfig
::parse_proxy_url(s
)?
;
910 .type_text("[http://]<host>[:port]")