diff options
-rw-r--r-- | include/ibm/locks.hpp | 610 | ||||
-rw-r--r-- | include/ibm/management_console_rest.hpp | 339 | ||||
-rw-r--r-- | include/sessions.hpp | 10 | ||||
-rw-r--r-- | meson.build | 1 | ||||
-rw-r--r-- | src/webserver_run.cpp | 1 | ||||
-rw-r--r-- | test/include/ibm/lock_test.cpp | 314 |
6 files changed, 1 insertions, 1274 deletions
diff --git a/include/ibm/locks.hpp b/include/ibm/locks.hpp deleted file mode 100644 index 3bb82b9479..0000000000 --- a/include/ibm/locks.hpp +++ /dev/null @@ -1,610 +0,0 @@ -#pragma once - -#include "ibm/utils.hpp" -#include "logging.hpp" - -#include <boost/container/flat_map.hpp> -#include <boost/endian/conversion.hpp> -#include <nlohmann/json.hpp> - -#include <filesystem> -#include <fstream> -#include <variant> - -namespace crow -{ -namespace ibm_mc_lock -{ - -using SType = std::string; - -/*---------------------------------------- -|Segment flags : LockFlag | SegmentLength| -------------------------------------------*/ - -using SegmentFlags = std::vector<std::pair<SType, uint32_t>>; - -// Lockrequest = session-id | hmc-id | locktype | resourceid | segmentinfo -using LockRequest = std::tuple<SType, SType, SType, uint64_t, SegmentFlags>; -using LockRequests = std::vector<LockRequest>; -using Rc = - std::pair<bool, std::variant<uint32_t, std::pair<uint32_t, LockRequest>>>; -using RcRelaseLock = std::pair<bool, std::pair<uint32_t, LockRequest>>; -using RcGetLockList = - std::variant<std::string, std::vector<std::pair<uint32_t, LockRequests>>>; -using ListOfTransactionIds = std::vector<uint32_t>; -using RcAcquireLock = std::pair<bool, std::variant<Rc, std::pair<bool, int>>>; -using RcReleaseLockApi = std::pair<bool, std::variant<bool, RcRelaseLock>>; -using SessionFlags = std::pair<SType, SType>; -using ListOfSessionIds = std::vector<std::string>; - -class Lock -{ - uint32_t transactionId = 0; - boost::container::flat_map<uint32_t, LockRequests> lockTable; - - protected: - /* - * This function implements the logic for validating an incoming - * lock request/requests. - * - * Returns : True (if Valid) - * Returns : False (if not a Valid lock request) - */ - - virtual bool isValidLockRequest(const LockRequest& refLockRecord); - - /* - * This function implements the logic of checking if the incoming - * multi-lock request is not having conflicting requirements. - * - * Returns : True (if conflicting) - * Returns : False (if not conflicting) - */ - - virtual bool isConflictRequest(const LockRequests& refLockRequestStructure); - /* - * Implements the core algorithm to find the conflicting - * lock requests. - * - * This functions takes two lock requests and check if both - * are conflicting to each other. - * - * Returns : True (if conflicting) - * Returns : False (if not conflicting) - */ - virtual bool isConflictRecord(const LockRequest& refLockRecord1, - const LockRequest& refLockRecord2); - - /* - * This function implements the logic of checking the conflicting - * locks from a incoming single/multi lock requests with the already - * existing lock request in the lock table. - * - */ - - virtual Rc isConflictWithTable(const LockRequests& refLockRequestStructure); - /* - * This function implements the logic of checking the ownership of the - * lock from the releaselock request. - * - * Returns : True (if the requesting HMC & Session owns the lock(s)) - * Returns : False (if the request HMC or Session does not own the lock(s)) - */ - - virtual RcRelaseLock isItMyLock(const ListOfTransactionIds& refRids, - const SessionFlags& ids); - - /* - * This function validates the the list of transactionID's and returns false - * if the transaction ID is not valid & not present in the lock table - */ - - virtual bool validateRids(const ListOfTransactionIds& refRids); - - /* - * This function releases the locks that are already obtained by the - * requesting Management console. - */ - - void releaseLock(const ListOfTransactionIds& refRids); - - Lock() - { - transactionId = lockTable.empty() ? 0 : prev(lockTable.end())->first; - } - - /* - * This function implements the algorithm for checking the respective - * bytes of the resource id based on the lock management algorithm. - */ - - static bool checkByte(uint64_t resourceId1, uint64_t resourceId2, - uint32_t position); - - /* - * This functions implements a counter that generates a unique 32 bit - * number for every successful transaction. This number will be used by - * the Management Console for debug. - */ - virtual uint32_t generateTransactionId(); - - public: - /* - * Explicitly deleted copy and move constructors - */ - Lock(const Lock&) = delete; - Lock(Lock&&) = delete; - Lock& operator=(const Lock&) = delete; - Lock& operator=(Lock&&) = delete; - - /* - * This function implements the logic for acquiring a lock on a - * resource if the incoming request is legitimate without any - * conflicting requirements & without any conflicting requirement - * with the existing locks in the lock table. - * - */ - - RcAcquireLock acquireLock(const LockRequests& lockRequestStructure); - - /* - * This function implements the logic for releasing the lock that are - * owned by a management console session. - * - * The locks can be released by two ways - * - Using list of transaction ID's - * - Using a Session ID - * - * Client can choose either of the ways by using `Type` JSON key. - * - */ - RcReleaseLockApi releaseLock(const ListOfTransactionIds& p, - const SessionFlags& ids); - - /* - * This function implements the logic for getting the list of locks obtained - * by a particular management console. - */ - RcGetLockList getLockList(const ListOfSessionIds& listSessionId); - - /* - * This function is releases all the locks obtained by a particular - * session. - */ - - void releaseLock(const std::string& sessionId); - - static Lock& getInstance() - { - static Lock lockObject; - return lockObject; - } - - virtual ~Lock() = default; -}; - -inline RcGetLockList Lock::getLockList(const ListOfSessionIds& listSessionId) -{ - std::vector<std::pair<uint32_t, LockRequests>> lockList{}; - - if (!lockTable.empty()) - { - for (const auto& i : listSessionId) - { - auto it = lockTable.begin(); - while (it != lockTable.end()) - { - // Check if session id of this entry matches with session id - // given - if (std::get<0>(it->second[0]) == i) - { - BMCWEB_LOG_DEBUG("Session id is found in the locktable"); - - // Push the whole lock record into a vector for returning - // the json - lockList.emplace_back(it->first, it->second); - } - // Go to next entry in map - it++; - } - } - } - // we may have found at least one entry with the given session id - // return the json list of lock records pertaining to the given - // session id, or send an empty list if lock table is empty - return {lockList}; -} - -inline RcReleaseLockApi Lock::releaseLock(const ListOfTransactionIds& p, - const SessionFlags& ids) -{ - bool status = validateRids(p); - - if (!status) - { - // Validation of rids failed - BMCWEB_LOG_ERROR("releaseLock: Contains invalid request id"); - return std::make_pair(false, status); - } - // Validation passed, check if all the locks are owned by the - // requesting HMC - auto status2 = isItMyLock(p, ids); - if (!status2.first) - { - return std::make_pair(false, status2); - } - return std::make_pair(true, status2); -} - -inline RcAcquireLock Lock::acquireLock(const LockRequests& lockRequestStructure) -{ - // validate the lock request - - for (const auto& lockRecord : lockRequestStructure) - { - bool status = isValidLockRequest(lockRecord); - if (!status) - { - BMCWEB_LOG_DEBUG("Not a Valid record"); - BMCWEB_LOG_DEBUG("Bad json in request"); - return std::make_pair(true, std::make_pair(status, 0)); - } - } - // check for conflict record - - const LockRequests& multiRequest = lockRequestStructure; - bool status = isConflictRequest(multiRequest); - - if (status) - { - BMCWEB_LOG_DEBUG("There is a conflict within itself"); - return std::make_pair(true, std::make_pair(status, 1)); - } - BMCWEB_LOG_DEBUG("The request is not conflicting within itself"); - - // Need to check for conflict with the locktable entries. - - auto conflict = isConflictWithTable(multiRequest); - - BMCWEB_LOG_DEBUG("Done with checking conflict with the locktable"); - return std::make_pair(false, conflict); -} - -inline void Lock::releaseLock(const std::string& sessionId) -{ - if (!lockTable.empty()) - { - auto it = lockTable.begin(); - while (it != lockTable.end()) - { - if (!it->second.empty()) - { - // Check if session id of this entry matches with session id - // given - if (std::get<0>(it->second[0]) == sessionId) - { - BMCWEB_LOG_DEBUG("Remove the lock from the locktable " - "having sessionID={}", - sessionId); - BMCWEB_LOG_DEBUG("TransactionID ={}", it->first); - it = lockTable.erase(it); - } - else - { - it++; - } - } - } - } -} -inline RcRelaseLock Lock::isItMyLock(const ListOfTransactionIds& refRids, - const SessionFlags& ids) -{ - for (const auto& id : refRids) - { - // Just need to compare the client id of the first lock records in the - // complete lock row(in the map), because the rest of the lock records - // would have the same client id - - std::string expectedClientId = std::get<1>(lockTable[id][0]); - std::string expectedSessionId = std::get<0>(lockTable[id][0]); - - if ((expectedClientId == ids.first) && - (expectedSessionId == ids.second)) - { - // It is owned by the currently request hmc - BMCWEB_LOG_DEBUG("Lock is owned by the current hmc"); - // remove the lock - if (lockTable.erase(id) != 0U) - { - BMCWEB_LOG_DEBUG("Removing the locks with transaction ID : {}", - id); - } - else - { - BMCWEB_LOG_ERROR("Removing the locks from the lock table " - "failed, transaction ID: {}", - id); - } - } - else - { - BMCWEB_LOG_DEBUG("Lock is not owned by the current hmc"); - return std::make_pair(false, std::make_pair(id, lockTable[id][0])); - } - } - return std::make_pair(true, std::make_pair(0, LockRequest())); -} - -inline bool Lock::validateRids(const ListOfTransactionIds& refRids) -{ - for (const auto& id : refRids) - { - auto search = lockTable.find(id); - - if (search != lockTable.end()) - { - BMCWEB_LOG_DEBUG("Valid Transaction id"); - // continue for the next rid - } - else - { - BMCWEB_LOG_ERROR("validateRids: At least 1 inValid Request id: {}", - id); - return false; - } - } - return true; -} - -inline bool Lock::isValidLockRequest(const LockRequest& refLockRecord) -{ - // validate the locktype - - if (!((std::get<2>(refLockRecord) == "Read" || - (std::get<2>(refLockRecord) == "Write")))) - { - BMCWEB_LOG_DEBUG("Validation of LockType Failed"); - BMCWEB_LOG_DEBUG("Locktype : {}", std::get<2>(refLockRecord)); - return false; - } - - BMCWEB_LOG_DEBUG("{}", static_cast<int>(std::get<4>(refLockRecord).size())); - - // validate the number of segments - // Allowed No of segments are between 2 and 6 - if ((static_cast<int>(std::get<4>(refLockRecord).size()) > 6) || - (static_cast<int>(std::get<4>(refLockRecord).size()) < 2)) - { - BMCWEB_LOG_DEBUG("Validation of Number of Segments Failed"); - BMCWEB_LOG_DEBUG("Number of Segments provided : {}", - std::get<4>(refLockRecord).size()); - return false; - } - - int lockFlag = 0; - // validate the lockflags & segment length - - for (const auto& p : std::get<4>(refLockRecord)) - { - // validate the lock flags - // Allowed lockflags are locksame,lockall & dontlock - - if (!((p.first == "LockSame" || (p.first == "LockAll") || - (p.first == "DontLock")))) - { - BMCWEB_LOG_DEBUG("Validation of lock flags failed"); - BMCWEB_LOG_DEBUG("{}", p.first); - return false; - } - - // validate the segment length - // Allowed values of segment length are between 1 and 4 - - if (p.second < 1 || p.second > 4) - { - BMCWEB_LOG_DEBUG("Validation of Segment Length Failed"); - BMCWEB_LOG_DEBUG("{}", p.second); - return false; - } - - if ((p.first == "LockSame" || (p.first == "LockAll"))) - { - ++lockFlag; - if (lockFlag >= 2) - { - return false; - } - } - } - - return true; -} - -inline Rc Lock::isConflictWithTable(const LockRequests& refLockRequestStructure) -{ - if (lockTable.empty()) - { - uint32_t thisTransactionId = generateTransactionId(); - BMCWEB_LOG_DEBUG("{}", thisTransactionId); - // Lock table is empty, so we are safe to add the lockrecords - // as there will be no conflict - BMCWEB_LOG_DEBUG("Lock table is empty, so adding the lockrecords"); - lockTable.emplace(thisTransactionId, refLockRequestStructure); - - return std::make_pair(false, thisTransactionId); - } - BMCWEB_LOG_DEBUG( - "Lock table is not empty, check for conflict with lock table"); - // Lock table is not empty, compare the lockrequest entries with - // the entries in the lock table - - for (const auto& lockRecord1 : refLockRequestStructure) - { - for (const auto& map : lockTable) - { - for (const auto& lockRecord2 : map.second) - { - bool status = isConflictRecord(lockRecord1, lockRecord2); - if (status) - { - return std::make_pair( - true, std::make_pair(map.first, lockRecord2)); - } - } - } - } - - // Reached here, so no conflict with the locktable, so we are safe to - // add the request records into the lock table - - // Lock table is empty, so we are safe to add the lockrecords - // as there will be no conflict - BMCWEB_LOG_DEBUG(" Adding elements into lock table"); - transactionId = generateTransactionId(); - lockTable.emplace(std::make_pair(transactionId, refLockRequestStructure)); - - return std::make_pair(false, transactionId); -} - -inline bool Lock::isConflictRequest(const LockRequests& refLockRequestStructure) -{ - // check for all the locks coming in as a part of single request - // return conflict if any two lock requests are conflicting - - if (refLockRequestStructure.size() == 1) - { - BMCWEB_LOG_DEBUG("Only single lock request, so there is no conflict"); - // This means , we have only one lock request in the current - // request , so no conflict within the request - return false; - } - - BMCWEB_LOG_DEBUG( - "There are multiple lock requests coming in a single request"); - - // There are multiple requests a part of one request - - for (uint32_t i = 0; i < refLockRequestStructure.size(); i++) - { - for (uint32_t j = i + 1; j < refLockRequestStructure.size(); j++) - { - const LockRequest& p = refLockRequestStructure[i]; - const LockRequest& q = refLockRequestStructure[j]; - bool status = isConflictRecord(p, q); - - if (status) - { - return true; - } - } - } - return false; -} - -// This function converts the provided uint64_t resource id's from the two -// lock requests subjected for comparison, and this function also compares -// the content by bytes mentioned by a uint32_t number. - -// If all the elements in the lock requests which are subjected for comparison -// are same, then the last comparison would be to check for the respective -// bytes in the resourceid based on the segment length. -inline bool Lock::checkByte(uint64_t resourceId1, uint64_t resourceId2, - uint32_t position) -{ - if (position >= sizeof(resourceId1)) - { - return false; - } - - uint8_t pPosition = 0; - uint8_t qPosition = 0; - pPosition = 0xFF & (resourceId1 >> (8 * position)); - qPosition = 0xFF & (resourceId2 >> (8 * position)); - - return pPosition == qPosition; -} - -inline bool Lock::isConflictRecord(const LockRequest& refLockRecord1, - const LockRequest& refLockRecord2) -{ - // No conflict if both are read locks - - if (std::get<2>(refLockRecord1) == "Read" && - std::get<2>(refLockRecord2) == "Read") - { - BMCWEB_LOG_DEBUG("Both are read locks, no conflict"); - return false; - } - - uint32_t i = 0; - for (const auto& p : std::get<4>(refLockRecord1)) - { - // return conflict when any of them is try to lock all resources - // under the current resource level. - if (p.first == "LockAll" || - std::get<4>(refLockRecord2)[i].first == "LockAll") - { - BMCWEB_LOG_DEBUG( - "Either of the Comparing locks are trying to lock all " - "resources under the current resource level"); - return true; - } - - // determine if there is a lock-all-with-same-segment-size. - // If the current segment sizes are the same,then we should fail. - - if ((p.first == "LockSame" || - std::get<4>(refLockRecord2)[i].first == "LockSame") && - (p.second == std::get<4>(refLockRecord2)[i].second)) - { - return true; - } - - // if segment lengths are not the same, it means two different locks - // So no conflict - if (p.second != std::get<4>(refLockRecord2)[i].second) - { - BMCWEB_LOG_DEBUG("Segment lengths are not same"); - BMCWEB_LOG_DEBUG("Segment 1 length : {}", p.second); - BMCWEB_LOG_DEBUG("Segment 2 length : {}", - std::get<4>(refLockRecord2)[i].second); - return false; - } - - // compare segment data - - for (uint32_t j = 0; j < p.second; j++) - { - // if the segment data is different, then the locks is on a - // different resource so no conflict between the lock - // records. - // BMC is little endian, but the resourceID is formed by - // the Management Console in such a way that, the first byte - // from the MSB Position corresponds to the First Segment - // data. Therefore we need to convert the incoming - // resourceID into Big Endian before processing further. - if (!(checkByte( - boost::endian::endian_reverse(std::get<3>(refLockRecord1)), - boost::endian::endian_reverse(std::get<3>(refLockRecord2)), - j))) - { - return false; - } - } - - ++i; - } - - return true; -} - -inline uint32_t Lock::generateTransactionId() -{ - ++transactionId; - return transactionId; -} - -} // namespace ibm_mc_lock -} // namespace crow diff --git a/include/ibm/management_console_rest.hpp b/include/ibm/management_console_rest.hpp index ec8d4d653d..51437c9ac0 100644 --- a/include/ibm/management_console_rest.hpp +++ b/include/ibm/management_console_rest.hpp @@ -4,7 +4,7 @@ #include "async_resp.hpp" #include "error_messages.hpp" #include "event_service_manager.hpp" -#include "ibm/locks.hpp" +#include "ibm/utils.hpp" #include "resource_messages.hpp" #include "str_utility.hpp" #include "utils/json_utils.hpp" @@ -16,14 +16,6 @@ #include <filesystem> #include <fstream> -using SType = std::string; -using SegmentFlags = std::vector<std::pair<std::string, uint32_t>>; -using LockRequest = std::tuple<SType, SType, SType, uint64_t, SegmentFlags>; -using LockRequests = std::vector<LockRequest>; -using Rc = std::pair<bool, std::variant<uint32_t, LockRequest>>; -using RcGetLockList = - std::variant<std::string, std::vector<std::pair<uint32_t, LockRequests>>>; -using ListOfSessionIds = std::vector<std::string>; namespace crow { namespace ibm_mc @@ -277,22 +269,6 @@ inline void } } -inline void - getLockServiceData(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) -{ - asyncResp->res.jsonValue["@odata.type"] = "#LockService.v1_0_0.LockService"; - asyncResp->res.jsonValue["@odata.id"] = "/ibm/v1/HMC/LockService/"; - asyncResp->res.jsonValue["Id"] = "LockService"; - asyncResp->res.jsonValue["Name"] = "LockService"; - - asyncResp->res.jsonValue["Actions"]["#LockService.AcquireLock"] = { - {"target", "/ibm/v1/HMC/LockService/Actions/LockService.AcquireLock"}}; - asyncResp->res.jsonValue["Actions"]["#LockService.ReleaseLock"] = { - {"target", "/ibm/v1/HMC/LockService/Actions/LockService.ReleaseLock"}}; - asyncResp->res.jsonValue["Actions"]["#LockService.GetLockList"] = { - {"target", "/ibm/v1/HMC/LockService/Actions/LockService.GetLockList"}}; -} - inline void handleFileGet(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, const std::string& fileID) { @@ -399,248 +375,6 @@ inline void handleFileUrl(const crow::Request& req, } } -inline void - handleAcquireLockAPI(const crow::Request& req, - const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, - std::vector<nlohmann::json::object_t> body) -{ - LockRequests lockRequestStructure; - for (auto& element : body) - { - std::string lockType; - uint64_t resourceId = 0; - - SegmentFlags segInfo; - std::vector<nlohmann::json::object_t> segmentFlags; - - if (!redfish::json_util::readJsonObject( - element, asyncResp->res, "LockType", lockType, "ResourceID", - resourceId, "SegmentFlags", segmentFlags)) - { - BMCWEB_LOG_DEBUG("Not a Valid JSON"); - asyncResp->res.result(boost::beast::http::status::bad_request); - return; - } - BMCWEB_LOG_DEBUG("{}", lockType); - BMCWEB_LOG_DEBUG("{}", resourceId); - - BMCWEB_LOG_DEBUG("Segment Flags are present"); - - for (auto& e : segmentFlags) - { - std::string lockFlags; - uint32_t segmentLength = 0; - - if (!redfish::json_util::readJsonObject( - e, asyncResp->res, "LockFlag", lockFlags, "SegmentLength", - segmentLength)) - { - asyncResp->res.result(boost::beast::http::status::bad_request); - return; - } - - BMCWEB_LOG_DEBUG("Lockflag : {}", lockFlags); - BMCWEB_LOG_DEBUG("SegmentLength : {}", segmentLength); - - segInfo.emplace_back(std::make_pair(lockFlags, segmentLength)); - } - - lockRequestStructure.emplace_back(make_tuple( - req.session->uniqueId, req.session->clientId.value_or(""), lockType, - resourceId, segInfo)); - } - - // print lock request into journal - - for (auto& i : lockRequestStructure) - { - BMCWEB_LOG_DEBUG("{}", std::get<0>(i)); - BMCWEB_LOG_DEBUG("{}", std::get<1>(i)); - BMCWEB_LOG_DEBUG("{}", std::get<2>(i)); - BMCWEB_LOG_DEBUG("{}", std::get<3>(i)); - - for (const auto& p : std::get<4>(i)) - { - BMCWEB_LOG_DEBUG("{}, {}", p.first, p.second); - } - } - - const LockRequests& t = lockRequestStructure; - - auto varAcquireLock = crow::ibm_mc_lock::Lock::getInstance().acquireLock(t); - - if (varAcquireLock.first) - { - // Either validity failure of there is a conflict with itself - - auto validityStatus = - std::get<std::pair<bool, int>>(varAcquireLock.second); - - if ((!validityStatus.first) && (validityStatus.second == 0)) - { - BMCWEB_LOG_DEBUG("Not a Valid record"); - BMCWEB_LOG_DEBUG("Bad json in request"); - asyncResp->res.result(boost::beast::http::status::bad_request); - return; - } - if (validityStatus.first && (validityStatus.second == 1)) - { - BMCWEB_LOG_ERROR("There is a conflict within itself"); - asyncResp->res.result(boost::beast::http::status::conflict); - return; - } - } - else - { - auto conflictStatus = - std::get<crow::ibm_mc_lock::Rc>(varAcquireLock.second); - if (!conflictStatus.first) - { - BMCWEB_LOG_DEBUG("There is no conflict with the locktable"); - asyncResp->res.result(boost::beast::http::status::ok); - - auto var = std::get<uint32_t>(conflictStatus.second); - nlohmann::json returnJson; - returnJson["id"] = var; - asyncResp->res.jsonValue["TransactionID"] = var; - return; - } - BMCWEB_LOG_DEBUG("There is a conflict with the lock table"); - asyncResp->res.result(boost::beast::http::status::conflict); - auto var = - std::get<std::pair<uint32_t, LockRequest>>(conflictStatus.second); - nlohmann::json returnJson; - nlohmann::json segments; - nlohmann::json myarray = nlohmann::json::array(); - returnJson["TransactionID"] = var.first; - returnJson["SessionID"] = std::get<0>(var.second); - returnJson["HMCID"] = std::get<1>(var.second); - returnJson["LockType"] = std::get<2>(var.second); - returnJson["ResourceID"] = std::get<3>(var.second); - - for (const auto& i : std::get<4>(var.second)) - { - segments["LockFlag"] = i.first; - segments["SegmentLength"] = i.second; - myarray.push_back(segments); - } - - returnJson["SegmentFlags"] = myarray; - BMCWEB_LOG_ERROR("Conflicting lock record: {}", returnJson); - asyncResp->res.jsonValue["Record"] = returnJson; - return; - } -} -inline void - handleRelaseAllAPI(const crow::Request& req, - const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) -{ - crow::ibm_mc_lock::Lock::getInstance().releaseLock(req.session->uniqueId); - asyncResp->res.result(boost::beast::http::status::ok); -} - -inline void - handleReleaseLockAPI(const crow::Request& req, - const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, - const std::vector<uint32_t>& listTransactionIds) -{ - BMCWEB_LOG_DEBUG("{}", listTransactionIds.size()); - BMCWEB_LOG_DEBUG("Data is present"); - for (unsigned int listTransactionId : listTransactionIds) - { - BMCWEB_LOG_DEBUG("{}", listTransactionId); - } - - // validate the request ids - - auto varReleaselock = crow::ibm_mc_lock::Lock::getInstance().releaseLock( - listTransactionIds, std::make_pair(req.session->clientId.value_or(""), - req.session->uniqueId)); - - if (!varReleaselock.first) - { - // validation Failed - BMCWEB_LOG_ERROR("handleReleaseLockAPI: validation failed"); - asyncResp->res.result(boost::beast::http::status::bad_request); - return; - } - auto statusRelease = - std::get<crow::ibm_mc_lock::RcRelaseLock>(varReleaselock.second); - if (statusRelease.first) - { - // The current hmc owns all the locks, so we already released - // them - return; - } - - // valid rid, but the current hmc does not own all the locks - BMCWEB_LOG_DEBUG("Current HMC does not own all the locks"); - asyncResp->res.result(boost::beast::http::status::unauthorized); - - auto var = statusRelease.second; - nlohmann::json returnJson; - nlohmann::json segments; - nlohmann::json myArray = nlohmann::json::array(); - returnJson["TransactionID"] = var.first; - returnJson["SessionID"] = std::get<0>(var.second); - returnJson["HMCID"] = std::get<1>(var.second); - returnJson["LockType"] = std::get<2>(var.second); - returnJson["ResourceID"] = std::get<3>(var.second); - - for (const auto& i : std::get<4>(var.second)) - { - segments["LockFlag"] = i.first; - segments["SegmentLength"] = i.second; - myArray.push_back(segments); - } - - returnJson["SegmentFlags"] = myArray; - BMCWEB_LOG_DEBUG("handleReleaseLockAPI: lockrecord: {}", returnJson); - asyncResp->res.jsonValue["Record"] = returnJson; -} - -inline void - handleGetLockListAPI(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, - const ListOfSessionIds& listSessionIds) -{ - BMCWEB_LOG_DEBUG("{}", listSessionIds.size()); - - auto status = - crow::ibm_mc_lock::Lock::getInstance().getLockList(listSessionIds); - auto var = std::get<std::vector<std::pair<uint32_t, LockRequests>>>(status); - - nlohmann::json lockRecords = nlohmann::json::array(); - - for (const auto& transactionId : var) - { - for (const auto& lockRecord : transactionId.second) - { - nlohmann::json returnJson; - - returnJson["TransactionID"] = transactionId.first; - returnJson["SessionID"] = std::get<0>(lockRecord); - returnJson["HMCID"] = std::get<1>(lockRecord); - returnJson["LockType"] = std::get<2>(lockRecord); - returnJson["ResourceID"] = std::get<3>(lockRecord); - - nlohmann::json segments; - nlohmann::json segmentInfoArray = nlohmann::json::array(); - - for (const auto& segment : std::get<4>(lockRecord)) - { - segments["LockFlag"] = segment.first; - segments["SegmentLength"] = segment.second; - segmentInfoArray.push_back(segments); - } - - returnJson["SegmentFlags"] = segmentInfoArray; - lockRecords.push_back(returnJson); - } - } - asyncResp->res.result(boost::beast::http::status::ok); - asyncResp->res.jsonValue["Records"] = lockRecords; -} - inline bool isValidConfigFileName(const std::string& fileName, crow::Response& res) { @@ -690,8 +424,6 @@ inline void requestRoutes(App& app) asyncResp->res.jsonValue["Name"] = "IBM Service Root"; asyncResp->res.jsonValue["ConfigFiles"]["@odata.id"] = "/ibm/v1/Host/ConfigFiles"; - asyncResp->res.jsonValue["LockService"]["@odata.id"] = - "/ibm/v1/HMC/LockService"; asyncResp->res.jsonValue["BroadcastService"]["@odata.id"] = "/ibm/v1/HMC/BroadcastService"; }); @@ -730,75 +462,6 @@ inline void requestRoutes(App& app) handleFileUrl(req, asyncResp, fileName); }); - BMCWEB_ROUTE(app, "/ibm/v1/HMC/LockService") - .privileges({{"ConfigureComponents", "ConfigureManager"}}) - .methods(boost::beast::http::verb::get)( - [](const crow::Request&, - const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { - getLockServiceData(asyncResp); - }); - - BMCWEB_ROUTE(app, "/ibm/v1/HMC/LockService/Actions/LockService.AcquireLock") - .privileges({{"ConfigureComponents", "ConfigureManager"}}) - .methods(boost::beast::http::verb::post)( - [](const crow::Request& req, - const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { - std::vector<nlohmann::json::object_t> body; - if (!redfish::json_util::readJsonAction(req, asyncResp->res, "Request", - body)) - { - BMCWEB_LOG_DEBUG("Not a Valid JSON"); - asyncResp->res.result(boost::beast::http::status::bad_request); - return; - } - handleAcquireLockAPI(req, asyncResp, body); - }); - BMCWEB_ROUTE(app, "/ibm/v1/HMC/LockService/Actions/LockService.ReleaseLock") - .privileges({{"ConfigureComponents", "ConfigureManager"}}) - .methods(boost::beast::http::verb::post)( - [](const crow::Request& req, - const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { - std::string type; - std::vector<uint32_t> listTransactionIds; - - if (!redfish::json_util::readJsonPatch(req, asyncResp->res, "Type", - type, "TransactionIDs", - listTransactionIds)) - { - asyncResp->res.result(boost::beast::http::status::bad_request); - return; - } - if (type == "Transaction") - { - handleReleaseLockAPI(req, asyncResp, listTransactionIds); - } - else if (type == "Session") - { - handleRelaseAllAPI(req, asyncResp); - } - else - { - BMCWEB_LOG_DEBUG(" Value of Type : {}is Not a Valid key", type); - redfish::messages::propertyValueNotInList(asyncResp->res, type, - "Type"); - } - }); - BMCWEB_ROUTE(app, "/ibm/v1/HMC/LockService/Actions/LockService.GetLockList") - .privileges({{"ConfigureComponents", "ConfigureManager"}}) - .methods(boost::beast::http::verb::post)( - [](const crow::Request& req, - const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { - ListOfSessionIds listSessionIds; - - if (!redfish::json_util::readJsonPatch(req, asyncResp->res, - "SessionIDs", listSessionIds)) - { - asyncResp->res.result(boost::beast::http::status::bad_request); - return; - } - handleGetLockListAPI(asyncResp, listSessionIds); - }); - BMCWEB_ROUTE(app, "/ibm/v1/HMC/BroadcastService") .privileges({{"ConfigureComponents", "ConfigureManager"}}) .methods(boost::beast::http::verb::post)( diff --git a/include/sessions.hpp b/include/sessions.hpp index fb7276212c..1d0b620fb1 100644 --- a/include/sessions.hpp +++ b/include/sessions.hpp @@ -11,9 +11,6 @@ #include <csignal> #include <optional> #include <random> -#ifdef BMCWEB_ENABLE_IBM_MANAGEMENT_CONSOLE -#include "ibm/locks.hpp" -#endif namespace persistent_data { @@ -310,9 +307,6 @@ class SessionStore void removeSession(const std::shared_ptr<UserSession>& session) { -#ifdef BMCWEB_ENABLE_IBM_MANAGEMENT_CONSOLE - crow::ibm_mc_lock::Lock::getInstance().releaseLock(session->uniqueId); -#endif authTokens.erase(session->sessionToken); needWrite = true; } @@ -396,10 +390,6 @@ class SessionStore if (timeNow - authTokensIt->second->lastUpdated >= timeoutInSeconds) { -#ifdef BMCWEB_ENABLE_IBM_MANAGEMENT_CONSOLE - crow::ibm_mc_lock::Lock::getInstance().releaseLock( - authTokensIt->second->uniqueId); -#endif authTokensIt = authTokens.erase(authTokensIt); needWrite = true; diff --git a/meson.build b/meson.build index a965b7ff43..ee8a91f500 100644 --- a/meson.build +++ b/meson.build @@ -464,7 +464,6 @@ srcfiles_unittest = files( 'test/include/http_utility_test.cpp', 'test/include/human_sort_test.cpp', 'test/include/ibm/configfile_test.cpp', - 'test/include/ibm/lock_test.cpp', 'test/include/json_html_serializer.cpp', 'test/include/multipart_test.cpp', 'test/include/openbmc_dbus_rest_test.cpp', diff --git a/src/webserver_run.cpp b/src/webserver_run.cpp index 2f28e16818..3c1c615539 100644 --- a/src/webserver_run.cpp +++ b/src/webserver_run.cpp @@ -76,7 +76,6 @@ int run() #ifdef BMCWEB_ENABLE_IBM_MANAGEMENT_CONSOLE crow::ibm_mc::requestRoutes(app); - crow::ibm_mc_lock::Lock::getInstance(); #endif #ifdef BMCWEB_ENABLE_GOOGLE_API diff --git a/test/include/ibm/lock_test.cpp b/test/include/ibm/lock_test.cpp deleted file mode 100644 index 9570ec6f90..0000000000 --- a/test/include/ibm/lock_test.cpp +++ /dev/null @@ -1,314 +0,0 @@ -#include "ibm/locks.hpp" - -#include <cstdint> -#include <string> -#include <tuple> -#include <utility> -#include <variant> -#include <vector> - -#include <gmock/gmock.h> // IWYU pragma: keep -#include <gtest/gtest.h> // IWYU pragma: keep - -// IWYU pragma: no_include <gtest/gtest-message.h> -// IWYU pragma: no_include <gtest/gtest-test-part.h> -// IWYU pragma: no_include "gtest/gtest_pred_impl.h" - -namespace crow::ibm_mc_lock -{ -namespace -{ - -using SType = std::string; -using LockRequest = std::tuple<SType, SType, SType, uint64_t, SegmentFlags>; -using LockRequests = std::vector<LockRequest>; -using Rc = - std::pair<bool, std::variant<uint32_t, std::pair<uint32_t, LockRequest>>>; -using RcRelaseLock = std::pair<bool, std::pair<uint32_t, LockRequest>>; -using RcGetLockList = - std::variant<std::string, std::vector<std::pair<uint32_t, LockRequests>>>; -using ListOfTransactionIds = std::vector<uint32_t>; -using RcAcquireLock = std::pair<bool, std::variant<Rc, std::pair<bool, int>>>; -using RcReleaseLockApi = std::pair<bool, std::variant<bool, RcRelaseLock>>; -using SessionFlags = std::pair<SType, SType>; -using ListOfSessionIds = std::vector<std::string>; -using ::testing::IsEmpty; - -class LockTest : public ::testing::Test -{ - protected: - LockRequests request; - LockRequests request1, request2; - LockRequest record; - - public: - LockTest() : - // lockrequest with multiple lockrequests - request{{"xxxxx", - "hmc-id", - "Read", - 234, - {{"DontLock", 2}, {"DontLock", 4}}}, - {"xxxxx", - "hmc-id", - "Read", - 234, - {{"DontLock", 2}, {"DontLock", 4}}}}, - request1{{"xxxxx", - "hmc-id", - "Read", - 234, - {{"DontLock", 2}, {"DontLock", 4}}}}, - request2{{"xxxxx", - "hmc-id", - "Write", - 234, - {{"LockAll", 2}, {"DontLock", 4}}}}, - record{ - "xxxxx", "hmc-id", "Read", 234, {{"DontLock", 2}, {"DontLock", 4}}} - {} - - ~LockTest() override = default; - - LockTest(const LockTest&) = delete; - LockTest(LockTest&&) = delete; - LockTest& operator=(const LockTest&) = delete; - LockTest& operator=(const LockTest&&) = delete; -}; - -class MockLock : public crow::ibm_mc_lock::Lock -{ - public: - bool isValidLockRequest(const LockRequest& record1) override - { - bool status = Lock::isValidLockRequest(record1); - return status; - } - bool isConflictRequest(const LockRequests& request) override - { - bool status = Lock::isConflictRequest(request); - return status; - } - Rc isConflictWithTable(const LockRequests& request) override - { - auto conflict = Lock::isConflictWithTable(request); - return conflict; - } - uint32_t generateTransactionId() override - { - uint32_t tid = Lock::generateTransactionId(); - return tid; - } - - bool validateRids(const ListOfTransactionIds& tids) override - { - bool status = Lock::validateRids(tids); - return status; - } - RcRelaseLock isItMyLock(const ListOfTransactionIds& tids, - const SessionFlags& ids) override - { - auto status = Lock::isItMyLock(tids, ids); - return status; - } - friend class LockTest; -}; - -TEST_F(LockTest, ValidationGoodTestCase) -{ - MockLock lockManager; - const LockRequest& t = record; - EXPECT_TRUE(lockManager.isValidLockRequest(t)); -} - -TEST_F(LockTest, ValidationBadTestWithLocktype) -{ - MockLock lockManager; - // Corrupt the lock type - std::get<2>(record) = "rwrite"; - const LockRequest& t = record; - EXPECT_FALSE(lockManager.isValidLockRequest(t)); -} - -TEST_F(LockTest, ValidationBadTestWithlockFlags) -{ - MockLock lockManager; - // Corrupt the lockflag - std::get<4>(record)[0].first = "lock"; - const LockRequest& t = record; - EXPECT_FALSE(lockManager.isValidLockRequest(t)); -} - -TEST_F(LockTest, ValidationBadTestWithSegmentlength) -{ - MockLock lockManager; - // Corrupt the Segment length - std::get<4>(record)[0].second = 7; - const LockRequest& t = record; - EXPECT_FALSE(lockManager.isValidLockRequest(t)); -} - -TEST_F(LockTest, MultiRequestWithoutConflict) -{ - MockLock lockManager; - const LockRequests& t = request; - EXPECT_FALSE(lockManager.isConflictRequest(t)); -} - -TEST_F(LockTest, MultiRequestWithConflictduetoSameSegmentLength) -{ - MockLock lockManager; - // Corrupt the locktype - std::get<2>(request[0]) = "Write"; - // Match the segment lengths to points them to lock similar kind of - // resource - std::get<4>(request[0])[0].first = "LockAll"; - const LockRequests& t = request; - EXPECT_TRUE(lockManager.isConflictRequest(t)); -} - -TEST_F(LockTest, MultiRequestWithoutConflictduetoDifferentSegmentLength) -{ - MockLock lockManager; - // Corrupt the locktype - std::get<2>(request[0]) = "Write"; - // Match the segment lengths to points them to lock similar kind of - // resource - std::get<4>(request[0])[0].first = "LockSame"; - // Change the segment length , so that the requests are trying to lock - // two different kind of resources - std::get<4>(request[0])[0].second = 3; - const LockRequests& t = request; - // Return No Conflict - EXPECT_FALSE(lockManager.isConflictRequest(t)); -} - -TEST_F(LockTest, MultiRequestWithoutConflictduetoReadLocktype) -{ - MockLock lockManager; - // Match the segment lengths to points them to lock similar kind of - // resource - std::get<4>(request[0])[0].first = "LockAll"; - const LockRequests& t = request; - // Return No Conflict - EXPECT_FALSE(lockManager.isConflictRequest(t)); -} - -TEST_F(LockTest, MultiRequestWithoutConflictduetoReadLocktypeAndLockall) -{ - MockLock lockManager; - // Match the segment lengths to points them to lock similar kind of - // resource - std::get<4>(request[0])[0].first = "LockAll"; - std::get<4>(request[0])[1].first = "LockAll"; - const LockRequests& t = request; - // Return No Conflict - EXPECT_FALSE(lockManager.isConflictRequest(t)); -} - -TEST_F(LockTest, RequestNotConflictedWithLockTableEntries) -{ - MockLock lockManager; - const LockRequests& t = request1; - // Insert the request1 into the lock table - auto rc1 = lockManager.isConflictWithTable(t); - // Corrupt the lock type - std::get<2>(request[0]) = "Read"; - // Corrupt the lockflag - std::get<4>(request[0])[1].first = "LockAll"; - const LockRequests& p = request; - auto rc2 = lockManager.isConflictWithTable(p); - // Return No Conflict - EXPECT_FALSE(rc2.first); -} - -TEST_F(LockTest, TestGenerateTransactionIDFunction) -{ - MockLock lockManager; - uint32_t transactionId1 = lockManager.generateTransactionId(); - uint32_t transactionId2 = lockManager.generateTransactionId(); - EXPECT_EQ(transactionId2, ++transactionId1); -} - -TEST_F(LockTest, ValidateTransactionIDsGoodTestCase) -{ - MockLock lockManager; - const LockRequests& t = request1; - // Insert the request1 into the lock table - auto rc1 = lockManager.isConflictWithTable(t); - std::vector<uint32_t> tids = {1}; - const std::vector<uint32_t>& p = tids; - EXPECT_TRUE(lockManager.validateRids(p)); -} - -TEST_F(LockTest, ValidateTransactionIDsBadTestCase) -{ - MockLock lockManager; - // Insert the request1 into the lock table - const LockRequests& t = request1; - auto rc1 = lockManager.isConflictWithTable(t); - std::vector<uint32_t> tids = {10}; - const std::vector<uint32_t>& p = tids; - EXPECT_FALSE(lockManager.validateRids(p)); -} - -TEST_F(LockTest, ValidateisItMyLockGoodTestCase) -{ - MockLock lockManager; - // Insert the request1 into the lock table - const LockRequests& t = request1; - auto rc1 = lockManager.isConflictWithTable(t); - std::vector<uint32_t> tids = {1}; - const std::vector<uint32_t>& p = tids; - std::string hmcid = "hmc-id"; - std::string sessionid = "xxxxx"; - std::pair<SType, SType> ids = std::make_pair(hmcid, sessionid); - auto rc = lockManager.isItMyLock(p, ids); - EXPECT_TRUE(rc.first); -} - -TEST_F(LockTest, ValidateisItMyLockBadTestCase) -{ - MockLock lockManager; - // Corrupt the client identifier - std::get<1>(request1[0]) = "randomid"; - // Insert the request1 into the lock table - const LockRequests& t = request1; - auto rc1 = lockManager.isConflictWithTable(t); - std::vector<uint32_t> tids = {1}; - const std::vector<uint32_t>& p = tids; - std::string hmcid = "hmc-id"; - std::string sessionid = "random"; - std::pair<SType, SType> ids = std::make_pair(hmcid, sessionid); - auto rc = lockManager.isItMyLock(p, ids); - EXPECT_FALSE(rc.first); -} - -TEST_F(LockTest, ValidateSessionIDForGetlocklistBadTestCase) -{ - MockLock lockManager; - // Insert the request1 into the lock table - const LockRequests& t = request1; - auto rc1 = lockManager.isConflictWithTable(t); - std::vector<std::string> sessionid = {"random"}; - auto status = lockManager.getLockList(sessionid); - auto result = - std::get<std::vector<std::pair<uint32_t, LockRequests>>>(status); - EXPECT_THAT(result, IsEmpty()); -} - -TEST_F(LockTest, ValidateSessionIDForGetlocklistGoodTestCase) -{ - MockLock lockManager; - // Insert the request1 into the lock table - const LockRequests& t = request1; - auto rc1 = lockManager.isConflictWithTable(t); - std::vector<std::string> sessionid = {"xxxxx"}; - auto status = lockManager.getLockList(sessionid); - auto result = - std::get<std::vector<std::pair<uint32_t, LockRequests>>>(status); - EXPECT_EQ(result.size(), 1); -} - -} // namespace -} // namespace crow::ibm_mc_lock |