blob: 45e5e348ec5cf1c968b69dad5e416ff30f4dd92f [file] [log] [blame]
#pragma once
#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)
{
sdbusplus::asio::getAllProperties(
*crow::connections::systemBus, serviceName, path,
"xyz.openbmc_project.Inventory.Decorator.Asset",
[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;
}
});
}
/**
* @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 std::vector<std::string>& assemblies)
{
aResp->res.jsonValue["Assemblies@odata.count"] = assemblies.size();
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;
}
crow::connections::systemBus->async_method_call(
[aResp, assembly, assemblyId, name](
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;
}
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", name}});
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 + "/chassis");
}
else
{
std::optional<std::string> type =
location_util::getLocationType(interface);
if (type)
{
assembliesJson[assemblyIndex]["Location"]
["PartLocation"]["LocationType"] = *type;
}
}
}
}
},
"xyz.openbmc_project.ObjectMapper",
"/xyz/openbmc_project/object_mapper",
"xyz.openbmc_project.ObjectMapper", "GetObject", assembly,
std::to_array<std::string>(
{"xyz.openbmc_project.Inventory.Decorator.Asset",
"xyz.openbmc_project.Inventory.Decorator.LocationCode",
"xyz.openbmc_project.Inventory.Connector.Embedded",
"xyz.openbmc_project.Inventory.Connector.Slot"}));
}
}
/**
* @brief Api to get assembly endpoints from mapper.
* @param[in] aResp - Shared pointer for asynchronous calls.
* @param[in] assemblyId - Assembly resource ID.
* @param[in] assemblyPath - DBus path of assembly association.
*
* @return None.
*/
inline void
getAssemblyEndpoints(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
const boost::urls::url& assemblyId,
const std::string& assemblyPath)
{
// if there is assembly association, look
// for endpoints
sdbusplus::asio::getProperty<std::vector<std::string>>(
*crow::connections::systemBus, "xyz.openbmc_project.ObjectMapper",
assemblyPath, "xyz.openbmc_project.Association", "endpoints",
[aResp, assemblyId](const boost::system::error_code ec,
const std::vector<std::string>& endpoints) {
if (ec)
{
BMCWEB_LOG_DEBUG << "DBUS response error";
messages::internalError(aResp->res);
return;
}
std::vector<std::string> sortedAssemblyList = endpoints;
std::sort(sortedAssemblyList.begin(), sortedAssemblyList.end(),
AlphanumLess<std::string>());
getAssemblyProperties(aResp, assemblyId, sortedAssemblyList);
});
}
/**
* @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
crow::connections::systemBus->async_method_call(
[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() ==
"assembly")
{
getAssemblyEndpoints(aResp, assemblyId, path);
return;
}
}
},
"xyz.openbmc_project.ObjectMapper",
"/xyz/openbmc_project/object_mapper",
"xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", parentPath, 0,
std::array<const char*, 1>{"xyz.openbmc_project.Association"});
}
} // namespace redfish