blob: 5a66c97bc8eb51b51fb4d44b51a6358a6945c947 [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"
AppaRao Pulie5aaf042020-03-20 01:05:52 +053023
Ed Tanous601c71a2021-09-08 16:40:12 -070024#include <boost/beast/http/fields.hpp>
Ed Tanoused398212021-06-09 17:05:54 -070025
Patrick Williams1e270c52021-12-04 06:06:56 -060026#include <span>
27
AppaRao Pulie5aaf042020-03-20 01:05:52 +053028namespace redfish
29{
30
AppaRao Puli156d6b02020-04-25 06:04:05 +053031static constexpr const std::array<const char*, 2> supportedEvtFormatTypes = {
32 eventFormatType, metricReportFormatType};
AppaRao Pulie5aaf042020-03-20 01:05:52 +053033static constexpr const std::array<const char*, 3> supportedRegPrefixes = {
P Dheeraj Srujan Kumarb304bd72021-01-29 17:46:35 +053034 "Base", "OpenBMC", "TaskEvent"};
AppaRao Pulie5aaf042020-03-20 01:05:52 +053035static constexpr const std::array<const char*, 3> supportedRetryPolicies = {
36 "TerminateAfterRetries", "SuspendRetries", "RetryForever"};
37
Sunitha Harishe56f2542020-07-22 02:38:59 -050038#ifdef BMCWEB_ENABLE_IBM_MANAGEMENT_CONSOLE
39static constexpr const std::array<const char*, 2> supportedResourceTypes = {
40 "IBMConfigFile", "Task"};
41#else
42static constexpr const std::array<const char*, 1> supportedResourceTypes = {
43 "Task"};
44#endif
45
AppaRao Pulie5aaf042020-03-20 01:05:52 +053046static constexpr const uint8_t maxNoOfSubscriptions = 20;
47
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";
65 asyncResp->res.jsonValue["Subscriptions"]["@odata.id"] =
66 "/redfish/v1/EventService/Subscriptions";
67 asyncResp->res
68 .jsonValue["Actions"]["#EventService.SubmitTestEvent"]["target"] =
69 "/redfish/v1/EventService/Actions/EventService.SubmitTestEvent";
AppaRao Pulie5aaf042020-03-20 01:05:52 +053070
Ed Tanous002d39b2022-05-31 08:59:27 -070071 const persistent_data::EventServiceConfig eventServiceConfig =
72 persistent_data::EventServiceStore::getInstance()
73 .getEventServiceConfig();
zhanghch058d1b46d2021-04-01 11:18:24 +080074
Ed Tanous002d39b2022-05-31 08:59:27 -070075 asyncResp->res.jsonValue["Status"]["State"] =
76 (eventServiceConfig.enabled ? "Enabled" : "Disabled");
77 asyncResp->res.jsonValue["ServiceEnabled"] = eventServiceConfig.enabled;
78 asyncResp->res.jsonValue["DeliveryRetryAttempts"] =
79 eventServiceConfig.retryAttempts;
80 asyncResp->res.jsonValue["DeliveryRetryIntervalSeconds"] =
81 eventServiceConfig.retryTimeoutInterval;
82 asyncResp->res.jsonValue["EventFormatTypes"] = supportedEvtFormatTypes;
83 asyncResp->res.jsonValue["RegistryPrefixes"] = supportedRegPrefixes;
84 asyncResp->res.jsonValue["ResourceTypes"] = supportedResourceTypes;
AppaRao Pulie5aaf042020-03-20 01:05:52 +053085
Ed Tanous613dabe2022-07-09 11:17:36 -070086 nlohmann::json::object_t supportedSSEFilters;
87 supportedSSEFilters["EventFormatType"] = true;
88 supportedSSEFilters["MessageId"] = true;
89 supportedSSEFilters["MetricReportDefinition"] = true;
90 supportedSSEFilters["RegistryPrefix"] = true;
91 supportedSSEFilters["OriginResource"] = false;
92 supportedSSEFilters["ResourceType"] = false;
AppaRao Puli7d1cc382020-05-16 02:42:22 +053093
Ed Tanous002d39b2022-05-31 08:59:27 -070094 asyncResp->res.jsonValue["SSEFilterPropertiesSupported"] =
Ed Tanous613dabe2022-07-09 11:17:36 -070095 std::move(supportedSSEFilters);
George Liu0fda0f12021-11-16 10:06:17 +080096 });
Ayushi Smriti07941a82020-05-21 15:55:34 +053097
John Edward Broadbent7e860f12021-04-08 15:57:16 -070098 BMCWEB_ROUTE(app, "/redfish/v1/EventService/")
Ed Tanoused398212021-06-09 17:05:54 -070099 .privileges(redfish::privileges::patchEventService)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700100 .methods(boost::beast::http::verb::patch)(
Ed Tanous45ca1b82022-03-25 13:07:27 -0700101 [&app](const crow::Request& req,
102 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Carson Labrado3ba00072022-06-06 19:40:56 +0000103 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -0700104 {
105 return;
106 }
107 std::optional<bool> serviceEnabled;
108 std::optional<uint32_t> retryAttemps;
109 std::optional<uint32_t> retryInterval;
AppaRao Pulie5aaf042020-03-20 01:05:52 +0530110
Ed Tanous002d39b2022-05-31 08:59:27 -0700111 if (!json_util::readJsonPatch(
112 req, asyncResp->res, "ServiceEnabled", serviceEnabled,
113 "DeliveryRetryAttempts", retryAttemps,
114 "DeliveryRetryIntervalSeconds", retryInterval))
115 {
116 return;
117 }
AppaRao Pulie5aaf042020-03-20 01:05:52 +0530118
Ed Tanous002d39b2022-05-31 08:59:27 -0700119 persistent_data::EventServiceConfig eventServiceConfig =
120 persistent_data::EventServiceStore::getInstance()
121 .getEventServiceConfig();
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700122
Ed Tanous002d39b2022-05-31 08:59:27 -0700123 if (serviceEnabled)
124 {
125 eventServiceConfig.enabled = *serviceEnabled;
126 }
Sunitha Harishe56f2542020-07-22 02:38:59 -0500127
Ed Tanous002d39b2022-05-31 08:59:27 -0700128 if (retryAttemps)
129 {
130 // Supported range [1-3]
131 if ((*retryAttemps < 1) || (*retryAttemps > 3))
132 {
133 messages::queryParameterOutOfRange(
134 asyncResp->res, std::to_string(*retryAttemps),
135 "DeliveryRetryAttempts", "[1-3]");
136 }
137 else
138 {
139 eventServiceConfig.retryAttempts = *retryAttemps;
140 }
141 }
P Dheeraj Srujan Kumarb304bd72021-01-29 17:46:35 +0530142
Ed Tanous002d39b2022-05-31 08:59:27 -0700143 if (retryInterval)
144 {
Gunnar Mills33a32b32022-11-17 14:29:07 -0600145 // Supported range [5 - 180]
146 if ((*retryInterval < 5) || (*retryInterval > 180))
Ed Tanous002d39b2022-05-31 08:59:27 -0700147 {
148 messages::queryParameterOutOfRange(
149 asyncResp->res, std::to_string(*retryInterval),
Gunnar Mills33a32b32022-11-17 14:29:07 -0600150 "DeliveryRetryIntervalSeconds", "[5-180]");
Ed Tanous002d39b2022-05-31 08:59:27 -0700151 }
152 else
153 {
154 eventServiceConfig.retryTimeoutInterval = *retryInterval;
155 }
156 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700157
Ed Tanous002d39b2022-05-31 08:59:27 -0700158 EventServiceManager::getInstance().setEventServiceConfig(
159 eventServiceConfig);
160 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700161}
162
163inline void requestRoutesSubmitTestEvent(App& app)
164{
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700165 BMCWEB_ROUTE(
166 app, "/redfish/v1/EventService/Actions/EventService.SubmitTestEvent/")
Ed Tanoused398212021-06-09 17:05:54 -0700167 .privileges(redfish::privileges::postEventService)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700168 .methods(boost::beast::http::verb::post)(
Ed Tanous45ca1b82022-03-25 13:07:27 -0700169 [&app](const crow::Request& req,
170 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Carson Labrado3ba00072022-06-06 19:40:56 +0000171 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -0700172 {
173 return;
174 }
175 if (!EventServiceManager::getInstance().sendTestEventLog())
176 {
177 messages::serviceDisabled(asyncResp->res,
178 "/redfish/v1/EventService/");
179 return;
180 }
181 asyncResp->res.result(boost::beast::http::status::no_content);
182 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700183}
184
185inline void requestRoutesEventDestinationCollection(App& app)
186{
Gayathri Leburu1ebe3e42022-02-09 10:45:19 +0000187 BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/")
Ed Tanoused398212021-06-09 17:05:54 -0700188 .privileges(redfish::privileges::getEventDestinationCollection)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700189 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -0700190 [&app](const crow::Request& req,
191 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Carson Labrado3ba00072022-06-06 19:40:56 +0000192 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -0700193 {
194 return;
195 }
196 asyncResp->res.jsonValue["@odata.type"] =
197 "#EventDestinationCollection.EventDestinationCollection";
198 asyncResp->res.jsonValue["@odata.id"] =
199 "/redfish/v1/EventService/Subscriptions";
200 asyncResp->res.jsonValue["Name"] = "Event Destination Collections";
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700201
Ed Tanous002d39b2022-05-31 08:59:27 -0700202 nlohmann::json& memberArray = asyncResp->res.jsonValue["Members"];
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700203
Ed Tanous002d39b2022-05-31 08:59:27 -0700204 std::vector<std::string> subscripIds =
205 EventServiceManager::getInstance().getAllIDs();
206 memberArray = nlohmann::json::array();
207 asyncResp->res.jsonValue["Members@odata.count"] = subscripIds.size();
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700208
Ed Tanous002d39b2022-05-31 08:59:27 -0700209 for (const std::string& id : subscripIds)
210 {
211 nlohmann::json::object_t member;
Patrick Williams89492a12023-05-10 07:51:34 -0500212 member["@odata.id"] = "/redfish/v1/EventService/Subscriptions/" +
213 id;
Patrick Williamsb2ba3072023-05-12 10:27:39 -0500214 memberArray.emplace_back(std::move(member));
Ed Tanous002d39b2022-05-31 08:59:27 -0700215 }
216 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700217 BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/")
Abhishek Patel7eeafa72021-07-28 10:59:16 -0500218 .privileges(redfish::privileges::postEventDestinationCollection)
Ed Tanous002d39b2022-05-31 08:59:27 -0700219 .methods(boost::beast::http::verb::post)(
220 [&app](const crow::Request& req,
221 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Carson Labrado3ba00072022-06-06 19:40:56 +0000222 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -0700223 {
224 return;
225 }
226 if (EventServiceManager::getInstance().getNumberOfSubscriptions() >=
227 maxNoOfSubscriptions)
228 {
229 messages::eventSubscriptionLimitExceeded(asyncResp->res);
230 return;
231 }
232 std::string destUrl;
233 std::string protocol;
234 std::optional<std::string> context;
235 std::optional<std::string> subscriptionType;
236 std::optional<std::string> eventFormatType2;
237 std::optional<std::string> retryPolicy;
238 std::optional<std::vector<std::string>> msgIds;
239 std::optional<std::vector<std::string>> regPrefixes;
240 std::optional<std::vector<std::string>> resTypes;
241 std::optional<std::vector<nlohmann::json>> headers;
242 std::optional<std::vector<nlohmann::json>> mrdJsonArray;
Ed Tanousfffb8c12022-02-07 23:53:03 -0800243
Ed Tanous002d39b2022-05-31 08:59:27 -0700244 if (!json_util::readJsonPatch(
245 req, asyncResp->res, "Destination", destUrl, "Context", context,
246 "Protocol", protocol, "SubscriptionType", subscriptionType,
247 "EventFormatType", eventFormatType2, "HttpHeaders", headers,
248 "RegistryPrefixes", regPrefixes, "MessageIds", msgIds,
249 "DeliveryRetryPolicy", retryPolicy, "MetricReportDefinitions",
250 mrdJsonArray, "ResourceTypes", resTypes))
251 {
252 return;
253 }
254
AppaRao Puli600af5f2021-10-06 21:51:16 +0000255 // https://stackoverflow.com/questions/417142/what-is-the-maximum-length-of-a-url-in-different-browsers
256 static constexpr const uint16_t maxDestinationSize = 2000;
257 if (destUrl.size() > maxDestinationSize)
258 {
259 messages::stringValueTooLong(asyncResp->res, "Destination",
260 maxDestinationSize);
261 return;
262 }
263
Ed Tanous002d39b2022-05-31 08:59:27 -0700264 if (regPrefixes && msgIds)
265 {
266 if (!regPrefixes->empty() && !msgIds->empty())
Ed Tanousfffb8c12022-02-07 23:53:03 -0800267 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700268 messages::propertyValueConflict(asyncResp->res, "MessageIds",
269 "RegistryPrefixes");
Ed Tanousfffb8c12022-02-07 23:53:03 -0800270 return;
271 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700272 }
Ed Tanousfffb8c12022-02-07 23:53:03 -0800273
Ed Tanous002d39b2022-05-31 08:59:27 -0700274 std::string host;
275 std::string urlProto;
276 uint16_t port = 0;
277 std::string path;
278
279 if (!crow::utility::validateAndSplitUrl(destUrl, urlProto, host, port,
280 path))
281 {
282 BMCWEB_LOG_WARNING
283 << "Failed to validate and split destination url";
284 messages::propertyValueFormatError(asyncResp->res, destUrl,
285 "Destination");
286 return;
287 }
288
289 if (path.empty())
290 {
291 path = "/";
292 }
Ed Tanousf8ca6d72022-06-28 12:12:03 -0700293 std::shared_ptr<Subscription> subValue = std::make_shared<Subscription>(
294 host, port, path, urlProto, app.ioContext());
Ed Tanous002d39b2022-05-31 08:59:27 -0700295
296 subValue->destinationUrl = destUrl;
297
298 if (subscriptionType)
299 {
300 if (*subscriptionType != "RedfishEvent")
Ed Tanousfffb8c12022-02-07 23:53:03 -0800301 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700302 messages::propertyValueNotInList(
303 asyncResp->res, *subscriptionType, "SubscriptionType");
304 return;
305 }
306 subValue->subscriptionType = *subscriptionType;
307 }
308 else
309 {
310 subValue->subscriptionType = "RedfishEvent"; // Default
311 }
312
313 if (protocol != "Redfish")
314 {
315 messages::propertyValueNotInList(asyncResp->res, protocol,
316 "Protocol");
317 return;
318 }
319 subValue->protocol = protocol;
320
321 if (eventFormatType2)
322 {
323 if (std::find(supportedEvtFormatTypes.begin(),
324 supportedEvtFormatTypes.end(),
325 *eventFormatType2) == supportedEvtFormatTypes.end())
326 {
327 messages::propertyValueNotInList(
328 asyncResp->res, *eventFormatType2, "EventFormatType");
329 return;
330 }
331 subValue->eventFormatType = *eventFormatType2;
332 }
333 else
334 {
335 // If not specified, use default "Event"
336 subValue->eventFormatType = "Event";
337 }
338
339 if (context)
340 {
AppaRao Puli600af5f2021-10-06 21:51:16 +0000341 // This value is selected aribitrarily.
342 constexpr const size_t maxContextSize = 256;
343 if (context->size() > maxContextSize)
344 {
345 messages::stringValueTooLong(asyncResp->res, "Context",
346 maxContextSize);
347 return;
348 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700349 subValue->customText = *context;
350 }
351
352 if (headers)
353 {
AppaRao Puli600af5f2021-10-06 21:51:16 +0000354 size_t cumulativeLen = 0;
355
Ed Tanous002d39b2022-05-31 08:59:27 -0700356 for (const nlohmann::json& headerChunk : *headers)
357 {
AppaRao Puli600af5f2021-10-06 21:51:16 +0000358 std::string hdr{headerChunk.dump(
359 -1, ' ', true, nlohmann::json::error_handler_t::replace)};
360 cumulativeLen += hdr.length();
361
362 // This value is selected to mirror http_connection.hpp
363 constexpr const uint16_t maxHeaderSizeED = 8096;
364 if (cumulativeLen > maxHeaderSizeED)
365 {
366 messages::arraySizeTooLong(asyncResp->res, "HttpHeaders",
367 maxHeaderSizeED);
368 return;
369 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700370 for (const auto& item : headerChunk.items())
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700371 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700372 const std::string* value =
373 item.value().get_ptr<const std::string*>();
374 if (value == nullptr)
375 {
376 messages::propertyValueFormatError(
377 asyncResp->res, item.value().dump(2, 1),
378 "HttpHeaders/" + item.key());
379 return;
380 }
381 subValue->httpHeaders.set(item.key(), *value);
382 }
383 }
384 }
385
386 if (regPrefixes)
387 {
388 for (const std::string& it : *regPrefixes)
389 {
390 if (std::find(supportedRegPrefixes.begin(),
391 supportedRegPrefixes.end(),
392 it) == supportedRegPrefixes.end())
393 {
394 messages::propertyValueNotInList(asyncResp->res, it,
395 "RegistryPrefixes");
P Dheeraj Srujan Kumarb304bd72021-01-29 17:46:35 +0530396 return;
397 }
Ed Tanousfffb8c12022-02-07 23:53:03 -0800398 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700399 subValue->registryPrefixes = *regPrefixes;
400 }
P Dheeraj Srujan Kumarb304bd72021-01-29 17:46:35 +0530401
Ed Tanous002d39b2022-05-31 08:59:27 -0700402 if (resTypes)
403 {
404 for (const std::string& it : *resTypes)
Ed Tanousfffb8c12022-02-07 23:53:03 -0800405 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700406 if (std::find(supportedResourceTypes.begin(),
407 supportedResourceTypes.end(),
408 it) == supportedResourceTypes.end())
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700409 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700410 messages::propertyValueNotInList(asyncResp->res, it,
411 "ResourceTypes");
AppaRao Puli144b6312020-08-03 22:23:12 +0530412 return;
413 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700414 }
415 subValue->resourceTypes = *resTypes;
416 }
417
418 if (msgIds)
419 {
420 std::vector<std::string> registryPrefix;
421
422 // If no registry prefixes are mentioned, consider all
423 // supported prefixes
424 if (subValue->registryPrefixes.empty())
425 {
426 registryPrefix.assign(supportedRegPrefixes.begin(),
427 supportedRegPrefixes.end());
Ed Tanousfffb8c12022-02-07 23:53:03 -0800428 }
429 else
430 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700431 registryPrefix = subValue->registryPrefixes;
Ed Tanousfffb8c12022-02-07 23:53:03 -0800432 }
AppaRao Puli156d6b02020-04-25 06:04:05 +0530433
Ed Tanous002d39b2022-05-31 08:59:27 -0700434 for (const std::string& id : *msgIds)
Ed Tanousfffb8c12022-02-07 23:53:03 -0800435 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700436 bool validId = false;
Ed Tanousfffb8c12022-02-07 23:53:03 -0800437
Ed Tanous002d39b2022-05-31 08:59:27 -0700438 // Check for Message ID in each of the selected Registry
439 for (const std::string& it : registryPrefix)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700440 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700441 const std::span<const redfish::registries::MessageEntry>
442 registry =
443 redfish::registries::getRegistryFromPrefix(it);
444
445 if (std::any_of(
446 registry.begin(), registry.end(),
447 [&id](const redfish::registries::MessageEntry&
448 messageEntry) {
449 return id == messageEntry.first;
450 }))
451 {
452 validId = true;
453 break;
454 }
455 }
456
457 if (!validId)
458 {
459 messages::propertyValueNotInList(asyncResp->res, id,
460 "MessageIds");
Ed Tanousfffb8c12022-02-07 23:53:03 -0800461 return;
462 }
Ed Tanousfffb8c12022-02-07 23:53:03 -0800463 }
464
Ed Tanous002d39b2022-05-31 08:59:27 -0700465 subValue->registryMsgIds = *msgIds;
466 }
467
468 if (retryPolicy)
469 {
470 if (std::find(supportedRetryPolicies.begin(),
471 supportedRetryPolicies.end(),
472 *retryPolicy) == supportedRetryPolicies.end())
Ed Tanousfffb8c12022-02-07 23:53:03 -0800473 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700474 messages::propertyValueNotInList(asyncResp->res, *retryPolicy,
475 "DeliveryRetryPolicy");
Ed Tanousfffb8c12022-02-07 23:53:03 -0800476 return;
477 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700478 subValue->retryPolicy = *retryPolicy;
479 }
480 else
481 {
482 // Default "TerminateAfterRetries"
483 subValue->retryPolicy = "TerminateAfterRetries";
484 }
Ed Tanousfffb8c12022-02-07 23:53:03 -0800485
Ed Tanous002d39b2022-05-31 08:59:27 -0700486 if (mrdJsonArray)
487 {
488 for (nlohmann::json& mrdObj : *mrdJsonArray)
489 {
490 std::string mrdUri;
491
492 if (!json_util::readJson(mrdObj, asyncResp->res, "@odata.id",
493 mrdUri))
494
495 {
496 return;
497 }
498 subValue->metricReportDefinitions.emplace_back(mrdUri);
499 }
500 }
501
502 std::string id =
503 EventServiceManager::getInstance().addSubscription(subValue);
504 if (id.empty())
505 {
506 messages::internalError(asyncResp->res);
507 return;
508 }
509
510 messages::created(asyncResp->res);
511 asyncResp->res.addHeader(
512 "Location", "/redfish/v1/EventService/Subscriptions/" + id);
Ed Tanousfffb8c12022-02-07 23:53:03 -0800513 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700514}
515
516inline void requestRoutesEventDestination(App& app)
AppaRao Pulie5aaf042020-03-20 01:05:52 +0530517{
Ravi Teja9d41aec2021-07-23 01:57:01 -0500518 BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -0700519 .privileges(redfish::privileges::getEventDestination)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700520 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -0700521 [&app](const crow::Request& req,
522 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
523 const std::string& param) {
Carson Labrado3ba00072022-06-06 19:40:56 +0000524 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -0700525 {
526 return;
527 }
528 std::shared_ptr<Subscription> subValue =
529 EventServiceManager::getInstance().getSubscription(param);
530 if (subValue == nullptr)
531 {
532 asyncResp->res.result(boost::beast::http::status::not_found);
533 return;
534 }
535 const std::string& id = param;
AppaRao Pulie5aaf042020-03-20 01:05:52 +0530536
Ed Tanous002d39b2022-05-31 08:59:27 -0700537 asyncResp->res.jsonValue["@odata.type"] =
538 "#EventDestination.v1_7_0.EventDestination";
539 asyncResp->res.jsonValue["Protocol"] = "Redfish";
540 asyncResp->res.jsonValue["@odata.id"] =
541 "/redfish/v1/EventService/Subscriptions/" + id;
542 asyncResp->res.jsonValue["Id"] = id;
543 asyncResp->res.jsonValue["Name"] = "Event Destination " + id;
544 asyncResp->res.jsonValue["Destination"] = subValue->destinationUrl;
545 asyncResp->res.jsonValue["Context"] = subValue->customText;
546 asyncResp->res.jsonValue["SubscriptionType"] =
547 subValue->subscriptionType;
548 asyncResp->res.jsonValue["HttpHeaders"] = nlohmann::json::array();
549 asyncResp->res.jsonValue["EventFormatType"] = subValue->eventFormatType;
550 asyncResp->res.jsonValue["RegistryPrefixes"] =
551 subValue->registryPrefixes;
552 asyncResp->res.jsonValue["ResourceTypes"] = subValue->resourceTypes;
zhanghch058d1b46d2021-04-01 11:18:24 +0800553
Ed Tanous002d39b2022-05-31 08:59:27 -0700554 asyncResp->res.jsonValue["MessageIds"] = subValue->registryMsgIds;
555 asyncResp->res.jsonValue["DeliveryRetryPolicy"] = subValue->retryPolicy;
AppaRao Pulie5aaf042020-03-20 01:05:52 +0530556
Ed Tanous002d39b2022-05-31 08:59:27 -0700557 nlohmann::json::array_t mrdJsonArray;
558 for (const auto& mdrUri : subValue->metricReportDefinitions)
559 {
560 nlohmann::json::object_t mdr;
561 mdr["@odata.id"] = mdrUri;
562 mrdJsonArray.emplace_back(std::move(mdr));
563 }
564 asyncResp->res.jsonValue["MetricReportDefinitions"] = mrdJsonArray;
565 });
Ravi Teja9d41aec2021-07-23 01:57:01 -0500566 BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -0700567 // The below privilege is wrong, it should be ConfigureManager OR
568 // ConfigureSelf
Abhishek Patel7eeafa72021-07-28 10:59:16 -0500569 // https://github.com/openbmc/bmcweb/issues/220
Ed Tanoused398212021-06-09 17:05:54 -0700570 //.privileges(redfish::privileges::patchEventDestination)
Ed Tanous432a8902021-06-14 15:28:56 -0700571 .privileges({{"ConfigureManager"}})
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700572 .methods(boost::beast::http::verb::patch)(
Ed Tanous45ca1b82022-03-25 13:07:27 -0700573 [&app](const crow::Request& req,
574 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
575 const std::string& param) {
Carson Labrado3ba00072022-06-06 19:40:56 +0000576 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -0700577 {
578 return;
579 }
580 std::shared_ptr<Subscription> subValue =
581 EventServiceManager::getInstance().getSubscription(param);
582 if (subValue == nullptr)
583 {
584 asyncResp->res.result(boost::beast::http::status::not_found);
585 return;
586 }
AppaRao Pulie5aaf042020-03-20 01:05:52 +0530587
Ed Tanous002d39b2022-05-31 08:59:27 -0700588 std::optional<std::string> context;
589 std::optional<std::string> retryPolicy;
590 std::optional<std::vector<nlohmann::json>> headers;
Sunitha Harishe56f2542020-07-22 02:38:59 -0500591
Ed Tanous002d39b2022-05-31 08:59:27 -0700592 if (!json_util::readJsonPatch(req, asyncResp->res, "Context", context,
593 "DeliveryRetryPolicy", retryPolicy,
594 "HttpHeaders", headers))
595 {
596 return;
597 }
AppaRao Puli144b6312020-08-03 22:23:12 +0530598
Ed Tanous002d39b2022-05-31 08:59:27 -0700599 if (context)
600 {
601 subValue->customText = *context;
602 }
AppaRao Pulie5aaf042020-03-20 01:05:52 +0530603
Ed Tanous002d39b2022-05-31 08:59:27 -0700604 if (headers)
605 {
606 boost::beast::http::fields fields;
607 for (const nlohmann::json& headerChunk : *headers)
608 {
Patrick Williams62bafc02022-09-08 17:35:35 -0500609 for (const auto& it : headerChunk.items())
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700610 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700611 const std::string* value =
612 it.value().get_ptr<const std::string*>();
613 if (value == nullptr)
Ed Tanous601c71a2021-09-08 16:40:12 -0700614 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700615 messages::propertyValueFormatError(
616 asyncResp->res, it.value().dump(2, ' ', true),
617 "HttpHeaders/" + it.key());
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700618 return;
619 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700620 fields.set(it.key(), *value);
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700621 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700622 }
623 subValue->httpHeaders = fields;
624 }
AppaRao Pulie5aaf042020-03-20 01:05:52 +0530625
Ed Tanous002d39b2022-05-31 08:59:27 -0700626 if (retryPolicy)
627 {
628 if (std::find(supportedRetryPolicies.begin(),
629 supportedRetryPolicies.end(),
630 *retryPolicy) == supportedRetryPolicies.end())
631 {
632 messages::propertyValueNotInList(asyncResp->res, *retryPolicy,
633 "DeliveryRetryPolicy");
634 return;
635 }
636 subValue->retryPolicy = *retryPolicy;
Ed Tanous002d39b2022-05-31 08:59:27 -0700637 }
638
639 EventServiceManager::getInstance().updateSubscriptionData();
640 });
Ravi Teja9d41aec2021-07-23 01:57:01 -0500641 BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -0700642 // The below privilege is wrong, it should be ConfigureManager OR
643 // ConfigureSelf
Abhishek Patel7eeafa72021-07-28 10:59:16 -0500644 // https://github.com/openbmc/bmcweb/issues/220
Ed Tanoused398212021-06-09 17:05:54 -0700645 //.privileges(redfish::privileges::deleteEventDestination)
Ed Tanous432a8902021-06-14 15:28:56 -0700646 .privileges({{"ConfigureManager"}})
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700647 .methods(boost::beast::http::verb::delete_)(
Ed Tanous45ca1b82022-03-25 13:07:27 -0700648 [&app](const crow::Request& req,
649 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
650 const std::string& param) {
Carson Labrado3ba00072022-06-06 19:40:56 +0000651 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -0700652 {
653 return;
654 }
655 if (!EventServiceManager::getInstance().isSubscriptionExist(param))
656 {
657 asyncResp->res.result(boost::beast::http::status::not_found);
658 return;
659 }
660 EventServiceManager::getInstance().deleteSubscription(param);
661 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700662}
AppaRao Pulie5aaf042020-03-20 01:05:52 +0530663
664} // namespace redfish