xref: /openbmc/bmcweb/features/redfish/lib/event_service.hpp (revision b52664e2f47512c4eb7ce8f036eacf7a4b161320)
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
17*b52664e2SAppaRao Puli #include "event_service_manager.hpp"
18e5aaf047SAppaRao Puli 
19e5aaf047SAppaRao Puli namespace redfish
20e5aaf047SAppaRao Puli {
21e5aaf047SAppaRao Puli 
22e5aaf047SAppaRao Puli static constexpr const std::array<const char*, 1> supportedEvtFormatTypes = {
23e5aaf047SAppaRao Puli     "Event"};
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"}}},
58e5aaf047SAppaRao Puli             {"@odata.id", "/redfish/v1/EventService"}};
59e5aaf047SAppaRao Puli 
60e5aaf047SAppaRao Puli         asyncResp->res.jsonValue["Status"]["State"] = "Enabled";
61*b52664e2SAppaRao Puli         asyncResp->res.jsonValue["ServiceEnabled"] =
62*b52664e2SAppaRao Puli             EventServiceManager::getInstance().enabled;
63e5aaf047SAppaRao Puli         asyncResp->res.jsonValue["DeliveryRetryAttempts"] =
64*b52664e2SAppaRao Puli             EventServiceManager::getInstance().retryAttempts;
65e5aaf047SAppaRao Puli         asyncResp->res.jsonValue["DeliveryRetryIntervalSeconds"] =
66*b52664e2SAppaRao Puli             EventServiceManager::getInstance().retryTimeoutInterval;
67e5aaf047SAppaRao Puli         asyncResp->res.jsonValue["EventFormatTypes"] = supportedEvtFormatTypes;
68e5aaf047SAppaRao Puli         asyncResp->res.jsonValue["RegistryPrefixes"] = supportedRegPrefixes;
69e5aaf047SAppaRao Puli     }
70e5aaf047SAppaRao Puli 
71e5aaf047SAppaRao Puli     void doPatch(crow::Response& res, const crow::Request& req,
72e5aaf047SAppaRao Puli                  const std::vector<std::string>& params) override
73e5aaf047SAppaRao Puli     {
74e5aaf047SAppaRao Puli         auto asyncResp = std::make_shared<AsyncResp>(res);
75e5aaf047SAppaRao Puli 
76e5aaf047SAppaRao Puli         std::optional<bool> serviceEnabled;
77e5aaf047SAppaRao Puli         std::optional<uint32_t> retryAttemps;
78e5aaf047SAppaRao Puli         std::optional<uint32_t> retryInterval;
79e5aaf047SAppaRao Puli 
80e5aaf047SAppaRao Puli         if (!json_util::readJson(req, res, "ServiceEnabled", serviceEnabled,
81e5aaf047SAppaRao Puli                                  "DeliveryRetryAttempts", retryAttemps,
82e5aaf047SAppaRao Puli                                  "DeliveryRetryIntervalSeconds", retryInterval))
83e5aaf047SAppaRao Puli         {
84e5aaf047SAppaRao Puli             return;
85e5aaf047SAppaRao Puli         }
86e5aaf047SAppaRao Puli 
87e5aaf047SAppaRao Puli         if (serviceEnabled)
88e5aaf047SAppaRao Puli         {
89*b52664e2SAppaRao Puli             EventServiceManager::getInstance().enabled = *serviceEnabled;
90e5aaf047SAppaRao Puli         }
91e5aaf047SAppaRao Puli 
92e5aaf047SAppaRao Puli         if (retryAttemps)
93e5aaf047SAppaRao Puli         {
94e5aaf047SAppaRao Puli             // Supported range [1-3]
95e5aaf047SAppaRao Puli             if ((*retryAttemps < 1) || (*retryAttemps > 3))
96e5aaf047SAppaRao Puli             {
97e5aaf047SAppaRao Puli                 messages::queryParameterOutOfRange(
98e5aaf047SAppaRao Puli                     asyncResp->res, std::to_string(*retryAttemps),
99e5aaf047SAppaRao Puli                     "DeliveryRetryAttempts", "[1-3]");
100e5aaf047SAppaRao Puli             }
101e5aaf047SAppaRao Puli             else
102e5aaf047SAppaRao Puli             {
103*b52664e2SAppaRao Puli                 EventServiceManager::getInstance().retryAttempts =
104*b52664e2SAppaRao Puli                     *retryAttemps;
105e5aaf047SAppaRao Puli             }
106e5aaf047SAppaRao Puli         }
107e5aaf047SAppaRao Puli 
108e5aaf047SAppaRao Puli         if (retryInterval)
109e5aaf047SAppaRao Puli         {
110e5aaf047SAppaRao Puli             // Supported range [30 - 180]
111e5aaf047SAppaRao Puli             if ((*retryInterval < 30) || (*retryInterval > 180))
112e5aaf047SAppaRao Puli             {
113e5aaf047SAppaRao Puli                 messages::queryParameterOutOfRange(
114e5aaf047SAppaRao Puli                     asyncResp->res, std::to_string(*retryInterval),
115e5aaf047SAppaRao Puli                     "DeliveryRetryIntervalSeconds", "[30-180]");
116e5aaf047SAppaRao Puli             }
117e5aaf047SAppaRao Puli             else
118e5aaf047SAppaRao Puli             {
119*b52664e2SAppaRao Puli                 EventServiceManager::getInstance().retryTimeoutInterval =
120*b52664e2SAppaRao Puli                     *retryInterval;
121e5aaf047SAppaRao Puli             }
122e5aaf047SAppaRao Puli         }
123e5aaf047SAppaRao Puli 
124*b52664e2SAppaRao Puli         EventServiceManager::getInstance().updateSubscriptionData();
125e5aaf047SAppaRao Puli     }
126e5aaf047SAppaRao Puli };
127e5aaf047SAppaRao Puli 
128e5aaf047SAppaRao Puli class EventDestinationCollection : public Node
129e5aaf047SAppaRao Puli {
130e5aaf047SAppaRao Puli   public:
131e5aaf047SAppaRao Puli     EventDestinationCollection(CrowApp& app) :
132e5aaf047SAppaRao Puli         Node(app, "/redfish/v1/EventService/Subscriptions/")
133e5aaf047SAppaRao Puli     {
134e5aaf047SAppaRao Puli         entityPrivileges = {
135e5aaf047SAppaRao Puli             {boost::beast::http::verb::get, {{"Login"}}},
136e5aaf047SAppaRao Puli             {boost::beast::http::verb::head, {{"Login"}}},
137e5aaf047SAppaRao Puli             {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
138e5aaf047SAppaRao Puli             {boost::beast::http::verb::put, {{"ConfigureManager"}}},
139e5aaf047SAppaRao Puli             {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
140e5aaf047SAppaRao Puli             {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
141e5aaf047SAppaRao Puli     }
142e5aaf047SAppaRao Puli 
143e5aaf047SAppaRao Puli   private:
144e5aaf047SAppaRao Puli     void doGet(crow::Response& res, const crow::Request& req,
145e5aaf047SAppaRao Puli                const std::vector<std::string>& params) override
146e5aaf047SAppaRao Puli     {
147e5aaf047SAppaRao Puli         auto asyncResp = std::make_shared<AsyncResp>(res);
148e5aaf047SAppaRao Puli 
149e5aaf047SAppaRao Puli         res.jsonValue = {
150e5aaf047SAppaRao Puli             {"@odata.type",
151e5aaf047SAppaRao Puli              "#EventDestinationCollection.EventDestinationCollection"},
152e5aaf047SAppaRao Puli             {"@odata.id", "/redfish/v1/EventService/Subscriptions"},
153e5aaf047SAppaRao Puli             {"Name", "Event Destination Collections"}};
154e5aaf047SAppaRao Puli 
155e5aaf047SAppaRao Puli         nlohmann::json& memberArray = asyncResp->res.jsonValue["Members"];
156e5aaf047SAppaRao Puli 
157*b52664e2SAppaRao Puli         std::vector<std::string> subscripIds =
158*b52664e2SAppaRao Puli             EventServiceManager::getInstance().getAllIDs();
159*b52664e2SAppaRao Puli         memberArray = nlohmann::json::array();
160*b52664e2SAppaRao Puli         asyncResp->res.jsonValue["Members@odata.count"] = subscripIds.size();
161*b52664e2SAppaRao Puli 
162*b52664e2SAppaRao Puli         for (const std::string& id : subscripIds)
163e5aaf047SAppaRao Puli         {
164e5aaf047SAppaRao Puli             memberArray.push_back(
165e5aaf047SAppaRao Puli                 {{"@odata.id",
166*b52664e2SAppaRao Puli                   "/redfish/v1/EventService/Subscriptions/" + id}});
167e5aaf047SAppaRao Puli         }
168e5aaf047SAppaRao Puli     }
169e5aaf047SAppaRao Puli 
170e5aaf047SAppaRao Puli     void doPost(crow::Response& res, const crow::Request& req,
171e5aaf047SAppaRao Puli                 const std::vector<std::string>& params) override
172e5aaf047SAppaRao Puli     {
173e5aaf047SAppaRao Puli         auto asyncResp = std::make_shared<AsyncResp>(res);
174e5aaf047SAppaRao Puli 
175*b52664e2SAppaRao Puli         if (EventServiceManager::getInstance().getNumberOfSubscriptions() >=
176*b52664e2SAppaRao Puli             maxNoOfSubscriptions)
177e5aaf047SAppaRao Puli         {
178e5aaf047SAppaRao Puli             messages::eventSubscriptionLimitExceeded(asyncResp->res);
179e5aaf047SAppaRao Puli             return;
180e5aaf047SAppaRao Puli         }
181e5aaf047SAppaRao Puli         std::string destUrl;
182e5aaf047SAppaRao Puli         std::string protocol;
183e5aaf047SAppaRao Puli         std::optional<std::string> context;
184e5aaf047SAppaRao Puli         std::optional<std::string> subscriptionType;
185e5aaf047SAppaRao Puli         std::optional<std::string> eventFormatType;
186e5aaf047SAppaRao Puli         std::optional<std::string> retryPolicy;
187e5aaf047SAppaRao Puli         std::optional<std::vector<std::string>> msgIds;
188e5aaf047SAppaRao Puli         std::optional<std::vector<std::string>> regPrefixes;
189e5aaf047SAppaRao Puli         std::optional<std::vector<nlohmann::json>> headers;
190e5aaf047SAppaRao Puli 
191e5aaf047SAppaRao Puli         if (!json_util::readJson(
192e5aaf047SAppaRao Puli                 req, res, "Destination", destUrl, "Context", context,
193e5aaf047SAppaRao Puli                 "Protocol", protocol, "SubscriptionType", subscriptionType,
194e5aaf047SAppaRao Puli                 "EventFormatType", eventFormatType, "HttpHeaders", headers,
195e5aaf047SAppaRao Puli                 "RegistryPrefixes", regPrefixes, "MessageIds", msgIds,
196e5aaf047SAppaRao Puli                 "DeliveryRetryPolicy", retryPolicy))
197e5aaf047SAppaRao Puli         {
198e5aaf047SAppaRao Puli             return;
199e5aaf047SAppaRao Puli         }
200e5aaf047SAppaRao Puli 
201e5aaf047SAppaRao Puli         // Validate the URL using regex expression
202*b52664e2SAppaRao Puli         // Format: <protocol>://<host>:<port>/<uri>
203*b52664e2SAppaRao Puli         // protocol: http/https
204*b52664e2SAppaRao Puli         // host: Exclude ' ', ':', '#', '?'
205*b52664e2SAppaRao Puli         // port: Empty or numeric value with ':' seperator.
206*b52664e2SAppaRao Puli         // uri: Start with '/' and Exclude '#', ' '
207*b52664e2SAppaRao Puli         //      Can include query params(ex: '/event?test=1')
208*b52664e2SAppaRao Puli         // TODO: Need to validate hostname extensively(as per rfc)
209*b52664e2SAppaRao Puli         const std::regex urlRegex(
210*b52664e2SAppaRao Puli             "(http|https)://([^/\\x20\\x3f\\x23\\x3a]+):?([0-9]*)(/"
211*b52664e2SAppaRao Puli             "([^\\x20\\x23\\x3f]*\\x3f?([^\\x20\\x23\\x3f])*)?)");
212*b52664e2SAppaRao Puli         std::cmatch match;
213*b52664e2SAppaRao Puli         if (!std::regex_match(destUrl.c_str(), match, urlRegex))
214e5aaf047SAppaRao Puli         {
215e5aaf047SAppaRao Puli             messages::propertyValueFormatError(asyncResp->res, destUrl,
216e5aaf047SAppaRao Puli                                                "Destination");
217e5aaf047SAppaRao Puli             return;
218e5aaf047SAppaRao Puli         }
219*b52664e2SAppaRao Puli 
220*b52664e2SAppaRao Puli         std::string uriProto = std::string(match[1].first, match[1].second);
221*b52664e2SAppaRao Puli         if (uriProto == "http")
222*b52664e2SAppaRao Puli         {
223*b52664e2SAppaRao Puli #ifndef BMCWEB_INSECURE_ENABLE_HTTP_PUSH_STYLE_EVENTING
224*b52664e2SAppaRao Puli             messages::propertyValueFormatError(asyncResp->res, destUrl,
225*b52664e2SAppaRao Puli                                                "Destination");
226*b52664e2SAppaRao Puli             return;
227*b52664e2SAppaRao Puli #endif
228*b52664e2SAppaRao Puli         }
229*b52664e2SAppaRao Puli 
230*b52664e2SAppaRao Puli         std::string host = std::string(match[2].first, match[2].second);
231*b52664e2SAppaRao Puli         std::string port = std::string(match[3].first, match[3].second);
232*b52664e2SAppaRao Puli         std::string path = std::string(match[4].first, match[4].second);
233*b52664e2SAppaRao Puli         if (port.empty())
234*b52664e2SAppaRao Puli         {
235*b52664e2SAppaRao Puli             if (uriProto == "http")
236*b52664e2SAppaRao Puli             {
237*b52664e2SAppaRao Puli                 port = "80";
238*b52664e2SAppaRao Puli             }
239*b52664e2SAppaRao Puli             else
240*b52664e2SAppaRao Puli             {
241*b52664e2SAppaRao Puli                 port = "443";
242*b52664e2SAppaRao Puli             }
243*b52664e2SAppaRao Puli         }
244*b52664e2SAppaRao Puli         if (path.empty())
245*b52664e2SAppaRao Puli         {
246*b52664e2SAppaRao Puli             path = "/";
247*b52664e2SAppaRao Puli         }
248*b52664e2SAppaRao Puli 
249*b52664e2SAppaRao Puli         std::shared_ptr<Subscription> subValue =
250*b52664e2SAppaRao Puli             std::make_shared<Subscription>(host, port, path, uriProto);
251*b52664e2SAppaRao Puli 
252*b52664e2SAppaRao Puli         subValue->destinationUrl = destUrl;
253e5aaf047SAppaRao Puli 
254e5aaf047SAppaRao Puli         if (subscriptionType)
255e5aaf047SAppaRao Puli         {
256e5aaf047SAppaRao Puli             if (*subscriptionType != "RedfishEvent")
257e5aaf047SAppaRao Puli             {
258e5aaf047SAppaRao Puli                 messages::propertyValueNotInList(
259e5aaf047SAppaRao Puli                     asyncResp->res, *subscriptionType, "SubscriptionType");
260e5aaf047SAppaRao Puli                 return;
261e5aaf047SAppaRao Puli             }
262*b52664e2SAppaRao Puli             subValue->subscriptionType = *subscriptionType;
263e5aaf047SAppaRao Puli         }
264e5aaf047SAppaRao Puli         else
265e5aaf047SAppaRao Puli         {
266*b52664e2SAppaRao Puli             subValue->subscriptionType = "RedfishEvent"; // Default
267e5aaf047SAppaRao Puli         }
268e5aaf047SAppaRao Puli 
269e5aaf047SAppaRao Puli         if (protocol != "Redfish")
270e5aaf047SAppaRao Puli         {
271e5aaf047SAppaRao Puli             messages::propertyValueNotInList(asyncResp->res, protocol,
272e5aaf047SAppaRao Puli                                              "Protocol");
273e5aaf047SAppaRao Puli             return;
274e5aaf047SAppaRao Puli         }
275*b52664e2SAppaRao Puli         subValue->protocol = protocol;
276e5aaf047SAppaRao Puli 
277e5aaf047SAppaRao Puli         if (eventFormatType)
278e5aaf047SAppaRao Puli         {
279e5aaf047SAppaRao Puli             if (std::find(supportedEvtFormatTypes.begin(),
280e5aaf047SAppaRao Puli                           supportedEvtFormatTypes.end(),
281e5aaf047SAppaRao Puli                           *eventFormatType) == supportedEvtFormatTypes.end())
282e5aaf047SAppaRao Puli             {
283e5aaf047SAppaRao Puli                 messages::propertyValueNotInList(
284e5aaf047SAppaRao Puli                     asyncResp->res, *eventFormatType, "EventFormatType");
285e5aaf047SAppaRao Puli                 return;
286e5aaf047SAppaRao Puli             }
287*b52664e2SAppaRao Puli             subValue->eventFormatType = *eventFormatType;
288e5aaf047SAppaRao Puli         }
289e5aaf047SAppaRao Puli         else
290e5aaf047SAppaRao Puli         {
291e5aaf047SAppaRao Puli             // If not specified, use default "Event"
292*b52664e2SAppaRao Puli             subValue->eventFormatType.assign({"Event"});
293e5aaf047SAppaRao Puli         }
294e5aaf047SAppaRao Puli 
295e5aaf047SAppaRao Puli         if (context)
296e5aaf047SAppaRao Puli         {
297*b52664e2SAppaRao Puli             subValue->customText = *context;
298e5aaf047SAppaRao Puli         }
299e5aaf047SAppaRao Puli 
300e5aaf047SAppaRao Puli         if (headers)
301e5aaf047SAppaRao Puli         {
302*b52664e2SAppaRao Puli             subValue->httpHeaders = *headers;
303e5aaf047SAppaRao Puli         }
304e5aaf047SAppaRao Puli 
305e5aaf047SAppaRao Puli         if (regPrefixes)
306e5aaf047SAppaRao Puli         {
307e5aaf047SAppaRao Puli             for (const std::string& it : *regPrefixes)
308e5aaf047SAppaRao Puli             {
309e5aaf047SAppaRao Puli                 if (std::find(supportedRegPrefixes.begin(),
310e5aaf047SAppaRao Puli                               supportedRegPrefixes.end(),
311e5aaf047SAppaRao Puli                               it) == supportedRegPrefixes.end())
312e5aaf047SAppaRao Puli                 {
313e5aaf047SAppaRao Puli                     messages::propertyValueNotInList(asyncResp->res, it,
314e5aaf047SAppaRao Puli                                                      "RegistryPrefixes");
315e5aaf047SAppaRao Puli                     return;
316e5aaf047SAppaRao Puli                 }
317e5aaf047SAppaRao Puli             }
318*b52664e2SAppaRao Puli             subValue->registryPrefixes = *regPrefixes;
319e5aaf047SAppaRao Puli         }
320e5aaf047SAppaRao Puli 
321e5aaf047SAppaRao Puli         if (msgIds)
322e5aaf047SAppaRao Puli         {
323e5aaf047SAppaRao Puli             // Do we need to loop-up MessageRegistry and validate
324e5aaf047SAppaRao Puli             // data for authenticity??? Not mandate, i believe.
325*b52664e2SAppaRao Puli             subValue->registryMsgIds = *msgIds;
326e5aaf047SAppaRao Puli         }
327e5aaf047SAppaRao Puli 
328e5aaf047SAppaRao Puli         if (retryPolicy)
329e5aaf047SAppaRao Puli         {
330e5aaf047SAppaRao Puli             if (std::find(supportedRetryPolicies.begin(),
331e5aaf047SAppaRao Puli                           supportedRetryPolicies.end(),
332e5aaf047SAppaRao Puli                           *retryPolicy) == supportedRetryPolicies.end())
333e5aaf047SAppaRao Puli             {
334e5aaf047SAppaRao Puli                 messages::propertyValueNotInList(asyncResp->res, *retryPolicy,
335e5aaf047SAppaRao Puli                                                  "DeliveryRetryPolicy");
336e5aaf047SAppaRao Puli                 return;
337e5aaf047SAppaRao Puli             }
338*b52664e2SAppaRao Puli             subValue->retryPolicy = *retryPolicy;
339e5aaf047SAppaRao Puli         }
340e5aaf047SAppaRao Puli         else
341e5aaf047SAppaRao Puli         {
342e5aaf047SAppaRao Puli             // Default "TerminateAfterRetries"
343*b52664e2SAppaRao Puli             subValue->retryPolicy = "TerminateAfterRetries";
344e5aaf047SAppaRao Puli         }
345e5aaf047SAppaRao Puli 
346*b52664e2SAppaRao Puli         std::string id =
347*b52664e2SAppaRao Puli             EventServiceManager::getInstance().addSubscription(subValue);
348*b52664e2SAppaRao Puli         if (id.empty())
349e5aaf047SAppaRao Puli         {
350e5aaf047SAppaRao Puli             messages::internalError(asyncResp->res);
351e5aaf047SAppaRao Puli             return;
352e5aaf047SAppaRao Puli         }
353e5aaf047SAppaRao Puli 
354e5aaf047SAppaRao Puli         messages::created(asyncResp->res);
355e5aaf047SAppaRao Puli         asyncResp->res.addHeader(
356e5aaf047SAppaRao Puli             "Location", "/redfish/v1/EventService/Subscriptions/" + id);
357e5aaf047SAppaRao Puli     }
358e5aaf047SAppaRao Puli };
359e5aaf047SAppaRao Puli 
360e5aaf047SAppaRao Puli class EventDestination : public Node
361e5aaf047SAppaRao Puli {
362e5aaf047SAppaRao Puli   public:
363e5aaf047SAppaRao Puli     EventDestination(CrowApp& app) :
364e5aaf047SAppaRao Puli         Node(app, "/redfish/v1/EventService/Subscriptions/<str>/",
365e5aaf047SAppaRao Puli              std::string())
366e5aaf047SAppaRao Puli     {
367e5aaf047SAppaRao Puli         entityPrivileges = {
368e5aaf047SAppaRao Puli             {boost::beast::http::verb::get, {{"Login"}}},
369e5aaf047SAppaRao Puli             {boost::beast::http::verb::head, {{"Login"}}},
370e5aaf047SAppaRao Puli             {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
371e5aaf047SAppaRao Puli             {boost::beast::http::verb::put, {{"ConfigureManager"}}},
372e5aaf047SAppaRao Puli             {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
373e5aaf047SAppaRao Puli             {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
374e5aaf047SAppaRao Puli     }
375e5aaf047SAppaRao Puli 
376e5aaf047SAppaRao Puli   private:
377e5aaf047SAppaRao Puli     void doGet(crow::Response& res, const crow::Request& req,
378e5aaf047SAppaRao Puli                const std::vector<std::string>& params) override
379e5aaf047SAppaRao Puli     {
380e5aaf047SAppaRao Puli         auto asyncResp = std::make_shared<AsyncResp>(res);
381e5aaf047SAppaRao Puli         if (params.size() != 1)
382e5aaf047SAppaRao Puli         {
383e5aaf047SAppaRao Puli             messages::internalError(asyncResp->res);
384e5aaf047SAppaRao Puli             return;
385e5aaf047SAppaRao Puli         }
386e5aaf047SAppaRao Puli 
387*b52664e2SAppaRao Puli         std::shared_ptr<Subscription> subValue =
388*b52664e2SAppaRao Puli             EventServiceManager::getInstance().getSubscription(params[0]);
389*b52664e2SAppaRao Puli         if (subValue == nullptr)
390e5aaf047SAppaRao Puli         {
391e5aaf047SAppaRao Puli             res.result(boost::beast::http::status::not_found);
392e5aaf047SAppaRao Puli             res.end();
393e5aaf047SAppaRao Puli             return;
394e5aaf047SAppaRao Puli         }
395*b52664e2SAppaRao Puli         const std::string& id = params[0];
396e5aaf047SAppaRao Puli 
397e5aaf047SAppaRao Puli         res.jsonValue = {
398e5aaf047SAppaRao Puli             {"@odata.type", "#EventDestination.v1_7_0.EventDestination"},
399e5aaf047SAppaRao Puli             {"Protocol", "Redfish"}};
400e5aaf047SAppaRao Puli         asyncResp->res.jsonValue["@odata.id"] =
401e5aaf047SAppaRao Puli             "/redfish/v1/EventService/Subscriptions/" + id;
402e5aaf047SAppaRao Puli         asyncResp->res.jsonValue["Id"] = id;
403e5aaf047SAppaRao Puli         asyncResp->res.jsonValue["Name"] = "Event Destination " + id;
404*b52664e2SAppaRao Puli         asyncResp->res.jsonValue["Destination"] = subValue->destinationUrl;
405*b52664e2SAppaRao Puli         asyncResp->res.jsonValue["Context"] = subValue->customText;
406e5aaf047SAppaRao Puli         asyncResp->res.jsonValue["SubscriptionType"] =
407*b52664e2SAppaRao Puli             subValue->subscriptionType;
408*b52664e2SAppaRao Puli         asyncResp->res.jsonValue["HttpHeaders"] = subValue->httpHeaders;
409*b52664e2SAppaRao Puli         asyncResp->res.jsonValue["EventFormatType"] = subValue->eventFormatType;
410e5aaf047SAppaRao Puli         asyncResp->res.jsonValue["RegistryPrefixes"] =
411*b52664e2SAppaRao Puli             subValue->registryPrefixes;
412*b52664e2SAppaRao Puli         asyncResp->res.jsonValue["MessageIds"] = subValue->registryMsgIds;
413*b52664e2SAppaRao Puli         asyncResp->res.jsonValue["DeliveryRetryPolicy"] = subValue->retryPolicy;
414e5aaf047SAppaRao Puli     }
415e5aaf047SAppaRao Puli 
416e5aaf047SAppaRao Puli     void doPatch(crow::Response& res, const crow::Request& req,
417e5aaf047SAppaRao Puli                  const std::vector<std::string>& params) override
418e5aaf047SAppaRao Puli     {
419e5aaf047SAppaRao Puli         auto asyncResp = std::make_shared<AsyncResp>(res);
420e5aaf047SAppaRao Puli         if (params.size() != 1)
421e5aaf047SAppaRao Puli         {
422e5aaf047SAppaRao Puli             messages::internalError(asyncResp->res);
423e5aaf047SAppaRao Puli             return;
424e5aaf047SAppaRao Puli         }
425e5aaf047SAppaRao Puli 
426*b52664e2SAppaRao Puli         std::shared_ptr<Subscription> subValue =
427*b52664e2SAppaRao Puli             EventServiceManager::getInstance().getSubscription(params[0]);
428*b52664e2SAppaRao Puli         if (subValue == nullptr)
429e5aaf047SAppaRao Puli         {
430e5aaf047SAppaRao Puli             res.result(boost::beast::http::status::not_found);
431e5aaf047SAppaRao Puli             res.end();
432e5aaf047SAppaRao Puli             return;
433e5aaf047SAppaRao Puli         }
434e5aaf047SAppaRao Puli 
435e5aaf047SAppaRao Puli         std::optional<std::string> context;
436e5aaf047SAppaRao Puli         std::optional<std::string> retryPolicy;
437e5aaf047SAppaRao Puli         std::optional<std::vector<nlohmann::json>> headers;
438e5aaf047SAppaRao Puli 
439e5aaf047SAppaRao Puli         if (!json_util::readJson(req, res, "Context", context,
440e5aaf047SAppaRao Puli                                  "DeliveryRetryPolicy", retryPolicy,
441e5aaf047SAppaRao Puli                                  "HttpHeaders", headers))
442e5aaf047SAppaRao Puli         {
443e5aaf047SAppaRao Puli             return;
444e5aaf047SAppaRao Puli         }
445e5aaf047SAppaRao Puli 
446e5aaf047SAppaRao Puli         if (context)
447e5aaf047SAppaRao Puli         {
448*b52664e2SAppaRao Puli             subValue->customText = *context;
449e5aaf047SAppaRao Puli         }
450e5aaf047SAppaRao Puli 
451e5aaf047SAppaRao Puli         if (headers)
452e5aaf047SAppaRao Puli         {
453*b52664e2SAppaRao Puli             subValue->httpHeaders = *headers;
454e5aaf047SAppaRao Puli         }
455e5aaf047SAppaRao Puli 
456e5aaf047SAppaRao Puli         if (retryPolicy)
457e5aaf047SAppaRao Puli         {
458e5aaf047SAppaRao Puli             if (std::find(supportedRetryPolicies.begin(),
459e5aaf047SAppaRao Puli                           supportedRetryPolicies.end(),
460e5aaf047SAppaRao Puli                           *retryPolicy) == supportedRetryPolicies.end())
461e5aaf047SAppaRao Puli             {
462e5aaf047SAppaRao Puli                 messages::propertyValueNotInList(asyncResp->res, *retryPolicy,
463e5aaf047SAppaRao Puli                                                  "DeliveryRetryPolicy");
464e5aaf047SAppaRao Puli                 return;
465e5aaf047SAppaRao Puli             }
466*b52664e2SAppaRao Puli             subValue->retryPolicy = *retryPolicy;
467e5aaf047SAppaRao Puli         }
468e5aaf047SAppaRao Puli 
469*b52664e2SAppaRao Puli         EventServiceManager::getInstance().updateSubscriptionData();
470e5aaf047SAppaRao Puli     }
471e5aaf047SAppaRao Puli 
472e5aaf047SAppaRao Puli     void doDelete(crow::Response& res, const crow::Request& req,
473e5aaf047SAppaRao Puli                   const std::vector<std::string>& params) override
474e5aaf047SAppaRao Puli     {
475e5aaf047SAppaRao Puli         auto asyncResp = std::make_shared<AsyncResp>(res);
476e5aaf047SAppaRao Puli 
477e5aaf047SAppaRao Puli         if (params.size() != 1)
478e5aaf047SAppaRao Puli         {
479e5aaf047SAppaRao Puli             messages::internalError(asyncResp->res);
480e5aaf047SAppaRao Puli             return;
481e5aaf047SAppaRao Puli         }
482e5aaf047SAppaRao Puli 
483*b52664e2SAppaRao Puli         if (!EventServiceManager::getInstance().isSubscriptionExist(params[0]))
484e5aaf047SAppaRao Puli         {
485e5aaf047SAppaRao Puli             res.result(boost::beast::http::status::not_found);
486e5aaf047SAppaRao Puli             res.end();
487e5aaf047SAppaRao Puli             return;
488e5aaf047SAppaRao Puli         }
489*b52664e2SAppaRao Puli         EventServiceManager::getInstance().deleteSubscription(params[0]);
490e5aaf047SAppaRao Puli     }
491e5aaf047SAppaRao Puli };
492e5aaf047SAppaRao Puli 
493e5aaf047SAppaRao Puli } // namespace redfish
494