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> 21ed398213SEd Tanous #include <registries/privilege_registry.hpp> 22ed398213SEd Tanous 231e270c5fSPatrick Williams #include <span> 241e270c5fSPatrick Williams 25e5aaf047SAppaRao Puli namespace redfish 26e5aaf047SAppaRao Puli { 27e5aaf047SAppaRao Puli 28156d6b00SAppaRao Puli static constexpr const std::array<const char*, 2> supportedEvtFormatTypes = { 29156d6b00SAppaRao Puli eventFormatType, metricReportFormatType}; 30e5aaf047SAppaRao Puli static constexpr const std::array<const char*, 3> supportedRegPrefixes = { 31b304bd79SP Dheeraj Srujan Kumar "Base", "OpenBMC", "TaskEvent"}; 32e5aaf047SAppaRao Puli static constexpr const std::array<const char*, 3> supportedRetryPolicies = { 33e5aaf047SAppaRao Puli "TerminateAfterRetries", "SuspendRetries", "RetryForever"}; 34e5aaf047SAppaRao Puli 35e56f254cSSunitha Harish #ifdef BMCWEB_ENABLE_IBM_MANAGEMENT_CONSOLE 36e56f254cSSunitha Harish static constexpr const std::array<const char*, 2> supportedResourceTypes = { 37e56f254cSSunitha Harish "IBMConfigFile", "Task"}; 38e56f254cSSunitha Harish #else 39e56f254cSSunitha Harish static constexpr const std::array<const char*, 1> supportedResourceTypes = { 40e56f254cSSunitha Harish "Task"}; 41e56f254cSSunitha Harish #endif 42e56f254cSSunitha Harish 43e5aaf047SAppaRao Puli static constexpr const uint8_t maxNoOfSubscriptions = 20; 44e5aaf047SAppaRao Puli 457e860f15SJohn Edward Broadbent inline void requestRoutesEventService(App& app) 46e5aaf047SAppaRao Puli { 477e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, "/redfish/v1/EventService/") 48ed398213SEd Tanous .privileges(redfish::privileges::getEventService) 490fda0f12SGeorge Liu .methods( 500fda0f12SGeorge Liu boost::beast::http::verb:: 510fda0f12SGeorge Liu get)([](const crow::Request&, 527e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 538d1b46d7Szhanghch05 asyncResp->res.jsonValue = { 54e5aaf047SAppaRao Puli {"@odata.type", "#EventService.v1_5_0.EventService"}, 55e5aaf047SAppaRao Puli {"Id", "EventService"}, 56e5aaf047SAppaRao Puli {"Name", "Event Service"}, 57e5aaf047SAppaRao Puli {"Subscriptions", 58e5aaf047SAppaRao Puli {{"@odata.id", "/redfish/v1/EventService/Subscriptions"}}}, 590b4bdd93SAppaRao Puli {"Actions", 600b4bdd93SAppaRao Puli {{"#EventService.SubmitTestEvent", 610fda0f12SGeorge Liu {{"target", 620fda0f12SGeorge Liu "/redfish/v1/EventService/Actions/EventService.SubmitTestEvent"}}}}}, 63e5aaf047SAppaRao Puli {"@odata.id", "/redfish/v1/EventService"}}; 64e5aaf047SAppaRao Puli 6528afb49cSJunLin Chen const persistent_data::EventServiceConfig eventServiceConfig = 6628afb49cSJunLin Chen persistent_data::EventServiceStore::getInstance() 6728afb49cSJunLin Chen .getEventServiceConfig(); 687d1cc387SAppaRao Puli 697d1cc387SAppaRao Puli asyncResp->res.jsonValue["Status"]["State"] = 7028afb49cSJunLin Chen (eventServiceConfig.enabled ? "Enabled" : "Disabled"); 7128afb49cSJunLin Chen asyncResp->res.jsonValue["ServiceEnabled"] = 7228afb49cSJunLin Chen eventServiceConfig.enabled; 737e860f15SJohn Edward Broadbent asyncResp->res.jsonValue["DeliveryRetryAttempts"] = 7428afb49cSJunLin Chen eventServiceConfig.retryAttempts; 75e5aaf047SAppaRao Puli asyncResp->res.jsonValue["DeliveryRetryIntervalSeconds"] = 7628afb49cSJunLin Chen eventServiceConfig.retryTimeoutInterval; 777e860f15SJohn Edward Broadbent asyncResp->res.jsonValue["EventFormatTypes"] = 787e860f15SJohn Edward Broadbent supportedEvtFormatTypes; 790fda0f12SGeorge Liu asyncResp->res.jsonValue["RegistryPrefixes"] = supportedRegPrefixes; 800fda0f12SGeorge Liu asyncResp->res.jsonValue["ResourceTypes"] = supportedResourceTypes; 8107941a88SAyushi Smriti 8207941a88SAyushi Smriti nlohmann::json supportedSSEFilters = { 8307941a88SAyushi Smriti {"EventFormatType", true}, {"MessageId", true}, 8407941a88SAyushi Smriti {"MetricReportDefinition", true}, {"RegistryPrefix", true}, 8507941a88SAyushi Smriti {"OriginResource", false}, {"ResourceType", false}}; 8607941a88SAyushi Smriti 8707941a88SAyushi Smriti asyncResp->res.jsonValue["SSEFilterPropertiesSupported"] = 8807941a88SAyushi Smriti supportedSSEFilters; 897e860f15SJohn Edward Broadbent }); 90e5aaf047SAppaRao Puli 917e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, "/redfish/v1/EventService/") 92ed398213SEd Tanous .privileges(redfish::privileges::patchEventService) 937e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::patch)( 947e860f15SJohn Edward Broadbent [](const crow::Request& req, 957e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 967e860f15SJohn Edward Broadbent 97e5aaf047SAppaRao Puli { 98e5aaf047SAppaRao Puli std::optional<bool> serviceEnabled; 99e5aaf047SAppaRao Puli std::optional<uint32_t> retryAttemps; 100e5aaf047SAppaRao Puli std::optional<uint32_t> retryInterval; 101e5aaf047SAppaRao Puli 10215ed6780SWilly Tu if (!json_util::readJsonPatch( 1037e860f15SJohn Edward Broadbent req, asyncResp->res, "ServiceEnabled", serviceEnabled, 1047e860f15SJohn Edward Broadbent "DeliveryRetryAttempts", retryAttemps, 1057e860f15SJohn Edward Broadbent "DeliveryRetryIntervalSeconds", retryInterval)) 106e5aaf047SAppaRao Puli { 107e5aaf047SAppaRao Puli return; 108e5aaf047SAppaRao Puli } 109e5aaf047SAppaRao Puli 11028afb49cSJunLin Chen persistent_data::EventServiceConfig eventServiceConfig = 11128afb49cSJunLin Chen persistent_data::EventServiceStore::getInstance() 11228afb49cSJunLin Chen .getEventServiceConfig(); 1137d1cc387SAppaRao Puli 114e5aaf047SAppaRao Puli if (serviceEnabled) 115e5aaf047SAppaRao Puli { 11628afb49cSJunLin Chen eventServiceConfig.enabled = *serviceEnabled; 117e5aaf047SAppaRao Puli } 118e5aaf047SAppaRao Puli 119e5aaf047SAppaRao Puli if (retryAttemps) 120e5aaf047SAppaRao Puli { 121e5aaf047SAppaRao Puli // Supported range [1-3] 122e5aaf047SAppaRao Puli if ((*retryAttemps < 1) || (*retryAttemps > 3)) 123e5aaf047SAppaRao Puli { 124e5aaf047SAppaRao Puli messages::queryParameterOutOfRange( 125e5aaf047SAppaRao Puli asyncResp->res, std::to_string(*retryAttemps), 126e5aaf047SAppaRao Puli "DeliveryRetryAttempts", "[1-3]"); 127e5aaf047SAppaRao Puli } 128e5aaf047SAppaRao Puli else 129e5aaf047SAppaRao Puli { 13028afb49cSJunLin Chen eventServiceConfig.retryAttempts = *retryAttemps; 131e5aaf047SAppaRao Puli } 132e5aaf047SAppaRao Puli } 133e5aaf047SAppaRao Puli 134e5aaf047SAppaRao Puli if (retryInterval) 135e5aaf047SAppaRao Puli { 136e5aaf047SAppaRao Puli // Supported range [30 - 180] 137e5aaf047SAppaRao Puli if ((*retryInterval < 30) || (*retryInterval > 180)) 138e5aaf047SAppaRao Puli { 139e5aaf047SAppaRao Puli messages::queryParameterOutOfRange( 140e5aaf047SAppaRao Puli asyncResp->res, std::to_string(*retryInterval), 141e5aaf047SAppaRao Puli "DeliveryRetryIntervalSeconds", "[30-180]"); 142e5aaf047SAppaRao Puli } 143e5aaf047SAppaRao Puli else 144e5aaf047SAppaRao Puli { 14528afb49cSJunLin Chen eventServiceConfig.retryTimeoutInterval = 14628afb49cSJunLin Chen *retryInterval; 147e5aaf047SAppaRao Puli } 148e5aaf047SAppaRao Puli } 149e5aaf047SAppaRao Puli 1507d1cc387SAppaRao Puli EventServiceManager::getInstance().setEventServiceConfig( 15128afb49cSJunLin Chen eventServiceConfig); 1527e860f15SJohn Edward Broadbent }); 1530b4bdd93SAppaRao Puli } 1540b4bdd93SAppaRao Puli 1557e860f15SJohn Edward Broadbent inline void requestRoutesSubmitTestEvent(App& app) 1560b4bdd93SAppaRao Puli { 1577e860f15SJohn Edward Broadbent 1587e860f15SJohn Edward Broadbent BMCWEB_ROUTE( 1597e860f15SJohn Edward Broadbent app, "/redfish/v1/EventService/Actions/EventService.SubmitTestEvent/") 160ed398213SEd Tanous .privileges(redfish::privileges::postEventService) 1617e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::post)( 1627e860f15SJohn Edward Broadbent [](const crow::Request&, 1637e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 1646ba8c82eSsunharis_in if (!EventServiceManager::getInstance().sendTestEventLog()) 1656ba8c82eSsunharis_in { 1666ba8c82eSsunharis_in messages::serviceDisabled(asyncResp->res, 1676ba8c82eSsunharis_in "/redfish/v1/EventService/"); 1686ba8c82eSsunharis_in return; 1696ba8c82eSsunharis_in } 1708d1b46d7Szhanghch05 asyncResp->res.result(boost::beast::http::status::no_content); 1717e860f15SJohn Edward Broadbent }); 172e5aaf047SAppaRao Puli } 173e5aaf047SAppaRao Puli 1747e860f15SJohn Edward Broadbent inline void requestRoutesEventDestinationCollection(App& app) 175e5aaf047SAppaRao Puli { 1761ebe3e41SGayathri Leburu BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/") 177ed398213SEd Tanous .privileges(redfish::privileges::getEventDestinationCollection) 1787e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 1797e860f15SJohn Edward Broadbent [](const crow::Request&, 1807e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 1818d1b46d7Szhanghch05 asyncResp->res.jsonValue = { 182e5aaf047SAppaRao Puli {"@odata.type", 183e5aaf047SAppaRao Puli "#EventDestinationCollection.EventDestinationCollection"}, 184e5aaf047SAppaRao Puli {"@odata.id", "/redfish/v1/EventService/Subscriptions"}, 185e5aaf047SAppaRao Puli {"Name", "Event Destination Collections"}}; 186e5aaf047SAppaRao Puli 1877e860f15SJohn Edward Broadbent nlohmann::json& memberArray = 1887e860f15SJohn Edward Broadbent asyncResp->res.jsonValue["Members"]; 189e5aaf047SAppaRao Puli 190b52664e2SAppaRao Puli std::vector<std::string> subscripIds = 191b52664e2SAppaRao Puli EventServiceManager::getInstance().getAllIDs(); 192b52664e2SAppaRao Puli memberArray = nlohmann::json::array(); 1937e860f15SJohn Edward Broadbent asyncResp->res.jsonValue["Members@odata.count"] = 1947e860f15SJohn Edward Broadbent subscripIds.size(); 195b52664e2SAppaRao Puli 196b52664e2SAppaRao Puli for (const std::string& id : subscripIds) 197e5aaf047SAppaRao Puli { 198e5aaf047SAppaRao Puli memberArray.push_back( 199e5aaf047SAppaRao Puli {{"@odata.id", 200b52664e2SAppaRao Puli "/redfish/v1/EventService/Subscriptions/" + id}}); 201e5aaf047SAppaRao Puli } 2027e860f15SJohn Edward Broadbent }); 2037e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/") 2047eeafa76SAbhishek Patel .privileges(redfish::privileges::postEventDestinationCollection) 205*fffb8c1fSEd Tanous .methods( 206*fffb8c1fSEd Tanous boost::beast::http::verb:: 207*fffb8c1fSEd Tanous post)([](const crow::Request& req, 2087e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 209*fffb8c1fSEd Tanous if (EventServiceManager::getInstance().getNumberOfSubscriptions() >= 210*fffb8c1fSEd Tanous maxNoOfSubscriptions) 211e5aaf047SAppaRao Puli { 212e5aaf047SAppaRao Puli messages::eventSubscriptionLimitExceeded(asyncResp->res); 213e5aaf047SAppaRao Puli return; 214e5aaf047SAppaRao Puli } 215e5aaf047SAppaRao Puli std::string destUrl; 216e5aaf047SAppaRao Puli std::string protocol; 217e5aaf047SAppaRao Puli std::optional<std::string> context; 218e5aaf047SAppaRao Puli std::optional<std::string> subscriptionType; 21923a21a1cSEd Tanous std::optional<std::string> eventFormatType2; 220e5aaf047SAppaRao Puli std::optional<std::string> retryPolicy; 221e5aaf047SAppaRao Puli std::optional<std::vector<std::string>> msgIds; 222e5aaf047SAppaRao Puli std::optional<std::vector<std::string>> regPrefixes; 223e56f254cSSunitha Harish std::optional<std::vector<std::string>> resTypes; 224e5aaf047SAppaRao Puli std::optional<std::vector<nlohmann::json>> headers; 225144b6318SAppaRao Puli std::optional<std::vector<nlohmann::json>> mrdJsonArray; 226e5aaf047SAppaRao Puli 22715ed6780SWilly Tu if (!json_util::readJsonPatch( 2287e860f15SJohn Edward Broadbent req, asyncResp->res, "Destination", destUrl, "Context", 2297e860f15SJohn Edward Broadbent context, "Protocol", protocol, "SubscriptionType", 2307e860f15SJohn Edward Broadbent subscriptionType, "EventFormatType", eventFormatType2, 2317e860f15SJohn Edward Broadbent "HttpHeaders", headers, "RegistryPrefixes", regPrefixes, 232*fffb8c1fSEd Tanous "MessageIds", msgIds, "DeliveryRetryPolicy", retryPolicy, 233*fffb8c1fSEd Tanous "MetricReportDefinitions", mrdJsonArray, "ResourceTypes", 234*fffb8c1fSEd Tanous resTypes)) 235e5aaf047SAppaRao Puli { 236e5aaf047SAppaRao Puli return; 237e5aaf047SAppaRao Puli } 238e5aaf047SAppaRao Puli 239dd28ba82SAppaRao Puli if (regPrefixes && msgIds) 240dd28ba82SAppaRao Puli { 24126f6976fSEd Tanous if (!regPrefixes->empty() && !msgIds->empty()) 242dd28ba82SAppaRao Puli { 2430a4304cfSEd Tanous messages::propertyValueConflict( 2440a4304cfSEd Tanous asyncResp->res, "MessageIds", "RegistryPrefixes"); 245dd28ba82SAppaRao Puli return; 246dd28ba82SAppaRao Puli } 247dd28ba82SAppaRao Puli } 248dd28ba82SAppaRao Puli 249e5aaf047SAppaRao Puli // Validate the URL using regex expression 250b52664e2SAppaRao Puli // Format: <protocol>://<host>:<port>/<uri> 251b52664e2SAppaRao Puli // protocol: http/https 252b52664e2SAppaRao Puli // host: Exclude ' ', ':', '#', '?' 2534e0453b1SGunnar Mills // port: Empty or numeric value with ':' separator. 254b52664e2SAppaRao Puli // uri: Start with '/' and Exclude '#', ' ' 255b52664e2SAppaRao Puli // Can include query params(ex: '/event?test=1') 256b52664e2SAppaRao Puli // TODO: Need to validate hostname extensively(as per rfc) 257b52664e2SAppaRao Puli const std::regex urlRegex( 258b52664e2SAppaRao Puli "(http|https)://([^/\\x20\\x3f\\x23\\x3a]+):?([0-9]*)(/" 259b52664e2SAppaRao Puli "([^\\x20\\x23\\x3f]*\\x3f?([^\\x20\\x23\\x3f])*)?)"); 260b52664e2SAppaRao Puli std::cmatch match; 261b52664e2SAppaRao Puli if (!std::regex_match(destUrl.c_str(), match, urlRegex)) 262e5aaf047SAppaRao Puli { 263e5aaf047SAppaRao Puli messages::propertyValueFormatError(asyncResp->res, destUrl, 264e5aaf047SAppaRao Puli "Destination"); 265e5aaf047SAppaRao Puli return; 266e5aaf047SAppaRao Puli } 267b52664e2SAppaRao Puli 268*fffb8c1fSEd Tanous std::string uriProto = std::string(match[1].first, match[1].second); 269b52664e2SAppaRao Puli if (uriProto == "http") 270b52664e2SAppaRao Puli { 271b52664e2SAppaRao Puli #ifndef BMCWEB_INSECURE_ENABLE_HTTP_PUSH_STYLE_EVENTING 272b52664e2SAppaRao Puli messages::propertyValueFormatError(asyncResp->res, destUrl, 273b52664e2SAppaRao Puli "Destination"); 274b52664e2SAppaRao Puli return; 275b52664e2SAppaRao Puli #endif 276b52664e2SAppaRao Puli } 277b52664e2SAppaRao Puli 278b52664e2SAppaRao Puli std::string host = std::string(match[2].first, match[2].second); 279b52664e2SAppaRao Puli std::string port = std::string(match[3].first, match[3].second); 280b52664e2SAppaRao Puli std::string path = std::string(match[4].first, match[4].second); 281b52664e2SAppaRao Puli if (port.empty()) 282b52664e2SAppaRao Puli { 283b52664e2SAppaRao Puli if (uriProto == "http") 284b52664e2SAppaRao Puli { 285b52664e2SAppaRao Puli port = "80"; 286b52664e2SAppaRao Puli } 287b52664e2SAppaRao Puli else 288b52664e2SAppaRao Puli { 289b52664e2SAppaRao Puli port = "443"; 290b52664e2SAppaRao Puli } 291b52664e2SAppaRao Puli } 292b52664e2SAppaRao Puli if (path.empty()) 293b52664e2SAppaRao Puli { 294b52664e2SAppaRao Puli path = "/"; 295b52664e2SAppaRao Puli } 296b52664e2SAppaRao Puli 297b52664e2SAppaRao Puli std::shared_ptr<Subscription> subValue = 298b52664e2SAppaRao Puli std::make_shared<Subscription>(host, port, path, uriProto); 299b52664e2SAppaRao Puli 300b52664e2SAppaRao Puli subValue->destinationUrl = destUrl; 301e5aaf047SAppaRao Puli 302e5aaf047SAppaRao Puli if (subscriptionType) 303e5aaf047SAppaRao Puli { 304e5aaf047SAppaRao Puli if (*subscriptionType != "RedfishEvent") 305e5aaf047SAppaRao Puli { 306*fffb8c1fSEd Tanous messages::propertyValueNotInList( 307*fffb8c1fSEd Tanous asyncResp->res, *subscriptionType, "SubscriptionType"); 308e5aaf047SAppaRao Puli return; 309e5aaf047SAppaRao Puli } 310b52664e2SAppaRao Puli subValue->subscriptionType = *subscriptionType; 311e5aaf047SAppaRao Puli } 312e5aaf047SAppaRao Puli else 313e5aaf047SAppaRao Puli { 314b52664e2SAppaRao Puli subValue->subscriptionType = "RedfishEvent"; // Default 315e5aaf047SAppaRao Puli } 316e5aaf047SAppaRao Puli 317e5aaf047SAppaRao Puli if (protocol != "Redfish") 318e5aaf047SAppaRao Puli { 319e5aaf047SAppaRao Puli messages::propertyValueNotInList(asyncResp->res, protocol, 320e5aaf047SAppaRao Puli "Protocol"); 321e5aaf047SAppaRao Puli return; 322e5aaf047SAppaRao Puli } 323b52664e2SAppaRao Puli subValue->protocol = protocol; 324e5aaf047SAppaRao Puli 32523a21a1cSEd Tanous if (eventFormatType2) 326e5aaf047SAppaRao Puli { 327e5aaf047SAppaRao Puli if (std::find(supportedEvtFormatTypes.begin(), 328e5aaf047SAppaRao Puli supportedEvtFormatTypes.end(), 3297e860f15SJohn Edward Broadbent *eventFormatType2) == 3307e860f15SJohn Edward Broadbent supportedEvtFormatTypes.end()) 331e5aaf047SAppaRao Puli { 332*fffb8c1fSEd Tanous messages::propertyValueNotInList( 333*fffb8c1fSEd Tanous asyncResp->res, *eventFormatType2, "EventFormatType"); 334e5aaf047SAppaRao Puli return; 335e5aaf047SAppaRao Puli } 33623a21a1cSEd Tanous subValue->eventFormatType = *eventFormatType2; 337e5aaf047SAppaRao Puli } 338e5aaf047SAppaRao Puli else 339e5aaf047SAppaRao Puli { 340e5aaf047SAppaRao Puli // If not specified, use default "Event" 34123a21a1cSEd Tanous subValue->eventFormatType = "Event"; 342e5aaf047SAppaRao Puli } 343e5aaf047SAppaRao Puli 344e5aaf047SAppaRao Puli if (context) 345e5aaf047SAppaRao Puli { 346b52664e2SAppaRao Puli subValue->customText = *context; 347e5aaf047SAppaRao Puli } 348e5aaf047SAppaRao Puli 349e5aaf047SAppaRao Puli if (headers) 350e5aaf047SAppaRao Puli { 351601c71aeSEd Tanous for (const nlohmann::json& headerChunk : *headers) 352601c71aeSEd Tanous { 353601c71aeSEd Tanous for (const auto& item : headerChunk.items()) 354601c71aeSEd Tanous { 355601c71aeSEd Tanous const std::string* value = 356601c71aeSEd Tanous item.value().get_ptr<const std::string*>(); 357601c71aeSEd Tanous if (value == nullptr) 358601c71aeSEd Tanous { 359601c71aeSEd Tanous messages::propertyValueFormatError( 360e662eae8SEd Tanous asyncResp->res, item.value().dump(2, 1), 361601c71aeSEd Tanous "HttpHeaders/" + item.key()); 362601c71aeSEd Tanous return; 363601c71aeSEd Tanous } 364601c71aeSEd Tanous subValue->httpHeaders.set(item.key(), *value); 365601c71aeSEd Tanous } 366601c71aeSEd Tanous } 367e5aaf047SAppaRao Puli } 368e5aaf047SAppaRao Puli 369e5aaf047SAppaRao Puli if (regPrefixes) 370e5aaf047SAppaRao Puli { 371e5aaf047SAppaRao Puli for (const std::string& it : *regPrefixes) 372e5aaf047SAppaRao Puli { 373e5aaf047SAppaRao Puli if (std::find(supportedRegPrefixes.begin(), 374e5aaf047SAppaRao Puli supportedRegPrefixes.end(), 375e5aaf047SAppaRao Puli it) == supportedRegPrefixes.end()) 376e5aaf047SAppaRao Puli { 377*fffb8c1fSEd Tanous messages::propertyValueNotInList(asyncResp->res, it, 378*fffb8c1fSEd Tanous "RegistryPrefixes"); 379e5aaf047SAppaRao Puli return; 380e5aaf047SAppaRao Puli } 381e5aaf047SAppaRao Puli } 382b52664e2SAppaRao Puli subValue->registryPrefixes = *regPrefixes; 383e5aaf047SAppaRao Puli } 384e5aaf047SAppaRao Puli 385e56f254cSSunitha Harish if (resTypes) 386e56f254cSSunitha Harish { 387e56f254cSSunitha Harish for (const std::string& it : *resTypes) 388e56f254cSSunitha Harish { 389e56f254cSSunitha Harish if (std::find(supportedResourceTypes.begin(), 390e56f254cSSunitha Harish supportedResourceTypes.end(), 391e56f254cSSunitha Harish it) == supportedResourceTypes.end()) 392e56f254cSSunitha Harish { 393e56f254cSSunitha Harish messages::propertyValueNotInList(asyncResp->res, it, 394e56f254cSSunitha Harish "ResourceTypes"); 395e56f254cSSunitha Harish return; 396e56f254cSSunitha Harish } 397e56f254cSSunitha Harish } 398e56f254cSSunitha Harish subValue->resourceTypes = *resTypes; 399e56f254cSSunitha Harish } 400e56f254cSSunitha Harish 401e5aaf047SAppaRao Puli if (msgIds) 402e5aaf047SAppaRao Puli { 403b304bd79SP Dheeraj Srujan Kumar std::vector<std::string> registryPrefix; 404b304bd79SP Dheeraj Srujan Kumar 4057e860f15SJohn Edward Broadbent // If no registry prefixes are mentioned, consider all 4067e860f15SJohn Edward Broadbent // supported prefixes 407b304bd79SP Dheeraj Srujan Kumar if (subValue->registryPrefixes.empty()) 408b304bd79SP Dheeraj Srujan Kumar { 409b304bd79SP Dheeraj Srujan Kumar registryPrefix.assign(supportedRegPrefixes.begin(), 410b304bd79SP Dheeraj Srujan Kumar supportedRegPrefixes.end()); 411b304bd79SP Dheeraj Srujan Kumar } 412b304bd79SP Dheeraj Srujan Kumar else 413b304bd79SP Dheeraj Srujan Kumar { 414b304bd79SP Dheeraj Srujan Kumar registryPrefix = subValue->registryPrefixes; 415b304bd79SP Dheeraj Srujan Kumar } 416b304bd79SP Dheeraj Srujan Kumar 417b304bd79SP Dheeraj Srujan Kumar for (const std::string& id : *msgIds) 418b304bd79SP Dheeraj Srujan Kumar { 419b304bd79SP Dheeraj Srujan Kumar bool validId = false; 420b304bd79SP Dheeraj Srujan Kumar 421b304bd79SP Dheeraj Srujan Kumar // Check for Message ID in each of the selected Registry 422b304bd79SP Dheeraj Srujan Kumar for (const std::string& it : registryPrefix) 423b304bd79SP Dheeraj Srujan Kumar { 424*fffb8c1fSEd Tanous const std::span<const redfish::registries::MessageEntry> 425*fffb8c1fSEd Tanous registry = 426*fffb8c1fSEd Tanous redfish::registries::getRegistryFromPrefix(it); 427b304bd79SP Dheeraj Srujan Kumar 428b304bd79SP Dheeraj Srujan Kumar if (std::any_of( 42926702d01SEd Tanous registry.begin(), registry.end(), 430*fffb8c1fSEd Tanous [&id](const redfish::registries::MessageEntry& 431*fffb8c1fSEd Tanous messageEntry) { 432*fffb8c1fSEd Tanous return id.compare(messageEntry.first) == 0; 433b304bd79SP Dheeraj Srujan Kumar })) 434b304bd79SP Dheeraj Srujan Kumar { 435b304bd79SP Dheeraj Srujan Kumar validId = true; 436b304bd79SP Dheeraj Srujan Kumar break; 437b304bd79SP Dheeraj Srujan Kumar } 438b304bd79SP Dheeraj Srujan Kumar } 439b304bd79SP Dheeraj Srujan Kumar 440b304bd79SP Dheeraj Srujan Kumar if (!validId) 441b304bd79SP Dheeraj Srujan Kumar { 442b304bd79SP Dheeraj Srujan Kumar messages::propertyValueNotInList(asyncResp->res, id, 443b304bd79SP Dheeraj Srujan Kumar "MessageIds"); 444b304bd79SP Dheeraj Srujan Kumar return; 445b304bd79SP Dheeraj Srujan Kumar } 446b304bd79SP Dheeraj Srujan Kumar } 447b304bd79SP Dheeraj Srujan Kumar 448b52664e2SAppaRao Puli subValue->registryMsgIds = *msgIds; 449e5aaf047SAppaRao Puli } 450e5aaf047SAppaRao Puli 451e5aaf047SAppaRao Puli if (retryPolicy) 452e5aaf047SAppaRao Puli { 453e5aaf047SAppaRao Puli if (std::find(supportedRetryPolicies.begin(), 454e5aaf047SAppaRao Puli supportedRetryPolicies.end(), 455e5aaf047SAppaRao Puli *retryPolicy) == supportedRetryPolicies.end()) 456e5aaf047SAppaRao Puli { 457*fffb8c1fSEd Tanous messages::propertyValueNotInList( 458*fffb8c1fSEd Tanous asyncResp->res, *retryPolicy, "DeliveryRetryPolicy"); 459e5aaf047SAppaRao Puli return; 460e5aaf047SAppaRao Puli } 461b52664e2SAppaRao Puli subValue->retryPolicy = *retryPolicy; 462e5aaf047SAppaRao Puli } 463e5aaf047SAppaRao Puli else 464e5aaf047SAppaRao Puli { 465e5aaf047SAppaRao Puli // Default "TerminateAfterRetries" 466b52664e2SAppaRao Puli subValue->retryPolicy = "TerminateAfterRetries"; 467e5aaf047SAppaRao Puli } 468e5aaf047SAppaRao Puli 469144b6318SAppaRao Puli if (mrdJsonArray) 470156d6b00SAppaRao Puli { 471144b6318SAppaRao Puli for (nlohmann::json& mrdObj : *mrdJsonArray) 472144b6318SAppaRao Puli { 473144b6318SAppaRao Puli std::string mrdUri; 474ea2e6eecSWilly Tu 475ea2e6eecSWilly Tu if (!json_util::readJson(mrdObj, asyncResp->res, 476ea2e6eecSWilly Tu "@odata.id", mrdUri)) 477ea2e6eecSWilly Tu 478144b6318SAppaRao Puli { 479144b6318SAppaRao Puli return; 480144b6318SAppaRao Puli } 481ea2e6eecSWilly Tu subValue->metricReportDefinitions.emplace_back(mrdUri); 482144b6318SAppaRao Puli } 483156d6b00SAppaRao Puli } 484156d6b00SAppaRao Puli 485b52664e2SAppaRao Puli std::string id = 486*fffb8c1fSEd Tanous EventServiceManager::getInstance().addSubscription(subValue); 487b52664e2SAppaRao Puli if (id.empty()) 488e5aaf047SAppaRao Puli { 489e5aaf047SAppaRao Puli messages::internalError(asyncResp->res); 490e5aaf047SAppaRao Puli return; 491e5aaf047SAppaRao Puli } 492e5aaf047SAppaRao Puli 493e5aaf047SAppaRao Puli messages::created(asyncResp->res); 494e5aaf047SAppaRao Puli asyncResp->res.addHeader( 495e5aaf047SAppaRao Puli "Location", "/redfish/v1/EventService/Subscriptions/" + id); 4967e860f15SJohn Edward Broadbent }); 497e5aaf047SAppaRao Puli } 498e5aaf047SAppaRao Puli 4997e860f15SJohn Edward Broadbent inline void requestRoutesEventDestination(App& app) 500e5aaf047SAppaRao Puli { 5019d41aec6SRavi Teja BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/<str>/") 502ed398213SEd Tanous .privileges(redfish::privileges::getEventDestination) 5037e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 5047e860f15SJohn Edward Broadbent [](const crow::Request&, 5057e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 5067e860f15SJohn Edward Broadbent const std::string& param) { 507b52664e2SAppaRao Puli std::shared_ptr<Subscription> subValue = 5087e860f15SJohn Edward Broadbent EventServiceManager::getInstance().getSubscription(param); 509b52664e2SAppaRao Puli if (subValue == nullptr) 510e5aaf047SAppaRao Puli { 5117e860f15SJohn Edward Broadbent asyncResp->res.result( 5127e860f15SJohn Edward Broadbent boost::beast::http::status::not_found); 513e5aaf047SAppaRao Puli return; 514e5aaf047SAppaRao Puli } 5157e860f15SJohn Edward Broadbent const std::string& id = param; 516e5aaf047SAppaRao Puli 5178d1b46d7Szhanghch05 asyncResp->res.jsonValue = { 5187e860f15SJohn Edward Broadbent {"@odata.type", 5197e860f15SJohn Edward Broadbent "#EventDestination.v1_7_0.EventDestination"}, 520e5aaf047SAppaRao Puli {"Protocol", "Redfish"}}; 521e5aaf047SAppaRao Puli asyncResp->res.jsonValue["@odata.id"] = 522e5aaf047SAppaRao Puli "/redfish/v1/EventService/Subscriptions/" + id; 523e5aaf047SAppaRao Puli asyncResp->res.jsonValue["Id"] = id; 524e5aaf047SAppaRao Puli asyncResp->res.jsonValue["Name"] = "Event Destination " + id; 5257e860f15SJohn Edward Broadbent asyncResp->res.jsonValue["Destination"] = 5267e860f15SJohn Edward Broadbent subValue->destinationUrl; 527b52664e2SAppaRao Puli asyncResp->res.jsonValue["Context"] = subValue->customText; 528e5aaf047SAppaRao Puli asyncResp->res.jsonValue["SubscriptionType"] = 529b52664e2SAppaRao Puli subValue->subscriptionType; 530ad22fefeSEd Tanous asyncResp->res.jsonValue["HttpHeaders"] = 531ad22fefeSEd Tanous nlohmann::json::array(); 5327e860f15SJohn Edward Broadbent asyncResp->res.jsonValue["EventFormatType"] = 5337e860f15SJohn Edward Broadbent subValue->eventFormatType; 534e5aaf047SAppaRao Puli asyncResp->res.jsonValue["RegistryPrefixes"] = 535b52664e2SAppaRao Puli subValue->registryPrefixes; 5367e860f15SJohn Edward Broadbent asyncResp->res.jsonValue["ResourceTypes"] = 5377e860f15SJohn Edward Broadbent subValue->resourceTypes; 538e56f254cSSunitha Harish 5397e860f15SJohn Edward Broadbent asyncResp->res.jsonValue["MessageIds"] = 5407e860f15SJohn Edward Broadbent subValue->registryMsgIds; 5417e860f15SJohn Edward Broadbent asyncResp->res.jsonValue["DeliveryRetryPolicy"] = 5427e860f15SJohn Edward Broadbent subValue->retryPolicy; 543144b6318SAppaRao Puli 544144b6318SAppaRao Puli std::vector<nlohmann::json> mrdJsonArray; 545144b6318SAppaRao Puli for (const auto& mdrUri : subValue->metricReportDefinitions) 546144b6318SAppaRao Puli { 547144b6318SAppaRao Puli mrdJsonArray.push_back({{"@odata.id", mdrUri}}); 548144b6318SAppaRao Puli } 5497e860f15SJohn Edward Broadbent asyncResp->res.jsonValue["MetricReportDefinitions"] = 5507e860f15SJohn Edward Broadbent mrdJsonArray; 5517e860f15SJohn Edward Broadbent }); 5529d41aec6SRavi Teja BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/<str>/") 553ed398213SEd Tanous // The below privilege is wrong, it should be ConfigureManager OR 554ed398213SEd Tanous // ConfigureSelf 5557eeafa76SAbhishek Patel // https://github.com/openbmc/bmcweb/issues/220 556ed398213SEd Tanous //.privileges(redfish::privileges::patchEventDestination) 557432a890cSEd Tanous .privileges({{"ConfigureManager"}}) 5587e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::patch)( 5597e860f15SJohn Edward Broadbent [](const crow::Request& req, 5607e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 5617e860f15SJohn Edward Broadbent const std::string& param) { 562b52664e2SAppaRao Puli std::shared_ptr<Subscription> subValue = 5637e860f15SJohn Edward Broadbent EventServiceManager::getInstance().getSubscription(param); 564b52664e2SAppaRao Puli if (subValue == nullptr) 565e5aaf047SAppaRao Puli { 5667e860f15SJohn Edward Broadbent asyncResp->res.result( 5677e860f15SJohn Edward Broadbent boost::beast::http::status::not_found); 568e5aaf047SAppaRao Puli return; 569e5aaf047SAppaRao Puli } 570e5aaf047SAppaRao Puli 571e5aaf047SAppaRao Puli std::optional<std::string> context; 572e5aaf047SAppaRao Puli std::optional<std::string> retryPolicy; 573e5aaf047SAppaRao Puli std::optional<std::vector<nlohmann::json>> headers; 574e5aaf047SAppaRao Puli 57515ed6780SWilly Tu if (!json_util::readJsonPatch(req, asyncResp->res, "Context", 5767e860f15SJohn Edward Broadbent context, "DeliveryRetryPolicy", 57715ed6780SWilly Tu retryPolicy, "HttpHeaders", 57815ed6780SWilly Tu headers)) 579e5aaf047SAppaRao Puli { 580e5aaf047SAppaRao Puli return; 581e5aaf047SAppaRao Puli } 582e5aaf047SAppaRao Puli 583e5aaf047SAppaRao Puli if (context) 584e5aaf047SAppaRao Puli { 585b52664e2SAppaRao Puli subValue->customText = *context; 586e5aaf047SAppaRao Puli } 587e5aaf047SAppaRao Puli 588e5aaf047SAppaRao Puli if (headers) 589e5aaf047SAppaRao Puli { 590601c71aeSEd Tanous boost::beast::http::fields fields; 591601c71aeSEd Tanous for (const nlohmann::json& headerChunk : *headers) 592601c71aeSEd Tanous { 593601c71aeSEd Tanous for (auto& it : headerChunk.items()) 594601c71aeSEd Tanous { 595601c71aeSEd Tanous const std::string* value = 596601c71aeSEd Tanous it.value().get_ptr<const std::string*>(); 597601c71aeSEd Tanous if (value == nullptr) 598601c71aeSEd Tanous { 599601c71aeSEd Tanous messages::propertyValueFormatError( 600601c71aeSEd Tanous asyncResp->res, 601601c71aeSEd Tanous it.value().dump(2, ' ', true), 602601c71aeSEd Tanous "HttpHeaders/" + it.key()); 603601c71aeSEd Tanous return; 604601c71aeSEd Tanous } 605601c71aeSEd Tanous fields.set(it.key(), *value); 606601c71aeSEd Tanous } 607601c71aeSEd Tanous } 608601c71aeSEd Tanous subValue->httpHeaders = fields; 609e5aaf047SAppaRao Puli } 610e5aaf047SAppaRao Puli 611e5aaf047SAppaRao Puli if (retryPolicy) 612e5aaf047SAppaRao Puli { 613e5aaf047SAppaRao Puli if (std::find(supportedRetryPolicies.begin(), 614e5aaf047SAppaRao Puli supportedRetryPolicies.end(), 615e5aaf047SAppaRao Puli *retryPolicy) == supportedRetryPolicies.end()) 616e5aaf047SAppaRao Puli { 6177e860f15SJohn Edward Broadbent messages::propertyValueNotInList(asyncResp->res, 6187e860f15SJohn Edward Broadbent *retryPolicy, 619e5aaf047SAppaRao Puli "DeliveryRetryPolicy"); 620e5aaf047SAppaRao Puli return; 621e5aaf047SAppaRao Puli } 622b52664e2SAppaRao Puli subValue->retryPolicy = *retryPolicy; 623fe44eb0bSAyushi Smriti subValue->updateRetryPolicy(); 624e5aaf047SAppaRao Puli } 625e5aaf047SAppaRao Puli 626b52664e2SAppaRao Puli EventServiceManager::getInstance().updateSubscriptionData(); 6277e860f15SJohn Edward Broadbent }); 6289d41aec6SRavi Teja BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/<str>/") 629ed398213SEd Tanous // The below privilege is wrong, it should be ConfigureManager OR 630ed398213SEd Tanous // ConfigureSelf 6317eeafa76SAbhishek Patel // https://github.com/openbmc/bmcweb/issues/220 632ed398213SEd Tanous //.privileges(redfish::privileges::deleteEventDestination) 633432a890cSEd Tanous .privileges({{"ConfigureManager"}}) 6347e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::delete_)( 6357e860f15SJohn Edward Broadbent [](const crow::Request&, 6367e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 6377e860f15SJohn Edward Broadbent const std::string& param) { 6387e860f15SJohn Edward Broadbent if (!EventServiceManager::getInstance().isSubscriptionExist( 6397e860f15SJohn Edward Broadbent param)) 640e5aaf047SAppaRao Puli { 6417e860f15SJohn Edward Broadbent asyncResp->res.result( 6427e860f15SJohn Edward Broadbent boost::beast::http::status::not_found); 643e5aaf047SAppaRao Puli return; 644e5aaf047SAppaRao Puli } 6457e860f15SJohn Edward Broadbent EventServiceManager::getInstance().deleteSubscription(param); 6467e860f15SJohn Edward Broadbent }); 647e5aaf047SAppaRao Puli } 648e5aaf047SAppaRao Puli 649e5aaf047SAppaRao Puli } // namespace redfish 650