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