xref: /openbmc/bmcweb/features/redfish/lib/event_service.hpp (revision dd28ba829972906cbe2d372cf4ec00fdf82fbb83)
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 
29e56f254cSSunitha Harish #ifdef BMCWEB_ENABLE_IBM_MANAGEMENT_CONSOLE
30e56f254cSSunitha Harish static constexpr const std::array<const char*, 2> supportedResourceTypes = {
31e56f254cSSunitha Harish     "IBMConfigFile", "Task"};
32e56f254cSSunitha Harish #else
33e56f254cSSunitha Harish static constexpr const std::array<const char*, 1> supportedResourceTypes = {
34e56f254cSSunitha Harish     "Task"};
35e56f254cSSunitha Harish #endif
36e56f254cSSunitha Harish 
37e5aaf047SAppaRao Puli static constexpr const uint8_t maxNoOfSubscriptions = 20;
38e5aaf047SAppaRao Puli 
39e5aaf047SAppaRao Puli class EventService : public Node
40e5aaf047SAppaRao Puli {
41e5aaf047SAppaRao Puli   public:
4252cc112dSEd Tanous     EventService(App& app) : Node(app, "/redfish/v1/EventService/")
43e5aaf047SAppaRao Puli     {
44e5aaf047SAppaRao Puli         entityPrivileges = {
45e5aaf047SAppaRao Puli             {boost::beast::http::verb::get, {{"Login"}}},
46e5aaf047SAppaRao Puli             {boost::beast::http::verb::head, {{"Login"}}},
47e5aaf047SAppaRao Puli             {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
48e5aaf047SAppaRao Puli             {boost::beast::http::verb::put, {{"ConfigureManager"}}},
49e5aaf047SAppaRao Puli             {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
50e5aaf047SAppaRao Puli             {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
51e5aaf047SAppaRao Puli     }
52e5aaf047SAppaRao Puli 
53e5aaf047SAppaRao Puli   private:
54cb13a392SEd Tanous     void doGet(crow::Response& res, const crow::Request&,
55cb13a392SEd Tanous                const std::vector<std::string>&) override
56e5aaf047SAppaRao Puli     {
57e5aaf047SAppaRao Puli         auto asyncResp = std::make_shared<AsyncResp>(res);
58e5aaf047SAppaRao Puli         res.jsonValue = {
59e5aaf047SAppaRao Puli             {"@odata.type", "#EventService.v1_5_0.EventService"},
60e5aaf047SAppaRao Puli             {"Id", "EventService"},
61e5aaf047SAppaRao Puli             {"Name", "Event Service"},
62e5aaf047SAppaRao Puli             {"Subscriptions",
63e5aaf047SAppaRao Puli              {{"@odata.id", "/redfish/v1/EventService/Subscriptions"}}},
640b4bdd93SAppaRao Puli             {"Actions",
650b4bdd93SAppaRao Puli              {{"#EventService.SubmitTestEvent",
660b4bdd93SAppaRao Puli                {{"target", "/redfish/v1/EventService/Actions/"
670b4bdd93SAppaRao Puli                            "EventService.SubmitTestEvent"}}}}},
68e5aaf047SAppaRao Puli             {"@odata.id", "/redfish/v1/EventService"}};
69e5aaf047SAppaRao Puli 
707d1cc387SAppaRao Puli         const auto& [enabled, retryAttempts, retryTimeoutInterval] =
717d1cc387SAppaRao Puli             EventServiceManager::getInstance().getEventServiceConfig();
727d1cc387SAppaRao Puli 
737d1cc387SAppaRao Puli         asyncResp->res.jsonValue["Status"]["State"] =
747d1cc387SAppaRao Puli             (enabled ? "Enabled" : "Disabled");
757d1cc387SAppaRao Puli         asyncResp->res.jsonValue["ServiceEnabled"] = enabled;
767d1cc387SAppaRao Puli         asyncResp->res.jsonValue["DeliveryRetryAttempts"] = retryAttempts;
77e5aaf047SAppaRao Puli         asyncResp->res.jsonValue["DeliveryRetryIntervalSeconds"] =
787d1cc387SAppaRao Puli             retryTimeoutInterval;
79e5aaf047SAppaRao Puli         asyncResp->res.jsonValue["EventFormatTypes"] = supportedEvtFormatTypes;
80e5aaf047SAppaRao Puli         asyncResp->res.jsonValue["RegistryPrefixes"] = supportedRegPrefixes;
81e56f254cSSunitha Harish         asyncResp->res.jsonValue["ResourceTypes"] = supportedResourceTypes;
8207941a88SAyushi Smriti 
8307941a88SAyushi Smriti         nlohmann::json supportedSSEFilters = {
8407941a88SAyushi Smriti             {"EventFormatType", true},        {"MessageId", true},
8507941a88SAyushi Smriti             {"MetricReportDefinition", true}, {"RegistryPrefix", true},
8607941a88SAyushi Smriti             {"OriginResource", false},        {"ResourceType", false}};
8707941a88SAyushi Smriti 
8807941a88SAyushi Smriti         asyncResp->res.jsonValue["SSEFilterPropertiesSupported"] =
8907941a88SAyushi Smriti             supportedSSEFilters;
90e5aaf047SAppaRao Puli     }
91e5aaf047SAppaRao Puli 
92e5aaf047SAppaRao Puli     void doPatch(crow::Response& res, const crow::Request& req,
93cb13a392SEd Tanous                  const std::vector<std::string>&) override
94e5aaf047SAppaRao Puli     {
95e5aaf047SAppaRao Puli         auto asyncResp = std::make_shared<AsyncResp>(res);
96e5aaf047SAppaRao Puli 
97e5aaf047SAppaRao Puli         std::optional<bool> serviceEnabled;
98e5aaf047SAppaRao Puli         std::optional<uint32_t> retryAttemps;
99e5aaf047SAppaRao Puli         std::optional<uint32_t> retryInterval;
100e5aaf047SAppaRao Puli 
101e5aaf047SAppaRao Puli         if (!json_util::readJson(req, res, "ServiceEnabled", serviceEnabled,
102e5aaf047SAppaRao Puli                                  "DeliveryRetryAttempts", retryAttemps,
103e5aaf047SAppaRao Puli                                  "DeliveryRetryIntervalSeconds", retryInterval))
104e5aaf047SAppaRao Puli         {
105e5aaf047SAppaRao Puli             return;
106e5aaf047SAppaRao Puli         }
107e5aaf047SAppaRao Puli 
1087d1cc387SAppaRao Puli         auto [enabled, retryCount, retryTimeoutInterval] =
1097d1cc387SAppaRao Puli             EventServiceManager::getInstance().getEventServiceConfig();
1107d1cc387SAppaRao Puli 
111e5aaf047SAppaRao Puli         if (serviceEnabled)
112e5aaf047SAppaRao Puli         {
1137d1cc387SAppaRao Puli             enabled = *serviceEnabled;
114e5aaf047SAppaRao Puli         }
115e5aaf047SAppaRao Puli 
116e5aaf047SAppaRao Puli         if (retryAttemps)
117e5aaf047SAppaRao Puli         {
118e5aaf047SAppaRao Puli             // Supported range [1-3]
119e5aaf047SAppaRao Puli             if ((*retryAttemps < 1) || (*retryAttemps > 3))
120e5aaf047SAppaRao Puli             {
121e5aaf047SAppaRao Puli                 messages::queryParameterOutOfRange(
122e5aaf047SAppaRao Puli                     asyncResp->res, std::to_string(*retryAttemps),
123e5aaf047SAppaRao Puli                     "DeliveryRetryAttempts", "[1-3]");
124e5aaf047SAppaRao Puli             }
125e5aaf047SAppaRao Puli             else
126e5aaf047SAppaRao Puli             {
1277d1cc387SAppaRao Puli                 retryCount = *retryAttemps;
128e5aaf047SAppaRao Puli             }
129e5aaf047SAppaRao Puli         }
130e5aaf047SAppaRao Puli 
131e5aaf047SAppaRao Puli         if (retryInterval)
132e5aaf047SAppaRao Puli         {
133e5aaf047SAppaRao Puli             // Supported range [30 - 180]
134e5aaf047SAppaRao Puli             if ((*retryInterval < 30) || (*retryInterval > 180))
135e5aaf047SAppaRao Puli             {
136e5aaf047SAppaRao Puli                 messages::queryParameterOutOfRange(
137e5aaf047SAppaRao Puli                     asyncResp->res, std::to_string(*retryInterval),
138e5aaf047SAppaRao Puli                     "DeliveryRetryIntervalSeconds", "[30-180]");
139e5aaf047SAppaRao Puli             }
140e5aaf047SAppaRao Puli             else
141e5aaf047SAppaRao Puli             {
1427d1cc387SAppaRao Puli                 retryTimeoutInterval = *retryInterval;
143e5aaf047SAppaRao Puli             }
144e5aaf047SAppaRao Puli         }
145e5aaf047SAppaRao Puli 
1467d1cc387SAppaRao Puli         EventServiceManager::getInstance().setEventServiceConfig(
1477d1cc387SAppaRao Puli             std::make_tuple(enabled, retryCount, retryTimeoutInterval));
148e5aaf047SAppaRao Puli     }
149e5aaf047SAppaRao Puli };
150e5aaf047SAppaRao Puli 
1510b4bdd93SAppaRao Puli class SubmitTestEvent : public Node
1520b4bdd93SAppaRao Puli {
1530b4bdd93SAppaRao Puli   public:
15452cc112dSEd Tanous     SubmitTestEvent(App& app) :
1550b4bdd93SAppaRao Puli         Node(app,
1560b4bdd93SAppaRao Puli              "/redfish/v1/EventService/Actions/EventService.SubmitTestEvent/")
1570b4bdd93SAppaRao Puli     {
1580b4bdd93SAppaRao Puli         entityPrivileges = {
1590b4bdd93SAppaRao Puli             {boost::beast::http::verb::get, {{"Login"}}},
1600b4bdd93SAppaRao Puli             {boost::beast::http::verb::head, {{"Login"}}},
1610b4bdd93SAppaRao Puli             {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
1620b4bdd93SAppaRao Puli             {boost::beast::http::verb::put, {{"ConfigureManager"}}},
1630b4bdd93SAppaRao Puli             {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
1640b4bdd93SAppaRao Puli             {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
1650b4bdd93SAppaRao Puli     }
1660b4bdd93SAppaRao Puli 
1670b4bdd93SAppaRao Puli   private:
168cb13a392SEd Tanous     void doPost(crow::Response& res, const crow::Request&,
169cb13a392SEd Tanous                 const std::vector<std::string>&) override
1700b4bdd93SAppaRao Puli     {
1710b4bdd93SAppaRao Puli         EventServiceManager::getInstance().sendTestEventLog();
1720b4bdd93SAppaRao Puli         res.result(boost::beast::http::status::no_content);
1730b4bdd93SAppaRao Puli         res.end();
1740b4bdd93SAppaRao Puli     }
1750b4bdd93SAppaRao Puli };
1760b4bdd93SAppaRao Puli 
177e5aaf047SAppaRao Puli class EventDestinationCollection : public Node
178e5aaf047SAppaRao Puli {
179e5aaf047SAppaRao Puli   public:
18052cc112dSEd Tanous     EventDestinationCollection(App& app) :
181e5aaf047SAppaRao Puli         Node(app, "/redfish/v1/EventService/Subscriptions/")
182e5aaf047SAppaRao Puli     {
183e5aaf047SAppaRao Puli         entityPrivileges = {
184e5aaf047SAppaRao Puli             {boost::beast::http::verb::get, {{"Login"}}},
185e5aaf047SAppaRao Puli             {boost::beast::http::verb::head, {{"Login"}}},
186e5aaf047SAppaRao Puli             {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
187e5aaf047SAppaRao Puli             {boost::beast::http::verb::put, {{"ConfigureManager"}}},
188e5aaf047SAppaRao Puli             {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
189e5aaf047SAppaRao Puli             {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
190e5aaf047SAppaRao Puli     }
191e5aaf047SAppaRao Puli 
192e5aaf047SAppaRao Puli   private:
193cb13a392SEd Tanous     void doGet(crow::Response& res, const crow::Request&,
194cb13a392SEd Tanous                const std::vector<std::string>&) override
195e5aaf047SAppaRao Puli     {
196e5aaf047SAppaRao Puli         auto asyncResp = std::make_shared<AsyncResp>(res);
197e5aaf047SAppaRao Puli 
198e5aaf047SAppaRao Puli         res.jsonValue = {
199e5aaf047SAppaRao Puli             {"@odata.type",
200e5aaf047SAppaRao Puli              "#EventDestinationCollection.EventDestinationCollection"},
201e5aaf047SAppaRao Puli             {"@odata.id", "/redfish/v1/EventService/Subscriptions"},
202e5aaf047SAppaRao Puli             {"Name", "Event Destination Collections"}};
203e5aaf047SAppaRao Puli 
204e5aaf047SAppaRao Puli         nlohmann::json& memberArray = asyncResp->res.jsonValue["Members"];
205e5aaf047SAppaRao Puli 
206b52664e2SAppaRao Puli         std::vector<std::string> subscripIds =
207b52664e2SAppaRao Puli             EventServiceManager::getInstance().getAllIDs();
208b52664e2SAppaRao Puli         memberArray = nlohmann::json::array();
209b52664e2SAppaRao Puli         asyncResp->res.jsonValue["Members@odata.count"] = subscripIds.size();
210b52664e2SAppaRao Puli 
211b52664e2SAppaRao Puli         for (const std::string& id : subscripIds)
212e5aaf047SAppaRao Puli         {
213e5aaf047SAppaRao Puli             memberArray.push_back(
214e5aaf047SAppaRao Puli                 {{"@odata.id",
215b52664e2SAppaRao Puli                   "/redfish/v1/EventService/Subscriptions/" + id}});
216e5aaf047SAppaRao Puli         }
217e5aaf047SAppaRao Puli     }
218e5aaf047SAppaRao Puli 
219e5aaf047SAppaRao Puli     void doPost(crow::Response& res, const crow::Request& req,
220cb13a392SEd Tanous                 const std::vector<std::string>&) override
221e5aaf047SAppaRao Puli     {
222e5aaf047SAppaRao Puli         auto asyncResp = std::make_shared<AsyncResp>(res);
223e5aaf047SAppaRao Puli 
224b52664e2SAppaRao Puli         if (EventServiceManager::getInstance().getNumberOfSubscriptions() >=
225b52664e2SAppaRao Puli             maxNoOfSubscriptions)
226e5aaf047SAppaRao Puli         {
227e5aaf047SAppaRao Puli             messages::eventSubscriptionLimitExceeded(asyncResp->res);
228e5aaf047SAppaRao Puli             return;
229e5aaf047SAppaRao Puli         }
230e5aaf047SAppaRao Puli         std::string destUrl;
231e5aaf047SAppaRao Puli         std::string protocol;
232e5aaf047SAppaRao Puli         std::optional<std::string> context;
233e5aaf047SAppaRao Puli         std::optional<std::string> subscriptionType;
23423a21a1cSEd Tanous         std::optional<std::string> eventFormatType2;
235e5aaf047SAppaRao Puli         std::optional<std::string> retryPolicy;
236e5aaf047SAppaRao Puli         std::optional<std::vector<std::string>> msgIds;
237e5aaf047SAppaRao Puli         std::optional<std::vector<std::string>> regPrefixes;
238e56f254cSSunitha Harish         std::optional<std::vector<std::string>> resTypes;
239e5aaf047SAppaRao Puli         std::optional<std::vector<nlohmann::json>> headers;
240144b6318SAppaRao Puli         std::optional<std::vector<nlohmann::json>> mrdJsonArray;
241e5aaf047SAppaRao Puli 
242e5aaf047SAppaRao Puli         if (!json_util::readJson(
243e5aaf047SAppaRao Puli                 req, res, "Destination", destUrl, "Context", context,
244e5aaf047SAppaRao Puli                 "Protocol", protocol, "SubscriptionType", subscriptionType,
24523a21a1cSEd Tanous                 "EventFormatType", eventFormatType2, "HttpHeaders", headers,
246e5aaf047SAppaRao Puli                 "RegistryPrefixes", regPrefixes, "MessageIds", msgIds,
247156d6b00SAppaRao Puli                 "DeliveryRetryPolicy", retryPolicy, "MetricReportDefinitions",
248144b6318SAppaRao Puli                 mrdJsonArray, "ResourceTypes", resTypes))
249e5aaf047SAppaRao Puli         {
250e5aaf047SAppaRao Puli             return;
251e5aaf047SAppaRao Puli         }
252e5aaf047SAppaRao Puli 
253*dd28ba82SAppaRao Puli         if (regPrefixes && msgIds)
254*dd28ba82SAppaRao Puli         {
255*dd28ba82SAppaRao Puli             if (regPrefixes->size() && msgIds->size())
256*dd28ba82SAppaRao Puli             {
257*dd28ba82SAppaRao Puli                 messages::mutualExclusiveProperties(
258*dd28ba82SAppaRao Puli                     asyncResp->res, "RegistryPrefixes", "MessageIds");
259*dd28ba82SAppaRao Puli                 return;
260*dd28ba82SAppaRao Puli             }
261*dd28ba82SAppaRao Puli         }
262*dd28ba82SAppaRao Puli 
263e5aaf047SAppaRao Puli         // Validate the URL using regex expression
264b52664e2SAppaRao Puli         // Format: <protocol>://<host>:<port>/<uri>
265b52664e2SAppaRao Puli         // protocol: http/https
266b52664e2SAppaRao Puli         // host: Exclude ' ', ':', '#', '?'
2674e0453b1SGunnar Mills         // port: Empty or numeric value with ':' separator.
268b52664e2SAppaRao Puli         // uri: Start with '/' and Exclude '#', ' '
269b52664e2SAppaRao Puli         //      Can include query params(ex: '/event?test=1')
270b52664e2SAppaRao Puli         // TODO: Need to validate hostname extensively(as per rfc)
271b52664e2SAppaRao Puli         const std::regex urlRegex(
272b52664e2SAppaRao Puli             "(http|https)://([^/\\x20\\x3f\\x23\\x3a]+):?([0-9]*)(/"
273b52664e2SAppaRao Puli             "([^\\x20\\x23\\x3f]*\\x3f?([^\\x20\\x23\\x3f])*)?)");
274b52664e2SAppaRao Puli         std::cmatch match;
275b52664e2SAppaRao Puli         if (!std::regex_match(destUrl.c_str(), match, urlRegex))
276e5aaf047SAppaRao Puli         {
277e5aaf047SAppaRao Puli             messages::propertyValueFormatError(asyncResp->res, destUrl,
278e5aaf047SAppaRao Puli                                                "Destination");
279e5aaf047SAppaRao Puli             return;
280e5aaf047SAppaRao Puli         }
281b52664e2SAppaRao Puli 
282b52664e2SAppaRao Puli         std::string uriProto = std::string(match[1].first, match[1].second);
283b52664e2SAppaRao Puli         if (uriProto == "http")
284b52664e2SAppaRao Puli         {
285b52664e2SAppaRao Puli #ifndef BMCWEB_INSECURE_ENABLE_HTTP_PUSH_STYLE_EVENTING
286b52664e2SAppaRao Puli             messages::propertyValueFormatError(asyncResp->res, destUrl,
287b52664e2SAppaRao Puli                                                "Destination");
288b52664e2SAppaRao Puli             return;
289b52664e2SAppaRao Puli #endif
290b52664e2SAppaRao Puli         }
291b52664e2SAppaRao Puli 
292b52664e2SAppaRao Puli         std::string host = std::string(match[2].first, match[2].second);
293b52664e2SAppaRao Puli         std::string port = std::string(match[3].first, match[3].second);
294b52664e2SAppaRao Puli         std::string path = std::string(match[4].first, match[4].second);
295b52664e2SAppaRao Puli         if (port.empty())
296b52664e2SAppaRao Puli         {
297b52664e2SAppaRao Puli             if (uriProto == "http")
298b52664e2SAppaRao Puli             {
299b52664e2SAppaRao Puli                 port = "80";
300b52664e2SAppaRao Puli             }
301b52664e2SAppaRao Puli             else
302b52664e2SAppaRao Puli             {
303b52664e2SAppaRao Puli                 port = "443";
304b52664e2SAppaRao Puli             }
305b52664e2SAppaRao Puli         }
306b52664e2SAppaRao Puli         if (path.empty())
307b52664e2SAppaRao Puli         {
308b52664e2SAppaRao Puli             path = "/";
309b52664e2SAppaRao Puli         }
310b52664e2SAppaRao Puli 
311b52664e2SAppaRao Puli         std::shared_ptr<Subscription> subValue =
312b52664e2SAppaRao Puli             std::make_shared<Subscription>(host, port, path, uriProto);
313b52664e2SAppaRao Puli 
314b52664e2SAppaRao Puli         subValue->destinationUrl = destUrl;
315e5aaf047SAppaRao Puli 
316e5aaf047SAppaRao Puli         if (subscriptionType)
317e5aaf047SAppaRao Puli         {
318e5aaf047SAppaRao Puli             if (*subscriptionType != "RedfishEvent")
319e5aaf047SAppaRao Puli             {
320e5aaf047SAppaRao Puli                 messages::propertyValueNotInList(
321e5aaf047SAppaRao Puli                     asyncResp->res, *subscriptionType, "SubscriptionType");
322e5aaf047SAppaRao Puli                 return;
323e5aaf047SAppaRao Puli             }
324b52664e2SAppaRao Puli             subValue->subscriptionType = *subscriptionType;
325e5aaf047SAppaRao Puli         }
326e5aaf047SAppaRao Puli         else
327e5aaf047SAppaRao Puli         {
328b52664e2SAppaRao Puli             subValue->subscriptionType = "RedfishEvent"; // Default
329e5aaf047SAppaRao Puli         }
330e5aaf047SAppaRao Puli 
331e5aaf047SAppaRao Puli         if (protocol != "Redfish")
332e5aaf047SAppaRao Puli         {
333e5aaf047SAppaRao Puli             messages::propertyValueNotInList(asyncResp->res, protocol,
334e5aaf047SAppaRao Puli                                              "Protocol");
335e5aaf047SAppaRao Puli             return;
336e5aaf047SAppaRao Puli         }
337b52664e2SAppaRao Puli         subValue->protocol = protocol;
338e5aaf047SAppaRao Puli 
33923a21a1cSEd Tanous         if (eventFormatType2)
340e5aaf047SAppaRao Puli         {
341e5aaf047SAppaRao Puli             if (std::find(supportedEvtFormatTypes.begin(),
342e5aaf047SAppaRao Puli                           supportedEvtFormatTypes.end(),
34323a21a1cSEd Tanous                           *eventFormatType2) == supportedEvtFormatTypes.end())
344e5aaf047SAppaRao Puli             {
345e5aaf047SAppaRao Puli                 messages::propertyValueNotInList(
34623a21a1cSEd Tanous                     asyncResp->res, *eventFormatType2, "EventFormatType");
347e5aaf047SAppaRao Puli                 return;
348e5aaf047SAppaRao Puli             }
34923a21a1cSEd Tanous             subValue->eventFormatType = *eventFormatType2;
350e5aaf047SAppaRao Puli         }
351e5aaf047SAppaRao Puli         else
352e5aaf047SAppaRao Puli         {
353e5aaf047SAppaRao Puli             // If not specified, use default "Event"
35423a21a1cSEd Tanous             subValue->eventFormatType = "Event";
355e5aaf047SAppaRao Puli         }
356e5aaf047SAppaRao Puli 
357e5aaf047SAppaRao Puli         if (context)
358e5aaf047SAppaRao Puli         {
359b52664e2SAppaRao Puli             subValue->customText = *context;
360e5aaf047SAppaRao Puli         }
361e5aaf047SAppaRao Puli 
362e5aaf047SAppaRao Puli         if (headers)
363e5aaf047SAppaRao Puli         {
364b52664e2SAppaRao Puli             subValue->httpHeaders = *headers;
365e5aaf047SAppaRao Puli         }
366e5aaf047SAppaRao Puli 
367e5aaf047SAppaRao Puli         if (regPrefixes)
368e5aaf047SAppaRao Puli         {
369e5aaf047SAppaRao Puli             for (const std::string& it : *regPrefixes)
370e5aaf047SAppaRao Puli             {
371e5aaf047SAppaRao Puli                 if (std::find(supportedRegPrefixes.begin(),
372e5aaf047SAppaRao Puli                               supportedRegPrefixes.end(),
373e5aaf047SAppaRao Puli                               it) == supportedRegPrefixes.end())
374e5aaf047SAppaRao Puli                 {
375e5aaf047SAppaRao Puli                     messages::propertyValueNotInList(asyncResp->res, it,
376e5aaf047SAppaRao Puli                                                      "RegistryPrefixes");
377e5aaf047SAppaRao Puli                     return;
378e5aaf047SAppaRao Puli                 }
379e5aaf047SAppaRao Puli             }
380b52664e2SAppaRao Puli             subValue->registryPrefixes = *regPrefixes;
381e5aaf047SAppaRao Puli         }
382e5aaf047SAppaRao Puli 
383e56f254cSSunitha Harish         if (resTypes)
384e56f254cSSunitha Harish         {
385e56f254cSSunitha Harish             for (const std::string& it : *resTypes)
386e56f254cSSunitha Harish             {
387e56f254cSSunitha Harish                 if (std::find(supportedResourceTypes.begin(),
388e56f254cSSunitha Harish                               supportedResourceTypes.end(),
389e56f254cSSunitha Harish                               it) == supportedResourceTypes.end())
390e56f254cSSunitha Harish                 {
391e56f254cSSunitha Harish                     messages::propertyValueNotInList(asyncResp->res, it,
392e56f254cSSunitha Harish                                                      "ResourceTypes");
393e56f254cSSunitha Harish                     return;
394e56f254cSSunitha Harish                 }
395e56f254cSSunitha Harish             }
396e56f254cSSunitha Harish             subValue->resourceTypes = *resTypes;
397e56f254cSSunitha Harish         }
398e56f254cSSunitha Harish 
399e5aaf047SAppaRao Puli         if (msgIds)
400e5aaf047SAppaRao Puli         {
401e5aaf047SAppaRao Puli             // Do we need to loop-up MessageRegistry and validate
402e5aaf047SAppaRao Puli             // data for authenticity??? Not mandate, i believe.
403b52664e2SAppaRao Puli             subValue->registryMsgIds = *msgIds;
404e5aaf047SAppaRao Puli         }
405e5aaf047SAppaRao Puli 
406e5aaf047SAppaRao Puli         if (retryPolicy)
407e5aaf047SAppaRao Puli         {
408e5aaf047SAppaRao Puli             if (std::find(supportedRetryPolicies.begin(),
409e5aaf047SAppaRao Puli                           supportedRetryPolicies.end(),
410e5aaf047SAppaRao Puli                           *retryPolicy) == supportedRetryPolicies.end())
411e5aaf047SAppaRao Puli             {
412e5aaf047SAppaRao Puli                 messages::propertyValueNotInList(asyncResp->res, *retryPolicy,
413e5aaf047SAppaRao Puli                                                  "DeliveryRetryPolicy");
414e5aaf047SAppaRao Puli                 return;
415e5aaf047SAppaRao Puli             }
416b52664e2SAppaRao Puli             subValue->retryPolicy = *retryPolicy;
417e5aaf047SAppaRao Puli         }
418e5aaf047SAppaRao Puli         else
419e5aaf047SAppaRao Puli         {
420e5aaf047SAppaRao Puli             // Default "TerminateAfterRetries"
421b52664e2SAppaRao Puli             subValue->retryPolicy = "TerminateAfterRetries";
422e5aaf047SAppaRao Puli         }
423e5aaf047SAppaRao Puli 
424144b6318SAppaRao Puli         if (mrdJsonArray)
425156d6b00SAppaRao Puli         {
426144b6318SAppaRao Puli             for (nlohmann::json& mrdObj : *mrdJsonArray)
427144b6318SAppaRao Puli             {
428144b6318SAppaRao Puli                 std::string mrdUri;
429144b6318SAppaRao Puli                 if (json_util::getValueFromJsonObject(mrdObj, "@odata.id",
430144b6318SAppaRao Puli                                                       mrdUri))
431144b6318SAppaRao Puli                 {
432144b6318SAppaRao Puli                     subValue->metricReportDefinitions.emplace_back(mrdUri);
433144b6318SAppaRao Puli                 }
434144b6318SAppaRao Puli                 else
435144b6318SAppaRao Puli                 {
436144b6318SAppaRao Puli                     messages::propertyValueFormatError(
437144b6318SAppaRao Puli                         asyncResp->res, mrdObj.dump(),
438144b6318SAppaRao Puli                         "MetricReportDefinitions");
439144b6318SAppaRao Puli                     return;
440144b6318SAppaRao Puli                 }
441144b6318SAppaRao Puli             }
442156d6b00SAppaRao Puli         }
443156d6b00SAppaRao Puli 
444b52664e2SAppaRao Puli         std::string id =
445b52664e2SAppaRao Puli             EventServiceManager::getInstance().addSubscription(subValue);
446b52664e2SAppaRao Puli         if (id.empty())
447e5aaf047SAppaRao Puli         {
448e5aaf047SAppaRao Puli             messages::internalError(asyncResp->res);
449e5aaf047SAppaRao Puli             return;
450e5aaf047SAppaRao Puli         }
451e5aaf047SAppaRao Puli 
452e5aaf047SAppaRao Puli         messages::created(asyncResp->res);
453e5aaf047SAppaRao Puli         asyncResp->res.addHeader(
454e5aaf047SAppaRao Puli             "Location", "/redfish/v1/EventService/Subscriptions/" + id);
455e5aaf047SAppaRao Puli     }
456e5aaf047SAppaRao Puli };
457e5aaf047SAppaRao Puli 
458e5aaf047SAppaRao Puli class EventDestination : public Node
459e5aaf047SAppaRao Puli {
460e5aaf047SAppaRao Puli   public:
46152cc112dSEd Tanous     EventDestination(App& app) :
462e5aaf047SAppaRao Puli         Node(app, "/redfish/v1/EventService/Subscriptions/<str>/",
463e5aaf047SAppaRao Puli              std::string())
464e5aaf047SAppaRao Puli     {
465e5aaf047SAppaRao Puli         entityPrivileges = {
466e5aaf047SAppaRao Puli             {boost::beast::http::verb::get, {{"Login"}}},
467e5aaf047SAppaRao Puli             {boost::beast::http::verb::head, {{"Login"}}},
468e5aaf047SAppaRao Puli             {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
469e5aaf047SAppaRao Puli             {boost::beast::http::verb::put, {{"ConfigureManager"}}},
470e5aaf047SAppaRao Puli             {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
471e5aaf047SAppaRao Puli             {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
472e5aaf047SAppaRao Puli     }
473e5aaf047SAppaRao Puli 
474e5aaf047SAppaRao Puli   private:
475cb13a392SEd Tanous     void doGet(crow::Response& res, const crow::Request&,
476e5aaf047SAppaRao Puli                const std::vector<std::string>& params) override
477e5aaf047SAppaRao Puli     {
478e5aaf047SAppaRao Puli         auto asyncResp = std::make_shared<AsyncResp>(res);
479e5aaf047SAppaRao Puli         if (params.size() != 1)
480e5aaf047SAppaRao Puli         {
481e5aaf047SAppaRao Puli             messages::internalError(asyncResp->res);
482e5aaf047SAppaRao Puli             return;
483e5aaf047SAppaRao Puli         }
484e5aaf047SAppaRao Puli 
485b52664e2SAppaRao Puli         std::shared_ptr<Subscription> subValue =
486b52664e2SAppaRao Puli             EventServiceManager::getInstance().getSubscription(params[0]);
487b52664e2SAppaRao Puli         if (subValue == nullptr)
488e5aaf047SAppaRao Puli         {
489e5aaf047SAppaRao Puli             res.result(boost::beast::http::status::not_found);
490e5aaf047SAppaRao Puli             res.end();
491e5aaf047SAppaRao Puli             return;
492e5aaf047SAppaRao Puli         }
493b52664e2SAppaRao Puli         const std::string& id = params[0];
494e5aaf047SAppaRao Puli 
495e5aaf047SAppaRao Puli         res.jsonValue = {
496e5aaf047SAppaRao Puli             {"@odata.type", "#EventDestination.v1_7_0.EventDestination"},
497e5aaf047SAppaRao Puli             {"Protocol", "Redfish"}};
498e5aaf047SAppaRao Puli         asyncResp->res.jsonValue["@odata.id"] =
499e5aaf047SAppaRao Puli             "/redfish/v1/EventService/Subscriptions/" + id;
500e5aaf047SAppaRao Puli         asyncResp->res.jsonValue["Id"] = id;
501e5aaf047SAppaRao Puli         asyncResp->res.jsonValue["Name"] = "Event Destination " + id;
502b52664e2SAppaRao Puli         asyncResp->res.jsonValue["Destination"] = subValue->destinationUrl;
503b52664e2SAppaRao Puli         asyncResp->res.jsonValue["Context"] = subValue->customText;
504e5aaf047SAppaRao Puli         asyncResp->res.jsonValue["SubscriptionType"] =
505b52664e2SAppaRao Puli             subValue->subscriptionType;
506b52664e2SAppaRao Puli         asyncResp->res.jsonValue["HttpHeaders"] = subValue->httpHeaders;
507b52664e2SAppaRao Puli         asyncResp->res.jsonValue["EventFormatType"] = subValue->eventFormatType;
508e5aaf047SAppaRao Puli         asyncResp->res.jsonValue["RegistryPrefixes"] =
509b52664e2SAppaRao Puli             subValue->registryPrefixes;
510e56f254cSSunitha Harish         asyncResp->res.jsonValue["ResourceTypes"] = subValue->resourceTypes;
511e56f254cSSunitha Harish 
512b52664e2SAppaRao Puli         asyncResp->res.jsonValue["MessageIds"] = subValue->registryMsgIds;
513b52664e2SAppaRao Puli         asyncResp->res.jsonValue["DeliveryRetryPolicy"] = subValue->retryPolicy;
514144b6318SAppaRao Puli 
515144b6318SAppaRao Puli         std::vector<nlohmann::json> mrdJsonArray;
516144b6318SAppaRao Puli         for (const auto& mdrUri : subValue->metricReportDefinitions)
517144b6318SAppaRao Puli         {
518144b6318SAppaRao Puli             mrdJsonArray.push_back({{"@odata.id", mdrUri}});
519144b6318SAppaRao Puli         }
520144b6318SAppaRao Puli         asyncResp->res.jsonValue["MetricReportDefinitions"] = mrdJsonArray;
521e5aaf047SAppaRao Puli     }
522e5aaf047SAppaRao Puli 
523e5aaf047SAppaRao Puli     void doPatch(crow::Response& res, const crow::Request& req,
524e5aaf047SAppaRao Puli                  const std::vector<std::string>& params) override
525e5aaf047SAppaRao Puli     {
526e5aaf047SAppaRao Puli         auto asyncResp = std::make_shared<AsyncResp>(res);
527e5aaf047SAppaRao Puli         if (params.size() != 1)
528e5aaf047SAppaRao Puli         {
529e5aaf047SAppaRao Puli             messages::internalError(asyncResp->res);
530e5aaf047SAppaRao Puli             return;
531e5aaf047SAppaRao Puli         }
532e5aaf047SAppaRao Puli 
533b52664e2SAppaRao Puli         std::shared_ptr<Subscription> subValue =
534b52664e2SAppaRao Puli             EventServiceManager::getInstance().getSubscription(params[0]);
535b52664e2SAppaRao Puli         if (subValue == nullptr)
536e5aaf047SAppaRao Puli         {
537e5aaf047SAppaRao Puli             res.result(boost::beast::http::status::not_found);
538e5aaf047SAppaRao Puli             res.end();
539e5aaf047SAppaRao Puli             return;
540e5aaf047SAppaRao Puli         }
541e5aaf047SAppaRao Puli 
542e5aaf047SAppaRao Puli         std::optional<std::string> context;
543e5aaf047SAppaRao Puli         std::optional<std::string> retryPolicy;
544e5aaf047SAppaRao Puli         std::optional<std::vector<nlohmann::json>> headers;
545e5aaf047SAppaRao Puli 
546e5aaf047SAppaRao Puli         if (!json_util::readJson(req, res, "Context", context,
547e5aaf047SAppaRao Puli                                  "DeliveryRetryPolicy", retryPolicy,
548e5aaf047SAppaRao Puli                                  "HttpHeaders", headers))
549e5aaf047SAppaRao Puli         {
550e5aaf047SAppaRao Puli             return;
551e5aaf047SAppaRao Puli         }
552e5aaf047SAppaRao Puli 
553e5aaf047SAppaRao Puli         if (context)
554e5aaf047SAppaRao Puli         {
555b52664e2SAppaRao Puli             subValue->customText = *context;
556e5aaf047SAppaRao Puli         }
557e5aaf047SAppaRao Puli 
558e5aaf047SAppaRao Puli         if (headers)
559e5aaf047SAppaRao Puli         {
560b52664e2SAppaRao Puli             subValue->httpHeaders = *headers;
561e5aaf047SAppaRao Puli         }
562e5aaf047SAppaRao Puli 
563e5aaf047SAppaRao Puli         if (retryPolicy)
564e5aaf047SAppaRao Puli         {
565e5aaf047SAppaRao Puli             if (std::find(supportedRetryPolicies.begin(),
566e5aaf047SAppaRao Puli                           supportedRetryPolicies.end(),
567e5aaf047SAppaRao Puli                           *retryPolicy) == supportedRetryPolicies.end())
568e5aaf047SAppaRao Puli             {
569e5aaf047SAppaRao Puli                 messages::propertyValueNotInList(asyncResp->res, *retryPolicy,
570e5aaf047SAppaRao Puli                                                  "DeliveryRetryPolicy");
571e5aaf047SAppaRao Puli                 return;
572e5aaf047SAppaRao Puli             }
573b52664e2SAppaRao Puli             subValue->retryPolicy = *retryPolicy;
574fe44eb0bSAyushi Smriti             subValue->updateRetryPolicy();
575e5aaf047SAppaRao Puli         }
576e5aaf047SAppaRao Puli 
577b52664e2SAppaRao Puli         EventServiceManager::getInstance().updateSubscriptionData();
578e5aaf047SAppaRao Puli     }
579e5aaf047SAppaRao Puli 
580cb13a392SEd Tanous     void doDelete(crow::Response& res, const crow::Request&,
581e5aaf047SAppaRao Puli                   const std::vector<std::string>& params) override
582e5aaf047SAppaRao Puli     {
583e5aaf047SAppaRao Puli         auto asyncResp = std::make_shared<AsyncResp>(res);
584e5aaf047SAppaRao Puli 
585e5aaf047SAppaRao Puli         if (params.size() != 1)
586e5aaf047SAppaRao Puli         {
587e5aaf047SAppaRao Puli             messages::internalError(asyncResp->res);
588e5aaf047SAppaRao Puli             return;
589e5aaf047SAppaRao Puli         }
590e5aaf047SAppaRao Puli 
591b52664e2SAppaRao Puli         if (!EventServiceManager::getInstance().isSubscriptionExist(params[0]))
592e5aaf047SAppaRao Puli         {
593e5aaf047SAppaRao Puli             res.result(boost::beast::http::status::not_found);
594e5aaf047SAppaRao Puli             res.end();
595e5aaf047SAppaRao Puli             return;
596e5aaf047SAppaRao Puli         }
597b52664e2SAppaRao Puli         EventServiceManager::getInstance().deleteSubscription(params[0]);
598e5aaf047SAppaRao Puli     }
599e5aaf047SAppaRao Puli };
600e5aaf047SAppaRao Puli 
601e5aaf047SAppaRao Puli } // namespace redfish
602