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