Adding Hypervisor system and Hypervisor Interface

This commit implements the GET commands for Power hypervisor
Virtual Management Interface's interface collection.

Tested by:
1. GET https://${bmc}/redfish/v1/Systems
2. GET https://${bmc}/redfish/v1/Systems/hypervisor
3. GET https://${bmc}/redfish/v1/Systems/hypervisor/EthernetInterfaces
4. Successfully ran the Redfish Validator

*** /redfish/v1/Systems
         Type (#ComputerSystemCollection.ComputerSystemCollection), GET SUCCESS (time: 0.335171)
         PASS

*** /redfish/v1/Systems/hypervisor
         Type (#ComputerSystem.v1_6_0.ComputerSystem), GET SUCCESS (time: 0.341849)
         PASS

*** /redfish/v1/Systems/hypervisor/EthernetInterfaces
         Type (#EthernetInterfaceCollection.EthernetInterfaceCollection), GET SUCCESS (time: 0.362111)
         PASS
5. Verified the hypervisor in not listed on BMC which does not implement
   the Hypervisor object

Signed-off-by: Sunitha Harish <sunithaharish04@gmail.com>
Change-Id: Ie1eb166808473137dd65df54fb4d748cfd1131d2
diff --git a/redfish-core/include/redfish.hpp b/redfish-core/include/redfish.hpp
index 62c7ad8..f8524ac 100644
--- a/redfish-core/include/redfish.hpp
+++ b/redfish-core/include/redfish.hpp
@@ -40,6 +40,7 @@
 #ifdef BMCWEB_ENABLE_VM_NBDPROXY
 #include "../lib/virtual_media.hpp"
 #endif // BMCWEB_ENABLE_VM_NBDPROXY
+#include "../lib/hypervisor_ethernet.hpp"
 #include "webserver_common.hpp"
 
 namespace redfish
@@ -171,6 +172,7 @@
 
         nodes.emplace_back(std::make_unique<SensorCollection>(app));
         nodes.emplace_back(std::make_unique<Sensor>(app));
+
         nodes.emplace_back(std::make_unique<TaskMonitor>(app));
         nodes.emplace_back(std::make_unique<TaskService>(app));
         nodes.emplace_back(std::make_unique<TaskCollection>(app));
@@ -178,6 +180,11 @@
         nodes.emplace_back(std::make_unique<EventService>(app));
         nodes.emplace_back(std::make_unique<EventDestinationCollection>(app));
         nodes.emplace_back(std::make_unique<EventDestination>(app));
+
+        nodes.emplace_back(
+            std::make_unique<HypervisorInterfaceCollection>(app));
+        nodes.emplace_back(std::make_unique<HypervisorSystem>(app));
+
         for (const auto& node : nodes)
         {
             node->initPrivileges();
diff --git a/redfish-core/lib/hypervisor_ethernet.hpp b/redfish-core/lib/hypervisor_ethernet.hpp
new file mode 100644
index 0000000..ab6c0a5
--- /dev/null
+++ b/redfish-core/lib/hypervisor_ethernet.hpp
@@ -0,0 +1,146 @@
+#pragma once
+
+#include <boost/container/flat_map.hpp>
+#include <boost/container/flat_set.hpp>
+#include <dbus_singleton.hpp>
+#include <error_messages.hpp>
+#include <node.hpp>
+#include <optional>
+#include <utils/json_utils.hpp>
+#include <variant>
+
+namespace redfish
+{
+
+/**
+ * Hypervisor Systems derived class for delivering Computer Systems Schema.
+ */
+class HypervisorSystem : public Node
+{
+  public:
+    /*
+     * Default Constructor
+     */
+    HypervisorSystem(CrowApp &app) :
+        Node(app, "/redfish/v1/Systems/hypervisor/")
+    {
+        entityPrivileges = {
+            {boost::beast::http::verb::get, {{"Login"}}},
+            {boost::beast::http::verb::head, {{"Login"}}},
+            {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}};
+    }
+
+  private:
+    /**
+     * Functions triggers appropriate requests on DBus
+     */
+    void doGet(crow::Response &res, const crow::Request &req,
+               const std::vector<std::string> &params) override
+    {
+        std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
+        crow::connections::systemBus->async_method_call(
+            [asyncResp](const boost::system::error_code ec,
+                        const std::variant<std::string> &hostName) {
+                if (ec)
+                {
+                    messages::resourceNotFound(asyncResp->res, "System",
+                                               "hypervisor");
+                    return;
+                }
+                BMCWEB_LOG_DEBUG << "Hypervisor is available";
+
+                asyncResp->res.jsonValue["@odata.type"] =
+                    "#ComputerSystem.v1_6_0.ComputerSystem";
+                asyncResp->res.jsonValue["@odata.id"] =
+                    "/redfish/v1/Systems/hypervisor";
+                asyncResp->res.jsonValue["Description"] = "Hypervisor";
+                asyncResp->res.jsonValue["Name"] = "Hypervisor";
+                asyncResp->res.jsonValue["Id"] = "hypervisor";
+                asyncResp->res.jsonValue["Links"]["ManagedBy"] = {
+                    {{"@odata.id", "/redfish/v1/Managers/bmc"}}};
+                asyncResp->res.jsonValue["EthernetInterfaces"] = {
+                    {"@odata.id", "/redfish/v1/Systems/hypervisor/"
+                                  "EthernetInterfaces"}};
+                // TODO: Add "SystemType" : "hypervisor"
+            },
+            "xyz.openbmc_project.Settings", "/xyz/openbmc_project/network/vmi",
+            "org.freedesktop.DBus.Properties", "Get",
+            "xyz.openbmc_project.Network.SystemConfiguration", "HostName");
+    }
+};
+
+/**
+ * HypervisorInterfaceCollection class to handle the GET and PATCH on Hypervisor
+ * Interface
+ */
+class HypervisorInterfaceCollection : public Node
+{
+  public:
+    template <typename CrowApp>
+    HypervisorInterfaceCollection(CrowApp &app) :
+        Node(app, "/redfish/v1/Systems/hypervisor/EthernetInterfaces/")
+    {
+        entityPrivileges = {
+            {boost::beast::http::verb::get, {{"Login"}}},
+            {boost::beast::http::verb::head, {{"Login"}}},
+            {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}};
+    }
+
+  private:
+    /**
+     * Functions triggers appropriate requests on DBus
+     */
+    void doGet(crow::Response &res, const crow::Request &req,
+               const std::vector<std::string> &params) override
+    {
+        std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
+        const std::array<const char *, 1> interfaces = {
+            "xyz.openbmc_project.Network.EthernetInterface"};
+
+        crow::connections::systemBus->async_method_call(
+            [asyncResp](const boost::system::error_code error_code,
+                        const std::vector<std::string> &iface_list) {
+                if (error_code)
+                {
+                    messages::resourceNotFound(asyncResp->res, "System",
+                                               "hypervisor");
+                    return;
+                }
+                asyncResp->res.jsonValue["@odata.type"] =
+                    "#EthernetInterfaceCollection."
+                    "EthernetInterfaceCollection";
+                asyncResp->res.jsonValue["@odata.id"] =
+                    "/redfish/v1/Systems/hypervisor/EthernetInterfaces";
+                asyncResp->res.jsonValue["Name"] =
+                    "Virtual Management Ethernet "
+                    "Network Interface Collection";
+                asyncResp->res.jsonValue["Description"] =
+                    "Collection of Virtual Management "
+                    "Interfaces for the hypervisor";
+
+                nlohmann::json &iface_array =
+                    asyncResp->res.jsonValue["Members"];
+                iface_array = nlohmann::json::array();
+                for (const std::string &iface_item : iface_list)
+                {
+                    std::size_t last_pos = iface_item.rfind("/");
+                    if (last_pos != std::string::npos)
+                    {
+                        iface_array.push_back(
+                            {{"@odata.id",
+                              "/redfish/v1/Systems/hypervisor/"
+                              "EthernetInterfaces/" +
+                                  iface_item.substr(last_pos + 1)}});
+                    }
+                }
+                asyncResp->res.jsonValue["Members@odata.count"] =
+                    iface_array.size();
+            },
+            "xyz.openbmc_project.ObjectMapper",
+            "/xyz/openbmc_project/object_mapper",
+            "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths",
+            "/xyz/openbmc_project/network/vmi", 0, interfaces);
+    }
+};
+
+} // namespace redfish
diff --git a/redfish-core/lib/systems.hpp b/redfish-core/lib/systems.hpp
index 0d7e6f4..0aa0d64 100644
--- a/redfish-core/lib/systems.hpp
+++ b/redfish-core/lib/systems.hpp
@@ -1367,14 +1367,37 @@
     void doGet(crow::Response &res, const crow::Request &req,
                const std::vector<std::string> &params) override
     {
+        std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
         res.jsonValue["@odata.type"] =
             "#ComputerSystemCollection.ComputerSystemCollection";
         res.jsonValue["@odata.id"] = "/redfish/v1/Systems";
         res.jsonValue["Name"] = "Computer System Collection";
-        res.jsonValue["Members"] = {
-            {{"@odata.id", "/redfish/v1/Systems/system"}}};
-        res.jsonValue["Members@odata.count"] = 1;
-        res.end();
+
+        crow::connections::systemBus->async_method_call(
+            [asyncResp](const boost::system::error_code ec,
+                        const std::variant<std::string> &hostName) {
+                nlohmann::json &iface_array =
+                    asyncResp->res.jsonValue["Members"];
+                iface_array = nlohmann::json::array();
+                auto &count = asyncResp->res.jsonValue["Members@odata.count"];
+                count = 0;
+                if (ec)
+                {
+                    iface_array.push_back(
+                        {{"@odata.id", "/redfish/v1/Systems/system"}});
+                    count = iface_array.size();
+                    return;
+                }
+                BMCWEB_LOG_DEBUG << "Hypervisor is available";
+                iface_array.push_back(
+                    {{"@odata.id", "/redfish/v1/Systems/system"}});
+                iface_array.push_back(
+                    {{"@odata.id", "/redfish/v1/Systems/hypervisor"}});
+                count = iface_array.size();
+            },
+            "xyz.openbmc_project.Settings", "/xyz/openbmc_project/network/vmi",
+            "org.freedesktop.DBus.Properties", "Get",
+            "xyz.openbmc_project.Network.SystemConfiguration", "HostName");
     }
 };