1e5aaf047SAppaRao Puli /* 2e5aaf047SAppaRao Puli // Copyright (c) 2020 Intel Corporation 3e5aaf047SAppaRao Puli // 4e5aaf047SAppaRao Puli // Licensed under the Apache License, Version 2.0 (the "License"); 5e5aaf047SAppaRao Puli // you may not use this file except in compliance with the License. 6e5aaf047SAppaRao Puli // You may obtain a copy of the License at 7e5aaf047SAppaRao Puli // 8e5aaf047SAppaRao Puli // http://www.apache.org/licenses/LICENSE-2.0 9e5aaf047SAppaRao Puli // 10e5aaf047SAppaRao Puli // Unless required by applicable law or agreed to in writing, software 11e5aaf047SAppaRao Puli // distributed under the License is distributed on an "AS IS" BASIS, 12e5aaf047SAppaRao Puli // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13e5aaf047SAppaRao Puli // See the License for the specific language governing permissions and 14e5aaf047SAppaRao Puli // limitations under the License. 15e5aaf047SAppaRao Puli */ 16e5aaf047SAppaRao Puli #pragma once 17b52664e2SAppaRao Puli #include "event_service_manager.hpp" 18e5aaf047SAppaRao Puli 197e860f15SJohn Edward Broadbent #include <app.hpp> 20601c71aeSEd Tanous #include <boost/beast/http/fields.hpp> 21*45ca1b86SEd Tanous #include <query.hpp> 22ed398213SEd Tanous #include <registries/privilege_registry.hpp> 23ed398213SEd Tanous 241e270c5fSPatrick Williams #include <span> 251e270c5fSPatrick Williams 26e5aaf047SAppaRao Puli namespace redfish 27e5aaf047SAppaRao Puli { 28e5aaf047SAppaRao Puli 29156d6b00SAppaRao Puli static constexpr const std::array<const char*, 2> supportedEvtFormatTypes = { 30156d6b00SAppaRao Puli eventFormatType, metricReportFormatType}; 31e5aaf047SAppaRao Puli static constexpr const std::array<const char*, 3> supportedRegPrefixes = { 32b304bd79SP Dheeraj Srujan Kumar "Base", "OpenBMC", "TaskEvent"}; 33e5aaf047SAppaRao Puli static constexpr const std::array<const char*, 3> supportedRetryPolicies = { 34e5aaf047SAppaRao Puli "TerminateAfterRetries", "SuspendRetries", "RetryForever"}; 35e5aaf047SAppaRao Puli 36e56f254cSSunitha Harish #ifdef BMCWEB_ENABLE_IBM_MANAGEMENT_CONSOLE 37e56f254cSSunitha Harish static constexpr const std::array<const char*, 2> supportedResourceTypes = { 38e56f254cSSunitha Harish "IBMConfigFile", "Task"}; 39e56f254cSSunitha Harish #else 40e56f254cSSunitha Harish static constexpr const std::array<const char*, 1> supportedResourceTypes = { 41e56f254cSSunitha Harish "Task"}; 42e56f254cSSunitha Harish #endif 43e56f254cSSunitha Harish 44e5aaf047SAppaRao Puli static constexpr const uint8_t maxNoOfSubscriptions = 20; 45e5aaf047SAppaRao Puli 467e860f15SJohn Edward Broadbent inline void requestRoutesEventService(App& app) 47e5aaf047SAppaRao Puli { 487e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, "/redfish/v1/EventService/") 49ed398213SEd Tanous .privileges(redfish::privileges::getEventService) 50*45ca1b86SEd Tanous .methods(boost::beast::http::verb::get)([&app](const crow::Request& req, 51*45ca1b86SEd Tanous const std::shared_ptr< 52*45ca1b86SEd Tanous bmcweb::AsyncResp>& 53*45ca1b86SEd Tanous asyncResp) { 54*45ca1b86SEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp->res)) 55*45ca1b86SEd Tanous { 56*45ca1b86SEd Tanous return; 57*45ca1b86SEd Tanous } 588d1b46d7Szhanghch05 asyncResp->res.jsonValue = { 59e5aaf047SAppaRao Puli {"@odata.type", "#EventService.v1_5_0.EventService"}, 60e5aaf047SAppaRao Puli {"Id", "EventService"}, 61e5aaf047SAppaRao Puli {"Name", "Event Service"}, 62e5aaf047SAppaRao Puli {"Subscriptions", 63e5aaf047SAppaRao Puli {{"@odata.id", "/redfish/v1/EventService/Subscriptions"}}}, 640b4bdd93SAppaRao Puli {"Actions", 650b4bdd93SAppaRao Puli {{"#EventService.SubmitTestEvent", 660fda0f12SGeorge Liu {{"target", 670fda0f12SGeorge Liu "/redfish/v1/EventService/Actions/EventService.SubmitTestEvent"}}}}}, 68e5aaf047SAppaRao Puli {"@odata.id", "/redfish/v1/EventService"}}; 69e5aaf047SAppaRao Puli 7028afb49cSJunLin Chen const persistent_data::EventServiceConfig eventServiceConfig = 7128afb49cSJunLin Chen persistent_data::EventServiceStore::getInstance() 7228afb49cSJunLin Chen .getEventServiceConfig(); 737d1cc387SAppaRao Puli 747d1cc387SAppaRao Puli asyncResp->res.jsonValue["Status"]["State"] = 7528afb49cSJunLin Chen (eventServiceConfig.enabled ? "Enabled" : "Disabled"); 7628afb49cSJunLin Chen asyncResp->res.jsonValue["ServiceEnabled"] = 7728afb49cSJunLin Chen eventServiceConfig.enabled; 787e860f15SJohn Edward Broadbent asyncResp->res.jsonValue["DeliveryRetryAttempts"] = 7928afb49cSJunLin Chen eventServiceConfig.retryAttempts; 80e5aaf047SAppaRao Puli asyncResp->res.jsonValue["DeliveryRetryIntervalSeconds"] = 8128afb49cSJunLin Chen eventServiceConfig.retryTimeoutInterval; 827e860f15SJohn Edward Broadbent asyncResp->res.jsonValue["EventFormatTypes"] = 837e860f15SJohn Edward Broadbent supportedEvtFormatTypes; 840fda0f12SGeorge Liu asyncResp->res.jsonValue["RegistryPrefixes"] = supportedRegPrefixes; 850fda0f12SGeorge Liu asyncResp->res.jsonValue["ResourceTypes"] = supportedResourceTypes; 8607941a88SAyushi Smriti 8707941a88SAyushi Smriti nlohmann::json supportedSSEFilters = { 8807941a88SAyushi Smriti {"EventFormatType", true}, {"MessageId", true}, 8907941a88SAyushi Smriti {"MetricReportDefinition", true}, {"RegistryPrefix", true}, 9007941a88SAyushi Smriti {"OriginResource", false}, {"ResourceType", false}}; 9107941a88SAyushi Smriti 9207941a88SAyushi Smriti asyncResp->res.jsonValue["SSEFilterPropertiesSupported"] = 9307941a88SAyushi Smriti supportedSSEFilters; 947e860f15SJohn Edward Broadbent }); 95e5aaf047SAppaRao Puli 967e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, "/redfish/v1/EventService/") 97ed398213SEd Tanous .privileges(redfish::privileges::patchEventService) 987e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::patch)( 99*45ca1b86SEd Tanous [&app](const crow::Request& req, 100*45ca1b86SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 101*45ca1b86SEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp->res)) 102e5aaf047SAppaRao Puli { 103*45ca1b86SEd Tanous return; 104*45ca1b86SEd Tanous } 105e5aaf047SAppaRao Puli std::optional<bool> serviceEnabled; 106e5aaf047SAppaRao Puli std::optional<uint32_t> retryAttemps; 107e5aaf047SAppaRao Puli std::optional<uint32_t> retryInterval; 108e5aaf047SAppaRao Puli 10915ed6780SWilly Tu if (!json_util::readJsonPatch( 1107e860f15SJohn Edward Broadbent req, asyncResp->res, "ServiceEnabled", serviceEnabled, 1117e860f15SJohn Edward Broadbent "DeliveryRetryAttempts", retryAttemps, 1127e860f15SJohn Edward Broadbent "DeliveryRetryIntervalSeconds", retryInterval)) 113e5aaf047SAppaRao Puli { 114e5aaf047SAppaRao Puli return; 115e5aaf047SAppaRao Puli } 116e5aaf047SAppaRao Puli 11728afb49cSJunLin Chen persistent_data::EventServiceConfig eventServiceConfig = 11828afb49cSJunLin Chen persistent_data::EventServiceStore::getInstance() 11928afb49cSJunLin Chen .getEventServiceConfig(); 1207d1cc387SAppaRao Puli 121e5aaf047SAppaRao Puli if (serviceEnabled) 122e5aaf047SAppaRao Puli { 12328afb49cSJunLin Chen eventServiceConfig.enabled = *serviceEnabled; 124e5aaf047SAppaRao Puli } 125e5aaf047SAppaRao Puli 126e5aaf047SAppaRao Puli if (retryAttemps) 127e5aaf047SAppaRao Puli { 128e5aaf047SAppaRao Puli // Supported range [1-3] 129e5aaf047SAppaRao Puli if ((*retryAttemps < 1) || (*retryAttemps > 3)) 130e5aaf047SAppaRao Puli { 131e5aaf047SAppaRao Puli messages::queryParameterOutOfRange( 132e5aaf047SAppaRao Puli asyncResp->res, std::to_string(*retryAttemps), 133e5aaf047SAppaRao Puli "DeliveryRetryAttempts", "[1-3]"); 134e5aaf047SAppaRao Puli } 135e5aaf047SAppaRao Puli else 136e5aaf047SAppaRao Puli { 13728afb49cSJunLin Chen eventServiceConfig.retryAttempts = *retryAttemps; 138e5aaf047SAppaRao Puli } 139e5aaf047SAppaRao Puli } 140e5aaf047SAppaRao Puli 141e5aaf047SAppaRao Puli if (retryInterval) 142e5aaf047SAppaRao Puli { 143e5aaf047SAppaRao Puli // Supported range [30 - 180] 144e5aaf047SAppaRao Puli if ((*retryInterval < 30) || (*retryInterval > 180)) 145e5aaf047SAppaRao Puli { 146e5aaf047SAppaRao Puli messages::queryParameterOutOfRange( 147e5aaf047SAppaRao Puli asyncResp->res, std::to_string(*retryInterval), 148e5aaf047SAppaRao Puli "DeliveryRetryIntervalSeconds", "[30-180]"); 149e5aaf047SAppaRao Puli } 150e5aaf047SAppaRao Puli else 151e5aaf047SAppaRao Puli { 15228afb49cSJunLin Chen eventServiceConfig.retryTimeoutInterval = 15328afb49cSJunLin Chen *retryInterval; 154e5aaf047SAppaRao Puli } 155e5aaf047SAppaRao Puli } 156e5aaf047SAppaRao Puli 1577d1cc387SAppaRao Puli EventServiceManager::getInstance().setEventServiceConfig( 15828afb49cSJunLin Chen eventServiceConfig); 1597e860f15SJohn Edward Broadbent }); 1600b4bdd93SAppaRao Puli } 1610b4bdd93SAppaRao Puli 1627e860f15SJohn Edward Broadbent inline void requestRoutesSubmitTestEvent(App& app) 1630b4bdd93SAppaRao Puli { 1647e860f15SJohn Edward Broadbent 1657e860f15SJohn Edward Broadbent BMCWEB_ROUTE( 1667e860f15SJohn Edward Broadbent app, "/redfish/v1/EventService/Actions/EventService.SubmitTestEvent/") 167ed398213SEd Tanous .privileges(redfish::privileges::postEventService) 1687e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::post)( 169*45ca1b86SEd Tanous [&app](const crow::Request& req, 1707e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 171*45ca1b86SEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp->res)) 172*45ca1b86SEd Tanous { 173*45ca1b86SEd Tanous return; 174*45ca1b86SEd Tanous } 1756ba8c82eSsunharis_in if (!EventServiceManager::getInstance().sendTestEventLog()) 1766ba8c82eSsunharis_in { 1776ba8c82eSsunharis_in messages::serviceDisabled(asyncResp->res, 1786ba8c82eSsunharis_in "/redfish/v1/EventService/"); 1796ba8c82eSsunharis_in return; 1806ba8c82eSsunharis_in } 1818d1b46d7Szhanghch05 asyncResp->res.result(boost::beast::http::status::no_content); 1827e860f15SJohn Edward Broadbent }); 183e5aaf047SAppaRao Puli } 184e5aaf047SAppaRao Puli 1857e860f15SJohn Edward Broadbent inline void requestRoutesEventDestinationCollection(App& app) 186e5aaf047SAppaRao Puli { 1871ebe3e41SGayathri Leburu BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/") 188ed398213SEd Tanous .privileges(redfish::privileges::getEventDestinationCollection) 1897e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 190*45ca1b86SEd Tanous [&app](const crow::Request& req, 1917e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 192*45ca1b86SEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp->res)) 193*45ca1b86SEd Tanous { 194*45ca1b86SEd Tanous return; 195*45ca1b86SEd Tanous } 1968d1b46d7Szhanghch05 asyncResp->res.jsonValue = { 197e5aaf047SAppaRao Puli {"@odata.type", 198e5aaf047SAppaRao Puli "#EventDestinationCollection.EventDestinationCollection"}, 199e5aaf047SAppaRao Puli {"@odata.id", "/redfish/v1/EventService/Subscriptions"}, 200e5aaf047SAppaRao Puli {"Name", "Event Destination Collections"}}; 201e5aaf047SAppaRao Puli 2027e860f15SJohn Edward Broadbent nlohmann::json& memberArray = 2037e860f15SJohn Edward Broadbent asyncResp->res.jsonValue["Members"]; 204e5aaf047SAppaRao Puli 205b52664e2SAppaRao Puli std::vector<std::string> subscripIds = 206b52664e2SAppaRao Puli EventServiceManager::getInstance().getAllIDs(); 207b52664e2SAppaRao Puli memberArray = nlohmann::json::array(); 2087e860f15SJohn Edward Broadbent asyncResp->res.jsonValue["Members@odata.count"] = 2097e860f15SJohn Edward Broadbent subscripIds.size(); 210b52664e2SAppaRao Puli 211b52664e2SAppaRao Puli for (const std::string& id : subscripIds) 212e5aaf047SAppaRao Puli { 213e5aaf047SAppaRao Puli memberArray.push_back( 214e5aaf047SAppaRao Puli {{"@odata.id", 215b52664e2SAppaRao Puli "/redfish/v1/EventService/Subscriptions/" + id}}); 216e5aaf047SAppaRao Puli } 2177e860f15SJohn Edward Broadbent }); 2187e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/") 2197eeafa76SAbhishek Patel .privileges(redfish::privileges::postEventDestinationCollection) 220fffb8c1fSEd Tanous .methods( 221fffb8c1fSEd Tanous boost::beast::http::verb:: 222*45ca1b86SEd Tanous post)([&app]( 223*45ca1b86SEd Tanous const crow::Request& req, 2247e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 225*45ca1b86SEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp->res)) 226*45ca1b86SEd Tanous { 227*45ca1b86SEd Tanous return; 228*45ca1b86SEd Tanous } 229fffb8c1fSEd Tanous if (EventServiceManager::getInstance().getNumberOfSubscriptions() >= 230fffb8c1fSEd Tanous maxNoOfSubscriptions) 231e5aaf047SAppaRao Puli { 232e5aaf047SAppaRao Puli messages::eventSubscriptionLimitExceeded(asyncResp->res); 233e5aaf047SAppaRao Puli return; 234e5aaf047SAppaRao Puli } 235e5aaf047SAppaRao Puli std::string destUrl; 236e5aaf047SAppaRao Puli std::string protocol; 237e5aaf047SAppaRao Puli std::optional<std::string> context; 238e5aaf047SAppaRao Puli std::optional<std::string> subscriptionType; 23923a21a1cSEd Tanous std::optional<std::string> eventFormatType2; 240e5aaf047SAppaRao Puli std::optional<std::string> retryPolicy; 241e5aaf047SAppaRao Puli std::optional<std::vector<std::string>> msgIds; 242e5aaf047SAppaRao Puli std::optional<std::vector<std::string>> regPrefixes; 243e56f254cSSunitha Harish std::optional<std::vector<std::string>> resTypes; 244e5aaf047SAppaRao Puli std::optional<std::vector<nlohmann::json>> headers; 245144b6318SAppaRao Puli std::optional<std::vector<nlohmann::json>> mrdJsonArray; 246e5aaf047SAppaRao Puli 24715ed6780SWilly Tu if (!json_util::readJsonPatch( 2487e860f15SJohn Edward Broadbent req, asyncResp->res, "Destination", destUrl, "Context", 2497e860f15SJohn Edward Broadbent context, "Protocol", protocol, "SubscriptionType", 2507e860f15SJohn Edward Broadbent subscriptionType, "EventFormatType", eventFormatType2, 2517e860f15SJohn Edward Broadbent "HttpHeaders", headers, "RegistryPrefixes", regPrefixes, 252fffb8c1fSEd Tanous "MessageIds", msgIds, "DeliveryRetryPolicy", retryPolicy, 253fffb8c1fSEd Tanous "MetricReportDefinitions", mrdJsonArray, "ResourceTypes", 254fffb8c1fSEd Tanous resTypes)) 255e5aaf047SAppaRao Puli { 256e5aaf047SAppaRao Puli return; 257e5aaf047SAppaRao Puli } 258e5aaf047SAppaRao Puli 259dd28ba82SAppaRao Puli if (regPrefixes && msgIds) 260dd28ba82SAppaRao Puli { 26126f6976fSEd Tanous if (!regPrefixes->empty() && !msgIds->empty()) 262dd28ba82SAppaRao Puli { 2630a4304cfSEd Tanous messages::propertyValueConflict( 2640a4304cfSEd Tanous asyncResp->res, "MessageIds", "RegistryPrefixes"); 265dd28ba82SAppaRao Puli return; 266dd28ba82SAppaRao Puli } 267dd28ba82SAppaRao Puli } 268dd28ba82SAppaRao Puli 269e5aaf047SAppaRao Puli // Validate the URL using regex expression 270b52664e2SAppaRao Puli // Format: <protocol>://<host>:<port>/<uri> 271b52664e2SAppaRao Puli // protocol: http/https 272b52664e2SAppaRao Puli // host: Exclude ' ', ':', '#', '?' 2734e0453b1SGunnar Mills // port: Empty or numeric value with ':' separator. 274b52664e2SAppaRao Puli // uri: Start with '/' and Exclude '#', ' ' 275b52664e2SAppaRao Puli // Can include query params(ex: '/event?test=1') 276b52664e2SAppaRao Puli // TODO: Need to validate hostname extensively(as per rfc) 277b52664e2SAppaRao Puli const std::regex urlRegex( 278b52664e2SAppaRao Puli "(http|https)://([^/\\x20\\x3f\\x23\\x3a]+):?([0-9]*)(/" 279b52664e2SAppaRao Puli "([^\\x20\\x23\\x3f]*\\x3f?([^\\x20\\x23\\x3f])*)?)"); 280b52664e2SAppaRao Puli std::cmatch match; 281b52664e2SAppaRao Puli if (!std::regex_match(destUrl.c_str(), match, urlRegex)) 282e5aaf047SAppaRao Puli { 283e5aaf047SAppaRao Puli messages::propertyValueFormatError(asyncResp->res, destUrl, 284e5aaf047SAppaRao Puli "Destination"); 285e5aaf047SAppaRao Puli return; 286e5aaf047SAppaRao Puli } 287b52664e2SAppaRao Puli 288fffb8c1fSEd Tanous std::string uriProto = std::string(match[1].first, match[1].second); 289b52664e2SAppaRao Puli if (uriProto == "http") 290b52664e2SAppaRao Puli { 291b52664e2SAppaRao Puli #ifndef BMCWEB_INSECURE_ENABLE_HTTP_PUSH_STYLE_EVENTING 292b52664e2SAppaRao Puli messages::propertyValueFormatError(asyncResp->res, destUrl, 293b52664e2SAppaRao Puli "Destination"); 294b52664e2SAppaRao Puli return; 295b52664e2SAppaRao Puli #endif 296b52664e2SAppaRao Puli } 297b52664e2SAppaRao Puli 298b52664e2SAppaRao Puli std::string host = std::string(match[2].first, match[2].second); 299b52664e2SAppaRao Puli std::string port = std::string(match[3].first, match[3].second); 300b52664e2SAppaRao Puli std::string path = std::string(match[4].first, match[4].second); 301b52664e2SAppaRao Puli if (port.empty()) 302b52664e2SAppaRao Puli { 303b52664e2SAppaRao Puli if (uriProto == "http") 304b52664e2SAppaRao Puli { 305b52664e2SAppaRao Puli port = "80"; 306b52664e2SAppaRao Puli } 307b52664e2SAppaRao Puli else 308b52664e2SAppaRao Puli { 309b52664e2SAppaRao Puli port = "443"; 310b52664e2SAppaRao Puli } 311b52664e2SAppaRao Puli } 312b52664e2SAppaRao Puli if (path.empty()) 313b52664e2SAppaRao Puli { 314b52664e2SAppaRao Puli path = "/"; 315b52664e2SAppaRao Puli } 316b52664e2SAppaRao Puli 317b52664e2SAppaRao Puli std::shared_ptr<Subscription> subValue = 318b52664e2SAppaRao Puli std::make_shared<Subscription>(host, port, path, uriProto); 319b52664e2SAppaRao Puli 320b52664e2SAppaRao Puli subValue->destinationUrl = destUrl; 321e5aaf047SAppaRao Puli 322e5aaf047SAppaRao Puli if (subscriptionType) 323e5aaf047SAppaRao Puli { 324e5aaf047SAppaRao Puli if (*subscriptionType != "RedfishEvent") 325e5aaf047SAppaRao Puli { 326fffb8c1fSEd Tanous messages::propertyValueNotInList( 327fffb8c1fSEd Tanous asyncResp->res, *subscriptionType, "SubscriptionType"); 328e5aaf047SAppaRao Puli return; 329e5aaf047SAppaRao Puli } 330b52664e2SAppaRao Puli subValue->subscriptionType = *subscriptionType; 331e5aaf047SAppaRao Puli } 332e5aaf047SAppaRao Puli else 333e5aaf047SAppaRao Puli { 334b52664e2SAppaRao Puli subValue->subscriptionType = "RedfishEvent"; // Default 335e5aaf047SAppaRao Puli } 336e5aaf047SAppaRao Puli 337e5aaf047SAppaRao Puli if (protocol != "Redfish") 338e5aaf047SAppaRao Puli { 339e5aaf047SAppaRao Puli messages::propertyValueNotInList(asyncResp->res, protocol, 340e5aaf047SAppaRao Puli "Protocol"); 341e5aaf047SAppaRao Puli return; 342e5aaf047SAppaRao Puli } 343b52664e2SAppaRao Puli subValue->protocol = protocol; 344e5aaf047SAppaRao Puli 34523a21a1cSEd Tanous if (eventFormatType2) 346e5aaf047SAppaRao Puli { 347e5aaf047SAppaRao Puli if (std::find(supportedEvtFormatTypes.begin(), 348e5aaf047SAppaRao Puli supportedEvtFormatTypes.end(), 3497e860f15SJohn Edward Broadbent *eventFormatType2) == 3507e860f15SJohn Edward Broadbent supportedEvtFormatTypes.end()) 351e5aaf047SAppaRao Puli { 352fffb8c1fSEd Tanous messages::propertyValueNotInList( 353fffb8c1fSEd Tanous asyncResp->res, *eventFormatType2, "EventFormatType"); 354e5aaf047SAppaRao Puli return; 355e5aaf047SAppaRao Puli } 35623a21a1cSEd Tanous subValue->eventFormatType = *eventFormatType2; 357e5aaf047SAppaRao Puli } 358e5aaf047SAppaRao Puli else 359e5aaf047SAppaRao Puli { 360e5aaf047SAppaRao Puli // If not specified, use default "Event" 36123a21a1cSEd Tanous subValue->eventFormatType = "Event"; 362e5aaf047SAppaRao Puli } 363e5aaf047SAppaRao Puli 364e5aaf047SAppaRao Puli if (context) 365e5aaf047SAppaRao Puli { 366b52664e2SAppaRao Puli subValue->customText = *context; 367e5aaf047SAppaRao Puli } 368e5aaf047SAppaRao Puli 369e5aaf047SAppaRao Puli if (headers) 370e5aaf047SAppaRao Puli { 371601c71aeSEd Tanous for (const nlohmann::json& headerChunk : *headers) 372601c71aeSEd Tanous { 373601c71aeSEd Tanous for (const auto& item : headerChunk.items()) 374601c71aeSEd Tanous { 375601c71aeSEd Tanous const std::string* value = 376601c71aeSEd Tanous item.value().get_ptr<const std::string*>(); 377601c71aeSEd Tanous if (value == nullptr) 378601c71aeSEd Tanous { 379601c71aeSEd Tanous messages::propertyValueFormatError( 380e662eae8SEd Tanous asyncResp->res, item.value().dump(2, 1), 381601c71aeSEd Tanous "HttpHeaders/" + item.key()); 382601c71aeSEd Tanous return; 383601c71aeSEd Tanous } 384601c71aeSEd Tanous subValue->httpHeaders.set(item.key(), *value); 385601c71aeSEd Tanous } 386601c71aeSEd Tanous } 387e5aaf047SAppaRao Puli } 388e5aaf047SAppaRao Puli 389e5aaf047SAppaRao Puli if (regPrefixes) 390e5aaf047SAppaRao Puli { 391e5aaf047SAppaRao Puli for (const std::string& it : *regPrefixes) 392e5aaf047SAppaRao Puli { 393e5aaf047SAppaRao Puli if (std::find(supportedRegPrefixes.begin(), 394e5aaf047SAppaRao Puli supportedRegPrefixes.end(), 395e5aaf047SAppaRao Puli it) == supportedRegPrefixes.end()) 396e5aaf047SAppaRao Puli { 397fffb8c1fSEd Tanous messages::propertyValueNotInList(asyncResp->res, it, 398fffb8c1fSEd Tanous "RegistryPrefixes"); 399e5aaf047SAppaRao Puli return; 400e5aaf047SAppaRao Puli } 401e5aaf047SAppaRao Puli } 402b52664e2SAppaRao Puli subValue->registryPrefixes = *regPrefixes; 403e5aaf047SAppaRao Puli } 404e5aaf047SAppaRao Puli 405e56f254cSSunitha Harish if (resTypes) 406e56f254cSSunitha Harish { 407e56f254cSSunitha Harish for (const std::string& it : *resTypes) 408e56f254cSSunitha Harish { 409e56f254cSSunitha Harish if (std::find(supportedResourceTypes.begin(), 410e56f254cSSunitha Harish supportedResourceTypes.end(), 411e56f254cSSunitha Harish it) == supportedResourceTypes.end()) 412e56f254cSSunitha Harish { 413e56f254cSSunitha Harish messages::propertyValueNotInList(asyncResp->res, it, 414e56f254cSSunitha Harish "ResourceTypes"); 415e56f254cSSunitha Harish return; 416e56f254cSSunitha Harish } 417e56f254cSSunitha Harish } 418e56f254cSSunitha Harish subValue->resourceTypes = *resTypes; 419e56f254cSSunitha Harish } 420e56f254cSSunitha Harish 421e5aaf047SAppaRao Puli if (msgIds) 422e5aaf047SAppaRao Puli { 423b304bd79SP Dheeraj Srujan Kumar std::vector<std::string> registryPrefix; 424b304bd79SP Dheeraj Srujan Kumar 4257e860f15SJohn Edward Broadbent // If no registry prefixes are mentioned, consider all 4267e860f15SJohn Edward Broadbent // supported prefixes 427b304bd79SP Dheeraj Srujan Kumar if (subValue->registryPrefixes.empty()) 428b304bd79SP Dheeraj Srujan Kumar { 429b304bd79SP Dheeraj Srujan Kumar registryPrefix.assign(supportedRegPrefixes.begin(), 430b304bd79SP Dheeraj Srujan Kumar supportedRegPrefixes.end()); 431b304bd79SP Dheeraj Srujan Kumar } 432b304bd79SP Dheeraj Srujan Kumar else 433b304bd79SP Dheeraj Srujan Kumar { 434b304bd79SP Dheeraj Srujan Kumar registryPrefix = subValue->registryPrefixes; 435b304bd79SP Dheeraj Srujan Kumar } 436b304bd79SP Dheeraj Srujan Kumar 437b304bd79SP Dheeraj Srujan Kumar for (const std::string& id : *msgIds) 438b304bd79SP Dheeraj Srujan Kumar { 439b304bd79SP Dheeraj Srujan Kumar bool validId = false; 440b304bd79SP Dheeraj Srujan Kumar 441b304bd79SP Dheeraj Srujan Kumar // Check for Message ID in each of the selected Registry 442b304bd79SP Dheeraj Srujan Kumar for (const std::string& it : registryPrefix) 443b304bd79SP Dheeraj Srujan Kumar { 444fffb8c1fSEd Tanous const std::span<const redfish::registries::MessageEntry> 445fffb8c1fSEd Tanous registry = 446fffb8c1fSEd Tanous redfish::registries::getRegistryFromPrefix(it); 447b304bd79SP Dheeraj Srujan Kumar 448b304bd79SP Dheeraj Srujan Kumar if (std::any_of( 44926702d01SEd Tanous registry.begin(), registry.end(), 450fffb8c1fSEd Tanous [&id](const redfish::registries::MessageEntry& 451fffb8c1fSEd Tanous messageEntry) { 45255f79e6fSEd Tanous return id == messageEntry.first; 453b304bd79SP Dheeraj Srujan Kumar })) 454b304bd79SP Dheeraj Srujan Kumar { 455b304bd79SP Dheeraj Srujan Kumar validId = true; 456b304bd79SP Dheeraj Srujan Kumar break; 457b304bd79SP Dheeraj Srujan Kumar } 458b304bd79SP Dheeraj Srujan Kumar } 459b304bd79SP Dheeraj Srujan Kumar 460b304bd79SP Dheeraj Srujan Kumar if (!validId) 461b304bd79SP Dheeraj Srujan Kumar { 462b304bd79SP Dheeraj Srujan Kumar messages::propertyValueNotInList(asyncResp->res, id, 463b304bd79SP Dheeraj Srujan Kumar "MessageIds"); 464b304bd79SP Dheeraj Srujan Kumar return; 465b304bd79SP Dheeraj Srujan Kumar } 466b304bd79SP Dheeraj Srujan Kumar } 467b304bd79SP Dheeraj Srujan Kumar 468b52664e2SAppaRao Puli subValue->registryMsgIds = *msgIds; 469e5aaf047SAppaRao Puli } 470e5aaf047SAppaRao Puli 471e5aaf047SAppaRao Puli if (retryPolicy) 472e5aaf047SAppaRao Puli { 473e5aaf047SAppaRao Puli if (std::find(supportedRetryPolicies.begin(), 474e5aaf047SAppaRao Puli supportedRetryPolicies.end(), 475e5aaf047SAppaRao Puli *retryPolicy) == supportedRetryPolicies.end()) 476e5aaf047SAppaRao Puli { 477fffb8c1fSEd Tanous messages::propertyValueNotInList( 478fffb8c1fSEd Tanous asyncResp->res, *retryPolicy, "DeliveryRetryPolicy"); 479e5aaf047SAppaRao Puli return; 480e5aaf047SAppaRao Puli } 481b52664e2SAppaRao Puli subValue->retryPolicy = *retryPolicy; 482e5aaf047SAppaRao Puli } 483e5aaf047SAppaRao Puli else 484e5aaf047SAppaRao Puli { 485e5aaf047SAppaRao Puli // Default "TerminateAfterRetries" 486b52664e2SAppaRao Puli subValue->retryPolicy = "TerminateAfterRetries"; 487e5aaf047SAppaRao Puli } 488e5aaf047SAppaRao Puli 489144b6318SAppaRao Puli if (mrdJsonArray) 490156d6b00SAppaRao Puli { 491144b6318SAppaRao Puli for (nlohmann::json& mrdObj : *mrdJsonArray) 492144b6318SAppaRao Puli { 493144b6318SAppaRao Puli std::string mrdUri; 494ea2e6eecSWilly Tu 495ea2e6eecSWilly Tu if (!json_util::readJson(mrdObj, asyncResp->res, 496ea2e6eecSWilly Tu "@odata.id", mrdUri)) 497ea2e6eecSWilly Tu 498144b6318SAppaRao Puli { 499144b6318SAppaRao Puli return; 500144b6318SAppaRao Puli } 501ea2e6eecSWilly Tu subValue->metricReportDefinitions.emplace_back(mrdUri); 502144b6318SAppaRao Puli } 503156d6b00SAppaRao Puli } 504156d6b00SAppaRao Puli 505b52664e2SAppaRao Puli std::string id = 506fffb8c1fSEd Tanous EventServiceManager::getInstance().addSubscription(subValue); 507b52664e2SAppaRao Puli if (id.empty()) 508e5aaf047SAppaRao Puli { 509e5aaf047SAppaRao Puli messages::internalError(asyncResp->res); 510e5aaf047SAppaRao Puli return; 511e5aaf047SAppaRao Puli } 512e5aaf047SAppaRao Puli 513e5aaf047SAppaRao Puli messages::created(asyncResp->res); 514e5aaf047SAppaRao Puli asyncResp->res.addHeader( 515e5aaf047SAppaRao Puli "Location", "/redfish/v1/EventService/Subscriptions/" + id); 5167e860f15SJohn Edward Broadbent }); 517e5aaf047SAppaRao Puli } 518e5aaf047SAppaRao Puli 5197e860f15SJohn Edward Broadbent inline void requestRoutesEventDestination(App& app) 520e5aaf047SAppaRao Puli { 5219d41aec6SRavi Teja BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/<str>/") 522ed398213SEd Tanous .privileges(redfish::privileges::getEventDestination) 5237e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 524*45ca1b86SEd Tanous [&app](const crow::Request& req, 5257e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 5267e860f15SJohn Edward Broadbent const std::string& param) { 527*45ca1b86SEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp->res)) 528*45ca1b86SEd Tanous { 529*45ca1b86SEd Tanous return; 530*45ca1b86SEd Tanous } 531b52664e2SAppaRao Puli std::shared_ptr<Subscription> subValue = 5327e860f15SJohn Edward Broadbent EventServiceManager::getInstance().getSubscription(param); 533b52664e2SAppaRao Puli if (subValue == nullptr) 534e5aaf047SAppaRao Puli { 5357e860f15SJohn Edward Broadbent asyncResp->res.result( 5367e860f15SJohn Edward Broadbent boost::beast::http::status::not_found); 537e5aaf047SAppaRao Puli return; 538e5aaf047SAppaRao Puli } 5397e860f15SJohn Edward Broadbent const std::string& id = param; 540e5aaf047SAppaRao Puli 5418d1b46d7Szhanghch05 asyncResp->res.jsonValue = { 5427e860f15SJohn Edward Broadbent {"@odata.type", 5437e860f15SJohn Edward Broadbent "#EventDestination.v1_7_0.EventDestination"}, 544e5aaf047SAppaRao Puli {"Protocol", "Redfish"}}; 545e5aaf047SAppaRao Puli asyncResp->res.jsonValue["@odata.id"] = 546e5aaf047SAppaRao Puli "/redfish/v1/EventService/Subscriptions/" + id; 547e5aaf047SAppaRao Puli asyncResp->res.jsonValue["Id"] = id; 548e5aaf047SAppaRao Puli asyncResp->res.jsonValue["Name"] = "Event Destination " + id; 5497e860f15SJohn Edward Broadbent asyncResp->res.jsonValue["Destination"] = 5507e860f15SJohn Edward Broadbent subValue->destinationUrl; 551b52664e2SAppaRao Puli asyncResp->res.jsonValue["Context"] = subValue->customText; 552e5aaf047SAppaRao Puli asyncResp->res.jsonValue["SubscriptionType"] = 553b52664e2SAppaRao Puli subValue->subscriptionType; 554ad22fefeSEd Tanous asyncResp->res.jsonValue["HttpHeaders"] = 555ad22fefeSEd Tanous nlohmann::json::array(); 5567e860f15SJohn Edward Broadbent asyncResp->res.jsonValue["EventFormatType"] = 5577e860f15SJohn Edward Broadbent subValue->eventFormatType; 558e5aaf047SAppaRao Puli asyncResp->res.jsonValue["RegistryPrefixes"] = 559b52664e2SAppaRao Puli subValue->registryPrefixes; 5607e860f15SJohn Edward Broadbent asyncResp->res.jsonValue["ResourceTypes"] = 5617e860f15SJohn Edward Broadbent subValue->resourceTypes; 562e56f254cSSunitha Harish 5637e860f15SJohn Edward Broadbent asyncResp->res.jsonValue["MessageIds"] = 5647e860f15SJohn Edward Broadbent subValue->registryMsgIds; 5657e860f15SJohn Edward Broadbent asyncResp->res.jsonValue["DeliveryRetryPolicy"] = 5667e860f15SJohn Edward Broadbent subValue->retryPolicy; 567144b6318SAppaRao Puli 568144b6318SAppaRao Puli std::vector<nlohmann::json> mrdJsonArray; 569144b6318SAppaRao Puli for (const auto& mdrUri : subValue->metricReportDefinitions) 570144b6318SAppaRao Puli { 571144b6318SAppaRao Puli mrdJsonArray.push_back({{"@odata.id", mdrUri}}); 572144b6318SAppaRao Puli } 5737e860f15SJohn Edward Broadbent asyncResp->res.jsonValue["MetricReportDefinitions"] = 5747e860f15SJohn Edward Broadbent mrdJsonArray; 5757e860f15SJohn Edward Broadbent }); 5769d41aec6SRavi Teja BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/<str>/") 577ed398213SEd Tanous // The below privilege is wrong, it should be ConfigureManager OR 578ed398213SEd Tanous // ConfigureSelf 5797eeafa76SAbhishek Patel // https://github.com/openbmc/bmcweb/issues/220 580ed398213SEd Tanous //.privileges(redfish::privileges::patchEventDestination) 581432a890cSEd Tanous .privileges({{"ConfigureManager"}}) 5827e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::patch)( 583*45ca1b86SEd Tanous [&app](const crow::Request& req, 5847e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 5857e860f15SJohn Edward Broadbent const std::string& param) { 586*45ca1b86SEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp->res)) 587*45ca1b86SEd Tanous { 588*45ca1b86SEd Tanous return; 589*45ca1b86SEd Tanous } 590b52664e2SAppaRao Puli std::shared_ptr<Subscription> subValue = 5917e860f15SJohn Edward Broadbent EventServiceManager::getInstance().getSubscription(param); 592b52664e2SAppaRao Puli if (subValue == nullptr) 593e5aaf047SAppaRao Puli { 5947e860f15SJohn Edward Broadbent asyncResp->res.result( 5957e860f15SJohn Edward Broadbent boost::beast::http::status::not_found); 596e5aaf047SAppaRao Puli return; 597e5aaf047SAppaRao Puli } 598e5aaf047SAppaRao Puli 599e5aaf047SAppaRao Puli std::optional<std::string> context; 600e5aaf047SAppaRao Puli std::optional<std::string> retryPolicy; 601e5aaf047SAppaRao Puli std::optional<std::vector<nlohmann::json>> headers; 602e5aaf047SAppaRao Puli 60315ed6780SWilly Tu if (!json_util::readJsonPatch(req, asyncResp->res, "Context", 6047e860f15SJohn Edward Broadbent context, "DeliveryRetryPolicy", 60515ed6780SWilly Tu retryPolicy, "HttpHeaders", 60615ed6780SWilly Tu headers)) 607e5aaf047SAppaRao Puli { 608e5aaf047SAppaRao Puli return; 609e5aaf047SAppaRao Puli } 610e5aaf047SAppaRao Puli 611e5aaf047SAppaRao Puli if (context) 612e5aaf047SAppaRao Puli { 613b52664e2SAppaRao Puli subValue->customText = *context; 614e5aaf047SAppaRao Puli } 615e5aaf047SAppaRao Puli 616e5aaf047SAppaRao Puli if (headers) 617e5aaf047SAppaRao Puli { 618601c71aeSEd Tanous boost::beast::http::fields fields; 619601c71aeSEd Tanous for (const nlohmann::json& headerChunk : *headers) 620601c71aeSEd Tanous { 621601c71aeSEd Tanous for (auto& it : headerChunk.items()) 622601c71aeSEd Tanous { 623601c71aeSEd Tanous const std::string* value = 624601c71aeSEd Tanous it.value().get_ptr<const std::string*>(); 625601c71aeSEd Tanous if (value == nullptr) 626601c71aeSEd Tanous { 627601c71aeSEd Tanous messages::propertyValueFormatError( 628601c71aeSEd Tanous asyncResp->res, 629601c71aeSEd Tanous it.value().dump(2, ' ', true), 630601c71aeSEd Tanous "HttpHeaders/" + it.key()); 631601c71aeSEd Tanous return; 632601c71aeSEd Tanous } 633601c71aeSEd Tanous fields.set(it.key(), *value); 634601c71aeSEd Tanous } 635601c71aeSEd Tanous } 636601c71aeSEd Tanous subValue->httpHeaders = fields; 637e5aaf047SAppaRao Puli } 638e5aaf047SAppaRao Puli 639e5aaf047SAppaRao Puli if (retryPolicy) 640e5aaf047SAppaRao Puli { 641e5aaf047SAppaRao Puli if (std::find(supportedRetryPolicies.begin(), 642e5aaf047SAppaRao Puli supportedRetryPolicies.end(), 643e5aaf047SAppaRao Puli *retryPolicy) == supportedRetryPolicies.end()) 644e5aaf047SAppaRao Puli { 6457e860f15SJohn Edward Broadbent messages::propertyValueNotInList(asyncResp->res, 6467e860f15SJohn Edward Broadbent *retryPolicy, 647e5aaf047SAppaRao Puli "DeliveryRetryPolicy"); 648e5aaf047SAppaRao Puli return; 649e5aaf047SAppaRao Puli } 650b52664e2SAppaRao Puli subValue->retryPolicy = *retryPolicy; 651fe44eb0bSAyushi Smriti subValue->updateRetryPolicy(); 652e5aaf047SAppaRao Puli } 653e5aaf047SAppaRao Puli 654b52664e2SAppaRao Puli EventServiceManager::getInstance().updateSubscriptionData(); 6557e860f15SJohn Edward Broadbent }); 6569d41aec6SRavi Teja BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/<str>/") 657ed398213SEd Tanous // The below privilege is wrong, it should be ConfigureManager OR 658ed398213SEd Tanous // ConfigureSelf 6597eeafa76SAbhishek Patel // https://github.com/openbmc/bmcweb/issues/220 660ed398213SEd Tanous //.privileges(redfish::privileges::deleteEventDestination) 661432a890cSEd Tanous .privileges({{"ConfigureManager"}}) 6627e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::delete_)( 663*45ca1b86SEd Tanous [&app](const crow::Request& req, 6647e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 6657e860f15SJohn Edward Broadbent const std::string& param) { 666*45ca1b86SEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp->res)) 667*45ca1b86SEd Tanous { 668*45ca1b86SEd Tanous return; 669*45ca1b86SEd Tanous } 6707e860f15SJohn Edward Broadbent if (!EventServiceManager::getInstance().isSubscriptionExist( 6717e860f15SJohn Edward Broadbent param)) 672e5aaf047SAppaRao Puli { 6737e860f15SJohn Edward Broadbent asyncResp->res.result( 6747e860f15SJohn Edward Broadbent boost::beast::http::status::not_found); 675e5aaf047SAppaRao Puli return; 676e5aaf047SAppaRao Puli } 6777e860f15SJohn Edward Broadbent EventServiceManager::getInstance().deleteSubscription(param); 6787e860f15SJohn Edward Broadbent }); 679e5aaf047SAppaRao Puli } 680e5aaf047SAppaRao Puli 681e5aaf047SAppaRao Puli } // namespace redfish 682