blob: 60946b29782b37ba6ef2016c205094c8d226e0f0 [file] [log] [blame]
AppaRao Pulie5aaf042020-03-20 01:05:52 +05301/*
Ed Tanous6be832e2024-09-10 11:44:48 -07002Copyright (c) 2020 Intel Corporation
3
4Licensed under the Apache License, Version 2.0 (the "License");
5you may not use this file except in compliance with the License.
6You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10Unless required by applicable law or agreed to in writing, software
11distributed under the License is distributed on an "AS IS" BASIS,
12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13See the License for the specific language governing permissions and
14limitations under the License.
AppaRao Pulie5aaf042020-03-20 01:05:52 +053015*/
16#pragma once
Ed Tanous3ccb3ad2023-01-13 17:40:03 -080017#include "app.hpp"
AppaRao Pulib52664e2020-04-09 21:36:51 +053018#include "event_service_manager.hpp"
Ed Tanous539d8c62024-06-19 14:38:27 -070019#include "generated/enums/event_service.hpp"
Ed Tanous3ccb3ad2023-01-13 17:40:03 -080020#include "http/utility.hpp"
21#include "logging.hpp"
22#include "query.hpp"
23#include "registries/privilege_registry.hpp"
Chicago Duan3d307082020-11-26 14:12:12 +080024#include "snmp_trap_event_clients.hpp"
AppaRao Pulie5aaf042020-03-20 01:05:52 +053025
Ed Tanous601c71a2021-09-08 16:40:12 -070026#include <boost/beast/http/fields.hpp>
Chicago Duan3d307082020-11-26 14:12:12 +080027#include <boost/system/error_code.hpp>
Ed Tanousa716aa72023-08-01 11:35:53 -070028#include <boost/url/parse.hpp>
Chicago Duan3d307082020-11-26 14:12:12 +080029#include <sdbusplus/unpack_properties.hpp>
30#include <utils/dbus_utils.hpp>
Ed Tanoused398212021-06-09 17:05:54 -070031
Chicago Duan3d307082020-11-26 14:12:12 +080032#include <charconv>
33#include <memory>
Ed Tanous3544d2a2023-08-06 18:12:20 -070034#include <ranges>
Patrick Williams1e270c52021-12-04 06:06:56 -060035#include <span>
Chicago Duan3d307082020-11-26 14:12:12 +080036#include <string>
Ed Tanousa14c9112024-09-04 10:46:47 -070037#include <vector>
Patrick Williams1e270c52021-12-04 06:06:56 -060038
AppaRao Pulie5aaf042020-03-20 01:05:52 +053039namespace redfish
40{
41
AppaRao Puli156d6b02020-04-25 06:04:05 +053042static constexpr const std::array<const char*, 2> supportedEvtFormatTypes = {
43 eventFormatType, metricReportFormatType};
AppaRao Pulie5aaf042020-03-20 01:05:52 +053044static constexpr const std::array<const char*, 3> supportedRegPrefixes = {
P Dheeraj Srujan Kumarb304bd72021-01-29 17:46:35 +053045 "Base", "OpenBMC", "TaskEvent"};
AppaRao Pulie5aaf042020-03-20 01:05:52 +053046static constexpr const std::array<const char*, 3> supportedRetryPolicies = {
47 "TerminateAfterRetries", "SuspendRetries", "RetryForever"};
48
Sunitha Harishe56f2542020-07-22 02:38:59 -050049static constexpr const std::array<const char*, 1> supportedResourceTypes = {
50 "Task"};
Sunitha Harishe56f2542020-07-22 02:38:59 -050051
John Edward Broadbent7e860f12021-04-08 15:57:16 -070052inline void requestRoutesEventService(App& app)
AppaRao Pulie5aaf042020-03-20 01:05:52 +053053{
John Edward Broadbent7e860f12021-04-08 15:57:16 -070054 BMCWEB_ROUTE(app, "/redfish/v1/EventService/")
Ed Tanoused398212021-06-09 17:05:54 -070055 .privileges(redfish::privileges::getEventService)
Patrick Williamsbd79bce2024-08-16 15:22:20 -040056 .methods(
57 boost::beast::http::verb::
58 get)([&app](
59 const crow::Request& req,
60 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
61 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
62 {
63 return;
64 }
Ed Tanous14766872022-03-15 10:44:42 -070065
Patrick Williamsbd79bce2024-08-16 15:22:20 -040066 asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/EventService";
67 asyncResp->res.jsonValue["@odata.type"] =
68 "#EventService.v1_5_0.EventService";
69 asyncResp->res.jsonValue["Id"] = "EventService";
70 asyncResp->res.jsonValue["Name"] = "Event Service";
71 asyncResp->res.jsonValue["ServerSentEventUri"] =
72 "/redfish/v1/EventService/SSE";
AppaRao Puli5e44e3d2021-03-16 15:37:24 +000073
Patrick Williamsbd79bce2024-08-16 15:22:20 -040074 asyncResp->res.jsonValue["Subscriptions"]["@odata.id"] =
75 "/redfish/v1/EventService/Subscriptions";
76 asyncResp->res.jsonValue["Actions"]["#EventService.SubmitTestEvent"]
77 ["target"] =
78 "/redfish/v1/EventService/Actions/EventService.SubmitTestEvent";
AppaRao Pulie5aaf042020-03-20 01:05:52 +053079
Patrick Williamsbd79bce2024-08-16 15:22:20 -040080 const persistent_data::EventServiceConfig eventServiceConfig =
81 persistent_data::EventServiceStore::getInstance()
82 .getEventServiceConfig();
zhanghch058d1b46d2021-04-01 11:18:24 +080083
Patrick Williamsbd79bce2024-08-16 15:22:20 -040084 asyncResp->res.jsonValue["Status"]["State"] =
85 (eventServiceConfig.enabled ? "Enabled" : "Disabled");
86 asyncResp->res.jsonValue["ServiceEnabled"] =
87 eventServiceConfig.enabled;
88 asyncResp->res.jsonValue["DeliveryRetryAttempts"] =
89 eventServiceConfig.retryAttempts;
90 asyncResp->res.jsonValue["DeliveryRetryIntervalSeconds"] =
91 eventServiceConfig.retryTimeoutInterval;
92 asyncResp->res.jsonValue["EventFormatTypes"] =
93 supportedEvtFormatTypes;
94 asyncResp->res.jsonValue["RegistryPrefixes"] = supportedRegPrefixes;
95 asyncResp->res.jsonValue["ResourceTypes"] = supportedResourceTypes;
AppaRao Pulie5aaf042020-03-20 01:05:52 +053096
Patrick Williamsbd79bce2024-08-16 15:22:20 -040097 nlohmann::json::object_t supportedSSEFilters;
98 supportedSSEFilters["EventFormatType"] = true;
99 supportedSSEFilters["MessageId"] = true;
100 supportedSSEFilters["MetricReportDefinition"] = true;
101 supportedSSEFilters["RegistryPrefix"] = true;
102 supportedSSEFilters["OriginResource"] = false;
103 supportedSSEFilters["ResourceType"] = false;
AppaRao Puli7d1cc382020-05-16 02:42:22 +0530104
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400105 asyncResp->res.jsonValue["SSEFilterPropertiesSupported"] =
106 std::move(supportedSSEFilters);
107 });
Ayushi Smriti07941a82020-05-21 15:55:34 +0530108
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700109 BMCWEB_ROUTE(app, "/redfish/v1/EventService/")
Ed Tanoused398212021-06-09 17:05:54 -0700110 .privileges(redfish::privileges::patchEventService)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700111 .methods(boost::beast::http::verb::patch)(
Ed Tanous45ca1b82022-03-25 13:07:27 -0700112 [&app](const crow::Request& req,
113 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400114 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
115 {
116 return;
117 }
118 std::optional<bool> serviceEnabled;
119 std::optional<uint32_t> retryAttemps;
120 std::optional<uint32_t> retryInterval;
AppaRao Pulie5aaf042020-03-20 01:05:52 +0530121
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400122 if (!json_util::readJsonPatch(
123 req, asyncResp->res, "ServiceEnabled", serviceEnabled,
124 "DeliveryRetryAttempts", retryAttemps,
125 "DeliveryRetryIntervalSeconds", retryInterval))
126 {
127 return;
128 }
AppaRao Pulie5aaf042020-03-20 01:05:52 +0530129
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400130 persistent_data::EventServiceConfig eventServiceConfig =
131 persistent_data::EventServiceStore::getInstance()
132 .getEventServiceConfig();
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700133
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400134 if (serviceEnabled)
135 {
136 eventServiceConfig.enabled = *serviceEnabled;
137 }
Sunitha Harishe56f2542020-07-22 02:38:59 -0500138
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400139 if (retryAttemps)
140 {
141 // Supported range [1-3]
142 if ((*retryAttemps < 1) || (*retryAttemps > 3))
143 {
144 messages::queryParameterOutOfRange(
145 asyncResp->res, std::to_string(*retryAttemps),
146 "DeliveryRetryAttempts", "[1-3]");
147 }
148 else
149 {
150 eventServiceConfig.retryAttempts = *retryAttemps;
151 }
152 }
P Dheeraj Srujan Kumarb304bd72021-01-29 17:46:35 +0530153
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400154 if (retryInterval)
155 {
156 // Supported range [5 - 180]
157 if ((*retryInterval < 5) || (*retryInterval > 180))
158 {
159 messages::queryParameterOutOfRange(
160 asyncResp->res, std::to_string(*retryInterval),
161 "DeliveryRetryIntervalSeconds", "[5-180]");
162 }
163 else
164 {
165 eventServiceConfig.retryTimeoutInterval =
166 *retryInterval;
167 }
168 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700169
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400170 EventServiceManager::getInstance().setEventServiceConfig(
171 eventServiceConfig);
172 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700173}
174
175inline void requestRoutesSubmitTestEvent(App& app)
176{
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700177 BMCWEB_ROUTE(
178 app, "/redfish/v1/EventService/Actions/EventService.SubmitTestEvent/")
Ed Tanoused398212021-06-09 17:05:54 -0700179 .privileges(redfish::privileges::postEventService)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700180 .methods(boost::beast::http::verb::post)(
Ed Tanous45ca1b82022-03-25 13:07:27 -0700181 [&app](const crow::Request& req,
182 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400183 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
184 {
185 return;
186 }
187 if (!EventServiceManager::getInstance().sendTestEventLog())
188 {
189 messages::serviceDisabled(asyncResp->res,
190 "/redfish/v1/EventService/");
191 return;
192 }
193 asyncResp->res.result(boost::beast::http::status::no_content);
194 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700195}
196
Chicago Duan3d307082020-11-26 14:12:12 +0800197inline void doSubscriptionCollection(
Ed Tanouse81de512023-06-27 17:07:00 -0700198 const boost::system::error_code& ec,
Chicago Duan3d307082020-11-26 14:12:12 +0800199 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
200 const dbus::utility::ManagedObjectType& resp)
201{
202 if (ec)
203 {
Ed Tanous13061012023-07-25 11:12:19 -0700204 if (ec.value() == EBADR || ec.value() == EHOSTUNREACH)
Chicago Duan3d307082020-11-26 14:12:12 +0800205 {
206 // This is an optional process so just return if it isn't there
207 return;
208 }
209
Ed Tanous62598e32023-07-17 17:06:25 -0700210 BMCWEB_LOG_ERROR("D-Bus response error on GetManagedObjects {}", ec);
Chicago Duan3d307082020-11-26 14:12:12 +0800211 messages::internalError(asyncResp->res);
212 return;
213 }
214 nlohmann::json& memberArray = asyncResp->res.jsonValue["Members"];
215 for (const auto& objpath : resp)
216 {
217 sdbusplus::message::object_path path(objpath.first);
218 const std::string snmpId = path.filename();
219 if (snmpId.empty())
220 {
Ed Tanous62598e32023-07-17 17:06:25 -0700221 BMCWEB_LOG_ERROR("The SNMP client ID is wrong");
Chicago Duan3d307082020-11-26 14:12:12 +0800222 messages::internalError(asyncResp->res);
223 return;
224 }
225
226 getSnmpSubscriptionList(asyncResp, snmpId, memberArray);
227 }
228}
229
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700230inline void requestRoutesEventDestinationCollection(App& app)
231{
Gayathri Leburu1ebe3e42022-02-09 10:45:19 +0000232 BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/")
Ed Tanoused398212021-06-09 17:05:54 -0700233 .privileges(redfish::privileges::getEventDestinationCollection)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700234 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -0700235 [&app](const crow::Request& req,
236 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400237 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
238 {
239 return;
240 }
241 asyncResp->res.jsonValue["@odata.type"] =
242 "#EventDestinationCollection.EventDestinationCollection";
243 asyncResp->res.jsonValue["@odata.id"] =
244 "/redfish/v1/EventService/Subscriptions";
245 asyncResp->res.jsonValue["Name"] =
246 "Event Destination Collections";
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700247
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400248 nlohmann::json& memberArray =
249 asyncResp->res.jsonValue["Members"];
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700250
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400251 std::vector<std::string> subscripIds =
252 EventServiceManager::getInstance().getAllIDs();
253 memberArray = nlohmann::json::array();
254 asyncResp->res.jsonValue["Members@odata.count"] =
255 subscripIds.size();
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700256
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400257 for (const std::string& id : subscripIds)
258 {
259 nlohmann::json::object_t member;
260 member["@odata.id"] = boost::urls::format(
261 "/redfish/v1/EventService/Subscriptions/{}" + id);
262 memberArray.emplace_back(std::move(member));
263 }
264 crow::connections::systemBus->async_method_call(
265 [asyncResp](const boost::system::error_code& ec,
266 const dbus::utility::ManagedObjectType& resp) {
267 doSubscriptionCollection(ec, asyncResp, resp);
268 },
269 "xyz.openbmc_project.Network.SNMP",
270 "/xyz/openbmc_project/network/snmp/manager",
271 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
272 });
Chicago Duan3d307082020-11-26 14:12:12 +0800273
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700274 BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/")
Abhishek Patel7eeafa72021-07-28 10:59:16 -0500275 .privileges(redfish::privileges::postEventDestinationCollection)
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400276 .methods(
277 boost::beast::http::verb::
278 post)([&app](
279 const crow::Request& req,
280 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
281 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
282 {
283 return;
284 }
285 if (EventServiceManager::getInstance().getNumberOfSubscriptions() >=
286 maxNoOfSubscriptions)
287 {
288 messages::eventSubscriptionLimitExceeded(asyncResp->res);
289 return;
290 }
291 std::string destUrl;
292 std::string protocol;
293 std::optional<bool> verifyCertificate;
294 std::optional<std::string> context;
295 std::optional<std::string> subscriptionType;
296 std::optional<std::string> eventFormatType2;
297 std::optional<std::string> retryPolicy;
298 std::optional<std::vector<std::string>> msgIds;
299 std::optional<std::vector<std::string>> regPrefixes;
Ed Tanousa14c9112024-09-04 10:46:47 -0700300 std::optional<std::vector<std::string>> originResources;
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400301 std::optional<std::vector<std::string>> resTypes;
302 std::optional<std::vector<nlohmann::json::object_t>> headers;
303 std::optional<std::vector<nlohmann::json::object_t>> mrdJsonArray;
Ed Tanousfffb8c12022-02-07 23:53:03 -0800304
Ed Tanous4b712a22023-08-02 12:56:52 -0700305 // clang-format off
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400306 if (!json_util::readJsonPatch(
Ed Tanous4b712a22023-08-02 12:56:52 -0700307 req, asyncResp->res,
308 "Context", context,
Ed Tanousa14c9112024-09-04 10:46:47 -0700309 "DeliveryRetryPolicy", retryPolicy,
Ed Tanous4b712a22023-08-02 12:56:52 -0700310 "Destination", destUrl,
311 "EventFormatType", eventFormatType2,
312 "HttpHeaders", headers,
313 "MessageIds", msgIds,
314 "MetricReportDefinitions", mrdJsonArray,
315 "OriginResources", originResources,
316 "Protocol", protocol,
317 "RegistryPrefixes", regPrefixes,
318 "ResourceTypes", resTypes,
319 "SubscriptionType", subscriptionType,
320 "VerifyCertificate", verifyCertificate
321 ))
Ed Tanousfffb8c12022-02-07 23:53:03 -0800322 {
Ed Tanousa716aa72023-08-01 11:35:53 -0700323 return;
324 }
Ed Tanous4b712a22023-08-02 12:56:52 -0700325 // clang-format on
Chicago Duan3d307082020-11-26 14:12:12 +0800326
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400327 // https://stackoverflow.com/questions/417142/what-is-the-maximum-length-of-a-url-in-different-browsers
328 static constexpr const uint16_t maxDestinationSize = 2000;
329 if (destUrl.size() > maxDestinationSize)
Ed Tanousfffb8c12022-02-07 23:53:03 -0800330 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400331 messages::stringValueTooLong(asyncResp->res, "Destination",
332 maxDestinationSize);
Ed Tanous002d39b2022-05-31 08:59:27 -0700333 return;
334 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700335
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400336 if (regPrefixes && msgIds)
Ed Tanous002d39b2022-05-31 08:59:27 -0700337 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400338 if (!regPrefixes->empty() && !msgIds->empty())
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700339 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400340 messages::propertyValueConflict(
341 asyncResp->res, "MessageIds", "RegistryPrefixes");
P Dheeraj Srujan Kumarb304bd72021-01-29 17:46:35 +0530342 return;
343 }
Ed Tanousfffb8c12022-02-07 23:53:03 -0800344 }
P Dheeraj Srujan Kumarb304bd72021-01-29 17:46:35 +0530345
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400346 boost::system::result<boost::urls::url> url =
347 boost::urls::parse_absolute_uri(destUrl);
348 if (!url)
Ed Tanousfffb8c12022-02-07 23:53:03 -0800349 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400350 BMCWEB_LOG_WARNING(
351 "Failed to validate and split destination url");
352 messages::propertyValueFormatError(asyncResp->res, destUrl,
353 "Destination");
354 return;
355 }
356 url->normalize();
357 crow::utility::setProtocolDefaults(*url, protocol);
358 crow::utility::setPortDefaults(*url);
359
360 if (url->path().empty())
361 {
362 url->set_path("/");
363 }
364
365 if (url->has_userinfo())
366 {
367 messages::propertyValueFormatError(asyncResp->res, destUrl,
368 "Destination");
369 return;
370 }
371
372 if (protocol == "SNMPv2c")
373 {
374 if (context)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700375 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400376 messages::propertyValueConflict(asyncResp->res, "Context",
377 "Protocol");
AppaRao Puli144b6312020-08-03 22:23:12 +0530378 return;
379 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400380 if (eventFormatType2)
381 {
382 messages::propertyValueConflict(
383 asyncResp->res, "EventFormatType", "Protocol");
384 return;
385 }
386 if (retryPolicy)
387 {
388 messages::propertyValueConflict(asyncResp->res,
389 "RetryPolicy", "Protocol");
390 return;
391 }
392 if (msgIds)
393 {
394 messages::propertyValueConflict(asyncResp->res,
395 "MessageIds", "Protocol");
396 return;
397 }
398 if (regPrefixes)
399 {
400 messages::propertyValueConflict(
401 asyncResp->res, "RegistryPrefixes", "Protocol");
402 return;
403 }
404 if (resTypes)
405 {
406 messages::propertyValueConflict(
407 asyncResp->res, "ResourceTypes", "Protocol");
408 return;
409 }
410 if (headers)
411 {
412 messages::propertyValueConflict(asyncResp->res,
413 "HttpHeaders", "Protocol");
414 return;
415 }
416 if (mrdJsonArray)
417 {
418 messages::propertyValueConflict(
419 asyncResp->res, "MetricReportDefinitions", "Protocol");
420 return;
421 }
422 if (url->scheme() != "snmp")
423 {
424 messages::propertyValueConflict(asyncResp->res,
425 "Destination", "Protocol");
426 return;
427 }
428
429 addSnmpTrapClient(asyncResp, url->host_address(),
430 url->port_number());
431 return;
Ed Tanous002d39b2022-05-31 08:59:27 -0700432 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700433
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400434 std::shared_ptr<Subscription> subValue =
435 std::make_shared<Subscription>(*url, app.ioContext());
Ed Tanous002d39b2022-05-31 08:59:27 -0700436
Ed Tanous4b712a22023-08-02 12:56:52 -0700437 subValue->userSub.destinationUrl = std::move(*url);
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400438
439 if (subscriptionType)
Ed Tanous002d39b2022-05-31 08:59:27 -0700440 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400441 if (*subscriptionType != "RedfishEvent")
442 {
443 messages::propertyValueNotInList(
444 asyncResp->res, *subscriptionType, "SubscriptionType");
445 return;
446 }
Ed Tanous4b712a22023-08-02 12:56:52 -0700447 subValue->userSub.subscriptionType = *subscriptionType;
Ed Tanousfffb8c12022-02-07 23:53:03 -0800448 }
449 else
450 {
Ed Tanous4b712a22023-08-02 12:56:52 -0700451 // Default
452 subValue->userSub.subscriptionType = "RedfishEvent";
Ed Tanousfffb8c12022-02-07 23:53:03 -0800453 }
AppaRao Puli156d6b02020-04-25 06:04:05 +0530454
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400455 if (protocol != "Redfish")
Ed Tanousfffb8c12022-02-07 23:53:03 -0800456 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400457 messages::propertyValueNotInList(asyncResp->res, protocol,
458 "Protocol");
459 return;
460 }
Ed Tanous4b712a22023-08-02 12:56:52 -0700461 subValue->userSub.protocol = protocol;
Ed Tanousfffb8c12022-02-07 23:53:03 -0800462
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400463 if (verifyCertificate)
464 {
Ed Tanous4b712a22023-08-02 12:56:52 -0700465 subValue->userSub.verifyCertificate = *verifyCertificate;
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400466 }
467
468 if (eventFormatType2)
469 {
470 if (std::ranges::find(supportedEvtFormatTypes,
471 *eventFormatType2) ==
472 supportedEvtFormatTypes.end())
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700473 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400474 messages::propertyValueNotInList(
475 asyncResp->res, *eventFormatType2, "EventFormatType");
476 return;
477 }
Ed Tanous4b712a22023-08-02 12:56:52 -0700478 subValue->userSub.eventFormatType = *eventFormatType2;
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400479 }
480 else
481 {
482 // If not specified, use default "Event"
Ed Tanous4b712a22023-08-02 12:56:52 -0700483 subValue->userSub.eventFormatType = "Event";
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400484 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700485
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400486 if (context)
487 {
488 // This value is selected arbitrarily.
489 constexpr const size_t maxContextSize = 256;
490 if (context->size() > maxContextSize)
491 {
492 messages::stringValueTooLong(asyncResp->res, "Context",
493 maxContextSize);
494 return;
495 }
Ed Tanous4b712a22023-08-02 12:56:52 -0700496 subValue->userSub.customText = *context;
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400497 }
498
499 if (headers)
500 {
501 size_t cumulativeLen = 0;
502
503 for (const nlohmann::json::object_t& headerChunk : *headers)
504 {
505 for (const auto& item : headerChunk)
Ed Tanous002d39b2022-05-31 08:59:27 -0700506 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400507 const std::string* value =
508 item.second.get_ptr<const std::string*>();
509 if (value == nullptr)
510 {
511 messages::propertyValueFormatError(
512 asyncResp->res, item.second,
513 "HttpHeaders/" + item.first);
514 return;
515 }
516 // Adding a new json value is the size of the key, +
517 // the size of the value + 2 * 2 quotes for each, +
518 // the colon and space between. example:
519 // "key": "value"
520 cumulativeLen += item.first.size() + value->size() + 6;
521 // This value is selected to mirror http_connection.hpp
522 constexpr const uint16_t maxHeaderSizeED = 8096;
523 if (cumulativeLen > maxHeaderSizeED)
524 {
525 messages::arraySizeTooLong(
526 asyncResp->res, "HttpHeaders", maxHeaderSizeED);
527 return;
528 }
Ed Tanous4b712a22023-08-02 12:56:52 -0700529 subValue->userSub.httpHeaders.set(item.first, *value);
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400530 }
531 }
532 }
533
534 if (regPrefixes)
535 {
536 for (const std::string& it : *regPrefixes)
537 {
538 if (std::ranges::find(supportedRegPrefixes, it) ==
539 supportedRegPrefixes.end())
540 {
541 messages::propertyValueNotInList(asyncResp->res, it,
542 "RegistryPrefixes");
543 return;
544 }
545 }
Ed Tanous4b712a22023-08-02 12:56:52 -0700546 subValue->userSub.registryPrefixes = *regPrefixes;
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400547 }
548
Ed Tanousa14c9112024-09-04 10:46:47 -0700549 if (originResources)
550 {
Ed Tanous4b712a22023-08-02 12:56:52 -0700551 subValue->userSub.originResources = *originResources;
Ed Tanousa14c9112024-09-04 10:46:47 -0700552 }
553
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400554 if (resTypes)
555 {
556 for (const std::string& it : *resTypes)
557 {
558 if (std::ranges::find(supportedResourceTypes, it) ==
559 supportedResourceTypes.end())
560 {
561 messages::propertyValueNotInList(asyncResp->res, it,
562 "ResourceTypes");
563 return;
564 }
565 }
Ed Tanous4b712a22023-08-02 12:56:52 -0700566 subValue->userSub.resourceTypes = *resTypes;
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400567 }
568
569 if (msgIds)
570 {
571 std::vector<std::string> registryPrefix;
572
573 // If no registry prefixes are mentioned, consider all
574 // supported prefixes
Ed Tanous4b712a22023-08-02 12:56:52 -0700575 if (subValue->userSub.registryPrefixes.empty())
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400576 {
577 registryPrefix.assign(supportedRegPrefixes.begin(),
578 supportedRegPrefixes.end());
579 }
580 else
581 {
Ed Tanous4b712a22023-08-02 12:56:52 -0700582 registryPrefix = subValue->userSub.registryPrefixes;
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400583 }
584
585 for (const std::string& id : *msgIds)
586 {
587 bool validId = false;
588
589 // Check for Message ID in each of the selected Registry
590 for (const std::string& it : registryPrefix)
591 {
592 const std::span<const redfish::registries::MessageEntry>
593 registry =
594 redfish::registries::getRegistryFromPrefix(it);
595
596 if (std::ranges::any_of(
597 registry,
598 [&id](const redfish::registries::MessageEntry&
599 messageEntry) {
600 return id == messageEntry.first;
601 }))
602 {
603 validId = true;
604 break;
605 }
606 }
607
608 if (!validId)
609 {
610 messages::propertyValueNotInList(asyncResp->res, id,
611 "MessageIds");
612 return;
Ed Tanous002d39b2022-05-31 08:59:27 -0700613 }
614 }
615
Ed Tanous4b712a22023-08-02 12:56:52 -0700616 subValue->userSub.registryMsgIds = *msgIds;
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400617 }
618
619 if (retryPolicy)
620 {
621 if (std::ranges::find(supportedRetryPolicies, *retryPolicy) ==
622 supportedRetryPolicies.end())
Ed Tanous002d39b2022-05-31 08:59:27 -0700623 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400624 messages::propertyValueNotInList(
625 asyncResp->res, *retryPolicy, "DeliveryRetryPolicy");
Ed Tanousfffb8c12022-02-07 23:53:03 -0800626 return;
627 }
Ed Tanous4b712a22023-08-02 12:56:52 -0700628 subValue->userSub.retryPolicy = *retryPolicy;
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400629 }
630 else
631 {
632 // Default "TerminateAfterRetries"
Ed Tanous4b712a22023-08-02 12:56:52 -0700633 subValue->userSub.retryPolicy = "TerminateAfterRetries";
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400634 }
635
636 if (mrdJsonArray)
637 {
638 for (nlohmann::json::object_t& mrdObj : *mrdJsonArray)
639 {
640 std::string mrdUri;
641
642 if (!json_util::readJsonObject(mrdObj, asyncResp->res,
643 "@odata.id", mrdUri))
644
645 {
646 return;
647 }
Ed Tanous4b712a22023-08-02 12:56:52 -0700648 subValue->userSub.metricReportDefinitions.emplace_back(
649 mrdUri);
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400650 }
Ed Tanousfffb8c12022-02-07 23:53:03 -0800651 }
652
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400653 std::string id =
654 EventServiceManager::getInstance().addPushSubscription(
655 subValue);
656 if (id.empty())
Ed Tanousfffb8c12022-02-07 23:53:03 -0800657 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400658 messages::internalError(asyncResp->res);
Ed Tanousfffb8c12022-02-07 23:53:03 -0800659 return;
660 }
661
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400662 messages::created(asyncResp->res);
663 asyncResp->res.addHeader(
664 "Location", "/redfish/v1/EventService/Subscriptions/" + id);
665 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700666}
667
668inline void requestRoutesEventDestination(App& app)
AppaRao Pulie5aaf042020-03-20 01:05:52 +0530669{
Ravi Teja9d41aec2021-07-23 01:57:01 -0500670 BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -0700671 .privileges(redfish::privileges::getEventDestination)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700672 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -0700673 [&app](const crow::Request& req,
674 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
675 const std::string& param) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400676 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
677 {
678 return;
679 }
Chicago Duan3d307082020-11-26 14:12:12 +0800680
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400681 if (param.starts_with("snmp"))
682 {
683 getSnmpTrapClient(asyncResp, param);
684 return;
685 }
Chicago Duan3d307082020-11-26 14:12:12 +0800686
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400687 std::shared_ptr<Subscription> subValue =
688 EventServiceManager::getInstance().getSubscription(param);
689 if (subValue == nullptr)
690 {
691 asyncResp->res.result(
692 boost::beast::http::status::not_found);
693 return;
694 }
695 const std::string& id = param;
AppaRao Pulie5aaf042020-03-20 01:05:52 +0530696
Ed Tanous4b712a22023-08-02 12:56:52 -0700697 const persistent_data::UserSubscription& userSub =
698 subValue->userSub;
zhanghch058d1b46d2021-04-01 11:18:24 +0800699
Ed Tanous4b712a22023-08-02 12:56:52 -0700700 nlohmann::json& jVal = asyncResp->res.jsonValue;
701 jVal["@odata.type"] =
702 "#EventDestination.v1_14_1.EventDestination";
703 jVal["Protocol"] =
704 event_destination::EventDestinationProtocol::Redfish;
705 jVal["@odata.id"] = boost::urls::format(
706 "/redfish/v1/EventService/Subscriptions/{}", id);
707 jVal["Id"] = id;
708 jVal["Name"] = "Event Destination " + id;
709 jVal["Destination"] = userSub.destinationUrl;
710 jVal["Context"] = userSub.customText;
711 jVal["SubscriptionType"] = userSub.subscriptionType;
712 jVal["HttpHeaders"] = nlohmann::json::array();
713 jVal["EventFormatType"] = userSub.eventFormatType;
714 jVal["RegistryPrefixes"] = userSub.registryPrefixes;
715 jVal["ResourceTypes"] = userSub.resourceTypes;
716
717 jVal["MessageIds"] = userSub.registryMsgIds;
718 jVal["DeliveryRetryPolicy"] = userSub.retryPolicy;
719 jVal["VerifyCertificate"] = userSub.verifyCertificate;
AppaRao Pulie5aaf042020-03-20 01:05:52 +0530720
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400721 nlohmann::json::array_t mrdJsonArray;
Ed Tanous4b712a22023-08-02 12:56:52 -0700722 for (const auto& mdrUri : userSub.metricReportDefinitions)
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400723 {
724 nlohmann::json::object_t mdr;
725 mdr["@odata.id"] = mdrUri;
726 mrdJsonArray.emplace_back(std::move(mdr));
727 }
Ed Tanous4b712a22023-08-02 12:56:52 -0700728 jVal["MetricReportDefinitions"] = mrdJsonArray;
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400729 });
Ravi Teja9d41aec2021-07-23 01:57:01 -0500730 BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -0700731 // The below privilege is wrong, it should be ConfigureManager OR
732 // ConfigureSelf
Abhishek Patel7eeafa72021-07-28 10:59:16 -0500733 // https://github.com/openbmc/bmcweb/issues/220
Ed Tanoused398212021-06-09 17:05:54 -0700734 //.privileges(redfish::privileges::patchEventDestination)
Ed Tanous432a8902021-06-14 15:28:56 -0700735 .privileges({{"ConfigureManager"}})
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700736 .methods(boost::beast::http::verb::patch)(
Ed Tanous45ca1b82022-03-25 13:07:27 -0700737 [&app](const crow::Request& req,
738 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
739 const std::string& param) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400740 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700741 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400742 return;
743 }
744 std::shared_ptr<Subscription> subValue =
745 EventServiceManager::getInstance().getSubscription(param);
746 if (subValue == nullptr)
747 {
748 asyncResp->res.result(
749 boost::beast::http::status::not_found);
750 return;
751 }
752
753 std::optional<std::string> context;
754 std::optional<std::string> retryPolicy;
755 std::optional<bool> verifyCertificate;
756 std::optional<std::vector<nlohmann::json::object_t>> headers;
757
758 if (!json_util::readJsonPatch(
759 req, asyncResp->res, "Context", context,
760 "VerifyCertificate", verifyCertificate,
761 "DeliveryRetryPolicy", retryPolicy, "HttpHeaders",
762 headers))
763 {
764 return;
765 }
766
767 if (context)
768 {
Ed Tanous4b712a22023-08-02 12:56:52 -0700769 subValue->userSub.customText = *context;
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400770 }
771
772 if (headers)
773 {
774 boost::beast::http::fields fields;
775 for (const nlohmann::json::object_t& headerChunk : *headers)
Ed Tanous601c71a2021-09-08 16:40:12 -0700776 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400777 for (const auto& it : headerChunk)
778 {
779 const std::string* value =
780 it.second.get_ptr<const std::string*>();
781 if (value == nullptr)
782 {
783 messages::propertyValueFormatError(
784 asyncResp->res, it.second,
785 "HttpHeaders/" + it.first);
786 return;
787 }
788 fields.set(it.first, *value);
789 }
790 }
Ed Tanous4b712a22023-08-02 12:56:52 -0700791 subValue->userSub.httpHeaders = std::move(fields);
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400792 }
793
794 if (retryPolicy)
795 {
796 if (std::ranges::find(supportedRetryPolicies,
797 *retryPolicy) ==
798 supportedRetryPolicies.end())
799 {
800 messages::propertyValueNotInList(asyncResp->res,
801 *retryPolicy,
802 "DeliveryRetryPolicy");
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700803 return;
804 }
Ed Tanous4b712a22023-08-02 12:56:52 -0700805 subValue->userSub.retryPolicy = *retryPolicy;
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700806 }
AppaRao Pulie5aaf042020-03-20 01:05:52 +0530807
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400808 if (verifyCertificate)
809 {
Ed Tanous4b712a22023-08-02 12:56:52 -0700810 subValue->userSub.verifyCertificate = *verifyCertificate;
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400811 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700812
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400813 EventServiceManager::getInstance().updateSubscriptionData();
814 });
Ravi Teja9d41aec2021-07-23 01:57:01 -0500815 BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -0700816 // The below privilege is wrong, it should be ConfigureManager OR
817 // ConfigureSelf
Abhishek Patel7eeafa72021-07-28 10:59:16 -0500818 // https://github.com/openbmc/bmcweb/issues/220
Ed Tanoused398212021-06-09 17:05:54 -0700819 //.privileges(redfish::privileges::deleteEventDestination)
Ed Tanous432a8902021-06-14 15:28:56 -0700820 .privileges({{"ConfigureManager"}})
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700821 .methods(boost::beast::http::verb::delete_)(
Ed Tanous45ca1b82022-03-25 13:07:27 -0700822 [&app](const crow::Request& req,
823 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
824 const std::string& param) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400825 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
826 {
827 return;
828 }
Ed Tanous4b712a22023-08-02 12:56:52 -0700829 EventServiceManager& event = EventServiceManager::getInstance();
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400830 if (param.starts_with("snmp"))
831 {
832 deleteSnmpTrapClient(asyncResp, param);
Ed Tanous4b712a22023-08-02 12:56:52 -0700833 event.deleteSubscription(param);
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400834 return;
835 }
Chicago Duan3d307082020-11-26 14:12:12 +0800836
Ed Tanous4b712a22023-08-02 12:56:52 -0700837 if (!event.deleteSubscription(param))
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400838 {
Ed Tanous4b712a22023-08-02 12:56:52 -0700839 messages::resourceNotFound(asyncResp->res,
840 "EventDestination", param);
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400841 return;
842 }
Ed Tanous4b712a22023-08-02 12:56:52 -0700843 messages::success(asyncResp->res);
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400844 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700845}
AppaRao Pulie5aaf042020-03-20 01:05:52 +0530846
847} // namespace redfish