xref: /openbmc/bmcweb/features/redfish/lib/event_service.hpp (revision 1476687deb1697d865b20458a0097c9ab5fd44e2)
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>
20601c71aeSEd Tanous #include <boost/beast/http/fields.hpp>
21eb1c47d3SEd Tanous #include <http/utility.hpp>
22eb1c47d3SEd Tanous #include <logging.hpp>
2345ca1b86SEd Tanous #include <query.hpp>
24ed398213SEd Tanous #include <registries/privilege_registry.hpp>
25ed398213SEd Tanous 
261e270c5fSPatrick Williams #include <span>
271e270c5fSPatrick Williams 
28e5aaf047SAppaRao Puli namespace redfish
29e5aaf047SAppaRao Puli {
30e5aaf047SAppaRao Puli 
31156d6b00SAppaRao Puli static constexpr const std::array<const char*, 2> supportedEvtFormatTypes = {
32156d6b00SAppaRao Puli     eventFormatType, metricReportFormatType};
33e5aaf047SAppaRao Puli static constexpr const std::array<const char*, 3> supportedRegPrefixes = {
34b304bd79SP Dheeraj Srujan Kumar     "Base", "OpenBMC", "TaskEvent"};
35e5aaf047SAppaRao Puli static constexpr const std::array<const char*, 3> supportedRetryPolicies = {
36e5aaf047SAppaRao Puli     "TerminateAfterRetries", "SuspendRetries", "RetryForever"};
37e5aaf047SAppaRao Puli 
38e56f254cSSunitha Harish #ifdef BMCWEB_ENABLE_IBM_MANAGEMENT_CONSOLE
39e56f254cSSunitha Harish static constexpr const std::array<const char*, 2> supportedResourceTypes = {
40e56f254cSSunitha Harish     "IBMConfigFile", "Task"};
41e56f254cSSunitha Harish #else
42e56f254cSSunitha Harish static constexpr const std::array<const char*, 1> supportedResourceTypes = {
43e56f254cSSunitha Harish     "Task"};
44e56f254cSSunitha Harish #endif
45e56f254cSSunitha Harish 
46e5aaf047SAppaRao Puli static constexpr const uint8_t maxNoOfSubscriptions = 20;
47e5aaf047SAppaRao Puli 
487e860f15SJohn Edward Broadbent inline void requestRoutesEventService(App& app)
49e5aaf047SAppaRao Puli {
507e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app, "/redfish/v1/EventService/")
51ed398213SEd Tanous         .privileges(redfish::privileges::getEventService)
5245ca1b86SEd Tanous         .methods(boost::beast::http::verb::get)([&app](const crow::Request& req,
5345ca1b86SEd Tanous                                                        const std::shared_ptr<
5445ca1b86SEd Tanous                                                            bmcweb::AsyncResp>&
5545ca1b86SEd Tanous                                                            asyncResp) {
5645ca1b86SEd Tanous             if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
5745ca1b86SEd Tanous             {
5845ca1b86SEd Tanous                 return;
5945ca1b86SEd Tanous             }
60*1476687dSEd Tanous 
61*1476687dSEd Tanous             asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/EventService";
62*1476687dSEd Tanous             asyncResp->res.jsonValue["@odata.type"] =
63*1476687dSEd Tanous                 "#EventService.v1_5_0.EventService";
64*1476687dSEd Tanous             asyncResp->res.jsonValue["Id"] = "EventService";
65*1476687dSEd Tanous             asyncResp->res.jsonValue["Name"] = "Event Service";
66*1476687dSEd Tanous             asyncResp->res.jsonValue["Subscriptions"]["@odata.id"] =
67*1476687dSEd Tanous                 "/redfish/v1/EventService/Subscriptions";
68*1476687dSEd Tanous             asyncResp->res.jsonValue["Actions"]["#EventService.SubmitTestEvent"]
69*1476687dSEd Tanous                                     ["target"] =
70*1476687dSEd Tanous                 "/redfish/v1/EventService/Actions/EventService.SubmitTestEvent";
71e5aaf047SAppaRao Puli 
7228afb49cSJunLin Chen             const persistent_data::EventServiceConfig eventServiceConfig =
7328afb49cSJunLin Chen                 persistent_data::EventServiceStore::getInstance()
7428afb49cSJunLin Chen                     .getEventServiceConfig();
757d1cc387SAppaRao Puli 
767d1cc387SAppaRao Puli             asyncResp->res.jsonValue["Status"]["State"] =
7728afb49cSJunLin Chen                 (eventServiceConfig.enabled ? "Enabled" : "Disabled");
7828afb49cSJunLin Chen             asyncResp->res.jsonValue["ServiceEnabled"] =
7928afb49cSJunLin Chen                 eventServiceConfig.enabled;
807e860f15SJohn Edward Broadbent             asyncResp->res.jsonValue["DeliveryRetryAttempts"] =
8128afb49cSJunLin Chen                 eventServiceConfig.retryAttempts;
82e5aaf047SAppaRao Puli             asyncResp->res.jsonValue["DeliveryRetryIntervalSeconds"] =
8328afb49cSJunLin Chen                 eventServiceConfig.retryTimeoutInterval;
847e860f15SJohn Edward Broadbent             asyncResp->res.jsonValue["EventFormatTypes"] =
857e860f15SJohn Edward Broadbent                 supportedEvtFormatTypes;
860fda0f12SGeorge Liu             asyncResp->res.jsonValue["RegistryPrefixes"] = supportedRegPrefixes;
870fda0f12SGeorge Liu             asyncResp->res.jsonValue["ResourceTypes"] = supportedResourceTypes;
8807941a88SAyushi Smriti 
8907941a88SAyushi Smriti             nlohmann::json supportedSSEFilters = {
9007941a88SAyushi Smriti                 {"EventFormatType", true},        {"MessageId", true},
9107941a88SAyushi Smriti                 {"MetricReportDefinition", true}, {"RegistryPrefix", true},
9207941a88SAyushi Smriti                 {"OriginResource", false},        {"ResourceType", false}};
9307941a88SAyushi Smriti 
9407941a88SAyushi Smriti             asyncResp->res.jsonValue["SSEFilterPropertiesSupported"] =
9507941a88SAyushi Smriti                 supportedSSEFilters;
967e860f15SJohn Edward Broadbent         });
97e5aaf047SAppaRao Puli 
987e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app, "/redfish/v1/EventService/")
99ed398213SEd Tanous         .privileges(redfish::privileges::patchEventService)
1007e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::patch)(
10145ca1b86SEd Tanous             [&app](const crow::Request& req,
10245ca1b86SEd Tanous                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
10345ca1b86SEd Tanous                 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
104e5aaf047SAppaRao Puli                 {
10545ca1b86SEd Tanous                     return;
10645ca1b86SEd Tanous                 }
107e5aaf047SAppaRao Puli                 std::optional<bool> serviceEnabled;
108e5aaf047SAppaRao Puli                 std::optional<uint32_t> retryAttemps;
109e5aaf047SAppaRao Puli                 std::optional<uint32_t> retryInterval;
110e5aaf047SAppaRao Puli 
11115ed6780SWilly Tu                 if (!json_util::readJsonPatch(
1127e860f15SJohn Edward Broadbent                         req, asyncResp->res, "ServiceEnabled", serviceEnabled,
1137e860f15SJohn Edward Broadbent                         "DeliveryRetryAttempts", retryAttemps,
1147e860f15SJohn Edward Broadbent                         "DeliveryRetryIntervalSeconds", retryInterval))
115e5aaf047SAppaRao Puli                 {
116e5aaf047SAppaRao Puli                     return;
117e5aaf047SAppaRao Puli                 }
118e5aaf047SAppaRao Puli 
11928afb49cSJunLin Chen                 persistent_data::EventServiceConfig eventServiceConfig =
12028afb49cSJunLin Chen                     persistent_data::EventServiceStore::getInstance()
12128afb49cSJunLin Chen                         .getEventServiceConfig();
1227d1cc387SAppaRao Puli 
123e5aaf047SAppaRao Puli                 if (serviceEnabled)
124e5aaf047SAppaRao Puli                 {
12528afb49cSJunLin Chen                     eventServiceConfig.enabled = *serviceEnabled;
126e5aaf047SAppaRao Puli                 }
127e5aaf047SAppaRao Puli 
128e5aaf047SAppaRao Puli                 if (retryAttemps)
129e5aaf047SAppaRao Puli                 {
130e5aaf047SAppaRao Puli                     // Supported range [1-3]
131e5aaf047SAppaRao Puli                     if ((*retryAttemps < 1) || (*retryAttemps > 3))
132e5aaf047SAppaRao Puli                     {
133e5aaf047SAppaRao Puli                         messages::queryParameterOutOfRange(
134e5aaf047SAppaRao Puli                             asyncResp->res, std::to_string(*retryAttemps),
135e5aaf047SAppaRao Puli                             "DeliveryRetryAttempts", "[1-3]");
136e5aaf047SAppaRao Puli                     }
137e5aaf047SAppaRao Puli                     else
138e5aaf047SAppaRao Puli                     {
13928afb49cSJunLin Chen                         eventServiceConfig.retryAttempts = *retryAttemps;
140e5aaf047SAppaRao Puli                     }
141e5aaf047SAppaRao Puli                 }
142e5aaf047SAppaRao Puli 
143e5aaf047SAppaRao Puli                 if (retryInterval)
144e5aaf047SAppaRao Puli                 {
145e5aaf047SAppaRao Puli                     // Supported range [30 - 180]
146e5aaf047SAppaRao Puli                     if ((*retryInterval < 30) || (*retryInterval > 180))
147e5aaf047SAppaRao Puli                     {
148e5aaf047SAppaRao Puli                         messages::queryParameterOutOfRange(
149e5aaf047SAppaRao Puli                             asyncResp->res, std::to_string(*retryInterval),
150e5aaf047SAppaRao Puli                             "DeliveryRetryIntervalSeconds", "[30-180]");
151e5aaf047SAppaRao Puli                     }
152e5aaf047SAppaRao Puli                     else
153e5aaf047SAppaRao Puli                     {
15428afb49cSJunLin Chen                         eventServiceConfig.retryTimeoutInterval =
15528afb49cSJunLin Chen                             *retryInterval;
156e5aaf047SAppaRao Puli                     }
157e5aaf047SAppaRao Puli                 }
158e5aaf047SAppaRao Puli 
1597d1cc387SAppaRao Puli                 EventServiceManager::getInstance().setEventServiceConfig(
16028afb49cSJunLin Chen                     eventServiceConfig);
1617e860f15SJohn Edward Broadbent             });
1620b4bdd93SAppaRao Puli }
1630b4bdd93SAppaRao Puli 
1647e860f15SJohn Edward Broadbent inline void requestRoutesSubmitTestEvent(App& app)
1650b4bdd93SAppaRao Puli {
1667e860f15SJohn Edward Broadbent 
1677e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(
1687e860f15SJohn Edward Broadbent         app, "/redfish/v1/EventService/Actions/EventService.SubmitTestEvent/")
169ed398213SEd Tanous         .privileges(redfish::privileges::postEventService)
1707e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::post)(
17145ca1b86SEd Tanous             [&app](const crow::Request& req,
1727e860f15SJohn Edward Broadbent                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
17345ca1b86SEd Tanous                 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
17445ca1b86SEd Tanous                 {
17545ca1b86SEd Tanous                     return;
17645ca1b86SEd Tanous                 }
1776ba8c82eSsunharis_in                 if (!EventServiceManager::getInstance().sendTestEventLog())
1786ba8c82eSsunharis_in                 {
1796ba8c82eSsunharis_in                     messages::serviceDisabled(asyncResp->res,
1806ba8c82eSsunharis_in                                               "/redfish/v1/EventService/");
1816ba8c82eSsunharis_in                     return;
1826ba8c82eSsunharis_in                 }
1838d1b46d7Szhanghch05                 asyncResp->res.result(boost::beast::http::status::no_content);
1847e860f15SJohn Edward Broadbent             });
185e5aaf047SAppaRao Puli }
186e5aaf047SAppaRao Puli 
1877e860f15SJohn Edward Broadbent inline void requestRoutesEventDestinationCollection(App& app)
188e5aaf047SAppaRao Puli {
1891ebe3e41SGayathri Leburu     BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/")
190ed398213SEd Tanous         .privileges(redfish::privileges::getEventDestinationCollection)
1917e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::get)(
19245ca1b86SEd Tanous             [&app](const crow::Request& req,
1937e860f15SJohn Edward Broadbent                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
19445ca1b86SEd Tanous                 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
19545ca1b86SEd Tanous                 {
19645ca1b86SEd Tanous                     return;
19745ca1b86SEd Tanous                 }
198*1476687dSEd Tanous                 asyncResp->res.jsonValue["@odata.type"] =
199*1476687dSEd Tanous                     "#EventDestinationCollection.EventDestinationCollection";
200*1476687dSEd Tanous                 asyncResp->res.jsonValue["@odata.id"] =
201*1476687dSEd Tanous                     "/redfish/v1/EventService/Subscriptions";
202*1476687dSEd Tanous                 asyncResp->res.jsonValue["Name"] =
203*1476687dSEd Tanous                     "Event Destination Collections";
204e5aaf047SAppaRao Puli 
2057e860f15SJohn Edward Broadbent                 nlohmann::json& memberArray =
2067e860f15SJohn Edward Broadbent                     asyncResp->res.jsonValue["Members"];
207e5aaf047SAppaRao Puli 
208b52664e2SAppaRao Puli                 std::vector<std::string> subscripIds =
209b52664e2SAppaRao Puli                     EventServiceManager::getInstance().getAllIDs();
210b52664e2SAppaRao Puli                 memberArray = nlohmann::json::array();
2117e860f15SJohn Edward Broadbent                 asyncResp->res.jsonValue["Members@odata.count"] =
2127e860f15SJohn Edward Broadbent                     subscripIds.size();
213b52664e2SAppaRao Puli 
214b52664e2SAppaRao Puli                 for (const std::string& id : subscripIds)
215e5aaf047SAppaRao Puli                 {
216*1476687dSEd Tanous                     nlohmann::json::object_t member;
217*1476687dSEd Tanous                     member["@odata.id"] =
218*1476687dSEd Tanous                         "/redfish/v1/EventService/Subscriptions/" + id;
219*1476687dSEd Tanous                     memberArray.push_back(std::move(member));
220e5aaf047SAppaRao Puli                 }
2217e860f15SJohn Edward Broadbent             });
2227e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/")
2237eeafa76SAbhishek Patel         .privileges(redfish::privileges::postEventDestinationCollection)
224fffb8c1fSEd Tanous         .methods(
225fffb8c1fSEd Tanous             boost::beast::http::verb::
22645ca1b86SEd Tanous                 post)([&app](
22745ca1b86SEd Tanous                           const crow::Request& req,
2287e860f15SJohn Edward Broadbent                           const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
22945ca1b86SEd Tanous             if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
23045ca1b86SEd Tanous             {
23145ca1b86SEd Tanous                 return;
23245ca1b86SEd Tanous             }
233fffb8c1fSEd Tanous             if (EventServiceManager::getInstance().getNumberOfSubscriptions() >=
234fffb8c1fSEd Tanous                 maxNoOfSubscriptions)
235e5aaf047SAppaRao Puli             {
236e5aaf047SAppaRao Puli                 messages::eventSubscriptionLimitExceeded(asyncResp->res);
237e5aaf047SAppaRao Puli                 return;
238e5aaf047SAppaRao Puli             }
239e5aaf047SAppaRao Puli             std::string destUrl;
240e5aaf047SAppaRao Puli             std::string protocol;
241e5aaf047SAppaRao Puli             std::optional<std::string> context;
242e5aaf047SAppaRao Puli             std::optional<std::string> subscriptionType;
24323a21a1cSEd Tanous             std::optional<std::string> eventFormatType2;
244e5aaf047SAppaRao Puli             std::optional<std::string> retryPolicy;
245e5aaf047SAppaRao Puli             std::optional<std::vector<std::string>> msgIds;
246e5aaf047SAppaRao Puli             std::optional<std::vector<std::string>> regPrefixes;
247e56f254cSSunitha Harish             std::optional<std::vector<std::string>> resTypes;
248e5aaf047SAppaRao Puli             std::optional<std::vector<nlohmann::json>> headers;
249144b6318SAppaRao Puli             std::optional<std::vector<nlohmann::json>> mrdJsonArray;
250e5aaf047SAppaRao Puli 
25115ed6780SWilly Tu             if (!json_util::readJsonPatch(
2527e860f15SJohn Edward Broadbent                     req, asyncResp->res, "Destination", destUrl, "Context",
2537e860f15SJohn Edward Broadbent                     context, "Protocol", protocol, "SubscriptionType",
2547e860f15SJohn Edward Broadbent                     subscriptionType, "EventFormatType", eventFormatType2,
2557e860f15SJohn Edward Broadbent                     "HttpHeaders", headers, "RegistryPrefixes", regPrefixes,
256fffb8c1fSEd Tanous                     "MessageIds", msgIds, "DeliveryRetryPolicy", retryPolicy,
257fffb8c1fSEd Tanous                     "MetricReportDefinitions", mrdJsonArray, "ResourceTypes",
258fffb8c1fSEd Tanous                     resTypes))
259e5aaf047SAppaRao Puli             {
260e5aaf047SAppaRao Puli                 return;
261e5aaf047SAppaRao Puli             }
262e5aaf047SAppaRao Puli 
263dd28ba82SAppaRao Puli             if (regPrefixes && msgIds)
264dd28ba82SAppaRao Puli             {
26526f6976fSEd Tanous                 if (!regPrefixes->empty() && !msgIds->empty())
266dd28ba82SAppaRao Puli                 {
2670a4304cfSEd Tanous                     messages::propertyValueConflict(
2680a4304cfSEd Tanous                         asyncResp->res, "MessageIds", "RegistryPrefixes");
269dd28ba82SAppaRao Puli                     return;
270dd28ba82SAppaRao Puli                 }
271dd28ba82SAppaRao Puli             }
272dd28ba82SAppaRao Puli 
273eb1c47d3SEd Tanous             std::string host;
274eb1c47d3SEd Tanous             std::string urlProto;
275eb1c47d3SEd Tanous             uint16_t port = 0;
276eb1c47d3SEd Tanous             std::string path;
277eb1c47d3SEd Tanous 
278eb1c47d3SEd Tanous             if (!crow::utility::validateAndSplitUrl(destUrl, urlProto, host,
279eb1c47d3SEd Tanous                                                     port, path))
280e5aaf047SAppaRao Puli             {
281eb1c47d3SEd Tanous                 BMCWEB_LOG_WARNING
282eb1c47d3SEd Tanous                     << "Failed to validate and split destination url";
283e5aaf047SAppaRao Puli                 messages::propertyValueFormatError(asyncResp->res, destUrl,
284e5aaf047SAppaRao Puli                                                    "Destination");
285e5aaf047SAppaRao Puli                 return;
286e5aaf047SAppaRao Puli             }
287b52664e2SAppaRao Puli 
288b52664e2SAppaRao Puli             if (path.empty())
289b52664e2SAppaRao Puli             {
290b52664e2SAppaRao Puli                 path = "/";
291b52664e2SAppaRao Puli             }
292b52664e2SAppaRao Puli             std::shared_ptr<Subscription> subValue =
293eb1c47d3SEd Tanous                 std::make_shared<Subscription>(host, port, path, urlProto);
294b52664e2SAppaRao Puli 
295b52664e2SAppaRao Puli             subValue->destinationUrl = destUrl;
296e5aaf047SAppaRao Puli 
297e5aaf047SAppaRao Puli             if (subscriptionType)
298e5aaf047SAppaRao Puli             {
299e5aaf047SAppaRao Puli                 if (*subscriptionType != "RedfishEvent")
300e5aaf047SAppaRao Puli                 {
301fffb8c1fSEd Tanous                     messages::propertyValueNotInList(
302fffb8c1fSEd Tanous                         asyncResp->res, *subscriptionType, "SubscriptionType");
303e5aaf047SAppaRao Puli                     return;
304e5aaf047SAppaRao Puli                 }
305b52664e2SAppaRao Puli                 subValue->subscriptionType = *subscriptionType;
306e5aaf047SAppaRao Puli             }
307e5aaf047SAppaRao Puli             else
308e5aaf047SAppaRao Puli             {
309b52664e2SAppaRao Puli                 subValue->subscriptionType = "RedfishEvent"; // Default
310e5aaf047SAppaRao Puli             }
311e5aaf047SAppaRao Puli 
312e5aaf047SAppaRao Puli             if (protocol != "Redfish")
313e5aaf047SAppaRao Puli             {
314e5aaf047SAppaRao Puli                 messages::propertyValueNotInList(asyncResp->res, protocol,
315e5aaf047SAppaRao Puli                                                  "Protocol");
316e5aaf047SAppaRao Puli                 return;
317e5aaf047SAppaRao Puli             }
318b52664e2SAppaRao Puli             subValue->protocol = protocol;
319e5aaf047SAppaRao Puli 
32023a21a1cSEd Tanous             if (eventFormatType2)
321e5aaf047SAppaRao Puli             {
322e5aaf047SAppaRao Puli                 if (std::find(supportedEvtFormatTypes.begin(),
323e5aaf047SAppaRao Puli                               supportedEvtFormatTypes.end(),
3247e860f15SJohn Edward Broadbent                               *eventFormatType2) ==
3257e860f15SJohn Edward Broadbent                     supportedEvtFormatTypes.end())
326e5aaf047SAppaRao Puli                 {
327fffb8c1fSEd Tanous                     messages::propertyValueNotInList(
328fffb8c1fSEd Tanous                         asyncResp->res, *eventFormatType2, "EventFormatType");
329e5aaf047SAppaRao Puli                     return;
330e5aaf047SAppaRao Puli                 }
33123a21a1cSEd Tanous                 subValue->eventFormatType = *eventFormatType2;
332e5aaf047SAppaRao Puli             }
333e5aaf047SAppaRao Puli             else
334e5aaf047SAppaRao Puli             {
335e5aaf047SAppaRao Puli                 // If not specified, use default "Event"
33623a21a1cSEd Tanous                 subValue->eventFormatType = "Event";
337e5aaf047SAppaRao Puli             }
338e5aaf047SAppaRao Puli 
339e5aaf047SAppaRao Puli             if (context)
340e5aaf047SAppaRao Puli             {
341b52664e2SAppaRao Puli                 subValue->customText = *context;
342e5aaf047SAppaRao Puli             }
343e5aaf047SAppaRao Puli 
344e5aaf047SAppaRao Puli             if (headers)
345e5aaf047SAppaRao Puli             {
346601c71aeSEd Tanous                 for (const nlohmann::json& headerChunk : *headers)
347601c71aeSEd Tanous                 {
348601c71aeSEd Tanous                     for (const auto& item : headerChunk.items())
349601c71aeSEd Tanous                     {
350601c71aeSEd Tanous                         const std::string* value =
351601c71aeSEd Tanous                             item.value().get_ptr<const std::string*>();
352601c71aeSEd Tanous                         if (value == nullptr)
353601c71aeSEd Tanous                         {
354601c71aeSEd Tanous                             messages::propertyValueFormatError(
355e662eae8SEd Tanous                                 asyncResp->res, item.value().dump(2, 1),
356601c71aeSEd Tanous                                 "HttpHeaders/" + item.key());
357601c71aeSEd Tanous                             return;
358601c71aeSEd Tanous                         }
359601c71aeSEd Tanous                         subValue->httpHeaders.set(item.key(), *value);
360601c71aeSEd Tanous                     }
361601c71aeSEd Tanous                 }
362e5aaf047SAppaRao Puli             }
363e5aaf047SAppaRao Puli 
364e5aaf047SAppaRao Puli             if (regPrefixes)
365e5aaf047SAppaRao Puli             {
366e5aaf047SAppaRao Puli                 for (const std::string& it : *regPrefixes)
367e5aaf047SAppaRao Puli                 {
368e5aaf047SAppaRao Puli                     if (std::find(supportedRegPrefixes.begin(),
369e5aaf047SAppaRao Puli                                   supportedRegPrefixes.end(),
370e5aaf047SAppaRao Puli                                   it) == supportedRegPrefixes.end())
371e5aaf047SAppaRao Puli                     {
372fffb8c1fSEd Tanous                         messages::propertyValueNotInList(asyncResp->res, it,
373fffb8c1fSEd Tanous                                                          "RegistryPrefixes");
374e5aaf047SAppaRao Puli                         return;
375e5aaf047SAppaRao Puli                     }
376e5aaf047SAppaRao Puli                 }
377b52664e2SAppaRao Puli                 subValue->registryPrefixes = *regPrefixes;
378e5aaf047SAppaRao Puli             }
379e5aaf047SAppaRao Puli 
380e56f254cSSunitha Harish             if (resTypes)
381e56f254cSSunitha Harish             {
382e56f254cSSunitha Harish                 for (const std::string& it : *resTypes)
383e56f254cSSunitha Harish                 {
384e56f254cSSunitha Harish                     if (std::find(supportedResourceTypes.begin(),
385e56f254cSSunitha Harish                                   supportedResourceTypes.end(),
386e56f254cSSunitha Harish                                   it) == supportedResourceTypes.end())
387e56f254cSSunitha Harish                     {
388e56f254cSSunitha Harish                         messages::propertyValueNotInList(asyncResp->res, it,
389e56f254cSSunitha Harish                                                          "ResourceTypes");
390e56f254cSSunitha Harish                         return;
391e56f254cSSunitha Harish                     }
392e56f254cSSunitha Harish                 }
393e56f254cSSunitha Harish                 subValue->resourceTypes = *resTypes;
394e56f254cSSunitha Harish             }
395e56f254cSSunitha Harish 
396e5aaf047SAppaRao Puli             if (msgIds)
397e5aaf047SAppaRao Puli             {
398b304bd79SP Dheeraj Srujan Kumar                 std::vector<std::string> registryPrefix;
399b304bd79SP Dheeraj Srujan Kumar 
4007e860f15SJohn Edward Broadbent                 // If no registry prefixes are mentioned, consider all
4017e860f15SJohn Edward Broadbent                 // supported prefixes
402b304bd79SP Dheeraj Srujan Kumar                 if (subValue->registryPrefixes.empty())
403b304bd79SP Dheeraj Srujan Kumar                 {
404b304bd79SP Dheeraj Srujan Kumar                     registryPrefix.assign(supportedRegPrefixes.begin(),
405b304bd79SP Dheeraj Srujan Kumar                                           supportedRegPrefixes.end());
406b304bd79SP Dheeraj Srujan Kumar                 }
407b304bd79SP Dheeraj Srujan Kumar                 else
408b304bd79SP Dheeraj Srujan Kumar                 {
409b304bd79SP Dheeraj Srujan Kumar                     registryPrefix = subValue->registryPrefixes;
410b304bd79SP Dheeraj Srujan Kumar                 }
411b304bd79SP Dheeraj Srujan Kumar 
412b304bd79SP Dheeraj Srujan Kumar                 for (const std::string& id : *msgIds)
413b304bd79SP Dheeraj Srujan Kumar                 {
414b304bd79SP Dheeraj Srujan Kumar                     bool validId = false;
415b304bd79SP Dheeraj Srujan Kumar 
416b304bd79SP Dheeraj Srujan Kumar                     // Check for Message ID in each of the selected Registry
417b304bd79SP Dheeraj Srujan Kumar                     for (const std::string& it : registryPrefix)
418b304bd79SP Dheeraj Srujan Kumar                     {
419fffb8c1fSEd Tanous                         const std::span<const redfish::registries::MessageEntry>
420fffb8c1fSEd Tanous                             registry =
421fffb8c1fSEd Tanous                                 redfish::registries::getRegistryFromPrefix(it);
422b304bd79SP Dheeraj Srujan Kumar 
423b304bd79SP Dheeraj Srujan Kumar                         if (std::any_of(
42426702d01SEd Tanous                                 registry.begin(), registry.end(),
425fffb8c1fSEd Tanous                                 [&id](const redfish::registries::MessageEntry&
426fffb8c1fSEd Tanous                                           messageEntry) {
42755f79e6fSEd Tanous                                     return id == messageEntry.first;
428b304bd79SP Dheeraj Srujan Kumar                                 }))
429b304bd79SP Dheeraj Srujan Kumar                         {
430b304bd79SP Dheeraj Srujan Kumar                             validId = true;
431b304bd79SP Dheeraj Srujan Kumar                             break;
432b304bd79SP Dheeraj Srujan Kumar                         }
433b304bd79SP Dheeraj Srujan Kumar                     }
434b304bd79SP Dheeraj Srujan Kumar 
435b304bd79SP Dheeraj Srujan Kumar                     if (!validId)
436b304bd79SP Dheeraj Srujan Kumar                     {
437b304bd79SP Dheeraj Srujan Kumar                         messages::propertyValueNotInList(asyncResp->res, id,
438b304bd79SP Dheeraj Srujan Kumar                                                          "MessageIds");
439b304bd79SP Dheeraj Srujan Kumar                         return;
440b304bd79SP Dheeraj Srujan Kumar                     }
441b304bd79SP Dheeraj Srujan Kumar                 }
442b304bd79SP Dheeraj Srujan Kumar 
443b52664e2SAppaRao Puli                 subValue->registryMsgIds = *msgIds;
444e5aaf047SAppaRao Puli             }
445e5aaf047SAppaRao Puli 
446e5aaf047SAppaRao Puli             if (retryPolicy)
447e5aaf047SAppaRao Puli             {
448e5aaf047SAppaRao Puli                 if (std::find(supportedRetryPolicies.begin(),
449e5aaf047SAppaRao Puli                               supportedRetryPolicies.end(),
450e5aaf047SAppaRao Puli                               *retryPolicy) == supportedRetryPolicies.end())
451e5aaf047SAppaRao Puli                 {
452fffb8c1fSEd Tanous                     messages::propertyValueNotInList(
453fffb8c1fSEd Tanous                         asyncResp->res, *retryPolicy, "DeliveryRetryPolicy");
454e5aaf047SAppaRao Puli                     return;
455e5aaf047SAppaRao Puli                 }
456b52664e2SAppaRao Puli                 subValue->retryPolicy = *retryPolicy;
457e5aaf047SAppaRao Puli             }
458e5aaf047SAppaRao Puli             else
459e5aaf047SAppaRao Puli             {
460e5aaf047SAppaRao Puli                 // Default "TerminateAfterRetries"
461b52664e2SAppaRao Puli                 subValue->retryPolicy = "TerminateAfterRetries";
462e5aaf047SAppaRao Puli             }
463e5aaf047SAppaRao Puli 
464144b6318SAppaRao Puli             if (mrdJsonArray)
465156d6b00SAppaRao Puli             {
466144b6318SAppaRao Puli                 for (nlohmann::json& mrdObj : *mrdJsonArray)
467144b6318SAppaRao Puli                 {
468144b6318SAppaRao Puli                     std::string mrdUri;
469ea2e6eecSWilly Tu 
470ea2e6eecSWilly Tu                     if (!json_util::readJson(mrdObj, asyncResp->res,
471ea2e6eecSWilly Tu                                              "@odata.id", mrdUri))
472ea2e6eecSWilly Tu 
473144b6318SAppaRao Puli                     {
474144b6318SAppaRao Puli                         return;
475144b6318SAppaRao Puli                     }
476ea2e6eecSWilly Tu                     subValue->metricReportDefinitions.emplace_back(mrdUri);
477144b6318SAppaRao Puli                 }
478156d6b00SAppaRao Puli             }
479156d6b00SAppaRao Puli 
480b52664e2SAppaRao Puli             std::string id =
481fffb8c1fSEd Tanous                 EventServiceManager::getInstance().addSubscription(subValue);
482b52664e2SAppaRao Puli             if (id.empty())
483e5aaf047SAppaRao Puli             {
484e5aaf047SAppaRao Puli                 messages::internalError(asyncResp->res);
485e5aaf047SAppaRao Puli                 return;
486e5aaf047SAppaRao Puli             }
487e5aaf047SAppaRao Puli 
488e5aaf047SAppaRao Puli             messages::created(asyncResp->res);
489e5aaf047SAppaRao Puli             asyncResp->res.addHeader(
490e5aaf047SAppaRao Puli                 "Location", "/redfish/v1/EventService/Subscriptions/" + id);
4917e860f15SJohn Edward Broadbent         });
492e5aaf047SAppaRao Puli }
493e5aaf047SAppaRao Puli 
4947e860f15SJohn Edward Broadbent inline void requestRoutesEventDestination(App& app)
495e5aaf047SAppaRao Puli {
4969d41aec6SRavi Teja     BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/<str>/")
497ed398213SEd Tanous         .privileges(redfish::privileges::getEventDestination)
4987e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::get)(
49945ca1b86SEd Tanous             [&app](const crow::Request& req,
5007e860f15SJohn Edward Broadbent                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
5017e860f15SJohn Edward Broadbent                    const std::string& param) {
50245ca1b86SEd Tanous                 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
50345ca1b86SEd Tanous                 {
50445ca1b86SEd Tanous                     return;
50545ca1b86SEd Tanous                 }
506b52664e2SAppaRao Puli                 std::shared_ptr<Subscription> subValue =
5077e860f15SJohn Edward Broadbent                     EventServiceManager::getInstance().getSubscription(param);
508b52664e2SAppaRao Puli                 if (subValue == nullptr)
509e5aaf047SAppaRao Puli                 {
5107e860f15SJohn Edward Broadbent                     asyncResp->res.result(
5117e860f15SJohn Edward Broadbent                         boost::beast::http::status::not_found);
512e5aaf047SAppaRao Puli                     return;
513e5aaf047SAppaRao Puli                 }
5147e860f15SJohn Edward Broadbent                 const std::string& id = param;
515e5aaf047SAppaRao Puli 
516*1476687dSEd Tanous                 asyncResp->res.jsonValue["@odata.type"] =
517*1476687dSEd Tanous                     "#EventDestination.v1_7_0.EventDestination";
518*1476687dSEd Tanous                 asyncResp->res.jsonValue["Protocol"] = "Redfish";
519e5aaf047SAppaRao Puli                 asyncResp->res.jsonValue["@odata.id"] =
520e5aaf047SAppaRao Puli                     "/redfish/v1/EventService/Subscriptions/" + id;
521e5aaf047SAppaRao Puli                 asyncResp->res.jsonValue["Id"] = id;
522e5aaf047SAppaRao Puli                 asyncResp->res.jsonValue["Name"] = "Event Destination " + id;
5237e860f15SJohn Edward Broadbent                 asyncResp->res.jsonValue["Destination"] =
5247e860f15SJohn Edward Broadbent                     subValue->destinationUrl;
525b52664e2SAppaRao Puli                 asyncResp->res.jsonValue["Context"] = subValue->customText;
526e5aaf047SAppaRao Puli                 asyncResp->res.jsonValue["SubscriptionType"] =
527b52664e2SAppaRao Puli                     subValue->subscriptionType;
528ad22fefeSEd Tanous                 asyncResp->res.jsonValue["HttpHeaders"] =
529ad22fefeSEd Tanous                     nlohmann::json::array();
5307e860f15SJohn Edward Broadbent                 asyncResp->res.jsonValue["EventFormatType"] =
5317e860f15SJohn Edward Broadbent                     subValue->eventFormatType;
532e5aaf047SAppaRao Puli                 asyncResp->res.jsonValue["RegistryPrefixes"] =
533b52664e2SAppaRao Puli                     subValue->registryPrefixes;
5347e860f15SJohn Edward Broadbent                 asyncResp->res.jsonValue["ResourceTypes"] =
5357e860f15SJohn Edward Broadbent                     subValue->resourceTypes;
536e56f254cSSunitha Harish 
5377e860f15SJohn Edward Broadbent                 asyncResp->res.jsonValue["MessageIds"] =
5387e860f15SJohn Edward Broadbent                     subValue->registryMsgIds;
5397e860f15SJohn Edward Broadbent                 asyncResp->res.jsonValue["DeliveryRetryPolicy"] =
5407e860f15SJohn Edward Broadbent                     subValue->retryPolicy;
541144b6318SAppaRao Puli 
542*1476687dSEd Tanous                 nlohmann::json::array_t mrdJsonArray;
543144b6318SAppaRao Puli                 for (const auto& mdrUri : subValue->metricReportDefinitions)
544144b6318SAppaRao Puli                 {
545*1476687dSEd Tanous                     nlohmann::json::object_t mdr;
546*1476687dSEd Tanous                     mdr["@odata.id"] = mdrUri;
547*1476687dSEd Tanous                     mrdJsonArray.emplace_back(std::move(mdr));
548144b6318SAppaRao Puli                 }
5497e860f15SJohn Edward Broadbent                 asyncResp->res.jsonValue["MetricReportDefinitions"] =
5507e860f15SJohn Edward Broadbent                     mrdJsonArray;
5517e860f15SJohn Edward Broadbent             });
5529d41aec6SRavi Teja     BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/<str>/")
553ed398213SEd Tanous         // The below privilege is wrong, it should be ConfigureManager OR
554ed398213SEd Tanous         // ConfigureSelf
5557eeafa76SAbhishek Patel         // https://github.com/openbmc/bmcweb/issues/220
556ed398213SEd Tanous         //.privileges(redfish::privileges::patchEventDestination)
557432a890cSEd Tanous         .privileges({{"ConfigureManager"}})
5587e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::patch)(
55945ca1b86SEd Tanous             [&app](const crow::Request& req,
5607e860f15SJohn Edward Broadbent                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
5617e860f15SJohn Edward Broadbent                    const std::string& param) {
56245ca1b86SEd Tanous                 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
56345ca1b86SEd Tanous                 {
56445ca1b86SEd Tanous                     return;
56545ca1b86SEd Tanous                 }
566b52664e2SAppaRao Puli                 std::shared_ptr<Subscription> subValue =
5677e860f15SJohn Edward Broadbent                     EventServiceManager::getInstance().getSubscription(param);
568b52664e2SAppaRao Puli                 if (subValue == nullptr)
569e5aaf047SAppaRao Puli                 {
5707e860f15SJohn Edward Broadbent                     asyncResp->res.result(
5717e860f15SJohn Edward Broadbent                         boost::beast::http::status::not_found);
572e5aaf047SAppaRao Puli                     return;
573e5aaf047SAppaRao Puli                 }
574e5aaf047SAppaRao Puli 
575e5aaf047SAppaRao Puli                 std::optional<std::string> context;
576e5aaf047SAppaRao Puli                 std::optional<std::string> retryPolicy;
577e5aaf047SAppaRao Puli                 std::optional<std::vector<nlohmann::json>> headers;
578e5aaf047SAppaRao Puli 
57915ed6780SWilly Tu                 if (!json_util::readJsonPatch(req, asyncResp->res, "Context",
5807e860f15SJohn Edward Broadbent                                               context, "DeliveryRetryPolicy",
58115ed6780SWilly Tu                                               retryPolicy, "HttpHeaders",
58215ed6780SWilly Tu                                               headers))
583e5aaf047SAppaRao Puli                 {
584e5aaf047SAppaRao Puli                     return;
585e5aaf047SAppaRao Puli                 }
586e5aaf047SAppaRao Puli 
587e5aaf047SAppaRao Puli                 if (context)
588e5aaf047SAppaRao Puli                 {
589b52664e2SAppaRao Puli                     subValue->customText = *context;
590e5aaf047SAppaRao Puli                 }
591e5aaf047SAppaRao Puli 
592e5aaf047SAppaRao Puli                 if (headers)
593e5aaf047SAppaRao Puli                 {
594601c71aeSEd Tanous                     boost::beast::http::fields fields;
595601c71aeSEd Tanous                     for (const nlohmann::json& headerChunk : *headers)
596601c71aeSEd Tanous                     {
597601c71aeSEd Tanous                         for (auto& it : headerChunk.items())
598601c71aeSEd Tanous                         {
599601c71aeSEd Tanous                             const std::string* value =
600601c71aeSEd Tanous                                 it.value().get_ptr<const std::string*>();
601601c71aeSEd Tanous                             if (value == nullptr)
602601c71aeSEd Tanous                             {
603601c71aeSEd Tanous                                 messages::propertyValueFormatError(
604601c71aeSEd Tanous                                     asyncResp->res,
605601c71aeSEd Tanous                                     it.value().dump(2, ' ', true),
606601c71aeSEd Tanous                                     "HttpHeaders/" + it.key());
607601c71aeSEd Tanous                                 return;
608601c71aeSEd Tanous                             }
609601c71aeSEd Tanous                             fields.set(it.key(), *value);
610601c71aeSEd Tanous                         }
611601c71aeSEd Tanous                     }
612601c71aeSEd Tanous                     subValue->httpHeaders = fields;
613e5aaf047SAppaRao Puli                 }
614e5aaf047SAppaRao Puli 
615e5aaf047SAppaRao Puli                 if (retryPolicy)
616e5aaf047SAppaRao Puli                 {
617e5aaf047SAppaRao Puli                     if (std::find(supportedRetryPolicies.begin(),
618e5aaf047SAppaRao Puli                                   supportedRetryPolicies.end(),
619e5aaf047SAppaRao Puli                                   *retryPolicy) == supportedRetryPolicies.end())
620e5aaf047SAppaRao Puli                     {
6217e860f15SJohn Edward Broadbent                         messages::propertyValueNotInList(asyncResp->res,
6227e860f15SJohn Edward Broadbent                                                          *retryPolicy,
623e5aaf047SAppaRao Puli                                                          "DeliveryRetryPolicy");
624e5aaf047SAppaRao Puli                         return;
625e5aaf047SAppaRao Puli                     }
626b52664e2SAppaRao Puli                     subValue->retryPolicy = *retryPolicy;
627fe44eb0bSAyushi Smriti                     subValue->updateRetryPolicy();
628e5aaf047SAppaRao Puli                 }
629e5aaf047SAppaRao Puli 
630b52664e2SAppaRao Puli                 EventServiceManager::getInstance().updateSubscriptionData();
6317e860f15SJohn Edward Broadbent             });
6329d41aec6SRavi Teja     BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/<str>/")
633ed398213SEd Tanous         // The below privilege is wrong, it should be ConfigureManager OR
634ed398213SEd Tanous         // ConfigureSelf
6357eeafa76SAbhishek Patel         // https://github.com/openbmc/bmcweb/issues/220
636ed398213SEd Tanous         //.privileges(redfish::privileges::deleteEventDestination)
637432a890cSEd Tanous         .privileges({{"ConfigureManager"}})
6387e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::delete_)(
63945ca1b86SEd Tanous             [&app](const crow::Request& req,
6407e860f15SJohn Edward Broadbent                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
6417e860f15SJohn Edward Broadbent                    const std::string& param) {
64245ca1b86SEd Tanous                 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
64345ca1b86SEd Tanous                 {
64445ca1b86SEd Tanous                     return;
64545ca1b86SEd Tanous                 }
6467e860f15SJohn Edward Broadbent                 if (!EventServiceManager::getInstance().isSubscriptionExist(
6477e860f15SJohn Edward Broadbent                         param))
648e5aaf047SAppaRao Puli                 {
6497e860f15SJohn Edward Broadbent                     asyncResp->res.result(
6507e860f15SJohn Edward Broadbent                         boost::beast::http::status::not_found);
651e5aaf047SAppaRao Puli                     return;
652e5aaf047SAppaRao Puli                 }
6537e860f15SJohn Edward Broadbent                 EventServiceManager::getInstance().deleteSubscription(param);
6547e860f15SJohn Edward Broadbent             });
655e5aaf047SAppaRao Puli }
656e5aaf047SAppaRao Puli 
657e5aaf047SAppaRao Puli } // namespace redfish
658