blob: 311395996fa9502b55fddbe4b82f3e0412efd9a6 [file] [log] [blame]
#ifndef THIRD_PARTY_GBMCWEB_REDFISH_CORE_INCLUDE_UTILS_FAN_UTILS_H_
#define THIRD_PARTY_GBMCWEB_REDFISH_CORE_INCLUDE_UTILS_FAN_UTILS_H_
#include <array>
#include <memory>
#include <string>
#include <string_view>
#include <unordered_map>
#include <utility>
#include <variant>
#include "logging.hpp"
#include "utility.hpp"
#include "async_resp.hpp"
#include "dbus_utility.hpp"
#include "error_messages.hpp"
#include <nlohmann/json.hpp>
#include "managed_store.hpp"
#include "managed_store_types.hpp"
#include "sdbusplus/message/native_types.hpp"
#ifdef UNIT_TEST_BUILD
#include "test/g3/mock_managed_store.hpp" // NOLINT
#endif
namespace redfish {
namespace fan_utils {
constexpr std::array<std::string_view, 1> fanInterfaces = {
"xyz.openbmc_project.Configuration.Fan"};
inline void fillFanProperties(
const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
const std::string& objectPath,
const dbus::utility::DBusPropertiesMap& properties,
const std::shared_ptr<std::unordered_map<std::string, std::string>>&
fanSensorToInventoryPath) {
for (const auto& [propKey, propVariant] : properties) {
if (propKey == "TachSensor") {
const std::string* tachSensor = std::get_if<std::string>(&propVariant);
if (tachSensor == nullptr) {
messages::internalError(asyncResp->res);
return;
}
(*fanSensorToInventoryPath)[*tachSensor] = objectPath;
} else if (propKey == "PWMSensor") {
const std::string* pwmSensor = std::get_if<std::string>(&propVariant);
if (pwmSensor == nullptr) {
messages::internalError(asyncResp->res);
return;
}
(*fanSensorToInventoryPath)[*pwmSensor] = objectPath;
}
}
}
template <typename Callback>
inline void getFanInventory(
const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
const std::shared_ptr<std::unordered_map<std::string, std::string>>&
fanSensorToInventoryPath,
Callback callback) {
managedStore::ManagedObjectStoreContext requestContext(asyncResp);
managedStore::GetManagedObjectStore()->getSubTree(
"/xyz/openbmc_project/inventory", 0, fanInterfaces, requestContext,
[asyncResp, fanSensorToInventoryPath, requestContext, callback{callback}](
const boost::system::error_code ec,
const dbus::utility::MapperGetSubTreeResponse& subtree) {
if (ec) {
BMCWEB_LOG_DEBUG << "DBUS response error";
messages::internalError(asyncResp->res);
return;
}
if (subtree.empty()) {
callback();
return;
}
auto fanConfigurationsQueried = std::make_shared<int>(subtree.size());
for (const auto& [objectPath, serviceMap] : subtree) {
for (const auto& [service, interfaces] : serviceMap) {
for (const auto& interface : interfaces) {
if (interface != fanInterfaces[0]) {
continue;
}
managedStore::GetManagedObjectStore()->getAllProperties(
service, objectPath, interface, requestContext,
[asyncResp, fanSensorToInventoryPath, objectPath, callback,
fanConfigurationsQueried](
const boost::system::error_code& ec,
const dbus::utility::DBusPropertiesMap& properties) {
if (ec) {
BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
messages::internalError(asyncResp->res);
return;
}
fillFanProperties(asyncResp, objectPath, properties,
fanSensorToInventoryPath);
if (*fanConfigurationsQueried <= 0) {
BMCWEB_LOG_ERROR << "Unaccounted fan configuration";
messages::internalError(asyncResp->res);
return;
}
if (*fanConfigurationsQueried == 1) {
callback();
}
--(*fanConfigurationsQueried);
});
}
}
}
});
}
inline void AddThermalSubsystemLink(
const sdbusplus::message::object_path& fanInventoryPath,
nlohmann::json& sensorJson) {
nlohmann::json::object_t obj;
obj["@odata.id"] = crow::utility::urlFromPieces(
"redfish", "v1", "Chassis", fanInventoryPath.parent_path().filename(),
"ThermalSubsystem", "Fans", fanInventoryPath.filename());
sensorJson["RelatedItem"] = nlohmann::json::array_t{std::move(obj)};
}
inline void AddRelatedItemForFanSensor(
const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
const std::string& sensorName) {
auto fanSensorToInventoryPath =
std::make_shared<std::unordered_map<std::string, std::string>>();
getFanInventory(
asyncResp, fanSensorToInventoryPath,
[asyncResp, sensorName, fanSensorToInventoryPath]() {
auto findFanObjectPath = fanSensorToInventoryPath->find(sensorName);
if (findFanObjectPath != fanSensorToInventoryPath->end()) {
sdbusplus::message::object_path fanInventoryPath(
findFanObjectPath->second);
AddThermalSubsystemLink(fanInventoryPath, asyncResp->res.jsonValue);
}
});
}
} // namespace fan_utils
} // namespace redfish
#endif // THIRD_PARTY_GBMCWEB_REDFISH_CORE_INCLUDE_UTILS_FAN_UTILS_H_