blob: 76f3c5a9ed0962385f9815aca2a351921278ee89 [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
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400305 if (!json_util::readJsonPatch(
306 req, asyncResp->res, "Destination", destUrl, "Context",
307 context, "Protocol", protocol, "SubscriptionType",
308 subscriptionType, "EventFormatType", eventFormatType2,
309 "HttpHeaders", headers, "RegistryPrefixes", regPrefixes,
Ed Tanousa14c9112024-09-04 10:46:47 -0700310 "OriginResources", originResources, "MessageIds", msgIds,
311 "DeliveryRetryPolicy", retryPolicy,
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400312 "MetricReportDefinitions", mrdJsonArray, "ResourceTypes",
313 resTypes, "VerifyCertificate", verifyCertificate))
Ed Tanousfffb8c12022-02-07 23:53:03 -0800314 {
Ed Tanousa716aa72023-08-01 11:35:53 -0700315 return;
316 }
Chicago Duan3d307082020-11-26 14:12:12 +0800317
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400318 // https://stackoverflow.com/questions/417142/what-is-the-maximum-length-of-a-url-in-different-browsers
319 static constexpr const uint16_t maxDestinationSize = 2000;
320 if (destUrl.size() > maxDestinationSize)
Ed Tanousfffb8c12022-02-07 23:53:03 -0800321 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400322 messages::stringValueTooLong(asyncResp->res, "Destination",
323 maxDestinationSize);
Ed Tanous002d39b2022-05-31 08:59:27 -0700324 return;
325 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700326
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400327 if (regPrefixes && msgIds)
Ed Tanous002d39b2022-05-31 08:59:27 -0700328 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400329 if (!regPrefixes->empty() && !msgIds->empty())
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700330 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400331 messages::propertyValueConflict(
332 asyncResp->res, "MessageIds", "RegistryPrefixes");
P Dheeraj Srujan Kumarb304bd72021-01-29 17:46:35 +0530333 return;
334 }
Ed Tanousfffb8c12022-02-07 23:53:03 -0800335 }
P Dheeraj Srujan Kumarb304bd72021-01-29 17:46:35 +0530336
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400337 boost::system::result<boost::urls::url> url =
338 boost::urls::parse_absolute_uri(destUrl);
339 if (!url)
Ed Tanousfffb8c12022-02-07 23:53:03 -0800340 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400341 BMCWEB_LOG_WARNING(
342 "Failed to validate and split destination url");
343 messages::propertyValueFormatError(asyncResp->res, destUrl,
344 "Destination");
345 return;
346 }
347 url->normalize();
348 crow::utility::setProtocolDefaults(*url, protocol);
349 crow::utility::setPortDefaults(*url);
350
351 if (url->path().empty())
352 {
353 url->set_path("/");
354 }
355
356 if (url->has_userinfo())
357 {
358 messages::propertyValueFormatError(asyncResp->res, destUrl,
359 "Destination");
360 return;
361 }
362
363 if (protocol == "SNMPv2c")
364 {
365 if (context)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700366 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400367 messages::propertyValueConflict(asyncResp->res, "Context",
368 "Protocol");
AppaRao Puli144b6312020-08-03 22:23:12 +0530369 return;
370 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400371 if (eventFormatType2)
372 {
373 messages::propertyValueConflict(
374 asyncResp->res, "EventFormatType", "Protocol");
375 return;
376 }
377 if (retryPolicy)
378 {
379 messages::propertyValueConflict(asyncResp->res,
380 "RetryPolicy", "Protocol");
381 return;
382 }
383 if (msgIds)
384 {
385 messages::propertyValueConflict(asyncResp->res,
386 "MessageIds", "Protocol");
387 return;
388 }
389 if (regPrefixes)
390 {
391 messages::propertyValueConflict(
392 asyncResp->res, "RegistryPrefixes", "Protocol");
393 return;
394 }
395 if (resTypes)
396 {
397 messages::propertyValueConflict(
398 asyncResp->res, "ResourceTypes", "Protocol");
399 return;
400 }
401 if (headers)
402 {
403 messages::propertyValueConflict(asyncResp->res,
404 "HttpHeaders", "Protocol");
405 return;
406 }
407 if (mrdJsonArray)
408 {
409 messages::propertyValueConflict(
410 asyncResp->res, "MetricReportDefinitions", "Protocol");
411 return;
412 }
413 if (url->scheme() != "snmp")
414 {
415 messages::propertyValueConflict(asyncResp->res,
416 "Destination", "Protocol");
417 return;
418 }
419
420 addSnmpTrapClient(asyncResp, url->host_address(),
421 url->port_number());
422 return;
Ed Tanous002d39b2022-05-31 08:59:27 -0700423 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700424
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400425 std::shared_ptr<Subscription> subValue =
426 std::make_shared<Subscription>(*url, app.ioContext());
Ed Tanous002d39b2022-05-31 08:59:27 -0700427
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400428 subValue->destinationUrl = std::move(*url);
429
430 if (subscriptionType)
Ed Tanous002d39b2022-05-31 08:59:27 -0700431 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400432 if (*subscriptionType != "RedfishEvent")
433 {
434 messages::propertyValueNotInList(
435 asyncResp->res, *subscriptionType, "SubscriptionType");
436 return;
437 }
438 subValue->subscriptionType = *subscriptionType;
Ed Tanousfffb8c12022-02-07 23:53:03 -0800439 }
440 else
441 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400442 subValue->subscriptionType = "RedfishEvent"; // Default
Ed Tanousfffb8c12022-02-07 23:53:03 -0800443 }
AppaRao Puli156d6b02020-04-25 06:04:05 +0530444
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400445 if (protocol != "Redfish")
Ed Tanousfffb8c12022-02-07 23:53:03 -0800446 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400447 messages::propertyValueNotInList(asyncResp->res, protocol,
448 "Protocol");
449 return;
450 }
451 subValue->protocol = protocol;
Ed Tanousfffb8c12022-02-07 23:53:03 -0800452
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400453 if (verifyCertificate)
454 {
455 subValue->verifyCertificate = *verifyCertificate;
456 }
457
458 if (eventFormatType2)
459 {
460 if (std::ranges::find(supportedEvtFormatTypes,
461 *eventFormatType2) ==
462 supportedEvtFormatTypes.end())
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700463 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400464 messages::propertyValueNotInList(
465 asyncResp->res, *eventFormatType2, "EventFormatType");
466 return;
467 }
468 subValue->eventFormatType = *eventFormatType2;
469 }
470 else
471 {
472 // If not specified, use default "Event"
473 subValue->eventFormatType = "Event";
474 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700475
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400476 if (context)
477 {
478 // This value is selected arbitrarily.
479 constexpr const size_t maxContextSize = 256;
480 if (context->size() > maxContextSize)
481 {
482 messages::stringValueTooLong(asyncResp->res, "Context",
483 maxContextSize);
484 return;
485 }
486 subValue->customText = *context;
487 }
488
489 if (headers)
490 {
491 size_t cumulativeLen = 0;
492
493 for (const nlohmann::json::object_t& headerChunk : *headers)
494 {
495 for (const auto& item : headerChunk)
Ed Tanous002d39b2022-05-31 08:59:27 -0700496 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400497 const std::string* value =
498 item.second.get_ptr<const std::string*>();
499 if (value == nullptr)
500 {
501 messages::propertyValueFormatError(
502 asyncResp->res, item.second,
503 "HttpHeaders/" + item.first);
504 return;
505 }
506 // Adding a new json value is the size of the key, +
507 // the size of the value + 2 * 2 quotes for each, +
508 // the colon and space between. example:
509 // "key": "value"
510 cumulativeLen += item.first.size() + value->size() + 6;
511 // This value is selected to mirror http_connection.hpp
512 constexpr const uint16_t maxHeaderSizeED = 8096;
513 if (cumulativeLen > maxHeaderSizeED)
514 {
515 messages::arraySizeTooLong(
516 asyncResp->res, "HttpHeaders", maxHeaderSizeED);
517 return;
518 }
519 subValue->httpHeaders.set(item.first, *value);
520 }
521 }
522 }
523
524 if (regPrefixes)
525 {
526 for (const std::string& it : *regPrefixes)
527 {
528 if (std::ranges::find(supportedRegPrefixes, it) ==
529 supportedRegPrefixes.end())
530 {
531 messages::propertyValueNotInList(asyncResp->res, it,
532 "RegistryPrefixes");
533 return;
534 }
535 }
536 subValue->registryPrefixes = *regPrefixes;
537 }
538
Ed Tanousa14c9112024-09-04 10:46:47 -0700539 if (originResources)
540 {
541 subValue->originResources = *originResources;
542 }
543
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400544 if (resTypes)
545 {
546 for (const std::string& it : *resTypes)
547 {
548 if (std::ranges::find(supportedResourceTypes, it) ==
549 supportedResourceTypes.end())
550 {
551 messages::propertyValueNotInList(asyncResp->res, it,
552 "ResourceTypes");
553 return;
554 }
555 }
556 subValue->resourceTypes = *resTypes;
557 }
558
559 if (msgIds)
560 {
561 std::vector<std::string> registryPrefix;
562
563 // If no registry prefixes are mentioned, consider all
564 // supported prefixes
565 if (subValue->registryPrefixes.empty())
566 {
567 registryPrefix.assign(supportedRegPrefixes.begin(),
568 supportedRegPrefixes.end());
569 }
570 else
571 {
572 registryPrefix = subValue->registryPrefixes;
573 }
574
575 for (const std::string& id : *msgIds)
576 {
577 bool validId = false;
578
579 // Check for Message ID in each of the selected Registry
580 for (const std::string& it : registryPrefix)
581 {
582 const std::span<const redfish::registries::MessageEntry>
583 registry =
584 redfish::registries::getRegistryFromPrefix(it);
585
586 if (std::ranges::any_of(
587 registry,
588 [&id](const redfish::registries::MessageEntry&
589 messageEntry) {
590 return id == messageEntry.first;
591 }))
592 {
593 validId = true;
594 break;
595 }
596 }
597
598 if (!validId)
599 {
600 messages::propertyValueNotInList(asyncResp->res, id,
601 "MessageIds");
602 return;
Ed Tanous002d39b2022-05-31 08:59:27 -0700603 }
604 }
605
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400606 subValue->registryMsgIds = *msgIds;
607 }
608
609 if (retryPolicy)
610 {
611 if (std::ranges::find(supportedRetryPolicies, *retryPolicy) ==
612 supportedRetryPolicies.end())
Ed Tanous002d39b2022-05-31 08:59:27 -0700613 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400614 messages::propertyValueNotInList(
615 asyncResp->res, *retryPolicy, "DeliveryRetryPolicy");
Ed Tanousfffb8c12022-02-07 23:53:03 -0800616 return;
617 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400618 subValue->retryPolicy = *retryPolicy;
619 }
620 else
621 {
622 // Default "TerminateAfterRetries"
623 subValue->retryPolicy = "TerminateAfterRetries";
624 }
625
626 if (mrdJsonArray)
627 {
628 for (nlohmann::json::object_t& mrdObj : *mrdJsonArray)
629 {
630 std::string mrdUri;
631
632 if (!json_util::readJsonObject(mrdObj, asyncResp->res,
633 "@odata.id", mrdUri))
634
635 {
636 return;
637 }
638 subValue->metricReportDefinitions.emplace_back(mrdUri);
639 }
Ed Tanousfffb8c12022-02-07 23:53:03 -0800640 }
641
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400642 std::string id =
643 EventServiceManager::getInstance().addPushSubscription(
644 subValue);
645 if (id.empty())
Ed Tanousfffb8c12022-02-07 23:53:03 -0800646 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400647 messages::internalError(asyncResp->res);
Ed Tanousfffb8c12022-02-07 23:53:03 -0800648 return;
649 }
650
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400651 messages::created(asyncResp->res);
652 asyncResp->res.addHeader(
653 "Location", "/redfish/v1/EventService/Subscriptions/" + id);
654 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700655}
656
657inline void requestRoutesEventDestination(App& app)
AppaRao Pulie5aaf042020-03-20 01:05:52 +0530658{
Ravi Teja9d41aec2021-07-23 01:57:01 -0500659 BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -0700660 .privileges(redfish::privileges::getEventDestination)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700661 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -0700662 [&app](const crow::Request& req,
663 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
664 const std::string& param) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400665 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
666 {
667 return;
668 }
Chicago Duan3d307082020-11-26 14:12:12 +0800669
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400670 if (param.starts_with("snmp"))
671 {
672 getSnmpTrapClient(asyncResp, param);
673 return;
674 }
Chicago Duan3d307082020-11-26 14:12:12 +0800675
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400676 std::shared_ptr<Subscription> subValue =
677 EventServiceManager::getInstance().getSubscription(param);
678 if (subValue == nullptr)
679 {
680 asyncResp->res.result(
681 boost::beast::http::status::not_found);
682 return;
683 }
684 const std::string& id = param;
AppaRao Pulie5aaf042020-03-20 01:05:52 +0530685
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400686 asyncResp->res.jsonValue["@odata.type"] =
Myung Bae87599612024-09-11 10:11:34 -0400687 "#EventDestination.v1_14_1.EventDestination";
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400688 asyncResp->res.jsonValue["Protocol"] =
689 event_destination::EventDestinationProtocol::Redfish;
690 asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
691 "/redfish/v1/EventService/Subscriptions/{}", id);
692 asyncResp->res.jsonValue["Id"] = id;
693 asyncResp->res.jsonValue["Name"] = "Event Destination " + id;
694 asyncResp->res.jsonValue["Destination"] =
695 subValue->destinationUrl;
696 asyncResp->res.jsonValue["Context"] = subValue->customText;
697 asyncResp->res.jsonValue["SubscriptionType"] =
698 subValue->subscriptionType;
699 asyncResp->res.jsonValue["HttpHeaders"] =
700 nlohmann::json::array();
701 asyncResp->res.jsonValue["EventFormatType"] =
702 subValue->eventFormatType;
703 asyncResp->res.jsonValue["RegistryPrefixes"] =
704 subValue->registryPrefixes;
705 asyncResp->res.jsonValue["ResourceTypes"] =
706 subValue->resourceTypes;
zhanghch058d1b46d2021-04-01 11:18:24 +0800707
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400708 asyncResp->res.jsonValue["MessageIds"] =
709 subValue->registryMsgIds;
710 asyncResp->res.jsonValue["DeliveryRetryPolicy"] =
711 subValue->retryPolicy;
712 asyncResp->res.jsonValue["VerifyCertificate"] =
713 subValue->verifyCertificate;
AppaRao Pulie5aaf042020-03-20 01:05:52 +0530714
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400715 nlohmann::json::array_t mrdJsonArray;
716 for (const auto& mdrUri : subValue->metricReportDefinitions)
717 {
718 nlohmann::json::object_t mdr;
719 mdr["@odata.id"] = mdrUri;
720 mrdJsonArray.emplace_back(std::move(mdr));
721 }
722 asyncResp->res.jsonValue["MetricReportDefinitions"] =
723 mrdJsonArray;
724 });
Ravi Teja9d41aec2021-07-23 01:57:01 -0500725 BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -0700726 // The below privilege is wrong, it should be ConfigureManager OR
727 // ConfigureSelf
Abhishek Patel7eeafa72021-07-28 10:59:16 -0500728 // https://github.com/openbmc/bmcweb/issues/220
Ed Tanoused398212021-06-09 17:05:54 -0700729 //.privileges(redfish::privileges::patchEventDestination)
Ed Tanous432a8902021-06-14 15:28:56 -0700730 .privileges({{"ConfigureManager"}})
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700731 .methods(boost::beast::http::verb::patch)(
Ed Tanous45ca1b82022-03-25 13:07:27 -0700732 [&app](const crow::Request& req,
733 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
734 const std::string& param) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400735 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700736 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400737 return;
738 }
739 std::shared_ptr<Subscription> subValue =
740 EventServiceManager::getInstance().getSubscription(param);
741 if (subValue == nullptr)
742 {
743 asyncResp->res.result(
744 boost::beast::http::status::not_found);
745 return;
746 }
747
748 std::optional<std::string> context;
749 std::optional<std::string> retryPolicy;
750 std::optional<bool> verifyCertificate;
751 std::optional<std::vector<nlohmann::json::object_t>> headers;
752
753 if (!json_util::readJsonPatch(
754 req, asyncResp->res, "Context", context,
755 "VerifyCertificate", verifyCertificate,
756 "DeliveryRetryPolicy", retryPolicy, "HttpHeaders",
757 headers))
758 {
759 return;
760 }
761
762 if (context)
763 {
764 subValue->customText = *context;
765 }
766
767 if (headers)
768 {
769 boost::beast::http::fields fields;
770 for (const nlohmann::json::object_t& headerChunk : *headers)
Ed Tanous601c71a2021-09-08 16:40:12 -0700771 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400772 for (const auto& it : headerChunk)
773 {
774 const std::string* value =
775 it.second.get_ptr<const std::string*>();
776 if (value == nullptr)
777 {
778 messages::propertyValueFormatError(
779 asyncResp->res, it.second,
780 "HttpHeaders/" + it.first);
781 return;
782 }
783 fields.set(it.first, *value);
784 }
785 }
786 subValue->httpHeaders = std::move(fields);
787 }
788
789 if (retryPolicy)
790 {
791 if (std::ranges::find(supportedRetryPolicies,
792 *retryPolicy) ==
793 supportedRetryPolicies.end())
794 {
795 messages::propertyValueNotInList(asyncResp->res,
796 *retryPolicy,
797 "DeliveryRetryPolicy");
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700798 return;
799 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400800 subValue->retryPolicy = *retryPolicy;
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700801 }
AppaRao Pulie5aaf042020-03-20 01:05:52 +0530802
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400803 if (verifyCertificate)
804 {
805 subValue->verifyCertificate = *verifyCertificate;
806 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700807
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400808 EventServiceManager::getInstance().updateSubscriptionData();
809 });
Ravi Teja9d41aec2021-07-23 01:57:01 -0500810 BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -0700811 // The below privilege is wrong, it should be ConfigureManager OR
812 // ConfigureSelf
Abhishek Patel7eeafa72021-07-28 10:59:16 -0500813 // https://github.com/openbmc/bmcweb/issues/220
Ed Tanoused398212021-06-09 17:05:54 -0700814 //.privileges(redfish::privileges::deleteEventDestination)
Ed Tanous432a8902021-06-14 15:28:56 -0700815 .privileges({{"ConfigureManager"}})
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700816 .methods(boost::beast::http::verb::delete_)(
Ed Tanous45ca1b82022-03-25 13:07:27 -0700817 [&app](const crow::Request& req,
818 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
819 const std::string& param) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400820 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
821 {
822 return;
823 }
Chicago Duan3d307082020-11-26 14:12:12 +0800824
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400825 if (param.starts_with("snmp"))
826 {
827 deleteSnmpTrapClient(asyncResp, param);
828 EventServiceManager::getInstance().deleteSubscription(
829 param);
830 return;
831 }
Chicago Duan3d307082020-11-26 14:12:12 +0800832
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400833 if (!EventServiceManager::getInstance().isSubscriptionExist(
834 param))
835 {
836 asyncResp->res.result(
837 boost::beast::http::status::not_found);
838 return;
839 }
840 EventServiceManager::getInstance().deleteSubscription(param);
841 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700842}
AppaRao Pulie5aaf042020-03-20 01:05:52 +0530843
844} // namespace redfish