1*40e9b92eSEd Tanous // SPDX-License-Identifier: Apache-2.0 2*40e9b92eSEd Tanous // SPDX-FileCopyrightText: Copyright OpenBMC Authors 3*40e9b92eSEd Tanous // SPDX-FileCopyrightText: Copyright 2020 Intel Corporation 4e5aaf047SAppaRao Puli #pragma once 53ccb3adbSEd Tanous #include "app.hpp" 6b52664e2SAppaRao Puli #include "event_service_manager.hpp" 7539d8c6bSEd Tanous #include "generated/enums/event_service.hpp" 83ccb3adbSEd Tanous #include "http/utility.hpp" 93ccb3adbSEd Tanous #include "logging.hpp" 103ccb3adbSEd Tanous #include "query.hpp" 11d109e2b6SAlexander Hansen #include "registries.hpp" 123ccb3adbSEd Tanous #include "registries/privilege_registry.hpp" 13d109e2b6SAlexander Hansen #include "registries_selector.hpp" 143d30708fSChicago Duan #include "snmp_trap_event_clients.hpp" 15d109e2b6SAlexander Hansen #include "utils/json_utils.hpp" 16e5aaf047SAppaRao Puli 17601c71aeSEd Tanous #include <boost/beast/http/fields.hpp> 183d30708fSChicago Duan #include <boost/system/error_code.hpp> 19a716aa74SEd Tanous #include <boost/url/parse.hpp> 203d30708fSChicago Duan #include <sdbusplus/unpack_properties.hpp> 213d30708fSChicago Duan #include <utils/dbus_utils.hpp> 22ed398213SEd Tanous 233d30708fSChicago Duan #include <charconv> 243d30708fSChicago Duan #include <memory> 255064a25bSMyung Bae #include <optional> 263544d2a7SEd Tanous #include <ranges> 271e270c5fSPatrick Williams #include <span> 283d30708fSChicago Duan #include <string> 29a14c9113SEd Tanous #include <vector> 301e270c5fSPatrick Williams 31e5aaf047SAppaRao Puli namespace redfish 32e5aaf047SAppaRao Puli { 33e5aaf047SAppaRao Puli 34156d6b00SAppaRao Puli static constexpr const std::array<const char*, 2> supportedEvtFormatTypes = { 35156d6b00SAppaRao Puli eventFormatType, metricReportFormatType}; 36fb546105SMyung Bae static constexpr const std::array<const char*, 4> supportedRegPrefixes = { 37fb546105SMyung Bae "Base", "OpenBMC", "TaskEvent", "HeartbeatEvent"}; 38e5aaf047SAppaRao Puli static constexpr const std::array<const char*, 3> supportedRetryPolicies = { 39e5aaf047SAppaRao Puli "TerminateAfterRetries", "SuspendRetries", "RetryForever"}; 40e5aaf047SAppaRao Puli 41fb546105SMyung Bae static constexpr const std::array<const char*, 2> supportedResourceTypes = { 42fb546105SMyung Bae "Task", "Heartbeat"}; 43e56f254cSSunitha Harish 447e860f15SJohn Edward Broadbent inline void requestRoutesEventService(App& app) 45e5aaf047SAppaRao Puli { 467e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, "/redfish/v1/EventService/") 47ed398213SEd Tanous .privileges(redfish::privileges::getEventService) 48bd79bce8SPatrick Williams .methods( 49bd79bce8SPatrick Williams boost::beast::http::verb:: 50bd79bce8SPatrick Williams get)([&app]( 51bd79bce8SPatrick Williams const crow::Request& req, 52002d39b4SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 533ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 5445ca1b86SEd Tanous { 5545ca1b86SEd Tanous return; 5645ca1b86SEd Tanous } 571476687dSEd Tanous 581476687dSEd Tanous asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/EventService"; 591476687dSEd Tanous asyncResp->res.jsonValue["@odata.type"] = 601476687dSEd Tanous "#EventService.v1_5_0.EventService"; 611476687dSEd Tanous asyncResp->res.jsonValue["Id"] = "EventService"; 621476687dSEd Tanous asyncResp->res.jsonValue["Name"] = "Event Service"; 635e44e3d8SAppaRao Puli asyncResp->res.jsonValue["ServerSentEventUri"] = 645e44e3d8SAppaRao Puli "/redfish/v1/EventService/SSE"; 655e44e3d8SAppaRao Puli 661476687dSEd Tanous asyncResp->res.jsonValue["Subscriptions"]["@odata.id"] = 671476687dSEd Tanous "/redfish/v1/EventService/Subscriptions"; 68bd79bce8SPatrick Williams asyncResp->res.jsonValue["Actions"]["#EventService.SubmitTestEvent"] 69bd79bce8SPatrick Williams ["target"] = 701476687dSEd Tanous "/redfish/v1/EventService/Actions/EventService.SubmitTestEvent"; 71e5aaf047SAppaRao Puli 7228afb49cSJunLin Chen const persistent_data::EventServiceConfig eventServiceConfig = 7328afb49cSJunLin Chen persistent_data::EventServiceStore::getInstance() 7428afb49cSJunLin Chen .getEventServiceConfig(); 757d1cc387SAppaRao Puli 767d1cc387SAppaRao Puli asyncResp->res.jsonValue["Status"]["State"] = 7728afb49cSJunLin Chen (eventServiceConfig.enabled ? "Enabled" : "Disabled"); 78bd79bce8SPatrick Williams asyncResp->res.jsonValue["ServiceEnabled"] = 79bd79bce8SPatrick Williams eventServiceConfig.enabled; 807e860f15SJohn Edward Broadbent asyncResp->res.jsonValue["DeliveryRetryAttempts"] = 8128afb49cSJunLin Chen eventServiceConfig.retryAttempts; 82e5aaf047SAppaRao Puli asyncResp->res.jsonValue["DeliveryRetryIntervalSeconds"] = 8328afb49cSJunLin Chen eventServiceConfig.retryTimeoutInterval; 84bd79bce8SPatrick Williams asyncResp->res.jsonValue["EventFormatTypes"] = 85bd79bce8SPatrick Williams supportedEvtFormatTypes; 860fda0f12SGeorge Liu asyncResp->res.jsonValue["RegistryPrefixes"] = supportedRegPrefixes; 870fda0f12SGeorge Liu asyncResp->res.jsonValue["ResourceTypes"] = supportedResourceTypes; 8807941a88SAyushi Smriti 89613dabeaSEd Tanous nlohmann::json::object_t supportedSSEFilters; 90613dabeaSEd Tanous supportedSSEFilters["EventFormatType"] = true; 91613dabeaSEd Tanous supportedSSEFilters["MessageId"] = true; 92613dabeaSEd Tanous supportedSSEFilters["MetricReportDefinition"] = true; 93613dabeaSEd Tanous supportedSSEFilters["RegistryPrefix"] = true; 94613dabeaSEd Tanous supportedSSEFilters["OriginResource"] = false; 95613dabeaSEd Tanous supportedSSEFilters["ResourceType"] = false; 9607941a88SAyushi Smriti 9707941a88SAyushi Smriti asyncResp->res.jsonValue["SSEFilterPropertiesSupported"] = 98613dabeaSEd Tanous std::move(supportedSSEFilters); 997e860f15SJohn Edward Broadbent }); 100e5aaf047SAppaRao Puli 1017e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, "/redfish/v1/EventService/") 102ed398213SEd Tanous .privileges(redfish::privileges::patchEventService) 1037e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::patch)( 10445ca1b86SEd Tanous [&app](const crow::Request& req, 10545ca1b86SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 1063ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 107e5aaf047SAppaRao Puli { 10845ca1b86SEd Tanous return; 10945ca1b86SEd Tanous } 110e5aaf047SAppaRao Puli std::optional<bool> serviceEnabled; 111e5aaf047SAppaRao Puli std::optional<uint32_t> retryAttemps; 112e5aaf047SAppaRao Puli std::optional<uint32_t> retryInterval; 113afc474aeSMyung Bae if (!json_util::readJsonPatch( // 114afc474aeSMyung Bae req, asyncResp->res, // 115afc474aeSMyung Bae "DeliveryRetryAttempts", retryAttemps, // 116afc474aeSMyung Bae "DeliveryRetryIntervalSeconds", retryInterval, // 117afc474aeSMyung Bae "ServiceEnabled", serviceEnabled // 118afc474aeSMyung Bae )) 119e5aaf047SAppaRao Puli { 120e5aaf047SAppaRao Puli return; 121e5aaf047SAppaRao Puli } 122e5aaf047SAppaRao Puli 12328afb49cSJunLin Chen persistent_data::EventServiceConfig eventServiceConfig = 12428afb49cSJunLin Chen persistent_data::EventServiceStore::getInstance() 12528afb49cSJunLin Chen .getEventServiceConfig(); 1267d1cc387SAppaRao Puli 127e5aaf047SAppaRao Puli if (serviceEnabled) 128e5aaf047SAppaRao Puli { 12928afb49cSJunLin Chen eventServiceConfig.enabled = *serviceEnabled; 130e5aaf047SAppaRao Puli } 131e5aaf047SAppaRao Puli 132e5aaf047SAppaRao Puli if (retryAttemps) 133e5aaf047SAppaRao Puli { 134e5aaf047SAppaRao Puli // Supported range [1-3] 135e5aaf047SAppaRao Puli if ((*retryAttemps < 1) || (*retryAttemps > 3)) 136e5aaf047SAppaRao Puli { 137e5aaf047SAppaRao Puli messages::queryParameterOutOfRange( 138e5aaf047SAppaRao Puli asyncResp->res, std::to_string(*retryAttemps), 139e5aaf047SAppaRao Puli "DeliveryRetryAttempts", "[1-3]"); 140e5aaf047SAppaRao Puli } 141e5aaf047SAppaRao Puli else 142e5aaf047SAppaRao Puli { 14328afb49cSJunLin Chen eventServiceConfig.retryAttempts = *retryAttemps; 144e5aaf047SAppaRao Puli } 145e5aaf047SAppaRao Puli } 146e5aaf047SAppaRao Puli 147e5aaf047SAppaRao Puli if (retryInterval) 148e5aaf047SAppaRao Puli { 14933a32b34SGunnar Mills // Supported range [5 - 180] 15033a32b34SGunnar Mills if ((*retryInterval < 5) || (*retryInterval > 180)) 151e5aaf047SAppaRao Puli { 152e5aaf047SAppaRao Puli messages::queryParameterOutOfRange( 153e5aaf047SAppaRao Puli asyncResp->res, std::to_string(*retryInterval), 15433a32b34SGunnar Mills "DeliveryRetryIntervalSeconds", "[5-180]"); 155e5aaf047SAppaRao Puli } 156e5aaf047SAppaRao Puli else 157e5aaf047SAppaRao Puli { 158bd79bce8SPatrick Williams eventServiceConfig.retryTimeoutInterval = 159bd79bce8SPatrick Williams *retryInterval; 160e5aaf047SAppaRao Puli } 161e5aaf047SAppaRao Puli } 162e5aaf047SAppaRao Puli 1637d1cc387SAppaRao Puli EventServiceManager::getInstance().setEventServiceConfig( 16428afb49cSJunLin Chen eventServiceConfig); 1657e860f15SJohn Edward Broadbent }); 1660b4bdd93SAppaRao Puli } 1670b4bdd93SAppaRao Puli 1687e860f15SJohn Edward Broadbent inline void requestRoutesSubmitTestEvent(App& app) 1690b4bdd93SAppaRao Puli { 1707e860f15SJohn Edward Broadbent BMCWEB_ROUTE( 1717e860f15SJohn Edward Broadbent app, "/redfish/v1/EventService/Actions/EventService.SubmitTestEvent/") 172ed398213SEd Tanous .privileges(redfish::privileges::postEventService) 1737e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::post)( 17445ca1b86SEd Tanous [&app](const crow::Request& req, 1757e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 1763ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 17745ca1b86SEd Tanous { 17845ca1b86SEd Tanous return; 17945ca1b86SEd Tanous } 18081ee0e74SChandramohan Harkude 18181ee0e74SChandramohan Harkude TestEvent testEvent; 18281ee0e74SChandramohan Harkude // clang-format off 18381ee0e74SChandramohan Harkude if (!json_util::readJsonAction( 18481ee0e74SChandramohan Harkude req, asyncResp->res, 18581ee0e74SChandramohan Harkude "EventGroupId", testEvent.eventGroupId, 18681ee0e74SChandramohan Harkude "EventId", testEvent.eventId, 18781ee0e74SChandramohan Harkude "EventTimestamp", testEvent.eventTimestamp, 18881ee0e74SChandramohan Harkude "Message", testEvent.message, 18981ee0e74SChandramohan Harkude "MessageArgs", testEvent.messageArgs, 19081ee0e74SChandramohan Harkude "MessageId", testEvent.messageId, 19181ee0e74SChandramohan Harkude "OriginOfCondition", testEvent.originOfCondition, 19281ee0e74SChandramohan Harkude "Resolution", testEvent.resolution, 19381ee0e74SChandramohan Harkude "Severity", testEvent.severity)) 19481ee0e74SChandramohan Harkude { 19581ee0e74SChandramohan Harkude return; 19681ee0e74SChandramohan Harkude } 19781ee0e74SChandramohan Harkude // clang-format on 19881ee0e74SChandramohan Harkude 19981ee0e74SChandramohan Harkude if (!EventServiceManager::getInstance().sendTestEventLog( 20081ee0e74SChandramohan Harkude testEvent)) 2016ba8c82eSsunharis_in { 2026ba8c82eSsunharis_in messages::serviceDisabled(asyncResp->res, 2036ba8c82eSsunharis_in "/redfish/v1/EventService/"); 2046ba8c82eSsunharis_in return; 2056ba8c82eSsunharis_in } 2068d1b46d7Szhanghch05 asyncResp->res.result(boost::beast::http::status::no_content); 2077e860f15SJohn Edward Broadbent }); 208e5aaf047SAppaRao Puli } 209e5aaf047SAppaRao Puli 2103d30708fSChicago Duan inline void doSubscriptionCollection( 211e81de512SEd Tanous const boost::system::error_code& ec, 2123d30708fSChicago Duan const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2133d30708fSChicago Duan const dbus::utility::ManagedObjectType& resp) 2143d30708fSChicago Duan { 2153d30708fSChicago Duan if (ec) 2163d30708fSChicago Duan { 2171306101eSEd Tanous if (ec.value() == EBADR || ec.value() == EHOSTUNREACH) 2183d30708fSChicago Duan { 2193d30708fSChicago Duan // This is an optional process so just return if it isn't there 2203d30708fSChicago Duan return; 2213d30708fSChicago Duan } 2223d30708fSChicago Duan 22362598e31SEd Tanous BMCWEB_LOG_ERROR("D-Bus response error on GetManagedObjects {}", ec); 2243d30708fSChicago Duan messages::internalError(asyncResp->res); 2253d30708fSChicago Duan return; 2263d30708fSChicago Duan } 2273d30708fSChicago Duan nlohmann::json& memberArray = asyncResp->res.jsonValue["Members"]; 2283d30708fSChicago Duan for (const auto& objpath : resp) 2293d30708fSChicago Duan { 2303d30708fSChicago Duan sdbusplus::message::object_path path(objpath.first); 2313d30708fSChicago Duan const std::string snmpId = path.filename(); 2323d30708fSChicago Duan if (snmpId.empty()) 2333d30708fSChicago Duan { 23462598e31SEd Tanous BMCWEB_LOG_ERROR("The SNMP client ID is wrong"); 2353d30708fSChicago Duan messages::internalError(asyncResp->res); 2363d30708fSChicago Duan return; 2373d30708fSChicago Duan } 2383d30708fSChicago Duan 2393d30708fSChicago Duan getSnmpSubscriptionList(asyncResp, snmpId, memberArray); 2403d30708fSChicago Duan } 2413d30708fSChicago Duan } 2423d30708fSChicago Duan 2437e860f15SJohn Edward Broadbent inline void requestRoutesEventDestinationCollection(App& app) 244e5aaf047SAppaRao Puli { 2451ebe3e41SGayathri Leburu BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/") 246ed398213SEd Tanous .privileges(redfish::privileges::getEventDestinationCollection) 2477e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 24845ca1b86SEd Tanous [&app](const crow::Request& req, 2497e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 2503ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 25145ca1b86SEd Tanous { 25245ca1b86SEd Tanous return; 25345ca1b86SEd Tanous } 2541476687dSEd Tanous asyncResp->res.jsonValue["@odata.type"] = 2551476687dSEd Tanous "#EventDestinationCollection.EventDestinationCollection"; 2561476687dSEd Tanous asyncResp->res.jsonValue["@odata.id"] = 2571476687dSEd Tanous "/redfish/v1/EventService/Subscriptions"; 258bd79bce8SPatrick Williams asyncResp->res.jsonValue["Name"] = 259bd79bce8SPatrick Williams "Event Destination Collections"; 260e5aaf047SAppaRao Puli 261bd79bce8SPatrick Williams nlohmann::json& memberArray = 262bd79bce8SPatrick Williams asyncResp->res.jsonValue["Members"]; 263e5aaf047SAppaRao Puli 264b52664e2SAppaRao Puli std::vector<std::string> subscripIds = 265b52664e2SAppaRao Puli EventServiceManager::getInstance().getAllIDs(); 266b52664e2SAppaRao Puli memberArray = nlohmann::json::array(); 267bd79bce8SPatrick Williams asyncResp->res.jsonValue["Members@odata.count"] = 268bd79bce8SPatrick Williams subscripIds.size(); 269b52664e2SAppaRao Puli 270b52664e2SAppaRao Puli for (const std::string& id : subscripIds) 271e5aaf047SAppaRao Puli { 2721476687dSEd Tanous nlohmann::json::object_t member; 2733d30708fSChicago Duan member["@odata.id"] = boost::urls::format( 2743d30708fSChicago Duan "/redfish/v1/EventService/Subscriptions/{}" + id); 275b2ba3072SPatrick Williams memberArray.emplace_back(std::move(member)); 276e5aaf047SAppaRao Puli } 2773d30708fSChicago Duan crow::connections::systemBus->async_method_call( 278e81de512SEd Tanous [asyncResp](const boost::system::error_code& ec, 2793d30708fSChicago Duan const dbus::utility::ManagedObjectType& resp) { 2803d30708fSChicago Duan doSubscriptionCollection(ec, asyncResp, resp); 2813d30708fSChicago Duan }, 2823d30708fSChicago Duan "xyz.openbmc_project.Network.SNMP", 2833d30708fSChicago Duan "/xyz/openbmc_project/network/snmp/manager", 2843d30708fSChicago Duan "org.freedesktop.DBus.ObjectManager", "GetManagedObjects"); 2857e860f15SJohn Edward Broadbent }); 2863d30708fSChicago Duan 2877e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/") 2887eeafa76SAbhishek Patel .privileges(redfish::privileges::postEventDestinationCollection) 289bd79bce8SPatrick Williams .methods( 290bd79bce8SPatrick Williams boost::beast::http::verb:: 291bd79bce8SPatrick Williams post)([&app]( 292bd79bce8SPatrick Williams const crow::Request& req, 2937e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 2943ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 29545ca1b86SEd Tanous { 29645ca1b86SEd Tanous return; 29745ca1b86SEd Tanous } 298fffb8c1fSEd Tanous if (EventServiceManager::getInstance().getNumberOfSubscriptions() >= 299fffb8c1fSEd Tanous maxNoOfSubscriptions) 300e5aaf047SAppaRao Puli { 301e5aaf047SAppaRao Puli messages::eventSubscriptionLimitExceeded(asyncResp->res); 302e5aaf047SAppaRao Puli return; 303e5aaf047SAppaRao Puli } 304e5aaf047SAppaRao Puli std::string destUrl; 305e5aaf047SAppaRao Puli std::string protocol; 30619bb362bSEd Tanous std::optional<bool> verifyCertificate; 307e5aaf047SAppaRao Puli std::optional<std::string> context; 308e5aaf047SAppaRao Puli std::optional<std::string> subscriptionType; 30923a21a1cSEd Tanous std::optional<std::string> eventFormatType2; 310e5aaf047SAppaRao Puli std::optional<std::string> retryPolicy; 3115064a25bSMyung Bae std::optional<bool> sendHeartbeat; 3125064a25bSMyung Bae std::optional<uint64_t> hbIntervalMinutes; 313e5aaf047SAppaRao Puli std::optional<std::vector<std::string>> msgIds; 314e5aaf047SAppaRao Puli std::optional<std::vector<std::string>> regPrefixes; 315a14c9113SEd Tanous std::optional<std::vector<std::string>> originResources; 316e56f254cSSunitha Harish std::optional<std::vector<std::string>> resTypes; 31778d4ec4fSEd Tanous std::optional<std::vector<nlohmann::json::object_t>> headers; 31878d4ec4fSEd Tanous std::optional<std::vector<nlohmann::json::object_t>> mrdJsonArray; 319e5aaf047SAppaRao Puli 320afc474aeSMyung Bae if (!json_util::readJsonPatch( // 321afc474aeSMyung Bae req, asyncResp->res, // 322afc474aeSMyung Bae "Context", context, // 323afc474aeSMyung Bae "DeliveryRetryPolicy", retryPolicy, // 324afc474aeSMyung Bae "Destination", destUrl, // 325afc474aeSMyung Bae "EventFormatType", eventFormatType2, // 3265064a25bSMyung Bae "HeartbeatIntervalMinutes", hbIntervalMinutes, // 327afc474aeSMyung Bae "HttpHeaders", headers, // 328afc474aeSMyung Bae "MessageIds", msgIds, // 329afc474aeSMyung Bae "MetricReportDefinitions", mrdJsonArray, // 330afc474aeSMyung Bae "OriginResources", originResources, // 331afc474aeSMyung Bae "Protocol", protocol, // 332afc474aeSMyung Bae "RegistryPrefixes", regPrefixes, // 333afc474aeSMyung Bae "ResourceTypes", resTypes, // 3345064a25bSMyung Bae "SendHeartbeat", sendHeartbeat, // 335afc474aeSMyung Bae "SubscriptionType", subscriptionType, // 336afc474aeSMyung Bae "VerifyCertificate", verifyCertificate // 3374b712a29SEd Tanous )) 338e5aaf047SAppaRao Puli { 339e5aaf047SAppaRao Puli return; 340e5aaf047SAppaRao Puli } 3414b712a29SEd Tanous // clang-format on 342e5aaf047SAppaRao Puli 343600af5f1SAppaRao Puli // https://stackoverflow.com/questions/417142/what-is-the-maximum-length-of-a-url-in-different-browsers 344600af5f1SAppaRao Puli static constexpr const uint16_t maxDestinationSize = 2000; 345600af5f1SAppaRao Puli if (destUrl.size() > maxDestinationSize) 346600af5f1SAppaRao Puli { 347600af5f1SAppaRao Puli messages::stringValueTooLong(asyncResp->res, "Destination", 348600af5f1SAppaRao Puli maxDestinationSize); 349600af5f1SAppaRao Puli return; 350600af5f1SAppaRao Puli } 351600af5f1SAppaRao Puli 352dd28ba82SAppaRao Puli if (regPrefixes && msgIds) 353dd28ba82SAppaRao Puli { 35426f6976fSEd Tanous if (!regPrefixes->empty() && !msgIds->empty()) 355dd28ba82SAppaRao Puli { 356bd79bce8SPatrick Williams messages::propertyValueConflict( 357bd79bce8SPatrick Williams asyncResp->res, "MessageIds", "RegistryPrefixes"); 358dd28ba82SAppaRao Puli return; 359dd28ba82SAppaRao Puli } 360dd28ba82SAppaRao Puli } 361dd28ba82SAppaRao Puli 3626fd29553SEd Tanous boost::system::result<boost::urls::url> url = 363a716aa74SEd Tanous boost::urls::parse_absolute_uri(destUrl); 364a716aa74SEd Tanous if (!url) 365e5aaf047SAppaRao Puli { 366bd79bce8SPatrick Williams BMCWEB_LOG_WARNING( 367bd79bce8SPatrick Williams "Failed to validate and split destination url"); 368e5aaf047SAppaRao Puli messages::propertyValueFormatError(asyncResp->res, destUrl, 369e5aaf047SAppaRao Puli "Destination"); 370e5aaf047SAppaRao Puli return; 371e5aaf047SAppaRao Puli } 372a716aa74SEd Tanous url->normalize(); 373b07942e3SGeorge Liu 374b07942e3SGeorge Liu // port_number returns zero if it is not a valid representable port 375b07942e3SGeorge Liu if (url->has_port() && url->port_number() == 0) 376b07942e3SGeorge Liu { 377b07942e3SGeorge Liu BMCWEB_LOG_WARNING("{} is an invalid port in destination url", 378b07942e3SGeorge Liu url->port()); 379b07942e3SGeorge Liu messages::propertyValueFormatError(asyncResp->res, destUrl, 380b07942e3SGeorge Liu "Destination"); 381b07942e3SGeorge Liu return; 382b07942e3SGeorge Liu } 383b07942e3SGeorge Liu 384a716aa74SEd Tanous crow::utility::setProtocolDefaults(*url, protocol); 385a716aa74SEd Tanous crow::utility::setPortDefaults(*url); 386a716aa74SEd Tanous 387a716aa74SEd Tanous if (url->path().empty()) 388a716aa74SEd Tanous { 389a716aa74SEd Tanous url->set_path("/"); 390a716aa74SEd Tanous } 391a716aa74SEd Tanous 392a716aa74SEd Tanous if (url->has_userinfo()) 393a716aa74SEd Tanous { 394a716aa74SEd Tanous messages::propertyValueFormatError(asyncResp->res, destUrl, 395a716aa74SEd Tanous "Destination"); 396a716aa74SEd Tanous return; 397a716aa74SEd Tanous } 398b52664e2SAppaRao Puli 3993d30708fSChicago Duan if (protocol == "SNMPv2c") 4003d30708fSChicago Duan { 4013d30708fSChicago Duan if (context) 4023d30708fSChicago Duan { 4033d30708fSChicago Duan messages::propertyValueConflict(asyncResp->res, "Context", 4043d30708fSChicago Duan "Protocol"); 4053d30708fSChicago Duan return; 4063d30708fSChicago Duan } 4073d30708fSChicago Duan if (eventFormatType2) 4083d30708fSChicago Duan { 409bd79bce8SPatrick Williams messages::propertyValueConflict( 410bd79bce8SPatrick Williams asyncResp->res, "EventFormatType", "Protocol"); 4113d30708fSChicago Duan return; 4123d30708fSChicago Duan } 4133d30708fSChicago Duan if (retryPolicy) 4143d30708fSChicago Duan { 415bd79bce8SPatrick Williams messages::propertyValueConflict(asyncResp->res, 416bd79bce8SPatrick Williams "RetryPolicy", "Protocol"); 4173d30708fSChicago Duan return; 4183d30708fSChicago Duan } 4195064a25bSMyung Bae if (sendHeartbeat) 4205064a25bSMyung Bae { 4215064a25bSMyung Bae messages::propertyValueConflict( 4225064a25bSMyung Bae asyncResp->res, "SendHeartbeat", "Protocol"); 4235064a25bSMyung Bae return; 4245064a25bSMyung Bae } 4255064a25bSMyung Bae if (hbIntervalMinutes) 4265064a25bSMyung Bae { 4275064a25bSMyung Bae messages::propertyValueConflict( 4285064a25bSMyung Bae asyncResp->res, "HeartbeatIntervalMinutes", "Protocol"); 4295064a25bSMyung Bae return; 4305064a25bSMyung Bae } 4313d30708fSChicago Duan if (msgIds) 4323d30708fSChicago Duan { 433bd79bce8SPatrick Williams messages::propertyValueConflict(asyncResp->res, 434bd79bce8SPatrick Williams "MessageIds", "Protocol"); 4353d30708fSChicago Duan return; 4363d30708fSChicago Duan } 4373d30708fSChicago Duan if (regPrefixes) 4383d30708fSChicago Duan { 439bd79bce8SPatrick Williams messages::propertyValueConflict( 440bd79bce8SPatrick Williams asyncResp->res, "RegistryPrefixes", "Protocol"); 4413d30708fSChicago Duan return; 4423d30708fSChicago Duan } 4433d30708fSChicago Duan if (resTypes) 4443d30708fSChicago Duan { 445bd79bce8SPatrick Williams messages::propertyValueConflict( 446bd79bce8SPatrick Williams asyncResp->res, "ResourceTypes", "Protocol"); 4473d30708fSChicago Duan return; 4483d30708fSChicago Duan } 4493d30708fSChicago Duan if (headers) 4503d30708fSChicago Duan { 451bd79bce8SPatrick Williams messages::propertyValueConflict(asyncResp->res, 452bd79bce8SPatrick Williams "HttpHeaders", "Protocol"); 4533d30708fSChicago Duan return; 4543d30708fSChicago Duan } 4553d30708fSChicago Duan if (mrdJsonArray) 4563d30708fSChicago Duan { 4573d30708fSChicago Duan messages::propertyValueConflict( 4583d30708fSChicago Duan asyncResp->res, "MetricReportDefinitions", "Protocol"); 4593d30708fSChicago Duan return; 4603d30708fSChicago Duan } 461a716aa74SEd Tanous if (url->scheme() != "snmp") 462a716aa74SEd Tanous { 463bd79bce8SPatrick Williams messages::propertyValueConflict(asyncResp->res, 464bd79bce8SPatrick Williams "Destination", "Protocol"); 4653d30708fSChicago Duan return; 4663d30708fSChicago Duan } 4673d30708fSChicago Duan 468a716aa74SEd Tanous addSnmpTrapClient(asyncResp, url->host_address(), 469a716aa74SEd Tanous url->port_number()); 470a716aa74SEd Tanous return; 471b52664e2SAppaRao Puli } 4723d30708fSChicago Duan 473a716aa74SEd Tanous std::shared_ptr<Subscription> subValue = 47421a94d5cSMyung Bae std::make_shared<Subscription>( 4755fe4ef35SMyung Bae std::make_shared<persistent_data::UserSubscription>(), *url, 4765fe4ef35SMyung Bae app.ioContext()); 477e5aaf047SAppaRao Puli 478e5aaf047SAppaRao Puli if (subscriptionType) 479e5aaf047SAppaRao Puli { 480e5aaf047SAppaRao Puli if (*subscriptionType != "RedfishEvent") 481e5aaf047SAppaRao Puli { 482fffb8c1fSEd Tanous messages::propertyValueNotInList( 483fffb8c1fSEd Tanous asyncResp->res, *subscriptionType, "SubscriptionType"); 484e5aaf047SAppaRao Puli return; 485e5aaf047SAppaRao Puli } 4865fe4ef35SMyung Bae subValue->userSub->subscriptionType = *subscriptionType; 487e5aaf047SAppaRao Puli } 488e5aaf047SAppaRao Puli else 489e5aaf047SAppaRao Puli { 4904b712a29SEd Tanous // Default 4915fe4ef35SMyung Bae subValue->userSub->subscriptionType = "RedfishEvent"; 492e5aaf047SAppaRao Puli } 493e5aaf047SAppaRao Puli 494e5aaf047SAppaRao Puli if (protocol != "Redfish") 495e5aaf047SAppaRao Puli { 496e5aaf047SAppaRao Puli messages::propertyValueNotInList(asyncResp->res, protocol, 497e5aaf047SAppaRao Puli "Protocol"); 498e5aaf047SAppaRao Puli return; 499e5aaf047SAppaRao Puli } 5005fe4ef35SMyung Bae subValue->userSub->protocol = protocol; 501e5aaf047SAppaRao Puli 50219bb362bSEd Tanous if (verifyCertificate) 50319bb362bSEd Tanous { 5045fe4ef35SMyung Bae subValue->userSub->verifyCertificate = *verifyCertificate; 50519bb362bSEd Tanous } 50619bb362bSEd Tanous 50723a21a1cSEd Tanous if (eventFormatType2) 508e5aaf047SAppaRao Puli { 509bd79bce8SPatrick Williams if (std::ranges::find(supportedEvtFormatTypes, 510bd79bce8SPatrick Williams *eventFormatType2) == 5113544d2a7SEd Tanous supportedEvtFormatTypes.end()) 512e5aaf047SAppaRao Puli { 513fffb8c1fSEd Tanous messages::propertyValueNotInList( 514fffb8c1fSEd Tanous asyncResp->res, *eventFormatType2, "EventFormatType"); 515e5aaf047SAppaRao Puli return; 516e5aaf047SAppaRao Puli } 5175fe4ef35SMyung Bae subValue->userSub->eventFormatType = *eventFormatType2; 518e5aaf047SAppaRao Puli } 519e5aaf047SAppaRao Puli else 520e5aaf047SAppaRao Puli { 521e5aaf047SAppaRao Puli // If not specified, use default "Event" 5225fe4ef35SMyung Bae subValue->userSub->eventFormatType = "Event"; 523e5aaf047SAppaRao Puli } 524e5aaf047SAppaRao Puli 525e5aaf047SAppaRao Puli if (context) 526e5aaf047SAppaRao Puli { 5278ece0e45SEd Tanous // This value is selected arbitrarily. 528600af5f1SAppaRao Puli constexpr const size_t maxContextSize = 256; 529600af5f1SAppaRao Puli if (context->size() > maxContextSize) 530600af5f1SAppaRao Puli { 531600af5f1SAppaRao Puli messages::stringValueTooLong(asyncResp->res, "Context", 532600af5f1SAppaRao Puli maxContextSize); 533600af5f1SAppaRao Puli return; 534600af5f1SAppaRao Puli } 5355fe4ef35SMyung Bae subValue->userSub->customText = *context; 536e5aaf047SAppaRao Puli } 537e5aaf047SAppaRao Puli 538e5aaf047SAppaRao Puli if (headers) 539e5aaf047SAppaRao Puli { 540600af5f1SAppaRao Puli size_t cumulativeLen = 0; 541600af5f1SAppaRao Puli 54278d4ec4fSEd Tanous for (const nlohmann::json::object_t& headerChunk : *headers) 543601c71aeSEd Tanous { 54478d4ec4fSEd Tanous for (const auto& item : headerChunk) 54578d4ec4fSEd Tanous { 54678d4ec4fSEd Tanous const std::string* value = 54778d4ec4fSEd Tanous item.second.get_ptr<const std::string*>(); 54878d4ec4fSEd Tanous if (value == nullptr) 54978d4ec4fSEd Tanous { 55078d4ec4fSEd Tanous messages::propertyValueFormatError( 55178d4ec4fSEd Tanous asyncResp->res, item.second, 55278d4ec4fSEd Tanous "HttpHeaders/" + item.first); 55378d4ec4fSEd Tanous return; 55478d4ec4fSEd Tanous } 55578d4ec4fSEd Tanous // Adding a new json value is the size of the key, + 55678d4ec4fSEd Tanous // the size of the value + 2 * 2 quotes for each, + 55778d4ec4fSEd Tanous // the colon and space between. example: 55878d4ec4fSEd Tanous // "key": "value" 55978d4ec4fSEd Tanous cumulativeLen += item.first.size() + value->size() + 6; 560600af5f1SAppaRao Puli // This value is selected to mirror http_connection.hpp 561600af5f1SAppaRao Puli constexpr const uint16_t maxHeaderSizeED = 8096; 562600af5f1SAppaRao Puli if (cumulativeLen > maxHeaderSizeED) 563600af5f1SAppaRao Puli { 56478d4ec4fSEd Tanous messages::arraySizeTooLong( 56578d4ec4fSEd Tanous asyncResp->res, "HttpHeaders", maxHeaderSizeED); 566600af5f1SAppaRao Puli return; 567600af5f1SAppaRao Puli } 5685fe4ef35SMyung Bae subValue->userSub->httpHeaders.set(item.first, *value); 569601c71aeSEd Tanous } 570601c71aeSEd Tanous } 571e5aaf047SAppaRao Puli } 572e5aaf047SAppaRao Puli 573e5aaf047SAppaRao Puli if (regPrefixes) 574e5aaf047SAppaRao Puli { 575e5aaf047SAppaRao Puli for (const std::string& it : *regPrefixes) 576e5aaf047SAppaRao Puli { 5773544d2a7SEd Tanous if (std::ranges::find(supportedRegPrefixes, it) == 5783544d2a7SEd Tanous supportedRegPrefixes.end()) 579e5aaf047SAppaRao Puli { 580fffb8c1fSEd Tanous messages::propertyValueNotInList(asyncResp->res, it, 581fffb8c1fSEd Tanous "RegistryPrefixes"); 582e5aaf047SAppaRao Puli return; 583e5aaf047SAppaRao Puli } 584e5aaf047SAppaRao Puli } 5855fe4ef35SMyung Bae subValue->userSub->registryPrefixes = *regPrefixes; 586e5aaf047SAppaRao Puli } 587e5aaf047SAppaRao Puli 588a14c9113SEd Tanous if (originResources) 589a14c9113SEd Tanous { 5905fe4ef35SMyung Bae subValue->userSub->originResources = *originResources; 591a14c9113SEd Tanous } 592a14c9113SEd Tanous 593e56f254cSSunitha Harish if (resTypes) 594e56f254cSSunitha Harish { 595e56f254cSSunitha Harish for (const std::string& it : *resTypes) 596e56f254cSSunitha Harish { 5973544d2a7SEd Tanous if (std::ranges::find(supportedResourceTypes, it) == 5983544d2a7SEd Tanous supportedResourceTypes.end()) 599e56f254cSSunitha Harish { 600e56f254cSSunitha Harish messages::propertyValueNotInList(asyncResp->res, it, 601e56f254cSSunitha Harish "ResourceTypes"); 602e56f254cSSunitha Harish return; 603e56f254cSSunitha Harish } 604e56f254cSSunitha Harish } 6055fe4ef35SMyung Bae subValue->userSub->resourceTypes = *resTypes; 606e56f254cSSunitha Harish } 607e56f254cSSunitha Harish 608e5aaf047SAppaRao Puli if (msgIds) 609e5aaf047SAppaRao Puli { 610b304bd79SP Dheeraj Srujan Kumar std::vector<std::string> registryPrefix; 611b304bd79SP Dheeraj Srujan Kumar 6127e860f15SJohn Edward Broadbent // If no registry prefixes are mentioned, consider all 6137e860f15SJohn Edward Broadbent // supported prefixes 6145fe4ef35SMyung Bae if (subValue->userSub->registryPrefixes.empty()) 615b304bd79SP Dheeraj Srujan Kumar { 616b304bd79SP Dheeraj Srujan Kumar registryPrefix.assign(supportedRegPrefixes.begin(), 617b304bd79SP Dheeraj Srujan Kumar supportedRegPrefixes.end()); 618b304bd79SP Dheeraj Srujan Kumar } 619b304bd79SP Dheeraj Srujan Kumar else 620b304bd79SP Dheeraj Srujan Kumar { 6215fe4ef35SMyung Bae registryPrefix = subValue->userSub->registryPrefixes; 622b304bd79SP Dheeraj Srujan Kumar } 623b304bd79SP Dheeraj Srujan Kumar 624b304bd79SP Dheeraj Srujan Kumar for (const std::string& id : *msgIds) 625b304bd79SP Dheeraj Srujan Kumar { 626b304bd79SP Dheeraj Srujan Kumar bool validId = false; 627b304bd79SP Dheeraj Srujan Kumar 628b304bd79SP Dheeraj Srujan Kumar // Check for Message ID in each of the selected Registry 629b304bd79SP Dheeraj Srujan Kumar for (const std::string& it : registryPrefix) 630b304bd79SP Dheeraj Srujan Kumar { 631fffb8c1fSEd Tanous const std::span<const redfish::registries::MessageEntry> 632fffb8c1fSEd Tanous registry = 633fffb8c1fSEd Tanous redfish::registries::getRegistryFromPrefix(it); 634b304bd79SP Dheeraj Srujan Kumar 6353544d2a7SEd Tanous if (std::ranges::any_of( 6363544d2a7SEd Tanous registry, 637fffb8c1fSEd Tanous [&id](const redfish::registries::MessageEntry& 638fffb8c1fSEd Tanous messageEntry) { 63955f79e6fSEd Tanous return id == messageEntry.first; 640b304bd79SP Dheeraj Srujan Kumar })) 641b304bd79SP Dheeraj Srujan Kumar { 642b304bd79SP Dheeraj Srujan Kumar validId = true; 643b304bd79SP Dheeraj Srujan Kumar break; 644b304bd79SP Dheeraj Srujan Kumar } 645b304bd79SP Dheeraj Srujan Kumar } 646b304bd79SP Dheeraj Srujan Kumar 647b304bd79SP Dheeraj Srujan Kumar if (!validId) 648b304bd79SP Dheeraj Srujan Kumar { 649b304bd79SP Dheeraj Srujan Kumar messages::propertyValueNotInList(asyncResp->res, id, 650b304bd79SP Dheeraj Srujan Kumar "MessageIds"); 651b304bd79SP Dheeraj Srujan Kumar return; 652b304bd79SP Dheeraj Srujan Kumar } 653b304bd79SP Dheeraj Srujan Kumar } 654b304bd79SP Dheeraj Srujan Kumar 6555fe4ef35SMyung Bae subValue->userSub->registryMsgIds = *msgIds; 656e5aaf047SAppaRao Puli } 657e5aaf047SAppaRao Puli 658e5aaf047SAppaRao Puli if (retryPolicy) 659e5aaf047SAppaRao Puli { 6603544d2a7SEd Tanous if (std::ranges::find(supportedRetryPolicies, *retryPolicy) == 6613544d2a7SEd Tanous supportedRetryPolicies.end()) 662e5aaf047SAppaRao Puli { 663bd79bce8SPatrick Williams messages::propertyValueNotInList( 664bd79bce8SPatrick Williams asyncResp->res, *retryPolicy, "DeliveryRetryPolicy"); 665e5aaf047SAppaRao Puli return; 666e5aaf047SAppaRao Puli } 6675fe4ef35SMyung Bae subValue->userSub->retryPolicy = *retryPolicy; 668e5aaf047SAppaRao Puli } 669e5aaf047SAppaRao Puli else 670e5aaf047SAppaRao Puli { 671e5aaf047SAppaRao Puli // Default "TerminateAfterRetries" 6725fe4ef35SMyung Bae subValue->userSub->retryPolicy = "TerminateAfterRetries"; 673e5aaf047SAppaRao Puli } 6745064a25bSMyung Bae if (sendHeartbeat) 6755064a25bSMyung Bae { 6765064a25bSMyung Bae subValue->userSub->sendHeartbeat = *sendHeartbeat; 6775064a25bSMyung Bae } 6785064a25bSMyung Bae if (hbIntervalMinutes) 6795064a25bSMyung Bae { 6805064a25bSMyung Bae if (*hbIntervalMinutes < 1 || *hbIntervalMinutes > 65535) 6815064a25bSMyung Bae { 6825064a25bSMyung Bae messages::propertyValueOutOfRange( 6835064a25bSMyung Bae asyncResp->res, *hbIntervalMinutes, 6845064a25bSMyung Bae "HeartbeatIntervalMinutes"); 6855064a25bSMyung Bae return; 6865064a25bSMyung Bae } 6875064a25bSMyung Bae subValue->userSub->hbIntervalMinutes = *hbIntervalMinutes; 6885064a25bSMyung Bae } 689e5aaf047SAppaRao Puli 690144b6318SAppaRao Puli if (mrdJsonArray) 691156d6b00SAppaRao Puli { 69278d4ec4fSEd Tanous for (nlohmann::json::object_t& mrdObj : *mrdJsonArray) 693144b6318SAppaRao Puli { 694144b6318SAppaRao Puli std::string mrdUri; 695ea2e6eecSWilly Tu 69678d4ec4fSEd Tanous if (!json_util::readJsonObject(mrdObj, asyncResp->res, 69778d4ec4fSEd Tanous "@odata.id", mrdUri)) 698ea2e6eecSWilly Tu 699144b6318SAppaRao Puli { 700144b6318SAppaRao Puli return; 701144b6318SAppaRao Puli } 7025fe4ef35SMyung Bae subValue->userSub->metricReportDefinitions.emplace_back( 7034b712a29SEd Tanous mrdUri); 704144b6318SAppaRao Puli } 705156d6b00SAppaRao Puli } 706156d6b00SAppaRao Puli 707b52664e2SAppaRao Puli std::string id = 708bd79bce8SPatrick Williams EventServiceManager::getInstance().addPushSubscription( 709bd79bce8SPatrick Williams subValue); 710b52664e2SAppaRao Puli if (id.empty()) 711e5aaf047SAppaRao Puli { 712e5aaf047SAppaRao Puli messages::internalError(asyncResp->res); 713e5aaf047SAppaRao Puli return; 714e5aaf047SAppaRao Puli } 715e5aaf047SAppaRao Puli 716e5aaf047SAppaRao Puli messages::created(asyncResp->res); 717e5aaf047SAppaRao Puli asyncResp->res.addHeader( 718e5aaf047SAppaRao Puli "Location", "/redfish/v1/EventService/Subscriptions/" + id); 719fb546105SMyung Bae 720fb546105SMyung Bae // schedule a heartbeat 721fb546105SMyung Bae if (subValue->userSub->sendHeartbeat) 722fb546105SMyung Bae { 723fb546105SMyung Bae subValue->scheduleNextHeartbeatEvent(); 724fb546105SMyung Bae } 7257e860f15SJohn Edward Broadbent }); 726e5aaf047SAppaRao Puli } 727e5aaf047SAppaRao Puli 7287e860f15SJohn Edward Broadbent inline void requestRoutesEventDestination(App& app) 729e5aaf047SAppaRao Puli { 7309d41aec6SRavi Teja BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/<str>/") 731ed398213SEd Tanous .privileges(redfish::privileges::getEventDestination) 7327e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 73345ca1b86SEd Tanous [&app](const crow::Request& req, 7347e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 7357e860f15SJohn Edward Broadbent const std::string& param) { 7363ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 73745ca1b86SEd Tanous { 73845ca1b86SEd Tanous return; 73945ca1b86SEd Tanous } 7403d30708fSChicago Duan 7413d30708fSChicago Duan if (param.starts_with("snmp")) 7423d30708fSChicago Duan { 7433d30708fSChicago Duan getSnmpTrapClient(asyncResp, param); 7443d30708fSChicago Duan return; 7453d30708fSChicago Duan } 7463d30708fSChicago Duan 747b52664e2SAppaRao Puli std::shared_ptr<Subscription> subValue = 7487e860f15SJohn Edward Broadbent EventServiceManager::getInstance().getSubscription(param); 749b52664e2SAppaRao Puli if (subValue == nullptr) 750e5aaf047SAppaRao Puli { 751bd79bce8SPatrick Williams asyncResp->res.result( 752bd79bce8SPatrick Williams boost::beast::http::status::not_found); 753e5aaf047SAppaRao Puli return; 754e5aaf047SAppaRao Puli } 7557e860f15SJohn Edward Broadbent const std::string& id = param; 756e5aaf047SAppaRao Puli 7574b712a29SEd Tanous const persistent_data::UserSubscription& userSub = 7585fe4ef35SMyung Bae *subValue->userSub; 759e56f254cSSunitha Harish 7604b712a29SEd Tanous nlohmann::json& jVal = asyncResp->res.jsonValue; 7614b712a29SEd Tanous jVal["@odata.type"] = 7624b712a29SEd Tanous "#EventDestination.v1_14_1.EventDestination"; 7634b712a29SEd Tanous jVal["Protocol"] = 7644b712a29SEd Tanous event_destination::EventDestinationProtocol::Redfish; 7654b712a29SEd Tanous jVal["@odata.id"] = boost::urls::format( 7664b712a29SEd Tanous "/redfish/v1/EventService/Subscriptions/{}", id); 7674b712a29SEd Tanous jVal["Id"] = id; 7684b712a29SEd Tanous jVal["Name"] = "Event Destination " + id; 7694b712a29SEd Tanous jVal["Destination"] = userSub.destinationUrl; 7704b712a29SEd Tanous jVal["Context"] = userSub.customText; 7714b712a29SEd Tanous jVal["SubscriptionType"] = userSub.subscriptionType; 7724b712a29SEd Tanous jVal["HttpHeaders"] = nlohmann::json::array(); 7734b712a29SEd Tanous jVal["EventFormatType"] = userSub.eventFormatType; 7744b712a29SEd Tanous jVal["RegistryPrefixes"] = userSub.registryPrefixes; 7754b712a29SEd Tanous jVal["ResourceTypes"] = userSub.resourceTypes; 7764b712a29SEd Tanous 7774b712a29SEd Tanous jVal["MessageIds"] = userSub.registryMsgIds; 7784b712a29SEd Tanous jVal["DeliveryRetryPolicy"] = userSub.retryPolicy; 7795064a25bSMyung Bae jVal["SendHeartbeat"] = userSub.sendHeartbeat; 7805064a25bSMyung Bae jVal["HeartbeatIntervalMinutes"] = userSub.hbIntervalMinutes; 7814b712a29SEd Tanous jVal["VerifyCertificate"] = userSub.verifyCertificate; 782144b6318SAppaRao Puli 7831476687dSEd Tanous nlohmann::json::array_t mrdJsonArray; 7844b712a29SEd Tanous for (const auto& mdrUri : userSub.metricReportDefinitions) 785144b6318SAppaRao Puli { 7861476687dSEd Tanous nlohmann::json::object_t mdr; 7871476687dSEd Tanous mdr["@odata.id"] = mdrUri; 7881476687dSEd Tanous mrdJsonArray.emplace_back(std::move(mdr)); 789144b6318SAppaRao Puli } 7904b712a29SEd Tanous jVal["MetricReportDefinitions"] = mrdJsonArray; 7917e860f15SJohn Edward Broadbent }); 7929d41aec6SRavi Teja BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/<str>/") 793ed398213SEd Tanous // The below privilege is wrong, it should be ConfigureManager OR 794ed398213SEd Tanous // ConfigureSelf 7957eeafa76SAbhishek Patel // https://github.com/openbmc/bmcweb/issues/220 796ed398213SEd Tanous //.privileges(redfish::privileges::patchEventDestination) 797432a890cSEd Tanous .privileges({{"ConfigureManager"}}) 7987e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::patch)( 79945ca1b86SEd Tanous [&app](const crow::Request& req, 8007e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 8017e860f15SJohn Edward Broadbent const std::string& param) { 8023ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 80345ca1b86SEd Tanous { 80445ca1b86SEd Tanous return; 80545ca1b86SEd Tanous } 806b52664e2SAppaRao Puli std::shared_ptr<Subscription> subValue = 8077e860f15SJohn Edward Broadbent EventServiceManager::getInstance().getSubscription(param); 808b52664e2SAppaRao Puli if (subValue == nullptr) 809e5aaf047SAppaRao Puli { 810bd79bce8SPatrick Williams asyncResp->res.result( 811bd79bce8SPatrick Williams boost::beast::http::status::not_found); 812e5aaf047SAppaRao Puli return; 813e5aaf047SAppaRao Puli } 814e5aaf047SAppaRao Puli 815e5aaf047SAppaRao Puli std::optional<std::string> context; 816e5aaf047SAppaRao Puli std::optional<std::string> retryPolicy; 8175064a25bSMyung Bae std::optional<bool> sendHeartbeat; 8185064a25bSMyung Bae std::optional<uint64_t> hbIntervalMinutes; 81919bb362bSEd Tanous std::optional<bool> verifyCertificate; 82078d4ec4fSEd Tanous std::optional<std::vector<nlohmann::json::object_t>> headers; 821e5aaf047SAppaRao Puli 822afc474aeSMyung Bae if (!json_util::readJsonPatch( // 823afc474aeSMyung Bae req, asyncResp->res, // 824afc474aeSMyung Bae "Context", context, // 825afc474aeSMyung Bae "DeliveryRetryPolicy", retryPolicy, // 8265064a25bSMyung Bae "HeartbeatIntervalMinutes", hbIntervalMinutes, // 827afc474aeSMyung Bae "HttpHeaders", headers, // 8285064a25bSMyung Bae "SendHeartbeat", sendHeartbeat, // 829afc474aeSMyung Bae "VerifyCertificate", verifyCertificate // 830afc474aeSMyung Bae )) 831e5aaf047SAppaRao Puli { 832e5aaf047SAppaRao Puli return; 833e5aaf047SAppaRao Puli } 834e5aaf047SAppaRao Puli 835e5aaf047SAppaRao Puli if (context) 836e5aaf047SAppaRao Puli { 8375fe4ef35SMyung Bae subValue->userSub->customText = *context; 838e5aaf047SAppaRao Puli } 839e5aaf047SAppaRao Puli 840e5aaf047SAppaRao Puli if (headers) 841e5aaf047SAppaRao Puli { 842601c71aeSEd Tanous boost::beast::http::fields fields; 84378d4ec4fSEd Tanous for (const nlohmann::json::object_t& headerChunk : *headers) 844601c71aeSEd Tanous { 84578d4ec4fSEd Tanous for (const auto& it : headerChunk) 846601c71aeSEd Tanous { 847601c71aeSEd Tanous const std::string* value = 84878d4ec4fSEd Tanous it.second.get_ptr<const std::string*>(); 849601c71aeSEd Tanous if (value == nullptr) 850601c71aeSEd Tanous { 851601c71aeSEd Tanous messages::propertyValueFormatError( 85278d4ec4fSEd Tanous asyncResp->res, it.second, 85378d4ec4fSEd Tanous "HttpHeaders/" + it.first); 854601c71aeSEd Tanous return; 855601c71aeSEd Tanous } 85678d4ec4fSEd Tanous fields.set(it.first, *value); 857601c71aeSEd Tanous } 858601c71aeSEd Tanous } 8595fe4ef35SMyung Bae subValue->userSub->httpHeaders = std::move(fields); 860e5aaf047SAppaRao Puli } 861e5aaf047SAppaRao Puli 862e5aaf047SAppaRao Puli if (retryPolicy) 863e5aaf047SAppaRao Puli { 864bd79bce8SPatrick Williams if (std::ranges::find(supportedRetryPolicies, 865bd79bce8SPatrick Williams *retryPolicy) == 8663544d2a7SEd Tanous supportedRetryPolicies.end()) 867e5aaf047SAppaRao Puli { 868bd79bce8SPatrick Williams messages::propertyValueNotInList(asyncResp->res, 869bd79bce8SPatrick Williams *retryPolicy, 870e5aaf047SAppaRao Puli "DeliveryRetryPolicy"); 871e5aaf047SAppaRao Puli return; 872e5aaf047SAppaRao Puli } 8735fe4ef35SMyung Bae subValue->userSub->retryPolicy = *retryPolicy; 874e5aaf047SAppaRao Puli } 875e5aaf047SAppaRao Puli 8765064a25bSMyung Bae if (sendHeartbeat) 8775064a25bSMyung Bae { 8785064a25bSMyung Bae subValue->userSub->sendHeartbeat = *sendHeartbeat; 8795064a25bSMyung Bae } 8805064a25bSMyung Bae if (hbIntervalMinutes) 8815064a25bSMyung Bae { 8825064a25bSMyung Bae if (*hbIntervalMinutes < 1 || *hbIntervalMinutes > 65535) 8835064a25bSMyung Bae { 8845064a25bSMyung Bae messages::propertyValueOutOfRange( 8855064a25bSMyung Bae asyncResp->res, *hbIntervalMinutes, 8865064a25bSMyung Bae "HeartbeatIntervalMinutes"); 8875064a25bSMyung Bae return; 8885064a25bSMyung Bae } 8895064a25bSMyung Bae subValue->userSub->hbIntervalMinutes = *hbIntervalMinutes; 8905064a25bSMyung Bae } 8915064a25bSMyung Bae 892fb546105SMyung Bae if (hbIntervalMinutes || sendHeartbeat) 893fb546105SMyung Bae { 894fb546105SMyung Bae // if Heartbeat interval or send heart were changed, cancel 895fb546105SMyung Bae // the heartbeat timer if running and start a new heartbeat 896fb546105SMyung Bae // if needed 897fb546105SMyung Bae subValue->heartbeatParametersChanged(); 898fb546105SMyung Bae } 899fb546105SMyung Bae 90019bb362bSEd Tanous if (verifyCertificate) 90119bb362bSEd Tanous { 9025fe4ef35SMyung Bae subValue->userSub->verifyCertificate = *verifyCertificate; 90319bb362bSEd Tanous } 90419bb362bSEd Tanous 905b52664e2SAppaRao Puli EventServiceManager::getInstance().updateSubscriptionData(); 9067e860f15SJohn Edward Broadbent }); 9079d41aec6SRavi Teja BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/<str>/") 908ed398213SEd Tanous // The below privilege is wrong, it should be ConfigureManager OR 909ed398213SEd Tanous // ConfigureSelf 9107eeafa76SAbhishek Patel // https://github.com/openbmc/bmcweb/issues/220 911ed398213SEd Tanous //.privileges(redfish::privileges::deleteEventDestination) 912432a890cSEd Tanous .privileges({{"ConfigureManager"}}) 9137e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::delete_)( 91445ca1b86SEd Tanous [&app](const crow::Request& req, 9157e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 9167e860f15SJohn Edward Broadbent const std::string& param) { 9173ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 91845ca1b86SEd Tanous { 91945ca1b86SEd Tanous return; 92045ca1b86SEd Tanous } 9214b712a29SEd Tanous EventServiceManager& event = EventServiceManager::getInstance(); 9223d30708fSChicago Duan if (param.starts_with("snmp")) 9233d30708fSChicago Duan { 9243d30708fSChicago Duan deleteSnmpTrapClient(asyncResp, param); 9254b712a29SEd Tanous event.deleteSubscription(param); 9263d30708fSChicago Duan return; 9273d30708fSChicago Duan } 9283d30708fSChicago Duan 9294b712a29SEd Tanous if (!event.deleteSubscription(param)) 930e5aaf047SAppaRao Puli { 9314b712a29SEd Tanous messages::resourceNotFound(asyncResp->res, 9324b712a29SEd Tanous "EventDestination", param); 933e5aaf047SAppaRao Puli return; 934e5aaf047SAppaRao Puli } 9354b712a29SEd Tanous messages::success(asyncResp->res); 9367e860f15SJohn Edward Broadbent }); 937e5aaf047SAppaRao Puli } 938e5aaf047SAppaRao Puli 939e5aaf047SAppaRao Puli } // namespace redfish 940