Use the newly created WireGuard section types to add the WireGuard
variants to the existing fabrics section config enum. By adding the
new WireGuard variants, they are automatically exposed via the API
methods defined in proxmox-perl-rs and are available for the existing
CRUD endpoints in pve-network.

Originally-by: Christoph Heiss <[email protected]>
Signed-off-by: Stefan Hanreich <[email protected]>
---
 proxmox-ve-config/src/sdn/fabric/frr.rs       |   1 +
 proxmox-ve-config/src/sdn/fabric/mod.rs       | 168 ++++++++++++++++++
 .../src/sdn/fabric/section_config/fabric.rs   |  25 +++
 .../src/sdn/fabric/section_config/mod.rs      |  58 ++++++
 .../src/sdn/fabric/section_config/node.rs     |  44 ++++-
 5 files changed, 292 insertions(+), 4 deletions(-)

diff --git a/proxmox-ve-config/src/sdn/fabric/frr.rs 
b/proxmox-ve-config/src/sdn/fabric/frr.rs
index 10025b3..fc41410 100644
--- a/proxmox-ve-config/src/sdn/fabric/frr.rs
+++ b/proxmox-ve-config/src/sdn/fabric/frr.rs
@@ -232,6 +232,7 @@ pub fn build_fabric(
 
                 frr_config.protocol_routemaps.insert(protocol_routemap);
             }
+            FabricEntry::WireGuard(_) => {} // not a frr fabric
         }
     }
     Ok(())
diff --git a/proxmox-ve-config/src/sdn/fabric/mod.rs 
b/proxmox-ve-config/src/sdn/fabric/mod.rs
index d0add92..53ce87f 100644
--- a/proxmox-ve-config/src/sdn/fabric/mod.rs
+++ b/proxmox-ve-config/src/sdn/fabric/mod.rs
@@ -7,6 +7,7 @@ use std::marker::PhantomData;
 use std::ops::Deref;
 
 use anyhow::Error;
+use section_config::protocol::wireguard::WireGuardProperties;
 use serde::{Deserialize, Serialize};
 
 use proxmox_section_config::typed::{ApiSectionDataEntry, SectionConfigData};
@@ -28,6 +29,10 @@ use crate::sdn::fabric::section_config::protocol::ospf::{
     OspfDeletableProperties, OspfNodeDeletableProperties, OspfNodeProperties,
     OspfNodePropertiesUpdater, OspfProperties, OspfPropertiesUpdater,
 };
+use crate::sdn::fabric::section_config::protocol::wireguard::{
+    WireGuardDeletableProperties, WireGuardNode, 
WireGuardNodeDeletableProperties,
+    WireGuardNodeUpdater, WireGuardPropertiesUpdater,
+};
 use crate::sdn::fabric::section_config::{FabricOrNode, Section};
 
 #[derive(thiserror::Error, Debug)]
@@ -189,6 +194,7 @@ macro_rules! impl_entry {
 
 impl_entry!(Openfabric, OpenfabricProperties, OpenfabricNodeProperties);
 impl_entry!(Ospf, OspfProperties, OspfNodeProperties);
+impl_entry!(WireGuard, WireGuardProperties, WireGuardNode);
 
 /// All possible entries in a [`FabricConfig`].
 ///
@@ -198,6 +204,7 @@ impl_entry!(Ospf, OspfProperties, OspfNodeProperties);
 pub enum FabricEntry {
     Openfabric(Entry<OpenfabricProperties, OpenfabricNodeProperties>),
     Ospf(Entry<OspfProperties, OspfNodeProperties>),
+    WireGuard(Entry<WireGuardProperties, WireGuardNode>),
 }
 
 impl FabricEntry {
@@ -209,6 +216,9 @@ impl FabricEntry {
                 entry.add_node(node_section)
             }
             (FabricEntry::Ospf(entry), Node::Ospf(node_section)) => 
entry.add_node(node_section),
+            (FabricEntry::WireGuard(entry), Node::WireGuard(node_section)) => {
+                entry.add_node(node_section)
+            }
             _ => Err(FabricConfigError::ProtocolMismatch),
         }
     }
@@ -219,6 +229,7 @@ impl FabricEntry {
         match self {
             FabricEntry::Openfabric(entry) => entry.get_node(id),
             FabricEntry::Ospf(entry) => entry.get_node(id),
+            FabricEntry::WireGuard(entry) => entry.get_node(id),
         }
     }
 
@@ -228,6 +239,7 @@ impl FabricEntry {
         match self {
             FabricEntry::Openfabric(entry) => entry.get_node_mut(id),
             FabricEntry::Ospf(entry) => entry.get_node_mut(id),
+            FabricEntry::WireGuard(entry) => entry.get_node_mut(id),
         }
     }
 
@@ -307,6 +319,109 @@ impl FabricEntry {
 
                 Ok(())
             }
+            (Node::WireGuard(node_section), NodeUpdater::WireGuard(updater)) 
=> {
+                let NodeDataUpdater::<WireGuardNodeUpdater, 
WireGuardNodeDeletableProperties> {
+                    ip,
+                    ip6,
+                    properties,
+                    delete,
+                } = updater;
+
+                if let Some(ip) = ip {
+                    node_section.ip = Some(ip);
+                }
+
+                if let Some(ip) = ip6 {
+                    node_section.ip6 = Some(ip);
+                }
+
+                for property in &delete {
+                    match property {
+                        NodeDeletableProperties::Ip => node_section.ip = None,
+                        NodeDeletableProperties::Ip6 => node_section.ip6 = 
None,
+                        // handled below, since internal / external nodes have 
different properties
+                        NodeDeletableProperties::Protocol(_) => continue,
+                    }
+                }
+
+                match (node_section.properties_mut(), properties) {
+                    (
+                        WireGuardNode::Internal(internal_wireguard_node),
+                        
WireGuardNodeUpdater::Internal(internal_wireguard_node_updater),
+                    ) => {
+                        if let Some(interfaces) = 
internal_wireguard_node_updater.interfaces {
+                            internal_wireguard_node.interfaces = interfaces;
+                        }
+
+                        if let Some(endpoint) = 
internal_wireguard_node_updater.endpoint {
+                            internal_wireguard_node.endpoint = Some(endpoint);
+                        }
+
+                        if let Some(peers) = 
internal_wireguard_node_updater.peers {
+                            internal_wireguard_node.peers = peers;
+                        }
+
+                        if let Some(allowed_ips) = 
internal_wireguard_node_updater.allowed_ips {
+                            internal_wireguard_node.allowed_ips = allowed_ips;
+                        }
+
+                        for property in &delete {
+                            match property {
+                                
NodeDeletableProperties::Protocol(protocol_property) => {
+                                    match protocol_property {
+                                        
WireGuardNodeDeletableProperties::Interfaces => {
+                                            internal_wireguard_node.interfaces 
= Vec::new()
+                                        }
+                                        
WireGuardNodeDeletableProperties::Endpoint => {
+                                            internal_wireguard_node.endpoint = 
None
+                                        }
+                                        
WireGuardNodeDeletableProperties::Peers => {
+                                            internal_wireguard_node.peers = 
Vec::new()
+                                        }
+                                        
WireGuardNodeDeletableProperties::AllowedIps => {
+                                            
internal_wireguard_node.allowed_ips = Vec::new()
+                                        }
+                                    }
+                                }
+                                _ => continue,
+                            }
+                        }
+                    }
+                    (
+                        WireGuardNode::External(external_wire_guard_node),
+                        
WireGuardNodeUpdater::External(external_wire_guard_node_updater),
+                    ) => {
+                        if let Some(endpoint) = 
external_wire_guard_node_updater.endpoint {
+                            external_wire_guard_node.endpoint = endpoint;
+                        }
+
+                        if let Some(public_key) = 
external_wire_guard_node_updater.public_key {
+                            external_wire_guard_node.public_key = public_key;
+                        }
+
+                        if let Some(allowed_ips) = 
external_wire_guard_node_updater.allowed_ips {
+                            external_wire_guard_node.allowed_ips = allowed_ips;
+                        }
+
+                        for property in &delete {
+                            match property {
+                                
NodeDeletableProperties::Protocol(protocol_property) => {
+                                    match protocol_property {
+                                        
WireGuardNodeDeletableProperties::AllowedIps => {
+                                            
external_wire_guard_node.allowed_ips = Vec::new()
+                                        }
+                                        _ => return 
Err(FabricConfigError::ProtocolMismatch),
+                                    }
+                                }
+                                _ => continue,
+                            }
+                        }
+                    }
+                    _ => return Err(FabricConfigError::ProtocolMismatch),
+                }
+
+                Ok(())
+            }
             _ => Err(FabricConfigError::ProtocolMismatch),
         }
     }
@@ -316,6 +431,7 @@ impl FabricEntry {
         match self {
             FabricEntry::Openfabric(entry) => entry.nodes.iter(),
             FabricEntry::Ospf(entry) => entry.nodes.iter(),
+            FabricEntry::WireGuard(entry) => entry.nodes.iter(),
         }
     }
 
@@ -324,6 +440,7 @@ impl FabricEntry {
         match self {
             FabricEntry::Openfabric(entry) => entry.delete_node(id),
             FabricEntry::Ospf(entry) => entry.delete_node(id),
+            FabricEntry::WireGuard(entry) => entry.delete_node(id),
         }
     }
 
@@ -333,6 +450,7 @@ impl FabricEntry {
         match self {
             FabricEntry::Openfabric(entry) => entry.into_pair(),
             FabricEntry::Ospf(entry) => entry.into_pair(),
+            FabricEntry::WireGuard(entry) => entry.into_pair(),
         }
     }
 
@@ -341,6 +459,7 @@ impl FabricEntry {
         match self {
             FabricEntry::Openfabric(entry) => &entry.fabric,
             FabricEntry::Ospf(entry) => &entry.fabric,
+            FabricEntry::WireGuard(entry) => &entry.fabric,
         }
     }
 
@@ -349,6 +468,7 @@ impl FabricEntry {
         match self {
             FabricEntry::Openfabric(entry) => &mut entry.fabric,
             FabricEntry::Ospf(entry) => &mut entry.fabric,
+            FabricEntry::WireGuard(entry) => &mut entry.fabric,
         }
     }
 }
@@ -360,6 +480,7 @@ impl From<Fabric> for FabricEntry {
                 FabricEntry::Openfabric(Entry::new(fabric_section))
             }
             Fabric::Ospf(fabric_section) => 
FabricEntry::Ospf(Entry::new(fabric_section)),
+            Fabric::WireGuard(fabric_section) => 
FabricEntry::WireGuard(Entry::new(fabric_section)),
         }
     }
 }
@@ -541,6 +662,9 @@ impl Validatable for FabricConfig {
                             return Err(FabricConfigError::DuplicateInterface);
                         }
                     }
+                    Node::WireGuard(_node_section) => {
+                        return Ok(());
+                    }
                 }
             }
 
@@ -695,6 +819,50 @@ impl FabricConfig {
 
                 Ok(())
             }
+            (Fabric::WireGuard(fabric_section), 
FabricUpdater::WireGuard(updater)) => {
+                let FabricSectionUpdater::<
+                    WireGuardPropertiesUpdater,
+                    WireGuardDeletableProperties,
+                > {
+                    ip_prefix,
+                    ip6_prefix,
+                    properties:
+                        WireGuardPropertiesUpdater {
+                            persistent_keepalive,
+                        },
+                    delete,
+                } = updater;
+
+                if let Some(prefix) = ip_prefix {
+                    fabric_section.ip_prefix = Some(prefix);
+                }
+
+                if let Some(prefix) = ip6_prefix {
+                    fabric_section.ip6_prefix = Some(prefix);
+                }
+
+                if let Some(keepalive) = persistent_keepalive {
+                    fabric_section.properties.persistent_keepalive = 
Some(keepalive);
+                }
+
+                for property in delete {
+                    match property {
+                        FabricDeletableProperties::IpPrefix => {
+                            fabric_section.ip_prefix = None;
+                        }
+                        FabricDeletableProperties::Ip6Prefix => {
+                            fabric_section.ip6_prefix = None;
+                        }
+                        FabricDeletableProperties::Protocol(
+                            WireGuardDeletableProperties::PersistentKeepalive,
+                        ) => {
+                            fabric_section.properties.persistent_keepalive = 
None;
+                        }
+                    }
+                }
+
+                Ok(())
+            }
             _ => Err(FabricConfigError::ProtocolMismatch),
         }
     }
diff --git a/proxmox-ve-config/src/sdn/fabric/section_config/fabric.rs 
b/proxmox-ve-config/src/sdn/fabric/section_config/fabric.rs
index 38911a6..e92074c 100644
--- a/proxmox-ve-config/src/sdn/fabric/section_config/fabric.rs
+++ b/proxmox-ve-config/src/sdn/fabric/section_config/fabric.rs
@@ -16,6 +16,10 @@ use crate::sdn::fabric::section_config::protocol::ospf::{
 };
 use crate::sdn::fabric::FabricConfigError;
 
+use super::protocol::wireguard::{
+    WireGuardDeletableProperties, WireGuardProperties, 
WireGuardPropertiesUpdater,
+};
+
 pub const FABRIC_ID_REGEX_STR: &str = 
r"(?:[a-zA-Z0-9])(?:[a-zA-Z0-9\-]){0,6}(?:[a-zA-Z0-9])?";
 
 const_regex! {
@@ -139,6 +143,10 @@ impl UpdaterType for FabricSection<OspfProperties> {
     type Updater = FabricSectionUpdater<OspfPropertiesUpdater, 
OspfDeletableProperties>;
 }
 
+impl UpdaterType for FabricSection<WireGuardProperties> {
+    type Updater = FabricSectionUpdater<WireGuardPropertiesUpdater, 
WireGuardDeletableProperties>;
+}
+
 /// Enum containing all types of fabrics.
 ///
 /// It utilizes [`FabricSection<T>`] to define all possible types of fabrics. 
For parsing the
@@ -159,6 +167,8 @@ impl UpdaterType for FabricSection<OspfProperties> {
 pub enum Fabric {
     Openfabric(FabricSection<OpenfabricProperties>),
     Ospf(FabricSection<OspfProperties>),
+    #[serde(rename = "wireguard")]
+    WireGuard(FabricSection<WireGuardProperties>),
 }
 
 impl UpdaterType for Fabric {
@@ -173,6 +183,7 @@ impl Fabric {
         match self {
             Self::Openfabric(fabric_section) => fabric_section.id(),
             Self::Ospf(fabric_section) => fabric_section.id(),
+            Self::WireGuard(fabric_section) => fabric_section.id(),
         }
     }
 
@@ -183,6 +194,7 @@ impl Fabric {
         match self {
             Fabric::Openfabric(fabric_section) => fabric_section.ip_prefix(),
             Fabric::Ospf(fabric_section) => fabric_section.ip_prefix(),
+            Fabric::WireGuard(fabric_section) => fabric_section.ip_prefix(),
         }
     }
 
@@ -193,6 +205,7 @@ impl Fabric {
         match self {
             Fabric::Openfabric(fabric_section) => fabric_section.ip_prefix = 
Some(ipv4_cidr),
             Fabric::Ospf(fabric_section) => fabric_section.ip_prefix = 
Some(ipv4_cidr),
+            Fabric::WireGuard(fabric_section) => fabric_section.ip_prefix = 
Some(ipv4_cidr),
         }
     }
 
@@ -203,6 +216,7 @@ impl Fabric {
         match self {
             Fabric::Openfabric(fabric_section) => fabric_section.ip6_prefix(),
             Fabric::Ospf(fabric_section) => fabric_section.ip6_prefix(),
+            Fabric::WireGuard(fabric_section) => fabric_section.ip6_prefix(),
         }
     }
 
@@ -213,6 +227,7 @@ impl Fabric {
         match self {
             Fabric::Openfabric(fabric_section) => fabric_section.ip6_prefix = 
Some(ipv6_cidr),
             Fabric::Ospf(fabric_section) => fabric_section.ip6_prefix = 
Some(ipv6_cidr),
+            Fabric::WireGuard(fabric_section) => fabric_section.ip6_prefix = 
Some(ipv6_cidr),
         }
     }
 }
@@ -225,6 +240,7 @@ impl Validatable for Fabric {
         match self {
             Fabric::Openfabric(fabric_section) => fabric_section.validate(),
             Fabric::Ospf(fabric_section) => fabric_section.validate(),
+            Fabric::WireGuard(_fabric_section) => Ok(()),
         }
     }
 }
@@ -241,12 +257,20 @@ impl From<FabricSection<OspfProperties>> for Fabric {
     }
 }
 
+impl From<FabricSection<WireGuardProperties>> for Fabric {
+    fn from(section: FabricSection<WireGuardProperties>) -> Self {
+        Fabric::WireGuard(section)
+    }
+}
+
 /// Enum containing all updater types for fabrics
 #[derive(Debug, Clone, Serialize, Deserialize)]
 #[serde(rename_all = "snake_case", tag = "protocol")]
 pub enum FabricUpdater {
     Openfabric(<FabricSection<OpenfabricProperties> as UpdaterType>::Updater),
     Ospf(<FabricSection<OspfProperties> as UpdaterType>::Updater),
+    #[serde(rename = "wireguard")]
+    WireGuard(<FabricSection<WireGuardProperties> as UpdaterType>::Updater),
 }
 
 impl Updater for FabricUpdater {
@@ -254,6 +278,7 @@ impl Updater for FabricUpdater {
         match self {
             FabricUpdater::Openfabric(updater) => updater.is_empty(),
             FabricUpdater::Ospf(updater) => updater.is_empty(),
+            FabricUpdater::WireGuard(updater) => updater.is_empty(),
         }
     }
 }
diff --git a/proxmox-ve-config/src/sdn/fabric/section_config/mod.rs 
b/proxmox-ve-config/src/sdn/fabric/section_config/mod.rs
index d02d4ae..f47a522 100644
--- a/proxmox-ve-config/src/sdn/fabric/section_config/mod.rs
+++ b/proxmox-ve-config/src/sdn/fabric/section_config/mod.rs
@@ -4,6 +4,7 @@ pub mod node;
 pub mod protocol;
 
 use const_format::concatcp;
+use protocol::wireguard::WireGuardProperties;
 use serde::{Deserialize, Serialize};
 
 use crate::sdn::fabric::section_config::{
@@ -12,6 +13,7 @@ use crate::sdn::fabric::section_config::{
     protocol::{
         openfabric::{OpenfabricNodeProperties, OpenfabricProperties},
         ospf::{OspfNodeProperties, OspfProperties},
+        wireguard::WireGuardNode,
     },
 };
 
@@ -31,8 +33,10 @@ impl From<Section> for FabricOrNode<Fabric, Node> {
         match section {
             Section::OpenfabricFabric(fabric_section) => 
Self::Fabric(fabric_section.into()),
             Section::OspfFabric(fabric_section) => 
Self::Fabric(fabric_section.into()),
+            Section::WireGuardFabric(fabric_section) => 
Self::Fabric(fabric_section.into()),
             Section::OpenfabricNode(node_section) => 
Self::Node(node_section.into()),
             Section::OspfNode(node_section) => Self::Node(node_section.into()),
+            Section::WireGuardNode(node_section) => 
Self::Node(node_section.into()),
         }
     }
 }
@@ -62,8 +66,12 @@ pub const SECTION_ID_FORMAT: ApiStringFormat = 
ApiStringFormat::Pattern(&SECTION
 pub enum Section {
     OpenfabricFabric(FabricSection<OpenfabricProperties>),
     OspfFabric(FabricSection<OspfProperties>),
+    #[serde(rename = "wireguard_fabric")]
+    WireGuardFabric(FabricSection<WireGuardProperties>),
     OpenfabricNode(NodeSection<OpenfabricNodeProperties>),
     OspfNode(NodeSection<OspfNodeProperties>),
+    #[serde(rename = "wireguard_node")]
+    WireGuardNode(NodeSection<WireGuardNode>),
 }
 
 impl From<FabricSection<OpenfabricProperties>> for Section {
@@ -78,6 +86,12 @@ impl From<FabricSection<OspfProperties>> for Section {
     }
 }
 
+impl From<FabricSection<WireGuardProperties>> for Section {
+    fn from(section: FabricSection<WireGuardProperties>) -> Self {
+        Self::WireGuardFabric(section)
+    }
+}
+
 impl From<NodeSection<OpenfabricNodeProperties>> for Section {
     fn from(section: NodeSection<OpenfabricNodeProperties>) -> Self {
         Self::OpenfabricNode(section)
@@ -90,11 +104,18 @@ impl From<NodeSection<OspfNodeProperties>> for Section {
     }
 }
 
+impl From<NodeSection<WireGuardNode>> for Section {
+    fn from(section: NodeSection<WireGuardNode>) -> Self {
+        Self::WireGuardNode(section)
+    }
+}
+
 impl From<Fabric> for Section {
     fn from(fabric: Fabric) -> Self {
         match fabric {
             Fabric::Openfabric(fabric_section) => fabric_section.into(),
             Fabric::Ospf(fabric_section) => fabric_section.into(),
+            Fabric::WireGuard(fabric_section) => fabric_section.into(),
         }
     }
 }
@@ -104,6 +125,43 @@ impl From<Node> for Section {
         match node {
             Node::Openfabric(node_section) => node_section.into(),
             Node::Ospf(node_section) => node_section.into(),
+            Node::WireGuard(node_section) => node_section.into(),
         }
     }
 }
+
+#[cfg(test)]
+mod tests {
+    use crate::sdn::fabric::FabricConfig;
+    use proxmox_section_config::typed::ApiSectionDataEntry;
+
+    use super::*;
+
+    #[test]
+    fn test_wireguard_fabric() -> Result<(), anyhow::Error> {
+        let section_config = r#"
+wireguard_fabric: wireg
+
+wireguard_node: wireg_external
+    role external
+    endpoint 192.0.2.1:123
+    public_key Kay64UG8yvCyLhqU000LxzYeUm0L/hLIl5S8kyKWbdc=
+
+wireguard_node: wireg_pve1
+    role internal
+    endpoint 192.0.2.2
+    interfaces 
name=wg0,listen_port=51111,public_key=Kay64UG8yvCyLhqU000LxzYeUm0L/hLIl5S8kyKWbdc=
+    peers type=internal,node=pve2,node_iface=wg0,iface=wg0
+
+wireguard_node: wireg_pve2
+    role internal
+    endpoint 192.0.2.3
+    interfaces 
name=wg0,listen_port=51111,public_key=Kay64UG8yvCyLhqU000LxzYeUm0L/hLIl5S8kyKWbdc=
+    peers type=internal,node=pve1,node_iface=wg0,iface=wg0
+"#;
+        let parsed_config = Section::parse_section_config("fabrics.cfg", 
section_config)?;
+        FabricConfig::from_section_config(parsed_config).expect("valid 
wireguard configuration");
+
+        Ok(())
+    }
+}
diff --git a/proxmox-ve-config/src/sdn/fabric/section_config/node.rs 
b/proxmox-ve-config/src/sdn/fabric/section_config/node.rs
index 17d2f0b..77ce15f 100644
--- a/proxmox-ve-config/src/sdn/fabric/section_config/node.rs
+++ b/proxmox-ve-config/src/sdn/fabric/section_config/node.rs
@@ -10,6 +10,7 @@ use proxmox_schema::{
 };
 
 use crate::common::valid::Validatable;
+use crate::sdn::fabric::section_config::protocol::wireguard::WireGuardNode;
 use crate::sdn::fabric::section_config::{
     fabric::{FabricId, FABRIC_ID_REGEX_STR},
     protocol::{openfabric::OpenfabricNodeProperties, ospf::OspfNodeProperties},
@@ -36,6 +37,18 @@ api_string_type! {
     pub struct NodeId(String);
 }
 
+impl std::str::FromStr for NodeId {
+    type Err = anyhow::Error;
+
+    fn from_str(value: &str) -> Result<Self, Self::Err> {
+        Self::API_SCHEMA
+            .unwrap_string_schema()
+            .check_constraints(value)?;
+
+        Ok(unsafe { Self::from_string_unchecked(value.to_string()) })
+    }
+}
+
 /// ID of a node in the section config.
 ///
 /// This corresponds to the ID of the fabric, that contains this node, as well 
as the hostname of
@@ -147,8 +160,8 @@ impl<T> NodeSection<T> {
     /// Get the IPv4 address (Router-ID) of the [`NodeSection`].
     ///
     /// Either the [`NodeSection::ip`] (IPv4) address or the 
[`NodeSection::ip6`] (IPv6) address *must*
-    /// be set. This is checked during the validation, so it's guaranteed. 
OpenFabric can also be
-    /// used dual-stack, so both IPv4 and IPv6 addresses can be set.
+    /// be set. This is checked during the validation, so it's guaranteed. 
OpenFabric and WireGuard
+    /// can also be used dual-stack, so both IPv4 and IPv6 addresses can be 
set.
     pub fn ip(&self) -> Option<std::net::Ipv4Addr> {
         self.ip.as_deref().copied()
     }
@@ -156,8 +169,8 @@ impl<T> NodeSection<T> {
     /// Get the IPv6 address (Router-ID) of the [`NodeSection`].
     ///
     /// Either the [`NodeSection::ip`] (IPv4) address or the 
[`NodeSection::ip6`] (IPv6) address *must*
-    /// be set. This is checked during the validation, so it's guaranteed. 
OpenFabric can also be
-    /// used dual-stack, so both IPv4 and IPv6 addresses can be set.
+    /// be set. This is checked during the validation, so it's guaranteed. 
OpenFabric and WireGuard
+    /// can also be used dual-stack, so both IPv4 and IPv6 addresses can be 
set.
     pub fn ip6(&self) -> Option<std::net::Ipv6Addr> {
         self.ip6.as_deref().copied()
     }
@@ -186,6 +199,8 @@ impl<T: ApiType> ApiType for NodeSection<T> {
 pub enum Node {
     Openfabric(NodeSection<OpenfabricNodeProperties>),
     Ospf(NodeSection<OspfNodeProperties>),
+    #[serde(rename = "wireguard")]
+    WireGuard(NodeSection<WireGuardNode>),
 }
 
 impl Node {
@@ -194,6 +209,7 @@ impl Node {
         match self {
             Node::Openfabric(node_section) => node_section.id(),
             Node::Ospf(node_section) => node_section.id(),
+            Node::WireGuard(node_section) => node_section.id(),
         }
     }
 
@@ -202,6 +218,7 @@ impl Node {
         match self {
             Node::Openfabric(node_section) => node_section.ip(),
             Node::Ospf(node_section) => node_section.ip(),
+            Node::WireGuard(node_section) => node_section.ip(),
         }
     }
 
@@ -210,6 +227,7 @@ impl Node {
         match self {
             Node::Openfabric(node_section) => node_section.ip6(),
             Node::Ospf(node_section) => node_section.ip6(),
+            Node::WireGuard(node_section) => node_section.ip6(),
         }
     }
 }
@@ -221,6 +239,7 @@ impl Validatable for Node {
         match self {
             Node::Openfabric(node_section) => node_section.validate(),
             Node::Ospf(node_section) => node_section.validate(),
+            Node::WireGuard(_node_section) => Ok(()),
         }
     }
 }
@@ -237,6 +256,12 @@ impl From<NodeSection<OspfNodeProperties>> for Node {
     }
 }
 
+impl From<NodeSection<WireGuardNode>> for Node {
+    fn from(value: NodeSection<WireGuardNode>) -> Self {
+        Self::WireGuard(value)
+    }
+}
+
 /// API types for SDN fabric node configurations.
 ///
 /// This module provides specialized types that are used for API interactions 
when retrieving,
@@ -263,6 +288,7 @@ pub mod api {
             OpenfabricNodePropertiesUpdater,
         },
         ospf::{OspfNodeDeletableProperties, OspfNodeProperties, 
OspfNodePropertiesUpdater},
+        wireguard::{WireGuardNodeDeletableProperties, WireGuardNodeUpdater},
     };
 
     use super::*;
@@ -320,6 +346,8 @@ pub mod api {
     pub enum Node {
         Openfabric(NodeData<OpenfabricNodeProperties>),
         Ospf(NodeData<OspfNodeProperties>),
+        #[serde(rename = "wireguard")]
+        WireGuard(NodeData<WireGuardNode>),
     }
 
     impl From<super::Node> for Node {
@@ -327,6 +355,7 @@ pub mod api {
             match value {
                 super::Node::Openfabric(node_section) => 
Self::Openfabric(node_section.into()),
                 super::Node::Ospf(node_section) => 
Self::Ospf(node_section.into()),
+                super::Node::WireGuard(node_section) => 
Self::WireGuard(node_section.into()),
             }
         }
     }
@@ -336,6 +365,7 @@ pub mod api {
             match value {
                 Node::Openfabric(node_section) => 
Self::Openfabric(node_section.into()),
                 Node::Ospf(node_section) => Self::Ospf(node_section.into()),
+                Node::WireGuard(node_section) => 
Self::WireGuard(node_section.into()),
             }
         }
     }
@@ -349,6 +379,10 @@ pub mod api {
         type Updater = NodeDataUpdater<OspfNodePropertiesUpdater, 
OspfNodeDeletableProperties>;
     }
 
+    impl UpdaterType for NodeData<WireGuardNode> {
+        type Updater = NodeDataUpdater<WireGuardNodeUpdater, 
WireGuardNodeDeletableProperties>;
+    }
+
     #[derive(Debug, Clone, Serialize, Deserialize)]
     pub struct NodeDataUpdater<T, D> {
         #[serde(skip_serializing_if = "Option::is_none")]
@@ -384,6 +418,8 @@ pub mod api {
             NodeDataUpdater<OpenfabricNodePropertiesUpdater, 
OpenfabricNodeDeletableProperties>,
         ),
         Ospf(NodeDataUpdater<OspfNodePropertiesUpdater, 
OspfNodeDeletableProperties>),
+        #[serde(rename = "wireguard")]
+        WireGuard(NodeDataUpdater<WireGuardNodeUpdater, 
WireGuardNodeDeletableProperties>),
     }
 
     #[derive(Debug, Clone, Serialize, Deserialize)]
-- 
2.47.3



Reply via email to