140e9b92eSEd Tanous // SPDX-License-Identifier: Apache-2.0 240e9b92eSEd Tanous // SPDX-FileCopyrightText: Copyright OpenBMC Authors 340e9b92eSEd Tanous // SPDX-FileCopyrightText: Copyright 2020 Intel Corporation 4e5aaf047SAppaRao Puli #pragma once 53ccb3adbSEd Tanous #include "app.hpp" 6*d7857201SEd Tanous #include "async_resp.hpp" 7*d7857201SEd Tanous #include "dbus_singleton.hpp" 8*d7857201SEd Tanous #include "dbus_utility.hpp" 9*d7857201SEd Tanous #include "error_messages.hpp" 10b52664e2SAppaRao Puli #include "event_service_manager.hpp" 11*d7857201SEd Tanous #include "event_service_store.hpp" 12*d7857201SEd Tanous #include "generated/enums/event_destination.hpp" 133ccb3adbSEd Tanous #include "http/utility.hpp" 14*d7857201SEd Tanous #include "http_request.hpp" 153ccb3adbSEd Tanous #include "logging.hpp" 163ccb3adbSEd Tanous #include "query.hpp" 17d109e2b6SAlexander Hansen #include "registries.hpp" 183ccb3adbSEd Tanous #include "registries/privilege_registry.hpp" 19d109e2b6SAlexander Hansen #include "registries_selector.hpp" 203d30708fSChicago Duan #include "snmp_trap_event_clients.hpp" 21*d7857201SEd Tanous #include "subscription.hpp" 22d109e2b6SAlexander Hansen #include "utils/json_utils.hpp" 23e5aaf047SAppaRao Puli 24*d7857201SEd Tanous #include <asm-generic/errno.h> 25ed398213SEd Tanous 26*d7857201SEd Tanous #include <boost/beast/http/fields.hpp> 27*d7857201SEd Tanous #include <boost/beast/http/status.hpp> 28*d7857201SEd Tanous #include <boost/beast/http/verb.hpp> 29*d7857201SEd Tanous #include <boost/system/error_code.hpp> 30*d7857201SEd Tanous #include <boost/system/result.hpp> 31*d7857201SEd Tanous #include <boost/url/format.hpp> 32*d7857201SEd Tanous #include <boost/url/parse.hpp> 33*d7857201SEd Tanous #include <boost/url/url.hpp> 34*d7857201SEd Tanous #include <sdbusplus/message/native_types.hpp> 35*d7857201SEd Tanous 36*d7857201SEd Tanous #include <algorithm> 37*d7857201SEd Tanous #include <array> 38*d7857201SEd Tanous #include <cerrno> 39*d7857201SEd Tanous #include <cstddef> 40*d7857201SEd Tanous #include <cstdint> 413d30708fSChicago Duan #include <memory> 425064a25bSMyung Bae #include <optional> 433544d2a7SEd Tanous #include <ranges> 441e270c5fSPatrick Williams #include <span> 453d30708fSChicago Duan #include <string> 46*d7857201SEd Tanous #include <utility> 47a14c9113SEd Tanous #include <vector> 481e270c5fSPatrick Williams 49e5aaf047SAppaRao Puli namespace redfish 50e5aaf047SAppaRao Puli { 51e5aaf047SAppaRao Puli 52156d6b00SAppaRao Puli static constexpr const std::array<const char*, 2> supportedEvtFormatTypes = { 53156d6b00SAppaRao Puli eventFormatType, metricReportFormatType}; 54fb546105SMyung Bae static constexpr const std::array<const char*, 4> supportedRegPrefixes = { 55fb546105SMyung Bae "Base", "OpenBMC", "TaskEvent", "HeartbeatEvent"}; 56e5aaf047SAppaRao Puli static constexpr const std::array<const char*, 3> supportedRetryPolicies = { 57e5aaf047SAppaRao Puli "TerminateAfterRetries", "SuspendRetries", "RetryForever"}; 58e5aaf047SAppaRao Puli 59fb546105SMyung Bae static constexpr const std::array<const char*, 2> supportedResourceTypes = { 60fb546105SMyung Bae "Task", "Heartbeat"}; 61e56f254cSSunitha Harish 627e860f15SJohn Edward Broadbent inline void requestRoutesEventService(App& app) 63e5aaf047SAppaRao Puli { 647e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, "/redfish/v1/EventService/") 65ed398213SEd Tanous .privileges(redfish::privileges::getEventService) 66bd79bce8SPatrick Williams .methods( 67bd79bce8SPatrick Williams boost::beast::http::verb:: 68bd79bce8SPatrick Williams get)([&app]( 69bd79bce8SPatrick Williams const crow::Request& req, 70002d39b4SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 713ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 7245ca1b86SEd Tanous { 7345ca1b86SEd Tanous return; 7445ca1b86SEd Tanous } 751476687dSEd Tanous 761476687dSEd Tanous asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/EventService"; 771476687dSEd Tanous asyncResp->res.jsonValue["@odata.type"] = 781476687dSEd Tanous "#EventService.v1_5_0.EventService"; 791476687dSEd Tanous asyncResp->res.jsonValue["Id"] = "EventService"; 801476687dSEd Tanous asyncResp->res.jsonValue["Name"] = "Event Service"; 815e44e3d8SAppaRao Puli asyncResp->res.jsonValue["ServerSentEventUri"] = 825e44e3d8SAppaRao Puli "/redfish/v1/EventService/SSE"; 835e44e3d8SAppaRao Puli 841476687dSEd Tanous asyncResp->res.jsonValue["Subscriptions"]["@odata.id"] = 851476687dSEd Tanous "/redfish/v1/EventService/Subscriptions"; 86bd79bce8SPatrick Williams asyncResp->res.jsonValue["Actions"]["#EventService.SubmitTestEvent"] 87bd79bce8SPatrick Williams ["target"] = 881476687dSEd Tanous "/redfish/v1/EventService/Actions/EventService.SubmitTestEvent"; 89e5aaf047SAppaRao Puli 9028afb49cSJunLin Chen const persistent_data::EventServiceConfig eventServiceConfig = 9128afb49cSJunLin Chen persistent_data::EventServiceStore::getInstance() 9228afb49cSJunLin Chen .getEventServiceConfig(); 937d1cc387SAppaRao Puli 947d1cc387SAppaRao Puli asyncResp->res.jsonValue["Status"]["State"] = 9528afb49cSJunLin Chen (eventServiceConfig.enabled ? "Enabled" : "Disabled"); 96bd79bce8SPatrick Williams asyncResp->res.jsonValue["ServiceEnabled"] = 97bd79bce8SPatrick Williams eventServiceConfig.enabled; 987e860f15SJohn Edward Broadbent asyncResp->res.jsonValue["DeliveryRetryAttempts"] = 9928afb49cSJunLin Chen eventServiceConfig.retryAttempts; 100e5aaf047SAppaRao Puli asyncResp->res.jsonValue["DeliveryRetryIntervalSeconds"] = 10128afb49cSJunLin Chen eventServiceConfig.retryTimeoutInterval; 102bd79bce8SPatrick Williams asyncResp->res.jsonValue["EventFormatTypes"] = 103bd79bce8SPatrick Williams supportedEvtFormatTypes; 1040fda0f12SGeorge Liu asyncResp->res.jsonValue["RegistryPrefixes"] = supportedRegPrefixes; 1050fda0f12SGeorge Liu asyncResp->res.jsonValue["ResourceTypes"] = supportedResourceTypes; 10607941a88SAyushi Smriti 107613dabeaSEd Tanous nlohmann::json::object_t supportedSSEFilters; 108613dabeaSEd Tanous supportedSSEFilters["EventFormatType"] = true; 109613dabeaSEd Tanous supportedSSEFilters["MessageId"] = true; 110613dabeaSEd Tanous supportedSSEFilters["MetricReportDefinition"] = true; 111613dabeaSEd Tanous supportedSSEFilters["RegistryPrefix"] = true; 112613dabeaSEd Tanous supportedSSEFilters["OriginResource"] = false; 113613dabeaSEd Tanous supportedSSEFilters["ResourceType"] = false; 11407941a88SAyushi Smriti 11507941a88SAyushi Smriti asyncResp->res.jsonValue["SSEFilterPropertiesSupported"] = 116613dabeaSEd Tanous std::move(supportedSSEFilters); 1177e860f15SJohn Edward Broadbent }); 118e5aaf047SAppaRao Puli 1197e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, "/redfish/v1/EventService/") 120ed398213SEd Tanous .privileges(redfish::privileges::patchEventService) 1217e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::patch)( 12245ca1b86SEd Tanous [&app](const crow::Request& req, 12345ca1b86SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 1243ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 125e5aaf047SAppaRao Puli { 12645ca1b86SEd Tanous return; 12745ca1b86SEd Tanous } 128e5aaf047SAppaRao Puli std::optional<bool> serviceEnabled; 129e5aaf047SAppaRao Puli std::optional<uint32_t> retryAttemps; 130e5aaf047SAppaRao Puli std::optional<uint32_t> retryInterval; 131afc474aeSMyung Bae if (!json_util::readJsonPatch( // 132afc474aeSMyung Bae req, asyncResp->res, // 133afc474aeSMyung Bae "DeliveryRetryAttempts", retryAttemps, // 134afc474aeSMyung Bae "DeliveryRetryIntervalSeconds", retryInterval, // 135afc474aeSMyung Bae "ServiceEnabled", serviceEnabled // 136afc474aeSMyung Bae )) 137e5aaf047SAppaRao Puli { 138e5aaf047SAppaRao Puli return; 139e5aaf047SAppaRao Puli } 140e5aaf047SAppaRao Puli 14128afb49cSJunLin Chen persistent_data::EventServiceConfig eventServiceConfig = 14228afb49cSJunLin Chen persistent_data::EventServiceStore::getInstance() 14328afb49cSJunLin Chen .getEventServiceConfig(); 1447d1cc387SAppaRao Puli 145e5aaf047SAppaRao Puli if (serviceEnabled) 146e5aaf047SAppaRao Puli { 14728afb49cSJunLin Chen eventServiceConfig.enabled = *serviceEnabled; 148e5aaf047SAppaRao Puli } 149e5aaf047SAppaRao Puli 150e5aaf047SAppaRao Puli if (retryAttemps) 151e5aaf047SAppaRao Puli { 152e5aaf047SAppaRao Puli // Supported range [1-3] 153e5aaf047SAppaRao Puli if ((*retryAttemps < 1) || (*retryAttemps > 3)) 154e5aaf047SAppaRao Puli { 155e5aaf047SAppaRao Puli messages::queryParameterOutOfRange( 156e5aaf047SAppaRao Puli asyncResp->res, std::to_string(*retryAttemps), 157e5aaf047SAppaRao Puli "DeliveryRetryAttempts", "[1-3]"); 158e5aaf047SAppaRao Puli } 159e5aaf047SAppaRao Puli else 160e5aaf047SAppaRao Puli { 16128afb49cSJunLin Chen eventServiceConfig.retryAttempts = *retryAttemps; 162e5aaf047SAppaRao Puli } 163e5aaf047SAppaRao Puli } 164e5aaf047SAppaRao Puli 165e5aaf047SAppaRao Puli if (retryInterval) 166e5aaf047SAppaRao Puli { 16733a32b34SGunnar Mills // Supported range [5 - 180] 16833a32b34SGunnar Mills if ((*retryInterval < 5) || (*retryInterval > 180)) 169e5aaf047SAppaRao Puli { 170e5aaf047SAppaRao Puli messages::queryParameterOutOfRange( 171e5aaf047SAppaRao Puli asyncResp->res, std::to_string(*retryInterval), 17233a32b34SGunnar Mills "DeliveryRetryIntervalSeconds", "[5-180]"); 173e5aaf047SAppaRao Puli } 174e5aaf047SAppaRao Puli else 175e5aaf047SAppaRao Puli { 176bd79bce8SPatrick Williams eventServiceConfig.retryTimeoutInterval = 177bd79bce8SPatrick Williams *retryInterval; 178e5aaf047SAppaRao Puli } 179e5aaf047SAppaRao Puli } 180e5aaf047SAppaRao Puli 1817d1cc387SAppaRao Puli EventServiceManager::getInstance().setEventServiceConfig( 18228afb49cSJunLin Chen eventServiceConfig); 1837e860f15SJohn Edward Broadbent }); 1840b4bdd93SAppaRao Puli } 1850b4bdd93SAppaRao Puli 1867e860f15SJohn Edward Broadbent inline void requestRoutesSubmitTestEvent(App& app) 1870b4bdd93SAppaRao Puli { 1887e860f15SJohn Edward Broadbent BMCWEB_ROUTE( 1897e860f15SJohn Edward Broadbent app, "/redfish/v1/EventService/Actions/EventService.SubmitTestEvent/") 190ed398213SEd Tanous .privileges(redfish::privileges::postEventService) 1917e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::post)( 19245ca1b86SEd Tanous [&app](const crow::Request& req, 1937e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 1943ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 19545ca1b86SEd Tanous { 19645ca1b86SEd Tanous return; 19745ca1b86SEd Tanous } 19881ee0e74SChandramohan Harkude 19981ee0e74SChandramohan Harkude TestEvent testEvent; 20081ee0e74SChandramohan Harkude // clang-format off 20181ee0e74SChandramohan Harkude if (!json_util::readJsonAction( 20281ee0e74SChandramohan Harkude req, asyncResp->res, 20381ee0e74SChandramohan Harkude "EventGroupId", testEvent.eventGroupId, 20481ee0e74SChandramohan Harkude "EventId", testEvent.eventId, 20581ee0e74SChandramohan Harkude "EventTimestamp", testEvent.eventTimestamp, 20681ee0e74SChandramohan Harkude "Message", testEvent.message, 20781ee0e74SChandramohan Harkude "MessageArgs", testEvent.messageArgs, 20881ee0e74SChandramohan Harkude "MessageId", testEvent.messageId, 20981ee0e74SChandramohan Harkude "OriginOfCondition", testEvent.originOfCondition, 21081ee0e74SChandramohan Harkude "Resolution", testEvent.resolution, 21181ee0e74SChandramohan Harkude "Severity", testEvent.severity)) 21281ee0e74SChandramohan Harkude { 21381ee0e74SChandramohan Harkude return; 21481ee0e74SChandramohan Harkude } 21581ee0e74SChandramohan Harkude // clang-format on 21681ee0e74SChandramohan Harkude 21781ee0e74SChandramohan Harkude if (!EventServiceManager::getInstance().sendTestEventLog( 21881ee0e74SChandramohan Harkude testEvent)) 2196ba8c82eSsunharis_in { 2206ba8c82eSsunharis_in messages::serviceDisabled(asyncResp->res, 2216ba8c82eSsunharis_in "/redfish/v1/EventService/"); 2226ba8c82eSsunharis_in return; 2236ba8c82eSsunharis_in } 2248d1b46d7Szhanghch05 asyncResp->res.result(boost::beast::http::status::no_content); 2257e860f15SJohn Edward Broadbent }); 226e5aaf047SAppaRao Puli } 227e5aaf047SAppaRao Puli 2283d30708fSChicago Duan inline void doSubscriptionCollection( 229e81de512SEd Tanous const boost::system::error_code& ec, 2303d30708fSChicago Duan const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2313d30708fSChicago Duan const dbus::utility::ManagedObjectType& resp) 2323d30708fSChicago Duan { 2333d30708fSChicago Duan if (ec) 2343d30708fSChicago Duan { 2351306101eSEd Tanous if (ec.value() == EBADR || ec.value() == EHOSTUNREACH) 2363d30708fSChicago Duan { 2373d30708fSChicago Duan // This is an optional process so just return if it isn't there 2383d30708fSChicago Duan return; 2393d30708fSChicago Duan } 2403d30708fSChicago Duan 24162598e31SEd Tanous BMCWEB_LOG_ERROR("D-Bus response error on GetManagedObjects {}", ec); 2423d30708fSChicago Duan messages::internalError(asyncResp->res); 2433d30708fSChicago Duan return; 2443d30708fSChicago Duan } 2453d30708fSChicago Duan nlohmann::json& memberArray = asyncResp->res.jsonValue["Members"]; 2463d30708fSChicago Duan for (const auto& objpath : resp) 2473d30708fSChicago Duan { 2483d30708fSChicago Duan sdbusplus::message::object_path path(objpath.first); 2493d30708fSChicago Duan const std::string snmpId = path.filename(); 2503d30708fSChicago Duan if (snmpId.empty()) 2513d30708fSChicago Duan { 25262598e31SEd Tanous BMCWEB_LOG_ERROR("The SNMP client ID is wrong"); 2533d30708fSChicago Duan messages::internalError(asyncResp->res); 2543d30708fSChicago Duan return; 2553d30708fSChicago Duan } 2563d30708fSChicago Duan 2573d30708fSChicago Duan getSnmpSubscriptionList(asyncResp, snmpId, memberArray); 2583d30708fSChicago Duan } 2593d30708fSChicago Duan } 2603d30708fSChicago Duan 2617e860f15SJohn Edward Broadbent inline void requestRoutesEventDestinationCollection(App& app) 262e5aaf047SAppaRao Puli { 2631ebe3e41SGayathri Leburu BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/") 264ed398213SEd Tanous .privileges(redfish::privileges::getEventDestinationCollection) 2657e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 26645ca1b86SEd Tanous [&app](const crow::Request& req, 2677e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 2683ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 26945ca1b86SEd Tanous { 27045ca1b86SEd Tanous return; 27145ca1b86SEd Tanous } 2721476687dSEd Tanous asyncResp->res.jsonValue["@odata.type"] = 2731476687dSEd Tanous "#EventDestinationCollection.EventDestinationCollection"; 2741476687dSEd Tanous asyncResp->res.jsonValue["@odata.id"] = 2751476687dSEd Tanous "/redfish/v1/EventService/Subscriptions"; 276bd79bce8SPatrick Williams asyncResp->res.jsonValue["Name"] = 277bd79bce8SPatrick Williams "Event Destination Collections"; 278e5aaf047SAppaRao Puli 279bd79bce8SPatrick Williams nlohmann::json& memberArray = 280bd79bce8SPatrick Williams asyncResp->res.jsonValue["Members"]; 281e5aaf047SAppaRao Puli 282b52664e2SAppaRao Puli std::vector<std::string> subscripIds = 283b52664e2SAppaRao Puli EventServiceManager::getInstance().getAllIDs(); 284b52664e2SAppaRao Puli memberArray = nlohmann::json::array(); 285bd79bce8SPatrick Williams asyncResp->res.jsonValue["Members@odata.count"] = 286bd79bce8SPatrick Williams subscripIds.size(); 287b52664e2SAppaRao Puli 288b52664e2SAppaRao Puli for (const std::string& id : subscripIds) 289e5aaf047SAppaRao Puli { 2901476687dSEd Tanous nlohmann::json::object_t member; 2913d30708fSChicago Duan member["@odata.id"] = boost::urls::format( 2923d30708fSChicago Duan "/redfish/v1/EventService/Subscriptions/{}" + id); 293b2ba3072SPatrick Williams memberArray.emplace_back(std::move(member)); 294e5aaf047SAppaRao Puli } 2953d30708fSChicago Duan crow::connections::systemBus->async_method_call( 296e81de512SEd Tanous [asyncResp](const boost::system::error_code& ec, 2973d30708fSChicago Duan const dbus::utility::ManagedObjectType& resp) { 2983d30708fSChicago Duan doSubscriptionCollection(ec, asyncResp, resp); 2993d30708fSChicago Duan }, 3003d30708fSChicago Duan "xyz.openbmc_project.Network.SNMP", 3013d30708fSChicago Duan "/xyz/openbmc_project/network/snmp/manager", 3023d30708fSChicago Duan "org.freedesktop.DBus.ObjectManager", "GetManagedObjects"); 3037e860f15SJohn Edward Broadbent }); 3043d30708fSChicago Duan 3057e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/") 3067eeafa76SAbhishek Patel .privileges(redfish::privileges::postEventDestinationCollection) 307bd79bce8SPatrick Williams .methods( 308bd79bce8SPatrick Williams boost::beast::http::verb:: 309bd79bce8SPatrick Williams post)([&app]( 310bd79bce8SPatrick Williams const crow::Request& req, 3117e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 3123ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 31345ca1b86SEd Tanous { 31445ca1b86SEd Tanous return; 31545ca1b86SEd Tanous } 316fffb8c1fSEd Tanous if (EventServiceManager::getInstance().getNumberOfSubscriptions() >= 317fffb8c1fSEd Tanous maxNoOfSubscriptions) 318e5aaf047SAppaRao Puli { 319e5aaf047SAppaRao Puli messages::eventSubscriptionLimitExceeded(asyncResp->res); 320e5aaf047SAppaRao Puli return; 321e5aaf047SAppaRao Puli } 322e5aaf047SAppaRao Puli std::string destUrl; 323e5aaf047SAppaRao Puli std::string protocol; 32419bb362bSEd Tanous std::optional<bool> verifyCertificate; 325e5aaf047SAppaRao Puli std::optional<std::string> context; 326e5aaf047SAppaRao Puli std::optional<std::string> subscriptionType; 32723a21a1cSEd Tanous std::optional<std::string> eventFormatType2; 328e5aaf047SAppaRao Puli std::optional<std::string> retryPolicy; 3295064a25bSMyung Bae std::optional<bool> sendHeartbeat; 3305064a25bSMyung Bae std::optional<uint64_t> hbIntervalMinutes; 331e5aaf047SAppaRao Puli std::optional<std::vector<std::string>> msgIds; 332e5aaf047SAppaRao Puli std::optional<std::vector<std::string>> regPrefixes; 333a14c9113SEd Tanous std::optional<std::vector<std::string>> originResources; 334e56f254cSSunitha Harish std::optional<std::vector<std::string>> resTypes; 33578d4ec4fSEd Tanous std::optional<std::vector<nlohmann::json::object_t>> headers; 33678d4ec4fSEd Tanous std::optional<std::vector<nlohmann::json::object_t>> mrdJsonArray; 337e5aaf047SAppaRao Puli 338afc474aeSMyung Bae if (!json_util::readJsonPatch( // 339afc474aeSMyung Bae req, asyncResp->res, // 340afc474aeSMyung Bae "Context", context, // 341afc474aeSMyung Bae "DeliveryRetryPolicy", retryPolicy, // 342afc474aeSMyung Bae "Destination", destUrl, // 343afc474aeSMyung Bae "EventFormatType", eventFormatType2, // 3445064a25bSMyung Bae "HeartbeatIntervalMinutes", hbIntervalMinutes, // 345afc474aeSMyung Bae "HttpHeaders", headers, // 346afc474aeSMyung Bae "MessageIds", msgIds, // 347afc474aeSMyung Bae "MetricReportDefinitions", mrdJsonArray, // 348afc474aeSMyung Bae "OriginResources", originResources, // 349afc474aeSMyung Bae "Protocol", protocol, // 350afc474aeSMyung Bae "RegistryPrefixes", regPrefixes, // 351afc474aeSMyung Bae "ResourceTypes", resTypes, // 3525064a25bSMyung Bae "SendHeartbeat", sendHeartbeat, // 353afc474aeSMyung Bae "SubscriptionType", subscriptionType, // 354afc474aeSMyung Bae "VerifyCertificate", verifyCertificate // 3554b712a29SEd Tanous )) 356e5aaf047SAppaRao Puli { 357e5aaf047SAppaRao Puli return; 358e5aaf047SAppaRao Puli } 3594b712a29SEd Tanous // clang-format on 360e5aaf047SAppaRao Puli 361600af5f1SAppaRao Puli // https://stackoverflow.com/questions/417142/what-is-the-maximum-length-of-a-url-in-different-browsers 362600af5f1SAppaRao Puli static constexpr const uint16_t maxDestinationSize = 2000; 363600af5f1SAppaRao Puli if (destUrl.size() > maxDestinationSize) 364600af5f1SAppaRao Puli { 365600af5f1SAppaRao Puli messages::stringValueTooLong(asyncResp->res, "Destination", 366600af5f1SAppaRao Puli maxDestinationSize); 367600af5f1SAppaRao Puli return; 368600af5f1SAppaRao Puli } 369600af5f1SAppaRao Puli 370dd28ba82SAppaRao Puli if (regPrefixes && msgIds) 371dd28ba82SAppaRao Puli { 37226f6976fSEd Tanous if (!regPrefixes->empty() && !msgIds->empty()) 373dd28ba82SAppaRao Puli { 374bd79bce8SPatrick Williams messages::propertyValueConflict( 375bd79bce8SPatrick Williams asyncResp->res, "MessageIds", "RegistryPrefixes"); 376dd28ba82SAppaRao Puli return; 377dd28ba82SAppaRao Puli } 378dd28ba82SAppaRao Puli } 379dd28ba82SAppaRao Puli 3806fd29553SEd Tanous boost::system::result<boost::urls::url> url = 381a716aa74SEd Tanous boost::urls::parse_absolute_uri(destUrl); 382a716aa74SEd Tanous if (!url) 383e5aaf047SAppaRao Puli { 384bd79bce8SPatrick Williams BMCWEB_LOG_WARNING( 385bd79bce8SPatrick Williams "Failed to validate and split destination url"); 386e5aaf047SAppaRao Puli messages::propertyValueFormatError(asyncResp->res, destUrl, 387e5aaf047SAppaRao Puli "Destination"); 388e5aaf047SAppaRao Puli return; 389e5aaf047SAppaRao Puli } 390a716aa74SEd Tanous url->normalize(); 391b07942e3SGeorge Liu 392b07942e3SGeorge Liu // port_number returns zero if it is not a valid representable port 393b07942e3SGeorge Liu if (url->has_port() && url->port_number() == 0) 394b07942e3SGeorge Liu { 395b07942e3SGeorge Liu BMCWEB_LOG_WARNING("{} is an invalid port in destination url", 396b07942e3SGeorge Liu url->port()); 397b07942e3SGeorge Liu messages::propertyValueFormatError(asyncResp->res, destUrl, 398b07942e3SGeorge Liu "Destination"); 399b07942e3SGeorge Liu return; 400b07942e3SGeorge Liu } 401b07942e3SGeorge Liu 402a716aa74SEd Tanous crow::utility::setProtocolDefaults(*url, protocol); 403a716aa74SEd Tanous crow::utility::setPortDefaults(*url); 404a716aa74SEd Tanous 405a716aa74SEd Tanous if (url->path().empty()) 406a716aa74SEd Tanous { 407a716aa74SEd Tanous url->set_path("/"); 408a716aa74SEd Tanous } 409a716aa74SEd Tanous 410a716aa74SEd Tanous if (url->has_userinfo()) 411a716aa74SEd Tanous { 412a716aa74SEd Tanous messages::propertyValueFormatError(asyncResp->res, destUrl, 413a716aa74SEd Tanous "Destination"); 414a716aa74SEd Tanous return; 415a716aa74SEd Tanous } 416b52664e2SAppaRao Puli 4173d30708fSChicago Duan if (protocol == "SNMPv2c") 4183d30708fSChicago Duan { 4193d30708fSChicago Duan if (context) 4203d30708fSChicago Duan { 4213d30708fSChicago Duan messages::propertyValueConflict(asyncResp->res, "Context", 4223d30708fSChicago Duan "Protocol"); 4233d30708fSChicago Duan return; 4243d30708fSChicago Duan } 4253d30708fSChicago Duan if (eventFormatType2) 4263d30708fSChicago Duan { 427bd79bce8SPatrick Williams messages::propertyValueConflict( 428bd79bce8SPatrick Williams asyncResp->res, "EventFormatType", "Protocol"); 4293d30708fSChicago Duan return; 4303d30708fSChicago Duan } 4313d30708fSChicago Duan if (retryPolicy) 4323d30708fSChicago Duan { 433bd79bce8SPatrick Williams messages::propertyValueConflict(asyncResp->res, 434bd79bce8SPatrick Williams "RetryPolicy", "Protocol"); 4353d30708fSChicago Duan return; 4363d30708fSChicago Duan } 4375064a25bSMyung Bae if (sendHeartbeat) 4385064a25bSMyung Bae { 4395064a25bSMyung Bae messages::propertyValueConflict( 4405064a25bSMyung Bae asyncResp->res, "SendHeartbeat", "Protocol"); 4415064a25bSMyung Bae return; 4425064a25bSMyung Bae } 4435064a25bSMyung Bae if (hbIntervalMinutes) 4445064a25bSMyung Bae { 4455064a25bSMyung Bae messages::propertyValueConflict( 4465064a25bSMyung Bae asyncResp->res, "HeartbeatIntervalMinutes", "Protocol"); 4475064a25bSMyung Bae return; 4485064a25bSMyung Bae } 4493d30708fSChicago Duan if (msgIds) 4503d30708fSChicago Duan { 451bd79bce8SPatrick Williams messages::propertyValueConflict(asyncResp->res, 452bd79bce8SPatrick Williams "MessageIds", "Protocol"); 4533d30708fSChicago Duan return; 4543d30708fSChicago Duan } 4553d30708fSChicago Duan if (regPrefixes) 4563d30708fSChicago Duan { 457bd79bce8SPatrick Williams messages::propertyValueConflict( 458bd79bce8SPatrick Williams asyncResp->res, "RegistryPrefixes", "Protocol"); 4593d30708fSChicago Duan return; 4603d30708fSChicago Duan } 4613d30708fSChicago Duan if (resTypes) 4623d30708fSChicago Duan { 463bd79bce8SPatrick Williams messages::propertyValueConflict( 464bd79bce8SPatrick Williams asyncResp->res, "ResourceTypes", "Protocol"); 4653d30708fSChicago Duan return; 4663d30708fSChicago Duan } 4673d30708fSChicago Duan if (headers) 4683d30708fSChicago Duan { 469bd79bce8SPatrick Williams messages::propertyValueConflict(asyncResp->res, 470bd79bce8SPatrick Williams "HttpHeaders", "Protocol"); 4713d30708fSChicago Duan return; 4723d30708fSChicago Duan } 4733d30708fSChicago Duan if (mrdJsonArray) 4743d30708fSChicago Duan { 4753d30708fSChicago Duan messages::propertyValueConflict( 4763d30708fSChicago Duan asyncResp->res, "MetricReportDefinitions", "Protocol"); 4773d30708fSChicago Duan return; 4783d30708fSChicago Duan } 479a716aa74SEd Tanous if (url->scheme() != "snmp") 480a716aa74SEd Tanous { 481bd79bce8SPatrick Williams messages::propertyValueConflict(asyncResp->res, 482bd79bce8SPatrick Williams "Destination", "Protocol"); 4833d30708fSChicago Duan return; 4843d30708fSChicago Duan } 4853d30708fSChicago Duan 486a716aa74SEd Tanous addSnmpTrapClient(asyncResp, url->host_address(), 487a716aa74SEd Tanous url->port_number()); 488a716aa74SEd Tanous return; 489b52664e2SAppaRao Puli } 4903d30708fSChicago Duan 491a716aa74SEd Tanous std::shared_ptr<Subscription> subValue = 49221a94d5cSMyung Bae std::make_shared<Subscription>( 4935fe4ef35SMyung Bae std::make_shared<persistent_data::UserSubscription>(), *url, 4945fe4ef35SMyung Bae app.ioContext()); 495e5aaf047SAppaRao Puli 496e5aaf047SAppaRao Puli if (subscriptionType) 497e5aaf047SAppaRao Puli { 498e5aaf047SAppaRao Puli if (*subscriptionType != "RedfishEvent") 499e5aaf047SAppaRao Puli { 500fffb8c1fSEd Tanous messages::propertyValueNotInList( 501fffb8c1fSEd Tanous asyncResp->res, *subscriptionType, "SubscriptionType"); 502e5aaf047SAppaRao Puli return; 503e5aaf047SAppaRao Puli } 5045fe4ef35SMyung Bae subValue->userSub->subscriptionType = *subscriptionType; 505e5aaf047SAppaRao Puli } 506e5aaf047SAppaRao Puli else 507e5aaf047SAppaRao Puli { 5084b712a29SEd Tanous // Default 5095fe4ef35SMyung Bae subValue->userSub->subscriptionType = "RedfishEvent"; 510e5aaf047SAppaRao Puli } 511e5aaf047SAppaRao Puli 512e5aaf047SAppaRao Puli if (protocol != "Redfish") 513e5aaf047SAppaRao Puli { 514e5aaf047SAppaRao Puli messages::propertyValueNotInList(asyncResp->res, protocol, 515e5aaf047SAppaRao Puli "Protocol"); 516e5aaf047SAppaRao Puli return; 517e5aaf047SAppaRao Puli } 5185fe4ef35SMyung Bae subValue->userSub->protocol = protocol; 519e5aaf047SAppaRao Puli 52019bb362bSEd Tanous if (verifyCertificate) 52119bb362bSEd Tanous { 5225fe4ef35SMyung Bae subValue->userSub->verifyCertificate = *verifyCertificate; 52319bb362bSEd Tanous } 52419bb362bSEd Tanous 52523a21a1cSEd Tanous if (eventFormatType2) 526e5aaf047SAppaRao Puli { 527bd79bce8SPatrick Williams if (std::ranges::find(supportedEvtFormatTypes, 528bd79bce8SPatrick Williams *eventFormatType2) == 5293544d2a7SEd Tanous supportedEvtFormatTypes.end()) 530e5aaf047SAppaRao Puli { 531fffb8c1fSEd Tanous messages::propertyValueNotInList( 532fffb8c1fSEd Tanous asyncResp->res, *eventFormatType2, "EventFormatType"); 533e5aaf047SAppaRao Puli return; 534e5aaf047SAppaRao Puli } 5355fe4ef35SMyung Bae subValue->userSub->eventFormatType = *eventFormatType2; 536e5aaf047SAppaRao Puli } 537e5aaf047SAppaRao Puli else 538e5aaf047SAppaRao Puli { 539e5aaf047SAppaRao Puli // If not specified, use default "Event" 5405fe4ef35SMyung Bae subValue->userSub->eventFormatType = "Event"; 541e5aaf047SAppaRao Puli } 542e5aaf047SAppaRao Puli 543e5aaf047SAppaRao Puli if (context) 544e5aaf047SAppaRao Puli { 5458ece0e45SEd Tanous // This value is selected arbitrarily. 546600af5f1SAppaRao Puli constexpr const size_t maxContextSize = 256; 547600af5f1SAppaRao Puli if (context->size() > maxContextSize) 548600af5f1SAppaRao Puli { 549600af5f1SAppaRao Puli messages::stringValueTooLong(asyncResp->res, "Context", 550600af5f1SAppaRao Puli maxContextSize); 551600af5f1SAppaRao Puli return; 552600af5f1SAppaRao Puli } 5535fe4ef35SMyung Bae subValue->userSub->customText = *context; 554e5aaf047SAppaRao Puli } 555e5aaf047SAppaRao Puli 556e5aaf047SAppaRao Puli if (headers) 557e5aaf047SAppaRao Puli { 558600af5f1SAppaRao Puli size_t cumulativeLen = 0; 559600af5f1SAppaRao Puli 56078d4ec4fSEd Tanous for (const nlohmann::json::object_t& headerChunk : *headers) 561601c71aeSEd Tanous { 56278d4ec4fSEd Tanous for (const auto& item : headerChunk) 56378d4ec4fSEd Tanous { 56478d4ec4fSEd Tanous const std::string* value = 56578d4ec4fSEd Tanous item.second.get_ptr<const std::string*>(); 56678d4ec4fSEd Tanous if (value == nullptr) 56778d4ec4fSEd Tanous { 56878d4ec4fSEd Tanous messages::propertyValueFormatError( 56978d4ec4fSEd Tanous asyncResp->res, item.second, 57078d4ec4fSEd Tanous "HttpHeaders/" + item.first); 57178d4ec4fSEd Tanous return; 57278d4ec4fSEd Tanous } 57378d4ec4fSEd Tanous // Adding a new json value is the size of the key, + 57478d4ec4fSEd Tanous // the size of the value + 2 * 2 quotes for each, + 57578d4ec4fSEd Tanous // the colon and space between. example: 57678d4ec4fSEd Tanous // "key": "value" 57778d4ec4fSEd Tanous cumulativeLen += item.first.size() + value->size() + 6; 578600af5f1SAppaRao Puli // This value is selected to mirror http_connection.hpp 579600af5f1SAppaRao Puli constexpr const uint16_t maxHeaderSizeED = 8096; 580600af5f1SAppaRao Puli if (cumulativeLen > maxHeaderSizeED) 581600af5f1SAppaRao Puli { 58278d4ec4fSEd Tanous messages::arraySizeTooLong( 58378d4ec4fSEd Tanous asyncResp->res, "HttpHeaders", maxHeaderSizeED); 584600af5f1SAppaRao Puli return; 585600af5f1SAppaRao Puli } 5865fe4ef35SMyung Bae subValue->userSub->httpHeaders.set(item.first, *value); 587601c71aeSEd Tanous } 588601c71aeSEd Tanous } 589e5aaf047SAppaRao Puli } 590e5aaf047SAppaRao Puli 591e5aaf047SAppaRao Puli if (regPrefixes) 592e5aaf047SAppaRao Puli { 593e5aaf047SAppaRao Puli for (const std::string& it : *regPrefixes) 594e5aaf047SAppaRao Puli { 5953544d2a7SEd Tanous if (std::ranges::find(supportedRegPrefixes, it) == 5963544d2a7SEd Tanous supportedRegPrefixes.end()) 597e5aaf047SAppaRao Puli { 598fffb8c1fSEd Tanous messages::propertyValueNotInList(asyncResp->res, it, 599fffb8c1fSEd Tanous "RegistryPrefixes"); 600e5aaf047SAppaRao Puli return; 601e5aaf047SAppaRao Puli } 602e5aaf047SAppaRao Puli } 6035fe4ef35SMyung Bae subValue->userSub->registryPrefixes = *regPrefixes; 604e5aaf047SAppaRao Puli } 605e5aaf047SAppaRao Puli 606a14c9113SEd Tanous if (originResources) 607a14c9113SEd Tanous { 6085fe4ef35SMyung Bae subValue->userSub->originResources = *originResources; 609a14c9113SEd Tanous } 610a14c9113SEd Tanous 611e56f254cSSunitha Harish if (resTypes) 612e56f254cSSunitha Harish { 613e56f254cSSunitha Harish for (const std::string& it : *resTypes) 614e56f254cSSunitha Harish { 6153544d2a7SEd Tanous if (std::ranges::find(supportedResourceTypes, it) == 6163544d2a7SEd Tanous supportedResourceTypes.end()) 617e56f254cSSunitha Harish { 618e56f254cSSunitha Harish messages::propertyValueNotInList(asyncResp->res, it, 619e56f254cSSunitha Harish "ResourceTypes"); 620e56f254cSSunitha Harish return; 621e56f254cSSunitha Harish } 622e56f254cSSunitha Harish } 6235fe4ef35SMyung Bae subValue->userSub->resourceTypes = *resTypes; 624e56f254cSSunitha Harish } 625e56f254cSSunitha Harish 626e5aaf047SAppaRao Puli if (msgIds) 627e5aaf047SAppaRao Puli { 628b304bd79SP Dheeraj Srujan Kumar std::vector<std::string> registryPrefix; 629b304bd79SP Dheeraj Srujan Kumar 6307e860f15SJohn Edward Broadbent // If no registry prefixes are mentioned, consider all 6317e860f15SJohn Edward Broadbent // supported prefixes 6325fe4ef35SMyung Bae if (subValue->userSub->registryPrefixes.empty()) 633b304bd79SP Dheeraj Srujan Kumar { 634b304bd79SP Dheeraj Srujan Kumar registryPrefix.assign(supportedRegPrefixes.begin(), 635b304bd79SP Dheeraj Srujan Kumar supportedRegPrefixes.end()); 636b304bd79SP Dheeraj Srujan Kumar } 637b304bd79SP Dheeraj Srujan Kumar else 638b304bd79SP Dheeraj Srujan Kumar { 6395fe4ef35SMyung Bae registryPrefix = subValue->userSub->registryPrefixes; 640b304bd79SP Dheeraj Srujan Kumar } 641b304bd79SP Dheeraj Srujan Kumar 642b304bd79SP Dheeraj Srujan Kumar for (const std::string& id : *msgIds) 643b304bd79SP Dheeraj Srujan Kumar { 644b304bd79SP Dheeraj Srujan Kumar bool validId = false; 645b304bd79SP Dheeraj Srujan Kumar 646b304bd79SP Dheeraj Srujan Kumar // Check for Message ID in each of the selected Registry 647b304bd79SP Dheeraj Srujan Kumar for (const std::string& it : registryPrefix) 648b304bd79SP Dheeraj Srujan Kumar { 649fffb8c1fSEd Tanous const std::span<const redfish::registries::MessageEntry> 650fffb8c1fSEd Tanous registry = 651fffb8c1fSEd Tanous redfish::registries::getRegistryFromPrefix(it); 652b304bd79SP Dheeraj Srujan Kumar 6533544d2a7SEd Tanous if (std::ranges::any_of( 6543544d2a7SEd Tanous registry, 655fffb8c1fSEd Tanous [&id](const redfish::registries::MessageEntry& 656fffb8c1fSEd Tanous messageEntry) { 65755f79e6fSEd Tanous return id == messageEntry.first; 658b304bd79SP Dheeraj Srujan Kumar })) 659b304bd79SP Dheeraj Srujan Kumar { 660b304bd79SP Dheeraj Srujan Kumar validId = true; 661b304bd79SP Dheeraj Srujan Kumar break; 662b304bd79SP Dheeraj Srujan Kumar } 663b304bd79SP Dheeraj Srujan Kumar } 664b304bd79SP Dheeraj Srujan Kumar 665b304bd79SP Dheeraj Srujan Kumar if (!validId) 666b304bd79SP Dheeraj Srujan Kumar { 667b304bd79SP Dheeraj Srujan Kumar messages::propertyValueNotInList(asyncResp->res, id, 668b304bd79SP Dheeraj Srujan Kumar "MessageIds"); 669b304bd79SP Dheeraj Srujan Kumar return; 670b304bd79SP Dheeraj Srujan Kumar } 671b304bd79SP Dheeraj Srujan Kumar } 672b304bd79SP Dheeraj Srujan Kumar 6735fe4ef35SMyung Bae subValue->userSub->registryMsgIds = *msgIds; 674e5aaf047SAppaRao Puli } 675e5aaf047SAppaRao Puli 676e5aaf047SAppaRao Puli if (retryPolicy) 677e5aaf047SAppaRao Puli { 6783544d2a7SEd Tanous if (std::ranges::find(supportedRetryPolicies, *retryPolicy) == 6793544d2a7SEd Tanous supportedRetryPolicies.end()) 680e5aaf047SAppaRao Puli { 681bd79bce8SPatrick Williams messages::propertyValueNotInList( 682bd79bce8SPatrick Williams asyncResp->res, *retryPolicy, "DeliveryRetryPolicy"); 683e5aaf047SAppaRao Puli return; 684e5aaf047SAppaRao Puli } 6855fe4ef35SMyung Bae subValue->userSub->retryPolicy = *retryPolicy; 686e5aaf047SAppaRao Puli } 687e5aaf047SAppaRao Puli else 688e5aaf047SAppaRao Puli { 689e5aaf047SAppaRao Puli // Default "TerminateAfterRetries" 6905fe4ef35SMyung Bae subValue->userSub->retryPolicy = "TerminateAfterRetries"; 691e5aaf047SAppaRao Puli } 6925064a25bSMyung Bae if (sendHeartbeat) 6935064a25bSMyung Bae { 6945064a25bSMyung Bae subValue->userSub->sendHeartbeat = *sendHeartbeat; 6955064a25bSMyung Bae } 6965064a25bSMyung Bae if (hbIntervalMinutes) 6975064a25bSMyung Bae { 6985064a25bSMyung Bae if (*hbIntervalMinutes < 1 || *hbIntervalMinutes > 65535) 6995064a25bSMyung Bae { 7005064a25bSMyung Bae messages::propertyValueOutOfRange( 7015064a25bSMyung Bae asyncResp->res, *hbIntervalMinutes, 7025064a25bSMyung Bae "HeartbeatIntervalMinutes"); 7035064a25bSMyung Bae return; 7045064a25bSMyung Bae } 7055064a25bSMyung Bae subValue->userSub->hbIntervalMinutes = *hbIntervalMinutes; 7065064a25bSMyung Bae } 707e5aaf047SAppaRao Puli 708144b6318SAppaRao Puli if (mrdJsonArray) 709156d6b00SAppaRao Puli { 71078d4ec4fSEd Tanous for (nlohmann::json::object_t& mrdObj : *mrdJsonArray) 711144b6318SAppaRao Puli { 712144b6318SAppaRao Puli std::string mrdUri; 713ea2e6eecSWilly Tu 71478d4ec4fSEd Tanous if (!json_util::readJsonObject(mrdObj, asyncResp->res, 71578d4ec4fSEd Tanous "@odata.id", mrdUri)) 716ea2e6eecSWilly Tu 717144b6318SAppaRao Puli { 718144b6318SAppaRao Puli return; 719144b6318SAppaRao Puli } 7205fe4ef35SMyung Bae subValue->userSub->metricReportDefinitions.emplace_back( 7214b712a29SEd Tanous mrdUri); 722144b6318SAppaRao Puli } 723156d6b00SAppaRao Puli } 724156d6b00SAppaRao Puli 725b52664e2SAppaRao Puli std::string id = 726bd79bce8SPatrick Williams EventServiceManager::getInstance().addPushSubscription( 727bd79bce8SPatrick Williams subValue); 728b52664e2SAppaRao Puli if (id.empty()) 729e5aaf047SAppaRao Puli { 730e5aaf047SAppaRao Puli messages::internalError(asyncResp->res); 731e5aaf047SAppaRao Puli return; 732e5aaf047SAppaRao Puli } 733e5aaf047SAppaRao Puli 734e5aaf047SAppaRao Puli messages::created(asyncResp->res); 735e5aaf047SAppaRao Puli asyncResp->res.addHeader( 736e5aaf047SAppaRao Puli "Location", "/redfish/v1/EventService/Subscriptions/" + id); 737fb546105SMyung Bae 738fb546105SMyung Bae // schedule a heartbeat 739fb546105SMyung Bae if (subValue->userSub->sendHeartbeat) 740fb546105SMyung Bae { 741fb546105SMyung Bae subValue->scheduleNextHeartbeatEvent(); 742fb546105SMyung Bae } 7437e860f15SJohn Edward Broadbent }); 744e5aaf047SAppaRao Puli } 745e5aaf047SAppaRao Puli 7467e860f15SJohn Edward Broadbent inline void requestRoutesEventDestination(App& app) 747e5aaf047SAppaRao Puli { 7489d41aec6SRavi Teja BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/<str>/") 749ed398213SEd Tanous .privileges(redfish::privileges::getEventDestination) 7507e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 75145ca1b86SEd Tanous [&app](const crow::Request& req, 7527e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 7537e860f15SJohn Edward Broadbent const std::string& param) { 7543ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 75545ca1b86SEd Tanous { 75645ca1b86SEd Tanous return; 75745ca1b86SEd Tanous } 7583d30708fSChicago Duan 7593d30708fSChicago Duan if (param.starts_with("snmp")) 7603d30708fSChicago Duan { 7613d30708fSChicago Duan getSnmpTrapClient(asyncResp, param); 7623d30708fSChicago Duan return; 7633d30708fSChicago Duan } 7643d30708fSChicago Duan 765b52664e2SAppaRao Puli std::shared_ptr<Subscription> subValue = 7667e860f15SJohn Edward Broadbent EventServiceManager::getInstance().getSubscription(param); 767b52664e2SAppaRao Puli if (subValue == nullptr) 768e5aaf047SAppaRao Puli { 769bd79bce8SPatrick Williams asyncResp->res.result( 770bd79bce8SPatrick Williams boost::beast::http::status::not_found); 771e5aaf047SAppaRao Puli return; 772e5aaf047SAppaRao Puli } 7737e860f15SJohn Edward Broadbent const std::string& id = param; 774e5aaf047SAppaRao Puli 7754b712a29SEd Tanous const persistent_data::UserSubscription& userSub = 7765fe4ef35SMyung Bae *subValue->userSub; 777e56f254cSSunitha Harish 7784b712a29SEd Tanous nlohmann::json& jVal = asyncResp->res.jsonValue; 7794b712a29SEd Tanous jVal["@odata.type"] = 7804b712a29SEd Tanous "#EventDestination.v1_14_1.EventDestination"; 7814b712a29SEd Tanous jVal["Protocol"] = 7824b712a29SEd Tanous event_destination::EventDestinationProtocol::Redfish; 7834b712a29SEd Tanous jVal["@odata.id"] = boost::urls::format( 7844b712a29SEd Tanous "/redfish/v1/EventService/Subscriptions/{}", id); 7854b712a29SEd Tanous jVal["Id"] = id; 7864b712a29SEd Tanous jVal["Name"] = "Event Destination " + id; 7874b712a29SEd Tanous jVal["Destination"] = userSub.destinationUrl; 7884b712a29SEd Tanous jVal["Context"] = userSub.customText; 7894b712a29SEd Tanous jVal["SubscriptionType"] = userSub.subscriptionType; 7904b712a29SEd Tanous jVal["HttpHeaders"] = nlohmann::json::array(); 7914b712a29SEd Tanous jVal["EventFormatType"] = userSub.eventFormatType; 7924b712a29SEd Tanous jVal["RegistryPrefixes"] = userSub.registryPrefixes; 7934b712a29SEd Tanous jVal["ResourceTypes"] = userSub.resourceTypes; 7944b712a29SEd Tanous 7954b712a29SEd Tanous jVal["MessageIds"] = userSub.registryMsgIds; 7964b712a29SEd Tanous jVal["DeliveryRetryPolicy"] = userSub.retryPolicy; 7975064a25bSMyung Bae jVal["SendHeartbeat"] = userSub.sendHeartbeat; 7985064a25bSMyung Bae jVal["HeartbeatIntervalMinutes"] = userSub.hbIntervalMinutes; 7994b712a29SEd Tanous jVal["VerifyCertificate"] = userSub.verifyCertificate; 800144b6318SAppaRao Puli 8011476687dSEd Tanous nlohmann::json::array_t mrdJsonArray; 8024b712a29SEd Tanous for (const auto& mdrUri : userSub.metricReportDefinitions) 803144b6318SAppaRao Puli { 8041476687dSEd Tanous nlohmann::json::object_t mdr; 8051476687dSEd Tanous mdr["@odata.id"] = mdrUri; 8061476687dSEd Tanous mrdJsonArray.emplace_back(std::move(mdr)); 807144b6318SAppaRao Puli } 8084b712a29SEd Tanous jVal["MetricReportDefinitions"] = mrdJsonArray; 8097e860f15SJohn Edward Broadbent }); 8109d41aec6SRavi Teja BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/<str>/") 811ed398213SEd Tanous // The below privilege is wrong, it should be ConfigureManager OR 812ed398213SEd Tanous // ConfigureSelf 8137eeafa76SAbhishek Patel // https://github.com/openbmc/bmcweb/issues/220 814ed398213SEd Tanous //.privileges(redfish::privileges::patchEventDestination) 815432a890cSEd Tanous .privileges({{"ConfigureManager"}}) 8167e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::patch)( 81745ca1b86SEd Tanous [&app](const crow::Request& req, 8187e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 8197e860f15SJohn Edward Broadbent const std::string& param) { 8203ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 82145ca1b86SEd Tanous { 82245ca1b86SEd Tanous return; 82345ca1b86SEd Tanous } 824b52664e2SAppaRao Puli std::shared_ptr<Subscription> subValue = 8257e860f15SJohn Edward Broadbent EventServiceManager::getInstance().getSubscription(param); 826b52664e2SAppaRao Puli if (subValue == nullptr) 827e5aaf047SAppaRao Puli { 828bd79bce8SPatrick Williams asyncResp->res.result( 829bd79bce8SPatrick Williams boost::beast::http::status::not_found); 830e5aaf047SAppaRao Puli return; 831e5aaf047SAppaRao Puli } 832e5aaf047SAppaRao Puli 833e5aaf047SAppaRao Puli std::optional<std::string> context; 834e5aaf047SAppaRao Puli std::optional<std::string> retryPolicy; 8355064a25bSMyung Bae std::optional<bool> sendHeartbeat; 8365064a25bSMyung Bae std::optional<uint64_t> hbIntervalMinutes; 83719bb362bSEd Tanous std::optional<bool> verifyCertificate; 83878d4ec4fSEd Tanous std::optional<std::vector<nlohmann::json::object_t>> headers; 839e5aaf047SAppaRao Puli 840afc474aeSMyung Bae if (!json_util::readJsonPatch( // 841afc474aeSMyung Bae req, asyncResp->res, // 842afc474aeSMyung Bae "Context", context, // 843afc474aeSMyung Bae "DeliveryRetryPolicy", retryPolicy, // 8445064a25bSMyung Bae "HeartbeatIntervalMinutes", hbIntervalMinutes, // 845afc474aeSMyung Bae "HttpHeaders", headers, // 8465064a25bSMyung Bae "SendHeartbeat", sendHeartbeat, // 847afc474aeSMyung Bae "VerifyCertificate", verifyCertificate // 848afc474aeSMyung Bae )) 849e5aaf047SAppaRao Puli { 850e5aaf047SAppaRao Puli return; 851e5aaf047SAppaRao Puli } 852e5aaf047SAppaRao Puli 853e5aaf047SAppaRao Puli if (context) 854e5aaf047SAppaRao Puli { 8555fe4ef35SMyung Bae subValue->userSub->customText = *context; 856e5aaf047SAppaRao Puli } 857e5aaf047SAppaRao Puli 858e5aaf047SAppaRao Puli if (headers) 859e5aaf047SAppaRao Puli { 860601c71aeSEd Tanous boost::beast::http::fields fields; 86178d4ec4fSEd Tanous for (const nlohmann::json::object_t& headerChunk : *headers) 862601c71aeSEd Tanous { 86378d4ec4fSEd Tanous for (const auto& it : headerChunk) 864601c71aeSEd Tanous { 865601c71aeSEd Tanous const std::string* value = 86678d4ec4fSEd Tanous it.second.get_ptr<const std::string*>(); 867601c71aeSEd Tanous if (value == nullptr) 868601c71aeSEd Tanous { 869601c71aeSEd Tanous messages::propertyValueFormatError( 87078d4ec4fSEd Tanous asyncResp->res, it.second, 87178d4ec4fSEd Tanous "HttpHeaders/" + it.first); 872601c71aeSEd Tanous return; 873601c71aeSEd Tanous } 87478d4ec4fSEd Tanous fields.set(it.first, *value); 875601c71aeSEd Tanous } 876601c71aeSEd Tanous } 8775fe4ef35SMyung Bae subValue->userSub->httpHeaders = std::move(fields); 878e5aaf047SAppaRao Puli } 879e5aaf047SAppaRao Puli 880e5aaf047SAppaRao Puli if (retryPolicy) 881e5aaf047SAppaRao Puli { 882bd79bce8SPatrick Williams if (std::ranges::find(supportedRetryPolicies, 883bd79bce8SPatrick Williams *retryPolicy) == 8843544d2a7SEd Tanous supportedRetryPolicies.end()) 885e5aaf047SAppaRao Puli { 886bd79bce8SPatrick Williams messages::propertyValueNotInList(asyncResp->res, 887bd79bce8SPatrick Williams *retryPolicy, 888e5aaf047SAppaRao Puli "DeliveryRetryPolicy"); 889e5aaf047SAppaRao Puli return; 890e5aaf047SAppaRao Puli } 8915fe4ef35SMyung Bae subValue->userSub->retryPolicy = *retryPolicy; 892e5aaf047SAppaRao Puli } 893e5aaf047SAppaRao Puli 8945064a25bSMyung Bae if (sendHeartbeat) 8955064a25bSMyung Bae { 8965064a25bSMyung Bae subValue->userSub->sendHeartbeat = *sendHeartbeat; 8975064a25bSMyung Bae } 8985064a25bSMyung Bae if (hbIntervalMinutes) 8995064a25bSMyung Bae { 9005064a25bSMyung Bae if (*hbIntervalMinutes < 1 || *hbIntervalMinutes > 65535) 9015064a25bSMyung Bae { 9025064a25bSMyung Bae messages::propertyValueOutOfRange( 9035064a25bSMyung Bae asyncResp->res, *hbIntervalMinutes, 9045064a25bSMyung Bae "HeartbeatIntervalMinutes"); 9055064a25bSMyung Bae return; 9065064a25bSMyung Bae } 9075064a25bSMyung Bae subValue->userSub->hbIntervalMinutes = *hbIntervalMinutes; 9085064a25bSMyung Bae } 9095064a25bSMyung Bae 910fb546105SMyung Bae if (hbIntervalMinutes || sendHeartbeat) 911fb546105SMyung Bae { 912fb546105SMyung Bae // if Heartbeat interval or send heart were changed, cancel 913fb546105SMyung Bae // the heartbeat timer if running and start a new heartbeat 914fb546105SMyung Bae // if needed 915fb546105SMyung Bae subValue->heartbeatParametersChanged(); 916fb546105SMyung Bae } 917fb546105SMyung Bae 91819bb362bSEd Tanous if (verifyCertificate) 91919bb362bSEd Tanous { 9205fe4ef35SMyung Bae subValue->userSub->verifyCertificate = *verifyCertificate; 92119bb362bSEd Tanous } 92219bb362bSEd Tanous 923b52664e2SAppaRao Puli EventServiceManager::getInstance().updateSubscriptionData(); 9247e860f15SJohn Edward Broadbent }); 9259d41aec6SRavi Teja BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/<str>/") 926ed398213SEd Tanous // The below privilege is wrong, it should be ConfigureManager OR 927ed398213SEd Tanous // ConfigureSelf 9287eeafa76SAbhishek Patel // https://github.com/openbmc/bmcweb/issues/220 929ed398213SEd Tanous //.privileges(redfish::privileges::deleteEventDestination) 930432a890cSEd Tanous .privileges({{"ConfigureManager"}}) 9317e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::delete_)( 93245ca1b86SEd Tanous [&app](const crow::Request& req, 9337e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 9347e860f15SJohn Edward Broadbent const std::string& param) { 9353ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 93645ca1b86SEd Tanous { 93745ca1b86SEd Tanous return; 93845ca1b86SEd Tanous } 9394b712a29SEd Tanous EventServiceManager& event = EventServiceManager::getInstance(); 9403d30708fSChicago Duan if (param.starts_with("snmp")) 9413d30708fSChicago Duan { 9423d30708fSChicago Duan deleteSnmpTrapClient(asyncResp, param); 9434b712a29SEd Tanous event.deleteSubscription(param); 9443d30708fSChicago Duan return; 9453d30708fSChicago Duan } 9463d30708fSChicago Duan 9474b712a29SEd Tanous if (!event.deleteSubscription(param)) 948e5aaf047SAppaRao Puli { 9494b712a29SEd Tanous messages::resourceNotFound(asyncResp->res, 9504b712a29SEd Tanous "EventDestination", param); 951e5aaf047SAppaRao Puli return; 952e5aaf047SAppaRao Puli } 9534b712a29SEd Tanous messages::success(asyncResp->res); 9547e860f15SJohn Edward Broadbent }); 955e5aaf047SAppaRao Puli } 956e5aaf047SAppaRao Puli 957e5aaf047SAppaRao Puli } // namespace redfish 958