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_utility.hpp" 8d7857201SEd Tanous #include "error_messages.hpp" 9b52664e2SAppaRao Puli #include "event_service_manager.hpp" 10d7857201SEd Tanous #include "event_service_store.hpp" 11d7857201SEd Tanous #include "generated/enums/event_destination.hpp" 123ccb3adbSEd Tanous #include "http/utility.hpp" 13d7857201SEd Tanous #include "http_request.hpp" 149838eb20SEd Tanous #include "io_context_singleton.hpp" 153ccb3adbSEd Tanous #include "logging.hpp" 163ccb3adbSEd Tanous #include "query.hpp" 17d109e2b6SAlexander Hansen #include "registries.hpp" 183ccb3adbSEd Tanous #include "registries/privilege_registry.hpp" 193d30708fSChicago Duan #include "snmp_trap_event_clients.hpp" 20d7857201SEd Tanous #include "subscription.hpp" 21d109e2b6SAlexander Hansen #include "utils/json_utils.hpp" 22e5aaf047SAppaRao Puli 23d7857201SEd Tanous #include <asm-generic/errno.h> 24ed398213SEd Tanous 25d7857201SEd Tanous #include <boost/beast/http/status.hpp> 26d7857201SEd Tanous #include <boost/beast/http/verb.hpp> 27d7857201SEd Tanous #include <boost/system/error_code.hpp> 28d7857201SEd Tanous #include <boost/system/result.hpp> 29d7857201SEd Tanous #include <boost/url/format.hpp> 30d7857201SEd Tanous #include <boost/url/parse.hpp> 31d7857201SEd Tanous #include <boost/url/url.hpp> 32d7857201SEd Tanous #include <sdbusplus/message/native_types.hpp> 33d7857201SEd Tanous 34d7857201SEd Tanous #include <algorithm> 35d7857201SEd Tanous #include <array> 36d7857201SEd Tanous #include <cerrno> 37d7857201SEd Tanous #include <cstddef> 38d7857201SEd Tanous #include <cstdint> 393d30708fSChicago Duan #include <memory> 405064a25bSMyung Bae #include <optional> 413544d2a7SEd Tanous #include <ranges> 423d30708fSChicago Duan #include <string> 43d7857201SEd Tanous #include <utility> 44a14c9113SEd Tanous #include <vector> 451e270c5fSPatrick Williams 46e5aaf047SAppaRao Puli namespace redfish 47e5aaf047SAppaRao Puli { 48e5aaf047SAppaRao Puli 49156d6b00SAppaRao Puli static constexpr const std::array<const char*, 2> supportedEvtFormatTypes = { 50156d6b00SAppaRao Puli eventFormatType, metricReportFormatType}; 51fb546105SMyung Bae static constexpr const std::array<const char*, 4> supportedRegPrefixes = { 52fb546105SMyung Bae "Base", "OpenBMC", "TaskEvent", "HeartbeatEvent"}; 53e5aaf047SAppaRao Puli static constexpr const std::array<const char*, 3> supportedRetryPolicies = { 54e5aaf047SAppaRao Puli "TerminateAfterRetries", "SuspendRetries", "RetryForever"}; 55e5aaf047SAppaRao Puli 56fb546105SMyung Bae static constexpr const std::array<const char*, 2> supportedResourceTypes = { 57fb546105SMyung Bae "Task", "Heartbeat"}; 58e56f254cSSunitha Harish 597e860f15SJohn Edward Broadbent inline void requestRoutesEventService(App& app) 60e5aaf047SAppaRao Puli { 617e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, "/redfish/v1/EventService/") 62ed398213SEd Tanous .privileges(redfish::privileges::getEventService) 63bd79bce8SPatrick Williams .methods( 64bd79bce8SPatrick Williams boost::beast::http::verb:: 65bd79bce8SPatrick Williams get)([&app]( 66bd79bce8SPatrick Williams const crow::Request& req, 67002d39b4SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 683ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 6945ca1b86SEd Tanous { 7045ca1b86SEd Tanous return; 7145ca1b86SEd Tanous } 721476687dSEd Tanous 731476687dSEd Tanous asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/EventService"; 741476687dSEd Tanous asyncResp->res.jsonValue["@odata.type"] = 751476687dSEd Tanous "#EventService.v1_5_0.EventService"; 761476687dSEd Tanous asyncResp->res.jsonValue["Id"] = "EventService"; 771476687dSEd Tanous asyncResp->res.jsonValue["Name"] = "Event Service"; 785e44e3d8SAppaRao Puli asyncResp->res.jsonValue["ServerSentEventUri"] = 795e44e3d8SAppaRao Puli "/redfish/v1/EventService/SSE"; 805e44e3d8SAppaRao Puli 811476687dSEd Tanous asyncResp->res.jsonValue["Subscriptions"]["@odata.id"] = 821476687dSEd Tanous "/redfish/v1/EventService/Subscriptions"; 83bd79bce8SPatrick Williams asyncResp->res.jsonValue["Actions"]["#EventService.SubmitTestEvent"] 84bd79bce8SPatrick Williams ["target"] = 851476687dSEd Tanous "/redfish/v1/EventService/Actions/EventService.SubmitTestEvent"; 86e5aaf047SAppaRao Puli 8728afb49cSJunLin Chen const persistent_data::EventServiceConfig eventServiceConfig = 8828afb49cSJunLin Chen persistent_data::EventServiceStore::getInstance() 8928afb49cSJunLin Chen .getEventServiceConfig(); 907d1cc387SAppaRao Puli 917d1cc387SAppaRao Puli asyncResp->res.jsonValue["Status"]["State"] = 9228afb49cSJunLin Chen (eventServiceConfig.enabled ? "Enabled" : "Disabled"); 93bd79bce8SPatrick Williams asyncResp->res.jsonValue["ServiceEnabled"] = 94bd79bce8SPatrick Williams eventServiceConfig.enabled; 957e860f15SJohn Edward Broadbent asyncResp->res.jsonValue["DeliveryRetryAttempts"] = 9628afb49cSJunLin Chen eventServiceConfig.retryAttempts; 97e5aaf047SAppaRao Puli asyncResp->res.jsonValue["DeliveryRetryIntervalSeconds"] = 9828afb49cSJunLin Chen eventServiceConfig.retryTimeoutInterval; 99bd79bce8SPatrick Williams asyncResp->res.jsonValue["EventFormatTypes"] = 100bd79bce8SPatrick Williams supportedEvtFormatTypes; 1010fda0f12SGeorge Liu asyncResp->res.jsonValue["RegistryPrefixes"] = supportedRegPrefixes; 1020fda0f12SGeorge Liu asyncResp->res.jsonValue["ResourceTypes"] = supportedResourceTypes; 10307941a88SAyushi Smriti 104613dabeaSEd Tanous nlohmann::json::object_t supportedSSEFilters; 105613dabeaSEd Tanous supportedSSEFilters["EventFormatType"] = true; 106613dabeaSEd Tanous supportedSSEFilters["MessageId"] = true; 107613dabeaSEd Tanous supportedSSEFilters["MetricReportDefinition"] = true; 108613dabeaSEd Tanous supportedSSEFilters["RegistryPrefix"] = true; 109613dabeaSEd Tanous supportedSSEFilters["OriginResource"] = false; 110613dabeaSEd Tanous supportedSSEFilters["ResourceType"] = false; 11107941a88SAyushi Smriti 11207941a88SAyushi Smriti asyncResp->res.jsonValue["SSEFilterPropertiesSupported"] = 113613dabeaSEd Tanous std::move(supportedSSEFilters); 1147e860f15SJohn Edward Broadbent }); 115e5aaf047SAppaRao Puli 1167e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, "/redfish/v1/EventService/") 117ed398213SEd Tanous .privileges(redfish::privileges::patchEventService) 1187e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::patch)( 11945ca1b86SEd Tanous [&app](const crow::Request& req, 12045ca1b86SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 1213ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 122e5aaf047SAppaRao Puli { 12345ca1b86SEd Tanous return; 12445ca1b86SEd Tanous } 125e5aaf047SAppaRao Puli std::optional<bool> serviceEnabled; 126e5aaf047SAppaRao Puli std::optional<uint32_t> retryAttemps; 127e5aaf047SAppaRao Puli std::optional<uint32_t> retryInterval; 128afc474aeSMyung Bae if (!json_util::readJsonPatch( // 129afc474aeSMyung Bae req, asyncResp->res, // 130afc474aeSMyung Bae "DeliveryRetryAttempts", retryAttemps, // 131afc474aeSMyung Bae "DeliveryRetryIntervalSeconds", retryInterval, // 132afc474aeSMyung Bae "ServiceEnabled", serviceEnabled // 133afc474aeSMyung Bae )) 134e5aaf047SAppaRao Puli { 135e5aaf047SAppaRao Puli return; 136e5aaf047SAppaRao Puli } 137e5aaf047SAppaRao Puli 13828afb49cSJunLin Chen persistent_data::EventServiceConfig eventServiceConfig = 13928afb49cSJunLin Chen persistent_data::EventServiceStore::getInstance() 14028afb49cSJunLin Chen .getEventServiceConfig(); 1417d1cc387SAppaRao Puli 142e5aaf047SAppaRao Puli if (serviceEnabled) 143e5aaf047SAppaRao Puli { 14428afb49cSJunLin Chen eventServiceConfig.enabled = *serviceEnabled; 145e5aaf047SAppaRao Puli } 146e5aaf047SAppaRao Puli 147e5aaf047SAppaRao Puli if (retryAttemps) 148e5aaf047SAppaRao Puli { 149e5aaf047SAppaRao Puli // Supported range [1-3] 150e5aaf047SAppaRao Puli if ((*retryAttemps < 1) || (*retryAttemps > 3)) 151e5aaf047SAppaRao Puli { 152e5aaf047SAppaRao Puli messages::queryParameterOutOfRange( 153e5aaf047SAppaRao Puli asyncResp->res, std::to_string(*retryAttemps), 154e5aaf047SAppaRao Puli "DeliveryRetryAttempts", "[1-3]"); 155e5aaf047SAppaRao Puli } 156e5aaf047SAppaRao Puli else 157e5aaf047SAppaRao Puli { 15828afb49cSJunLin Chen eventServiceConfig.retryAttempts = *retryAttemps; 159e5aaf047SAppaRao Puli } 160e5aaf047SAppaRao Puli } 161e5aaf047SAppaRao Puli 162e5aaf047SAppaRao Puli if (retryInterval) 163e5aaf047SAppaRao Puli { 16433a32b34SGunnar Mills // Supported range [5 - 180] 16533a32b34SGunnar Mills if ((*retryInterval < 5) || (*retryInterval > 180)) 166e5aaf047SAppaRao Puli { 167e5aaf047SAppaRao Puli messages::queryParameterOutOfRange( 168e5aaf047SAppaRao Puli asyncResp->res, std::to_string(*retryInterval), 16933a32b34SGunnar Mills "DeliveryRetryIntervalSeconds", "[5-180]"); 170e5aaf047SAppaRao Puli } 171e5aaf047SAppaRao Puli else 172e5aaf047SAppaRao Puli { 173bd79bce8SPatrick Williams eventServiceConfig.retryTimeoutInterval = 174bd79bce8SPatrick Williams *retryInterval; 175e5aaf047SAppaRao Puli } 176e5aaf047SAppaRao Puli } 177e5aaf047SAppaRao Puli 1787d1cc387SAppaRao Puli EventServiceManager::getInstance().setEventServiceConfig( 17928afb49cSJunLin Chen eventServiceConfig); 1807e860f15SJohn Edward Broadbent }); 1810b4bdd93SAppaRao Puli } 1820b4bdd93SAppaRao Puli 1837e860f15SJohn Edward Broadbent inline void requestRoutesSubmitTestEvent(App& app) 1840b4bdd93SAppaRao Puli { 1857e860f15SJohn Edward Broadbent BMCWEB_ROUTE( 1867e860f15SJohn Edward Broadbent app, "/redfish/v1/EventService/Actions/EventService.SubmitTestEvent/") 187ed398213SEd Tanous .privileges(redfish::privileges::postEventService) 1887e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::post)( 18945ca1b86SEd Tanous [&app](const crow::Request& req, 1907e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 1913ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 19245ca1b86SEd Tanous { 19345ca1b86SEd Tanous return; 19445ca1b86SEd Tanous } 19581ee0e74SChandramohan Harkude 1964a19a7b5SEd Tanous // From the Redfish spec on EventId 1974a19a7b5SEd Tanous // A service can ignore this value and replace it with its own. 1984a19a7b5SEd Tanous // note that this parameter is intentionally ignored 1994a19a7b5SEd Tanous 2004a19a7b5SEd Tanous std::optional<std::string> eventId; 20181ee0e74SChandramohan Harkude TestEvent testEvent; 20281ee0e74SChandramohan Harkude // clang-format off 20381ee0e74SChandramohan Harkude if (!json_util::readJsonAction( 20481ee0e74SChandramohan Harkude req, asyncResp->res, 20581ee0e74SChandramohan Harkude "EventGroupId", testEvent.eventGroupId, 2064a19a7b5SEd Tanous "EventId", eventId, 20781ee0e74SChandramohan Harkude "EventTimestamp", testEvent.eventTimestamp, 20881ee0e74SChandramohan Harkude "Message", testEvent.message, 20981ee0e74SChandramohan Harkude "MessageArgs", testEvent.messageArgs, 21081ee0e74SChandramohan Harkude "MessageId", testEvent.messageId, 21181ee0e74SChandramohan Harkude "OriginOfCondition", testEvent.originOfCondition, 21281ee0e74SChandramohan Harkude "Resolution", testEvent.resolution, 21381ee0e74SChandramohan Harkude "Severity", testEvent.severity)) 21481ee0e74SChandramohan Harkude { 21581ee0e74SChandramohan Harkude return; 21681ee0e74SChandramohan Harkude } 21781ee0e74SChandramohan Harkude // clang-format on 21881ee0e74SChandramohan Harkude 21981ee0e74SChandramohan Harkude if (!EventServiceManager::getInstance().sendTestEventLog( 22081ee0e74SChandramohan Harkude testEvent)) 2216ba8c82eSsunharis_in { 2226ba8c82eSsunharis_in messages::serviceDisabled(asyncResp->res, 2236ba8c82eSsunharis_in "/redfish/v1/EventService/"); 2246ba8c82eSsunharis_in return; 2256ba8c82eSsunharis_in } 2268d1b46d7Szhanghch05 asyncResp->res.result(boost::beast::http::status::no_content); 2277e860f15SJohn Edward Broadbent }); 228e5aaf047SAppaRao Puli } 229e5aaf047SAppaRao Puli 2303d30708fSChicago Duan inline void doSubscriptionCollection( 231e81de512SEd Tanous const boost::system::error_code& ec, 2323d30708fSChicago Duan const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2333d30708fSChicago Duan const dbus::utility::ManagedObjectType& resp) 2343d30708fSChicago Duan { 2353d30708fSChicago Duan if (ec) 2363d30708fSChicago Duan { 2371306101eSEd Tanous if (ec.value() == EBADR || ec.value() == EHOSTUNREACH) 2383d30708fSChicago Duan { 2393d30708fSChicago Duan // This is an optional process so just return if it isn't there 2403d30708fSChicago Duan return; 2413d30708fSChicago Duan } 2423d30708fSChicago Duan 24362598e31SEd Tanous BMCWEB_LOG_ERROR("D-Bus response error on GetManagedObjects {}", ec); 2443d30708fSChicago Duan messages::internalError(asyncResp->res); 2453d30708fSChicago Duan return; 2463d30708fSChicago Duan } 2473d30708fSChicago Duan nlohmann::json& memberArray = asyncResp->res.jsonValue["Members"]; 2483d30708fSChicago Duan for (const auto& objpath : resp) 2493d30708fSChicago Duan { 2503d30708fSChicago Duan sdbusplus::message::object_path path(objpath.first); 2513d30708fSChicago Duan const std::string snmpId = path.filename(); 2523d30708fSChicago Duan if (snmpId.empty()) 2533d30708fSChicago Duan { 25462598e31SEd Tanous BMCWEB_LOG_ERROR("The SNMP client ID is wrong"); 2553d30708fSChicago Duan messages::internalError(asyncResp->res); 2563d30708fSChicago Duan return; 2573d30708fSChicago Duan } 2583d30708fSChicago Duan 2593d30708fSChicago Duan getSnmpSubscriptionList(asyncResp, snmpId, memberArray); 2603d30708fSChicago Duan } 2613d30708fSChicago Duan } 2623d30708fSChicago Duan 2637e860f15SJohn Edward Broadbent inline void requestRoutesEventDestinationCollection(App& app) 264e5aaf047SAppaRao Puli { 2651ebe3e41SGayathri Leburu BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/") 266ed398213SEd Tanous .privileges(redfish::privileges::getEventDestinationCollection) 2677e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 26845ca1b86SEd Tanous [&app](const crow::Request& req, 2697e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 2703ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 27145ca1b86SEd Tanous { 27245ca1b86SEd Tanous return; 27345ca1b86SEd Tanous } 2741476687dSEd Tanous asyncResp->res.jsonValue["@odata.type"] = 2751476687dSEd Tanous "#EventDestinationCollection.EventDestinationCollection"; 2761476687dSEd Tanous asyncResp->res.jsonValue["@odata.id"] = 2771476687dSEd Tanous "/redfish/v1/EventService/Subscriptions"; 278bd79bce8SPatrick Williams asyncResp->res.jsonValue["Name"] = 279bd79bce8SPatrick Williams "Event Destination Collections"; 280e5aaf047SAppaRao Puli 281bd79bce8SPatrick Williams nlohmann::json& memberArray = 282bd79bce8SPatrick Williams asyncResp->res.jsonValue["Members"]; 283e5aaf047SAppaRao Puli 284b52664e2SAppaRao Puli std::vector<std::string> subscripIds = 285b52664e2SAppaRao Puli EventServiceManager::getInstance().getAllIDs(); 286b52664e2SAppaRao Puli memberArray = nlohmann::json::array(); 287bd79bce8SPatrick Williams asyncResp->res.jsonValue["Members@odata.count"] = 288bd79bce8SPatrick Williams subscripIds.size(); 289b52664e2SAppaRao Puli 290b52664e2SAppaRao Puli for (const std::string& id : subscripIds) 291e5aaf047SAppaRao Puli { 2921476687dSEd Tanous nlohmann::json::object_t member; 2933d30708fSChicago Duan member["@odata.id"] = boost::urls::format( 2943d30708fSChicago Duan "/redfish/v1/EventService/Subscriptions/{}" + id); 295b2ba3072SPatrick Williams memberArray.emplace_back(std::move(member)); 296e5aaf047SAppaRao Puli } 297177612aaSEd Tanous dbus::utility::async_method_call( 298177612aaSEd Tanous asyncResp, 299e81de512SEd Tanous [asyncResp](const boost::system::error_code& ec, 3003d30708fSChicago Duan const dbus::utility::ManagedObjectType& resp) { 3013d30708fSChicago Duan doSubscriptionCollection(ec, asyncResp, resp); 3023d30708fSChicago Duan }, 3033d30708fSChicago Duan "xyz.openbmc_project.Network.SNMP", 3043d30708fSChicago Duan "/xyz/openbmc_project/network/snmp/manager", 3053d30708fSChicago Duan "org.freedesktop.DBus.ObjectManager", "GetManagedObjects"); 3067e860f15SJohn Edward Broadbent }); 3073d30708fSChicago Duan 3087e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/") 3097eeafa76SAbhishek Patel .privileges(redfish::privileges::postEventDestinationCollection) 310bd79bce8SPatrick Williams .methods( 311bd79bce8SPatrick Williams boost::beast::http::verb:: 312bd79bce8SPatrick Williams post)([&app]( 313bd79bce8SPatrick Williams const crow::Request& req, 3147e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 3153ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 31645ca1b86SEd Tanous { 31745ca1b86SEd Tanous return; 31845ca1b86SEd Tanous } 319fffb8c1fSEd Tanous if (EventServiceManager::getInstance().getNumberOfSubscriptions() >= 320fffb8c1fSEd Tanous maxNoOfSubscriptions) 321e5aaf047SAppaRao Puli { 322e5aaf047SAppaRao Puli messages::eventSubscriptionLimitExceeded(asyncResp->res); 323e5aaf047SAppaRao Puli return; 324e5aaf047SAppaRao Puli } 325e5aaf047SAppaRao Puli std::string destUrl; 326e5aaf047SAppaRao Puli std::string protocol; 32719bb362bSEd Tanous std::optional<bool> verifyCertificate; 328e5aaf047SAppaRao Puli std::optional<std::string> context; 329e5aaf047SAppaRao Puli std::optional<std::string> subscriptionType; 33023a21a1cSEd Tanous std::optional<std::string> eventFormatType2; 331e5aaf047SAppaRao Puli std::optional<std::string> retryPolicy; 3325064a25bSMyung Bae std::optional<bool> sendHeartbeat; 3335064a25bSMyung Bae std::optional<uint64_t> hbIntervalMinutes; 334e5aaf047SAppaRao Puli std::optional<std::vector<std::string>> msgIds; 335e5aaf047SAppaRao Puli std::optional<std::vector<std::string>> regPrefixes; 336a14c9113SEd Tanous std::optional<std::vector<std::string>> originResources; 337e56f254cSSunitha Harish std::optional<std::vector<std::string>> resTypes; 33878d4ec4fSEd Tanous std::optional<std::vector<nlohmann::json::object_t>> headers; 33978d4ec4fSEd Tanous std::optional<std::vector<nlohmann::json::object_t>> mrdJsonArray; 340e5aaf047SAppaRao Puli 341afc474aeSMyung Bae if (!json_util::readJsonPatch( // 342afc474aeSMyung Bae req, asyncResp->res, // 343afc474aeSMyung Bae "Context", context, // 344afc474aeSMyung Bae "DeliveryRetryPolicy", retryPolicy, // 345afc474aeSMyung Bae "Destination", destUrl, // 346afc474aeSMyung Bae "EventFormatType", eventFormatType2, // 3475064a25bSMyung Bae "HeartbeatIntervalMinutes", hbIntervalMinutes, // 348afc474aeSMyung Bae "HttpHeaders", headers, // 349afc474aeSMyung Bae "MessageIds", msgIds, // 350afc474aeSMyung Bae "MetricReportDefinitions", mrdJsonArray, // 351afc474aeSMyung Bae "OriginResources", originResources, // 352afc474aeSMyung Bae "Protocol", protocol, // 353afc474aeSMyung Bae "RegistryPrefixes", regPrefixes, // 354afc474aeSMyung Bae "ResourceTypes", resTypes, // 3555064a25bSMyung Bae "SendHeartbeat", sendHeartbeat, // 356afc474aeSMyung Bae "SubscriptionType", subscriptionType, // 357afc474aeSMyung Bae "VerifyCertificate", verifyCertificate // 3584b712a29SEd Tanous )) 359e5aaf047SAppaRao Puli { 360e5aaf047SAppaRao Puli return; 361e5aaf047SAppaRao Puli } 3624b712a29SEd Tanous // clang-format on 363e5aaf047SAppaRao Puli 364600af5f1SAppaRao Puli // https://stackoverflow.com/questions/417142/what-is-the-maximum-length-of-a-url-in-different-browsers 365600af5f1SAppaRao Puli static constexpr const uint16_t maxDestinationSize = 2000; 366600af5f1SAppaRao Puli if (destUrl.size() > maxDestinationSize) 367600af5f1SAppaRao Puli { 368600af5f1SAppaRao Puli messages::stringValueTooLong(asyncResp->res, "Destination", 369600af5f1SAppaRao Puli maxDestinationSize); 370600af5f1SAppaRao Puli return; 371600af5f1SAppaRao Puli } 372600af5f1SAppaRao Puli 373dd28ba82SAppaRao Puli if (regPrefixes && msgIds) 374dd28ba82SAppaRao Puli { 37526f6976fSEd Tanous if (!regPrefixes->empty() && !msgIds->empty()) 376dd28ba82SAppaRao Puli { 377bd79bce8SPatrick Williams messages::propertyValueConflict( 378bd79bce8SPatrick Williams asyncResp->res, "MessageIds", "RegistryPrefixes"); 379dd28ba82SAppaRao Puli return; 380dd28ba82SAppaRao Puli } 381dd28ba82SAppaRao Puli } 382dd28ba82SAppaRao Puli 3836fd29553SEd Tanous boost::system::result<boost::urls::url> url = 384a716aa74SEd Tanous boost::urls::parse_absolute_uri(destUrl); 385a716aa74SEd Tanous if (!url) 386e5aaf047SAppaRao Puli { 387bd79bce8SPatrick Williams BMCWEB_LOG_WARNING( 388bd79bce8SPatrick Williams "Failed to validate and split destination url"); 389e5aaf047SAppaRao Puli messages::propertyValueFormatError(asyncResp->res, destUrl, 390e5aaf047SAppaRao Puli "Destination"); 391e5aaf047SAppaRao Puli return; 392e5aaf047SAppaRao Puli } 393a716aa74SEd Tanous url->normalize(); 394b07942e3SGeorge Liu 395b07942e3SGeorge Liu // port_number returns zero if it is not a valid representable port 396b07942e3SGeorge Liu if (url->has_port() && url->port_number() == 0) 397b07942e3SGeorge Liu { 398b07942e3SGeorge Liu BMCWEB_LOG_WARNING("{} is an invalid port in destination url", 399b07942e3SGeorge Liu url->port()); 400b07942e3SGeorge Liu messages::propertyValueFormatError(asyncResp->res, destUrl, 401b07942e3SGeorge Liu "Destination"); 402b07942e3SGeorge Liu return; 403b07942e3SGeorge Liu } 404b07942e3SGeorge Liu 405a716aa74SEd Tanous crow::utility::setProtocolDefaults(*url, protocol); 406a716aa74SEd Tanous crow::utility::setPortDefaults(*url); 407a716aa74SEd Tanous 408a716aa74SEd Tanous if (url->path().empty()) 409a716aa74SEd Tanous { 410a716aa74SEd Tanous url->set_path("/"); 411a716aa74SEd Tanous } 412a716aa74SEd Tanous 413a716aa74SEd Tanous if (url->has_userinfo()) 414a716aa74SEd Tanous { 415a716aa74SEd Tanous messages::propertyValueFormatError(asyncResp->res, destUrl, 416a716aa74SEd Tanous "Destination"); 417a716aa74SEd Tanous return; 418a716aa74SEd Tanous } 419b52664e2SAppaRao Puli 4203d30708fSChicago Duan if (protocol == "SNMPv2c") 4213d30708fSChicago Duan { 4223d30708fSChicago Duan if (context) 4233d30708fSChicago Duan { 4243d30708fSChicago Duan messages::propertyValueConflict(asyncResp->res, "Context", 4253d30708fSChicago Duan "Protocol"); 4263d30708fSChicago Duan return; 4273d30708fSChicago Duan } 4283d30708fSChicago Duan if (eventFormatType2) 4293d30708fSChicago Duan { 430bd79bce8SPatrick Williams messages::propertyValueConflict( 431bd79bce8SPatrick Williams asyncResp->res, "EventFormatType", "Protocol"); 4323d30708fSChicago Duan return; 4333d30708fSChicago Duan } 4343d30708fSChicago Duan if (retryPolicy) 4353d30708fSChicago Duan { 436bd79bce8SPatrick Williams messages::propertyValueConflict(asyncResp->res, 437bd79bce8SPatrick Williams "RetryPolicy", "Protocol"); 4383d30708fSChicago Duan return; 4393d30708fSChicago Duan } 4405064a25bSMyung Bae if (sendHeartbeat) 4415064a25bSMyung Bae { 4425064a25bSMyung Bae messages::propertyValueConflict( 4435064a25bSMyung Bae asyncResp->res, "SendHeartbeat", "Protocol"); 4445064a25bSMyung Bae return; 4455064a25bSMyung Bae } 4465064a25bSMyung Bae if (hbIntervalMinutes) 4475064a25bSMyung Bae { 4485064a25bSMyung Bae messages::propertyValueConflict( 4495064a25bSMyung Bae asyncResp->res, "HeartbeatIntervalMinutes", "Protocol"); 4505064a25bSMyung Bae return; 4515064a25bSMyung Bae } 4523d30708fSChicago Duan if (msgIds) 4533d30708fSChicago Duan { 454bd79bce8SPatrick Williams messages::propertyValueConflict(asyncResp->res, 455bd79bce8SPatrick Williams "MessageIds", "Protocol"); 4563d30708fSChicago Duan return; 4573d30708fSChicago Duan } 4583d30708fSChicago Duan if (regPrefixes) 4593d30708fSChicago Duan { 460bd79bce8SPatrick Williams messages::propertyValueConflict( 461bd79bce8SPatrick Williams asyncResp->res, "RegistryPrefixes", "Protocol"); 4623d30708fSChicago Duan return; 4633d30708fSChicago Duan } 4643d30708fSChicago Duan if (resTypes) 4653d30708fSChicago Duan { 466bd79bce8SPatrick Williams messages::propertyValueConflict( 467bd79bce8SPatrick Williams asyncResp->res, "ResourceTypes", "Protocol"); 4683d30708fSChicago Duan return; 4693d30708fSChicago Duan } 4703d30708fSChicago Duan if (headers) 4713d30708fSChicago Duan { 472bd79bce8SPatrick Williams messages::propertyValueConflict(asyncResp->res, 473bd79bce8SPatrick Williams "HttpHeaders", "Protocol"); 4743d30708fSChicago Duan return; 4753d30708fSChicago Duan } 4763d30708fSChicago Duan if (mrdJsonArray) 4773d30708fSChicago Duan { 4783d30708fSChicago Duan messages::propertyValueConflict( 4793d30708fSChicago Duan asyncResp->res, "MetricReportDefinitions", "Protocol"); 4803d30708fSChicago Duan return; 4813d30708fSChicago Duan } 482a716aa74SEd Tanous if (url->scheme() != "snmp") 483a716aa74SEd Tanous { 484bd79bce8SPatrick Williams messages::propertyValueConflict(asyncResp->res, 485bd79bce8SPatrick Williams "Destination", "Protocol"); 4863d30708fSChicago Duan return; 4873d30708fSChicago Duan } 4883d30708fSChicago Duan 489a716aa74SEd Tanous addSnmpTrapClient(asyncResp, url->host_address(), 490a716aa74SEd Tanous url->port_number()); 491a716aa74SEd Tanous return; 492b52664e2SAppaRao Puli } 4933d30708fSChicago Duan 494a716aa74SEd Tanous std::shared_ptr<Subscription> subValue = 49521a94d5cSMyung Bae std::make_shared<Subscription>( 4965fe4ef35SMyung Bae std::make_shared<persistent_data::UserSubscription>(), *url, 4979838eb20SEd Tanous getIoContext()); 498e5aaf047SAppaRao Puli 499e5aaf047SAppaRao Puli if (subscriptionType) 500e5aaf047SAppaRao Puli { 501e5aaf047SAppaRao Puli if (*subscriptionType != "RedfishEvent") 502e5aaf047SAppaRao Puli { 503fffb8c1fSEd Tanous messages::propertyValueNotInList( 504fffb8c1fSEd Tanous asyncResp->res, *subscriptionType, "SubscriptionType"); 505e5aaf047SAppaRao Puli return; 506e5aaf047SAppaRao Puli } 5075fe4ef35SMyung Bae subValue->userSub->subscriptionType = *subscriptionType; 508e5aaf047SAppaRao Puli } 509e5aaf047SAppaRao Puli else 510e5aaf047SAppaRao Puli { 5114b712a29SEd Tanous // Default 5125fe4ef35SMyung Bae subValue->userSub->subscriptionType = "RedfishEvent"; 513e5aaf047SAppaRao Puli } 514e5aaf047SAppaRao Puli 515e5aaf047SAppaRao Puli if (protocol != "Redfish") 516e5aaf047SAppaRao Puli { 517e5aaf047SAppaRao Puli messages::propertyValueNotInList(asyncResp->res, protocol, 518e5aaf047SAppaRao Puli "Protocol"); 519e5aaf047SAppaRao Puli return; 520e5aaf047SAppaRao Puli } 5215fe4ef35SMyung Bae subValue->userSub->protocol = protocol; 522e5aaf047SAppaRao Puli 52319bb362bSEd Tanous if (verifyCertificate) 52419bb362bSEd Tanous { 5255fe4ef35SMyung Bae subValue->userSub->verifyCertificate = *verifyCertificate; 52619bb362bSEd Tanous } 52719bb362bSEd Tanous 52823a21a1cSEd Tanous if (eventFormatType2) 529e5aaf047SAppaRao Puli { 530bd79bce8SPatrick Williams if (std::ranges::find(supportedEvtFormatTypes, 531bd79bce8SPatrick Williams *eventFormatType2) == 5323544d2a7SEd Tanous supportedEvtFormatTypes.end()) 533e5aaf047SAppaRao Puli { 534fffb8c1fSEd Tanous messages::propertyValueNotInList( 535fffb8c1fSEd Tanous asyncResp->res, *eventFormatType2, "EventFormatType"); 536e5aaf047SAppaRao Puli return; 537e5aaf047SAppaRao Puli } 5385fe4ef35SMyung Bae subValue->userSub->eventFormatType = *eventFormatType2; 539e5aaf047SAppaRao Puli } 540e5aaf047SAppaRao Puli else 541e5aaf047SAppaRao Puli { 542e5aaf047SAppaRao Puli // If not specified, use default "Event" 5435fe4ef35SMyung Bae subValue->userSub->eventFormatType = "Event"; 544e5aaf047SAppaRao Puli } 545e5aaf047SAppaRao Puli 546e5aaf047SAppaRao Puli if (context) 547e5aaf047SAppaRao Puli { 5488ece0e45SEd Tanous // This value is selected arbitrarily. 549600af5f1SAppaRao Puli constexpr const size_t maxContextSize = 256; 550600af5f1SAppaRao Puli if (context->size() > maxContextSize) 551600af5f1SAppaRao Puli { 552600af5f1SAppaRao Puli messages::stringValueTooLong(asyncResp->res, "Context", 553600af5f1SAppaRao Puli maxContextSize); 554600af5f1SAppaRao Puli return; 555600af5f1SAppaRao Puli } 5565fe4ef35SMyung Bae subValue->userSub->customText = *context; 557e5aaf047SAppaRao Puli } 558e5aaf047SAppaRao Puli 559e5aaf047SAppaRao Puli if (headers) 560e5aaf047SAppaRao Puli { 561600af5f1SAppaRao Puli size_t cumulativeLen = 0; 562600af5f1SAppaRao Puli 56378d4ec4fSEd Tanous for (const nlohmann::json::object_t& headerChunk : *headers) 564601c71aeSEd Tanous { 56578d4ec4fSEd Tanous for (const auto& item : headerChunk) 56678d4ec4fSEd Tanous { 56778d4ec4fSEd Tanous const std::string* value = 56878d4ec4fSEd Tanous item.second.get_ptr<const std::string*>(); 56978d4ec4fSEd Tanous if (value == nullptr) 57078d4ec4fSEd Tanous { 57178d4ec4fSEd Tanous messages::propertyValueFormatError( 57278d4ec4fSEd Tanous asyncResp->res, item.second, 57378d4ec4fSEd Tanous "HttpHeaders/" + item.first); 57478d4ec4fSEd Tanous return; 57578d4ec4fSEd Tanous } 57678d4ec4fSEd Tanous // Adding a new json value is the size of the key, + 57778d4ec4fSEd Tanous // the size of the value + 2 * 2 quotes for each, + 57878d4ec4fSEd Tanous // the colon and space between. example: 57978d4ec4fSEd Tanous // "key": "value" 58078d4ec4fSEd Tanous cumulativeLen += item.first.size() + value->size() + 6; 581600af5f1SAppaRao Puli // This value is selected to mirror http_connection.hpp 582600af5f1SAppaRao Puli constexpr const uint16_t maxHeaderSizeED = 8096; 583600af5f1SAppaRao Puli if (cumulativeLen > maxHeaderSizeED) 584600af5f1SAppaRao Puli { 58578d4ec4fSEd Tanous messages::arraySizeTooLong( 58678d4ec4fSEd Tanous asyncResp->res, "HttpHeaders", maxHeaderSizeED); 587600af5f1SAppaRao Puli return; 588600af5f1SAppaRao Puli } 5895fe4ef35SMyung Bae subValue->userSub->httpHeaders.set(item.first, *value); 590601c71aeSEd Tanous } 591601c71aeSEd Tanous } 592e5aaf047SAppaRao Puli } 593e5aaf047SAppaRao Puli 594e5aaf047SAppaRao Puli if (regPrefixes) 595e5aaf047SAppaRao Puli { 596e5aaf047SAppaRao Puli for (const std::string& it : *regPrefixes) 597e5aaf047SAppaRao Puli { 5983544d2a7SEd Tanous if (std::ranges::find(supportedRegPrefixes, it) == 5993544d2a7SEd Tanous supportedRegPrefixes.end()) 600e5aaf047SAppaRao Puli { 601fffb8c1fSEd Tanous messages::propertyValueNotInList(asyncResp->res, it, 602fffb8c1fSEd Tanous "RegistryPrefixes"); 603e5aaf047SAppaRao Puli return; 604e5aaf047SAppaRao Puli } 605e5aaf047SAppaRao Puli } 6065fe4ef35SMyung Bae subValue->userSub->registryPrefixes = *regPrefixes; 607e5aaf047SAppaRao Puli } 608e5aaf047SAppaRao Puli 609a14c9113SEd Tanous if (originResources) 610a14c9113SEd Tanous { 6115fe4ef35SMyung Bae subValue->userSub->originResources = *originResources; 612a14c9113SEd Tanous } 613a14c9113SEd Tanous 614e56f254cSSunitha Harish if (resTypes) 615e56f254cSSunitha Harish { 616e56f254cSSunitha Harish for (const std::string& it : *resTypes) 617e56f254cSSunitha Harish { 6183544d2a7SEd Tanous if (std::ranges::find(supportedResourceTypes, it) == 6193544d2a7SEd Tanous supportedResourceTypes.end()) 620e56f254cSSunitha Harish { 621e56f254cSSunitha Harish messages::propertyValueNotInList(asyncResp->res, it, 622e56f254cSSunitha Harish "ResourceTypes"); 623e56f254cSSunitha Harish return; 624e56f254cSSunitha Harish } 625e56f254cSSunitha Harish } 6265fe4ef35SMyung Bae subValue->userSub->resourceTypes = *resTypes; 627e56f254cSSunitha Harish } 628e56f254cSSunitha Harish 629e5aaf047SAppaRao Puli if (msgIds) 630e5aaf047SAppaRao Puli { 631b304bd79SP Dheeraj Srujan Kumar std::vector<std::string> registryPrefix; 632b304bd79SP Dheeraj Srujan Kumar 6337e860f15SJohn Edward Broadbent // If no registry prefixes are mentioned, consider all 6347e860f15SJohn Edward Broadbent // supported prefixes 6355fe4ef35SMyung Bae if (subValue->userSub->registryPrefixes.empty()) 636b304bd79SP Dheeraj Srujan Kumar { 637b304bd79SP Dheeraj Srujan Kumar registryPrefix.assign(supportedRegPrefixes.begin(), 638b304bd79SP Dheeraj Srujan Kumar supportedRegPrefixes.end()); 639b304bd79SP Dheeraj Srujan Kumar } 640b304bd79SP Dheeraj Srujan Kumar else 641b304bd79SP Dheeraj Srujan Kumar { 6425fe4ef35SMyung Bae registryPrefix = subValue->userSub->registryPrefixes; 643b304bd79SP Dheeraj Srujan Kumar } 644b304bd79SP Dheeraj Srujan Kumar 645b304bd79SP Dheeraj Srujan Kumar for (const std::string& id : *msgIds) 646b304bd79SP Dheeraj Srujan Kumar { 647b304bd79SP Dheeraj Srujan Kumar bool validId = false; 648b304bd79SP Dheeraj Srujan Kumar 649b304bd79SP Dheeraj Srujan Kumar // Check for Message ID in each of the selected Registry 650b304bd79SP Dheeraj Srujan Kumar for (const std::string& it : registryPrefix) 651b304bd79SP Dheeraj Srujan Kumar { 652*4a102cd4SPatrick Williams const registries::MessageEntries registry = 653*4a102cd4SPatrick Williams redfish::registries::getRegistryMessagesFromPrefix( 654*4a102cd4SPatrick Williams it); 655b304bd79SP Dheeraj Srujan Kumar 6563544d2a7SEd Tanous if (std::ranges::any_of( 6573544d2a7SEd Tanous registry, 658fffb8c1fSEd Tanous [&id](const redfish::registries::MessageEntry& 659fffb8c1fSEd Tanous messageEntry) { 66055f79e6fSEd Tanous return id == messageEntry.first; 661b304bd79SP Dheeraj Srujan Kumar })) 662b304bd79SP Dheeraj Srujan Kumar { 663b304bd79SP Dheeraj Srujan Kumar validId = true; 664b304bd79SP Dheeraj Srujan Kumar break; 665b304bd79SP Dheeraj Srujan Kumar } 666b304bd79SP Dheeraj Srujan Kumar } 667b304bd79SP Dheeraj Srujan Kumar 668b304bd79SP Dheeraj Srujan Kumar if (!validId) 669b304bd79SP Dheeraj Srujan Kumar { 670b304bd79SP Dheeraj Srujan Kumar messages::propertyValueNotInList(asyncResp->res, id, 671b304bd79SP Dheeraj Srujan Kumar "MessageIds"); 672b304bd79SP Dheeraj Srujan Kumar return; 673b304bd79SP Dheeraj Srujan Kumar } 674b304bd79SP Dheeraj Srujan Kumar } 675b304bd79SP Dheeraj Srujan Kumar 6765fe4ef35SMyung Bae subValue->userSub->registryMsgIds = *msgIds; 677e5aaf047SAppaRao Puli } 678e5aaf047SAppaRao Puli 679e5aaf047SAppaRao Puli if (retryPolicy) 680e5aaf047SAppaRao Puli { 6813544d2a7SEd Tanous if (std::ranges::find(supportedRetryPolicies, *retryPolicy) == 6823544d2a7SEd Tanous supportedRetryPolicies.end()) 683e5aaf047SAppaRao Puli { 684bd79bce8SPatrick Williams messages::propertyValueNotInList( 685bd79bce8SPatrick Williams asyncResp->res, *retryPolicy, "DeliveryRetryPolicy"); 686e5aaf047SAppaRao Puli return; 687e5aaf047SAppaRao Puli } 6885fe4ef35SMyung Bae subValue->userSub->retryPolicy = *retryPolicy; 689e5aaf047SAppaRao Puli } 690e5aaf047SAppaRao Puli else 691e5aaf047SAppaRao Puli { 692e5aaf047SAppaRao Puli // Default "TerminateAfterRetries" 6935fe4ef35SMyung Bae subValue->userSub->retryPolicy = "TerminateAfterRetries"; 694e5aaf047SAppaRao Puli } 6955064a25bSMyung Bae if (sendHeartbeat) 6965064a25bSMyung Bae { 6975064a25bSMyung Bae subValue->userSub->sendHeartbeat = *sendHeartbeat; 6985064a25bSMyung Bae } 6995064a25bSMyung Bae if (hbIntervalMinutes) 7005064a25bSMyung Bae { 7015064a25bSMyung Bae if (*hbIntervalMinutes < 1 || *hbIntervalMinutes > 65535) 7025064a25bSMyung Bae { 7035064a25bSMyung Bae messages::propertyValueOutOfRange( 7045064a25bSMyung Bae asyncResp->res, *hbIntervalMinutes, 7055064a25bSMyung Bae "HeartbeatIntervalMinutes"); 7065064a25bSMyung Bae return; 7075064a25bSMyung Bae } 7085064a25bSMyung Bae subValue->userSub->hbIntervalMinutes = *hbIntervalMinutes; 7095064a25bSMyung Bae } 710e5aaf047SAppaRao Puli 711144b6318SAppaRao Puli if (mrdJsonArray) 712156d6b00SAppaRao Puli { 71378d4ec4fSEd Tanous for (nlohmann::json::object_t& mrdObj : *mrdJsonArray) 714144b6318SAppaRao Puli { 715144b6318SAppaRao Puli std::string mrdUri; 716ea2e6eecSWilly Tu 71778d4ec4fSEd Tanous if (!json_util::readJsonObject(mrdObj, asyncResp->res, 71878d4ec4fSEd Tanous "@odata.id", mrdUri)) 719ea2e6eecSWilly Tu 720144b6318SAppaRao Puli { 721144b6318SAppaRao Puli return; 722144b6318SAppaRao Puli } 7235fe4ef35SMyung Bae subValue->userSub->metricReportDefinitions.emplace_back( 7244b712a29SEd Tanous mrdUri); 725144b6318SAppaRao Puli } 726156d6b00SAppaRao Puli } 727156d6b00SAppaRao Puli 728b52664e2SAppaRao Puli std::string id = 729bd79bce8SPatrick Williams EventServiceManager::getInstance().addPushSubscription( 730bd79bce8SPatrick Williams subValue); 731b52664e2SAppaRao Puli if (id.empty()) 732e5aaf047SAppaRao Puli { 733e5aaf047SAppaRao Puli messages::internalError(asyncResp->res); 734e5aaf047SAppaRao Puli return; 735e5aaf047SAppaRao Puli } 736e5aaf047SAppaRao Puli 737e5aaf047SAppaRao Puli messages::created(asyncResp->res); 738e5aaf047SAppaRao Puli asyncResp->res.addHeader( 739e5aaf047SAppaRao Puli "Location", "/redfish/v1/EventService/Subscriptions/" + id); 740fb546105SMyung Bae 741fb546105SMyung Bae // schedule a heartbeat 742fb546105SMyung Bae if (subValue->userSub->sendHeartbeat) 743fb546105SMyung Bae { 744fb546105SMyung Bae subValue->scheduleNextHeartbeatEvent(); 745fb546105SMyung Bae } 7467e860f15SJohn Edward Broadbent }); 747e5aaf047SAppaRao Puli } 748e5aaf047SAppaRao Puli 7497e860f15SJohn Edward Broadbent inline void requestRoutesEventDestination(App& app) 750e5aaf047SAppaRao Puli { 7519d41aec6SRavi Teja BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/<str>/") 752ed398213SEd Tanous .privileges(redfish::privileges::getEventDestination) 7537e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 75445ca1b86SEd Tanous [&app](const crow::Request& req, 7557e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 7567e860f15SJohn Edward Broadbent const std::string& param) { 7573ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 75845ca1b86SEd Tanous { 75945ca1b86SEd Tanous return; 76045ca1b86SEd Tanous } 7613d30708fSChicago Duan 7623d30708fSChicago Duan if (param.starts_with("snmp")) 7633d30708fSChicago Duan { 7643d30708fSChicago Duan getSnmpTrapClient(asyncResp, param); 7653d30708fSChicago Duan return; 7663d30708fSChicago Duan } 7673d30708fSChicago Duan 768b52664e2SAppaRao Puli std::shared_ptr<Subscription> subValue = 7697e860f15SJohn Edward Broadbent EventServiceManager::getInstance().getSubscription(param); 770b52664e2SAppaRao Puli if (subValue == nullptr) 771e5aaf047SAppaRao Puli { 772bd79bce8SPatrick Williams asyncResp->res.result( 773bd79bce8SPatrick Williams boost::beast::http::status::not_found); 774e5aaf047SAppaRao Puli return; 775e5aaf047SAppaRao Puli } 7767e860f15SJohn Edward Broadbent const std::string& id = param; 777e5aaf047SAppaRao Puli 7784b712a29SEd Tanous const persistent_data::UserSubscription& userSub = 7795fe4ef35SMyung Bae *subValue->userSub; 780e56f254cSSunitha Harish 7814b712a29SEd Tanous nlohmann::json& jVal = asyncResp->res.jsonValue; 7824b712a29SEd Tanous jVal["@odata.type"] = 7834b712a29SEd Tanous "#EventDestination.v1_14_1.EventDestination"; 7844b712a29SEd Tanous jVal["Protocol"] = 7854b712a29SEd Tanous event_destination::EventDestinationProtocol::Redfish; 7864b712a29SEd Tanous jVal["@odata.id"] = boost::urls::format( 7874b712a29SEd Tanous "/redfish/v1/EventService/Subscriptions/{}", id); 7884b712a29SEd Tanous jVal["Id"] = id; 7894b712a29SEd Tanous jVal["Name"] = "Event Destination " + id; 7904b712a29SEd Tanous jVal["Destination"] = userSub.destinationUrl; 7914b712a29SEd Tanous jVal["Context"] = userSub.customText; 7924b712a29SEd Tanous jVal["SubscriptionType"] = userSub.subscriptionType; 7934b712a29SEd Tanous jVal["HttpHeaders"] = nlohmann::json::array(); 7944b712a29SEd Tanous jVal["EventFormatType"] = userSub.eventFormatType; 7954b712a29SEd Tanous jVal["RegistryPrefixes"] = userSub.registryPrefixes; 7964b712a29SEd Tanous jVal["ResourceTypes"] = userSub.resourceTypes; 7974b712a29SEd Tanous 7984b712a29SEd Tanous jVal["MessageIds"] = userSub.registryMsgIds; 7994b712a29SEd Tanous jVal["DeliveryRetryPolicy"] = userSub.retryPolicy; 8005064a25bSMyung Bae jVal["SendHeartbeat"] = userSub.sendHeartbeat; 8015064a25bSMyung Bae jVal["HeartbeatIntervalMinutes"] = userSub.hbIntervalMinutes; 8024b712a29SEd Tanous jVal["VerifyCertificate"] = userSub.verifyCertificate; 803144b6318SAppaRao Puli 8041476687dSEd Tanous nlohmann::json::array_t mrdJsonArray; 8054b712a29SEd Tanous for (const auto& mdrUri : userSub.metricReportDefinitions) 806144b6318SAppaRao Puli { 8071476687dSEd Tanous nlohmann::json::object_t mdr; 8081476687dSEd Tanous mdr["@odata.id"] = mdrUri; 8091476687dSEd Tanous mrdJsonArray.emplace_back(std::move(mdr)); 810144b6318SAppaRao Puli } 8114b712a29SEd Tanous jVal["MetricReportDefinitions"] = mrdJsonArray; 8127e860f15SJohn Edward Broadbent }); 8139d41aec6SRavi Teja BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/<str>/") 814ed398213SEd Tanous // The below privilege is wrong, it should be ConfigureManager OR 815ed398213SEd Tanous // ConfigureSelf 8167eeafa76SAbhishek Patel // https://github.com/openbmc/bmcweb/issues/220 817ed398213SEd Tanous //.privileges(redfish::privileges::patchEventDestination) 818432a890cSEd Tanous .privileges({{"ConfigureManager"}}) 8197e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::patch)( 82045ca1b86SEd Tanous [&app](const crow::Request& req, 8217e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 8227e860f15SJohn Edward Broadbent const std::string& param) { 8233ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 82445ca1b86SEd Tanous { 82545ca1b86SEd Tanous return; 82645ca1b86SEd Tanous } 827b52664e2SAppaRao Puli std::shared_ptr<Subscription> subValue = 8287e860f15SJohn Edward Broadbent EventServiceManager::getInstance().getSubscription(param); 829b52664e2SAppaRao Puli if (subValue == nullptr) 830e5aaf047SAppaRao Puli { 831bd79bce8SPatrick Williams asyncResp->res.result( 832bd79bce8SPatrick Williams boost::beast::http::status::not_found); 833e5aaf047SAppaRao Puli return; 834e5aaf047SAppaRao Puli } 835e5aaf047SAppaRao Puli 836e5aaf047SAppaRao Puli std::optional<std::string> context; 837e5aaf047SAppaRao Puli std::optional<std::string> retryPolicy; 8385064a25bSMyung Bae std::optional<bool> sendHeartbeat; 8395064a25bSMyung Bae std::optional<uint64_t> hbIntervalMinutes; 84019bb362bSEd Tanous std::optional<bool> verifyCertificate; 84178d4ec4fSEd Tanous std::optional<std::vector<nlohmann::json::object_t>> headers; 842e5aaf047SAppaRao Puli 843afc474aeSMyung Bae if (!json_util::readJsonPatch( // 844afc474aeSMyung Bae req, asyncResp->res, // 845afc474aeSMyung Bae "Context", context, // 846afc474aeSMyung Bae "DeliveryRetryPolicy", retryPolicy, // 8475064a25bSMyung Bae "HeartbeatIntervalMinutes", hbIntervalMinutes, // 848afc474aeSMyung Bae "HttpHeaders", headers, // 8495064a25bSMyung Bae "SendHeartbeat", sendHeartbeat, // 850afc474aeSMyung Bae "VerifyCertificate", verifyCertificate // 851afc474aeSMyung Bae )) 852e5aaf047SAppaRao Puli { 853e5aaf047SAppaRao Puli return; 854e5aaf047SAppaRao Puli } 855e5aaf047SAppaRao Puli 856e5aaf047SAppaRao Puli if (context) 857e5aaf047SAppaRao Puli { 8585fe4ef35SMyung Bae subValue->userSub->customText = *context; 859e5aaf047SAppaRao Puli } 860e5aaf047SAppaRao Puli 861e5aaf047SAppaRao Puli if (headers) 862e5aaf047SAppaRao Puli { 863601c71aeSEd Tanous boost::beast::http::fields fields; 86478d4ec4fSEd Tanous for (const nlohmann::json::object_t& headerChunk : *headers) 865601c71aeSEd Tanous { 86678d4ec4fSEd Tanous for (const auto& it : headerChunk) 867601c71aeSEd Tanous { 868601c71aeSEd Tanous const std::string* value = 86978d4ec4fSEd Tanous it.second.get_ptr<const std::string*>(); 870601c71aeSEd Tanous if (value == nullptr) 871601c71aeSEd Tanous { 872601c71aeSEd Tanous messages::propertyValueFormatError( 87378d4ec4fSEd Tanous asyncResp->res, it.second, 87478d4ec4fSEd Tanous "HttpHeaders/" + it.first); 875601c71aeSEd Tanous return; 876601c71aeSEd Tanous } 87778d4ec4fSEd Tanous fields.set(it.first, *value); 878601c71aeSEd Tanous } 879601c71aeSEd Tanous } 8805fe4ef35SMyung Bae subValue->userSub->httpHeaders = std::move(fields); 881e5aaf047SAppaRao Puli } 882e5aaf047SAppaRao Puli 883e5aaf047SAppaRao Puli if (retryPolicy) 884e5aaf047SAppaRao Puli { 885bd79bce8SPatrick Williams if (std::ranges::find(supportedRetryPolicies, 886bd79bce8SPatrick Williams *retryPolicy) == 8873544d2a7SEd Tanous supportedRetryPolicies.end()) 888e5aaf047SAppaRao Puli { 889bd79bce8SPatrick Williams messages::propertyValueNotInList(asyncResp->res, 890bd79bce8SPatrick Williams *retryPolicy, 891e5aaf047SAppaRao Puli "DeliveryRetryPolicy"); 892e5aaf047SAppaRao Puli return; 893e5aaf047SAppaRao Puli } 8945fe4ef35SMyung Bae subValue->userSub->retryPolicy = *retryPolicy; 895e5aaf047SAppaRao Puli } 896e5aaf047SAppaRao Puli 8975064a25bSMyung Bae if (sendHeartbeat) 8985064a25bSMyung Bae { 8995064a25bSMyung Bae subValue->userSub->sendHeartbeat = *sendHeartbeat; 9005064a25bSMyung Bae } 9015064a25bSMyung Bae if (hbIntervalMinutes) 9025064a25bSMyung Bae { 9035064a25bSMyung Bae if (*hbIntervalMinutes < 1 || *hbIntervalMinutes > 65535) 9045064a25bSMyung Bae { 9055064a25bSMyung Bae messages::propertyValueOutOfRange( 9065064a25bSMyung Bae asyncResp->res, *hbIntervalMinutes, 9075064a25bSMyung Bae "HeartbeatIntervalMinutes"); 9085064a25bSMyung Bae return; 9095064a25bSMyung Bae } 9105064a25bSMyung Bae subValue->userSub->hbIntervalMinutes = *hbIntervalMinutes; 9115064a25bSMyung Bae } 9125064a25bSMyung Bae 913fb546105SMyung Bae if (hbIntervalMinutes || sendHeartbeat) 914fb546105SMyung Bae { 915fb546105SMyung Bae // if Heartbeat interval or send heart were changed, cancel 916fb546105SMyung Bae // the heartbeat timer if running and start a new heartbeat 917fb546105SMyung Bae // if needed 918fb546105SMyung Bae subValue->heartbeatParametersChanged(); 919fb546105SMyung Bae } 920fb546105SMyung Bae 92119bb362bSEd Tanous if (verifyCertificate) 92219bb362bSEd Tanous { 9235fe4ef35SMyung Bae subValue->userSub->verifyCertificate = *verifyCertificate; 92419bb362bSEd Tanous } 92519bb362bSEd Tanous 926b52664e2SAppaRao Puli EventServiceManager::getInstance().updateSubscriptionData(); 9277e860f15SJohn Edward Broadbent }); 9289d41aec6SRavi Teja BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/<str>/") 929ed398213SEd Tanous // The below privilege is wrong, it should be ConfigureManager OR 930ed398213SEd Tanous // ConfigureSelf 9317eeafa76SAbhishek Patel // https://github.com/openbmc/bmcweb/issues/220 932ed398213SEd Tanous //.privileges(redfish::privileges::deleteEventDestination) 933432a890cSEd Tanous .privileges({{"ConfigureManager"}}) 9347e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::delete_)( 93545ca1b86SEd Tanous [&app](const crow::Request& req, 9367e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 9377e860f15SJohn Edward Broadbent const std::string& param) { 9383ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 93945ca1b86SEd Tanous { 94045ca1b86SEd Tanous return; 94145ca1b86SEd Tanous } 9424b712a29SEd Tanous EventServiceManager& event = EventServiceManager::getInstance(); 9433d30708fSChicago Duan if (param.starts_with("snmp")) 9443d30708fSChicago Duan { 9453d30708fSChicago Duan deleteSnmpTrapClient(asyncResp, param); 9464b712a29SEd Tanous event.deleteSubscription(param); 9473d30708fSChicago Duan return; 9483d30708fSChicago Duan } 9493d30708fSChicago Duan 9504b712a29SEd Tanous if (!event.deleteSubscription(param)) 951e5aaf047SAppaRao Puli { 9524b712a29SEd Tanous messages::resourceNotFound(asyncResp->res, 9534b712a29SEd Tanous "EventDestination", param); 954e5aaf047SAppaRao Puli return; 955e5aaf047SAppaRao Puli } 9564b712a29SEd Tanous messages::success(asyncResp->res); 9577e860f15SJohn Edward Broadbent }); 958e5aaf047SAppaRao Puli } 959e5aaf047SAppaRao Puli 960e5aaf047SAppaRao Puli } // namespace redfish 961