diff options
-rw-r--r-- | Redfish.md | 8 | ||||
-rw-r--r-- | meson.build | 1 | ||||
-rw-r--r-- | redfish-core/lib/systems.hpp | 123 | ||||
-rw-r--r-- | test/redfish-core/lib/system_test.cpp | 132 |
4 files changed, 245 insertions, 19 deletions
diff --git a/Redfish.md b/Redfish.md index cdec1f90c0..93105ebfce 100644 --- a/Redfish.md +++ b/Redfish.md @@ -936,6 +936,14 @@ other. - TotalThreads - Version +### /redfish/v1/Systems/system/ResetActionInfo/ + +#### ActionInfo + +- Parameters/AllowableValues +- Parameters/DataType +- Parameters/Required + ### /redfish/v1/Systems/system/Storage/ #### StorageCollection diff --git a/meson.build b/meson.build index f4976c1f9b..65aa99a939 100644 --- a/meson.build +++ b/meson.build @@ -455,6 +455,7 @@ srcfiles_unittest = files( 'test/redfish-core/include/utils/time_utils_test.cpp', 'test/redfish-core/lib/chassis_test.cpp', 'test/redfish-core/lib/sensors_test.cpp', + 'test/redfish-core/lib/system_test.cpp', 'test/redfish-core/lib/log_services_dump_test.cpp', 'test/redfish-core/lib/log_services_test.cpp', 'test/redfish-core/lib/update_service_test.cpp', diff --git a/redfish-core/lib/systems.hpp b/redfish-core/lib/systems.hpp index 24a8752a2e..37599e7d96 100644 --- a/redfish-core/lib/systems.hpp +++ b/redfish-core/lib/systems.hpp @@ -21,6 +21,7 @@ #include "dbus_singleton.hpp" #include "dbus_utility.hpp" #include "generated/enums/computer_system.hpp" +#include "generated/enums/resource.hpp" #include "health.hpp" #include "hypervisor_system.hpp" #include "led.hpp" @@ -36,6 +37,7 @@ #include <boost/asio/error.hpp> #include <boost/container/flat_map.hpp> #include <boost/system/error_code.hpp> +#include <boost/system/linux_error.hpp> #include <boost/url/format.hpp> #include <generated/enums/computer_system.hpp> #include <sdbusplus/asio/property.hpp> @@ -43,6 +45,7 @@ #include <sdbusplus/unpack_properties.hpp> #include <array> +#include <memory> #include <string> #include <string_view> #include <variant> @@ -3585,6 +3588,98 @@ inline void handleSystemCollectionResetActionHead( boost::beast::http::field::link, "</redfish/v1/JsonSchemas/ActionInfo/ActionInfo.json>; rel=describedby"); } + +/** + * @brief Translates allowed host transitions to redfish string + * + * @param[in] dbusAllowedHostTran The allowed host transition on dbus + * @param[out] allowableValues The translated host transition(s) + * + * @return Emplaces correpsonding Redfish translated value(s) in + * allowableValues. If translation not possible, does nothing to + * allowableValues. + */ +inline void + dbusToRfAllowedHostTransitions(const std::string& dbusAllowedHostTran, + nlohmann::json::array_t& allowableValues) +{ + if (dbusAllowedHostTran == "xyz.openbmc_project.State.Host.Transition.On") + { + allowableValues.emplace_back(resource::ResetType::On); + allowableValues.emplace_back(resource::ResetType::ForceOn); + } + else if (dbusAllowedHostTran == + "xyz.openbmc_project.State.Host.Transition.Off") + { + allowableValues.emplace_back(resource::ResetType::GracefulShutdown); + } + else if (dbusAllowedHostTran == + "xyz.openbmc_project.State.Host.Transition.GracefulWarmReboot") + { + allowableValues.emplace_back(resource::ResetType::GracefulRestart); + } + else if (dbusAllowedHostTran == + "xyz.openbmc_project.State.Host.Transition.ForceWarmReboot") + { + allowableValues.emplace_back(resource::ResetType::ForceRestart); + } + else + { + BMCWEB_LOG_WARNING("Unsupported host tran {}", dbusAllowedHostTran); + } +} + +inline void afterGetAllowedHostTransitions( + const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, + const boost::system::error_code& ec, + const std::vector<std::string>& allowedHostTransitions) +{ + nlohmann::json::array_t allowableValues; + + // Supported on all systems currently + allowableValues.emplace_back(resource::ResetType::ForceOff); + allowableValues.emplace_back(resource::ResetType::PowerCycle); + allowableValues.emplace_back(resource::ResetType::Nmi); + + if (ec) + { + if (ec == boost::system::linux_error::bad_request_descriptor || + ec == boost::asio::error::basic_errors::host_unreachable) + { + // Property not implemented so just return defaults + BMCWEB_LOG_DEBUG("Property not available {}", ec); + allowableValues.emplace_back(resource::ResetType::On); + allowableValues.emplace_back(resource::ResetType::ForceOn); + allowableValues.emplace_back(resource::ResetType::ForceRestart); + allowableValues.emplace_back(resource::ResetType::GracefulRestart); + allowableValues.emplace_back(resource::ResetType::GracefulShutdown); + } + else + { + BMCWEB_LOG_ERROR("DBUS response error {}", ec); + messages::internalError(asyncResp->res); + return; + } + } + else + { + for (const std::string& transition : allowedHostTransitions) + { + BMCWEB_LOG_DEBUG("Found allowed host tran {}", transition); + dbusToRfAllowedHostTransitions(transition, allowableValues); + } + } + + nlohmann::json::object_t parameter; + parameter["Name"] = "ResetType"; + parameter["Required"] = true; + parameter["DataType"] = "String"; + parameter["AllowableValues"] = std::move(allowableValues); + nlohmann::json::array_t parameters; + parameters.emplace_back(std::move(parameter)); + asyncResp->res.jsonValue["Parameters"] = std::move(parameters); +} + inline void handleSystemCollectionResetActionGet( crow::App& app, const crow::Request& req, const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, @@ -3625,25 +3720,15 @@ inline void handleSystemCollectionResetActionGet( asyncResp->res.jsonValue["Name"] = "Reset Action Info"; asyncResp->res.jsonValue["Id"] = "ResetActionInfo"; - nlohmann::json::array_t parameters; - nlohmann::json::object_t parameter; - - parameter["Name"] = "ResetType"; - parameter["Required"] = true; - parameter["DataType"] = "String"; - nlohmann::json::array_t allowableValues; - allowableValues.emplace_back("On"); - allowableValues.emplace_back("ForceOff"); - allowableValues.emplace_back("ForceOn"); - allowableValues.emplace_back("ForceRestart"); - allowableValues.emplace_back("GracefulRestart"); - allowableValues.emplace_back("GracefulShutdown"); - allowableValues.emplace_back("PowerCycle"); - allowableValues.emplace_back("Nmi"); - parameter["AllowableValues"] = std::move(allowableValues); - parameters.emplace_back(std::move(parameter)); - - asyncResp->res.jsonValue["Parameters"] = std::move(parameters); + // Look to see if system defines AllowedHostTransitions + sdbusplus::asio::getProperty<std::vector<std::string>>( + *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<std::string>& allowedHostTransitions) { + afterGetAllowedHostTransitions(asyncResp, ec, allowedHostTransitions); + }); } /** * SystemResetActionInfo derived class for delivering Computer Systems diff --git a/test/redfish-core/lib/system_test.cpp b/test/redfish-core/lib/system_test.cpp new file mode 100644 index 0000000000..481c0df746 --- /dev/null +++ b/test/redfish-core/lib/system_test.cpp @@ -0,0 +1,132 @@ +#include "app.hpp" +#include "async_resp.hpp" +#include "http_request.hpp" +#include "http_response.hpp" +#include "systems.hpp" + +#include <boost/beast/core/string_type.hpp> +#include <boost/beast/http/message.hpp> +#include <boost/system/error_code.hpp> +#include <nlohmann/json.hpp> + +#include <memory> +#include <string> +#include <system_error> +#include <vector> + +#include <gtest/gtest.h> + +namespace redfish +{ +namespace +{ + +TEST(GetAllowedHostTransition, UnexpectedError) +{ + auto response = std::make_shared<bmcweb::AsyncResp>(); + boost::system::error_code ec = boost::asio::error::invalid_argument; + std::vector<std::string> allowedHostTransitions; + + afterGetAllowedHostTransitions(response, ec, allowedHostTransitions); + + EXPECT_EQ(response->res.result(), + boost::beast::http::status::internal_server_error); +} + +TEST(GetAllowedHostTransition, NoPropOnDbus) +{ + auto response = std::make_shared<bmcweb::AsyncResp>(); + boost::system::error_code ec = + boost::system::linux_error::bad_request_descriptor; + std::vector<std::string> allowedHostTransitions; + + afterGetAllowedHostTransitions(response, ec, allowedHostTransitions); + + nlohmann::json::array_t parameters; + nlohmann::json::object_t parameter; + parameter["Name"] = "ResetType"; + parameter["Required"] = true; + parameter["DataType"] = "String"; + nlohmann::json::array_t allowed; + allowed.emplace_back(resource::ResetType::ForceOff); + allowed.emplace_back(resource::ResetType::PowerCycle); + allowed.emplace_back(resource::ResetType::Nmi); + allowed.emplace_back(resource::ResetType::On); + allowed.emplace_back(resource::ResetType::ForceOn); + allowed.emplace_back(resource::ResetType::ForceRestart); + allowed.emplace_back(resource::ResetType::GracefulRestart); + allowed.emplace_back(resource::ResetType::GracefulShutdown); + parameter["AllowableValues"] = std::move(allowed); + parameters.emplace_back(std::move(parameter)); + + EXPECT_EQ(response->res.jsonValue["Parameters"], parameters); +} + +TEST(GetAllowedHostTransition, NoForceRestart) +{ + auto response = std::make_shared<bmcweb::AsyncResp>(); + boost::system::error_code ec; + + std::vector<std::string> allowedHostTransitions = { + "xyz.openbmc_project.State.Host.Transition.On", + "xyz.openbmc_project.State.Host.Transition.Off", + "xyz.openbmc_project.State.Host.Transition.GracefulWarmReboot", + }; + + afterGetAllowedHostTransitions(response, ec, allowedHostTransitions); + + nlohmann::json::array_t parameters; + nlohmann::json::object_t parameter; + parameter["Name"] = "ResetType"; + parameter["Required"] = true; + parameter["DataType"] = "String"; + nlohmann::json::array_t allowed; + allowed.emplace_back(resource::ResetType::ForceOff); + allowed.emplace_back(resource::ResetType::PowerCycle); + allowed.emplace_back(resource::ResetType::Nmi); + allowed.emplace_back(resource::ResetType::On); + allowed.emplace_back(resource::ResetType::ForceOn); + allowed.emplace_back(resource::ResetType::GracefulShutdown); + allowed.emplace_back(resource::ResetType::GracefulRestart); + parameter["AllowableValues"] = std::move(allowed); + parameters.emplace_back(std::move(parameter)); + + EXPECT_EQ(response->res.jsonValue["Parameters"], parameters); +} + +TEST(GetAllowedHostTransition, AllSupported) +{ + auto response = std::make_shared<bmcweb::AsyncResp>(); + boost::system::error_code ec; + + std::vector<std::string> allowedHostTransitions = { + "xyz.openbmc_project.State.Host.Transition.On", + "xyz.openbmc_project.State.Host.Transition.Off", + "xyz.openbmc_project.State.Host.Transition.GracefulWarmReboot", + "xyz.openbmc_project.State.Host.Transition.ForceWarmReboot", + }; + + afterGetAllowedHostTransitions(response, ec, allowedHostTransitions); + + nlohmann::json::array_t parameters; + nlohmann::json::object_t parameter; + parameter["Name"] = "ResetType"; + parameter["Required"] = true; + parameter["DataType"] = "String"; + nlohmann::json::array_t allowed; + allowed.emplace_back(resource::ResetType::ForceOff); + allowed.emplace_back(resource::ResetType::PowerCycle); + allowed.emplace_back(resource::ResetType::Nmi); + allowed.emplace_back(resource::ResetType::On); + allowed.emplace_back(resource::ResetType::ForceOn); + allowed.emplace_back(resource::ResetType::GracefulShutdown); + allowed.emplace_back(resource::ResetType::GracefulRestart); + allowed.emplace_back(resource::ResetType::ForceRestart); + parameter["AllowableValues"] = std::move(allowed); + parameters.emplace_back(std::move(parameter)); + + EXPECT_EQ(response->res.jsonValue["Parameters"], parameters); +} + +} // namespace +} // namespace redfish |