blob: 3231b11d27f7eff39129bfa7dffbe4a7488f6c03 [file] [log] [blame]
#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