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