1*e5aaf047SAppaRao Puli /* 2*e5aaf047SAppaRao Puli // Copyright (c) 2020 Intel Corporation 3*e5aaf047SAppaRao Puli // 4*e5aaf047SAppaRao Puli // Licensed under the Apache License, Version 2.0 (the "License"); 5*e5aaf047SAppaRao Puli // you may not use this file except in compliance with the License. 6*e5aaf047SAppaRao Puli // You may obtain a copy of the License at 7*e5aaf047SAppaRao Puli // 8*e5aaf047SAppaRao Puli // http://www.apache.org/licenses/LICENSE-2.0 9*e5aaf047SAppaRao Puli // 10*e5aaf047SAppaRao Puli // Unless required by applicable law or agreed to in writing, software 11*e5aaf047SAppaRao Puli // distributed under the License is distributed on an "AS IS" BASIS, 12*e5aaf047SAppaRao Puli // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13*e5aaf047SAppaRao Puli // See the License for the specific language governing permissions and 14*e5aaf047SAppaRao Puli // limitations under the License. 15*e5aaf047SAppaRao Puli */ 16*e5aaf047SAppaRao Puli #pragma once 17*e5aaf047SAppaRao Puli #include "node.hpp" 18*e5aaf047SAppaRao Puli 19*e5aaf047SAppaRao Puli #include <boost/container/flat_map.hpp> 20*e5aaf047SAppaRao Puli #include <error_messages.hpp> 21*e5aaf047SAppaRao Puli #include <utils/json_utils.hpp> 22*e5aaf047SAppaRao Puli #include <variant> 23*e5aaf047SAppaRao Puli 24*e5aaf047SAppaRao Puli namespace redfish 25*e5aaf047SAppaRao Puli { 26*e5aaf047SAppaRao Puli 27*e5aaf047SAppaRao Puli static constexpr const std::array<const char*, 1> supportedEvtFormatTypes = { 28*e5aaf047SAppaRao Puli "Event"}; 29*e5aaf047SAppaRao Puli static constexpr const std::array<const char*, 3> supportedRegPrefixes = { 30*e5aaf047SAppaRao Puli "Base", "OpenBMC", "Task"}; 31*e5aaf047SAppaRao Puli static constexpr const std::array<const char*, 3> supportedRetryPolicies = { 32*e5aaf047SAppaRao Puli "TerminateAfterRetries", "SuspendRetries", "RetryForever"}; 33*e5aaf047SAppaRao Puli 34*e5aaf047SAppaRao Puli static constexpr const uint8_t maxNoOfSubscriptions = 20; 35*e5aaf047SAppaRao Puli 36*e5aaf047SAppaRao Puli struct EventSrvConfig 37*e5aaf047SAppaRao Puli { 38*e5aaf047SAppaRao Puli bool enabled; 39*e5aaf047SAppaRao Puli uint32_t retryAttempts; 40*e5aaf047SAppaRao Puli uint32_t retryTimeoutInterval; 41*e5aaf047SAppaRao Puli }; 42*e5aaf047SAppaRao Puli 43*e5aaf047SAppaRao Puli struct EventSrvSubscription 44*e5aaf047SAppaRao Puli { 45*e5aaf047SAppaRao Puli std::string destinationUrl; 46*e5aaf047SAppaRao Puli std::string protocol; 47*e5aaf047SAppaRao Puli std::string retryPolicy; 48*e5aaf047SAppaRao Puli std::string customText; 49*e5aaf047SAppaRao Puli std::string eventFormatType; 50*e5aaf047SAppaRao Puli std::string subscriptionType; 51*e5aaf047SAppaRao Puli std::vector<std::string> registryMsgIds; 52*e5aaf047SAppaRao Puli std::vector<std::string> registryPrefixes; 53*e5aaf047SAppaRao Puli std::vector<nlohmann::json> httpHeaders; // key-value pair 54*e5aaf047SAppaRao Puli }; 55*e5aaf047SAppaRao Puli 56*e5aaf047SAppaRao Puli EventSrvConfig configData; 57*e5aaf047SAppaRao Puli boost::container::flat_map<std::string, EventSrvSubscription> subscriptionsMap; 58*e5aaf047SAppaRao Puli 59*e5aaf047SAppaRao Puli inline void initEventSrvStore() 60*e5aaf047SAppaRao Puli { 61*e5aaf047SAppaRao Puli // TODO: Read the persistent data from store and populate. 62*e5aaf047SAppaRao Puli // Populating with default. 63*e5aaf047SAppaRao Puli configData.enabled = true; 64*e5aaf047SAppaRao Puli configData.retryAttempts = 3; 65*e5aaf047SAppaRao Puli configData.retryTimeoutInterval = 30; // seconds 66*e5aaf047SAppaRao Puli } 67*e5aaf047SAppaRao Puli 68*e5aaf047SAppaRao Puli inline void updateSubscriptionData() 69*e5aaf047SAppaRao Puli { 70*e5aaf047SAppaRao Puli // Persist the config and subscription data. 71*e5aaf047SAppaRao Puli // TODO: subscriptionsMap & configData need to be 72*e5aaf047SAppaRao Puli // written to Persist store. 73*e5aaf047SAppaRao Puli return; 74*e5aaf047SAppaRao Puli } 75*e5aaf047SAppaRao Puli class EventService : public Node 76*e5aaf047SAppaRao Puli { 77*e5aaf047SAppaRao Puli public: 78*e5aaf047SAppaRao Puli EventService(CrowApp& app) : Node(app, "/redfish/v1/EventService/") 79*e5aaf047SAppaRao Puli { 80*e5aaf047SAppaRao Puli initEventSrvStore(); 81*e5aaf047SAppaRao Puli 82*e5aaf047SAppaRao Puli entityPrivileges = { 83*e5aaf047SAppaRao Puli {boost::beast::http::verb::get, {{"Login"}}}, 84*e5aaf047SAppaRao Puli {boost::beast::http::verb::head, {{"Login"}}}, 85*e5aaf047SAppaRao Puli {boost::beast::http::verb::patch, {{"ConfigureManager"}}}, 86*e5aaf047SAppaRao Puli {boost::beast::http::verb::put, {{"ConfigureManager"}}}, 87*e5aaf047SAppaRao Puli {boost::beast::http::verb::delete_, {{"ConfigureManager"}}}, 88*e5aaf047SAppaRao Puli {boost::beast::http::verb::post, {{"ConfigureManager"}}}}; 89*e5aaf047SAppaRao Puli } 90*e5aaf047SAppaRao Puli 91*e5aaf047SAppaRao Puli private: 92*e5aaf047SAppaRao Puli void doGet(crow::Response& res, const crow::Request& req, 93*e5aaf047SAppaRao Puli const std::vector<std::string>& params) override 94*e5aaf047SAppaRao Puli { 95*e5aaf047SAppaRao Puli auto asyncResp = std::make_shared<AsyncResp>(res); 96*e5aaf047SAppaRao Puli res.jsonValue = { 97*e5aaf047SAppaRao Puli {"@odata.type", "#EventService.v1_5_0.EventService"}, 98*e5aaf047SAppaRao Puli {"Id", "EventService"}, 99*e5aaf047SAppaRao Puli {"Name", "Event Service"}, 100*e5aaf047SAppaRao Puli {"ServerSentEventUri", 101*e5aaf047SAppaRao Puli "/redfish/v1/EventService/Subscriptions/SSE"}, 102*e5aaf047SAppaRao Puli {"Subscriptions", 103*e5aaf047SAppaRao Puli {{"@odata.id", "/redfish/v1/EventService/Subscriptions"}}}, 104*e5aaf047SAppaRao Puli {"@odata.id", "/redfish/v1/EventService"}}; 105*e5aaf047SAppaRao Puli 106*e5aaf047SAppaRao Puli asyncResp->res.jsonValue["Status"]["State"] = "Enabled"; 107*e5aaf047SAppaRao Puli asyncResp->res.jsonValue["ServiceEnabled"] = configData.enabled; 108*e5aaf047SAppaRao Puli asyncResp->res.jsonValue["DeliveryRetryAttempts"] = 109*e5aaf047SAppaRao Puli configData.retryAttempts; 110*e5aaf047SAppaRao Puli asyncResp->res.jsonValue["DeliveryRetryIntervalSeconds"] = 111*e5aaf047SAppaRao Puli configData.retryTimeoutInterval; 112*e5aaf047SAppaRao Puli asyncResp->res.jsonValue["EventFormatTypes"] = supportedEvtFormatTypes; 113*e5aaf047SAppaRao Puli asyncResp->res.jsonValue["RegistryPrefixes"] = supportedRegPrefixes; 114*e5aaf047SAppaRao Puli } 115*e5aaf047SAppaRao Puli 116*e5aaf047SAppaRao Puli void doPatch(crow::Response& res, const crow::Request& req, 117*e5aaf047SAppaRao Puli const std::vector<std::string>& params) override 118*e5aaf047SAppaRao Puli { 119*e5aaf047SAppaRao Puli auto asyncResp = std::make_shared<AsyncResp>(res); 120*e5aaf047SAppaRao Puli 121*e5aaf047SAppaRao Puli std::optional<bool> serviceEnabled; 122*e5aaf047SAppaRao Puli std::optional<uint32_t> retryAttemps; 123*e5aaf047SAppaRao Puli std::optional<uint32_t> retryInterval; 124*e5aaf047SAppaRao Puli 125*e5aaf047SAppaRao Puli if (!json_util::readJson(req, res, "ServiceEnabled", serviceEnabled, 126*e5aaf047SAppaRao Puli "DeliveryRetryAttempts", retryAttemps, 127*e5aaf047SAppaRao Puli "DeliveryRetryIntervalSeconds", retryInterval)) 128*e5aaf047SAppaRao Puli { 129*e5aaf047SAppaRao Puli return; 130*e5aaf047SAppaRao Puli } 131*e5aaf047SAppaRao Puli 132*e5aaf047SAppaRao Puli if (serviceEnabled) 133*e5aaf047SAppaRao Puli { 134*e5aaf047SAppaRao Puli configData.enabled = *serviceEnabled; 135*e5aaf047SAppaRao Puli } 136*e5aaf047SAppaRao Puli 137*e5aaf047SAppaRao Puli if (retryAttemps) 138*e5aaf047SAppaRao Puli { 139*e5aaf047SAppaRao Puli // Supported range [1-3] 140*e5aaf047SAppaRao Puli if ((*retryAttemps < 1) || (*retryAttemps > 3)) 141*e5aaf047SAppaRao Puli { 142*e5aaf047SAppaRao Puli messages::queryParameterOutOfRange( 143*e5aaf047SAppaRao Puli asyncResp->res, std::to_string(*retryAttemps), 144*e5aaf047SAppaRao Puli "DeliveryRetryAttempts", "[1-3]"); 145*e5aaf047SAppaRao Puli } 146*e5aaf047SAppaRao Puli else 147*e5aaf047SAppaRao Puli { 148*e5aaf047SAppaRao Puli configData.retryAttempts = *retryAttemps; 149*e5aaf047SAppaRao Puli } 150*e5aaf047SAppaRao Puli } 151*e5aaf047SAppaRao Puli 152*e5aaf047SAppaRao Puli if (retryInterval) 153*e5aaf047SAppaRao Puli { 154*e5aaf047SAppaRao Puli // Supported range [30 - 180] 155*e5aaf047SAppaRao Puli if ((*retryInterval < 30) || (*retryInterval > 180)) 156*e5aaf047SAppaRao Puli { 157*e5aaf047SAppaRao Puli messages::queryParameterOutOfRange( 158*e5aaf047SAppaRao Puli asyncResp->res, std::to_string(*retryInterval), 159*e5aaf047SAppaRao Puli "DeliveryRetryIntervalSeconds", "[30-180]"); 160*e5aaf047SAppaRao Puli } 161*e5aaf047SAppaRao Puli else 162*e5aaf047SAppaRao Puli { 163*e5aaf047SAppaRao Puli configData.retryTimeoutInterval = *retryInterval; 164*e5aaf047SAppaRao Puli } 165*e5aaf047SAppaRao Puli } 166*e5aaf047SAppaRao Puli 167*e5aaf047SAppaRao Puli updateSubscriptionData(); 168*e5aaf047SAppaRao Puli } 169*e5aaf047SAppaRao Puli }; 170*e5aaf047SAppaRao Puli 171*e5aaf047SAppaRao Puli class EventDestinationCollection : public Node 172*e5aaf047SAppaRao Puli { 173*e5aaf047SAppaRao Puli public: 174*e5aaf047SAppaRao Puli EventDestinationCollection(CrowApp& app) : 175*e5aaf047SAppaRao Puli Node(app, "/redfish/v1/EventService/Subscriptions/") 176*e5aaf047SAppaRao Puli { 177*e5aaf047SAppaRao Puli entityPrivileges = { 178*e5aaf047SAppaRao Puli {boost::beast::http::verb::get, {{"Login"}}}, 179*e5aaf047SAppaRao Puli {boost::beast::http::verb::head, {{"Login"}}}, 180*e5aaf047SAppaRao Puli {boost::beast::http::verb::patch, {{"ConfigureManager"}}}, 181*e5aaf047SAppaRao Puli {boost::beast::http::verb::put, {{"ConfigureManager"}}}, 182*e5aaf047SAppaRao Puli {boost::beast::http::verb::delete_, {{"ConfigureManager"}}}, 183*e5aaf047SAppaRao Puli {boost::beast::http::verb::post, {{"ConfigureManager"}}}}; 184*e5aaf047SAppaRao Puli } 185*e5aaf047SAppaRao Puli 186*e5aaf047SAppaRao Puli private: 187*e5aaf047SAppaRao Puli void doGet(crow::Response& res, const crow::Request& req, 188*e5aaf047SAppaRao Puli const std::vector<std::string>& params) override 189*e5aaf047SAppaRao Puli { 190*e5aaf047SAppaRao Puli auto asyncResp = std::make_shared<AsyncResp>(res); 191*e5aaf047SAppaRao Puli 192*e5aaf047SAppaRao Puli res.jsonValue = { 193*e5aaf047SAppaRao Puli {"@odata.type", 194*e5aaf047SAppaRao Puli "#EventDestinationCollection.EventDestinationCollection"}, 195*e5aaf047SAppaRao Puli {"@odata.id", "/redfish/v1/EventService/Subscriptions"}, 196*e5aaf047SAppaRao Puli {"Name", "Event Destination Collections"}}; 197*e5aaf047SAppaRao Puli 198*e5aaf047SAppaRao Puli nlohmann::json& memberArray = asyncResp->res.jsonValue["Members"]; 199*e5aaf047SAppaRao Puli memberArray = nlohmann::json::array(); 200*e5aaf047SAppaRao Puli asyncResp->res.jsonValue["Members@odata.count"] = 201*e5aaf047SAppaRao Puli subscriptionsMap.size(); 202*e5aaf047SAppaRao Puli 203*e5aaf047SAppaRao Puli for (auto& it : subscriptionsMap) 204*e5aaf047SAppaRao Puli { 205*e5aaf047SAppaRao Puli memberArray.push_back( 206*e5aaf047SAppaRao Puli {{"@odata.id", 207*e5aaf047SAppaRao Puli "/redfish/v1/EventService/Subscriptions/" + it.first}}); 208*e5aaf047SAppaRao Puli } 209*e5aaf047SAppaRao Puli } 210*e5aaf047SAppaRao Puli 211*e5aaf047SAppaRao Puli void doPost(crow::Response& res, const crow::Request& req, 212*e5aaf047SAppaRao Puli const std::vector<std::string>& params) override 213*e5aaf047SAppaRao Puli { 214*e5aaf047SAppaRao Puli auto asyncResp = std::make_shared<AsyncResp>(res); 215*e5aaf047SAppaRao Puli 216*e5aaf047SAppaRao Puli if (subscriptionsMap.size() >= maxNoOfSubscriptions) 217*e5aaf047SAppaRao Puli { 218*e5aaf047SAppaRao Puli messages::eventSubscriptionLimitExceeded(asyncResp->res); 219*e5aaf047SAppaRao Puli return; 220*e5aaf047SAppaRao Puli } 221*e5aaf047SAppaRao Puli std::string destUrl; 222*e5aaf047SAppaRao Puli std::string protocol; 223*e5aaf047SAppaRao Puli std::optional<std::string> context; 224*e5aaf047SAppaRao Puli std::optional<std::string> subscriptionType; 225*e5aaf047SAppaRao Puli std::optional<std::string> eventFormatType; 226*e5aaf047SAppaRao Puli std::optional<std::string> retryPolicy; 227*e5aaf047SAppaRao Puli std::optional<std::vector<std::string>> msgIds; 228*e5aaf047SAppaRao Puli std::optional<std::vector<std::string>> regPrefixes; 229*e5aaf047SAppaRao Puli std::optional<std::vector<nlohmann::json>> headers; 230*e5aaf047SAppaRao Puli 231*e5aaf047SAppaRao Puli if (!json_util::readJson( 232*e5aaf047SAppaRao Puli req, res, "Destination", destUrl, "Context", context, 233*e5aaf047SAppaRao Puli "Protocol", protocol, "SubscriptionType", subscriptionType, 234*e5aaf047SAppaRao Puli "EventFormatType", eventFormatType, "HttpHeaders", headers, 235*e5aaf047SAppaRao Puli "RegistryPrefixes", regPrefixes, "MessageIds", msgIds, 236*e5aaf047SAppaRao Puli "DeliveryRetryPolicy", retryPolicy)) 237*e5aaf047SAppaRao Puli { 238*e5aaf047SAppaRao Puli return; 239*e5aaf047SAppaRao Puli } 240*e5aaf047SAppaRao Puli 241*e5aaf047SAppaRao Puli EventSrvSubscription subValue; 242*e5aaf047SAppaRao Puli 243*e5aaf047SAppaRao Puli // Validate the URL using regex expression 244*e5aaf047SAppaRao Puli // Format: <protocol>://<host>:<port>/uri 245*e5aaf047SAppaRao Puli // protocol: http/https, uri: can include params. 246*e5aaf047SAppaRao Puli const std::regex urlRegex("(http|https)://([^/ :]+):?.*"); 247*e5aaf047SAppaRao Puli if (!std::regex_match(destUrl, urlRegex)) 248*e5aaf047SAppaRao Puli { 249*e5aaf047SAppaRao Puli messages::propertyValueFormatError(asyncResp->res, destUrl, 250*e5aaf047SAppaRao Puli "Destination"); 251*e5aaf047SAppaRao Puli return; 252*e5aaf047SAppaRao Puli } 253*e5aaf047SAppaRao Puli subValue.destinationUrl = destUrl; 254*e5aaf047SAppaRao Puli 255*e5aaf047SAppaRao Puli if (subscriptionType) 256*e5aaf047SAppaRao Puli { 257*e5aaf047SAppaRao Puli if (*subscriptionType != "RedfishEvent") 258*e5aaf047SAppaRao Puli { 259*e5aaf047SAppaRao Puli messages::propertyValueNotInList( 260*e5aaf047SAppaRao Puli asyncResp->res, *subscriptionType, "SubscriptionType"); 261*e5aaf047SAppaRao Puli return; 262*e5aaf047SAppaRao Puli } 263*e5aaf047SAppaRao Puli subValue.subscriptionType = *subscriptionType; 264*e5aaf047SAppaRao Puli } 265*e5aaf047SAppaRao Puli else 266*e5aaf047SAppaRao Puli { 267*e5aaf047SAppaRao Puli subValue.subscriptionType = "RedfishEvent"; // Default 268*e5aaf047SAppaRao Puli } 269*e5aaf047SAppaRao Puli 270*e5aaf047SAppaRao Puli if (protocol != "Redfish") 271*e5aaf047SAppaRao Puli { 272*e5aaf047SAppaRao Puli messages::propertyValueNotInList(asyncResp->res, protocol, 273*e5aaf047SAppaRao Puli "Protocol"); 274*e5aaf047SAppaRao Puli return; 275*e5aaf047SAppaRao Puli } 276*e5aaf047SAppaRao Puli subValue.protocol = protocol; 277*e5aaf047SAppaRao Puli 278*e5aaf047SAppaRao Puli if (eventFormatType) 279*e5aaf047SAppaRao Puli { 280*e5aaf047SAppaRao Puli if (std::find(supportedEvtFormatTypes.begin(), 281*e5aaf047SAppaRao Puli supportedEvtFormatTypes.end(), 282*e5aaf047SAppaRao Puli *eventFormatType) == supportedEvtFormatTypes.end()) 283*e5aaf047SAppaRao Puli { 284*e5aaf047SAppaRao Puli messages::propertyValueNotInList( 285*e5aaf047SAppaRao Puli asyncResp->res, *eventFormatType, "EventFormatType"); 286*e5aaf047SAppaRao Puli return; 287*e5aaf047SAppaRao Puli } 288*e5aaf047SAppaRao Puli subValue.eventFormatType = *eventFormatType; 289*e5aaf047SAppaRao Puli } 290*e5aaf047SAppaRao Puli else 291*e5aaf047SAppaRao Puli { 292*e5aaf047SAppaRao Puli // If not specified, use default "Event" 293*e5aaf047SAppaRao Puli subValue.eventFormatType.assign({"Event"}); 294*e5aaf047SAppaRao Puli } 295*e5aaf047SAppaRao Puli 296*e5aaf047SAppaRao Puli if (context) 297*e5aaf047SAppaRao Puli { 298*e5aaf047SAppaRao Puli subValue.customText = *context; 299*e5aaf047SAppaRao Puli } 300*e5aaf047SAppaRao Puli 301*e5aaf047SAppaRao Puli if (headers) 302*e5aaf047SAppaRao Puli { 303*e5aaf047SAppaRao Puli subValue.httpHeaders = *headers; 304*e5aaf047SAppaRao Puli } 305*e5aaf047SAppaRao Puli 306*e5aaf047SAppaRao Puli if (regPrefixes) 307*e5aaf047SAppaRao Puli { 308*e5aaf047SAppaRao Puli for (const std::string& it : *regPrefixes) 309*e5aaf047SAppaRao Puli { 310*e5aaf047SAppaRao Puli if (std::find(supportedRegPrefixes.begin(), 311*e5aaf047SAppaRao Puli supportedRegPrefixes.end(), 312*e5aaf047SAppaRao Puli it) == supportedRegPrefixes.end()) 313*e5aaf047SAppaRao Puli { 314*e5aaf047SAppaRao Puli messages::propertyValueNotInList(asyncResp->res, it, 315*e5aaf047SAppaRao Puli "RegistryPrefixes"); 316*e5aaf047SAppaRao Puli return; 317*e5aaf047SAppaRao Puli } 318*e5aaf047SAppaRao Puli } 319*e5aaf047SAppaRao Puli subValue.registryPrefixes = *regPrefixes; 320*e5aaf047SAppaRao Puli } 321*e5aaf047SAppaRao Puli 322*e5aaf047SAppaRao Puli if (msgIds) 323*e5aaf047SAppaRao Puli { 324*e5aaf047SAppaRao Puli // Do we need to loop-up MessageRegistry and validate 325*e5aaf047SAppaRao Puli // data for authenticity??? Not mandate, i believe. 326*e5aaf047SAppaRao Puli subValue.registryMsgIds = *msgIds; 327*e5aaf047SAppaRao Puli } 328*e5aaf047SAppaRao Puli 329*e5aaf047SAppaRao Puli if (retryPolicy) 330*e5aaf047SAppaRao Puli { 331*e5aaf047SAppaRao Puli if (std::find(supportedRetryPolicies.begin(), 332*e5aaf047SAppaRao Puli supportedRetryPolicies.end(), 333*e5aaf047SAppaRao Puli *retryPolicy) == supportedRetryPolicies.end()) 334*e5aaf047SAppaRao Puli { 335*e5aaf047SAppaRao Puli messages::propertyValueNotInList(asyncResp->res, *retryPolicy, 336*e5aaf047SAppaRao Puli "DeliveryRetryPolicy"); 337*e5aaf047SAppaRao Puli return; 338*e5aaf047SAppaRao Puli } 339*e5aaf047SAppaRao Puli subValue.retryPolicy = *retryPolicy; 340*e5aaf047SAppaRao Puli } 341*e5aaf047SAppaRao Puli else 342*e5aaf047SAppaRao Puli { 343*e5aaf047SAppaRao Puli // Default "TerminateAfterRetries" 344*e5aaf047SAppaRao Puli subValue.retryPolicy = "TerminateAfterRetries"; 345*e5aaf047SAppaRao Puli } 346*e5aaf047SAppaRao Puli 347*e5aaf047SAppaRao Puli std::srand(static_cast<uint32_t>(std::time(0))); 348*e5aaf047SAppaRao Puli std::string id; 349*e5aaf047SAppaRao Puli 350*e5aaf047SAppaRao Puli int retry = 3; 351*e5aaf047SAppaRao Puli while (retry) 352*e5aaf047SAppaRao Puli { 353*e5aaf047SAppaRao Puli id = std::to_string(std::rand()); 354*e5aaf047SAppaRao Puli auto inserted = subscriptionsMap.insert(std::pair(id, subValue)); 355*e5aaf047SAppaRao Puli if (inserted.second) 356*e5aaf047SAppaRao Puli { 357*e5aaf047SAppaRao Puli break; 358*e5aaf047SAppaRao Puli } 359*e5aaf047SAppaRao Puli retry--; 360*e5aaf047SAppaRao Puli }; 361*e5aaf047SAppaRao Puli 362*e5aaf047SAppaRao Puli if (retry <= 0) 363*e5aaf047SAppaRao Puli { 364*e5aaf047SAppaRao Puli messages::internalError(asyncResp->res); 365*e5aaf047SAppaRao Puli return; 366*e5aaf047SAppaRao Puli } 367*e5aaf047SAppaRao Puli 368*e5aaf047SAppaRao Puli updateSubscriptionData(); 369*e5aaf047SAppaRao Puli 370*e5aaf047SAppaRao Puli messages::created(asyncResp->res); 371*e5aaf047SAppaRao Puli asyncResp->res.addHeader( 372*e5aaf047SAppaRao Puli "Location", "/redfish/v1/EventService/Subscriptions/" + id); 373*e5aaf047SAppaRao Puli } 374*e5aaf047SAppaRao Puli }; 375*e5aaf047SAppaRao Puli 376*e5aaf047SAppaRao Puli class EventDestination : public Node 377*e5aaf047SAppaRao Puli { 378*e5aaf047SAppaRao Puli public: 379*e5aaf047SAppaRao Puli EventDestination(CrowApp& app) : 380*e5aaf047SAppaRao Puli Node(app, "/redfish/v1/EventService/Subscriptions/<str>/", 381*e5aaf047SAppaRao Puli std::string()) 382*e5aaf047SAppaRao Puli { 383*e5aaf047SAppaRao Puli entityPrivileges = { 384*e5aaf047SAppaRao Puli {boost::beast::http::verb::get, {{"Login"}}}, 385*e5aaf047SAppaRao Puli {boost::beast::http::verb::head, {{"Login"}}}, 386*e5aaf047SAppaRao Puli {boost::beast::http::verb::patch, {{"ConfigureManager"}}}, 387*e5aaf047SAppaRao Puli {boost::beast::http::verb::put, {{"ConfigureManager"}}}, 388*e5aaf047SAppaRao Puli {boost::beast::http::verb::delete_, {{"ConfigureManager"}}}, 389*e5aaf047SAppaRao Puli {boost::beast::http::verb::post, {{"ConfigureManager"}}}}; 390*e5aaf047SAppaRao Puli } 391*e5aaf047SAppaRao Puli 392*e5aaf047SAppaRao Puli private: 393*e5aaf047SAppaRao Puli void doGet(crow::Response& res, const crow::Request& req, 394*e5aaf047SAppaRao Puli const std::vector<std::string>& params) override 395*e5aaf047SAppaRao Puli { 396*e5aaf047SAppaRao Puli auto asyncResp = std::make_shared<AsyncResp>(res); 397*e5aaf047SAppaRao Puli if (params.size() != 1) 398*e5aaf047SAppaRao Puli { 399*e5aaf047SAppaRao Puli messages::internalError(asyncResp->res); 400*e5aaf047SAppaRao Puli return; 401*e5aaf047SAppaRao Puli } 402*e5aaf047SAppaRao Puli 403*e5aaf047SAppaRao Puli const std::string& id = params[0]; 404*e5aaf047SAppaRao Puli auto obj = subscriptionsMap.find(id); 405*e5aaf047SAppaRao Puli if (obj == subscriptionsMap.end()) 406*e5aaf047SAppaRao Puli { 407*e5aaf047SAppaRao Puli res.result(boost::beast::http::status::not_found); 408*e5aaf047SAppaRao Puli res.end(); 409*e5aaf047SAppaRao Puli return; 410*e5aaf047SAppaRao Puli } 411*e5aaf047SAppaRao Puli 412*e5aaf047SAppaRao Puli EventSrvSubscription& subValue = obj->second; 413*e5aaf047SAppaRao Puli 414*e5aaf047SAppaRao Puli res.jsonValue = { 415*e5aaf047SAppaRao Puli {"@odata.type", "#EventDestination.v1_7_0.EventDestination"}, 416*e5aaf047SAppaRao Puli {"Protocol", "Redfish"}}; 417*e5aaf047SAppaRao Puli asyncResp->res.jsonValue["@odata.id"] = 418*e5aaf047SAppaRao Puli "/redfish/v1/EventService/Subscriptions/" + id; 419*e5aaf047SAppaRao Puli asyncResp->res.jsonValue["Id"] = id; 420*e5aaf047SAppaRao Puli asyncResp->res.jsonValue["Name"] = "Event Destination " + id; 421*e5aaf047SAppaRao Puli asyncResp->res.jsonValue["Destination"] = subValue.destinationUrl; 422*e5aaf047SAppaRao Puli asyncResp->res.jsonValue["Context"] = subValue.customText; 423*e5aaf047SAppaRao Puli asyncResp->res.jsonValue["SubscriptionType"] = 424*e5aaf047SAppaRao Puli subValue.subscriptionType; 425*e5aaf047SAppaRao Puli asyncResp->res.jsonValue["HttpHeaders"] = subValue.httpHeaders; 426*e5aaf047SAppaRao Puli asyncResp->res.jsonValue["EventFormatType"] = subValue.eventFormatType; 427*e5aaf047SAppaRao Puli asyncResp->res.jsonValue["RegistryPrefixes"] = 428*e5aaf047SAppaRao Puli subValue.registryPrefixes; 429*e5aaf047SAppaRao Puli asyncResp->res.jsonValue["MessageIds"] = subValue.registryMsgIds; 430*e5aaf047SAppaRao Puli asyncResp->res.jsonValue["DeliveryRetryPolicy"] = subValue.retryPolicy; 431*e5aaf047SAppaRao Puli } 432*e5aaf047SAppaRao Puli 433*e5aaf047SAppaRao Puli void doPatch(crow::Response& res, const crow::Request& req, 434*e5aaf047SAppaRao Puli const std::vector<std::string>& params) override 435*e5aaf047SAppaRao Puli { 436*e5aaf047SAppaRao Puli auto asyncResp = std::make_shared<AsyncResp>(res); 437*e5aaf047SAppaRao Puli if (params.size() != 1) 438*e5aaf047SAppaRao Puli { 439*e5aaf047SAppaRao Puli messages::internalError(asyncResp->res); 440*e5aaf047SAppaRao Puli return; 441*e5aaf047SAppaRao Puli } 442*e5aaf047SAppaRao Puli 443*e5aaf047SAppaRao Puli const std::string& id = params[0]; 444*e5aaf047SAppaRao Puli auto obj = subscriptionsMap.find(id); 445*e5aaf047SAppaRao Puli if (obj == subscriptionsMap.end()) 446*e5aaf047SAppaRao Puli { 447*e5aaf047SAppaRao Puli res.result(boost::beast::http::status::not_found); 448*e5aaf047SAppaRao Puli res.end(); 449*e5aaf047SAppaRao Puli return; 450*e5aaf047SAppaRao Puli } 451*e5aaf047SAppaRao Puli 452*e5aaf047SAppaRao Puli std::optional<std::string> context; 453*e5aaf047SAppaRao Puli std::optional<std::string> retryPolicy; 454*e5aaf047SAppaRao Puli std::optional<std::vector<nlohmann::json>> headers; 455*e5aaf047SAppaRao Puli 456*e5aaf047SAppaRao Puli if (!json_util::readJson(req, res, "Context", context, 457*e5aaf047SAppaRao Puli "DeliveryRetryPolicy", retryPolicy, 458*e5aaf047SAppaRao Puli "HttpHeaders", headers)) 459*e5aaf047SAppaRao Puli { 460*e5aaf047SAppaRao Puli return; 461*e5aaf047SAppaRao Puli } 462*e5aaf047SAppaRao Puli 463*e5aaf047SAppaRao Puli EventSrvSubscription& subValue = obj->second; 464*e5aaf047SAppaRao Puli 465*e5aaf047SAppaRao Puli if (context) 466*e5aaf047SAppaRao Puli { 467*e5aaf047SAppaRao Puli subValue.customText = *context; 468*e5aaf047SAppaRao Puli } 469*e5aaf047SAppaRao Puli 470*e5aaf047SAppaRao Puli if (headers) 471*e5aaf047SAppaRao Puli { 472*e5aaf047SAppaRao Puli subValue.httpHeaders = *headers; 473*e5aaf047SAppaRao Puli } 474*e5aaf047SAppaRao Puli 475*e5aaf047SAppaRao Puli if (retryPolicy) 476*e5aaf047SAppaRao Puli { 477*e5aaf047SAppaRao Puli if (std::find(supportedRetryPolicies.begin(), 478*e5aaf047SAppaRao Puli supportedRetryPolicies.end(), 479*e5aaf047SAppaRao Puli *retryPolicy) == supportedRetryPolicies.end()) 480*e5aaf047SAppaRao Puli { 481*e5aaf047SAppaRao Puli messages::propertyValueNotInList(asyncResp->res, *retryPolicy, 482*e5aaf047SAppaRao Puli "DeliveryRetryPolicy"); 483*e5aaf047SAppaRao Puli return; 484*e5aaf047SAppaRao Puli } 485*e5aaf047SAppaRao Puli subValue.retryPolicy = *retryPolicy; 486*e5aaf047SAppaRao Puli } 487*e5aaf047SAppaRao Puli 488*e5aaf047SAppaRao Puli updateSubscriptionData(); 489*e5aaf047SAppaRao Puli } 490*e5aaf047SAppaRao Puli 491*e5aaf047SAppaRao Puli void doDelete(crow::Response& res, const crow::Request& req, 492*e5aaf047SAppaRao Puli const std::vector<std::string>& params) override 493*e5aaf047SAppaRao Puli { 494*e5aaf047SAppaRao Puli auto asyncResp = std::make_shared<AsyncResp>(res); 495*e5aaf047SAppaRao Puli 496*e5aaf047SAppaRao Puli if (params.size() != 1) 497*e5aaf047SAppaRao Puli { 498*e5aaf047SAppaRao Puli messages::internalError(asyncResp->res); 499*e5aaf047SAppaRao Puli return; 500*e5aaf047SAppaRao Puli } 501*e5aaf047SAppaRao Puli 502*e5aaf047SAppaRao Puli const std::string& id = params[0]; 503*e5aaf047SAppaRao Puli auto obj = subscriptionsMap.find(id); 504*e5aaf047SAppaRao Puli if (obj == subscriptionsMap.end()) 505*e5aaf047SAppaRao Puli { 506*e5aaf047SAppaRao Puli res.result(boost::beast::http::status::not_found); 507*e5aaf047SAppaRao Puli res.end(); 508*e5aaf047SAppaRao Puli return; 509*e5aaf047SAppaRao Puli } 510*e5aaf047SAppaRao Puli 511*e5aaf047SAppaRao Puli subscriptionsMap.erase(obj); 512*e5aaf047SAppaRao Puli 513*e5aaf047SAppaRao Puli updateSubscriptionData(); 514*e5aaf047SAppaRao Puli } 515*e5aaf047SAppaRao Puli }; 516*e5aaf047SAppaRao Puli 517*e5aaf047SAppaRao Puli } // namespace redfish 518