dbus-sensors: Associate PSU sensors correctly
PSUSensors associate sensors with the inventory item that defined its
config in EM. It also needs to associate the sensor with the containing
chassis. Today, it associates the sensor with the object that defined
the config *and* with any all objects that implement Inventory.System.
In the situation where the sensor is defined in a PowerSupply
configuration, this works because the PowerSupply itself is not a
chassis. As a result, the "chassis" <-> "all_sensors" association
pointing to the power supply inventory object is ignored. However, if
the power supply is itself a chassis, this sensor is now associated with
at least two different chassis, which results in it showing up in two
different Redfish resources in bmcweb (the defining chassis and the
system chassis).
This change uses the defining object as the chassis if it is actually a
chassis or board (i.e. represented as a Redfish Chassis resource). If it
is not, it uses the system chassis. This will not work correctly if
there is more than one chassis which also implements Inventory.System,
but we presently assume that there is only one system in a number of
places. This should be fixed when we add support for multiple Systems.
Tested: Sensors on PSUs that are also chassis have a single "chassis"
association:
busctl get-property \
xyz.openbmc_project.PSUSensor \
/xyz/openbmc_project/sensors/power/hotswap_in_Input_Power \
xyz.openbmc_project.Association.Definitions Associations
a(sss) 2 "inventory" "sensors" "/xyz/openbmc_project/inventory/system/board/psu_chassis" "chassis" "all_sensors" "/xyz/openbmc_project/inventory/system/board/psu_chassis"
Changed PSU to PowerSupply type:
busctl get-property \
xyz.openbmc_project.PSUSensor \
/xyz/openbmc_project/sensors/power/hotswap_in_Input_Power \
xyz.openbmc_project.Association.Definitions Associations
a(sss) 2 "inventory" "sensors" "/xyz/openbmc_project/inventory/system/powersupply/psu_chassis" "chassis" "all_sensors" "/xyz/openbmc_project/inventory/system/board/mainboard"
Change-Id: I8a9e4191c427b441d96f0ab53ba59825eccee997
Signed-off-by: Shounak Mitra <shounak@google.com>
diff --git a/src/Utils.cpp b/src/Utils.cpp
index 56428bc..d659d37 100644
--- a/src/Utils.cpp
+++ b/src/Utils.cpp
@@ -597,28 +597,49 @@
void setInventoryAssociation(
const std::shared_ptr<sdbusplus::asio::dbus_interface>& association,
- const std::string& path,
- const std::vector<std::string>& chassisPaths = std::vector<std::string>())
+ const std::string& inventoryPath, const std::string& chassisPath)
{
if (association)
{
- fs::path p(path);
std::vector<Association> associations;
- std::string objPath(p.parent_path().string());
-
- associations.emplace_back("inventory", "sensors", objPath);
- associations.emplace_back("chassis", "all_sensors", objPath);
-
- for (const std::string& chassisPath : chassisPaths)
- {
- associations.emplace_back("chassis", "all_sensors", chassisPath);
- }
+ associations.emplace_back("inventory", "sensors", inventoryPath);
+ associations.emplace_back("chassis", "all_sensors", chassisPath);
association->register_property("Associations", associations);
association->initialize();
}
}
+std::optional<std::string> findContainingChassis(std::string_view configParent,
+ const GetSubTreeType& subtree)
+{
+ // A parent that is a chassis takes precedence
+ for (const auto& [obj, services] : subtree)
+ {
+ if (obj == configParent)
+ {
+ return obj;
+ }
+ }
+
+ // If the parent is not a chassis, the system chassis is used. This does not
+ // work if there is more than one System, but we assume there is only one
+ // today.
+ for (const auto& [obj, services] : subtree)
+ {
+ for (const auto& [service, interfaces] : services)
+ {
+ if (std::find(interfaces.begin(), interfaces.end(),
+ "xyz.openbmc_project.Inventory.Item.System") !=
+ interfaces.end())
+ {
+ return obj;
+ }
+ }
+ }
+ return std::nullopt;
+}
+
void createInventoryAssoc(
const std::shared_ptr<sdbusplus::asio::connection>& conn,
const std::shared_ptr<sdbusplus::asio::dbus_interface>& association,
@@ -629,22 +650,31 @@
return;
}
+ constexpr auto allInterfaces = std::to_array({
+ "xyz.openbmc_project.Inventory.Item.Board",
+ "xyz.openbmc_project.Inventory.Item.Chassis",
+ });
+
conn->async_method_call(
[association, path](const boost::system::error_code ec,
- const std::vector<std::string>& invSysObjPaths) {
+ const GetSubTreeType& subtree) {
+ // The parent of the config is always the inventory object, and may be
+ // the associated chassis. If the parent is not itself a chassis or
+ // board, the sensor is associated with the system chassis.
+ std::string parent = fs::path(path).parent_path().string();
if (ec)
{
// In case of error, set the default associations and
// initialize the association Interface.
- setInventoryAssociation(association, path);
+ setInventoryAssociation(association, parent, parent);
return;
}
- setInventoryAssociation(association, path, invSysObjPaths);
+ setInventoryAssociation(
+ association, parent,
+ findContainingChassis(parent, subtree).value_or(parent));
},
- mapper::busName, mapper::path, mapper::interface, "GetSubTreePaths",
- "/xyz/openbmc_project/inventory/system", 2,
- std::array<std::string, 1>{
- "xyz.openbmc_project.Inventory.Item.System"});
+ mapper::busName, mapper::path, mapper::interface, "GetSubTree",
+ "/xyz/openbmc_project/inventory/system", 2, allInterfaces);
}
std::optional<double> readFile(const std::string& thresholdFile,