xref: /openbmc/bmcweb/features/redfish/lib/event_service.hpp (revision 601c71aef4ac54e28933bc6e022c7e1f6e8bf1e8)
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>
20*601c71aeSEd Tanous #include <boost/beast/http/fields.hpp>
21ed398213SEd Tanous #include <registries/privilege_registry.hpp>
22ed398213SEd Tanous 
23e5aaf047SAppaRao Puli namespace redfish
24e5aaf047SAppaRao Puli {
25e5aaf047SAppaRao Puli 
26156d6b00SAppaRao Puli static constexpr const std::array<const char*, 2> supportedEvtFormatTypes = {
27156d6b00SAppaRao Puli     eventFormatType, metricReportFormatType};
28e5aaf047SAppaRao Puli static constexpr const std::array<const char*, 3> supportedRegPrefixes = {
29b304bd79SP Dheeraj Srujan Kumar     "Base", "OpenBMC", "TaskEvent"};
30e5aaf047SAppaRao Puli static constexpr const std::array<const char*, 3> supportedRetryPolicies = {
31e5aaf047SAppaRao Puli     "TerminateAfterRetries", "SuspendRetries", "RetryForever"};
32e5aaf047SAppaRao Puli 
33e56f254cSSunitha Harish #ifdef BMCWEB_ENABLE_IBM_MANAGEMENT_CONSOLE
34e56f254cSSunitha Harish static constexpr const std::array<const char*, 2> supportedResourceTypes = {
35e56f254cSSunitha Harish     "IBMConfigFile", "Task"};
36e56f254cSSunitha Harish #else
37e56f254cSSunitha Harish static constexpr const std::array<const char*, 1> supportedResourceTypes = {
38e56f254cSSunitha Harish     "Task"};
39e56f254cSSunitha Harish #endif
40e56f254cSSunitha Harish 
41e5aaf047SAppaRao Puli static constexpr const uint8_t maxNoOfSubscriptions = 20;
42e5aaf047SAppaRao Puli 
437e860f15SJohn Edward Broadbent inline void requestRoutesEventService(App& app)
44e5aaf047SAppaRao Puli {
457e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app, "/redfish/v1/EventService/")
46ed398213SEd Tanous         .privileges(redfish::privileges::getEventService)
477e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::get)(
487e860f15SJohn Edward Broadbent             [](const crow::Request&,
497e860f15SJohn Edward Broadbent                const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
508d1b46d7Szhanghch05                 asyncResp->res.jsonValue = {
51e5aaf047SAppaRao Puli                     {"@odata.type", "#EventService.v1_5_0.EventService"},
52e5aaf047SAppaRao Puli                     {"Id", "EventService"},
53e5aaf047SAppaRao Puli                     {"Name", "Event Service"},
54e5aaf047SAppaRao Puli                     {"Subscriptions",
55e5aaf047SAppaRao Puli                      {{"@odata.id", "/redfish/v1/EventService/Subscriptions"}}},
560b4bdd93SAppaRao Puli                     {"Actions",
570b4bdd93SAppaRao Puli                      {{"#EventService.SubmitTestEvent",
580b4bdd93SAppaRao Puli                        {{"target", "/redfish/v1/EventService/Actions/"
590b4bdd93SAppaRao Puli                                    "EventService.SubmitTestEvent"}}}}},
60e5aaf047SAppaRao Puli                     {"@odata.id", "/redfish/v1/EventService"}};
61e5aaf047SAppaRao Puli 
6228afb49cSJunLin Chen                 const persistent_data::EventServiceConfig eventServiceConfig =
6328afb49cSJunLin Chen                     persistent_data::EventServiceStore::getInstance()
6428afb49cSJunLin Chen                         .getEventServiceConfig();
657d1cc387SAppaRao Puli 
667d1cc387SAppaRao Puli                 asyncResp->res.jsonValue["Status"]["State"] =
6728afb49cSJunLin Chen                     (eventServiceConfig.enabled ? "Enabled" : "Disabled");
6828afb49cSJunLin Chen                 asyncResp->res.jsonValue["ServiceEnabled"] =
6928afb49cSJunLin Chen                     eventServiceConfig.enabled;
707e860f15SJohn Edward Broadbent                 asyncResp->res.jsonValue["DeliveryRetryAttempts"] =
7128afb49cSJunLin Chen                     eventServiceConfig.retryAttempts;
72e5aaf047SAppaRao Puli                 asyncResp->res.jsonValue["DeliveryRetryIntervalSeconds"] =
7328afb49cSJunLin Chen                     eventServiceConfig.retryTimeoutInterval;
747e860f15SJohn Edward Broadbent                 asyncResp->res.jsonValue["EventFormatTypes"] =
757e860f15SJohn Edward Broadbent                     supportedEvtFormatTypes;
767e860f15SJohn Edward Broadbent                 asyncResp->res.jsonValue["RegistryPrefixes"] =
777e860f15SJohn Edward Broadbent                     supportedRegPrefixes;
787e860f15SJohn Edward Broadbent                 asyncResp->res.jsonValue["ResourceTypes"] =
797e860f15SJohn Edward Broadbent                     supportedResourceTypes;
8007941a88SAyushi Smriti 
8107941a88SAyushi Smriti                 nlohmann::json supportedSSEFilters = {
8207941a88SAyushi Smriti                     {"EventFormatType", true},        {"MessageId", true},
8307941a88SAyushi Smriti                     {"MetricReportDefinition", true}, {"RegistryPrefix", true},
8407941a88SAyushi Smriti                     {"OriginResource", false},        {"ResourceType", false}};
8507941a88SAyushi Smriti 
8607941a88SAyushi Smriti                 asyncResp->res.jsonValue["SSEFilterPropertiesSupported"] =
8707941a88SAyushi Smriti                     supportedSSEFilters;
887e860f15SJohn Edward Broadbent             });
89e5aaf047SAppaRao Puli 
907e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app, "/redfish/v1/EventService/")
91ed398213SEd Tanous         .privileges(redfish::privileges::patchEventService)
927e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::patch)(
937e860f15SJohn Edward Broadbent             [](const crow::Request& req,
947e860f15SJohn Edward Broadbent                const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
957e860f15SJohn Edward Broadbent 
96e5aaf047SAppaRao Puli             {
97e5aaf047SAppaRao Puli                 std::optional<bool> serviceEnabled;
98e5aaf047SAppaRao Puli                 std::optional<uint32_t> retryAttemps;
99e5aaf047SAppaRao Puli                 std::optional<uint32_t> retryInterval;
100e5aaf047SAppaRao Puli 
1017e860f15SJohn Edward Broadbent                 if (!json_util::readJson(
1027e860f15SJohn Edward Broadbent                         req, asyncResp->res, "ServiceEnabled", serviceEnabled,
1037e860f15SJohn Edward Broadbent                         "DeliveryRetryAttempts", retryAttemps,
1047e860f15SJohn Edward Broadbent                         "DeliveryRetryIntervalSeconds", retryInterval))
105e5aaf047SAppaRao Puli                 {
106e5aaf047SAppaRao Puli                     return;
107e5aaf047SAppaRao Puli                 }
108e5aaf047SAppaRao Puli 
10928afb49cSJunLin Chen                 persistent_data::EventServiceConfig eventServiceConfig =
11028afb49cSJunLin Chen                     persistent_data::EventServiceStore::getInstance()
11128afb49cSJunLin Chen                         .getEventServiceConfig();
1127d1cc387SAppaRao Puli 
113e5aaf047SAppaRao Puli                 if (serviceEnabled)
114e5aaf047SAppaRao Puli                 {
11528afb49cSJunLin Chen                     eventServiceConfig.enabled = *serviceEnabled;
116e5aaf047SAppaRao Puli                 }
117e5aaf047SAppaRao Puli 
118e5aaf047SAppaRao Puli                 if (retryAttemps)
119e5aaf047SAppaRao Puli                 {
120e5aaf047SAppaRao Puli                     // Supported range [1-3]
121e5aaf047SAppaRao Puli                     if ((*retryAttemps < 1) || (*retryAttemps > 3))
122e5aaf047SAppaRao Puli                     {
123e5aaf047SAppaRao Puli                         messages::queryParameterOutOfRange(
124e5aaf047SAppaRao Puli                             asyncResp->res, std::to_string(*retryAttemps),
125e5aaf047SAppaRao Puli                             "DeliveryRetryAttempts", "[1-3]");
126e5aaf047SAppaRao Puli                     }
127e5aaf047SAppaRao Puli                     else
128e5aaf047SAppaRao Puli                     {
12928afb49cSJunLin Chen                         eventServiceConfig.retryAttempts = *retryAttemps;
130e5aaf047SAppaRao Puli                     }
131e5aaf047SAppaRao Puli                 }
132e5aaf047SAppaRao Puli 
133e5aaf047SAppaRao Puli                 if (retryInterval)
134e5aaf047SAppaRao Puli                 {
135e5aaf047SAppaRao Puli                     // Supported range [30 - 180]
136e5aaf047SAppaRao Puli                     if ((*retryInterval < 30) || (*retryInterval > 180))
137e5aaf047SAppaRao Puli                     {
138e5aaf047SAppaRao Puli                         messages::queryParameterOutOfRange(
139e5aaf047SAppaRao Puli                             asyncResp->res, std::to_string(*retryInterval),
140e5aaf047SAppaRao Puli                             "DeliveryRetryIntervalSeconds", "[30-180]");
141e5aaf047SAppaRao Puli                     }
142e5aaf047SAppaRao Puli                     else
143e5aaf047SAppaRao Puli                     {
14428afb49cSJunLin Chen                         eventServiceConfig.retryTimeoutInterval =
14528afb49cSJunLin Chen                             *retryInterval;
146e5aaf047SAppaRao Puli                     }
147e5aaf047SAppaRao Puli                 }
148e5aaf047SAppaRao Puli 
1497d1cc387SAppaRao Puli                 EventServiceManager::getInstance().setEventServiceConfig(
15028afb49cSJunLin Chen                     eventServiceConfig);
1517e860f15SJohn Edward Broadbent             });
1520b4bdd93SAppaRao Puli }
1530b4bdd93SAppaRao Puli 
1547e860f15SJohn Edward Broadbent inline void requestRoutesSubmitTestEvent(App& app)
1550b4bdd93SAppaRao Puli {
1567e860f15SJohn Edward Broadbent 
1577e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(
1587e860f15SJohn Edward Broadbent         app, "/redfish/v1/EventService/Actions/EventService.SubmitTestEvent/")
159ed398213SEd Tanous         .privileges(redfish::privileges::postEventService)
1607e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::post)(
1617e860f15SJohn Edward Broadbent             [](const crow::Request&,
1627e860f15SJohn Edward Broadbent                const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
1630b4bdd93SAppaRao Puli                 EventServiceManager::getInstance().sendTestEventLog();
1648d1b46d7Szhanghch05                 asyncResp->res.result(boost::beast::http::status::no_content);
1657e860f15SJohn Edward Broadbent             });
166e5aaf047SAppaRao Puli }
167e5aaf047SAppaRao Puli 
1687e860f15SJohn Edward Broadbent inline void requestRoutesEventDestinationCollection(App& app)
169e5aaf047SAppaRao Puli {
1707e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions")
171ed398213SEd Tanous         .privileges(redfish::privileges::getEventDestinationCollection)
1727e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::get)(
1737e860f15SJohn Edward Broadbent             [](const crow::Request&,
1747e860f15SJohn Edward Broadbent                const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
1758d1b46d7Szhanghch05                 asyncResp->res.jsonValue = {
176e5aaf047SAppaRao Puli                     {"@odata.type",
177e5aaf047SAppaRao Puli                      "#EventDestinationCollection.EventDestinationCollection"},
178e5aaf047SAppaRao Puli                     {"@odata.id", "/redfish/v1/EventService/Subscriptions"},
179e5aaf047SAppaRao Puli                     {"Name", "Event Destination Collections"}};
180e5aaf047SAppaRao Puli 
1817e860f15SJohn Edward Broadbent                 nlohmann::json& memberArray =
1827e860f15SJohn Edward Broadbent                     asyncResp->res.jsonValue["Members"];
183e5aaf047SAppaRao Puli 
184b52664e2SAppaRao Puli                 std::vector<std::string> subscripIds =
185b52664e2SAppaRao Puli                     EventServiceManager::getInstance().getAllIDs();
186b52664e2SAppaRao Puli                 memberArray = nlohmann::json::array();
1877e860f15SJohn Edward Broadbent                 asyncResp->res.jsonValue["Members@odata.count"] =
1887e860f15SJohn Edward Broadbent                     subscripIds.size();
189b52664e2SAppaRao Puli 
190b52664e2SAppaRao Puli                 for (const std::string& id : subscripIds)
191e5aaf047SAppaRao Puli                 {
192e5aaf047SAppaRao Puli                     memberArray.push_back(
193e5aaf047SAppaRao Puli                         {{"@odata.id",
194b52664e2SAppaRao Puli                           "/redfish/v1/EventService/Subscriptions/" + id}});
195e5aaf047SAppaRao Puli                 }
1967e860f15SJohn Edward Broadbent             });
1977e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/")
1987eeafa76SAbhishek Patel         .privileges(redfish::privileges::postEventDestinationCollection)
1997e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::post)(
2007e860f15SJohn Edward Broadbent             [](const crow::Request& req,
2017e860f15SJohn Edward Broadbent                const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
2027e860f15SJohn Edward Broadbent                 if (EventServiceManager::getInstance()
2037e860f15SJohn Edward Broadbent                         .getNumberOfSubscriptions() >= maxNoOfSubscriptions)
204e5aaf047SAppaRao Puli                 {
205e5aaf047SAppaRao Puli                     messages::eventSubscriptionLimitExceeded(asyncResp->res);
206e5aaf047SAppaRao Puli                     return;
207e5aaf047SAppaRao Puli                 }
208e5aaf047SAppaRao Puli                 std::string destUrl;
209e5aaf047SAppaRao Puli                 std::string protocol;
210e5aaf047SAppaRao Puli                 std::optional<std::string> context;
211e5aaf047SAppaRao Puli                 std::optional<std::string> subscriptionType;
21223a21a1cSEd Tanous                 std::optional<std::string> eventFormatType2;
213e5aaf047SAppaRao Puli                 std::optional<std::string> retryPolicy;
214e5aaf047SAppaRao Puli                 std::optional<std::vector<std::string>> msgIds;
215e5aaf047SAppaRao Puli                 std::optional<std::vector<std::string>> regPrefixes;
216e56f254cSSunitha Harish                 std::optional<std::vector<std::string>> resTypes;
217e5aaf047SAppaRao Puli                 std::optional<std::vector<nlohmann::json>> headers;
218144b6318SAppaRao Puli                 std::optional<std::vector<nlohmann::json>> mrdJsonArray;
219e5aaf047SAppaRao Puli 
220e5aaf047SAppaRao Puli                 if (!json_util::readJson(
2217e860f15SJohn Edward Broadbent                         req, asyncResp->res, "Destination", destUrl, "Context",
2227e860f15SJohn Edward Broadbent                         context, "Protocol", protocol, "SubscriptionType",
2237e860f15SJohn Edward Broadbent                         subscriptionType, "EventFormatType", eventFormatType2,
2247e860f15SJohn Edward Broadbent                         "HttpHeaders", headers, "RegistryPrefixes", regPrefixes,
2257e860f15SJohn Edward Broadbent                         "MessageIds", msgIds, "DeliveryRetryPolicy",
2267e860f15SJohn Edward Broadbent                         retryPolicy, "MetricReportDefinitions", mrdJsonArray,
2277e860f15SJohn Edward Broadbent                         "ResourceTypes", resTypes))
228e5aaf047SAppaRao Puli                 {
229e5aaf047SAppaRao Puli                     return;
230e5aaf047SAppaRao Puli                 }
231e5aaf047SAppaRao Puli 
232dd28ba82SAppaRao Puli                 if (regPrefixes && msgIds)
233dd28ba82SAppaRao Puli                 {
234dd28ba82SAppaRao Puli                     if (regPrefixes->size() && msgIds->size())
235dd28ba82SAppaRao Puli                     {
236dd28ba82SAppaRao Puli                         messages::mutualExclusiveProperties(
237dd28ba82SAppaRao Puli                             asyncResp->res, "RegistryPrefixes", "MessageIds");
238dd28ba82SAppaRao Puli                         return;
239dd28ba82SAppaRao Puli                     }
240dd28ba82SAppaRao Puli                 }
241dd28ba82SAppaRao Puli 
242e5aaf047SAppaRao Puli                 // Validate the URL using regex expression
243b52664e2SAppaRao Puli                 // Format: <protocol>://<host>:<port>/<uri>
244b52664e2SAppaRao Puli                 // protocol: http/https
245b52664e2SAppaRao Puli                 // host: Exclude ' ', ':', '#', '?'
2464e0453b1SGunnar Mills                 // port: Empty or numeric value with ':' separator.
247b52664e2SAppaRao Puli                 // uri: Start with '/' and Exclude '#', ' '
248b52664e2SAppaRao Puli                 //      Can include query params(ex: '/event?test=1')
249b52664e2SAppaRao Puli                 // TODO: Need to validate hostname extensively(as per rfc)
250b52664e2SAppaRao Puli                 const std::regex urlRegex(
251b52664e2SAppaRao Puli                     "(http|https)://([^/\\x20\\x3f\\x23\\x3a]+):?([0-9]*)(/"
252b52664e2SAppaRao Puli                     "([^\\x20\\x23\\x3f]*\\x3f?([^\\x20\\x23\\x3f])*)?)");
253b52664e2SAppaRao Puli                 std::cmatch match;
254b52664e2SAppaRao Puli                 if (!std::regex_match(destUrl.c_str(), match, urlRegex))
255e5aaf047SAppaRao Puli                 {
256e5aaf047SAppaRao Puli                     messages::propertyValueFormatError(asyncResp->res, destUrl,
257e5aaf047SAppaRao Puli                                                        "Destination");
258e5aaf047SAppaRao Puli                     return;
259e5aaf047SAppaRao Puli                 }
260b52664e2SAppaRao Puli 
2617e860f15SJohn Edward Broadbent                 std::string uriProto =
2627e860f15SJohn Edward Broadbent                     std::string(match[1].first, match[1].second);
263b52664e2SAppaRao Puli                 if (uriProto == "http")
264b52664e2SAppaRao Puli                 {
265b52664e2SAppaRao Puli #ifndef BMCWEB_INSECURE_ENABLE_HTTP_PUSH_STYLE_EVENTING
266b52664e2SAppaRao Puli                     messages::propertyValueFormatError(asyncResp->res, destUrl,
267b52664e2SAppaRao Puli                                                        "Destination");
268b52664e2SAppaRao Puli                     return;
269b52664e2SAppaRao Puli #endif
270b52664e2SAppaRao Puli                 }
271b52664e2SAppaRao Puli 
272b52664e2SAppaRao Puli                 std::string host = std::string(match[2].first, match[2].second);
273b52664e2SAppaRao Puli                 std::string port = std::string(match[3].first, match[3].second);
274b52664e2SAppaRao Puli                 std::string path = std::string(match[4].first, match[4].second);
275b52664e2SAppaRao Puli                 if (port.empty())
276b52664e2SAppaRao Puli                 {
277b52664e2SAppaRao Puli                     if (uriProto == "http")
278b52664e2SAppaRao Puli                     {
279b52664e2SAppaRao Puli                         port = "80";
280b52664e2SAppaRao Puli                     }
281b52664e2SAppaRao Puli                     else
282b52664e2SAppaRao Puli                     {
283b52664e2SAppaRao Puli                         port = "443";
284b52664e2SAppaRao Puli                     }
285b52664e2SAppaRao Puli                 }
286b52664e2SAppaRao Puli                 if (path.empty())
287b52664e2SAppaRao Puli                 {
288b52664e2SAppaRao Puli                     path = "/";
289b52664e2SAppaRao Puli                 }
290b52664e2SAppaRao Puli 
291b52664e2SAppaRao Puli                 std::shared_ptr<Subscription> subValue =
292b52664e2SAppaRao Puli                     std::make_shared<Subscription>(host, port, path, uriProto);
293b52664e2SAppaRao Puli 
294b52664e2SAppaRao Puli                 subValue->destinationUrl = destUrl;
295e5aaf047SAppaRao Puli 
296e5aaf047SAppaRao Puli                 if (subscriptionType)
297e5aaf047SAppaRao Puli                 {
298e5aaf047SAppaRao Puli                     if (*subscriptionType != "RedfishEvent")
299e5aaf047SAppaRao Puli                     {
3007e860f15SJohn Edward Broadbent                         messages::propertyValueNotInList(asyncResp->res,
3017e860f15SJohn Edward Broadbent                                                          *subscriptionType,
3027e860f15SJohn Edward Broadbent                                                          "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                     {
3277e860f15SJohn Edward Broadbent                         messages::propertyValueNotInList(asyncResp->res,
3287e860f15SJohn Edward Broadbent                                                          *eventFormatType2,
3297e860f15SJohn Edward Broadbent                                                          "EventFormatType");
330e5aaf047SAppaRao Puli                         return;
331e5aaf047SAppaRao Puli                     }
33223a21a1cSEd Tanous                     subValue->eventFormatType = *eventFormatType2;
333e5aaf047SAppaRao Puli                 }
334e5aaf047SAppaRao Puli                 else
335e5aaf047SAppaRao Puli                 {
336e5aaf047SAppaRao Puli                     // If not specified, use default "Event"
33723a21a1cSEd Tanous                     subValue->eventFormatType = "Event";
338e5aaf047SAppaRao Puli                 }
339e5aaf047SAppaRao Puli 
340e5aaf047SAppaRao Puli                 if (context)
341e5aaf047SAppaRao Puli                 {
342b52664e2SAppaRao Puli                     subValue->customText = *context;
343e5aaf047SAppaRao Puli                 }
344e5aaf047SAppaRao Puli 
345e5aaf047SAppaRao Puli                 if (headers)
346e5aaf047SAppaRao Puli                 {
347*601c71aeSEd Tanous                     for (const nlohmann::json& headerChunk : *headers)
348*601c71aeSEd Tanous                     {
349*601c71aeSEd Tanous                         for (const auto& item : headerChunk.items())
350*601c71aeSEd Tanous                         {
351*601c71aeSEd Tanous                             const std::string* value =
352*601c71aeSEd Tanous                                 item.value().get_ptr<const std::string*>();
353*601c71aeSEd Tanous                             if (value == nullptr)
354*601c71aeSEd Tanous                             {
355*601c71aeSEd Tanous                                 messages::propertyValueFormatError(
356*601c71aeSEd Tanous                                     asyncResp->res, item.value().dump(2, true),
357*601c71aeSEd Tanous                                     "HttpHeaders/" + item.key());
358*601c71aeSEd Tanous                                 return;
359*601c71aeSEd Tanous                             }
360*601c71aeSEd Tanous                             subValue->httpHeaders.set(item.key(), *value);
361*601c71aeSEd Tanous                         }
362*601c71aeSEd Tanous                     }
363e5aaf047SAppaRao Puli                 }
364e5aaf047SAppaRao Puli 
365e5aaf047SAppaRao Puli                 if (regPrefixes)
366e5aaf047SAppaRao Puli                 {
367e5aaf047SAppaRao Puli                     for (const std::string& it : *regPrefixes)
368e5aaf047SAppaRao Puli                     {
369e5aaf047SAppaRao Puli                         if (std::find(supportedRegPrefixes.begin(),
370e5aaf047SAppaRao Puli                                       supportedRegPrefixes.end(),
371e5aaf047SAppaRao Puli                                       it) == supportedRegPrefixes.end())
372e5aaf047SAppaRao Puli                         {
3737e860f15SJohn Edward Broadbent                             messages::propertyValueNotInList(
3747e860f15SJohn Edward Broadbent                                 asyncResp->res, it, "RegistryPrefixes");
375e5aaf047SAppaRao Puli                             return;
376e5aaf047SAppaRao Puli                         }
377e5aaf047SAppaRao Puli                     }
378b52664e2SAppaRao Puli                     subValue->registryPrefixes = *regPrefixes;
379e5aaf047SAppaRao Puli                 }
380e5aaf047SAppaRao Puli 
381e56f254cSSunitha Harish                 if (resTypes)
382e56f254cSSunitha Harish                 {
383e56f254cSSunitha Harish                     for (const std::string& it : *resTypes)
384e56f254cSSunitha Harish                     {
385e56f254cSSunitha Harish                         if (std::find(supportedResourceTypes.begin(),
386e56f254cSSunitha Harish                                       supportedResourceTypes.end(),
387e56f254cSSunitha Harish                                       it) == supportedResourceTypes.end())
388e56f254cSSunitha Harish                         {
389e56f254cSSunitha Harish                             messages::propertyValueNotInList(asyncResp->res, it,
390e56f254cSSunitha Harish                                                              "ResourceTypes");
391e56f254cSSunitha Harish                             return;
392e56f254cSSunitha Harish                         }
393e56f254cSSunitha Harish                     }
394e56f254cSSunitha Harish                     subValue->resourceTypes = *resTypes;
395e56f254cSSunitha Harish                 }
396e56f254cSSunitha Harish 
397e5aaf047SAppaRao Puli                 if (msgIds)
398e5aaf047SAppaRao Puli                 {
399b304bd79SP Dheeraj Srujan Kumar                     std::vector<std::string> registryPrefix;
400b304bd79SP Dheeraj Srujan Kumar 
4017e860f15SJohn Edward Broadbent                     // If no registry prefixes are mentioned, consider all
4027e860f15SJohn Edward Broadbent                     // supported prefixes
403b304bd79SP Dheeraj Srujan Kumar                     if (subValue->registryPrefixes.empty())
404b304bd79SP Dheeraj Srujan Kumar                     {
405b304bd79SP Dheeraj Srujan Kumar                         registryPrefix.assign(supportedRegPrefixes.begin(),
406b304bd79SP Dheeraj Srujan Kumar                                               supportedRegPrefixes.end());
407b304bd79SP Dheeraj Srujan Kumar                     }
408b304bd79SP Dheeraj Srujan Kumar                     else
409b304bd79SP Dheeraj Srujan Kumar                     {
410b304bd79SP Dheeraj Srujan Kumar                         registryPrefix = subValue->registryPrefixes;
411b304bd79SP Dheeraj Srujan Kumar                     }
412b304bd79SP Dheeraj Srujan Kumar 
413b304bd79SP Dheeraj Srujan Kumar                     for (const std::string& id : *msgIds)
414b304bd79SP Dheeraj Srujan Kumar                     {
415b304bd79SP Dheeraj Srujan Kumar                         bool validId = false;
416b304bd79SP Dheeraj Srujan Kumar 
417b304bd79SP Dheeraj Srujan Kumar                         // Check for Message ID in each of the selected Registry
418b304bd79SP Dheeraj Srujan Kumar                         for (const std::string& it : registryPrefix)
419b304bd79SP Dheeraj Srujan Kumar                         {
420b304bd79SP Dheeraj Srujan Kumar                             const boost::beast::span<
421b304bd79SP Dheeraj Srujan Kumar                                 const redfish::message_registries::MessageEntry>
4227e860f15SJohn Edward Broadbent                                 registry = redfish::message_registries::
4237e860f15SJohn Edward Broadbent                                     getRegistryFromPrefix(it);
424b304bd79SP Dheeraj Srujan Kumar 
425b304bd79SP Dheeraj Srujan Kumar                             if (std::any_of(
426b304bd79SP Dheeraj Srujan Kumar                                     registry.cbegin(), registry.cend(),
4277e860f15SJohn Edward Broadbent                                     [&id](const redfish::message_registries::
4287e860f15SJohn Edward Broadbent                                               MessageEntry& messageEntry) {
429b304bd79SP Dheeraj Srujan Kumar                                         return !id.compare(messageEntry.first);
430b304bd79SP Dheeraj Srujan Kumar                                     }))
431b304bd79SP Dheeraj Srujan Kumar                             {
432b304bd79SP Dheeraj Srujan Kumar                                 validId = true;
433b304bd79SP Dheeraj Srujan Kumar                                 break;
434b304bd79SP Dheeraj Srujan Kumar                             }
435b304bd79SP Dheeraj Srujan Kumar                         }
436b304bd79SP Dheeraj Srujan Kumar 
437b304bd79SP Dheeraj Srujan Kumar                         if (!validId)
438b304bd79SP Dheeraj Srujan Kumar                         {
439b304bd79SP Dheeraj Srujan Kumar                             messages::propertyValueNotInList(asyncResp->res, id,
440b304bd79SP Dheeraj Srujan Kumar                                                              "MessageIds");
441b304bd79SP Dheeraj Srujan Kumar                             return;
442b304bd79SP Dheeraj Srujan Kumar                         }
443b304bd79SP Dheeraj Srujan Kumar                     }
444b304bd79SP Dheeraj Srujan Kumar 
445b52664e2SAppaRao Puli                     subValue->registryMsgIds = *msgIds;
446e5aaf047SAppaRao Puli                 }
447e5aaf047SAppaRao Puli 
448e5aaf047SAppaRao Puli                 if (retryPolicy)
449e5aaf047SAppaRao Puli                 {
450e5aaf047SAppaRao Puli                     if (std::find(supportedRetryPolicies.begin(),
451e5aaf047SAppaRao Puli                                   supportedRetryPolicies.end(),
452e5aaf047SAppaRao Puli                                   *retryPolicy) == supportedRetryPolicies.end())
453e5aaf047SAppaRao Puli                     {
4547e860f15SJohn Edward Broadbent                         messages::propertyValueNotInList(asyncResp->res,
4557e860f15SJohn Edward Broadbent                                                          *retryPolicy,
456e5aaf047SAppaRao Puli                                                          "DeliveryRetryPolicy");
457e5aaf047SAppaRao Puli                         return;
458e5aaf047SAppaRao Puli                     }
459b52664e2SAppaRao Puli                     subValue->retryPolicy = *retryPolicy;
460e5aaf047SAppaRao Puli                 }
461e5aaf047SAppaRao Puli                 else
462e5aaf047SAppaRao Puli                 {
463e5aaf047SAppaRao Puli                     // Default "TerminateAfterRetries"
464b52664e2SAppaRao Puli                     subValue->retryPolicy = "TerminateAfterRetries";
465e5aaf047SAppaRao Puli                 }
466e5aaf047SAppaRao Puli 
467144b6318SAppaRao Puli                 if (mrdJsonArray)
468156d6b00SAppaRao Puli                 {
469144b6318SAppaRao Puli                     for (nlohmann::json& mrdObj : *mrdJsonArray)
470144b6318SAppaRao Puli                     {
471144b6318SAppaRao Puli                         std::string mrdUri;
4727e860f15SJohn Edward Broadbent                         if (json_util::getValueFromJsonObject(
4737e860f15SJohn Edward Broadbent                                 mrdObj, "@odata.id", mrdUri))
474144b6318SAppaRao Puli                         {
4757e860f15SJohn Edward Broadbent                             subValue->metricReportDefinitions.emplace_back(
4767e860f15SJohn Edward Broadbent                                 mrdUri);
477144b6318SAppaRao Puli                         }
478144b6318SAppaRao Puli                         else
479144b6318SAppaRao Puli                         {
480144b6318SAppaRao Puli                             messages::propertyValueFormatError(
48171f52d96SEd Tanous                                 asyncResp->res,
4827e860f15SJohn Edward Broadbent                                 mrdObj.dump(
4837e860f15SJohn Edward Broadbent                                     2, ' ', true,
48471f52d96SEd Tanous                                     nlohmann::json::error_handler_t::replace),
485144b6318SAppaRao Puli                                 "MetricReportDefinitions");
486144b6318SAppaRao Puli                             return;
487144b6318SAppaRao Puli                         }
488144b6318SAppaRao Puli                     }
489156d6b00SAppaRao Puli                 }
490156d6b00SAppaRao Puli 
491b52664e2SAppaRao Puli                 std::string id =
4927e860f15SJohn Edward Broadbent                     EventServiceManager::getInstance().addSubscription(
4937e860f15SJohn Edward Broadbent                         subValue);
494b52664e2SAppaRao Puli                 if (id.empty())
495e5aaf047SAppaRao Puli                 {
496e5aaf047SAppaRao Puli                     messages::internalError(asyncResp->res);
497e5aaf047SAppaRao Puli                     return;
498e5aaf047SAppaRao Puli                 }
499e5aaf047SAppaRao Puli 
500e5aaf047SAppaRao Puli                 messages::created(asyncResp->res);
501e5aaf047SAppaRao Puli                 asyncResp->res.addHeader(
502e5aaf047SAppaRao Puli                     "Location", "/redfish/v1/EventService/Subscriptions/" + id);
5037e860f15SJohn Edward Broadbent             });
504e5aaf047SAppaRao Puli }
505e5aaf047SAppaRao Puli 
5067e860f15SJohn Edward Broadbent inline void requestRoutesEventDestination(App& app)
507e5aaf047SAppaRao Puli {
5089d41aec6SRavi Teja     BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/<str>/")
509ed398213SEd Tanous         .privileges(redfish::privileges::getEventDestination)
5107e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::get)(
5117e860f15SJohn Edward Broadbent             [](const crow::Request&,
5127e860f15SJohn Edward Broadbent                const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
5137e860f15SJohn Edward Broadbent                const std::string& param) {
514b52664e2SAppaRao Puli                 std::shared_ptr<Subscription> subValue =
5157e860f15SJohn Edward Broadbent                     EventServiceManager::getInstance().getSubscription(param);
516b52664e2SAppaRao Puli                 if (subValue == nullptr)
517e5aaf047SAppaRao Puli                 {
5187e860f15SJohn Edward Broadbent                     asyncResp->res.result(
5197e860f15SJohn Edward Broadbent                         boost::beast::http::status::not_found);
520e5aaf047SAppaRao Puli                     return;
521e5aaf047SAppaRao Puli                 }
5227e860f15SJohn Edward Broadbent                 const std::string& id = param;
523e5aaf047SAppaRao Puli 
5248d1b46d7Szhanghch05                 asyncResp->res.jsonValue = {
5257e860f15SJohn Edward Broadbent                     {"@odata.type",
5267e860f15SJohn Edward Broadbent                      "#EventDestination.v1_7_0.EventDestination"},
527e5aaf047SAppaRao Puli                     {"Protocol", "Redfish"}};
528e5aaf047SAppaRao Puli                 asyncResp->res.jsonValue["@odata.id"] =
529e5aaf047SAppaRao Puli                     "/redfish/v1/EventService/Subscriptions/" + id;
530e5aaf047SAppaRao Puli                 asyncResp->res.jsonValue["Id"] = id;
531e5aaf047SAppaRao Puli                 asyncResp->res.jsonValue["Name"] = "Event Destination " + id;
5327e860f15SJohn Edward Broadbent                 asyncResp->res.jsonValue["Destination"] =
5337e860f15SJohn Edward Broadbent                     subValue->destinationUrl;
534b52664e2SAppaRao Puli                 asyncResp->res.jsonValue["Context"] = subValue->customText;
535e5aaf047SAppaRao Puli                 asyncResp->res.jsonValue["SubscriptionType"] =
536b52664e2SAppaRao Puli                     subValue->subscriptionType;
537ad22fefeSEd Tanous                 asyncResp->res.jsonValue["HttpHeaders"] =
538ad22fefeSEd Tanous                     nlohmann::json::array();
5397e860f15SJohn Edward Broadbent                 asyncResp->res.jsonValue["EventFormatType"] =
5407e860f15SJohn Edward Broadbent                     subValue->eventFormatType;
541e5aaf047SAppaRao Puli                 asyncResp->res.jsonValue["RegistryPrefixes"] =
542b52664e2SAppaRao Puli                     subValue->registryPrefixes;
5437e860f15SJohn Edward Broadbent                 asyncResp->res.jsonValue["ResourceTypes"] =
5447e860f15SJohn Edward Broadbent                     subValue->resourceTypes;
545e56f254cSSunitha Harish 
5467e860f15SJohn Edward Broadbent                 asyncResp->res.jsonValue["MessageIds"] =
5477e860f15SJohn Edward Broadbent                     subValue->registryMsgIds;
5487e860f15SJohn Edward Broadbent                 asyncResp->res.jsonValue["DeliveryRetryPolicy"] =
5497e860f15SJohn Edward Broadbent                     subValue->retryPolicy;
550144b6318SAppaRao Puli 
551144b6318SAppaRao Puli                 std::vector<nlohmann::json> mrdJsonArray;
552144b6318SAppaRao Puli                 for (const auto& mdrUri : subValue->metricReportDefinitions)
553144b6318SAppaRao Puli                 {
554144b6318SAppaRao Puli                     mrdJsonArray.push_back({{"@odata.id", mdrUri}});
555144b6318SAppaRao Puli                 }
5567e860f15SJohn Edward Broadbent                 asyncResp->res.jsonValue["MetricReportDefinitions"] =
5577e860f15SJohn Edward Broadbent                     mrdJsonArray;
5587e860f15SJohn Edward Broadbent             });
5599d41aec6SRavi Teja     BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/<str>/")
560ed398213SEd Tanous         // The below privilege is wrong, it should be ConfigureManager OR
561ed398213SEd Tanous         // ConfigureSelf
5627eeafa76SAbhishek Patel         // https://github.com/openbmc/bmcweb/issues/220
563ed398213SEd Tanous         //.privileges(redfish::privileges::patchEventDestination)
564432a890cSEd Tanous         .privileges({{"ConfigureManager"}})
5657e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::patch)(
5667e860f15SJohn Edward Broadbent             [](const crow::Request& req,
5677e860f15SJohn Edward Broadbent                const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
5687e860f15SJohn Edward Broadbent                const std::string& param) {
569b52664e2SAppaRao Puli                 std::shared_ptr<Subscription> subValue =
5707e860f15SJohn Edward Broadbent                     EventServiceManager::getInstance().getSubscription(param);
571b52664e2SAppaRao Puli                 if (subValue == nullptr)
572e5aaf047SAppaRao Puli                 {
5737e860f15SJohn Edward Broadbent                     asyncResp->res.result(
5747e860f15SJohn Edward Broadbent                         boost::beast::http::status::not_found);
575e5aaf047SAppaRao Puli                     return;
576e5aaf047SAppaRao Puli                 }
577e5aaf047SAppaRao Puli 
578e5aaf047SAppaRao Puli                 std::optional<std::string> context;
579e5aaf047SAppaRao Puli                 std::optional<std::string> retryPolicy;
580e5aaf047SAppaRao Puli                 std::optional<std::vector<nlohmann::json>> headers;
581e5aaf047SAppaRao Puli 
5827e860f15SJohn Edward Broadbent                 if (!json_util::readJson(req, asyncResp->res, "Context",
5837e860f15SJohn Edward Broadbent                                          context, "DeliveryRetryPolicy",
5847e860f15SJohn Edward Broadbent                                          retryPolicy, "HttpHeaders", headers))
585e5aaf047SAppaRao Puli                 {
586e5aaf047SAppaRao Puli                     return;
587e5aaf047SAppaRao Puli                 }
588e5aaf047SAppaRao Puli 
589e5aaf047SAppaRao Puli                 if (context)
590e5aaf047SAppaRao Puli                 {
591b52664e2SAppaRao Puli                     subValue->customText = *context;
592e5aaf047SAppaRao Puli                 }
593e5aaf047SAppaRao Puli 
594e5aaf047SAppaRao Puli                 if (headers)
595e5aaf047SAppaRao Puli                 {
596*601c71aeSEd Tanous                     boost::beast::http::fields fields;
597*601c71aeSEd Tanous                     for (const nlohmann::json& headerChunk : *headers)
598*601c71aeSEd Tanous                     {
599*601c71aeSEd Tanous                         for (auto& it : headerChunk.items())
600*601c71aeSEd Tanous                         {
601*601c71aeSEd Tanous                             const std::string* value =
602*601c71aeSEd Tanous                                 it.value().get_ptr<const std::string*>();
603*601c71aeSEd Tanous                             if (value == nullptr)
604*601c71aeSEd Tanous                             {
605*601c71aeSEd Tanous                                 messages::propertyValueFormatError(
606*601c71aeSEd Tanous                                     asyncResp->res,
607*601c71aeSEd Tanous                                     it.value().dump(2, ' ', true),
608*601c71aeSEd Tanous                                     "HttpHeaders/" + it.key());
609*601c71aeSEd Tanous                                 return;
610*601c71aeSEd Tanous                             }
611*601c71aeSEd Tanous                             fields.set(it.key(), *value);
612*601c71aeSEd Tanous                         }
613*601c71aeSEd Tanous                     }
614*601c71aeSEd Tanous                     subValue->httpHeaders = fields;
615e5aaf047SAppaRao Puli                 }
616e5aaf047SAppaRao Puli 
617e5aaf047SAppaRao Puli                 if (retryPolicy)
618e5aaf047SAppaRao Puli                 {
619e5aaf047SAppaRao Puli                     if (std::find(supportedRetryPolicies.begin(),
620e5aaf047SAppaRao Puli                                   supportedRetryPolicies.end(),
621e5aaf047SAppaRao Puli                                   *retryPolicy) == supportedRetryPolicies.end())
622e5aaf047SAppaRao Puli                     {
6237e860f15SJohn Edward Broadbent                         messages::propertyValueNotInList(asyncResp->res,
6247e860f15SJohn Edward Broadbent                                                          *retryPolicy,
625e5aaf047SAppaRao Puli                                                          "DeliveryRetryPolicy");
626e5aaf047SAppaRao Puli                         return;
627e5aaf047SAppaRao Puli                     }
628b52664e2SAppaRao Puli                     subValue->retryPolicy = *retryPolicy;
629fe44eb0bSAyushi Smriti                     subValue->updateRetryPolicy();
630e5aaf047SAppaRao Puli                 }
631e5aaf047SAppaRao Puli 
632b52664e2SAppaRao Puli                 EventServiceManager::getInstance().updateSubscriptionData();
6337e860f15SJohn Edward Broadbent             });
6349d41aec6SRavi Teja     BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/<str>/")
635ed398213SEd Tanous         // The below privilege is wrong, it should be ConfigureManager OR
636ed398213SEd Tanous         // ConfigureSelf
6377eeafa76SAbhishek Patel         // https://github.com/openbmc/bmcweb/issues/220
638ed398213SEd Tanous         //.privileges(redfish::privileges::deleteEventDestination)
639432a890cSEd Tanous         .privileges({{"ConfigureManager"}})
6407e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::delete_)(
6417e860f15SJohn Edward Broadbent             [](const crow::Request&,
6427e860f15SJohn Edward Broadbent                const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
6437e860f15SJohn Edward Broadbent                const std::string& param) {
6447e860f15SJohn Edward Broadbent                 if (!EventServiceManager::getInstance().isSubscriptionExist(
6457e860f15SJohn Edward Broadbent                         param))
646e5aaf047SAppaRao Puli                 {
6477e860f15SJohn Edward Broadbent                     asyncResp->res.result(
6487e860f15SJohn Edward Broadbent                         boost::beast::http::status::not_found);
649e5aaf047SAppaRao Puli                     return;
650e5aaf047SAppaRao Puli                 }
6517e860f15SJohn Edward Broadbent                 EventServiceManager::getInstance().deleteSubscription(param);
6527e860f15SJohn Edward Broadbent             });
653e5aaf047SAppaRao Puli }
654e5aaf047SAppaRao Puli 
655e5aaf047SAppaRao Puli } // namespace redfish
656