xref: /openbmc/bmcweb/redfish-core/lib/aggregation_service.hpp (revision d78572018fc2022091ff8b8eb5a7fef2172ba3d6)
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 
handleAggregationServiceHead(App & app,const crow::Request & req,const std::shared_ptr<bmcweb::AsyncResp> & asyncResp)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 
handleAggregationServiceGet(App & app,const crow::Request & req,const std::shared_ptr<bmcweb::AsyncResp> & asyncResp)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 
requestRoutesAggregationService(App & app)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 
populateAggregationSourceCollection(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const boost::system::error_code & ec,const std::unordered_map<std::string,boost::urls::url> & satelliteInfo)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 = nlohmann::json::array();
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 
handleAggregationSourceCollectionGet(App & app,const crow::Request & req,const std::shared_ptr<bmcweb::AsyncResp> & asyncResp)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 
handleAggregationSourceCollectionHead(App & app,const crow::Request & req,const std::shared_ptr<bmcweb::AsyncResp> & asyncResp)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 
requestRoutesAggregationSourceCollection(App & app)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 
populateAggregationSource(const std::string & aggregationSourceId,const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const boost::system::error_code & ec,const std::unordered_map<std::string,boost::urls::url> & satelliteInfo)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 
handleAggregationSourceGet(App & app,const crow::Request & req,const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & aggregationSourceId)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 
handleAggregationSourceHead(App & app,const crow::Request & req,const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & aggregationSourceId)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 
requestRoutesAggregationSource(App & app)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::get)(
232             std::bind_front(handleAggregationSourceGet, std::ref(app)));
233 }
234 
235 } // namespace redfish
236