blob: aef4d4727834f7f84054558356f72fcf2eddc763 [file] [log] [blame]
AppaRao Pulie5aaf042020-03-20 01:05:52 +05301/*
2// Copyright (c) 2020 Intel Corporation
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15*/
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 Tanous3ccb3ad2023-01-13 17:40:03 -080019#include "http/utility.hpp"
20#include "logging.hpp"
21#include "query.hpp"
22#include "registries/privilege_registry.hpp"
Chicago Duan3d307082020-11-26 14:12:12 +080023#include "snmp_trap_event_clients.hpp"
AppaRao Pulie5aaf042020-03-20 01:05:52 +053024
Ed Tanous601c71a2021-09-08 16:40:12 -070025#include <boost/beast/http/fields.hpp>
Chicago Duan3d307082020-11-26 14:12:12 +080026#include <boost/system/error_code.hpp>
27#include <sdbusplus/unpack_properties.hpp>
28#include <utils/dbus_utils.hpp>
Ed Tanoused398212021-06-09 17:05:54 -070029
Chicago Duan3d307082020-11-26 14:12:12 +080030#include <charconv>
31#include <memory>
Patrick Williams1e270c52021-12-04 06:06:56 -060032#include <span>
Chicago Duan3d307082020-11-26 14:12:12 +080033#include <string>
Patrick Williams1e270c52021-12-04 06:06:56 -060034
AppaRao Pulie5aaf042020-03-20 01:05:52 +053035namespace redfish
36{
37
AppaRao Puli156d6b02020-04-25 06:04:05 +053038static constexpr const std::array<const char*, 2> supportedEvtFormatTypes = {
39 eventFormatType, metricReportFormatType};
AppaRao Pulie5aaf042020-03-20 01:05:52 +053040static constexpr const std::array<const char*, 3> supportedRegPrefixes = {
P Dheeraj Srujan Kumarb304bd72021-01-29 17:46:35 +053041 "Base", "OpenBMC", "TaskEvent"};
AppaRao Pulie5aaf042020-03-20 01:05:52 +053042static constexpr const std::array<const char*, 3> supportedRetryPolicies = {
43 "TerminateAfterRetries", "SuspendRetries", "RetryForever"};
44
Sunitha Harishe56f2542020-07-22 02:38:59 -050045#ifdef BMCWEB_ENABLE_IBM_MANAGEMENT_CONSOLE
46static constexpr const std::array<const char*, 2> supportedResourceTypes = {
47 "IBMConfigFile", "Task"};
48#else
49static constexpr const std::array<const char*, 1> supportedResourceTypes = {
50 "Task"};
51#endif
52
John Edward Broadbent7e860f12021-04-08 15:57:16 -070053inline void requestRoutesEventService(App& app)
AppaRao Pulie5aaf042020-03-20 01:05:52 +053054{
John Edward Broadbent7e860f12021-04-08 15:57:16 -070055 BMCWEB_ROUTE(app, "/redfish/v1/EventService/")
Ed Tanoused398212021-06-09 17:05:54 -070056 .privileges(redfish::privileges::getEventService)
Ed Tanous002d39b2022-05-31 08:59:27 -070057 .methods(boost::beast::http::verb::get)(
58 [&app](const crow::Request& req,
59 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Carson Labrado3ba00072022-06-06 19:40:56 +000060 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -070061 {
62 return;
63 }
Ed Tanous14766872022-03-15 10:44:42 -070064
Ed Tanous002d39b2022-05-31 08:59:27 -070065 asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/EventService";
66 asyncResp->res.jsonValue["@odata.type"] =
67 "#EventService.v1_5_0.EventService";
68 asyncResp->res.jsonValue["Id"] = "EventService";
69 asyncResp->res.jsonValue["Name"] = "Event Service";
AppaRao Puli5e44e3d2021-03-16 15:37:24 +000070 asyncResp->res.jsonValue["ServerSentEventUri"] =
71 "/redfish/v1/EventService/SSE";
72
Ed Tanous002d39b2022-05-31 08:59:27 -070073 asyncResp->res.jsonValue["Subscriptions"]["@odata.id"] =
74 "/redfish/v1/EventService/Subscriptions";
75 asyncResp->res
76 .jsonValue["Actions"]["#EventService.SubmitTestEvent"]["target"] =
77 "/redfish/v1/EventService/Actions/EventService.SubmitTestEvent";
AppaRao Pulie5aaf042020-03-20 01:05:52 +053078
Ed Tanous002d39b2022-05-31 08:59:27 -070079 const persistent_data::EventServiceConfig eventServiceConfig =
80 persistent_data::EventServiceStore::getInstance()
81 .getEventServiceConfig();
zhanghch058d1b46d2021-04-01 11:18:24 +080082
Ed Tanous002d39b2022-05-31 08:59:27 -070083 asyncResp->res.jsonValue["Status"]["State"] =
84 (eventServiceConfig.enabled ? "Enabled" : "Disabled");
85 asyncResp->res.jsonValue["ServiceEnabled"] = eventServiceConfig.enabled;
86 asyncResp->res.jsonValue["DeliveryRetryAttempts"] =
87 eventServiceConfig.retryAttempts;
88 asyncResp->res.jsonValue["DeliveryRetryIntervalSeconds"] =
89 eventServiceConfig.retryTimeoutInterval;
90 asyncResp->res.jsonValue["EventFormatTypes"] = supportedEvtFormatTypes;
91 asyncResp->res.jsonValue["RegistryPrefixes"] = supportedRegPrefixes;
92 asyncResp->res.jsonValue["ResourceTypes"] = supportedResourceTypes;
AppaRao Pulie5aaf042020-03-20 01:05:52 +053093
Ed Tanous613dabe2022-07-09 11:17:36 -070094 nlohmann::json::object_t supportedSSEFilters;
95 supportedSSEFilters["EventFormatType"] = true;
96 supportedSSEFilters["MessageId"] = true;
97 supportedSSEFilters["MetricReportDefinition"] = true;
98 supportedSSEFilters["RegistryPrefix"] = true;
99 supportedSSEFilters["OriginResource"] = false;
100 supportedSSEFilters["ResourceType"] = false;
AppaRao Puli7d1cc382020-05-16 02:42:22 +0530101
Ed Tanous002d39b2022-05-31 08:59:27 -0700102 asyncResp->res.jsonValue["SSEFilterPropertiesSupported"] =
Ed Tanous613dabe2022-07-09 11:17:36 -0700103 std::move(supportedSSEFilters);
George Liu0fda0f12021-11-16 10:06:17 +0800104 });
Ayushi Smriti07941a82020-05-21 15:55:34 +0530105
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700106 BMCWEB_ROUTE(app, "/redfish/v1/EventService/")
Ed Tanoused398212021-06-09 17:05:54 -0700107 .privileges(redfish::privileges::patchEventService)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700108 .methods(boost::beast::http::verb::patch)(
Ed Tanous45ca1b82022-03-25 13:07:27 -0700109 [&app](const crow::Request& req,
110 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Carson Labrado3ba00072022-06-06 19:40:56 +0000111 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -0700112 {
113 return;
114 }
115 std::optional<bool> serviceEnabled;
116 std::optional<uint32_t> retryAttemps;
117 std::optional<uint32_t> retryInterval;
AppaRao Pulie5aaf042020-03-20 01:05:52 +0530118
Ed Tanous002d39b2022-05-31 08:59:27 -0700119 if (!json_util::readJsonPatch(
120 req, asyncResp->res, "ServiceEnabled", serviceEnabled,
121 "DeliveryRetryAttempts", retryAttemps,
122 "DeliveryRetryIntervalSeconds", retryInterval))
123 {
124 return;
125 }
AppaRao Pulie5aaf042020-03-20 01:05:52 +0530126
Ed Tanous002d39b2022-05-31 08:59:27 -0700127 persistent_data::EventServiceConfig eventServiceConfig =
128 persistent_data::EventServiceStore::getInstance()
129 .getEventServiceConfig();
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700130
Ed Tanous002d39b2022-05-31 08:59:27 -0700131 if (serviceEnabled)
132 {
133 eventServiceConfig.enabled = *serviceEnabled;
134 }
Sunitha Harishe56f2542020-07-22 02:38:59 -0500135
Ed Tanous002d39b2022-05-31 08:59:27 -0700136 if (retryAttemps)
137 {
138 // Supported range [1-3]
139 if ((*retryAttemps < 1) || (*retryAttemps > 3))
140 {
141 messages::queryParameterOutOfRange(
142 asyncResp->res, std::to_string(*retryAttemps),
143 "DeliveryRetryAttempts", "[1-3]");
144 }
145 else
146 {
147 eventServiceConfig.retryAttempts = *retryAttemps;
148 }
149 }
P Dheeraj Srujan Kumarb304bd72021-01-29 17:46:35 +0530150
Ed Tanous002d39b2022-05-31 08:59:27 -0700151 if (retryInterval)
152 {
Gunnar Mills33a32b32022-11-17 14:29:07 -0600153 // Supported range [5 - 180]
154 if ((*retryInterval < 5) || (*retryInterval > 180))
Ed Tanous002d39b2022-05-31 08:59:27 -0700155 {
156 messages::queryParameterOutOfRange(
157 asyncResp->res, std::to_string(*retryInterval),
Gunnar Mills33a32b32022-11-17 14:29:07 -0600158 "DeliveryRetryIntervalSeconds", "[5-180]");
Ed Tanous002d39b2022-05-31 08:59:27 -0700159 }
160 else
161 {
162 eventServiceConfig.retryTimeoutInterval = *retryInterval;
163 }
164 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700165
Ed Tanous002d39b2022-05-31 08:59:27 -0700166 EventServiceManager::getInstance().setEventServiceConfig(
167 eventServiceConfig);
168 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700169}
170
171inline void requestRoutesSubmitTestEvent(App& app)
172{
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700173 BMCWEB_ROUTE(
174 app, "/redfish/v1/EventService/Actions/EventService.SubmitTestEvent/")
Ed Tanoused398212021-06-09 17:05:54 -0700175 .privileges(redfish::privileges::postEventService)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700176 .methods(boost::beast::http::verb::post)(
Ed Tanous45ca1b82022-03-25 13:07:27 -0700177 [&app](const crow::Request& req,
178 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Carson Labrado3ba00072022-06-06 19:40:56 +0000179 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -0700180 {
181 return;
182 }
183 if (!EventServiceManager::getInstance().sendTestEventLog())
184 {
185 messages::serviceDisabled(asyncResp->res,
186 "/redfish/v1/EventService/");
187 return;
188 }
189 asyncResp->res.result(boost::beast::http::status::no_content);
190 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700191}
192
Chicago Duan3d307082020-11-26 14:12:12 +0800193inline void doSubscriptionCollection(
194 const boost::system::error_code ec,
195 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
196 const dbus::utility::ManagedObjectType& resp)
197{
198 if (ec)
199 {
200 if (ec.value() == EBADR)
201 {
202 // This is an optional process so just return if it isn't there
203 return;
204 }
205
206 BMCWEB_LOG_ERROR << "D-Bus response error on GetManagedObjects " << ec;
207 messages::internalError(asyncResp->res);
208 return;
209 }
210 nlohmann::json& memberArray = asyncResp->res.jsonValue["Members"];
211 for (const auto& objpath : resp)
212 {
213 sdbusplus::message::object_path path(objpath.first);
214 const std::string snmpId = path.filename();
215 if (snmpId.empty())
216 {
217 BMCWEB_LOG_ERROR << "The SNMP client ID is wrong";
218 messages::internalError(asyncResp->res);
219 return;
220 }
221
222 getSnmpSubscriptionList(asyncResp, snmpId, memberArray);
223 }
224}
225
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700226inline void requestRoutesEventDestinationCollection(App& app)
227{
Gayathri Leburu1ebe3e42022-02-09 10:45:19 +0000228 BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/")
Ed Tanoused398212021-06-09 17:05:54 -0700229 .privileges(redfish::privileges::getEventDestinationCollection)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700230 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -0700231 [&app](const crow::Request& req,
232 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Carson Labrado3ba00072022-06-06 19:40:56 +0000233 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -0700234 {
235 return;
236 }
237 asyncResp->res.jsonValue["@odata.type"] =
238 "#EventDestinationCollection.EventDestinationCollection";
239 asyncResp->res.jsonValue["@odata.id"] =
240 "/redfish/v1/EventService/Subscriptions";
241 asyncResp->res.jsonValue["Name"] = "Event Destination Collections";
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700242
Ed Tanous002d39b2022-05-31 08:59:27 -0700243 nlohmann::json& memberArray = asyncResp->res.jsonValue["Members"];
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700244
Ed Tanous002d39b2022-05-31 08:59:27 -0700245 std::vector<std::string> subscripIds =
246 EventServiceManager::getInstance().getAllIDs();
247 memberArray = nlohmann::json::array();
248 asyncResp->res.jsonValue["Members@odata.count"] = subscripIds.size();
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700249
Ed Tanous002d39b2022-05-31 08:59:27 -0700250 for (const std::string& id : subscripIds)
251 {
252 nlohmann::json::object_t member;
Chicago Duan3d307082020-11-26 14:12:12 +0800253 member["@odata.id"] = boost::urls::format(
254 "/redfish/v1/EventService/Subscriptions/{}" + id);
Patrick Williamsb2ba3072023-05-12 10:27:39 -0500255 memberArray.emplace_back(std::move(member));
Ed Tanous002d39b2022-05-31 08:59:27 -0700256 }
Chicago Duan3d307082020-11-26 14:12:12 +0800257 crow::connections::systemBus->async_method_call(
258 [asyncResp](const boost::system::error_code ec,
259 const dbus::utility::ManagedObjectType& resp) {
260 doSubscriptionCollection(ec, asyncResp, resp);
261 },
262 "xyz.openbmc_project.Network.SNMP",
263 "/xyz/openbmc_project/network/snmp/manager",
264 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
Ed Tanous002d39b2022-05-31 08:59:27 -0700265 });
Chicago Duan3d307082020-11-26 14:12:12 +0800266
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700267 BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/")
Abhishek Patel7eeafa72021-07-28 10:59:16 -0500268 .privileges(redfish::privileges::postEventDestinationCollection)
Ed Tanous002d39b2022-05-31 08:59:27 -0700269 .methods(boost::beast::http::verb::post)(
270 [&app](const crow::Request& req,
271 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Carson Labrado3ba00072022-06-06 19:40:56 +0000272 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -0700273 {
274 return;
275 }
276 if (EventServiceManager::getInstance().getNumberOfSubscriptions() >=
277 maxNoOfSubscriptions)
278 {
279 messages::eventSubscriptionLimitExceeded(asyncResp->res);
280 return;
281 }
282 std::string destUrl;
283 std::string protocol;
284 std::optional<std::string> context;
285 std::optional<std::string> subscriptionType;
286 std::optional<std::string> eventFormatType2;
287 std::optional<std::string> retryPolicy;
288 std::optional<std::vector<std::string>> msgIds;
289 std::optional<std::vector<std::string>> regPrefixes;
290 std::optional<std::vector<std::string>> resTypes;
291 std::optional<std::vector<nlohmann::json>> headers;
292 std::optional<std::vector<nlohmann::json>> mrdJsonArray;
Ed Tanousfffb8c12022-02-07 23:53:03 -0800293
Ed Tanous002d39b2022-05-31 08:59:27 -0700294 if (!json_util::readJsonPatch(
295 req, asyncResp->res, "Destination", destUrl, "Context", context,
296 "Protocol", protocol, "SubscriptionType", subscriptionType,
297 "EventFormatType", eventFormatType2, "HttpHeaders", headers,
298 "RegistryPrefixes", regPrefixes, "MessageIds", msgIds,
299 "DeliveryRetryPolicy", retryPolicy, "MetricReportDefinitions",
300 mrdJsonArray, "ResourceTypes", resTypes))
301 {
302 return;
303 }
304
AppaRao Puli600af5f2021-10-06 21:51:16 +0000305 // https://stackoverflow.com/questions/417142/what-is-the-maximum-length-of-a-url-in-different-browsers
306 static constexpr const uint16_t maxDestinationSize = 2000;
307 if (destUrl.size() > maxDestinationSize)
308 {
309 messages::stringValueTooLong(asyncResp->res, "Destination",
310 maxDestinationSize);
311 return;
312 }
313
Ed Tanous002d39b2022-05-31 08:59:27 -0700314 if (regPrefixes && msgIds)
315 {
316 if (!regPrefixes->empty() && !msgIds->empty())
Ed Tanousfffb8c12022-02-07 23:53:03 -0800317 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700318 messages::propertyValueConflict(asyncResp->res, "MessageIds",
319 "RegistryPrefixes");
Ed Tanousfffb8c12022-02-07 23:53:03 -0800320 return;
321 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700322 }
Ed Tanousfffb8c12022-02-07 23:53:03 -0800323
Ed Tanous002d39b2022-05-31 08:59:27 -0700324 std::string host;
325 std::string urlProto;
326 uint16_t port = 0;
327 std::string path;
328
329 if (!crow::utility::validateAndSplitUrl(destUrl, urlProto, host, port,
330 path))
331 {
332 BMCWEB_LOG_WARNING
333 << "Failed to validate and split destination url";
334 messages::propertyValueFormatError(asyncResp->res, destUrl,
335 "Destination");
336 return;
337 }
338
Chicago Duan3d307082020-11-26 14:12:12 +0800339 if (protocol == "SNMPv2c")
340 {
341 if (context)
342 {
343 messages::propertyValueConflict(asyncResp->res, "Context",
344 "Protocol");
345 return;
346 }
347 if (eventFormatType2)
348 {
349 messages::propertyValueConflict(asyncResp->res,
350 "EventFormatType", "Protocol");
351 return;
352 }
353 if (retryPolicy)
354 {
355 messages::propertyValueConflict(asyncResp->res, "RetryPolicy",
356 "Protocol");
357 return;
358 }
359 if (msgIds)
360 {
361 messages::propertyValueConflict(asyncResp->res, "MessageIds",
362 "Protocol");
363 return;
364 }
365 if (regPrefixes)
366 {
367 messages::propertyValueConflict(asyncResp->res,
368 "RegistryPrefixes", "Protocol");
369 return;
370 }
371 if (resTypes)
372 {
373 messages::propertyValueConflict(asyncResp->res, "ResourceTypes",
374 "Protocol");
375 return;
376 }
377 if (headers)
378 {
379 messages::propertyValueConflict(asyncResp->res, "HttpHeaders",
380 "Protocol");
381 return;
382 }
383 if (mrdJsonArray)
384 {
385 messages::propertyValueConflict(
386 asyncResp->res, "MetricReportDefinitions", "Protocol");
387 return;
388 }
389
390 addSnmpTrapClient(asyncResp, host, port);
391 return;
392 }
393
Ed Tanous002d39b2022-05-31 08:59:27 -0700394 if (path.empty())
395 {
396 path = "/";
397 }
Chicago Duan3d307082020-11-26 14:12:12 +0800398
Ed Tanousf8ca6d72022-06-28 12:12:03 -0700399 std::shared_ptr<Subscription> subValue = std::make_shared<Subscription>(
400 host, port, path, urlProto, app.ioContext());
Ed Tanous002d39b2022-05-31 08:59:27 -0700401
402 subValue->destinationUrl = destUrl;
403
404 if (subscriptionType)
405 {
406 if (*subscriptionType != "RedfishEvent")
Ed Tanousfffb8c12022-02-07 23:53:03 -0800407 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700408 messages::propertyValueNotInList(
409 asyncResp->res, *subscriptionType, "SubscriptionType");
410 return;
411 }
412 subValue->subscriptionType = *subscriptionType;
413 }
414 else
415 {
416 subValue->subscriptionType = "RedfishEvent"; // Default
417 }
418
419 if (protocol != "Redfish")
420 {
421 messages::propertyValueNotInList(asyncResp->res, protocol,
422 "Protocol");
423 return;
424 }
425 subValue->protocol = protocol;
426
427 if (eventFormatType2)
428 {
429 if (std::find(supportedEvtFormatTypes.begin(),
430 supportedEvtFormatTypes.end(),
431 *eventFormatType2) == supportedEvtFormatTypes.end())
432 {
433 messages::propertyValueNotInList(
434 asyncResp->res, *eventFormatType2, "EventFormatType");
435 return;
436 }
437 subValue->eventFormatType = *eventFormatType2;
438 }
439 else
440 {
441 // If not specified, use default "Event"
442 subValue->eventFormatType = "Event";
443 }
444
445 if (context)
446 {
AppaRao Puli600af5f2021-10-06 21:51:16 +0000447 // This value is selected aribitrarily.
448 constexpr const size_t maxContextSize = 256;
449 if (context->size() > maxContextSize)
450 {
451 messages::stringValueTooLong(asyncResp->res, "Context",
452 maxContextSize);
453 return;
454 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700455 subValue->customText = *context;
456 }
457
458 if (headers)
459 {
AppaRao Puli600af5f2021-10-06 21:51:16 +0000460 size_t cumulativeLen = 0;
461
Ed Tanous002d39b2022-05-31 08:59:27 -0700462 for (const nlohmann::json& headerChunk : *headers)
463 {
AppaRao Puli600af5f2021-10-06 21:51:16 +0000464 std::string hdr{headerChunk.dump(
465 -1, ' ', true, nlohmann::json::error_handler_t::replace)};
466 cumulativeLen += hdr.length();
467
468 // This value is selected to mirror http_connection.hpp
469 constexpr const uint16_t maxHeaderSizeED = 8096;
470 if (cumulativeLen > maxHeaderSizeED)
471 {
472 messages::arraySizeTooLong(asyncResp->res, "HttpHeaders",
473 maxHeaderSizeED);
474 return;
475 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700476 for (const auto& item : headerChunk.items())
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700477 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700478 const std::string* value =
479 item.value().get_ptr<const std::string*>();
480 if (value == nullptr)
481 {
482 messages::propertyValueFormatError(
Ed Tanousf818b042022-06-27 13:17:35 -0700483 asyncResp->res, item.value(),
Ed Tanous002d39b2022-05-31 08:59:27 -0700484 "HttpHeaders/" + item.key());
485 return;
486 }
487 subValue->httpHeaders.set(item.key(), *value);
488 }
489 }
490 }
491
492 if (regPrefixes)
493 {
494 for (const std::string& it : *regPrefixes)
495 {
496 if (std::find(supportedRegPrefixes.begin(),
497 supportedRegPrefixes.end(),
498 it) == supportedRegPrefixes.end())
499 {
500 messages::propertyValueNotInList(asyncResp->res, it,
501 "RegistryPrefixes");
P Dheeraj Srujan Kumarb304bd72021-01-29 17:46:35 +0530502 return;
503 }
Ed Tanousfffb8c12022-02-07 23:53:03 -0800504 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700505 subValue->registryPrefixes = *regPrefixes;
506 }
P Dheeraj Srujan Kumarb304bd72021-01-29 17:46:35 +0530507
Ed Tanous002d39b2022-05-31 08:59:27 -0700508 if (resTypes)
509 {
510 for (const std::string& it : *resTypes)
Ed Tanousfffb8c12022-02-07 23:53:03 -0800511 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700512 if (std::find(supportedResourceTypes.begin(),
513 supportedResourceTypes.end(),
514 it) == supportedResourceTypes.end())
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700515 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700516 messages::propertyValueNotInList(asyncResp->res, it,
517 "ResourceTypes");
AppaRao Puli144b6312020-08-03 22:23:12 +0530518 return;
519 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700520 }
521 subValue->resourceTypes = *resTypes;
522 }
523
524 if (msgIds)
525 {
526 std::vector<std::string> registryPrefix;
527
528 // If no registry prefixes are mentioned, consider all
529 // supported prefixes
530 if (subValue->registryPrefixes.empty())
531 {
532 registryPrefix.assign(supportedRegPrefixes.begin(),
533 supportedRegPrefixes.end());
Ed Tanousfffb8c12022-02-07 23:53:03 -0800534 }
535 else
536 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700537 registryPrefix = subValue->registryPrefixes;
Ed Tanousfffb8c12022-02-07 23:53:03 -0800538 }
AppaRao Puli156d6b02020-04-25 06:04:05 +0530539
Ed Tanous002d39b2022-05-31 08:59:27 -0700540 for (const std::string& id : *msgIds)
Ed Tanousfffb8c12022-02-07 23:53:03 -0800541 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700542 bool validId = false;
Ed Tanousfffb8c12022-02-07 23:53:03 -0800543
Ed Tanous002d39b2022-05-31 08:59:27 -0700544 // Check for Message ID in each of the selected Registry
545 for (const std::string& it : registryPrefix)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700546 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700547 const std::span<const redfish::registries::MessageEntry>
548 registry =
549 redfish::registries::getRegistryFromPrefix(it);
550
551 if (std::any_of(
552 registry.begin(), registry.end(),
553 [&id](const redfish::registries::MessageEntry&
554 messageEntry) {
555 return id == messageEntry.first;
556 }))
557 {
558 validId = true;
559 break;
560 }
561 }
562
563 if (!validId)
564 {
565 messages::propertyValueNotInList(asyncResp->res, id,
566 "MessageIds");
Ed Tanousfffb8c12022-02-07 23:53:03 -0800567 return;
568 }
Ed Tanousfffb8c12022-02-07 23:53:03 -0800569 }
570
Ed Tanous002d39b2022-05-31 08:59:27 -0700571 subValue->registryMsgIds = *msgIds;
572 }
573
574 if (retryPolicy)
575 {
576 if (std::find(supportedRetryPolicies.begin(),
577 supportedRetryPolicies.end(),
578 *retryPolicy) == supportedRetryPolicies.end())
Ed Tanousfffb8c12022-02-07 23:53:03 -0800579 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700580 messages::propertyValueNotInList(asyncResp->res, *retryPolicy,
581 "DeliveryRetryPolicy");
Ed Tanousfffb8c12022-02-07 23:53:03 -0800582 return;
583 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700584 subValue->retryPolicy = *retryPolicy;
585 }
586 else
587 {
588 // Default "TerminateAfterRetries"
589 subValue->retryPolicy = "TerminateAfterRetries";
590 }
Ed Tanousfffb8c12022-02-07 23:53:03 -0800591
Ed Tanous002d39b2022-05-31 08:59:27 -0700592 if (mrdJsonArray)
593 {
594 for (nlohmann::json& mrdObj : *mrdJsonArray)
595 {
596 std::string mrdUri;
597
598 if (!json_util::readJson(mrdObj, asyncResp->res, "@odata.id",
599 mrdUri))
600
601 {
602 return;
603 }
604 subValue->metricReportDefinitions.emplace_back(mrdUri);
605 }
606 }
607
608 std::string id =
609 EventServiceManager::getInstance().addSubscription(subValue);
610 if (id.empty())
611 {
612 messages::internalError(asyncResp->res);
613 return;
614 }
615
616 messages::created(asyncResp->res);
617 asyncResp->res.addHeader(
618 "Location", "/redfish/v1/EventService/Subscriptions/" + id);
Ed Tanousfffb8c12022-02-07 23:53:03 -0800619 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700620}
621
622inline void requestRoutesEventDestination(App& app)
AppaRao Pulie5aaf042020-03-20 01:05:52 +0530623{
Ravi Teja9d41aec2021-07-23 01:57:01 -0500624 BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -0700625 .privileges(redfish::privileges::getEventDestination)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700626 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -0700627 [&app](const crow::Request& req,
628 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
629 const std::string& param) {
Carson Labrado3ba00072022-06-06 19:40:56 +0000630 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -0700631 {
632 return;
633 }
Chicago Duan3d307082020-11-26 14:12:12 +0800634
635 if (param.starts_with("snmp"))
636 {
637 getSnmpTrapClient(asyncResp, param);
638 return;
639 }
640
Ed Tanous002d39b2022-05-31 08:59:27 -0700641 std::shared_ptr<Subscription> subValue =
642 EventServiceManager::getInstance().getSubscription(param);
643 if (subValue == nullptr)
644 {
645 asyncResp->res.result(boost::beast::http::status::not_found);
646 return;
647 }
648 const std::string& id = param;
AppaRao Pulie5aaf042020-03-20 01:05:52 +0530649
Ed Tanous002d39b2022-05-31 08:59:27 -0700650 asyncResp->res.jsonValue["@odata.type"] =
Chicago Duan3d307082020-11-26 14:12:12 +0800651 "#EventDestination.v1_8_0.EventDestination";
Ed Tanous002d39b2022-05-31 08:59:27 -0700652 asyncResp->res.jsonValue["Protocol"] = "Redfish";
653 asyncResp->res.jsonValue["@odata.id"] =
654 "/redfish/v1/EventService/Subscriptions/" + id;
655 asyncResp->res.jsonValue["Id"] = id;
656 asyncResp->res.jsonValue["Name"] = "Event Destination " + id;
657 asyncResp->res.jsonValue["Destination"] = subValue->destinationUrl;
658 asyncResp->res.jsonValue["Context"] = subValue->customText;
659 asyncResp->res.jsonValue["SubscriptionType"] =
660 subValue->subscriptionType;
661 asyncResp->res.jsonValue["HttpHeaders"] = nlohmann::json::array();
662 asyncResp->res.jsonValue["EventFormatType"] = subValue->eventFormatType;
663 asyncResp->res.jsonValue["RegistryPrefixes"] =
664 subValue->registryPrefixes;
665 asyncResp->res.jsonValue["ResourceTypes"] = subValue->resourceTypes;
zhanghch058d1b46d2021-04-01 11:18:24 +0800666
Ed Tanous002d39b2022-05-31 08:59:27 -0700667 asyncResp->res.jsonValue["MessageIds"] = subValue->registryMsgIds;
668 asyncResp->res.jsonValue["DeliveryRetryPolicy"] = subValue->retryPolicy;
AppaRao Pulie5aaf042020-03-20 01:05:52 +0530669
Ed Tanous002d39b2022-05-31 08:59:27 -0700670 nlohmann::json::array_t mrdJsonArray;
671 for (const auto& mdrUri : subValue->metricReportDefinitions)
672 {
673 nlohmann::json::object_t mdr;
674 mdr["@odata.id"] = mdrUri;
675 mrdJsonArray.emplace_back(std::move(mdr));
676 }
677 asyncResp->res.jsonValue["MetricReportDefinitions"] = mrdJsonArray;
678 });
Ravi Teja9d41aec2021-07-23 01:57:01 -0500679 BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -0700680 // The below privilege is wrong, it should be ConfigureManager OR
681 // ConfigureSelf
Abhishek Patel7eeafa72021-07-28 10:59:16 -0500682 // https://github.com/openbmc/bmcweb/issues/220
Ed Tanoused398212021-06-09 17:05:54 -0700683 //.privileges(redfish::privileges::patchEventDestination)
Ed Tanous432a8902021-06-14 15:28:56 -0700684 .privileges({{"ConfigureManager"}})
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700685 .methods(boost::beast::http::verb::patch)(
Ed Tanous45ca1b82022-03-25 13:07:27 -0700686 [&app](const crow::Request& req,
687 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
688 const std::string& param) {
Carson Labrado3ba00072022-06-06 19:40:56 +0000689 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -0700690 {
691 return;
692 }
693 std::shared_ptr<Subscription> subValue =
694 EventServiceManager::getInstance().getSubscription(param);
695 if (subValue == nullptr)
696 {
697 asyncResp->res.result(boost::beast::http::status::not_found);
698 return;
699 }
AppaRao Pulie5aaf042020-03-20 01:05:52 +0530700
Ed Tanous002d39b2022-05-31 08:59:27 -0700701 std::optional<std::string> context;
702 std::optional<std::string> retryPolicy;
703 std::optional<std::vector<nlohmann::json>> headers;
Sunitha Harishe56f2542020-07-22 02:38:59 -0500704
Ed Tanous002d39b2022-05-31 08:59:27 -0700705 if (!json_util::readJsonPatch(req, asyncResp->res, "Context", context,
706 "DeliveryRetryPolicy", retryPolicy,
707 "HttpHeaders", headers))
708 {
709 return;
710 }
AppaRao Puli144b6312020-08-03 22:23:12 +0530711
Ed Tanous002d39b2022-05-31 08:59:27 -0700712 if (context)
713 {
714 subValue->customText = *context;
715 }
AppaRao Pulie5aaf042020-03-20 01:05:52 +0530716
Ed Tanous002d39b2022-05-31 08:59:27 -0700717 if (headers)
718 {
719 boost::beast::http::fields fields;
720 for (const nlohmann::json& headerChunk : *headers)
721 {
Patrick Williams62bafc02022-09-08 17:35:35 -0500722 for (const auto& it : headerChunk.items())
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700723 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700724 const std::string* value =
725 it.value().get_ptr<const std::string*>();
726 if (value == nullptr)
Ed Tanous601c71a2021-09-08 16:40:12 -0700727 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700728 messages::propertyValueFormatError(
Ed Tanousf818b042022-06-27 13:17:35 -0700729 asyncResp->res, it.value(),
Ed Tanous002d39b2022-05-31 08:59:27 -0700730 "HttpHeaders/" + it.key());
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700731 return;
732 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700733 fields.set(it.key(), *value);
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700734 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700735 }
736 subValue->httpHeaders = fields;
737 }
AppaRao Pulie5aaf042020-03-20 01:05:52 +0530738
Ed Tanous002d39b2022-05-31 08:59:27 -0700739 if (retryPolicy)
740 {
741 if (std::find(supportedRetryPolicies.begin(),
742 supportedRetryPolicies.end(),
743 *retryPolicy) == supportedRetryPolicies.end())
744 {
745 messages::propertyValueNotInList(asyncResp->res, *retryPolicy,
746 "DeliveryRetryPolicy");
747 return;
748 }
749 subValue->retryPolicy = *retryPolicy;
Ed Tanous002d39b2022-05-31 08:59:27 -0700750 }
751
752 EventServiceManager::getInstance().updateSubscriptionData();
753 });
Ravi Teja9d41aec2021-07-23 01:57:01 -0500754 BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -0700755 // The below privilege is wrong, it should be ConfigureManager OR
756 // ConfigureSelf
Abhishek Patel7eeafa72021-07-28 10:59:16 -0500757 // https://github.com/openbmc/bmcweb/issues/220
Ed Tanoused398212021-06-09 17:05:54 -0700758 //.privileges(redfish::privileges::deleteEventDestination)
Ed Tanous432a8902021-06-14 15:28:56 -0700759 .privileges({{"ConfigureManager"}})
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700760 .methods(boost::beast::http::verb::delete_)(
Ed Tanous45ca1b82022-03-25 13:07:27 -0700761 [&app](const crow::Request& req,
762 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
763 const std::string& param) {
Carson Labrado3ba00072022-06-06 19:40:56 +0000764 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -0700765 {
766 return;
767 }
Chicago Duan3d307082020-11-26 14:12:12 +0800768
769 if (param.starts_with("snmp"))
770 {
771 deleteSnmpTrapClient(asyncResp, param);
772 EventServiceManager::getInstance().deleteSubscription(param);
773 return;
774 }
775
Ed Tanous002d39b2022-05-31 08:59:27 -0700776 if (!EventServiceManager::getInstance().isSubscriptionExist(param))
777 {
778 asyncResp->res.result(boost::beast::http::status::not_found);
779 return;
780 }
781 EventServiceManager::getInstance().deleteSubscription(param);
782 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700783}
AppaRao Pulie5aaf042020-03-20 01:05:52 +0530784
785} // namespace redfish