xref: /openbmc/bmcweb/features/redfish/lib/event_service.hpp (revision 4bbf237f4217afd1a0fa8c474a921a9175732b13)
1e5aaf047SAppaRao Puli /*
2e5aaf047SAppaRao Puli // Copyright (c) 2020 Intel Corporation
3e5aaf047SAppaRao Puli //
4e5aaf047SAppaRao Puli // Licensed under the Apache License, Version 2.0 (the "License");
5e5aaf047SAppaRao Puli // you may not use this file except in compliance with the License.
6e5aaf047SAppaRao Puli // You may obtain a copy of the License at
7e5aaf047SAppaRao Puli //
8e5aaf047SAppaRao Puli //      http://www.apache.org/licenses/LICENSE-2.0
9e5aaf047SAppaRao Puli //
10e5aaf047SAppaRao Puli // Unless required by applicable law or agreed to in writing, software
11e5aaf047SAppaRao Puli // distributed under the License is distributed on an "AS IS" BASIS,
12e5aaf047SAppaRao Puli // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13e5aaf047SAppaRao Puli // See the License for the specific language governing permissions and
14e5aaf047SAppaRao Puli // limitations under the License.
15e5aaf047SAppaRao Puli */
16e5aaf047SAppaRao Puli #pragma once
17b52664e2SAppaRao Puli #include "event_service_manager.hpp"
18e5aaf047SAppaRao Puli 
19e5aaf047SAppaRao Puli namespace redfish
20e5aaf047SAppaRao Puli {
21e5aaf047SAppaRao Puli 
22156d6b00SAppaRao Puli static constexpr const std::array<const char*, 2> supportedEvtFormatTypes = {
23156d6b00SAppaRao Puli     eventFormatType, metricReportFormatType};
24e5aaf047SAppaRao Puli static constexpr const std::array<const char*, 3> supportedRegPrefixes = {
25e5aaf047SAppaRao Puli     "Base", "OpenBMC", "Task"};
26e5aaf047SAppaRao Puli static constexpr const std::array<const char*, 3> supportedRetryPolicies = {
27e5aaf047SAppaRao Puli     "TerminateAfterRetries", "SuspendRetries", "RetryForever"};
28e5aaf047SAppaRao Puli 
29e5aaf047SAppaRao Puli static constexpr const uint8_t maxNoOfSubscriptions = 20;
30e5aaf047SAppaRao Puli 
31e5aaf047SAppaRao Puli class EventService : public Node
32e5aaf047SAppaRao Puli {
33e5aaf047SAppaRao Puli   public:
34e5aaf047SAppaRao Puli     EventService(CrowApp& app) : Node(app, "/redfish/v1/EventService/")
35e5aaf047SAppaRao Puli     {
36e5aaf047SAppaRao Puli         entityPrivileges = {
37e5aaf047SAppaRao Puli             {boost::beast::http::verb::get, {{"Login"}}},
38e5aaf047SAppaRao Puli             {boost::beast::http::verb::head, {{"Login"}}},
39e5aaf047SAppaRao Puli             {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
40e5aaf047SAppaRao Puli             {boost::beast::http::verb::put, {{"ConfigureManager"}}},
41e5aaf047SAppaRao Puli             {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
42e5aaf047SAppaRao Puli             {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
43e5aaf047SAppaRao Puli     }
44e5aaf047SAppaRao Puli 
45e5aaf047SAppaRao Puli   private:
46e5aaf047SAppaRao Puli     void doGet(crow::Response& res, const crow::Request& req,
47e5aaf047SAppaRao Puli                const std::vector<std::string>& params) override
48e5aaf047SAppaRao Puli     {
49e5aaf047SAppaRao Puli         auto asyncResp = std::make_shared<AsyncResp>(res);
50e5aaf047SAppaRao Puli         res.jsonValue = {
51e5aaf047SAppaRao Puli             {"@odata.type", "#EventService.v1_5_0.EventService"},
52e5aaf047SAppaRao Puli             {"Id", "EventService"},
53e5aaf047SAppaRao Puli             {"Name", "Event Service"},
54e5aaf047SAppaRao Puli             {"ServerSentEventUri",
55e5aaf047SAppaRao Puli              "/redfish/v1/EventService/Subscriptions/SSE"},
56e5aaf047SAppaRao Puli             {"Subscriptions",
57e5aaf047SAppaRao Puli              {{"@odata.id", "/redfish/v1/EventService/Subscriptions"}}},
580b4bdd93SAppaRao Puli             {"Actions",
590b4bdd93SAppaRao Puli              {{"#EventService.SubmitTestEvent",
600b4bdd93SAppaRao Puli                {{"target", "/redfish/v1/EventService/Actions/"
610b4bdd93SAppaRao Puli                            "EventService.SubmitTestEvent"}}}}},
62e5aaf047SAppaRao Puli             {"@odata.id", "/redfish/v1/EventService"}};
63e5aaf047SAppaRao Puli 
647d1cc387SAppaRao Puli         const auto& [enabled, retryAttempts, retryTimeoutInterval] =
657d1cc387SAppaRao Puli             EventServiceManager::getInstance().getEventServiceConfig();
667d1cc387SAppaRao Puli 
677d1cc387SAppaRao Puli         asyncResp->res.jsonValue["Status"]["State"] =
687d1cc387SAppaRao Puli             (enabled ? "Enabled" : "Disabled");
697d1cc387SAppaRao Puli         asyncResp->res.jsonValue["ServiceEnabled"] = enabled;
707d1cc387SAppaRao Puli         asyncResp->res.jsonValue["DeliveryRetryAttempts"] = retryAttempts;
71e5aaf047SAppaRao Puli         asyncResp->res.jsonValue["DeliveryRetryIntervalSeconds"] =
727d1cc387SAppaRao Puli             retryTimeoutInterval;
73e5aaf047SAppaRao Puli         asyncResp->res.jsonValue["EventFormatTypes"] = supportedEvtFormatTypes;
74e5aaf047SAppaRao Puli         asyncResp->res.jsonValue["RegistryPrefixes"] = supportedRegPrefixes;
75e5aaf047SAppaRao Puli     }
76e5aaf047SAppaRao Puli 
77e5aaf047SAppaRao Puli     void doPatch(crow::Response& res, const crow::Request& req,
78e5aaf047SAppaRao Puli                  const std::vector<std::string>& params) override
79e5aaf047SAppaRao Puli     {
80e5aaf047SAppaRao Puli         auto asyncResp = std::make_shared<AsyncResp>(res);
81e5aaf047SAppaRao Puli 
82e5aaf047SAppaRao Puli         std::optional<bool> serviceEnabled;
83e5aaf047SAppaRao Puli         std::optional<uint32_t> retryAttemps;
84e5aaf047SAppaRao Puli         std::optional<uint32_t> retryInterval;
85e5aaf047SAppaRao Puli 
86e5aaf047SAppaRao Puli         if (!json_util::readJson(req, res, "ServiceEnabled", serviceEnabled,
87e5aaf047SAppaRao Puli                                  "DeliveryRetryAttempts", retryAttemps,
88e5aaf047SAppaRao Puli                                  "DeliveryRetryIntervalSeconds", retryInterval))
89e5aaf047SAppaRao Puli         {
90e5aaf047SAppaRao Puli             return;
91e5aaf047SAppaRao Puli         }
92e5aaf047SAppaRao Puli 
937d1cc387SAppaRao Puli         auto [enabled, retryCount, retryTimeoutInterval] =
947d1cc387SAppaRao Puli             EventServiceManager::getInstance().getEventServiceConfig();
957d1cc387SAppaRao Puli 
96e5aaf047SAppaRao Puli         if (serviceEnabled)
97e5aaf047SAppaRao Puli         {
987d1cc387SAppaRao Puli             enabled = *serviceEnabled;
99e5aaf047SAppaRao Puli         }
100e5aaf047SAppaRao Puli 
101e5aaf047SAppaRao Puli         if (retryAttemps)
102e5aaf047SAppaRao Puli         {
103e5aaf047SAppaRao Puli             // Supported range [1-3]
104e5aaf047SAppaRao Puli             if ((*retryAttemps < 1) || (*retryAttemps > 3))
105e5aaf047SAppaRao Puli             {
106e5aaf047SAppaRao Puli                 messages::queryParameterOutOfRange(
107e5aaf047SAppaRao Puli                     asyncResp->res, std::to_string(*retryAttemps),
108e5aaf047SAppaRao Puli                     "DeliveryRetryAttempts", "[1-3]");
109e5aaf047SAppaRao Puli             }
110e5aaf047SAppaRao Puli             else
111e5aaf047SAppaRao Puli             {
1127d1cc387SAppaRao Puli                 retryCount = *retryAttemps;
113e5aaf047SAppaRao Puli             }
114e5aaf047SAppaRao Puli         }
115e5aaf047SAppaRao Puli 
116e5aaf047SAppaRao Puli         if (retryInterval)
117e5aaf047SAppaRao Puli         {
118e5aaf047SAppaRao Puli             // Supported range [30 - 180]
119e5aaf047SAppaRao Puli             if ((*retryInterval < 30) || (*retryInterval > 180))
120e5aaf047SAppaRao Puli             {
121e5aaf047SAppaRao Puli                 messages::queryParameterOutOfRange(
122e5aaf047SAppaRao Puli                     asyncResp->res, std::to_string(*retryInterval),
123e5aaf047SAppaRao Puli                     "DeliveryRetryIntervalSeconds", "[30-180]");
124e5aaf047SAppaRao Puli             }
125e5aaf047SAppaRao Puli             else
126e5aaf047SAppaRao Puli             {
1277d1cc387SAppaRao Puli                 retryTimeoutInterval = *retryInterval;
128e5aaf047SAppaRao Puli             }
129e5aaf047SAppaRao Puli         }
130e5aaf047SAppaRao Puli 
1317d1cc387SAppaRao Puli         EventServiceManager::getInstance().setEventServiceConfig(
1327d1cc387SAppaRao Puli             std::make_tuple(enabled, retryCount, retryTimeoutInterval));
133e5aaf047SAppaRao Puli     }
134e5aaf047SAppaRao Puli };
135e5aaf047SAppaRao Puli 
1360b4bdd93SAppaRao Puli class SubmitTestEvent : public Node
1370b4bdd93SAppaRao Puli {
1380b4bdd93SAppaRao Puli   public:
1390b4bdd93SAppaRao Puli     SubmitTestEvent(CrowApp& app) :
1400b4bdd93SAppaRao Puli         Node(app,
1410b4bdd93SAppaRao Puli              "/redfish/v1/EventService/Actions/EventService.SubmitTestEvent/")
1420b4bdd93SAppaRao Puli     {
1430b4bdd93SAppaRao Puli         entityPrivileges = {
1440b4bdd93SAppaRao Puli             {boost::beast::http::verb::get, {{"Login"}}},
1450b4bdd93SAppaRao Puli             {boost::beast::http::verb::head, {{"Login"}}},
1460b4bdd93SAppaRao Puli             {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
1470b4bdd93SAppaRao Puli             {boost::beast::http::verb::put, {{"ConfigureManager"}}},
1480b4bdd93SAppaRao Puli             {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
1490b4bdd93SAppaRao Puli             {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
1500b4bdd93SAppaRao Puli     }
1510b4bdd93SAppaRao Puli 
1520b4bdd93SAppaRao Puli   private:
1530b4bdd93SAppaRao Puli     void doPost(crow::Response& res, const crow::Request& req,
1540b4bdd93SAppaRao Puli                 const std::vector<std::string>& params) override
1550b4bdd93SAppaRao Puli     {
1560b4bdd93SAppaRao Puli         EventServiceManager::getInstance().sendTestEventLog();
1570b4bdd93SAppaRao Puli         res.result(boost::beast::http::status::no_content);
1580b4bdd93SAppaRao Puli         res.end();
1590b4bdd93SAppaRao Puli     }
1600b4bdd93SAppaRao Puli };
1610b4bdd93SAppaRao Puli 
162e5aaf047SAppaRao Puli class EventDestinationCollection : public Node
163e5aaf047SAppaRao Puli {
164e5aaf047SAppaRao Puli   public:
165e5aaf047SAppaRao Puli     EventDestinationCollection(CrowApp& app) :
166e5aaf047SAppaRao Puli         Node(app, "/redfish/v1/EventService/Subscriptions/")
167e5aaf047SAppaRao Puli     {
168e5aaf047SAppaRao Puli         entityPrivileges = {
169e5aaf047SAppaRao Puli             {boost::beast::http::verb::get, {{"Login"}}},
170e5aaf047SAppaRao Puli             {boost::beast::http::verb::head, {{"Login"}}},
171e5aaf047SAppaRao Puli             {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
172e5aaf047SAppaRao Puli             {boost::beast::http::verb::put, {{"ConfigureManager"}}},
173e5aaf047SAppaRao Puli             {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
174e5aaf047SAppaRao Puli             {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
175e5aaf047SAppaRao Puli     }
176e5aaf047SAppaRao Puli 
177e5aaf047SAppaRao Puli   private:
178e5aaf047SAppaRao Puli     void doGet(crow::Response& res, const crow::Request& req,
179e5aaf047SAppaRao Puli                const std::vector<std::string>& params) override
180e5aaf047SAppaRao Puli     {
181e5aaf047SAppaRao Puli         auto asyncResp = std::make_shared<AsyncResp>(res);
182e5aaf047SAppaRao Puli 
183e5aaf047SAppaRao Puli         res.jsonValue = {
184e5aaf047SAppaRao Puli             {"@odata.type",
185e5aaf047SAppaRao Puli              "#EventDestinationCollection.EventDestinationCollection"},
186e5aaf047SAppaRao Puli             {"@odata.id", "/redfish/v1/EventService/Subscriptions"},
187e5aaf047SAppaRao Puli             {"Name", "Event Destination Collections"}};
188e5aaf047SAppaRao Puli 
189e5aaf047SAppaRao Puli         nlohmann::json& memberArray = asyncResp->res.jsonValue["Members"];
190e5aaf047SAppaRao Puli 
191b52664e2SAppaRao Puli         std::vector<std::string> subscripIds =
192b52664e2SAppaRao Puli             EventServiceManager::getInstance().getAllIDs();
193b52664e2SAppaRao Puli         memberArray = nlohmann::json::array();
194b52664e2SAppaRao Puli         asyncResp->res.jsonValue["Members@odata.count"] = subscripIds.size();
195b52664e2SAppaRao Puli 
196b52664e2SAppaRao Puli         for (const std::string& id : subscripIds)
197e5aaf047SAppaRao Puli         {
198e5aaf047SAppaRao Puli             memberArray.push_back(
199e5aaf047SAppaRao Puli                 {{"@odata.id",
200b52664e2SAppaRao Puli                   "/redfish/v1/EventService/Subscriptions/" + id}});
201e5aaf047SAppaRao Puli         }
202e5aaf047SAppaRao Puli     }
203e5aaf047SAppaRao Puli 
204e5aaf047SAppaRao Puli     void doPost(crow::Response& res, const crow::Request& req,
205e5aaf047SAppaRao Puli                 const std::vector<std::string>& params) override
206e5aaf047SAppaRao Puli     {
207e5aaf047SAppaRao Puli         auto asyncResp = std::make_shared<AsyncResp>(res);
208e5aaf047SAppaRao Puli 
209b52664e2SAppaRao Puli         if (EventServiceManager::getInstance().getNumberOfSubscriptions() >=
210b52664e2SAppaRao Puli             maxNoOfSubscriptions)
211e5aaf047SAppaRao Puli         {
212e5aaf047SAppaRao Puli             messages::eventSubscriptionLimitExceeded(asyncResp->res);
213e5aaf047SAppaRao Puli             return;
214e5aaf047SAppaRao Puli         }
215e5aaf047SAppaRao Puli         std::string destUrl;
216e5aaf047SAppaRao Puli         std::string protocol;
217e5aaf047SAppaRao Puli         std::optional<std::string> context;
218e5aaf047SAppaRao Puli         std::optional<std::string> subscriptionType;
219e5aaf047SAppaRao Puli         std::optional<std::string> eventFormatType;
220e5aaf047SAppaRao Puli         std::optional<std::string> retryPolicy;
221e5aaf047SAppaRao Puli         std::optional<std::vector<std::string>> msgIds;
222e5aaf047SAppaRao Puli         std::optional<std::vector<std::string>> regPrefixes;
223e5aaf047SAppaRao Puli         std::optional<std::vector<nlohmann::json>> headers;
224156d6b00SAppaRao Puli         std::optional<std::vector<nlohmann::json>> metricReportDefinitions;
225e5aaf047SAppaRao Puli 
226e5aaf047SAppaRao Puli         if (!json_util::readJson(
227e5aaf047SAppaRao Puli                 req, res, "Destination", destUrl, "Context", context,
228e5aaf047SAppaRao Puli                 "Protocol", protocol, "SubscriptionType", subscriptionType,
229e5aaf047SAppaRao Puli                 "EventFormatType", eventFormatType, "HttpHeaders", headers,
230e5aaf047SAppaRao Puli                 "RegistryPrefixes", regPrefixes, "MessageIds", msgIds,
231156d6b00SAppaRao Puli                 "DeliveryRetryPolicy", retryPolicy, "MetricReportDefinitions",
232156d6b00SAppaRao Puli                 metricReportDefinitions))
233e5aaf047SAppaRao Puli         {
234e5aaf047SAppaRao Puli             return;
235e5aaf047SAppaRao Puli         }
236e5aaf047SAppaRao Puli 
237e5aaf047SAppaRao Puli         // Validate the URL using regex expression
238b52664e2SAppaRao Puli         // Format: <protocol>://<host>:<port>/<uri>
239b52664e2SAppaRao Puli         // protocol: http/https
240b52664e2SAppaRao Puli         // host: Exclude ' ', ':', '#', '?'
241b52664e2SAppaRao Puli         // port: Empty or numeric value with ':' seperator.
242b52664e2SAppaRao Puli         // uri: Start with '/' and Exclude '#', ' '
243b52664e2SAppaRao Puli         //      Can include query params(ex: '/event?test=1')
244b52664e2SAppaRao Puli         // TODO: Need to validate hostname extensively(as per rfc)
245b52664e2SAppaRao Puli         const std::regex urlRegex(
246b52664e2SAppaRao Puli             "(http|https)://([^/\\x20\\x3f\\x23\\x3a]+):?([0-9]*)(/"
247b52664e2SAppaRao Puli             "([^\\x20\\x23\\x3f]*\\x3f?([^\\x20\\x23\\x3f])*)?)");
248b52664e2SAppaRao Puli         std::cmatch match;
249b52664e2SAppaRao Puli         if (!std::regex_match(destUrl.c_str(), match, urlRegex))
250e5aaf047SAppaRao Puli         {
251e5aaf047SAppaRao Puli             messages::propertyValueFormatError(asyncResp->res, destUrl,
252e5aaf047SAppaRao Puli                                                "Destination");
253e5aaf047SAppaRao Puli             return;
254e5aaf047SAppaRao Puli         }
255b52664e2SAppaRao Puli 
256b52664e2SAppaRao Puli         std::string uriProto = std::string(match[1].first, match[1].second);
257b52664e2SAppaRao Puli         if (uriProto == "http")
258b52664e2SAppaRao Puli         {
259b52664e2SAppaRao Puli #ifndef BMCWEB_INSECURE_ENABLE_HTTP_PUSH_STYLE_EVENTING
260b52664e2SAppaRao Puli             messages::propertyValueFormatError(asyncResp->res, destUrl,
261b52664e2SAppaRao Puli                                                "Destination");
262b52664e2SAppaRao Puli             return;
263b52664e2SAppaRao Puli #endif
264b52664e2SAppaRao Puli         }
265b52664e2SAppaRao Puli 
266b52664e2SAppaRao Puli         std::string host = std::string(match[2].first, match[2].second);
267b52664e2SAppaRao Puli         std::string port = std::string(match[3].first, match[3].second);
268b52664e2SAppaRao Puli         std::string path = std::string(match[4].first, match[4].second);
269b52664e2SAppaRao Puli         if (port.empty())
270b52664e2SAppaRao Puli         {
271b52664e2SAppaRao Puli             if (uriProto == "http")
272b52664e2SAppaRao Puli             {
273b52664e2SAppaRao Puli                 port = "80";
274b52664e2SAppaRao Puli             }
275b52664e2SAppaRao Puli             else
276b52664e2SAppaRao Puli             {
277b52664e2SAppaRao Puli                 port = "443";
278b52664e2SAppaRao Puli             }
279b52664e2SAppaRao Puli         }
280b52664e2SAppaRao Puli         if (path.empty())
281b52664e2SAppaRao Puli         {
282b52664e2SAppaRao Puli             path = "/";
283b52664e2SAppaRao Puli         }
284b52664e2SAppaRao Puli 
285b52664e2SAppaRao Puli         std::shared_ptr<Subscription> subValue =
286b52664e2SAppaRao Puli             std::make_shared<Subscription>(host, port, path, uriProto);
287b52664e2SAppaRao Puli 
288b52664e2SAppaRao Puli         subValue->destinationUrl = destUrl;
289e5aaf047SAppaRao Puli 
290e5aaf047SAppaRao Puli         if (subscriptionType)
291e5aaf047SAppaRao Puli         {
292e5aaf047SAppaRao Puli             if (*subscriptionType != "RedfishEvent")
293e5aaf047SAppaRao Puli             {
294e5aaf047SAppaRao Puli                 messages::propertyValueNotInList(
295e5aaf047SAppaRao Puli                     asyncResp->res, *subscriptionType, "SubscriptionType");
296e5aaf047SAppaRao Puli                 return;
297e5aaf047SAppaRao Puli             }
298b52664e2SAppaRao Puli             subValue->subscriptionType = *subscriptionType;
299e5aaf047SAppaRao Puli         }
300e5aaf047SAppaRao Puli         else
301e5aaf047SAppaRao Puli         {
302b52664e2SAppaRao Puli             subValue->subscriptionType = "RedfishEvent"; // Default
303e5aaf047SAppaRao Puli         }
304e5aaf047SAppaRao Puli 
305e5aaf047SAppaRao Puli         if (protocol != "Redfish")
306e5aaf047SAppaRao Puli         {
307e5aaf047SAppaRao Puli             messages::propertyValueNotInList(asyncResp->res, protocol,
308e5aaf047SAppaRao Puli                                              "Protocol");
309e5aaf047SAppaRao Puli             return;
310e5aaf047SAppaRao Puli         }
311b52664e2SAppaRao Puli         subValue->protocol = protocol;
312e5aaf047SAppaRao Puli 
313e5aaf047SAppaRao Puli         if (eventFormatType)
314e5aaf047SAppaRao Puli         {
315e5aaf047SAppaRao Puli             if (std::find(supportedEvtFormatTypes.begin(),
316e5aaf047SAppaRao Puli                           supportedEvtFormatTypes.end(),
317e5aaf047SAppaRao Puli                           *eventFormatType) == supportedEvtFormatTypes.end())
318e5aaf047SAppaRao Puli             {
319e5aaf047SAppaRao Puli                 messages::propertyValueNotInList(
320e5aaf047SAppaRao Puli                     asyncResp->res, *eventFormatType, "EventFormatType");
321e5aaf047SAppaRao Puli                 return;
322e5aaf047SAppaRao Puli             }
323b52664e2SAppaRao Puli             subValue->eventFormatType = *eventFormatType;
324e5aaf047SAppaRao Puli         }
325e5aaf047SAppaRao Puli         else
326e5aaf047SAppaRao Puli         {
327e5aaf047SAppaRao Puli             // If not specified, use default "Event"
328b52664e2SAppaRao Puli             subValue->eventFormatType.assign({"Event"});
329e5aaf047SAppaRao Puli         }
330e5aaf047SAppaRao Puli 
331e5aaf047SAppaRao Puli         if (context)
332e5aaf047SAppaRao Puli         {
333b52664e2SAppaRao Puli             subValue->customText = *context;
334e5aaf047SAppaRao Puli         }
335e5aaf047SAppaRao Puli 
336e5aaf047SAppaRao Puli         if (headers)
337e5aaf047SAppaRao Puli         {
338b52664e2SAppaRao Puli             subValue->httpHeaders = *headers;
339e5aaf047SAppaRao Puli         }
340e5aaf047SAppaRao Puli 
341e5aaf047SAppaRao Puli         if (regPrefixes)
342e5aaf047SAppaRao Puli         {
343e5aaf047SAppaRao Puli             for (const std::string& it : *regPrefixes)
344e5aaf047SAppaRao Puli             {
345e5aaf047SAppaRao Puli                 if (std::find(supportedRegPrefixes.begin(),
346e5aaf047SAppaRao Puli                               supportedRegPrefixes.end(),
347e5aaf047SAppaRao Puli                               it) == supportedRegPrefixes.end())
348e5aaf047SAppaRao Puli                 {
349e5aaf047SAppaRao Puli                     messages::propertyValueNotInList(asyncResp->res, it,
350e5aaf047SAppaRao Puli                                                      "RegistryPrefixes");
351e5aaf047SAppaRao Puli                     return;
352e5aaf047SAppaRao Puli                 }
353e5aaf047SAppaRao Puli             }
354b52664e2SAppaRao Puli             subValue->registryPrefixes = *regPrefixes;
355e5aaf047SAppaRao Puli         }
356e5aaf047SAppaRao Puli 
357e5aaf047SAppaRao Puli         if (msgIds)
358e5aaf047SAppaRao Puli         {
359e5aaf047SAppaRao Puli             // Do we need to loop-up MessageRegistry and validate
360e5aaf047SAppaRao Puli             // data for authenticity??? Not mandate, i believe.
361b52664e2SAppaRao Puli             subValue->registryMsgIds = *msgIds;
362e5aaf047SAppaRao Puli         }
363e5aaf047SAppaRao Puli 
364e5aaf047SAppaRao Puli         if (retryPolicy)
365e5aaf047SAppaRao Puli         {
366e5aaf047SAppaRao Puli             if (std::find(supportedRetryPolicies.begin(),
367e5aaf047SAppaRao Puli                           supportedRetryPolicies.end(),
368e5aaf047SAppaRao Puli                           *retryPolicy) == supportedRetryPolicies.end())
369e5aaf047SAppaRao Puli             {
370e5aaf047SAppaRao Puli                 messages::propertyValueNotInList(asyncResp->res, *retryPolicy,
371e5aaf047SAppaRao Puli                                                  "DeliveryRetryPolicy");
372e5aaf047SAppaRao Puli                 return;
373e5aaf047SAppaRao Puli             }
374b52664e2SAppaRao Puli             subValue->retryPolicy = *retryPolicy;
375e5aaf047SAppaRao Puli         }
376e5aaf047SAppaRao Puli         else
377e5aaf047SAppaRao Puli         {
378e5aaf047SAppaRao Puli             // Default "TerminateAfterRetries"
379b52664e2SAppaRao Puli             subValue->retryPolicy = "TerminateAfterRetries";
380e5aaf047SAppaRao Puli         }
381e5aaf047SAppaRao Puli 
382156d6b00SAppaRao Puli         if (metricReportDefinitions)
383156d6b00SAppaRao Puli         {
384156d6b00SAppaRao Puli             subValue->metricReportDefinitions = *metricReportDefinitions;
385156d6b00SAppaRao Puli         }
386156d6b00SAppaRao Puli 
387b52664e2SAppaRao Puli         std::string id =
388b52664e2SAppaRao Puli             EventServiceManager::getInstance().addSubscription(subValue);
389b52664e2SAppaRao Puli         if (id.empty())
390e5aaf047SAppaRao Puli         {
391e5aaf047SAppaRao Puli             messages::internalError(asyncResp->res);
392e5aaf047SAppaRao Puli             return;
393e5aaf047SAppaRao Puli         }
394e5aaf047SAppaRao Puli 
395e5aaf047SAppaRao Puli         messages::created(asyncResp->res);
396e5aaf047SAppaRao Puli         asyncResp->res.addHeader(
397e5aaf047SAppaRao Puli             "Location", "/redfish/v1/EventService/Subscriptions/" + id);
398e5aaf047SAppaRao Puli     }
399e5aaf047SAppaRao Puli };
400e5aaf047SAppaRao Puli 
401*4bbf237fSAppaRao Puli class EventServiceSSE : public Node
402*4bbf237fSAppaRao Puli {
403*4bbf237fSAppaRao Puli   public:
404*4bbf237fSAppaRao Puli     EventServiceSSE(CrowApp& app) :
405*4bbf237fSAppaRao Puli         Node(app, "/redfish/v1/EventService/Subscriptions/SSE/")
406*4bbf237fSAppaRao Puli     {
407*4bbf237fSAppaRao Puli         entityPrivileges = {
408*4bbf237fSAppaRao Puli             {boost::beast::http::verb::get, {{"ConfigureManager"}}},
409*4bbf237fSAppaRao Puli             {boost::beast::http::verb::head, {{"ConfigureManager"}}},
410*4bbf237fSAppaRao Puli             {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
411*4bbf237fSAppaRao Puli             {boost::beast::http::verb::put, {{"ConfigureManager"}}},
412*4bbf237fSAppaRao Puli             {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
413*4bbf237fSAppaRao Puli             {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
414*4bbf237fSAppaRao Puli     }
415*4bbf237fSAppaRao Puli 
416*4bbf237fSAppaRao Puli   private:
417*4bbf237fSAppaRao Puli     void doGet(crow::Response& res, const crow::Request& req,
418*4bbf237fSAppaRao Puli                const std::vector<std::string>& params) override
419*4bbf237fSAppaRao Puli     {
420*4bbf237fSAppaRao Puli         if (EventServiceManager::getInstance().getNumberOfSubscriptions() >=
421*4bbf237fSAppaRao Puli             maxNoOfSubscriptions)
422*4bbf237fSAppaRao Puli         {
423*4bbf237fSAppaRao Puli             messages::eventSubscriptionLimitExceeded(res);
424*4bbf237fSAppaRao Puli             res.end();
425*4bbf237fSAppaRao Puli             return;
426*4bbf237fSAppaRao Puli         }
427*4bbf237fSAppaRao Puli 
428*4bbf237fSAppaRao Puli         std::shared_ptr<crow::Request::Adaptor> sseConn =
429*4bbf237fSAppaRao Puli             std::make_shared<crow::Request::Adaptor>(std::move(req.socket()));
430*4bbf237fSAppaRao Puli         std::shared_ptr<Subscription> subValue =
431*4bbf237fSAppaRao Puli             std::make_shared<Subscription>(sseConn);
432*4bbf237fSAppaRao Puli 
433*4bbf237fSAppaRao Puli         // GET on this URI means, Its SSE subscriptionType.
434*4bbf237fSAppaRao Puli         subValue->subscriptionType = "SSE";
435*4bbf237fSAppaRao Puli         subValue->protocol = "Redfish";
436*4bbf237fSAppaRao Puli 
437*4bbf237fSAppaRao Puli         char* filters = req.urlParams.get("$filter");
438*4bbf237fSAppaRao Puli         if (filters == nullptr)
439*4bbf237fSAppaRao Puli         {
440*4bbf237fSAppaRao Puli             subValue->eventFormatType = "Event";
441*4bbf237fSAppaRao Puli             subValue->retryPolicy = "TerminateAfterRetries";
442*4bbf237fSAppaRao Puli         }
443*4bbf237fSAppaRao Puli         else
444*4bbf237fSAppaRao Puli         {
445*4bbf237fSAppaRao Puli             // TODO: Need to read this from query params.
446*4bbf237fSAppaRao Puli             subValue->eventFormatType = "Event";
447*4bbf237fSAppaRao Puli             subValue->retryPolicy = "TerminateAfterRetries";
448*4bbf237fSAppaRao Puli         }
449*4bbf237fSAppaRao Puli 
450*4bbf237fSAppaRao Puli         std::string id =
451*4bbf237fSAppaRao Puli             EventServiceManager::getInstance().addSubscription(subValue, false);
452*4bbf237fSAppaRao Puli         if (id.empty())
453*4bbf237fSAppaRao Puli         {
454*4bbf237fSAppaRao Puli             messages::internalError(res);
455*4bbf237fSAppaRao Puli             res.end();
456*4bbf237fSAppaRao Puli             return;
457*4bbf237fSAppaRao Puli         }
458*4bbf237fSAppaRao Puli     }
459*4bbf237fSAppaRao Puli };
460*4bbf237fSAppaRao Puli 
461e5aaf047SAppaRao Puli class EventDestination : public Node
462e5aaf047SAppaRao Puli {
463e5aaf047SAppaRao Puli   public:
464e5aaf047SAppaRao Puli     EventDestination(CrowApp& app) :
465e5aaf047SAppaRao Puli         Node(app, "/redfish/v1/EventService/Subscriptions/<str>/",
466e5aaf047SAppaRao Puli              std::string())
467e5aaf047SAppaRao Puli     {
468e5aaf047SAppaRao Puli         entityPrivileges = {
469e5aaf047SAppaRao Puli             {boost::beast::http::verb::get, {{"Login"}}},
470e5aaf047SAppaRao Puli             {boost::beast::http::verb::head, {{"Login"}}},
471e5aaf047SAppaRao Puli             {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
472e5aaf047SAppaRao Puli             {boost::beast::http::verb::put, {{"ConfigureManager"}}},
473e5aaf047SAppaRao Puli             {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
474e5aaf047SAppaRao Puli             {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
475e5aaf047SAppaRao Puli     }
476e5aaf047SAppaRao Puli 
477e5aaf047SAppaRao Puli   private:
478e5aaf047SAppaRao Puli     void doGet(crow::Response& res, const crow::Request& req,
479e5aaf047SAppaRao Puli                const std::vector<std::string>& params) override
480e5aaf047SAppaRao Puli     {
481e5aaf047SAppaRao Puli         auto asyncResp = std::make_shared<AsyncResp>(res);
482e5aaf047SAppaRao Puli         if (params.size() != 1)
483e5aaf047SAppaRao Puli         {
484e5aaf047SAppaRao Puli             messages::internalError(asyncResp->res);
485e5aaf047SAppaRao Puli             return;
486e5aaf047SAppaRao Puli         }
487e5aaf047SAppaRao Puli 
488b52664e2SAppaRao Puli         std::shared_ptr<Subscription> subValue =
489b52664e2SAppaRao Puli             EventServiceManager::getInstance().getSubscription(params[0]);
490b52664e2SAppaRao Puli         if (subValue == nullptr)
491e5aaf047SAppaRao Puli         {
492e5aaf047SAppaRao Puli             res.result(boost::beast::http::status::not_found);
493e5aaf047SAppaRao Puli             res.end();
494e5aaf047SAppaRao Puli             return;
495e5aaf047SAppaRao Puli         }
496b52664e2SAppaRao Puli         const std::string& id = params[0];
497e5aaf047SAppaRao Puli 
498e5aaf047SAppaRao Puli         res.jsonValue = {
499e5aaf047SAppaRao Puli             {"@odata.type", "#EventDestination.v1_7_0.EventDestination"},
500e5aaf047SAppaRao Puli             {"Protocol", "Redfish"}};
501e5aaf047SAppaRao Puli         asyncResp->res.jsonValue["@odata.id"] =
502e5aaf047SAppaRao Puli             "/redfish/v1/EventService/Subscriptions/" + id;
503e5aaf047SAppaRao Puli         asyncResp->res.jsonValue["Id"] = id;
504e5aaf047SAppaRao Puli         asyncResp->res.jsonValue["Name"] = "Event Destination " + id;
505b52664e2SAppaRao Puli         asyncResp->res.jsonValue["Destination"] = subValue->destinationUrl;
506b52664e2SAppaRao Puli         asyncResp->res.jsonValue["Context"] = subValue->customText;
507e5aaf047SAppaRao Puli         asyncResp->res.jsonValue["SubscriptionType"] =
508b52664e2SAppaRao Puli             subValue->subscriptionType;
509b52664e2SAppaRao Puli         asyncResp->res.jsonValue["HttpHeaders"] = subValue->httpHeaders;
510b52664e2SAppaRao Puli         asyncResp->res.jsonValue["EventFormatType"] = subValue->eventFormatType;
511e5aaf047SAppaRao Puli         asyncResp->res.jsonValue["RegistryPrefixes"] =
512b52664e2SAppaRao Puli             subValue->registryPrefixes;
513b52664e2SAppaRao Puli         asyncResp->res.jsonValue["MessageIds"] = subValue->registryMsgIds;
514b52664e2SAppaRao Puli         asyncResp->res.jsonValue["DeliveryRetryPolicy"] = subValue->retryPolicy;
515156d6b00SAppaRao Puli         asyncResp->res.jsonValue["MetricReportDefinitions"] =
516156d6b00SAppaRao Puli             subValue->metricReportDefinitions;
517e5aaf047SAppaRao Puli     }
518e5aaf047SAppaRao Puli 
519e5aaf047SAppaRao Puli     void doPatch(crow::Response& res, const crow::Request& req,
520e5aaf047SAppaRao Puli                  const std::vector<std::string>& params) override
521e5aaf047SAppaRao Puli     {
522e5aaf047SAppaRao Puli         auto asyncResp = std::make_shared<AsyncResp>(res);
523e5aaf047SAppaRao Puli         if (params.size() != 1)
524e5aaf047SAppaRao Puli         {
525e5aaf047SAppaRao Puli             messages::internalError(asyncResp->res);
526e5aaf047SAppaRao Puli             return;
527e5aaf047SAppaRao Puli         }
528e5aaf047SAppaRao Puli 
529b52664e2SAppaRao Puli         std::shared_ptr<Subscription> subValue =
530b52664e2SAppaRao Puli             EventServiceManager::getInstance().getSubscription(params[0]);
531b52664e2SAppaRao Puli         if (subValue == nullptr)
532e5aaf047SAppaRao Puli         {
533e5aaf047SAppaRao Puli             res.result(boost::beast::http::status::not_found);
534e5aaf047SAppaRao Puli             res.end();
535e5aaf047SAppaRao Puli             return;
536e5aaf047SAppaRao Puli         }
537e5aaf047SAppaRao Puli 
538e5aaf047SAppaRao Puli         std::optional<std::string> context;
539e5aaf047SAppaRao Puli         std::optional<std::string> retryPolicy;
540e5aaf047SAppaRao Puli         std::optional<std::vector<nlohmann::json>> headers;
541e5aaf047SAppaRao Puli 
542e5aaf047SAppaRao Puli         if (!json_util::readJson(req, res, "Context", context,
543e5aaf047SAppaRao Puli                                  "DeliveryRetryPolicy", retryPolicy,
544e5aaf047SAppaRao Puli                                  "HttpHeaders", headers))
545e5aaf047SAppaRao Puli         {
546e5aaf047SAppaRao Puli             return;
547e5aaf047SAppaRao Puli         }
548e5aaf047SAppaRao Puli 
549e5aaf047SAppaRao Puli         if (context)
550e5aaf047SAppaRao Puli         {
551b52664e2SAppaRao Puli             subValue->customText = *context;
552e5aaf047SAppaRao Puli         }
553e5aaf047SAppaRao Puli 
554e5aaf047SAppaRao Puli         if (headers)
555e5aaf047SAppaRao Puli         {
556b52664e2SAppaRao Puli             subValue->httpHeaders = *headers;
557e5aaf047SAppaRao Puli         }
558e5aaf047SAppaRao Puli 
559e5aaf047SAppaRao Puli         if (retryPolicy)
560e5aaf047SAppaRao Puli         {
561e5aaf047SAppaRao Puli             if (std::find(supportedRetryPolicies.begin(),
562e5aaf047SAppaRao Puli                           supportedRetryPolicies.end(),
563e5aaf047SAppaRao Puli                           *retryPolicy) == supportedRetryPolicies.end())
564e5aaf047SAppaRao Puli             {
565e5aaf047SAppaRao Puli                 messages::propertyValueNotInList(asyncResp->res, *retryPolicy,
566e5aaf047SAppaRao Puli                                                  "DeliveryRetryPolicy");
567e5aaf047SAppaRao Puli                 return;
568e5aaf047SAppaRao Puli             }
569b52664e2SAppaRao Puli             subValue->retryPolicy = *retryPolicy;
570fe44eb0bSAyushi Smriti             subValue->updateRetryPolicy();
571e5aaf047SAppaRao Puli         }
572e5aaf047SAppaRao Puli 
573b52664e2SAppaRao Puli         EventServiceManager::getInstance().updateSubscriptionData();
574e5aaf047SAppaRao Puli     }
575e5aaf047SAppaRao Puli 
576e5aaf047SAppaRao Puli     void doDelete(crow::Response& res, const crow::Request& req,
577e5aaf047SAppaRao Puli                   const std::vector<std::string>& params) override
578e5aaf047SAppaRao Puli     {
579e5aaf047SAppaRao Puli         auto asyncResp = std::make_shared<AsyncResp>(res);
580e5aaf047SAppaRao Puli 
581e5aaf047SAppaRao Puli         if (params.size() != 1)
582e5aaf047SAppaRao Puli         {
583e5aaf047SAppaRao Puli             messages::internalError(asyncResp->res);
584e5aaf047SAppaRao Puli             return;
585e5aaf047SAppaRao Puli         }
586e5aaf047SAppaRao Puli 
587b52664e2SAppaRao Puli         if (!EventServiceManager::getInstance().isSubscriptionExist(params[0]))
588e5aaf047SAppaRao Puli         {
589e5aaf047SAppaRao Puli             res.result(boost::beast::http::status::not_found);
590e5aaf047SAppaRao Puli             res.end();
591e5aaf047SAppaRao Puli             return;
592e5aaf047SAppaRao Puli         }
593b52664e2SAppaRao Puli         EventServiceManager::getInstance().deleteSubscription(params[0]);
594e5aaf047SAppaRao Puli     }
595e5aaf047SAppaRao Puli };
596e5aaf047SAppaRao Puli 
597e5aaf047SAppaRao Puli } // namespace redfish
598