diff options
author | Przemyslaw Czarnowski <przemyslaw.hawrylewicz.czarnowski@intel.com> | 2019-09-02 18:32:43 +0300 |
---|---|---|
committer | Przemyslaw Czarnowski <przemyslaw.hawrylewicz.czarnowski@intel.com> | 2020-01-27 12:53:00 +0300 |
commit | e13c27606f49f70910eca01f0ee496e7e9a6b330 (patch) | |
tree | fde8f959b02e6b3c6f3cad6aa8b1f7192a4acb29 /redfish-core/lib/virtual_media.hpp | |
parent | 107077def176ad4a29557fae353de9bb00381ca9 (diff) | |
download | bmcweb-e13c27606f49f70910eca01f0ee496e7e9a6b330.tar.xz |
InsertMedia and EjectMedia actions added to VirtualMedia schema
As continuation for VirtualMedia Redfish support, this patch adds
insertion and eject actions into existing VirtualMedia code base.
Testing:
* Manual tests together with nbd proxy and virtual media app
- For requests: Postman and/or HTTPie, with logs enabled and Valgrind)
- Manual result validation
* Tests run:
- GET on collection with manual validation
- PUT/POST/DELETE on collection
- GET on item/nonexistent item
- PUT/POST/DELETE on item
- GET/PUT/DELETE on action
- POST on action - EjectMedia/InsertMedia, legacy mode
- POST on action - InsertMedia, proxy mode
- POST on action - input validation (empty, invalid URL), legacy mode
* Redfish Service Validator tested, no new issues found.
Change-Id: Icccc433c1e84bc2ac37d9c295fe72749187fb735
Signed-off-by: Przemyslaw Czarnowski <przemyslaw.hawrylewicz.czarnowski@intel.com>
Diffstat (limited to 'redfish-core/lib/virtual_media.hpp')
-rw-r--r-- | redfish-core/lib/virtual_media.hpp | 377 |
1 files changed, 376 insertions, 1 deletions
diff --git a/redfish-core/lib/virtual_media.hpp b/redfish-core/lib/virtual_media.hpp index c12da70cc2..457b0b2f3b 100644 --- a/redfish-core/lib/virtual_media.hpp +++ b/redfish-core/lib/virtual_media.hpp @@ -19,7 +19,7 @@ #include <node.hpp> #include <utils/json_utils.hpp> // for GetObjectType and ManagedObjectType -#include <../lib/account_service.hpp> +#include <account_service.hpp> namespace redfish @@ -190,6 +190,7 @@ static void getVmData(std::shared_ptr<AsyncResp> aResp, if (ec) { BMCWEB_LOG_DEBUG << "DBUS response error"; + return; } @@ -211,8 +212,22 @@ static void getVmData(std::shared_ptr<AsyncResp> aResp, aResp->res.jsonValue = vmItemTemplate(name, resName); + // Check if dbus path is Legacy type + if (path.find("VirtualMedia/Legacy") != std::string::npos) + { + aResp->res.jsonValue["Actions"]["#VirtualMedia.InsertMedia"] + ["target"] = + "/redfish/v1/Managers/" + name + "/VirtualMedia/" + + resName + "/Actions/VirtualMedia.InsertMedia"; + } + vmParseInterfaceObject(item.second, aResp); + aResp->res.jsonValue["Actions"]["#VirtualMedia.EjectMedia"] + ["target"] = + "/redfish/v1/Managers/" + name + "/VirtualMedia/" + + resName + "/Actions/VirtualMedia.EjectMedia"; + return; } @@ -223,6 +238,366 @@ static void getVmData(std::shared_ptr<AsyncResp> aResp, "org.freedesktop.DBus.ObjectManager", "GetManagedObjects"); } +/** + @brief InsertMedia action class + */ +class VirtualMediaActionInsertMedia : public Node +{ + public: + VirtualMediaActionInsertMedia(CrowApp &app) : + Node(app, + "/redfish/v1/Managers/<str>/VirtualMedia/<str>/Actions/" + "VirtualMedia.InsertMedia", + std::string(), std::string()) + { + entityPrivileges = { + {boost::beast::http::verb::get, {{"Login"}}}, + {boost::beast::http::verb::head, {{"Login"}}}, + {boost::beast::http::verb::patch, {{"ConfigureManager"}}}, + {boost::beast::http::verb::put, {{"ConfigureManager"}}}, + {boost::beast::http::verb::delete_, {{"ConfigureManager"}}}, + {boost::beast::http::verb::post, {{"ConfigureManager"}}}}; + } + + private: + /** + * @brief Function handles POST method request. + * + * Analyzes POST body message before sends Reset request data to dbus. + */ + void doPost(crow::Response &res, const crow::Request &req, + const std::vector<std::string> ¶ms) override + { + auto aResp = std::make_shared<AsyncResp>(res); + + if (params.size() != 2) + { + messages::internalError(res); + return; + } + + // take resource name from URL + const std::string &resName = params[1]; + + if (params[0] != "bmc") + { + messages::resourceNotFound(res, "VirtualMedia.Insert", resName); + + return; + } + + crow::connections::systemBus->async_method_call( + [this, aResp{std::move(aResp)}, req, + resName](const boost::system::error_code ec, + const GetObjectType &getObjectType) { + if (ec) + { + BMCWEB_LOG_ERROR << "ObjectMapper::GetObject call failed: " + << ec; + messages::internalError(aResp->res); + + return; + } + std::string service = getObjectType.begin()->first; + BMCWEB_LOG_DEBUG << "GetObjectType: " << service; + + crow::connections::systemBus->async_method_call( + [this, service, resName, req, aResp{std::move(aResp)}]( + const boost::system::error_code ec, + ManagedObjectType &subtree) { + if (ec) + { + BMCWEB_LOG_DEBUG << "DBUS response error"; + + return; + } + + for (const auto &object : subtree) + { + const std::string &path = + static_cast<const std::string &>(object.first); + + std::size_t lastIndex = path.rfind("/"); + if (lastIndex == std::string::npos) + { + continue; + } + + lastIndex += 1; + + if (path.substr(lastIndex) == resName) + { + lastIndex = path.rfind("Proxy"); + if (lastIndex != std::string::npos) + { + // Not possible in proxy mode + BMCWEB_LOG_DEBUG << "InsertMedia not " + "allowed in proxy mode"; + messages::resourceNotFound( + aResp->res, "VirtualMedia.InsertMedia", + resName); + + return; + } + + lastIndex = path.rfind("Legacy"); + if (lastIndex != std::string::npos) + { + // Legacy mode + std::string imageUrl; + + // Read obligatory paramters (url of image) + if (!json_util::readJson(req, aResp->res, + "Image", imageUrl)) + { + BMCWEB_LOG_DEBUG + << "Image is not provided"; + return; + } + + // must not be empty + if (imageUrl.size() == 0) + { + BMCWEB_LOG_ERROR + << "Request action parameter " + "Image is empty."; + messages::propertyValueFormatError( + aResp->res, "<empty>", "Image"); + + return; + } + + // manager is irrelevant for VirtualMedia + // dbus calls + doVmAction(std::move(aResp), service, + resName, true, imageUrl); + + return; + } + } + } + BMCWEB_LOG_DEBUG << "Parent item not found"; + messages::resourceNotFound(aResp->res, "VirtualMedia", + resName); + }, + service, "/xyz/openbmc_project/VirtualMedia", + "org.freedesktop.DBus.ObjectManager", "GetManagedObjects"); + }, + "xyz.openbmc_project.ObjectMapper", + "/xyz/openbmc_project/object_mapper", + "xyz.openbmc_project.ObjectMapper", "GetObject", + "/xyz/openbmc_project/VirtualMedia", std::array<const char *, 0>()); + } + + /** + * @brief Function transceives data with dbus directly. + * + * All BMC state properties will be retrieved before sending reset request. + */ + void doVmAction(std::shared_ptr<AsyncResp> asyncResp, + const std::string &service, const std::string &name, + bool legacy, const std::string &imageUrl) + { + + // Legacy mount requires parameter with image + if (legacy) + { + crow::connections::systemBus->async_method_call( + [asyncResp](const boost::system::error_code ec) { + if (ec) + { + BMCWEB_LOG_ERROR << "Bad D-Bus request error: " << ec; + messages::internalError(asyncResp->res); + + return; + } + }, + service, "/xyz/openbmc_project/VirtualMedia/Legacy/" + name, + "xyz.openbmc_project.VirtualMedia.Legacy", "Mount", imageUrl); + } + else // proxy + { + crow::connections::systemBus->async_method_call( + [asyncResp](const boost::system::error_code ec) { + if (ec) + { + BMCWEB_LOG_ERROR << "Bad D-Bus request error: " << ec; + messages::internalError(asyncResp->res); + + return; + } + }, + service, "/xyz/openbmc_project/VirtualMedia/Proxy/" + name, + "xyz.openbmc_project.VirtualMedia.Proxy", "Mount"); + } + } +}; + +/** + @brief EjectMedia action class + */ +class VirtualMediaActionEjectMedia : public Node +{ + public: + VirtualMediaActionEjectMedia(CrowApp &app) : + Node(app, + "/redfish/v1/Managers/<str>/VirtualMedia/<str>/Actions/" + "VirtualMedia.EjectMedia", + std::string(), std::string()) + { + entityPrivileges = { + {boost::beast::http::verb::get, {{"Login"}}}, + {boost::beast::http::verb::head, {{"Login"}}}, + {boost::beast::http::verb::patch, {{"ConfigureManager"}}}, + {boost::beast::http::verb::put, {{"ConfigureManager"}}}, + {boost::beast::http::verb::delete_, {{"ConfigureManager"}}}, + {boost::beast::http::verb::post, {{"ConfigureManager"}}}}; + } + + private: + /** + * @brief Function handles POST method request. + * + * Analyzes POST body message before sends Reset request data to dbus. + */ + void doPost(crow::Response &res, const crow::Request &req, + const std::vector<std::string> ¶ms) override + { + auto aResp = std::make_shared<AsyncResp>(res); + + if (params.size() != 2) + { + messages::internalError(res); + return; + } + + // take resource name from URL + const std::string &resName = params[1]; + + if (params[0] != "bmc") + { + messages::resourceNotFound(res, "VirtualMedia.Eject", resName); + + return; + } + + crow::connections::systemBus->async_method_call( + [this, aResp{std::move(aResp)}, req, + resName](const boost::system::error_code ec, + const GetObjectType &getObjectType) { + if (ec) + { + BMCWEB_LOG_ERROR << "ObjectMapper::GetObject call failed: " + << ec; + messages::internalError(aResp->res); + + return; + } + std::string service = getObjectType.begin()->first; + BMCWEB_LOG_DEBUG << "GetObjectType: " << service; + + crow::connections::systemBus->async_method_call( + [this, resName, service, req, aResp{std::move(aResp)}]( + const boost::system::error_code ec, + ManagedObjectType &subtree) { + if (ec) + { + BMCWEB_LOG_DEBUG << "DBUS response error"; + + return; + } + + for (const auto &object : subtree) + { + const std::string &path = + static_cast<const std::string &>(object.first); + + std::size_t lastIndex = path.rfind("/"); + if (lastIndex == std::string::npos) + { + continue; + } + + lastIndex += 1; + + if (path.substr(lastIndex) == resName) + { + lastIndex = path.rfind("Proxy"); + if (lastIndex != std::string::npos) + { + // Proxy mode + doVmAction(std::move(aResp), service, + resName, false); + } + + lastIndex = path.rfind("Legacy"); + if (lastIndex != std::string::npos) + { + // Legacy mode + doVmAction(std::move(aResp), service, + resName, true); + } + + return; + } + } + BMCWEB_LOG_DEBUG << "Parent item not found"; + messages::resourceNotFound(aResp->res, "VirtualMedia", + resName); + }, + service, "/xyz/openbmc_project/VirtualMedia", + "org.freedesktop.DBus.ObjectManager", "GetManagedObjects"); + }, + "xyz.openbmc_project.ObjectMapper", + "/xyz/openbmc_project/object_mapper", + "xyz.openbmc_project.ObjectMapper", "GetObject", + "/xyz/openbmc_project/VirtualMedia", std::array<const char *, 0>()); + } + + /** + * @brief Function transceives data with dbus directly. + * + * All BMC state properties will be retrieved before sending reset request. + */ + void doVmAction(std::shared_ptr<AsyncResp> asyncResp, + const std::string &service, const std::string &name, + bool legacy) + { + + // Legacy mount requires parameter with image + if (legacy) + { + crow::connections::systemBus->async_method_call( + [asyncResp](const boost::system::error_code ec) { + if (ec) + { + BMCWEB_LOG_ERROR << "Bad D-Bus request error: " << ec; + + messages::internalError(asyncResp->res); + return; + } + }, + service, "/xyz/openbmc_project/VirtualMedia/Legacy/" + name, + "xyz.openbmc_project.VirtualMedia.Legacy", "Unmount"); + } + else // proxy + { + crow::connections::systemBus->async_method_call( + [asyncResp](const boost::system::error_code ec) { + if (ec) + { + BMCWEB_LOG_ERROR << "Bad D-Bus request error: " << ec; + + messages::internalError(asyncResp->res); + return; + } + }, + service, "/xyz/openbmc_project/VirtualMedia/Proxy/" + name, + "xyz.openbmc_project.VirtualMedia.Proxy", "Unmount"); + } + } +}; + class VirtualMediaCollection : public Node { public: |