Implement Cable schema
This commit implements Cable and Cable collection schema
on bmcweb.
Testing:
Validator:
@odata.id /redfish/v1/Cables odata Exists PASS
@odata.type #CableCollection.CableCollection odata Exists
PASS
Members@odata.count 2 odata Exists PASS
Members Array (size: 2) links: Cable Yes ...
Members[0] Link: /redfish/v1/Cables/dp0_cable0 link: Cable
Yes PASS
Members[1] Link: /redfish/v1/Cables/dp0_cable1 link: Cable
Yes PASS
Description Collection of Cable Entries none Yes PASS
Name Cable Collection none Yes PASS
Oem - Resource.Oem No Optional
Property Name Value Type Exists Result
@odata.id /redfish/v1/Cables/dp0_cable0 odata Exists PASS
@odata.type #Cable.v1_0_0.Cable odata Exists PASS
CableType string Yes PASS
LengthMeters - number No Optional
Id dp0_cable0 none Yes PASS
Name Cable none Yes PASS
Property Name Value Type Exists Result
@odata.id /redfish/v1/Cables/dp0_cable1 odata Exists PASS
@odata.type #Cable.v1_0_0.Cable odata Exists PASS
CableType string Yes PASS
LengthMeters - number No Optional
Id dp0_cable1 none Yes PASS
Name Cable none Yes PASS
Note: Removed some of the fields that are optional to reduce commit msg
Tesing with Curl commands:
$ curl -k -X GET https://{$bmc}/redfish/v1/Cables
{
"@odata.id": "/redfish/v1/Cables",
"@odata.type": "#CableCollection.CableCollection",
"Description": "Collection of Cable Entries",
"Members": [
{
"@odata.id": "/redfish/v1/Cables/dp0_cable0"
},
{
"@odata.id": "/redfish/v1/Cables/dp0_cable1"
}
],
"Members@odata.count": 2,
"Name": "Cable Collection"
}
$ curl -k -X GET https://{$bmc}/redfish/v1/Cables/dp0_cable0
{
"@odata.id": "/redfish/v1/Cables/dp0_cable0",
"@odata.type": "#Cable.v1_0_0.Cable",
"CableType": "",
"Id": "dp0_cable0",
"Name": "Cable"
}
$ curl -k -X GET https://{$bmc}/redfish/v1/Cables/dp0_cable1
{
"@odata.id": "/redfish/v1/Cables/dp0_cable1",
"@odata.type": "#Cable.v1_0_0.Cable",
"CableType": "",
"Id": "dp0_cable1",
"Name": "Cable"
}
Set Length property to 1.5 meters using busctl, and check the properties
busctl set-property xyz.openbmc_project.Inventory.Manager \
/xyz/openbmc_project/inventory/cables/dp0_cable0 \
xyz.openbmc_project.Inventory.Item.Cable Length d 1.5
$ curl -k -X GET https://{$bmc}/redfish/v1/Cables/dp0_cable0
{
"@odata.id": "/redfish/v1/Cables/dp0_cable0",
"@odata.type": "#Cable.v1_0_0.Cable",
"CableType": "",
"Id": "dp0_cable0",
"LengthMeters": 1.5,
"Name": "Cable"
}
Signed-off-by: Shantappa Teekappanavar <sbteeks@yahoo.com>
Change-Id: I832ff1c1053f4d8100d04a42cc8046a61e8c1613
diff --git a/redfish-core/lib/cable.hpp b/redfish-core/lib/cable.hpp
new file mode 100644
index 0000000..05da5f6
--- /dev/null
+++ b/redfish-core/lib/cable.hpp
@@ -0,0 +1,184 @@
+#pragma once
+#include <boost/container/flat_map.hpp>
+#include <utils/json_utils.hpp>
+
+namespace redfish
+{
+/**
+ * @brief Fill cable specific properties.
+ * @param[in,out] resp HTTP response.
+ * @param[in] ec Error code corresponding to Async method call.
+ * @param[in] properties List of Cable Properties key/value pairs.
+ */
+inline void
+ fillCableProperties(crow::Response& resp,
+ const boost::system::error_code ec,
+ const dbus::utility::DBusPropertiesMap& properties)
+{
+ if (ec)
+ {
+ BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
+ messages::internalError(resp);
+ return;
+ }
+
+ for (const auto& [propKey, propVariant] : properties)
+ {
+ if (propKey == "CableTypeDescription")
+ {
+ const std::string* cableTypeDescription =
+ std::get_if<std::string>(&propVariant);
+ if (cableTypeDescription == nullptr)
+ {
+ messages::internalError(resp);
+ return;
+ }
+ resp.jsonValue["CableType"] = *cableTypeDescription;
+ }
+ else if (propKey == "Length")
+ {
+ const double* cableLength = std::get_if<double>(&propVariant);
+ if (cableLength == nullptr)
+ {
+ messages::internalError(resp);
+ return;
+ }
+
+ if (!std::isfinite(*cableLength))
+ {
+ if (std::isnan(*cableLength))
+ {
+ continue;
+ }
+ messages::internalError(resp);
+ return;
+ }
+
+ resp.jsonValue["LengthMeters"] = *cableLength;
+ }
+ }
+}
+
+/**
+ * @brief Api to get Cable properties.
+ * @param[in,out] asyncResp Async HTTP response.
+ * @param[in] cableObjectPath Object path of the Cable.
+ * @param[in] serviceMap A map to hold Service and corresponding
+ * interface list for the given cable id.
+ */
+inline void
+ getCableProperties(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
+ const std::string& cableObjectPath,
+ const dbus::utility::MapperServiceMap& serviceMap)
+{
+ BMCWEB_LOG_DEBUG << "Get Properties for cable " << cableObjectPath;
+
+ for (const auto& [service, interfaces] : serviceMap)
+ {
+ for (const auto& interface : interfaces)
+ {
+ if (interface != "xyz.openbmc_project.Inventory.Item.Cable")
+ {
+ continue;
+ }
+
+ crow::connections::systemBus->async_method_call(
+ [asyncResp](
+ const boost::system::error_code ec,
+ const dbus::utility::DBusPropertiesMap& properties) {
+ fillCableProperties(asyncResp->res, ec, properties);
+ },
+ service, cableObjectPath, "org.freedesktop.DBus.Properties",
+ "GetAll", interface);
+ }
+ }
+}
+
+/**
+ * The Cable schema
+ */
+inline void requestRoutesCable(App& app)
+{
+ BMCWEB_ROUTE(app, "/redfish/v1/Cables/<str>/")
+ .privileges(redfish::privileges::getCable)
+ .methods(boost::beast::http::verb::get)(
+ [](const crow::Request&,
+ const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
+ const std::string& cableId) {
+ BMCWEB_LOG_DEBUG << "Cable Id: " << cableId;
+ auto respHandler =
+ [asyncResp,
+ cableId](const boost::system::error_code ec,
+ const dbus::utility::MapperGetSubTreeResponse&
+ subtree) {
+ if (ec.value() == EBADR)
+ {
+ messages::resourceNotFound(
+ asyncResp->res, "#Cable.v1_0_0.Cable", cableId);
+ return;
+ }
+
+ if (ec)
+ {
+ BMCWEB_LOG_ERROR << "DBUS response error " << ec;
+ messages::internalError(asyncResp->res);
+ return;
+ }
+
+ for (const auto& [objectPath, serviceMap] : subtree)
+ {
+ sdbusplus::message::object_path path(objectPath);
+ if (path.filename() != cableId)
+ {
+ continue;
+ }
+
+ asyncResp->res.jsonValue["@odata.type"] =
+ "#Cable.v1_0_0.Cable";
+ asyncResp->res.jsonValue["@odata.id"] =
+ "/redfish/v1/Cables/" + cableId;
+ asyncResp->res.jsonValue["Id"] = cableId;
+ asyncResp->res.jsonValue["Name"] = "Cable";
+
+ getCableProperties(asyncResp, objectPath,
+ serviceMap);
+ return;
+ }
+ messages::resourceNotFound(asyncResp->res, "Cable",
+ cableId);
+ };
+
+ crow::connections::systemBus->async_method_call(
+ respHandler, "xyz.openbmc_project.ObjectMapper",
+ "/xyz/openbmc_project/object_mapper",
+ "xyz.openbmc_project.ObjectMapper", "GetSubTree",
+ "/xyz/openbmc_project/inventory", 0,
+ std::array<const char*, 1>{
+ "xyz.openbmc_project.Inventory.Item.Cable"});
+ });
+}
+
+/**
+ * Collection of Cable resource instances
+ */
+inline void requestRoutesCableCollection(App& app)
+{
+ BMCWEB_ROUTE(app, "/redfish/v1/Cables/")
+ .privileges(redfish::privileges::getCableCollection)
+ .methods(boost::beast::http::verb::get)(
+ [](const crow::Request&,
+ const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
+ asyncResp->res.jsonValue["@odata.type"] =
+ "#CableCollection.CableCollection";
+ asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/Cables";
+ asyncResp->res.jsonValue["Name"] = "Cable Collection";
+ asyncResp->res.jsonValue["Description"] =
+ "Collection of Cable Entries";
+
+ collection_util::getCollectionMembers(
+ asyncResp, "/redfish/v1/Cables",
+ {"xyz.openbmc_project.Inventory.Item.Cable"});
+ });
+}
+
+} // namespace redfish
diff --git a/redfish-core/lib/service_root.hpp b/redfish-core/lib/service_root.hpp
index 63cc210..62be63f 100644
--- a/redfish-core/lib/service_root.hpp
+++ b/redfish-core/lib/service_root.hpp
@@ -29,7 +29,8 @@
{
std::string uuid = persistent_data::getConfig().systemUuid;
- asyncResp->res.jsonValue["@odata.type"] = "#ServiceRoot.v1_5_0.ServiceRoot";
+ asyncResp->res.jsonValue["@odata.type"] =
+ "#ServiceRoot.v1_11_0.ServiceRoot";
asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1";
asyncResp->res.jsonValue["Id"] = "RootService";
asyncResp->res.jsonValue["Name"] = "Root Service";
@@ -62,6 +63,7 @@
{"@odata.id", "/redfish/v1/EventService"}};
asyncResp->res.jsonValue["TelemetryService"] = {
{"@odata.id", "/redfish/v1/TelemetryService"}};
+ asyncResp->res.jsonValue["Cables"] = {{"@odata.id", "/redfish/v1/Cables"}};
}
inline void requestRoutesServiceRoot(App& app)