xref: /openbmc/bmcweb/include/ibm/management_console_rest.hpp (revision cb13a39253848ece442971301ade9c09d98bf08e)
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