From d6c6192c6b77028542a1c1e4256a2e1a15c7900e Mon Sep 17 00:00:00 2001 From: Ian Letourneau Date: Wed, 29 Oct 2025 11:27:20 -0400 Subject: [PATCH] adjust nm config policy serialization --- harmony/src/domain/topology/ha_cluster.rs | 11 ++-- harmony/src/infra/inventory/mod.rs | 2 +- harmony/src/modules/okd/crd/nmstate.rs | 64 +++++++++++++++++++++++ 3 files changed, 70 insertions(+), 7 deletions(-) diff --git a/harmony/src/domain/topology/ha_cluster.rs b/harmony/src/domain/topology/ha_cluster.rs index e16b6d2..d65d9aa 100644 --- a/harmony/src/domain/topology/ha_cluster.rs +++ b/harmony/src/domain/topology/ha_cluster.rs @@ -191,7 +191,7 @@ impl HAClusterTopology { info!("Configuring bond '{bond_name}' for host '{host_name}'..."); let mut bond_mtu: Option = None; - let mut bond_mac_address: Option = None; + let mut copy_mac_from: Option = None; let mut bond_ports = Vec::new(); let mut interfaces: Vec = Vec::new(); @@ -217,14 +217,14 @@ impl HAClusterTopology { ..Default::default() }); - bond_ports.push(interface_name); + bond_ports.push(interface_name.clone()); // Use the first port's details for the bond mtu and mac address if bond_mtu.is_none() { bond_mtu = Some(switch_port.interface.mtu); } - if bond_mac_address.is_none() { - bond_mac_address = Some(switch_port.interface.mac_address.to_string()); + if copy_mac_from.is_none() { + copy_mac_from = Some(interface_name); } } @@ -233,8 +233,7 @@ impl HAClusterTopology { description: Some(format!("Network bond for host {host_name}")), r#type: "bond".to_string(), state: "up".to_string(), - mtu: bond_mtu, - mac_address: bond_mac_address, + copy_mac_from, ipv4: Some(nmstate::IpStackSpec { dhcp: Some(true), enabled: Some(true), diff --git a/harmony/src/infra/inventory/mod.rs b/harmony/src/infra/inventory/mod.rs index 90d78ea..e0d80fe 100644 --- a/harmony/src/infra/inventory/mod.rs +++ b/harmony/src/infra/inventory/mod.rs @@ -11,7 +11,7 @@ pub struct InventoryRepositoryFactory; impl InventoryRepositoryFactory { pub async fn build() -> Result, RepoError> { Ok(Box::new( - SqliteInventoryRepository::new(&(*DATABASE_URL)).await?, + SqliteInventoryRepository::new(&DATABASE_URL).await?, )) } } diff --git a/harmony/src/modules/okd/crd/nmstate.rs b/harmony/src/modules/okd/crd/nmstate.rs index 4fb65c6..9f986e5 100644 --- a/harmony/src/modules/okd/crd/nmstate.rs +++ b/harmony/src/modules/okd/crd/nmstate.rs @@ -51,6 +51,7 @@ pub struct ProbeDns { )] #[serde(rename_all = "camelCase")] pub struct NodeNetworkConfigurationPolicySpec { + #[serde(skip_serializing_if = "Option::is_none")] pub node_selector: Option>, pub desired_state: DesiredStateSpec, } @@ -65,37 +66,64 @@ pub struct DesiredStateSpec { #[serde(rename_all = "kebab-case")] pub struct InterfaceSpec { pub name: String, + #[serde(skip_serializing_if = "Option::is_none")] pub description: Option, pub r#type: String, pub state: String, + #[serde(skip_serializing_if = "Option::is_none")] pub mac_address: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub copy_mac_from: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub mtu: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub controller: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub ipv4: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub ipv6: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub ethernet: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub link_aggregation: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub vlan: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub vxlan: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub mac_vtap: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub mac_vlan: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub infiniband: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub linux_bridge: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub ovs_bridge: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub ethtool: Option, } #[derive(Deserialize, Serialize, Clone, Debug, Default, JsonSchema)] #[serde(rename_all = "kebab-case")] pub struct IpStackSpec { + #[serde(skip_serializing_if = "Option::is_none")] pub enabled: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub dhcp: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub autoconf: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub address: Option>, + #[serde(skip_serializing_if = "Option::is_none")] pub auto_dns: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub auto_gateway: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub auto_routes: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub dhcp_client_id: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub dhcp_duid: Option, } @@ -109,8 +137,11 @@ pub struct IpAddressSpec { #[derive(Deserialize, Serialize, Clone, Debug, Default, JsonSchema)] #[serde(rename_all = "kebab-case")] pub struct EthernetSpec { + #[serde(skip_serializing_if = "Option::is_none")] pub speed: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub duplex: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub auto_negotiation: Option, } @@ -119,6 +150,7 @@ pub struct EthernetSpec { pub struct BondSpec { pub mode: String, pub ports: Vec, + #[serde(skip_serializing_if = "Option::is_none")] pub options: Option>, } @@ -127,6 +159,7 @@ pub struct BondSpec { pub struct VlanSpec { pub base_iface: String, pub id: u16, + #[serde(skip_serializing_if = "Option::is_none")] pub protocol: Option, } @@ -136,8 +169,11 @@ pub struct VxlanSpec { pub base_iface: String, pub id: u32, pub remote: String, + #[serde(skip_serializing_if = "Option::is_none")] pub local: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub learning: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub destination_port: Option, } @@ -146,6 +182,7 @@ pub struct VxlanSpec { pub struct MacVtapSpec { pub base_iface: String, pub mode: String, + #[serde(skip_serializing_if = "Option::is_none")] pub promiscuous: Option, } @@ -154,6 +191,7 @@ pub struct MacVtapSpec { pub struct MacVlanSpec { pub base_iface: String, pub mode: String, + #[serde(skip_serializing_if = "Option::is_none")] pub promiscuous: Option, } @@ -168,25 +206,35 @@ pub struct InfinibandSpec { #[derive(Deserialize, Serialize, Clone, Debug, Default, JsonSchema)] #[serde(rename_all = "kebab-case")] pub struct LinuxBridgeSpec { + #[serde(skip_serializing_if = "Option::is_none")] pub options: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub ports: Option>, } #[derive(Deserialize, Serialize, Clone, Debug, Default, JsonSchema)] #[serde(rename_all = "kebab-case")] pub struct LinuxBridgeOptions { + #[serde(skip_serializing_if = "Option::is_none")] pub mac_ageing_time: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub multicast_snooping: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub stp: Option, } #[derive(Deserialize, Serialize, Clone, Debug, Default, JsonSchema)] #[serde(rename_all = "kebab-case")] pub struct StpOptions { + #[serde(skip_serializing_if = "Option::is_none")] pub enabled: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub forward_delay: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub hello_time: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub max_age: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub priority: Option, } @@ -194,15 +242,20 @@ pub struct StpOptions { #[serde(rename_all = "kebab-case")] pub struct LinuxBridgePort { pub name: String, + #[serde(skip_serializing_if = "Option::is_none")] pub vlan: Option, } #[derive(Deserialize, Serialize, Clone, Debug, Default, JsonSchema)] #[serde(rename_all = "kebab-case")] pub struct LinuxBridgePortVlan { + #[serde(skip_serializing_if = "Option::is_none")] pub mode: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub trunk_tags: Option>, + #[serde(skip_serializing_if = "Option::is_none")] pub tag: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub enable_native: Option, } @@ -210,6 +263,7 @@ pub struct LinuxBridgePortVlan { #[serde(rename_all = "kebab-case")] pub struct VlanTag { pub id: u16, + #[serde(skip_serializing_if = "Option::is_none")] pub id_range: Option, } @@ -223,15 +277,20 @@ pub struct VlanIdRange { #[derive(Deserialize, Serialize, Clone, Debug, Default, JsonSchema)] #[serde(rename_all = "kebab-case")] pub struct OvsBridgeSpec { + #[serde(skip_serializing_if = "Option::is_none")] pub options: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub ports: Option>, } #[derive(Deserialize, Serialize, Clone, Debug, Default, JsonSchema)] #[serde(rename_all = "kebab-case")] pub struct OvsBridgeOptions { + #[serde(skip_serializing_if = "Option::is_none")] pub stp: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub rstp: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub mcast_snooping_enable: Option, } @@ -239,8 +298,11 @@ pub struct OvsBridgeOptions { #[serde(rename_all = "kebab-case")] pub struct OvsPortSpec { pub name: String, + #[serde(skip_serializing_if = "Option::is_none")] pub link_aggregation: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub vlan: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub r#type: Option, } @@ -253,6 +315,8 @@ pub struct EthtoolSpec { #[derive(Deserialize, Serialize, Clone, Debug, Default, JsonSchema)] #[serde(rename_all = "kebab-case")] pub struct EthtoolFecSpec { + #[serde(skip_serializing_if = "Option::is_none")] pub auto: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub mode: Option, }