1d5afb2caSAndrew Geissler #pragma once 2d5afb2caSAndrew Geissler 3d5afb2caSAndrew Geissler #include <boost/container/flat_map.hpp> 4d5afb2caSAndrew Geissler #include <boost/container/flat_set.hpp> 5d5afb2caSAndrew Geissler #include <dbus_singleton.hpp> 6d5afb2caSAndrew Geissler #include <error_messages.hpp> 7d5afb2caSAndrew Geissler #include <node.hpp> 8d5afb2caSAndrew Geissler #include <utils/json_utils.hpp> 9d5afb2caSAndrew Geissler 10d5afb2caSAndrew Geissler #include <optional> 11d5afb2caSAndrew Geissler #include <utility> 12d5afb2caSAndrew Geissler #include <variant> 13d5afb2caSAndrew Geissler 14d5afb2caSAndrew Geissler namespace redfish 15d5afb2caSAndrew Geissler { 16d5afb2caSAndrew Geissler 17d5afb2caSAndrew Geissler /** 18cc0bb6f2SAndrew Geissler * @brief Retrieves hypervisor state properties over dbus 19cc0bb6f2SAndrew Geissler * 20cc0bb6f2SAndrew Geissler * The hypervisor state object is optional so this function will only set the 21cc0bb6f2SAndrew Geissler * state variables if the object is found 22cc0bb6f2SAndrew Geissler * 23cc0bb6f2SAndrew Geissler * @param[in] aResp Shared pointer for completing asynchronous calls. 24cc0bb6f2SAndrew Geissler * 25cc0bb6f2SAndrew Geissler * @return None. 26cc0bb6f2SAndrew Geissler */ 27cc0bb6f2SAndrew Geissler inline void getHypervisorState(const std::shared_ptr<AsyncResp>& aResp) 28cc0bb6f2SAndrew Geissler { 29cc0bb6f2SAndrew Geissler BMCWEB_LOG_DEBUG << "Get hypervisor state information."; 30cc0bb6f2SAndrew Geissler crow::connections::systemBus->async_method_call( 31cc0bb6f2SAndrew Geissler [aResp](const boost::system::error_code ec, 32cc0bb6f2SAndrew Geissler const std::variant<std::string>& hostState) { 33cc0bb6f2SAndrew Geissler if (ec) 34cc0bb6f2SAndrew Geissler { 35cc0bb6f2SAndrew Geissler BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 36cc0bb6f2SAndrew Geissler // This is an optional D-Bus object so just return if 37cc0bb6f2SAndrew Geissler // error occurs 38cc0bb6f2SAndrew Geissler return; 39cc0bb6f2SAndrew Geissler } 40cc0bb6f2SAndrew Geissler 41cc0bb6f2SAndrew Geissler const std::string* s = std::get_if<std::string>(&hostState); 42cc0bb6f2SAndrew Geissler if (s == nullptr) 43cc0bb6f2SAndrew Geissler { 44cc0bb6f2SAndrew Geissler messages::internalError(aResp->res); 45cc0bb6f2SAndrew Geissler return; 46cc0bb6f2SAndrew Geissler } 47cc0bb6f2SAndrew Geissler 48cc0bb6f2SAndrew Geissler BMCWEB_LOG_DEBUG << "Hypervisor state: " << *s; 49cc0bb6f2SAndrew Geissler // Verify Host State 50cc0bb6f2SAndrew Geissler if (*s == "xyz.openbmc_project.State.Host.HostState.Running") 51cc0bb6f2SAndrew Geissler { 52cc0bb6f2SAndrew Geissler aResp->res.jsonValue["PowerState"] = "On"; 53cc0bb6f2SAndrew Geissler aResp->res.jsonValue["Status"]["State"] = "Enabled"; 54cc0bb6f2SAndrew Geissler } 55cc0bb6f2SAndrew Geissler else if (*s == "xyz.openbmc_project.State.Host.HostState." 56cc0bb6f2SAndrew Geissler "Quiesced") 57cc0bb6f2SAndrew Geissler { 58cc0bb6f2SAndrew Geissler aResp->res.jsonValue["PowerState"] = "On"; 59cc0bb6f2SAndrew Geissler aResp->res.jsonValue["Status"]["State"] = "Quiesced"; 60cc0bb6f2SAndrew Geissler } 61cc0bb6f2SAndrew Geissler else if (*s == "xyz.openbmc_project.State.Host.HostState." 62cc0bb6f2SAndrew Geissler "Standby") 63cc0bb6f2SAndrew Geissler { 64cc0bb6f2SAndrew Geissler aResp->res.jsonValue["PowerState"] = "On"; 65cc0bb6f2SAndrew Geissler aResp->res.jsonValue["Status"]["State"] = "StandbyOffline"; 66cc0bb6f2SAndrew Geissler } 67cc0bb6f2SAndrew Geissler else if (*s == "xyz.openbmc_project.State.Host.HostState." 68cc0bb6f2SAndrew Geissler "TransitioningToRunning") 69cc0bb6f2SAndrew Geissler { 70cc0bb6f2SAndrew Geissler aResp->res.jsonValue["PowerState"] = "PoweringOn"; 71cc0bb6f2SAndrew Geissler aResp->res.jsonValue["Status"]["State"] = "Starting"; 72cc0bb6f2SAndrew Geissler } 73cc0bb6f2SAndrew Geissler else if (*s == "xyz.openbmc_project.State.Host.HostState." 74cc0bb6f2SAndrew Geissler "TransitioningToOff") 75cc0bb6f2SAndrew Geissler { 76cc0bb6f2SAndrew Geissler aResp->res.jsonValue["PowerState"] = "PoweringOff"; 77cc0bb6f2SAndrew Geissler aResp->res.jsonValue["Status"]["State"] = "Enabled"; 78cc0bb6f2SAndrew Geissler } 79cc0bb6f2SAndrew Geissler else if (*s == "xyz.openbmc_project.State.Host.HostState.Off") 80cc0bb6f2SAndrew Geissler { 81cc0bb6f2SAndrew Geissler aResp->res.jsonValue["PowerState"] = "Off"; 82cc0bb6f2SAndrew Geissler aResp->res.jsonValue["Status"]["State"] = "Disabled"; 83cc0bb6f2SAndrew Geissler } 84cc0bb6f2SAndrew Geissler else 85cc0bb6f2SAndrew Geissler { 86cc0bb6f2SAndrew Geissler messages::internalError(aResp->res); 87cc0bb6f2SAndrew Geissler return; 88cc0bb6f2SAndrew Geissler } 89cc0bb6f2SAndrew Geissler }, 90cc0bb6f2SAndrew Geissler "xyz.openbmc_project.State.Hypervisor", 91cc0bb6f2SAndrew Geissler "/xyz/openbmc_project/state/hypervisor0", 92cc0bb6f2SAndrew Geissler "org.freedesktop.DBus.Properties", "Get", 93cc0bb6f2SAndrew Geissler "xyz.openbmc_project.State.Host", "CurrentHostState"); 94cc0bb6f2SAndrew Geissler } 95cc0bb6f2SAndrew Geissler 96cc0bb6f2SAndrew Geissler /** 97*4fbaf64aSAndrew Geissler * @brief Populate Actions if any are valid for hypervisor object 98*4fbaf64aSAndrew Geissler * 99*4fbaf64aSAndrew Geissler * The hypervisor state object is optional so this function will only set the 100*4fbaf64aSAndrew Geissler * Action if the object is found 101*4fbaf64aSAndrew Geissler * 102*4fbaf64aSAndrew Geissler * @param[in] aResp Shared pointer for completing asynchronous calls. 103*4fbaf64aSAndrew Geissler * 104*4fbaf64aSAndrew Geissler * @return None. 105*4fbaf64aSAndrew Geissler */ 106*4fbaf64aSAndrew Geissler inline void getHypervisorActions(const std::shared_ptr<AsyncResp>& aResp) 107*4fbaf64aSAndrew Geissler { 108*4fbaf64aSAndrew Geissler BMCWEB_LOG_DEBUG << "Get hypervisor actions."; 109*4fbaf64aSAndrew Geissler crow::connections::systemBus->async_method_call( 110*4fbaf64aSAndrew Geissler [aResp]( 111*4fbaf64aSAndrew Geissler const boost::system::error_code ec, 112*4fbaf64aSAndrew Geissler const std::vector<std::pair<std::string, std::vector<std::string>>>& 113*4fbaf64aSAndrew Geissler objInfo) { 114*4fbaf64aSAndrew Geissler if (ec) 115*4fbaf64aSAndrew Geissler { 116*4fbaf64aSAndrew Geissler BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 117*4fbaf64aSAndrew Geissler // This is an optional D-Bus object so just return if 118*4fbaf64aSAndrew Geissler // error occurs 119*4fbaf64aSAndrew Geissler return; 120*4fbaf64aSAndrew Geissler } 121*4fbaf64aSAndrew Geissler 122*4fbaf64aSAndrew Geissler if (objInfo.size() == 0) 123*4fbaf64aSAndrew Geissler { 124*4fbaf64aSAndrew Geissler // As noted above, this is an optional interface so just return 125*4fbaf64aSAndrew Geissler // if there is no instance found 126*4fbaf64aSAndrew Geissler return; 127*4fbaf64aSAndrew Geissler } 128*4fbaf64aSAndrew Geissler 129*4fbaf64aSAndrew Geissler if (objInfo.size() > 1) 130*4fbaf64aSAndrew Geissler { 131*4fbaf64aSAndrew Geissler // More then one hypervisor object is not supported and is an 132*4fbaf64aSAndrew Geissler // error 133*4fbaf64aSAndrew Geissler messages::internalError(aResp->res); 134*4fbaf64aSAndrew Geissler return; 135*4fbaf64aSAndrew Geissler } 136*4fbaf64aSAndrew Geissler 137*4fbaf64aSAndrew Geissler // Object present so system support limited ComputerSystem Action 138*4fbaf64aSAndrew Geissler aResp->res.jsonValue["Actions"]["#ComputerSystem.Reset"] = { 139*4fbaf64aSAndrew Geissler {"target", 140*4fbaf64aSAndrew Geissler "/redfish/v1/Systems/hypervisor/Actions/ComputerSystem.Reset"}, 141*4fbaf64aSAndrew Geissler {"@Redfish.ActionInfo", 142*4fbaf64aSAndrew Geissler "/redfish/v1/Systems/hypervisor/ResetActionInfo"}}; 143*4fbaf64aSAndrew Geissler }, 144*4fbaf64aSAndrew Geissler "xyz.openbmc_project.ObjectMapper", 145*4fbaf64aSAndrew Geissler "/xyz/openbmc_project/object_mapper", 146*4fbaf64aSAndrew Geissler "xyz.openbmc_project.ObjectMapper", "GetObject", 147*4fbaf64aSAndrew Geissler "/xyz/openbmc_project/state/hypervisor0", 148*4fbaf64aSAndrew Geissler std::array<const char*, 1>{"xyz.openbmc_project.State.Host"}); 149*4fbaf64aSAndrew Geissler } 150*4fbaf64aSAndrew Geissler 151*4fbaf64aSAndrew Geissler /** 152d5afb2caSAndrew Geissler * Hypervisor Systems derived class for delivering Computer Systems Schema. 153d5afb2caSAndrew Geissler */ 154d5afb2caSAndrew Geissler class HypervisorSystem : public Node 155d5afb2caSAndrew Geissler { 156d5afb2caSAndrew Geissler public: 157d5afb2caSAndrew Geissler /* 158d5afb2caSAndrew Geissler * Default Constructor 159d5afb2caSAndrew Geissler */ 160d5afb2caSAndrew Geissler HypervisorSystem(App& app) : Node(app, "/redfish/v1/Systems/hypervisor/") 161d5afb2caSAndrew Geissler { 162d5afb2caSAndrew Geissler entityPrivileges = { 163d5afb2caSAndrew Geissler {boost::beast::http::verb::get, {{"Login"}}}, 164d5afb2caSAndrew Geissler {boost::beast::http::verb::head, {{"Login"}}}, 165d5afb2caSAndrew Geissler {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}}; 166d5afb2caSAndrew Geissler } 167d5afb2caSAndrew Geissler 168d5afb2caSAndrew Geissler private: 169d5afb2caSAndrew Geissler /** 170d5afb2caSAndrew Geissler * Functions triggers appropriate requests on DBus 171d5afb2caSAndrew Geissler */ 172d5afb2caSAndrew Geissler void doGet(crow::Response& res, const crow::Request&, 173d5afb2caSAndrew Geissler const std::vector<std::string>&) override 174d5afb2caSAndrew Geissler { 175d5afb2caSAndrew Geissler std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res); 176d5afb2caSAndrew Geissler crow::connections::systemBus->async_method_call( 177d5afb2caSAndrew Geissler [asyncResp](const boost::system::error_code ec, 178d5afb2caSAndrew Geissler const std::variant<std::string>& /*hostName*/) { 179d5afb2caSAndrew Geissler if (ec) 180d5afb2caSAndrew Geissler { 181d5afb2caSAndrew Geissler messages::resourceNotFound(asyncResp->res, "System", 182d5afb2caSAndrew Geissler "hypervisor"); 183d5afb2caSAndrew Geissler return; 184d5afb2caSAndrew Geissler } 185d5afb2caSAndrew Geissler BMCWEB_LOG_DEBUG << "Hypervisor is available"; 186d5afb2caSAndrew Geissler 187d5afb2caSAndrew Geissler asyncResp->res.jsonValue["@odata.type"] = 188d5afb2caSAndrew Geissler "#ComputerSystem.v1_6_0.ComputerSystem"; 189d5afb2caSAndrew Geissler asyncResp->res.jsonValue["@odata.id"] = 190d5afb2caSAndrew Geissler "/redfish/v1/Systems/hypervisor"; 191d5afb2caSAndrew Geissler asyncResp->res.jsonValue["Description"] = "Hypervisor"; 192d5afb2caSAndrew Geissler asyncResp->res.jsonValue["Name"] = "Hypervisor"; 193d5afb2caSAndrew Geissler asyncResp->res.jsonValue["Id"] = "hypervisor"; 194d5afb2caSAndrew Geissler asyncResp->res.jsonValue["Links"]["ManagedBy"] = { 195d5afb2caSAndrew Geissler {{"@odata.id", "/redfish/v1/Managers/bmc"}}}; 196d5afb2caSAndrew Geissler asyncResp->res.jsonValue["EthernetInterfaces"] = { 197d5afb2caSAndrew Geissler {"@odata.id", "/redfish/v1/Systems/hypervisor/" 198d5afb2caSAndrew Geissler "EthernetInterfaces"}}; 199cc0bb6f2SAndrew Geissler getHypervisorState(asyncResp); 200*4fbaf64aSAndrew Geissler getHypervisorActions(asyncResp); 201d5afb2caSAndrew Geissler // TODO: Add "SystemType" : "hypervisor" 202d5afb2caSAndrew Geissler }, 203d5afb2caSAndrew Geissler "xyz.openbmc_project.Settings", 204d5afb2caSAndrew Geissler "/xyz/openbmc_project/network/hypervisor", 205d5afb2caSAndrew Geissler "org.freedesktop.DBus.Properties", "Get", 206d5afb2caSAndrew Geissler "xyz.openbmc_project.Network.SystemConfiguration", "HostName"); 207d5afb2caSAndrew Geissler } 208d5afb2caSAndrew Geissler }; 209d5afb2caSAndrew Geissler 210d5afb2caSAndrew Geissler /** 211d5afb2caSAndrew Geissler * HypervisorInterfaceCollection class to handle the GET and PATCH on Hypervisor 212d5afb2caSAndrew Geissler * Interface 213d5afb2caSAndrew Geissler */ 214d5afb2caSAndrew Geissler class HypervisorInterfaceCollection : public Node 215d5afb2caSAndrew Geissler { 216d5afb2caSAndrew Geissler public: 217d5afb2caSAndrew Geissler HypervisorInterfaceCollection(App& app) : 218d5afb2caSAndrew Geissler Node(app, "/redfish/v1/Systems/hypervisor/EthernetInterfaces/") 219d5afb2caSAndrew Geissler { 220d5afb2caSAndrew Geissler entityPrivileges = { 221d5afb2caSAndrew Geissler {boost::beast::http::verb::get, {{"Login"}}}, 222d5afb2caSAndrew Geissler {boost::beast::http::verb::head, {{"Login"}}}, 223d5afb2caSAndrew Geissler {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}}; 224d5afb2caSAndrew Geissler } 225d5afb2caSAndrew Geissler 226d5afb2caSAndrew Geissler private: 227d5afb2caSAndrew Geissler /** 228d5afb2caSAndrew Geissler * Functions triggers appropriate requests on DBus 229d5afb2caSAndrew Geissler */ 230d5afb2caSAndrew Geissler void doGet(crow::Response& res, const crow::Request&, 231d5afb2caSAndrew Geissler const std::vector<std::string>&) override 232d5afb2caSAndrew Geissler { 233d5afb2caSAndrew Geissler std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res); 234d5afb2caSAndrew Geissler const std::array<const char*, 1> interfaces = { 235d5afb2caSAndrew Geissler "xyz.openbmc_project.Network.EthernetInterface"}; 236d5afb2caSAndrew Geissler 237d5afb2caSAndrew Geissler crow::connections::systemBus->async_method_call( 238d5afb2caSAndrew Geissler [asyncResp](const boost::system::error_code error, 239d5afb2caSAndrew Geissler const std::vector<std::string>& ifaceList) { 240d5afb2caSAndrew Geissler if (error) 241d5afb2caSAndrew Geissler { 242d5afb2caSAndrew Geissler messages::resourceNotFound(asyncResp->res, "System", 243d5afb2caSAndrew Geissler "hypervisor"); 244d5afb2caSAndrew Geissler return; 245d5afb2caSAndrew Geissler } 246d5afb2caSAndrew Geissler asyncResp->res.jsonValue["@odata.type"] = 247d5afb2caSAndrew Geissler "#EthernetInterfaceCollection." 248d5afb2caSAndrew Geissler "EthernetInterfaceCollection"; 249d5afb2caSAndrew Geissler asyncResp->res.jsonValue["@odata.id"] = 250d5afb2caSAndrew Geissler "/redfish/v1/Systems/hypervisor/EthernetInterfaces"; 251d5afb2caSAndrew Geissler asyncResp->res.jsonValue["Name"] = "Hypervisor Ethernet " 252d5afb2caSAndrew Geissler "Interface Collection"; 253d5afb2caSAndrew Geissler asyncResp->res.jsonValue["Description"] = 254d5afb2caSAndrew Geissler "Collection of Virtual Management " 255d5afb2caSAndrew Geissler "Interfaces for the hypervisor"; 256d5afb2caSAndrew Geissler 257d5afb2caSAndrew Geissler nlohmann::json& ifaceArray = 258d5afb2caSAndrew Geissler asyncResp->res.jsonValue["Members"]; 259d5afb2caSAndrew Geissler ifaceArray = nlohmann::json::array(); 260d5afb2caSAndrew Geissler for (const std::string& iface : ifaceList) 261d5afb2caSAndrew Geissler { 2622dfd18efSEd Tanous sdbusplus::message::object_path path(iface); 2632dfd18efSEd Tanous std::string name = path.filename(); 2642dfd18efSEd Tanous if (name.empty()) 265d5afb2caSAndrew Geissler { 2662dfd18efSEd Tanous continue; 2672dfd18efSEd Tanous } 2682dfd18efSEd Tanous 269d5afb2caSAndrew Geissler ifaceArray.push_back( 270d5afb2caSAndrew Geissler {{"@odata.id", "/redfish/v1/Systems/hypervisor/" 271d5afb2caSAndrew Geissler "EthernetInterfaces/" + 2722dfd18efSEd Tanous name}}); 273d5afb2caSAndrew Geissler } 274d5afb2caSAndrew Geissler asyncResp->res.jsonValue["Members@odata.count"] = 275d5afb2caSAndrew Geissler ifaceArray.size(); 276d5afb2caSAndrew Geissler }, 277d5afb2caSAndrew Geissler "xyz.openbmc_project.ObjectMapper", 278d5afb2caSAndrew Geissler "/xyz/openbmc_project/object_mapper", 279d5afb2caSAndrew Geissler "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", 280d5afb2caSAndrew Geissler "/xyz/openbmc_project/network/hypervisor", 0, interfaces); 281d5afb2caSAndrew Geissler } 282d5afb2caSAndrew Geissler }; 283d5afb2caSAndrew Geissler 284d5afb2caSAndrew Geissler inline bool extractHypervisorInterfaceData( 285d5afb2caSAndrew Geissler const std::string& ethIfaceId, const GetManagedObjects& dbusData, 286d5afb2caSAndrew Geissler EthernetInterfaceData& ethData, 287d5afb2caSAndrew Geissler boost::container::flat_set<IPv4AddressData>& ipv4Config) 288d5afb2caSAndrew Geissler { 289d5afb2caSAndrew Geissler bool idFound = false; 290d5afb2caSAndrew Geissler for (const auto& objpath : dbusData) 291d5afb2caSAndrew Geissler { 292d5afb2caSAndrew Geissler for (const auto& ifacePair : objpath.second) 293d5afb2caSAndrew Geissler { 294d5afb2caSAndrew Geissler if (objpath.first == 295d5afb2caSAndrew Geissler "/xyz/openbmc_project/network/hypervisor/" + ethIfaceId) 296d5afb2caSAndrew Geissler { 297d5afb2caSAndrew Geissler idFound = true; 298d5afb2caSAndrew Geissler if (ifacePair.first == "xyz.openbmc_project.Network.MACAddress") 299d5afb2caSAndrew Geissler { 300d5afb2caSAndrew Geissler for (const auto& propertyPair : ifacePair.second) 301d5afb2caSAndrew Geissler { 302d5afb2caSAndrew Geissler if (propertyPair.first == "MACAddress") 303d5afb2caSAndrew Geissler { 304d5afb2caSAndrew Geissler const std::string* mac = 305d5afb2caSAndrew Geissler std::get_if<std::string>(&propertyPair.second); 306d5afb2caSAndrew Geissler if (mac != nullptr) 307d5afb2caSAndrew Geissler { 308d5afb2caSAndrew Geissler ethData.mac_address = *mac; 309d5afb2caSAndrew Geissler } 310d5afb2caSAndrew Geissler } 311d5afb2caSAndrew Geissler } 312d5afb2caSAndrew Geissler } 313d5afb2caSAndrew Geissler else if (ifacePair.first == 314d5afb2caSAndrew Geissler "xyz.openbmc_project.Network.EthernetInterface") 315d5afb2caSAndrew Geissler { 316d5afb2caSAndrew Geissler for (const auto& propertyPair : ifacePair.second) 317d5afb2caSAndrew Geissler { 318d5afb2caSAndrew Geissler if (propertyPair.first == "DHCPEnabled") 319d5afb2caSAndrew Geissler { 320d5afb2caSAndrew Geissler const std::string* dhcp = 321d5afb2caSAndrew Geissler std::get_if<std::string>(&propertyPair.second); 322d5afb2caSAndrew Geissler if (dhcp != nullptr) 323d5afb2caSAndrew Geissler { 324d5afb2caSAndrew Geissler ethData.DHCPEnabled = *dhcp; 325d5afb2caSAndrew Geissler break; // Interested on only "DHCPEnabled". 326d5afb2caSAndrew Geissler // Stop parsing since we got the 327d5afb2caSAndrew Geissler // "DHCPEnabled" value. 328d5afb2caSAndrew Geissler } 329d5afb2caSAndrew Geissler } 330d5afb2caSAndrew Geissler } 331d5afb2caSAndrew Geissler } 332d5afb2caSAndrew Geissler } 333d5afb2caSAndrew Geissler if (objpath.first == "/xyz/openbmc_project/network/hypervisor/" + 334d5afb2caSAndrew Geissler ethIfaceId + "/ipv4/addr0") 335d5afb2caSAndrew Geissler { 336d5afb2caSAndrew Geissler std::pair<boost::container::flat_set<IPv4AddressData>::iterator, 337d5afb2caSAndrew Geissler bool> 338d5afb2caSAndrew Geissler it = ipv4Config.insert(IPv4AddressData{}); 339d5afb2caSAndrew Geissler IPv4AddressData& ipv4Address = *it.first; 340d5afb2caSAndrew Geissler if (ifacePair.first == "xyz.openbmc_project.Object.Enable") 341d5afb2caSAndrew Geissler { 342d5afb2caSAndrew Geissler for (auto& property : ifacePair.second) 343d5afb2caSAndrew Geissler { 344d5afb2caSAndrew Geissler if (property.first == "Enabled") 345d5afb2caSAndrew Geissler { 346d5afb2caSAndrew Geissler const bool* intfEnable = 347d5afb2caSAndrew Geissler std::get_if<bool>(&property.second); 348d5afb2caSAndrew Geissler if (intfEnable != nullptr) 349d5afb2caSAndrew Geissler { 350d5afb2caSAndrew Geissler ipv4Address.isActive = *intfEnable; 351d5afb2caSAndrew Geissler break; 352d5afb2caSAndrew Geissler } 353d5afb2caSAndrew Geissler } 354d5afb2caSAndrew Geissler } 355d5afb2caSAndrew Geissler } 356d5afb2caSAndrew Geissler if (ifacePair.first == "xyz.openbmc_project.Network.IP") 357d5afb2caSAndrew Geissler { 358d5afb2caSAndrew Geissler for (auto& property : ifacePair.second) 359d5afb2caSAndrew Geissler { 360d5afb2caSAndrew Geissler if (property.first == "Address") 361d5afb2caSAndrew Geissler { 362d5afb2caSAndrew Geissler const std::string* address = 363d5afb2caSAndrew Geissler std::get_if<std::string>(&property.second); 364d5afb2caSAndrew Geissler if (address != nullptr) 365d5afb2caSAndrew Geissler { 366d5afb2caSAndrew Geissler ipv4Address.address = *address; 367d5afb2caSAndrew Geissler } 368d5afb2caSAndrew Geissler } 369d5afb2caSAndrew Geissler else if (property.first == "Origin") 370d5afb2caSAndrew Geissler { 371d5afb2caSAndrew Geissler const std::string* origin = 372d5afb2caSAndrew Geissler std::get_if<std::string>(&property.second); 373d5afb2caSAndrew Geissler if (origin != nullptr) 374d5afb2caSAndrew Geissler { 375d5afb2caSAndrew Geissler ipv4Address.origin = 376d5afb2caSAndrew Geissler translateAddressOriginDbusToRedfish(*origin, 377d5afb2caSAndrew Geissler true); 378d5afb2caSAndrew Geissler } 379d5afb2caSAndrew Geissler } 380d5afb2caSAndrew Geissler else if (property.first == "PrefixLength") 381d5afb2caSAndrew Geissler { 382d5afb2caSAndrew Geissler const uint8_t* mask = 383d5afb2caSAndrew Geissler std::get_if<uint8_t>(&property.second); 384d5afb2caSAndrew Geissler if (mask != nullptr) 385d5afb2caSAndrew Geissler { 386d5afb2caSAndrew Geissler // convert it to the string 387d5afb2caSAndrew Geissler ipv4Address.netmask = getNetmask(*mask); 388d5afb2caSAndrew Geissler } 389d5afb2caSAndrew Geissler } 390d5afb2caSAndrew Geissler else 391d5afb2caSAndrew Geissler { 392d5afb2caSAndrew Geissler BMCWEB_LOG_ERROR 393d5afb2caSAndrew Geissler << "Got extra property: " << property.first 394d5afb2caSAndrew Geissler << " on the " << objpath.first.str << " object"; 395d5afb2caSAndrew Geissler } 396d5afb2caSAndrew Geissler } 397d5afb2caSAndrew Geissler } 398d5afb2caSAndrew Geissler } 399d5afb2caSAndrew Geissler if (objpath.first == "/xyz/openbmc_project/network/hypervisor") 400d5afb2caSAndrew Geissler { 401d5afb2caSAndrew Geissler // System configuration shows up in the global namespace, so no 402d5afb2caSAndrew Geissler // need to check eth number 403d5afb2caSAndrew Geissler if (ifacePair.first == 404d5afb2caSAndrew Geissler "xyz.openbmc_project.Network.SystemConfiguration") 405d5afb2caSAndrew Geissler { 406d5afb2caSAndrew Geissler for (const auto& propertyPair : ifacePair.second) 407d5afb2caSAndrew Geissler { 408d5afb2caSAndrew Geissler if (propertyPair.first == "HostName") 409d5afb2caSAndrew Geissler { 410d5afb2caSAndrew Geissler const std::string* hostName = 411d5afb2caSAndrew Geissler std::get_if<std::string>(&propertyPair.second); 412d5afb2caSAndrew Geissler if (hostName != nullptr) 413d5afb2caSAndrew Geissler { 414d5afb2caSAndrew Geissler ethData.hostname = *hostName; 415d5afb2caSAndrew Geissler } 416d5afb2caSAndrew Geissler } 417d5afb2caSAndrew Geissler else if (propertyPair.first == "DefaultGateway") 418d5afb2caSAndrew Geissler { 419d5afb2caSAndrew Geissler const std::string* defaultGateway = 420d5afb2caSAndrew Geissler std::get_if<std::string>(&propertyPair.second); 421d5afb2caSAndrew Geissler if (defaultGateway != nullptr) 422d5afb2caSAndrew Geissler { 423d5afb2caSAndrew Geissler ethData.default_gateway = *defaultGateway; 424d5afb2caSAndrew Geissler } 425d5afb2caSAndrew Geissler } 426d5afb2caSAndrew Geissler } 427d5afb2caSAndrew Geissler } 428d5afb2caSAndrew Geissler } 429d5afb2caSAndrew Geissler } 430d5afb2caSAndrew Geissler } 431d5afb2caSAndrew Geissler return idFound; 432d5afb2caSAndrew Geissler } 433d5afb2caSAndrew Geissler /** 434d5afb2caSAndrew Geissler * Function that retrieves all properties for given Hypervisor Ethernet 435d5afb2caSAndrew Geissler * Interface Object from Settings Manager 436d5afb2caSAndrew Geissler * @param ethIfaceId Hypervisor ethernet interface id to query on DBus 437d5afb2caSAndrew Geissler * @param callback a function that shall be called to convert Dbus output 438d5afb2caSAndrew Geissler * into JSON 439d5afb2caSAndrew Geissler */ 440d5afb2caSAndrew Geissler template <typename CallbackFunc> 441d5afb2caSAndrew Geissler void getHypervisorIfaceData(const std::string& ethIfaceId, 442d5afb2caSAndrew Geissler CallbackFunc&& callback) 443d5afb2caSAndrew Geissler { 444d5afb2caSAndrew Geissler crow::connections::systemBus->async_method_call( 445d5afb2caSAndrew Geissler [ethIfaceId{std::string{ethIfaceId}}, 446d5afb2caSAndrew Geissler callback{std::move(callback)}](const boost::system::error_code error, 447d5afb2caSAndrew Geissler const GetManagedObjects& resp) { 448d5afb2caSAndrew Geissler EthernetInterfaceData ethData{}; 449d5afb2caSAndrew Geissler boost::container::flat_set<IPv4AddressData> ipv4Data; 450d5afb2caSAndrew Geissler if (error) 451d5afb2caSAndrew Geissler { 452d5afb2caSAndrew Geissler callback(false, ethData, ipv4Data); 453d5afb2caSAndrew Geissler return; 454d5afb2caSAndrew Geissler } 455d5afb2caSAndrew Geissler 456d5afb2caSAndrew Geissler bool found = extractHypervisorInterfaceData(ethIfaceId, resp, 457d5afb2caSAndrew Geissler ethData, ipv4Data); 458d5afb2caSAndrew Geissler if (!found) 459d5afb2caSAndrew Geissler { 460d5afb2caSAndrew Geissler BMCWEB_LOG_INFO << "Hypervisor Interface not found"; 461d5afb2caSAndrew Geissler } 462d5afb2caSAndrew Geissler callback(found, ethData, ipv4Data); 463d5afb2caSAndrew Geissler }, 464d5afb2caSAndrew Geissler "xyz.openbmc_project.Settings", "/", 465d5afb2caSAndrew Geissler "org.freedesktop.DBus.ObjectManager", "GetManagedObjects"); 466d5afb2caSAndrew Geissler } 467d5afb2caSAndrew Geissler 468d5afb2caSAndrew Geissler /** 469d5afb2caSAndrew Geissler * @brief Sets the Hypervisor Interface IPAddress DBUS 470d5afb2caSAndrew Geissler * 471d5afb2caSAndrew Geissler * @param[in] aResp Shared pointer for generating response message. 472d5afb2caSAndrew Geissler * @param[in] ipv4Address Address from the incoming request 473d5afb2caSAndrew Geissler * @param[in] ethIfaceId Hypervisor Interface Id 474d5afb2caSAndrew Geissler * 475d5afb2caSAndrew Geissler * @return None. 476d5afb2caSAndrew Geissler */ 477d5afb2caSAndrew Geissler inline void setHypervisorIPv4Address(const std::shared_ptr<AsyncResp>& aResp, 478d5afb2caSAndrew Geissler const std::string& ethIfaceId, 479d5afb2caSAndrew Geissler const std::string& ipv4Address) 480d5afb2caSAndrew Geissler { 481d5afb2caSAndrew Geissler BMCWEB_LOG_DEBUG << "Setting the Hypervisor IPaddress : " << ipv4Address 482d5afb2caSAndrew Geissler << " on Iface: " << ethIfaceId; 483d5afb2caSAndrew Geissler crow::connections::systemBus->async_method_call( 484d5afb2caSAndrew Geissler [aResp](const boost::system::error_code ec) { 485d5afb2caSAndrew Geissler if (ec) 486d5afb2caSAndrew Geissler { 487d5afb2caSAndrew Geissler BMCWEB_LOG_ERROR << "DBUS response error " << ec; 488d5afb2caSAndrew Geissler return; 489d5afb2caSAndrew Geissler } 490d5afb2caSAndrew Geissler BMCWEB_LOG_DEBUG << "Hypervisor IPaddress is Set"; 491d5afb2caSAndrew Geissler }, 492d5afb2caSAndrew Geissler "xyz.openbmc_project.Settings", 493d5afb2caSAndrew Geissler "/xyz/openbmc_project/network/hypervisor/" + ethIfaceId + "/ipv4/addr0", 494d5afb2caSAndrew Geissler "org.freedesktop.DBus.Properties", "Set", 495d5afb2caSAndrew Geissler "xyz.openbmc_project.Network.IP", "Address", 496d5afb2caSAndrew Geissler std::variant<std::string>(ipv4Address)); 497d5afb2caSAndrew Geissler } 498d5afb2caSAndrew Geissler 499d5afb2caSAndrew Geissler /** 500d5afb2caSAndrew Geissler * @brief Sets the Hypervisor Interface SubnetMask DBUS 501d5afb2caSAndrew Geissler * 502d5afb2caSAndrew Geissler * @param[in] aResp Shared pointer for generating response message. 503d5afb2caSAndrew Geissler * @param[in] subnet SubnetMask from the incoming request 504d5afb2caSAndrew Geissler * @param[in] ethIfaceId Hypervisor Interface Id 505d5afb2caSAndrew Geissler * 506d5afb2caSAndrew Geissler * @return None. 507d5afb2caSAndrew Geissler */ 508d5afb2caSAndrew Geissler inline void setHypervisorIPv4Subnet(const std::shared_ptr<AsyncResp>& aResp, 509d5afb2caSAndrew Geissler const std::string& ethIfaceId, 510d5afb2caSAndrew Geissler const uint8_t subnet) 511d5afb2caSAndrew Geissler { 512d5afb2caSAndrew Geissler BMCWEB_LOG_DEBUG << "Setting the Hypervisor subnet : " << subnet 513d5afb2caSAndrew Geissler << " on Iface: " << ethIfaceId; 514d5afb2caSAndrew Geissler 515d5afb2caSAndrew Geissler crow::connections::systemBus->async_method_call( 516d5afb2caSAndrew Geissler [aResp](const boost::system::error_code ec) { 517d5afb2caSAndrew Geissler if (ec) 518d5afb2caSAndrew Geissler { 519d5afb2caSAndrew Geissler BMCWEB_LOG_ERROR << "DBUS response error " << ec; 520d5afb2caSAndrew Geissler return; 521d5afb2caSAndrew Geissler } 522d5afb2caSAndrew Geissler BMCWEB_LOG_DEBUG << "SubnetMask is Set"; 523d5afb2caSAndrew Geissler }, 524d5afb2caSAndrew Geissler "xyz.openbmc_project.Settings", 525d5afb2caSAndrew Geissler "/xyz/openbmc_project/network/hypervisor/" + ethIfaceId + "/ipv4/addr0", 526d5afb2caSAndrew Geissler "org.freedesktop.DBus.Properties", "Set", 527d5afb2caSAndrew Geissler "xyz.openbmc_project.Network.IP", "PrefixLength", 528d5afb2caSAndrew Geissler std::variant<uint8_t>(subnet)); 529d5afb2caSAndrew Geissler } 530d5afb2caSAndrew Geissler 531d5afb2caSAndrew Geissler /** 532d5afb2caSAndrew Geissler * @brief Sets the Hypervisor Interface Gateway DBUS 533d5afb2caSAndrew Geissler * 534d5afb2caSAndrew Geissler * @param[in] aResp Shared pointer for generating response message. 535d5afb2caSAndrew Geissler * @param[in] gateway Gateway from the incoming request 536d5afb2caSAndrew Geissler * @param[in] ethIfaceId Hypervisor Interface Id 537d5afb2caSAndrew Geissler * 538d5afb2caSAndrew Geissler * @return None. 539d5afb2caSAndrew Geissler */ 540d5afb2caSAndrew Geissler inline void setHypervisorIPv4Gateway(const std::shared_ptr<AsyncResp>& aResp, 541d5afb2caSAndrew Geissler const std::string& gateway) 542d5afb2caSAndrew Geissler { 543d5afb2caSAndrew Geissler BMCWEB_LOG_DEBUG 544d5afb2caSAndrew Geissler << "Setting the DefaultGateway to the last configured gateway"; 545d5afb2caSAndrew Geissler 546d5afb2caSAndrew Geissler crow::connections::systemBus->async_method_call( 547d5afb2caSAndrew Geissler [aResp](const boost::system::error_code ec) { 548d5afb2caSAndrew Geissler if (ec) 549d5afb2caSAndrew Geissler { 550d5afb2caSAndrew Geissler BMCWEB_LOG_ERROR << "DBUS response error " << ec; 551d5afb2caSAndrew Geissler return; 552d5afb2caSAndrew Geissler } 553d5afb2caSAndrew Geissler BMCWEB_LOG_DEBUG << "Default Gateway is Set"; 554d5afb2caSAndrew Geissler }, 555d5afb2caSAndrew Geissler "xyz.openbmc_project.Settings", 556d5afb2caSAndrew Geissler "/xyz/openbmc_project/network/hypervisor", 557d5afb2caSAndrew Geissler "org.freedesktop.DBus.Properties", "Set", 558d5afb2caSAndrew Geissler "xyz.openbmc_project.Network.SystemConfiguration", "DefaultGateway", 559d5afb2caSAndrew Geissler std::variant<std::string>(gateway)); 560d5afb2caSAndrew Geissler } 561d5afb2caSAndrew Geissler 562d5afb2caSAndrew Geissler /** 563d5afb2caSAndrew Geissler * @brief Creates a static IPv4 entry 564d5afb2caSAndrew Geissler * 565d5afb2caSAndrew Geissler * @param[in] ifaceId Id of interface upon which to create the IPv4 entry 566d5afb2caSAndrew Geissler * @param[in] prefixLength IPv4 prefix syntax for the subnet mask 567d5afb2caSAndrew Geissler * @param[in] gateway IPv4 address of this interfaces gateway 568d5afb2caSAndrew Geissler * @param[in] address IPv4 address to assign to this interface 569d5afb2caSAndrew Geissler * @param[io] asyncResp Response object that will be returned to client 570d5afb2caSAndrew Geissler * 571d5afb2caSAndrew Geissler * @return None 572d5afb2caSAndrew Geissler */ 573d5afb2caSAndrew Geissler inline void createHypervisorIPv4(const std::string& ifaceId, 574d5afb2caSAndrew Geissler uint8_t prefixLength, 575d5afb2caSAndrew Geissler const std::string& gateway, 576d5afb2caSAndrew Geissler const std::string& address, 577d5afb2caSAndrew Geissler const std::shared_ptr<AsyncResp>& asyncResp) 578d5afb2caSAndrew Geissler { 579d5afb2caSAndrew Geissler setHypervisorIPv4Address(asyncResp, ifaceId, address); 580d5afb2caSAndrew Geissler setHypervisorIPv4Gateway(asyncResp, gateway); 581d5afb2caSAndrew Geissler setHypervisorIPv4Subnet(asyncResp, ifaceId, prefixLength); 582d5afb2caSAndrew Geissler } 583d5afb2caSAndrew Geissler 584d5afb2caSAndrew Geissler /** 585d5afb2caSAndrew Geissler * @brief Deletes given IPv4 interface 586d5afb2caSAndrew Geissler * 587d5afb2caSAndrew Geissler * @param[in] ifaceId Id of interface whose IP should be deleted 588d5afb2caSAndrew Geissler * @param[io] asyncResp Response object that will be returned to client 589d5afb2caSAndrew Geissler * 590d5afb2caSAndrew Geissler * @return None 591d5afb2caSAndrew Geissler */ 592d5afb2caSAndrew Geissler inline void deleteHypervisorIPv4(const std::string& ifaceId, 593d5afb2caSAndrew Geissler const std::shared_ptr<AsyncResp>& asyncResp) 594d5afb2caSAndrew Geissler { 595d5afb2caSAndrew Geissler std::string address = "0.0.0.0"; 596d5afb2caSAndrew Geissler std::string gateway = "0.0.0.0"; 597d5afb2caSAndrew Geissler const uint8_t prefixLength = 0; 598d5afb2caSAndrew Geissler setHypervisorIPv4Address(asyncResp, ifaceId, address); 599d5afb2caSAndrew Geissler setHypervisorIPv4Gateway(asyncResp, gateway); 600d5afb2caSAndrew Geissler setHypervisorIPv4Subnet(asyncResp, ifaceId, prefixLength); 601d5afb2caSAndrew Geissler } 602d5afb2caSAndrew Geissler 603d5afb2caSAndrew Geissler /** 604d5afb2caSAndrew Geissler * HypervisorInterface derived class for delivering Ethernet Schema 605d5afb2caSAndrew Geissler */ 606d5afb2caSAndrew Geissler class HypervisorInterface : public Node 607d5afb2caSAndrew Geissler { 608d5afb2caSAndrew Geissler public: 609d5afb2caSAndrew Geissler /* 610d5afb2caSAndrew Geissler * Default Constructor 611d5afb2caSAndrew Geissler */ 612d5afb2caSAndrew Geissler HypervisorInterface(App& app) : 613d5afb2caSAndrew Geissler Node(app, "/redfish/v1/Systems/hypervisor/EthernetInterfaces/<str>/", 614d5afb2caSAndrew Geissler std::string()) 615d5afb2caSAndrew Geissler { 616d5afb2caSAndrew Geissler entityPrivileges = { 617d5afb2caSAndrew Geissler {boost::beast::http::verb::get, {{"Login"}}}, 618d5afb2caSAndrew Geissler {boost::beast::http::verb::head, {{"Login"}}}, 619d5afb2caSAndrew Geissler {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}}; 620d5afb2caSAndrew Geissler } 621d5afb2caSAndrew Geissler 622d5afb2caSAndrew Geissler private: 623d5afb2caSAndrew Geissler void parseInterfaceData( 624d5afb2caSAndrew Geissler nlohmann::json& jsonResponse, const std::string& ifaceId, 625d5afb2caSAndrew Geissler const EthernetInterfaceData& ethData, 626d5afb2caSAndrew Geissler const boost::container::flat_set<IPv4AddressData>& ipv4Data) 627d5afb2caSAndrew Geissler { 628d5afb2caSAndrew Geissler jsonResponse["Id"] = ifaceId; 629d5afb2caSAndrew Geissler jsonResponse["@odata.id"] = 630d5afb2caSAndrew Geissler "/redfish/v1/Systems/hypervisor/EthernetInterfaces/" + ifaceId; 631d5afb2caSAndrew Geissler jsonResponse["InterfaceEnabled"] = true; 632d5afb2caSAndrew Geissler jsonResponse["MACAddress"] = ethData.mac_address; 633d5afb2caSAndrew Geissler 634d5afb2caSAndrew Geissler jsonResponse["HostName"] = ethData.hostname; 635d5afb2caSAndrew Geissler jsonResponse["DHCPv4"]["DHCPEnabled"] = 636d5afb2caSAndrew Geissler translateDHCPEnabledToBool(ethData.DHCPEnabled, true); 637d5afb2caSAndrew Geissler 638d5afb2caSAndrew Geissler nlohmann::json& ipv4Array = jsonResponse["IPv4Addresses"]; 639d5afb2caSAndrew Geissler nlohmann::json& ipv4StaticArray = jsonResponse["IPv4StaticAddresses"]; 640d5afb2caSAndrew Geissler ipv4Array = nlohmann::json::array(); 641d5afb2caSAndrew Geissler ipv4StaticArray = nlohmann::json::array(); 642d5afb2caSAndrew Geissler for (auto& ipv4Config : ipv4Data) 643d5afb2caSAndrew Geissler { 644d5afb2caSAndrew Geissler if (ipv4Config.isActive) 645d5afb2caSAndrew Geissler { 646d5afb2caSAndrew Geissler 647d5afb2caSAndrew Geissler ipv4Array.push_back({{"AddressOrigin", ipv4Config.origin}, 648d5afb2caSAndrew Geissler {"SubnetMask", ipv4Config.netmask}, 649d5afb2caSAndrew Geissler {"Address", ipv4Config.address}, 650d5afb2caSAndrew Geissler {"Gateway", ethData.default_gateway}}); 651d5afb2caSAndrew Geissler if (ipv4Config.origin == "Static") 652d5afb2caSAndrew Geissler { 653d5afb2caSAndrew Geissler ipv4StaticArray.push_back( 654d5afb2caSAndrew Geissler {{"AddressOrigin", ipv4Config.origin}, 655d5afb2caSAndrew Geissler {"SubnetMask", ipv4Config.netmask}, 656d5afb2caSAndrew Geissler {"Address", ipv4Config.address}, 657d5afb2caSAndrew Geissler {"Gateway", ethData.default_gateway}}); 658d5afb2caSAndrew Geissler } 659d5afb2caSAndrew Geissler } 660d5afb2caSAndrew Geissler } 661d5afb2caSAndrew Geissler } 662d5afb2caSAndrew Geissler 663d5afb2caSAndrew Geissler void handleHypervisorIPv4StaticPatch( 664d5afb2caSAndrew Geissler const std::string& ifaceId, const nlohmann::json& input, 665d5afb2caSAndrew Geissler const std::shared_ptr<AsyncResp>& asyncResp) 666d5afb2caSAndrew Geissler { 667d5afb2caSAndrew Geissler if ((!input.is_array()) || input.empty()) 668d5afb2caSAndrew Geissler { 669d5afb2caSAndrew Geissler messages::propertyValueTypeError(asyncResp->res, input.dump(), 670d5afb2caSAndrew Geissler "IPv4StaticAddresses"); 671d5afb2caSAndrew Geissler return; 672d5afb2caSAndrew Geissler } 673d5afb2caSAndrew Geissler 674d5afb2caSAndrew Geissler // Hypervisor considers the first IP address in the array list 675d5afb2caSAndrew Geissler // as the Hypervisor's virtual management interface supports single IPv4 676d5afb2caSAndrew Geissler // address 677d5afb2caSAndrew Geissler const nlohmann::json& thisJson = input[0]; 678d5afb2caSAndrew Geissler 679d5afb2caSAndrew Geissler // For the error string 680d5afb2caSAndrew Geissler std::string pathString = "IPv4StaticAddresses/1"; 681d5afb2caSAndrew Geissler 682d5afb2caSAndrew Geissler if (!thisJson.is_null() && !thisJson.empty()) 683d5afb2caSAndrew Geissler { 684d5afb2caSAndrew Geissler std::optional<std::string> address; 685d5afb2caSAndrew Geissler std::optional<std::string> subnetMask; 686d5afb2caSAndrew Geissler std::optional<std::string> gateway; 687d5afb2caSAndrew Geissler nlohmann::json thisJsonCopy = thisJson; 688d5afb2caSAndrew Geissler if (!json_util::readJson(thisJsonCopy, asyncResp->res, "Address", 689d5afb2caSAndrew Geissler address, "SubnetMask", subnetMask, 690d5afb2caSAndrew Geissler "Gateway", gateway)) 691d5afb2caSAndrew Geissler { 69271f52d96SEd Tanous messages::propertyValueFormatError( 69371f52d96SEd Tanous asyncResp->res, 69471f52d96SEd Tanous thisJson.dump(2, ' ', true, 69571f52d96SEd Tanous nlohmann::json::error_handler_t::replace), 69671f52d96SEd Tanous pathString); 697d5afb2caSAndrew Geissler return; 698d5afb2caSAndrew Geissler } 699d5afb2caSAndrew Geissler 700d5afb2caSAndrew Geissler uint8_t prefixLength = 0; 701d5afb2caSAndrew Geissler bool errorInEntry = false; 702d5afb2caSAndrew Geissler if (address) 703d5afb2caSAndrew Geissler { 704d5afb2caSAndrew Geissler if (!ipv4VerifyIpAndGetBitcount(*address)) 705d5afb2caSAndrew Geissler { 706d5afb2caSAndrew Geissler messages::propertyValueFormatError(asyncResp->res, *address, 707d5afb2caSAndrew Geissler pathString + "/Address"); 708d5afb2caSAndrew Geissler errorInEntry = true; 709d5afb2caSAndrew Geissler } 710d5afb2caSAndrew Geissler } 711d5afb2caSAndrew Geissler else 712d5afb2caSAndrew Geissler { 713d5afb2caSAndrew Geissler messages::propertyMissing(asyncResp->res, 714d5afb2caSAndrew Geissler pathString + "/Address"); 715d5afb2caSAndrew Geissler errorInEntry = true; 716d5afb2caSAndrew Geissler } 717d5afb2caSAndrew Geissler 718d5afb2caSAndrew Geissler if (subnetMask) 719d5afb2caSAndrew Geissler { 720d5afb2caSAndrew Geissler if (!ipv4VerifyIpAndGetBitcount(*subnetMask, &prefixLength)) 721d5afb2caSAndrew Geissler { 722d5afb2caSAndrew Geissler messages::propertyValueFormatError( 723d5afb2caSAndrew Geissler asyncResp->res, *subnetMask, 724d5afb2caSAndrew Geissler pathString + "/SubnetMask"); 725d5afb2caSAndrew Geissler errorInEntry = true; 726d5afb2caSAndrew Geissler } 727d5afb2caSAndrew Geissler } 728d5afb2caSAndrew Geissler else 729d5afb2caSAndrew Geissler { 730d5afb2caSAndrew Geissler messages::propertyMissing(asyncResp->res, 731d5afb2caSAndrew Geissler pathString + "/SubnetMask"); 732d5afb2caSAndrew Geissler errorInEntry = true; 733d5afb2caSAndrew Geissler } 734d5afb2caSAndrew Geissler 735d5afb2caSAndrew Geissler if (gateway) 736d5afb2caSAndrew Geissler { 737d5afb2caSAndrew Geissler if (!ipv4VerifyIpAndGetBitcount(*gateway)) 738d5afb2caSAndrew Geissler { 739d5afb2caSAndrew Geissler messages::propertyValueFormatError(asyncResp->res, *gateway, 740d5afb2caSAndrew Geissler pathString + "/Gateway"); 741d5afb2caSAndrew Geissler errorInEntry = true; 742d5afb2caSAndrew Geissler } 743d5afb2caSAndrew Geissler } 744d5afb2caSAndrew Geissler else 745d5afb2caSAndrew Geissler { 746d5afb2caSAndrew Geissler messages::propertyMissing(asyncResp->res, 747d5afb2caSAndrew Geissler pathString + "/Gateway"); 748d5afb2caSAndrew Geissler errorInEntry = true; 749d5afb2caSAndrew Geissler } 750d5afb2caSAndrew Geissler 751d5afb2caSAndrew Geissler if (errorInEntry) 752d5afb2caSAndrew Geissler { 753d5afb2caSAndrew Geissler return; 754d5afb2caSAndrew Geissler } 755d5afb2caSAndrew Geissler 756d5afb2caSAndrew Geissler BMCWEB_LOG_DEBUG << "Calling createHypervisorIPv4 on : " << ifaceId 757d5afb2caSAndrew Geissler << "," << *address; 758d5afb2caSAndrew Geissler createHypervisorIPv4(ifaceId, prefixLength, *gateway, *address, 759d5afb2caSAndrew Geissler asyncResp); 760d5afb2caSAndrew Geissler // Set the DHCPEnabled to false since the Static IPv4 is set 761d5afb2caSAndrew Geissler setDHCPEnabled(ifaceId, false, asyncResp); 762d5afb2caSAndrew Geissler } 763d5afb2caSAndrew Geissler else 764d5afb2caSAndrew Geissler { 765d5afb2caSAndrew Geissler if (thisJson.is_null()) 766d5afb2caSAndrew Geissler { 767d5afb2caSAndrew Geissler deleteHypervisorIPv4(ifaceId, asyncResp); 768d5afb2caSAndrew Geissler } 769d5afb2caSAndrew Geissler } 770d5afb2caSAndrew Geissler } 771d5afb2caSAndrew Geissler 772d5afb2caSAndrew Geissler bool isHostnameValid(const std::string& hostName) 773d5afb2caSAndrew Geissler { 774d5afb2caSAndrew Geissler // As per RFC 1123 775d5afb2caSAndrew Geissler // Allow up to 255 characters 776d5afb2caSAndrew Geissler if (hostName.length() > 255) 777d5afb2caSAndrew Geissler { 778d5afb2caSAndrew Geissler return false; 779d5afb2caSAndrew Geissler } 780d5afb2caSAndrew Geissler // Validate the regex 781d5afb2caSAndrew Geissler const std::regex pattern( 782d5afb2caSAndrew Geissler "^[a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\\-]{0,61}[a-zA-Z0-9]$"); 783d5afb2caSAndrew Geissler 784d5afb2caSAndrew Geissler return std::regex_match(hostName, pattern); 785d5afb2caSAndrew Geissler } 786d5afb2caSAndrew Geissler 787d5afb2caSAndrew Geissler void handleHostnamePatch(const std::string& hostName, 788d5afb2caSAndrew Geissler const std::shared_ptr<AsyncResp>& asyncResp) 789d5afb2caSAndrew Geissler { 790d5afb2caSAndrew Geissler if (!isHostnameValid(hostName)) 791d5afb2caSAndrew Geissler { 792d5afb2caSAndrew Geissler messages::propertyValueFormatError(asyncResp->res, hostName, 793d5afb2caSAndrew Geissler "HostName"); 794d5afb2caSAndrew Geissler return; 795d5afb2caSAndrew Geissler } 796d5afb2caSAndrew Geissler 797d5afb2caSAndrew Geissler asyncResp->res.jsonValue["HostName"] = hostName; 798d5afb2caSAndrew Geissler crow::connections::systemBus->async_method_call( 799d5afb2caSAndrew Geissler [asyncResp](const boost::system::error_code ec) { 800d5afb2caSAndrew Geissler if (ec) 801d5afb2caSAndrew Geissler { 802d5afb2caSAndrew Geissler messages::internalError(asyncResp->res); 803d5afb2caSAndrew Geissler } 804d5afb2caSAndrew Geissler }, 805d5afb2caSAndrew Geissler "xyz.openbmc_project.Settings", 806d5afb2caSAndrew Geissler "/xyz/openbmc_project/network/hypervisor", 807d5afb2caSAndrew Geissler "org.freedesktop.DBus.Properties", "Set", 808d5afb2caSAndrew Geissler "xyz.openbmc_project.Network.SystemConfiguration", "HostName", 809d5afb2caSAndrew Geissler std::variant<std::string>(hostName)); 810d5afb2caSAndrew Geissler } 811d5afb2caSAndrew Geissler 812d5afb2caSAndrew Geissler void setIPv4InterfaceEnabled(const std::string& ifaceId, 813d5afb2caSAndrew Geissler const bool& isActive, 814d5afb2caSAndrew Geissler const std::shared_ptr<AsyncResp>& asyncResp) 815d5afb2caSAndrew Geissler { 816d5afb2caSAndrew Geissler crow::connections::systemBus->async_method_call( 817d5afb2caSAndrew Geissler [asyncResp](const boost::system::error_code ec) { 818d5afb2caSAndrew Geissler if (ec) 819d5afb2caSAndrew Geissler { 820d5afb2caSAndrew Geissler BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec; 821d5afb2caSAndrew Geissler messages::internalError(asyncResp->res); 822d5afb2caSAndrew Geissler return; 823d5afb2caSAndrew Geissler } 824d5afb2caSAndrew Geissler }, 825d5afb2caSAndrew Geissler "xyz.openbmc_project.Settings", 826d5afb2caSAndrew Geissler "/xyz/openbmc_project/network/hypervisor/" + ifaceId + 827d5afb2caSAndrew Geissler "/ipv4/addr0", 828d5afb2caSAndrew Geissler "org.freedesktop.DBus.Properties", "Set", 829d5afb2caSAndrew Geissler "xyz.openbmc_project.Object.Enable", "Enabled", 830d5afb2caSAndrew Geissler std::variant<bool>(isActive)); 831d5afb2caSAndrew Geissler } 832d5afb2caSAndrew Geissler 833d5afb2caSAndrew Geissler void setDHCPEnabled(const std::string& ifaceId, const bool& ipv4DHCPEnabled, 834d5afb2caSAndrew Geissler const std::shared_ptr<AsyncResp>& asyncResp) 835d5afb2caSAndrew Geissler { 836d5afb2caSAndrew Geissler const std::string dhcp = 837d5afb2caSAndrew Geissler getDhcpEnabledEnumeration(ipv4DHCPEnabled, false); 838d5afb2caSAndrew Geissler crow::connections::systemBus->async_method_call( 839d5afb2caSAndrew Geissler [asyncResp](const boost::system::error_code ec) { 840d5afb2caSAndrew Geissler if (ec) 841d5afb2caSAndrew Geissler { 842d5afb2caSAndrew Geissler BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec; 843d5afb2caSAndrew Geissler messages::internalError(asyncResp->res); 844d5afb2caSAndrew Geissler return; 845d5afb2caSAndrew Geissler } 846d5afb2caSAndrew Geissler }, 847d5afb2caSAndrew Geissler "xyz.openbmc_project.Settings", 848d5afb2caSAndrew Geissler "/xyz/openbmc_project/network/hypervisor/" + ifaceId, 849d5afb2caSAndrew Geissler "org.freedesktop.DBus.Properties", "Set", 850d5afb2caSAndrew Geissler "xyz.openbmc_project.Network.EthernetInterface", "DHCPEnabled", 851d5afb2caSAndrew Geissler std::variant<std::string>{dhcp}); 852d5afb2caSAndrew Geissler 853d5afb2caSAndrew Geissler // Set the IPv4 address origin to the DHCP / Static as per the new value 854d5afb2caSAndrew Geissler // of the DHCPEnabled property 855d5afb2caSAndrew Geissler std::string origin; 856d5afb2caSAndrew Geissler if (ipv4DHCPEnabled == false) 857d5afb2caSAndrew Geissler { 858d5afb2caSAndrew Geissler origin = "xyz.openbmc_project.Network.IP.AddressOrigin.Static"; 859d5afb2caSAndrew Geissler } 860d5afb2caSAndrew Geissler else 861d5afb2caSAndrew Geissler { 862d5afb2caSAndrew Geissler // DHCPEnabled is set to true. Delete the current IPv4 settings 863d5afb2caSAndrew Geissler // to receive the new values from DHCP server. 864d5afb2caSAndrew Geissler deleteHypervisorIPv4(ifaceId, asyncResp); 865d5afb2caSAndrew Geissler origin = "xyz.openbmc_project.Network.IP.AddressOrigin.DHCP"; 866d5afb2caSAndrew Geissler } 867d5afb2caSAndrew Geissler crow::connections::systemBus->async_method_call( 868d5afb2caSAndrew Geissler [asyncResp](const boost::system::error_code ec) { 869d5afb2caSAndrew Geissler if (ec) 870d5afb2caSAndrew Geissler { 871d5afb2caSAndrew Geissler BMCWEB_LOG_ERROR << "DBUS response error " << ec; 872d5afb2caSAndrew Geissler messages::internalError(asyncResp->res); 873d5afb2caSAndrew Geissler return; 874d5afb2caSAndrew Geissler } 875d5afb2caSAndrew Geissler BMCWEB_LOG_DEBUG << "Hypervisor IPaddress Origin is Set"; 876d5afb2caSAndrew Geissler }, 877d5afb2caSAndrew Geissler "xyz.openbmc_project.Settings", 878d5afb2caSAndrew Geissler "/xyz/openbmc_project/network/hypervisor/" + ifaceId + 879d5afb2caSAndrew Geissler "/ipv4/addr0", 880d5afb2caSAndrew Geissler "org.freedesktop.DBus.Properties", "Set", 881d5afb2caSAndrew Geissler "xyz.openbmc_project.Network.IP", "Origin", 882d5afb2caSAndrew Geissler std::variant<std::string>(origin)); 883d5afb2caSAndrew Geissler } 884d5afb2caSAndrew Geissler 885d5afb2caSAndrew Geissler /** 886d5afb2caSAndrew Geissler * Functions triggers appropriate requests on DBus 887d5afb2caSAndrew Geissler */ 888d5afb2caSAndrew Geissler void doGet(crow::Response& res, const crow::Request&, 889d5afb2caSAndrew Geissler const std::vector<std::string>& params) override 890d5afb2caSAndrew Geissler { 891d5afb2caSAndrew Geissler std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res); 892d5afb2caSAndrew Geissler if (params.size() != 1) 893d5afb2caSAndrew Geissler { 894d5afb2caSAndrew Geissler messages::internalError(asyncResp->res); 895d5afb2caSAndrew Geissler return; 896d5afb2caSAndrew Geissler } 897d5afb2caSAndrew Geissler 898d5afb2caSAndrew Geissler getHypervisorIfaceData( 899d5afb2caSAndrew Geissler params[0], 900d5afb2caSAndrew Geissler [this, asyncResp, ifaceId{std::string(params[0])}]( 901d5afb2caSAndrew Geissler const bool& success, const EthernetInterfaceData& ethData, 902d5afb2caSAndrew Geissler const boost::container::flat_set<IPv4AddressData>& ipv4Data) { 903d5afb2caSAndrew Geissler if (!success) 904d5afb2caSAndrew Geissler { 905d5afb2caSAndrew Geissler messages::resourceNotFound(asyncResp->res, 906d5afb2caSAndrew Geissler "EthernetInterface", ifaceId); 907d5afb2caSAndrew Geissler return; 908d5afb2caSAndrew Geissler } 909d5afb2caSAndrew Geissler asyncResp->res.jsonValue["@odata.type"] = 910d5afb2caSAndrew Geissler "#EthernetInterface.v1_5_1.EthernetInterface"; 911d5afb2caSAndrew Geissler asyncResp->res.jsonValue["Name"] = 912d5afb2caSAndrew Geissler "Hypervisor Ethernet Interface"; 913d5afb2caSAndrew Geissler asyncResp->res.jsonValue["Description"] = 914d5afb2caSAndrew Geissler "Hypervisor's Virtual Management Ethernet Interface"; 915d5afb2caSAndrew Geissler parseInterfaceData(asyncResp->res.jsonValue, ifaceId, ethData, 916d5afb2caSAndrew Geissler ipv4Data); 917d5afb2caSAndrew Geissler }); 918d5afb2caSAndrew Geissler } 919d5afb2caSAndrew Geissler 920d5afb2caSAndrew Geissler void doPatch(crow::Response& res, const crow::Request& req, 921d5afb2caSAndrew Geissler const std::vector<std::string>& params) override 922d5afb2caSAndrew Geissler { 923d5afb2caSAndrew Geissler std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res); 924d5afb2caSAndrew Geissler if (params.size() != 1) 925d5afb2caSAndrew Geissler { 926d5afb2caSAndrew Geissler messages::internalError(asyncResp->res); 927d5afb2caSAndrew Geissler return; 928d5afb2caSAndrew Geissler } 929d5afb2caSAndrew Geissler 930d5afb2caSAndrew Geissler const std::string& ifaceId = params[0]; 931d5afb2caSAndrew Geissler std::optional<std::string> hostName; 932d5afb2caSAndrew Geissler std::optional<nlohmann::json> ipv4StaticAddresses; 933d5afb2caSAndrew Geissler std::optional<nlohmann::json> ipv4Addresses; 934d5afb2caSAndrew Geissler std::optional<nlohmann::json> dhcpv4; 935d5afb2caSAndrew Geissler std::optional<bool> ipv4DHCPEnabled; 936d5afb2caSAndrew Geissler 937d5afb2caSAndrew Geissler if (!json_util::readJson(req, res, "HostName", hostName, 938d5afb2caSAndrew Geissler "IPv4StaticAddresses", ipv4StaticAddresses, 939d5afb2caSAndrew Geissler "IPv4Addresses", ipv4Addresses, "DHCPv4", 940d5afb2caSAndrew Geissler dhcpv4)) 941d5afb2caSAndrew Geissler { 942d5afb2caSAndrew Geissler return; 943d5afb2caSAndrew Geissler } 944d5afb2caSAndrew Geissler 945d5afb2caSAndrew Geissler if (ipv4Addresses) 946d5afb2caSAndrew Geissler { 947d5afb2caSAndrew Geissler messages::propertyNotWritable(asyncResp->res, "IPv4Addresses"); 948d5afb2caSAndrew Geissler } 949d5afb2caSAndrew Geissler 950d5afb2caSAndrew Geissler if (dhcpv4) 951d5afb2caSAndrew Geissler { 952d5afb2caSAndrew Geissler if (!json_util::readJson(*dhcpv4, res, "DHCPEnabled", 953d5afb2caSAndrew Geissler ipv4DHCPEnabled)) 954d5afb2caSAndrew Geissler { 955d5afb2caSAndrew Geissler return; 956d5afb2caSAndrew Geissler } 957d5afb2caSAndrew Geissler } 958d5afb2caSAndrew Geissler 959d5afb2caSAndrew Geissler getHypervisorIfaceData( 960d5afb2caSAndrew Geissler ifaceId, 961d5afb2caSAndrew Geissler [this, asyncResp, ifaceId, hostName = std::move(hostName), 962d5afb2caSAndrew Geissler ipv4StaticAddresses = std::move(ipv4StaticAddresses), 963d5afb2caSAndrew Geissler ipv4DHCPEnabled, dhcpv4 = std::move(dhcpv4)]( 964d5afb2caSAndrew Geissler const bool& success, const EthernetInterfaceData& ethData, 965d5afb2caSAndrew Geissler const boost::container::flat_set<IPv4AddressData>&) { 966d5afb2caSAndrew Geissler if (!success) 967d5afb2caSAndrew Geissler { 968d5afb2caSAndrew Geissler messages::resourceNotFound(asyncResp->res, 969d5afb2caSAndrew Geissler "EthernetInterface", ifaceId); 970d5afb2caSAndrew Geissler return; 971d5afb2caSAndrew Geissler } 972d5afb2caSAndrew Geissler 973d5afb2caSAndrew Geissler if (ipv4StaticAddresses) 974d5afb2caSAndrew Geissler { 975d5afb2caSAndrew Geissler const nlohmann::json& ipv4Static = *ipv4StaticAddresses; 976d5afb2caSAndrew Geissler const nlohmann::json& ipv4Json = ipv4Static[0]; 977d5afb2caSAndrew Geissler // Check if the param is 'null'. If its null, it means that 978d5afb2caSAndrew Geissler // user wants to delete the IP address. Deleting the IP 979d5afb2caSAndrew Geissler // address is allowed only if its statically configured. 980d5afb2caSAndrew Geissler // Deleting the address originated from DHCP is not allowed. 981d5afb2caSAndrew Geissler if ((ipv4Json.is_null()) && 982d5afb2caSAndrew Geissler (translateDHCPEnabledToBool(ethData.DHCPEnabled, true))) 983d5afb2caSAndrew Geissler { 984d5afb2caSAndrew Geissler BMCWEB_LOG_INFO 985d5afb2caSAndrew Geissler << "Ignoring the delete on ipv4StaticAddresses " 986d5afb2caSAndrew Geissler "as the interface is DHCP enabled"; 987d5afb2caSAndrew Geissler } 988d5afb2caSAndrew Geissler else 989d5afb2caSAndrew Geissler { 990d5afb2caSAndrew Geissler handleHypervisorIPv4StaticPatch(ifaceId, ipv4Static, 991d5afb2caSAndrew Geissler asyncResp); 992d5afb2caSAndrew Geissler } 993d5afb2caSAndrew Geissler } 994d5afb2caSAndrew Geissler 995d5afb2caSAndrew Geissler if (hostName) 996d5afb2caSAndrew Geissler { 997d5afb2caSAndrew Geissler handleHostnamePatch(*hostName, asyncResp); 998d5afb2caSAndrew Geissler } 999d5afb2caSAndrew Geissler 1000d5afb2caSAndrew Geissler if (dhcpv4) 1001d5afb2caSAndrew Geissler { 1002d5afb2caSAndrew Geissler setDHCPEnabled(ifaceId, *ipv4DHCPEnabled, asyncResp); 1003d5afb2caSAndrew Geissler } 1004d5afb2caSAndrew Geissler 1005d5afb2caSAndrew Geissler // Set this interface to disabled/inactive. This will be set to 1006d5afb2caSAndrew Geissler // enabled/active by the pldm once the hypervisor consumes the 1007d5afb2caSAndrew Geissler // updated settings from the user. 1008d5afb2caSAndrew Geissler setIPv4InterfaceEnabled(ifaceId, false, asyncResp); 1009d5afb2caSAndrew Geissler }); 1010d5afb2caSAndrew Geissler res.result(boost::beast::http::status::accepted); 1011d5afb2caSAndrew Geissler } 1012d5afb2caSAndrew Geissler }; 1013*4fbaf64aSAndrew Geissler 1014*4fbaf64aSAndrew Geissler /** 1015*4fbaf64aSAndrew Geissler * HypervisorResetActionInfo derived class for delivering Computer Systems 1016*4fbaf64aSAndrew Geissler * ResetType AllowableValues using ResetInfo schema. 1017*4fbaf64aSAndrew Geissler */ 1018*4fbaf64aSAndrew Geissler class HypervisorResetActionInfo : public Node 1019*4fbaf64aSAndrew Geissler { 1020*4fbaf64aSAndrew Geissler public: 1021*4fbaf64aSAndrew Geissler /* 1022*4fbaf64aSAndrew Geissler * Default Constructor 1023*4fbaf64aSAndrew Geissler */ 1024*4fbaf64aSAndrew Geissler HypervisorResetActionInfo(App& app) : 1025*4fbaf64aSAndrew Geissler Node(app, "/redfish/v1/Systems/hypervisor/ResetActionInfo/") 1026*4fbaf64aSAndrew Geissler { 1027*4fbaf64aSAndrew Geissler entityPrivileges = { 1028*4fbaf64aSAndrew Geissler {boost::beast::http::verb::get, {{"Login"}}}, 1029*4fbaf64aSAndrew Geissler {boost::beast::http::verb::head, {{"Login"}}}, 1030*4fbaf64aSAndrew Geissler {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 1031*4fbaf64aSAndrew Geissler {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 1032*4fbaf64aSAndrew Geissler {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 1033*4fbaf64aSAndrew Geissler {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 1034*4fbaf64aSAndrew Geissler } 1035*4fbaf64aSAndrew Geissler 1036*4fbaf64aSAndrew Geissler private: 1037*4fbaf64aSAndrew Geissler /** 1038*4fbaf64aSAndrew Geissler * Functions triggers appropriate requests on DBus 1039*4fbaf64aSAndrew Geissler */ 1040*4fbaf64aSAndrew Geissler void doGet(crow::Response& res, const crow::Request&, 1041*4fbaf64aSAndrew Geissler const std::vector<std::string>&) override 1042*4fbaf64aSAndrew Geissler { 1043*4fbaf64aSAndrew Geissler std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res); 1044*4fbaf64aSAndrew Geissler 1045*4fbaf64aSAndrew Geissler // Only return action info if hypervisor D-Bus object present 1046*4fbaf64aSAndrew Geissler crow::connections::systemBus->async_method_call( 1047*4fbaf64aSAndrew Geissler [asyncResp](const boost::system::error_code ec, 1048*4fbaf64aSAndrew Geissler const std::vector<std::pair< 1049*4fbaf64aSAndrew Geissler std::string, std::vector<std::string>>>& objInfo) { 1050*4fbaf64aSAndrew Geissler if (ec) 1051*4fbaf64aSAndrew Geissler { 1052*4fbaf64aSAndrew Geissler BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 1053*4fbaf64aSAndrew Geissler 1054*4fbaf64aSAndrew Geissler // No hypervisor objects found by mapper 1055*4fbaf64aSAndrew Geissler if (ec.value() == boost::system::errc::io_error) 1056*4fbaf64aSAndrew Geissler { 1057*4fbaf64aSAndrew Geissler messages::resourceNotFound(asyncResp->res, "hypervisor", 1058*4fbaf64aSAndrew Geissler "ResetActionInfo"); 1059*4fbaf64aSAndrew Geissler return; 1060*4fbaf64aSAndrew Geissler } 1061*4fbaf64aSAndrew Geissler 1062*4fbaf64aSAndrew Geissler messages::internalError(asyncResp->res); 1063*4fbaf64aSAndrew Geissler return; 1064*4fbaf64aSAndrew Geissler } 1065*4fbaf64aSAndrew Geissler 1066*4fbaf64aSAndrew Geissler // One and only one hypervisor instance supported 1067*4fbaf64aSAndrew Geissler if (objInfo.size() != 1) 1068*4fbaf64aSAndrew Geissler { 1069*4fbaf64aSAndrew Geissler messages::internalError(asyncResp->res); 1070*4fbaf64aSAndrew Geissler return; 1071*4fbaf64aSAndrew Geissler } 1072*4fbaf64aSAndrew Geissler 1073*4fbaf64aSAndrew Geissler // The hypervisor object only support the ability to turn On 1074*4fbaf64aSAndrew Geissler // The system object Action should be utilized for other 1075*4fbaf64aSAndrew Geissler // operations 1076*4fbaf64aSAndrew Geissler asyncResp->res.jsonValue = { 1077*4fbaf64aSAndrew Geissler {"@odata.type", "#ActionInfo.v1_1_2.ActionInfo"}, 1078*4fbaf64aSAndrew Geissler {"@odata.id", 1079*4fbaf64aSAndrew Geissler "/redfish/v1/Systems/hypervisor/ResetActionInfo"}, 1080*4fbaf64aSAndrew Geissler {"Name", "Reset Action Info"}, 1081*4fbaf64aSAndrew Geissler {"Id", "ResetActionInfo"}, 1082*4fbaf64aSAndrew Geissler {"Parameters", 1083*4fbaf64aSAndrew Geissler {{{"Name", "ResetType"}, 1084*4fbaf64aSAndrew Geissler {"Required", true}, 1085*4fbaf64aSAndrew Geissler {"DataType", "String"}, 1086*4fbaf64aSAndrew Geissler {"AllowableValues", {"On"}}}}}}; 1087*4fbaf64aSAndrew Geissler }, 1088*4fbaf64aSAndrew Geissler "xyz.openbmc_project.ObjectMapper", 1089*4fbaf64aSAndrew Geissler "/xyz/openbmc_project/object_mapper", 1090*4fbaf64aSAndrew Geissler "xyz.openbmc_project.ObjectMapper", "GetObject", 1091*4fbaf64aSAndrew Geissler "/xyz/openbmc_project/state/hypervisor0", 1092*4fbaf64aSAndrew Geissler std::array<const char*, 1>{"xyz.openbmc_project.State.Host"}); 1093*4fbaf64aSAndrew Geissler } 1094*4fbaf64aSAndrew Geissler }; 1095*4fbaf64aSAndrew Geissler 1096*4fbaf64aSAndrew Geissler /** 1097*4fbaf64aSAndrew Geissler * HypervisorActionsReset class supports the POST method for Reset action. 1098*4fbaf64aSAndrew Geissler * The class sends data directly to D-Bus. 1099*4fbaf64aSAndrew Geissler */ 1100*4fbaf64aSAndrew Geissler class HypervisorActionsReset : public Node 1101*4fbaf64aSAndrew Geissler { 1102*4fbaf64aSAndrew Geissler public: 1103*4fbaf64aSAndrew Geissler HypervisorActionsReset(App& app) : 1104*4fbaf64aSAndrew Geissler Node(app, 1105*4fbaf64aSAndrew Geissler "/redfish/v1/Systems/hypervisor/Actions/ComputerSystem.Reset/") 1106*4fbaf64aSAndrew Geissler { 1107*4fbaf64aSAndrew Geissler entityPrivileges = { 1108*4fbaf64aSAndrew Geissler {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 1109*4fbaf64aSAndrew Geissler } 1110*4fbaf64aSAndrew Geissler 1111*4fbaf64aSAndrew Geissler private: 1112*4fbaf64aSAndrew Geissler /** 1113*4fbaf64aSAndrew Geissler * Function handles POST method request. 1114*4fbaf64aSAndrew Geissler * Analyzes POST body message before sends Reset request data to D-Bus. 1115*4fbaf64aSAndrew Geissler */ 1116*4fbaf64aSAndrew Geissler void doPost(crow::Response& res, const crow::Request& req, 1117*4fbaf64aSAndrew Geissler const std::vector<std::string>&) override 1118*4fbaf64aSAndrew Geissler { 1119*4fbaf64aSAndrew Geissler std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res); 1120*4fbaf64aSAndrew Geissler 1121*4fbaf64aSAndrew Geissler std::optional<std::string> resetType; 1122*4fbaf64aSAndrew Geissler if (!json_util::readJson(req, res, "ResetType", resetType)) 1123*4fbaf64aSAndrew Geissler { 1124*4fbaf64aSAndrew Geissler // readJson adds appropriate error to response 1125*4fbaf64aSAndrew Geissler return; 1126*4fbaf64aSAndrew Geissler } 1127*4fbaf64aSAndrew Geissler 1128*4fbaf64aSAndrew Geissler if (!resetType) 1129*4fbaf64aSAndrew Geissler { 1130*4fbaf64aSAndrew Geissler messages::actionParameterMissing( 1131*4fbaf64aSAndrew Geissler asyncResp->res, "ComputerSystem.Reset", "ResetType"); 1132*4fbaf64aSAndrew Geissler return; 1133*4fbaf64aSAndrew Geissler } 1134*4fbaf64aSAndrew Geissler 1135*4fbaf64aSAndrew Geissler // Hypervisor object only support On operation 1136*4fbaf64aSAndrew Geissler if (resetType != "On") 1137*4fbaf64aSAndrew Geissler { 1138*4fbaf64aSAndrew Geissler messages::propertyValueNotInList(asyncResp->res, *resetType, 1139*4fbaf64aSAndrew Geissler "ResetType"); 1140*4fbaf64aSAndrew Geissler return; 1141*4fbaf64aSAndrew Geissler } 1142*4fbaf64aSAndrew Geissler 1143*4fbaf64aSAndrew Geissler std::string command = "xyz.openbmc_project.State.Host.Transition.On"; 1144*4fbaf64aSAndrew Geissler 1145*4fbaf64aSAndrew Geissler crow::connections::systemBus->async_method_call( 1146*4fbaf64aSAndrew Geissler [asyncResp, resetType](const boost::system::error_code ec) { 1147*4fbaf64aSAndrew Geissler if (ec) 1148*4fbaf64aSAndrew Geissler { 1149*4fbaf64aSAndrew Geissler BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec; 1150*4fbaf64aSAndrew Geissler if (ec.value() == boost::asio::error::invalid_argument) 1151*4fbaf64aSAndrew Geissler { 1152*4fbaf64aSAndrew Geissler messages::actionParameterNotSupported( 1153*4fbaf64aSAndrew Geissler asyncResp->res, *resetType, "Reset"); 1154*4fbaf64aSAndrew Geissler return; 1155*4fbaf64aSAndrew Geissler } 1156*4fbaf64aSAndrew Geissler 1157*4fbaf64aSAndrew Geissler if (ec.value() == boost::asio::error::host_unreachable) 1158*4fbaf64aSAndrew Geissler { 1159*4fbaf64aSAndrew Geissler messages::resourceNotFound(asyncResp->res, "Actions", 1160*4fbaf64aSAndrew Geissler "Reset"); 1161*4fbaf64aSAndrew Geissler return; 1162*4fbaf64aSAndrew Geissler } 1163*4fbaf64aSAndrew Geissler 1164*4fbaf64aSAndrew Geissler messages::internalError(asyncResp->res); 1165*4fbaf64aSAndrew Geissler return; 1166*4fbaf64aSAndrew Geissler } 1167*4fbaf64aSAndrew Geissler messages::success(asyncResp->res); 1168*4fbaf64aSAndrew Geissler }, 1169*4fbaf64aSAndrew Geissler "xyz.openbmc_project.State.Hypervisor", 1170*4fbaf64aSAndrew Geissler "/xyz/openbmc_project/state/hypervisor0", 1171*4fbaf64aSAndrew Geissler "org.freedesktop.DBus.Properties", "Set", 1172*4fbaf64aSAndrew Geissler "xyz.openbmc_project.State.Host", "RequestedHostTransition", 1173*4fbaf64aSAndrew Geissler std::variant<std::string>{std::move(command)}); 1174*4fbaf64aSAndrew Geissler } 1175*4fbaf64aSAndrew Geissler }; 1176d5afb2caSAndrew Geissler } // namespace redfish 1177