* [pdm-devel] [PATCH proxmox 3/3] pve-api-types: regenerate
2025-10-21 13:50 [pdm-devel] [PATCH proxmox{, -datacenter-manager} 0/4] generate Vec's for string-lists Hannes Laimer
2025-10-21 13:50 ` [pdm-devel] [PATCH proxmox 1/3] pve-api-types: schema2rust: generate arrays for types with format `-list` Hannes Laimer
2025-10-21 13:50 ` [pdm-devel] [PATCH proxmox 2/3] pve-api-types: add regex for both storage- and bridge-pair Hannes Laimer
@ 2025-10-21 13:50 ` Hannes Laimer
2025-10-21 13:50 ` [pdm-devel] [PATCH proxmox-datacenter-manager 1/1] server: use types indead of string for migration parameters Hannes Laimer
3 siblings, 0 replies; 5+ messages in thread
From: Hannes Laimer @ 2025-10-21 13:50 UTC (permalink / raw)
To: pdm-devel
Signed-off-by: Hannes Laimer <h.laimer@proxmox.com>
---
pve-api-types/src/generated/code.rs | 2 +-
pve-api-types/src/generated/types.rs | 335 ++++++++++++++-------------
2 files changed, 173 insertions(+), 164 deletions(-)
diff --git a/pve-api-types/src/generated/code.rs b/pve-api-types/src/generated/code.rs
index 8b3c6696..788e4bf5 100644
--- a/pve-api-types/src/generated/code.rs
+++ b/pve-api-types/src/generated/code.rs
@@ -900,7 +900,7 @@ where
.maybe_arg("since", &p_since)
.maybe_arg("source", &p_source)
.maybe_arg("start", &p_start)
- .maybe_arg("statusfilter", &p_statusfilter)
+ .maybe_list_arg("statusfilter", &p_statusfilter)
.maybe_arg("typefilter", &p_typefilter)
.maybe_arg("until", &p_until)
.maybe_arg("userfilter", &p_userfilter)
diff --git a/pve-api-types/src/generated/types.rs b/pve-api-types/src/generated/types.rs
index 98cb012b..66177998 100644
--- a/pve-api-types/src/generated/types.rs
+++ b/pve-api-types/src/generated/types.rs
@@ -1027,9 +1027,13 @@ fn test_regex_compilation_5() {
type: String,
},
"isis-ifaces": {
- format: &ApiStringFormat::Pattern(&CREATE_CONTROLLER_ISIS_IFACES_RE),
+ items: {
+ description: "List item of type pve-iface.",
+ format: &ApiStringFormat::Pattern(&CREATE_CONTROLLER_ISIS_IFACES_RE),
+ type: String,
+ },
optional: true,
- type: String,
+ type: Array,
},
"isis-net": {
format: &ApiStringFormat::Pattern(&CREATE_CONTROLLER_ISIS_NET_RE),
@@ -1050,9 +1054,13 @@ fn test_regex_compilation_5() {
type: String,
},
peers: {
- format: &ApiStringFormat::VerifyFn(verifiers::verify_ip),
+ items: {
+ description: "List item of type ip.",
+ format: &ApiStringFormat::VerifyFn(verifiers::verify_ip),
+ type: String,
+ },
optional: true,
- type: String,
+ type: Array,
},
type: {
type: ListControllersType,
@@ -1099,7 +1107,7 @@ pub struct CreateController {
/// Comma-separated list of interfaces where IS-IS should be active.
#[serde(default, skip_serializing_if = "Option::is_none")]
#[serde(rename = "isis-ifaces")]
- pub isis_ifaces: Option<String>,
+ pub isis_ifaces: Option<Vec<String>>,
/// Network Entity title for this node in the IS-IS network.
#[serde(default, skip_serializing_if = "Option::is_none")]
@@ -1121,7 +1129,7 @@ pub struct CreateController {
/// peers address list.
#[serde(default, skip_serializing_if = "Option::is_none")]
- pub peers: Option<String>,
+ pub peers: Option<Vec<String>>,
#[serde(rename = "type")]
pub ty: ListControllersType,
@@ -1381,9 +1389,13 @@ fn test_regex_compilation_6() {
type: Integer,
},
exitnodes: {
- format: &ApiStringFormat::Pattern(&CREATE_ZONE_EXITNODES_RE),
+ items: {
+ description: "List item of type pve-node.",
+ format: &ApiStringFormat::Pattern(&CREATE_ZONE_EXITNODES_RE),
+ type: String,
+ },
optional: true,
- type: String,
+ type: Array,
},
"exitnodes-local-routing": {
default: false,
@@ -1417,23 +1429,35 @@ fn test_regex_compilation_6() {
type: Integer,
},
nodes: {
- format: &ApiStringFormat::Pattern(&CREATE_ZONE_NODES_RE),
+ items: {
+ description: "List item of type pve-node.",
+ format: &ApiStringFormat::Pattern(&CREATE_ZONE_NODES_RE),
+ type: String,
+ },
optional: true,
- type: String,
+ type: Array,
},
peers: {
- format: &ApiStringFormat::VerifyFn(verifiers::verify_ip),
+ items: {
+ description: "List item of type ip.",
+ format: &ApiStringFormat::VerifyFn(verifiers::verify_ip),
+ type: String,
+ },
optional: true,
- type: String,
+ type: Array,
},
reversedns: {
optional: true,
type: String,
},
"rt-import": {
- format: &ApiStringFormat::VerifyFn(verifiers::verify_sdn_bgp_rt),
+ items: {
+ description: "List item of type pve-sdn-bgp-rt.",
+ format: &ApiStringFormat::VerifyFn(verifiers::verify_sdn_bgp_rt),
+ type: String,
+ },
optional: true,
- type: String,
+ type: Array,
},
tag: {
minimum: 0,
@@ -1515,7 +1539,7 @@ pub struct CreateZone {
/// List of cluster node names.
#[serde(default, skip_serializing_if = "Option::is_none")]
- pub exitnodes: Option<String>,
+ pub exitnodes: Option<Vec<String>>,
/// Allow exitnodes to connect to EVPN guests.
#[serde(deserialize_with = "proxmox_serde::perl::deserialize_bool")]
@@ -1552,12 +1576,12 @@ pub struct CreateZone {
/// List of cluster node names.
#[serde(default, skip_serializing_if = "Option::is_none")]
- pub nodes: Option<String>,
+ pub nodes: Option<Vec<String>>,
/// Comma-separated list of peers, that are part of the VXLAN zone. Usually
/// the IPs of the nodes.
#[serde(default, skip_serializing_if = "Option::is_none")]
- pub peers: Option<String>,
+ pub peers: Option<Vec<String>>,
/// reverse dns api server
#[serde(default, skip_serializing_if = "Option::is_none")]
@@ -1566,7 +1590,7 @@ pub struct CreateZone {
/// List of Route Targets that should be imported into the VRF of the zone.
#[serde(default, skip_serializing_if = "Option::is_none")]
#[serde(rename = "rt-import")]
- pub rt_import: Option<String>,
+ pub rt_import: Option<Vec<String>>,
/// Service-VLAN Tag (outer VLAN)
#[serde(deserialize_with = "proxmox_serde::perl::deserialize_u64")]
@@ -1610,101 +1634,6 @@ pub enum IsRunning {
serde_plain::derive_display_from_serialize!(IsRunning);
serde_plain::derive_fromstr_from_deserialize!(IsRunning);
-const LIST_STORAGES_CONTENT: Schema =
- proxmox_schema::ArraySchema::new("list", &StorageContent::API_SCHEMA).schema();
-
-mod list_storages_content {
- use serde::{Deserialize, Deserializer, Serialize, Serializer};
-
- #[doc(hidden)]
- pub trait Ser: Sized {
- fn ser<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error>;
- fn de<'de, D>(deserializer: D) -> Result<Self, D::Error>
- where
- D: Deserializer<'de>;
- }
-
- impl<T: Serialize + for<'a> Deserialize<'a>> Ser for Vec<T> {
- fn ser<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
- where
- S: Serializer,
- {
- super::stringlist::serialize(&self[..], serializer, &super::LIST_STORAGES_CONTENT)
- }
-
- fn de<'de, D>(deserializer: D) -> Result<Self, D::Error>
- where
- D: Deserializer<'de>,
- {
- super::stringlist::deserialize(deserializer, &super::LIST_STORAGES_CONTENT)
- }
- }
-
- impl<T: Ser> Ser for Option<T> {
- fn ser<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
- where
- S: Serializer,
- {
- match self {
- None => serializer.serialize_none(),
- Some(inner) => inner.ser(serializer),
- }
- }
-
- fn de<'de, D>(deserializer: D) -> Result<Self, D::Error>
- where
- D: Deserializer<'de>,
- {
- use std::fmt;
- use std::marker::PhantomData;
-
- struct V<T: Ser>(PhantomData<T>);
-
- impl<'de, T: Ser> serde::de::Visitor<'de> for V<T> {
- type Value = Option<T>;
-
- fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
- f.write_str("an optional string")
- }
-
- fn visit_none<E: serde::de::Error>(self) -> Result<Self::Value, E> {
- Ok(None)
- }
-
- fn visit_some<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
- where
- D: Deserializer<'de>,
- {
- T::de(deserializer).map(Some)
- }
-
- fn visit_str<E: serde::de::Error>(self, value: &str) -> Result<Self::Value, E> {
- use serde::de::IntoDeserializer;
- T::de(value.into_deserializer()).map(Some)
- }
- }
-
- deserializer.deserialize_option(V::<T>(PhantomData))
- }
- }
-
- pub fn serialize<T, S>(this: &T, serializer: S) -> Result<S::Ok, S::Error>
- where
- S: serde::Serializer,
- T: Ser,
- {
- this.ser(serializer)
- }
-
- pub fn deserialize<'de, T, D>(deserializer: D) -> Result<T, D::Error>
- where
- D: serde::Deserializer<'de>,
- T: Ser,
- {
- T::de(deserializer)
- }
-}
-
#[api]
/// Only list sdn controllers of specific type
#[derive(Clone, Copy, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize)]
@@ -1864,9 +1793,13 @@ fn test_regex_compilation_7() {
type: Integer,
},
statusfilter: {
- format: &ApiStringFormat::Pattern(&LIST_TASKS_STATUSFILTER_RE),
+ items: {
+ description: "List item of type pve-task-status-type.",
+ format: &ApiStringFormat::Pattern(&LIST_TASKS_STATUSFILTER_RE),
+ type: String,
+ },
optional: true,
- type: String,
+ type: Array,
},
typefilter: {
optional: true,
@@ -1916,7 +1849,7 @@ pub struct ListTasks {
/// List of Task States that should be returned.
#[serde(default, skip_serializing_if = "Option::is_none")]
- pub statusfilter: Option<String>,
+ pub statusfilter: Option<Vec<String>>,
/// Only list tasks of this type (e.g., vzstart, vzdump).
#[serde(default, skip_serializing_if = "Option::is_none")]
@@ -3450,6 +3383,7 @@ pub struct LxcStatus {
const_regex! {
MIGRATE_LXC_TARGET_RE = r##"^(?i:[a-z0-9](?i:[a-z0-9\-]*[a-z0-9])?)$"##;
+MIGRATE_LXC_TARGET_STORAGE_RE = r##"^(?i:[a-z][a-z0-9\-_.]*[a-z0-9]):(?i:[a-z][a-z0-9\-_.]*[a-z0-9])|(?i:[a-z][a-z0-9\-_.]*[a-z0-9])|1$"##;
}
@@ -3457,6 +3391,7 @@ MIGRATE_LXC_TARGET_RE = r##"^(?i:[a-z0-9](?i:[a-z0-9\-]*[a-z0-9])?)$"##;
fn test_regex_compilation_12() {
use regex::Regex;
let _: &Regex = &MIGRATE_LXC_TARGET_RE;
+ let _: &Regex = &MIGRATE_LXC_TARGET_STORAGE_RE;
}
#[api(
properties: {
@@ -3477,9 +3412,13 @@ fn test_regex_compilation_12() {
type: String,
},
"target-storage": {
- format: &ApiStringFormat::VerifyFn(verifiers::verify_storage_pair),
+ items: {
+ description: "List item of type storage-pair.",
+ format: &ApiStringFormat::Pattern(&MIGRATE_LXC_TARGET_STORAGE_RE),
+ type: String,
+ },
optional: true,
- type: String,
+ type: Array,
},
timeout: {
default: 180,
@@ -3514,7 +3453,7 @@ pub struct MigrateLxc {
/// '1' will map each source storage to itself.
#[serde(default, skip_serializing_if = "Option::is_none")]
#[serde(rename = "target-storage")]
- pub target_storage: Option<String>,
+ pub target_storage: Option<Vec<String>>,
/// Timeout in seconds for shutdown for restart migration
#[serde(deserialize_with = "proxmox_serde::perl::deserialize_i64")]
@@ -3525,6 +3464,7 @@ pub struct MigrateLxc {
const_regex! {
MIGRATE_QEMU_TARGET_RE = r##"^(?i:[a-z0-9](?i:[a-z0-9\-]*[a-z0-9])?)$"##;
+MIGRATE_QEMU_TARGETSTORAGE_RE = r##"^(?i:[a-z][a-z0-9\-_.]*[a-z0-9]):(?i:[a-z][a-z0-9\-_.]*[a-z0-9])|(?i:[a-z][a-z0-9\-_.]*[a-z0-9])|1$"##;
}
@@ -3532,6 +3472,7 @@ MIGRATE_QEMU_TARGET_RE = r##"^(?i:[a-z0-9](?i:[a-z0-9\-]*[a-z0-9])?)$"##;
fn test_regex_compilation_13() {
use regex::Regex;
let _: &Regex = &MIGRATE_QEMU_TARGET_RE;
+ let _: &Regex = &MIGRATE_QEMU_TARGETSTORAGE_RE;
}
#[api(
properties: {
@@ -3562,9 +3503,13 @@ fn test_regex_compilation_13() {
type: String,
},
targetstorage: {
- format: &ApiStringFormat::VerifyFn(verifiers::verify_storage_pair),
+ items: {
+ description: "List item of type storage-pair.",
+ format: &ApiStringFormat::Pattern(&MIGRATE_QEMU_TARGETSTORAGE_RE),
+ type: String,
+ },
optional: true,
- type: String,
+ type: Array,
},
"with-conntrack-state": {
default: false,
@@ -3609,7 +3554,7 @@ pub struct MigrateQemu {
/// ID maps all source storages to that storage. Providing the special value
/// '1' will map each source storage to itself.
#[serde(default, skip_serializing_if = "Option::is_none")]
- pub targetstorage: Option<String>,
+ pub targetstorage: Option<Vec<String>>,
/// Whether to migrate conntrack entries for running VMs.
#[serde(deserialize_with = "proxmox_serde::perl::deserialize_bool")]
@@ -9762,6 +9707,19 @@ pub struct ReloadSdn {
pub release_lock: Option<bool>,
}
+const_regex! {
+
+REMOTE_MIGRATE_LXC_TARGET_BRIDGE_RE = r##"^[-_.\w\d]+:[-_.\w\d]+|[-_.\w\d]+|1$"##;
+REMOTE_MIGRATE_LXC_TARGET_STORAGE_RE = r##"^(?i:[a-z][a-z0-9\-_.]*[a-z0-9]):(?i:[a-z][a-z0-9\-_.]*[a-z0-9])|(?i:[a-z][a-z0-9\-_.]*[a-z0-9])|1$"##;
+
+}
+
+#[test]
+fn test_regex_compilation_26() {
+ use regex::Regex;
+ let _: &Regex = &REMOTE_MIGRATE_LXC_TARGET_BRIDGE_RE;
+ let _: &Regex = &REMOTE_MIGRATE_LXC_TARGET_STORAGE_RE;
+}
#[api(
properties: {
bwlimit: {
@@ -9781,16 +9739,24 @@ pub struct ReloadSdn {
optional: true,
},
"target-bridge": {
- format: &ApiStringFormat::VerifyFn(verifiers::verify_bridge_pair),
- type: String,
+ items: {
+ description: "List item of type bridge-pair.",
+ format: &ApiStringFormat::Pattern(&REMOTE_MIGRATE_LXC_TARGET_BRIDGE_RE),
+ type: String,
+ },
+ type: Array,
},
"target-endpoint": {
format: &ApiStringFormat::PropertyString(&ProxmoxRemote::API_SCHEMA),
type: String,
},
"target-storage": {
- format: &ApiStringFormat::VerifyFn(verifiers::verify_storage_pair),
- type: String,
+ items: {
+ description: "List item of type storage-pair.",
+ format: &ApiStringFormat::Pattern(&REMOTE_MIGRATE_LXC_TARGET_STORAGE_RE),
+ type: String,
+ },
+ type: Array,
},
"target-vmid": {
maximum: 999999999,
@@ -9834,7 +9800,7 @@ pub struct RemoteMigrateLxc {
/// maps all source bridges to that bridge. Providing the special value '1'
/// will map each source bridge to itself.
#[serde(rename = "target-bridge")]
- pub target_bridge: String,
+ pub target_bridge: Vec<String>,
/// Remote target endpoint
#[serde(rename = "target-endpoint")]
@@ -9844,7 +9810,7 @@ pub struct RemoteMigrateLxc {
/// ID maps all source storages to that storage. Providing the special value
/// '1' will map each source storage to itself.
#[serde(rename = "target-storage")]
- pub target_storage: String,
+ pub target_storage: Vec<String>,
/// The (unique) ID of the VM.
#[serde(deserialize_with = "proxmox_serde::perl::deserialize_u32")]
@@ -9858,6 +9824,19 @@ pub struct RemoteMigrateLxc {
pub timeout: Option<i64>,
}
+const_regex! {
+
+REMOTE_MIGRATE_QEMU_TARGET_BRIDGE_RE = r##"^[-_.\w\d]+:[-_.\w\d]+|[-_.\w\d]+|1$"##;
+REMOTE_MIGRATE_QEMU_TARGET_STORAGE_RE = r##"^(?i:[a-z][a-z0-9\-_.]*[a-z0-9]):(?i:[a-z][a-z0-9\-_.]*[a-z0-9])|(?i:[a-z][a-z0-9\-_.]*[a-z0-9])|1$"##;
+
+}
+
+#[test]
+fn test_regex_compilation_27() {
+ use regex::Regex;
+ let _: &Regex = &REMOTE_MIGRATE_QEMU_TARGET_BRIDGE_RE;
+ let _: &Regex = &REMOTE_MIGRATE_QEMU_TARGET_STORAGE_RE;
+}
#[api(
properties: {
bwlimit: {
@@ -9874,16 +9853,24 @@ pub struct RemoteMigrateLxc {
optional: true,
},
"target-bridge": {
- format: &ApiStringFormat::VerifyFn(verifiers::verify_bridge_pair),
- type: String,
+ items: {
+ description: "List item of type bridge-pair.",
+ format: &ApiStringFormat::Pattern(&REMOTE_MIGRATE_QEMU_TARGET_BRIDGE_RE),
+ type: String,
+ },
+ type: Array,
},
"target-endpoint": {
format: &ApiStringFormat::PropertyString(&ProxmoxRemote::API_SCHEMA),
type: String,
},
"target-storage": {
- format: &ApiStringFormat::VerifyFn(verifiers::verify_storage_pair),
- type: String,
+ items: {
+ description: "List item of type storage-pair.",
+ format: &ApiStringFormat::Pattern(&REMOTE_MIGRATE_QEMU_TARGET_STORAGE_RE),
+ type: String,
+ },
+ type: Array,
},
"target-vmid": {
maximum: 999999999,
@@ -9917,7 +9904,7 @@ pub struct RemoteMigrateQemu {
/// maps all source bridges to that bridge. Providing the special value '1'
/// will map each source bridge to itself.
#[serde(rename = "target-bridge")]
- pub target_bridge: String,
+ pub target_bridge: Vec<String>,
/// Remote target endpoint
#[serde(rename = "target-endpoint")]
@@ -9927,7 +9914,7 @@ pub struct RemoteMigrateQemu {
/// ID maps all source storages to that storage. Providing the special value
/// '1' will map each source storage to itself.
#[serde(rename = "target-storage")]
- pub target_storage: String,
+ pub target_storage: Vec<String>,
/// The (unique) ID of the VM.
#[serde(deserialize_with = "proxmox_serde::perl::deserialize_u32")]
@@ -10162,7 +10149,7 @@ SDN_CONTROLLER_ISIS_NET_RE = r##"^[a-fA-F0-9]{2}(\.[a-fA-F0-9]{4}){3,9}\.[a-fA-F
}
#[test]
-fn test_regex_compilation_26() {
+fn test_regex_compilation_28() {
use regex::Regex;
let _: &Regex = &SDN_CONTROLLER_ISIS_IFACES_RE;
let _: &Regex = &SDN_CONTROLLER_ISIS_NET_RE;
@@ -10315,7 +10302,7 @@ SDN_CONTROLLER_PENDING_ISIS_NET_RE = r##"^[a-fA-F0-9]{2}(\.[a-fA-F0-9]{4}){3,9}\
}
#[test]
-fn test_regex_compilation_27() {
+fn test_regex_compilation_29() {
use regex::Regex;
let _: &Regex = &SDN_CONTROLLER_PENDING_ISIS_IFACES_RE;
let _: &Regex = &SDN_CONTROLLER_PENDING_ISIS_NET_RE;
@@ -10610,7 +10597,7 @@ SDN_ZONE_EXITNODES_PRIMARY_RE = r##"^(?i:[a-z0-9](?i:[a-z0-9\-]*[a-z0-9])?)$"##;
}
#[test]
-fn test_regex_compilation_28() {
+fn test_regex_compilation_30() {
use regex::Regex;
let _: &Regex = &SDN_ZONE_EXITNODES_RE;
let _: &Regex = &SDN_ZONE_EXITNODES_PRIMARY_RE;
@@ -10884,7 +10871,7 @@ SDN_ZONE_PENDING_EXITNODES_PRIMARY_RE = r##"^(?i:[a-z0-9](?i:[a-z0-9\-]*[a-z0-9]
}
#[test]
-fn test_regex_compilation_29() {
+fn test_regex_compilation_31() {
use regex::Regex;
let _: &Regex = &SDN_ZONE_PENDING_EXITNODES_RE;
let _: &Regex = &SDN_ZONE_PENDING_EXITNODES_PRIMARY_RE;
@@ -11209,13 +11196,15 @@ pub struct StartLxc {
const_regex! {
START_QEMU_MIGRATEDFROM_RE = r##"^(?i:[a-z0-9](?i:[a-z0-9\-]*[a-z0-9])?)$"##;
+START_QEMU_TARGETSTORAGE_RE = r##"^(?i:[a-z][a-z0-9\-_.]*[a-z0-9]):(?i:[a-z][a-z0-9\-_.]*[a-z0-9])|(?i:[a-z][a-z0-9\-_.]*[a-z0-9])|1$"##;
}
#[test]
-fn test_regex_compilation_30() {
+fn test_regex_compilation_32() {
use regex::Regex;
let _: &Regex = &START_QEMU_MIGRATEDFROM_RE;
+ let _: &Regex = &START_QEMU_TARGETSTORAGE_RE;
}
#[api(
properties: {
@@ -11256,9 +11245,13 @@ fn test_regex_compilation_30() {
type: String,
},
targetstorage: {
- format: &ApiStringFormat::VerifyFn(verifiers::verify_storage_pair),
+ items: {
+ description: "List item of type storage-pair.",
+ format: &ApiStringFormat::Pattern(&START_QEMU_TARGETSTORAGE_RE),
+ type: String,
+ },
optional: true,
- type: String,
+ type: Array,
},
timeout: {
default: 30,
@@ -11316,7 +11309,7 @@ pub struct StartQemu {
/// ID maps all source storages to that storage. Providing the special value
/// '1' will map each source storage to itself.
#[serde(default, skip_serializing_if = "Option::is_none")]
- pub targetstorage: Option<String>,
+ pub targetstorage: Option<Vec<String>>,
/// Wait maximal timeout seconds.
#[serde(deserialize_with = "proxmox_serde::perl::deserialize_u64")]
@@ -11379,7 +11372,7 @@ STOP_QEMU_MIGRATEDFROM_RE = r##"^(?i:[a-z0-9](?i:[a-z0-9\-]*[a-z0-9])?)$"##;
}
#[test]
-fn test_regex_compilation_31() {
+fn test_regex_compilation_33() {
use regex::Regex;
let _: &Regex = &STOP_QEMU_MIGRATEDFROM_RE;
}
@@ -11478,7 +11471,7 @@ STORAGE_INFO_STORAGE_RE = r##"^(?i:[a-z][a-z0-9\-_.]*[a-z0-9])$"##;
}
#[test]
-fn test_regex_compilation_32() {
+fn test_regex_compilation_34() {
use regex::Regex;
let _: &Regex = &STORAGE_INFO_STORAGE_RE;
}
@@ -11756,7 +11749,7 @@ UPDATE_QEMU_CONFIG_VMSTATESTORAGE_RE = r##"^(?i:[a-z][a-z0-9\-_.]*[a-z0-9])$"##;
}
#[test]
-fn test_regex_compilation_33() {
+fn test_regex_compilation_35() {
use regex::Regex;
let _: &Regex = &UPDATE_QEMU_CONFIG_AFFINITY_RE;
let _: &Regex = &UPDATE_QEMU_CONFIG_BOOTDISK_RE;
@@ -11882,9 +11875,13 @@ fn test_regex_compilation_33() {
type: Integer,
},
delete: {
- format: &ApiStringFormat::Pattern(&UPDATE_QEMU_CONFIG_DELETE_RE),
+ items: {
+ description: "List item of type pve-configid.",
+ format: &ApiStringFormat::Pattern(&UPDATE_QEMU_CONFIG_DELETE_RE),
+ type: String,
+ },
optional: true,
- type: String,
+ type: Array,
},
description: {
max_length: 8192,
@@ -11989,9 +11986,13 @@ fn test_regex_compilation_33() {
type: String,
},
nameserver: {
- format: &ApiStringFormat::VerifyFn(verifiers::verify_address),
+ items: {
+ description: "List item of type address.",
+ format: &ApiStringFormat::VerifyFn(verifiers::verify_address),
+ type: String,
+ },
optional: true,
- type: String,
+ type: Array,
},
net: {
type: QemuConfigNetArray,
@@ -12023,9 +12024,13 @@ fn test_regex_compilation_33() {
optional: true,
},
revert: {
- format: &ApiStringFormat::Pattern(&UPDATE_QEMU_CONFIG_REVERT_RE),
+ items: {
+ description: "List item of type pve-configid.",
+ format: &ApiStringFormat::Pattern(&UPDATE_QEMU_CONFIG_REVERT_RE),
+ type: String,
+ },
optional: true,
- type: String,
+ type: Array,
},
rng0: {
format: &ApiStringFormat::PropertyString(&PveQmRng::API_SCHEMA),
@@ -12104,9 +12109,13 @@ fn test_regex_compilation_33() {
optional: true,
},
tags: {
- format: &ApiStringFormat::Pattern(&UPDATE_QEMU_CONFIG_TAGS_RE),
+ items: {
+ description: "List item of type pve-tag.",
+ format: &ApiStringFormat::Pattern(&UPDATE_QEMU_CONFIG_TAGS_RE),
+ type: String,
+ },
optional: true,
- type: String,
+ type: Array,
},
tdf: {
default: false,
@@ -12274,7 +12283,7 @@ pub struct UpdateQemuConfig {
/// A list of settings you want to delete.
#[serde(default, skip_serializing_if = "Option::is_none")]
- pub delete: Option<String>,
+ pub delete: Option<Vec<String>>,
/// Description for the VM. Shown in the web-interface VM's summary. This is
/// saved as comment inside the configuration file.
@@ -12413,7 +12422,7 @@ pub struct UpdateQemuConfig {
/// automatically use the setting from the host if neither searchdomain nor
/// nameserver are set.
#[serde(default, skip_serializing_if = "Option::is_none")]
- pub nameserver: Option<String>,
+ pub nameserver: Option<Vec<String>>,
/// Specify network devices.
#[serde(flatten)]
@@ -12453,7 +12462,7 @@ pub struct UpdateQemuConfig {
/// Revert a pending change.
#[serde(default, skip_serializing_if = "Option::is_none")]
- pub revert: Option<String>,
+ pub revert: Option<Vec<String>>,
/// Configure a VirtIO-based Random Number Generator.
#[serde(default, skip_serializing_if = "Option::is_none")]
@@ -12538,7 +12547,7 @@ pub struct UpdateQemuConfig {
/// Tags of the VM. This is only meta information.
#[serde(default, skip_serializing_if = "Option::is_none")]
- pub tags: Option<String>,
+ pub tags: Option<Vec<String>>,
/// Enable/disable time drift fix.
#[serde(deserialize_with = "proxmox_serde::perl::deserialize_bool")]
@@ -12649,7 +12658,7 @@ UPDATE_QEMU_CONFIG_EFIDISK0_SIZE_RE = r##"^(\d+(\.\d+)?)([KMGT])?$"##;
}
#[test]
-fn test_regex_compilation_34() {
+fn test_regex_compilation_36() {
use regex::Regex;
let _: &Regex = &UPDATE_QEMU_CONFIG_EFIDISK0_SIZE_RE;
}
@@ -12726,7 +12735,7 @@ UPDATE_QEMU_CONFIG_IDE_SIZE_RE = r##"^(\d+(\.\d+)?)([KMGT])?$"##;
}
#[test]
-fn test_regex_compilation_35() {
+fn test_regex_compilation_37() {
use regex::Regex;
let _: &Regex = &UPDATE_QEMU_CONFIG_IDE_MODEL_RE;
let _: &Regex = &UPDATE_QEMU_CONFIG_IDE_SERIAL_RE;
@@ -13082,7 +13091,7 @@ UPDATE_QEMU_CONFIG_SATA_SIZE_RE = r##"^(\d+(\.\d+)?)([KMGT])?$"##;
}
#[test]
-fn test_regex_compilation_36() {
+fn test_regex_compilation_38() {
use regex::Regex;
let _: &Regex = &UPDATE_QEMU_CONFIG_SATA_SERIAL_RE;
let _: &Regex = &UPDATE_QEMU_CONFIG_SATA_SIZE_RE;
@@ -13427,7 +13436,7 @@ UPDATE_QEMU_CONFIG_SCSI_SIZE_RE = r##"^(\d+(\.\d+)?)([KMGT])?$"##;
}
#[test]
-fn test_regex_compilation_37() {
+fn test_regex_compilation_39() {
use regex::Regex;
let _: &Regex = &UPDATE_QEMU_CONFIG_SCSI_SERIAL_RE;
let _: &Regex = &UPDATE_QEMU_CONFIG_SCSI_SIZE_RE;
@@ -13827,7 +13836,7 @@ UPDATE_QEMU_CONFIG_TPMSTATE0_SIZE_RE = r##"^(\d+(\.\d+)?)([KMGT])?$"##;
}
#[test]
-fn test_regex_compilation_38() {
+fn test_regex_compilation_40() {
use regex::Regex;
let _: &Regex = &UPDATE_QEMU_CONFIG_TPMSTATE0_SIZE_RE;
}
@@ -13883,7 +13892,7 @@ UPDATE_QEMU_CONFIG_VIRTIO_SIZE_RE = r##"^(\d+(\.\d+)?)([KMGT])?$"##;
}
#[test]
-fn test_regex_compilation_39() {
+fn test_regex_compilation_41() {
use regex::Regex;
let _: &Regex = &UPDATE_QEMU_CONFIG_VIRTIO_SERIAL_RE;
let _: &Regex = &UPDATE_QEMU_CONFIG_VIRTIO_SIZE_RE;
--
2.47.3
_______________________________________________
pdm-devel mailing list
pdm-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pdm-devel
^ permalink raw reply [flat|nested] 5+ messages in thread
* [pdm-devel] [PATCH proxmox-datacenter-manager 1/1] server: use types indead of string for migration parameters
2025-10-21 13:50 [pdm-devel] [PATCH proxmox{, -datacenter-manager} 0/4] generate Vec's for string-lists Hannes Laimer
` (2 preceding siblings ...)
2025-10-21 13:50 ` [pdm-devel] [PATCH proxmox 3/3] pve-api-types: regenerate Hannes Laimer
@ 2025-10-21 13:50 ` Hannes Laimer
3 siblings, 0 replies; 5+ messages in thread
From: Hannes Laimer @ 2025-10-21 13:50 UTC (permalink / raw)
To: pdm-devel
This is specifically about target-storage and target-bridge, these were
strings, but are now actaul Vec's with mappings as items. Since
pve-api-types now generates Vec's instead of Strings for list parameters
we can directly use the type.
Signed-off-by: Hannes Laimer <h.laimer@proxmox.com>
---
server/src/api/pve/lxc.rs | 133 ++++++++----------------------------
server/src/api/pve/qemu.rs | 135 ++++++++-----------------------------
2 files changed, 56 insertions(+), 212 deletions(-)
diff --git a/server/src/api/pve/lxc.rs b/server/src/api/pve/lxc.rs
index 83f9f4a..61db8ff 100644
--- a/server/src/api/pve/lxc.rs
+++ b/server/src/api/pve/lxc.rs
@@ -288,29 +288,10 @@ pub async fn lxc_shutdown(
schema: NODE_SCHEMA,
optional: true,
},
- target: { schema: NODE_SCHEMA },
vmid: { schema: VMID_SCHEMA },
- online: {
- type: bool,
- description: "Attempt an online migration if the container is running.",
- optional: true,
- },
- restart: {
- type: bool,
- description: "Perform a restart-migration if the container is running.",
- optional: true,
- },
- "target-storage": {
- description: "Mapping of source storages to target storages.",
- optional: true,
- },
- bwlimit: {
- description: "Override I/O bandwidth limit (in KiB/s).",
- optional: true,
- },
- timeout: {
- description: "Shutdown timeout for restart-migrations.",
- optional: true,
+ migrate: {
+ type: pve_api_types::MigrateLxc,
+ flatten: true,
},
},
},
@@ -327,35 +308,23 @@ pub async fn lxc_migrate(
remote: String,
node: Option<String>,
vmid: u32,
- bwlimit: Option<u64>,
- restart: Option<bool>,
- online: Option<bool>,
- target: String,
- target_storage: Option<String>,
- timeout: Option<i64>,
+ migrate: pve_api_types::MigrateLxc,
) -> Result<RemoteUpid, Error> {
- let bwlimit = bwlimit.map(|n| n as f64);
-
- log::info!("in-cluster migration requested for remote {remote:?} ct {vmid} to node {target:?}");
+ log::info!(
+ "in-cluster migration requested for remote {remote:?} ct {vmid} to node {:?}",
+ migrate.target
+ );
let (remotes, _) = pdm_config::remotes::config()?;
let pve = connect_to_remote(&remotes, &remote)?;
let node = find_node_for_vm(node, vmid, pve.as_ref()).await?;
- if node == target {
+ if node == migrate.target {
bail!("refusing migration to the same node");
}
- let params = pve_api_types::MigrateLxc {
- bwlimit,
- online,
- restart,
- target,
- target_storage,
- timeout,
- };
- let upid = pve.migrate_lxc(&node, vmid, params).await?;
+ let upid = pve.migrate_lxc(&node, vmid, migrate).await?;
new_remote_upid(remote, upid).await
}
@@ -370,44 +339,10 @@ pub async fn lxc_migrate(
optional: true,
},
vmid: { schema: VMID_SCHEMA },
- "target-vmid": {
- optional: true,
- schema: VMID_SCHEMA,
- },
- delete: {
- description: "Delete the original VM and related data after successful migration.",
- optional: true,
- default: false,
- },
- online: {
- type: bool,
- description: "Perform an online migration if the vm is running.",
- optional: true,
- default: false,
- },
- "target-storage": {
- description: "Mapping of source storages to target storages.",
- },
- "target-bridge": {
- description: "Mapping of source bridges to remote bridges.",
- },
- bwlimit: {
- description: "Override I/O bandwidth limit (in KiB/s).",
- optional: true,
- },
- restart: {
- description: "Perform a restart-migration.",
- optional: true,
- },
- timeout: {
- description: "Add a shutdown timeout for the restart-migration.",
- optional: true,
- },
// TODO better to change remote migration to proxy to node?
- "target-endpoint": {
- type: String,
- optional: true,
- description: "The target endpoint to use for the connection.",
+ remote_migrate: {
+ type: pve_api_types::RemoteMigrateLxc,
+ flatten: true,
},
},
},
@@ -425,15 +360,7 @@ pub async fn lxc_remote_migrate(
target: String, // this is the destination remote name
node: Option<String>,
vmid: u32,
- target_vmid: Option<u32>,
- delete: bool,
- online: bool,
- target_storage: String,
- target_bridge: String,
- bwlimit: Option<u64>,
- restart: Option<bool>,
- timeout: Option<i64>,
- target_endpoint: Option<String>,
+ remote_migrate: pve_api_types::RemoteMigrateLxc,
rpcenv: &mut dyn RpcEnvironment,
) -> Result<RemoteUpid, Error> {
let user_info = CachedUserInfo::new()?;
@@ -447,7 +374,7 @@ pub async fn lxc_remote_migrate(
"resource",
&target,
"guest",
- &target_vmid.unwrap_or(vmid).to_string(),
+ &remote_migrate.target_vmid.unwrap_or(vmid).to_string(),
],
);
if target_privs & PRIV_RESOURCE_MIGRATE == 0 {
@@ -456,7 +383,7 @@ pub async fn lxc_remote_migrate(
"missing PRIV_RESOURCE_MIGRATE on target remote+vmid"
);
}
- if delete {
+ if remote_migrate.delete.unwrap_or_default() {
check_guest_delete_perms(rpcenv, &remote, vmid)?;
}
@@ -477,14 +404,17 @@ pub async fn lxc_remote_migrate(
// FIXME: For now we'll only try with the first node but we should probably try others, too, in
// case some are offline?
+ // TODO: target_endpoint optional? if single node i guess
let target_node = target
.nodes
.iter()
- .find(|endpoint| match target_endpoint.as_deref() {
- Some(target) => target == endpoint.hostname,
- None => true,
- })
- .ok_or_else(|| match target_endpoint {
+ .find(
+ |endpoint| match Some(remote_migrate.target_endpoint.clone()).as_deref() {
+ Some(target) => target == endpoint.hostname,
+ None => true,
+ },
+ )
+ .ok_or_else(|| match Some(remote_migrate.target_endpoint.clone()) {
Some(endpoint) => format_err!("{endpoint} not configured for target cluster"),
None => format_err!("no nodes configured for target cluster"),
})?;
@@ -504,19 +434,10 @@ pub async fn lxc_remote_migrate(
}
log::info!("forwarding remote migration requested");
- let params = pve_api_types::RemoteMigrateLxc {
- target_bridge,
- target_storage,
- delete: Some(delete),
- online: Some(online),
- target_vmid,
- target_endpoint,
- bwlimit: bwlimit.map(|limit| limit as f64),
- restart,
- timeout,
- };
log::info!("migrating vm {vmid} of node {node:?}");
- let upid = source_conn.remote_migrate_lxc(&node, vmid, params).await?;
+ let upid = source_conn
+ .remote_migrate_lxc(&node, vmid, remote_migrate)
+ .await?;
new_remote_upid(source, upid).await
}
diff --git a/server/src/api/pve/qemu.rs b/server/src/api/pve/qemu.rs
index 54ede11..6158bef 100644
--- a/server/src/api/pve/qemu.rs
+++ b/server/src/api/pve/qemu.rs
@@ -10,11 +10,11 @@ use proxmox_sortable_macro::sortable;
use pdm_api_types::remotes::REMOTE_ID_SCHEMA;
use pdm_api_types::{
- Authid, ConfigurationState, RemoteUpid, CIDR_FORMAT, NODE_SCHEMA, PRIV_RESOURCE_AUDIT,
- PRIV_RESOURCE_MANAGE, PRIV_RESOURCE_MIGRATE, SNAPSHOT_NAME_SCHEMA, VMID_SCHEMA,
+ Authid, ConfigurationState, RemoteUpid, NODE_SCHEMA, PRIV_RESOURCE_AUDIT, PRIV_RESOURCE_MANAGE,
+ PRIV_RESOURCE_MIGRATE, SNAPSHOT_NAME_SCHEMA, VMID_SCHEMA,
};
-use pve_api_types::{QemuMigratePreconditions, StartQemuMigrationType};
+use pve_api_types::QemuMigratePreconditions;
use crate::api::pve::get_remote;
@@ -297,37 +297,9 @@ pub async fn qemu_shutdown(
},
target: { schema: NODE_SCHEMA },
vmid: { schema: VMID_SCHEMA },
- online: {
- type: bool,
- description: "Perform an online migration if the vm is running.",
- optional: true,
- },
- "target-storage": {
- description: "Mapping of source storages to target storages.",
- optional: true,
- },
- bwlimit: {
- description: "Override I/O bandwidth limit (in KiB/s).",
- optional: true,
- },
- "migration-network": {
- description: "CIDR of the (sub) network that is used for migration.",
- type: String,
- format: &CIDR_FORMAT,
- optional: true,
- },
- "migration-type": {
- type: StartQemuMigrationType,
- optional: true,
- },
- force: {
- description: "Allow to migrate VMs with local devices.",
- optional: true,
- default: false,
- },
- "with-local-disks": {
- description: "Enable live storage migration for local disks.",
- optional: true,
+ migrate: {
+ type: pve_api_types::MigrateQemu,
+ flatten: true,
},
},
},
@@ -344,38 +316,23 @@ pub async fn qemu_migrate(
remote: String,
node: Option<String>,
vmid: u32,
- bwlimit: Option<u64>,
- force: Option<bool>,
- migration_network: Option<String>,
- migration_type: Option<StartQemuMigrationType>,
- online: Option<bool>,
- target: String,
- target_storage: Option<String>,
- with_local_disks: Option<bool>,
+ migrate: pve_api_types::MigrateQemu,
) -> Result<RemoteUpid, Error> {
- log::info!("in-cluster migration requested for remote {remote:?} vm {vmid} to node {target:?}");
+ log::info!(
+ "in-cluster migration requested for remote {remote:?} vm {vmid} to node {:?}",
+ migrate.target
+ );
let (remotes, _) = pdm_config::remotes::config()?;
let pve = connect_to_remote(&remotes, &remote)?;
let node = find_node_for_vm(node, vmid, pve.as_ref()).await?;
- if node == target {
+ if node == migrate.target {
bail!("refusing migration to the same node");
}
- let params = pve_api_types::MigrateQemu {
- bwlimit,
- force,
- migration_network,
- migration_type,
- online,
- target,
- targetstorage: target_storage,
- with_local_disks,
- with_conntrack_state: None,
- };
- let upid = pve.migrate_qemu(&node, vmid, params).await?;
+ let upid = pve.migrate_qemu(&node, vmid, migrate).await?;
new_remote_upid(remote, upid).await
}
@@ -431,32 +388,9 @@ async fn qemu_migrate_preconditions(
optional: true,
schema: VMID_SCHEMA,
},
- delete: {
- description: "Delete the original VM and related data after successful migration.",
- optional: true,
- default: false,
- },
- online: {
- type: bool,
- description: "Perform an online migration if the vm is running.",
- optional: true,
- default: false,
- },
- "target-storage": {
- description: "Mapping of source storages to target storages.",
- },
- "target-bridge": {
- description: "Mapping of source bridges to remote bridges.",
- },
- bwlimit: {
- description: "Override I/O bandwidth limit (in KiB/s).",
- optional: true,
- },
- // TODO better to change remote migration to proxy to node?
- "target-endpoint": {
- type: String,
- optional: true,
- description: "The target endpoint to use for the connection.",
+ remote_migrate: {
+ type: pve_api_types::RemoteMigrateQemu,
+ flatten: true,
},
},
},
@@ -474,13 +408,7 @@ pub async fn qemu_remote_migrate(
target: String, // this is the destination remote name
node: Option<String>,
vmid: u32,
- target_vmid: Option<u32>,
- delete: bool,
- online: bool,
- target_storage: String,
- target_bridge: String,
- bwlimit: Option<u64>,
- target_endpoint: Option<String>,
+ remote_migrate: pve_api_types::RemoteMigrateQemu,
rpcenv: &mut dyn RpcEnvironment,
) -> Result<RemoteUpid, Error> {
let user_info = CachedUserInfo::new()?;
@@ -494,7 +422,7 @@ pub async fn qemu_remote_migrate(
"resource",
&target,
"guest",
- &target_vmid.unwrap_or(vmid).to_string(),
+ &remote_migrate.target_vmid.unwrap_or(vmid).to_string(),
],
);
if target_privs & PRIV_RESOURCE_MIGRATE == 0 {
@@ -504,7 +432,7 @@ pub async fn qemu_remote_migrate(
);
}
- if delete {
+ if remote_migrate.delete.unwrap_or_default() {
check_guest_delete_perms(rpcenv, &remote, vmid)?;
}
@@ -528,11 +456,13 @@ pub async fn qemu_remote_migrate(
let target_node = target
.nodes
.iter()
- .find(|endpoint| match target_endpoint.as_deref() {
- Some(target) => target == endpoint.hostname,
- None => true,
- })
- .ok_or_else(|| match target_endpoint {
+ .find(
+ |endpoint| match Some(remote_migrate.target_endpoint.clone()).as_deref() {
+ Some(target) => target == endpoint.hostname,
+ None => true,
+ },
+ )
+ .ok_or_else(|| match Some(remote_migrate.target_endpoint.clone()) {
Some(endpoint) => format_err!("{endpoint} not configured for target cluster"),
None => format_err!("no nodes configured for target cluster"),
})?;
@@ -552,17 +482,10 @@ pub async fn qemu_remote_migrate(
}
log::info!("forwarding remote migration requested");
- let params = pve_api_types::RemoteMigrateQemu {
- target_bridge,
- target_storage,
- delete: Some(delete),
- online: Some(online),
- target_vmid,
- target_endpoint,
- bwlimit,
- };
log::info!("migrating vm {vmid} of node {node:?}");
- let upid = source_conn.remote_migrate_qemu(&node, vmid, params).await?;
+ let upid = source_conn
+ .remote_migrate_qemu(&node, vmid, remote_migrate)
+ .await?;
new_remote_upid(source, upid).await
}
--
2.47.3
_______________________________________________
pdm-devel mailing list
pdm-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pdm-devel
^ permalink raw reply [flat|nested] 5+ messages in thread