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" 6d7857201SEd Tanous #include "async_resp.hpp" 7d7857201SEd Tanous #include "dbus_singleton.hpp" 8d7857201SEd Tanous #include "dbus_utility.hpp" 9d7857201SEd Tanous #include "error_messages.hpp" 10b52664e2SAppaRao Puli #include "event_service_manager.hpp" 11d7857201SEd Tanous #include "event_service_store.hpp" 12d7857201SEd Tanous #include "generated/enums/event_destination.hpp" 133ccb3adbSEd Tanous #include "http/utility.hpp" 14d7857201SEd Tanous #include "http_request.hpp" 15*9838eb20SEd Tanous #include "io_context_singleton.hpp" 163ccb3adbSEd Tanous #include "logging.hpp" 173ccb3adbSEd Tanous #include "query.hpp" 18d109e2b6SAlexander Hansen #include "registries.hpp" 193ccb3adbSEd Tanous #include "registries/privilege_registry.hpp" 20d109e2b6SAlexander Hansen #include "registries_selector.hpp" 213d30708fSChicago Duan #include "snmp_trap_event_clients.hpp" 22d7857201SEd Tanous #include "subscription.hpp" 23d109e2b6SAlexander Hansen #include "utils/json_utils.hpp" 24e5aaf047SAppaRao Puli 25d7857201SEd Tanous #include <asm-generic/errno.h> 26ed398213SEd Tanous 27d7857201SEd Tanous #include <boost/beast/http/fields.hpp> 28d7857201SEd Tanous #include <boost/beast/http/status.hpp> 29d7857201SEd Tanous #include <boost/beast/http/verb.hpp> 30d7857201SEd Tanous #include <boost/system/error_code.hpp> 31d7857201SEd Tanous #include <boost/system/result.hpp> 32d7857201SEd Tanous #include <boost/url/format.hpp> 33d7857201SEd Tanous #include <boost/url/parse.hpp> 34d7857201SEd Tanous #include <boost/url/url.hpp> 35d7857201SEd Tanous #include <sdbusplus/message/native_types.hpp> 36d7857201SEd Tanous 37d7857201SEd Tanous #include <algorithm> 38d7857201SEd Tanous #include <array> 39d7857201SEd Tanous #include <cerrno> 40d7857201SEd Tanous #include <cstddef> 41d7857201SEd Tanous #include <cstdint> 423d30708fSChicago Duan #include <memory> 435064a25bSMyung Bae #include <optional> 443544d2a7SEd Tanous #include <ranges> 451e270c5fSPatrick Williams #include <span> 463d30708fSChicago Duan #include <string> 47d7857201SEd Tanous #include <utility> 48a14c9113SEd Tanous #include <vector> 491e270c5fSPatrick Williams 50e5aaf047SAppaRao Puli namespace redfish 51e5aaf047SAppaRao Puli { 52e5aaf047SAppaRao Puli 53156d6b00SAppaRao Puli static constexpr const std::array<const char*, 2> supportedEvtFormatTypes = { 54156d6b00SAppaRao Puli eventFormatType, metricReportFormatType}; 55fb546105SMyung Bae static constexpr const std::array<const char*, 4> supportedRegPrefixes = { 56fb546105SMyung Bae "Base", "OpenBMC", "TaskEvent", "HeartbeatEvent"}; 57e5aaf047SAppaRao Puli static constexpr const std::array<const char*, 3> supportedRetryPolicies = { 58e5aaf047SAppaRao Puli "TerminateAfterRetries", "SuspendRetries", "RetryForever"}; 59e5aaf047SAppaRao Puli 60fb546105SMyung Bae static constexpr const std::array<const char*, 2> supportedResourceTypes = { 61fb546105SMyung Bae "Task", "Heartbeat"}; 62e56f254cSSunitha Harish 637e860f15SJohn Edward Broadbent inline void requestRoutesEventService(App& app) 64e5aaf047SAppaRao Puli { 657e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, "/redfish/v1/EventService/") 66ed398213SEd Tanous .privileges(redfish::privileges::getEventService) 67bd79bce8SPatrick Williams .methods( 68bd79bce8SPatrick Williams boost::beast::http::verb:: 69bd79bce8SPatrick Williams get)([&app]( 70bd79bce8SPatrick Williams const crow::Request& req, 71002d39b4SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 723ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 7345ca1b86SEd Tanous { 7445ca1b86SEd Tanous return; 7545ca1b86SEd Tanous } 761476687dSEd Tanous 771476687dSEd Tanous asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/EventService"; 781476687dSEd Tanous asyncResp->res.jsonValue["@odata.type"] = 791476687dSEd Tanous "#EventService.v1_5_0.EventService"; 801476687dSEd Tanous asyncResp->res.jsonValue["Id"] = "EventService"; 811476687dSEd Tanous asyncResp->res.jsonValue["Name"] = "Event Service"; 825e44e3d8SAppaRao Puli asyncResp->res.jsonValue["ServerSentEventUri"] = 835e44e3d8SAppaRao Puli "/redfish/v1/EventService/SSE"; 845e44e3d8SAppaRao Puli 851476687dSEd Tanous asyncResp->res.jsonValue["Subscriptions"]["@odata.id"] = 861476687dSEd Tanous "/redfish/v1/EventService/Subscriptions"; 87bd79bce8SPatrick Williams asyncResp->res.jsonValue["Actions"]["#EventService.SubmitTestEvent"] 88bd79bce8SPatrick Williams ["target"] = 891476687dSEd Tanous "/redfish/v1/EventService/Actions/EventService.SubmitTestEvent"; 90e5aaf047SAppaRao Puli 9128afb49cSJunLin Chen const persistent_data::EventServiceConfig eventServiceConfig = 9228afb49cSJunLin Chen persistent_data::EventServiceStore::getInstance() 9328afb49cSJunLin Chen .getEventServiceConfig(); 947d1cc387SAppaRao Puli 957d1cc387SAppaRao Puli asyncResp->res.jsonValue["Status"]["State"] = 9628afb49cSJunLin Chen (eventServiceConfig.enabled ? "Enabled" : "Disabled"); 97bd79bce8SPatrick Williams asyncResp->res.jsonValue["ServiceEnabled"] = 98bd79bce8SPatrick Williams eventServiceConfig.enabled; 997e860f15SJohn Edward Broadbent asyncResp->res.jsonValue["DeliveryRetryAttempts"] = 10028afb49cSJunLin Chen eventServiceConfig.retryAttempts; 101e5aaf047SAppaRao Puli asyncResp->res.jsonValue["DeliveryRetryIntervalSeconds"] = 10228afb49cSJunLin Chen eventServiceConfig.retryTimeoutInterval; 103bd79bce8SPatrick Williams asyncResp->res.jsonValue["EventFormatTypes"] = 104bd79bce8SPatrick Williams supportedEvtFormatTypes; 1050fda0f12SGeorge Liu asyncResp->res.jsonValue["RegistryPrefixes"] = supportedRegPrefixes; 1060fda0f12SGeorge Liu asyncResp->res.jsonValue["ResourceTypes"] = supportedResourceTypes; 10707941a88SAyushi Smriti 108613dabeaSEd Tanous nlohmann::json::object_t supportedSSEFilters; 109613dabeaSEd Tanous supportedSSEFilters["EventFormatType"] = true; 110613dabeaSEd Tanous supportedSSEFilters["MessageId"] = true; 111613dabeaSEd Tanous supportedSSEFilters["MetricReportDefinition"] = true; 112613dabeaSEd Tanous supportedSSEFilters["RegistryPrefix"] = true; 113613dabeaSEd Tanous supportedSSEFilters["OriginResource"] = false; 114613dabeaSEd Tanous supportedSSEFilters["ResourceType"] = false; 11507941a88SAyushi Smriti 11607941a88SAyushi Smriti asyncResp->res.jsonValue["SSEFilterPropertiesSupported"] = 117613dabeaSEd Tanous std::move(supportedSSEFilters); 1187e860f15SJohn Edward Broadbent }); 119e5aaf047SAppaRao Puli 1207e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, "/redfish/v1/EventService/") 121ed398213SEd Tanous .privileges(redfish::privileges::patchEventService) 1227e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::patch)( 12345ca1b86SEd Tanous [&app](const crow::Request& req, 12445ca1b86SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 1253ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 126e5aaf047SAppaRao Puli { 12745ca1b86SEd Tanous return; 12845ca1b86SEd Tanous } 129e5aaf047SAppaRao Puli std::optional<bool> serviceEnabled; 130e5aaf047SAppaRao Puli std::optional<uint32_t> retryAttemps; 131e5aaf047SAppaRao Puli std::optional<uint32_t> retryInterval; 132afc474aeSMyung Bae if (!json_util::readJsonPatch( // 133afc474aeSMyung Bae req, asyncResp->res, // 134afc474aeSMyung Bae "DeliveryRetryAttempts", retryAttemps, // 135afc474aeSMyung Bae "DeliveryRetryIntervalSeconds", retryInterval, // 136afc474aeSMyung Bae "ServiceEnabled", serviceEnabled // 137afc474aeSMyung Bae )) 138e5aaf047SAppaRao Puli { 139e5aaf047SAppaRao Puli return; 140e5aaf047SAppaRao Puli } 141e5aaf047SAppaRao Puli 14228afb49cSJunLin Chen persistent_data::EventServiceConfig eventServiceConfig = 14328afb49cSJunLin Chen persistent_data::EventServiceStore::getInstance() 14428afb49cSJunLin Chen .getEventServiceConfig(); 1457d1cc387SAppaRao Puli 146e5aaf047SAppaRao Puli if (serviceEnabled) 147e5aaf047SAppaRao Puli { 14828afb49cSJunLin Chen eventServiceConfig.enabled = *serviceEnabled; 149e5aaf047SAppaRao Puli } 150e5aaf047SAppaRao Puli 151e5aaf047SAppaRao Puli if (retryAttemps) 152e5aaf047SAppaRao Puli { 153e5aaf047SAppaRao Puli // Supported range [1-3] 154e5aaf047SAppaRao Puli if ((*retryAttemps < 1) || (*retryAttemps > 3)) 155e5aaf047SAppaRao Puli { 156e5aaf047SAppaRao Puli messages::queryParameterOutOfRange( 157e5aaf047SAppaRao Puli asyncResp->res, std::to_string(*retryAttemps), 158e5aaf047SAppaRao Puli "DeliveryRetryAttempts", "[1-3]"); 159e5aaf047SAppaRao Puli } 160e5aaf047SAppaRao Puli else 161e5aaf047SAppaRao Puli { 16228afb49cSJunLin Chen eventServiceConfig.retryAttempts = *retryAttemps; 163e5aaf047SAppaRao Puli } 164e5aaf047SAppaRao Puli } 165e5aaf047SAppaRao Puli 166e5aaf047SAppaRao Puli if (retryInterval) 167e5aaf047SAppaRao Puli { 16833a32b34SGunnar Mills // Supported range [5 - 180] 16933a32b34SGunnar Mills if ((*retryInterval < 5) || (*retryInterval > 180)) 170e5aaf047SAppaRao Puli { 171e5aaf047SAppaRao Puli messages::queryParameterOutOfRange( 172e5aaf047SAppaRao Puli asyncResp->res, std::to_string(*retryInterval), 17333a32b34SGunnar Mills "DeliveryRetryIntervalSeconds", "[5-180]"); 174e5aaf047SAppaRao Puli } 175e5aaf047SAppaRao Puli else 176e5aaf047SAppaRao Puli { 177bd79bce8SPatrick Williams eventServiceConfig.retryTimeoutInterval = 178bd79bce8SPatrick Williams *retryInterval; 179e5aaf047SAppaRao Puli } 180e5aaf047SAppaRao Puli } 181e5aaf047SAppaRao Puli 1827d1cc387SAppaRao Puli EventServiceManager::getInstance().setEventServiceConfig( 18328afb49cSJunLin Chen eventServiceConfig); 1847e860f15SJohn Edward Broadbent }); 1850b4bdd93SAppaRao Puli } 1860b4bdd93SAppaRao Puli 1877e860f15SJohn Edward Broadbent inline void requestRoutesSubmitTestEvent(App& app) 1880b4bdd93SAppaRao Puli { 1897e860f15SJohn Edward Broadbent BMCWEB_ROUTE( 1907e860f15SJohn Edward Broadbent app, "/redfish/v1/EventService/Actions/EventService.SubmitTestEvent/") 191ed398213SEd Tanous .privileges(redfish::privileges::postEventService) 1927e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::post)( 19345ca1b86SEd Tanous [&app](const crow::Request& req, 1947e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 1953ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 19645ca1b86SEd Tanous { 19745ca1b86SEd Tanous return; 19845ca1b86SEd Tanous } 19981ee0e74SChandramohan Harkude 20081ee0e74SChandramohan Harkude TestEvent testEvent; 20181ee0e74SChandramohan Harkude // clang-format off 20281ee0e74SChandramohan Harkude if (!json_util::readJsonAction( 20381ee0e74SChandramohan Harkude req, asyncResp->res, 20481ee0e74SChandramohan Harkude "EventGroupId", testEvent.eventGroupId, 20581ee0e74SChandramohan Harkude "EventId", testEvent.eventId, 20681ee0e74SChandramohan Harkude "EventTimestamp", testEvent.eventTimestamp, 20781ee0e74SChandramohan Harkude "Message", testEvent.message, 20881ee0e74SChandramohan Harkude "MessageArgs", testEvent.messageArgs, 20981ee0e74SChandramohan Harkude "MessageId", testEvent.messageId, 21081ee0e74SChandramohan Harkude "OriginOfCondition", testEvent.originOfCondition, 21181ee0e74SChandramohan Harkude "Resolution", testEvent.resolution, 21281ee0e74SChandramohan Harkude "Severity", testEvent.severity)) 21381ee0e74SChandramohan Harkude { 21481ee0e74SChandramohan Harkude return; 21581ee0e74SChandramohan Harkude } 21681ee0e74SChandramohan Harkude // clang-format on 21781ee0e74SChandramohan Harkude 21881ee0e74SChandramohan Harkude if (!EventServiceManager::getInstance().sendTestEventLog( 21981ee0e74SChandramohan Harkude testEvent)) 2206ba8c82eSsunharis_in { 2216ba8c82eSsunharis_in messages::serviceDisabled(asyncResp->res, 2226ba8c82eSsunharis_in "/redfish/v1/EventService/"); 2236ba8c82eSsunharis_in return; 2246ba8c82eSsunharis_in } 2258d1b46d7Szhanghch05 asyncResp->res.result(boost::beast::http::status::no_content); 2267e860f15SJohn Edward Broadbent }); 227e5aaf047SAppaRao Puli } 228e5aaf047SAppaRao Puli 2293d30708fSChicago Duan inline void doSubscriptionCollection( 230e81de512SEd Tanous const boost::system::error_code& ec, 2313d30708fSChicago Duan const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2323d30708fSChicago Duan const dbus::utility::ManagedObjectType& resp) 2333d30708fSChicago Duan { 2343d30708fSChicago Duan if (ec) 2353d30708fSChicago Duan { 2361306101eSEd Tanous if (ec.value() == EBADR || ec.value() == EHOSTUNREACH) 2373d30708fSChicago Duan { 2383d30708fSChicago Duan // This is an optional process so just return if it isn't there 2393d30708fSChicago Duan return; 2403d30708fSChicago Duan } 2413d30708fSChicago Duan 24262598e31SEd Tanous BMCWEB_LOG_ERROR("D-Bus response error on GetManagedObjects {}", ec); 2433d30708fSChicago Duan messages::internalError(asyncResp->res); 2443d30708fSChicago Duan return; 2453d30708fSChicago Duan } 2463d30708fSChicago Duan nlohmann::json& memberArray = asyncResp->res.jsonValue["Members"]; 2473d30708fSChicago Duan for (const auto& objpath : resp) 2483d30708fSChicago Duan { 2493d30708fSChicago Duan sdbusplus::message::object_path path(objpath.first); 2503d30708fSChicago Duan const std::string snmpId = path.filename(); 2513d30708fSChicago Duan if (snmpId.empty()) 2523d30708fSChicago Duan { 25362598e31SEd Tanous BMCWEB_LOG_ERROR("The SNMP client ID is wrong"); 2543d30708fSChicago Duan messages::internalError(asyncResp->res); 2553d30708fSChicago Duan return; 2563d30708fSChicago Duan } 2573d30708fSChicago Duan 2583d30708fSChicago Duan getSnmpSubscriptionList(asyncResp, snmpId, memberArray); 2593d30708fSChicago Duan } 2603d30708fSChicago Duan } 2613d30708fSChicago Duan 2627e860f15SJohn Edward Broadbent inline void requestRoutesEventDestinationCollection(App& app) 263e5aaf047SAppaRao Puli { 2641ebe3e41SGayathri Leburu BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/") 265ed398213SEd Tanous .privileges(redfish::privileges::getEventDestinationCollection) 2667e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 26745ca1b86SEd Tanous [&app](const crow::Request& req, 2687e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 2693ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 27045ca1b86SEd Tanous { 27145ca1b86SEd Tanous return; 27245ca1b86SEd Tanous } 2731476687dSEd Tanous asyncResp->res.jsonValue["@odata.type"] = 2741476687dSEd Tanous "#EventDestinationCollection.EventDestinationCollection"; 2751476687dSEd Tanous asyncResp->res.jsonValue["@odata.id"] = 2761476687dSEd Tanous "/redfish/v1/EventService/Subscriptions"; 277bd79bce8SPatrick Williams asyncResp->res.jsonValue["Name"] = 278bd79bce8SPatrick Williams "Event Destination Collections"; 279e5aaf047SAppaRao Puli 280bd79bce8SPatrick Williams nlohmann::json& memberArray = 281bd79bce8SPatrick Williams asyncResp->res.jsonValue["Members"]; 282e5aaf047SAppaRao Puli 283b52664e2SAppaRao Puli std::vector<std::string> subscripIds = 284b52664e2SAppaRao Puli EventServiceManager::getInstance().getAllIDs(); 285b52664e2SAppaRao Puli memberArray = nlohmann::json::array(); 286bd79bce8SPatrick Williams asyncResp->res.jsonValue["Members@odata.count"] = 287bd79bce8SPatrick Williams subscripIds.size(); 288b52664e2SAppaRao Puli 289b52664e2SAppaRao Puli for (const std::string& id : subscripIds) 290e5aaf047SAppaRao Puli { 2911476687dSEd Tanous nlohmann::json::object_t member; 2923d30708fSChicago Duan member["@odata.id"] = boost::urls::format( 2933d30708fSChicago Duan "/redfish/v1/EventService/Subscriptions/{}" + id); 294b2ba3072SPatrick Williams memberArray.emplace_back(std::move(member)); 295e5aaf047SAppaRao Puli } 2963d30708fSChicago Duan crow::connections::systemBus->async_method_call( 297e81de512SEd Tanous [asyncResp](const boost::system::error_code& ec, 2983d30708fSChicago Duan const dbus::utility::ManagedObjectType& resp) { 2993d30708fSChicago Duan doSubscriptionCollection(ec, asyncResp, resp); 3003d30708fSChicago Duan }, 3013d30708fSChicago Duan "xyz.openbmc_project.Network.SNMP", 3023d30708fSChicago Duan "/xyz/openbmc_project/network/snmp/manager", 3033d30708fSChicago Duan "org.freedesktop.DBus.ObjectManager", "GetManagedObjects"); 3047e860f15SJohn Edward Broadbent }); 3053d30708fSChicago Duan 3067e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/") 3077eeafa76SAbhishek Patel .privileges(redfish::privileges::postEventDestinationCollection) 308bd79bce8SPatrick Williams .methods( 309bd79bce8SPatrick Williams boost::beast::http::verb:: 310bd79bce8SPatrick Williams post)([&app]( 311bd79bce8SPatrick Williams const crow::Request& req, 3127e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 3133ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 31445ca1b86SEd Tanous { 31545ca1b86SEd Tanous return; 31645ca1b86SEd Tanous } 317fffb8c1fSEd Tanous if (EventServiceManager::getInstance().getNumberOfSubscriptions() >= 318fffb8c1fSEd Tanous maxNoOfSubscriptions) 319e5aaf047SAppaRao Puli { 320e5aaf047SAppaRao Puli messages::eventSubscriptionLimitExceeded(asyncResp->res); 321e5aaf047SAppaRao Puli return; 322e5aaf047SAppaRao Puli } 323e5aaf047SAppaRao Puli std::string destUrl; 324e5aaf047SAppaRao Puli std::string protocol; 32519bb362bSEd Tanous std::optional<bool> verifyCertificate; 326e5aaf047SAppaRao Puli std::optional<std::string> context; 327e5aaf047SAppaRao Puli std::optional<std::string> subscriptionType; 32823a21a1cSEd Tanous std::optional<std::string> eventFormatType2; 329e5aaf047SAppaRao Puli std::optional<std::string> retryPolicy; 3305064a25bSMyung Bae std::optional<bool> sendHeartbeat; 3315064a25bSMyung Bae std::optional<uint64_t> hbIntervalMinutes; 332e5aaf047SAppaRao Puli std::optional<std::vector<std::string>> msgIds; 333e5aaf047SAppaRao Puli std::optional<std::vector<std::string>> regPrefixes; 334a14c9113SEd Tanous std::optional<std::vector<std::string>> originResources; 335e56f254cSSunitha Harish std::optional<std::vector<std::string>> resTypes; 33678d4ec4fSEd Tanous std::optional<std::vector<nlohmann::json::object_t>> headers; 33778d4ec4fSEd Tanous std::optional<std::vector<nlohmann::json::object_t>> mrdJsonArray; 338e5aaf047SAppaRao Puli 339afc474aeSMyung Bae if (!json_util::readJsonPatch( // 340afc474aeSMyung Bae req, asyncResp->res, // 341afc474aeSMyung Bae "Context", context, // 342afc474aeSMyung Bae "DeliveryRetryPolicy", retryPolicy, // 343afc474aeSMyung Bae "Destination", destUrl, // 344afc474aeSMyung Bae "EventFormatType", eventFormatType2, // 3455064a25bSMyung Bae "HeartbeatIntervalMinutes", hbIntervalMinutes, // 346afc474aeSMyung Bae "HttpHeaders", headers, // 347afc474aeSMyung Bae "MessageIds", msgIds, // 348afc474aeSMyung Bae "MetricReportDefinitions", mrdJsonArray, // 349afc474aeSMyung Bae "OriginResources", originResources, // 350afc474aeSMyung Bae "Protocol", protocol, // 351afc474aeSMyung Bae "RegistryPrefixes", regPrefixes, // 352afc474aeSMyung Bae "ResourceTypes", resTypes, // 3535064a25bSMyung Bae "SendHeartbeat", sendHeartbeat, // 354afc474aeSMyung Bae "SubscriptionType", subscriptionType, // 355afc474aeSMyung Bae "VerifyCertificate", verifyCertificate // 3564b712a29SEd Tanous )) 357e5aaf047SAppaRao Puli { 358e5aaf047SAppaRao Puli return; 359e5aaf047SAppaRao Puli } 3604b712a29SEd Tanous // clang-format on 361e5aaf047SAppaRao Puli 362600af5f1SAppaRao Puli // https://stackoverflow.com/questions/417142/what-is-the-maximum-length-of-a-url-in-different-browsers 363600af5f1SAppaRao Puli static constexpr const uint16_t maxDestinationSize = 2000; 364600af5f1SAppaRao Puli if (destUrl.size() > maxDestinationSize) 365600af5f1SAppaRao Puli { 366600af5f1SAppaRao Puli messages::stringValueTooLong(asyncResp->res, "Destination", 367600af5f1SAppaRao Puli maxDestinationSize); 368600af5f1SAppaRao Puli return; 369600af5f1SAppaRao Puli } 370600af5f1SAppaRao Puli 371dd28ba82SAppaRao Puli if (regPrefixes && msgIds) 372dd28ba82SAppaRao Puli { 37326f6976fSEd Tanous if (!regPrefixes->empty() && !msgIds->empty()) 374dd28ba82SAppaRao Puli { 375bd79bce8SPatrick Williams messages::propertyValueConflict( 376bd79bce8SPatrick Williams asyncResp->res, "MessageIds", "RegistryPrefixes"); 377dd28ba82SAppaRao Puli return; 378dd28ba82SAppaRao Puli } 379dd28ba82SAppaRao Puli } 380dd28ba82SAppaRao Puli 3816fd29553SEd Tanous boost::system::result<boost::urls::url> url = 382a716aa74SEd Tanous boost::urls::parse_absolute_uri(destUrl); 383a716aa74SEd Tanous if (!url) 384e5aaf047SAppaRao Puli { 385bd79bce8SPatrick Williams BMCWEB_LOG_WARNING( 386bd79bce8SPatrick Williams "Failed to validate and split destination url"); 387e5aaf047SAppaRao Puli messages::propertyValueFormatError(asyncResp->res, destUrl, 388e5aaf047SAppaRao Puli "Destination"); 389e5aaf047SAppaRao Puli return; 390e5aaf047SAppaRao Puli } 391a716aa74SEd Tanous url->normalize(); 392b07942e3SGeorge Liu 393b07942e3SGeorge Liu // port_number returns zero if it is not a valid representable port 394b07942e3SGeorge Liu if (url->has_port() && url->port_number() == 0) 395b07942e3SGeorge Liu { 396b07942e3SGeorge Liu BMCWEB_LOG_WARNING("{} is an invalid port in destination url", 397b07942e3SGeorge Liu url->port()); 398b07942e3SGeorge Liu messages::propertyValueFormatError(asyncResp->res, destUrl, 399b07942e3SGeorge Liu "Destination"); 400b07942e3SGeorge Liu return; 401b07942e3SGeorge Liu } 402b07942e3SGeorge Liu 403a716aa74SEd Tanous crow::utility::setProtocolDefaults(*url, protocol); 404a716aa74SEd Tanous crow::utility::setPortDefaults(*url); 405a716aa74SEd Tanous 406a716aa74SEd Tanous if (url->path().empty()) 407a716aa74SEd Tanous { 408a716aa74SEd Tanous url->set_path("/"); 409a716aa74SEd Tanous } 410a716aa74SEd Tanous 411a716aa74SEd Tanous if (url->has_userinfo()) 412a716aa74SEd Tanous { 413a716aa74SEd Tanous messages::propertyValueFormatError(asyncResp->res, destUrl, 414a716aa74SEd Tanous "Destination"); 415a716aa74SEd Tanous return; 416a716aa74SEd Tanous } 417b52664e2SAppaRao Puli 4183d30708fSChicago Duan if (protocol == "SNMPv2c") 4193d30708fSChicago Duan { 4203d30708fSChicago Duan if (context) 4213d30708fSChicago Duan { 4223d30708fSChicago Duan messages::propertyValueConflict(asyncResp->res, "Context", 4233d30708fSChicago Duan "Protocol"); 4243d30708fSChicago Duan return; 4253d30708fSChicago Duan } 4263d30708fSChicago Duan if (eventFormatType2) 4273d30708fSChicago Duan { 428bd79bce8SPatrick Williams messages::propertyValueConflict( 429bd79bce8SPatrick Williams asyncResp->res, "EventFormatType", "Protocol"); 4303d30708fSChicago Duan return; 4313d30708fSChicago Duan } 4323d30708fSChicago Duan if (retryPolicy) 4333d30708fSChicago Duan { 434bd79bce8SPatrick Williams messages::propertyValueConflict(asyncResp->res, 435bd79bce8SPatrick Williams "RetryPolicy", "Protocol"); 4363d30708fSChicago Duan return; 4373d30708fSChicago Duan } 4385064a25bSMyung Bae if (sendHeartbeat) 4395064a25bSMyung Bae { 4405064a25bSMyung Bae messages::propertyValueConflict( 4415064a25bSMyung Bae asyncResp->res, "SendHeartbeat", "Protocol"); 4425064a25bSMyung Bae return; 4435064a25bSMyung Bae } 4445064a25bSMyung Bae if (hbIntervalMinutes) 4455064a25bSMyung Bae { 4465064a25bSMyung Bae messages::propertyValueConflict( 4475064a25bSMyung Bae asyncResp->res, "HeartbeatIntervalMinutes", "Protocol"); 4485064a25bSMyung Bae return; 4495064a25bSMyung Bae } 4503d30708fSChicago Duan if (msgIds) 4513d30708fSChicago Duan { 452bd79bce8SPatrick Williams messages::propertyValueConflict(asyncResp->res, 453bd79bce8SPatrick Williams "MessageIds", "Protocol"); 4543d30708fSChicago Duan return; 4553d30708fSChicago Duan } 4563d30708fSChicago Duan if (regPrefixes) 4573d30708fSChicago Duan { 458bd79bce8SPatrick Williams messages::propertyValueConflict( 459bd79bce8SPatrick Williams asyncResp->res, "RegistryPrefixes", "Protocol"); 4603d30708fSChicago Duan return; 4613d30708fSChicago Duan } 4623d30708fSChicago Duan if (resTypes) 4633d30708fSChicago Duan { 464bd79bce8SPatrick Williams messages::propertyValueConflict( 465bd79bce8SPatrick Williams asyncResp->res, "ResourceTypes", "Protocol"); 4663d30708fSChicago Duan return; 4673d30708fSChicago Duan } 4683d30708fSChicago Duan if (headers) 4693d30708fSChicago Duan { 470bd79bce8SPatrick Williams messages::propertyValueConflict(asyncResp->res, 471bd79bce8SPatrick Williams "HttpHeaders", "Protocol"); 4723d30708fSChicago Duan return; 4733d30708fSChicago Duan } 4743d30708fSChicago Duan if (mrdJsonArray) 4753d30708fSChicago Duan { 4763d30708fSChicago Duan messages::propertyValueConflict( 4773d30708fSChicago Duan asyncResp->res, "MetricReportDefinitions", "Protocol"); 4783d30708fSChicago Duan return; 4793d30708fSChicago Duan } 480a716aa74SEd Tanous if (url->scheme() != "snmp") 481a716aa74SEd Tanous { 482bd79bce8SPatrick Williams messages::propertyValueConflict(asyncResp->res, 483bd79bce8SPatrick Williams "Destination", "Protocol"); 4843d30708fSChicago Duan return; 4853d30708fSChicago Duan } 4863d30708fSChicago Duan 487a716aa74SEd Tanous addSnmpTrapClient(asyncResp, url->host_address(), 488a716aa74SEd Tanous url->port_number()); 489a716aa74SEd Tanous return; 490b52664e2SAppaRao Puli } 4913d30708fSChicago Duan 492a716aa74SEd Tanous std::shared_ptr<Subscription> subValue = 49321a94d5cSMyung Bae std::make_shared<Subscription>( 4945fe4ef35SMyung Bae std::make_shared<persistent_data::UserSubscription>(), *url, 495*9838eb20SEd Tanous getIoContext()); 496e5aaf047SAppaRao Puli 497e5aaf047SAppaRao Puli if (subscriptionType) 498e5aaf047SAppaRao Puli { 499e5aaf047SAppaRao Puli if (*subscriptionType != "RedfishEvent") 500e5aaf047SAppaRao Puli { 501fffb8c1fSEd Tanous messages::propertyValueNotInList( 502fffb8c1fSEd Tanous asyncResp->res, *subscriptionType, "SubscriptionType"); 503e5aaf047SAppaRao Puli return; 504e5aaf047SAppaRao Puli } 5055fe4ef35SMyung Bae subValue->userSub->subscriptionType = *subscriptionType; 506e5aaf047SAppaRao Puli } 507e5aaf047SAppaRao Puli else 508e5aaf047SAppaRao Puli { 5094b712a29SEd Tanous // Default 5105fe4ef35SMyung Bae subValue->userSub->subscriptionType = "RedfishEvent"; 511e5aaf047SAppaRao Puli } 512e5aaf047SAppaRao Puli 513e5aaf047SAppaRao Puli if (protocol != "Redfish") 514e5aaf047SAppaRao Puli { 515e5aaf047SAppaRao Puli messages::propertyValueNotInList(asyncResp->res, protocol, 516e5aaf047SAppaRao Puli "Protocol"); 517e5aaf047SAppaRao Puli return; 518e5aaf047SAppaRao Puli } 5195fe4ef35SMyung Bae subValue->userSub->protocol = protocol; 520e5aaf047SAppaRao Puli 52119bb362bSEd Tanous if (verifyCertificate) 52219bb362bSEd Tanous { 5235fe4ef35SMyung Bae subValue->userSub->verifyCertificate = *verifyCertificate; 52419bb362bSEd Tanous } 52519bb362bSEd Tanous 52623a21a1cSEd Tanous if (eventFormatType2) 527e5aaf047SAppaRao Puli { 528bd79bce8SPatrick Williams if (std::ranges::find(supportedEvtFormatTypes, 529bd79bce8SPatrick Williams *eventFormatType2) == 5303544d2a7SEd Tanous supportedEvtFormatTypes.end()) 531e5aaf047SAppaRao Puli { 532fffb8c1fSEd Tanous messages::propertyValueNotInList( 533fffb8c1fSEd Tanous asyncResp->res, *eventFormatType2, "EventFormatType"); 534e5aaf047SAppaRao Puli return; 535e5aaf047SAppaRao Puli } 5365fe4ef35SMyung Bae subValue->userSub->eventFormatType = *eventFormatType2; 537e5aaf047SAppaRao Puli } 538e5aaf047SAppaRao Puli else 539e5aaf047SAppaRao Puli { 540e5aaf047SAppaRao Puli // If not specified, use default "Event" 5415fe4ef35SMyung Bae subValue->userSub->eventFormatType = "Event"; 542e5aaf047SAppaRao Puli } 543e5aaf047SAppaRao Puli 544e5aaf047SAppaRao Puli if (context) 545e5aaf047SAppaRao Puli { 5468ece0e45SEd Tanous // This value is selected arbitrarily. 547600af5f1SAppaRao Puli constexpr const size_t maxContextSize = 256; 548600af5f1SAppaRao Puli if (context->size() > maxContextSize) 549600af5f1SAppaRao Puli { 550600af5f1SAppaRao Puli messages::stringValueTooLong(asyncResp->res, "Context", 551600af5f1SAppaRao Puli maxContextSize); 552600af5f1SAppaRao Puli return; 553600af5f1SAppaRao Puli } 5545fe4ef35SMyung Bae subValue->userSub->customText = *context; 555e5aaf047SAppaRao Puli } 556e5aaf047SAppaRao Puli 557e5aaf047SAppaRao Puli if (headers) 558e5aaf047SAppaRao Puli { 559600af5f1SAppaRao Puli size_t cumulativeLen = 0; 560600af5f1SAppaRao Puli 56178d4ec4fSEd Tanous for (const nlohmann::json::object_t& headerChunk : *headers) 562601c71aeSEd Tanous { 56378d4ec4fSEd Tanous for (const auto& item : headerChunk) 56478d4ec4fSEd Tanous { 56578d4ec4fSEd Tanous const std::string* value = 56678d4ec4fSEd Tanous item.second.get_ptr<const std::string*>(); 56778d4ec4fSEd Tanous if (value == nullptr) 56878d4ec4fSEd Tanous { 56978d4ec4fSEd Tanous messages::propertyValueFormatError( 57078d4ec4fSEd Tanous asyncResp->res, item.second, 57178d4ec4fSEd Tanous "HttpHeaders/" + item.first); 57278d4ec4fSEd Tanous return; 57378d4ec4fSEd Tanous } 57478d4ec4fSEd Tanous // Adding a new json value is the size of the key, + 57578d4ec4fSEd Tanous // the size of the value + 2 * 2 quotes for each, + 57678d4ec4fSEd Tanous // the colon and space between. example: 57778d4ec4fSEd Tanous // "key": "value" 57878d4ec4fSEd Tanous cumulativeLen += item.first.size() + value->size() + 6; 579600af5f1SAppaRao Puli // This value is selected to mirror http_connection.hpp 580600af5f1SAppaRao Puli constexpr const uint16_t maxHeaderSizeED = 8096; 581600af5f1SAppaRao Puli if (cumulativeLen > maxHeaderSizeED) 582600af5f1SAppaRao Puli { 58378d4ec4fSEd Tanous messages::arraySizeTooLong( 58478d4ec4fSEd Tanous asyncResp->res, "HttpHeaders", maxHeaderSizeED); 585600af5f1SAppaRao Puli return; 586600af5f1SAppaRao Puli } 5875fe4ef35SMyung Bae subValue->userSub->httpHeaders.set(item.first, *value); 588601c71aeSEd Tanous } 589601c71aeSEd Tanous } 590e5aaf047SAppaRao Puli } 591e5aaf047SAppaRao Puli 592e5aaf047SAppaRao Puli if (regPrefixes) 593e5aaf047SAppaRao Puli { 594e5aaf047SAppaRao Puli for (const std::string& it : *regPrefixes) 595e5aaf047SAppaRao Puli { 5963544d2a7SEd Tanous if (std::ranges::find(supportedRegPrefixes, it) == 5973544d2a7SEd Tanous supportedRegPrefixes.end()) 598e5aaf047SAppaRao Puli { 599fffb8c1fSEd Tanous messages::propertyValueNotInList(asyncResp->res, it, 600fffb8c1fSEd Tanous "RegistryPrefixes"); 601e5aaf047SAppaRao Puli return; 602e5aaf047SAppaRao Puli } 603e5aaf047SAppaRao Puli } 6045fe4ef35SMyung Bae subValue->userSub->registryPrefixes = *regPrefixes; 605e5aaf047SAppaRao Puli } 606e5aaf047SAppaRao Puli 607a14c9113SEd Tanous if (originResources) 608a14c9113SEd Tanous { 6095fe4ef35SMyung Bae subValue->userSub->originResources = *originResources; 610a14c9113SEd Tanous } 611a14c9113SEd Tanous 612e56f254cSSunitha Harish if (resTypes) 613e56f254cSSunitha Harish { 614e56f254cSSunitha Harish for (const std::string& it : *resTypes) 615e56f254cSSunitha Harish { 6163544d2a7SEd Tanous if (std::ranges::find(supportedResourceTypes, it) == 6173544d2a7SEd Tanous supportedResourceTypes.end()) 618e56f254cSSunitha Harish { 619e56f254cSSunitha Harish messages::propertyValueNotInList(asyncResp->res, it, 620e56f254cSSunitha Harish "ResourceTypes"); 621e56f254cSSunitha Harish return; 622e56f254cSSunitha Harish } 623e56f254cSSunitha Harish } 6245fe4ef35SMyung Bae subValue->userSub->resourceTypes = *resTypes; 625e56f254cSSunitha Harish } 626e56f254cSSunitha Harish 627e5aaf047SAppaRao Puli if (msgIds) 628e5aaf047SAppaRao Puli { 629b304bd79SP Dheeraj Srujan Kumar std::vector<std::string> registryPrefix; 630b304bd79SP Dheeraj Srujan Kumar 6317e860f15SJohn Edward Broadbent // If no registry prefixes are mentioned, consider all 6327e860f15SJohn Edward Broadbent // supported prefixes 6335fe4ef35SMyung Bae if (subValue->userSub->registryPrefixes.empty()) 634b304bd79SP Dheeraj Srujan Kumar { 635b304bd79SP Dheeraj Srujan Kumar registryPrefix.assign(supportedRegPrefixes.begin(), 636b304bd79SP Dheeraj Srujan Kumar supportedRegPrefixes.end()); 637b304bd79SP Dheeraj Srujan Kumar } 638b304bd79SP Dheeraj Srujan Kumar else 639b304bd79SP Dheeraj Srujan Kumar { 6405fe4ef35SMyung Bae registryPrefix = subValue->userSub->registryPrefixes; 641b304bd79SP Dheeraj Srujan Kumar } 642b304bd79SP Dheeraj Srujan Kumar 643b304bd79SP Dheeraj Srujan Kumar for (const std::string& id : *msgIds) 644b304bd79SP Dheeraj Srujan Kumar { 645b304bd79SP Dheeraj Srujan Kumar bool validId = false; 646b304bd79SP Dheeraj Srujan Kumar 647b304bd79SP Dheeraj Srujan Kumar // Check for Message ID in each of the selected Registry 648b304bd79SP Dheeraj Srujan Kumar for (const std::string& it : registryPrefix) 649b304bd79SP Dheeraj Srujan Kumar { 650fffb8c1fSEd Tanous const std::span<const redfish::registries::MessageEntry> 651fffb8c1fSEd Tanous registry = 652fffb8c1fSEd Tanous redfish::registries::getRegistryFromPrefix(it); 653b304bd79SP Dheeraj Srujan Kumar 6543544d2a7SEd Tanous if (std::ranges::any_of( 6553544d2a7SEd Tanous registry, 656fffb8c1fSEd Tanous [&id](const redfish::registries::MessageEntry& 657fffb8c1fSEd Tanous messageEntry) { 65855f79e6fSEd Tanous return id == messageEntry.first; 659b304bd79SP Dheeraj Srujan Kumar })) 660b304bd79SP Dheeraj Srujan Kumar { 661b304bd79SP Dheeraj Srujan Kumar validId = true; 662b304bd79SP Dheeraj Srujan Kumar break; 663b304bd79SP Dheeraj Srujan Kumar } 664b304bd79SP Dheeraj Srujan Kumar } 665b304bd79SP Dheeraj Srujan Kumar 666b304bd79SP Dheeraj Srujan Kumar if (!validId) 667b304bd79SP Dheeraj Srujan Kumar { 668b304bd79SP Dheeraj Srujan Kumar messages::propertyValueNotInList(asyncResp->res, id, 669b304bd79SP Dheeraj Srujan Kumar "MessageIds"); 670b304bd79SP Dheeraj Srujan Kumar return; 671b304bd79SP Dheeraj Srujan Kumar } 672b304bd79SP Dheeraj Srujan Kumar } 673b304bd79SP Dheeraj Srujan Kumar 6745fe4ef35SMyung Bae subValue->userSub->registryMsgIds = *msgIds; 675e5aaf047SAppaRao Puli } 676e5aaf047SAppaRao Puli 677e5aaf047SAppaRao Puli if (retryPolicy) 678e5aaf047SAppaRao Puli { 6793544d2a7SEd Tanous if (std::ranges::find(supportedRetryPolicies, *retryPolicy) == 6803544d2a7SEd Tanous supportedRetryPolicies.end()) 681e5aaf047SAppaRao Puli { 682bd79bce8SPatrick Williams messages::propertyValueNotInList( 683bd79bce8SPatrick Williams asyncResp->res, *retryPolicy, "DeliveryRetryPolicy"); 684e5aaf047SAppaRao Puli return; 685e5aaf047SAppaRao Puli } 6865fe4ef35SMyung Bae subValue->userSub->retryPolicy = *retryPolicy; 687e5aaf047SAppaRao Puli } 688e5aaf047SAppaRao Puli else 689e5aaf047SAppaRao Puli { 690e5aaf047SAppaRao Puli // Default "TerminateAfterRetries" 6915fe4ef35SMyung Bae subValue->userSub->retryPolicy = "TerminateAfterRetries"; 692e5aaf047SAppaRao Puli } 6935064a25bSMyung Bae if (sendHeartbeat) 6945064a25bSMyung Bae { 6955064a25bSMyung Bae subValue->userSub->sendHeartbeat = *sendHeartbeat; 6965064a25bSMyung Bae } 6975064a25bSMyung Bae if (hbIntervalMinutes) 6985064a25bSMyung Bae { 6995064a25bSMyung Bae if (*hbIntervalMinutes < 1 || *hbIntervalMinutes > 65535) 7005064a25bSMyung Bae { 7015064a25bSMyung Bae messages::propertyValueOutOfRange( 7025064a25bSMyung Bae asyncResp->res, *hbIntervalMinutes, 7035064a25bSMyung Bae "HeartbeatIntervalMinutes"); 7045064a25bSMyung Bae return; 7055064a25bSMyung Bae } 7065064a25bSMyung Bae subValue->userSub->hbIntervalMinutes = *hbIntervalMinutes; 7075064a25bSMyung Bae } 708e5aaf047SAppaRao Puli 709144b6318SAppaRao Puli if (mrdJsonArray) 710156d6b00SAppaRao Puli { 71178d4ec4fSEd Tanous for (nlohmann::json::object_t& mrdObj : *mrdJsonArray) 712144b6318SAppaRao Puli { 713144b6318SAppaRao Puli std::string mrdUri; 714ea2e6eecSWilly Tu 71578d4ec4fSEd Tanous if (!json_util::readJsonObject(mrdObj, asyncResp->res, 71678d4ec4fSEd Tanous "@odata.id", mrdUri)) 717ea2e6eecSWilly Tu 718144b6318SAppaRao Puli { 719144b6318SAppaRao Puli return; 720144b6318SAppaRao Puli } 7215fe4ef35SMyung Bae subValue->userSub->metricReportDefinitions.emplace_back( 7224b712a29SEd Tanous mrdUri); 723144b6318SAppaRao Puli } 724156d6b00SAppaRao Puli } 725156d6b00SAppaRao Puli 726b52664e2SAppaRao Puli std::string id = 727bd79bce8SPatrick Williams EventServiceManager::getInstance().addPushSubscription( 728bd79bce8SPatrick Williams subValue); 729b52664e2SAppaRao Puli if (id.empty()) 730e5aaf047SAppaRao Puli { 731e5aaf047SAppaRao Puli messages::internalError(asyncResp->res); 732e5aaf047SAppaRao Puli return; 733e5aaf047SAppaRao Puli } 734e5aaf047SAppaRao Puli 735e5aaf047SAppaRao Puli messages::created(asyncResp->res); 736e5aaf047SAppaRao Puli asyncResp->res.addHeader( 737e5aaf047SAppaRao Puli "Location", "/redfish/v1/EventService/Subscriptions/" + id); 738fb546105SMyung Bae 739fb546105SMyung Bae // schedule a heartbeat 740fb546105SMyung Bae if (subValue->userSub->sendHeartbeat) 741fb546105SMyung Bae { 742fb546105SMyung Bae subValue->scheduleNextHeartbeatEvent(); 743fb546105SMyung Bae } 7447e860f15SJohn Edward Broadbent }); 745e5aaf047SAppaRao Puli } 746e5aaf047SAppaRao Puli 7477e860f15SJohn Edward Broadbent inline void requestRoutesEventDestination(App& app) 748e5aaf047SAppaRao Puli { 7499d41aec6SRavi Teja BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/<str>/") 750ed398213SEd Tanous .privileges(redfish::privileges::getEventDestination) 7517e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 75245ca1b86SEd Tanous [&app](const crow::Request& req, 7537e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 7547e860f15SJohn Edward Broadbent const std::string& param) { 7553ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 75645ca1b86SEd Tanous { 75745ca1b86SEd Tanous return; 75845ca1b86SEd Tanous } 7593d30708fSChicago Duan 7603d30708fSChicago Duan if (param.starts_with("snmp")) 7613d30708fSChicago Duan { 7623d30708fSChicago Duan getSnmpTrapClient(asyncResp, param); 7633d30708fSChicago Duan return; 7643d30708fSChicago Duan } 7653d30708fSChicago Duan 766b52664e2SAppaRao Puli std::shared_ptr<Subscription> subValue = 7677e860f15SJohn Edward Broadbent EventServiceManager::getInstance().getSubscription(param); 768b52664e2SAppaRao Puli if (subValue == nullptr) 769e5aaf047SAppaRao Puli { 770bd79bce8SPatrick Williams asyncResp->res.result( 771bd79bce8SPatrick Williams boost::beast::http::status::not_found); 772e5aaf047SAppaRao Puli return; 773e5aaf047SAppaRao Puli } 7747e860f15SJohn Edward Broadbent const std::string& id = param; 775e5aaf047SAppaRao Puli 7764b712a29SEd Tanous const persistent_data::UserSubscription& userSub = 7775fe4ef35SMyung Bae *subValue->userSub; 778e56f254cSSunitha Harish 7794b712a29SEd Tanous nlohmann::json& jVal = asyncResp->res.jsonValue; 7804b712a29SEd Tanous jVal["@odata.type"] = 7814b712a29SEd Tanous "#EventDestination.v1_14_1.EventDestination"; 7824b712a29SEd Tanous jVal["Protocol"] = 7834b712a29SEd Tanous event_destination::EventDestinationProtocol::Redfish; 7844b712a29SEd Tanous jVal["@odata.id"] = boost::urls::format( 7854b712a29SEd Tanous "/redfish/v1/EventService/Subscriptions/{}", id); 7864b712a29SEd Tanous jVal["Id"] = id; 7874b712a29SEd Tanous jVal["Name"] = "Event Destination " + id; 7884b712a29SEd Tanous jVal["Destination"] = userSub.destinationUrl; 7894b712a29SEd Tanous jVal["Context"] = userSub.customText; 7904b712a29SEd Tanous jVal["SubscriptionType"] = userSub.subscriptionType; 7914b712a29SEd Tanous jVal["HttpHeaders"] = nlohmann::json::array(); 7924b712a29SEd Tanous jVal["EventFormatType"] = userSub.eventFormatType; 7934b712a29SEd Tanous jVal["RegistryPrefixes"] = userSub.registryPrefixes; 7944b712a29SEd Tanous jVal["ResourceTypes"] = userSub.resourceTypes; 7954b712a29SEd Tanous 7964b712a29SEd Tanous jVal["MessageIds"] = userSub.registryMsgIds; 7974b712a29SEd Tanous jVal["DeliveryRetryPolicy"] = userSub.retryPolicy; 7985064a25bSMyung Bae jVal["SendHeartbeat"] = userSub.sendHeartbeat; 7995064a25bSMyung Bae jVal["HeartbeatIntervalMinutes"] = userSub.hbIntervalMinutes; 8004b712a29SEd Tanous jVal["VerifyCertificate"] = userSub.verifyCertificate; 801144b6318SAppaRao Puli 8021476687dSEd Tanous nlohmann::json::array_t mrdJsonArray; 8034b712a29SEd Tanous for (const auto& mdrUri : userSub.metricReportDefinitions) 804144b6318SAppaRao Puli { 8051476687dSEd Tanous nlohmann::json::object_t mdr; 8061476687dSEd Tanous mdr["@odata.id"] = mdrUri; 8071476687dSEd Tanous mrdJsonArray.emplace_back(std::move(mdr)); 808144b6318SAppaRao Puli } 8094b712a29SEd Tanous jVal["MetricReportDefinitions"] = mrdJsonArray; 8107e860f15SJohn Edward Broadbent }); 8119d41aec6SRavi Teja BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/<str>/") 812ed398213SEd Tanous // The below privilege is wrong, it should be ConfigureManager OR 813ed398213SEd Tanous // ConfigureSelf 8147eeafa76SAbhishek Patel // https://github.com/openbmc/bmcweb/issues/220 815ed398213SEd Tanous //.privileges(redfish::privileges::patchEventDestination) 816432a890cSEd Tanous .privileges({{"ConfigureManager"}}) 8177e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::patch)( 81845ca1b86SEd Tanous [&app](const crow::Request& req, 8197e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 8207e860f15SJohn Edward Broadbent const std::string& param) { 8213ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 82245ca1b86SEd Tanous { 82345ca1b86SEd Tanous return; 82445ca1b86SEd Tanous } 825b52664e2SAppaRao Puli std::shared_ptr<Subscription> subValue = 8267e860f15SJohn Edward Broadbent EventServiceManager::getInstance().getSubscription(param); 827b52664e2SAppaRao Puli if (subValue == nullptr) 828e5aaf047SAppaRao Puli { 829bd79bce8SPatrick Williams asyncResp->res.result( 830bd79bce8SPatrick Williams boost::beast::http::status::not_found); 831e5aaf047SAppaRao Puli return; 832e5aaf047SAppaRao Puli } 833e5aaf047SAppaRao Puli 834e5aaf047SAppaRao Puli std::optional<std::string> context; 835e5aaf047SAppaRao Puli std::optional<std::string> retryPolicy; 8365064a25bSMyung Bae std::optional<bool> sendHeartbeat; 8375064a25bSMyung Bae std::optional<uint64_t> hbIntervalMinutes; 83819bb362bSEd Tanous std::optional<bool> verifyCertificate; 83978d4ec4fSEd Tanous std::optional<std::vector<nlohmann::json::object_t>> headers; 840e5aaf047SAppaRao Puli 841afc474aeSMyung Bae if (!json_util::readJsonPatch( // 842afc474aeSMyung Bae req, asyncResp->res, // 843afc474aeSMyung Bae "Context", context, // 844afc474aeSMyung Bae "DeliveryRetryPolicy", retryPolicy, // 8455064a25bSMyung Bae "HeartbeatIntervalMinutes", hbIntervalMinutes, // 846afc474aeSMyung Bae "HttpHeaders", headers, // 8475064a25bSMyung Bae "SendHeartbeat", sendHeartbeat, // 848afc474aeSMyung Bae "VerifyCertificate", verifyCertificate // 849afc474aeSMyung Bae )) 850e5aaf047SAppaRao Puli { 851e5aaf047SAppaRao Puli return; 852e5aaf047SAppaRao Puli } 853e5aaf047SAppaRao Puli 854e5aaf047SAppaRao Puli if (context) 855e5aaf047SAppaRao Puli { 8565fe4ef35SMyung Bae subValue->userSub->customText = *context; 857e5aaf047SAppaRao Puli } 858e5aaf047SAppaRao Puli 859e5aaf047SAppaRao Puli if (headers) 860e5aaf047SAppaRao Puli { 861601c71aeSEd Tanous boost::beast::http::fields fields; 86278d4ec4fSEd Tanous for (const nlohmann::json::object_t& headerChunk : *headers) 863601c71aeSEd Tanous { 86478d4ec4fSEd Tanous for (const auto& it : headerChunk) 865601c71aeSEd Tanous { 866601c71aeSEd Tanous const std::string* value = 86778d4ec4fSEd Tanous it.second.get_ptr<const std::string*>(); 868601c71aeSEd Tanous if (value == nullptr) 869601c71aeSEd Tanous { 870601c71aeSEd Tanous messages::propertyValueFormatError( 87178d4ec4fSEd Tanous asyncResp->res, it.second, 87278d4ec4fSEd Tanous "HttpHeaders/" + it.first); 873601c71aeSEd Tanous return; 874601c71aeSEd Tanous } 87578d4ec4fSEd Tanous fields.set(it.first, *value); 876601c71aeSEd Tanous } 877601c71aeSEd Tanous } 8785fe4ef35SMyung Bae subValue->userSub->httpHeaders = std::move(fields); 879e5aaf047SAppaRao Puli } 880e5aaf047SAppaRao Puli 881e5aaf047SAppaRao Puli if (retryPolicy) 882e5aaf047SAppaRao Puli { 883bd79bce8SPatrick Williams if (std::ranges::find(supportedRetryPolicies, 884bd79bce8SPatrick Williams *retryPolicy) == 8853544d2a7SEd Tanous supportedRetryPolicies.end()) 886e5aaf047SAppaRao Puli { 887bd79bce8SPatrick Williams messages::propertyValueNotInList(asyncResp->res, 888bd79bce8SPatrick Williams *retryPolicy, 889e5aaf047SAppaRao Puli "DeliveryRetryPolicy"); 890e5aaf047SAppaRao Puli return; 891e5aaf047SAppaRao Puli } 8925fe4ef35SMyung Bae subValue->userSub->retryPolicy = *retryPolicy; 893e5aaf047SAppaRao Puli } 894e5aaf047SAppaRao Puli 8955064a25bSMyung Bae if (sendHeartbeat) 8965064a25bSMyung Bae { 8975064a25bSMyung Bae subValue->userSub->sendHeartbeat = *sendHeartbeat; 8985064a25bSMyung Bae } 8995064a25bSMyung Bae if (hbIntervalMinutes) 9005064a25bSMyung Bae { 9015064a25bSMyung Bae if (*hbIntervalMinutes < 1 || *hbIntervalMinutes > 65535) 9025064a25bSMyung Bae { 9035064a25bSMyung Bae messages::propertyValueOutOfRange( 9045064a25bSMyung Bae asyncResp->res, *hbIntervalMinutes, 9055064a25bSMyung Bae "HeartbeatIntervalMinutes"); 9065064a25bSMyung Bae return; 9075064a25bSMyung Bae } 9085064a25bSMyung Bae subValue->userSub->hbIntervalMinutes = *hbIntervalMinutes; 9095064a25bSMyung Bae } 9105064a25bSMyung Bae 911fb546105SMyung Bae if (hbIntervalMinutes || sendHeartbeat) 912fb546105SMyung Bae { 913fb546105SMyung Bae // if Heartbeat interval or send heart were changed, cancel 914fb546105SMyung Bae // the heartbeat timer if running and start a new heartbeat 915fb546105SMyung Bae // if needed 916fb546105SMyung Bae subValue->heartbeatParametersChanged(); 917fb546105SMyung Bae } 918fb546105SMyung Bae 91919bb362bSEd Tanous if (verifyCertificate) 92019bb362bSEd Tanous { 9215fe4ef35SMyung Bae subValue->userSub->verifyCertificate = *verifyCertificate; 92219bb362bSEd Tanous } 92319bb362bSEd Tanous 924b52664e2SAppaRao Puli EventServiceManager::getInstance().updateSubscriptionData(); 9257e860f15SJohn Edward Broadbent }); 9269d41aec6SRavi Teja BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/<str>/") 927ed398213SEd Tanous // The below privilege is wrong, it should be ConfigureManager OR 928ed398213SEd Tanous // ConfigureSelf 9297eeafa76SAbhishek Patel // https://github.com/openbmc/bmcweb/issues/220 930ed398213SEd Tanous //.privileges(redfish::privileges::deleteEventDestination) 931432a890cSEd Tanous .privileges({{"ConfigureManager"}}) 9327e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::delete_)( 93345ca1b86SEd Tanous [&app](const crow::Request& req, 9347e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 9357e860f15SJohn Edward Broadbent const std::string& param) { 9363ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 93745ca1b86SEd Tanous { 93845ca1b86SEd Tanous return; 93945ca1b86SEd Tanous } 9404b712a29SEd Tanous EventServiceManager& event = EventServiceManager::getInstance(); 9413d30708fSChicago Duan if (param.starts_with("snmp")) 9423d30708fSChicago Duan { 9433d30708fSChicago Duan deleteSnmpTrapClient(asyncResp, param); 9444b712a29SEd Tanous event.deleteSubscription(param); 9453d30708fSChicago Duan return; 9463d30708fSChicago Duan } 9473d30708fSChicago Duan 9484b712a29SEd Tanous if (!event.deleteSubscription(param)) 949e5aaf047SAppaRao Puli { 9504b712a29SEd Tanous messages::resourceNotFound(asyncResp->res, 9514b712a29SEd Tanous "EventDestination", param); 952e5aaf047SAppaRao Puli return; 953e5aaf047SAppaRao Puli } 9544b712a29SEd Tanous messages::success(asyncResp->res); 9557e860f15SJohn Edward Broadbent }); 956e5aaf047SAppaRao Puli } 957e5aaf047SAppaRao Puli 958e5aaf047SAppaRao Puli } // namespace redfish 959