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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.