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