From: Christoph Heiss <c.heiss@proxmox.com>
To: pdm-devel@lists.proxmox.com
Subject: [PATCH datacenter-manager 1/5] config: auto-install: add new options for configuring vlan and bond
Date: Mon, 2 Nov 2026 13:49:33 +0100 [thread overview]
Message-ID: <20261102124939.1023342-2-c.heiss@proxmox.com> (raw)
In-Reply-To: <20261102124939.1023342-1-c.heiss@proxmox.com>
This mostly mirror the the options available from
`proxmox_installer_types::NetworkVlanOptions` and
`proxmox_installer_types::NetworkBondOptions`.
For bonding, an additional, explicit on/off setting is required to
properly keep UI state, and only udev filters are supported, not fixed
member lists.
Signed-off-by: Christoph Heiss <c.heiss@proxmox.com>
---
Cargo.toml | 2 +-
lib/pdm-config/Cargo.toml | 1 +
lib/pdm-config/src/auto_install.rs | 138 +++++++++++++++++++++++++++++
3 files changed, 140 insertions(+), 1 deletion(-)
diff --git a/Cargo.toml b/Cargo.toml
index d9e7dece..b8450a1d 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -68,7 +68,7 @@ proxmox-tfa = { version = "6", features = [ "api-types" ], default-features = fa
proxmox-time = "2"
proxmox-upgrade-checks = "1.1.1"
proxmox-uuid = "1"
-proxmox-installer-types = "0.2"
+proxmox-installer-types = "0.3"
proxmox-network-types = "1.1"
# other proxmox crates
diff --git a/lib/pdm-config/Cargo.toml b/lib/pdm-config/Cargo.toml
index 8c1b46da..af077a62 100644
--- a/lib/pdm-config/Cargo.toml
+++ b/lib/pdm-config/Cargo.toml
@@ -26,6 +26,7 @@ proxmox-sys = { workspace = true, features = [ "acl", "crypt", "timer" ] }
proxmox-acme-api.workspace = true
proxmox-serde.workspace = true
proxmox-installer-types = { workspace = true, features = [ "api-types" ] }
+proxmox-network-api.workspace = true
proxmox-network-types.workspace = true
pdm-api-types.workspace = true
pdm-buildcfg.workspace = true
diff --git a/lib/pdm-config/src/auto_install.rs b/lib/pdm-config/src/auto_install.rs
index 8ac48fb6..ccb9eaa6 100644
--- a/lib/pdm-config/src/auto_install.rs
+++ b/lib/pdm-config/src/auto_install.rs
@@ -38,6 +38,7 @@ pub mod types {
},
};
use proxmox_installer_types::answer::SUBSCRIPTION_KEY_SCHEMA;
+ use proxmox_network_api::{BondXmitHashPolicy, LinuxBondMode};
use proxmox_schema::{ApiStringFormat, ApiType, PropertyString, api};
#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
@@ -124,6 +125,19 @@ pub mod types {
type: String,
optional: true,
},
+ "bond-enabled": {
+ optional: true,
+ },
+ "bond-members-filter": {
+ type: String,
+ optional: true,
+ },
+ "vlan-id": {
+ type: Integer,
+ optional: true,
+ minimum: 2,
+ maximum: 4094,
+ },
filesystem: {
type: String,
},
@@ -256,6 +270,26 @@ pub mod types {
/// Whether to enable network interface name pinning.
pub netif_name_pinning_enabled: bool,
+ /// Whether to enable interface bonding for the management network.
+ #[serde(default)]
+ pub bond_enabled: bool,
+ /// Netdev filter for selecting management network bond members
+ #[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
+ pub bond_members_filter: PropertyString<BTreeMapWrapper<String>>,
+ /// Whether it is enough that any filter matches on a network interface or all given
+ /// filters must match to select an interface as bond member.
+ #[serde(default, skip_serializing_if = "Option::is_none")]
+ pub bond_members_filter_match: Option<answer::FilterMatch>,
+ /// Mode of the management interface bond.
+ #[serde(default, skip_serializing_if = "Option::is_none")]
+ pub bond_mode: Option<LinuxBondMode>,
+ /// Hash policy of the management interface bond.
+ #[serde(default, skip_serializing_if = "Option::is_none")]
+ pub bond_hash_policy: Option<BondXmitHashPolicy>,
+ /// VLAN tag to configure on the management interface.
+ #[serde(default, skip_serializing_if = "Option::is_none")]
+ pub vlan_id: Option<u16>,
+
/// Root filesystem options.
pub filesystem: PropertyString<answer::FilesystemOptions>,
@@ -319,6 +353,12 @@ pub mod types {
dns: conf.dns,
netdev_filter: PropertyString::new(BTreeMapWrapper(conf.netdev_filter)),
netif_name_pinning_enabled: conf.netif_name_pinning_enabled,
+ bond_enabled: conf.bond_enabled,
+ bond_members_filter: PropertyString::new(BTreeMapWrapper(conf.bond_members_filter)),
+ bond_members_filter_match: conf.bond_members_filter_match,
+ bond_mode: conf.bond_mode,
+ bond_hash_policy: conf.bond_hash_policy,
+ vlan_id: conf.vlan_id,
// disk options
filesystem: PropertyString::new(conf.filesystem),
disk_mode: conf.disk_mode,
@@ -372,6 +412,12 @@ pub mod types {
dns: self.dns,
netdev_filter: self.netdev_filter.into_inner().0,
netif_name_pinning_enabled: self.netif_name_pinning_enabled,
+ bond_enabled: self.bond_enabled,
+ bond_members_filter: self.bond_members_filter.into_inner().0,
+ bond_members_filter_match: self.bond_members_filter_match,
+ bond_mode: self.bond_mode,
+ bond_hash_policy: self.bond_hash_policy,
+ vlan_id: self.vlan_id,
// disk options
filesystem: self.filesystem.into_inner(),
disk_mode: self.disk_mode,
@@ -660,3 +706,95 @@ fn write_token_shadow(data: HashMap<String, String>) -> Result<()> {
let raw = serde_json::to_string(&data)?;
replace_config(TOKENS_SHADOW_FILE, raw.as_bytes())
}
+
+#[cfg(test)]
+mod tests {
+ use serde_json::json;
+
+ use super::types::*;
+ use super::*;
+ use pdm_api_types::auto_installer::PreparedInstallationConfig;
+
+ fn prepared_config(extra: serde_json::Value) -> PreparedInstallationConfig {
+ let mut value = json!({
+ "id": "test",
+ "is-default": true,
+ "country": "at",
+ "fqdn": "test.example.com",
+ "use-dhcp-fqdn": false,
+ "keyboard": "en-us",
+ "mailto": "root@example.com",
+ "timezone": "UTC",
+ "reboot-on-error": false,
+ "reboot-mode": "reboot",
+ "use-dhcp-network": false,
+ "cidr": "192.168.100.2/24",
+ "gateway": "192.168.100.1",
+ "dns": "192.168.100.254",
+ "netif-name-pinning-enabled": false,
+ "filesystem": { "filesystem": "ext4" },
+ "disk-mode": "fixed",
+ });
+
+ for (key, v) in extra.as_object().unwrap() {
+ value
+ .as_object_mut()
+ .unwrap()
+ .insert(key.clone(), v.clone());
+ }
+
+ serde_json::from_value(value).unwrap()
+ }
+
+ fn round_trip(conf: PreparedInstallationConfig) -> PreparedInstallationConfig {
+ let mut data: SectionConfigData<PreparedInstallationSectionConfigWrapper> =
+ HashMap::new().into();
+ data.insert(conf.id.clone(), conf.clone().try_into().unwrap());
+
+ let raw = PreparedInstallationSectionConfigWrapper::write_section_config(
+ PREPARED_CONF_FILE,
+ &data,
+ )
+ .unwrap();
+ let parsed = PreparedInstallationSectionConfigWrapper::parse_section_config(
+ PREPARED_CONF_FILE,
+ &raw,
+ )
+ .unwrap();
+
+ match parsed.get(&conf.id).expect("entry survived the round trip") {
+ PreparedInstallationSectionConfigWrapper::PreparedConfig(section) => {
+ section.clone().try_into().unwrap()
+ }
+ }
+ }
+
+ #[test]
+ fn bond_and_vlan_survive_the_config_file_round_trip() {
+ let conf = prepared_config(json!({
+ "bond-members": ["bc:24:11:49:8d:75", "bc:24:11:49:8d:76"],
+ "bond-mode": "802.3ad",
+ "bond-hash-policy": "layer2+3",
+ "vlan-id": 100,
+ }));
+
+ let back = round_trip(conf.clone());
+
+ assert_eq!(conf.bond_members_filter, back.bond_members_filter);
+ assert_eq!(conf.bond_mode, back.bond_mode);
+ assert_eq!(conf.bond_hash_policy, back.bond_hash_policy);
+ assert_eq!(conf.vlan_id, back.vlan_id);
+ assert_eq!(conf, back);
+ }
+
+ #[test]
+ fn absent_bond_and_vlan_stay_absent() {
+ let conf = prepared_config(json!({}));
+ let back = round_trip(conf.clone());
+
+ assert!(back.bond_members_filter.is_empty());
+ assert_eq!(back.bond_mode, None);
+ assert_eq!(back.vlan_id, None);
+ assert_eq!(conf, back);
+ }
+}
--
2.55.0
next prev parent reply other threads:[~2026-11-02 12:50 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-02 12:49 [PATCH datacenter-manager 0/5] auto-install: add support for VLAN and bond configurations Christoph Heiss
2026-11-02 12:49 ` Christoph Heiss [this message]
2026-11-02 12:49 ` [PATCH datacenter-manager 2/5] api-types: auto-installer: add new options for configuring vlan and bond Christoph Heiss
2026-11-02 12:49 ` [PATCH datacenter-manager 3/5] api: auto-installer: wire up new vlan and bond network options Christoph Heiss
2026-11-02 12:49 ` [PATCH datacenter-manager 4/5] ui: auto-installer: use .to_string() instead of manual serde variant Christoph Heiss
2026-11-02 12:49 ` [PATCH datacenter-manager 5/5] ui: auto-installer: add vlan and bond config as advanced options Christoph Heiss
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261102124939.1023342-2-c.heiss@proxmox.com \
--to=c.heiss@proxmox.com \
--cc=pdm-devel@lists.proxmox.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox