xref: /openbmc/bmcweb/features/redfish/lib/event_service.hpp (revision e5aaf047b6b41b0837ef0846cf5356c9a6bcb030)
1*e5aaf047SAppaRao Puli /*
2*e5aaf047SAppaRao Puli // Copyright (c) 2020 Intel Corporation
3*e5aaf047SAppaRao Puli //
4*e5aaf047SAppaRao Puli // Licensed under the Apache License, Version 2.0 (the "License");
5*e5aaf047SAppaRao Puli // you may not use this file except in compliance with the License.
6*e5aaf047SAppaRao Puli // You may obtain a copy of the License at
7*e5aaf047SAppaRao Puli //
8*e5aaf047SAppaRao Puli //      http://www.apache.org/licenses/LICENSE-2.0
9*e5aaf047SAppaRao Puli //
10*e5aaf047SAppaRao Puli // Unless required by applicable law or agreed to in writing, software
11*e5aaf047SAppaRao Puli // distributed under the License is distributed on an "AS IS" BASIS,
12*e5aaf047SAppaRao Puli // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*e5aaf047SAppaRao Puli // See the License for the specific language governing permissions and
14*e5aaf047SAppaRao Puli // limitations under the License.
15*e5aaf047SAppaRao Puli */
16*e5aaf047SAppaRao Puli #pragma once
17*e5aaf047SAppaRao Puli #include "node.hpp"
18*e5aaf047SAppaRao Puli 
19*e5aaf047SAppaRao Puli #include <boost/container/flat_map.hpp>
20*e5aaf047SAppaRao Puli #include <error_messages.hpp>
21*e5aaf047SAppaRao Puli #include <utils/json_utils.hpp>
22*e5aaf047SAppaRao Puli #include <variant>
23*e5aaf047SAppaRao Puli 
24*e5aaf047SAppaRao Puli namespace redfish
25*e5aaf047SAppaRao Puli {
26*e5aaf047SAppaRao Puli 
27*e5aaf047SAppaRao Puli static constexpr const std::array<const char*, 1> supportedEvtFormatTypes = {
28*e5aaf047SAppaRao Puli     "Event"};
29*e5aaf047SAppaRao Puli static constexpr const std::array<const char*, 3> supportedRegPrefixes = {
30*e5aaf047SAppaRao Puli     "Base", "OpenBMC", "Task"};
31*e5aaf047SAppaRao Puli static constexpr const std::array<const char*, 3> supportedRetryPolicies = {
32*e5aaf047SAppaRao Puli     "TerminateAfterRetries", "SuspendRetries", "RetryForever"};
33*e5aaf047SAppaRao Puli 
34*e5aaf047SAppaRao Puli static constexpr const uint8_t maxNoOfSubscriptions = 20;
35*e5aaf047SAppaRao Puli 
36*e5aaf047SAppaRao Puli struct EventSrvConfig
37*e5aaf047SAppaRao Puli {
38*e5aaf047SAppaRao Puli     bool enabled;
39*e5aaf047SAppaRao Puli     uint32_t retryAttempts;
40*e5aaf047SAppaRao Puli     uint32_t retryTimeoutInterval;
41*e5aaf047SAppaRao Puli };
42*e5aaf047SAppaRao Puli 
43*e5aaf047SAppaRao Puli struct EventSrvSubscription
44*e5aaf047SAppaRao Puli {
45*e5aaf047SAppaRao Puli     std::string destinationUrl;
46*e5aaf047SAppaRao Puli     std::string protocol;
47*e5aaf047SAppaRao Puli     std::string retryPolicy;
48*e5aaf047SAppaRao Puli     std::string customText;
49*e5aaf047SAppaRao Puli     std::string eventFormatType;
50*e5aaf047SAppaRao Puli     std::string subscriptionType;
51*e5aaf047SAppaRao Puli     std::vector<std::string> registryMsgIds;
52*e5aaf047SAppaRao Puli     std::vector<std::string> registryPrefixes;
53*e5aaf047SAppaRao Puli     std::vector<nlohmann::json> httpHeaders; // key-value pair
54*e5aaf047SAppaRao Puli };
55*e5aaf047SAppaRao Puli 
56*e5aaf047SAppaRao Puli EventSrvConfig configData;
57*e5aaf047SAppaRao Puli boost::container::flat_map<std::string, EventSrvSubscription> subscriptionsMap;
58*e5aaf047SAppaRao Puli 
59*e5aaf047SAppaRao Puli inline void initEventSrvStore()
60*e5aaf047SAppaRao Puli {
61*e5aaf047SAppaRao Puli     // TODO: Read the persistent data from store and populate.
62*e5aaf047SAppaRao Puli     // Populating with default.
63*e5aaf047SAppaRao Puli     configData.enabled = true;
64*e5aaf047SAppaRao Puli     configData.retryAttempts = 3;
65*e5aaf047SAppaRao Puli     configData.retryTimeoutInterval = 30; // seconds
66*e5aaf047SAppaRao Puli }
67*e5aaf047SAppaRao Puli 
68*e5aaf047SAppaRao Puli inline void updateSubscriptionData()
69*e5aaf047SAppaRao Puli {
70*e5aaf047SAppaRao Puli     // Persist the config and subscription data.
71*e5aaf047SAppaRao Puli     // TODO: subscriptionsMap & configData need to be
72*e5aaf047SAppaRao Puli     // written to Persist store.
73*e5aaf047SAppaRao Puli     return;
74*e5aaf047SAppaRao Puli }
75*e5aaf047SAppaRao Puli class EventService : public Node
76*e5aaf047SAppaRao Puli {
77*e5aaf047SAppaRao Puli   public:
78*e5aaf047SAppaRao Puli     EventService(CrowApp& app) : Node(app, "/redfish/v1/EventService/")
79*e5aaf047SAppaRao Puli     {
80*e5aaf047SAppaRao Puli         initEventSrvStore();
81*e5aaf047SAppaRao Puli 
82*e5aaf047SAppaRao Puli         entityPrivileges = {
83*e5aaf047SAppaRao Puli             {boost::beast::http::verb::get, {{"Login"}}},
84*e5aaf047SAppaRao Puli             {boost::beast::http::verb::head, {{"Login"}}},
85*e5aaf047SAppaRao Puli             {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
86*e5aaf047SAppaRao Puli             {boost::beast::http::verb::put, {{"ConfigureManager"}}},
87*e5aaf047SAppaRao Puli             {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
88*e5aaf047SAppaRao Puli             {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
89*e5aaf047SAppaRao Puli     }
90*e5aaf047SAppaRao Puli 
91*e5aaf047SAppaRao Puli   private:
92*e5aaf047SAppaRao Puli     void doGet(crow::Response& res, const crow::Request& req,
93*e5aaf047SAppaRao Puli                const std::vector<std::string>& params) override
94*e5aaf047SAppaRao Puli     {
95*e5aaf047SAppaRao Puli         auto asyncResp = std::make_shared<AsyncResp>(res);
96*e5aaf047SAppaRao Puli         res.jsonValue = {
97*e5aaf047SAppaRao Puli             {"@odata.type", "#EventService.v1_5_0.EventService"},
98*e5aaf047SAppaRao Puli             {"Id", "EventService"},
99*e5aaf047SAppaRao Puli             {"Name", "Event Service"},
100*e5aaf047SAppaRao Puli             {"ServerSentEventUri",
101*e5aaf047SAppaRao Puli              "/redfish/v1/EventService/Subscriptions/SSE"},
102*e5aaf047SAppaRao Puli             {"Subscriptions",
103*e5aaf047SAppaRao Puli              {{"@odata.id", "/redfish/v1/EventService/Subscriptions"}}},
104*e5aaf047SAppaRao Puli             {"@odata.id", "/redfish/v1/EventService"}};
105*e5aaf047SAppaRao Puli 
106*e5aaf047SAppaRao Puli         asyncResp->res.jsonValue["Status"]["State"] = "Enabled";
107*e5aaf047SAppaRao Puli         asyncResp->res.jsonValue["ServiceEnabled"] = configData.enabled;
108*e5aaf047SAppaRao Puli         asyncResp->res.jsonValue["DeliveryRetryAttempts"] =
109*e5aaf047SAppaRao Puli             configData.retryAttempts;
110*e5aaf047SAppaRao Puli         asyncResp->res.jsonValue["DeliveryRetryIntervalSeconds"] =
111*e5aaf047SAppaRao Puli             configData.retryTimeoutInterval;
112*e5aaf047SAppaRao Puli         asyncResp->res.jsonValue["EventFormatTypes"] = supportedEvtFormatTypes;
113*e5aaf047SAppaRao Puli         asyncResp->res.jsonValue["RegistryPrefixes"] = supportedRegPrefixes;
114*e5aaf047SAppaRao Puli     }
115*e5aaf047SAppaRao Puli 
116*e5aaf047SAppaRao Puli     void doPatch(crow::Response& res, const crow::Request& req,
117*e5aaf047SAppaRao Puli                  const std::vector<std::string>& params) override
118*e5aaf047SAppaRao Puli     {
119*e5aaf047SAppaRao Puli         auto asyncResp = std::make_shared<AsyncResp>(res);
120*e5aaf047SAppaRao Puli 
121*e5aaf047SAppaRao Puli         std::optional<bool> serviceEnabled;
122*e5aaf047SAppaRao Puli         std::optional<uint32_t> retryAttemps;
123*e5aaf047SAppaRao Puli         std::optional<uint32_t> retryInterval;
124*e5aaf047SAppaRao Puli 
125*e5aaf047SAppaRao Puli         if (!json_util::readJson(req, res, "ServiceEnabled", serviceEnabled,
126*e5aaf047SAppaRao Puli                                  "DeliveryRetryAttempts", retryAttemps,
127*e5aaf047SAppaRao Puli                                  "DeliveryRetryIntervalSeconds", retryInterval))
128*e5aaf047SAppaRao Puli         {
129*e5aaf047SAppaRao Puli             return;
130*e5aaf047SAppaRao Puli         }
131*e5aaf047SAppaRao Puli 
132*e5aaf047SAppaRao Puli         if (serviceEnabled)
133*e5aaf047SAppaRao Puli         {
134*e5aaf047SAppaRao Puli             configData.enabled = *serviceEnabled;
135*e5aaf047SAppaRao Puli         }
136*e5aaf047SAppaRao Puli 
137*e5aaf047SAppaRao Puli         if (retryAttemps)
138*e5aaf047SAppaRao Puli         {
139*e5aaf047SAppaRao Puli             // Supported range [1-3]
140*e5aaf047SAppaRao Puli             if ((*retryAttemps < 1) || (*retryAttemps > 3))
141*e5aaf047SAppaRao Puli             {
142*e5aaf047SAppaRao Puli                 messages::queryParameterOutOfRange(
143*e5aaf047SAppaRao Puli                     asyncResp->res, std::to_string(*retryAttemps),
144*e5aaf047SAppaRao Puli                     "DeliveryRetryAttempts", "[1-3]");
145*e5aaf047SAppaRao Puli             }
146*e5aaf047SAppaRao Puli             else
147*e5aaf047SAppaRao Puli             {
148*e5aaf047SAppaRao Puli                 configData.retryAttempts = *retryAttemps;
149*e5aaf047SAppaRao Puli             }
150*e5aaf047SAppaRao Puli         }
151*e5aaf047SAppaRao Puli 
152*e5aaf047SAppaRao Puli         if (retryInterval)
153*e5aaf047SAppaRao Puli         {
154*e5aaf047SAppaRao Puli             // Supported range [30 - 180]
155*e5aaf047SAppaRao Puli             if ((*retryInterval < 30) || (*retryInterval > 180))
156*e5aaf047SAppaRao Puli             {
157*e5aaf047SAppaRao Puli                 messages::queryParameterOutOfRange(
158*e5aaf047SAppaRao Puli                     asyncResp->res, std::to_string(*retryInterval),
159*e5aaf047SAppaRao Puli                     "DeliveryRetryIntervalSeconds", "[30-180]");
160*e5aaf047SAppaRao Puli             }
161*e5aaf047SAppaRao Puli             else
162*e5aaf047SAppaRao Puli             {
163*e5aaf047SAppaRao Puli                 configData.retryTimeoutInterval = *retryInterval;
164*e5aaf047SAppaRao Puli             }
165*e5aaf047SAppaRao Puli         }
166*e5aaf047SAppaRao Puli 
167*e5aaf047SAppaRao Puli         updateSubscriptionData();
168*e5aaf047SAppaRao Puli     }
169*e5aaf047SAppaRao Puli };
170*e5aaf047SAppaRao Puli 
171*e5aaf047SAppaRao Puli class EventDestinationCollection : public Node
172*e5aaf047SAppaRao Puli {
173*e5aaf047SAppaRao Puli   public:
174*e5aaf047SAppaRao Puli     EventDestinationCollection(CrowApp& app) :
175*e5aaf047SAppaRao Puli         Node(app, "/redfish/v1/EventService/Subscriptions/")
176*e5aaf047SAppaRao Puli     {
177*e5aaf047SAppaRao Puli         entityPrivileges = {
178*e5aaf047SAppaRao Puli             {boost::beast::http::verb::get, {{"Login"}}},
179*e5aaf047SAppaRao Puli             {boost::beast::http::verb::head, {{"Login"}}},
180*e5aaf047SAppaRao Puli             {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
181*e5aaf047SAppaRao Puli             {boost::beast::http::verb::put, {{"ConfigureManager"}}},
182*e5aaf047SAppaRao Puli             {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
183*e5aaf047SAppaRao Puli             {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
184*e5aaf047SAppaRao Puli     }
185*e5aaf047SAppaRao Puli 
186*e5aaf047SAppaRao Puli   private:
187*e5aaf047SAppaRao Puli     void doGet(crow::Response& res, const crow::Request& req,
188*e5aaf047SAppaRao Puli                const std::vector<std::string>& params) override
189*e5aaf047SAppaRao Puli     {
190*e5aaf047SAppaRao Puli         auto asyncResp = std::make_shared<AsyncResp>(res);
191*e5aaf047SAppaRao Puli 
192*e5aaf047SAppaRao Puli         res.jsonValue = {
193*e5aaf047SAppaRao Puli             {"@odata.type",
194*e5aaf047SAppaRao Puli              "#EventDestinationCollection.EventDestinationCollection"},
195*e5aaf047SAppaRao Puli             {"@odata.id", "/redfish/v1/EventService/Subscriptions"},
196*e5aaf047SAppaRao Puli             {"Name", "Event Destination Collections"}};
197*e5aaf047SAppaRao Puli 
198*e5aaf047SAppaRao Puli         nlohmann::json& memberArray = asyncResp->res.jsonValue["Members"];
199*e5aaf047SAppaRao Puli         memberArray = nlohmann::json::array();
200*e5aaf047SAppaRao Puli         asyncResp->res.jsonValue["Members@odata.count"] =
201*e5aaf047SAppaRao Puli             subscriptionsMap.size();
202*e5aaf047SAppaRao Puli 
203*e5aaf047SAppaRao Puli         for (auto& it : subscriptionsMap)
204*e5aaf047SAppaRao Puli         {
205*e5aaf047SAppaRao Puli             memberArray.push_back(
206*e5aaf047SAppaRao Puli                 {{"@odata.id",
207*e5aaf047SAppaRao Puli                   "/redfish/v1/EventService/Subscriptions/" + it.first}});
208*e5aaf047SAppaRao Puli         }
209*e5aaf047SAppaRao Puli     }
210*e5aaf047SAppaRao Puli 
211*e5aaf047SAppaRao Puli     void doPost(crow::Response& res, const crow::Request& req,
212*e5aaf047SAppaRao Puli                 const std::vector<std::string>& params) override
213*e5aaf047SAppaRao Puli     {
214*e5aaf047SAppaRao Puli         auto asyncResp = std::make_shared<AsyncResp>(res);
215*e5aaf047SAppaRao Puli 
216*e5aaf047SAppaRao Puli         if (subscriptionsMap.size() >= maxNoOfSubscriptions)
217*e5aaf047SAppaRao Puli         {
218*e5aaf047SAppaRao Puli             messages::eventSubscriptionLimitExceeded(asyncResp->res);
219*e5aaf047SAppaRao Puli             return;
220*e5aaf047SAppaRao Puli         }
221*e5aaf047SAppaRao Puli         std::string destUrl;
222*e5aaf047SAppaRao Puli         std::string protocol;
223*e5aaf047SAppaRao Puli         std::optional<std::string> context;
224*e5aaf047SAppaRao Puli         std::optional<std::string> subscriptionType;
225*e5aaf047SAppaRao Puli         std::optional<std::string> eventFormatType;
226*e5aaf047SAppaRao Puli         std::optional<std::string> retryPolicy;
227*e5aaf047SAppaRao Puli         std::optional<std::vector<std::string>> msgIds;
228*e5aaf047SAppaRao Puli         std::optional<std::vector<std::string>> regPrefixes;
229*e5aaf047SAppaRao Puli         std::optional<std::vector<nlohmann::json>> headers;
230*e5aaf047SAppaRao Puli 
231*e5aaf047SAppaRao Puli         if (!json_util::readJson(
232*e5aaf047SAppaRao Puli                 req, res, "Destination", destUrl, "Context", context,
233*e5aaf047SAppaRao Puli                 "Protocol", protocol, "SubscriptionType", subscriptionType,
234*e5aaf047SAppaRao Puli                 "EventFormatType", eventFormatType, "HttpHeaders", headers,
235*e5aaf047SAppaRao Puli                 "RegistryPrefixes", regPrefixes, "MessageIds", msgIds,
236*e5aaf047SAppaRao Puli                 "DeliveryRetryPolicy", retryPolicy))
237*e5aaf047SAppaRao Puli         {
238*e5aaf047SAppaRao Puli             return;
239*e5aaf047SAppaRao Puli         }
240*e5aaf047SAppaRao Puli 
241*e5aaf047SAppaRao Puli         EventSrvSubscription subValue;
242*e5aaf047SAppaRao Puli 
243*e5aaf047SAppaRao Puli         // Validate the URL using regex expression
244*e5aaf047SAppaRao Puli         // Format: <protocol>://<host>:<port>/uri
245*e5aaf047SAppaRao Puli         // protocol: http/https, uri: can include params.
246*e5aaf047SAppaRao Puli         const std::regex urlRegex("(http|https)://([^/ :]+):?.*");
247*e5aaf047SAppaRao Puli         if (!std::regex_match(destUrl, urlRegex))
248*e5aaf047SAppaRao Puli         {
249*e5aaf047SAppaRao Puli             messages::propertyValueFormatError(asyncResp->res, destUrl,
250*e5aaf047SAppaRao Puli                                                "Destination");
251*e5aaf047SAppaRao Puli             return;
252*e5aaf047SAppaRao Puli         }
253*e5aaf047SAppaRao Puli         subValue.destinationUrl = destUrl;
254*e5aaf047SAppaRao Puli 
255*e5aaf047SAppaRao Puli         if (subscriptionType)
256*e5aaf047SAppaRao Puli         {
257*e5aaf047SAppaRao Puli             if (*subscriptionType != "RedfishEvent")
258*e5aaf047SAppaRao Puli             {
259*e5aaf047SAppaRao Puli                 messages::propertyValueNotInList(
260*e5aaf047SAppaRao Puli                     asyncResp->res, *subscriptionType, "SubscriptionType");
261*e5aaf047SAppaRao Puli                 return;
262*e5aaf047SAppaRao Puli             }
263*e5aaf047SAppaRao Puli             subValue.subscriptionType = *subscriptionType;
264*e5aaf047SAppaRao Puli         }
265*e5aaf047SAppaRao Puli         else
266*e5aaf047SAppaRao Puli         {
267*e5aaf047SAppaRao Puli             subValue.subscriptionType = "RedfishEvent"; // Default
268*e5aaf047SAppaRao Puli         }
269*e5aaf047SAppaRao Puli 
270*e5aaf047SAppaRao Puli         if (protocol != "Redfish")
271*e5aaf047SAppaRao Puli         {
272*e5aaf047SAppaRao Puli             messages::propertyValueNotInList(asyncResp->res, protocol,
273*e5aaf047SAppaRao Puli                                              "Protocol");
274*e5aaf047SAppaRao Puli             return;
275*e5aaf047SAppaRao Puli         }
276*e5aaf047SAppaRao Puli         subValue.protocol = protocol;
277*e5aaf047SAppaRao Puli 
278*e5aaf047SAppaRao Puli         if (eventFormatType)
279*e5aaf047SAppaRao Puli         {
280*e5aaf047SAppaRao Puli             if (std::find(supportedEvtFormatTypes.begin(),
281*e5aaf047SAppaRao Puli                           supportedEvtFormatTypes.end(),
282*e5aaf047SAppaRao Puli                           *eventFormatType) == supportedEvtFormatTypes.end())
283*e5aaf047SAppaRao Puli             {
284*e5aaf047SAppaRao Puli                 messages::propertyValueNotInList(
285*e5aaf047SAppaRao Puli                     asyncResp->res, *eventFormatType, "EventFormatType");
286*e5aaf047SAppaRao Puli                 return;
287*e5aaf047SAppaRao Puli             }
288*e5aaf047SAppaRao Puli             subValue.eventFormatType = *eventFormatType;
289*e5aaf047SAppaRao Puli         }
290*e5aaf047SAppaRao Puli         else
291*e5aaf047SAppaRao Puli         {
292*e5aaf047SAppaRao Puli             // If not specified, use default "Event"
293*e5aaf047SAppaRao Puli             subValue.eventFormatType.assign({"Event"});
294*e5aaf047SAppaRao Puli         }
295*e5aaf047SAppaRao Puli 
296*e5aaf047SAppaRao Puli         if (context)
297*e5aaf047SAppaRao Puli         {
298*e5aaf047SAppaRao Puli             subValue.customText = *context;
299*e5aaf047SAppaRao Puli         }
300*e5aaf047SAppaRao Puli 
301*e5aaf047SAppaRao Puli         if (headers)
302*e5aaf047SAppaRao Puli         {
303*e5aaf047SAppaRao Puli             subValue.httpHeaders = *headers;
304*e5aaf047SAppaRao Puli         }
305*e5aaf047SAppaRao Puli 
306*e5aaf047SAppaRao Puli         if (regPrefixes)
307*e5aaf047SAppaRao Puli         {
308*e5aaf047SAppaRao Puli             for (const std::string& it : *regPrefixes)
309*e5aaf047SAppaRao Puli             {
310*e5aaf047SAppaRao Puli                 if (std::find(supportedRegPrefixes.begin(),
311*e5aaf047SAppaRao Puli                               supportedRegPrefixes.end(),
312*e5aaf047SAppaRao Puli                               it) == supportedRegPrefixes.end())
313*e5aaf047SAppaRao Puli                 {
314*e5aaf047SAppaRao Puli                     messages::propertyValueNotInList(asyncResp->res, it,
315*e5aaf047SAppaRao Puli                                                      "RegistryPrefixes");
316*e5aaf047SAppaRao Puli                     return;
317*e5aaf047SAppaRao Puli                 }
318*e5aaf047SAppaRao Puli             }
319*e5aaf047SAppaRao Puli             subValue.registryPrefixes = *regPrefixes;
320*e5aaf047SAppaRao Puli         }
321*e5aaf047SAppaRao Puli 
322*e5aaf047SAppaRao Puli         if (msgIds)
323*e5aaf047SAppaRao Puli         {
324*e5aaf047SAppaRao Puli             // Do we need to loop-up MessageRegistry and validate
325*e5aaf047SAppaRao Puli             // data for authenticity??? Not mandate, i believe.
326*e5aaf047SAppaRao Puli             subValue.registryMsgIds = *msgIds;
327*e5aaf047SAppaRao Puli         }
328*e5aaf047SAppaRao Puli 
329*e5aaf047SAppaRao Puli         if (retryPolicy)
330*e5aaf047SAppaRao Puli         {
331*e5aaf047SAppaRao Puli             if (std::find(supportedRetryPolicies.begin(),
332*e5aaf047SAppaRao Puli                           supportedRetryPolicies.end(),
333*e5aaf047SAppaRao Puli                           *retryPolicy) == supportedRetryPolicies.end())
334*e5aaf047SAppaRao Puli             {
335*e5aaf047SAppaRao Puli                 messages::propertyValueNotInList(asyncResp->res, *retryPolicy,
336*e5aaf047SAppaRao Puli                                                  "DeliveryRetryPolicy");
337*e5aaf047SAppaRao Puli                 return;
338*e5aaf047SAppaRao Puli             }
339*e5aaf047SAppaRao Puli             subValue.retryPolicy = *retryPolicy;
340*e5aaf047SAppaRao Puli         }
341*e5aaf047SAppaRao Puli         else
342*e5aaf047SAppaRao Puli         {
343*e5aaf047SAppaRao Puli             // Default "TerminateAfterRetries"
344*e5aaf047SAppaRao Puli             subValue.retryPolicy = "TerminateAfterRetries";
345*e5aaf047SAppaRao Puli         }
346*e5aaf047SAppaRao Puli 
347*e5aaf047SAppaRao Puli         std::srand(static_cast<uint32_t>(std::time(0)));
348*e5aaf047SAppaRao Puli         std::string id;
349*e5aaf047SAppaRao Puli 
350*e5aaf047SAppaRao Puli         int retry = 3;
351*e5aaf047SAppaRao Puli         while (retry)
352*e5aaf047SAppaRao Puli         {
353*e5aaf047SAppaRao Puli             id = std::to_string(std::rand());
354*e5aaf047SAppaRao Puli             auto inserted = subscriptionsMap.insert(std::pair(id, subValue));
355*e5aaf047SAppaRao Puli             if (inserted.second)
356*e5aaf047SAppaRao Puli             {
357*e5aaf047SAppaRao Puli                 break;
358*e5aaf047SAppaRao Puli             }
359*e5aaf047SAppaRao Puli             retry--;
360*e5aaf047SAppaRao Puli         };
361*e5aaf047SAppaRao Puli 
362*e5aaf047SAppaRao Puli         if (retry <= 0)
363*e5aaf047SAppaRao Puli         {
364*e5aaf047SAppaRao Puli             messages::internalError(asyncResp->res);
365*e5aaf047SAppaRao Puli             return;
366*e5aaf047SAppaRao Puli         }
367*e5aaf047SAppaRao Puli 
368*e5aaf047SAppaRao Puli         updateSubscriptionData();
369*e5aaf047SAppaRao Puli 
370*e5aaf047SAppaRao Puli         messages::created(asyncResp->res);
371*e5aaf047SAppaRao Puli         asyncResp->res.addHeader(
372*e5aaf047SAppaRao Puli             "Location", "/redfish/v1/EventService/Subscriptions/" + id);
373*e5aaf047SAppaRao Puli     }
374*e5aaf047SAppaRao Puli };
375*e5aaf047SAppaRao Puli 
376*e5aaf047SAppaRao Puli class EventDestination : public Node
377*e5aaf047SAppaRao Puli {
378*e5aaf047SAppaRao Puli   public:
379*e5aaf047SAppaRao Puli     EventDestination(CrowApp& app) :
380*e5aaf047SAppaRao Puli         Node(app, "/redfish/v1/EventService/Subscriptions/<str>/",
381*e5aaf047SAppaRao Puli              std::string())
382*e5aaf047SAppaRao Puli     {
383*e5aaf047SAppaRao Puli         entityPrivileges = {
384*e5aaf047SAppaRao Puli             {boost::beast::http::verb::get, {{"Login"}}},
385*e5aaf047SAppaRao Puli             {boost::beast::http::verb::head, {{"Login"}}},
386*e5aaf047SAppaRao Puli             {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
387*e5aaf047SAppaRao Puli             {boost::beast::http::verb::put, {{"ConfigureManager"}}},
388*e5aaf047SAppaRao Puli             {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
389*e5aaf047SAppaRao Puli             {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
390*e5aaf047SAppaRao Puli     }
391*e5aaf047SAppaRao Puli 
392*e5aaf047SAppaRao Puli   private:
393*e5aaf047SAppaRao Puli     void doGet(crow::Response& res, const crow::Request& req,
394*e5aaf047SAppaRao Puli                const std::vector<std::string>& params) override
395*e5aaf047SAppaRao Puli     {
396*e5aaf047SAppaRao Puli         auto asyncResp = std::make_shared<AsyncResp>(res);
397*e5aaf047SAppaRao Puli         if (params.size() != 1)
398*e5aaf047SAppaRao Puli         {
399*e5aaf047SAppaRao Puli             messages::internalError(asyncResp->res);
400*e5aaf047SAppaRao Puli             return;
401*e5aaf047SAppaRao Puli         }
402*e5aaf047SAppaRao Puli 
403*e5aaf047SAppaRao Puli         const std::string& id = params[0];
404*e5aaf047SAppaRao Puli         auto obj = subscriptionsMap.find(id);
405*e5aaf047SAppaRao Puli         if (obj == subscriptionsMap.end())
406*e5aaf047SAppaRao Puli         {
407*e5aaf047SAppaRao Puli             res.result(boost::beast::http::status::not_found);
408*e5aaf047SAppaRao Puli             res.end();
409*e5aaf047SAppaRao Puli             return;
410*e5aaf047SAppaRao Puli         }
411*e5aaf047SAppaRao Puli 
412*e5aaf047SAppaRao Puli         EventSrvSubscription& subValue = obj->second;
413*e5aaf047SAppaRao Puli 
414*e5aaf047SAppaRao Puli         res.jsonValue = {
415*e5aaf047SAppaRao Puli             {"@odata.type", "#EventDestination.v1_7_0.EventDestination"},
416*e5aaf047SAppaRao Puli             {"Protocol", "Redfish"}};
417*e5aaf047SAppaRao Puli         asyncResp->res.jsonValue["@odata.id"] =
418*e5aaf047SAppaRao Puli             "/redfish/v1/EventService/Subscriptions/" + id;
419*e5aaf047SAppaRao Puli         asyncResp->res.jsonValue["Id"] = id;
420*e5aaf047SAppaRao Puli         asyncResp->res.jsonValue["Name"] = "Event Destination " + id;
421*e5aaf047SAppaRao Puli         asyncResp->res.jsonValue["Destination"] = subValue.destinationUrl;
422*e5aaf047SAppaRao Puli         asyncResp->res.jsonValue["Context"] = subValue.customText;
423*e5aaf047SAppaRao Puli         asyncResp->res.jsonValue["SubscriptionType"] =
424*e5aaf047SAppaRao Puli             subValue.subscriptionType;
425*e5aaf047SAppaRao Puli         asyncResp->res.jsonValue["HttpHeaders"] = subValue.httpHeaders;
426*e5aaf047SAppaRao Puli         asyncResp->res.jsonValue["EventFormatType"] = subValue.eventFormatType;
427*e5aaf047SAppaRao Puli         asyncResp->res.jsonValue["RegistryPrefixes"] =
428*e5aaf047SAppaRao Puli             subValue.registryPrefixes;
429*e5aaf047SAppaRao Puli         asyncResp->res.jsonValue["MessageIds"] = subValue.registryMsgIds;
430*e5aaf047SAppaRao Puli         asyncResp->res.jsonValue["DeliveryRetryPolicy"] = subValue.retryPolicy;
431*e5aaf047SAppaRao Puli     }
432*e5aaf047SAppaRao Puli 
433*e5aaf047SAppaRao Puli     void doPatch(crow::Response& res, const crow::Request& req,
434*e5aaf047SAppaRao Puli                  const std::vector<std::string>& params) override
435*e5aaf047SAppaRao Puli     {
436*e5aaf047SAppaRao Puli         auto asyncResp = std::make_shared<AsyncResp>(res);
437*e5aaf047SAppaRao Puli         if (params.size() != 1)
438*e5aaf047SAppaRao Puli         {
439*e5aaf047SAppaRao Puli             messages::internalError(asyncResp->res);
440*e5aaf047SAppaRao Puli             return;
441*e5aaf047SAppaRao Puli         }
442*e5aaf047SAppaRao Puli 
443*e5aaf047SAppaRao Puli         const std::string& id = params[0];
444*e5aaf047SAppaRao Puli         auto obj = subscriptionsMap.find(id);
445*e5aaf047SAppaRao Puli         if (obj == subscriptionsMap.end())
446*e5aaf047SAppaRao Puli         {
447*e5aaf047SAppaRao Puli             res.result(boost::beast::http::status::not_found);
448*e5aaf047SAppaRao Puli             res.end();
449*e5aaf047SAppaRao Puli             return;
450*e5aaf047SAppaRao Puli         }
451*e5aaf047SAppaRao Puli 
452*e5aaf047SAppaRao Puli         std::optional<std::string> context;
453*e5aaf047SAppaRao Puli         std::optional<std::string> retryPolicy;
454*e5aaf047SAppaRao Puli         std::optional<std::vector<nlohmann::json>> headers;
455*e5aaf047SAppaRao Puli 
456*e5aaf047SAppaRao Puli         if (!json_util::readJson(req, res, "Context", context,
457*e5aaf047SAppaRao Puli                                  "DeliveryRetryPolicy", retryPolicy,
458*e5aaf047SAppaRao Puli                                  "HttpHeaders", headers))
459*e5aaf047SAppaRao Puli         {
460*e5aaf047SAppaRao Puli             return;
461*e5aaf047SAppaRao Puli         }
462*e5aaf047SAppaRao Puli 
463*e5aaf047SAppaRao Puli         EventSrvSubscription& subValue = obj->second;
464*e5aaf047SAppaRao Puli 
465*e5aaf047SAppaRao Puli         if (context)
466*e5aaf047SAppaRao Puli         {
467*e5aaf047SAppaRao Puli             subValue.customText = *context;
468*e5aaf047SAppaRao Puli         }
469*e5aaf047SAppaRao Puli 
470*e5aaf047SAppaRao Puli         if (headers)
471*e5aaf047SAppaRao Puli         {
472*e5aaf047SAppaRao Puli             subValue.httpHeaders = *headers;
473*e5aaf047SAppaRao Puli         }
474*e5aaf047SAppaRao Puli 
475*e5aaf047SAppaRao Puli         if (retryPolicy)
476*e5aaf047SAppaRao Puli         {
477*e5aaf047SAppaRao Puli             if (std::find(supportedRetryPolicies.begin(),
478*e5aaf047SAppaRao Puli                           supportedRetryPolicies.end(),
479*e5aaf047SAppaRao Puli                           *retryPolicy) == supportedRetryPolicies.end())
480*e5aaf047SAppaRao Puli             {
481*e5aaf047SAppaRao Puli                 messages::propertyValueNotInList(asyncResp->res, *retryPolicy,
482*e5aaf047SAppaRao Puli                                                  "DeliveryRetryPolicy");
483*e5aaf047SAppaRao Puli                 return;
484*e5aaf047SAppaRao Puli             }
485*e5aaf047SAppaRao Puli             subValue.retryPolicy = *retryPolicy;
486*e5aaf047SAppaRao Puli         }
487*e5aaf047SAppaRao Puli 
488*e5aaf047SAppaRao Puli         updateSubscriptionData();
489*e5aaf047SAppaRao Puli     }
490*e5aaf047SAppaRao Puli 
491*e5aaf047SAppaRao Puli     void doDelete(crow::Response& res, const crow::Request& req,
492*e5aaf047SAppaRao Puli                   const std::vector<std::string>& params) override
493*e5aaf047SAppaRao Puli     {
494*e5aaf047SAppaRao Puli         auto asyncResp = std::make_shared<AsyncResp>(res);
495*e5aaf047SAppaRao Puli 
496*e5aaf047SAppaRao Puli         if (params.size() != 1)
497*e5aaf047SAppaRao Puli         {
498*e5aaf047SAppaRao Puli             messages::internalError(asyncResp->res);
499*e5aaf047SAppaRao Puli             return;
500*e5aaf047SAppaRao Puli         }
501*e5aaf047SAppaRao Puli 
502*e5aaf047SAppaRao Puli         const std::string& id = params[0];
503*e5aaf047SAppaRao Puli         auto obj = subscriptionsMap.find(id);
504*e5aaf047SAppaRao Puli         if (obj == subscriptionsMap.end())
505*e5aaf047SAppaRao Puli         {
506*e5aaf047SAppaRao Puli             res.result(boost::beast::http::status::not_found);
507*e5aaf047SAppaRao Puli             res.end();
508*e5aaf047SAppaRao Puli             return;
509*e5aaf047SAppaRao Puli         }
510*e5aaf047SAppaRao Puli 
511*e5aaf047SAppaRao Puli         subscriptionsMap.erase(obj);
512*e5aaf047SAppaRao Puli 
513*e5aaf047SAppaRao Puli         updateSubscriptionData();
514*e5aaf047SAppaRao Puli     }
515*e5aaf047SAppaRao Puli };
516*e5aaf047SAppaRao Puli 
517*e5aaf047SAppaRao Puli } // namespace redfish
518