xref: /openbmc/bmcweb/features/redfish/lib/event_service.hpp (revision eb1c47d3d98a186164ffb90214037c6062da7937)
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>
21*eb1c47d3SEd Tanous #include <http/utility.hpp>
22*eb1c47d3SEd 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             }
608d1b46d7Szhanghch05             asyncResp->res.jsonValue = {
61e5aaf047SAppaRao Puli                 {"@odata.type", "#EventService.v1_5_0.EventService"},
62e5aaf047SAppaRao Puli                 {"Id", "EventService"},
63e5aaf047SAppaRao Puli                 {"Name", "Event Service"},
64e5aaf047SAppaRao Puli                 {"Subscriptions",
65e5aaf047SAppaRao Puli                  {{"@odata.id", "/redfish/v1/EventService/Subscriptions"}}},
660b4bdd93SAppaRao Puli                 {"Actions",
670b4bdd93SAppaRao Puli                  {{"#EventService.SubmitTestEvent",
680fda0f12SGeorge Liu                    {{"target",
690fda0f12SGeorge Liu                      "/redfish/v1/EventService/Actions/EventService.SubmitTestEvent"}}}}},
70e5aaf047SAppaRao Puli                 {"@odata.id", "/redfish/v1/EventService"}};
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                 }
1988d1b46d7Szhanghch05                 asyncResp->res.jsonValue = {
199e5aaf047SAppaRao Puli                     {"@odata.type",
200e5aaf047SAppaRao Puli                      "#EventDestinationCollection.EventDestinationCollection"},
201e5aaf047SAppaRao Puli                     {"@odata.id", "/redfish/v1/EventService/Subscriptions"},
202e5aaf047SAppaRao Puli                     {"Name", "Event Destination Collections"}};
203e5aaf047SAppaRao Puli 
2047e860f15SJohn Edward Broadbent                 nlohmann::json& memberArray =
2057e860f15SJohn Edward Broadbent                     asyncResp->res.jsonValue["Members"];
206e5aaf047SAppaRao Puli 
207b52664e2SAppaRao Puli                 std::vector<std::string> subscripIds =
208b52664e2SAppaRao Puli                     EventServiceManager::getInstance().getAllIDs();
209b52664e2SAppaRao Puli                 memberArray = nlohmann::json::array();
2107e860f15SJohn Edward Broadbent                 asyncResp->res.jsonValue["Members@odata.count"] =
2117e860f15SJohn Edward Broadbent                     subscripIds.size();
212b52664e2SAppaRao Puli 
213b52664e2SAppaRao Puli                 for (const std::string& id : subscripIds)
214e5aaf047SAppaRao Puli                 {
215e5aaf047SAppaRao Puli                     memberArray.push_back(
216e5aaf047SAppaRao Puli                         {{"@odata.id",
217b52664e2SAppaRao Puli                           "/redfish/v1/EventService/Subscriptions/" + id}});
218e5aaf047SAppaRao Puli                 }
2197e860f15SJohn Edward Broadbent             });
2207e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/")
2217eeafa76SAbhishek Patel         .privileges(redfish::privileges::postEventDestinationCollection)
222fffb8c1fSEd Tanous         .methods(
223fffb8c1fSEd Tanous             boost::beast::http::verb::
22445ca1b86SEd Tanous                 post)([&app](
22545ca1b86SEd Tanous                           const crow::Request& req,
2267e860f15SJohn Edward Broadbent                           const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
22745ca1b86SEd Tanous             if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
22845ca1b86SEd Tanous             {
22945ca1b86SEd Tanous                 return;
23045ca1b86SEd Tanous             }
231fffb8c1fSEd Tanous             if (EventServiceManager::getInstance().getNumberOfSubscriptions() >=
232fffb8c1fSEd Tanous                 maxNoOfSubscriptions)
233e5aaf047SAppaRao Puli             {
234e5aaf047SAppaRao Puli                 messages::eventSubscriptionLimitExceeded(asyncResp->res);
235e5aaf047SAppaRao Puli                 return;
236e5aaf047SAppaRao Puli             }
237e5aaf047SAppaRao Puli             std::string destUrl;
238e5aaf047SAppaRao Puli             std::string protocol;
239e5aaf047SAppaRao Puli             std::optional<std::string> context;
240e5aaf047SAppaRao Puli             std::optional<std::string> subscriptionType;
24123a21a1cSEd Tanous             std::optional<std::string> eventFormatType2;
242e5aaf047SAppaRao Puli             std::optional<std::string> retryPolicy;
243e5aaf047SAppaRao Puli             std::optional<std::vector<std::string>> msgIds;
244e5aaf047SAppaRao Puli             std::optional<std::vector<std::string>> regPrefixes;
245e56f254cSSunitha Harish             std::optional<std::vector<std::string>> resTypes;
246e5aaf047SAppaRao Puli             std::optional<std::vector<nlohmann::json>> headers;
247144b6318SAppaRao Puli             std::optional<std::vector<nlohmann::json>> mrdJsonArray;
248e5aaf047SAppaRao Puli 
24915ed6780SWilly Tu             if (!json_util::readJsonPatch(
2507e860f15SJohn Edward Broadbent                     req, asyncResp->res, "Destination", destUrl, "Context",
2517e860f15SJohn Edward Broadbent                     context, "Protocol", protocol, "SubscriptionType",
2527e860f15SJohn Edward Broadbent                     subscriptionType, "EventFormatType", eventFormatType2,
2537e860f15SJohn Edward Broadbent                     "HttpHeaders", headers, "RegistryPrefixes", regPrefixes,
254fffb8c1fSEd Tanous                     "MessageIds", msgIds, "DeliveryRetryPolicy", retryPolicy,
255fffb8c1fSEd Tanous                     "MetricReportDefinitions", mrdJsonArray, "ResourceTypes",
256fffb8c1fSEd Tanous                     resTypes))
257e5aaf047SAppaRao Puli             {
258e5aaf047SAppaRao Puli                 return;
259e5aaf047SAppaRao Puli             }
260e5aaf047SAppaRao Puli 
261dd28ba82SAppaRao Puli             if (regPrefixes && msgIds)
262dd28ba82SAppaRao Puli             {
26326f6976fSEd Tanous                 if (!regPrefixes->empty() && !msgIds->empty())
264dd28ba82SAppaRao Puli                 {
2650a4304cfSEd Tanous                     messages::propertyValueConflict(
2660a4304cfSEd Tanous                         asyncResp->res, "MessageIds", "RegistryPrefixes");
267dd28ba82SAppaRao Puli                     return;
268dd28ba82SAppaRao Puli                 }
269dd28ba82SAppaRao Puli             }
270dd28ba82SAppaRao Puli 
271*eb1c47d3SEd Tanous             std::string host;
272*eb1c47d3SEd Tanous             std::string urlProto;
273*eb1c47d3SEd Tanous             uint16_t port = 0;
274*eb1c47d3SEd Tanous             std::string path;
275*eb1c47d3SEd Tanous 
276*eb1c47d3SEd Tanous             if (!crow::utility::validateAndSplitUrl(destUrl, urlProto, host,
277*eb1c47d3SEd Tanous                                                     port, path))
278e5aaf047SAppaRao Puli             {
279*eb1c47d3SEd Tanous                 BMCWEB_LOG_WARNING
280*eb1c47d3SEd Tanous                     << "Failed to validate and split destination url";
281e5aaf047SAppaRao Puli                 messages::propertyValueFormatError(asyncResp->res, destUrl,
282e5aaf047SAppaRao Puli                                                    "Destination");
283e5aaf047SAppaRao Puli                 return;
284e5aaf047SAppaRao Puli             }
285b52664e2SAppaRao Puli 
286b52664e2SAppaRao Puli             if (path.empty())
287b52664e2SAppaRao Puli             {
288b52664e2SAppaRao Puli                 path = "/";
289b52664e2SAppaRao Puli             }
290b52664e2SAppaRao Puli             std::shared_ptr<Subscription> subValue =
291*eb1c47d3SEd Tanous                 std::make_shared<Subscription>(host, port, path, urlProto);
292b52664e2SAppaRao Puli 
293b52664e2SAppaRao Puli             subValue->destinationUrl = destUrl;
294e5aaf047SAppaRao Puli 
295e5aaf047SAppaRao Puli             if (subscriptionType)
296e5aaf047SAppaRao Puli             {
297e5aaf047SAppaRao Puli                 if (*subscriptionType != "RedfishEvent")
298e5aaf047SAppaRao Puli                 {
299fffb8c1fSEd Tanous                     messages::propertyValueNotInList(
300fffb8c1fSEd Tanous                         asyncResp->res, *subscriptionType, "SubscriptionType");
301e5aaf047SAppaRao Puli                     return;
302e5aaf047SAppaRao Puli                 }
303b52664e2SAppaRao Puli                 subValue->subscriptionType = *subscriptionType;
304e5aaf047SAppaRao Puli             }
305e5aaf047SAppaRao Puli             else
306e5aaf047SAppaRao Puli             {
307b52664e2SAppaRao Puli                 subValue->subscriptionType = "RedfishEvent"; // Default
308e5aaf047SAppaRao Puli             }
309e5aaf047SAppaRao Puli 
310e5aaf047SAppaRao Puli             if (protocol != "Redfish")
311e5aaf047SAppaRao Puli             {
312e5aaf047SAppaRao Puli                 messages::propertyValueNotInList(asyncResp->res, protocol,
313e5aaf047SAppaRao Puli                                                  "Protocol");
314e5aaf047SAppaRao Puli                 return;
315e5aaf047SAppaRao Puli             }
316b52664e2SAppaRao Puli             subValue->protocol = protocol;
317e5aaf047SAppaRao Puli 
31823a21a1cSEd Tanous             if (eventFormatType2)
319e5aaf047SAppaRao Puli             {
320e5aaf047SAppaRao Puli                 if (std::find(supportedEvtFormatTypes.begin(),
321e5aaf047SAppaRao Puli                               supportedEvtFormatTypes.end(),
3227e860f15SJohn Edward Broadbent                               *eventFormatType2) ==
3237e860f15SJohn Edward Broadbent                     supportedEvtFormatTypes.end())
324e5aaf047SAppaRao Puli                 {
325fffb8c1fSEd Tanous                     messages::propertyValueNotInList(
326fffb8c1fSEd Tanous                         asyncResp->res, *eventFormatType2, "EventFormatType");
327e5aaf047SAppaRao Puli                     return;
328e5aaf047SAppaRao Puli                 }
32923a21a1cSEd Tanous                 subValue->eventFormatType = *eventFormatType2;
330e5aaf047SAppaRao Puli             }
331e5aaf047SAppaRao Puli             else
332e5aaf047SAppaRao Puli             {
333e5aaf047SAppaRao Puli                 // If not specified, use default "Event"
33423a21a1cSEd Tanous                 subValue->eventFormatType = "Event";
335e5aaf047SAppaRao Puli             }
336e5aaf047SAppaRao Puli 
337e5aaf047SAppaRao Puli             if (context)
338e5aaf047SAppaRao Puli             {
339b52664e2SAppaRao Puli                 subValue->customText = *context;
340e5aaf047SAppaRao Puli             }
341e5aaf047SAppaRao Puli 
342e5aaf047SAppaRao Puli             if (headers)
343e5aaf047SAppaRao Puli             {
344601c71aeSEd Tanous                 for (const nlohmann::json& headerChunk : *headers)
345601c71aeSEd Tanous                 {
346601c71aeSEd Tanous                     for (const auto& item : headerChunk.items())
347601c71aeSEd Tanous                     {
348601c71aeSEd Tanous                         const std::string* value =
349601c71aeSEd Tanous                             item.value().get_ptr<const std::string*>();
350601c71aeSEd Tanous                         if (value == nullptr)
351601c71aeSEd Tanous                         {
352601c71aeSEd Tanous                             messages::propertyValueFormatError(
353e662eae8SEd Tanous                                 asyncResp->res, item.value().dump(2, 1),
354601c71aeSEd Tanous                                 "HttpHeaders/" + item.key());
355601c71aeSEd Tanous                             return;
356601c71aeSEd Tanous                         }
357601c71aeSEd Tanous                         subValue->httpHeaders.set(item.key(), *value);
358601c71aeSEd Tanous                     }
359601c71aeSEd Tanous                 }
360e5aaf047SAppaRao Puli             }
361e5aaf047SAppaRao Puli 
362e5aaf047SAppaRao Puli             if (regPrefixes)
363e5aaf047SAppaRao Puli             {
364e5aaf047SAppaRao Puli                 for (const std::string& it : *regPrefixes)
365e5aaf047SAppaRao Puli                 {
366e5aaf047SAppaRao Puli                     if (std::find(supportedRegPrefixes.begin(),
367e5aaf047SAppaRao Puli                                   supportedRegPrefixes.end(),
368e5aaf047SAppaRao Puli                                   it) == supportedRegPrefixes.end())
369e5aaf047SAppaRao Puli                     {
370fffb8c1fSEd Tanous                         messages::propertyValueNotInList(asyncResp->res, it,
371fffb8c1fSEd Tanous                                                          "RegistryPrefixes");
372e5aaf047SAppaRao Puli                         return;
373e5aaf047SAppaRao Puli                     }
374e5aaf047SAppaRao Puli                 }
375b52664e2SAppaRao Puli                 subValue->registryPrefixes = *regPrefixes;
376e5aaf047SAppaRao Puli             }
377e5aaf047SAppaRao Puli 
378e56f254cSSunitha Harish             if (resTypes)
379e56f254cSSunitha Harish             {
380e56f254cSSunitha Harish                 for (const std::string& it : *resTypes)
381e56f254cSSunitha Harish                 {
382e56f254cSSunitha Harish                     if (std::find(supportedResourceTypes.begin(),
383e56f254cSSunitha Harish                                   supportedResourceTypes.end(),
384e56f254cSSunitha Harish                                   it) == supportedResourceTypes.end())
385e56f254cSSunitha Harish                     {
386e56f254cSSunitha Harish                         messages::propertyValueNotInList(asyncResp->res, it,
387e56f254cSSunitha Harish                                                          "ResourceTypes");
388e56f254cSSunitha Harish                         return;
389e56f254cSSunitha Harish                     }
390e56f254cSSunitha Harish                 }
391e56f254cSSunitha Harish                 subValue->resourceTypes = *resTypes;
392e56f254cSSunitha Harish             }
393e56f254cSSunitha Harish 
394e5aaf047SAppaRao Puli             if (msgIds)
395e5aaf047SAppaRao Puli             {
396b304bd79SP Dheeraj Srujan Kumar                 std::vector<std::string> registryPrefix;
397b304bd79SP Dheeraj Srujan Kumar 
3987e860f15SJohn Edward Broadbent                 // If no registry prefixes are mentioned, consider all
3997e860f15SJohn Edward Broadbent                 // supported prefixes
400b304bd79SP Dheeraj Srujan Kumar                 if (subValue->registryPrefixes.empty())
401b304bd79SP Dheeraj Srujan Kumar                 {
402b304bd79SP Dheeraj Srujan Kumar                     registryPrefix.assign(supportedRegPrefixes.begin(),
403b304bd79SP Dheeraj Srujan Kumar                                           supportedRegPrefixes.end());
404b304bd79SP Dheeraj Srujan Kumar                 }
405b304bd79SP Dheeraj Srujan Kumar                 else
406b304bd79SP Dheeraj Srujan Kumar                 {
407b304bd79SP Dheeraj Srujan Kumar                     registryPrefix = subValue->registryPrefixes;
408b304bd79SP Dheeraj Srujan Kumar                 }
409b304bd79SP Dheeraj Srujan Kumar 
410b304bd79SP Dheeraj Srujan Kumar                 for (const std::string& id : *msgIds)
411b304bd79SP Dheeraj Srujan Kumar                 {
412b304bd79SP Dheeraj Srujan Kumar                     bool validId = false;
413b304bd79SP Dheeraj Srujan Kumar 
414b304bd79SP Dheeraj Srujan Kumar                     // Check for Message ID in each of the selected Registry
415b304bd79SP Dheeraj Srujan Kumar                     for (const std::string& it : registryPrefix)
416b304bd79SP Dheeraj Srujan Kumar                     {
417fffb8c1fSEd Tanous                         const std::span<const redfish::registries::MessageEntry>
418fffb8c1fSEd Tanous                             registry =
419fffb8c1fSEd Tanous                                 redfish::registries::getRegistryFromPrefix(it);
420b304bd79SP Dheeraj Srujan Kumar 
421b304bd79SP Dheeraj Srujan Kumar                         if (std::any_of(
42226702d01SEd Tanous                                 registry.begin(), registry.end(),
423fffb8c1fSEd Tanous                                 [&id](const redfish::registries::MessageEntry&
424fffb8c1fSEd Tanous                                           messageEntry) {
42555f79e6fSEd Tanous                                     return id == messageEntry.first;
426b304bd79SP Dheeraj Srujan Kumar                                 }))
427b304bd79SP Dheeraj Srujan Kumar                         {
428b304bd79SP Dheeraj Srujan Kumar                             validId = true;
429b304bd79SP Dheeraj Srujan Kumar                             break;
430b304bd79SP Dheeraj Srujan Kumar                         }
431b304bd79SP Dheeraj Srujan Kumar                     }
432b304bd79SP Dheeraj Srujan Kumar 
433b304bd79SP Dheeraj Srujan Kumar                     if (!validId)
434b304bd79SP Dheeraj Srujan Kumar                     {
435b304bd79SP Dheeraj Srujan Kumar                         messages::propertyValueNotInList(asyncResp->res, id,
436b304bd79SP Dheeraj Srujan Kumar                                                          "MessageIds");
437b304bd79SP Dheeraj Srujan Kumar                         return;
438b304bd79SP Dheeraj Srujan Kumar                     }
439b304bd79SP Dheeraj Srujan Kumar                 }
440b304bd79SP Dheeraj Srujan Kumar 
441b52664e2SAppaRao Puli                 subValue->registryMsgIds = *msgIds;
442e5aaf047SAppaRao Puli             }
443e5aaf047SAppaRao Puli 
444e5aaf047SAppaRao Puli             if (retryPolicy)
445e5aaf047SAppaRao Puli             {
446e5aaf047SAppaRao Puli                 if (std::find(supportedRetryPolicies.begin(),
447e5aaf047SAppaRao Puli                               supportedRetryPolicies.end(),
448e5aaf047SAppaRao Puli                               *retryPolicy) == supportedRetryPolicies.end())
449e5aaf047SAppaRao Puli                 {
450fffb8c1fSEd Tanous                     messages::propertyValueNotInList(
451fffb8c1fSEd Tanous                         asyncResp->res, *retryPolicy, "DeliveryRetryPolicy");
452e5aaf047SAppaRao Puli                     return;
453e5aaf047SAppaRao Puli                 }
454b52664e2SAppaRao Puli                 subValue->retryPolicy = *retryPolicy;
455e5aaf047SAppaRao Puli             }
456e5aaf047SAppaRao Puli             else
457e5aaf047SAppaRao Puli             {
458e5aaf047SAppaRao Puli                 // Default "TerminateAfterRetries"
459b52664e2SAppaRao Puli                 subValue->retryPolicy = "TerminateAfterRetries";
460e5aaf047SAppaRao Puli             }
461e5aaf047SAppaRao Puli 
462144b6318SAppaRao Puli             if (mrdJsonArray)
463156d6b00SAppaRao Puli             {
464144b6318SAppaRao Puli                 for (nlohmann::json& mrdObj : *mrdJsonArray)
465144b6318SAppaRao Puli                 {
466144b6318SAppaRao Puli                     std::string mrdUri;
467ea2e6eecSWilly Tu 
468ea2e6eecSWilly Tu                     if (!json_util::readJson(mrdObj, asyncResp->res,
469ea2e6eecSWilly Tu                                              "@odata.id", mrdUri))
470ea2e6eecSWilly Tu 
471144b6318SAppaRao Puli                     {
472144b6318SAppaRao Puli                         return;
473144b6318SAppaRao Puli                     }
474ea2e6eecSWilly Tu                     subValue->metricReportDefinitions.emplace_back(mrdUri);
475144b6318SAppaRao Puli                 }
476156d6b00SAppaRao Puli             }
477156d6b00SAppaRao Puli 
478b52664e2SAppaRao Puli             std::string id =
479fffb8c1fSEd Tanous                 EventServiceManager::getInstance().addSubscription(subValue);
480b52664e2SAppaRao Puli             if (id.empty())
481e5aaf047SAppaRao Puli             {
482e5aaf047SAppaRao Puli                 messages::internalError(asyncResp->res);
483e5aaf047SAppaRao Puli                 return;
484e5aaf047SAppaRao Puli             }
485e5aaf047SAppaRao Puli 
486e5aaf047SAppaRao Puli             messages::created(asyncResp->res);
487e5aaf047SAppaRao Puli             asyncResp->res.addHeader(
488e5aaf047SAppaRao Puli                 "Location", "/redfish/v1/EventService/Subscriptions/" + id);
4897e860f15SJohn Edward Broadbent         });
490e5aaf047SAppaRao Puli }
491e5aaf047SAppaRao Puli 
4927e860f15SJohn Edward Broadbent inline void requestRoutesEventDestination(App& app)
493e5aaf047SAppaRao Puli {
4949d41aec6SRavi Teja     BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/<str>/")
495ed398213SEd Tanous         .privileges(redfish::privileges::getEventDestination)
4967e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::get)(
49745ca1b86SEd Tanous             [&app](const crow::Request& req,
4987e860f15SJohn Edward Broadbent                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
4997e860f15SJohn Edward Broadbent                    const std::string& param) {
50045ca1b86SEd Tanous                 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
50145ca1b86SEd Tanous                 {
50245ca1b86SEd Tanous                     return;
50345ca1b86SEd Tanous                 }
504b52664e2SAppaRao Puli                 std::shared_ptr<Subscription> subValue =
5057e860f15SJohn Edward Broadbent                     EventServiceManager::getInstance().getSubscription(param);
506b52664e2SAppaRao Puli                 if (subValue == nullptr)
507e5aaf047SAppaRao Puli                 {
5087e860f15SJohn Edward Broadbent                     asyncResp->res.result(
5097e860f15SJohn Edward Broadbent                         boost::beast::http::status::not_found);
510e5aaf047SAppaRao Puli                     return;
511e5aaf047SAppaRao Puli                 }
5127e860f15SJohn Edward Broadbent                 const std::string& id = param;
513e5aaf047SAppaRao Puli 
5148d1b46d7Szhanghch05                 asyncResp->res.jsonValue = {
5157e860f15SJohn Edward Broadbent                     {"@odata.type",
5167e860f15SJohn Edward Broadbent                      "#EventDestination.v1_7_0.EventDestination"},
517e5aaf047SAppaRao Puli                     {"Protocol", "Redfish"}};
518e5aaf047SAppaRao Puli                 asyncResp->res.jsonValue["@odata.id"] =
519e5aaf047SAppaRao Puli                     "/redfish/v1/EventService/Subscriptions/" + id;
520e5aaf047SAppaRao Puli                 asyncResp->res.jsonValue["Id"] = id;
521e5aaf047SAppaRao Puli                 asyncResp->res.jsonValue["Name"] = "Event Destination " + id;
5227e860f15SJohn Edward Broadbent                 asyncResp->res.jsonValue["Destination"] =
5237e860f15SJohn Edward Broadbent                     subValue->destinationUrl;
524b52664e2SAppaRao Puli                 asyncResp->res.jsonValue["Context"] = subValue->customText;
525e5aaf047SAppaRao Puli                 asyncResp->res.jsonValue["SubscriptionType"] =
526b52664e2SAppaRao Puli                     subValue->subscriptionType;
527ad22fefeSEd Tanous                 asyncResp->res.jsonValue["HttpHeaders"] =
528ad22fefeSEd Tanous                     nlohmann::json::array();
5297e860f15SJohn Edward Broadbent                 asyncResp->res.jsonValue["EventFormatType"] =
5307e860f15SJohn Edward Broadbent                     subValue->eventFormatType;
531e5aaf047SAppaRao Puli                 asyncResp->res.jsonValue["RegistryPrefixes"] =
532b52664e2SAppaRao Puli                     subValue->registryPrefixes;
5337e860f15SJohn Edward Broadbent                 asyncResp->res.jsonValue["ResourceTypes"] =
5347e860f15SJohn Edward Broadbent                     subValue->resourceTypes;
535e56f254cSSunitha Harish 
5367e860f15SJohn Edward Broadbent                 asyncResp->res.jsonValue["MessageIds"] =
5377e860f15SJohn Edward Broadbent                     subValue->registryMsgIds;
5387e860f15SJohn Edward Broadbent                 asyncResp->res.jsonValue["DeliveryRetryPolicy"] =
5397e860f15SJohn Edward Broadbent                     subValue->retryPolicy;
540144b6318SAppaRao Puli 
541144b6318SAppaRao Puli                 std::vector<nlohmann::json> mrdJsonArray;
542144b6318SAppaRao Puli                 for (const auto& mdrUri : subValue->metricReportDefinitions)
543144b6318SAppaRao Puli                 {
544144b6318SAppaRao Puli                     mrdJsonArray.push_back({{"@odata.id", mdrUri}});
545144b6318SAppaRao Puli                 }
5467e860f15SJohn Edward Broadbent                 asyncResp->res.jsonValue["MetricReportDefinitions"] =
5477e860f15SJohn Edward Broadbent                     mrdJsonArray;
5487e860f15SJohn Edward Broadbent             });
5499d41aec6SRavi Teja     BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/<str>/")
550ed398213SEd Tanous         // The below privilege is wrong, it should be ConfigureManager OR
551ed398213SEd Tanous         // ConfigureSelf
5527eeafa76SAbhishek Patel         // https://github.com/openbmc/bmcweb/issues/220
553ed398213SEd Tanous         //.privileges(redfish::privileges::patchEventDestination)
554432a890cSEd Tanous         .privileges({{"ConfigureManager"}})
5557e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::patch)(
55645ca1b86SEd Tanous             [&app](const crow::Request& req,
5577e860f15SJohn Edward Broadbent                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
5587e860f15SJohn Edward Broadbent                    const std::string& param) {
55945ca1b86SEd Tanous                 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
56045ca1b86SEd Tanous                 {
56145ca1b86SEd Tanous                     return;
56245ca1b86SEd Tanous                 }
563b52664e2SAppaRao Puli                 std::shared_ptr<Subscription> subValue =
5647e860f15SJohn Edward Broadbent                     EventServiceManager::getInstance().getSubscription(param);
565b52664e2SAppaRao Puli                 if (subValue == nullptr)
566e5aaf047SAppaRao Puli                 {
5677e860f15SJohn Edward Broadbent                     asyncResp->res.result(
5687e860f15SJohn Edward Broadbent                         boost::beast::http::status::not_found);
569e5aaf047SAppaRao Puli                     return;
570e5aaf047SAppaRao Puli                 }
571e5aaf047SAppaRao Puli 
572e5aaf047SAppaRao Puli                 std::optional<std::string> context;
573e5aaf047SAppaRao Puli                 std::optional<std::string> retryPolicy;
574e5aaf047SAppaRao Puli                 std::optional<std::vector<nlohmann::json>> headers;
575e5aaf047SAppaRao Puli 
57615ed6780SWilly Tu                 if (!json_util::readJsonPatch(req, asyncResp->res, "Context",
5777e860f15SJohn Edward Broadbent                                               context, "DeliveryRetryPolicy",
57815ed6780SWilly Tu                                               retryPolicy, "HttpHeaders",
57915ed6780SWilly Tu                                               headers))
580e5aaf047SAppaRao Puli                 {
581e5aaf047SAppaRao Puli                     return;
582e5aaf047SAppaRao Puli                 }
583e5aaf047SAppaRao Puli 
584e5aaf047SAppaRao Puli                 if (context)
585e5aaf047SAppaRao Puli                 {
586b52664e2SAppaRao Puli                     subValue->customText = *context;
587e5aaf047SAppaRao Puli                 }
588e5aaf047SAppaRao Puli 
589e5aaf047SAppaRao Puli                 if (headers)
590e5aaf047SAppaRao Puli                 {
591601c71aeSEd Tanous                     boost::beast::http::fields fields;
592601c71aeSEd Tanous                     for (const nlohmann::json& headerChunk : *headers)
593601c71aeSEd Tanous                     {
594601c71aeSEd Tanous                         for (auto& it : headerChunk.items())
595601c71aeSEd Tanous                         {
596601c71aeSEd Tanous                             const std::string* value =
597601c71aeSEd Tanous                                 it.value().get_ptr<const std::string*>();
598601c71aeSEd Tanous                             if (value == nullptr)
599601c71aeSEd Tanous                             {
600601c71aeSEd Tanous                                 messages::propertyValueFormatError(
601601c71aeSEd Tanous                                     asyncResp->res,
602601c71aeSEd Tanous                                     it.value().dump(2, ' ', true),
603601c71aeSEd Tanous                                     "HttpHeaders/" + it.key());
604601c71aeSEd Tanous                                 return;
605601c71aeSEd Tanous                             }
606601c71aeSEd Tanous                             fields.set(it.key(), *value);
607601c71aeSEd Tanous                         }
608601c71aeSEd Tanous                     }
609601c71aeSEd Tanous                     subValue->httpHeaders = fields;
610e5aaf047SAppaRao Puli                 }
611e5aaf047SAppaRao Puli 
612e5aaf047SAppaRao Puli                 if (retryPolicy)
613e5aaf047SAppaRao Puli                 {
614e5aaf047SAppaRao Puli                     if (std::find(supportedRetryPolicies.begin(),
615e5aaf047SAppaRao Puli                                   supportedRetryPolicies.end(),
616e5aaf047SAppaRao Puli                                   *retryPolicy) == supportedRetryPolicies.end())
617e5aaf047SAppaRao Puli                     {
6187e860f15SJohn Edward Broadbent                         messages::propertyValueNotInList(asyncResp->res,
6197e860f15SJohn Edward Broadbent                                                          *retryPolicy,
620e5aaf047SAppaRao Puli                                                          "DeliveryRetryPolicy");
621e5aaf047SAppaRao Puli                         return;
622e5aaf047SAppaRao Puli                     }
623b52664e2SAppaRao Puli                     subValue->retryPolicy = *retryPolicy;
624fe44eb0bSAyushi Smriti                     subValue->updateRetryPolicy();
625e5aaf047SAppaRao Puli                 }
626e5aaf047SAppaRao Puli 
627b52664e2SAppaRao Puli                 EventServiceManager::getInstance().updateSubscriptionData();
6287e860f15SJohn Edward Broadbent             });
6299d41aec6SRavi Teja     BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/<str>/")
630ed398213SEd Tanous         // The below privilege is wrong, it should be ConfigureManager OR
631ed398213SEd Tanous         // ConfigureSelf
6327eeafa76SAbhishek Patel         // https://github.com/openbmc/bmcweb/issues/220
633ed398213SEd Tanous         //.privileges(redfish::privileges::deleteEventDestination)
634432a890cSEd Tanous         .privileges({{"ConfigureManager"}})
6357e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::delete_)(
63645ca1b86SEd Tanous             [&app](const crow::Request& req,
6377e860f15SJohn Edward Broadbent                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
6387e860f15SJohn Edward Broadbent                    const std::string& param) {
63945ca1b86SEd Tanous                 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
64045ca1b86SEd Tanous                 {
64145ca1b86SEd Tanous                     return;
64245ca1b86SEd Tanous                 }
6437e860f15SJohn Edward Broadbent                 if (!EventServiceManager::getInstance().isSubscriptionExist(
6447e860f15SJohn Edward Broadbent                         param))
645e5aaf047SAppaRao Puli                 {
6467e860f15SJohn Edward Broadbent                     asyncResp->res.result(
6477e860f15SJohn Edward Broadbent                         boost::beast::http::status::not_found);
648e5aaf047SAppaRao Puli                     return;
649e5aaf047SAppaRao Puli                 }
6507e860f15SJohn Edward Broadbent                 EventServiceManager::getInstance().deleteSubscription(param);
6517e860f15SJohn Edward Broadbent             });
652e5aaf047SAppaRao Puli }
653e5aaf047SAppaRao Puli 
654e5aaf047SAppaRao Puli } // namespace redfish
655