blob: 30103badf0e71ecf335207e91f2c7d99a1258dcb [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 -050045static constexpr const std::array<const char*, 1> supportedResourceTypes = {
46 "Task"};
Sunitha Harishe56f2542020-07-22 02:38:59 -050047
John Edward Broadbent7e860f12021-04-08 15:57:16 -070048inline void requestRoutesEventService(App& app)
AppaRao Pulie5aaf042020-03-20 01:05:52 +053049{
John Edward Broadbent7e860f12021-04-08 15:57:16 -070050 BMCWEB_ROUTE(app, "/redfish/v1/EventService/")
Ed Tanoused398212021-06-09 17:05:54 -070051 .privileges(redfish::privileges::getEventService)
Ed Tanous002d39b2022-05-31 08:59:27 -070052 .methods(boost::beast::http::verb::get)(
53 [&app](const crow::Request& req,
54 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Carson Labrado3ba00072022-06-06 19:40:56 +000055 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -070056 {
57 return;
58 }
Ed Tanous14766872022-03-15 10:44:42 -070059
Ed Tanous002d39b2022-05-31 08:59:27 -070060 asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/EventService";
61 asyncResp->res.jsonValue["@odata.type"] =
62 "#EventService.v1_5_0.EventService";
63 asyncResp->res.jsonValue["Id"] = "EventService";
64 asyncResp->res.jsonValue["Name"] = "Event Service";
AppaRao Puli5e44e3d2021-03-16 15:37:24 +000065 asyncResp->res.jsonValue["ServerSentEventUri"] =
66 "/redfish/v1/EventService/SSE";
67
Ed Tanous002d39b2022-05-31 08:59:27 -070068 asyncResp->res.jsonValue["Subscriptions"]["@odata.id"] =
69 "/redfish/v1/EventService/Subscriptions";
70 asyncResp->res
71 .jsonValue["Actions"]["#EventService.SubmitTestEvent"]["target"] =
72 "/redfish/v1/EventService/Actions/EventService.SubmitTestEvent";
AppaRao Pulie5aaf042020-03-20 01:05:52 +053073
Ed Tanous002d39b2022-05-31 08:59:27 -070074 const persistent_data::EventServiceConfig eventServiceConfig =
75 persistent_data::EventServiceStore::getInstance()
76 .getEventServiceConfig();
zhanghch058d1b46d2021-04-01 11:18:24 +080077
Ed Tanous002d39b2022-05-31 08:59:27 -070078 asyncResp->res.jsonValue["Status"]["State"] =
79 (eventServiceConfig.enabled ? "Enabled" : "Disabled");
80 asyncResp->res.jsonValue["ServiceEnabled"] = eventServiceConfig.enabled;
81 asyncResp->res.jsonValue["DeliveryRetryAttempts"] =
82 eventServiceConfig.retryAttempts;
83 asyncResp->res.jsonValue["DeliveryRetryIntervalSeconds"] =
84 eventServiceConfig.retryTimeoutInterval;
85 asyncResp->res.jsonValue["EventFormatTypes"] = supportedEvtFormatTypes;
86 asyncResp->res.jsonValue["RegistryPrefixes"] = supportedRegPrefixes;
87 asyncResp->res.jsonValue["ResourceTypes"] = supportedResourceTypes;
AppaRao Pulie5aaf042020-03-20 01:05:52 +053088
Ed Tanous613dabe2022-07-09 11:17:36 -070089 nlohmann::json::object_t supportedSSEFilters;
90 supportedSSEFilters["EventFormatType"] = true;
91 supportedSSEFilters["MessageId"] = true;
92 supportedSSEFilters["MetricReportDefinition"] = true;
93 supportedSSEFilters["RegistryPrefix"] = true;
94 supportedSSEFilters["OriginResource"] = false;
95 supportedSSEFilters["ResourceType"] = false;
AppaRao Puli7d1cc382020-05-16 02:42:22 +053096
Ed Tanous002d39b2022-05-31 08:59:27 -070097 asyncResp->res.jsonValue["SSEFilterPropertiesSupported"] =
Ed Tanous613dabe2022-07-09 11:17:36 -070098 std::move(supportedSSEFilters);
George Liu0fda0f12021-11-16 10:06:17 +080099 });
Ayushi Smriti07941a82020-05-21 15:55:34 +0530100
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700101 BMCWEB_ROUTE(app, "/redfish/v1/EventService/")
Ed Tanoused398212021-06-09 17:05:54 -0700102 .privileges(redfish::privileges::patchEventService)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700103 .methods(boost::beast::http::verb::patch)(
Ed Tanous45ca1b82022-03-25 13:07:27 -0700104 [&app](const crow::Request& req,
105 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Carson Labrado3ba00072022-06-06 19:40:56 +0000106 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -0700107 {
108 return;
109 }
110 std::optional<bool> serviceEnabled;
111 std::optional<uint32_t> retryAttemps;
112 std::optional<uint32_t> retryInterval;
AppaRao Pulie5aaf042020-03-20 01:05:52 +0530113
Ed Tanous002d39b2022-05-31 08:59:27 -0700114 if (!json_util::readJsonPatch(
115 req, asyncResp->res, "ServiceEnabled", serviceEnabled,
116 "DeliveryRetryAttempts", retryAttemps,
117 "DeliveryRetryIntervalSeconds", retryInterval))
118 {
119 return;
120 }
AppaRao Pulie5aaf042020-03-20 01:05:52 +0530121
Ed Tanous002d39b2022-05-31 08:59:27 -0700122 persistent_data::EventServiceConfig eventServiceConfig =
123 persistent_data::EventServiceStore::getInstance()
124 .getEventServiceConfig();
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700125
Ed Tanous002d39b2022-05-31 08:59:27 -0700126 if (serviceEnabled)
127 {
128 eventServiceConfig.enabled = *serviceEnabled;
129 }
Sunitha Harishe56f2542020-07-22 02:38:59 -0500130
Ed Tanous002d39b2022-05-31 08:59:27 -0700131 if (retryAttemps)
132 {
133 // Supported range [1-3]
134 if ((*retryAttemps < 1) || (*retryAttemps > 3))
135 {
136 messages::queryParameterOutOfRange(
137 asyncResp->res, std::to_string(*retryAttemps),
138 "DeliveryRetryAttempts", "[1-3]");
139 }
140 else
141 {
142 eventServiceConfig.retryAttempts = *retryAttemps;
143 }
144 }
P Dheeraj Srujan Kumarb304bd72021-01-29 17:46:35 +0530145
Ed Tanous002d39b2022-05-31 08:59:27 -0700146 if (retryInterval)
147 {
Gunnar Mills33a32b32022-11-17 14:29:07 -0600148 // Supported range [5 - 180]
149 if ((*retryInterval < 5) || (*retryInterval > 180))
Ed Tanous002d39b2022-05-31 08:59:27 -0700150 {
151 messages::queryParameterOutOfRange(
152 asyncResp->res, std::to_string(*retryInterval),
Gunnar Mills33a32b32022-11-17 14:29:07 -0600153 "DeliveryRetryIntervalSeconds", "[5-180]");
Ed Tanous002d39b2022-05-31 08:59:27 -0700154 }
155 else
156 {
157 eventServiceConfig.retryTimeoutInterval = *retryInterval;
158 }
159 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700160
Ed Tanous002d39b2022-05-31 08:59:27 -0700161 EventServiceManager::getInstance().setEventServiceConfig(
162 eventServiceConfig);
163 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700164}
165
166inline void requestRoutesSubmitTestEvent(App& app)
167{
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700168 BMCWEB_ROUTE(
169 app, "/redfish/v1/EventService/Actions/EventService.SubmitTestEvent/")
Ed Tanoused398212021-06-09 17:05:54 -0700170 .privileges(redfish::privileges::postEventService)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700171 .methods(boost::beast::http::verb::post)(
Ed Tanous45ca1b82022-03-25 13:07:27 -0700172 [&app](const crow::Request& req,
173 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Carson Labrado3ba00072022-06-06 19:40:56 +0000174 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -0700175 {
176 return;
177 }
178 if (!EventServiceManager::getInstance().sendTestEventLog())
179 {
180 messages::serviceDisabled(asyncResp->res,
181 "/redfish/v1/EventService/");
182 return;
183 }
184 asyncResp->res.result(boost::beast::http::status::no_content);
185 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700186}
187
Chicago Duan3d307082020-11-26 14:12:12 +0800188inline void doSubscriptionCollection(
Ed Tanouse81de512023-06-27 17:07:00 -0700189 const boost::system::error_code& ec,
Chicago Duan3d307082020-11-26 14:12:12 +0800190 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
191 const dbus::utility::ManagedObjectType& resp)
192{
193 if (ec)
194 {
Ed Tanous13061012023-07-25 11:12:19 -0700195 if (ec.value() == EBADR || ec.value() == EHOSTUNREACH)
Chicago Duan3d307082020-11-26 14:12:12 +0800196 {
197 // This is an optional process so just return if it isn't there
198 return;
199 }
200
Ed Tanous62598e32023-07-17 17:06:25 -0700201 BMCWEB_LOG_ERROR("D-Bus response error on GetManagedObjects {}", ec);
Chicago Duan3d307082020-11-26 14:12:12 +0800202 messages::internalError(asyncResp->res);
203 return;
204 }
205 nlohmann::json& memberArray = asyncResp->res.jsonValue["Members"];
206 for (const auto& objpath : resp)
207 {
208 sdbusplus::message::object_path path(objpath.first);
209 const std::string snmpId = path.filename();
210 if (snmpId.empty())
211 {
Ed Tanous62598e32023-07-17 17:06:25 -0700212 BMCWEB_LOG_ERROR("The SNMP client ID is wrong");
Chicago Duan3d307082020-11-26 14:12:12 +0800213 messages::internalError(asyncResp->res);
214 return;
215 }
216
217 getSnmpSubscriptionList(asyncResp, snmpId, memberArray);
218 }
219}
220
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700221inline void requestRoutesEventDestinationCollection(App& app)
222{
Gayathri Leburu1ebe3e42022-02-09 10:45:19 +0000223 BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/")
Ed Tanoused398212021-06-09 17:05:54 -0700224 .privileges(redfish::privileges::getEventDestinationCollection)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700225 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -0700226 [&app](const crow::Request& req,
227 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Carson Labrado3ba00072022-06-06 19:40:56 +0000228 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -0700229 {
230 return;
231 }
232 asyncResp->res.jsonValue["@odata.type"] =
233 "#EventDestinationCollection.EventDestinationCollection";
234 asyncResp->res.jsonValue["@odata.id"] =
235 "/redfish/v1/EventService/Subscriptions";
236 asyncResp->res.jsonValue["Name"] = "Event Destination Collections";
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700237
Ed Tanous002d39b2022-05-31 08:59:27 -0700238 nlohmann::json& memberArray = asyncResp->res.jsonValue["Members"];
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700239
Ed Tanous002d39b2022-05-31 08:59:27 -0700240 std::vector<std::string> subscripIds =
241 EventServiceManager::getInstance().getAllIDs();
242 memberArray = nlohmann::json::array();
243 asyncResp->res.jsonValue["Members@odata.count"] = subscripIds.size();
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700244
Ed Tanous002d39b2022-05-31 08:59:27 -0700245 for (const std::string& id : subscripIds)
246 {
247 nlohmann::json::object_t member;
Chicago Duan3d307082020-11-26 14:12:12 +0800248 member["@odata.id"] = boost::urls::format(
249 "/redfish/v1/EventService/Subscriptions/{}" + id);
Patrick Williamsb2ba3072023-05-12 10:27:39 -0500250 memberArray.emplace_back(std::move(member));
Ed Tanous002d39b2022-05-31 08:59:27 -0700251 }
Chicago Duan3d307082020-11-26 14:12:12 +0800252 crow::connections::systemBus->async_method_call(
Ed Tanouse81de512023-06-27 17:07:00 -0700253 [asyncResp](const boost::system::error_code& ec,
Chicago Duan3d307082020-11-26 14:12:12 +0800254 const dbus::utility::ManagedObjectType& resp) {
255 doSubscriptionCollection(ec, asyncResp, resp);
256 },
257 "xyz.openbmc_project.Network.SNMP",
258 "/xyz/openbmc_project/network/snmp/manager",
259 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
Ed Tanous002d39b2022-05-31 08:59:27 -0700260 });
Chicago Duan3d307082020-11-26 14:12:12 +0800261
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700262 BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/")
Abhishek Patel7eeafa72021-07-28 10:59:16 -0500263 .privileges(redfish::privileges::postEventDestinationCollection)
Ed Tanous002d39b2022-05-31 08:59:27 -0700264 .methods(boost::beast::http::verb::post)(
265 [&app](const crow::Request& req,
266 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Carson Labrado3ba00072022-06-06 19:40:56 +0000267 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -0700268 {
269 return;
270 }
271 if (EventServiceManager::getInstance().getNumberOfSubscriptions() >=
272 maxNoOfSubscriptions)
273 {
274 messages::eventSubscriptionLimitExceeded(asyncResp->res);
275 return;
276 }
277 std::string destUrl;
278 std::string protocol;
279 std::optional<std::string> context;
280 std::optional<std::string> subscriptionType;
281 std::optional<std::string> eventFormatType2;
282 std::optional<std::string> retryPolicy;
283 std::optional<std::vector<std::string>> msgIds;
284 std::optional<std::vector<std::string>> regPrefixes;
285 std::optional<std::vector<std::string>> resTypes;
286 std::optional<std::vector<nlohmann::json>> headers;
287 std::optional<std::vector<nlohmann::json>> mrdJsonArray;
Ed Tanousfffb8c12022-02-07 23:53:03 -0800288
Ed Tanous002d39b2022-05-31 08:59:27 -0700289 if (!json_util::readJsonPatch(
290 req, asyncResp->res, "Destination", destUrl, "Context", context,
291 "Protocol", protocol, "SubscriptionType", subscriptionType,
292 "EventFormatType", eventFormatType2, "HttpHeaders", headers,
293 "RegistryPrefixes", regPrefixes, "MessageIds", msgIds,
294 "DeliveryRetryPolicy", retryPolicy, "MetricReportDefinitions",
295 mrdJsonArray, "ResourceTypes", resTypes))
296 {
297 return;
298 }
299
AppaRao Puli600af5f2021-10-06 21:51:16 +0000300 // https://stackoverflow.com/questions/417142/what-is-the-maximum-length-of-a-url-in-different-browsers
301 static constexpr const uint16_t maxDestinationSize = 2000;
302 if (destUrl.size() > maxDestinationSize)
303 {
304 messages::stringValueTooLong(asyncResp->res, "Destination",
305 maxDestinationSize);
306 return;
307 }
308
Ed Tanous002d39b2022-05-31 08:59:27 -0700309 if (regPrefixes && msgIds)
310 {
311 if (!regPrefixes->empty() && !msgIds->empty())
Ed Tanousfffb8c12022-02-07 23:53:03 -0800312 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700313 messages::propertyValueConflict(asyncResp->res, "MessageIds",
314 "RegistryPrefixes");
Ed Tanousfffb8c12022-02-07 23:53:03 -0800315 return;
316 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700317 }
Ed Tanousfffb8c12022-02-07 23:53:03 -0800318
Ed Tanous002d39b2022-05-31 08:59:27 -0700319 std::string host;
320 std::string urlProto;
321 uint16_t port = 0;
322 std::string path;
323
324 if (!crow::utility::validateAndSplitUrl(destUrl, urlProto, host, port,
325 path))
326 {
Ed Tanous62598e32023-07-17 17:06:25 -0700327 BMCWEB_LOG_WARNING("Failed to validate and split destination url");
Ed Tanous002d39b2022-05-31 08:59:27 -0700328 messages::propertyValueFormatError(asyncResp->res, destUrl,
329 "Destination");
330 return;
331 }
332
Chicago Duan3d307082020-11-26 14:12:12 +0800333 if (protocol == "SNMPv2c")
334 {
335 if (context)
336 {
337 messages::propertyValueConflict(asyncResp->res, "Context",
338 "Protocol");
339 return;
340 }
341 if (eventFormatType2)
342 {
343 messages::propertyValueConflict(asyncResp->res,
344 "EventFormatType", "Protocol");
345 return;
346 }
347 if (retryPolicy)
348 {
349 messages::propertyValueConflict(asyncResp->res, "RetryPolicy",
350 "Protocol");
351 return;
352 }
353 if (msgIds)
354 {
355 messages::propertyValueConflict(asyncResp->res, "MessageIds",
356 "Protocol");
357 return;
358 }
359 if (regPrefixes)
360 {
361 messages::propertyValueConflict(asyncResp->res,
362 "RegistryPrefixes", "Protocol");
363 return;
364 }
365 if (resTypes)
366 {
367 messages::propertyValueConflict(asyncResp->res, "ResourceTypes",
368 "Protocol");
369 return;
370 }
371 if (headers)
372 {
373 messages::propertyValueConflict(asyncResp->res, "HttpHeaders",
374 "Protocol");
375 return;
376 }
377 if (mrdJsonArray)
378 {
379 messages::propertyValueConflict(
380 asyncResp->res, "MetricReportDefinitions", "Protocol");
381 return;
382 }
383
384 addSnmpTrapClient(asyncResp, host, port);
385 return;
386 }
387
Ed Tanous002d39b2022-05-31 08:59:27 -0700388 if (path.empty())
389 {
390 path = "/";
391 }
Chicago Duan3d307082020-11-26 14:12:12 +0800392
Ed Tanousf8ca6d72022-06-28 12:12:03 -0700393 std::shared_ptr<Subscription> subValue = std::make_shared<Subscription>(
394 host, port, path, urlProto, app.ioContext());
Ed Tanous002d39b2022-05-31 08:59:27 -0700395
396 subValue->destinationUrl = destUrl;
397
398 if (subscriptionType)
399 {
400 if (*subscriptionType != "RedfishEvent")
Ed Tanousfffb8c12022-02-07 23:53:03 -0800401 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700402 messages::propertyValueNotInList(
403 asyncResp->res, *subscriptionType, "SubscriptionType");
404 return;
405 }
406 subValue->subscriptionType = *subscriptionType;
407 }
408 else
409 {
410 subValue->subscriptionType = "RedfishEvent"; // Default
411 }
412
413 if (protocol != "Redfish")
414 {
415 messages::propertyValueNotInList(asyncResp->res, protocol,
416 "Protocol");
417 return;
418 }
419 subValue->protocol = protocol;
420
421 if (eventFormatType2)
422 {
423 if (std::find(supportedEvtFormatTypes.begin(),
424 supportedEvtFormatTypes.end(),
425 *eventFormatType2) == supportedEvtFormatTypes.end())
426 {
427 messages::propertyValueNotInList(
428 asyncResp->res, *eventFormatType2, "EventFormatType");
429 return;
430 }
431 subValue->eventFormatType = *eventFormatType2;
432 }
433 else
434 {
435 // If not specified, use default "Event"
436 subValue->eventFormatType = "Event";
437 }
438
439 if (context)
440 {
AppaRao Puli600af5f2021-10-06 21:51:16 +0000441 // This value is selected aribitrarily.
442 constexpr const size_t maxContextSize = 256;
443 if (context->size() > maxContextSize)
444 {
445 messages::stringValueTooLong(asyncResp->res, "Context",
446 maxContextSize);
447 return;
448 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700449 subValue->customText = *context;
450 }
451
452 if (headers)
453 {
AppaRao Puli600af5f2021-10-06 21:51:16 +0000454 size_t cumulativeLen = 0;
455
Ed Tanous002d39b2022-05-31 08:59:27 -0700456 for (const nlohmann::json& headerChunk : *headers)
457 {
AppaRao Puli600af5f2021-10-06 21:51:16 +0000458 std::string hdr{headerChunk.dump(
459 -1, ' ', true, nlohmann::json::error_handler_t::replace)};
460 cumulativeLen += hdr.length();
461
462 // This value is selected to mirror http_connection.hpp
463 constexpr const uint16_t maxHeaderSizeED = 8096;
464 if (cumulativeLen > maxHeaderSizeED)
465 {
466 messages::arraySizeTooLong(asyncResp->res, "HttpHeaders",
467 maxHeaderSizeED);
468 return;
469 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700470 for (const auto& item : headerChunk.items())
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700471 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700472 const std::string* value =
473 item.value().get_ptr<const std::string*>();
474 if (value == nullptr)
475 {
476 messages::propertyValueFormatError(
Ed Tanousf818b042022-06-27 13:17:35 -0700477 asyncResp->res, item.value(),
Ed Tanous002d39b2022-05-31 08:59:27 -0700478 "HttpHeaders/" + item.key());
479 return;
480 }
481 subValue->httpHeaders.set(item.key(), *value);
482 }
483 }
484 }
485
486 if (regPrefixes)
487 {
488 for (const std::string& it : *regPrefixes)
489 {
490 if (std::find(supportedRegPrefixes.begin(),
491 supportedRegPrefixes.end(),
492 it) == supportedRegPrefixes.end())
493 {
494 messages::propertyValueNotInList(asyncResp->res, it,
495 "RegistryPrefixes");
P Dheeraj Srujan Kumarb304bd72021-01-29 17:46:35 +0530496 return;
497 }
Ed Tanousfffb8c12022-02-07 23:53:03 -0800498 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700499 subValue->registryPrefixes = *regPrefixes;
500 }
P Dheeraj Srujan Kumarb304bd72021-01-29 17:46:35 +0530501
Ed Tanous002d39b2022-05-31 08:59:27 -0700502 if (resTypes)
503 {
504 for (const std::string& it : *resTypes)
Ed Tanousfffb8c12022-02-07 23:53:03 -0800505 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700506 if (std::find(supportedResourceTypes.begin(),
507 supportedResourceTypes.end(),
508 it) == supportedResourceTypes.end())
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700509 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700510 messages::propertyValueNotInList(asyncResp->res, it,
511 "ResourceTypes");
AppaRao Puli144b6312020-08-03 22:23:12 +0530512 return;
513 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700514 }
515 subValue->resourceTypes = *resTypes;
516 }
517
518 if (msgIds)
519 {
520 std::vector<std::string> registryPrefix;
521
522 // If no registry prefixes are mentioned, consider all
523 // supported prefixes
524 if (subValue->registryPrefixes.empty())
525 {
526 registryPrefix.assign(supportedRegPrefixes.begin(),
527 supportedRegPrefixes.end());
Ed Tanousfffb8c12022-02-07 23:53:03 -0800528 }
529 else
530 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700531 registryPrefix = subValue->registryPrefixes;
Ed Tanousfffb8c12022-02-07 23:53:03 -0800532 }
AppaRao Puli156d6b02020-04-25 06:04:05 +0530533
Ed Tanous002d39b2022-05-31 08:59:27 -0700534 for (const std::string& id : *msgIds)
Ed Tanousfffb8c12022-02-07 23:53:03 -0800535 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700536 bool validId = false;
Ed Tanousfffb8c12022-02-07 23:53:03 -0800537
Ed Tanous002d39b2022-05-31 08:59:27 -0700538 // Check for Message ID in each of the selected Registry
539 for (const std::string& it : registryPrefix)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700540 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700541 const std::span<const redfish::registries::MessageEntry>
542 registry =
543 redfish::registries::getRegistryFromPrefix(it);
544
545 if (std::any_of(
546 registry.begin(), registry.end(),
547 [&id](const redfish::registries::MessageEntry&
548 messageEntry) {
549 return id == messageEntry.first;
550 }))
551 {
552 validId = true;
553 break;
554 }
555 }
556
557 if (!validId)
558 {
559 messages::propertyValueNotInList(asyncResp->res, id,
560 "MessageIds");
Ed Tanousfffb8c12022-02-07 23:53:03 -0800561 return;
562 }
Ed Tanousfffb8c12022-02-07 23:53:03 -0800563 }
564
Ed Tanous002d39b2022-05-31 08:59:27 -0700565 subValue->registryMsgIds = *msgIds;
566 }
567
568 if (retryPolicy)
569 {
570 if (std::find(supportedRetryPolicies.begin(),
571 supportedRetryPolicies.end(),
572 *retryPolicy) == supportedRetryPolicies.end())
Ed Tanousfffb8c12022-02-07 23:53:03 -0800573 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700574 messages::propertyValueNotInList(asyncResp->res, *retryPolicy,
575 "DeliveryRetryPolicy");
Ed Tanousfffb8c12022-02-07 23:53:03 -0800576 return;
577 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700578 subValue->retryPolicy = *retryPolicy;
579 }
580 else
581 {
582 // Default "TerminateAfterRetries"
583 subValue->retryPolicy = "TerminateAfterRetries";
584 }
Ed Tanousfffb8c12022-02-07 23:53:03 -0800585
Ed Tanous002d39b2022-05-31 08:59:27 -0700586 if (mrdJsonArray)
587 {
588 for (nlohmann::json& mrdObj : *mrdJsonArray)
589 {
590 std::string mrdUri;
591
592 if (!json_util::readJson(mrdObj, asyncResp->res, "@odata.id",
593 mrdUri))
594
595 {
596 return;
597 }
598 subValue->metricReportDefinitions.emplace_back(mrdUri);
599 }
600 }
601
602 std::string id =
603 EventServiceManager::getInstance().addSubscription(subValue);
604 if (id.empty())
605 {
606 messages::internalError(asyncResp->res);
607 return;
608 }
609
610 messages::created(asyncResp->res);
611 asyncResp->res.addHeader(
612 "Location", "/redfish/v1/EventService/Subscriptions/" + id);
Ed Tanousfffb8c12022-02-07 23:53:03 -0800613 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700614}
615
616inline void requestRoutesEventDestination(App& app)
AppaRao Pulie5aaf042020-03-20 01:05:52 +0530617{
Ravi Teja9d41aec2021-07-23 01:57:01 -0500618 BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -0700619 .privileges(redfish::privileges::getEventDestination)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700620 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -0700621 [&app](const crow::Request& req,
622 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
623 const std::string& param) {
Carson Labrado3ba00072022-06-06 19:40:56 +0000624 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -0700625 {
626 return;
627 }
Chicago Duan3d307082020-11-26 14:12:12 +0800628
629 if (param.starts_with("snmp"))
630 {
631 getSnmpTrapClient(asyncResp, param);
632 return;
633 }
634
Ed Tanous002d39b2022-05-31 08:59:27 -0700635 std::shared_ptr<Subscription> subValue =
636 EventServiceManager::getInstance().getSubscription(param);
637 if (subValue == nullptr)
638 {
639 asyncResp->res.result(boost::beast::http::status::not_found);
640 return;
641 }
642 const std::string& id = param;
AppaRao Pulie5aaf042020-03-20 01:05:52 +0530643
Ed Tanous002d39b2022-05-31 08:59:27 -0700644 asyncResp->res.jsonValue["@odata.type"] =
Chicago Duan3d307082020-11-26 14:12:12 +0800645 "#EventDestination.v1_8_0.EventDestination";
Ed Tanous002d39b2022-05-31 08:59:27 -0700646 asyncResp->res.jsonValue["Protocol"] = "Redfish";
647 asyncResp->res.jsonValue["@odata.id"] =
648 "/redfish/v1/EventService/Subscriptions/" + id;
649 asyncResp->res.jsonValue["Id"] = id;
650 asyncResp->res.jsonValue["Name"] = "Event Destination " + id;
651 asyncResp->res.jsonValue["Destination"] = subValue->destinationUrl;
652 asyncResp->res.jsonValue["Context"] = subValue->customText;
653 asyncResp->res.jsonValue["SubscriptionType"] =
654 subValue->subscriptionType;
655 asyncResp->res.jsonValue["HttpHeaders"] = nlohmann::json::array();
656 asyncResp->res.jsonValue["EventFormatType"] = subValue->eventFormatType;
657 asyncResp->res.jsonValue["RegistryPrefixes"] =
658 subValue->registryPrefixes;
659 asyncResp->res.jsonValue["ResourceTypes"] = subValue->resourceTypes;
zhanghch058d1b46d2021-04-01 11:18:24 +0800660
Ed Tanous002d39b2022-05-31 08:59:27 -0700661 asyncResp->res.jsonValue["MessageIds"] = subValue->registryMsgIds;
662 asyncResp->res.jsonValue["DeliveryRetryPolicy"] = subValue->retryPolicy;
AppaRao Pulie5aaf042020-03-20 01:05:52 +0530663
Ed Tanous002d39b2022-05-31 08:59:27 -0700664 nlohmann::json::array_t mrdJsonArray;
665 for (const auto& mdrUri : subValue->metricReportDefinitions)
666 {
667 nlohmann::json::object_t mdr;
668 mdr["@odata.id"] = mdrUri;
669 mrdJsonArray.emplace_back(std::move(mdr));
670 }
671 asyncResp->res.jsonValue["MetricReportDefinitions"] = mrdJsonArray;
672 });
Ravi Teja9d41aec2021-07-23 01:57:01 -0500673 BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -0700674 // The below privilege is wrong, it should be ConfigureManager OR
675 // ConfigureSelf
Abhishek Patel7eeafa72021-07-28 10:59:16 -0500676 // https://github.com/openbmc/bmcweb/issues/220
Ed Tanoused398212021-06-09 17:05:54 -0700677 //.privileges(redfish::privileges::patchEventDestination)
Ed Tanous432a8902021-06-14 15:28:56 -0700678 .privileges({{"ConfigureManager"}})
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700679 .methods(boost::beast::http::verb::patch)(
Ed Tanous45ca1b82022-03-25 13:07:27 -0700680 [&app](const crow::Request& req,
681 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
682 const std::string& param) {
Carson Labrado3ba00072022-06-06 19:40:56 +0000683 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -0700684 {
685 return;
686 }
687 std::shared_ptr<Subscription> subValue =
688 EventServiceManager::getInstance().getSubscription(param);
689 if (subValue == nullptr)
690 {
691 asyncResp->res.result(boost::beast::http::status::not_found);
692 return;
693 }
AppaRao Pulie5aaf042020-03-20 01:05:52 +0530694
Ed Tanous002d39b2022-05-31 08:59:27 -0700695 std::optional<std::string> context;
696 std::optional<std::string> retryPolicy;
697 std::optional<std::vector<nlohmann::json>> headers;
Sunitha Harishe56f2542020-07-22 02:38:59 -0500698
Ed Tanous002d39b2022-05-31 08:59:27 -0700699 if (!json_util::readJsonPatch(req, asyncResp->res, "Context", context,
700 "DeliveryRetryPolicy", retryPolicy,
701 "HttpHeaders", headers))
702 {
703 return;
704 }
AppaRao Puli144b6312020-08-03 22:23:12 +0530705
Ed Tanous002d39b2022-05-31 08:59:27 -0700706 if (context)
707 {
708 subValue->customText = *context;
709 }
AppaRao Pulie5aaf042020-03-20 01:05:52 +0530710
Ed Tanous002d39b2022-05-31 08:59:27 -0700711 if (headers)
712 {
713 boost::beast::http::fields fields;
714 for (const nlohmann::json& headerChunk : *headers)
715 {
Patrick Williams62bafc02022-09-08 17:35:35 -0500716 for (const auto& it : headerChunk.items())
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700717 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700718 const std::string* value =
719 it.value().get_ptr<const std::string*>();
720 if (value == nullptr)
Ed Tanous601c71a2021-09-08 16:40:12 -0700721 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700722 messages::propertyValueFormatError(
Ed Tanousf818b042022-06-27 13:17:35 -0700723 asyncResp->res, it.value(),
Ed Tanous002d39b2022-05-31 08:59:27 -0700724 "HttpHeaders/" + it.key());
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700725 return;
726 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700727 fields.set(it.key(), *value);
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700728 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700729 }
730 subValue->httpHeaders = fields;
731 }
AppaRao Pulie5aaf042020-03-20 01:05:52 +0530732
Ed Tanous002d39b2022-05-31 08:59:27 -0700733 if (retryPolicy)
734 {
735 if (std::find(supportedRetryPolicies.begin(),
736 supportedRetryPolicies.end(),
737 *retryPolicy) == supportedRetryPolicies.end())
738 {
739 messages::propertyValueNotInList(asyncResp->res, *retryPolicy,
740 "DeliveryRetryPolicy");
741 return;
742 }
743 subValue->retryPolicy = *retryPolicy;
Ed Tanous002d39b2022-05-31 08:59:27 -0700744 }
745
746 EventServiceManager::getInstance().updateSubscriptionData();
747 });
Ravi Teja9d41aec2021-07-23 01:57:01 -0500748 BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -0700749 // The below privilege is wrong, it should be ConfigureManager OR
750 // ConfigureSelf
Abhishek Patel7eeafa72021-07-28 10:59:16 -0500751 // https://github.com/openbmc/bmcweb/issues/220
Ed Tanoused398212021-06-09 17:05:54 -0700752 //.privileges(redfish::privileges::deleteEventDestination)
Ed Tanous432a8902021-06-14 15:28:56 -0700753 .privileges({{"ConfigureManager"}})
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700754 .methods(boost::beast::http::verb::delete_)(
Ed Tanous45ca1b82022-03-25 13:07:27 -0700755 [&app](const crow::Request& req,
756 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
757 const std::string& param) {
Carson Labrado3ba00072022-06-06 19:40:56 +0000758 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -0700759 {
760 return;
761 }
Chicago Duan3d307082020-11-26 14:12:12 +0800762
763 if (param.starts_with("snmp"))
764 {
765 deleteSnmpTrapClient(asyncResp, param);
766 EventServiceManager::getInstance().deleteSubscription(param);
767 return;
768 }
769
Ed Tanous002d39b2022-05-31 08:59:27 -0700770 if (!EventServiceManager::getInstance().isSubscriptionExist(param))
771 {
772 asyncResp->res.result(boost::beast::http::status::not_found);
773 return;
774 }
775 EventServiceManager::getInstance().deleteSubscription(param);
776 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700777}
AppaRao Pulie5aaf042020-03-20 01:05:52 +0530778
779} // namespace redfish