Add topology links for Chassis
Implement the physical topology design[0] for Chassis resources to
report which Chassis contain or are contained by other Chassis.
Query this information from the object mapper using associations
defined in phosphor-dbus-interfaces[1] and make it available in the
Links section of the Redfish result.
[0] https://gerrit.openbmc.org/c/openbmc/docs/+/54205
[1] https://gerrit.openbmc.org/c/openbmc/phosphor-dbus-interfaces/+/58441
Tested:
Built for evb-ast2600 with example JSON configs and ran in QEMU
Ran Redfish Service Validator with no new warnings
Sample output:
'''
curl -k -u root:0penBmc -X GET https://127.0.0.1:60443/redfish/v1/Chassis/Subchassis
{
"@odata.id": "/redfish/v1/Chassis/Subchassis",
"@odata.type": "#Chassis.v1_16_0.Chassis",
...
"Id": "Subchassis",
"Links": {
"ComputerSystems": [
{
"@odata.id": "/redfish/v1/Systems/system"
}
],
"ContainedBy": {
"@odata.id": "/redfish/v1/Chassis/Superchassis"
},
"ManagedBy": [
{
"@odata.id": "/redfish/v1/Managers/bmc"
}
]
},
...
}
curl -k -u root:0penBmc -X GET https://127.0.0.1:60443/redfish/v1/Chassis/Superchassis
{
"@odata.id": "/redfish/v1/Chassis/Superchassis",
"@odata.type": "#Chassis.v1_16_0.Chassis",
...
"Id": "Superchassis",
"Links": {
"ComputerSystems": [
{
"@odata.id": "/redfish/v1/Systems/system"
}
],
"Contains": [
{
"@odata.id": "/redfish/v1/Chassis/Subchassis"
}
],
"Contains@odata.count": 1,
"ManagedBy": [
{
"@odata.id": "/redfish/v1/Managers/bmc"
}
]
},
...
}
'''
Signed-off-by: Jie Yang <jjy@google.com>
Signed-off-by: Zhenwei Chen <zhenweichen0207@gmail.com>
Signed-off-by: Benjamin Fair <benjaminfair@google.com>
Change-Id: Idc4c3e99b8269bcc5f94112e977a89970abd0bf3
diff --git a/redfish-core/lib/chassis.hpp b/redfish-core/lib/chassis.hpp
index 30ba4bc..fc89d03 100644
--- a/redfish-core/lib/chassis.hpp
+++ b/redfish-core/lib/chassis.hpp
@@ -211,6 +211,104 @@
asyncResp, boost::urls::url("/redfish/v1/Chassis"), interfaces);
}
+inline void getChassisContainedBy(
+ const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
+ const std::string& chassisId, const boost::system::error_code& ec,
+ const dbus::utility::MapperEndPoints& upstreamChassisPaths)
+{
+ if (ec)
+ {
+ if (ec.value() != EBADR)
+ {
+ BMCWEB_LOG_ERROR << "DBUS response error " << ec;
+ messages::internalError(asyncResp->res);
+ }
+ return;
+ }
+ if (upstreamChassisPaths.empty())
+ {
+ return;
+ }
+ if (upstreamChassisPaths.size() > 1)
+ {
+ BMCWEB_LOG_ERROR << chassisId << " is contained by mutliple chassis";
+ messages::internalError(asyncResp->res);
+ return;
+ }
+
+ sdbusplus::message::object_path upstreamChassisPath(
+ upstreamChassisPaths[0]);
+ std::string upstreamChassis = upstreamChassisPath.filename();
+ if (upstreamChassis.empty())
+ {
+ BMCWEB_LOG_WARNING << "Malformed upstream Chassis path "
+ << upstreamChassisPath.str << " on " << chassisId;
+ return;
+ }
+
+ asyncResp->res.jsonValue["Links"]["ContainedBy"]["@odata.id"] =
+ boost::urls::format("/redfish/v1/Chassis/{}", upstreamChassis);
+}
+
+inline void getChassisContains(
+ const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
+ const std::string& chassisId, const boost::system::error_code& ec,
+ const dbus::utility::MapperEndPoints& downstreamChassisPaths)
+{
+ if (ec)
+ {
+ if (ec.value() != EBADR)
+ {
+ BMCWEB_LOG_ERROR << "DBUS response error " << ec;
+ messages::internalError(asyncResp->res);
+ }
+ return;
+ }
+ if (downstreamChassisPaths.empty())
+ {
+ return;
+ }
+ nlohmann::json& jValue = asyncResp->res.jsonValue["Links"]["Contains"];
+ if (!jValue.is_array())
+ {
+ // Create the array if it was empty
+ jValue = nlohmann::json::array();
+ }
+ for (const auto& p : downstreamChassisPaths)
+ {
+ sdbusplus::message::object_path downstreamChassisPath(p);
+ std::string downstreamChassis = downstreamChassisPath.filename();
+ if (downstreamChassis.empty())
+ {
+ BMCWEB_LOG_WARNING << "Malformed downstream Chassis path "
+ << downstreamChassisPath.str << " on "
+ << chassisId;
+ continue;
+ }
+ nlohmann::json link;
+ link["@odata.id"] = boost::urls::format("/redfish/v1/Chassis/{}",
+ downstreamChassis);
+ jValue.push_back(std::move(link));
+ }
+ asyncResp->res.jsonValue["Links"]["Contains@odata.count"] = jValue.size();
+}
+
+inline void
+ getChassisConnectivity(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
+ const std::string& chassisId,
+ const std::string& chassisPath)
+{
+ BMCWEB_LOG_DEBUG << "Get chassis connectivity";
+
+ dbus::utility::getAssociationEndPoints(
+ chassisPath + "/contained_by",
+ std::bind_front(getChassisContainedBy, asyncResp, chassisId));
+
+ dbus::utility::getAssociationEndPoints(
+ chassisPath + "/containing",
+ std::bind_front(getChassisContains, asyncResp, chassisId));
+}
+
/**
* ChassisCollection derived class for delivering Chassis Collection Schema
* Functions triggers appropriate requests on DBus
@@ -304,6 +402,8 @@
continue;
}
+ getChassisConnectivity(asyncResp, chassisId, path);
+
auto health = std::make_shared<HealthPopulate>(asyncResp);
if constexpr (bmcwebEnableHealthPopulate)