| #pragma once |
| |
| #include "managed_store_types.hpp" |
| |
| #include <dbus_utility.hpp> |
| #include <human_sort.hpp> |
| #include <sdbusplus/asio/property.hpp> |
| #include <utility.hpp> |
| #include <utils/json_utils.hpp> |
| #include <utils/location_utils.hpp> |
| |
| namespace redfish |
| { |
| inline void addAssemblyAssetProperties( |
| const std::string& serviceName, const std::string& path, |
| const std::shared_ptr<bmcweb::AsyncResp>& aResp, std::size_t index) |
| { |
| managedStore::ManagedObjectStoreContext context(aResp); |
| managedStore::managedObjectStore->getAllProperties( |
| serviceName, path, "xyz.openbmc_project.Inventory.Decorator.Asset", |
| context, |
| [aResp, index](const boost::system::error_code ec, |
| const dbus::utility::DBusPropertiesMap& propertiesList) { |
| if (ec) |
| { |
| BMCWEB_LOG_ERROR << "Failed to get asset properties: " << ec; |
| messages::internalError(aResp->res); |
| return; |
| } |
| |
| nlohmann::json& assembliesJson = aResp->res.jsonValue["Assemblies"]; |
| if (!assembliesJson.is_array() || assembliesJson.size() <= index) |
| { |
| BMCWEB_LOG_ERROR << "Assemblies list too small"; |
| messages::internalError(aResp->res); |
| return; |
| } |
| |
| for (const auto& [propertyName, value] : propertiesList) |
| { |
| // This should really be a string_view, but nlohmann::json |
| // doesn't support string_view keys. |
| std::string jsonKey; |
| if ((propertyName == "PartNumber") || |
| (propertyName == "SerialNumber") || (propertyName == "Model") || |
| (propertyName == "SparePartNumber")) |
| { |
| jsonKey = propertyName; |
| } |
| else if (propertyName == "Manufacturer") |
| { |
| jsonKey = "Producer"; |
| } |
| else if (propertyName == "BuildDate") |
| { |
| jsonKey = "ProductionDate"; |
| } |
| else |
| { |
| // Not supported. |
| BMCWEB_LOG_WARNING << "Unsupported assembly asset " |
| << propertyName; |
| continue; |
| } |
| |
| const auto* valueStr = std::get_if<std::string>(&value); |
| if (valueStr == nullptr) |
| { |
| BMCWEB_LOG_ERROR << "Null value returned for " << propertyName; |
| messages::internalError(aResp->res); |
| return; |
| } |
| // SparePartNumber default is empty |
| if (propertyName == "SparePartNumber" && valueStr->empty()) |
| { |
| continue; |
| } |
| |
| assembliesJson[index][jsonKey] = *valueStr; |
| } |
| }); |
| } |
| |
| inline void getAssemblyPrettyName( |
| const std::string& serviceName, const std::string& path, |
| const std::shared_ptr<bmcweb::AsyncResp>& aResp, std::size_t index) |
| { |
| managedStore::ManagedObjectStoreContext context(aResp); |
| redfish::dbus_utils::getProperty<std::string>( |
| serviceName, path, "xyz.openbmc_project.Inventory.Item", "PrettyName", |
| context, |
| [aResp, index](const boost::system::error_code& ec, |
| const std::string& prettyName) { |
| if (ec) |
| { |
| BMCWEB_LOG_ERROR << "Failed to get Item properties: " << ec; |
| messages::internalError(aResp->res); |
| return; |
| } |
| |
| aResp->res.jsonValue["Assemblies"][index]["Name"] = prettyName; |
| }); |
| } |
| |
| inline void populateAssemblyProperties( |
| const std::shared_ptr<bmcweb::AsyncResp>& aResp, |
| const std::string& assembly, const boost::urls::url& assemblyId, |
| const boost::system::error_code ec, |
| const std::vector<std::pair<std::string, std::vector<std::string>>>& object) |
| { |
| if (ec) |
| { |
| BMCWEB_LOG_DEBUG << "DBUS response error"; |
| messages::internalError(aResp->res); |
| return; |
| } |
| |
| // All Assemblys implement interface |
| // "xyz.openbmc_project.Inventory.Item.Component" |
| // If interface is not found, then it is not an Assembly connection and we |
| // should abort. |
| constexpr std::array<std::string_view, 1> assemblyInterface = { |
| "xyz.openbmc_project.Inventory.Item.Component", |
| }; |
| |
| if (!redfish::dbus_utils::findInterfacesInServiceMap(object, |
| assemblyInterface)) |
| { |
| return; |
| } |
| |
| nlohmann::json& assembliesJson = aResp->res.jsonValue["Assemblies"]; |
| std::size_t assemblyIndex = assembliesJson.size(); |
| boost::urls::url dataID = assemblyId; |
| dataID.set_fragment(crow::utility::urlFromPieces( |
| "Assemblies", std::to_string(assembliesJson.size())) |
| .buffer()); |
| |
| assembliesJson.push_back( |
| {{"@odata.type", "#Assembly.v1_3_0.AssemblyData"}, |
| {"@odata.id", dataID.buffer()}, |
| {"MemberId", std::to_string(assemblyIndex)}, |
| {"Name", sdbusplus::message::object_path(assembly).filename()}}); |
| aResp->res.jsonValue["Assemblies@odata.count"] = assembliesJson.size(); |
| |
| for (const auto& [serviceName, interfaceList] : object) |
| { |
| for (const auto& interface : interfaceList) |
| { |
| if (interface == "xyz.openbmc_project.Inventory.Decorator.Asset") |
| { |
| addAssemblyAssetProperties(serviceName, assembly, aResp, |
| assemblyIndex); |
| } |
| else if (interface == "xyz.openbmc_project.Inventory." |
| "Decorator.LocationCode") |
| { |
| nlohmann::json::json_pointer locationPtr = |
| "/Assemblies"_json_pointer / assemblyIndex / "Location"; |
| location_util::getLocationCode(aResp, serviceName, assembly, |
| locationPtr); |
| location_util::getPartLocationContext(aResp, locationPtr, |
| assembly + "/contained_by"); |
| } |
| else if (interface == "xyz.openbmc_project.Inventory.Item") |
| { |
| getAssemblyPrettyName(serviceName, assembly, aResp, |
| assemblyIndex); |
| } |
| else |
| { |
| std::optional<std::string> type = |
| location_util::getLocationType(interface); |
| if (type) |
| { |
| assembliesJson[assemblyIndex]["Location"]["PartLocation"] |
| ["LocationType"] = *type; |
| } |
| } |
| } |
| } |
| } |
| |
| /** |
| * @brief Get properties for an assembly |
| * @param[in] aResp - Shared pointer for asynchronous calls. |
| * @param[in] assemblyId - Assembly resource ID. |
| * @param[in] assemblies - list of all the dbus paths associated as an assembly |
| * with the parent. |
| * @return None. |
| */ |
| inline void |
| getAssemblyProperties(const std::shared_ptr<bmcweb::AsyncResp>& aResp, |
| const boost::urls::url& assemblyId, |
| const boost::system::error_code& ec, |
| const std::vector<std::string>& assemblies) |
| { |
| if (ec) |
| { |
| BMCWEB_LOG_DEBUG << "DBUS response error"; |
| messages::internalError(aResp->res); |
| return; |
| } |
| |
| aResp->res.jsonValue["Assemblies"] = nlohmann::json::array(); |
| |
| for (const std::string& assembly : assemblies) |
| { |
| std::string name = sdbusplus::message::object_path(assembly).filename(); |
| if (name.empty()) |
| { |
| BMCWEB_LOG_DEBUG << "Empty name in assembly"; |
| messages::internalError(aResp->res); |
| return; |
| } |
| |
| constexpr std::array<std::string_view, 4> interfaces = { |
| "xyz.openbmc_project.Inventory.Decorator.Asset", |
| "xyz.openbmc_project.Inventory.Decorator.LocationCode", |
| "xyz.openbmc_project.Inventory.Connector.Embedded", |
| "xyz.openbmc_project.Inventory.Connector.Slot"}; |
| |
| dbus::utility::getDbusObject(assembly, interfaces, |
| std::bind_front(populateAssemblyProperties, |
| aResp, assembly, |
| assemblyId)); |
| } |
| } |
| |
| /** |
| * @brief Gets assemblies from assembly associations to an object. |
| * @param[in] aResp - Shared pointer for asynchronous calls. |
| * @param[in] assemblyId - Assembly resource ID. |
| * @param[in] parentPath - DBus path of parent of assembly. |
| * |
| * @return None. |
| */ |
| inline void getAssembly(const std::shared_ptr<bmcweb::AsyncResp>& aResp, |
| const boost::urls::url& assemblyId, |
| const std::string& parentPath) |
| { |
| aResp->res.jsonValue["@odata.type"] = "#Assembly.v1_3_0.Assembly"; |
| aResp->res.jsonValue["@odata.id"] = assemblyId.buffer(); |
| aResp->res.jsonValue["Name"] = "Assembly Collection"; |
| aResp->res.jsonValue["Id"] = "Assembly"; |
| |
| aResp->res.jsonValue["Assemblies"] = nlohmann::json::array(); |
| aResp->res.jsonValue["Assemblies@odata.count"] = 0; |
| |
| // check if this chassis hosts any association |
| std::array<std::string_view, 1> interfaces{ |
| "xyz.openbmc_project.Association"}; |
| managedStore::ManagedObjectStoreContext requestContext(aResp); |
| managedStore::managedObjectStore->getSubTreePaths( |
| parentPath, 0, interfaces, requestContext, |
| [aResp, assemblyId](const boost::system::error_code ec, |
| const std::vector<std::string>& paths) { |
| if (ec) |
| { |
| BMCWEB_LOG_DEBUG << "DBUS response error"; |
| messages::internalError(aResp->res); |
| return; |
| } |
| for (const std::string& path : paths) |
| { |
| if (sdbusplus::message::object_path(path).filename() == |
| "containing") |
| { |
| dbus::utility::getAssociationEndPoints( |
| path, |
| std::bind_front(getAssemblyProperties, aResp, assemblyId)); |
| return; |
| } |
| } |
| }); |
| } |
| |
| } // namespace redfish |