summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPrzemyslaw Czarnowski <przemyslaw.hawrylewicz.czarnowski@intel.com>2019-09-02 17:32:43 +0200
committerPrzemyslaw Czarnowski <przemyslaw.hawrylewicz.czarnowski@intel.com>2020-01-27 09:53:00 +0000
commite13c27606f49f70910eca01f0ee496e7e9a6b330 (patch)
treefde8f959b02e6b3c6f3cad6aa8b1f7192a4acb29
parent107077def176ad4a29557fae353de9bb00381ca9 (diff)
downloadbmcweb-e13c27606f49f70910eca01f0ee496e7e9a6b330.tar.gz
bmcweb-e13c27606f49f70910eca01f0ee496e7e9a6b330.zip
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>
-rw-r--r--CMakeLists.txt1
-rw-r--r--redfish-core/include/redfish.hpp3
-rw-r--r--redfish-core/lib/virtual_media.hpp377
3 files changed, 380 insertions, 1 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index cf5a93f..f874d9d 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -301,6 +301,7 @@ set (WEBSERVER_MAIN src/webserver_main.cpp)
include_directories (${CMAKE_CURRENT_SOURCE_DIR}/include)
include_directories (${CMAKE_CURRENT_SOURCE_DIR}/redfish-core/include)
+include_directories (${CMAKE_CURRENT_SOURCE_DIR}/redfish-core/lib)
file (MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/include/bmcweb)
include_directories (${CMAKE_BINARY_DIR}/include)
diff --git a/redfish-core/include/redfish.hpp b/redfish-core/include/redfish.hpp
index c498a19..b1fd820 100644
--- a/redfish-core/include/redfish.hpp
+++ b/redfish-core/include/redfish.hpp
@@ -130,6 +130,9 @@ class RedfishService
#ifdef BMCWEB_ENABLE_VM_NBDPROXY
nodes.emplace_back(std::make_unique<VirtualMedia>(app));
nodes.emplace_back(std::make_unique<VirtualMediaCollection>(app));
+ nodes.emplace_back(
+ std::make_unique<VirtualMediaActionInsertMedia>(app));
+ nodes.emplace_back(std::make_unique<VirtualMediaActionEjectMedia>(app));
#endif // BMCWEB_ENABLE_VM_NBDPROXY
#ifdef BMCWEB_ENABLE_REDFISH_DBUS_LOG_ENTRIES
nodes.emplace_back(std::make_unique<DBusLogServiceActionsClear>(app));
diff --git a/redfish-core/lib/virtual_media.hpp b/redfish-core/lib/virtual_media.hpp
index c12da70..457b0b2 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> &params) 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> &params) 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:
OpenPOWER on IntegriCloud