1 #pragma once 2 #include <app.h> 3 #include <tinyxml2.h> 4 5 #include <async_resp.hpp> 6 #include <boost/algorithm/string.hpp> 7 #include <boost/container/flat_set.hpp> 8 #include <error_messages.hpp> 9 #include <event_service_manager.hpp> 10 #include <ibm/locks.hpp> 11 #include <nlohmann/json.hpp> 12 #include <resource_messages.hpp> 13 #include <sdbusplus/message/types.hpp> 14 #include <utils/json_utils.hpp> 15 16 #include <filesystem> 17 #include <fstream> 18 #include <regex> 19 20 using SType = std::string; 21 using SegmentFlags = std::vector<std::pair<std::string, uint32_t>>; 22 using LockRequest = std::tuple<SType, SType, SType, uint64_t, SegmentFlags>; 23 using LockRequests = std::vector<LockRequest>; 24 using Rc = std::pair<bool, std::variant<uint32_t, LockRequest>>; 25 using RcGetLockList = 26 std::variant<std::string, std::vector<std::pair<uint32_t, LockRequests>>>; 27 using ListOfSessionIds = std::vector<std::string>; 28 namespace crow 29 { 30 namespace ibm_mc 31 { 32 constexpr const char* methodNotAllowedMsg = "Method Not Allowed"; 33 constexpr const char* resourceNotFoundMsg = "Resource Not Found"; 34 constexpr const char* contentNotAcceptableMsg = "Content Not Acceptable"; 35 constexpr const char* internalServerError = "Internal Server Error"; 36 37 constexpr size_t maxSaveareaFileSize = 38 500000; // Allow save area file size upto 500KB 39 constexpr size_t maxBroadcastMsgSize = 40 1000; // Allow Broadcast message size upto 1KB 41 42 bool createSaveAreaPath(crow::Response& res) 43 { 44 // The path /var/lib/obmc will be created by initrdscripts 45 // Create the directories for the save-area files, when we get 46 // first file upload request 47 std::error_code ec; 48 if (!std::filesystem::is_directory("/var/lib/obmc/bmc-console-mgmt", ec)) 49 { 50 std::filesystem::create_directory("/var/lib/obmc/bmc-console-mgmt", ec); 51 } 52 if (ec) 53 { 54 res.result(boost::beast::http::status::internal_server_error); 55 res.jsonValue["Description"] = internalServerError; 56 BMCWEB_LOG_DEBUG 57 << "handleIbmPost: Failed to prepare save-area directory. ec : " 58 << ec; 59 return false; 60 } 61 62 if (!std::filesystem::is_directory( 63 "/var/lib/obmc/bmc-console-mgmt/save-area", ec)) 64 { 65 std::filesystem::create_directory( 66 "/var/lib/obmc/bmc-console-mgmt/save-area", ec); 67 } 68 if (ec) 69 { 70 res.result(boost::beast::http::status::internal_server_error); 71 res.jsonValue["Description"] = internalServerError; 72 BMCWEB_LOG_DEBUG 73 << "handleIbmPost: Failed to prepare save-area directory. ec : " 74 << ec; 75 return false; 76 } 77 return true; 78 } 79 void handleFilePut(const crow::Request& req, crow::Response& res, 80 const std::string& fileID) 81 { 82 // Check the content-type of the request 83 std::string_view contentType = req.getHeaderValue("content-type"); 84 if (boost::starts_with(contentType, "multipart/form-data")) 85 { 86 BMCWEB_LOG_DEBUG 87 << "This is multipart/form-data. Invalid content for PUT"; 88 89 res.result(boost::beast::http::status::not_acceptable); 90 res.jsonValue["Description"] = contentNotAcceptableMsg; 91 return; 92 } 93 else 94 { 95 BMCWEB_LOG_DEBUG << "Not a multipart/form-data. Continue.."; 96 } 97 98 BMCWEB_LOG_DEBUG 99 << "handleIbmPut: Request to create/update the save-area file"; 100 if (!createSaveAreaPath(res)) 101 { 102 res.result(boost::beast::http::status::not_found); 103 res.jsonValue["Description"] = resourceNotFoundMsg; 104 return; 105 } 106 // Create the file 107 std::ofstream file; 108 std::filesystem::path loc("/var/lib/obmc/bmc-console-mgmt/save-area"); 109 loc /= fileID; 110 111 std::string data = std::move(req.body); 112 BMCWEB_LOG_DEBUG << "data capaticty : " << data.capacity(); 113 if (data.capacity() > maxSaveareaFileSize) 114 { 115 res.result(boost::beast::http::status::bad_request); 116 res.jsonValue["Description"] = 117 "File size exceeds maximum allowed size[500KB]"; 118 return; 119 } 120 BMCWEB_LOG_DEBUG << "Writing to the file: " << loc; 121 122 bool fileExists = false; 123 if (std::filesystem::exists(loc)) 124 { 125 fileExists = true; 126 } 127 file.open(loc, std::ofstream::out); 128 if (file.fail()) 129 { 130 BMCWEB_LOG_DEBUG << "Error while opening the file for writing"; 131 res.result(boost::beast::http::status::internal_server_error); 132 res.jsonValue["Description"] = "Error while creating the file"; 133 return; 134 } 135 else 136 { 137 file << data; 138 std::string origin = "/ibm/v1/Host/ConfigFiles/" + fileID; 139 // Push an event 140 if (fileExists) 141 { 142 BMCWEB_LOG_DEBUG << "config file is updated"; 143 res.jsonValue["Description"] = "File Updated"; 144 145 redfish::EventServiceManager::getInstance().sendEvent( 146 redfish::messages::ResourceChanged(), origin, "IBMConfigFile"); 147 } 148 else 149 { 150 BMCWEB_LOG_DEBUG << "config file is created"; 151 res.jsonValue["Description"] = "File Created"; 152 153 redfish::EventServiceManager::getInstance().sendEvent( 154 redfish::messages::ResourceCreated(), origin, "IBMConfigFile"); 155 } 156 } 157 } 158 159 void handleConfigFileList(crow::Response& res) 160 { 161 std::vector<std::string> pathObjList; 162 std::filesystem::path loc("/var/lib/obmc/bmc-console-mgmt/save-area"); 163 if (std::filesystem::exists(loc) && std::filesystem::is_directory(loc)) 164 { 165 for (const auto& file : std::filesystem::directory_iterator(loc)) 166 { 167 std::filesystem::path pathObj(file.path()); 168 pathObjList.push_back("/ibm/v1/Host/ConfigFiles/" + 169 pathObj.filename().string()); 170 } 171 } 172 res.jsonValue["@odata.type"] = "#IBMConfigFile.v1_0_0.IBMConfigFile"; 173 res.jsonValue["@odata.id"] = "/ibm/v1/Host/ConfigFiles/"; 174 res.jsonValue["Id"] = "ConfigFiles"; 175 res.jsonValue["Name"] = "ConfigFiles"; 176 177 res.jsonValue["Members"] = std::move(pathObjList); 178 res.jsonValue["Actions"]["#IBMConfigFiles.DeleteAll"] = { 179 {"target", 180 "/ibm/v1/Host/ConfigFiles/Actions/IBMConfigFiles.DeleteAll"}}; 181 res.end(); 182 } 183 184 void deleteConfigFiles(crow::Response& res) 185 { 186 std::vector<std::string> pathObjList; 187 std::error_code ec; 188 std::filesystem::path loc("/var/lib/obmc/bmc-console-mgmt/save-area"); 189 if (std::filesystem::exists(loc) && std::filesystem::is_directory(loc)) 190 { 191 std::filesystem::remove_all(loc, ec); 192 if (ec) 193 { 194 res.result(boost::beast::http::status::internal_server_error); 195 res.jsonValue["Description"] = internalServerError; 196 BMCWEB_LOG_DEBUG << "deleteConfigFiles: Failed to delete the " 197 "config files directory. ec : " 198 << ec; 199 } 200 } 201 res.end(); 202 } 203 204 void getLockServiceData(crow::Response& res) 205 { 206 res.jsonValue["@odata.type"] = "#LockService.v1_0_0.LockService"; 207 res.jsonValue["@odata.id"] = "/ibm/v1/HMC/LockService/"; 208 res.jsonValue["Id"] = "LockService"; 209 res.jsonValue["Name"] = "LockService"; 210 211 res.jsonValue["Actions"]["#LockService.AcquireLock"] = { 212 {"target", "/ibm/v1/HMC/LockService/Actions/LockService.AcquireLock"}}; 213 res.jsonValue["Actions"]["#LockService.ReleaseLock"] = { 214 {"target", "/ibm/v1/HMC/LockService/Actions/LockService.ReleaseLock"}}; 215 res.jsonValue["Actions"]["#LockService.GetLockList"] = { 216 {"target", "/ibm/v1/HMC/LockService/Actions/LockService.GetLockList"}}; 217 res.end(); 218 } 219 220 void handleFileGet(crow::Response& res, const std::string& fileID) 221 { 222 BMCWEB_LOG_DEBUG << "HandleGet on SaveArea files on path: " << fileID; 223 std::filesystem::path loc("/var/lib/obmc/bmc-console-mgmt/save-area/" + 224 fileID); 225 if (!std::filesystem::exists(loc)) 226 { 227 BMCWEB_LOG_ERROR << loc << "Not found"; 228 res.result(boost::beast::http::status::not_found); 229 res.jsonValue["Description"] = resourceNotFoundMsg; 230 return; 231 } 232 233 std::ifstream readfile(loc.string()); 234 if (!readfile) 235 { 236 BMCWEB_LOG_ERROR << loc.string() << "Not found"; 237 res.result(boost::beast::http::status::not_found); 238 res.jsonValue["Description"] = resourceNotFoundMsg; 239 return; 240 } 241 242 std::string contentDispositionParam = 243 "attachment; filename=\"" + fileID + "\""; 244 res.addHeader("Content-Disposition", contentDispositionParam); 245 std::string fileData; 246 fileData = {std::istreambuf_iterator<char>(readfile), 247 std::istreambuf_iterator<char>()}; 248 res.jsonValue["Data"] = fileData; 249 return; 250 } 251 252 void handleFileDelete(crow::Response& res, const std::string& fileID) 253 { 254 std::string filePath("/var/lib/obmc/bmc-console-mgmt/save-area/" + fileID); 255 BMCWEB_LOG_DEBUG << "Removing the file : " << filePath << "\n"; 256 257 std::ifstream file_open(filePath.c_str()); 258 if (static_cast<bool>(file_open)) 259 if (remove(filePath.c_str()) == 0) 260 { 261 BMCWEB_LOG_DEBUG << "File removed!\n"; 262 res.jsonValue["Description"] = "File Deleted"; 263 } 264 else 265 { 266 BMCWEB_LOG_ERROR << "File not removed!\n"; 267 res.result(boost::beast::http::status::internal_server_error); 268 res.jsonValue["Description"] = internalServerError; 269 } 270 else 271 { 272 BMCWEB_LOG_ERROR << "File not found!\n"; 273 res.result(boost::beast::http::status::not_found); 274 res.jsonValue["Description"] = resourceNotFoundMsg; 275 } 276 return; 277 } 278 279 inline void handleBroadcastService(const crow::Request& req, 280 crow::Response& res) 281 { 282 std::string broadcastMsg; 283 284 if (!redfish::json_util::readJson(req, res, "Message", broadcastMsg)) 285 { 286 BMCWEB_LOG_DEBUG << "Not a Valid JSON"; 287 res.result(boost::beast::http::status::bad_request); 288 return; 289 } 290 if (broadcastMsg.size() > maxBroadcastMsgSize) 291 { 292 BMCWEB_LOG_ERROR << "Message size exceeds maximum allowed size[1KB]"; 293 res.result(boost::beast::http::status::bad_request); 294 return; 295 } 296 redfish::EventServiceManager::getInstance().sendBroadcastMsg(broadcastMsg); 297 res.end(); 298 return; 299 } 300 301 inline void handleFileUrl(const crow::Request& req, crow::Response& res, 302 const std::string& fileID) 303 { 304 if (req.method() == boost::beast::http::verb::put) 305 { 306 handleFilePut(req, res, fileID); 307 res.end(); 308 return; 309 } 310 if (req.method() == boost::beast::http::verb::get) 311 { 312 handleFileGet(res, fileID); 313 res.end(); 314 return; 315 } 316 if (req.method() == boost::beast::http::verb::delete_) 317 { 318 handleFileDelete(res, fileID); 319 res.end(); 320 return; 321 } 322 } 323 324 void handleAcquireLockAPI(const crow::Request& req, crow::Response& res, 325 std::vector<nlohmann::json> body) 326 { 327 LockRequests lockRequestStructure; 328 for (auto& element : body) 329 { 330 std::string lockType; 331 uint64_t resourceId; 332 333 SegmentFlags segInfo; 334 std::vector<nlohmann::json> segmentFlags; 335 336 if (!redfish::json_util::readJson(element, res, "LockType", lockType, 337 "ResourceID", resourceId, 338 "SegmentFlags", segmentFlags)) 339 { 340 BMCWEB_LOG_DEBUG << "Not a Valid JSON"; 341 res.result(boost::beast::http::status::bad_request); 342 res.end(); 343 return; 344 } 345 BMCWEB_LOG_DEBUG << lockType; 346 BMCWEB_LOG_DEBUG << resourceId; 347 348 BMCWEB_LOG_DEBUG << "Segment Flags are present"; 349 350 for (auto& e : segmentFlags) 351 { 352 std::string lockFlags; 353 uint32_t segmentLength; 354 355 if (!redfish::json_util::readJson(e, res, "LockFlag", lockFlags, 356 "SegmentLength", segmentLength)) 357 { 358 res.result(boost::beast::http::status::bad_request); 359 res.end(); 360 return; 361 } 362 363 BMCWEB_LOG_DEBUG << "Lockflag : " << lockFlags; 364 BMCWEB_LOG_DEBUG << "SegmentLength : " << segmentLength; 365 366 segInfo.push_back(std::make_pair(lockFlags, segmentLength)); 367 } 368 lockRequestStructure.push_back( 369 make_tuple(req.session->uniqueId, req.session->clientId, lockType, 370 resourceId, segInfo)); 371 } 372 373 // print lock request into journal 374 375 for (uint32_t i = 0; i < lockRequestStructure.size(); i++) 376 { 377 BMCWEB_LOG_DEBUG << std::get<0>(lockRequestStructure[i]); 378 BMCWEB_LOG_DEBUG << std::get<1>(lockRequestStructure[i]); 379 BMCWEB_LOG_DEBUG << std::get<2>(lockRequestStructure[i]); 380 BMCWEB_LOG_DEBUG << std::get<3>(lockRequestStructure[i]); 381 382 for (const auto& p : std::get<4>(lockRequestStructure[i])) 383 { 384 BMCWEB_LOG_DEBUG << p.first << ", " << p.second; 385 } 386 } 387 388 const LockRequests& t = lockRequestStructure; 389 390 auto varAcquireLock = crow::ibm_mc_lock::Lock::getInstance().acquireLock(t); 391 392 if (varAcquireLock.first) 393 { 394 // Either validity failure of there is a conflict with itself 395 396 auto validityStatus = 397 std::get<std::pair<bool, int>>(varAcquireLock.second); 398 399 if ((!validityStatus.first) && (validityStatus.second == 0)) 400 { 401 BMCWEB_LOG_DEBUG << "Not a Valid record"; 402 BMCWEB_LOG_DEBUG << "Bad json in request"; 403 res.result(boost::beast::http::status::bad_request); 404 res.end(); 405 return; 406 } 407 if (validityStatus.first && (validityStatus.second == 1)) 408 { 409 BMCWEB_LOG_DEBUG << "There is a conflict within itself"; 410 res.result(boost::beast::http::status::bad_request); 411 res.end(); 412 return; 413 } 414 } 415 else 416 { 417 auto conflictStatus = 418 std::get<crow::ibm_mc_lock::Rc>(varAcquireLock.second); 419 if (!conflictStatus.first) 420 { 421 BMCWEB_LOG_DEBUG << "There is no conflict with the locktable"; 422 res.result(boost::beast::http::status::ok); 423 424 auto var = std::get<uint32_t>(conflictStatus.second); 425 nlohmann::json returnJson; 426 returnJson["id"] = var; 427 res.jsonValue["TransactionID"] = var; 428 res.end(); 429 return; 430 } 431 else 432 { 433 BMCWEB_LOG_DEBUG << "There is a conflict with the lock table"; 434 res.result(boost::beast::http::status::conflict); 435 auto var = std::get<std::pair<uint32_t, LockRequest>>( 436 conflictStatus.second); 437 nlohmann::json returnJson, segments; 438 nlohmann::json myarray = nlohmann::json::array(); 439 returnJson["TransactionID"] = var.first; 440 returnJson["SessionID"] = std::get<0>(var.second); 441 returnJson["HMCID"] = std::get<1>(var.second); 442 returnJson["LockType"] = std::get<2>(var.second); 443 returnJson["ResourceID"] = std::get<3>(var.second); 444 445 for (uint32_t i = 0; i < std::get<4>(var.second).size(); i++) 446 { 447 segments["LockFlag"] = std::get<4>(var.second)[i].first; 448 segments["SegmentLength"] = std::get<4>(var.second)[i].second; 449 myarray.push_back(segments); 450 } 451 452 returnJson["SegmentFlags"] = myarray; 453 454 res.jsonValue["Record"] = returnJson; 455 res.end(); 456 return; 457 } 458 } 459 } 460 void handleRelaseAllAPI(const crow::Request& req, crow::Response& res) 461 { 462 crow::ibm_mc_lock::Lock::getInstance().releaseLock(req.session->uniqueId); 463 res.result(boost::beast::http::status::ok); 464 res.end(); 465 return; 466 } 467 468 void handleReleaseLockAPI(const crow::Request& req, crow::Response& res, 469 const std::vector<uint32_t>& listTransactionIds) 470 { 471 BMCWEB_LOG_DEBUG << listTransactionIds.size(); 472 BMCWEB_LOG_DEBUG << "Data is present"; 473 for (uint32_t i = 0; i < listTransactionIds.size(); i++) 474 { 475 BMCWEB_LOG_DEBUG << listTransactionIds[i]; 476 } 477 478 // validate the request ids 479 480 auto varReleaselock = crow::ibm_mc_lock::Lock::getInstance().releaseLock( 481 listTransactionIds, 482 std::make_pair(req.session->clientId, req.session->uniqueId)); 483 484 if (!varReleaselock.first) 485 { 486 // validation Failed 487 res.result(boost::beast::http::status::bad_request); 488 res.end(); 489 return; 490 } 491 else 492 { 493 auto statusRelease = 494 std::get<crow::ibm_mc_lock::RcRelaseLock>(varReleaselock.second); 495 if (statusRelease.first) 496 { 497 // The current hmc owns all the locks, so we already released 498 // them 499 res.result(boost::beast::http::status::ok); 500 res.end(); 501 return; 502 } 503 504 else 505 { 506 // valid rid, but the current hmc does not own all the locks 507 BMCWEB_LOG_DEBUG << "Current HMC does not own all the locks"; 508 res.result(boost::beast::http::status::unauthorized); 509 510 auto var = statusRelease.second; 511 nlohmann::json returnJson, segments; 512 nlohmann::json myArray = nlohmann::json::array(); 513 returnJson["TransactionID"] = var.first; 514 returnJson["SessionID"] = std::get<0>(var.second); 515 returnJson["HMCID"] = std::get<1>(var.second); 516 returnJson["LockType"] = std::get<2>(var.second); 517 returnJson["ResourceID"] = std::get<3>(var.second); 518 519 for (uint32_t i = 0; i < std::get<4>(var.second).size(); i++) 520 { 521 segments["LockFlag"] = std::get<4>(var.second)[i].first; 522 segments["SegmentLength"] = std::get<4>(var.second)[i].second; 523 myArray.push_back(segments); 524 } 525 526 returnJson["SegmentFlags"] = myArray; 527 res.jsonValue["Record"] = returnJson; 528 res.end(); 529 return; 530 } 531 } 532 } 533 534 void handleGetLockListAPI(crow::Response& res, 535 const ListOfSessionIds& listSessionIds) 536 { 537 BMCWEB_LOG_DEBUG << listSessionIds.size(); 538 539 auto status = 540 crow::ibm_mc_lock::Lock::getInstance().getLockList(listSessionIds); 541 auto var = std::get<std::vector<std::pair<uint32_t, LockRequests>>>(status); 542 543 nlohmann::json lockRecords = nlohmann::json::array(); 544 545 for (const auto& transactionId : var) 546 { 547 for (const auto& lockRecord : transactionId.second) 548 { 549 nlohmann::json returnJson; 550 551 returnJson["TransactionID"] = transactionId.first; 552 returnJson["SessionID"] = std::get<0>(lockRecord); 553 returnJson["HMCID"] = std::get<1>(lockRecord); 554 returnJson["LockType"] = std::get<2>(lockRecord); 555 returnJson["ResourceID"] = std::get<3>(lockRecord); 556 557 nlohmann::json segments; 558 nlohmann::json segmentInfoArray = nlohmann::json::array(); 559 560 for (const auto& segment : std::get<4>(lockRecord)) 561 { 562 segments["LockFlag"] = segment.first; 563 segments["SegmentLength"] = segment.second; 564 segmentInfoArray.push_back(segments); 565 } 566 567 returnJson["SegmentFlags"] = segmentInfoArray; 568 lockRecords.push_back(returnJson); 569 } 570 } 571 res.result(boost::beast::http::status::ok); 572 res.jsonValue["Records"] = lockRecords; 573 res.end(); 574 } 575 576 void requestRoutes(App& app) 577 { 578 579 // allowed only for admin 580 BMCWEB_ROUTE(app, "/ibm/v1/") 581 .privileges({"ConfigureComponents", "ConfigureManager"}) 582 .methods(boost::beast::http::verb::get)( 583 [](const crow::Request&, crow::Response& res) { 584 res.jsonValue["@odata.type"] = 585 "#ibmServiceRoot.v1_0_0.ibmServiceRoot"; 586 res.jsonValue["@odata.id"] = "/ibm/v1/"; 587 res.jsonValue["Id"] = "IBM Rest RootService"; 588 res.jsonValue["Name"] = "IBM Service Root"; 589 res.jsonValue["ConfigFiles"] = { 590 {"@odata.id", "/ibm/v1/Host/ConfigFiles"}}; 591 res.jsonValue["LockService"] = { 592 {"@odata.id", "/ibm/v1/HMC/LockService"}}; 593 res.jsonValue["BroadcastService"] = { 594 {"@odata.id", "/ibm/v1/HMC/BroadcastService"}}; 595 res.end(); 596 }); 597 598 BMCWEB_ROUTE(app, "/ibm/v1/Host/ConfigFiles") 599 .privileges({"ConfigureComponents", "ConfigureManager"}) 600 .methods(boost::beast::http::verb::get)( 601 [](const crow::Request&, crow::Response& res) { 602 handleConfigFileList(res); 603 }); 604 605 BMCWEB_ROUTE(app, 606 "/ibm/v1/Host/ConfigFiles/Actions/IBMConfigFiles.DeleteAll") 607 .privileges({"ConfigureComponents", "ConfigureManager"}) 608 .methods(boost::beast::http::verb::post)( 609 [](const crow::Request&, crow::Response& res) { 610 deleteConfigFiles(res); 611 }); 612 613 BMCWEB_ROUTE(app, "/ibm/v1/Host/ConfigFiles/<path>") 614 .privileges({"ConfigureComponents", "ConfigureManager"}) 615 .methods(boost::beast::http::verb::put, boost::beast::http::verb::get, 616 boost::beast::http::verb::delete_)( 617 [](const crow::Request& req, crow::Response& res, 618 const std::string& path) { handleFileUrl(req, res, path); }); 619 620 BMCWEB_ROUTE(app, "/ibm/v1/HMC/LockService") 621 .privileges({"ConfigureComponents", "ConfigureManager"}) 622 .methods(boost::beast::http::verb::get)( 623 [](const crow::Request&, crow::Response& res) { 624 getLockServiceData(res); 625 }); 626 627 BMCWEB_ROUTE(app, "/ibm/v1/HMC/LockService/Actions/LockService.AcquireLock") 628 .privileges({"ConfigureComponents", "ConfigureManager"}) 629 .methods(boost::beast::http::verb::post)( 630 [](const crow::Request& req, crow::Response& res) { 631 std::vector<nlohmann::json> body; 632 if (!redfish::json_util::readJson(req, res, "Request", body)) 633 { 634 BMCWEB_LOG_DEBUG << "Not a Valid JSON"; 635 res.result(boost::beast::http::status::bad_request); 636 res.end(); 637 return; 638 } 639 handleAcquireLockAPI(req, res, body); 640 }); 641 BMCWEB_ROUTE(app, "/ibm/v1/HMC/LockService/Actions/LockService.ReleaseLock") 642 .privileges({"ConfigureComponents", "ConfigureManager"}) 643 .methods(boost::beast::http::verb::post)([](const crow::Request& req, 644 crow::Response& res) { 645 std::string type; 646 std::vector<uint32_t> listTransactionIds; 647 648 if (!redfish::json_util::readJson(req, res, "Type", type, 649 "TransactionIDs", 650 listTransactionIds)) 651 { 652 res.result(boost::beast::http::status::bad_request); 653 res.end(); 654 return; 655 } 656 if (type == "Transaction") 657 { 658 handleReleaseLockAPI(req, res, listTransactionIds); 659 } 660 else if (type == "Session") 661 { 662 handleRelaseAllAPI(req, res); 663 } 664 else 665 { 666 BMCWEB_LOG_DEBUG << " Value of Type : " << type 667 << "is Not a Valid key"; 668 redfish::messages::propertyValueNotInList(res, type, "Type"); 669 } 670 }); 671 BMCWEB_ROUTE(app, "/ibm/v1/HMC/LockService/Actions/LockService.GetLockList") 672 .privileges({"ConfigureComponents", "ConfigureManager"}) 673 .methods(boost::beast::http::verb::post)( 674 [](const crow::Request& req, crow::Response& res) { 675 ListOfSessionIds listSessionIds; 676 677 if (!redfish::json_util::readJson(req, res, "SessionIDs", 678 listSessionIds)) 679 { 680 res.result(boost::beast::http::status::bad_request); 681 res.end(); 682 return; 683 } 684 handleGetLockListAPI(res, listSessionIds); 685 }); 686 687 BMCWEB_ROUTE(app, "/ibm/v1/HMC/BroadcastService") 688 .privileges({"ConfigureComponents", "ConfigureManager"}) 689 .methods(boost::beast::http::verb::post)( 690 [](const crow::Request& req, crow::Response& res) { 691 handleBroadcastService(req, res); 692 }); 693 } 694 695 } // namespace ibm_mc 696 } // namespace crow 697