blob: ca1e7138ada805a4fb38bcfa4f1395528be4fd06 [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;
Myung Baeafc474a2024-10-09 00:53:29 -0700121 if (!json_util::readJsonPatch( //
122 req, asyncResp->res, //
123 "DeliveryRetryAttempts", retryAttemps, //
124 "DeliveryRetryIntervalSeconds", retryInterval, //
125 "ServiceEnabled", serviceEnabled //
126 ))
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400127 {
128 return;
129 }
AppaRao Pulie5aaf042020-03-20 01:05:52 +0530130
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400131 persistent_data::EventServiceConfig eventServiceConfig =
132 persistent_data::EventServiceStore::getInstance()
133 .getEventServiceConfig();
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700134
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400135 if (serviceEnabled)
136 {
137 eventServiceConfig.enabled = *serviceEnabled;
138 }
Sunitha Harishe56f2542020-07-22 02:38:59 -0500139
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400140 if (retryAttemps)
141 {
142 // Supported range [1-3]
143 if ((*retryAttemps < 1) || (*retryAttemps > 3))
144 {
145 messages::queryParameterOutOfRange(
146 asyncResp->res, std::to_string(*retryAttemps),
147 "DeliveryRetryAttempts", "[1-3]");
148 }
149 else
150 {
151 eventServiceConfig.retryAttempts = *retryAttemps;
152 }
153 }
P Dheeraj Srujan Kumarb304bd72021-01-29 17:46:35 +0530154
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400155 if (retryInterval)
156 {
157 // Supported range [5 - 180]
158 if ((*retryInterval < 5) || (*retryInterval > 180))
159 {
160 messages::queryParameterOutOfRange(
161 asyncResp->res, std::to_string(*retryInterval),
162 "DeliveryRetryIntervalSeconds", "[5-180]");
163 }
164 else
165 {
166 eventServiceConfig.retryTimeoutInterval =
167 *retryInterval;
168 }
169 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700170
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400171 EventServiceManager::getInstance().setEventServiceConfig(
172 eventServiceConfig);
173 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700174}
175
176inline void requestRoutesSubmitTestEvent(App& app)
177{
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700178 BMCWEB_ROUTE(
179 app, "/redfish/v1/EventService/Actions/EventService.SubmitTestEvent/")
Ed Tanoused398212021-06-09 17:05:54 -0700180 .privileges(redfish::privileges::postEventService)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700181 .methods(boost::beast::http::verb::post)(
Ed Tanous45ca1b82022-03-25 13:07:27 -0700182 [&app](const crow::Request& req,
183 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400184 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
185 {
186 return;
187 }
188 if (!EventServiceManager::getInstance().sendTestEventLog())
189 {
190 messages::serviceDisabled(asyncResp->res,
191 "/redfish/v1/EventService/");
192 return;
193 }
194 asyncResp->res.result(boost::beast::http::status::no_content);
195 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700196}
197
Chicago Duan3d307082020-11-26 14:12:12 +0800198inline void doSubscriptionCollection(
Ed Tanouse81de512023-06-27 17:07:00 -0700199 const boost::system::error_code& ec,
Chicago Duan3d307082020-11-26 14:12:12 +0800200 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
201 const dbus::utility::ManagedObjectType& resp)
202{
203 if (ec)
204 {
Ed Tanous13061012023-07-25 11:12:19 -0700205 if (ec.value() == EBADR || ec.value() == EHOSTUNREACH)
Chicago Duan3d307082020-11-26 14:12:12 +0800206 {
207 // This is an optional process so just return if it isn't there
208 return;
209 }
210
Ed Tanous62598e32023-07-17 17:06:25 -0700211 BMCWEB_LOG_ERROR("D-Bus response error on GetManagedObjects {}", ec);
Chicago Duan3d307082020-11-26 14:12:12 +0800212 messages::internalError(asyncResp->res);
213 return;
214 }
215 nlohmann::json& memberArray = asyncResp->res.jsonValue["Members"];
216 for (const auto& objpath : resp)
217 {
218 sdbusplus::message::object_path path(objpath.first);
219 const std::string snmpId = path.filename();
220 if (snmpId.empty())
221 {
Ed Tanous62598e32023-07-17 17:06:25 -0700222 BMCWEB_LOG_ERROR("The SNMP client ID is wrong");
Chicago Duan3d307082020-11-26 14:12:12 +0800223 messages::internalError(asyncResp->res);
224 return;
225 }
226
227 getSnmpSubscriptionList(asyncResp, snmpId, memberArray);
228 }
229}
230
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700231inline void requestRoutesEventDestinationCollection(App& app)
232{
Gayathri Leburu1ebe3e42022-02-09 10:45:19 +0000233 BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/")
Ed Tanoused398212021-06-09 17:05:54 -0700234 .privileges(redfish::privileges::getEventDestinationCollection)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700235 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -0700236 [&app](const crow::Request& req,
237 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400238 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
239 {
240 return;
241 }
242 asyncResp->res.jsonValue["@odata.type"] =
243 "#EventDestinationCollection.EventDestinationCollection";
244 asyncResp->res.jsonValue["@odata.id"] =
245 "/redfish/v1/EventService/Subscriptions";
246 asyncResp->res.jsonValue["Name"] =
247 "Event Destination Collections";
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700248
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400249 nlohmann::json& memberArray =
250 asyncResp->res.jsonValue["Members"];
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700251
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400252 std::vector<std::string> subscripIds =
253 EventServiceManager::getInstance().getAllIDs();
254 memberArray = nlohmann::json::array();
255 asyncResp->res.jsonValue["Members@odata.count"] =
256 subscripIds.size();
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700257
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400258 for (const std::string& id : subscripIds)
259 {
260 nlohmann::json::object_t member;
261 member["@odata.id"] = boost::urls::format(
262 "/redfish/v1/EventService/Subscriptions/{}" + id);
263 memberArray.emplace_back(std::move(member));
264 }
265 crow::connections::systemBus->async_method_call(
266 [asyncResp](const boost::system::error_code& ec,
267 const dbus::utility::ManagedObjectType& resp) {
268 doSubscriptionCollection(ec, asyncResp, resp);
269 },
270 "xyz.openbmc_project.Network.SNMP",
271 "/xyz/openbmc_project/network/snmp/manager",
272 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
273 });
Chicago Duan3d307082020-11-26 14:12:12 +0800274
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700275 BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/")
Abhishek Patel7eeafa72021-07-28 10:59:16 -0500276 .privileges(redfish::privileges::postEventDestinationCollection)
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400277 .methods(
278 boost::beast::http::verb::
279 post)([&app](
280 const crow::Request& req,
281 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
282 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
283 {
284 return;
285 }
286 if (EventServiceManager::getInstance().getNumberOfSubscriptions() >=
287 maxNoOfSubscriptions)
288 {
289 messages::eventSubscriptionLimitExceeded(asyncResp->res);
290 return;
291 }
292 std::string destUrl;
293 std::string protocol;
294 std::optional<bool> verifyCertificate;
295 std::optional<std::string> context;
296 std::optional<std::string> subscriptionType;
297 std::optional<std::string> eventFormatType2;
298 std::optional<std::string> retryPolicy;
299 std::optional<std::vector<std::string>> msgIds;
300 std::optional<std::vector<std::string>> regPrefixes;
Ed Tanousa14c9112024-09-04 10:46:47 -0700301 std::optional<std::vector<std::string>> originResources;
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400302 std::optional<std::vector<std::string>> resTypes;
303 std::optional<std::vector<nlohmann::json::object_t>> headers;
304 std::optional<std::vector<nlohmann::json::object_t>> mrdJsonArray;
Ed Tanousfffb8c12022-02-07 23:53:03 -0800305
Myung Baeafc474a2024-10-09 00:53:29 -0700306 if (!json_util::readJsonPatch( //
307 req, asyncResp->res, //
308 "Context", context, //
309 "DeliveryRetryPolicy", retryPolicy, //
310 "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
Myung Baeafc474a2024-10-09 00:53:29 -0700758 if (!json_util::readJsonPatch( //
759 req, asyncResp->res, //
760 "Context", context, //
761 "DeliveryRetryPolicy", retryPolicy, //
762 "HttpHeaders", headers, //
763 "VerifyCertificate", verifyCertificate //
764 ))
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400765 {
766 return;
767 }
768
769 if (context)
770 {
Ed Tanous4b712a22023-08-02 12:56:52 -0700771 subValue->userSub.customText = *context;
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400772 }
773
774 if (headers)
775 {
776 boost::beast::http::fields fields;
777 for (const nlohmann::json::object_t& headerChunk : *headers)
Ed Tanous601c71a2021-09-08 16:40:12 -0700778 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400779 for (const auto& it : headerChunk)
780 {
781 const std::string* value =
782 it.second.get_ptr<const std::string*>();
783 if (value == nullptr)
784 {
785 messages::propertyValueFormatError(
786 asyncResp->res, it.second,
787 "HttpHeaders/" + it.first);
788 return;
789 }
790 fields.set(it.first, *value);
791 }
792 }
Ed Tanous4b712a22023-08-02 12:56:52 -0700793 subValue->userSub.httpHeaders = std::move(fields);
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400794 }
795
796 if (retryPolicy)
797 {
798 if (std::ranges::find(supportedRetryPolicies,
799 *retryPolicy) ==
800 supportedRetryPolicies.end())
801 {
802 messages::propertyValueNotInList(asyncResp->res,
803 *retryPolicy,
804 "DeliveryRetryPolicy");
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700805 return;
806 }
Ed Tanous4b712a22023-08-02 12:56:52 -0700807 subValue->userSub.retryPolicy = *retryPolicy;
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700808 }
AppaRao Pulie5aaf042020-03-20 01:05:52 +0530809
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400810 if (verifyCertificate)
811 {
Ed Tanous4b712a22023-08-02 12:56:52 -0700812 subValue->userSub.verifyCertificate = *verifyCertificate;
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400813 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700814
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400815 EventServiceManager::getInstance().updateSubscriptionData();
816 });
Ravi Teja9d41aec2021-07-23 01:57:01 -0500817 BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -0700818 // The below privilege is wrong, it should be ConfigureManager OR
819 // ConfigureSelf
Abhishek Patel7eeafa72021-07-28 10:59:16 -0500820 // https://github.com/openbmc/bmcweb/issues/220
Ed Tanoused398212021-06-09 17:05:54 -0700821 //.privileges(redfish::privileges::deleteEventDestination)
Ed Tanous432a8902021-06-14 15:28:56 -0700822 .privileges({{"ConfigureManager"}})
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700823 .methods(boost::beast::http::verb::delete_)(
Ed Tanous45ca1b82022-03-25 13:07:27 -0700824 [&app](const crow::Request& req,
825 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
826 const std::string& param) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400827 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
828 {
829 return;
830 }
Ed Tanous4b712a22023-08-02 12:56:52 -0700831 EventServiceManager& event = EventServiceManager::getInstance();
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400832 if (param.starts_with("snmp"))
833 {
834 deleteSnmpTrapClient(asyncResp, param);
Ed Tanous4b712a22023-08-02 12:56:52 -0700835 event.deleteSubscription(param);
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400836 return;
837 }
Chicago Duan3d307082020-11-26 14:12:12 +0800838
Ed Tanous4b712a22023-08-02 12:56:52 -0700839 if (!event.deleteSubscription(param))
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400840 {
Ed Tanous4b712a22023-08-02 12:56:52 -0700841 messages::resourceNotFound(asyncResp->res,
842 "EventDestination", param);
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400843 return;
844 }
Ed Tanous4b712a22023-08-02 12:56:52 -0700845 messages::success(asyncResp->res);
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400846 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700847}
AppaRao Pulie5aaf042020-03-20 01:05:52 +0530848
849} // namespace redfish