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