AllowedHostTransitions: look for on dbus
Commit [1] introduced a new optional dbus property that OpenBMC
developers can populate to define which
redfish/v1/Systems/system/ResetActionInfo AllowableValues are.
Look for that new property on dbus. If not found, hard code the
previous values otherwise utilize the property to fill in the return
value.
Tested:
- Put new property on dbus and confirmed Redfish API returned expected
values:
```
curl -k -H "X-Auth-Token: $token" -X GET https://${bmc}/redfish/v1/Systems/system/ResetActionInfo
{
"@odata.id": "/redfish/v1/Systems/system/ResetActionInfo",
"@odata.type": "#ActionInfo.v1_1_2.ActionInfo",
"Id": "ResetActionInfo",
"Name": "Reset Action Info",
"Parameters": [
{
"AllowableValues": [
"ForceOff",
"PowerCycle",
"Nmi",
"On",
"ForceOn",
"ForceRestart",
"GracefulRestart",
"GracefulShutdown"
],
"DataType": "String",
"Name": "ResetType",
"Required": true
}
]
}
```
- Did not run redfish validator as response was same as previous
[1]: https://gerrit.openbmc.org/c/openbmc/phosphor-dbus-interfaces/+/68933
Change-Id: Iecece14e7ff55db98d96df71b106ecc9e3f0ac33
Signed-off-by: Andrew Geissler <geissonator@yahoo.com>
Signed-off-by: Gunnar Mills <gmills@us.ibm.com>
diff --git a/Redfish.md b/Redfish.md
index cdec1f9..93105eb 100644
--- a/Redfish.md
+++ b/Redfish.md
@@ -936,6 +936,14 @@
- 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 f4976c1..65aa99a 100644
--- a/meson.build
+++ b/meson.build
@@ -455,6 +455,7 @@
'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 24a8752..37599e7 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 @@
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 @@
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 0000000..481c0df
--- /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