1*7bf29ab3SChristopher Meis // SPDX-License-Identifier: Apache-2.0 2*7bf29ab3SChristopher Meis // SPDX-FileCopyrightText: Copyright OpenBMC Authors 3*7bf29ab3SChristopher Meis // SPDX-FileCopyrightText: Copyright 2019 Intel Corporation 4*7bf29ab3SChristopher Meis #pragma once 5*7bf29ab3SChristopher Meis 6*7bf29ab3SChristopher Meis #include "app.hpp" 7*7bf29ab3SChristopher Meis #include "async_resp.hpp" 8*7bf29ab3SChristopher Meis #include "generated/enums/resource.hpp" 9*7bf29ab3SChristopher Meis #include "http_request.hpp" 10*7bf29ab3SChristopher Meis #include "query.hpp" 11*7bf29ab3SChristopher Meis #include "registries/privilege_registry.hpp" 12*7bf29ab3SChristopher Meis 13*7bf29ab3SChristopher Meis namespace redfish 14*7bf29ab3SChristopher Meis { 15*7bf29ab3SChristopher Meis 16*7bf29ab3SChristopher Meis inline void populateStorageController( 17*7bf29ab3SChristopher Meis const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 18*7bf29ab3SChristopher Meis const std::string& controllerId, const std::string& connectionName, 19*7bf29ab3SChristopher Meis const std::string& path) 20*7bf29ab3SChristopher Meis { 21*7bf29ab3SChristopher Meis asyncResp->res.jsonValue["@odata.type"] = 22*7bf29ab3SChristopher Meis "#StorageController.v1_6_0.StorageController"; 23*7bf29ab3SChristopher Meis asyncResp->res.jsonValue["@odata.id"] = 24*7bf29ab3SChristopher Meis boost::urls::format("/redfish/v1/Systems/{}/Storage/1/Controllers/{}", 25*7bf29ab3SChristopher Meis BMCWEB_REDFISH_SYSTEM_URI_NAME, controllerId); 26*7bf29ab3SChristopher Meis asyncResp->res.jsonValue["Name"] = controllerId; 27*7bf29ab3SChristopher Meis asyncResp->res.jsonValue["Id"] = controllerId; 28*7bf29ab3SChristopher Meis asyncResp->res.jsonValue["Status"]["State"] = resource::State::Enabled; 29*7bf29ab3SChristopher Meis 30*7bf29ab3SChristopher Meis dbus::utility::getProperty<bool>( 31*7bf29ab3SChristopher Meis connectionName, path, "xyz.openbmc_project.Inventory.Item", "Present", 32*7bf29ab3SChristopher Meis [asyncResp](const boost::system::error_code& ec, bool isPresent) { 33*7bf29ab3SChristopher Meis // this interface isn't necessary, only check it 34*7bf29ab3SChristopher Meis // if we get a good return 35*7bf29ab3SChristopher Meis if (ec) 36*7bf29ab3SChristopher Meis { 37*7bf29ab3SChristopher Meis BMCWEB_LOG_DEBUG("Failed to get Present property"); 38*7bf29ab3SChristopher Meis return; 39*7bf29ab3SChristopher Meis } 40*7bf29ab3SChristopher Meis if (!isPresent) 41*7bf29ab3SChristopher Meis { 42*7bf29ab3SChristopher Meis asyncResp->res.jsonValue["Status"]["State"] = 43*7bf29ab3SChristopher Meis resource::State::Absent; 44*7bf29ab3SChristopher Meis } 45*7bf29ab3SChristopher Meis }); 46*7bf29ab3SChristopher Meis 47*7bf29ab3SChristopher Meis asset_utils::getAssetInfo(asyncResp, connectionName, path, ""_json_pointer, 48*7bf29ab3SChristopher Meis false); 49*7bf29ab3SChristopher Meis } 50*7bf29ab3SChristopher Meis 51*7bf29ab3SChristopher Meis inline void getStorageControllerHandler( 52*7bf29ab3SChristopher Meis const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 53*7bf29ab3SChristopher Meis const std::string& controllerId, const boost::system::error_code& ec, 54*7bf29ab3SChristopher Meis const dbus::utility::MapperGetSubTreeResponse& subtree) 55*7bf29ab3SChristopher Meis { 56*7bf29ab3SChristopher Meis if (ec || subtree.empty()) 57*7bf29ab3SChristopher Meis { 58*7bf29ab3SChristopher Meis // doesn't have to be there 59*7bf29ab3SChristopher Meis BMCWEB_LOG_DEBUG("Failed to handle StorageController"); 60*7bf29ab3SChristopher Meis return; 61*7bf29ab3SChristopher Meis } 62*7bf29ab3SChristopher Meis 63*7bf29ab3SChristopher Meis for (const auto& [path, interfaceDict] : subtree) 64*7bf29ab3SChristopher Meis { 65*7bf29ab3SChristopher Meis sdbusplus::message::object_path object(path); 66*7bf29ab3SChristopher Meis std::string id = object.filename(); 67*7bf29ab3SChristopher Meis if (id.empty()) 68*7bf29ab3SChristopher Meis { 69*7bf29ab3SChristopher Meis BMCWEB_LOG_ERROR("Failed to find filename in {}", path); 70*7bf29ab3SChristopher Meis return; 71*7bf29ab3SChristopher Meis } 72*7bf29ab3SChristopher Meis if (id != controllerId) 73*7bf29ab3SChristopher Meis { 74*7bf29ab3SChristopher Meis continue; 75*7bf29ab3SChristopher Meis } 76*7bf29ab3SChristopher Meis 77*7bf29ab3SChristopher Meis if (interfaceDict.size() != 1) 78*7bf29ab3SChristopher Meis { 79*7bf29ab3SChristopher Meis BMCWEB_LOG_ERROR("Connection size {}, greater than 1", 80*7bf29ab3SChristopher Meis interfaceDict.size()); 81*7bf29ab3SChristopher Meis messages::internalError(asyncResp->res); 82*7bf29ab3SChristopher Meis return; 83*7bf29ab3SChristopher Meis } 84*7bf29ab3SChristopher Meis 85*7bf29ab3SChristopher Meis const std::string& connectionName = interfaceDict.front().first; 86*7bf29ab3SChristopher Meis populateStorageController(asyncResp, controllerId, connectionName, 87*7bf29ab3SChristopher Meis path); 88*7bf29ab3SChristopher Meis } 89*7bf29ab3SChristopher Meis } 90*7bf29ab3SChristopher Meis 91*7bf29ab3SChristopher Meis inline void populateStorageControllerCollection( 92*7bf29ab3SChristopher Meis const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 93*7bf29ab3SChristopher Meis const boost::system::error_code& ec, 94*7bf29ab3SChristopher Meis const dbus::utility::MapperGetSubTreePathsResponse& controllerList) 95*7bf29ab3SChristopher Meis { 96*7bf29ab3SChristopher Meis nlohmann::json::array_t members; 97*7bf29ab3SChristopher Meis if (ec || controllerList.empty()) 98*7bf29ab3SChristopher Meis { 99*7bf29ab3SChristopher Meis asyncResp->res.jsonValue["Members"] = std::move(members); 100*7bf29ab3SChristopher Meis asyncResp->res.jsonValue["Members@odata.count"] = 0; 101*7bf29ab3SChristopher Meis BMCWEB_LOG_DEBUG("Failed to find any StorageController"); 102*7bf29ab3SChristopher Meis return; 103*7bf29ab3SChristopher Meis } 104*7bf29ab3SChristopher Meis 105*7bf29ab3SChristopher Meis for (const std::string& path : controllerList) 106*7bf29ab3SChristopher Meis { 107*7bf29ab3SChristopher Meis std::string id = sdbusplus::message::object_path(path).filename(); 108*7bf29ab3SChristopher Meis if (id.empty()) 109*7bf29ab3SChristopher Meis { 110*7bf29ab3SChristopher Meis BMCWEB_LOG_ERROR("Failed to find filename in {}", path); 111*7bf29ab3SChristopher Meis return; 112*7bf29ab3SChristopher Meis } 113*7bf29ab3SChristopher Meis nlohmann::json::object_t member; 114*7bf29ab3SChristopher Meis member["@odata.id"] = boost::urls::format( 115*7bf29ab3SChristopher Meis "/redfish/v1/Systems/{}/Storage/1/Controllers/{}", 116*7bf29ab3SChristopher Meis BMCWEB_REDFISH_SYSTEM_URI_NAME, id); 117*7bf29ab3SChristopher Meis members.emplace_back(member); 118*7bf29ab3SChristopher Meis } 119*7bf29ab3SChristopher Meis asyncResp->res.jsonValue["Members@odata.count"] = members.size(); 120*7bf29ab3SChristopher Meis asyncResp->res.jsonValue["Members"] = std::move(members); 121*7bf29ab3SChristopher Meis } 122*7bf29ab3SChristopher Meis 123*7bf29ab3SChristopher Meis inline void handleSystemsStorageControllerGet( 124*7bf29ab3SChristopher Meis App& app, const crow::Request& req, 125*7bf29ab3SChristopher Meis const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 126*7bf29ab3SChristopher Meis const std::string& systemName, const std::string& controllerId) 127*7bf29ab3SChristopher Meis { 128*7bf29ab3SChristopher Meis if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 129*7bf29ab3SChristopher Meis { 130*7bf29ab3SChristopher Meis BMCWEB_LOG_DEBUG("Failed to setup Redfish Route for StorageController"); 131*7bf29ab3SChristopher Meis return; 132*7bf29ab3SChristopher Meis } 133*7bf29ab3SChristopher Meis if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 134*7bf29ab3SChristopher Meis { 135*7bf29ab3SChristopher Meis messages::resourceNotFound(asyncResp->res, "ComputerSystem", 136*7bf29ab3SChristopher Meis systemName); 137*7bf29ab3SChristopher Meis BMCWEB_LOG_DEBUG("Failed to find ComputerSystem of {}", systemName); 138*7bf29ab3SChristopher Meis return; 139*7bf29ab3SChristopher Meis } 140*7bf29ab3SChristopher Meis constexpr std::array<std::string_view, 1> interfaces = { 141*7bf29ab3SChristopher Meis "xyz.openbmc_project.Inventory.Item.StorageController"}; 142*7bf29ab3SChristopher Meis dbus::utility::getSubTree( 143*7bf29ab3SChristopher Meis "/xyz/openbmc_project/inventory", 0, interfaces, 144*7bf29ab3SChristopher Meis [asyncResp, 145*7bf29ab3SChristopher Meis controllerId](const boost::system::error_code& ec, 146*7bf29ab3SChristopher Meis const dbus::utility::MapperGetSubTreeResponse& subtree) { 147*7bf29ab3SChristopher Meis getStorageControllerHandler(asyncResp, controllerId, ec, subtree); 148*7bf29ab3SChristopher Meis }); 149*7bf29ab3SChristopher Meis } 150*7bf29ab3SChristopher Meis 151*7bf29ab3SChristopher Meis inline void handleSystemsStorageControllerCollectionGet( 152*7bf29ab3SChristopher Meis App& app, const crow::Request& req, 153*7bf29ab3SChristopher Meis const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 154*7bf29ab3SChristopher Meis const std::string& systemName) 155*7bf29ab3SChristopher Meis { 156*7bf29ab3SChristopher Meis if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 157*7bf29ab3SChristopher Meis { 158*7bf29ab3SChristopher Meis BMCWEB_LOG_DEBUG( 159*7bf29ab3SChristopher Meis "Failed to setup Redfish Route for StorageController Collection"); 160*7bf29ab3SChristopher Meis return; 161*7bf29ab3SChristopher Meis } 162*7bf29ab3SChristopher Meis if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 163*7bf29ab3SChristopher Meis { 164*7bf29ab3SChristopher Meis messages::resourceNotFound(asyncResp->res, "ComputerSystem", 165*7bf29ab3SChristopher Meis systemName); 166*7bf29ab3SChristopher Meis BMCWEB_LOG_DEBUG("Failed to find ComputerSystem of {}", systemName); 167*7bf29ab3SChristopher Meis return; 168*7bf29ab3SChristopher Meis } 169*7bf29ab3SChristopher Meis 170*7bf29ab3SChristopher Meis asyncResp->res.jsonValue["@odata.type"] = 171*7bf29ab3SChristopher Meis "#StorageControllerCollection.StorageControllerCollection"; 172*7bf29ab3SChristopher Meis asyncResp->res.jsonValue["@odata.id"] = 173*7bf29ab3SChristopher Meis std::format("/redfish/v1/Systems/{}/Storage/1/Controllers", 174*7bf29ab3SChristopher Meis BMCWEB_REDFISH_SYSTEM_URI_NAME); 175*7bf29ab3SChristopher Meis asyncResp->res.jsonValue["Name"] = "Storage Controller Collection"; 176*7bf29ab3SChristopher Meis 177*7bf29ab3SChristopher Meis constexpr std::array<std::string_view, 1> interfaces = { 178*7bf29ab3SChristopher Meis "xyz.openbmc_project.Inventory.Item.StorageController"}; 179*7bf29ab3SChristopher Meis dbus::utility::getSubTreePaths( 180*7bf29ab3SChristopher Meis "/xyz/openbmc_project/inventory", 0, interfaces, 181*7bf29ab3SChristopher Meis [asyncResp](const boost::system::error_code& ec, 182*7bf29ab3SChristopher Meis const dbus::utility::MapperGetSubTreePathsResponse& 183*7bf29ab3SChristopher Meis controllerList) { 184*7bf29ab3SChristopher Meis populateStorageControllerCollection(asyncResp, ec, controllerList); 185*7bf29ab3SChristopher Meis }); 186*7bf29ab3SChristopher Meis } 187*7bf29ab3SChristopher Meis 188*7bf29ab3SChristopher Meis inline void requestRoutesStorageController(App& app) 189*7bf29ab3SChristopher Meis { 190*7bf29ab3SChristopher Meis BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/Storage/1/Controllers/") 191*7bf29ab3SChristopher Meis .privileges(redfish::privileges::getStorageControllerCollection) 192*7bf29ab3SChristopher Meis .methods(boost::beast::http::verb::get)(std::bind_front( 193*7bf29ab3SChristopher Meis handleSystemsStorageControllerCollectionGet, std::ref(app))); 194*7bf29ab3SChristopher Meis 195*7bf29ab3SChristopher Meis BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/Storage/1/Controllers/<str>") 196*7bf29ab3SChristopher Meis .privileges(redfish::privileges::getStorageController) 197*7bf29ab3SChristopher Meis .methods(boost::beast::http::verb::get)( 198*7bf29ab3SChristopher Meis std::bind_front(handleSystemsStorageControllerGet, std::ref(app))); 199*7bf29ab3SChristopher Meis } 200*7bf29ab3SChristopher Meis 201*7bf29ab3SChristopher Meis } // namespace redfish 202