Add helper methods for populating a FabricConfig from the section
config, as well as converting it back into the respective section
config structs.

By utilizing the Valid type, we can ensure that only valid
configurations get written via the provided write_section_config
method, since it is only implemented for Valid<FabricConfig>. Because
validation can be expensive, particularly when doing multiple changes
to the fabric config, we only validate the config directly before
converting it into the section config.

Co-authored-by: Gabriel Goller <g.gol...@proxmox.com>
Signed-off-by: Stefan Hanreich <s.hanre...@proxmox.com>
---
 proxmox-ve-config/src/sdn/fabric/mod.rs | 91 ++++++++++++++++++++++++-
 1 file changed, 90 insertions(+), 1 deletion(-)

diff --git a/proxmox-ve-config/src/sdn/fabric/mod.rs 
b/proxmox-ve-config/src/sdn/fabric/mod.rs
index b7d1f2d..57e2e6f 100644
--- a/proxmox-ve-config/src/sdn/fabric/mod.rs
+++ b/proxmox-ve-config/src/sdn/fabric/mod.rs
@@ -4,9 +4,12 @@ use std::collections::{BTreeMap, HashSet};
 use std::marker::PhantomData;
 use std::ops::Deref;
 
+use anyhow::Error;
 use serde::{Deserialize, Serialize};
 
-use crate::common::valid::Validatable;
+use proxmox_section_config::typed::{ApiSectionDataEntry, SectionConfigData};
+
+use crate::common::valid::{Valid, Validatable};
 
 use crate::sdn::fabric::section_config::{
     fabric::{
@@ -28,6 +31,7 @@ use crate::sdn::fabric::section_config::{
             OspfNodePropertiesUpdater, OspfProperties, OspfPropertiesUpdater,
         },
     },
+    Either, Section,
 };
 
 #[derive(thiserror::Error, Debug)]
@@ -638,4 +642,89 @@ impl FabricConfig {
             _ => Err(FabricConfigError::ProtocolMismatch),
         }
     }
+
+    /// Constructs a valid [FabricConfig] from section-config data.
+    ///
+    /// Iterates through the [SectionConfigData<Section>] and matches on the 
[Section] enum. Then
+    /// construct the [FabricConfig] and validate it.
+    pub fn from_section_config(
+        config: SectionConfigData<Section>,
+    ) -> Result<Valid<Self>, FabricConfigError> {
+        let mut fabrics = BTreeMap::new();
+        let mut nodes = Vec::new();
+
+        for (_id, section) in config {
+            let fabric_or_node = Either::from(section);
+
+            match fabric_or_node {
+                Either::Left(fabric) => {
+                    fabrics.insert(fabric.id().clone(), 
FabricEntry::from(fabric));
+                }
+                Either::Right(node) => {
+                    nodes.push(node);
+                }
+            };
+        }
+
+        for node in nodes {
+            fabrics
+                .get_mut(node.id().fabric_id())
+                .ok_or_else(|| {
+                    
FabricConfigError::FabricDoesNotExist(node.id().fabric_id().to_string())
+                })?
+                .add_node(node)?;
+        }
+
+        let config = Self { fabrics };
+        config.into_valid()
+    }
+
+    /// Constructs a valid [FabricConfig] from the raw section-config file 
content.
+    ///
+    /// This will call the [Section::parse_section_config] function to parse 
the raw string into a
+    /// [SectionConfigData<Section>] struct. Then construct the valid 
[FabricConfig] with
+    /// [Self::from_section_config].
+    pub fn parse_section_config(config: &str) -> Result<Valid<Self>, Error> {
+        let data = Section::parse_section_config("fabrics.cfg", config)?;
+        Self::from_section_config(data).map_err(anyhow::Error::msg)
+    }
+
+    /// Validate [FabricConfig] and write the raw config to a String. 
+    ///
+    /// Validates the config and calls 
[Valid<FabricConfig>::write_section_config].
+    pub fn write_section_config(&self) -> Result<String, Error> {
+        self.clone().into_valid()?.write_section_config()
+    }
+}
+
+impl Valid<FabricConfig> {
+    /// Converts a valid [FabricConfig] into a [SectionConfigData<Section>].
+    ///
+    /// This function is implemented on [Valid<FabricConfig>], ensuring that 
only a valid
+    /// [FabricConfig] can be written to the file.
+    pub fn into_section_config(self) -> SectionConfigData<Section> {
+        let config = self.into_inner();
+
+        let mut section_config = SectionConfigData::default();
+
+        for (fabric_id, fabric_entry) in config.fabrics {
+            let (fabric, fabric_nodes) = fabric_entry.into_section_config();
+
+            section_config.insert(fabric_id.to_string(), 
Section::from(fabric));
+
+            for node in fabric_nodes {
+                section_config.insert(node.id().to_string(), 
Section::from(node));
+            }
+        }
+
+        section_config
+    }
+
+    /// Consumes the [Valid<FabricConfig>] and writes the raw section-config 
content to a String.
+    ///
+    /// This function is implemented on [Valid<FabricConfig>], ensuring that 
only a valid
+    /// [FabricConfig] can be written to the file.
+    pub fn write_section_config(self) -> Result<String, Error> {
+        Section::write_section_config("fabrics.cfg", 
&self.into_section_config())
+    }
 }
-- 
2.39.5


_______________________________________________
pve-devel mailing list
pve-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel

Reply via email to