140e9b92eSEd Tanous // SPDX-License-Identifier: Apache-2.0 240e9b92eSEd Tanous // SPDX-FileCopyrightText: Copyright OpenBMC Authors 36c068982SEd Tanous #pragma once 46c068982SEd Tanous 56c068982SEd Tanous #include "app.hpp" 6d7857201SEd Tanous #include "async_resp.hpp" 76c068982SEd Tanous #include "error_messages.hpp" 86c068982SEd Tanous #include "http_request.hpp" 96c068982SEd Tanous #include "http_response.hpp" 10d7857201SEd Tanous #include "logging.hpp" 116c068982SEd Tanous #include "query.hpp" 128b2521a5SCarson Labrado #include "redfish_aggregator.hpp" 136c068982SEd Tanous #include "registries/privilege_registry.hpp" 146c068982SEd Tanous 15d7857201SEd Tanous #include <boost/beast/http/field.hpp> 16d7857201SEd Tanous #include <boost/beast/http/verb.hpp> 17ef4c65b7SEd Tanous #include <boost/url/format.hpp> 18d7857201SEd Tanous #include <boost/url/url.hpp> 196c068982SEd Tanous #include <nlohmann/json.hpp> 206c068982SEd Tanous 216c068982SEd Tanous #include <functional> 226c068982SEd Tanous #include <memory> 23d7857201SEd Tanous #include <unordered_map> 24d7857201SEd Tanous #include <utility> 256c068982SEd Tanous 266c068982SEd Tanous namespace redfish 276c068982SEd Tanous { 286c068982SEd Tanous 296c068982SEd Tanous inline void handleAggregationServiceHead( 306c068982SEd Tanous App& app, const crow::Request& req, 316c068982SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 326c068982SEd Tanous { 336c068982SEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 346c068982SEd Tanous { 356c068982SEd Tanous return; 366c068982SEd Tanous } 376c068982SEd Tanous asyncResp->res.addHeader( 386c068982SEd Tanous boost::beast::http::field::link, 396c068982SEd Tanous "</redfish/v1/JsonSchemas/AggregationService/AggregationService.json>; rel=describedby"); 406c068982SEd Tanous } 416c068982SEd Tanous 426c068982SEd Tanous inline void handleAggregationServiceGet( 436c068982SEd Tanous App& app, const crow::Request& req, 446c068982SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 456c068982SEd Tanous { 466c068982SEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 476c068982SEd Tanous { 486c068982SEd Tanous return; 496c068982SEd Tanous } 506c068982SEd Tanous asyncResp->res.addHeader( 516c068982SEd Tanous boost::beast::http::field::link, 526c068982SEd Tanous "</redfish/v1/JsonSchemas/AggregationService/AggregationService.json>; rel=describedby"); 536c068982SEd Tanous nlohmann::json& json = asyncResp->res.jsonValue; 546c068982SEd Tanous json["@odata.id"] = "/redfish/v1/AggregationService"; 556c068982SEd Tanous json["@odata.type"] = "#AggregationService.v1_0_1.AggregationService"; 566c068982SEd Tanous json["Id"] = "AggregationService"; 576c068982SEd Tanous json["Name"] = "Aggregation Service"; 586c068982SEd Tanous json["Description"] = "Aggregation Service"; 596c068982SEd Tanous json["ServiceEnabled"] = true; 605315c1b1SCarson Labrado json["AggregationSources"]["@odata.id"] = 615315c1b1SCarson Labrado "/redfish/v1/AggregationService/AggregationSources"; 626c068982SEd Tanous } 636c068982SEd Tanous 648b2521a5SCarson Labrado inline void requestRoutesAggregationService(App& app) 656c068982SEd Tanous { 666c068982SEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/AggregationService/") 676c068982SEd Tanous .privileges(redfish::privileges::headAggregationService) 686c068982SEd Tanous .methods(boost::beast::http::verb::head)( 696c068982SEd Tanous std::bind_front(handleAggregationServiceHead, std::ref(app))); 706c068982SEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/AggregationService/") 716c068982SEd Tanous .privileges(redfish::privileges::getAggregationService) 726c068982SEd Tanous .methods(boost::beast::http::verb::get)( 736c068982SEd Tanous std::bind_front(handleAggregationServiceGet, std::ref(app))); 746c068982SEd Tanous } 756c068982SEd Tanous 768b2521a5SCarson Labrado inline void populateAggregationSourceCollection( 778b2521a5SCarson Labrado const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 7881c4e330SEd Tanous const boost::system::error_code& ec, 798b2521a5SCarson Labrado const std::unordered_map<std::string, boost::urls::url>& satelliteInfo) 808b2521a5SCarson Labrado { 818b2521a5SCarson Labrado // Something went wrong while querying dbus 828b2521a5SCarson Labrado if (ec) 838b2521a5SCarson Labrado { 848b2521a5SCarson Labrado messages::internalError(asyncResp->res); 858b2521a5SCarson Labrado return; 868b2521a5SCarson Labrado } 8782b286fbSEd Tanous nlohmann::json::array_t members; 888b2521a5SCarson Labrado for (const auto& sat : satelliteInfo) 898b2521a5SCarson Labrado { 908b2521a5SCarson Labrado nlohmann::json::object_t member; 91ef4c65b7SEd Tanous member["@odata.id"] = boost::urls::format( 92ef4c65b7SEd Tanous "/redfish/v1/AggregationService/AggregationSources/{}", sat.first); 93ad539545SPatrick Williams members.emplace_back(std::move(member)); 948b2521a5SCarson Labrado } 958b2521a5SCarson Labrado asyncResp->res.jsonValue["Members@odata.count"] = members.size(); 968b2521a5SCarson Labrado asyncResp->res.jsonValue["Members"] = std::move(members); 978b2521a5SCarson Labrado } 988b2521a5SCarson Labrado 998b2521a5SCarson Labrado inline void handleAggregationSourceCollectionGet( 1005315c1b1SCarson Labrado App& app, const crow::Request& req, 1015315c1b1SCarson Labrado const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 1025315c1b1SCarson Labrado { 1035315c1b1SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 1045315c1b1SCarson Labrado { 1055315c1b1SCarson Labrado return; 1065315c1b1SCarson Labrado } 1075315c1b1SCarson Labrado asyncResp->res.addHeader( 1085315c1b1SCarson Labrado boost::beast::http::field::link, 1095315c1b1SCarson Labrado "</redfish/v1/JsonSchemas/AggregationSourceCollection/AggregationSourceCollection.json>; rel=describedby"); 1105315c1b1SCarson Labrado nlohmann::json& json = asyncResp->res.jsonValue; 1115315c1b1SCarson Labrado json["@odata.id"] = "/redfish/v1/AggregationService/AggregationSources"; 1125315c1b1SCarson Labrado json["@odata.type"] = 1135315c1b1SCarson Labrado "#AggregationSourceCollection.AggregationSourceCollection"; 1145315c1b1SCarson Labrado json["Name"] = "Aggregation Source Collection"; 1155315c1b1SCarson Labrado 1168b2521a5SCarson Labrado // Query D-Bus for satellite configs and add them to the Members array 1178b2521a5SCarson Labrado RedfishAggregator::getSatelliteConfigs( 1188b2521a5SCarson Labrado std::bind_front(populateAggregationSourceCollection, asyncResp)); 1195315c1b1SCarson Labrado } 1205315c1b1SCarson Labrado 1218b2521a5SCarson Labrado inline void handleAggregationSourceCollectionHead( 1228b2521a5SCarson Labrado App& app, const crow::Request& req, 1238b2521a5SCarson Labrado const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 1248b2521a5SCarson Labrado { 1258b2521a5SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 1268b2521a5SCarson Labrado { 1278b2521a5SCarson Labrado return; 1288b2521a5SCarson Labrado } 1298b2521a5SCarson Labrado asyncResp->res.addHeader( 1308b2521a5SCarson Labrado boost::beast::http::field::link, 1318b2521a5SCarson Labrado "</redfish/v1/JsonSchemas/AggregationService/AggregationSourceCollection.json>; rel=describedby"); 1328b2521a5SCarson Labrado } 1338b2521a5SCarson Labrado 1348b2521a5SCarson Labrado inline void requestRoutesAggregationSourceCollection(App& app) 1355315c1b1SCarson Labrado { 1365315c1b1SCarson Labrado BMCWEB_ROUTE(app, "/redfish/v1/AggregationService/AggregationSources/") 1378b2521a5SCarson Labrado .privileges(redfish::privileges::getAggregationSourceCollection) 1388b2521a5SCarson Labrado .methods(boost::beast::http::verb::get)(std::bind_front( 1398b2521a5SCarson Labrado handleAggregationSourceCollectionGet, std::ref(app))); 1408b2521a5SCarson Labrado 1418b2521a5SCarson Labrado BMCWEB_ROUTE(app, "/redfish/v1/AggregationService/AggregationSources/") 1428b2521a5SCarson Labrado .privileges(redfish::privileges::getAggregationSourceCollection) 1438b2521a5SCarson Labrado .methods(boost::beast::http::verb::head)(std::bind_front( 1448b2521a5SCarson Labrado handleAggregationSourceCollectionHead, std::ref(app))); 1458b2521a5SCarson Labrado } 1468b2521a5SCarson Labrado 1478b2521a5SCarson Labrado inline void populateAggregationSource( 1488b2521a5SCarson Labrado const std::string& aggregationSourceId, 1498b2521a5SCarson Labrado const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 15081c4e330SEd Tanous const boost::system::error_code& ec, 1518b2521a5SCarson Labrado const std::unordered_map<std::string, boost::urls::url>& satelliteInfo) 1528b2521a5SCarson Labrado { 1538b2521a5SCarson Labrado asyncResp->res.addHeader( 1548b2521a5SCarson Labrado boost::beast::http::field::link, 1558b2521a5SCarson Labrado "</redfish/v1/JsonSchemas/AggregationSource/AggregationSource.json>; rel=describedby"); 1568b2521a5SCarson Labrado 1578b2521a5SCarson Labrado // Something went wrong while querying dbus 1588b2521a5SCarson Labrado if (ec) 1598b2521a5SCarson Labrado { 1608b2521a5SCarson Labrado messages::internalError(asyncResp->res); 1618b2521a5SCarson Labrado return; 1628b2521a5SCarson Labrado } 1638b2521a5SCarson Labrado 1648b2521a5SCarson Labrado const auto& sat = satelliteInfo.find(aggregationSourceId); 1658b2521a5SCarson Labrado if (sat == satelliteInfo.end()) 1668b2521a5SCarson Labrado { 1678b2521a5SCarson Labrado messages::resourceNotFound(asyncResp->res, "AggregationSource", 1688b2521a5SCarson Labrado aggregationSourceId); 1698b2521a5SCarson Labrado return; 1708b2521a5SCarson Labrado } 1718b2521a5SCarson Labrado 172ef4c65b7SEd Tanous asyncResp->res.jsonValue["@odata.id"] = boost::urls::format( 173ef4c65b7SEd Tanous "/redfish/v1/AggregationService/AggregationSources/{}", 174ef4c65b7SEd Tanous aggregationSourceId); 1758b2521a5SCarson Labrado asyncResp->res.jsonValue["@odata.type"] = 1768b2521a5SCarson Labrado "#AggregationSource.v1_3_1.AggregationSource"; 1778b2521a5SCarson Labrado asyncResp->res.jsonValue["Id"] = aggregationSourceId; 1788b2521a5SCarson Labrado 1798b2521a5SCarson Labrado // TODO: We may want to change this whenever we support aggregating multiple 1808b2521a5SCarson Labrado // satellite BMCs. Otherwise all AggregationSource resources will have the 1818b2521a5SCarson Labrado // same "Name". 1828b2521a5SCarson Labrado // TODO: We should use the "Name" from the satellite config whenever we add 1838b2521a5SCarson Labrado // support for including it in the data returned in satelliteInfo. 1848b2521a5SCarson Labrado asyncResp->res.jsonValue["Name"] = "Aggregation source"; 1858b2521a5SCarson Labrado std::string hostName(sat->second.encoded_origin()); 1868b2521a5SCarson Labrado asyncResp->res.jsonValue["HostName"] = std::move(hostName); 1878b2521a5SCarson Labrado 1888b2521a5SCarson Labrado // The Redfish spec requires Password to be null in responses 1898b2521a5SCarson Labrado asyncResp->res.jsonValue["Password"] = nullptr; 1908b2521a5SCarson Labrado } 1918b2521a5SCarson Labrado 1928b2521a5SCarson Labrado inline void handleAggregationSourceGet( 1938b2521a5SCarson Labrado App& app, const crow::Request& req, 1948b2521a5SCarson Labrado const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 1958b2521a5SCarson Labrado const std::string& aggregationSourceId) 1968b2521a5SCarson Labrado { 1978b2521a5SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 1988b2521a5SCarson Labrado { 1998b2521a5SCarson Labrado return; 2008b2521a5SCarson Labrado } 2018b2521a5SCarson Labrado 2028b2521a5SCarson Labrado // Query D-Bus for satellite config corresponding to the specified 2038b2521a5SCarson Labrado // AggregationSource 2048b2521a5SCarson Labrado RedfishAggregator::getSatelliteConfigs(std::bind_front( 2058b2521a5SCarson Labrado populateAggregationSource, aggregationSourceId, asyncResp)); 2068b2521a5SCarson Labrado } 2078b2521a5SCarson Labrado 2088b2521a5SCarson Labrado inline void handleAggregationSourceHead( 2098b2521a5SCarson Labrado App& app, const crow::Request& req, 2108b2521a5SCarson Labrado const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2118b2521a5SCarson Labrado const std::string& aggregationSourceId) 2128b2521a5SCarson Labrado { 2138b2521a5SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 2148b2521a5SCarson Labrado { 2158b2521a5SCarson Labrado return; 2168b2521a5SCarson Labrado } 2178b2521a5SCarson Labrado asyncResp->res.addHeader( 2188b2521a5SCarson Labrado boost::beast::http::field::link, 2198b2521a5SCarson Labrado "</redfish/v1/JsonSchemas/AggregationService/AggregationSource.json>; rel=describedby"); 2208b2521a5SCarson Labrado 2218b2521a5SCarson Labrado // Needed to prevent unused variable error 22262598e31SEd Tanous BMCWEB_LOG_DEBUG("Added link header to response from {}", 22362598e31SEd Tanous aggregationSourceId); 2248b2521a5SCarson Labrado } 2258b2521a5SCarson Labrado 2268b2521a5SCarson Labrado inline void requestRoutesAggregationSource(App& app) 2278b2521a5SCarson Labrado { 2288b2521a5SCarson Labrado BMCWEB_ROUTE(app, 2298b2521a5SCarson Labrado "/redfish/v1/AggregationService/AggregationSources/<str>/") 2308b2521a5SCarson Labrado .privileges(redfish::privileges::getAggregationSource) 231*41024f39SEd Tanous .methods(boost::beast::http::verb::head)( 232*41024f39SEd Tanous std::bind_front(handleAggregationSourceHead, std::ref(app))); 233*41024f39SEd Tanous 234*41024f39SEd Tanous BMCWEB_ROUTE(app, 235*41024f39SEd Tanous "/redfish/v1/AggregationService/AggregationSources/<str>/") 236*41024f39SEd Tanous .privileges(redfish::privileges::getAggregationSource) 2375315c1b1SCarson Labrado .methods(boost::beast::http::verb::get)( 2388b2521a5SCarson Labrado std::bind_front(handleAggregationSourceGet, std::ref(app))); 2395315c1b1SCarson Labrado } 2405315c1b1SCarson Labrado 2416c068982SEd Tanous } // namespace redfish 242