Storage: Add Storage Controller
This adds support for Storage Controllers.
Tested: Validator passed
{
"@odata.context": "/redfish/v1/$metadata#Storage.Storage",
"@odata.id": "/redfish/v1/Systems/system/Storage/1",
"@odata.type": "#Storage.v1_7_1.Storage",
"Drives": [
{
"@odata.id": "/redfish/v1/Systems/system/Storage/1/Drives/Drive_1"
},
{
"@odata.id": "/redfish/v1/Systems/system/Storage/1/Drives/Drive_2"
},
{
"@odata.id": "/redfish/v1/Systems/system/Storage/1/Drives/Drive_3"
},
{
"@odata.id": "/redfish/v1/Systems/system/Storage/1/Drives/Drive_4"
},
{
"@odata.id": "/redfish/v1/Systems/system/Storage/1/Drives/Drive_5"
},
{
"@odata.id": "/redfish/v1/Systems/system/Storage/1/Drives/Drive_6"
},
{
"@odata.id": "/redfish/v1/Systems/system/Storage/1/Drives/Drive_7"
},
{
"@odata.id": "/redfish/v1/Systems/system/Storage/1/Drives/Drive_8"
}
],
"Drives@odata.count": 8,
"Id": "1",
"Name": "Storage Controller",
"Status": {
"Health": "OK",
"HealthRollup": "OK",
"State": "Enabled"
},
"StorageControllers": [
{
"@odata.context": "/redfish/v1/$metadata#Storage.StorageController",
"@odata.id": "/redfish/v1/Systems/system/Storage/1#/StorageControllers/0",
"@odata.type": "#Storage.v1_7_0.StorageController",
"Manufacturer": "$BOARD_MANUFACTURER",
"MemberId": "HSBP_1",
"Model": "$BOARD_PRODUCT_NAME",
"Name": "HSBP_1",
"PartNumber": "$BOARD_PART_NUMBER",
"SerialNumber": "$BOARD_SERIAL_NUMBER",
"Status": {
"Health": "OK",
"HealthRollup": "OK",
"State": "Enabled"
}
}
]
}
Change-Id: I9d956343daa74ddfa912e3cbe0d38b0e42a4859f
Signed-off-by: James Feist <james.feist@linux.intel.com>
diff --git a/CMakeLists.txt.in b/CMakeLists.txt.in
index 4e6f6b6..ae2155a 100644
--- a/CMakeLists.txt.in
+++ b/CMakeLists.txt.in
@@ -46,7 +46,7 @@
externalproject_add (
nlohmann-json GIT_REPOSITORY "https://github.com/nlohmann/json.git" GIT_TAG
- aafad2be1f3cd259a1e79d2f6fcf267d1ede9ec7 SOURCE_DIR
+ ea60d40f4a60a47d3be9560d8f7bc37c163fe47b SOURCE_DIR
"${CMAKE_BINARY_DIR}/nlohmann-json-src" BINARY_DIR
"${CMAKE_BINARY_DIR}/nlohmann-json-build" CONFIGURE_COMMAND "" BUILD_COMMAND
"" INSTALL_COMMAND mkdir -p "${CMAKE_BINARY_DIR}/prefix/include/nlohmann" &&
diff --git a/redfish-core/lib/storage.hpp b/redfish-core/lib/storage.hpp
index 9c51975..856ef5e 100644
--- a/redfish-core/lib/storage.hpp
+++ b/redfish-core/lib/storage.hpp
@@ -16,6 +16,7 @@
#pragma once
#include "health.hpp"
+#include "openbmc_dbus_rest.hpp"
#include <node.hpp>
@@ -74,19 +75,22 @@
res.jsonValue["@odata.context"] =
"/redfish/v1/$metadata#Storage.Storage";
res.jsonValue["@odata.id"] = "/redfish/v1/Systems/system/Storage/1";
- res.jsonValue["Name"] = "Storage Controller";
+ res.jsonValue["Name"] = "Storage";
res.jsonValue["Id"] = "1";
res.jsonValue["Status"]["State"] = "Enabled";
auto asyncResp = std::make_shared<AsyncResp>(res);
+ auto health = std::make_shared<HealthPopulate>(asyncResp);
+ health->populate();
+
crow::connections::systemBus->async_method_call(
- [asyncResp](const boost::system::error_code ec,
- const std::vector<std::string> &storageList) {
+ [asyncResp, health](const boost::system::error_code ec,
+ const std::vector<std::string> &storageList) {
nlohmann::json &storageArray =
asyncResp->res.jsonValue["Drives"];
storageArray = nlohmann::json::array();
- asyncResp->res.jsonValue["Drives@odata.count"] = 0;
- auto health = std::make_shared<HealthPopulate>(asyncResp);
+ auto &count = asyncResp->res.jsonValue["Drives@odata.count"];
+ count = 0;
if (ec)
{
@@ -95,8 +99,9 @@
return;
}
- health->inventory = storageList;
- health->populate();
+ health->inventory.insert(health->inventory.end(),
+ storageList.begin(),
+ storageList.end());
for (const std::string &objpath : storageList)
{
@@ -114,8 +119,7 @@
objpath.substr(lastPos + 1)}});
}
- asyncResp->res.jsonValue["Drives@odata.count"] =
- storageArray.size();
+ count = storageArray.size();
},
"xyz.openbmc_project.ObjectMapper",
"/xyz/openbmc_project/object_mapper",
@@ -123,6 +127,154 @@
"/xyz/openbmc_project/inventory", int32_t(0),
std::array<const char *, 1>{
"xyz.openbmc_project.Inventory.Item.Drive"});
+
+ crow::connections::systemBus->async_method_call(
+ [asyncResp,
+ health](const boost::system::error_code ec,
+ const crow::openbmc_mapper::GetSubTreeType &subtree) {
+ if (ec || !subtree.size())
+ {
+ messages::internalError(asyncResp->res);
+ return;
+ }
+
+ nlohmann::json &root =
+ asyncResp->res.jsonValue["StorageControllers"];
+ root = nlohmann::json::array();
+ for (const auto &[path, interfaceDict] : subtree)
+ {
+ std::size_t lastPos = path.rfind("/");
+ if (lastPos == std::string::npos ||
+ (path.size() <= lastPos + 1))
+ {
+ BMCWEB_LOG_ERROR << "Failed to find '/' in " << path;
+ return;
+ }
+
+ if (interfaceDict.size() != 1)
+ {
+ BMCWEB_LOG_ERROR << "Connection size "
+ << interfaceDict.size()
+ << ", greater than 1";
+ messages::internalError(asyncResp->res);
+ return;
+ }
+
+ const std::string &connectionName =
+ interfaceDict.front().first;
+
+ size_t index = root.size();
+ nlohmann::json &storageController =
+ root.emplace_back(nlohmann::json::object());
+
+ std::string id = path.substr(lastPos + 1);
+
+ storageController["@odata.type"] =
+ "#Storage.v1_7_0.StorageController";
+ storageController["@odata.context"] =
+ "/redfish/v1/$metadata#Storage.StorageController";
+ storageController["@odata.id"] =
+ "/redfish/v1/Systems/system/Storage/1"
+ "#/StorageControllers/" +
+ std::to_string(index);
+ storageController["Name"] = id;
+ storageController["MemberId"] = id;
+ storageController["Status"]["State"] = "Enabled";
+
+ crow::connections::systemBus->async_method_call(
+ [asyncResp, index](const boost::system::error_code ec,
+ const std::variant<bool> present) {
+ // this interface isn't necessary, only check it if
+ // we get a good return
+ if (ec)
+ {
+ return;
+ }
+ const bool *enabled = std::get_if<bool>(&present);
+ if (enabled == nullptr)
+ {
+ BMCWEB_LOG_DEBUG << "Illegal property present";
+ messages::internalError(asyncResp->res);
+ return;
+ }
+ if (!(*enabled))
+ {
+ asyncResp->res
+ .jsonValue["StorageControllers"][index]
+ ["Status"]["State"] = "Disabled";
+ }
+ },
+ connectionName, path, "org.freedesktop.DBus.Properties",
+ "Get", "xyz.openbmc_project.Inventory.Item", "Present");
+
+ crow::connections::systemBus->async_method_call(
+ [asyncResp,
+ index](const boost::system::error_code ec,
+ const std::vector<std::pair<
+ std::string,
+ std::variant<bool, std::string, uint64_t>>>
+ &propertiesList) {
+ if (ec)
+ {
+ // this interface isn't necessary
+ return;
+ }
+ for (const std::pair<
+ std::string,
+ std::variant<bool, std::string, uint64_t>>
+ &property : propertiesList)
+ {
+ // Store DBus properties that are also
+ // Redfish properties with same name and a
+ // string value
+ const std::string &propertyName =
+ property.first;
+ nlohmann::json &object =
+ asyncResp->res
+ .jsonValue["StorageControllers"][index];
+ if ((propertyName == "PartNumber") ||
+ (propertyName == "SerialNumber") ||
+ (propertyName == "Manufacturer") ||
+ (propertyName == "Model"))
+ {
+ const std::string *value =
+ std::get_if<std::string>(
+ &property.second);
+ if (value == nullptr)
+ {
+ // illegal property
+ messages::internalError(asyncResp->res);
+ continue;
+ }
+ object[propertyName] = *value;
+ }
+ }
+ },
+ connectionName, path, "org.freedesktop.DBus.Properties",
+ "GetAll",
+ "xyz.openbmc_project.Inventory.Decorator.Asset");
+ }
+
+ // this is done after we know the json array will no longer be
+ // resized, as json::array uses vector underneath and we need
+ // references to its members that won't change
+ size_t count = 0;
+ for (const auto &[path, interfaceDict] : subtree)
+ {
+ auto subHealth = std::make_shared<HealthPopulate>(
+ asyncResp, root[count]["Status"]);
+ subHealth->inventory.emplace_back(path);
+ health->inventory.emplace_back(path);
+ health->children.emplace_back(subHealth);
+ count++;
+ }
+ },
+ "xyz.openbmc_project.ObjectMapper",
+ "/xyz/openbmc_project/object_mapper",
+ "xyz.openbmc_project.ObjectMapper", "GetSubTree",
+ "/xyz/openbmc_project/inventory", int32_t(0),
+ std::array<const char *, 1>{
+ "xyz.openbmc_project.Inventory.Item.StorageController"});
}
};
@@ -146,17 +298,18 @@
void doGet(crow::Response &res, const crow::Request &req,
const std::vector<std::string> ¶ms) override
{
+ auto asyncResp = std::make_shared<AsyncResp>(res);
+ if (params.size() != 1)
+ {
+ messages::internalError(asyncResp->res);
+ return;
+ }
const std::string &driveId = params[0];
- auto asyncResp = std::make_shared<AsyncResp>(res);
-
crow::connections::systemBus->async_method_call(
- [asyncResp, driveId](
- const boost::system::error_code ec,
- const std::vector<std::pair<
- std::string, std::vector<std::pair<
- std::string, std::vector<std::string>>>>>
- &subtree) {
+ [asyncResp,
+ driveId](const boost::system::error_code ec,
+ const crow::openbmc_mapper::GetSubTreeType &subtree) {
if (ec)
{
BMCWEB_LOG_ERROR << "Drive mapper call error";
@@ -251,8 +404,7 @@
asyncResp->res.jsonValue["Status"]["State"] = "Enabled";
auto health = std::make_shared<HealthPopulate>(asyncResp);
- health->inventory = std::vector<std::string>{path};
-
+ health->inventory.emplace_back(path);
health->populate();
crow::connections::systemBus->async_method_call(
diff --git a/redfish-core/lib/systems.hpp b/redfish-core/lib/systems.hpp
index 4299227..0e6cb09 100644
--- a/redfish-core/lib/systems.hpp
+++ b/redfish-core/lib/systems.hpp
@@ -1700,10 +1700,11 @@
};
auto asyncResp = std::make_shared<AsyncResp>(res);
- constexpr const std::array<const char *, 3> inventoryForSystems = {
+ constexpr const std::array<const char *, 4> inventoryForSystems = {
"xyz.openbmc_project.Inventory.Item.Dimm",
"xyz.openbmc_project.Inventory.Item.Cpu",
- "xyz.openbmc_project.Inventory.Item.Drive"};
+ "xyz.openbmc_project.Inventory.Item.Drive",
+ "xyz.openbmc_project.Inventory.Item.StorageController"};
auto health = std::make_shared<HealthPopulate>(asyncResp);
crow::connections::systemBus->async_method_call(