Validate chassis path before populating FanZone Chassis link Update asyncPopulatePid to verify that the chassis name extracted from the PID zone configuration path exists in the inventory. Instead of unconditionally setting the Chassis link, the code now queries the inventory subtree paths and only populates the Chassis link if a matching chassis is found. Unit tests have been added to verify behavior for both valid and invalid chassis configurations. Google-Bug-Id:545645561 PiperOrigin-RevId: 967474295 Change-Id: I9af3608887d53435f2509879ed6510ed0974917c
diff --git a/redfish-core/lib/managers.hpp b/redfish-core/lib/managers.hpp index 3aa0560..6ed1bd9 100644 --- a/redfish-core/lib/managers.hpp +++ b/redfish-core/lib/managers.hpp
@@ -49,6 +49,7 @@ #include "query.hpp" #include "registries/privilege_registry.hpp" #include "boottime.hpp" +#include "chassis_utils.hpp" #include "collection.hpp" #include "dbus_utils.hpp" #include "json_utils.hpp" @@ -599,13 +600,35 @@ "redfish", "v1", "Managers", "bmc"); if (intfPair.first == pidZoneConfigurationIface) { std::string chassis; - if (!dbus::utility::getNthStringFromPath(pathPair.first.str, 5, - chassis)) { - chassis = "#IllegalValue"; + if (dbus::utility::getNthStringFromPath(pathPair.first.str, 5, + chassis)) { + managedStore::GetManagedObjectStore()->getSubTreePaths( + "/xyz/openbmc_project/inventory", 0, + chassis_utils::chassisInterfaces, context, + [asyncResp, name, chassis]( + const boost::system::error_code& ec2, + const dbus::utility::MapperGetSubTreePathsResponse& + chassisList) { + if (ec2) { + BMCWEB_LOG_ERROR + << "asyncPopulatePid: getSubTreePaths error: " + << ec2; + return; + } + for (const std::string& chassisPath : chassisList) { + sdbusplus::message::object_path path(chassisPath); + if (path.filename() == chassis) { + asyncResp->res + .jsonValue["Oem"]["OpenBmc"]["Fan"]["FanZones"] + [name]["Chassis"]["@odata.id"] = + crow::utility::urlFromPieces("redfish", "v1", + "Chassis", chassis); + return; + } + } + }); } nlohmann::json& zone = zones[name]; - zone["Chassis"]["@odata.id"] = crow::utility::urlFromPieces( - "redfish", "v1", "Chassis", chassis); url.set_fragment(("/Oem/OpenBmc/Fan/FanZones"_json_pointer / name) .to_string()); zone["@odata.id"] = url;
diff --git a/test/redfish-core/lib/manager_test.cpp b/test/redfish-core/lib/manager_test.cpp index 88a47fd..da3a399 100644 --- a/test/redfish-core/lib/manager_test.cpp +++ b/test/redfish-core/lib/manager_test.cpp
@@ -536,5 +536,105 @@ boost::beast::http::status::not_found); } +TEST_F(SnapshotFixture, asyncPopulatePidZoneChassisValid) { + const std::string connection = "xyz.openbmc_project.EntityManager"; + const std::string path = "/xyz/openbmc_project/inventory"; + const std::string zoneName = "Zone_0"; + const std::string chassisName = "TestChassis"; + + // Mock ManagedObjectType for asyncPopulatePid + dbus::utility::ManagedObjectType managedObj = { + {sdbusplus::message::object_path( + "/xyz/openbmc_project/inventory/system/chassis/" + chassisName + + "/" + zoneName), + {{"xyz.openbmc_project.Configuration.Pid.Zone", + {{"Name", DbusVariantType(zoneName)}, + {"Class", DbusVariantType("temp")}, + {"ZoneIndex", DbusVariantType(0.0)}, + {"MinThermalOutput", DbusVariantType(3000.0)}}}}}}; + + KeyType objKey(ManagedType::kManagedObject, connection, path); + ASSERT_TRUE(dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( + managedStore::GetManagedObjectStore()) + ->upsertMockObjectIntoManagedStore( + objKey, managedStore::MockManagedStoreTest::CreateValueType( + managedObj)) + .ok()); + + // Mock chassis subtree paths containing the matching chassis + std::vector<std::string> chassisPaths = { + "/xyz/openbmc_project/inventory/system/chassis/" + chassisName, + }; + KeyType chassisSubtreeKey( + ManagedType::kManagedSubtreePaths, "/xyz/openbmc_project/inventory", 0, + {"xyz.openbmc_project.Inventory.Item.Board", + "xyz.openbmc_project.Inventory.Item.Chassis"}); + ASSERT_TRUE(dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( + managedStore::GetManagedObjectStore()) + ->upsertMockObjectIntoManagedStore( + chassisSubtreeKey, + managedStore::MockManagedStoreTest::CreateValueType( + chassisPaths)) + .ok()); + + asyncPopulatePid(connection, path, "", {}, share_async_resp_); + RunIoUntilDone(); + + nlohmann::json& json = share_async_resp_->res.jsonValue; + EXPECT_EQ( + json["Oem"]["OpenBmc"]["Fan"]["FanZones"][zoneName]["Chassis"]["@odata.id"], + "/redfish/v1/Chassis/" + chassisName); +} + +TEST_F(SnapshotFixture, asyncPopulatePidZoneChassisInvalid) { + const std::string connection = "xyz.openbmc_project.EntityManager"; + const std::string path = "/xyz/openbmc_project/inventory"; + const std::string zoneName = "Zone_0"; + const std::string chassisName = "InvalidChassis"; + + // Mock ManagedObjectType with an invalid chassis name in the path + dbus::utility::ManagedObjectType managedObj = { + {sdbusplus::message::object_path( + "/xyz/openbmc_project/inventory/system/chassis/" + chassisName + + "/" + zoneName), + {{"xyz.openbmc_project.Configuration.Pid.Zone", + {{"Name", DbusVariantType(zoneName)}, + {"Class", DbusVariantType("temp")}, + {"ZoneIndex", DbusVariantType(0.0)}, + {"MinThermalOutput", DbusVariantType(3000.0)}}}}}}; + + KeyType objKey(ManagedType::kManagedObject, connection, path); + ASSERT_TRUE(dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( + managedStore::GetManagedObjectStore()) + ->upsertMockObjectIntoManagedStore( + objKey, managedStore::MockManagedStoreTest::CreateValueType( + managedObj)) + .ok()); + + // Mock chassis subtree paths containing only OtherChassis (not InvalidChassis) + std::vector<std::string> chassisPaths = { + "/xyz/openbmc_project/inventory/system/chassis/OtherChassis", + }; + KeyType chassisSubtreeKey( + ManagedType::kManagedSubtreePaths, "/xyz/openbmc_project/inventory", 0, + {"xyz.openbmc_project.Inventory.Item.Board", + "xyz.openbmc_project.Inventory.Item.Chassis"}); + ASSERT_TRUE(dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( + managedStore::GetManagedObjectStore()) + ->upsertMockObjectIntoManagedStore( + chassisSubtreeKey, + managedStore::MockManagedStoreTest::CreateValueType( + chassisPaths)) + .ok()); + + asyncPopulatePid(connection, path, "", {}, share_async_resp_); + RunIoUntilDone(); + + nlohmann::json& json = share_async_resp_->res.jsonValue; + // When chassis is invalid, Chassis property should not be reported + EXPECT_FALSE( + json["Oem"]["OpenBmc"]["Fan"]["FanZones"][zoneName].contains("Chassis")); +} + } // namespace } // namespace redfish