| #pragma once |
| |
| #include "dbus_utility.hpp" |
| #include "logging.hpp" |
| #include "managed_store.hpp" |
| |
| #include <sdbusplus/message/native_types.hpp> |
| #include <sdbusplus/unpack_properties.hpp> |
| |
| #include <set> |
| |
| #ifdef UNIT_TEST_BUILD |
| #include "test/g3/mock_managed_store.hpp" // NOLINT |
| #endif |
| |
| namespace redfish |
| { |
| namespace dbus_utils |
| { |
| |
| struct UnpackErrorPrinter |
| { |
| void operator()(const sdbusplus::UnpackErrorReason reason, |
| const std::string& property) const noexcept |
| { |
| BMCWEB_LOG_ERROR |
| << "DBUS property error in property: " << property << ", reason: " |
| << static_cast< |
| std::underlying_type_t<sdbusplus::UnpackErrorReason>>( |
| reason); |
| } |
| }; |
| |
| inline void getPropertiesFromManagedObjects( |
| const dbus::utility::ManagedObjectType& managedObjects, |
| const std::string& objPath, const std::string& interface, |
| dbus::utility::DBusPropertiesMap& properties) |
| { |
| for (const auto& object : managedObjects) |
| { |
| if (object.first.str != objPath) |
| { |
| continue; |
| } |
| |
| for (const auto& interfaceMap : object.second) |
| { |
| if (interfaceMap.first != interface) |
| { |
| continue; |
| } |
| properties = interfaceMap.second; |
| } |
| } |
| } |
| |
| // Populates |serviceNames| list with unique services found in the given |
| // subtree. |
| inline std::vector<std::string> getServiceNamesFromSubtree( |
| const dbus::utility::MapperGetSubTreeResponse& subtree) |
| { |
| std::set<std::string> uniqueServiceNames; |
| for (const auto& [_, serviceMap] : subtree) |
| { |
| for (const auto& servicePair : serviceMap) |
| { |
| uniqueServiceNames.insert(servicePair.first); |
| } |
| } |
| return {uniqueServiceNames.begin(), uniqueServiceNames.end()}; |
| } |
| |
| // Checks if any one of given interfaces is present in the service map. |
| inline bool findInterfacesInServiceMap( |
| const dbus::utility::MapperServiceMap& serviceMap, |
| std::span<const std::string_view> interfaces) |
| { |
| for (const auto& [serviceName, interfaceList] : serviceMap) |
| { |
| if (std::find_first_of(interfaceList.begin(), interfaceList.end(), |
| interfaces.begin(), |
| interfaces.end()) != interfaceList.end()) |
| { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| /** |
| * Recursively gets managed objects under given object path from each service in |
| * the given list of service names and maps objects to the service name they |
| * originate from. |
| * |
| * @param[in] serviceList Mutable list of unique service names. |
| * @param[in] objPath Managed objects are requested relative |
| * to this path. |
| * @param[in,out] managedObjectsByService Service name to managed objects map. |
| * @param[in] callback Callback to execute after getting |
| * managed objects from all service names |
| * in the list. |
| */ |
| template <typename Callback> |
| inline void getManagedObjectsInEachServiceCallback( |
| std::vector<std::string>&& serviceList, |
| const sdbusplus::message::object_path& objPath, |
| std::unordered_map<std::string, dbus::utility::ManagedObjectType>&& |
| managedObjectsByService, |
| const managedStore::ManagedObjectStoreContext& context, Callback&& callback) |
| { |
| BMCWEB_LOG_DEBUG << "GetManagedObjects from next service in list."; |
| if (serviceList.empty()) |
| { |
| BMCWEB_LOG_DEBUG << "Recieved managed objects from all services."; |
| callback(managedObjectsByService); |
| return; |
| } |
| std::string serviceName = serviceList.back(); |
| serviceList.pop_back(); |
| |
| managedStore::GetManagedObjectStore()->getManagedObjectsWithContext( |
| serviceName, objPath, context, |
| [serviceList{std::move(serviceList)}, serviceName, objPath, |
| managedObjectsByService{std::move(managedObjectsByService)}, |
| context = context, callback{std::forward<Callback>(callback)}]( |
| const boost::system::error_code& ec, |
| const dbus::utility::ManagedObjectType& managedObjects) mutable { |
| if (!ec) |
| { |
| managedObjectsByService[serviceName] = managedObjects; |
| } |
| getManagedObjectsInEachServiceCallback( |
| std::move(serviceList), objPath, std::move(managedObjectsByService), |
| context, std::forward<decltype(callback)>(callback)); |
| }); |
| } |
| |
| /** |
| * Gets managed objects under given object path from each service in the given |
| * list of service names. |
| * |
| * @param[in] serviceList Mutable list of unique service names. |
| * @param[in] objPath Managed objects are requested relative |
| * to this path. |
| * @param[in] callback Callback to execute after getting |
| * managed objects from all service names |
| * in the list. |
| */ |
| template <typename Callback> |
| inline void getManagedObjectsInEachService( |
| std::vector<std::string>&& serviceList, |
| const sdbusplus::message::object_path& objPath, |
| const managedStore::ManagedObjectStoreContext& context, Callback&& callback) |
| { |
| BMCWEB_LOG_DEBUG << "Requesting managed objects from given list of " |
| << "services "; |
| std::unordered_map<std::string, dbus::utility::ManagedObjectType> |
| managedObjectsByService; |
| if (serviceList.empty()) |
| { |
| BMCWEB_LOG_ERROR << "Service list is empty"; |
| callback(managedObjectsByService); |
| return; |
| } |
| std::string serviceName = serviceList.back(); |
| serviceList.pop_back(); |
| |
| managedStore::GetManagedObjectStore()->getManagedObjectsWithContext( |
| serviceName, objPath, context, |
| [serviceList{std::move(serviceList)}, serviceName, objPath, |
| managedObjectsByService{std::move(managedObjectsByService)}, |
| context = context, callback{std::forward<Callback>(callback)}]( |
| const boost::system::error_code& ec, |
| const dbus::utility::ManagedObjectType& managedObjects) mutable { |
| if (!ec) |
| { |
| managedObjectsByService[serviceName] = managedObjects; |
| } |
| getManagedObjectsInEachServiceCallback( |
| std::move(serviceList), objPath, std::move(managedObjectsByService), |
| context, std::forward<decltype(callback)>(callback)); |
| }); |
| } |
| |
| template <typename PropertyType> |
| void getProperty(const std::string& service, const std::string& path, |
| const std::string& interface, const std::string& property, |
| const managedStore::ManagedObjectStoreContext& requestContext, |
| std::function<void(const boost::system::error_code&, |
| const PropertyType&)>&& callback) |
| { |
| managedStore::KeyType keyType(managedStore::ManagedType::kManagedProperty, |
| service, {path}, interface, property); |
| BMCWEB_LOG_STATEFUL_DEBUG << "getProperty: Key " << keyType.toString() |
| << " requestContext " |
| << requestContext.toString(); |
| |
| managedStore::GetManagedObjectStore()->getProperty( |
| keyType, requestContext, |
| [callback{std::move(callback)}]( |
| const boost::system::error_code& ec, |
| const dbus::utility::DbusVariantType& managedProperty, |
| [[maybe_unused]] uint64_t age_ms) { |
| if (ec) |
| { |
| callback(ec, {}); |
| return; |
| } |
| const PropertyType* propertyValue = |
| std::get_if<PropertyType>(&managedProperty); |
| if (propertyValue) |
| { |
| callback(ec, *propertyValue); |
| return; |
| } |
| callback(boost::system::errc::make_error_code( |
| boost::system::errc::invalid_argument), |
| {}); |
| }); |
| } |
| |
| template <typename PropertyType> |
| void getProperty(const std::string& service, const std::string& path, |
| const std::string& interface, const std::string& property, |
| const managedStore::ManagedObjectStoreContext& requestContext, |
| std::function<void(const boost::system::error_code&, |
| const PropertyType&, uint64_t)>&& callback) |
| { |
| managedStore::KeyType keyType(managedStore::ManagedType::kManagedProperty, |
| service, {path}, interface, property); |
| BMCWEB_LOG_STATEFUL_DEBUG << "getProperty: Key " << keyType.toString() |
| << " requestContext " |
| << requestContext.toString(); |
| |
| managedStore::GetManagedObjectStore()->getProperty( |
| keyType, requestContext, |
| [callback{std::move(callback)}]( |
| const boost::system::error_code& ec, |
| const dbus::utility::DbusVariantType& managedProperty, |
| uint64_t age_ms) { |
| if (ec) |
| { |
| callback(ec, {}, 0); |
| return; |
| } |
| const PropertyType* propertyValue = |
| std::get_if<PropertyType>(&managedProperty); |
| if (propertyValue) |
| { |
| callback(ec, *propertyValue, age_ms); |
| return; |
| } |
| callback(boost::system::errc::make_error_code( |
| boost::system::errc::invalid_argument), |
| {}, 0); |
| }); |
| } |
| |
| inline void getAssociationEndPoints( |
| const std::string& path, |
| const managedStore::ManagedObjectStoreContext& requestContext, |
| std::function<void(const boost::system::error_code&, |
| const dbus::utility::MapperEndPoints&)>&& callback) |
| { |
| getProperty<dbus::utility::MapperEndPoints>( |
| "xyz.openbmc_project.ObjectMapper", {path}, |
| "xyz.openbmc_project.Association", "endpoints", requestContext, |
| std::move(callback)); |
| } |
| |
| template <typename Callback> |
| inline void |
| checkDbusPathExists(const std::string& path, |
| const managedStore::ManagedObjectStoreContext& context, |
| Callback&& callback) |
| { |
| managedStore::GetManagedObjectStore()->getDbusObject( |
| path, {}, context, |
| [callback{std::forward<Callback>(callback)}]( |
| const boost::system::error_code& ec, |
| const dbus::utility::MapperGetObject& objectNames) { |
| callback(!ec && !objectNames.empty()); |
| }); |
| } |
| |
| template <typename Callback> |
| inline void getAssociatedSubTree( |
| const sdbusplus::message::object_path& associatedPath, |
| const sdbusplus::message::object_path& path, int32_t depth, |
| std::span<const std::string_view> interfaces, |
| const managedStore::ManagedObjectStoreContext& context, |
| Callback&& callback) |
| { |
| managedStore::GetManagedObjectStore()->getAssociatedSubTree( |
| associatedPath, path, depth, interfaces, context, |
| std::forward<Callback>(callback)); |
| } |
| |
| template <typename Callback> |
| inline void getAssociatedSubTreePaths( |
| const sdbusplus::message::object_path& associatedPath, |
| const sdbusplus::message::object_path& path, int32_t depth, |
| std::span<const std::string_view> interfaces, |
| const managedStore::ManagedObjectStoreContext& context, |
| Callback&& callback) |
| { |
| managedStore::GetManagedObjectStore()->getAssociatedSubTreePaths( |
| associatedPath, path, depth, interfaces, context, |
| std::forward<Callback>(callback)); |
| } |
| |
| template <typename Callback> |
| inline void getSubTree( |
| const std::string& path, int32_t depth, |
| std::span<const std::string_view> interfaces, |
| const managedStore::ManagedObjectStoreContext& context, |
| Callback&& callback) |
| { |
| managedStore::GetManagedObjectStore()->getSubTree( |
| path, depth, interfaces, context, |
| std::forward<Callback>(callback)); |
| } |
| |
| // Overload to support span of strings for interface names. |
| template <typename Callback> |
| inline void getSubTree( |
| const std::string& path, int32_t depth, std::span<std::string> interfaces, |
| const managedStore::ManagedObjectStoreContext& context, |
| Callback&& callback) |
| { |
| managedStore::GetManagedObjectStore()->getSubTree( |
| path, depth, interfaces, context, |
| std::forward<Callback>(callback)); |
| } |
| |
| template <typename Callback> |
| inline void getSubTreePaths( |
| const std::string& path, int32_t depth, |
| std::span<const std::string_view> interfaces, |
| const managedStore::ManagedObjectStoreContext& context, |
| Callback&& callback) |
| { |
| managedStore::GetManagedObjectStore()->getSubTreePaths( |
| path, depth, interfaces, context, |
| std::forward<Callback>(callback)); |
| } |
| |
| template <typename Callback> |
| inline void getManagedObjects( |
| const std::string& service, const sdbusplus::message::object_path& path, |
| const managedStore::ManagedObjectStoreContext& context, |
| Callback&& callback) |
| { |
| managedStore::GetManagedObjectStore()->getManagedObjectsWithContext( |
| service, path, context, |
| std::forward<Callback>(callback)); |
| } |
| |
| template <typename Callback> |
| inline void getDbusObject(const std::string& path, |
| std::span<const std::string_view> interfaces, |
| const managedStore::ManagedObjectStoreContext& context, |
| Callback&& callback) |
| { |
| managedStore::GetManagedObjectStore()->getDbusObject( |
| path, interfaces, context, std::forward<Callback>(callback)); |
| } |
| |
| } // namespace dbus_utils |
| } // namespace redfish |