From 54989b92e96ba26dda3788b8f6a9005098f422ca Mon Sep 17 00:00:00 2001 From: Oliver Brewka Date: Wed, 8 May 2024 14:59:27 +0200 Subject: [PATCH] systems.hpp - initial multi-host implementation --- redfish-core/lib/systems.hpp | 1198 ++++++++++++++++++++++------------ 1 file changed, 786 insertions(+), 412 deletions(-) diff --git a/redfish-core/lib/systems.hpp b/redfish-core/lib/systems.hpp index e12db494ab..a284fe0ad4 100644 --- a/redfish-core/lib/systems.hpp +++ b/redfish-core/lib/systems.hpp @@ -22,11 +22,13 @@ #include "dbus_utility.hpp" #include "generated/enums/computer_system.hpp" #include "generated/enums/resource.hpp" +#include "http/utility.hpp" #include "hypervisor_system.hpp" #include "led.hpp" #include "query.hpp" #include "redfish_util.hpp" #include "registries/privilege_registry.hpp" +#include "utils/collection.hpp" #include "utils/dbus_utils.hpp" #include "utils/json_utils.hpp" #include "utils/pcie_util.hpp" @@ -52,6 +54,152 @@ namespace redfish { +/* @brief validate systemName and get system index from systemName + * + * @param[in] asyncResp Async HTTP response + * @param[in] systemName Requested system name + * @param[in] callback Callback to continue processing request upon + * determining the total count of available systems + * + * */ +inline void getComputerSystemCount( + const std::shared_ptr& asyncResp, + const std::function& callback) +{ + dbus::utility::getSubTreePaths( + "/xyz/openbmc_project/state", 0, + std::array{"xyz.openbmc_project.State.Host"}, + [asyncResp, + callback](const boost::system::error_code& ec, + const dbus::utility::MapperGetSubTreePathsResponse& + hostStatePaths) { + if (ec) + { + BMCWEB_LOG_ERROR("D-Bus response error on GetSubTreePaths {} ", ec); + messages::internalError(asyncResp->res); + return; + } + + int hostCount = 0; + for (const auto& path : hostStatePaths) + { + if (path.find("host") != std::string::npos) + { + hostCount++; + } + } + + BMCWEB_LOG_DEBUG("hostCount: {}", hostCount); + callback(hostCount, hostStatePaths); + }); +} + +/* @brief validate systemName and get system index from systemName + * + * @param[in] asyncResp Async HTTP response + * @param[in] systemName Requested system name + * @param[in] callback Callback to continue processing request upon + * finding and validating the index + * + * */ +inline void getComputerSystemIndex( + const std::shared_ptr& asyncResp, + const std::string& systemName, + const std::function& callback) +{ + BMCWEB_LOG_DEBUG("getting computerSystemIndex from {}", systemName); + if (systemName.starts_with("system")) + { + // single host request for "system" + if (systemName.size() == std::strlen("system")) + { + BMCWEB_LOG_DEBUG("found legacy systemName {}", systemName); + // get host count and check if it's single host + getComputerSystemCount( + asyncResp, + [asyncResp, systemName, + callback](const int count, + const dbus::utility::MapperGetSubTreePathsResponse& + hostStatePaths) { + if (count == 1 && + hostStatePaths.front().find("host0") != std::string::npos) + { + callback(0); + } + else + { + // return 404 on multi host + messages::resourceNotFound(asyncResp->res, "ComputerSystem", + systemName); + } + }); + return; + } + + // multi host request for "systemN" + int foundIndex = -1; + static constexpr std::string_view systemToken = "system"; + auto index = systemName.substr(0 + systemToken.length()); + + if (index.empty()) + { + BMCWEB_LOG_DEBUG("no index found"); + messages::resourceNotFound(asyncResp->res, "ComputerSystem", + systemName); + return; + } + + try + { + foundIndex = std::stoi(std::string(index)); + } + catch (const std::exception& e) + { + BMCWEB_LOG_ERROR("error parsing host index"); + messages::resourceNotFound(asyncResp->res, "ComputerSystem", + systemName); + return; + } + + BMCWEB_LOG_DEBUG("found index {}", foundIndex); + + // get host count and check index in range of 0 > index <= count + getComputerSystemCount( + asyncResp, [asyncResp, systemName, foundIndex, callback]( + const int count, + const dbus::utility::MapperGetSubTreePathsResponse& + hostStatePaths) { + // handle for edge case on single host, when requesting system1. + if (foundIndex == 1 && count == 1) + { + if (hostStatePaths.front().find("host0") != std::string::npos) + { + messages::resourceNotFound(asyncResp->res, "ComputerSystem", + systemName); + return; + } + } + if (foundIndex < 1 || foundIndex > count) + { + BMCWEB_LOG_ERROR("Host index out of range"); + messages::resourceNotFound(asyncResp->res, "ComputerSystem", + systemName); + return; + } + + callback(foundIndex); + }); + } + else + { + BMCWEB_LOG_ERROR("No computer systems found"); + messages::resourceNotFound(asyncResp->res, "ComputerSystem", + systemName); + } +} + const static std::array, 2> protocolToDBusForSystems{ {{"SSH", "obmc-console-ssh"}, {"IPMI", "phosphor-ipmi-net"}}}; @@ -526,15 +674,21 @@ inline void * @brief Retrieves host state properties over dbus * * @param[in] asyncResp Shared pointer for completing asynchronous calls. + * @param[in] computerSystemIndex represents host number * * @return None. */ -inline void getHostState(const std::shared_ptr& asyncResp) +inline void getHostState(const std::shared_ptr& asyncResp, + const int computerSystemIndex) { BMCWEB_LOG_DEBUG("Get host information."); + sdbusplus::message::object_path objectPath( + "/xyz/openbmc_project/state/host" + + std::to_string(computerSystemIndex)); + sdbusplus::asio::getProperty( *crow::connections::systemBus, "xyz.openbmc_project.State.Host", - "/xyz/openbmc_project/state/host0", "xyz.openbmc_project.State.Host", + std::string(objectPath), "xyz.openbmc_project.State.Host", "CurrentHostState", [asyncResp](const boost::system::error_code& ec, const std::string& hostState) { @@ -816,15 +970,21 @@ inline int * @brief Retrieves boot progress of the system * * @param[in] asyncResp Shared pointer for generating response message. + * @param[in] computerSystemIndex represents host number * * @return None. */ -inline void getBootProgress(const std::shared_ptr& asyncResp) +inline void getBootProgress(const std::shared_ptr& asyncResp, + const int computerSystemIndex) { + sdbusplus::message::object_path objectPath( + "/xyz/openbmc_project/state/host" + + std::to_string(computerSystemIndex)); + sdbusplus::asio::getProperty( *crow::connections::systemBus, "xyz.openbmc_project.State.Host", - "/xyz/openbmc_project/state/host0", - "xyz.openbmc_project.State.Boot.Progress", "BootProgress", + std::string(objectPath), "xyz.openbmc_project.State.Boot.Progress", + "BootProgress", [asyncResp](const boost::system::error_code& ec, const std::string& bootProgressStr) { if (ec) @@ -845,16 +1005,22 @@ inline void getBootProgress(const std::shared_ptr& asyncResp) * @brief Retrieves boot progress Last Update of the system * * @param[in] asyncResp Shared pointer for generating response message. + * @param[in] computerSystemIndex represents host number * * @return None. */ inline void getBootProgressLastStateTime( - const std::shared_ptr& asyncResp) + const std::shared_ptr& asyncResp, + const int computerSystemIndex) { + sdbusplus::message::object_path objectPath( + "/xyz/openbmc_project/state/host" + + std::to_string(computerSystemIndex)); + sdbusplus::asio::getProperty( *crow::connections::systemBus, "xyz.openbmc_project.State.Host", - "/xyz/openbmc_project/state/host0", - "xyz.openbmc_project.State.Boot.Progress", "BootProgressLastUpdate", + std::string(objectPath), "xyz.openbmc_project.State.Boot.Progress", + "BootProgressLastUpdate", [asyncResp](const boost::system::error_code& ec, const uint64_t lastStateTime) { if (ec) @@ -879,17 +1045,24 @@ inline void getBootProgressLastStateTime( * @brief Retrieves boot override type over DBUS and fills out the response * * @param[in] asyncResp Shared pointer for generating response message. + * @param[in] computerSystemIndex represents host number * * @return None. */ inline void - getBootOverrideType(const std::shared_ptr& asyncResp) + getBootOverrideType(const std::shared_ptr& asyncResp, + const int computerSystemIndex) { + sdbusplus::message::object_path objectPath( + "/xyz/openbmc_project/control/host" + + std::to_string(computerSystemIndex)); + objectPath /= "boot"; + sdbusplus::asio::getProperty( *crow::connections::systemBus, "xyz.openbmc_project.Settings", - "/xyz/openbmc_project/control/host0/boot", - "xyz.openbmc_project.Control.Boot.Type", "BootType", + std::string(objectPath), "xyz.openbmc_project.Control.Boot.Type", + "BootType", [asyncResp](const boost::system::error_code& ec, const std::string& bootType) { if (ec) @@ -920,17 +1093,24 @@ inline void * @brief Retrieves boot override mode over DBUS and fills out the response * * @param[in] asyncResp Shared pointer for generating response message. + * @param[in] computerSystemIndex represents host number * * @return None. */ inline void - getBootOverrideMode(const std::shared_ptr& asyncResp) + getBootOverrideMode(const std::shared_ptr& asyncResp, + const int computerSystemIndex) { + sdbusplus::message::object_path objectPath( + "/xyz/openbmc_project/control/host" + + std::to_string(computerSystemIndex)); + objectPath /= "boot"; + sdbusplus::asio::getProperty( *crow::connections::systemBus, "xyz.openbmc_project.Settings", - "/xyz/openbmc_project/control/host0/boot", - "xyz.openbmc_project.Control.Boot.Mode", "BootMode", + std::string(objectPath), "xyz.openbmc_project.Control.Boot.Mode", + "BootMode", [asyncResp](const boost::system::error_code& ec, const std::string& bootModeStr) { if (ec) @@ -964,19 +1144,26 @@ inline void * @brief Retrieves boot override source over DBUS * * @param[in] asyncResp Shared pointer for generating response message. + * @param[in] computerSystemIndex represents host number * * @return None. */ inline void - getBootOverrideSource(const std::shared_ptr& asyncResp) + getBootOverrideSource(const std::shared_ptr& asyncResp, + const int computerSystemIndex) { + sdbusplus::message::object_path objectPath( + "/xyz/openbmc_project/control/host" + + std::to_string(computerSystemIndex)); + objectPath /= "boot"; + sdbusplus::asio::getProperty( *crow::connections::systemBus, "xyz.openbmc_project.Settings", - "/xyz/openbmc_project/control/host0/boot", - "xyz.openbmc_project.Control.Boot.Source", "BootSource", - [asyncResp](const boost::system::error_code& ec, - const std::string& bootSourceStr) { + std::string(objectPath), "xyz.openbmc_project.Control.Boot.Source", + "BootSource", + [asyncResp, computerSystemIndex](const boost::system::error_code& ec, + const std::string& bootSourceStr) { if (ec) { if (ec.value() == boost::asio::error::host_unreachable) @@ -999,7 +1186,7 @@ inline void // Get BootMode as BootSourceOverrideTarget is constructed // from both BootSource and BootMode - getBootOverrideMode(asyncResp); + getBootOverrideMode(asyncResp, computerSystemIndex); }); } @@ -1009,13 +1196,14 @@ inline void * state * * @param[in] asyncResp Shared pointer for generating response message. + * @param[in] computerSystemIndex represents host number * * @return None. */ inline void processBootOverrideEnable( const std::shared_ptr& asyncResp, - const bool bootOverrideEnableSetting) + const int computerSystemIndex, const bool bootOverrideEnableSetting) { if (!bootOverrideEnableSetting) { @@ -1026,10 +1214,14 @@ inline void processBootOverrideEnable( // If boot source override is enabled, we need to check 'one_time' // property to set a correct value for the "BootSourceOverrideEnabled" + sdbusplus::message::object_path objectPath( + "/xyz/openbmc_project/control/host" + + std::to_string(computerSystemIndex)); + objectPath /= "boot/one_time"; + sdbusplus::asio::getProperty( *crow::connections::systemBus, "xyz.openbmc_project.Settings", - "/xyz/openbmc_project/control/host0/boot/one_time", - "xyz.openbmc_project.Object.Enable", "Enabled", + std::string(objectPath), "xyz.openbmc_project.Object.Enable", "Enabled", [asyncResp](const boost::system::error_code& ec, bool oneTimeSetting) { if (ec) { @@ -1055,19 +1247,25 @@ inline void processBootOverrideEnable( * @brief Retrieves boot override enable over DBUS * * @param[in] asyncResp Shared pointer for generating response message. + * @param[in] computerSystemIndex represents host number * * @return None. */ inline void - getBootOverrideEnable(const std::shared_ptr& asyncResp) + getBootOverrideEnable(const std::shared_ptr& asyncResp, + const int computerSystemIndex) { + sdbusplus::message::object_path objectPath( + "/xyz/openbmc_project/control/host" + + std::to_string(computerSystemIndex)); + objectPath /= "boot"; + sdbusplus::asio::getProperty( *crow::connections::systemBus, "xyz.openbmc_project.Settings", - "/xyz/openbmc_project/control/host0/boot", - "xyz.openbmc_project.Object.Enable", "Enabled", - [asyncResp](const boost::system::error_code& ec, - const bool bootOverrideEnable) { + std::string(objectPath), "xyz.openbmc_project.Object.Enable", "Enabled", + [asyncResp, computerSystemIndex](const boost::system::error_code& ec, + const bool bootOverrideEnable) { if (ec) { if (ec.value() == boost::asio::error::host_unreachable) @@ -1079,7 +1277,8 @@ inline void return; } - processBootOverrideEnable(asyncResp, bootOverrideEnable); + processBootOverrideEnable(asyncResp, computerSystemIndex, + bootOverrideEnable); }); } @@ -1087,17 +1286,19 @@ inline void * @brief Retrieves boot source override properties * * @param[in] asyncResp Shared pointer for generating response message. + * @param[in] computerSystemIndex represents host number * * @return None. */ inline void - getBootProperties(const std::shared_ptr& asyncResp) + getBootProperties(const std::shared_ptr& asyncResp, + const int computerSystemIndex) { BMCWEB_LOG_DEBUG("Get boot information."); - getBootOverrideSource(asyncResp); - getBootOverrideType(asyncResp); - getBootOverrideEnable(asyncResp); + getBootOverrideSource(asyncResp, computerSystemIndex); + getBootOverrideType(asyncResp, computerSystemIndex); + getBootOverrideEnable(asyncResp, computerSystemIndex); } /** @@ -1109,18 +1310,25 @@ inline void * last power operation time. * * @param[in] asyncResp Shared pointer for generating response message. + * @param[in] computerSystemIndex represents host number * * @return None. */ inline void - getLastResetTime(const std::shared_ptr& asyncResp) + getLastResetTime(const std::shared_ptr& asyncResp, + const int computerSystemIndex) { BMCWEB_LOG_DEBUG("Getting System Last Reset Time"); + sdbusplus::message::object_path objectPath( + "/xyz/openbmc_project/state/chassis"); + sdbusplus::asio::getProperty( - *crow::connections::systemBus, "xyz.openbmc_project.State.Chassis", - "/xyz/openbmc_project/state/chassis0", - "xyz.openbmc_project.State.Chassis", "LastStateChangeTime", + *crow::connections::systemBus, + ("xyz.openbmc_project.State.Chassis" + + std::to_string(computerSystemIndex)), + std::string(objectPath), "xyz.openbmc_project.State.Chassis", + "LastStateChangeTime", [asyncResp](const boost::system::error_code& ec, uint64_t lastResetTime) { if (ec) @@ -1148,17 +1356,23 @@ inline void * dbus. * * @param[in] asyncResp Shared pointer for generating response message. + * @param[in] computerSystemIndex represents host number * * @return None. */ inline void getAutomaticRebootAttempts( - const std::shared_ptr& asyncResp) + const std::shared_ptr& asyncResp, + const int computerSystemIndex) { BMCWEB_LOG_DEBUG("Get Automatic Retry policy"); + sdbusplus::message::object_path objectPath( + "/xyz/openbmc_project/state/host" + + std::to_string(computerSystemIndex)); + sdbusplus::asio::getAllProperties( *crow::connections::systemBus, "xyz.openbmc_project.State.Host", - "/xyz/openbmc_project/state/host0", + std::string(objectPath), "xyz.openbmc_project.Control.Boot.RebootAttempts", [asyncResp{asyncResp}]( const boost::system::error_code& ec, @@ -1205,20 +1419,27 @@ inline void getAutomaticRebootAttempts( * @brief Retrieves Automatic Retry properties. Known on D-Bus as AutoReboot. * * @param[in] asyncResp Shared pointer for generating response message. + * @param[in] computerSystemIndex represents host number * * @return None. */ inline void - getAutomaticRetryPolicy(const std::shared_ptr& asyncResp) + getAutomaticRetryPolicy(const std::shared_ptr& asyncResp, + const int computerSystemIndex) { BMCWEB_LOG_DEBUG("Get Automatic Retry policy"); + sdbusplus::message::object_path objectPath( + "/xyz/openbmc_project/control/host" + + std::to_string(computerSystemIndex)); + objectPath /= "auto_reboot"; + sdbusplus::asio::getProperty( *crow::connections::systemBus, "xyz.openbmc_project.Settings", - "/xyz/openbmc_project/control/host0/auto_reboot", + std::string(objectPath), "xyz.openbmc_project.Control.Boot.RebootPolicy", "AutoReboot", - [asyncResp](const boost::system::error_code& ec, - bool autoRebootEnabled) { + [asyncResp, computerSystemIndex](const boost::system::error_code& ec, + bool autoRebootEnabled) { if (ec) { if (ec.value() != EBADR) @@ -1240,7 +1461,7 @@ inline void asyncResp->res.jsonValue["Boot"]["AutomaticRetryConfig"] = "Disabled"; } - getAutomaticRebootAttempts(asyncResp); + getAutomaticRebootAttempts(asyncResp, computerSystemIndex); // "AutomaticRetryConfig" can be 3 values, Disabled, RetryAlways, // and RetryAttempts. OpenBMC only supports Disabled and @@ -1255,6 +1476,7 @@ inline void * @brief Sets RetryAttempts * * @param[in] asyncResp Shared pointer for generating response message. + * @param[in] computerSystemIndex represents host number * @param[in] retryAttempts "AutomaticRetryAttempts" from request. * *@return None. @@ -1262,14 +1484,18 @@ inline void inline void setAutomaticRetryAttempts( const std::shared_ptr& asyncResp, - const uint32_t retryAttempts) + const int computerSystemIndex, uint32_t retryAttempts) { BMCWEB_LOG_DEBUG("Set Automatic Retry Attempts."); - setDbusProperty( - asyncResp, "xyz.openbmc_project.State.Host", - sdbusplus::message::object_path("/xyz/openbmc_project/state/host0"), - "xyz.openbmc_project.Control.Boot.RebootAttempts", "RetryAttempts", - "Boot/AutomaticRetryAttempts", retryAttempts); + + sdbusplus::message::object_path objectPath( + "/xyz/openbmc_project/state/host" + + std::to_string(computerSystemIndex)); + + setDbusProperty(asyncResp, "xyz.openbmc_project.State.Host", objectPath, + "xyz.openbmc_project.Control.Boot.RebootAttempts", + "RetryAttempts", "Boot/AutomaticRetryAttempts", + retryAttempts); } inline computer_system::PowerRestorePolicyTypes @@ -1300,17 +1526,23 @@ inline computer_system::PowerRestorePolicyTypes * @brief Retrieves power restore policy over DBUS. * * @param[in] asyncResp Shared pointer for generating response message. + * @param[in] computerSystemIndex represents host number * * @return None. */ inline void - getPowerRestorePolicy(const std::shared_ptr& asyncResp) + getPowerRestorePolicy(const std::shared_ptr& asyncResp, + const int computerSystemIndex) { BMCWEB_LOG_DEBUG("Get power restore policy"); + sdbusplus::message::object_path objectPath( + "/xyz/openbmc_project/control/host" + + std::to_string(computerSystemIndex)); + objectPath /= "power_restore_policy"; sdbusplus::asio::getProperty( *crow::connections::systemBus, "xyz.openbmc_project.Settings", - "/xyz/openbmc_project/control/host0/power_restore_policy", + std::string(objectPath), "xyz.openbmc_project.Control.Power.RestorePolicy", "PowerRestorePolicy", [asyncResp](const boost::system::error_code& ec, const std::string& policy) { @@ -1530,10 +1762,13 @@ inline void setTrustedModuleRequiredToBoot( * @brief Sets boot properties into DBUS object(s). * * @param[in] asyncResp Shared pointer for generating response message. + * @param[in] computerSystemIndex represents host number * @param[in] bootType The boot type to set. + * * @return Integer error code. */ inline void setBootType(const std::shared_ptr& asyncResp, + const int computerSystemIndex, const std::optional& bootType) { std::string bootTypeStr; @@ -1567,9 +1802,12 @@ inline void setBootType(const std::shared_ptr& asyncResp, // Act on validated parameters BMCWEB_LOG_DEBUG("DBUS boot type: {}", bootTypeStr); - setDbusProperty(asyncResp, "xyz.openbmc_project.Settings", - sdbusplus::message::object_path( - "/xyz/openbmc_project/control/host0/boot"), + sdbusplus::message::object_path objectPath( + "/xyz/openbmc_project/control/host" + + std::to_string(computerSystemIndex)); + objectPath /= "boot"; + + setDbusProperty(asyncResp, "xyz.openbmc_project.Settings", objectPath, "xyz.openbmc_project.Control.Boot.Type", "BootType", "Boot/BootSourceOverrideMode", bootTypeStr); } @@ -1577,12 +1815,14 @@ inline void setBootType(const std::shared_ptr& asyncResp, /** * @brief Sets boot properties into DBUS object(s). * - * @param[in] asyncResp Shared pointer for generating response - * message. + * @param[in] asyncResp Shared pointer for generating response message. + * @param[in] computerSystemIndex represents host number * @param[in] bootType The boot type to set. + * * @return Integer error code. */ inline void setBootEnable(const std::shared_ptr& asyncResp, + const int computerSystemIndex, const std::optional& bootEnable) { if (!bootEnable) @@ -1622,9 +1862,12 @@ inline void setBootEnable(const std::shared_ptr& asyncResp, // Act on validated parameters BMCWEB_LOG_DEBUG("DBUS boot override enable: {}", bootOverrideEnable); - setDbusProperty(asyncResp, "xyz.openbmc_project.Settings", - sdbusplus::message::object_path( - "/xyz/openbmc_project/control/host0/boot"), + sdbusplus::message::object_path objectPath( + "/xyz/openbmc_project/control/host" + + std::to_string(computerSystemIndex)); + objectPath /= "boot"; + + setDbusProperty(asyncResp, "xyz.openbmc_project.Settings", objectPath, "xyz.openbmc_project.Object.Enable", "Enabled", "Boot/BootSourceOverrideEnabled", bootOverrideEnable); @@ -1638,9 +1881,8 @@ inline void setBootEnable(const std::shared_ptr& asyncResp, BMCWEB_LOG_DEBUG("DBUS boot override persistent: {}", bootOverridePersistent); - setDbusProperty(asyncResp, "xyz.openbmc_project.Settings", - sdbusplus::message::object_path( - "/xyz/openbmc_project/control/host0/boot/one_time"), + objectPath /= "one_time"; + setDbusProperty(asyncResp, "xyz.openbmc_project.Settings", objectPath, "xyz.openbmc_project.Object.Enable", "Enabled", "Boot/BootSourceOverrideEnabled", !bootOverridePersistent); } @@ -1649,12 +1891,14 @@ inline void setBootEnable(const std::shared_ptr& asyncResp, * @brief Sets boot properties into DBUS object(s). * * @param[in] asyncResp Shared pointer for generating response message. + * @param[in] computerSystemIndex represents host number * @param[in] bootSource The boot source to set. * * @return Integer error code. */ inline void setBootModeOrSource(const std::shared_ptr& asyncResp, + const int computerSystemIndex, const std::optional& bootSource) { std::string bootSourceStr; @@ -1683,14 +1927,14 @@ inline void BMCWEB_LOG_DEBUG("DBUS boot source: {}", bootSourceStr); BMCWEB_LOG_DEBUG("DBUS boot mode: {}", bootModeStr); - setDbusProperty(asyncResp, "xyz.openbmc_project.Settings", - sdbusplus::message::object_path( - "/xyz/openbmc_project/control/host0/boot"), + sdbusplus::message::object_path objectPath( + "/xyz/openbmc_project/control/host" + + std::to_string(computerSystemIndex)); + objectPath /= "boot"; + setDbusProperty(asyncResp, "xyz.openbmc_project.Settings", objectPath, "xyz.openbmc_project.Control.Boot.Source", "BootSource", "Boot/BootSourceOverrideTarget", bootSourceStr); - setDbusProperty(asyncResp, "xyz.openbmc_project.Settings", - sdbusplus::message::object_path( - "/xyz/openbmc_project/control/host0/boot"), + setDbusProperty(asyncResp, "xyz.openbmc_project.Settings", objectPath, "xyz.openbmc_project.Control.Boot.Mode", "BootMode", "Boot/BootSourceOverrideTarget", bootModeStr); } @@ -1699,6 +1943,7 @@ inline void * @brief Sets Boot source override properties. * * @param[in] asyncResp Shared pointer for generating response message. + * @param[in] computerSystemIndex represents host number * @param[in] bootSource The boot source from incoming RF request. * @param[in] bootType The boot type from incoming RF request. * @param[in] bootEnable The boot override enable from incoming RF request. @@ -1708,15 +1953,16 @@ inline void inline void setBootProperties(const std::shared_ptr& asyncResp, + const int computerSystemIndex, const std::optional& bootSource, const std::optional& bootType, const std::optional& bootEnable) { BMCWEB_LOG_DEBUG("Set boot information."); - setBootModeOrSource(asyncResp, bootSource); - setBootType(asyncResp, bootType); - setBootEnable(asyncResp, bootEnable); + setBootModeOrSource(asyncResp, computerSystemIndex, bootSource); + setBootType(asyncResp, computerSystemIndex, bootType); + setBootEnable(asyncResp, computerSystemIndex, bootEnable); } /** @@ -1840,12 +2086,14 @@ inline void * @brief Sets automaticRetry (Auto Reboot) * * @param[in] asyncResp Shared pointer for generating response message. + * @param[in] computerSystemIndex represents host number * @param[in] automaticRetryConfig "AutomaticRetryConfig" from request. * * @return None. */ inline void setAutomaticRetry(const std::shared_ptr& asyncResp, + const int computerSystemIndex, const std::string& automaticRetryConfig) { BMCWEB_LOG_DEBUG("Set Automatic Retry."); @@ -1870,9 +2118,12 @@ inline void return; } - setDbusProperty(asyncResp, "xyz.openbmc_project.Settings", - sdbusplus::message::object_path( - "/xyz/openbmc_project/control/host0/auto_reboot"), + sdbusplus::message::object_path objectPath( + "/xyz/openbmc_project/control/host" + + std::to_string(computerSystemIndex)); + objectPath /= "auto_reboot"; + + setDbusProperty(asyncResp, "xyz.openbmc_project.Settings", objectPath, "xyz.openbmc_project.Control.Boot.RebootPolicy", "AutoReboot", "Boot/AutomaticRetryConfig", autoRebootEnabled); @@ -1899,12 +2150,14 @@ inline std::string dbusPowerRestorePolicyFromRedfish(std::string_view policy) * @brief Sets power restore policy properties. * * @param[in] asyncResp Shared pointer for generating response message. + * @param[in] computerSystemIndex represents host number * @param[in] policy power restore policy properties from request. * * @return None. */ inline void setPowerRestorePolicy(const std::shared_ptr& asyncResp, + const int computerSystemIndex, std::string_view policy) { BMCWEB_LOG_DEBUG("Set power restore policy."); @@ -1918,12 +2171,15 @@ inline void return; } - setDbusProperty( - asyncResp, "xyz.openbmc_project.Settings", - sdbusplus::message::object_path( - "/xyz/openbmc_project/control/host0/power_restore_policy"), - "xyz.openbmc_project.Control.Power.RestorePolicy", "PowerRestorePolicy", - "PowerRestorePolicy", powerRestorePolicy); + sdbusplus::message::object_path objectPath( + "/xyz/openbmc_project/control/host" + + std::to_string(computerSystemIndex)); + objectPath /= "power_restore_policy"; + + setDbusProperty(asyncResp, "xyz.openbmc_project.Settings", objectPath, + "xyz.openbmc_project.Control.Power.RestorePolicy", + "PowerRestorePolicy", "PowerRestorePolicy", + powerRestorePolicy); } /** @@ -2363,17 +2619,22 @@ inline std::string rfToDbusWDTTimeOutAct(const std::string& rfAction) * @brief Retrieves host watchdog timer properties over DBUS * * @param[in] asyncResp Shared pointer for completing asynchronous calls. + * @param[in] computerSystemIndex represents host number * * @return None. */ inline void - getHostWatchdogTimer(const std::shared_ptr& asyncResp) + getHostWatchdogTimer(const std::shared_ptr& asyncResp, + const int computerSystemIndex) { BMCWEB_LOG_DEBUG("Get host watchodg"); + sdbusplus::message::object_path objectPath( + "/xyz/openbmc_project/watchdog/host" + + std::to_string(computerSystemIndex)); + sdbusplus::asio::getAllProperties( *crow::connections::systemBus, "xyz.openbmc_project.Watchdog", - "/xyz/openbmc_project/watchdog/host0", - "xyz.openbmc_project.State.Watchdog", + std::string(objectPath), "xyz.openbmc_project.State.Watchdog", [asyncResp](const boost::system::error_code& ec, const dbus::utility::DBusPropertiesMap& properties) { if (ec) @@ -2426,6 +2687,7 @@ inline void * @brief Sets Host WatchDog Timer properties. * * @param[in] asyncResp Shared pointer for generating response message. + * @param[in] computerSystemIndex represents host number * @param[in] wdtEnable The WDTimer Enable value (true/false) from incoming * RF request. * @param[in] wdtTimeOutAction The WDT Timeout action, from incoming RF request. @@ -2434,6 +2696,7 @@ inline void */ inline void setWDTProperties(const std::shared_ptr& asyncResp, + const int computerSystemIndex, const std::optional wdtEnable, const std::optional& wdtTimeOutAction) { @@ -2452,18 +2715,22 @@ inline void return; } - setDbusProperty(asyncResp, "xyz.openbmc_project.Watchdog", - sdbusplus::message::object_path( - "/xyz/openbmc_project/watchdog/host0"), + sdbusplus::message::object_path objectPath( + "/xyz/openbmc_project/watchdog/host" + + std::to_string(computerSystemIndex)); + + setDbusProperty(asyncResp, "xyz.openbmc_project.Watchdog", objectPath, "xyz.openbmc_project.State.Watchdog", "ExpireAction", "HostWatchdogTimer/TimeoutAction", wdtTimeOutActStr); } if (wdtEnable) { - setDbusProperty(asyncResp, "xyz.openbmc_project.Watchdog", - sdbusplus::message::object_path( - "/xyz/openbmc_project/watchdog/host0"), + sdbusplus::message::object_path objectPath( + "/xyz/openbmc_project/watchdog/host" + + std::to_string(computerSystemIndex)); + + setDbusProperty(asyncResp, "xyz.openbmc_project.Watchdog", objectPath, "xyz.openbmc_project.State.Watchdog", "Enabled", "HostWatchdogTimer/FunctionEnabled", *wdtEnable); } @@ -2754,6 +3021,78 @@ inline void handleComputerSystemCollectionHead( "; rel=describedby"); } +/** + * @brief Retrieve all available hosts via ObjectMapper and add them as Members + * to ComputerSystemCollection + * + * @param[i,o] asyncResp Async HTTP response + * @param[i] systemName Requested system name + * + */ +inline void getSystemsCollectionMembers( + const std::shared_ptr& asyncResp) +{ + getComputerSystemCount( + asyncResp, + [asyncResp](const int count, + const dbus::utility::MapperGetSubTreePathsResponse& + hostStatePaths) { + nlohmann::json& members = asyncResp->res.jsonValue["Members"]; + if (count == 0) + { + // respond with empty list (e.g every slot of chassis is empty) + members.push_back({{}}); + asyncResp->res.jsonValue["Members@odata.count"] = count; + return; + } + if (count == 1) + { + // single host handle for legacy system "system" + if (hostStatePaths.front().find("host0") != std::string::npos) + { + std::string computerSystemPath = "/redfish/v1/Systems/system"; + members.push_back({{"@odata.id", computerSystemPath}}); + asyncResp->res.jsonValue["Members@odata.count"] = count; + return; + } + } + + // multi host handle + for (const auto& path : hostStatePaths) + { + sdbusplus::message::object_path objectPath(path); + std::string nodeStr = objectPath.filename(); + if (nodeStr.empty()) + { + BMCWEB_LOG_DEBUG( + "handleComputerSystemCollectionGet : dbus path empty : "); + + continue; + } + std::string systemName; + std::string computerSystemIndex; + + if (nodeStr.find("host") != std::string::npos) + { + nodeStr.erase(remove(nodeStr.begin(), nodeStr.end(), '\"'), + nodeStr.end()); + computerSystemIndex = nodeStr.substr(nodeStr.find("host") + + (nodeStr.length() - 1)); + + systemName = "system" + computerSystemIndex; + + if (!systemName.empty()) + { + std::string computerSystemPath = "/redfish/v1/Systems/" + + systemName; + members.push_back({{"@odata.id", computerSystemPath}}); + } + } + } + asyncResp->res.jsonValue["Members@odata.count"] = members.size(); + }); +} + inline void handleComputerSystemCollectionGet( crow::App& app, const crow::Request& req, const std::shared_ptr& asyncResp) @@ -2771,18 +3110,8 @@ inline void handleComputerSystemCollectionGet( asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/Systems"; asyncResp->res.jsonValue["Name"] = "Computer System Collection"; - nlohmann::json& ifaceArray = asyncResp->res.jsonValue["Members"]; - ifaceArray = nlohmann::json::array(); - if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) - { - asyncResp->res.jsonValue["Members@odata.count"] = 0; - // Option currently returns no systems. TBD - return; - } - asyncResp->res.jsonValue["Members@odata.count"] = 1; - nlohmann::json::object_t system; - system["@odata.id"] = "/redfish/v1/Systems/system"; - ifaceArray.emplace_back(std::move(system)); + getSystemsCollectionMembers(asyncResp); + sdbusplus::asio::getProperty( *crow::connections::systemBus, "xyz.openbmc_project.Settings", "/xyz/openbmc_project/network/hypervisor", @@ -2816,11 +3145,21 @@ inline void handleComputerSystemCollectionGet( /** * Function transceives data with dbus directly. + * + * @param[in] asyncResp Shared pointer for generating response message. + * @param[in] computerSystemIndex represents host number + * */ -inline void doNMI(const std::shared_ptr& asyncResp) +inline void doNMI(const std::shared_ptr& asyncResp, + const int computerSystemIndex) { - constexpr const char* serviceName = "xyz.openbmc_project.Control.Host.NMI"; - constexpr const char* objectPath = "/xyz/openbmc_project/control/host0/nmi"; + std::string serviceName = "xyz.openbmc_project.Control.Host.NMI" + + std::to_string(computerSystemIndex); + sdbusplus::message::object_path objectPath( + "/xyz/openbmc_project/control/host" + + std::to_string(computerSystemIndex)); + objectPath /= "nmi"; + constexpr const char* interfaceName = "xyz.openbmc_project.Control.Host.NMI"; constexpr const char* method = "NMI"; @@ -2835,96 +3174,138 @@ inline void doNMI(const std::shared_ptr& asyncResp) } messages::success(asyncResp->res); }, - serviceName, objectPath, interfaceName, method); + serviceName, std::string(objectPath), interfaceName, method); } -inline void handleComputerSystemResetActionPost( - crow::App& app, const crow::Request& req, - const std::shared_ptr& asyncResp, - const std::string& systemName) +/** Handle error responses from d-bus for system power requests + */ +inline void handleSystemActionResetError(const boost::system::error_code& ec, + const sdbusplus::message_t& eMsg, + std::string_view resetType, + crow::Response& res) { - if (!redfish::setUpRedfishRoute(app, req, asyncResp)) - { - return; - } - if (systemName != "system") - { - messages::resourceNotFound(asyncResp->res, "ComputerSystem", - systemName); - return; - } - if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) + if (ec.value() == boost::asio::error::invalid_argument) { - // Option currently returns no systems. TBD - messages::resourceNotFound(asyncResp->res, "ComputerSystem", - systemName); + messages::actionParameterNotSupported(res, resetType, "Reset"); return; } - std::string resetType; - if (!json_util::readJsonAction(req, asyncResp->res, "ResetType", resetType)) + + if (eMsg.get_error() == nullptr) { + BMCWEB_LOG_ERROR("D-Bus response error: {}", ec); + messages::internalError(res); return; } + std::string_view errorMessage = eMsg.get_error()->name; - // Get the command and host vs. chassis - std::string command; - bool hostCommand = true; - if ((resetType == "On") || (resetType == "ForceOn")) + // If operation failed due to BMC not being in Ready state, tell + // user to retry in a bit + if ((errorMessage == + std::string_view( + "xyz.openbmc_project.State.Chassis.Error.BMCNotReady")) || + (errorMessage == + std::string_view("xyz.openbmc_project.State.Host.Error.BMCNotReady"))) { - command = "xyz.openbmc_project.State.Host.Transition.On"; - hostCommand = true; - } - else if (resetType == "ForceOff") - { - command = "xyz.openbmc_project.State.Chassis.Transition.Off"; - hostCommand = false; - } - else if (resetType == "ForceRestart") - { - command = "xyz.openbmc_project.State.Host.Transition.ForceWarmReboot"; - hostCommand = true; - } - else if (resetType == "GracefulShutdown") - { - command = "xyz.openbmc_project.State.Host.Transition.Off"; - hostCommand = true; - } - else if (resetType == "GracefulRestart") - { - command = - "xyz.openbmc_project.State.Host.Transition.GracefulWarmReboot"; - hostCommand = true; - } - else if (resetType == "PowerCycle") - { - command = "xyz.openbmc_project.State.Host.Transition.Reboot"; - hostCommand = true; - } - else if (resetType == "Nmi") - { - doNMI(asyncResp); + BMCWEB_LOG_DEBUG("BMC not ready, operation not allowed right now"); + messages::serviceTemporarilyUnavailable(res, "10"); return; } - else + + BMCWEB_LOG_ERROR("System Action Reset transition fail {} sdbusplus:{}", ec, + errorMessage); + messages::internalError(res); +} + +inline void handleComputerSystemResetActionPost( + crow::App& app, const crow::Request& req, + const std::shared_ptr& asyncResp, + const std::string& systemName) +{ + if (!redfish::setUpRedfishRoute(app, req, asyncResp)) { - messages::actionParameterUnknown(asyncResp->res, "Reset", resetType); return; } - sdbusplus::message::object_path statePath("/xyz/openbmc_project/state"); - if (hostCommand) - { - setDbusProperty(asyncResp, "xyz.openbmc_project.State.Host", - statePath / "host0", "xyz.openbmc_project.State.Host", - "RequestedHostTransition", "Reset", command); - } - else - { - setDbusProperty(asyncResp, "xyz.openbmc_project.State.Chassis", - statePath / "chassis0", - "xyz.openbmc_project.State.Chassis", - "RequestedPowerTransition", "Reset", command); - } + getComputerSystemIndex( + asyncResp, systemName, + [asyncResp, systemName, req](const int computerSystemIndex) { + std::string resetType; + if (!json_util::readJsonAction(req, asyncResp->res, "ResetType", + resetType)) + { + return; + } + + // Get the command and host vs. chassis + std::string command; + bool hostCommand = true; + if ((resetType == "On") || (resetType == "ForceOn")) + { + command = "xyz.openbmc_project.State.Host.Transition.On"; + hostCommand = true; + } + else if (resetType == "ForceOff") + { + command = "xyz.openbmc_project.State.Chassis.Transition.Off"; + hostCommand = false; + } + else if (resetType == "ForceRestart") + { + command = + "xyz.openbmc_project.State.Host.Transition.ForceWarmReboot"; + hostCommand = true; + } + else if (resetType == "GracefulShutdown") + { + command = "xyz.openbmc_project.State.Host.Transition.Off"; + hostCommand = true; + } + else if (resetType == "GracefulRestart") + { + command = + "xyz.openbmc_project.State.Host.Transition.GracefulWarmReboot"; + hostCommand = true; + } + else if (resetType == "PowerCycle") + { + command = "xyz.openbmc_project.State.Host.Transition.Reboot"; + hostCommand = true; + } + else if (resetType == "Nmi") + { + doNMI(asyncResp, computerSystemIndex); + return; + } + else + { + messages::actionParameterUnknown(asyncResp->res, "Reset", + resetType); + return; + } + + if (hostCommand) + { + sdbusplus::message::object_path statePath( + "/xyz/openbmc_project/state"); + + statePath /= "host" + std::to_string(computerSystemIndex); + + BMCWEB_LOG_DEBUG("Resetting host {} with command {}", + std::string(statePath), command); + + setDbusProperty(asyncResp, "xyz.openbmc_project.State.Host", + statePath, "xyz.openbmc_project.State.Host", + "RequestedHostTransition", "Reset", command); + } + else + { + sdbusplus::message::object_path statePath( + "/xyz/openbmc_project/state/chassis0"); + setDbusProperty(asyncResp, "xyz.openbmc_project.State.Chassis", + statePath, "xyz.openbmc_project.State.Chassis", + "RequestedPowerTransition", "Reset", command); + } + }); } inline void handleComputerSystemHead( @@ -2991,120 +3372,118 @@ inline void return; } - if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) - { - // Option currently returns no systems. TBD - messages::resourceNotFound(asyncResp->res, "ComputerSystem", - systemName); - return; - } - if (systemName == "hypervisor") { handleHypervisorSystemGet(asyncResp); return; } - if (systemName != "system") - { - messages::resourceNotFound(asyncResp->res, "ComputerSystem", - systemName); - return; - } - asyncResp->res.addHeader( - boost::beast::http::field::link, - "; rel=describedby"); - asyncResp->res.jsonValue["@odata.type"] = - "#ComputerSystem.v1_22_0.ComputerSystem"; - asyncResp->res.jsonValue["Name"] = "system"; - asyncResp->res.jsonValue["Id"] = "system"; - asyncResp->res.jsonValue["SystemType"] = "Physical"; - asyncResp->res.jsonValue["Description"] = "Computer System"; - asyncResp->res.jsonValue["ProcessorSummary"]["Count"] = 0; - asyncResp->res.jsonValue["MemorySummary"]["TotalSystemMemoryGiB"] = - double(0); - asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/Systems/system"; - - asyncResp->res.jsonValue["Processors"]["@odata.id"] = - "/redfish/v1/Systems/system/Processors"; - asyncResp->res.jsonValue["Memory"]["@odata.id"] = - "/redfish/v1/Systems/system/Memory"; - asyncResp->res.jsonValue["Storage"]["@odata.id"] = - "/redfish/v1/Systems/system/Storage"; - asyncResp->res.jsonValue["FabricAdapters"]["@odata.id"] = - "/redfish/v1/Systems/system/FabricAdapters"; - - asyncResp->res.jsonValue["Actions"]["#ComputerSystem.Reset"]["target"] = - "/redfish/v1/Systems/system/Actions/ComputerSystem.Reset"; - asyncResp->res - .jsonValue["Actions"]["#ComputerSystem.Reset"]["@Redfish.ActionInfo"] = - "/redfish/v1/Systems/system/ResetActionInfo"; - - asyncResp->res.jsonValue["LogServices"]["@odata.id"] = - "/redfish/v1/Systems/system/LogServices"; - asyncResp->res.jsonValue["Bios"]["@odata.id"] = - "/redfish/v1/Systems/system/Bios"; - - nlohmann::json::array_t managedBy; - nlohmann::json& manager = managedBy.emplace_back(); - manager["@odata.id"] = "/redfish/v1/Managers/bmc"; - asyncResp->res.jsonValue["Links"]["ManagedBy"] = std::move(managedBy); - asyncResp->res.jsonValue["Status"]["Health"] = "OK"; - asyncResp->res.jsonValue["Status"]["State"] = "Enabled"; - - // Fill in SerialConsole info - asyncResp->res.jsonValue["SerialConsole"]["MaxConcurrentSessions"] = 15; - asyncResp->res.jsonValue["SerialConsole"]["IPMI"]["ServiceEnabled"] = true; - - asyncResp->res.jsonValue["SerialConsole"]["SSH"]["ServiceEnabled"] = true; - asyncResp->res.jsonValue["SerialConsole"]["SSH"]["Port"] = 2200; - asyncResp->res.jsonValue["SerialConsole"]["SSH"]["HotKeySequenceDisplay"] = - "Press ~. to exit console"; - getPortStatusAndPath(std::span{protocolToDBusForSystems}, - std::bind_front(afterPortRequest, asyncResp)); - - if constexpr (BMCWEB_KVM) - { - // Fill in GraphicalConsole info - asyncResp->res.jsonValue["GraphicalConsole"]["ServiceEnabled"] = true; - asyncResp->res.jsonValue["GraphicalConsole"]["MaxConcurrentSessions"] = - 4; - asyncResp->res.jsonValue["GraphicalConsole"]["ConnectTypesSupported"] = - nlohmann::json::array_t({"KVMIP"}); - } - - getMainChassisId(asyncResp, - [](const std::string& chassisId, - const std::shared_ptr& aRsp) { - nlohmann::json::array_t chassisArray; - nlohmann::json& chassis = chassisArray.emplace_back(); - chassis["@odata.id"] = boost::urls::format("/redfish/v1/Chassis/{}", - chassisId); - aRsp->res.jsonValue["Links"]["Chassis"] = std::move(chassisArray); - }); + getComputerSystemIndex( + asyncResp, systemName, + [asyncResp, systemName](const int computerSystemIndex) { + asyncResp->res.addHeader( + boost::beast::http::field::link, + "; rel=describedby"); + asyncResp->res.jsonValue["@odata.type"] = + "#ComputerSystem.v1_22_0.ComputerSystem"; + asyncResp->res.jsonValue["Name"] = systemName; + asyncResp->res.jsonValue["Id"] = systemName; + asyncResp->res.jsonValue["SystemType"] = "Physical"; + asyncResp->res.jsonValue["Description"] = "Computer System"; + asyncResp->res.jsonValue["ProcessorSummary"]["Count"] = 0; + asyncResp->res.jsonValue["MemorySummary"]["TotalSystemMemoryGiB"] = + double(0); + asyncResp->res.jsonValue["@odata.id"] = + boost::urls::format("/redfish/v1/Systems/{}", systemName); + asyncResp->res.jsonValue["Processors"]["@odata.id"] = + boost::urls::format("/redfish/v1/Systems/{}/Processors", + systemName); + asyncResp->res.jsonValue["Memory"]["@odata.id"] = + boost::urls::format("/redfish/v1/Systems/{}/Memory", systemName); + asyncResp->res.jsonValue["Storage"]["@odata.id"] = + boost::urls::format("/redfish/v1/Systems/{}/Storage", systemName); + asyncResp->res.jsonValue["FabricAdapters"]["@odata.id"] = + boost::urls::format("/redfish/v1/Systems/{}/FabricAdapters", + systemName); + asyncResp->res.jsonValue["Actions"]["#ComputerSystem.Reset"]["target"] = + boost::urls::format( + "/redfish/v1/Systems/{}/Actions/ComputerSystem.Reset", + systemName); + asyncResp->res.jsonValue["Actions"]["#ComputerSystem.Reset"] + ["@Redfish.ActionInfo"] = boost::urls::format( + "/redfish/v1/Systems/{}/ResetActionInfo", systemName); + asyncResp->res.jsonValue["LogServices"]["@odata.id"] = + boost::urls::format("/redfish/v1/Systems/{}/LogServices", + systemName); + asyncResp->res.jsonValue["Bios"]["@odata.id"] = + boost::urls::format("/redfish/v1/Systems/{}/Bios", systemName); + + nlohmann::json::array_t managedBy; + nlohmann::json& manager = managedBy.emplace_back(); + manager["@odata.id"] = "/redfish/v1/Managers/bmc"; + asyncResp->res.jsonValue["Links"]["ManagedBy"] = std::move(managedBy); + asyncResp->res.jsonValue["Status"]["Health"] = "OK"; + asyncResp->res.jsonValue["Status"]["State"] = "Enabled"; + + // Fill in SerialConsole info + asyncResp->res.jsonValue["SerialConsole"]["MaxConcurrentSessions"] = 15; + asyncResp->res.jsonValue["SerialConsole"]["IPMI"]["ServiceEnabled"] = + true; + + asyncResp->res.jsonValue["SerialConsole"]["SSH"]["ServiceEnabled"] = + true; + asyncResp->res.jsonValue["SerialConsole"]["SSH"]["Port"] = 2200; + asyncResp->res + .jsonValue["SerialConsole"]["SSH"]["HotKeySequenceDisplay"] = + "Press ~. to exit console"; + getPortStatusAndPath(std::span{protocolToDBusForSystems}, + std::bind_front(afterPortRequest, asyncResp)); + + if constexpr (BMCWEB_KVM) + { + // Fill in GraphicalConsole info + asyncResp->res.jsonValue["GraphicalConsole"]["ServiceEnabled"] = + true; + asyncResp->res + .jsonValue["GraphicalConsole"]["MaxConcurrentSessions"] = 4; + asyncResp->res + .jsonValue["GraphicalConsole"]["ConnectTypesSupported"] = + nlohmann::json::array_t({"KVMIP"}); + } + + getMainChassisId(asyncResp, + [](const std::string& chassisId, + const std::shared_ptr& aRsp) { + nlohmann::json::array_t chassisArray; + nlohmann::json& chassis = chassisArray.emplace_back(); + chassis["@odata.id"] = boost::urls::format("/redfish/v1/Chassis/{}", + chassisId); + aRsp->res.jsonValue["Links"]["Chassis"] = std::move(chassisArray); + }); - getSystemLocationIndicatorActive(asyncResp); - // TODO (Gunnar): Remove IndicatorLED after enough time has passed - getIndicatorLedState(asyncResp); - getComputerSystem(asyncResp); - getHostState(asyncResp); - getBootProperties(asyncResp); - getBootProgress(asyncResp); - getBootProgressLastStateTime(asyncResp); - pcie_util::getPCIeDeviceList(asyncResp, - nlohmann::json::json_pointer("/PCIeDevices")); - getHostWatchdogTimer(asyncResp); - getPowerRestorePolicy(asyncResp); - getStopBootOnFault(asyncResp); - getAutomaticRetryPolicy(asyncResp); - getLastResetTime(asyncResp); - if constexpr (BMCWEB_REDFISH_PROVISIONING_FEATURE) - { - getProvisioningStatus(asyncResp); - } - getTrustedModuleRequiredToBoot(asyncResp); - getPowerMode(asyncResp); - getIdlePowerSaver(asyncResp); + getSystemLocationIndicatorActive(asyncResp); + // TODO (Gunnar): Remove IndicatorLED after enough time has passed + getIndicatorLedState(asyncResp); + getComputerSystem(asyncResp); + getHostState(asyncResp, computerSystemIndex); + getBootProperties(asyncResp, computerSystemIndex); + getBootProgress(asyncResp, computerSystemIndex); + getBootProgressLastStateTime(asyncResp, computerSystemIndex); + pcie_util::getPCIeDeviceList( + asyncResp, nlohmann::json::json_pointer("/PCIeDevices")); + getHostWatchdogTimer(asyncResp, computerSystemIndex); + getPowerRestorePolicy(asyncResp, computerSystemIndex); + getStopBootOnFault(asyncResp); + getAutomaticRetryPolicy(asyncResp, computerSystemIndex); + getLastResetTime(asyncResp, computerSystemIndex); + if constexpr (BMCWEB_REDFISH_PROVISIONING_FEATURE) + { + getProvisioningStatus(asyncResp); + } + getTrustedModuleRequiredToBoot(asyncResp); + getPowerMode(asyncResp); + getIdlePowerSaver(asyncResp); + }); } inline void handleComputerSystemPatch( @@ -3116,45 +3495,35 @@ inline void handleComputerSystemPatch( { return; } - if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) - { - // Option currently returns no systems. TBD - messages::resourceNotFound(asyncResp->res, "ComputerSystem", - systemName); - return; - } - if (systemName != "system") - { - messages::resourceNotFound(asyncResp->res, "ComputerSystem", - systemName); - return; - } - asyncResp->res.addHeader( - boost::beast::http::field::link, - "; rel=describedby"); - - std::optional locationIndicatorActive; - std::optional indicatorLed; - std::optional assetTag; - std::optional powerRestorePolicy; - std::optional powerMode; - std::optional wdtEnable; - std::optional wdtTimeOutAction; - std::optional bootSource; - std::optional bootType; - std::optional bootEnable; - std::optional bootAutomaticRetry; - std::optional bootAutomaticRetryAttempts; - std::optional bootTrustedModuleRequired; - std::optional stopBootOnFault; - std::optional ipsEnable; - std::optional ipsEnterUtil; - std::optional ipsEnterTime; - std::optional ipsExitUtil; - std::optional ipsExitTime; - - // clang-format off + getComputerSystemIndex( + asyncResp, systemName, + [asyncResp, systemName, req](const int computerSystemIndex) { + asyncResp->res.addHeader( + boost::beast::http::field::link, + "; rel=describedby"); + + std::optional locationIndicatorActive; + std::optional indicatorLed; + std::optional assetTag; + std::optional powerRestorePolicy; + std::optional powerMode; + std::optional wdtEnable; + std::optional wdtTimeOutAction; + std::optional bootSource; + std::optional bootType; + std::optional bootEnable; + std::optional bootAutomaticRetry; + std::optional bootAutomaticRetryAttempts; + std::optional bootTrustedModuleRequired; + std::optional stopBootOnFault; + std::optional ipsEnable; + std::optional ipsEnterUtil; + std::optional ipsEnterTime; + std::optional ipsExitUtil; + std::optional ipsExitTime; + + // clang-format off if (!json_util::readJsonPatch( req, asyncResp->res, "IndicatorLED", indicatorLed, @@ -3179,75 +3548,83 @@ inline void handleComputerSystemPatch( { return; } - // clang-format on + // clang-format on - asyncResp->res.result(boost::beast::http::status::no_content); + asyncResp->res.result(boost::beast::http::status::no_content); - if (assetTag) - { - setAssetTag(asyncResp, *assetTag); - } + if (assetTag) + { + setAssetTag(asyncResp, *assetTag); + } - if (wdtEnable || wdtTimeOutAction) - { - setWDTProperties(asyncResp, wdtEnable, wdtTimeOutAction); - } + if (wdtEnable || wdtTimeOutAction) + { + setWDTProperties(asyncResp, computerSystemIndex, wdtEnable, + wdtTimeOutAction); + } - if (bootSource || bootType || bootEnable) - { - setBootProperties(asyncResp, bootSource, bootType, bootEnable); - } - if (bootAutomaticRetry) - { - setAutomaticRetry(asyncResp, *bootAutomaticRetry); - } + if (bootSource || bootType || bootEnable) + { + setBootProperties(asyncResp, computerSystemIndex, bootSource, + bootType, bootEnable); + } + if (bootAutomaticRetry) + { + setAutomaticRetry(asyncResp, computerSystemIndex, + *bootAutomaticRetry); + } - if (bootAutomaticRetryAttempts) - { - setAutomaticRetryAttempts(asyncResp, - bootAutomaticRetryAttempts.value()); - } + if (bootAutomaticRetryAttempts) + { + setAutomaticRetryAttempts(asyncResp, computerSystemIndex, + bootAutomaticRetryAttempts.value()); + } - if (bootTrustedModuleRequired) - { - setTrustedModuleRequiredToBoot(asyncResp, *bootTrustedModuleRequired); - } + if (bootTrustedModuleRequired) + { + setTrustedModuleRequiredToBoot(asyncResp, + *bootTrustedModuleRequired); + } - if (stopBootOnFault) - { - setStopBootOnFault(asyncResp, *stopBootOnFault); - } + if (stopBootOnFault) + { + setStopBootOnFault(asyncResp, *stopBootOnFault); + } - if (locationIndicatorActive) - { - setSystemLocationIndicatorActive(asyncResp, *locationIndicatorActive); - } + if (locationIndicatorActive) + { + setSystemLocationIndicatorActive(asyncResp, + *locationIndicatorActive); + } - // TODO (Gunnar): Remove IndicatorLED after enough time has - // passed - if (indicatorLed) - { - setIndicatorLedState(asyncResp, *indicatorLed); - asyncResp->res.addHeader(boost::beast::http::field::warning, - "299 - \"IndicatorLED is deprecated. Use " - "LocationIndicatorActive instead.\""); - } + // TODO (Gunnar): Remove IndicatorLED after enough time has + // passed + if (indicatorLed) + { + setIndicatorLedState(asyncResp, *indicatorLed); + asyncResp->res.addHeader(boost::beast::http::field::warning, + "299 - \"IndicatorLED is deprecated. Use " + "LocationIndicatorActive instead.\""); + } - if (powerRestorePolicy) - { - setPowerRestorePolicy(asyncResp, *powerRestorePolicy); - } + if (powerRestorePolicy) + { + setPowerRestorePolicy(asyncResp, computerSystemIndex, + *powerRestorePolicy); + } - if (powerMode) - { - setPowerMode(asyncResp, *powerMode); - } + if (powerMode) + { + setPowerMode(asyncResp, *powerMode); + } - if (ipsEnable || ipsEnterUtil || ipsEnterTime || ipsExitUtil || ipsExitTime) - { - setIdlePowerSaver(asyncResp, ipsEnable, ipsEnterUtil, ipsEnterTime, - ipsExitUtil, ipsExitTime); - } + if (ipsEnable || ipsEnterUtil || ipsEnterTime || ipsExitUtil || + ipsExitTime) + { + setIdlePowerSaver(asyncResp, ipsEnable, ipsEnterUtil, ipsEnterTime, + ipsExitUtil, ipsExitTime); + } + }); } inline void handleSystemCollectionResetActionHead( @@ -3365,13 +3742,6 @@ inline void handleSystemCollectionResetActionGet( { return; } - if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) - { - // Option currently returns no systems. TBD - messages::resourceNotFound(asyncResp->res, "ComputerSystem", - systemName); - return; - } if (systemName == "hypervisor") { @@ -3379,31 +3749,35 @@ inline void handleSystemCollectionResetActionGet( return; } - if (systemName != "system") - { - messages::resourceNotFound(asyncResp->res, "ComputerSystem", - systemName); - return; - } - - asyncResp->res.addHeader( - boost::beast::http::field::link, - "; rel=describedby"); - - asyncResp->res.jsonValue["@odata.id"] = - "/redfish/v1/Systems/system/ResetActionInfo"; - asyncResp->res.jsonValue["@odata.type"] = "#ActionInfo.v1_1_2.ActionInfo"; - asyncResp->res.jsonValue["Name"] = "Reset Action Info"; - asyncResp->res.jsonValue["Id"] = "ResetActionInfo"; - - // Look to see if system defines AllowedHostTransitions - sdbusplus::asio::getProperty>( - *crow::connections::systemBus, "xyz.openbmc_project.State.Host", - "/xyz/openbmc_project/state/host0", "xyz.openbmc_project.State.Host", - "AllowedHostTransitions", - [asyncResp](const boost::system::error_code& ec, - const std::vector& allowedHostTransitions) { - afterGetAllowedHostTransitions(asyncResp, ec, allowedHostTransitions); + getComputerSystemIndex( + asyncResp, systemName, + [asyncResp, systemName](const int /* computerSystemIndex */) { + asyncResp->res.addHeader( + boost::beast::http::field::link, + "; rel=describedby"); + + asyncResp->res.jsonValue["@odata.id"] = boost::urls::format( + "/redfish/v1/Systems/{}/ResetActionInfo", systemName); + asyncResp->res.jsonValue["@odata.type"] = + "#ActionInfo.v1_1_2.ActionInfo"; + asyncResp->res.jsonValue["Name"] = "Reset Action Info"; + asyncResp->res.jsonValue["Id"] = "ResetActionInfo"; + + sdbusplus::message::object_path objectPath( + "/xyz/openbmc_project/state"); + objectPath /= systemName; + + // Look to see if system defines AllowedHostTransitions + sdbusplus::asio::getProperty>( + *crow::connections::systemBus, "xyz.openbmc_project.State.Host", + objectPath, "xyz.openbmc_project.State.Host", + "AllowedHostTransitions", + [asyncResp]( + const boost::system::error_code& ec, + const std::vector& allowedHostTransitions) { + afterGetAllowedHostTransitions(asyncResp, ec, + allowedHostTransitions); + }); }); } /**