blob: a75da35a99873ad5e44f7fdc69e30d3ee48711af [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();
George Liub07942e2024-11-01 09:59:40 +0800357
358 // port_number returns zero if it is not a valid representable port
359 if (url->has_port() && url->port_number() == 0)
360 {
361 BMCWEB_LOG_WARNING("{} is an invalid port in destination url",
362 url->port());
363 messages::propertyValueFormatError(asyncResp->res, destUrl,
364 "Destination");
365 return;
366 }
367
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400368 crow::utility::setProtocolDefaults(*url, protocol);
369 crow::utility::setPortDefaults(*url);
370
371 if (url->path().empty())
372 {
373 url->set_path("/");
374 }
375
376 if (url->has_userinfo())
377 {
378 messages::propertyValueFormatError(asyncResp->res, destUrl,
379 "Destination");
380 return;
381 }
382
383 if (protocol == "SNMPv2c")
384 {
385 if (context)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700386 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400387 messages::propertyValueConflict(asyncResp->res, "Context",
388 "Protocol");
AppaRao Puli144b6312020-08-03 22:23:12 +0530389 return;
390 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400391 if (eventFormatType2)
392 {
393 messages::propertyValueConflict(
394 asyncResp->res, "EventFormatType", "Protocol");
395 return;
396 }
397 if (retryPolicy)
398 {
399 messages::propertyValueConflict(asyncResp->res,
400 "RetryPolicy", "Protocol");
401 return;
402 }
403 if (msgIds)
404 {
405 messages::propertyValueConflict(asyncResp->res,
406 "MessageIds", "Protocol");
407 return;
408 }
409 if (regPrefixes)
410 {
411 messages::propertyValueConflict(
412 asyncResp->res, "RegistryPrefixes", "Protocol");
413 return;
414 }
415 if (resTypes)
416 {
417 messages::propertyValueConflict(
418 asyncResp->res, "ResourceTypes", "Protocol");
419 return;
420 }
421 if (headers)
422 {
423 messages::propertyValueConflict(asyncResp->res,
424 "HttpHeaders", "Protocol");
425 return;
426 }
427 if (mrdJsonArray)
428 {
429 messages::propertyValueConflict(
430 asyncResp->res, "MetricReportDefinitions", "Protocol");
431 return;
432 }
433 if (url->scheme() != "snmp")
434 {
435 messages::propertyValueConflict(asyncResp->res,
436 "Destination", "Protocol");
437 return;
438 }
439
440 addSnmpTrapClient(asyncResp, url->host_address(),
441 url->port_number());
442 return;
Ed Tanous002d39b2022-05-31 08:59:27 -0700443 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700444
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400445 std::shared_ptr<Subscription> subValue =
Myung Bae21a94d52024-10-14 15:02:57 -0700446 std::make_shared<Subscription>(
Myung Bae5fe4ef32024-10-19 09:56:02 -0400447 std::make_shared<persistent_data::UserSubscription>(), *url,
448 app.ioContext());
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400449
450 if (subscriptionType)
Ed Tanous002d39b2022-05-31 08:59:27 -0700451 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400452 if (*subscriptionType != "RedfishEvent")
453 {
454 messages::propertyValueNotInList(
455 asyncResp->res, *subscriptionType, "SubscriptionType");
456 return;
457 }
Myung Bae5fe4ef32024-10-19 09:56:02 -0400458 subValue->userSub->subscriptionType = *subscriptionType;
Ed Tanousfffb8c12022-02-07 23:53:03 -0800459 }
460 else
461 {
Ed Tanous4b712a22023-08-02 12:56:52 -0700462 // Default
Myung Bae5fe4ef32024-10-19 09:56:02 -0400463 subValue->userSub->subscriptionType = "RedfishEvent";
Ed Tanousfffb8c12022-02-07 23:53:03 -0800464 }
AppaRao Puli156d6b02020-04-25 06:04:05 +0530465
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400466 if (protocol != "Redfish")
Ed Tanousfffb8c12022-02-07 23:53:03 -0800467 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400468 messages::propertyValueNotInList(asyncResp->res, protocol,
469 "Protocol");
470 return;
471 }
Myung Bae5fe4ef32024-10-19 09:56:02 -0400472 subValue->userSub->protocol = protocol;
Ed Tanousfffb8c12022-02-07 23:53:03 -0800473
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400474 if (verifyCertificate)
475 {
Myung Bae5fe4ef32024-10-19 09:56:02 -0400476 subValue->userSub->verifyCertificate = *verifyCertificate;
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400477 }
478
479 if (eventFormatType2)
480 {
481 if (std::ranges::find(supportedEvtFormatTypes,
482 *eventFormatType2) ==
483 supportedEvtFormatTypes.end())
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700484 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400485 messages::propertyValueNotInList(
486 asyncResp->res, *eventFormatType2, "EventFormatType");
487 return;
488 }
Myung Bae5fe4ef32024-10-19 09:56:02 -0400489 subValue->userSub->eventFormatType = *eventFormatType2;
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400490 }
491 else
492 {
493 // If not specified, use default "Event"
Myung Bae5fe4ef32024-10-19 09:56:02 -0400494 subValue->userSub->eventFormatType = "Event";
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400495 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700496
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400497 if (context)
498 {
499 // This value is selected arbitrarily.
500 constexpr const size_t maxContextSize = 256;
501 if (context->size() > maxContextSize)
502 {
503 messages::stringValueTooLong(asyncResp->res, "Context",
504 maxContextSize);
505 return;
506 }
Myung Bae5fe4ef32024-10-19 09:56:02 -0400507 subValue->userSub->customText = *context;
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400508 }
509
510 if (headers)
511 {
512 size_t cumulativeLen = 0;
513
514 for (const nlohmann::json::object_t& headerChunk : *headers)
515 {
516 for (const auto& item : headerChunk)
Ed Tanous002d39b2022-05-31 08:59:27 -0700517 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400518 const std::string* value =
519 item.second.get_ptr<const std::string*>();
520 if (value == nullptr)
521 {
522 messages::propertyValueFormatError(
523 asyncResp->res, item.second,
524 "HttpHeaders/" + item.first);
525 return;
526 }
527 // Adding a new json value is the size of the key, +
528 // the size of the value + 2 * 2 quotes for each, +
529 // the colon and space between. example:
530 // "key": "value"
531 cumulativeLen += item.first.size() + value->size() + 6;
532 // This value is selected to mirror http_connection.hpp
533 constexpr const uint16_t maxHeaderSizeED = 8096;
534 if (cumulativeLen > maxHeaderSizeED)
535 {
536 messages::arraySizeTooLong(
537 asyncResp->res, "HttpHeaders", maxHeaderSizeED);
538 return;
539 }
Myung Bae5fe4ef32024-10-19 09:56:02 -0400540 subValue->userSub->httpHeaders.set(item.first, *value);
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400541 }
542 }
543 }
544
545 if (regPrefixes)
546 {
547 for (const std::string& it : *regPrefixes)
548 {
549 if (std::ranges::find(supportedRegPrefixes, it) ==
550 supportedRegPrefixes.end())
551 {
552 messages::propertyValueNotInList(asyncResp->res, it,
553 "RegistryPrefixes");
554 return;
555 }
556 }
Myung Bae5fe4ef32024-10-19 09:56:02 -0400557 subValue->userSub->registryPrefixes = *regPrefixes;
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400558 }
559
Ed Tanousa14c9112024-09-04 10:46:47 -0700560 if (originResources)
561 {
Myung Bae5fe4ef32024-10-19 09:56:02 -0400562 subValue->userSub->originResources = *originResources;
Ed Tanousa14c9112024-09-04 10:46:47 -0700563 }
564
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400565 if (resTypes)
566 {
567 for (const std::string& it : *resTypes)
568 {
569 if (std::ranges::find(supportedResourceTypes, it) ==
570 supportedResourceTypes.end())
571 {
572 messages::propertyValueNotInList(asyncResp->res, it,
573 "ResourceTypes");
574 return;
575 }
576 }
Myung Bae5fe4ef32024-10-19 09:56:02 -0400577 subValue->userSub->resourceTypes = *resTypes;
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400578 }
579
580 if (msgIds)
581 {
582 std::vector<std::string> registryPrefix;
583
584 // If no registry prefixes are mentioned, consider all
585 // supported prefixes
Myung Bae5fe4ef32024-10-19 09:56:02 -0400586 if (subValue->userSub->registryPrefixes.empty())
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400587 {
588 registryPrefix.assign(supportedRegPrefixes.begin(),
589 supportedRegPrefixes.end());
590 }
591 else
592 {
Myung Bae5fe4ef32024-10-19 09:56:02 -0400593 registryPrefix = subValue->userSub->registryPrefixes;
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400594 }
595
596 for (const std::string& id : *msgIds)
597 {
598 bool validId = false;
599
600 // Check for Message ID in each of the selected Registry
601 for (const std::string& it : registryPrefix)
602 {
603 const std::span<const redfish::registries::MessageEntry>
604 registry =
605 redfish::registries::getRegistryFromPrefix(it);
606
607 if (std::ranges::any_of(
608 registry,
609 [&id](const redfish::registries::MessageEntry&
610 messageEntry) {
611 return id == messageEntry.first;
612 }))
613 {
614 validId = true;
615 break;
616 }
617 }
618
619 if (!validId)
620 {
621 messages::propertyValueNotInList(asyncResp->res, id,
622 "MessageIds");
623 return;
Ed Tanous002d39b2022-05-31 08:59:27 -0700624 }
625 }
626
Myung Bae5fe4ef32024-10-19 09:56:02 -0400627 subValue->userSub->registryMsgIds = *msgIds;
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400628 }
629
630 if (retryPolicy)
631 {
632 if (std::ranges::find(supportedRetryPolicies, *retryPolicy) ==
633 supportedRetryPolicies.end())
Ed Tanous002d39b2022-05-31 08:59:27 -0700634 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400635 messages::propertyValueNotInList(
636 asyncResp->res, *retryPolicy, "DeliveryRetryPolicy");
Ed Tanousfffb8c12022-02-07 23:53:03 -0800637 return;
638 }
Myung Bae5fe4ef32024-10-19 09:56:02 -0400639 subValue->userSub->retryPolicy = *retryPolicy;
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400640 }
641 else
642 {
643 // Default "TerminateAfterRetries"
Myung Bae5fe4ef32024-10-19 09:56:02 -0400644 subValue->userSub->retryPolicy = "TerminateAfterRetries";
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400645 }
646
647 if (mrdJsonArray)
648 {
649 for (nlohmann::json::object_t& mrdObj : *mrdJsonArray)
650 {
651 std::string mrdUri;
652
653 if (!json_util::readJsonObject(mrdObj, asyncResp->res,
654 "@odata.id", mrdUri))
655
656 {
657 return;
658 }
Myung Bae5fe4ef32024-10-19 09:56:02 -0400659 subValue->userSub->metricReportDefinitions.emplace_back(
Ed Tanous4b712a22023-08-02 12:56:52 -0700660 mrdUri);
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400661 }
Ed Tanousfffb8c12022-02-07 23:53:03 -0800662 }
663
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400664 std::string id =
665 EventServiceManager::getInstance().addPushSubscription(
666 subValue);
667 if (id.empty())
Ed Tanousfffb8c12022-02-07 23:53:03 -0800668 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400669 messages::internalError(asyncResp->res);
Ed Tanousfffb8c12022-02-07 23:53:03 -0800670 return;
671 }
672
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400673 messages::created(asyncResp->res);
674 asyncResp->res.addHeader(
675 "Location", "/redfish/v1/EventService/Subscriptions/" + id);
676 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700677}
678
679inline void requestRoutesEventDestination(App& app)
AppaRao Pulie5aaf042020-03-20 01:05:52 +0530680{
Ravi Teja9d41aec2021-07-23 01:57:01 -0500681 BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -0700682 .privileges(redfish::privileges::getEventDestination)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700683 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -0700684 [&app](const crow::Request& req,
685 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
686 const std::string& param) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400687 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
688 {
689 return;
690 }
Chicago Duan3d307082020-11-26 14:12:12 +0800691
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400692 if (param.starts_with("snmp"))
693 {
694 getSnmpTrapClient(asyncResp, param);
695 return;
696 }
Chicago Duan3d307082020-11-26 14:12:12 +0800697
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400698 std::shared_ptr<Subscription> subValue =
699 EventServiceManager::getInstance().getSubscription(param);
700 if (subValue == nullptr)
701 {
702 asyncResp->res.result(
703 boost::beast::http::status::not_found);
704 return;
705 }
706 const std::string& id = param;
AppaRao Pulie5aaf042020-03-20 01:05:52 +0530707
Ed Tanous4b712a22023-08-02 12:56:52 -0700708 const persistent_data::UserSubscription& userSub =
Myung Bae5fe4ef32024-10-19 09:56:02 -0400709 *subValue->userSub;
zhanghch058d1b46d2021-04-01 11:18:24 +0800710
Ed Tanous4b712a22023-08-02 12:56:52 -0700711 nlohmann::json& jVal = asyncResp->res.jsonValue;
712 jVal["@odata.type"] =
713 "#EventDestination.v1_14_1.EventDestination";
714 jVal["Protocol"] =
715 event_destination::EventDestinationProtocol::Redfish;
716 jVal["@odata.id"] = boost::urls::format(
717 "/redfish/v1/EventService/Subscriptions/{}", id);
718 jVal["Id"] = id;
719 jVal["Name"] = "Event Destination " + id;
720 jVal["Destination"] = userSub.destinationUrl;
721 jVal["Context"] = userSub.customText;
722 jVal["SubscriptionType"] = userSub.subscriptionType;
723 jVal["HttpHeaders"] = nlohmann::json::array();
724 jVal["EventFormatType"] = userSub.eventFormatType;
725 jVal["RegistryPrefixes"] = userSub.registryPrefixes;
726 jVal["ResourceTypes"] = userSub.resourceTypes;
727
728 jVal["MessageIds"] = userSub.registryMsgIds;
729 jVal["DeliveryRetryPolicy"] = userSub.retryPolicy;
730 jVal["VerifyCertificate"] = userSub.verifyCertificate;
AppaRao Pulie5aaf042020-03-20 01:05:52 +0530731
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400732 nlohmann::json::array_t mrdJsonArray;
Ed Tanous4b712a22023-08-02 12:56:52 -0700733 for (const auto& mdrUri : userSub.metricReportDefinitions)
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400734 {
735 nlohmann::json::object_t mdr;
736 mdr["@odata.id"] = mdrUri;
737 mrdJsonArray.emplace_back(std::move(mdr));
738 }
Ed Tanous4b712a22023-08-02 12:56:52 -0700739 jVal["MetricReportDefinitions"] = mrdJsonArray;
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400740 });
Ravi Teja9d41aec2021-07-23 01:57:01 -0500741 BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -0700742 // The below privilege is wrong, it should be ConfigureManager OR
743 // ConfigureSelf
Abhishek Patel7eeafa72021-07-28 10:59:16 -0500744 // https://github.com/openbmc/bmcweb/issues/220
Ed Tanoused398212021-06-09 17:05:54 -0700745 //.privileges(redfish::privileges::patchEventDestination)
Ed Tanous432a8902021-06-14 15:28:56 -0700746 .privileges({{"ConfigureManager"}})
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700747 .methods(boost::beast::http::verb::patch)(
Ed Tanous45ca1b82022-03-25 13:07:27 -0700748 [&app](const crow::Request& req,
749 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
750 const std::string& param) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400751 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700752 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400753 return;
754 }
755 std::shared_ptr<Subscription> subValue =
756 EventServiceManager::getInstance().getSubscription(param);
757 if (subValue == nullptr)
758 {
759 asyncResp->res.result(
760 boost::beast::http::status::not_found);
761 return;
762 }
763
764 std::optional<std::string> context;
765 std::optional<std::string> retryPolicy;
766 std::optional<bool> verifyCertificate;
767 std::optional<std::vector<nlohmann::json::object_t>> headers;
768
Myung Baeafc474a2024-10-09 00:53:29 -0700769 if (!json_util::readJsonPatch( //
770 req, asyncResp->res, //
771 "Context", context, //
772 "DeliveryRetryPolicy", retryPolicy, //
773 "HttpHeaders", headers, //
774 "VerifyCertificate", verifyCertificate //
775 ))
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400776 {
777 return;
778 }
779
780 if (context)
781 {
Myung Bae5fe4ef32024-10-19 09:56:02 -0400782 subValue->userSub->customText = *context;
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400783 }
784
785 if (headers)
786 {
787 boost::beast::http::fields fields;
788 for (const nlohmann::json::object_t& headerChunk : *headers)
Ed Tanous601c71a2021-09-08 16:40:12 -0700789 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400790 for (const auto& it : headerChunk)
791 {
792 const std::string* value =
793 it.second.get_ptr<const std::string*>();
794 if (value == nullptr)
795 {
796 messages::propertyValueFormatError(
797 asyncResp->res, it.second,
798 "HttpHeaders/" + it.first);
799 return;
800 }
801 fields.set(it.first, *value);
802 }
803 }
Myung Bae5fe4ef32024-10-19 09:56:02 -0400804 subValue->userSub->httpHeaders = std::move(fields);
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400805 }
806
807 if (retryPolicy)
808 {
809 if (std::ranges::find(supportedRetryPolicies,
810 *retryPolicy) ==
811 supportedRetryPolicies.end())
812 {
813 messages::propertyValueNotInList(asyncResp->res,
814 *retryPolicy,
815 "DeliveryRetryPolicy");
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700816 return;
817 }
Myung Bae5fe4ef32024-10-19 09:56:02 -0400818 subValue->userSub->retryPolicy = *retryPolicy;
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700819 }
AppaRao Pulie5aaf042020-03-20 01:05:52 +0530820
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400821 if (verifyCertificate)
822 {
Myung Bae5fe4ef32024-10-19 09:56:02 -0400823 subValue->userSub->verifyCertificate = *verifyCertificate;
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400824 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700825
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400826 EventServiceManager::getInstance().updateSubscriptionData();
827 });
Ravi Teja9d41aec2021-07-23 01:57:01 -0500828 BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -0700829 // The below privilege is wrong, it should be ConfigureManager OR
830 // ConfigureSelf
Abhishek Patel7eeafa72021-07-28 10:59:16 -0500831 // https://github.com/openbmc/bmcweb/issues/220
Ed Tanoused398212021-06-09 17:05:54 -0700832 //.privileges(redfish::privileges::deleteEventDestination)
Ed Tanous432a8902021-06-14 15:28:56 -0700833 .privileges({{"ConfigureManager"}})
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700834 .methods(boost::beast::http::verb::delete_)(
Ed Tanous45ca1b82022-03-25 13:07:27 -0700835 [&app](const crow::Request& req,
836 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
837 const std::string& param) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400838 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
839 {
840 return;
841 }
Ed Tanous4b712a22023-08-02 12:56:52 -0700842 EventServiceManager& event = EventServiceManager::getInstance();
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400843 if (param.starts_with("snmp"))
844 {
845 deleteSnmpTrapClient(asyncResp, param);
Ed Tanous4b712a22023-08-02 12:56:52 -0700846 event.deleteSubscription(param);
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400847 return;
848 }
Chicago Duan3d307082020-11-26 14:12:12 +0800849
Ed Tanous4b712a22023-08-02 12:56:52 -0700850 if (!event.deleteSubscription(param))
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400851 {
Ed Tanous4b712a22023-08-02 12:56:52 -0700852 messages::resourceNotFound(asyncResp->res,
853 "EventDestination", param);
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400854 return;
855 }
Ed Tanous4b712a22023-08-02 12:56:52 -0700856 messages::success(asyncResp->res);
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400857 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700858}
AppaRao Pulie5aaf042020-03-20 01:05:52 +0530859
860} // namespace redfish