topology: schema rework: implementation

Implementation code for the schema change done in [1]. This change
enables entity-manager to consume the new schema and create associations
based on it.

Tested: next patch

References:
[1] https://gerrit.openbmc.org/c/openbmc/entity-manager/+/82817

Change-Id: If227949ab7bb216c2365241c307fe752b0a4cd93
Signed-off-by: Alexander Hansen <alexander.hansen@9elements.com>
diff --git a/src/entity_manager/topology.cpp b/src/entity_manager/topology.cpp
index 0581991..52ab478 100644
--- a/src/entity_manager/topology.cpp
+++ b/src/entity_manager/topology.cpp
@@ -7,6 +7,13 @@
 const AssocName assocPowering = AssocName("powering", "powered_by");
 const AssocName assocPoweredBy = assocPowering.getReverse();
 
+const std::vector<AssocName> supportedAssocs = {
+    assocContaining,
+    assocContainedBy,
+    assocPowering,
+    assocPoweredBy,
+};
+
 AssocName::AssocName(const std::string& name, const std::string& reverse) :
     name(name), reverse(reverse)
 {}
@@ -21,6 +28,18 @@
     return name < other.name;
 }
 
+std::optional<AssocName> Topology::getAssocByName(const std::string& name)
+{
+    for (const auto& assoc : supportedAssocs)
+    {
+        if (assoc.name == name)
+        {
+            return assoc;
+        }
+    }
+    return std::nullopt;
+}
+
 void Topology::addBoard(const std::string& path, const std::string& boardType,
                         const std::string& boardName,
                         const nlohmann::json& exposesItem)
@@ -39,6 +58,10 @@
     {
         addDownstreamPort(path, exposesItem);
     }
+    else if (exposesType == "Port")
+    {
+        addConfiguredPort(path, exposesItem);
+    }
     else if (exposesType.ends_with("Port"))
     {
         addPort(exposesType, path, assocContaining);
@@ -50,6 +73,36 @@
     boardTypes[path] = boardType;
 }
 
+void Topology::addConfiguredPort(const Path& path,
+                                 const nlohmann::json& exposesItem)
+{
+    const auto findConnectsToName = exposesItem.find("Name");
+    if (findConnectsToName == exposesItem.end())
+    {
+        lg2::error("Board at path {PATH} is missing 'Name'", "PATH", path);
+        return;
+    }
+    const std::string connectsToName = findConnectsToName->get<std::string>();
+
+    const auto findPortType = exposesItem.find("PortType");
+    if (findPortType == exposesItem.end())
+    {
+        lg2::error("Board at path {PATH} is missing PortType", "PATH", path);
+        return;
+    }
+    const std::string portType = findPortType->get<std::string>();
+
+    const auto assoc = getAssocByName(portType);
+    if (!assoc.has_value())
+    {
+        lg2::error("Could not find configured association name {ASSOC}",
+                   "ASSOC", portType);
+        return;
+    }
+
+    addPort(connectsToName, path, assoc.value());
+}
+
 void Topology::addDownstreamPort(const Path& path,
                                  const nlohmann::json& exposesItem)
 {