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 19e5aaf047SAppaRao Puli namespace redfish 20e5aaf047SAppaRao Puli { 21e5aaf047SAppaRao Puli 22156d6b00SAppaRao Puli static constexpr const std::array<const char*, 2> supportedEvtFormatTypes = { 23156d6b00SAppaRao Puli eventFormatType, metricReportFormatType}; 24e5aaf047SAppaRao Puli static constexpr const std::array<const char*, 3> supportedRegPrefixes = { 25e5aaf047SAppaRao Puli "Base", "OpenBMC", "Task"}; 26e5aaf047SAppaRao Puli static constexpr const std::array<const char*, 3> supportedRetryPolicies = { 27e5aaf047SAppaRao Puli "TerminateAfterRetries", "SuspendRetries", "RetryForever"}; 28e5aaf047SAppaRao Puli 29e56f254cSSunitha Harish #ifdef BMCWEB_ENABLE_IBM_MANAGEMENT_CONSOLE 30e56f254cSSunitha Harish static constexpr const std::array<const char*, 2> supportedResourceTypes = { 31e56f254cSSunitha Harish "IBMConfigFile", "Task"}; 32e56f254cSSunitha Harish #else 33e56f254cSSunitha Harish static constexpr const std::array<const char*, 1> supportedResourceTypes = { 34e56f254cSSunitha Harish "Task"}; 35e56f254cSSunitha Harish #endif 36e56f254cSSunitha Harish 37e5aaf047SAppaRao Puli static constexpr const uint8_t maxNoOfSubscriptions = 20; 38e5aaf047SAppaRao Puli 39e5aaf047SAppaRao Puli class EventService : public Node 40e5aaf047SAppaRao Puli { 41e5aaf047SAppaRao Puli public: 42e5aaf047SAppaRao Puli EventService(CrowApp& app) : Node(app, "/redfish/v1/EventService/") 43e5aaf047SAppaRao Puli { 44e5aaf047SAppaRao Puli entityPrivileges = { 45e5aaf047SAppaRao Puli {boost::beast::http::verb::get, {{"Login"}}}, 46e5aaf047SAppaRao Puli {boost::beast::http::verb::head, {{"Login"}}}, 47e5aaf047SAppaRao Puli {boost::beast::http::verb::patch, {{"ConfigureManager"}}}, 48e5aaf047SAppaRao Puli {boost::beast::http::verb::put, {{"ConfigureManager"}}}, 49e5aaf047SAppaRao Puli {boost::beast::http::verb::delete_, {{"ConfigureManager"}}}, 50e5aaf047SAppaRao Puli {boost::beast::http::verb::post, {{"ConfigureManager"}}}}; 51e5aaf047SAppaRao Puli } 52e5aaf047SAppaRao Puli 53e5aaf047SAppaRao Puli private: 54e5aaf047SAppaRao Puli void doGet(crow::Response& res, const crow::Request& req, 55e5aaf047SAppaRao Puli const std::vector<std::string>& params) override 56e5aaf047SAppaRao Puli { 57e5aaf047SAppaRao Puli auto asyncResp = std::make_shared<AsyncResp>(res); 58e5aaf047SAppaRao Puli res.jsonValue = { 59e5aaf047SAppaRao Puli {"@odata.type", "#EventService.v1_5_0.EventService"}, 60e5aaf047SAppaRao Puli {"Id", "EventService"}, 61e5aaf047SAppaRao Puli {"Name", "Event Service"}, 62e5aaf047SAppaRao Puli {"ServerSentEventUri", 63e5aaf047SAppaRao Puli "/redfish/v1/EventService/Subscriptions/SSE"}, 64e5aaf047SAppaRao Puli {"Subscriptions", 65e5aaf047SAppaRao Puli {{"@odata.id", "/redfish/v1/EventService/Subscriptions"}}}, 660b4bdd93SAppaRao Puli {"Actions", 670b4bdd93SAppaRao Puli {{"#EventService.SubmitTestEvent", 680b4bdd93SAppaRao Puli {{"target", "/redfish/v1/EventService/Actions/" 690b4bdd93SAppaRao Puli "EventService.SubmitTestEvent"}}}}}, 70e5aaf047SAppaRao Puli {"@odata.id", "/redfish/v1/EventService"}}; 71e5aaf047SAppaRao Puli 727d1cc387SAppaRao Puli const auto& [enabled, retryAttempts, retryTimeoutInterval] = 737d1cc387SAppaRao Puli EventServiceManager::getInstance().getEventServiceConfig(); 747d1cc387SAppaRao Puli 757d1cc387SAppaRao Puli asyncResp->res.jsonValue["Status"]["State"] = 767d1cc387SAppaRao Puli (enabled ? "Enabled" : "Disabled"); 777d1cc387SAppaRao Puli asyncResp->res.jsonValue["ServiceEnabled"] = enabled; 787d1cc387SAppaRao Puli asyncResp->res.jsonValue["DeliveryRetryAttempts"] = retryAttempts; 79e5aaf047SAppaRao Puli asyncResp->res.jsonValue["DeliveryRetryIntervalSeconds"] = 807d1cc387SAppaRao Puli retryTimeoutInterval; 81e5aaf047SAppaRao Puli asyncResp->res.jsonValue["EventFormatTypes"] = supportedEvtFormatTypes; 82e5aaf047SAppaRao Puli asyncResp->res.jsonValue["RegistryPrefixes"] = supportedRegPrefixes; 83e56f254cSSunitha Harish asyncResp->res.jsonValue["ResourceTypes"] = supportedResourceTypes; 8407941a88SAyushi Smriti 8507941a88SAyushi Smriti nlohmann::json supportedSSEFilters = { 8607941a88SAyushi Smriti {"EventFormatType", true}, {"MessageId", true}, 8707941a88SAyushi Smriti {"MetricReportDefinition", true}, {"RegistryPrefix", true}, 8807941a88SAyushi Smriti {"OriginResource", false}, {"ResourceType", false}}; 8907941a88SAyushi Smriti 9007941a88SAyushi Smriti asyncResp->res.jsonValue["SSEFilterPropertiesSupported"] = 9107941a88SAyushi Smriti supportedSSEFilters; 92e5aaf047SAppaRao Puli } 93e5aaf047SAppaRao Puli 94e5aaf047SAppaRao Puli void doPatch(crow::Response& res, const crow::Request& req, 95e5aaf047SAppaRao Puli const std::vector<std::string>& params) override 96e5aaf047SAppaRao Puli { 97e5aaf047SAppaRao Puli auto asyncResp = std::make_shared<AsyncResp>(res); 98e5aaf047SAppaRao Puli 99e5aaf047SAppaRao Puli std::optional<bool> serviceEnabled; 100e5aaf047SAppaRao Puli std::optional<uint32_t> retryAttemps; 101e5aaf047SAppaRao Puli std::optional<uint32_t> retryInterval; 102e5aaf047SAppaRao Puli 103e5aaf047SAppaRao Puli if (!json_util::readJson(req, res, "ServiceEnabled", serviceEnabled, 104e5aaf047SAppaRao Puli "DeliveryRetryAttempts", retryAttemps, 105e5aaf047SAppaRao Puli "DeliveryRetryIntervalSeconds", retryInterval)) 106e5aaf047SAppaRao Puli { 107e5aaf047SAppaRao Puli return; 108e5aaf047SAppaRao Puli } 109e5aaf047SAppaRao Puli 1107d1cc387SAppaRao Puli auto [enabled, retryCount, retryTimeoutInterval] = 1117d1cc387SAppaRao Puli EventServiceManager::getInstance().getEventServiceConfig(); 1127d1cc387SAppaRao Puli 113e5aaf047SAppaRao Puli if (serviceEnabled) 114e5aaf047SAppaRao Puli { 1157d1cc387SAppaRao Puli enabled = *serviceEnabled; 116e5aaf047SAppaRao Puli } 117e5aaf047SAppaRao Puli 118e5aaf047SAppaRao Puli if (retryAttemps) 119e5aaf047SAppaRao Puli { 120e5aaf047SAppaRao Puli // Supported range [1-3] 121e5aaf047SAppaRao Puli if ((*retryAttemps < 1) || (*retryAttemps > 3)) 122e5aaf047SAppaRao Puli { 123e5aaf047SAppaRao Puli messages::queryParameterOutOfRange( 124e5aaf047SAppaRao Puli asyncResp->res, std::to_string(*retryAttemps), 125e5aaf047SAppaRao Puli "DeliveryRetryAttempts", "[1-3]"); 126e5aaf047SAppaRao Puli } 127e5aaf047SAppaRao Puli else 128e5aaf047SAppaRao Puli { 1297d1cc387SAppaRao Puli retryCount = *retryAttemps; 130e5aaf047SAppaRao Puli } 131e5aaf047SAppaRao Puli } 132e5aaf047SAppaRao Puli 133e5aaf047SAppaRao Puli if (retryInterval) 134e5aaf047SAppaRao Puli { 135e5aaf047SAppaRao Puli // Supported range [30 - 180] 136e5aaf047SAppaRao Puli if ((*retryInterval < 30) || (*retryInterval > 180)) 137e5aaf047SAppaRao Puli { 138e5aaf047SAppaRao Puli messages::queryParameterOutOfRange( 139e5aaf047SAppaRao Puli asyncResp->res, std::to_string(*retryInterval), 140e5aaf047SAppaRao Puli "DeliveryRetryIntervalSeconds", "[30-180]"); 141e5aaf047SAppaRao Puli } 142e5aaf047SAppaRao Puli else 143e5aaf047SAppaRao Puli { 1447d1cc387SAppaRao Puli retryTimeoutInterval = *retryInterval; 145e5aaf047SAppaRao Puli } 146e5aaf047SAppaRao Puli } 147e5aaf047SAppaRao Puli 1487d1cc387SAppaRao Puli EventServiceManager::getInstance().setEventServiceConfig( 1497d1cc387SAppaRao Puli std::make_tuple(enabled, retryCount, retryTimeoutInterval)); 150e5aaf047SAppaRao Puli } 151e5aaf047SAppaRao Puli }; 152e5aaf047SAppaRao Puli 1530b4bdd93SAppaRao Puli class SubmitTestEvent : public Node 1540b4bdd93SAppaRao Puli { 1550b4bdd93SAppaRao Puli public: 1560b4bdd93SAppaRao Puli SubmitTestEvent(CrowApp& app) : 1570b4bdd93SAppaRao Puli Node(app, 1580b4bdd93SAppaRao Puli "/redfish/v1/EventService/Actions/EventService.SubmitTestEvent/") 1590b4bdd93SAppaRao Puli { 1600b4bdd93SAppaRao Puli entityPrivileges = { 1610b4bdd93SAppaRao Puli {boost::beast::http::verb::get, {{"Login"}}}, 1620b4bdd93SAppaRao Puli {boost::beast::http::verb::head, {{"Login"}}}, 1630b4bdd93SAppaRao Puli {boost::beast::http::verb::patch, {{"ConfigureManager"}}}, 1640b4bdd93SAppaRao Puli {boost::beast::http::verb::put, {{"ConfigureManager"}}}, 1650b4bdd93SAppaRao Puli {boost::beast::http::verb::delete_, {{"ConfigureManager"}}}, 1660b4bdd93SAppaRao Puli {boost::beast::http::verb::post, {{"ConfigureManager"}}}}; 1670b4bdd93SAppaRao Puli } 1680b4bdd93SAppaRao Puli 1690b4bdd93SAppaRao Puli private: 1700b4bdd93SAppaRao Puli void doPost(crow::Response& res, const crow::Request& req, 1710b4bdd93SAppaRao Puli const std::vector<std::string>& params) override 1720b4bdd93SAppaRao Puli { 1730b4bdd93SAppaRao Puli EventServiceManager::getInstance().sendTestEventLog(); 1740b4bdd93SAppaRao Puli res.result(boost::beast::http::status::no_content); 1750b4bdd93SAppaRao Puli res.end(); 1760b4bdd93SAppaRao Puli } 1770b4bdd93SAppaRao Puli }; 1780b4bdd93SAppaRao Puli 179e5aaf047SAppaRao Puli class EventDestinationCollection : public Node 180e5aaf047SAppaRao Puli { 181e5aaf047SAppaRao Puli public: 182e5aaf047SAppaRao Puli EventDestinationCollection(CrowApp& app) : 183e5aaf047SAppaRao Puli Node(app, "/redfish/v1/EventService/Subscriptions/") 184e5aaf047SAppaRao Puli { 185e5aaf047SAppaRao Puli entityPrivileges = { 186e5aaf047SAppaRao Puli {boost::beast::http::verb::get, {{"Login"}}}, 187e5aaf047SAppaRao Puli {boost::beast::http::verb::head, {{"Login"}}}, 188e5aaf047SAppaRao Puli {boost::beast::http::verb::patch, {{"ConfigureManager"}}}, 189e5aaf047SAppaRao Puli {boost::beast::http::verb::put, {{"ConfigureManager"}}}, 190e5aaf047SAppaRao Puli {boost::beast::http::verb::delete_, {{"ConfigureManager"}}}, 191e5aaf047SAppaRao Puli {boost::beast::http::verb::post, {{"ConfigureManager"}}}}; 192e5aaf047SAppaRao Puli } 193e5aaf047SAppaRao Puli 194e5aaf047SAppaRao Puli private: 195e5aaf047SAppaRao Puli void doGet(crow::Response& res, const crow::Request& req, 196e5aaf047SAppaRao Puli const std::vector<std::string>& params) override 197e5aaf047SAppaRao Puli { 198e5aaf047SAppaRao Puli auto asyncResp = std::make_shared<AsyncResp>(res); 199e5aaf047SAppaRao Puli 200e5aaf047SAppaRao Puli res.jsonValue = { 201e5aaf047SAppaRao Puli {"@odata.type", 202e5aaf047SAppaRao Puli "#EventDestinationCollection.EventDestinationCollection"}, 203e5aaf047SAppaRao Puli {"@odata.id", "/redfish/v1/EventService/Subscriptions"}, 204e5aaf047SAppaRao Puli {"Name", "Event Destination Collections"}}; 205e5aaf047SAppaRao Puli 206e5aaf047SAppaRao Puli nlohmann::json& memberArray = asyncResp->res.jsonValue["Members"]; 207e5aaf047SAppaRao Puli 208b52664e2SAppaRao Puli std::vector<std::string> subscripIds = 209b52664e2SAppaRao Puli EventServiceManager::getInstance().getAllIDs(); 210b52664e2SAppaRao Puli memberArray = nlohmann::json::array(); 211b52664e2SAppaRao Puli asyncResp->res.jsonValue["Members@odata.count"] = subscripIds.size(); 212b52664e2SAppaRao Puli 213b52664e2SAppaRao Puli for (const std::string& id : subscripIds) 214e5aaf047SAppaRao Puli { 215e5aaf047SAppaRao Puli memberArray.push_back( 216e5aaf047SAppaRao Puli {{"@odata.id", 217b52664e2SAppaRao Puli "/redfish/v1/EventService/Subscriptions/" + id}}); 218e5aaf047SAppaRao Puli } 219e5aaf047SAppaRao Puli } 220e5aaf047SAppaRao Puli 221e5aaf047SAppaRao Puli void doPost(crow::Response& res, const crow::Request& req, 222e5aaf047SAppaRao Puli const std::vector<std::string>& params) override 223e5aaf047SAppaRao Puli { 224e5aaf047SAppaRao Puli auto asyncResp = std::make_shared<AsyncResp>(res); 225e5aaf047SAppaRao Puli 226b52664e2SAppaRao Puli if (EventServiceManager::getInstance().getNumberOfSubscriptions() >= 227b52664e2SAppaRao Puli maxNoOfSubscriptions) 228e5aaf047SAppaRao Puli { 229e5aaf047SAppaRao Puli messages::eventSubscriptionLimitExceeded(asyncResp->res); 230e5aaf047SAppaRao Puli return; 231e5aaf047SAppaRao Puli } 232e5aaf047SAppaRao Puli std::string destUrl; 233e5aaf047SAppaRao Puli std::string protocol; 234e5aaf047SAppaRao Puli std::optional<std::string> context; 235e5aaf047SAppaRao Puli std::optional<std::string> subscriptionType; 236e5aaf047SAppaRao Puli std::optional<std::string> eventFormatType; 237e5aaf047SAppaRao Puli std::optional<std::string> retryPolicy; 238e5aaf047SAppaRao Puli std::optional<std::vector<std::string>> msgIds; 239e5aaf047SAppaRao Puli std::optional<std::vector<std::string>> regPrefixes; 240e56f254cSSunitha Harish std::optional<std::vector<std::string>> resTypes; 241e5aaf047SAppaRao Puli std::optional<std::vector<nlohmann::json>> headers; 242156d6b00SAppaRao Puli std::optional<std::vector<nlohmann::json>> metricReportDefinitions; 243e5aaf047SAppaRao Puli 244e5aaf047SAppaRao Puli if (!json_util::readJson( 245e5aaf047SAppaRao Puli req, res, "Destination", destUrl, "Context", context, 246e5aaf047SAppaRao Puli "Protocol", protocol, "SubscriptionType", subscriptionType, 247e5aaf047SAppaRao Puli "EventFormatType", eventFormatType, "HttpHeaders", headers, 248e5aaf047SAppaRao Puli "RegistryPrefixes", regPrefixes, "MessageIds", msgIds, 249156d6b00SAppaRao Puli "DeliveryRetryPolicy", retryPolicy, "MetricReportDefinitions", 250e56f254cSSunitha Harish metricReportDefinitions, "ResourceTypes", resTypes)) 251e5aaf047SAppaRao Puli { 252e5aaf047SAppaRao Puli return; 253e5aaf047SAppaRao Puli } 254e5aaf047SAppaRao Puli 255e5aaf047SAppaRao Puli // Validate the URL using regex expression 256b52664e2SAppaRao Puli // Format: <protocol>://<host>:<port>/<uri> 257b52664e2SAppaRao Puli // protocol: http/https 258b52664e2SAppaRao Puli // host: Exclude ' ', ':', '#', '?' 2594e0453b1SGunnar Mills // port: Empty or numeric value with ':' separator. 260b52664e2SAppaRao Puli // uri: Start with '/' and Exclude '#', ' ' 261b52664e2SAppaRao Puli // Can include query params(ex: '/event?test=1') 262b52664e2SAppaRao Puli // TODO: Need to validate hostname extensively(as per rfc) 263b52664e2SAppaRao Puli const std::regex urlRegex( 264b52664e2SAppaRao Puli "(http|https)://([^/\\x20\\x3f\\x23\\x3a]+):?([0-9]*)(/" 265b52664e2SAppaRao Puli "([^\\x20\\x23\\x3f]*\\x3f?([^\\x20\\x23\\x3f])*)?)"); 266b52664e2SAppaRao Puli std::cmatch match; 267b52664e2SAppaRao Puli if (!std::regex_match(destUrl.c_str(), match, urlRegex)) 268e5aaf047SAppaRao Puli { 269e5aaf047SAppaRao Puli messages::propertyValueFormatError(asyncResp->res, destUrl, 270e5aaf047SAppaRao Puli "Destination"); 271e5aaf047SAppaRao Puli return; 272e5aaf047SAppaRao Puli } 273b52664e2SAppaRao Puli 274b52664e2SAppaRao Puli std::string uriProto = std::string(match[1].first, match[1].second); 275b52664e2SAppaRao Puli if (uriProto == "http") 276b52664e2SAppaRao Puli { 277b52664e2SAppaRao Puli #ifndef BMCWEB_INSECURE_ENABLE_HTTP_PUSH_STYLE_EVENTING 278b52664e2SAppaRao Puli messages::propertyValueFormatError(asyncResp->res, destUrl, 279b52664e2SAppaRao Puli "Destination"); 280b52664e2SAppaRao Puli return; 281b52664e2SAppaRao Puli #endif 282b52664e2SAppaRao Puli } 283b52664e2SAppaRao Puli 284b52664e2SAppaRao Puli std::string host = std::string(match[2].first, match[2].second); 285b52664e2SAppaRao Puli std::string port = std::string(match[3].first, match[3].second); 286b52664e2SAppaRao Puli std::string path = std::string(match[4].first, match[4].second); 287b52664e2SAppaRao Puli if (port.empty()) 288b52664e2SAppaRao Puli { 289b52664e2SAppaRao Puli if (uriProto == "http") 290b52664e2SAppaRao Puli { 291b52664e2SAppaRao Puli port = "80"; 292b52664e2SAppaRao Puli } 293b52664e2SAppaRao Puli else 294b52664e2SAppaRao Puli { 295b52664e2SAppaRao Puli port = "443"; 296b52664e2SAppaRao Puli } 297b52664e2SAppaRao Puli } 298b52664e2SAppaRao Puli if (path.empty()) 299b52664e2SAppaRao Puli { 300b52664e2SAppaRao Puli path = "/"; 301b52664e2SAppaRao Puli } 302b52664e2SAppaRao Puli 303b52664e2SAppaRao Puli std::shared_ptr<Subscription> subValue = 304b52664e2SAppaRao Puli std::make_shared<Subscription>(host, port, path, uriProto); 305b52664e2SAppaRao Puli 306b52664e2SAppaRao Puli subValue->destinationUrl = destUrl; 307e5aaf047SAppaRao Puli 308e5aaf047SAppaRao Puli if (subscriptionType) 309e5aaf047SAppaRao Puli { 310e5aaf047SAppaRao Puli if (*subscriptionType != "RedfishEvent") 311e5aaf047SAppaRao Puli { 312e5aaf047SAppaRao Puli messages::propertyValueNotInList( 313e5aaf047SAppaRao Puli asyncResp->res, *subscriptionType, "SubscriptionType"); 314e5aaf047SAppaRao Puli return; 315e5aaf047SAppaRao Puli } 316b52664e2SAppaRao Puli subValue->subscriptionType = *subscriptionType; 317e5aaf047SAppaRao Puli } 318e5aaf047SAppaRao Puli else 319e5aaf047SAppaRao Puli { 320b52664e2SAppaRao Puli subValue->subscriptionType = "RedfishEvent"; // Default 321e5aaf047SAppaRao Puli } 322e5aaf047SAppaRao Puli 323e5aaf047SAppaRao Puli if (protocol != "Redfish") 324e5aaf047SAppaRao Puli { 325e5aaf047SAppaRao Puli messages::propertyValueNotInList(asyncResp->res, protocol, 326e5aaf047SAppaRao Puli "Protocol"); 327e5aaf047SAppaRao Puli return; 328e5aaf047SAppaRao Puli } 329b52664e2SAppaRao Puli subValue->protocol = protocol; 330e5aaf047SAppaRao Puli 331e5aaf047SAppaRao Puli if (eventFormatType) 332e5aaf047SAppaRao Puli { 333e5aaf047SAppaRao Puli if (std::find(supportedEvtFormatTypes.begin(), 334e5aaf047SAppaRao Puli supportedEvtFormatTypes.end(), 335e5aaf047SAppaRao Puli *eventFormatType) == supportedEvtFormatTypes.end()) 336e5aaf047SAppaRao Puli { 337e5aaf047SAppaRao Puli messages::propertyValueNotInList( 338e5aaf047SAppaRao Puli asyncResp->res, *eventFormatType, "EventFormatType"); 339e5aaf047SAppaRao Puli return; 340e5aaf047SAppaRao Puli } 341b52664e2SAppaRao Puli subValue->eventFormatType = *eventFormatType; 342e5aaf047SAppaRao Puli } 343e5aaf047SAppaRao Puli else 344e5aaf047SAppaRao Puli { 345e5aaf047SAppaRao Puli // If not specified, use default "Event" 346b52664e2SAppaRao Puli subValue->eventFormatType.assign({"Event"}); 347e5aaf047SAppaRao Puli } 348e5aaf047SAppaRao Puli 349e5aaf047SAppaRao Puli if (context) 350e5aaf047SAppaRao Puli { 351b52664e2SAppaRao Puli subValue->customText = *context; 352e5aaf047SAppaRao Puli } 353e5aaf047SAppaRao Puli 354e5aaf047SAppaRao Puli if (headers) 355e5aaf047SAppaRao Puli { 356b52664e2SAppaRao Puli subValue->httpHeaders = *headers; 357e5aaf047SAppaRao Puli } 358e5aaf047SAppaRao Puli 359e5aaf047SAppaRao Puli if (regPrefixes) 360e5aaf047SAppaRao Puli { 361e5aaf047SAppaRao Puli for (const std::string& it : *regPrefixes) 362e5aaf047SAppaRao Puli { 363e5aaf047SAppaRao Puli if (std::find(supportedRegPrefixes.begin(), 364e5aaf047SAppaRao Puli supportedRegPrefixes.end(), 365e5aaf047SAppaRao Puli it) == supportedRegPrefixes.end()) 366e5aaf047SAppaRao Puli { 367e5aaf047SAppaRao Puli messages::propertyValueNotInList(asyncResp->res, it, 368e5aaf047SAppaRao Puli "RegistryPrefixes"); 369e5aaf047SAppaRao Puli return; 370e5aaf047SAppaRao Puli } 371e5aaf047SAppaRao Puli } 372b52664e2SAppaRao Puli subValue->registryPrefixes = *regPrefixes; 373e5aaf047SAppaRao Puli } 374e5aaf047SAppaRao Puli 375e56f254cSSunitha Harish if (resTypes) 376e56f254cSSunitha Harish { 377e56f254cSSunitha Harish for (const std::string& it : *resTypes) 378e56f254cSSunitha Harish { 379e56f254cSSunitha Harish if (std::find(supportedResourceTypes.begin(), 380e56f254cSSunitha Harish supportedResourceTypes.end(), 381e56f254cSSunitha Harish it) == supportedResourceTypes.end()) 382e56f254cSSunitha Harish { 383e56f254cSSunitha Harish messages::propertyValueNotInList(asyncResp->res, it, 384e56f254cSSunitha Harish "ResourceTypes"); 385e56f254cSSunitha Harish return; 386e56f254cSSunitha Harish } 387e56f254cSSunitha Harish } 388e56f254cSSunitha Harish subValue->resourceTypes = *resTypes; 389e56f254cSSunitha Harish } 390e56f254cSSunitha Harish 391e5aaf047SAppaRao Puli if (msgIds) 392e5aaf047SAppaRao Puli { 393e5aaf047SAppaRao Puli // Do we need to loop-up MessageRegistry and validate 394e5aaf047SAppaRao Puli // data for authenticity??? Not mandate, i believe. 395b52664e2SAppaRao Puli subValue->registryMsgIds = *msgIds; 396e5aaf047SAppaRao Puli } 397e5aaf047SAppaRao Puli 398e5aaf047SAppaRao Puli if (retryPolicy) 399e5aaf047SAppaRao Puli { 400e5aaf047SAppaRao Puli if (std::find(supportedRetryPolicies.begin(), 401e5aaf047SAppaRao Puli supportedRetryPolicies.end(), 402e5aaf047SAppaRao Puli *retryPolicy) == supportedRetryPolicies.end()) 403e5aaf047SAppaRao Puli { 404e5aaf047SAppaRao Puli messages::propertyValueNotInList(asyncResp->res, *retryPolicy, 405e5aaf047SAppaRao Puli "DeliveryRetryPolicy"); 406e5aaf047SAppaRao Puli return; 407e5aaf047SAppaRao Puli } 408b52664e2SAppaRao Puli subValue->retryPolicy = *retryPolicy; 409e5aaf047SAppaRao Puli } 410e5aaf047SAppaRao Puli else 411e5aaf047SAppaRao Puli { 412e5aaf047SAppaRao Puli // Default "TerminateAfterRetries" 413b52664e2SAppaRao Puli subValue->retryPolicy = "TerminateAfterRetries"; 414e5aaf047SAppaRao Puli } 415e5aaf047SAppaRao Puli 416156d6b00SAppaRao Puli if (metricReportDefinitions) 417156d6b00SAppaRao Puli { 418156d6b00SAppaRao Puli subValue->metricReportDefinitions = *metricReportDefinitions; 419156d6b00SAppaRao Puli } 420156d6b00SAppaRao Puli 421b52664e2SAppaRao Puli std::string id = 422b52664e2SAppaRao Puli EventServiceManager::getInstance().addSubscription(subValue); 423b52664e2SAppaRao Puli if (id.empty()) 424e5aaf047SAppaRao Puli { 425e5aaf047SAppaRao Puli messages::internalError(asyncResp->res); 426e5aaf047SAppaRao Puli return; 427e5aaf047SAppaRao Puli } 428e5aaf047SAppaRao Puli 429e5aaf047SAppaRao Puli messages::created(asyncResp->res); 430e5aaf047SAppaRao Puli asyncResp->res.addHeader( 431e5aaf047SAppaRao Puli "Location", "/redfish/v1/EventService/Subscriptions/" + id); 432e5aaf047SAppaRao Puli } 433e5aaf047SAppaRao Puli }; 434e5aaf047SAppaRao Puli 4354bbf237fSAppaRao Puli class EventServiceSSE : public Node 4364bbf237fSAppaRao Puli { 4374bbf237fSAppaRao Puli public: 4384bbf237fSAppaRao Puli EventServiceSSE(CrowApp& app) : 4394bbf237fSAppaRao Puli Node(app, "/redfish/v1/EventService/Subscriptions/SSE/") 4404bbf237fSAppaRao Puli { 4414bbf237fSAppaRao Puli entityPrivileges = { 4424bbf237fSAppaRao Puli {boost::beast::http::verb::get, {{"ConfigureManager"}}}, 4434bbf237fSAppaRao Puli {boost::beast::http::verb::head, {{"ConfigureManager"}}}, 4444bbf237fSAppaRao Puli {boost::beast::http::verb::patch, {{"ConfigureManager"}}}, 4454bbf237fSAppaRao Puli {boost::beast::http::verb::put, {{"ConfigureManager"}}}, 4464bbf237fSAppaRao Puli {boost::beast::http::verb::delete_, {{"ConfigureManager"}}}, 4474bbf237fSAppaRao Puli {boost::beast::http::verb::post, {{"ConfigureManager"}}}}; 4484bbf237fSAppaRao Puli } 4494bbf237fSAppaRao Puli 4504bbf237fSAppaRao Puli private: 4514bbf237fSAppaRao Puli void doGet(crow::Response& res, const crow::Request& req, 4524bbf237fSAppaRao Puli const std::vector<std::string>& params) override 4534bbf237fSAppaRao Puli { 4544bbf237fSAppaRao Puli if (EventServiceManager::getInstance().getNumberOfSubscriptions() >= 4554bbf237fSAppaRao Puli maxNoOfSubscriptions) 4564bbf237fSAppaRao Puli { 4574bbf237fSAppaRao Puli messages::eventSubscriptionLimitExceeded(res); 4584bbf237fSAppaRao Puli res.end(); 4594bbf237fSAppaRao Puli return; 4604bbf237fSAppaRao Puli } 4614bbf237fSAppaRao Puli 4624bbf237fSAppaRao Puli std::shared_ptr<crow::Request::Adaptor> sseConn = 4634bbf237fSAppaRao Puli std::make_shared<crow::Request::Adaptor>(std::move(req.socket())); 4644bbf237fSAppaRao Puli std::shared_ptr<Subscription> subValue = 4654bbf237fSAppaRao Puli std::make_shared<Subscription>(sseConn); 4664bbf237fSAppaRao Puli 4674bbf237fSAppaRao Puli // GET on this URI means, Its SSE subscriptionType. 4684bbf237fSAppaRao Puli subValue->subscriptionType = "SSE"; 46907941a88SAyushi Smriti 47007941a88SAyushi Smriti // Default values 4714bbf237fSAppaRao Puli subValue->protocol = "Redfish"; 47207941a88SAyushi Smriti subValue->retryPolicy = "TerminateAfterRetries"; 4734bbf237fSAppaRao Puli 474*5a7e877eSJames Feist boost::urls::url_view::params_type::iterator it = 475*5a7e877eSJames Feist req.urlParams.find("$filter"); 476*5a7e877eSJames Feist if (it == req.urlParams.end()) 4774bbf237fSAppaRao Puli { 4784bbf237fSAppaRao Puli subValue->eventFormatType = "Event"; 4794bbf237fSAppaRao Puli } 480*5a7e877eSJames Feist 4814bbf237fSAppaRao Puli else 4824bbf237fSAppaRao Puli { 483*5a7e877eSJames Feist std::string filters = it->value(); 48407941a88SAyushi Smriti // Reading from query params. 48507941a88SAyushi Smriti bool status = readSSEQueryParams( 48607941a88SAyushi Smriti filters, subValue->eventFormatType, subValue->registryMsgIds, 48707941a88SAyushi Smriti subValue->registryPrefixes, subValue->metricReportDefinitions); 48807941a88SAyushi Smriti 48907941a88SAyushi Smriti if (!status) 49007941a88SAyushi Smriti { 49107941a88SAyushi Smriti messages::invalidObject(res, filters); 49207941a88SAyushi Smriti return; 49307941a88SAyushi Smriti } 49407941a88SAyushi Smriti 49507941a88SAyushi Smriti if (!subValue->eventFormatType.empty()) 49607941a88SAyushi Smriti { 49707941a88SAyushi Smriti if (std::find(supportedEvtFormatTypes.begin(), 49807941a88SAyushi Smriti supportedEvtFormatTypes.end(), 49907941a88SAyushi Smriti subValue->eventFormatType) == 50007941a88SAyushi Smriti supportedEvtFormatTypes.end()) 50107941a88SAyushi Smriti { 50207941a88SAyushi Smriti messages::propertyValueNotInList( 50307941a88SAyushi Smriti res, subValue->eventFormatType, "EventFormatType"); 50407941a88SAyushi Smriti return; 50507941a88SAyushi Smriti } 50607941a88SAyushi Smriti } 50707941a88SAyushi Smriti else 50807941a88SAyushi Smriti { 50907941a88SAyushi Smriti // If nothing specified, using default "Event" 51007941a88SAyushi Smriti subValue->eventFormatType.assign({"Event"}); 51107941a88SAyushi Smriti } 51207941a88SAyushi Smriti 51307941a88SAyushi Smriti if (!subValue->registryPrefixes.empty()) 51407941a88SAyushi Smriti { 51507941a88SAyushi Smriti for (const std::string& it : subValue->registryPrefixes) 51607941a88SAyushi Smriti { 51707941a88SAyushi Smriti if (std::find(supportedRegPrefixes.begin(), 51807941a88SAyushi Smriti supportedRegPrefixes.end(), 51907941a88SAyushi Smriti it) == supportedRegPrefixes.end()) 52007941a88SAyushi Smriti { 52107941a88SAyushi Smriti messages::propertyValueNotInList(res, it, 52207941a88SAyushi Smriti "RegistryPrefixes"); 52307941a88SAyushi Smriti return; 52407941a88SAyushi Smriti } 52507941a88SAyushi Smriti } 52607941a88SAyushi Smriti } 5274bbf237fSAppaRao Puli } 5284bbf237fSAppaRao Puli 5294bbf237fSAppaRao Puli std::string id = 5304bbf237fSAppaRao Puli EventServiceManager::getInstance().addSubscription(subValue, false); 5314bbf237fSAppaRao Puli if (id.empty()) 5324bbf237fSAppaRao Puli { 5334bbf237fSAppaRao Puli messages::internalError(res); 5344bbf237fSAppaRao Puli res.end(); 5354bbf237fSAppaRao Puli return; 5364bbf237fSAppaRao Puli } 5374bbf237fSAppaRao Puli } 5384bbf237fSAppaRao Puli }; 5394bbf237fSAppaRao Puli 540e5aaf047SAppaRao Puli class EventDestination : public Node 541e5aaf047SAppaRao Puli { 542e5aaf047SAppaRao Puli public: 543e5aaf047SAppaRao Puli EventDestination(CrowApp& app) : 544e5aaf047SAppaRao Puli Node(app, "/redfish/v1/EventService/Subscriptions/<str>/", 545e5aaf047SAppaRao Puli std::string()) 546e5aaf047SAppaRao Puli { 547e5aaf047SAppaRao Puli entityPrivileges = { 548e5aaf047SAppaRao Puli {boost::beast::http::verb::get, {{"Login"}}}, 549e5aaf047SAppaRao Puli {boost::beast::http::verb::head, {{"Login"}}}, 550e5aaf047SAppaRao Puli {boost::beast::http::verb::patch, {{"ConfigureManager"}}}, 551e5aaf047SAppaRao Puli {boost::beast::http::verb::put, {{"ConfigureManager"}}}, 552e5aaf047SAppaRao Puli {boost::beast::http::verb::delete_, {{"ConfigureManager"}}}, 553e5aaf047SAppaRao Puli {boost::beast::http::verb::post, {{"ConfigureManager"}}}}; 554e5aaf047SAppaRao Puli } 555e5aaf047SAppaRao Puli 556e5aaf047SAppaRao Puli private: 557e5aaf047SAppaRao Puli void doGet(crow::Response& res, const crow::Request& req, 558e5aaf047SAppaRao Puli const std::vector<std::string>& params) override 559e5aaf047SAppaRao Puli { 560e5aaf047SAppaRao Puli auto asyncResp = std::make_shared<AsyncResp>(res); 561e5aaf047SAppaRao Puli if (params.size() != 1) 562e5aaf047SAppaRao Puli { 563e5aaf047SAppaRao Puli messages::internalError(asyncResp->res); 564e5aaf047SAppaRao Puli return; 565e5aaf047SAppaRao Puli } 566e5aaf047SAppaRao Puli 567b52664e2SAppaRao Puli std::shared_ptr<Subscription> subValue = 568b52664e2SAppaRao Puli EventServiceManager::getInstance().getSubscription(params[0]); 569b52664e2SAppaRao Puli if (subValue == nullptr) 570e5aaf047SAppaRao Puli { 571e5aaf047SAppaRao Puli res.result(boost::beast::http::status::not_found); 572e5aaf047SAppaRao Puli res.end(); 573e5aaf047SAppaRao Puli return; 574e5aaf047SAppaRao Puli } 575b52664e2SAppaRao Puli const std::string& id = params[0]; 576e5aaf047SAppaRao Puli 577e5aaf047SAppaRao Puli res.jsonValue = { 578e5aaf047SAppaRao Puli {"@odata.type", "#EventDestination.v1_7_0.EventDestination"}, 579e5aaf047SAppaRao Puli {"Protocol", "Redfish"}}; 580e5aaf047SAppaRao Puli asyncResp->res.jsonValue["@odata.id"] = 581e5aaf047SAppaRao Puli "/redfish/v1/EventService/Subscriptions/" + id; 582e5aaf047SAppaRao Puli asyncResp->res.jsonValue["Id"] = id; 583e5aaf047SAppaRao Puli asyncResp->res.jsonValue["Name"] = "Event Destination " + id; 584b52664e2SAppaRao Puli asyncResp->res.jsonValue["Destination"] = subValue->destinationUrl; 585b52664e2SAppaRao Puli asyncResp->res.jsonValue["Context"] = subValue->customText; 586e5aaf047SAppaRao Puli asyncResp->res.jsonValue["SubscriptionType"] = 587b52664e2SAppaRao Puli subValue->subscriptionType; 588b52664e2SAppaRao Puli asyncResp->res.jsonValue["HttpHeaders"] = subValue->httpHeaders; 589b52664e2SAppaRao Puli asyncResp->res.jsonValue["EventFormatType"] = subValue->eventFormatType; 590e5aaf047SAppaRao Puli asyncResp->res.jsonValue["RegistryPrefixes"] = 591b52664e2SAppaRao Puli subValue->registryPrefixes; 592e56f254cSSunitha Harish asyncResp->res.jsonValue["ResourceTypes"] = subValue->resourceTypes; 593e56f254cSSunitha Harish 594b52664e2SAppaRao Puli asyncResp->res.jsonValue["MessageIds"] = subValue->registryMsgIds; 595b52664e2SAppaRao Puli asyncResp->res.jsonValue["DeliveryRetryPolicy"] = subValue->retryPolicy; 596156d6b00SAppaRao Puli asyncResp->res.jsonValue["MetricReportDefinitions"] = 597156d6b00SAppaRao Puli subValue->metricReportDefinitions; 598e5aaf047SAppaRao Puli } 599e5aaf047SAppaRao Puli 600e5aaf047SAppaRao Puli void doPatch(crow::Response& res, const crow::Request& req, 601e5aaf047SAppaRao Puli const std::vector<std::string>& params) override 602e5aaf047SAppaRao Puli { 603e5aaf047SAppaRao Puli auto asyncResp = std::make_shared<AsyncResp>(res); 604e5aaf047SAppaRao Puli if (params.size() != 1) 605e5aaf047SAppaRao Puli { 606e5aaf047SAppaRao Puli messages::internalError(asyncResp->res); 607e5aaf047SAppaRao Puli return; 608e5aaf047SAppaRao Puli } 609e5aaf047SAppaRao Puli 610b52664e2SAppaRao Puli std::shared_ptr<Subscription> subValue = 611b52664e2SAppaRao Puli EventServiceManager::getInstance().getSubscription(params[0]); 612b52664e2SAppaRao Puli if (subValue == nullptr) 613e5aaf047SAppaRao Puli { 614e5aaf047SAppaRao Puli res.result(boost::beast::http::status::not_found); 615e5aaf047SAppaRao Puli res.end(); 616e5aaf047SAppaRao Puli return; 617e5aaf047SAppaRao Puli } 618e5aaf047SAppaRao Puli 619e5aaf047SAppaRao Puli std::optional<std::string> context; 620e5aaf047SAppaRao Puli std::optional<std::string> retryPolicy; 621e5aaf047SAppaRao Puli std::optional<std::vector<nlohmann::json>> headers; 622e5aaf047SAppaRao Puli 623e5aaf047SAppaRao Puli if (!json_util::readJson(req, res, "Context", context, 624e5aaf047SAppaRao Puli "DeliveryRetryPolicy", retryPolicy, 625e5aaf047SAppaRao Puli "HttpHeaders", headers)) 626e5aaf047SAppaRao Puli { 627e5aaf047SAppaRao Puli return; 628e5aaf047SAppaRao Puli } 629e5aaf047SAppaRao Puli 630e5aaf047SAppaRao Puli if (context) 631e5aaf047SAppaRao Puli { 632b52664e2SAppaRao Puli subValue->customText = *context; 633e5aaf047SAppaRao Puli } 634e5aaf047SAppaRao Puli 635e5aaf047SAppaRao Puli if (headers) 636e5aaf047SAppaRao Puli { 637b52664e2SAppaRao Puli subValue->httpHeaders = *headers; 638e5aaf047SAppaRao Puli } 639e5aaf047SAppaRao Puli 640e5aaf047SAppaRao Puli if (retryPolicy) 641e5aaf047SAppaRao Puli { 642e5aaf047SAppaRao Puli if (std::find(supportedRetryPolicies.begin(), 643e5aaf047SAppaRao Puli supportedRetryPolicies.end(), 644e5aaf047SAppaRao Puli *retryPolicy) == supportedRetryPolicies.end()) 645e5aaf047SAppaRao Puli { 646e5aaf047SAppaRao Puli messages::propertyValueNotInList(asyncResp->res, *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(); 655e5aaf047SAppaRao Puli } 656e5aaf047SAppaRao Puli 657e5aaf047SAppaRao Puli void doDelete(crow::Response& res, const crow::Request& req, 658e5aaf047SAppaRao Puli const std::vector<std::string>& params) override 659e5aaf047SAppaRao Puli { 660e5aaf047SAppaRao Puli auto asyncResp = std::make_shared<AsyncResp>(res); 661e5aaf047SAppaRao Puli 662e5aaf047SAppaRao Puli if (params.size() != 1) 663e5aaf047SAppaRao Puli { 664e5aaf047SAppaRao Puli messages::internalError(asyncResp->res); 665e5aaf047SAppaRao Puli return; 666e5aaf047SAppaRao Puli } 667e5aaf047SAppaRao Puli 668b52664e2SAppaRao Puli if (!EventServiceManager::getInstance().isSubscriptionExist(params[0])) 669e5aaf047SAppaRao Puli { 670e5aaf047SAppaRao Puli res.result(boost::beast::http::status::not_found); 671e5aaf047SAppaRao Puli res.end(); 672e5aaf047SAppaRao Puli return; 673e5aaf047SAppaRao Puli } 674b52664e2SAppaRao Puli EventServiceManager::getInstance().deleteSubscription(params[0]); 675e5aaf047SAppaRao Puli } 676e5aaf047SAppaRao Puli }; 677e5aaf047SAppaRao Puli 678e5aaf047SAppaRao Puli } // namespace redfish 679