xref: /openbmc/bmcweb/features/redfish/lib/event_service.hpp (revision 28afb49c480790e763b8491be0b5a8e35964dbc9)
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 
197e860f15SJohn Edward Broadbent #include <app.hpp>
20ed398213SEd Tanous #include <registries/privilege_registry.hpp>
21ed398213SEd Tanous 
22e5aaf047SAppaRao Puli namespace redfish
23e5aaf047SAppaRao Puli {
24e5aaf047SAppaRao Puli 
25156d6b00SAppaRao Puli static constexpr const std::array<const char*, 2> supportedEvtFormatTypes = {
26156d6b00SAppaRao Puli     eventFormatType, metricReportFormatType};
27e5aaf047SAppaRao Puli static constexpr const std::array<const char*, 3> supportedRegPrefixes = {
28b304bd79SP Dheeraj Srujan Kumar     "Base", "OpenBMC", "TaskEvent"};
29e5aaf047SAppaRao Puli static constexpr const std::array<const char*, 3> supportedRetryPolicies = {
30e5aaf047SAppaRao Puli     "TerminateAfterRetries", "SuspendRetries", "RetryForever"};
31e5aaf047SAppaRao Puli 
32e56f254cSSunitha Harish #ifdef BMCWEB_ENABLE_IBM_MANAGEMENT_CONSOLE
33e56f254cSSunitha Harish static constexpr const std::array<const char*, 2> supportedResourceTypes = {
34e56f254cSSunitha Harish     "IBMConfigFile", "Task"};
35e56f254cSSunitha Harish #else
36e56f254cSSunitha Harish static constexpr const std::array<const char*, 1> supportedResourceTypes = {
37e56f254cSSunitha Harish     "Task"};
38e56f254cSSunitha Harish #endif
39e56f254cSSunitha Harish 
40e5aaf047SAppaRao Puli static constexpr const uint8_t maxNoOfSubscriptions = 20;
41e5aaf047SAppaRao Puli 
427e860f15SJohn Edward Broadbent inline void requestRoutesEventService(App& app)
43e5aaf047SAppaRao Puli {
447e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app, "/redfish/v1/EventService/")
45ed398213SEd Tanous         .privileges(redfish::privileges::getEventService)
467e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::get)(
477e860f15SJohn Edward Broadbent             [](const crow::Request&,
487e860f15SJohn Edward Broadbent                const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
498d1b46d7Szhanghch05                 asyncResp->res.jsonValue = {
50e5aaf047SAppaRao Puli                     {"@odata.type", "#EventService.v1_5_0.EventService"},
51e5aaf047SAppaRao Puli                     {"Id", "EventService"},
52e5aaf047SAppaRao Puli                     {"Name", "Event Service"},
53e5aaf047SAppaRao Puli                     {"Subscriptions",
54e5aaf047SAppaRao Puli                      {{"@odata.id", "/redfish/v1/EventService/Subscriptions"}}},
550b4bdd93SAppaRao Puli                     {"Actions",
560b4bdd93SAppaRao Puli                      {{"#EventService.SubmitTestEvent",
570b4bdd93SAppaRao Puli                        {{"target", "/redfish/v1/EventService/Actions/"
580b4bdd93SAppaRao Puli                                    "EventService.SubmitTestEvent"}}}}},
59e5aaf047SAppaRao Puli                     {"@odata.id", "/redfish/v1/EventService"}};
60e5aaf047SAppaRao Puli 
61*28afb49cSJunLin Chen                 const persistent_data::EventServiceConfig eventServiceConfig =
62*28afb49cSJunLin Chen                     persistent_data::EventServiceStore::getInstance()
63*28afb49cSJunLin Chen                         .getEventServiceConfig();
647d1cc387SAppaRao Puli 
657d1cc387SAppaRao Puli                 asyncResp->res.jsonValue["Status"]["State"] =
66*28afb49cSJunLin Chen                     (eventServiceConfig.enabled ? "Enabled" : "Disabled");
67*28afb49cSJunLin Chen                 asyncResp->res.jsonValue["ServiceEnabled"] =
68*28afb49cSJunLin Chen                     eventServiceConfig.enabled;
697e860f15SJohn Edward Broadbent                 asyncResp->res.jsonValue["DeliveryRetryAttempts"] =
70*28afb49cSJunLin Chen                     eventServiceConfig.retryAttempts;
71e5aaf047SAppaRao Puli                 asyncResp->res.jsonValue["DeliveryRetryIntervalSeconds"] =
72*28afb49cSJunLin Chen                     eventServiceConfig.retryTimeoutInterval;
737e860f15SJohn Edward Broadbent                 asyncResp->res.jsonValue["EventFormatTypes"] =
747e860f15SJohn Edward Broadbent                     supportedEvtFormatTypes;
757e860f15SJohn Edward Broadbent                 asyncResp->res.jsonValue["RegistryPrefixes"] =
767e860f15SJohn Edward Broadbent                     supportedRegPrefixes;
777e860f15SJohn Edward Broadbent                 asyncResp->res.jsonValue["ResourceTypes"] =
787e860f15SJohn Edward Broadbent                     supportedResourceTypes;
7907941a88SAyushi Smriti 
8007941a88SAyushi Smriti                 nlohmann::json supportedSSEFilters = {
8107941a88SAyushi Smriti                     {"EventFormatType", true},        {"MessageId", true},
8207941a88SAyushi Smriti                     {"MetricReportDefinition", true}, {"RegistryPrefix", true},
8307941a88SAyushi Smriti                     {"OriginResource", false},        {"ResourceType", false}};
8407941a88SAyushi Smriti 
8507941a88SAyushi Smriti                 asyncResp->res.jsonValue["SSEFilterPropertiesSupported"] =
8607941a88SAyushi Smriti                     supportedSSEFilters;
877e860f15SJohn Edward Broadbent             });
88e5aaf047SAppaRao Puli 
897e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app, "/redfish/v1/EventService/")
90ed398213SEd Tanous         .privileges(redfish::privileges::patchEventService)
917e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::patch)(
927e860f15SJohn Edward Broadbent             [](const crow::Request& req,
937e860f15SJohn Edward Broadbent                const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
947e860f15SJohn Edward Broadbent 
95e5aaf047SAppaRao Puli             {
96e5aaf047SAppaRao Puli                 std::optional<bool> serviceEnabled;
97e5aaf047SAppaRao Puli                 std::optional<uint32_t> retryAttemps;
98e5aaf047SAppaRao Puli                 std::optional<uint32_t> retryInterval;
99e5aaf047SAppaRao Puli 
1007e860f15SJohn Edward Broadbent                 if (!json_util::readJson(
1017e860f15SJohn Edward Broadbent                         req, asyncResp->res, "ServiceEnabled", serviceEnabled,
1027e860f15SJohn Edward Broadbent                         "DeliveryRetryAttempts", retryAttemps,
1037e860f15SJohn Edward Broadbent                         "DeliveryRetryIntervalSeconds", retryInterval))
104e5aaf047SAppaRao Puli                 {
105e5aaf047SAppaRao Puli                     return;
106e5aaf047SAppaRao Puli                 }
107e5aaf047SAppaRao Puli 
108*28afb49cSJunLin Chen                 persistent_data::EventServiceConfig eventServiceConfig =
109*28afb49cSJunLin Chen                     persistent_data::EventServiceStore::getInstance()
110*28afb49cSJunLin Chen                         .getEventServiceConfig();
1117d1cc387SAppaRao Puli 
112e5aaf047SAppaRao Puli                 if (serviceEnabled)
113e5aaf047SAppaRao Puli                 {
114*28afb49cSJunLin Chen                     eventServiceConfig.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                     {
128*28afb49cSJunLin Chen                         eventServiceConfig.retryAttempts = *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                     {
143*28afb49cSJunLin Chen                         eventServiceConfig.retryTimeoutInterval =
144*28afb49cSJunLin Chen                             *retryInterval;
145e5aaf047SAppaRao Puli                     }
146e5aaf047SAppaRao Puli                 }
147e5aaf047SAppaRao Puli 
1487d1cc387SAppaRao Puli                 EventServiceManager::getInstance().setEventServiceConfig(
149*28afb49cSJunLin Chen                     eventServiceConfig);
1507e860f15SJohn Edward Broadbent             });
1510b4bdd93SAppaRao Puli }
1520b4bdd93SAppaRao Puli 
1537e860f15SJohn Edward Broadbent inline void requestRoutesSubmitTestEvent(App& app)
1540b4bdd93SAppaRao Puli {
1557e860f15SJohn Edward Broadbent 
1567e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(
1577e860f15SJohn Edward Broadbent         app, "/redfish/v1/EventService/Actions/EventService.SubmitTestEvent/")
158ed398213SEd Tanous         .privileges(redfish::privileges::postEventService)
1597e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::post)(
1607e860f15SJohn Edward Broadbent             [](const crow::Request&,
1617e860f15SJohn Edward Broadbent                const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
1620b4bdd93SAppaRao Puli                 EventServiceManager::getInstance().sendTestEventLog();
1638d1b46d7Szhanghch05                 asyncResp->res.result(boost::beast::http::status::no_content);
1647e860f15SJohn Edward Broadbent             });
165e5aaf047SAppaRao Puli }
166e5aaf047SAppaRao Puli 
1677e860f15SJohn Edward Broadbent inline void requestRoutesEventDestinationCollection(App& app)
168e5aaf047SAppaRao Puli {
1697e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions")
170ed398213SEd Tanous         .privileges(redfish::privileges::getEventDestinationCollection)
1717e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::get)(
1727e860f15SJohn Edward Broadbent             [](const crow::Request&,
1737e860f15SJohn Edward Broadbent                const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
1748d1b46d7Szhanghch05                 asyncResp->res.jsonValue = {
175e5aaf047SAppaRao Puli                     {"@odata.type",
176e5aaf047SAppaRao Puli                      "#EventDestinationCollection.EventDestinationCollection"},
177e5aaf047SAppaRao Puli                     {"@odata.id", "/redfish/v1/EventService/Subscriptions"},
178e5aaf047SAppaRao Puli                     {"Name", "Event Destination Collections"}};
179e5aaf047SAppaRao Puli 
1807e860f15SJohn Edward Broadbent                 nlohmann::json& memberArray =
1817e860f15SJohn Edward Broadbent                     asyncResp->res.jsonValue["Members"];
182e5aaf047SAppaRao Puli 
183b52664e2SAppaRao Puli                 std::vector<std::string> subscripIds =
184b52664e2SAppaRao Puli                     EventServiceManager::getInstance().getAllIDs();
185b52664e2SAppaRao Puli                 memberArray = nlohmann::json::array();
1867e860f15SJohn Edward Broadbent                 asyncResp->res.jsonValue["Members@odata.count"] =
1877e860f15SJohn Edward Broadbent                     subscripIds.size();
188b52664e2SAppaRao Puli 
189b52664e2SAppaRao Puli                 for (const std::string& id : subscripIds)
190e5aaf047SAppaRao Puli                 {
191e5aaf047SAppaRao Puli                     memberArray.push_back(
192e5aaf047SAppaRao Puli                         {{"@odata.id",
193b52664e2SAppaRao Puli                           "/redfish/v1/EventService/Subscriptions/" + id}});
194e5aaf047SAppaRao Puli                 }
1957e860f15SJohn Edward Broadbent             });
1967e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/")
197ed398213SEd Tanous         // The below privilege is wrong, it should be ConfigureManager OR
198ed398213SEd Tanous         // ConfigureComponents
199ed398213SEd Tanous         //.privileges(redfish::privileges::postEventDestinationCollection)
200432a890cSEd Tanous         .privileges({{"ConfigureManager"}})
2017e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::post)(
2027e860f15SJohn Edward Broadbent             [](const crow::Request& req,
2037e860f15SJohn Edward Broadbent                const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
2047e860f15SJohn Edward Broadbent                 if (EventServiceManager::getInstance()
2057e860f15SJohn Edward Broadbent                         .getNumberOfSubscriptions() >= maxNoOfSubscriptions)
206e5aaf047SAppaRao Puli                 {
207e5aaf047SAppaRao Puli                     messages::eventSubscriptionLimitExceeded(asyncResp->res);
208e5aaf047SAppaRao Puli                     return;
209e5aaf047SAppaRao Puli                 }
210e5aaf047SAppaRao Puli                 std::string destUrl;
211e5aaf047SAppaRao Puli                 std::string protocol;
212e5aaf047SAppaRao Puli                 std::optional<std::string> context;
213e5aaf047SAppaRao Puli                 std::optional<std::string> subscriptionType;
21423a21a1cSEd Tanous                 std::optional<std::string> eventFormatType2;
215e5aaf047SAppaRao Puli                 std::optional<std::string> retryPolicy;
216e5aaf047SAppaRao Puli                 std::optional<std::vector<std::string>> msgIds;
217e5aaf047SAppaRao Puli                 std::optional<std::vector<std::string>> regPrefixes;
218e56f254cSSunitha Harish                 std::optional<std::vector<std::string>> resTypes;
219e5aaf047SAppaRao Puli                 std::optional<std::vector<nlohmann::json>> headers;
220144b6318SAppaRao Puli                 std::optional<std::vector<nlohmann::json>> mrdJsonArray;
221e5aaf047SAppaRao Puli 
222e5aaf047SAppaRao Puli                 if (!json_util::readJson(
2237e860f15SJohn Edward Broadbent                         req, asyncResp->res, "Destination", destUrl, "Context",
2247e860f15SJohn Edward Broadbent                         context, "Protocol", protocol, "SubscriptionType",
2257e860f15SJohn Edward Broadbent                         subscriptionType, "EventFormatType", eventFormatType2,
2267e860f15SJohn Edward Broadbent                         "HttpHeaders", headers, "RegistryPrefixes", regPrefixes,
2277e860f15SJohn Edward Broadbent                         "MessageIds", msgIds, "DeliveryRetryPolicy",
2287e860f15SJohn Edward Broadbent                         retryPolicy, "MetricReportDefinitions", mrdJsonArray,
2297e860f15SJohn Edward Broadbent                         "ResourceTypes", resTypes))
230e5aaf047SAppaRao Puli                 {
231e5aaf047SAppaRao Puli                     return;
232e5aaf047SAppaRao Puli                 }
233e5aaf047SAppaRao Puli 
234dd28ba82SAppaRao Puli                 if (regPrefixes && msgIds)
235dd28ba82SAppaRao Puli                 {
236dd28ba82SAppaRao Puli                     if (regPrefixes->size() && msgIds->size())
237dd28ba82SAppaRao Puli                     {
238dd28ba82SAppaRao Puli                         messages::mutualExclusiveProperties(
239dd28ba82SAppaRao Puli                             asyncResp->res, "RegistryPrefixes", "MessageIds");
240dd28ba82SAppaRao Puli                         return;
241dd28ba82SAppaRao Puli                     }
242dd28ba82SAppaRao Puli                 }
243dd28ba82SAppaRao Puli 
244e5aaf047SAppaRao Puli                 // Validate the URL using regex expression
245b52664e2SAppaRao Puli                 // Format: <protocol>://<host>:<port>/<uri>
246b52664e2SAppaRao Puli                 // protocol: http/https
247b52664e2SAppaRao Puli                 // host: Exclude ' ', ':', '#', '?'
2484e0453b1SGunnar Mills                 // port: Empty or numeric value with ':' separator.
249b52664e2SAppaRao Puli                 // uri: Start with '/' and Exclude '#', ' '
250b52664e2SAppaRao Puli                 //      Can include query params(ex: '/event?test=1')
251b52664e2SAppaRao Puli                 // TODO: Need to validate hostname extensively(as per rfc)
252b52664e2SAppaRao Puli                 const std::regex urlRegex(
253b52664e2SAppaRao Puli                     "(http|https)://([^/\\x20\\x3f\\x23\\x3a]+):?([0-9]*)(/"
254b52664e2SAppaRao Puli                     "([^\\x20\\x23\\x3f]*\\x3f?([^\\x20\\x23\\x3f])*)?)");
255b52664e2SAppaRao Puli                 std::cmatch match;
256b52664e2SAppaRao Puli                 if (!std::regex_match(destUrl.c_str(), match, urlRegex))
257e5aaf047SAppaRao Puli                 {
258e5aaf047SAppaRao Puli                     messages::propertyValueFormatError(asyncResp->res, destUrl,
259e5aaf047SAppaRao Puli                                                        "Destination");
260e5aaf047SAppaRao Puli                     return;
261e5aaf047SAppaRao Puli                 }
262b52664e2SAppaRao Puli 
2637e860f15SJohn Edward Broadbent                 std::string uriProto =
2647e860f15SJohn Edward Broadbent                     std::string(match[1].first, match[1].second);
265b52664e2SAppaRao Puli                 if (uriProto == "http")
266b52664e2SAppaRao Puli                 {
267b52664e2SAppaRao Puli #ifndef BMCWEB_INSECURE_ENABLE_HTTP_PUSH_STYLE_EVENTING
268b52664e2SAppaRao Puli                     messages::propertyValueFormatError(asyncResp->res, destUrl,
269b52664e2SAppaRao Puli                                                        "Destination");
270b52664e2SAppaRao Puli                     return;
271b52664e2SAppaRao Puli #endif
272b52664e2SAppaRao Puli                 }
273b52664e2SAppaRao Puli 
274b52664e2SAppaRao Puli                 std::string host = std::string(match[2].first, match[2].second);
275b52664e2SAppaRao Puli                 std::string port = std::string(match[3].first, match[3].second);
276b52664e2SAppaRao Puli                 std::string path = std::string(match[4].first, match[4].second);
277b52664e2SAppaRao Puli                 if (port.empty())
278b52664e2SAppaRao Puli                 {
279b52664e2SAppaRao Puli                     if (uriProto == "http")
280b52664e2SAppaRao Puli                     {
281b52664e2SAppaRao Puli                         port = "80";
282b52664e2SAppaRao Puli                     }
283b52664e2SAppaRao Puli                     else
284b52664e2SAppaRao Puli                     {
285b52664e2SAppaRao Puli                         port = "443";
286b52664e2SAppaRao Puli                     }
287b52664e2SAppaRao Puli                 }
288b52664e2SAppaRao Puli                 if (path.empty())
289b52664e2SAppaRao Puli                 {
290b52664e2SAppaRao Puli                     path = "/";
291b52664e2SAppaRao Puli                 }
292b52664e2SAppaRao Puli 
293b52664e2SAppaRao Puli                 std::shared_ptr<Subscription> subValue =
294b52664e2SAppaRao Puli                     std::make_shared<Subscription>(host, port, path, uriProto);
295b52664e2SAppaRao Puli 
296b52664e2SAppaRao Puli                 subValue->destinationUrl = destUrl;
297e5aaf047SAppaRao Puli 
298e5aaf047SAppaRao Puli                 if (subscriptionType)
299e5aaf047SAppaRao Puli                 {
300e5aaf047SAppaRao Puli                     if (*subscriptionType != "RedfishEvent")
301e5aaf047SAppaRao Puli                     {
3027e860f15SJohn Edward Broadbent                         messages::propertyValueNotInList(asyncResp->res,
3037e860f15SJohn Edward Broadbent                                                          *subscriptionType,
3047e860f15SJohn Edward Broadbent                                                          "SubscriptionType");
305e5aaf047SAppaRao Puli                         return;
306e5aaf047SAppaRao Puli                     }
307b52664e2SAppaRao Puli                     subValue->subscriptionType = *subscriptionType;
308e5aaf047SAppaRao Puli                 }
309e5aaf047SAppaRao Puli                 else
310e5aaf047SAppaRao Puli                 {
311b52664e2SAppaRao Puli                     subValue->subscriptionType = "RedfishEvent"; // Default
312e5aaf047SAppaRao Puli                 }
313e5aaf047SAppaRao Puli 
314e5aaf047SAppaRao Puli                 if (protocol != "Redfish")
315e5aaf047SAppaRao Puli                 {
316e5aaf047SAppaRao Puli                     messages::propertyValueNotInList(asyncResp->res, protocol,
317e5aaf047SAppaRao Puli                                                      "Protocol");
318e5aaf047SAppaRao Puli                     return;
319e5aaf047SAppaRao Puli                 }
320b52664e2SAppaRao Puli                 subValue->protocol = protocol;
321e5aaf047SAppaRao Puli 
32223a21a1cSEd Tanous                 if (eventFormatType2)
323e5aaf047SAppaRao Puli                 {
324e5aaf047SAppaRao Puli                     if (std::find(supportedEvtFormatTypes.begin(),
325e5aaf047SAppaRao Puli                                   supportedEvtFormatTypes.end(),
3267e860f15SJohn Edward Broadbent                                   *eventFormatType2) ==
3277e860f15SJohn Edward Broadbent                         supportedEvtFormatTypes.end())
328e5aaf047SAppaRao Puli                     {
3297e860f15SJohn Edward Broadbent                         messages::propertyValueNotInList(asyncResp->res,
3307e860f15SJohn Edward Broadbent                                                          *eventFormatType2,
3317e860f15SJohn Edward Broadbent                                                          "EventFormatType");
332e5aaf047SAppaRao Puli                         return;
333e5aaf047SAppaRao Puli                     }
33423a21a1cSEd Tanous                     subValue->eventFormatType = *eventFormatType2;
335e5aaf047SAppaRao Puli                 }
336e5aaf047SAppaRao Puli                 else
337e5aaf047SAppaRao Puli                 {
338e5aaf047SAppaRao Puli                     // If not specified, use default "Event"
33923a21a1cSEd Tanous                     subValue->eventFormatType = "Event";
340e5aaf047SAppaRao Puli                 }
341e5aaf047SAppaRao Puli 
342e5aaf047SAppaRao Puli                 if (context)
343e5aaf047SAppaRao Puli                 {
344b52664e2SAppaRao Puli                     subValue->customText = *context;
345e5aaf047SAppaRao Puli                 }
346e5aaf047SAppaRao Puli 
347e5aaf047SAppaRao Puli                 if (headers)
348e5aaf047SAppaRao Puli                 {
349b52664e2SAppaRao Puli                     subValue->httpHeaders = *headers;
350e5aaf047SAppaRao Puli                 }
351e5aaf047SAppaRao Puli 
352e5aaf047SAppaRao Puli                 if (regPrefixes)
353e5aaf047SAppaRao Puli                 {
354e5aaf047SAppaRao Puli                     for (const std::string& it : *regPrefixes)
355e5aaf047SAppaRao Puli                     {
356e5aaf047SAppaRao Puli                         if (std::find(supportedRegPrefixes.begin(),
357e5aaf047SAppaRao Puli                                       supportedRegPrefixes.end(),
358e5aaf047SAppaRao Puli                                       it) == supportedRegPrefixes.end())
359e5aaf047SAppaRao Puli                         {
3607e860f15SJohn Edward Broadbent                             messages::propertyValueNotInList(
3617e860f15SJohn Edward Broadbent                                 asyncResp->res, it, "RegistryPrefixes");
362e5aaf047SAppaRao Puli                             return;
363e5aaf047SAppaRao Puli                         }
364e5aaf047SAppaRao Puli                     }
365b52664e2SAppaRao Puli                     subValue->registryPrefixes = *regPrefixes;
366e5aaf047SAppaRao Puli                 }
367e5aaf047SAppaRao Puli 
368e56f254cSSunitha Harish                 if (resTypes)
369e56f254cSSunitha Harish                 {
370e56f254cSSunitha Harish                     for (const std::string& it : *resTypes)
371e56f254cSSunitha Harish                     {
372e56f254cSSunitha Harish                         if (std::find(supportedResourceTypes.begin(),
373e56f254cSSunitha Harish                                       supportedResourceTypes.end(),
374e56f254cSSunitha Harish                                       it) == supportedResourceTypes.end())
375e56f254cSSunitha Harish                         {
376e56f254cSSunitha Harish                             messages::propertyValueNotInList(asyncResp->res, it,
377e56f254cSSunitha Harish                                                              "ResourceTypes");
378e56f254cSSunitha Harish                             return;
379e56f254cSSunitha Harish                         }
380e56f254cSSunitha Harish                     }
381e56f254cSSunitha Harish                     subValue->resourceTypes = *resTypes;
382e56f254cSSunitha Harish                 }
383e56f254cSSunitha Harish 
384e5aaf047SAppaRao Puli                 if (msgIds)
385e5aaf047SAppaRao Puli                 {
386b304bd79SP Dheeraj Srujan Kumar                     std::vector<std::string> registryPrefix;
387b304bd79SP Dheeraj Srujan Kumar 
3887e860f15SJohn Edward Broadbent                     // If no registry prefixes are mentioned, consider all
3897e860f15SJohn Edward Broadbent                     // supported prefixes
390b304bd79SP Dheeraj Srujan Kumar                     if (subValue->registryPrefixes.empty())
391b304bd79SP Dheeraj Srujan Kumar                     {
392b304bd79SP Dheeraj Srujan Kumar                         registryPrefix.assign(supportedRegPrefixes.begin(),
393b304bd79SP Dheeraj Srujan Kumar                                               supportedRegPrefixes.end());
394b304bd79SP Dheeraj Srujan Kumar                     }
395b304bd79SP Dheeraj Srujan Kumar                     else
396b304bd79SP Dheeraj Srujan Kumar                     {
397b304bd79SP Dheeraj Srujan Kumar                         registryPrefix = subValue->registryPrefixes;
398b304bd79SP Dheeraj Srujan Kumar                     }
399b304bd79SP Dheeraj Srujan Kumar 
400b304bd79SP Dheeraj Srujan Kumar                     for (const std::string& id : *msgIds)
401b304bd79SP Dheeraj Srujan Kumar                     {
402b304bd79SP Dheeraj Srujan Kumar                         bool validId = false;
403b304bd79SP Dheeraj Srujan Kumar 
404b304bd79SP Dheeraj Srujan Kumar                         // Check for Message ID in each of the selected Registry
405b304bd79SP Dheeraj Srujan Kumar                         for (const std::string& it : registryPrefix)
406b304bd79SP Dheeraj Srujan Kumar                         {
407b304bd79SP Dheeraj Srujan Kumar                             const boost::beast::span<
408b304bd79SP Dheeraj Srujan Kumar                                 const redfish::message_registries::MessageEntry>
4097e860f15SJohn Edward Broadbent                                 registry = redfish::message_registries::
4107e860f15SJohn Edward Broadbent                                     getRegistryFromPrefix(it);
411b304bd79SP Dheeraj Srujan Kumar 
412b304bd79SP Dheeraj Srujan Kumar                             if (std::any_of(
413b304bd79SP Dheeraj Srujan Kumar                                     registry.cbegin(), registry.cend(),
4147e860f15SJohn Edward Broadbent                                     [&id](const redfish::message_registries::
4157e860f15SJohn Edward Broadbent                                               MessageEntry& messageEntry) {
416b304bd79SP Dheeraj Srujan Kumar                                         return !id.compare(messageEntry.first);
417b304bd79SP Dheeraj Srujan Kumar                                     }))
418b304bd79SP Dheeraj Srujan Kumar                             {
419b304bd79SP Dheeraj Srujan Kumar                                 validId = true;
420b304bd79SP Dheeraj Srujan Kumar                                 break;
421b304bd79SP Dheeraj Srujan Kumar                             }
422b304bd79SP Dheeraj Srujan Kumar                         }
423b304bd79SP Dheeraj Srujan Kumar 
424b304bd79SP Dheeraj Srujan Kumar                         if (!validId)
425b304bd79SP Dheeraj Srujan Kumar                         {
426b304bd79SP Dheeraj Srujan Kumar                             messages::propertyValueNotInList(asyncResp->res, id,
427b304bd79SP Dheeraj Srujan Kumar                                                              "MessageIds");
428b304bd79SP Dheeraj Srujan Kumar                             return;
429b304bd79SP Dheeraj Srujan Kumar                         }
430b304bd79SP Dheeraj Srujan Kumar                     }
431b304bd79SP Dheeraj Srujan Kumar 
432b52664e2SAppaRao Puli                     subValue->registryMsgIds = *msgIds;
433e5aaf047SAppaRao Puli                 }
434e5aaf047SAppaRao Puli 
435e5aaf047SAppaRao Puli                 if (retryPolicy)
436e5aaf047SAppaRao Puli                 {
437e5aaf047SAppaRao Puli                     if (std::find(supportedRetryPolicies.begin(),
438e5aaf047SAppaRao Puli                                   supportedRetryPolicies.end(),
439e5aaf047SAppaRao Puli                                   *retryPolicy) == supportedRetryPolicies.end())
440e5aaf047SAppaRao Puli                     {
4417e860f15SJohn Edward Broadbent                         messages::propertyValueNotInList(asyncResp->res,
4427e860f15SJohn Edward Broadbent                                                          *retryPolicy,
443e5aaf047SAppaRao Puli                                                          "DeliveryRetryPolicy");
444e5aaf047SAppaRao Puli                         return;
445e5aaf047SAppaRao Puli                     }
446b52664e2SAppaRao Puli                     subValue->retryPolicy = *retryPolicy;
447e5aaf047SAppaRao Puli                 }
448e5aaf047SAppaRao Puli                 else
449e5aaf047SAppaRao Puli                 {
450e5aaf047SAppaRao Puli                     // Default "TerminateAfterRetries"
451b52664e2SAppaRao Puli                     subValue->retryPolicy = "TerminateAfterRetries";
452e5aaf047SAppaRao Puli                 }
453e5aaf047SAppaRao Puli 
454144b6318SAppaRao Puli                 if (mrdJsonArray)
455156d6b00SAppaRao Puli                 {
456144b6318SAppaRao Puli                     for (nlohmann::json& mrdObj : *mrdJsonArray)
457144b6318SAppaRao Puli                     {
458144b6318SAppaRao Puli                         std::string mrdUri;
4597e860f15SJohn Edward Broadbent                         if (json_util::getValueFromJsonObject(
4607e860f15SJohn Edward Broadbent                                 mrdObj, "@odata.id", mrdUri))
461144b6318SAppaRao Puli                         {
4627e860f15SJohn Edward Broadbent                             subValue->metricReportDefinitions.emplace_back(
4637e860f15SJohn Edward Broadbent                                 mrdUri);
464144b6318SAppaRao Puli                         }
465144b6318SAppaRao Puli                         else
466144b6318SAppaRao Puli                         {
467144b6318SAppaRao Puli                             messages::propertyValueFormatError(
46871f52d96SEd Tanous                                 asyncResp->res,
4697e860f15SJohn Edward Broadbent                                 mrdObj.dump(
4707e860f15SJohn Edward Broadbent                                     2, ' ', true,
47171f52d96SEd Tanous                                     nlohmann::json::error_handler_t::replace),
472144b6318SAppaRao Puli                                 "MetricReportDefinitions");
473144b6318SAppaRao Puli                             return;
474144b6318SAppaRao Puli                         }
475144b6318SAppaRao Puli                     }
476156d6b00SAppaRao Puli                 }
477156d6b00SAppaRao Puli 
478b52664e2SAppaRao Puli                 std::string id =
4797e860f15SJohn Edward Broadbent                     EventServiceManager::getInstance().addSubscription(
4807e860f15SJohn Edward Broadbent                         subValue);
481b52664e2SAppaRao Puli                 if (id.empty())
482e5aaf047SAppaRao Puli                 {
483e5aaf047SAppaRao Puli                     messages::internalError(asyncResp->res);
484e5aaf047SAppaRao Puli                     return;
485e5aaf047SAppaRao Puli                 }
486e5aaf047SAppaRao Puli 
487e5aaf047SAppaRao Puli                 messages::created(asyncResp->res);
488e5aaf047SAppaRao Puli                 asyncResp->res.addHeader(
489e5aaf047SAppaRao Puli                     "Location", "/redfish/v1/EventService/Subscriptions/" + id);
4907e860f15SJohn Edward Broadbent             });
491e5aaf047SAppaRao Puli }
492e5aaf047SAppaRao Puli 
4937e860f15SJohn Edward Broadbent inline void requestRoutesEventDestination(App& app)
494e5aaf047SAppaRao Puli {
4959d41aec6SRavi Teja     BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/<str>/")
496ed398213SEd Tanous         .privileges(redfish::privileges::getEventDestination)
4977e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::get)(
4987e860f15SJohn Edward Broadbent             [](const crow::Request&,
4997e860f15SJohn Edward Broadbent                const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
5007e860f15SJohn Edward Broadbent                const std::string& param) {
501b52664e2SAppaRao Puli                 std::shared_ptr<Subscription> subValue =
5027e860f15SJohn Edward Broadbent                     EventServiceManager::getInstance().getSubscription(param);
503b52664e2SAppaRao Puli                 if (subValue == nullptr)
504e5aaf047SAppaRao Puli                 {
5057e860f15SJohn Edward Broadbent                     asyncResp->res.result(
5067e860f15SJohn Edward Broadbent                         boost::beast::http::status::not_found);
507e5aaf047SAppaRao Puli                     return;
508e5aaf047SAppaRao Puli                 }
5097e860f15SJohn Edward Broadbent                 const std::string& id = param;
510e5aaf047SAppaRao Puli 
5118d1b46d7Szhanghch05                 asyncResp->res.jsonValue = {
5127e860f15SJohn Edward Broadbent                     {"@odata.type",
5137e860f15SJohn Edward Broadbent                      "#EventDestination.v1_7_0.EventDestination"},
514e5aaf047SAppaRao Puli                     {"Protocol", "Redfish"}};
515e5aaf047SAppaRao Puli                 asyncResp->res.jsonValue["@odata.id"] =
516e5aaf047SAppaRao Puli                     "/redfish/v1/EventService/Subscriptions/" + id;
517e5aaf047SAppaRao Puli                 asyncResp->res.jsonValue["Id"] = id;
518e5aaf047SAppaRao Puli                 asyncResp->res.jsonValue["Name"] = "Event Destination " + id;
5197e860f15SJohn Edward Broadbent                 asyncResp->res.jsonValue["Destination"] =
5207e860f15SJohn Edward Broadbent                     subValue->destinationUrl;
521b52664e2SAppaRao Puli                 asyncResp->res.jsonValue["Context"] = subValue->customText;
522e5aaf047SAppaRao Puli                 asyncResp->res.jsonValue["SubscriptionType"] =
523b52664e2SAppaRao Puli                     subValue->subscriptionType;
524b52664e2SAppaRao Puli                 asyncResp->res.jsonValue["HttpHeaders"] = subValue->httpHeaders;
5257e860f15SJohn Edward Broadbent                 asyncResp->res.jsonValue["EventFormatType"] =
5267e860f15SJohn Edward Broadbent                     subValue->eventFormatType;
527e5aaf047SAppaRao Puli                 asyncResp->res.jsonValue["RegistryPrefixes"] =
528b52664e2SAppaRao Puli                     subValue->registryPrefixes;
5297e860f15SJohn Edward Broadbent                 asyncResp->res.jsonValue["ResourceTypes"] =
5307e860f15SJohn Edward Broadbent                     subValue->resourceTypes;
531e56f254cSSunitha Harish 
5327e860f15SJohn Edward Broadbent                 asyncResp->res.jsonValue["MessageIds"] =
5337e860f15SJohn Edward Broadbent                     subValue->registryMsgIds;
5347e860f15SJohn Edward Broadbent                 asyncResp->res.jsonValue["DeliveryRetryPolicy"] =
5357e860f15SJohn Edward Broadbent                     subValue->retryPolicy;
536144b6318SAppaRao Puli 
537144b6318SAppaRao Puli                 std::vector<nlohmann::json> mrdJsonArray;
538144b6318SAppaRao Puli                 for (const auto& mdrUri : subValue->metricReportDefinitions)
539144b6318SAppaRao Puli                 {
540144b6318SAppaRao Puli                     mrdJsonArray.push_back({{"@odata.id", mdrUri}});
541144b6318SAppaRao Puli                 }
5427e860f15SJohn Edward Broadbent                 asyncResp->res.jsonValue["MetricReportDefinitions"] =
5437e860f15SJohn Edward Broadbent                     mrdJsonArray;
5447e860f15SJohn Edward Broadbent             });
5457e860f15SJohn Edward Broadbent     /////redfish/v1/EventService/Subscriptions/
5467e860f15SJohn Edward Broadbent     // ConfigureManager
5479d41aec6SRavi Teja     BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/<str>/")
548ed398213SEd Tanous         // The below privilege is wrong, it should be ConfigureManager OR
549ed398213SEd Tanous         // ConfigureSelf
550ed398213SEd Tanous         // TODO(ed) follow up with DMTF spec and understand ConfigureSelf
551ed398213SEd Tanous         //.privileges(redfish::privileges::patchEventDestination)
552432a890cSEd Tanous         .privileges({{"ConfigureManager"}})
5537e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::patch)(
5547e860f15SJohn Edward Broadbent             [](const crow::Request& req,
5557e860f15SJohn Edward Broadbent                const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
5567e860f15SJohn Edward Broadbent                const std::string& param) {
557b52664e2SAppaRao Puli                 std::shared_ptr<Subscription> subValue =
5587e860f15SJohn Edward Broadbent                     EventServiceManager::getInstance().getSubscription(param);
559b52664e2SAppaRao Puli                 if (subValue == nullptr)
560e5aaf047SAppaRao Puli                 {
5617e860f15SJohn Edward Broadbent                     asyncResp->res.result(
5627e860f15SJohn Edward Broadbent                         boost::beast::http::status::not_found);
563e5aaf047SAppaRao Puli                     return;
564e5aaf047SAppaRao Puli                 }
565e5aaf047SAppaRao Puli 
566e5aaf047SAppaRao Puli                 std::optional<std::string> context;
567e5aaf047SAppaRao Puli                 std::optional<std::string> retryPolicy;
568e5aaf047SAppaRao Puli                 std::optional<std::vector<nlohmann::json>> headers;
569e5aaf047SAppaRao Puli 
5707e860f15SJohn Edward Broadbent                 if (!json_util::readJson(req, asyncResp->res, "Context",
5717e860f15SJohn Edward Broadbent                                          context, "DeliveryRetryPolicy",
5727e860f15SJohn Edward Broadbent                                          retryPolicy, "HttpHeaders", headers))
573e5aaf047SAppaRao Puli                 {
574e5aaf047SAppaRao Puli                     return;
575e5aaf047SAppaRao Puli                 }
576e5aaf047SAppaRao Puli 
577e5aaf047SAppaRao Puli                 if (context)
578e5aaf047SAppaRao Puli                 {
579b52664e2SAppaRao Puli                     subValue->customText = *context;
580e5aaf047SAppaRao Puli                 }
581e5aaf047SAppaRao Puli 
582e5aaf047SAppaRao Puli                 if (headers)
583e5aaf047SAppaRao Puli                 {
584b52664e2SAppaRao Puli                     subValue->httpHeaders = *headers;
585e5aaf047SAppaRao Puli                 }
586e5aaf047SAppaRao Puli 
587e5aaf047SAppaRao Puli                 if (retryPolicy)
588e5aaf047SAppaRao Puli                 {
589e5aaf047SAppaRao Puli                     if (std::find(supportedRetryPolicies.begin(),
590e5aaf047SAppaRao Puli                                   supportedRetryPolicies.end(),
591e5aaf047SAppaRao Puli                                   *retryPolicy) == supportedRetryPolicies.end())
592e5aaf047SAppaRao Puli                     {
5937e860f15SJohn Edward Broadbent                         messages::propertyValueNotInList(asyncResp->res,
5947e860f15SJohn Edward Broadbent                                                          *retryPolicy,
595e5aaf047SAppaRao Puli                                                          "DeliveryRetryPolicy");
596e5aaf047SAppaRao Puli                         return;
597e5aaf047SAppaRao Puli                     }
598b52664e2SAppaRao Puli                     subValue->retryPolicy = *retryPolicy;
599fe44eb0bSAyushi Smriti                     subValue->updateRetryPolicy();
600e5aaf047SAppaRao Puli                 }
601e5aaf047SAppaRao Puli 
602b52664e2SAppaRao Puli                 EventServiceManager::getInstance().updateSubscriptionData();
6037e860f15SJohn Edward Broadbent             });
6049d41aec6SRavi Teja     BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/<str>/")
605ed398213SEd Tanous         // The below privilege is wrong, it should be ConfigureManager OR
606ed398213SEd Tanous         // ConfigureSelf
607ed398213SEd Tanous         //.privileges(redfish::privileges::deleteEventDestination)
608432a890cSEd Tanous         .privileges({{"ConfigureManager"}})
6097e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::delete_)(
6107e860f15SJohn Edward Broadbent             [](const crow::Request&,
6117e860f15SJohn Edward Broadbent                const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
6127e860f15SJohn Edward Broadbent                const std::string& param) {
6137e860f15SJohn Edward Broadbent                 if (!EventServiceManager::getInstance().isSubscriptionExist(
6147e860f15SJohn Edward Broadbent                         param))
615e5aaf047SAppaRao Puli                 {
6167e860f15SJohn Edward Broadbent                     asyncResp->res.result(
6177e860f15SJohn Edward Broadbent                         boost::beast::http::status::not_found);
618e5aaf047SAppaRao Puli                     return;
619e5aaf047SAppaRao Puli                 }
6207e860f15SJohn Edward Broadbent                 EventServiceManager::getInstance().deleteSubscription(param);
6217e860f15SJohn Edward Broadbent             });
622e5aaf047SAppaRao Puli }
623e5aaf047SAppaRao Puli 
624e5aaf047SAppaRao Puli } // namespace redfish
625