blob: 0b6dce6a759fee1a8775e578fc5116871ad1c064 [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 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>
Patrick Williams1e270c52021-12-04 06:06:56 -060037
AppaRao Pulie5aaf042020-03-20 01:05:52 +053038namespace redfish
39{
40
AppaRao Puli156d6b02020-04-25 06:04:05 +053041static constexpr const std::array<const char*, 2> supportedEvtFormatTypes = {
42 eventFormatType, metricReportFormatType};
AppaRao Pulie5aaf042020-03-20 01:05:52 +053043static constexpr const std::array<const char*, 3> supportedRegPrefixes = {
P Dheeraj Srujan Kumarb304bd72021-01-29 17:46:35 +053044 "Base", "OpenBMC", "TaskEvent"};
AppaRao Pulie5aaf042020-03-20 01:05:52 +053045static constexpr const std::array<const char*, 3> supportedRetryPolicies = {
46 "TerminateAfterRetries", "SuspendRetries", "RetryForever"};
47
Sunitha Harishe56f2542020-07-22 02:38:59 -050048static constexpr const std::array<const char*, 1> supportedResourceTypes = {
49 "Task"};
Sunitha Harishe56f2542020-07-22 02:38:59 -050050
John Edward Broadbent7e860f12021-04-08 15:57:16 -070051inline void requestRoutesEventService(App& app)
AppaRao Pulie5aaf042020-03-20 01:05:52 +053052{
John Edward Broadbent7e860f12021-04-08 15:57:16 -070053 BMCWEB_ROUTE(app, "/redfish/v1/EventService/")
Ed Tanoused398212021-06-09 17:05:54 -070054 .privileges(redfish::privileges::getEventService)
Ed Tanous002d39b2022-05-31 08:59:27 -070055 .methods(boost::beast::http::verb::get)(
56 [&app](const crow::Request& req,
57 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Carson Labrado3ba00072022-06-06 19:40:56 +000058 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -070059 {
60 return;
61 }
Ed Tanous14766872022-03-15 10:44:42 -070062
Ed Tanous002d39b2022-05-31 08:59:27 -070063 asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/EventService";
64 asyncResp->res.jsonValue["@odata.type"] =
65 "#EventService.v1_5_0.EventService";
66 asyncResp->res.jsonValue["Id"] = "EventService";
67 asyncResp->res.jsonValue["Name"] = "Event Service";
AppaRao Puli5e44e3d2021-03-16 15:37:24 +000068 asyncResp->res.jsonValue["ServerSentEventUri"] =
69 "/redfish/v1/EventService/SSE";
70
Ed Tanous002d39b2022-05-31 08:59:27 -070071 asyncResp->res.jsonValue["Subscriptions"]["@odata.id"] =
72 "/redfish/v1/EventService/Subscriptions";
73 asyncResp->res
74 .jsonValue["Actions"]["#EventService.SubmitTestEvent"]["target"] =
75 "/redfish/v1/EventService/Actions/EventService.SubmitTestEvent";
AppaRao Pulie5aaf042020-03-20 01:05:52 +053076
Ed Tanous002d39b2022-05-31 08:59:27 -070077 const persistent_data::EventServiceConfig eventServiceConfig =
78 persistent_data::EventServiceStore::getInstance()
79 .getEventServiceConfig();
zhanghch058d1b46d2021-04-01 11:18:24 +080080
Ed Tanous002d39b2022-05-31 08:59:27 -070081 asyncResp->res.jsonValue["Status"]["State"] =
82 (eventServiceConfig.enabled ? "Enabled" : "Disabled");
83 asyncResp->res.jsonValue["ServiceEnabled"] = eventServiceConfig.enabled;
84 asyncResp->res.jsonValue["DeliveryRetryAttempts"] =
85 eventServiceConfig.retryAttempts;
86 asyncResp->res.jsonValue["DeliveryRetryIntervalSeconds"] =
87 eventServiceConfig.retryTimeoutInterval;
88 asyncResp->res.jsonValue["EventFormatTypes"] = supportedEvtFormatTypes;
89 asyncResp->res.jsonValue["RegistryPrefixes"] = supportedRegPrefixes;
90 asyncResp->res.jsonValue["ResourceTypes"] = supportedResourceTypes;
AppaRao Pulie5aaf042020-03-20 01:05:52 +053091
Ed Tanous613dabe2022-07-09 11:17:36 -070092 nlohmann::json::object_t supportedSSEFilters;
93 supportedSSEFilters["EventFormatType"] = true;
94 supportedSSEFilters["MessageId"] = true;
95 supportedSSEFilters["MetricReportDefinition"] = true;
96 supportedSSEFilters["RegistryPrefix"] = true;
97 supportedSSEFilters["OriginResource"] = false;
98 supportedSSEFilters["ResourceType"] = false;
AppaRao Puli7d1cc382020-05-16 02:42:22 +053099
Ed Tanous002d39b2022-05-31 08:59:27 -0700100 asyncResp->res.jsonValue["SSEFilterPropertiesSupported"] =
Ed Tanous613dabe2022-07-09 11:17:36 -0700101 std::move(supportedSSEFilters);
Patrick Williams5a39f772023-10-20 11:20:21 -0500102 });
Ayushi Smriti07941a82020-05-21 15:55:34 +0530103
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700104 BMCWEB_ROUTE(app, "/redfish/v1/EventService/")
Ed Tanoused398212021-06-09 17:05:54 -0700105 .privileges(redfish::privileges::patchEventService)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700106 .methods(boost::beast::http::verb::patch)(
Ed Tanous45ca1b82022-03-25 13:07:27 -0700107 [&app](const crow::Request& req,
108 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Carson Labrado3ba00072022-06-06 19:40:56 +0000109 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -0700110 {
111 return;
112 }
113 std::optional<bool> serviceEnabled;
114 std::optional<uint32_t> retryAttemps;
115 std::optional<uint32_t> retryInterval;
AppaRao Pulie5aaf042020-03-20 01:05:52 +0530116
Ed Tanous002d39b2022-05-31 08:59:27 -0700117 if (!json_util::readJsonPatch(
118 req, asyncResp->res, "ServiceEnabled", serviceEnabled,
119 "DeliveryRetryAttempts", retryAttemps,
120 "DeliveryRetryIntervalSeconds", retryInterval))
121 {
122 return;
123 }
AppaRao Pulie5aaf042020-03-20 01:05:52 +0530124
Ed Tanous002d39b2022-05-31 08:59:27 -0700125 persistent_data::EventServiceConfig eventServiceConfig =
126 persistent_data::EventServiceStore::getInstance()
127 .getEventServiceConfig();
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700128
Ed Tanous002d39b2022-05-31 08:59:27 -0700129 if (serviceEnabled)
130 {
131 eventServiceConfig.enabled = *serviceEnabled;
132 }
Sunitha Harishe56f2542020-07-22 02:38:59 -0500133
Ed Tanous002d39b2022-05-31 08:59:27 -0700134 if (retryAttemps)
135 {
136 // Supported range [1-3]
137 if ((*retryAttemps < 1) || (*retryAttemps > 3))
138 {
139 messages::queryParameterOutOfRange(
140 asyncResp->res, std::to_string(*retryAttemps),
141 "DeliveryRetryAttempts", "[1-3]");
142 }
143 else
144 {
145 eventServiceConfig.retryAttempts = *retryAttemps;
146 }
147 }
P Dheeraj Srujan Kumarb304bd72021-01-29 17:46:35 +0530148
Ed Tanous002d39b2022-05-31 08:59:27 -0700149 if (retryInterval)
150 {
Gunnar Mills33a32b32022-11-17 14:29:07 -0600151 // Supported range [5 - 180]
152 if ((*retryInterval < 5) || (*retryInterval > 180))
Ed Tanous002d39b2022-05-31 08:59:27 -0700153 {
154 messages::queryParameterOutOfRange(
155 asyncResp->res, std::to_string(*retryInterval),
Gunnar Mills33a32b32022-11-17 14:29:07 -0600156 "DeliveryRetryIntervalSeconds", "[5-180]");
Ed Tanous002d39b2022-05-31 08:59:27 -0700157 }
158 else
159 {
160 eventServiceConfig.retryTimeoutInterval = *retryInterval;
161 }
162 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700163
Ed Tanous002d39b2022-05-31 08:59:27 -0700164 EventServiceManager::getInstance().setEventServiceConfig(
165 eventServiceConfig);
Patrick Williams5a39f772023-10-20 11:20:21 -0500166 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700167}
168
169inline void requestRoutesSubmitTestEvent(App& app)
170{
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700171 BMCWEB_ROUTE(
172 app, "/redfish/v1/EventService/Actions/EventService.SubmitTestEvent/")
Ed Tanoused398212021-06-09 17:05:54 -0700173 .privileges(redfish::privileges::postEventService)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700174 .methods(boost::beast::http::verb::post)(
Ed Tanous45ca1b82022-03-25 13:07:27 -0700175 [&app](const crow::Request& req,
176 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Carson Labrado3ba00072022-06-06 19:40:56 +0000177 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -0700178 {
179 return;
180 }
181 if (!EventServiceManager::getInstance().sendTestEventLog())
182 {
183 messages::serviceDisabled(asyncResp->res,
184 "/redfish/v1/EventService/");
185 return;
186 }
187 asyncResp->res.result(boost::beast::http::status::no_content);
Patrick Williams5a39f772023-10-20 11:20:21 -0500188 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700189}
190
Chicago Duan3d307082020-11-26 14:12:12 +0800191inline void doSubscriptionCollection(
Ed Tanouse81de512023-06-27 17:07:00 -0700192 const boost::system::error_code& ec,
Chicago Duan3d307082020-11-26 14:12:12 +0800193 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
194 const dbus::utility::ManagedObjectType& resp)
195{
196 if (ec)
197 {
Ed Tanous13061012023-07-25 11:12:19 -0700198 if (ec.value() == EBADR || ec.value() == EHOSTUNREACH)
Chicago Duan3d307082020-11-26 14:12:12 +0800199 {
200 // This is an optional process so just return if it isn't there
201 return;
202 }
203
Ed Tanous62598e32023-07-17 17:06:25 -0700204 BMCWEB_LOG_ERROR("D-Bus response error on GetManagedObjects {}", ec);
Chicago Duan3d307082020-11-26 14:12:12 +0800205 messages::internalError(asyncResp->res);
206 return;
207 }
208 nlohmann::json& memberArray = asyncResp->res.jsonValue["Members"];
209 for (const auto& objpath : resp)
210 {
211 sdbusplus::message::object_path path(objpath.first);
212 const std::string snmpId = path.filename();
213 if (snmpId.empty())
214 {
Ed Tanous62598e32023-07-17 17:06:25 -0700215 BMCWEB_LOG_ERROR("The SNMP client ID is wrong");
Chicago Duan3d307082020-11-26 14:12:12 +0800216 messages::internalError(asyncResp->res);
217 return;
218 }
219
220 getSnmpSubscriptionList(asyncResp, snmpId, memberArray);
221 }
222}
223
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700224inline void requestRoutesEventDestinationCollection(App& app)
225{
Gayathri Leburu1ebe3e42022-02-09 10:45:19 +0000226 BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/")
Ed Tanoused398212021-06-09 17:05:54 -0700227 .privileges(redfish::privileges::getEventDestinationCollection)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700228 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -0700229 [&app](const crow::Request& req,
230 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Carson Labrado3ba00072022-06-06 19:40:56 +0000231 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -0700232 {
233 return;
234 }
235 asyncResp->res.jsonValue["@odata.type"] =
236 "#EventDestinationCollection.EventDestinationCollection";
237 asyncResp->res.jsonValue["@odata.id"] =
238 "/redfish/v1/EventService/Subscriptions";
239 asyncResp->res.jsonValue["Name"] = "Event Destination Collections";
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700240
Ed Tanous002d39b2022-05-31 08:59:27 -0700241 nlohmann::json& memberArray = asyncResp->res.jsonValue["Members"];
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700242
Ed Tanous002d39b2022-05-31 08:59:27 -0700243 std::vector<std::string> subscripIds =
244 EventServiceManager::getInstance().getAllIDs();
245 memberArray = nlohmann::json::array();
246 asyncResp->res.jsonValue["Members@odata.count"] = subscripIds.size();
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700247
Ed Tanous002d39b2022-05-31 08:59:27 -0700248 for (const std::string& id : subscripIds)
249 {
250 nlohmann::json::object_t member;
Chicago Duan3d307082020-11-26 14:12:12 +0800251 member["@odata.id"] = boost::urls::format(
252 "/redfish/v1/EventService/Subscriptions/{}" + id);
Patrick Williamsb2ba3072023-05-12 10:27:39 -0500253 memberArray.emplace_back(std::move(member));
Ed Tanous002d39b2022-05-31 08:59:27 -0700254 }
Chicago Duan3d307082020-11-26 14:12:12 +0800255 crow::connections::systemBus->async_method_call(
Ed Tanouse81de512023-06-27 17:07:00 -0700256 [asyncResp](const boost::system::error_code& ec,
Chicago Duan3d307082020-11-26 14:12:12 +0800257 const dbus::utility::ManagedObjectType& resp) {
258 doSubscriptionCollection(ec, asyncResp, resp);
Patrick Williams5a39f772023-10-20 11:20:21 -0500259 },
Chicago Duan3d307082020-11-26 14:12:12 +0800260 "xyz.openbmc_project.Network.SNMP",
261 "/xyz/openbmc_project/network/snmp/manager",
262 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
Patrick Williams5a39f772023-10-20 11:20:21 -0500263 });
Chicago Duan3d307082020-11-26 14:12:12 +0800264
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700265 BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/")
Abhishek Patel7eeafa72021-07-28 10:59:16 -0500266 .privileges(redfish::privileges::postEventDestinationCollection)
Ed Tanous002d39b2022-05-31 08:59:27 -0700267 .methods(boost::beast::http::verb::post)(
268 [&app](const crow::Request& req,
269 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Carson Labrado3ba00072022-06-06 19:40:56 +0000270 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -0700271 {
272 return;
273 }
274 if (EventServiceManager::getInstance().getNumberOfSubscriptions() >=
275 maxNoOfSubscriptions)
276 {
277 messages::eventSubscriptionLimitExceeded(asyncResp->res);
278 return;
279 }
280 std::string destUrl;
281 std::string protocol;
Ed Tanous19bb3622024-07-05 10:07:40 -0500282 std::optional<bool> verifyCertificate;
Ed Tanous002d39b2022-05-31 08:59:27 -0700283 std::optional<std::string> context;
284 std::optional<std::string> subscriptionType;
285 std::optional<std::string> eventFormatType2;
286 std::optional<std::string> retryPolicy;
287 std::optional<std::vector<std::string>> msgIds;
288 std::optional<std::vector<std::string>> regPrefixes;
289 std::optional<std::vector<std::string>> resTypes;
Ed Tanous78d4ec42024-03-06 17:36:33 -0800290 std::optional<std::vector<nlohmann::json::object_t>> headers;
291 std::optional<std::vector<nlohmann::json::object_t>> mrdJsonArray;
Ed Tanousfffb8c12022-02-07 23:53:03 -0800292
Ed Tanous002d39b2022-05-31 08:59:27 -0700293 if (!json_util::readJsonPatch(
294 req, asyncResp->res, "Destination", destUrl, "Context", context,
295 "Protocol", protocol, "SubscriptionType", subscriptionType,
296 "EventFormatType", eventFormatType2, "HttpHeaders", headers,
297 "RegistryPrefixes", regPrefixes, "MessageIds", msgIds,
298 "DeliveryRetryPolicy", retryPolicy, "MetricReportDefinitions",
Ed Tanous19bb3622024-07-05 10:07:40 -0500299 mrdJsonArray, "ResourceTypes", resTypes, "VerifyCertificate",
300 verifyCertificate))
Ed Tanous002d39b2022-05-31 08:59:27 -0700301 {
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 Tanous6fd29552023-10-04 09:40:14 -0700324 boost::system::result<boost::urls::url> url =
Ed Tanousa716aa72023-08-01 11:35:53 -0700325 boost::urls::parse_absolute_uri(destUrl);
326 if (!url)
Ed Tanous002d39b2022-05-31 08:59:27 -0700327 {
Ed Tanous62598e32023-07-17 17:06:25 -0700328 BMCWEB_LOG_WARNING("Failed to validate and split destination url");
Ed Tanous002d39b2022-05-31 08:59:27 -0700329 messages::propertyValueFormatError(asyncResp->res, destUrl,
330 "Destination");
331 return;
332 }
Ed Tanousa716aa72023-08-01 11:35:53 -0700333 url->normalize();
334 crow::utility::setProtocolDefaults(*url, protocol);
335 crow::utility::setPortDefaults(*url);
336
337 if (url->path().empty())
338 {
339 url->set_path("/");
340 }
341
342 if (url->has_userinfo())
343 {
344 messages::propertyValueFormatError(asyncResp->res, destUrl,
345 "Destination");
346 return;
347 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700348
Chicago Duan3d307082020-11-26 14:12:12 +0800349 if (protocol == "SNMPv2c")
350 {
351 if (context)
352 {
353 messages::propertyValueConflict(asyncResp->res, "Context",
354 "Protocol");
355 return;
356 }
357 if (eventFormatType2)
358 {
359 messages::propertyValueConflict(asyncResp->res,
360 "EventFormatType", "Protocol");
361 return;
362 }
363 if (retryPolicy)
364 {
365 messages::propertyValueConflict(asyncResp->res, "RetryPolicy",
366 "Protocol");
367 return;
368 }
369 if (msgIds)
370 {
371 messages::propertyValueConflict(asyncResp->res, "MessageIds",
372 "Protocol");
373 return;
374 }
375 if (regPrefixes)
376 {
377 messages::propertyValueConflict(asyncResp->res,
378 "RegistryPrefixes", "Protocol");
379 return;
380 }
381 if (resTypes)
382 {
383 messages::propertyValueConflict(asyncResp->res, "ResourceTypes",
384 "Protocol");
385 return;
386 }
387 if (headers)
388 {
389 messages::propertyValueConflict(asyncResp->res, "HttpHeaders",
390 "Protocol");
391 return;
392 }
393 if (mrdJsonArray)
394 {
395 messages::propertyValueConflict(
396 asyncResp->res, "MetricReportDefinitions", "Protocol");
397 return;
398 }
Ed Tanousa716aa72023-08-01 11:35:53 -0700399 if (url->scheme() != "snmp")
400 {
401 messages::propertyValueConflict(asyncResp->res, "Destination",
402 "Protocol");
403 return;
404 }
Chicago Duan3d307082020-11-26 14:12:12 +0800405
Ed Tanousa716aa72023-08-01 11:35:53 -0700406 addSnmpTrapClient(asyncResp, url->host_address(),
407 url->port_number());
Chicago Duan3d307082020-11-26 14:12:12 +0800408 return;
409 }
410
Ed Tanousa716aa72023-08-01 11:35:53 -0700411 std::shared_ptr<Subscription> subValue =
412 std::make_shared<Subscription>(*url, app.ioContext());
Chicago Duan3d307082020-11-26 14:12:12 +0800413
Ed Tanousa716aa72023-08-01 11:35:53 -0700414 subValue->destinationUrl = std::move(*url);
Ed Tanous002d39b2022-05-31 08:59:27 -0700415
416 if (subscriptionType)
417 {
418 if (*subscriptionType != "RedfishEvent")
Ed Tanousfffb8c12022-02-07 23:53:03 -0800419 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700420 messages::propertyValueNotInList(
421 asyncResp->res, *subscriptionType, "SubscriptionType");
422 return;
423 }
424 subValue->subscriptionType = *subscriptionType;
425 }
426 else
427 {
428 subValue->subscriptionType = "RedfishEvent"; // Default
429 }
430
431 if (protocol != "Redfish")
432 {
433 messages::propertyValueNotInList(asyncResp->res, protocol,
434 "Protocol");
435 return;
436 }
437 subValue->protocol = protocol;
438
Ed Tanous19bb3622024-07-05 10:07:40 -0500439 if (verifyCertificate)
440 {
441 subValue->verifyCertificate = *verifyCertificate;
442 }
443
Ed Tanous002d39b2022-05-31 08:59:27 -0700444 if (eventFormatType2)
445 {
Ed Tanous3544d2a2023-08-06 18:12:20 -0700446 if (std::ranges::find(supportedEvtFormatTypes, *eventFormatType2) ==
447 supportedEvtFormatTypes.end())
Ed Tanous002d39b2022-05-31 08:59:27 -0700448 {
449 messages::propertyValueNotInList(
450 asyncResp->res, *eventFormatType2, "EventFormatType");
451 return;
452 }
453 subValue->eventFormatType = *eventFormatType2;
454 }
455 else
456 {
457 // If not specified, use default "Event"
458 subValue->eventFormatType = "Event";
459 }
460
461 if (context)
462 {
Ed Tanous8ece0e42024-01-02 13:16:50 -0800463 // This value is selected arbitrarily.
AppaRao Puli600af5f2021-10-06 21:51:16 +0000464 constexpr const size_t maxContextSize = 256;
465 if (context->size() > maxContextSize)
466 {
467 messages::stringValueTooLong(asyncResp->res, "Context",
468 maxContextSize);
469 return;
470 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700471 subValue->customText = *context;
472 }
473
474 if (headers)
475 {
AppaRao Puli600af5f2021-10-06 21:51:16 +0000476 size_t cumulativeLen = 0;
477
Ed Tanous78d4ec42024-03-06 17:36:33 -0800478 for (const nlohmann::json::object_t& headerChunk : *headers)
Ed Tanous002d39b2022-05-31 08:59:27 -0700479 {
Ed Tanous78d4ec42024-03-06 17:36:33 -0800480 for (const auto& item : headerChunk)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700481 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700482 const std::string* value =
Ed Tanous78d4ec42024-03-06 17:36:33 -0800483 item.second.get_ptr<const std::string*>();
Ed Tanous002d39b2022-05-31 08:59:27 -0700484 if (value == nullptr)
485 {
486 messages::propertyValueFormatError(
Ed Tanous78d4ec42024-03-06 17:36:33 -0800487 asyncResp->res, item.second,
488 "HttpHeaders/" + item.first);
Ed Tanous002d39b2022-05-31 08:59:27 -0700489 return;
490 }
Ed Tanous78d4ec42024-03-06 17:36:33 -0800491 // Adding a new json value is the size of the key, +
492 // the size of the value + 2 * 2 quotes for each, +
493 // the colon and space between. example:
494 // "key": "value"
495 cumulativeLen += item.first.size() + value->size() + 6;
496 // This value is selected to mirror http_connection.hpp
497 constexpr const uint16_t maxHeaderSizeED = 8096;
498 if (cumulativeLen > maxHeaderSizeED)
499 {
500 messages::arraySizeTooLong(
501 asyncResp->res, "HttpHeaders", maxHeaderSizeED);
502 return;
503 }
504 subValue->httpHeaders.set(item.first, *value);
Ed Tanous002d39b2022-05-31 08:59:27 -0700505 }
506 }
507 }
508
509 if (regPrefixes)
510 {
511 for (const std::string& it : *regPrefixes)
512 {
Ed Tanous3544d2a2023-08-06 18:12:20 -0700513 if (std::ranges::find(supportedRegPrefixes, it) ==
514 supportedRegPrefixes.end())
Ed Tanous002d39b2022-05-31 08:59:27 -0700515 {
516 messages::propertyValueNotInList(asyncResp->res, it,
517 "RegistryPrefixes");
P Dheeraj Srujan Kumarb304bd72021-01-29 17:46:35 +0530518 return;
519 }
Ed Tanousfffb8c12022-02-07 23:53:03 -0800520 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700521 subValue->registryPrefixes = *regPrefixes;
522 }
P Dheeraj Srujan Kumarb304bd72021-01-29 17:46:35 +0530523
Ed Tanous002d39b2022-05-31 08:59:27 -0700524 if (resTypes)
525 {
526 for (const std::string& it : *resTypes)
Ed Tanousfffb8c12022-02-07 23:53:03 -0800527 {
Ed Tanous3544d2a2023-08-06 18:12:20 -0700528 if (std::ranges::find(supportedResourceTypes, it) ==
529 supportedResourceTypes.end())
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700530 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700531 messages::propertyValueNotInList(asyncResp->res, it,
532 "ResourceTypes");
AppaRao Puli144b6312020-08-03 22:23:12 +0530533 return;
534 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700535 }
536 subValue->resourceTypes = *resTypes;
537 }
538
539 if (msgIds)
540 {
541 std::vector<std::string> registryPrefix;
542
543 // If no registry prefixes are mentioned, consider all
544 // supported prefixes
545 if (subValue->registryPrefixes.empty())
546 {
547 registryPrefix.assign(supportedRegPrefixes.begin(),
548 supportedRegPrefixes.end());
Ed Tanousfffb8c12022-02-07 23:53:03 -0800549 }
550 else
551 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700552 registryPrefix = subValue->registryPrefixes;
Ed Tanousfffb8c12022-02-07 23:53:03 -0800553 }
AppaRao Puli156d6b02020-04-25 06:04:05 +0530554
Ed Tanous002d39b2022-05-31 08:59:27 -0700555 for (const std::string& id : *msgIds)
Ed Tanousfffb8c12022-02-07 23:53:03 -0800556 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700557 bool validId = false;
Ed Tanousfffb8c12022-02-07 23:53:03 -0800558
Ed Tanous002d39b2022-05-31 08:59:27 -0700559 // Check for Message ID in each of the selected Registry
560 for (const std::string& it : registryPrefix)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700561 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700562 const std::span<const redfish::registries::MessageEntry>
563 registry =
564 redfish::registries::getRegistryFromPrefix(it);
565
Ed Tanous3544d2a2023-08-06 18:12:20 -0700566 if (std::ranges::any_of(
567 registry,
Ed Tanous002d39b2022-05-31 08:59:27 -0700568 [&id](const redfish::registries::MessageEntry&
569 messageEntry) {
570 return id == messageEntry.first;
Patrick Williams5a39f772023-10-20 11:20:21 -0500571 }))
Ed Tanous002d39b2022-05-31 08:59:27 -0700572 {
573 validId = true;
574 break;
575 }
576 }
577
578 if (!validId)
579 {
580 messages::propertyValueNotInList(asyncResp->res, id,
581 "MessageIds");
Ed Tanousfffb8c12022-02-07 23:53:03 -0800582 return;
583 }
Ed Tanousfffb8c12022-02-07 23:53:03 -0800584 }
585
Ed Tanous002d39b2022-05-31 08:59:27 -0700586 subValue->registryMsgIds = *msgIds;
587 }
588
589 if (retryPolicy)
590 {
Ed Tanous3544d2a2023-08-06 18:12:20 -0700591 if (std::ranges::find(supportedRetryPolicies, *retryPolicy) ==
592 supportedRetryPolicies.end())
Ed Tanousfffb8c12022-02-07 23:53:03 -0800593 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700594 messages::propertyValueNotInList(asyncResp->res, *retryPolicy,
595 "DeliveryRetryPolicy");
Ed Tanousfffb8c12022-02-07 23:53:03 -0800596 return;
597 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700598 subValue->retryPolicy = *retryPolicy;
599 }
600 else
601 {
602 // Default "TerminateAfterRetries"
603 subValue->retryPolicy = "TerminateAfterRetries";
604 }
Ed Tanousfffb8c12022-02-07 23:53:03 -0800605
Ed Tanous002d39b2022-05-31 08:59:27 -0700606 if (mrdJsonArray)
607 {
Ed Tanous78d4ec42024-03-06 17:36:33 -0800608 for (nlohmann::json::object_t& mrdObj : *mrdJsonArray)
Ed Tanous002d39b2022-05-31 08:59:27 -0700609 {
610 std::string mrdUri;
611
Ed Tanous78d4ec42024-03-06 17:36:33 -0800612 if (!json_util::readJsonObject(mrdObj, asyncResp->res,
613 "@odata.id", mrdUri))
Ed Tanous002d39b2022-05-31 08:59:27 -0700614
615 {
616 return;
617 }
618 subValue->metricReportDefinitions.emplace_back(mrdUri);
619 }
620 }
621
622 std::string id =
Ed Tanousf80a87f2024-06-16 12:10:33 -0700623 EventServiceManager::getInstance().addPushSubscription(subValue);
Ed Tanous002d39b2022-05-31 08:59:27 -0700624 if (id.empty())
625 {
626 messages::internalError(asyncResp->res);
627 return;
628 }
629
630 messages::created(asyncResp->res);
631 asyncResp->res.addHeader(
632 "Location", "/redfish/v1/EventService/Subscriptions/" + id);
Patrick Williams5a39f772023-10-20 11:20:21 -0500633 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700634}
635
636inline void requestRoutesEventDestination(App& app)
AppaRao Pulie5aaf042020-03-20 01:05:52 +0530637{
Ravi Teja9d41aec2021-07-23 01:57:01 -0500638 BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -0700639 .privileges(redfish::privileges::getEventDestination)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700640 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -0700641 [&app](const crow::Request& req,
642 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
643 const std::string& param) {
Carson Labrado3ba00072022-06-06 19:40:56 +0000644 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -0700645 {
646 return;
647 }
Chicago Duan3d307082020-11-26 14:12:12 +0800648
649 if (param.starts_with("snmp"))
650 {
651 getSnmpTrapClient(asyncResp, param);
652 return;
653 }
654
Ed Tanous002d39b2022-05-31 08:59:27 -0700655 std::shared_ptr<Subscription> subValue =
656 EventServiceManager::getInstance().getSubscription(param);
657 if (subValue == nullptr)
658 {
659 asyncResp->res.result(boost::beast::http::status::not_found);
660 return;
661 }
662 const std::string& id = param;
AppaRao Pulie5aaf042020-03-20 01:05:52 +0530663
Ed Tanous002d39b2022-05-31 08:59:27 -0700664 asyncResp->res.jsonValue["@odata.type"] =
Chicago Duan3d307082020-11-26 14:12:12 +0800665 "#EventDestination.v1_8_0.EventDestination";
Ed Tanous539d8c62024-06-19 14:38:27 -0700666 asyncResp->res.jsonValue["Protocol"] =
667 event_destination::EventDestinationProtocol::Redfish;
Ed Tanous3b327802023-08-14 09:23:43 -0700668 asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
669 "/redfish/v1/EventService/Subscriptions/{}", id);
Ed Tanous002d39b2022-05-31 08:59:27 -0700670 asyncResp->res.jsonValue["Id"] = id;
671 asyncResp->res.jsonValue["Name"] = "Event Destination " + id;
672 asyncResp->res.jsonValue["Destination"] = subValue->destinationUrl;
673 asyncResp->res.jsonValue["Context"] = subValue->customText;
674 asyncResp->res.jsonValue["SubscriptionType"] =
675 subValue->subscriptionType;
676 asyncResp->res.jsonValue["HttpHeaders"] = nlohmann::json::array();
677 asyncResp->res.jsonValue["EventFormatType"] = subValue->eventFormatType;
678 asyncResp->res.jsonValue["RegistryPrefixes"] =
679 subValue->registryPrefixes;
680 asyncResp->res.jsonValue["ResourceTypes"] = subValue->resourceTypes;
zhanghch058d1b46d2021-04-01 11:18:24 +0800681
Ed Tanous002d39b2022-05-31 08:59:27 -0700682 asyncResp->res.jsonValue["MessageIds"] = subValue->registryMsgIds;
683 asyncResp->res.jsonValue["DeliveryRetryPolicy"] = subValue->retryPolicy;
Ed Tanous19bb3622024-07-05 10:07:40 -0500684 asyncResp->res.jsonValue["VerifyCertificate"] =
685 subValue->verifyCertificate;
AppaRao Pulie5aaf042020-03-20 01:05:52 +0530686
Ed Tanous002d39b2022-05-31 08:59:27 -0700687 nlohmann::json::array_t mrdJsonArray;
688 for (const auto& mdrUri : subValue->metricReportDefinitions)
689 {
690 nlohmann::json::object_t mdr;
691 mdr["@odata.id"] = mdrUri;
692 mrdJsonArray.emplace_back(std::move(mdr));
693 }
694 asyncResp->res.jsonValue["MetricReportDefinitions"] = mrdJsonArray;
Patrick Williams5a39f772023-10-20 11:20:21 -0500695 });
Ravi Teja9d41aec2021-07-23 01:57:01 -0500696 BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -0700697 // The below privilege is wrong, it should be ConfigureManager OR
698 // ConfigureSelf
Abhishek Patel7eeafa72021-07-28 10:59:16 -0500699 // https://github.com/openbmc/bmcweb/issues/220
Ed Tanoused398212021-06-09 17:05:54 -0700700 //.privileges(redfish::privileges::patchEventDestination)
Ed Tanous432a8902021-06-14 15:28:56 -0700701 .privileges({{"ConfigureManager"}})
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700702 .methods(boost::beast::http::verb::patch)(
Ed Tanous45ca1b82022-03-25 13:07:27 -0700703 [&app](const crow::Request& req,
704 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
705 const std::string& param) {
Carson Labrado3ba00072022-06-06 19:40:56 +0000706 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -0700707 {
708 return;
709 }
710 std::shared_ptr<Subscription> subValue =
711 EventServiceManager::getInstance().getSubscription(param);
712 if (subValue == nullptr)
713 {
714 asyncResp->res.result(boost::beast::http::status::not_found);
715 return;
716 }
AppaRao Pulie5aaf042020-03-20 01:05:52 +0530717
Ed Tanous002d39b2022-05-31 08:59:27 -0700718 std::optional<std::string> context;
719 std::optional<std::string> retryPolicy;
Ed Tanous19bb3622024-07-05 10:07:40 -0500720 std::optional<bool> verifyCertificate;
Ed Tanous78d4ec42024-03-06 17:36:33 -0800721 std::optional<std::vector<nlohmann::json::object_t>> headers;
Sunitha Harishe56f2542020-07-22 02:38:59 -0500722
Ed Tanous002d39b2022-05-31 08:59:27 -0700723 if (!json_util::readJsonPatch(req, asyncResp->res, "Context", context,
Ed Tanous19bb3622024-07-05 10:07:40 -0500724 "VerifyCertificate", verifyCertificate,
Ed Tanous002d39b2022-05-31 08:59:27 -0700725 "DeliveryRetryPolicy", retryPolicy,
726 "HttpHeaders", headers))
727 {
728 return;
729 }
AppaRao Puli144b6312020-08-03 22:23:12 +0530730
Ed Tanous002d39b2022-05-31 08:59:27 -0700731 if (context)
732 {
733 subValue->customText = *context;
734 }
AppaRao Pulie5aaf042020-03-20 01:05:52 +0530735
Ed Tanous002d39b2022-05-31 08:59:27 -0700736 if (headers)
737 {
738 boost::beast::http::fields fields;
Ed Tanous78d4ec42024-03-06 17:36:33 -0800739 for (const nlohmann::json::object_t& headerChunk : *headers)
Ed Tanous002d39b2022-05-31 08:59:27 -0700740 {
Ed Tanous78d4ec42024-03-06 17:36:33 -0800741 for (const auto& it : headerChunk)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700742 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700743 const std::string* value =
Ed Tanous78d4ec42024-03-06 17:36:33 -0800744 it.second.get_ptr<const std::string*>();
Ed Tanous002d39b2022-05-31 08:59:27 -0700745 if (value == nullptr)
Ed Tanous601c71a2021-09-08 16:40:12 -0700746 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700747 messages::propertyValueFormatError(
Ed Tanous78d4ec42024-03-06 17:36:33 -0800748 asyncResp->res, it.second,
749 "HttpHeaders/" + it.first);
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700750 return;
751 }
Ed Tanous78d4ec42024-03-06 17:36:33 -0800752 fields.set(it.first, *value);
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700753 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700754 }
Ed Tanous78d4ec42024-03-06 17:36:33 -0800755 subValue->httpHeaders = std::move(fields);
Ed Tanous002d39b2022-05-31 08:59:27 -0700756 }
AppaRao Pulie5aaf042020-03-20 01:05:52 +0530757
Ed Tanous002d39b2022-05-31 08:59:27 -0700758 if (retryPolicy)
759 {
Ed Tanous3544d2a2023-08-06 18:12:20 -0700760 if (std::ranges::find(supportedRetryPolicies, *retryPolicy) ==
761 supportedRetryPolicies.end())
Ed Tanous002d39b2022-05-31 08:59:27 -0700762 {
763 messages::propertyValueNotInList(asyncResp->res, *retryPolicy,
764 "DeliveryRetryPolicy");
765 return;
766 }
767 subValue->retryPolicy = *retryPolicy;
Ed Tanous002d39b2022-05-31 08:59:27 -0700768 }
769
Ed Tanous19bb3622024-07-05 10:07:40 -0500770 if (verifyCertificate)
771 {
772 subValue->verifyCertificate = *verifyCertificate;
773 }
774
Ed Tanous002d39b2022-05-31 08:59:27 -0700775 EventServiceManager::getInstance().updateSubscriptionData();
Patrick Williams5a39f772023-10-20 11:20:21 -0500776 });
Ravi Teja9d41aec2021-07-23 01:57:01 -0500777 BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -0700778 // The below privilege is wrong, it should be ConfigureManager OR
779 // ConfigureSelf
Abhishek Patel7eeafa72021-07-28 10:59:16 -0500780 // https://github.com/openbmc/bmcweb/issues/220
Ed Tanoused398212021-06-09 17:05:54 -0700781 //.privileges(redfish::privileges::deleteEventDestination)
Ed Tanous432a8902021-06-14 15:28:56 -0700782 .privileges({{"ConfigureManager"}})
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700783 .methods(boost::beast::http::verb::delete_)(
Ed Tanous45ca1b82022-03-25 13:07:27 -0700784 [&app](const crow::Request& req,
785 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
786 const std::string& param) {
Carson Labrado3ba00072022-06-06 19:40:56 +0000787 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -0700788 {
789 return;
790 }
Chicago Duan3d307082020-11-26 14:12:12 +0800791
792 if (param.starts_with("snmp"))
793 {
794 deleteSnmpTrapClient(asyncResp, param);
795 EventServiceManager::getInstance().deleteSubscription(param);
796 return;
797 }
798
Ed Tanous002d39b2022-05-31 08:59:27 -0700799 if (!EventServiceManager::getInstance().isSubscriptionExist(param))
800 {
801 asyncResp->res.result(boost::beast::http::status::not_found);
802 return;
803 }
804 EventServiceManager::getInstance().deleteSubscription(param);
Patrick Williams5a39f772023-10-20 11:20:21 -0500805 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700806}
AppaRao Pulie5aaf042020-03-20 01:05:52 +0530807
808} // namespace redfish