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: 4252cc112dSEd Tanous EventService(App& 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: 54*8d1b46d7Szhanghch05 void doGet(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 55*8d1b46d7Szhanghch05 const crow::Request&, const std::vector<std::string>&) override 56e5aaf047SAppaRao Puli { 57*8d1b46d7Szhanghch05 58*8d1b46d7Szhanghch05 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", 660b4bdd93SAppaRao Puli {{"target", "/redfish/v1/EventService/Actions/" 670b4bdd93SAppaRao Puli "EventService.SubmitTestEvent"}}}}}, 68e5aaf047SAppaRao Puli {"@odata.id", "/redfish/v1/EventService"}}; 69e5aaf047SAppaRao Puli 707d1cc387SAppaRao Puli const auto& [enabled, retryAttempts, retryTimeoutInterval] = 717d1cc387SAppaRao Puli EventServiceManager::getInstance().getEventServiceConfig(); 727d1cc387SAppaRao Puli 737d1cc387SAppaRao Puli asyncResp->res.jsonValue["Status"]["State"] = 747d1cc387SAppaRao Puli (enabled ? "Enabled" : "Disabled"); 757d1cc387SAppaRao Puli asyncResp->res.jsonValue["ServiceEnabled"] = enabled; 767d1cc387SAppaRao Puli asyncResp->res.jsonValue["DeliveryRetryAttempts"] = retryAttempts; 77e5aaf047SAppaRao Puli asyncResp->res.jsonValue["DeliveryRetryIntervalSeconds"] = 787d1cc387SAppaRao Puli retryTimeoutInterval; 79e5aaf047SAppaRao Puli asyncResp->res.jsonValue["EventFormatTypes"] = supportedEvtFormatTypes; 80e5aaf047SAppaRao Puli asyncResp->res.jsonValue["RegistryPrefixes"] = supportedRegPrefixes; 81e56f254cSSunitha Harish asyncResp->res.jsonValue["ResourceTypes"] = supportedResourceTypes; 8207941a88SAyushi Smriti 8307941a88SAyushi Smriti nlohmann::json supportedSSEFilters = { 8407941a88SAyushi Smriti {"EventFormatType", true}, {"MessageId", true}, 8507941a88SAyushi Smriti {"MetricReportDefinition", true}, {"RegistryPrefix", true}, 8607941a88SAyushi Smriti {"OriginResource", false}, {"ResourceType", false}}; 8707941a88SAyushi Smriti 8807941a88SAyushi Smriti asyncResp->res.jsonValue["SSEFilterPropertiesSupported"] = 8907941a88SAyushi Smriti supportedSSEFilters; 90e5aaf047SAppaRao Puli } 91e5aaf047SAppaRao Puli 92*8d1b46d7Szhanghch05 void doPatch(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 93*8d1b46d7Szhanghch05 const crow::Request& req, 94cb13a392SEd Tanous const std::vector<std::string>&) override 95e5aaf047SAppaRao Puli { 96e5aaf047SAppaRao Puli 97e5aaf047SAppaRao Puli std::optional<bool> serviceEnabled; 98e5aaf047SAppaRao Puli std::optional<uint32_t> retryAttemps; 99e5aaf047SAppaRao Puli std::optional<uint32_t> retryInterval; 100e5aaf047SAppaRao Puli 101*8d1b46d7Szhanghch05 if (!json_util::readJson(req, asyncResp->res, "ServiceEnabled", 102*8d1b46d7Szhanghch05 serviceEnabled, "DeliveryRetryAttempts", 103*8d1b46d7Szhanghch05 retryAttemps, "DeliveryRetryIntervalSeconds", 104*8d1b46d7Szhanghch05 retryInterval)) 105e5aaf047SAppaRao Puli { 106e5aaf047SAppaRao Puli return; 107e5aaf047SAppaRao Puli } 108e5aaf047SAppaRao Puli 1097d1cc387SAppaRao Puli auto [enabled, retryCount, retryTimeoutInterval] = 1107d1cc387SAppaRao Puli EventServiceManager::getInstance().getEventServiceConfig(); 1117d1cc387SAppaRao Puli 112e5aaf047SAppaRao Puli if (serviceEnabled) 113e5aaf047SAppaRao Puli { 1147d1cc387SAppaRao Puli enabled = *serviceEnabled; 115e5aaf047SAppaRao Puli } 116e5aaf047SAppaRao Puli 117e5aaf047SAppaRao Puli if (retryAttemps) 118e5aaf047SAppaRao Puli { 119e5aaf047SAppaRao Puli // Supported range [1-3] 120e5aaf047SAppaRao Puli if ((*retryAttemps < 1) || (*retryAttemps > 3)) 121e5aaf047SAppaRao Puli { 122e5aaf047SAppaRao Puli messages::queryParameterOutOfRange( 123e5aaf047SAppaRao Puli asyncResp->res, std::to_string(*retryAttemps), 124e5aaf047SAppaRao Puli "DeliveryRetryAttempts", "[1-3]"); 125e5aaf047SAppaRao Puli } 126e5aaf047SAppaRao Puli else 127e5aaf047SAppaRao Puli { 1287d1cc387SAppaRao Puli retryCount = *retryAttemps; 129e5aaf047SAppaRao Puli } 130e5aaf047SAppaRao Puli } 131e5aaf047SAppaRao Puli 132e5aaf047SAppaRao Puli if (retryInterval) 133e5aaf047SAppaRao Puli { 134e5aaf047SAppaRao Puli // Supported range [30 - 180] 135e5aaf047SAppaRao Puli if ((*retryInterval < 30) || (*retryInterval > 180)) 136e5aaf047SAppaRao Puli { 137e5aaf047SAppaRao Puli messages::queryParameterOutOfRange( 138e5aaf047SAppaRao Puli asyncResp->res, std::to_string(*retryInterval), 139e5aaf047SAppaRao Puli "DeliveryRetryIntervalSeconds", "[30-180]"); 140e5aaf047SAppaRao Puli } 141e5aaf047SAppaRao Puli else 142e5aaf047SAppaRao Puli { 1437d1cc387SAppaRao Puli retryTimeoutInterval = *retryInterval; 144e5aaf047SAppaRao Puli } 145e5aaf047SAppaRao Puli } 146e5aaf047SAppaRao Puli 1477d1cc387SAppaRao Puli EventServiceManager::getInstance().setEventServiceConfig( 1487d1cc387SAppaRao Puli std::make_tuple(enabled, retryCount, retryTimeoutInterval)); 149e5aaf047SAppaRao Puli } 150e5aaf047SAppaRao Puli }; 151e5aaf047SAppaRao Puli 1520b4bdd93SAppaRao Puli class SubmitTestEvent : public Node 1530b4bdd93SAppaRao Puli { 1540b4bdd93SAppaRao Puli public: 15552cc112dSEd Tanous SubmitTestEvent(App& app) : 1560b4bdd93SAppaRao Puli Node(app, 1570b4bdd93SAppaRao Puli "/redfish/v1/EventService/Actions/EventService.SubmitTestEvent/") 1580b4bdd93SAppaRao Puli { 1590b4bdd93SAppaRao Puli entityPrivileges = { 1600b4bdd93SAppaRao Puli {boost::beast::http::verb::get, {{"Login"}}}, 1610b4bdd93SAppaRao Puli {boost::beast::http::verb::head, {{"Login"}}}, 1620b4bdd93SAppaRao Puli {boost::beast::http::verb::patch, {{"ConfigureManager"}}}, 1630b4bdd93SAppaRao Puli {boost::beast::http::verb::put, {{"ConfigureManager"}}}, 1640b4bdd93SAppaRao Puli {boost::beast::http::verb::delete_, {{"ConfigureManager"}}}, 1650b4bdd93SAppaRao Puli {boost::beast::http::verb::post, {{"ConfigureManager"}}}}; 1660b4bdd93SAppaRao Puli } 1670b4bdd93SAppaRao Puli 1680b4bdd93SAppaRao Puli private: 169*8d1b46d7Szhanghch05 void doPost(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 170*8d1b46d7Szhanghch05 const crow::Request&, const std::vector<std::string>&) override 1710b4bdd93SAppaRao Puli { 1720b4bdd93SAppaRao Puli EventServiceManager::getInstance().sendTestEventLog(); 173*8d1b46d7Szhanghch05 asyncResp->res.result(boost::beast::http::status::no_content); 1740b4bdd93SAppaRao Puli } 1750b4bdd93SAppaRao Puli }; 1760b4bdd93SAppaRao Puli 177e5aaf047SAppaRao Puli class EventDestinationCollection : public Node 178e5aaf047SAppaRao Puli { 179e5aaf047SAppaRao Puli public: 18052cc112dSEd Tanous EventDestinationCollection(App& app) : 181e5aaf047SAppaRao Puli Node(app, "/redfish/v1/EventService/Subscriptions/") 182e5aaf047SAppaRao Puli { 183e5aaf047SAppaRao Puli entityPrivileges = { 184e5aaf047SAppaRao Puli {boost::beast::http::verb::get, {{"Login"}}}, 185e5aaf047SAppaRao Puli {boost::beast::http::verb::head, {{"Login"}}}, 186e5aaf047SAppaRao Puli {boost::beast::http::verb::patch, {{"ConfigureManager"}}}, 187e5aaf047SAppaRao Puli {boost::beast::http::verb::put, {{"ConfigureManager"}}}, 188e5aaf047SAppaRao Puli {boost::beast::http::verb::delete_, {{"ConfigureManager"}}}, 189e5aaf047SAppaRao Puli {boost::beast::http::verb::post, {{"ConfigureManager"}}}}; 190e5aaf047SAppaRao Puli } 191e5aaf047SAppaRao Puli 192e5aaf047SAppaRao Puli private: 193*8d1b46d7Szhanghch05 void doGet(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 194*8d1b46d7Szhanghch05 const crow::Request&, const std::vector<std::string>&) override 195e5aaf047SAppaRao Puli { 196e5aaf047SAppaRao Puli 197*8d1b46d7Szhanghch05 asyncResp->res.jsonValue = { 198e5aaf047SAppaRao Puli {"@odata.type", 199e5aaf047SAppaRao Puli "#EventDestinationCollection.EventDestinationCollection"}, 200e5aaf047SAppaRao Puli {"@odata.id", "/redfish/v1/EventService/Subscriptions"}, 201e5aaf047SAppaRao Puli {"Name", "Event Destination Collections"}}; 202e5aaf047SAppaRao Puli 203e5aaf047SAppaRao Puli nlohmann::json& memberArray = asyncResp->res.jsonValue["Members"]; 204e5aaf047SAppaRao Puli 205b52664e2SAppaRao Puli std::vector<std::string> subscripIds = 206b52664e2SAppaRao Puli EventServiceManager::getInstance().getAllIDs(); 207b52664e2SAppaRao Puli memberArray = nlohmann::json::array(); 208b52664e2SAppaRao Puli asyncResp->res.jsonValue["Members@odata.count"] = subscripIds.size(); 209b52664e2SAppaRao Puli 210b52664e2SAppaRao Puli for (const std::string& id : subscripIds) 211e5aaf047SAppaRao Puli { 212e5aaf047SAppaRao Puli memberArray.push_back( 213e5aaf047SAppaRao Puli {{"@odata.id", 214b52664e2SAppaRao Puli "/redfish/v1/EventService/Subscriptions/" + id}}); 215e5aaf047SAppaRao Puli } 216e5aaf047SAppaRao Puli } 217e5aaf047SAppaRao Puli 218*8d1b46d7Szhanghch05 void doPost(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 219*8d1b46d7Szhanghch05 const crow::Request& req, 220cb13a392SEd Tanous const std::vector<std::string>&) override 221e5aaf047SAppaRao Puli { 222e5aaf047SAppaRao Puli 223b52664e2SAppaRao Puli if (EventServiceManager::getInstance().getNumberOfSubscriptions() >= 224b52664e2SAppaRao Puli maxNoOfSubscriptions) 225e5aaf047SAppaRao Puli { 226e5aaf047SAppaRao Puli messages::eventSubscriptionLimitExceeded(asyncResp->res); 227e5aaf047SAppaRao Puli return; 228e5aaf047SAppaRao Puli } 229e5aaf047SAppaRao Puli std::string destUrl; 230e5aaf047SAppaRao Puli std::string protocol; 231e5aaf047SAppaRao Puli std::optional<std::string> context; 232e5aaf047SAppaRao Puli std::optional<std::string> subscriptionType; 23323a21a1cSEd Tanous std::optional<std::string> eventFormatType2; 234e5aaf047SAppaRao Puli std::optional<std::string> retryPolicy; 235e5aaf047SAppaRao Puli std::optional<std::vector<std::string>> msgIds; 236e5aaf047SAppaRao Puli std::optional<std::vector<std::string>> regPrefixes; 237e56f254cSSunitha Harish std::optional<std::vector<std::string>> resTypes; 238e5aaf047SAppaRao Puli std::optional<std::vector<nlohmann::json>> headers; 239144b6318SAppaRao Puli std::optional<std::vector<nlohmann::json>> mrdJsonArray; 240e5aaf047SAppaRao Puli 241e5aaf047SAppaRao Puli if (!json_util::readJson( 242*8d1b46d7Szhanghch05 req, asyncResp->res, "Destination", destUrl, "Context", context, 243e5aaf047SAppaRao Puli "Protocol", protocol, "SubscriptionType", subscriptionType, 24423a21a1cSEd Tanous "EventFormatType", eventFormatType2, "HttpHeaders", headers, 245e5aaf047SAppaRao Puli "RegistryPrefixes", regPrefixes, "MessageIds", msgIds, 246156d6b00SAppaRao Puli "DeliveryRetryPolicy", retryPolicy, "MetricReportDefinitions", 247144b6318SAppaRao Puli mrdJsonArray, "ResourceTypes", resTypes)) 248e5aaf047SAppaRao Puli { 249e5aaf047SAppaRao Puli return; 250e5aaf047SAppaRao Puli } 251e5aaf047SAppaRao Puli 252dd28ba82SAppaRao Puli if (regPrefixes && msgIds) 253dd28ba82SAppaRao Puli { 254dd28ba82SAppaRao Puli if (regPrefixes->size() && msgIds->size()) 255dd28ba82SAppaRao Puli { 256dd28ba82SAppaRao Puli messages::mutualExclusiveProperties( 257dd28ba82SAppaRao Puli asyncResp->res, "RegistryPrefixes", "MessageIds"); 258dd28ba82SAppaRao Puli return; 259dd28ba82SAppaRao Puli } 260dd28ba82SAppaRao Puli } 261dd28ba82SAppaRao Puli 262e5aaf047SAppaRao Puli // Validate the URL using regex expression 263b52664e2SAppaRao Puli // Format: <protocol>://<host>:<port>/<uri> 264b52664e2SAppaRao Puli // protocol: http/https 265b52664e2SAppaRao Puli // host: Exclude ' ', ':', '#', '?' 2664e0453b1SGunnar Mills // port: Empty or numeric value with ':' separator. 267b52664e2SAppaRao Puli // uri: Start with '/' and Exclude '#', ' ' 268b52664e2SAppaRao Puli // Can include query params(ex: '/event?test=1') 269b52664e2SAppaRao Puli // TODO: Need to validate hostname extensively(as per rfc) 270b52664e2SAppaRao Puli const std::regex urlRegex( 271b52664e2SAppaRao Puli "(http|https)://([^/\\x20\\x3f\\x23\\x3a]+):?([0-9]*)(/" 272b52664e2SAppaRao Puli "([^\\x20\\x23\\x3f]*\\x3f?([^\\x20\\x23\\x3f])*)?)"); 273b52664e2SAppaRao Puli std::cmatch match; 274b52664e2SAppaRao Puli if (!std::regex_match(destUrl.c_str(), match, urlRegex)) 275e5aaf047SAppaRao Puli { 276e5aaf047SAppaRao Puli messages::propertyValueFormatError(asyncResp->res, destUrl, 277e5aaf047SAppaRao Puli "Destination"); 278e5aaf047SAppaRao Puli return; 279e5aaf047SAppaRao Puli } 280b52664e2SAppaRao Puli 281b52664e2SAppaRao Puli std::string uriProto = std::string(match[1].first, match[1].second); 282b52664e2SAppaRao Puli if (uriProto == "http") 283b52664e2SAppaRao Puli { 284b52664e2SAppaRao Puli #ifndef BMCWEB_INSECURE_ENABLE_HTTP_PUSH_STYLE_EVENTING 285b52664e2SAppaRao Puli messages::propertyValueFormatError(asyncResp->res, destUrl, 286b52664e2SAppaRao Puli "Destination"); 287b52664e2SAppaRao Puli return; 288b52664e2SAppaRao Puli #endif 289b52664e2SAppaRao Puli } 290b52664e2SAppaRao Puli 291b52664e2SAppaRao Puli std::string host = std::string(match[2].first, match[2].second); 292b52664e2SAppaRao Puli std::string port = std::string(match[3].first, match[3].second); 293b52664e2SAppaRao Puli std::string path = std::string(match[4].first, match[4].second); 294b52664e2SAppaRao Puli if (port.empty()) 295b52664e2SAppaRao Puli { 296b52664e2SAppaRao Puli if (uriProto == "http") 297b52664e2SAppaRao Puli { 298b52664e2SAppaRao Puli port = "80"; 299b52664e2SAppaRao Puli } 300b52664e2SAppaRao Puli else 301b52664e2SAppaRao Puli { 302b52664e2SAppaRao Puli port = "443"; 303b52664e2SAppaRao Puli } 304b52664e2SAppaRao Puli } 305b52664e2SAppaRao Puli if (path.empty()) 306b52664e2SAppaRao Puli { 307b52664e2SAppaRao Puli path = "/"; 308b52664e2SAppaRao Puli } 309b52664e2SAppaRao Puli 310b52664e2SAppaRao Puli std::shared_ptr<Subscription> subValue = 311b52664e2SAppaRao Puli std::make_shared<Subscription>(host, port, path, uriProto); 312b52664e2SAppaRao Puli 313b52664e2SAppaRao Puli subValue->destinationUrl = destUrl; 314e5aaf047SAppaRao Puli 315e5aaf047SAppaRao Puli if (subscriptionType) 316e5aaf047SAppaRao Puli { 317e5aaf047SAppaRao Puli if (*subscriptionType != "RedfishEvent") 318e5aaf047SAppaRao Puli { 319e5aaf047SAppaRao Puli messages::propertyValueNotInList( 320e5aaf047SAppaRao Puli asyncResp->res, *subscriptionType, "SubscriptionType"); 321e5aaf047SAppaRao Puli return; 322e5aaf047SAppaRao Puli } 323b52664e2SAppaRao Puli subValue->subscriptionType = *subscriptionType; 324e5aaf047SAppaRao Puli } 325e5aaf047SAppaRao Puli else 326e5aaf047SAppaRao Puli { 327b52664e2SAppaRao Puli subValue->subscriptionType = "RedfishEvent"; // Default 328e5aaf047SAppaRao Puli } 329e5aaf047SAppaRao Puli 330e5aaf047SAppaRao Puli if (protocol != "Redfish") 331e5aaf047SAppaRao Puli { 332e5aaf047SAppaRao Puli messages::propertyValueNotInList(asyncResp->res, protocol, 333e5aaf047SAppaRao Puli "Protocol"); 334e5aaf047SAppaRao Puli return; 335e5aaf047SAppaRao Puli } 336b52664e2SAppaRao Puli subValue->protocol = protocol; 337e5aaf047SAppaRao Puli 33823a21a1cSEd Tanous if (eventFormatType2) 339e5aaf047SAppaRao Puli { 340e5aaf047SAppaRao Puli if (std::find(supportedEvtFormatTypes.begin(), 341e5aaf047SAppaRao Puli supportedEvtFormatTypes.end(), 34223a21a1cSEd Tanous *eventFormatType2) == supportedEvtFormatTypes.end()) 343e5aaf047SAppaRao Puli { 344e5aaf047SAppaRao Puli messages::propertyValueNotInList( 34523a21a1cSEd Tanous asyncResp->res, *eventFormatType2, "EventFormatType"); 346e5aaf047SAppaRao Puli return; 347e5aaf047SAppaRao Puli } 34823a21a1cSEd Tanous subValue->eventFormatType = *eventFormatType2; 349e5aaf047SAppaRao Puli } 350e5aaf047SAppaRao Puli else 351e5aaf047SAppaRao Puli { 352e5aaf047SAppaRao Puli // If not specified, use default "Event" 35323a21a1cSEd Tanous subValue->eventFormatType = "Event"; 354e5aaf047SAppaRao Puli } 355e5aaf047SAppaRao Puli 356e5aaf047SAppaRao Puli if (context) 357e5aaf047SAppaRao Puli { 358b52664e2SAppaRao Puli subValue->customText = *context; 359e5aaf047SAppaRao Puli } 360e5aaf047SAppaRao Puli 361e5aaf047SAppaRao Puli if (headers) 362e5aaf047SAppaRao Puli { 363b52664e2SAppaRao Puli subValue->httpHeaders = *headers; 364e5aaf047SAppaRao Puli } 365e5aaf047SAppaRao Puli 366e5aaf047SAppaRao Puli if (regPrefixes) 367e5aaf047SAppaRao Puli { 368e5aaf047SAppaRao Puli for (const std::string& it : *regPrefixes) 369e5aaf047SAppaRao Puli { 370e5aaf047SAppaRao Puli if (std::find(supportedRegPrefixes.begin(), 371e5aaf047SAppaRao Puli supportedRegPrefixes.end(), 372e5aaf047SAppaRao Puli it) == supportedRegPrefixes.end()) 373e5aaf047SAppaRao Puli { 374e5aaf047SAppaRao Puli messages::propertyValueNotInList(asyncResp->res, it, 375e5aaf047SAppaRao Puli "RegistryPrefixes"); 376e5aaf047SAppaRao Puli return; 377e5aaf047SAppaRao Puli } 378e5aaf047SAppaRao Puli } 379b52664e2SAppaRao Puli subValue->registryPrefixes = *regPrefixes; 380e5aaf047SAppaRao Puli } 381e5aaf047SAppaRao Puli 382e56f254cSSunitha Harish if (resTypes) 383e56f254cSSunitha Harish { 384e56f254cSSunitha Harish for (const std::string& it : *resTypes) 385e56f254cSSunitha Harish { 386e56f254cSSunitha Harish if (std::find(supportedResourceTypes.begin(), 387e56f254cSSunitha Harish supportedResourceTypes.end(), 388e56f254cSSunitha Harish it) == supportedResourceTypes.end()) 389e56f254cSSunitha Harish { 390e56f254cSSunitha Harish messages::propertyValueNotInList(asyncResp->res, it, 391e56f254cSSunitha Harish "ResourceTypes"); 392e56f254cSSunitha Harish return; 393e56f254cSSunitha Harish } 394e56f254cSSunitha Harish } 395e56f254cSSunitha Harish subValue->resourceTypes = *resTypes; 396e56f254cSSunitha Harish } 397e56f254cSSunitha Harish 398e5aaf047SAppaRao Puli if (msgIds) 399e5aaf047SAppaRao Puli { 400e5aaf047SAppaRao Puli // Do we need to loop-up MessageRegistry and validate 401e5aaf047SAppaRao Puli // data for authenticity??? Not mandate, i believe. 402b52664e2SAppaRao Puli subValue->registryMsgIds = *msgIds; 403e5aaf047SAppaRao Puli } 404e5aaf047SAppaRao Puli 405e5aaf047SAppaRao Puli if (retryPolicy) 406e5aaf047SAppaRao Puli { 407e5aaf047SAppaRao Puli if (std::find(supportedRetryPolicies.begin(), 408e5aaf047SAppaRao Puli supportedRetryPolicies.end(), 409e5aaf047SAppaRao Puli *retryPolicy) == supportedRetryPolicies.end()) 410e5aaf047SAppaRao Puli { 411e5aaf047SAppaRao Puli messages::propertyValueNotInList(asyncResp->res, *retryPolicy, 412e5aaf047SAppaRao Puli "DeliveryRetryPolicy"); 413e5aaf047SAppaRao Puli return; 414e5aaf047SAppaRao Puli } 415b52664e2SAppaRao Puli subValue->retryPolicy = *retryPolicy; 416e5aaf047SAppaRao Puli } 417e5aaf047SAppaRao Puli else 418e5aaf047SAppaRao Puli { 419e5aaf047SAppaRao Puli // Default "TerminateAfterRetries" 420b52664e2SAppaRao Puli subValue->retryPolicy = "TerminateAfterRetries"; 421e5aaf047SAppaRao Puli } 422e5aaf047SAppaRao Puli 423144b6318SAppaRao Puli if (mrdJsonArray) 424156d6b00SAppaRao Puli { 425144b6318SAppaRao Puli for (nlohmann::json& mrdObj : *mrdJsonArray) 426144b6318SAppaRao Puli { 427144b6318SAppaRao Puli std::string mrdUri; 428144b6318SAppaRao Puli if (json_util::getValueFromJsonObject(mrdObj, "@odata.id", 429144b6318SAppaRao Puli mrdUri)) 430144b6318SAppaRao Puli { 431144b6318SAppaRao Puli subValue->metricReportDefinitions.emplace_back(mrdUri); 432144b6318SAppaRao Puli } 433144b6318SAppaRao Puli else 434144b6318SAppaRao Puli { 435144b6318SAppaRao Puli messages::propertyValueFormatError( 43671f52d96SEd Tanous asyncResp->res, 43771f52d96SEd Tanous mrdObj.dump(2, ' ', true, 43871f52d96SEd Tanous nlohmann::json::error_handler_t::replace), 439144b6318SAppaRao Puli "MetricReportDefinitions"); 440144b6318SAppaRao Puli return; 441144b6318SAppaRao Puli } 442144b6318SAppaRao Puli } 443156d6b00SAppaRao Puli } 444156d6b00SAppaRao Puli 445b52664e2SAppaRao Puli std::string id = 446b52664e2SAppaRao Puli EventServiceManager::getInstance().addSubscription(subValue); 447b52664e2SAppaRao Puli if (id.empty()) 448e5aaf047SAppaRao Puli { 449e5aaf047SAppaRao Puli messages::internalError(asyncResp->res); 450e5aaf047SAppaRao Puli return; 451e5aaf047SAppaRao Puli } 452e5aaf047SAppaRao Puli 453e5aaf047SAppaRao Puli messages::created(asyncResp->res); 454e5aaf047SAppaRao Puli asyncResp->res.addHeader( 455e5aaf047SAppaRao Puli "Location", "/redfish/v1/EventService/Subscriptions/" + id); 456e5aaf047SAppaRao Puli } 457e5aaf047SAppaRao Puli }; 458e5aaf047SAppaRao Puli 459e5aaf047SAppaRao Puli class EventDestination : public Node 460e5aaf047SAppaRao Puli { 461e5aaf047SAppaRao Puli public: 46252cc112dSEd Tanous EventDestination(App& app) : 463e5aaf047SAppaRao Puli Node(app, "/redfish/v1/EventService/Subscriptions/<str>/", 464e5aaf047SAppaRao Puli std::string()) 465e5aaf047SAppaRao Puli { 466e5aaf047SAppaRao Puli entityPrivileges = { 467e5aaf047SAppaRao Puli {boost::beast::http::verb::get, {{"Login"}}}, 468e5aaf047SAppaRao Puli {boost::beast::http::verb::head, {{"Login"}}}, 469e5aaf047SAppaRao Puli {boost::beast::http::verb::patch, {{"ConfigureManager"}}}, 470e5aaf047SAppaRao Puli {boost::beast::http::verb::put, {{"ConfigureManager"}}}, 471e5aaf047SAppaRao Puli {boost::beast::http::verb::delete_, {{"ConfigureManager"}}}, 472e5aaf047SAppaRao Puli {boost::beast::http::verb::post, {{"ConfigureManager"}}}}; 473e5aaf047SAppaRao Puli } 474e5aaf047SAppaRao Puli 475e5aaf047SAppaRao Puli private: 476*8d1b46d7Szhanghch05 void doGet(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 477*8d1b46d7Szhanghch05 const crow::Request&, 478e5aaf047SAppaRao Puli const std::vector<std::string>& params) override 479e5aaf047SAppaRao Puli { 480*8d1b46d7Szhanghch05 481e5aaf047SAppaRao Puli if (params.size() != 1) 482e5aaf047SAppaRao Puli { 483e5aaf047SAppaRao Puli messages::internalError(asyncResp->res); 484e5aaf047SAppaRao Puli return; 485e5aaf047SAppaRao Puli } 486e5aaf047SAppaRao Puli 487b52664e2SAppaRao Puli std::shared_ptr<Subscription> subValue = 488b52664e2SAppaRao Puli EventServiceManager::getInstance().getSubscription(params[0]); 489b52664e2SAppaRao Puli if (subValue == nullptr) 490e5aaf047SAppaRao Puli { 491*8d1b46d7Szhanghch05 asyncResp->res.result(boost::beast::http::status::not_found); 492e5aaf047SAppaRao Puli return; 493e5aaf047SAppaRao Puli } 494b52664e2SAppaRao Puli const std::string& id = params[0]; 495e5aaf047SAppaRao Puli 496*8d1b46d7Szhanghch05 asyncResp->res.jsonValue = { 497e5aaf047SAppaRao Puli {"@odata.type", "#EventDestination.v1_7_0.EventDestination"}, 498e5aaf047SAppaRao Puli {"Protocol", "Redfish"}}; 499e5aaf047SAppaRao Puli asyncResp->res.jsonValue["@odata.id"] = 500e5aaf047SAppaRao Puli "/redfish/v1/EventService/Subscriptions/" + id; 501e5aaf047SAppaRao Puli asyncResp->res.jsonValue["Id"] = id; 502e5aaf047SAppaRao Puli asyncResp->res.jsonValue["Name"] = "Event Destination " + id; 503b52664e2SAppaRao Puli asyncResp->res.jsonValue["Destination"] = subValue->destinationUrl; 504b52664e2SAppaRao Puli asyncResp->res.jsonValue["Context"] = subValue->customText; 505e5aaf047SAppaRao Puli asyncResp->res.jsonValue["SubscriptionType"] = 506b52664e2SAppaRao Puli subValue->subscriptionType; 507b52664e2SAppaRao Puli asyncResp->res.jsonValue["HttpHeaders"] = subValue->httpHeaders; 508b52664e2SAppaRao Puli asyncResp->res.jsonValue["EventFormatType"] = subValue->eventFormatType; 509e5aaf047SAppaRao Puli asyncResp->res.jsonValue["RegistryPrefixes"] = 510b52664e2SAppaRao Puli subValue->registryPrefixes; 511e56f254cSSunitha Harish asyncResp->res.jsonValue["ResourceTypes"] = subValue->resourceTypes; 512e56f254cSSunitha Harish 513b52664e2SAppaRao Puli asyncResp->res.jsonValue["MessageIds"] = subValue->registryMsgIds; 514b52664e2SAppaRao Puli asyncResp->res.jsonValue["DeliveryRetryPolicy"] = subValue->retryPolicy; 515144b6318SAppaRao Puli 516144b6318SAppaRao Puli std::vector<nlohmann::json> mrdJsonArray; 517144b6318SAppaRao Puli for (const auto& mdrUri : subValue->metricReportDefinitions) 518144b6318SAppaRao Puli { 519144b6318SAppaRao Puli mrdJsonArray.push_back({{"@odata.id", mdrUri}}); 520144b6318SAppaRao Puli } 521144b6318SAppaRao Puli asyncResp->res.jsonValue["MetricReportDefinitions"] = mrdJsonArray; 522e5aaf047SAppaRao Puli } 523e5aaf047SAppaRao Puli 524*8d1b46d7Szhanghch05 void doPatch(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 525*8d1b46d7Szhanghch05 const crow::Request& req, 526e5aaf047SAppaRao Puli const std::vector<std::string>& params) override 527e5aaf047SAppaRao Puli { 528*8d1b46d7Szhanghch05 529e5aaf047SAppaRao Puli if (params.size() != 1) 530e5aaf047SAppaRao Puli { 531e5aaf047SAppaRao Puli messages::internalError(asyncResp->res); 532e5aaf047SAppaRao Puli return; 533e5aaf047SAppaRao Puli } 534e5aaf047SAppaRao Puli 535b52664e2SAppaRao Puli std::shared_ptr<Subscription> subValue = 536b52664e2SAppaRao Puli EventServiceManager::getInstance().getSubscription(params[0]); 537b52664e2SAppaRao Puli if (subValue == nullptr) 538e5aaf047SAppaRao Puli { 539*8d1b46d7Szhanghch05 asyncResp->res.result(boost::beast::http::status::not_found); 540e5aaf047SAppaRao Puli return; 541e5aaf047SAppaRao Puli } 542e5aaf047SAppaRao Puli 543e5aaf047SAppaRao Puli std::optional<std::string> context; 544e5aaf047SAppaRao Puli std::optional<std::string> retryPolicy; 545e5aaf047SAppaRao Puli std::optional<std::vector<nlohmann::json>> headers; 546e5aaf047SAppaRao Puli 547*8d1b46d7Szhanghch05 if (!json_util::readJson(req, asyncResp->res, "Context", context, 548e5aaf047SAppaRao Puli "DeliveryRetryPolicy", retryPolicy, 549e5aaf047SAppaRao Puli "HttpHeaders", headers)) 550e5aaf047SAppaRao Puli { 551e5aaf047SAppaRao Puli return; 552e5aaf047SAppaRao Puli } 553e5aaf047SAppaRao Puli 554e5aaf047SAppaRao Puli if (context) 555e5aaf047SAppaRao Puli { 556b52664e2SAppaRao Puli subValue->customText = *context; 557e5aaf047SAppaRao Puli } 558e5aaf047SAppaRao Puli 559e5aaf047SAppaRao Puli if (headers) 560e5aaf047SAppaRao Puli { 561b52664e2SAppaRao Puli subValue->httpHeaders = *headers; 562e5aaf047SAppaRao Puli } 563e5aaf047SAppaRao Puli 564e5aaf047SAppaRao Puli if (retryPolicy) 565e5aaf047SAppaRao Puli { 566e5aaf047SAppaRao Puli if (std::find(supportedRetryPolicies.begin(), 567e5aaf047SAppaRao Puli supportedRetryPolicies.end(), 568e5aaf047SAppaRao Puli *retryPolicy) == supportedRetryPolicies.end()) 569e5aaf047SAppaRao Puli { 570e5aaf047SAppaRao Puli messages::propertyValueNotInList(asyncResp->res, *retryPolicy, 571e5aaf047SAppaRao Puli "DeliveryRetryPolicy"); 572e5aaf047SAppaRao Puli return; 573e5aaf047SAppaRao Puli } 574b52664e2SAppaRao Puli subValue->retryPolicy = *retryPolicy; 575fe44eb0bSAyushi Smriti subValue->updateRetryPolicy(); 576e5aaf047SAppaRao Puli } 577e5aaf047SAppaRao Puli 578b52664e2SAppaRao Puli EventServiceManager::getInstance().updateSubscriptionData(); 579e5aaf047SAppaRao Puli } 580e5aaf047SAppaRao Puli 581*8d1b46d7Szhanghch05 void doDelete(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 582*8d1b46d7Szhanghch05 const crow::Request&, 583e5aaf047SAppaRao Puli const std::vector<std::string>& params) override 584e5aaf047SAppaRao Puli { 585e5aaf047SAppaRao Puli 586e5aaf047SAppaRao Puli if (params.size() != 1) 587e5aaf047SAppaRao Puli { 588e5aaf047SAppaRao Puli messages::internalError(asyncResp->res); 589e5aaf047SAppaRao Puli return; 590e5aaf047SAppaRao Puli } 591e5aaf047SAppaRao Puli 592b52664e2SAppaRao Puli if (!EventServiceManager::getInstance().isSubscriptionExist(params[0])) 593e5aaf047SAppaRao Puli { 594*8d1b46d7Szhanghch05 asyncResp->res.result(boost::beast::http::status::not_found); 595e5aaf047SAppaRao Puli return; 596e5aaf047SAppaRao Puli } 597b52664e2SAppaRao Puli EventServiceManager::getInstance().deleteSubscription(params[0]); 598e5aaf047SAppaRao Puli } 599e5aaf047SAppaRao Puli }; 600e5aaf047SAppaRao Puli 601e5aaf047SAppaRao Puli } // namespace redfish 602