| #ifndef THIRD_PARTY_GBMCWEB_REDFISH_CORE_LIB_TRUSTED_COMPONENT_H_ | |
| #define THIRD_PARTY_GBMCWEB_REDFISH_CORE_LIB_TRUSTED_COMPONENT_H_ | |
| /* | |
| // Copyright (c) 2023 Google | |
| / | |
| // Licensed under the Apache License, Version 2.0 (the "License"); | |
| // you may not use this file except in compliance with the License. | |
| // You may obtain a copy of the License at | |
| // | |
| // http://www.apache.org/licenses/LICENSE-2.0 | |
| // | |
| // Unless required by applicable law or agreed to in writing, software | |
| // distributed under the License is distributed on an "AS IS" BASIS, | |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| // See the License for the specific language governing permissions and | |
| // limitations under the License. | |
| */ | |
| #include <algorithm> | |
| #include <array> | |
| #include <functional> | |
| #include <memory> | |
| #include <optional> | |
| #include <string> | |
| #include <string_view> | |
| #include <tuple> | |
| #include <utility> | |
| #include <vector> | |
| #include "boost/container/flat_map.hpp" // NOLINT | |
| #include "boost/system/error_code.hpp" // NOLINT | |
| #include "boost/url/format.hpp" // NOLINT | |
| #include "app.hpp" | |
| #include "http_request.hpp" | |
| #include "logging.hpp" | |
| #include "utility.hpp" | |
| #include "async_resp.hpp" | |
| #include "dbus_utility.hpp" | |
| #include "error_messages.hpp" | |
| #include "query.hpp" | |
| #include "registries/privilege_registry.hpp" | |
| #include "chassis_utils.hpp" | |
| #include "collection.hpp" | |
| #include "dbus_utils.hpp" | |
| #include "system_utils.hpp" | |
| #include "component_integrity.hpp" | |
| #include <nlohmann/json.hpp> | |
| #include "managed_store.hpp" | |
| #include "managed_store_types.hpp" | |
| #include "sdbusplus/message/native_types.hpp" | |
| #include "sdbusplus/unpack_properties.hpp" | |
| namespace redfish { | |
| // Interfaces which imply a D-Bus object represents a TrustedComponent | |
| inline constexpr std::array<std::string_view, 1> trustedComponentInterfaces = { | |
| "xyz.openbmc_project.Inventory.Item.TrustedComponent"}; | |
| constexpr char const* discreteAttachType = | |
| "xyz.openbmc_project.Inventory.Item.TrustedComponent.ComponentAttachType." | |
| "Discrete"; | |
| constexpr char const* integratedAttachType = | |
| "xyz.openbmc_project.Inventory.Item.TrustedComponent.ComponentAttachType." | |
| "Integrated"; | |
| constexpr char const* decoratorAssetIntf = | |
| "xyz.openbmc_project.Inventory.Decorator.Asset"; | |
| constexpr char const* uuidIntf = "xyz.openbmc_project.Common.UUID"; | |
| constexpr char const* trustedComponentIntf = | |
| "xyz.openbmc_project.Inventory.Item.TrustedComponent"; | |
| /** | |
| * Map a given vector of D-Bus object path to an array of Redfish | |
| * URI. | |
| * | |
| * @param[in] property1 Redfish property name. | |
| * @param[in] property2 Optional second Redfish property name. | |
| * @param[in] nodeList vector of path string. | |
| * | |
| * @return entities Array of Redfish URI in json. | |
| */ | |
| inline std::optional<nlohmann::json> mapObjectPathVector( | |
| const std::string& property1, const std::string& property2, | |
| const std::vector<std::string>& pathList) { | |
| nlohmann::json entities = nlohmann::json::array(); | |
| for (const std::string& node : pathList) { | |
| sdbusplus::message::object_path path(node); | |
| std::string entityId = path.filename(); | |
| if (entityId.empty()) { | |
| BMCWEB_LOG_ERROR << "Invalid object path:" << property1 << " " | |
| << property2 << ":" << path.str; | |
| return std::nullopt; | |
| } | |
| nlohmann::json::object_t entity; | |
| if (property2.empty()) { | |
| entity["@odata.id"] = | |
| crow::utility::urlFromPieces("redfish", "v1", property1, entityId); | |
| } else { | |
| entity["@odata.id"] = crow::utility::urlFromPieces( | |
| "redfish", "v1", property1, property2, entityId); | |
| } | |
| entities.push_back(std::move(entity)); | |
| } | |
| return {std::move(entities)}; | |
| } | |
| /** | |
| * Find the D-Bus object representing the requested TrustedComponent, and call | |
| * the handler with the results. If matching object is not found, add 404 error | |
| * to response and don't call the handler. | |
| * | |
| * @param[in,out] resp Async HTTP response. | |
| * @param[in] chassisId Redfish Chassis Id. | |
| * @param[in] componentId Redfish TrustedComponent Id. | |
| * @param[in] handler Callback to continue processing request upon | |
| * successfully finding object. | |
| */ | |
| template <typename Handler> | |
| inline void getTrustedComponentObject( | |
| const std::shared_ptr<bmcweb::AsyncResp>& resp, | |
| const std::string& chassisId, const std::string& componentId, | |
| Handler&& handler) { | |
| BMCWEB_LOG_DEBUG << "Get available chassis trusted_component resources."; | |
| // GetSubTree on all interfaces which provide info about TrustedComponent | |
| constexpr std::array<std::string_view, 1> interfaces = {trustedComponentIntf}; | |
| std::string trustedComponentsPath = | |
| sdbusplus::message::object_path("/xyz/openbmc_project/Chassis") / | |
| chassisId / "TrustedComponents"; | |
| managedStore::ManagedObjectStoreContext context(resp); | |
| managedStore::GetManagedObjectStore()->getSubTree( | |
| trustedComponentsPath, 0, interfaces, context, | |
| [resp, chassisId, componentId, handler]( | |
| const boost::system::error_code& ec, | |
| const dbus::utility::MapperGetSubTreeResponse& subtree) { | |
| if (ec) { | |
| BMCWEB_LOG_ERROR << "DBUS response error: " << ec; | |
| messages::internalError(resp->res); | |
| return; | |
| } | |
| for (const auto& [objectPath, serviceMap] : subtree) { | |
| // Ignore any objects which don't end with our desired component | |
| // name | |
| if (!objectPath.ends_with(componentId)) { | |
| continue; | |
| } | |
| bool found = false; | |
| for (const auto& [serviceName, interfaceList] : serviceMap) { | |
| if (std::find_first_of(interfaceList.begin(), interfaceList.end(), | |
| trustedComponentInterfaces.begin(), | |
| trustedComponentInterfaces.end()) != | |
| interfaceList.end()) { | |
| found = true; | |
| break; | |
| } | |
| } | |
| if (!found) { | |
| continue; | |
| } | |
| // Found something, populate Name and Id before get Interface info | |
| resp->res.jsonValue["@odata.id"] = crow::utility::urlFromPieces( | |
| "redfish", "v1", "Chassis", chassisId, "TrustedComponents", | |
| componentId); | |
| resp->res.jsonValue["Name"] = componentId; | |
| resp->res.jsonValue["Id"] = componentId; | |
| handler(objectPath, serviceMap); | |
| return; | |
| } | |
| messages::resourceNotFound(resp->res, "TrustedComponent", componentId); | |
| }); | |
| } | |
| inline void getTrustedComponentIntegratedIntoInfo( | |
| const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, | |
| const std::string& trustedComponentObjPath, | |
| const boost::system::error_code& ec, | |
| const dbus::utility::MapperEndPoints& integratedIntoObjPaths) { | |
| if (ec) { | |
| if (ec.value() != EBADR) { | |
| BMCWEB_LOG_ERROR << "DBUS response error " << ec; | |
| messages::internalError(asyncResp->res); | |
| } | |
| return; | |
| } | |
| if (integratedIntoObjPaths.empty()) { | |
| return; | |
| } | |
| managedStore::ManagedObjectStoreContext requestContext(asyncResp); | |
| for (const auto& objpath : integratedIntoObjPaths) { | |
| sdbusplus::message::object_path integratedIntoObjPath(objpath); | |
| const std::string objName = integratedIntoObjPath.filename(); | |
| if (objName.empty()) { | |
| BMCWEB_LOG_WARNING << "Malformed integratedInto object path " | |
| << integratedIntoObjPath.str << " for " | |
| << trustedComponentObjPath; | |
| continue; | |
| } | |
| managedStore::GetManagedObjectStore()->getDbusObject( | |
| objpath, {}, requestContext, | |
| [asyncResp, integratedIntoObjPath, trustedComponentObjPath, | |
| requestContext, | |
| objName](const boost::system::error_code& ec2, | |
| const dbus::utility::MapperGetObject& object) { | |
| if (ec2) { | |
| BMCWEB_LOG_ERROR << "DBUS response error"; | |
| messages::internalError(asyncResp->res); | |
| return; | |
| } | |
| nlohmann::json::object_t integratedPath; | |
| // Link can be Chassis or Board, Processor, Drive, and NetworkAdapters | |
| // handle Chassis or Board case | |
| if (redfish::dbus_utils::findInterfacesInServiceMap( | |
| object, redfish::chassis_utils::chassisInterfaces)) { | |
| integratedPath["@odata.id"] = crow::utility::urlFromPieces( | |
| "redfish", "v1", "Chassis", objName); | |
| asyncResp->res.jsonValue["Links"]["IntegratedInto"] = | |
| std::move(integratedPath); | |
| return; | |
| } | |
| // handle NetworkAdaptors: parent resource can only be Chassis. | |
| if (redfish::dbus_utils::findInterfacesInServiceMap( | |
| object, networkAdapterInterfaces)) { | |
| const std::string parentObj = | |
| integratedIntoObjPath.parent_path().filename(); | |
| if (parentObj.empty()) { | |
| BMCWEB_LOG_WARNING << "Malformed integratedInto object path " | |
| << integratedIntoObjPath.str << " for " | |
| << trustedComponentObjPath; | |
| return; | |
| } | |
| integratedPath["@odata.id"] = crow::utility::urlFromPieces( | |
| "redfish", "v1", "Chassis", parentObj, "NetworkAdapters", | |
| objName); | |
| asyncResp->res.jsonValue["Links"]["IntegratedInto"] = | |
| std::move(integratedPath); | |
| return; | |
| } | |
| // TODO(b/552633100): The contained_by -> chassis id resolution below | |
| // is duplicated in component_integrity.h. Factor it out into a shared | |
| // helper under redfish_core/include/utils/ once the new file is | |
| // plumbed through copybara. | |
| if (redfish::dbus_utils::findInterfacesInServiceMap( | |
| object, componentItemInterfaces)) { | |
| const std::string containedByPath = | |
| integratedIntoObjPath.str + "/contained_by"; | |
| dbus_utils::getAssociationEndPoints( | |
| containedByPath, requestContext, | |
| [asyncResp, integratedIntoObjPath]( | |
| const boost::system::error_code& e, | |
| const dbus::utility::MapperEndPoints& endpoints) { | |
| std::string chassisId; | |
| if (!e && !endpoints.empty()) { | |
| sdbusplus::message::object_path boardPath(endpoints.at(0)); | |
| chassisId = boardPath.filename(); | |
| } | |
| if (chassisId.empty()) { | |
| chassisId = | |
| integratedIntoObjPath.parent_path().filename(); | |
| } | |
| nlohmann::json::object_t integratedPath; | |
| integratedPath["@odata.id"] = crow::utility::urlFromPieces( | |
| "redfish", "v1", "Chassis", chassisId); | |
| asyncResp->res.jsonValue["Links"]["IntegratedInto"] = | |
| std::move(integratedPath); | |
| }); | |
| return; | |
| } | |
| // handle Drives: parent resource can only be Chassis. | |
| if (redfish::dbus_utils::findInterfacesInServiceMap( | |
| object, driveInterfaces)) { | |
| const std::string parentObj = | |
| integratedIntoObjPath.parent_path().filename(); | |
| if (parentObj.empty()) { | |
| BMCWEB_LOG_WARNING << "Malformed integratedInto object path " | |
| << integratedIntoObjPath.str << " for " | |
| << trustedComponentObjPath; | |
| return; | |
| } | |
| integratedPath["@odata.id"] = crow::utility::urlFromPieces( | |
| "redfish", "v1", "Chassis", parentObj, "Drives", objName); | |
| asyncResp->res.jsonValue["Links"]["IntegratedInto"] = | |
| std::move(integratedPath); | |
| return; | |
| } | |
| if (redfish::dbus_utils::findInterfacesInServiceMap( | |
| object, processorsInterfaces)) { | |
| std::string parentPath = integratedIntoObjPath.parent_path().str; | |
| std::string parentObj = | |
| integratedIntoObjPath.parent_path().filename(); | |
| // e.g., | |
| // /xyz/openbmc_project/inventory/system/board/BoardName/system1/chassis/motherboard/cpu0 | |
| // filter out chassis|motherboard in object path. | |
| while (parentObj == "motherboard" || parentObj == "chassis") { | |
| sdbusplus::message::object_path tempObjPath(parentPath); | |
| parentPath = tempObjPath.parent_path().str; | |
| parentObj = tempObjPath.parent_path().filename(); | |
| } | |
| if (parentObj.empty()) { | |
| BMCWEB_LOG_WARNING << "Malformed integratedInto object path " | |
| << integratedIntoObjPath.str << " for " | |
| << trustedComponentObjPath; | |
| return; | |
| } | |
| managedStore::GetManagedObjectStore()->getDbusObject( | |
| parentPath, {}, requestContext, | |
| [asyncResp, objName, parentObj]( | |
| const boost::system::error_code& ec2, | |
| const dbus::utility::MapperGetObject& object) { | |
| if (ec2) { | |
| BMCWEB_LOG_ERROR << "DBUS response error"; | |
| messages::internalError(asyncResp->res); | |
| return; | |
| } | |
| // handle Processor: parent resource has to be Systems as | |
| // OpenBMC only search for Processor under Systems though | |
| // Redfish SPEC allows Processors to be modeled under Chassis | |
| // starting from DSP2046_2022.3.pdf. | |
| nlohmann::json::object_t integratedProcessorPath; | |
| std::string parentResourceType; | |
| std::string parentResourceName; | |
| if (redfish::dbus_utils::findInterfacesInServiceMap( | |
| object, redfish::chassis_utils::chassisInterfaces)) { | |
| parentResourceType = "Systems"; | |
| parentResourceName = "system"; | |
| } else if (redfish::dbus_utils::findInterfacesInServiceMap( | |
| object, | |
| redfish::system_utils::systemInterfaces)) { | |
| parentResourceType = "Systems"; | |
| parentResourceName = parentObj; | |
| } else { | |
| BMCWEB_LOG_ERROR << "Parent resource type not " | |
| "supported for Processor resource"; | |
| messages::internalError(asyncResp->res); | |
| return; | |
| } | |
| integratedProcessorPath["@odata.id"] = | |
| crow::utility::urlFromPieces( | |
| "redfish", "v1", parentResourceType, | |
| parentResourceName, "Processors", objName); | |
| asyncResp->res.jsonValue["Links"]["IntegratedInto"] = | |
| std::move(integratedProcessorPath); | |
| return; | |
| }); | |
| return; | |
| } // end of Processor interfaces handling | |
| // Unsupported resource type | |
| BMCWEB_LOG_ERROR << "Unsupported IntegratedInto resource for " | |
| << integratedIntoObjPath.str; | |
| messages::internalError(asyncResp->res); | |
| return; | |
| }); | |
| } | |
| } | |
| /** | |
| * @brief Fill out TrustedComponent interface related info by | |
| * requesting data from the given D-Bus object. | |
| * | |
| * @param[in,out] aResp Async HTTP response. | |
| * @param[in] service D-Bus service to query. | |
| * @param[in] objPath D-Bus object to query. | |
| */ | |
| inline void getTrustedComponentInterfaceData( | |
| const std::shared_ptr<bmcweb::AsyncResp>& aResp, const std::string& service, | |
| const std::string& objPath) { | |
| BMCWEB_LOG_DEBUG << "Get TrustedComponent Interface Data"; | |
| managedStore::ManagedObjectStoreContext context(aResp); | |
| managedStore::GetManagedObjectStore()->getAllProperties( | |
| service, objPath, trustedComponentIntf, context, | |
| [objPath, aResp{aResp}, context]( | |
| const boost::system::error_code& ec, | |
| const std::vector<std::pair< | |
| std::string, dbus::utility::DbusVariantType>>& properties) { | |
| if (ec) { | |
| BMCWEB_LOG_ERROR << "DBUS response error"; | |
| messages::internalError(aResp->res); | |
| return; | |
| } | |
| const std::string* type = nullptr; | |
| const std::string* firmwareVersion = nullptr; | |
| const bool success = sdbusplus::unpackPropertiesNoThrow( | |
| dbus_utils::UnpackErrorPrinter(), properties, "FirmwareVersion", | |
| firmwareVersion, "TrustedComponentType", type); | |
| if (!success) { | |
| messages::internalError(aResp->res); | |
| return; | |
| } | |
| if ((firmwareVersion != nullptr) && !firmwareVersion->empty()) { | |
| aResp->res.jsonValue["FirmwareVersion"] = *firmwareVersion; | |
| } | |
| // For Root-of-Trust, it is safe to hardcode it as Embedded. | |
| aResp->res.jsonValue["Location"]["PartLocation"]["LocationType"] = | |
| "Embedded"; | |
| // Get active software image info from associations. | |
| std::string activeSoftwarePath = objPath + "/actively_running"; | |
| dbus_utils::getAssociationEndPoints( | |
| activeSoftwarePath, context, | |
| [aResp]( | |
| const boost::system::error_code& e, | |
| const dbus::utility::MapperEndPoints& nodeActiveSoftwareList) { | |
| if (e) { | |
| if (e.value() != EBADR) { | |
| messages::internalError(aResp->res); | |
| return; | |
| } | |
| // No resource found. | |
| return; | |
| } | |
| // One TrustedComponent object should be associated with one | |
| // activeSoftwareImage object | |
| if (nodeActiveSoftwareList.size() != 1) { | |
| BMCWEB_LOG_ERROR | |
| << "Unexpected ActiveSoftwareImage #objs (expecting 1): " | |
| << nodeActiveSoftwareList.size(); | |
| messages::internalError(aResp->res); | |
| return; | |
| } | |
| const std::string& softwareImageURI = | |
| nodeActiveSoftwareList.at(0); | |
| sdbusplus::message::object_path activeSoftwareImage( | |
| softwareImageURI); | |
| std::string softwareId = activeSoftwareImage.filename(); | |
| nlohmann::json::object_t imagePath; | |
| if (softwareId.empty()) { | |
| BMCWEB_LOG_ERROR | |
| << "TrustedComponent contains invalid activeSoftwareImage:" | |
| << activeSoftwareImage.str; | |
| messages::internalError(aResp->res); | |
| return; | |
| } | |
| imagePath["@odata.id"] = | |
| crow::utility::urlFromPieces("redfish", "v1", "UpdateService", | |
| "FirmwareInventory", softwareId); | |
| aResp->res.jsonValue["Links"]["ActiveSoftwareImage"] = | |
| std::move(imagePath); | |
| }); | |
| // Get ComponentIntegrity info from associations. | |
| std::string componentIntegrityPath = objPath + "/reported_by"; | |
| dbus_utils::getAssociationEndPoints( | |
| componentIntegrityPath, context, | |
| [aResp](const boost::system::error_code& e, | |
| const dbus::utility::MapperEndPoints& | |
| nodeComponentIntegrityList) { | |
| if (e) { | |
| if (e.value() != EBADR) { | |
| messages::internalError(aResp->res); | |
| return; | |
| } | |
| // No resource found. | |
| return; | |
| } | |
| if (nodeComponentIntegrityList.empty()) { | |
| BMCWEB_LOG_DEBUG << "No ComponentIntegrity objects found!"; | |
| return; | |
| } | |
| std::optional<nlohmann::json> components = mapObjectPathVector( | |
| "ComponentIntegrity", "", nodeComponentIntegrityList); | |
| if (!components) { | |
| BMCWEB_LOG_ERROR << "ComponentIntegrity is invalid."; | |
| messages::internalError(aResp->res); | |
| return; | |
| } | |
| aResp->res.jsonValue["Links"]["ComponentIntegrity"] = *components; | |
| }); | |
| // Get protected components info from associations. | |
| std::string protectedComponentPath = objPath + "/protecting"; | |
| dbus_utils::getAssociationEndPoints( | |
| protectedComponentPath, context, | |
| std::bind_front(getProtectedComponentsInfo, aResp, objPath)); | |
| // Get integratedInto info from associations. | |
| std::string integratedInto = objPath + "/integrated_into"; | |
| dbus_utils::getAssociationEndPoints( | |
| integratedInto, context, | |
| std::bind_front(getTrustedComponentIntegratedIntoInfo, aResp, | |
| objPath)); | |
| // Get software images info from associations. | |
| std::string softwareImagesPath = objPath + "/runs"; | |
| dbus_utils::getAssociationEndPoints( | |
| softwareImagesPath, context, | |
| [aResp]( | |
| const boost::system::error_code& e, | |
| const dbus::utility::MapperEndPoints& nodeSoftwareImagesList) { | |
| if (e) { | |
| if (e.value() != EBADR) { | |
| messages::internalError(aResp->res); | |
| return; | |
| } | |
| // No resource found. | |
| return; | |
| } | |
| // One TrustedComponent object may be associated with one | |
| // or more SoftwareImage objects | |
| if (nodeSoftwareImagesList.empty()) { | |
| BMCWEB_LOG_DEBUG << "No software image objects found!"; | |
| return; | |
| } | |
| std::optional<nlohmann::json> images = mapObjectPathVector( | |
| "UpdateService", "FirmwareInventory", nodeSoftwareImagesList); | |
| if (!images) { | |
| BMCWEB_LOG_ERROR << "SoftwareImages is invalid."; | |
| messages::internalError(aResp->res); | |
| return; | |
| } | |
| aResp->res.jsonValue["Links"]["SoftwareImages"] = *images; | |
| }); | |
| if ((type != nullptr) && !type->empty()) { | |
| if (*type == discreteAttachType) { | |
| aResp->res.jsonValue["TrustedComponentType"] = "Discrete"; | |
| } else if (*type == integratedAttachType) { | |
| aResp->res.jsonValue["TrustedComponentType"] = "Integrated"; | |
| } else { | |
| BMCWEB_LOG_ERROR << "Unrecognized ComponentAttachType!"; | |
| messages::internalError(aResp->res); | |
| return; | |
| } | |
| } else { | |
| BMCWEB_LOG_ERROR << "No ComponentAttachType found!"; | |
| messages::internalError(aResp->res); | |
| return; | |
| } | |
| }); | |
| } | |
| /** | |
| * @brief Fill out Inventory.Decorator.Asset interface related info by | |
| * requesting data from the given D-Bus object. | |
| * | |
| * @param[in,out] aResp Async HTTP response. | |
| * @param[in] service D-Bus service to query. | |
| * @param[in] objPath D-Bus object to query. | |
| */ | |
| inline void getDecoratorAssetInterfaceData( | |
| const std::shared_ptr<bmcweb::AsyncResp>& aResp, const std::string& service, | |
| const std::string& objPath) { | |
| BMCWEB_LOG_DEBUG << "Get Decorator.Asset Interface Data"; | |
| managedStore::ManagedObjectStoreContext context(aResp); | |
| managedStore::GetManagedObjectStore()->getAllProperties( | |
| service, objPath, decoratorAssetIntf, context, | |
| [objPath, aResp{aResp}, context]( | |
| const boost::system::error_code& ec, | |
| const std::vector<std::pair< | |
| std::string, dbus::utility::DbusVariantType>>& properties) { | |
| if (ec) { | |
| BMCWEB_LOG_ERROR << "DBUS response error for DecoratorAssetIntf!"; | |
| messages::internalError(aResp->res); | |
| return; | |
| } | |
| const std::string* manufacturer = nullptr; | |
| const std::string* serialNumber = nullptr; | |
| const std::string* sku = nullptr; | |
| const std::string* partNumber = nullptr; | |
| const bool success = sdbusplus::unpackPropertiesNoThrow( | |
| dbus_utils::UnpackErrorPrinter(), properties, "Manufacturer", | |
| manufacturer, "SerialNumber", serialNumber, "PartNumber", | |
| partNumber, "SKU", sku); | |
| if (!success) { | |
| BMCWEB_LOG_ERROR << "Unpacking Inventory.Decorator.Asset failed!"; | |
| messages::internalError(aResp->res); | |
| return; | |
| } | |
| if ((manufacturer != nullptr) && !manufacturer->empty()) { | |
| aResp->res.jsonValue["Manufacturer"] = *manufacturer; | |
| } | |
| if ((serialNumber != nullptr) && !serialNumber->empty()) { | |
| aResp->res.jsonValue["SerialNumber"] = *serialNumber; | |
| } | |
| if ((sku != nullptr) && !sku->empty()) { | |
| aResp->res.jsonValue["SKU"] = *sku; | |
| } | |
| if ((partNumber != nullptr) && !partNumber->empty()) { | |
| aResp->res.jsonValue["PartNumber"] = *partNumber; | |
| } | |
| }); | |
| } | |
| /** | |
| * @brief Fill out Common.UUID interface related info by | |
| * requesting data from the given D-Bus object. | |
| * | |
| * @param[in,out] aResp Async HTTP response. | |
| * @param[in] service D-Bus service to query. | |
| * @param[in] objPath D-Bus object to query. | |
| */ | |
| inline void getCommonUUIDInterfaceData( | |
| const std::shared_ptr<bmcweb::AsyncResp>& aResp, const std::string& service, | |
| const std::string& objPath) { | |
| BMCWEB_LOG_DEBUG << "Get Common.UUID Interface Data"; | |
| managedStore::ManagedObjectStoreContext context(aResp); | |
| managedStore::GetManagedObjectStore()->getAllProperties( | |
| service, objPath, uuidIntf, context, | |
| [objPath, aResp{aResp}, context]( | |
| const boost::system::error_code& ec, | |
| const std::vector<std::pair< | |
| std::string, dbus::utility::DbusVariantType>>& properties) { | |
| if (ec) { | |
| BMCWEB_LOG_DEBUG << "DBUS response error"; | |
| messages::internalError(aResp->res); | |
| return; | |
| } | |
| const std::string* uuid = nullptr; | |
| const bool success = sdbusplus::unpackPropertiesNoThrow( | |
| dbus_utils::UnpackErrorPrinter(), properties, "UUID", uuid); | |
| if (!success) { | |
| messages::internalError(aResp->res); | |
| return; | |
| } | |
| if ((uuid != nullptr) && !uuid->empty()) { | |
| aResp->res.jsonValue["UUID"] = *uuid; | |
| } | |
| }); | |
| } | |
| inline void getTrustedComponentData( | |
| const std::shared_ptr<bmcweb::AsyncResp>& aResp, | |
| const std::string& objectPath, | |
| const dbus::utility::MapperServiceMap& serviceMap) { | |
| for (const auto& [serviceName, interfaceList] : serviceMap) { | |
| for (const auto& interface : interfaceList) { | |
| if (interface == trustedComponentIntf) { | |
| getTrustedComponentInterfaceData(aResp, serviceName, objectPath); | |
| } else if (interface == decoratorAssetIntf) { | |
| getDecoratorAssetInterfaceData(aResp, serviceName, objectPath); | |
| } else if (interface == uuidIntf) { | |
| getCommonUUIDInterfaceData(aResp, serviceName, objectPath); | |
| } | |
| } | |
| } | |
| } | |
| inline void handleTrustedComponentGet( | |
| crow::App& app, const crow::Request& req, | |
| const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, | |
| const std::string& chassisId, const std::string& componentId) { | |
| if (!redfish::setUpRedfishRoute(app, req, asyncResp)) { | |
| return; | |
| } | |
| asyncResp->res.addHeader(boost::beast::http::field::link, | |
| "</redfish/v1/JsonSchemas/TrustedComponent/" | |
| "TrustedComponent.json>; rel=describedby"); | |
| asyncResp->res.jsonValue["@odata.type"] = | |
| "#TrustedComponent.v1_0_0.TrustedComponent"; | |
| getTrustedComponentObject( | |
| asyncResp, chassisId, componentId, | |
| std::bind_front(getTrustedComponentData, asyncResp)); | |
| } | |
| inline void handleTrustedComponentCollectionGet( | |
| crow::App& app, const crow::Request& req, | |
| const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, | |
| const std::string& chassisId) { | |
| if (!redfish::setUpRedfishRoute(app, req, asyncResp)) { | |
| return; | |
| } | |
| boost::urls::url url = crow::utility::urlFromPieces( | |
| "redfish", "v1", "Chassis", chassisId, "TrustedComponents"); | |
| asyncResp->res.jsonValue["@odata.type"] = | |
| "#TrustedComponentCollection.TrustedComponentCollection"; | |
| asyncResp->res.jsonValue["@odata.id"] = url.buffer(); | |
| asyncResp->res.jsonValue["Name"] = "Trusted Component Collection"; | |
| asyncResp->res.jsonValue["Description"] = "Collection of Trusted Components"; | |
| std::string trustedComponentsPath = | |
| sdbusplus::message::object_path("/xyz/openbmc_project/Chassis") / | |
| chassisId / "TrustedComponents"; | |
| collection_util::getCollectionMembers(asyncResp, url, | |
| trustedComponentInterfaces, | |
| trustedComponentsPath.c_str()); | |
| } | |
| inline void requestRoutesTrustedComponent(App& app) { | |
| BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/TrustedComponents/<str>/") | |
| .privileges(redfish::privileges::getTrustedComponent) | |
| .methods(boost::beast::http::verb::get)( | |
| std::bind_front(handleTrustedComponentGet, std::ref(app))); | |
| } | |
| inline void requestRoutesTrustedComponentCollection(App& app) { | |
| BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/TrustedComponents/") | |
| .privileges(redfish::privileges::getTrustedComponentCollection) | |
| .methods(boost::beast::http::verb::get)( | |
| std::bind_front(handleTrustedComponentCollectionGet, std::ref(app))); | |
| } | |
| } // namespace redfish | |
| #endif // THIRD_PARTY_GBMCWEB_REDFISH_CORE_LIB_TRUSTED_COMPONENT_H_ |