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