1 // SPDX-License-Identifier: Apache-2.0 2 // SPDX-FileCopyrightText: Copyright OpenBMC Authors 3 #pragma once 4 5 #include "app.hpp" 6 #include "async_resp.hpp" 7 #include "error_messages.hpp" 8 #include "http_request.hpp" 9 #include "http_response.hpp" 10 #include "logging.hpp" 11 #include "query.hpp" 12 #include "redfish_aggregator.hpp" 13 #include "registries/privilege_registry.hpp" 14 15 #include <boost/beast/http/field.hpp> 16 #include <boost/beast/http/verb.hpp> 17 #include <boost/url/format.hpp> 18 #include <boost/url/url.hpp> 19 #include <nlohmann/json.hpp> 20 21 #include <functional> 22 #include <memory> 23 #include <unordered_map> 24 #include <utility> 25 26 namespace redfish 27 { 28 29 inline void handleAggregationServiceHead( 30 App& app, const crow::Request& req, 31 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 32 { 33 if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 34 { 35 return; 36 } 37 asyncResp->res.addHeader( 38 boost::beast::http::field::link, 39 "</redfish/v1/JsonSchemas/AggregationService/AggregationService.json>; rel=describedby"); 40 } 41 42 inline void handleAggregationServiceGet( 43 App& app, const crow::Request& req, 44 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 45 { 46 if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 47 { 48 return; 49 } 50 asyncResp->res.addHeader( 51 boost::beast::http::field::link, 52 "</redfish/v1/JsonSchemas/AggregationService/AggregationService.json>; rel=describedby"); 53 nlohmann::json& json = asyncResp->res.jsonValue; 54 json["@odata.id"] = "/redfish/v1/AggregationService"; 55 json["@odata.type"] = "#AggregationService.v1_0_1.AggregationService"; 56 json["Id"] = "AggregationService"; 57 json["Name"] = "Aggregation Service"; 58 json["Description"] = "Aggregation Service"; 59 json["ServiceEnabled"] = true; 60 json["AggregationSources"]["@odata.id"] = 61 "/redfish/v1/AggregationService/AggregationSources"; 62 } 63 64 inline void requestRoutesAggregationService(App& app) 65 { 66 BMCWEB_ROUTE(app, "/redfish/v1/AggregationService/") 67 .privileges(redfish::privileges::headAggregationService) 68 .methods(boost::beast::http::verb::head)( 69 std::bind_front(handleAggregationServiceHead, std::ref(app))); 70 BMCWEB_ROUTE(app, "/redfish/v1/AggregationService/") 71 .privileges(redfish::privileges::getAggregationService) 72 .methods(boost::beast::http::verb::get)( 73 std::bind_front(handleAggregationServiceGet, std::ref(app))); 74 } 75 76 inline void populateAggregationSourceCollection( 77 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 78 const boost::system::error_code& ec, 79 const std::unordered_map<std::string, boost::urls::url>& satelliteInfo) 80 { 81 // Something went wrong while querying dbus 82 if (ec) 83 { 84 messages::internalError(asyncResp->res); 85 return; 86 } 87 nlohmann::json::array_t members; 88 for (const auto& sat : satelliteInfo) 89 { 90 nlohmann::json::object_t member; 91 member["@odata.id"] = boost::urls::format( 92 "/redfish/v1/AggregationService/AggregationSources/{}", sat.first); 93 members.emplace_back(std::move(member)); 94 } 95 asyncResp->res.jsonValue["Members@odata.count"] = members.size(); 96 asyncResp->res.jsonValue["Members"] = std::move(members); 97 } 98 99 inline void handleAggregationSourceCollectionGet( 100 App& app, const crow::Request& req, 101 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 102 { 103 if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 104 { 105 return; 106 } 107 asyncResp->res.addHeader( 108 boost::beast::http::field::link, 109 "</redfish/v1/JsonSchemas/AggregationSourceCollection/AggregationSourceCollection.json>; rel=describedby"); 110 nlohmann::json& json = asyncResp->res.jsonValue; 111 json["@odata.id"] = "/redfish/v1/AggregationService/AggregationSources"; 112 json["@odata.type"] = 113 "#AggregationSourceCollection.AggregationSourceCollection"; 114 json["Name"] = "Aggregation Source Collection"; 115 116 // Query D-Bus for satellite configs and add them to the Members array 117 RedfishAggregator::getSatelliteConfigs( 118 std::bind_front(populateAggregationSourceCollection, asyncResp)); 119 } 120 121 inline void handleAggregationSourceCollectionHead( 122 App& app, const crow::Request& req, 123 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 124 { 125 if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 126 { 127 return; 128 } 129 asyncResp->res.addHeader( 130 boost::beast::http::field::link, 131 "</redfish/v1/JsonSchemas/AggregationService/AggregationSourceCollection.json>; rel=describedby"); 132 } 133 134 inline void requestRoutesAggregationSourceCollection(App& app) 135 { 136 BMCWEB_ROUTE(app, "/redfish/v1/AggregationService/AggregationSources/") 137 .privileges(redfish::privileges::getAggregationSourceCollection) 138 .methods(boost::beast::http::verb::get)(std::bind_front( 139 handleAggregationSourceCollectionGet, std::ref(app))); 140 141 BMCWEB_ROUTE(app, "/redfish/v1/AggregationService/AggregationSources/") 142 .privileges(redfish::privileges::getAggregationSourceCollection) 143 .methods(boost::beast::http::verb::head)(std::bind_front( 144 handleAggregationSourceCollectionHead, std::ref(app))); 145 } 146 147 inline void populateAggregationSource( 148 const std::string& aggregationSourceId, 149 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 150 const boost::system::error_code& ec, 151 const std::unordered_map<std::string, boost::urls::url>& satelliteInfo) 152 { 153 asyncResp->res.addHeader( 154 boost::beast::http::field::link, 155 "</redfish/v1/JsonSchemas/AggregationSource/AggregationSource.json>; rel=describedby"); 156 157 // Something went wrong while querying dbus 158 if (ec) 159 { 160 messages::internalError(asyncResp->res); 161 return; 162 } 163 164 const auto& sat = satelliteInfo.find(aggregationSourceId); 165 if (sat == satelliteInfo.end()) 166 { 167 messages::resourceNotFound(asyncResp->res, "AggregationSource", 168 aggregationSourceId); 169 return; 170 } 171 172 asyncResp->res.jsonValue["@odata.id"] = boost::urls::format( 173 "/redfish/v1/AggregationService/AggregationSources/{}", 174 aggregationSourceId); 175 asyncResp->res.jsonValue["@odata.type"] = 176 "#AggregationSource.v1_3_1.AggregationSource"; 177 asyncResp->res.jsonValue["Id"] = aggregationSourceId; 178 179 // TODO: We may want to change this whenever we support aggregating multiple 180 // satellite BMCs. Otherwise all AggregationSource resources will have the 181 // same "Name". 182 // TODO: We should use the "Name" from the satellite config whenever we add 183 // support for including it in the data returned in satelliteInfo. 184 asyncResp->res.jsonValue["Name"] = "Aggregation source"; 185 std::string hostName(sat->second.encoded_origin()); 186 asyncResp->res.jsonValue["HostName"] = std::move(hostName); 187 188 // The Redfish spec requires Password to be null in responses 189 asyncResp->res.jsonValue["Password"] = nullptr; 190 } 191 192 inline void handleAggregationSourceGet( 193 App& app, const crow::Request& req, 194 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 195 const std::string& aggregationSourceId) 196 { 197 if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 198 { 199 return; 200 } 201 202 // Query D-Bus for satellite config corresponding to the specified 203 // AggregationSource 204 RedfishAggregator::getSatelliteConfigs(std::bind_front( 205 populateAggregationSource, aggregationSourceId, asyncResp)); 206 } 207 208 inline void handleAggregationSourceHead( 209 App& app, const crow::Request& req, 210 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 211 const std::string& aggregationSourceId) 212 { 213 if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 214 { 215 return; 216 } 217 asyncResp->res.addHeader( 218 boost::beast::http::field::link, 219 "</redfish/v1/JsonSchemas/AggregationService/AggregationSource.json>; rel=describedby"); 220 221 // Needed to prevent unused variable error 222 BMCWEB_LOG_DEBUG("Added link header to response from {}", 223 aggregationSourceId); 224 } 225 226 inline void requestRoutesAggregationSource(App& app) 227 { 228 BMCWEB_ROUTE(app, 229 "/redfish/v1/AggregationService/AggregationSources/<str>/") 230 .privileges(redfish::privileges::getAggregationSource) 231 .methods(boost::beast::http::verb::head)( 232 std::bind_front(handleAggregationSourceHead, std::ref(app))); 233 234 BMCWEB_ROUTE(app, 235 "/redfish/v1/AggregationService/AggregationSources/<str>/") 236 .privileges(redfish::privileges::getAggregationSource) 237 .methods(boost::beast::http::verb::get)( 238 std::bind_front(handleAggregationSourceGet, std::ref(app))); 239 } 240 241 } // namespace redfish 242