xref: /openbmc/bmcweb/features/redfish/lib/event_service.hpp (revision 8d1b46d7f8d39db2ba048f9e9007106ca3a28c9b)
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:
54*8d1b46d7Szhanghch05     void doGet(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
55*8d1b46d7Szhanghch05                const crow::Request&, const std::vector<std::string>&) override
56e5aaf047SAppaRao Puli     {
57*8d1b46d7Szhanghch05 
58*8d1b46d7Szhanghch05         asyncResp->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 
92*8d1b46d7Szhanghch05     void doPatch(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
93*8d1b46d7Szhanghch05                  const crow::Request& req,
94cb13a392SEd Tanous                  const std::vector<std::string>&) override
95e5aaf047SAppaRao Puli     {
96e5aaf047SAppaRao Puli 
97e5aaf047SAppaRao Puli         std::optional<bool> serviceEnabled;
98e5aaf047SAppaRao Puli         std::optional<uint32_t> retryAttemps;
99e5aaf047SAppaRao Puli         std::optional<uint32_t> retryInterval;
100e5aaf047SAppaRao Puli 
101*8d1b46d7Szhanghch05         if (!json_util::readJson(req, asyncResp->res, "ServiceEnabled",
102*8d1b46d7Szhanghch05                                  serviceEnabled, "DeliveryRetryAttempts",
103*8d1b46d7Szhanghch05                                  retryAttemps, "DeliveryRetryIntervalSeconds",
104*8d1b46d7Szhanghch05                                  retryInterval))
105e5aaf047SAppaRao Puli         {
106e5aaf047SAppaRao Puli             return;
107e5aaf047SAppaRao Puli         }
108e5aaf047SAppaRao Puli 
1097d1cc387SAppaRao Puli         auto [enabled, retryCount, retryTimeoutInterval] =
1107d1cc387SAppaRao Puli             EventServiceManager::getInstance().getEventServiceConfig();
1117d1cc387SAppaRao Puli 
112e5aaf047SAppaRao Puli         if (serviceEnabled)
113e5aaf047SAppaRao Puli         {
1147d1cc387SAppaRao Puli             enabled = *serviceEnabled;
115e5aaf047SAppaRao Puli         }
116e5aaf047SAppaRao Puli 
117e5aaf047SAppaRao Puli         if (retryAttemps)
118e5aaf047SAppaRao Puli         {
119e5aaf047SAppaRao Puli             // Supported range [1-3]
120e5aaf047SAppaRao Puli             if ((*retryAttemps < 1) || (*retryAttemps > 3))
121e5aaf047SAppaRao Puli             {
122e5aaf047SAppaRao Puli                 messages::queryParameterOutOfRange(
123e5aaf047SAppaRao Puli                     asyncResp->res, std::to_string(*retryAttemps),
124e5aaf047SAppaRao Puli                     "DeliveryRetryAttempts", "[1-3]");
125e5aaf047SAppaRao Puli             }
126e5aaf047SAppaRao Puli             else
127e5aaf047SAppaRao Puli             {
1287d1cc387SAppaRao Puli                 retryCount = *retryAttemps;
129e5aaf047SAppaRao Puli             }
130e5aaf047SAppaRao Puli         }
131e5aaf047SAppaRao Puli 
132e5aaf047SAppaRao Puli         if (retryInterval)
133e5aaf047SAppaRao Puli         {
134e5aaf047SAppaRao Puli             // Supported range [30 - 180]
135e5aaf047SAppaRao Puli             if ((*retryInterval < 30) || (*retryInterval > 180))
136e5aaf047SAppaRao Puli             {
137e5aaf047SAppaRao Puli                 messages::queryParameterOutOfRange(
138e5aaf047SAppaRao Puli                     asyncResp->res, std::to_string(*retryInterval),
139e5aaf047SAppaRao Puli                     "DeliveryRetryIntervalSeconds", "[30-180]");
140e5aaf047SAppaRao Puli             }
141e5aaf047SAppaRao Puli             else
142e5aaf047SAppaRao Puli             {
1437d1cc387SAppaRao Puli                 retryTimeoutInterval = *retryInterval;
144e5aaf047SAppaRao Puli             }
145e5aaf047SAppaRao Puli         }
146e5aaf047SAppaRao Puli 
1477d1cc387SAppaRao Puli         EventServiceManager::getInstance().setEventServiceConfig(
1487d1cc387SAppaRao Puli             std::make_tuple(enabled, retryCount, retryTimeoutInterval));
149e5aaf047SAppaRao Puli     }
150e5aaf047SAppaRao Puli };
151e5aaf047SAppaRao Puli 
1520b4bdd93SAppaRao Puli class SubmitTestEvent : public Node
1530b4bdd93SAppaRao Puli {
1540b4bdd93SAppaRao Puli   public:
15552cc112dSEd Tanous     SubmitTestEvent(App& app) :
1560b4bdd93SAppaRao Puli         Node(app,
1570b4bdd93SAppaRao Puli              "/redfish/v1/EventService/Actions/EventService.SubmitTestEvent/")
1580b4bdd93SAppaRao Puli     {
1590b4bdd93SAppaRao Puli         entityPrivileges = {
1600b4bdd93SAppaRao Puli             {boost::beast::http::verb::get, {{"Login"}}},
1610b4bdd93SAppaRao Puli             {boost::beast::http::verb::head, {{"Login"}}},
1620b4bdd93SAppaRao Puli             {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
1630b4bdd93SAppaRao Puli             {boost::beast::http::verb::put, {{"ConfigureManager"}}},
1640b4bdd93SAppaRao Puli             {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
1650b4bdd93SAppaRao Puli             {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
1660b4bdd93SAppaRao Puli     }
1670b4bdd93SAppaRao Puli 
1680b4bdd93SAppaRao Puli   private:
169*8d1b46d7Szhanghch05     void doPost(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
170*8d1b46d7Szhanghch05                 const crow::Request&, const std::vector<std::string>&) override
1710b4bdd93SAppaRao Puli     {
1720b4bdd93SAppaRao Puli         EventServiceManager::getInstance().sendTestEventLog();
173*8d1b46d7Szhanghch05         asyncResp->res.result(boost::beast::http::status::no_content);
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:
193*8d1b46d7Szhanghch05     void doGet(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
194*8d1b46d7Szhanghch05                const crow::Request&, const std::vector<std::string>&) override
195e5aaf047SAppaRao Puli     {
196e5aaf047SAppaRao Puli 
197*8d1b46d7Szhanghch05         asyncResp->res.jsonValue = {
198e5aaf047SAppaRao Puli             {"@odata.type",
199e5aaf047SAppaRao Puli              "#EventDestinationCollection.EventDestinationCollection"},
200e5aaf047SAppaRao Puli             {"@odata.id", "/redfish/v1/EventService/Subscriptions"},
201e5aaf047SAppaRao Puli             {"Name", "Event Destination Collections"}};
202e5aaf047SAppaRao Puli 
203e5aaf047SAppaRao Puli         nlohmann::json& memberArray = asyncResp->res.jsonValue["Members"];
204e5aaf047SAppaRao Puli 
205b52664e2SAppaRao Puli         std::vector<std::string> subscripIds =
206b52664e2SAppaRao Puli             EventServiceManager::getInstance().getAllIDs();
207b52664e2SAppaRao Puli         memberArray = nlohmann::json::array();
208b52664e2SAppaRao Puli         asyncResp->res.jsonValue["Members@odata.count"] = subscripIds.size();
209b52664e2SAppaRao Puli 
210b52664e2SAppaRao Puli         for (const std::string& id : subscripIds)
211e5aaf047SAppaRao Puli         {
212e5aaf047SAppaRao Puli             memberArray.push_back(
213e5aaf047SAppaRao Puli                 {{"@odata.id",
214b52664e2SAppaRao Puli                   "/redfish/v1/EventService/Subscriptions/" + id}});
215e5aaf047SAppaRao Puli         }
216e5aaf047SAppaRao Puli     }
217e5aaf047SAppaRao Puli 
218*8d1b46d7Szhanghch05     void doPost(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
219*8d1b46d7Szhanghch05                 const crow::Request& req,
220cb13a392SEd Tanous                 const std::vector<std::string>&) override
221e5aaf047SAppaRao Puli     {
222e5aaf047SAppaRao Puli 
223b52664e2SAppaRao Puli         if (EventServiceManager::getInstance().getNumberOfSubscriptions() >=
224b52664e2SAppaRao Puli             maxNoOfSubscriptions)
225e5aaf047SAppaRao Puli         {
226e5aaf047SAppaRao Puli             messages::eventSubscriptionLimitExceeded(asyncResp->res);
227e5aaf047SAppaRao Puli             return;
228e5aaf047SAppaRao Puli         }
229e5aaf047SAppaRao Puli         std::string destUrl;
230e5aaf047SAppaRao Puli         std::string protocol;
231e5aaf047SAppaRao Puli         std::optional<std::string> context;
232e5aaf047SAppaRao Puli         std::optional<std::string> subscriptionType;
23323a21a1cSEd Tanous         std::optional<std::string> eventFormatType2;
234e5aaf047SAppaRao Puli         std::optional<std::string> retryPolicy;
235e5aaf047SAppaRao Puli         std::optional<std::vector<std::string>> msgIds;
236e5aaf047SAppaRao Puli         std::optional<std::vector<std::string>> regPrefixes;
237e56f254cSSunitha Harish         std::optional<std::vector<std::string>> resTypes;
238e5aaf047SAppaRao Puli         std::optional<std::vector<nlohmann::json>> headers;
239144b6318SAppaRao Puli         std::optional<std::vector<nlohmann::json>> mrdJsonArray;
240e5aaf047SAppaRao Puli 
241e5aaf047SAppaRao Puli         if (!json_util::readJson(
242*8d1b46d7Szhanghch05                 req, asyncResp->res, "Destination", destUrl, "Context", context,
243e5aaf047SAppaRao Puli                 "Protocol", protocol, "SubscriptionType", subscriptionType,
24423a21a1cSEd Tanous                 "EventFormatType", eventFormatType2, "HttpHeaders", headers,
245e5aaf047SAppaRao Puli                 "RegistryPrefixes", regPrefixes, "MessageIds", msgIds,
246156d6b00SAppaRao Puli                 "DeliveryRetryPolicy", retryPolicy, "MetricReportDefinitions",
247144b6318SAppaRao Puli                 mrdJsonArray, "ResourceTypes", resTypes))
248e5aaf047SAppaRao Puli         {
249e5aaf047SAppaRao Puli             return;
250e5aaf047SAppaRao Puli         }
251e5aaf047SAppaRao Puli 
252dd28ba82SAppaRao Puli         if (regPrefixes && msgIds)
253dd28ba82SAppaRao Puli         {
254dd28ba82SAppaRao Puli             if (regPrefixes->size() && msgIds->size())
255dd28ba82SAppaRao Puli             {
256dd28ba82SAppaRao Puli                 messages::mutualExclusiveProperties(
257dd28ba82SAppaRao Puli                     asyncResp->res, "RegistryPrefixes", "MessageIds");
258dd28ba82SAppaRao Puli                 return;
259dd28ba82SAppaRao Puli             }
260dd28ba82SAppaRao Puli         }
261dd28ba82SAppaRao Puli 
262e5aaf047SAppaRao Puli         // Validate the URL using regex expression
263b52664e2SAppaRao Puli         // Format: <protocol>://<host>:<port>/<uri>
264b52664e2SAppaRao Puli         // protocol: http/https
265b52664e2SAppaRao Puli         // host: Exclude ' ', ':', '#', '?'
2664e0453b1SGunnar Mills         // port: Empty or numeric value with ':' separator.
267b52664e2SAppaRao Puli         // uri: Start with '/' and Exclude '#', ' '
268b52664e2SAppaRao Puli         //      Can include query params(ex: '/event?test=1')
269b52664e2SAppaRao Puli         // TODO: Need to validate hostname extensively(as per rfc)
270b52664e2SAppaRao Puli         const std::regex urlRegex(
271b52664e2SAppaRao Puli             "(http|https)://([^/\\x20\\x3f\\x23\\x3a]+):?([0-9]*)(/"
272b52664e2SAppaRao Puli             "([^\\x20\\x23\\x3f]*\\x3f?([^\\x20\\x23\\x3f])*)?)");
273b52664e2SAppaRao Puli         std::cmatch match;
274b52664e2SAppaRao Puli         if (!std::regex_match(destUrl.c_str(), match, urlRegex))
275e5aaf047SAppaRao Puli         {
276e5aaf047SAppaRao Puli             messages::propertyValueFormatError(asyncResp->res, destUrl,
277e5aaf047SAppaRao Puli                                                "Destination");
278e5aaf047SAppaRao Puli             return;
279e5aaf047SAppaRao Puli         }
280b52664e2SAppaRao Puli 
281b52664e2SAppaRao Puli         std::string uriProto = std::string(match[1].first, match[1].second);
282b52664e2SAppaRao Puli         if (uriProto == "http")
283b52664e2SAppaRao Puli         {
284b52664e2SAppaRao Puli #ifndef BMCWEB_INSECURE_ENABLE_HTTP_PUSH_STYLE_EVENTING
285b52664e2SAppaRao Puli             messages::propertyValueFormatError(asyncResp->res, destUrl,
286b52664e2SAppaRao Puli                                                "Destination");
287b52664e2SAppaRao Puli             return;
288b52664e2SAppaRao Puli #endif
289b52664e2SAppaRao Puli         }
290b52664e2SAppaRao Puli 
291b52664e2SAppaRao Puli         std::string host = std::string(match[2].first, match[2].second);
292b52664e2SAppaRao Puli         std::string port = std::string(match[3].first, match[3].second);
293b52664e2SAppaRao Puli         std::string path = std::string(match[4].first, match[4].second);
294b52664e2SAppaRao Puli         if (port.empty())
295b52664e2SAppaRao Puli         {
296b52664e2SAppaRao Puli             if (uriProto == "http")
297b52664e2SAppaRao Puli             {
298b52664e2SAppaRao Puli                 port = "80";
299b52664e2SAppaRao Puli             }
300b52664e2SAppaRao Puli             else
301b52664e2SAppaRao Puli             {
302b52664e2SAppaRao Puli                 port = "443";
303b52664e2SAppaRao Puli             }
304b52664e2SAppaRao Puli         }
305b52664e2SAppaRao Puli         if (path.empty())
306b52664e2SAppaRao Puli         {
307b52664e2SAppaRao Puli             path = "/";
308b52664e2SAppaRao Puli         }
309b52664e2SAppaRao Puli 
310b52664e2SAppaRao Puli         std::shared_ptr<Subscription> subValue =
311b52664e2SAppaRao Puli             std::make_shared<Subscription>(host, port, path, uriProto);
312b52664e2SAppaRao Puli 
313b52664e2SAppaRao Puli         subValue->destinationUrl = destUrl;
314e5aaf047SAppaRao Puli 
315e5aaf047SAppaRao Puli         if (subscriptionType)
316e5aaf047SAppaRao Puli         {
317e5aaf047SAppaRao Puli             if (*subscriptionType != "RedfishEvent")
318e5aaf047SAppaRao Puli             {
319e5aaf047SAppaRao Puli                 messages::propertyValueNotInList(
320e5aaf047SAppaRao Puli                     asyncResp->res, *subscriptionType, "SubscriptionType");
321e5aaf047SAppaRao Puli                 return;
322e5aaf047SAppaRao Puli             }
323b52664e2SAppaRao Puli             subValue->subscriptionType = *subscriptionType;
324e5aaf047SAppaRao Puli         }
325e5aaf047SAppaRao Puli         else
326e5aaf047SAppaRao Puli         {
327b52664e2SAppaRao Puli             subValue->subscriptionType = "RedfishEvent"; // Default
328e5aaf047SAppaRao Puli         }
329e5aaf047SAppaRao Puli 
330e5aaf047SAppaRao Puli         if (protocol != "Redfish")
331e5aaf047SAppaRao Puli         {
332e5aaf047SAppaRao Puli             messages::propertyValueNotInList(asyncResp->res, protocol,
333e5aaf047SAppaRao Puli                                              "Protocol");
334e5aaf047SAppaRao Puli             return;
335e5aaf047SAppaRao Puli         }
336b52664e2SAppaRao Puli         subValue->protocol = protocol;
337e5aaf047SAppaRao Puli 
33823a21a1cSEd Tanous         if (eventFormatType2)
339e5aaf047SAppaRao Puli         {
340e5aaf047SAppaRao Puli             if (std::find(supportedEvtFormatTypes.begin(),
341e5aaf047SAppaRao Puli                           supportedEvtFormatTypes.end(),
34223a21a1cSEd Tanous                           *eventFormatType2) == supportedEvtFormatTypes.end())
343e5aaf047SAppaRao Puli             {
344e5aaf047SAppaRao Puli                 messages::propertyValueNotInList(
34523a21a1cSEd Tanous                     asyncResp->res, *eventFormatType2, "EventFormatType");
346e5aaf047SAppaRao Puli                 return;
347e5aaf047SAppaRao Puli             }
34823a21a1cSEd Tanous             subValue->eventFormatType = *eventFormatType2;
349e5aaf047SAppaRao Puli         }
350e5aaf047SAppaRao Puli         else
351e5aaf047SAppaRao Puli         {
352e5aaf047SAppaRao Puli             // If not specified, use default "Event"
35323a21a1cSEd Tanous             subValue->eventFormatType = "Event";
354e5aaf047SAppaRao Puli         }
355e5aaf047SAppaRao Puli 
356e5aaf047SAppaRao Puli         if (context)
357e5aaf047SAppaRao Puli         {
358b52664e2SAppaRao Puli             subValue->customText = *context;
359e5aaf047SAppaRao Puli         }
360e5aaf047SAppaRao Puli 
361e5aaf047SAppaRao Puli         if (headers)
362e5aaf047SAppaRao Puli         {
363b52664e2SAppaRao Puli             subValue->httpHeaders = *headers;
364e5aaf047SAppaRao Puli         }
365e5aaf047SAppaRao Puli 
366e5aaf047SAppaRao Puli         if (regPrefixes)
367e5aaf047SAppaRao Puli         {
368e5aaf047SAppaRao Puli             for (const std::string& it : *regPrefixes)
369e5aaf047SAppaRao Puli             {
370e5aaf047SAppaRao Puli                 if (std::find(supportedRegPrefixes.begin(),
371e5aaf047SAppaRao Puli                               supportedRegPrefixes.end(),
372e5aaf047SAppaRao Puli                               it) == supportedRegPrefixes.end())
373e5aaf047SAppaRao Puli                 {
374e5aaf047SAppaRao Puli                     messages::propertyValueNotInList(asyncResp->res, it,
375e5aaf047SAppaRao Puli                                                      "RegistryPrefixes");
376e5aaf047SAppaRao Puli                     return;
377e5aaf047SAppaRao Puli                 }
378e5aaf047SAppaRao Puli             }
379b52664e2SAppaRao Puli             subValue->registryPrefixes = *regPrefixes;
380e5aaf047SAppaRao Puli         }
381e5aaf047SAppaRao Puli 
382e56f254cSSunitha Harish         if (resTypes)
383e56f254cSSunitha Harish         {
384e56f254cSSunitha Harish             for (const std::string& it : *resTypes)
385e56f254cSSunitha Harish             {
386e56f254cSSunitha Harish                 if (std::find(supportedResourceTypes.begin(),
387e56f254cSSunitha Harish                               supportedResourceTypes.end(),
388e56f254cSSunitha Harish                               it) == supportedResourceTypes.end())
389e56f254cSSunitha Harish                 {
390e56f254cSSunitha Harish                     messages::propertyValueNotInList(asyncResp->res, it,
391e56f254cSSunitha Harish                                                      "ResourceTypes");
392e56f254cSSunitha Harish                     return;
393e56f254cSSunitha Harish                 }
394e56f254cSSunitha Harish             }
395e56f254cSSunitha Harish             subValue->resourceTypes = *resTypes;
396e56f254cSSunitha Harish         }
397e56f254cSSunitha Harish 
398e5aaf047SAppaRao Puli         if (msgIds)
399e5aaf047SAppaRao Puli         {
400e5aaf047SAppaRao Puli             // Do we need to loop-up MessageRegistry and validate
401e5aaf047SAppaRao Puli             // data for authenticity??? Not mandate, i believe.
402b52664e2SAppaRao Puli             subValue->registryMsgIds = *msgIds;
403e5aaf047SAppaRao Puli         }
404e5aaf047SAppaRao Puli 
405e5aaf047SAppaRao Puli         if (retryPolicy)
406e5aaf047SAppaRao Puli         {
407e5aaf047SAppaRao Puli             if (std::find(supportedRetryPolicies.begin(),
408e5aaf047SAppaRao Puli                           supportedRetryPolicies.end(),
409e5aaf047SAppaRao Puli                           *retryPolicy) == supportedRetryPolicies.end())
410e5aaf047SAppaRao Puli             {
411e5aaf047SAppaRao Puli                 messages::propertyValueNotInList(asyncResp->res, *retryPolicy,
412e5aaf047SAppaRao Puli                                                  "DeliveryRetryPolicy");
413e5aaf047SAppaRao Puli                 return;
414e5aaf047SAppaRao Puli             }
415b52664e2SAppaRao Puli             subValue->retryPolicy = *retryPolicy;
416e5aaf047SAppaRao Puli         }
417e5aaf047SAppaRao Puli         else
418e5aaf047SAppaRao Puli         {
419e5aaf047SAppaRao Puli             // Default "TerminateAfterRetries"
420b52664e2SAppaRao Puli             subValue->retryPolicy = "TerminateAfterRetries";
421e5aaf047SAppaRao Puli         }
422e5aaf047SAppaRao Puli 
423144b6318SAppaRao Puli         if (mrdJsonArray)
424156d6b00SAppaRao Puli         {
425144b6318SAppaRao Puli             for (nlohmann::json& mrdObj : *mrdJsonArray)
426144b6318SAppaRao Puli             {
427144b6318SAppaRao Puli                 std::string mrdUri;
428144b6318SAppaRao Puli                 if (json_util::getValueFromJsonObject(mrdObj, "@odata.id",
429144b6318SAppaRao Puli                                                       mrdUri))
430144b6318SAppaRao Puli                 {
431144b6318SAppaRao Puli                     subValue->metricReportDefinitions.emplace_back(mrdUri);
432144b6318SAppaRao Puli                 }
433144b6318SAppaRao Puli                 else
434144b6318SAppaRao Puli                 {
435144b6318SAppaRao Puli                     messages::propertyValueFormatError(
43671f52d96SEd Tanous                         asyncResp->res,
43771f52d96SEd Tanous                         mrdObj.dump(2, ' ', true,
43871f52d96SEd Tanous                                     nlohmann::json::error_handler_t::replace),
439144b6318SAppaRao Puli                         "MetricReportDefinitions");
440144b6318SAppaRao Puli                     return;
441144b6318SAppaRao Puli                 }
442144b6318SAppaRao Puli             }
443156d6b00SAppaRao Puli         }
444156d6b00SAppaRao Puli 
445b52664e2SAppaRao Puli         std::string id =
446b52664e2SAppaRao Puli             EventServiceManager::getInstance().addSubscription(subValue);
447b52664e2SAppaRao Puli         if (id.empty())
448e5aaf047SAppaRao Puli         {
449e5aaf047SAppaRao Puli             messages::internalError(asyncResp->res);
450e5aaf047SAppaRao Puli             return;
451e5aaf047SAppaRao Puli         }
452e5aaf047SAppaRao Puli 
453e5aaf047SAppaRao Puli         messages::created(asyncResp->res);
454e5aaf047SAppaRao Puli         asyncResp->res.addHeader(
455e5aaf047SAppaRao Puli             "Location", "/redfish/v1/EventService/Subscriptions/" + id);
456e5aaf047SAppaRao Puli     }
457e5aaf047SAppaRao Puli };
458e5aaf047SAppaRao Puli 
459e5aaf047SAppaRao Puli class EventDestination : public Node
460e5aaf047SAppaRao Puli {
461e5aaf047SAppaRao Puli   public:
46252cc112dSEd Tanous     EventDestination(App& app) :
463e5aaf047SAppaRao Puli         Node(app, "/redfish/v1/EventService/Subscriptions/<str>/",
464e5aaf047SAppaRao Puli              std::string())
465e5aaf047SAppaRao Puli     {
466e5aaf047SAppaRao Puli         entityPrivileges = {
467e5aaf047SAppaRao Puli             {boost::beast::http::verb::get, {{"Login"}}},
468e5aaf047SAppaRao Puli             {boost::beast::http::verb::head, {{"Login"}}},
469e5aaf047SAppaRao Puli             {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
470e5aaf047SAppaRao Puli             {boost::beast::http::verb::put, {{"ConfigureManager"}}},
471e5aaf047SAppaRao Puli             {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
472e5aaf047SAppaRao Puli             {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
473e5aaf047SAppaRao Puli     }
474e5aaf047SAppaRao Puli 
475e5aaf047SAppaRao Puli   private:
476*8d1b46d7Szhanghch05     void doGet(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
477*8d1b46d7Szhanghch05                const crow::Request&,
478e5aaf047SAppaRao Puli                const std::vector<std::string>& params) override
479e5aaf047SAppaRao Puli     {
480*8d1b46d7Szhanghch05 
481e5aaf047SAppaRao Puli         if (params.size() != 1)
482e5aaf047SAppaRao Puli         {
483e5aaf047SAppaRao Puli             messages::internalError(asyncResp->res);
484e5aaf047SAppaRao Puli             return;
485e5aaf047SAppaRao Puli         }
486e5aaf047SAppaRao Puli 
487b52664e2SAppaRao Puli         std::shared_ptr<Subscription> subValue =
488b52664e2SAppaRao Puli             EventServiceManager::getInstance().getSubscription(params[0]);
489b52664e2SAppaRao Puli         if (subValue == nullptr)
490e5aaf047SAppaRao Puli         {
491*8d1b46d7Szhanghch05             asyncResp->res.result(boost::beast::http::status::not_found);
492e5aaf047SAppaRao Puli             return;
493e5aaf047SAppaRao Puli         }
494b52664e2SAppaRao Puli         const std::string& id = params[0];
495e5aaf047SAppaRao Puli 
496*8d1b46d7Szhanghch05         asyncResp->res.jsonValue = {
497e5aaf047SAppaRao Puli             {"@odata.type", "#EventDestination.v1_7_0.EventDestination"},
498e5aaf047SAppaRao Puli             {"Protocol", "Redfish"}};
499e5aaf047SAppaRao Puli         asyncResp->res.jsonValue["@odata.id"] =
500e5aaf047SAppaRao Puli             "/redfish/v1/EventService/Subscriptions/" + id;
501e5aaf047SAppaRao Puli         asyncResp->res.jsonValue["Id"] = id;
502e5aaf047SAppaRao Puli         asyncResp->res.jsonValue["Name"] = "Event Destination " + id;
503b52664e2SAppaRao Puli         asyncResp->res.jsonValue["Destination"] = subValue->destinationUrl;
504b52664e2SAppaRao Puli         asyncResp->res.jsonValue["Context"] = subValue->customText;
505e5aaf047SAppaRao Puli         asyncResp->res.jsonValue["SubscriptionType"] =
506b52664e2SAppaRao Puli             subValue->subscriptionType;
507b52664e2SAppaRao Puli         asyncResp->res.jsonValue["HttpHeaders"] = subValue->httpHeaders;
508b52664e2SAppaRao Puli         asyncResp->res.jsonValue["EventFormatType"] = subValue->eventFormatType;
509e5aaf047SAppaRao Puli         asyncResp->res.jsonValue["RegistryPrefixes"] =
510b52664e2SAppaRao Puli             subValue->registryPrefixes;
511e56f254cSSunitha Harish         asyncResp->res.jsonValue["ResourceTypes"] = subValue->resourceTypes;
512e56f254cSSunitha Harish 
513b52664e2SAppaRao Puli         asyncResp->res.jsonValue["MessageIds"] = subValue->registryMsgIds;
514b52664e2SAppaRao Puli         asyncResp->res.jsonValue["DeliveryRetryPolicy"] = subValue->retryPolicy;
515144b6318SAppaRao Puli 
516144b6318SAppaRao Puli         std::vector<nlohmann::json> mrdJsonArray;
517144b6318SAppaRao Puli         for (const auto& mdrUri : subValue->metricReportDefinitions)
518144b6318SAppaRao Puli         {
519144b6318SAppaRao Puli             mrdJsonArray.push_back({{"@odata.id", mdrUri}});
520144b6318SAppaRao Puli         }
521144b6318SAppaRao Puli         asyncResp->res.jsonValue["MetricReportDefinitions"] = mrdJsonArray;
522e5aaf047SAppaRao Puli     }
523e5aaf047SAppaRao Puli 
524*8d1b46d7Szhanghch05     void doPatch(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
525*8d1b46d7Szhanghch05                  const crow::Request& req,
526e5aaf047SAppaRao Puli                  const std::vector<std::string>& params) override
527e5aaf047SAppaRao Puli     {
528*8d1b46d7Szhanghch05 
529e5aaf047SAppaRao Puli         if (params.size() != 1)
530e5aaf047SAppaRao Puli         {
531e5aaf047SAppaRao Puli             messages::internalError(asyncResp->res);
532e5aaf047SAppaRao Puli             return;
533e5aaf047SAppaRao Puli         }
534e5aaf047SAppaRao Puli 
535b52664e2SAppaRao Puli         std::shared_ptr<Subscription> subValue =
536b52664e2SAppaRao Puli             EventServiceManager::getInstance().getSubscription(params[0]);
537b52664e2SAppaRao Puli         if (subValue == nullptr)
538e5aaf047SAppaRao Puli         {
539*8d1b46d7Szhanghch05             asyncResp->res.result(boost::beast::http::status::not_found);
540e5aaf047SAppaRao Puli             return;
541e5aaf047SAppaRao Puli         }
542e5aaf047SAppaRao Puli 
543e5aaf047SAppaRao Puli         std::optional<std::string> context;
544e5aaf047SAppaRao Puli         std::optional<std::string> retryPolicy;
545e5aaf047SAppaRao Puli         std::optional<std::vector<nlohmann::json>> headers;
546e5aaf047SAppaRao Puli 
547*8d1b46d7Szhanghch05         if (!json_util::readJson(req, asyncResp->res, "Context", context,
548e5aaf047SAppaRao Puli                                  "DeliveryRetryPolicy", retryPolicy,
549e5aaf047SAppaRao Puli                                  "HttpHeaders", headers))
550e5aaf047SAppaRao Puli         {
551e5aaf047SAppaRao Puli             return;
552e5aaf047SAppaRao Puli         }
553e5aaf047SAppaRao Puli 
554e5aaf047SAppaRao Puli         if (context)
555e5aaf047SAppaRao Puli         {
556b52664e2SAppaRao Puli             subValue->customText = *context;
557e5aaf047SAppaRao Puli         }
558e5aaf047SAppaRao Puli 
559e5aaf047SAppaRao Puli         if (headers)
560e5aaf047SAppaRao Puli         {
561b52664e2SAppaRao Puli             subValue->httpHeaders = *headers;
562e5aaf047SAppaRao Puli         }
563e5aaf047SAppaRao Puli 
564e5aaf047SAppaRao Puli         if (retryPolicy)
565e5aaf047SAppaRao Puli         {
566e5aaf047SAppaRao Puli             if (std::find(supportedRetryPolicies.begin(),
567e5aaf047SAppaRao Puli                           supportedRetryPolicies.end(),
568e5aaf047SAppaRao Puli                           *retryPolicy) == supportedRetryPolicies.end())
569e5aaf047SAppaRao Puli             {
570e5aaf047SAppaRao Puli                 messages::propertyValueNotInList(asyncResp->res, *retryPolicy,
571e5aaf047SAppaRao Puli                                                  "DeliveryRetryPolicy");
572e5aaf047SAppaRao Puli                 return;
573e5aaf047SAppaRao Puli             }
574b52664e2SAppaRao Puli             subValue->retryPolicy = *retryPolicy;
575fe44eb0bSAyushi Smriti             subValue->updateRetryPolicy();
576e5aaf047SAppaRao Puli         }
577e5aaf047SAppaRao Puli 
578b52664e2SAppaRao Puli         EventServiceManager::getInstance().updateSubscriptionData();
579e5aaf047SAppaRao Puli     }
580e5aaf047SAppaRao Puli 
581*8d1b46d7Szhanghch05     void doDelete(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
582*8d1b46d7Szhanghch05                   const crow::Request&,
583e5aaf047SAppaRao Puli                   const std::vector<std::string>& params) override
584e5aaf047SAppaRao Puli     {
585e5aaf047SAppaRao Puli 
586e5aaf047SAppaRao Puli         if (params.size() != 1)
587e5aaf047SAppaRao Puli         {
588e5aaf047SAppaRao Puli             messages::internalError(asyncResp->res);
589e5aaf047SAppaRao Puli             return;
590e5aaf047SAppaRao Puli         }
591e5aaf047SAppaRao Puli 
592b52664e2SAppaRao Puli         if (!EventServiceManager::getInstance().isSubscriptionExist(params[0]))
593e5aaf047SAppaRao Puli         {
594*8d1b46d7Szhanghch05             asyncResp->res.result(boost::beast::http::status::not_found);
595e5aaf047SAppaRao Puli             return;
596e5aaf047SAppaRao Puli         }
597b52664e2SAppaRao Puli         EventServiceManager::getInstance().deleteSubscription(params[0]);
598e5aaf047SAppaRao Puli     }
599e5aaf047SAppaRao Puli };
600e5aaf047SAppaRao Puli 
601e5aaf047SAppaRao Puli } // namespace redfish
602