| /* |
| // Copyright (c) 2018 Intel Corporation |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| */ |
| #pragma once |
| |
| #include "account_service.hpp" |
| #include "app.hpp" |
| #include "async_resp.hpp" |
| #include "credential_pipe.hpp" |
| #include "dbus_utility.hpp" |
| #include "generated/enums/virtual_media.hpp" |
| #include "query.hpp" |
| #include "registries/privilege_registry.hpp" |
| #include "utils/json_utils.hpp" |
| |
| #include <boost/url/format.hpp> |
| #include <boost/url/url_view.hpp> |
| #include <boost/url/url_view_base.hpp> |
| |
| #include <array> |
| #include <ranges> |
| #include <string_view> |
| |
| namespace redfish |
| { |
| |
| enum class VmMode |
| { |
| Invalid, |
| Legacy, |
| Proxy |
| }; |
| |
| inline VmMode parseObjectPathAndGetMode( |
| const sdbusplus::message::object_path& itemPath, const std::string& resName) |
| { |
| std::string thisPath = itemPath.filename(); |
| BMCWEB_LOG_DEBUG("Filename: {}, ThisPath: {}", itemPath.str, thisPath); |
| |
| if (thisPath.empty()) |
| { |
| return VmMode::Invalid; |
| } |
| |
| if (thisPath != resName) |
| { |
| return VmMode::Invalid; |
| } |
| |
| auto mode = itemPath.parent_path(); |
| auto type = mode.parent_path(); |
| |
| if (mode.filename().empty() || type.filename().empty()) |
| { |
| return VmMode::Invalid; |
| } |
| |
| if (type.filename() != "VirtualMedia") |
| { |
| return VmMode::Invalid; |
| } |
| std::string modeStr = mode.filename(); |
| if (modeStr == "Legacy") |
| { |
| return VmMode::Legacy; |
| } |
| if (modeStr == "Proxy") |
| { |
| return VmMode::Proxy; |
| } |
| return VmMode::Invalid; |
| } |
| |
| using CheckItemHandler = |
| std::function<void(const std::string& service, const std::string& resName, |
| const std::shared_ptr<bmcweb::AsyncResp>&, |
| const std::pair<sdbusplus::message::object_path, |
| dbus::utility::DBusInterfacesMap>&)>; |
| |
| inline void |
| findAndParseObject(const std::string& service, const std::string& resName, |
| const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, |
| CheckItemHandler&& handler) |
| { |
| sdbusplus::message::object_path path("/xyz/openbmc_project/VirtualMedia"); |
| dbus::utility::getManagedObjects( |
| service, path, |
| [service, resName, asyncResp, handler = std::move(handler)]( |
| const boost::system::error_code& ec, |
| const dbus::utility::ManagedObjectType& subtree) { |
| if (ec) |
| { |
| BMCWEB_LOG_DEBUG("DBUS response error"); |
| |
| return; |
| } |
| |
| for (const auto& item : subtree) |
| { |
| VmMode mode = parseObjectPathAndGetMode(item.first, resName); |
| if (mode != VmMode::Invalid) |
| { |
| handler(service, resName, asyncResp, item); |
| return; |
| } |
| } |
| |
| BMCWEB_LOG_DEBUG("Parent item not found"); |
| asyncResp->res.result(boost::beast::http::status::not_found); |
| }); |
| } |
| |
| /** |
| * @brief Function extracts transfer protocol name from URI. |
| */ |
| inline std::string getTransferProtocolTypeFromUri(const std::string& imageUri) |
| { |
| boost::system::result<boost::urls::url_view> url = |
| boost::urls::parse_uri(imageUri); |
| if (!url) |
| { |
| return "None"; |
| } |
| std::string_view scheme = url->scheme(); |
| if (scheme == "smb") |
| { |
| return "CIFS"; |
| } |
| if (scheme == "https") |
| { |
| return "HTTPS"; |
| } |
| |
| return "None"; |
| } |
| |
| /** |
| * @brief Read all known properties from VM object interfaces |
| */ |
| inline void |
| vmParseInterfaceObject(const dbus::utility::DBusInterfacesMap& interfaces, |
| const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) |
| { |
| for (const auto& [interface, values] : interfaces) |
| { |
| if (interface == "xyz.openbmc_project.VirtualMedia.MountPoint") |
| { |
| for (const auto& [property, value] : values) |
| { |
| if (property == "EndpointId") |
| { |
| const std::string* endpointIdValue = |
| std::get_if<std::string>(&value); |
| if (endpointIdValue == nullptr) |
| { |
| continue; |
| } |
| if (!endpointIdValue->empty()) |
| { |
| // Proxy mode |
| asyncResp->res |
| .jsonValue["Oem"]["OpenBMC"]["WebSocketEndpoint"] = |
| *endpointIdValue; |
| asyncResp->res.jsonValue["TransferProtocolType"] = |
| "OEM"; |
| } |
| } |
| if (property == "ImageURL") |
| { |
| const std::string* imageUrlValue = |
| std::get_if<std::string>(&value); |
| if (imageUrlValue != nullptr && !imageUrlValue->empty()) |
| { |
| std::filesystem::path filePath = *imageUrlValue; |
| if (!filePath.has_filename()) |
| { |
| // this will handle https share, which not |
| // necessarily has to have filename given. |
| asyncResp->res.jsonValue["ImageName"] = ""; |
| } |
| else |
| { |
| asyncResp->res.jsonValue["ImageName"] = |
| filePath.filename(); |
| } |
| |
| asyncResp->res.jsonValue["Image"] = *imageUrlValue; |
| asyncResp->res.jsonValue["TransferProtocolType"] = |
| getTransferProtocolTypeFromUri(*imageUrlValue); |
| |
| asyncResp->res.jsonValue["ConnectedVia"] = |
| virtual_media::ConnectedVia::URI; |
| } |
| } |
| if (property == "WriteProtected") |
| { |
| const bool* writeProtectedValue = std::get_if<bool>(&value); |
| if (writeProtectedValue != nullptr) |
| { |
| asyncResp->res.jsonValue["WriteProtected"] = |
| *writeProtectedValue; |
| } |
| } |
| } |
| } |
| if (interface == "xyz.openbmc_project.VirtualMedia.Process") |
| { |
| for (const auto& [property, value] : values) |
| { |
| if (property == "Active") |
| { |
| const bool* activeValue = std::get_if<bool>(&value); |
| if (activeValue == nullptr) |
| { |
| BMCWEB_LOG_DEBUG("Value Active not found"); |
| return; |
| } |
| asyncResp->res.jsonValue["Inserted"] = *activeValue; |
| |
| if (*activeValue) |
| { |
| asyncResp->res.jsonValue["ConnectedVia"] = |
| virtual_media::ConnectedVia::Applet; |
| } |
| } |
| } |
| } |
| } |
| } |
| |
| /** |
| * @brief Fill template for Virtual Media Item. |
| */ |
| inline nlohmann::json vmItemTemplate(const std::string& name, |
| const std::string& resName) |
| { |
| nlohmann::json item; |
| item["@odata.id"] = boost::urls::format( |
| "/redfish/v1/Managers/{}/VirtualMedia/{}", name, resName); |
| |
| item["@odata.type"] = "#VirtualMedia.v1_3_0.VirtualMedia"; |
| item["Name"] = "Virtual Removable Media"; |
| item["Id"] = resName; |
| item["WriteProtected"] = true; |
| item["ConnectedVia"] = virtual_media::ConnectedVia::NotConnected; |
| item["MediaTypes"] = nlohmann::json::array_t({"CD", "USBStick"}); |
| item["TransferMethod"] = virtual_media::TransferMethod::Stream; |
| item["Oem"]["OpenBMC"]["@odata.type"] = |
| "#OpenBMCVirtualMedia.v1_0_0.VirtualMedia"; |
| item["Oem"]["OpenBMC"]["@odata.id"] = boost::urls::format( |
| "/redfish/v1/Managers/{}/VirtualMedia/{}#/Oem/OpenBMC", name, resName); |
| |
| return item; |
| } |
| |
| /** |
| * @brief Fills collection data |
| */ |
| inline void getVmResourceList(std::shared_ptr<bmcweb::AsyncResp> asyncResp, |
| const std::string& service, |
| const std::string& name) |
| { |
| BMCWEB_LOG_DEBUG("Get available Virtual Media resources."); |
| sdbusplus::message::object_path objPath( |
| "/xyz/openbmc_project/VirtualMedia"); |
| dbus::utility::getManagedObjects( |
| service, objPath, |
| [name, asyncResp{std::move(asyncResp)}]( |
| const boost::system::error_code& ec, |
| const dbus::utility::ManagedObjectType& subtree) { |
| if (ec) |
| { |
| BMCWEB_LOG_DEBUG("DBUS response error"); |
| return; |
| } |
| nlohmann::json& members = asyncResp->res.jsonValue["Members"]; |
| members = nlohmann::json::array(); |
| |
| for (const auto& object : subtree) |
| { |
| nlohmann::json item; |
| std::string path = object.first.filename(); |
| if (path.empty()) |
| { |
| continue; |
| } |
| |
| item["@odata.id"] = boost::urls::format( |
| "/redfish/v1/Managers/{}/VirtualMedia/{}", name, path); |
| members.emplace_back(std::move(item)); |
| } |
| asyncResp->res.jsonValue["Members@odata.count"] = members.size(); |
| }); |
| } |
| |
| inline void |
| afterGetVmData(const std::string& name, const std::string& /*service*/, |
| const std::string& resName, |
| const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, |
| const std::pair<sdbusplus::message::object_path, |
| dbus::utility::DBusInterfacesMap>& item) |
| { |
| VmMode mode = parseObjectPathAndGetMode(item.first, resName); |
| if (mode == VmMode::Invalid) |
| { |
| return; |
| } |
| |
| asyncResp->res.jsonValue = vmItemTemplate(name, resName); |
| |
| // Check if dbus path is Legacy type |
| if (mode == VmMode::Legacy) |
| { |
| asyncResp->res.jsonValue["Actions"]["#VirtualMedia.InsertMedia"] |
| ["target"] = boost::urls::format( |
| "/redfish/v1/Managers/{}/VirtualMedia/{}/Actions/VirtualMedia.InsertMedia", |
| name, resName); |
| } |
| |
| vmParseInterfaceObject(item.second, asyncResp); |
| |
| asyncResp->res.jsonValue["Actions"]["#VirtualMedia.EjectMedia"] |
| ["target"] = boost::urls::format( |
| "/redfish/v1/Managers/{}/VirtualMedia/{}/Actions/VirtualMedia.EjectMedia", |
| name, resName); |
| } |
| |
| /** |
| * @brief Fills data for specific resource |
| */ |
| inline void getVmData(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, |
| const std::string& service, const std::string& name, |
| const std::string& resName) |
| { |
| BMCWEB_LOG_DEBUG("Get Virtual Media resource data."); |
| |
| findAndParseObject(service, resName, asyncResp, |
| std::bind_front(afterGetVmData, name)); |
| } |
| |
| /** |
| * @brief Transfer protocols supported for InsertMedia action. |
| * |
| */ |
| enum class TransferProtocol |
| { |
| https, |
| smb, |
| invalid |
| }; |
| |
| /** |
| * @brief Function extracts transfer protocol type from URI. |
| * |
| */ |
| inline std::optional<TransferProtocol> |
| getTransferProtocolFromUri(const boost::urls::url_view_base& imageUri) |
| { |
| std::string_view scheme = imageUri.scheme(); |
| if (scheme == "smb") |
| { |
| return TransferProtocol::smb; |
| } |
| if (scheme == "https") |
| { |
| return TransferProtocol::https; |
| } |
| if (!scheme.empty()) |
| { |
| return TransferProtocol::invalid; |
| } |
| |
| return {}; |
| } |
| |
| /** |
| * @brief Function convert transfer protocol from string param. |
| * |
| */ |
| inline std::optional<TransferProtocol> getTransferProtocolFromParam( |
| const std::optional<std::string>& transferProtocolType) |
| { |
| if (!transferProtocolType) |
| { |
| return {}; |
| } |
| |
| if (*transferProtocolType == "CIFS") |
| { |
| return TransferProtocol::smb; |
| } |
| |
| if (*transferProtocolType == "HTTPS") |
| { |
| return TransferProtocol::https; |
| } |
| |
| return TransferProtocol::invalid; |
| } |
| |
| /** |
| * @brief Function extends URI with transfer protocol type. |
| * |
| */ |
| inline std::string getUriWithTransferProtocol( |
| const std::string& imageUri, const TransferProtocol& transferProtocol) |
| { |
| if (transferProtocol == TransferProtocol::smb) |
| { |
| return "smb://" + imageUri; |
| } |
| |
| if (transferProtocol == TransferProtocol::https) |
| { |
| return "https://" + imageUri; |
| } |
| |
| return imageUri; |
| } |
| |
| struct InsertMediaActionParams |
| { |
| std::optional<std::string> imageUrl; |
| std::optional<std::string> userName; |
| std::optional<std::string> password; |
| std::optional<std::string> transferMethod; |
| std::optional<std::string> transferProtocolType; |
| std::optional<bool> writeProtected = true; |
| std::optional<bool> inserted; |
| }; |
| |
| /** |
| * @brief Function transceives data with dbus directly. |
| * |
| * All BMC state properties will be retrieved before sending reset request. |
| */ |
| inline void doMountVmLegacy(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, |
| const std::string& service, const std::string& name, |
| const std::string& imageUrl, bool rw, |
| std::string&& userName, std::string&& password) |
| { |
| int fd = -1; |
| std::shared_ptr<CredentialsPipe> secretPipe; |
| if (!userName.empty() || !password.empty()) |
| { |
| // Payload must contain data + NULL delimiters |
| constexpr const size_t secretLimit = 1024; |
| if (userName.size() + password.size() + 2 > secretLimit) |
| { |
| BMCWEB_LOG_ERROR("Credentials too long to handle"); |
| messages::unrecognizedRequestBody(asyncResp->res); |
| return; |
| } |
| |
| // Open pipe |
| secretPipe = std::make_shared<CredentialsPipe>( |
| crow::connections::systemBus->get_io_context()); |
| fd = secretPipe->releaseFd(); |
| |
| // Pass secret over pipe |
| secretPipe->asyncWrite( |
| std::move(userName), std::move(password), |
| [asyncResp, |
| secretPipe](const boost::system::error_code& ec, std::size_t) { |
| if (ec) |
| { |
| BMCWEB_LOG_ERROR("Failed to pass secret: {}", ec); |
| messages::internalError(asyncResp->res); |
| } |
| }); |
| } |
| |
| dbus::utility::DbusVariantType unixFd( |
| std::in_place_type<sdbusplus::message::unix_fd>, fd); |
| |
| sdbusplus::message::object_path path( |
| "/xyz/openbmc_project/VirtualMedia/Legacy"); |
| path /= name; |
| crow::connections::systemBus->async_method_call( |
| [asyncResp, |
| secretPipe](const boost::system::error_code& ec, bool success) { |
| if (ec) |
| { |
| BMCWEB_LOG_ERROR("Bad D-Bus request error: {}", ec); |
| messages::internalError(asyncResp->res); |
| return; |
| } |
| if (!success) |
| { |
| BMCWEB_LOG_ERROR("Service responded with error"); |
| messages::internalError(asyncResp->res); |
| } |
| }, |
| service, path.str, "xyz.openbmc_project.VirtualMedia.Legacy", "Mount", |
| imageUrl, rw, unixFd); |
| } |
| |
| /** |
| * @brief Function validate parameters of insert media request. |
| * |
| */ |
| inline void validateParams(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, |
| const std::string& service, |
| const std::string& resName, |
| InsertMediaActionParams& actionParams) |
| { |
| BMCWEB_LOG_DEBUG("Validation started"); |
| // required param imageUrl must not be empty |
| if (!actionParams.imageUrl) |
| { |
| BMCWEB_LOG_ERROR("Request action parameter Image is empty."); |
| |
| messages::propertyValueFormatError(asyncResp->res, "<empty>", "Image"); |
| |
| return; |
| } |
| |
| // optional param inserted must be true |
| if (actionParams.inserted && !*actionParams.inserted) |
| { |
| BMCWEB_LOG_ERROR( |
| "Request action optional parameter Inserted must be true."); |
| |
| messages::actionParameterNotSupported(asyncResp->res, "Inserted", |
| "InsertMedia"); |
| |
| return; |
| } |
| |
| // optional param transferMethod must be stream |
| if (actionParams.transferMethod && |
| (*actionParams.transferMethod != "Stream")) |
| { |
| BMCWEB_LOG_ERROR("Request action optional parameter " |
| "TransferMethod must be Stream."); |
| |
| messages::actionParameterNotSupported(asyncResp->res, "TransferMethod", |
| "InsertMedia"); |
| |
| return; |
| } |
| boost::system::result<boost::urls::url_view> url = |
| boost::urls::parse_uri(*actionParams.imageUrl); |
| if (!url) |
| { |
| messages::actionParameterValueFormatError( |
| asyncResp->res, *actionParams.imageUrl, "Image", "InsertMedia"); |
| return; |
| } |
| std::optional<TransferProtocol> uriTransferProtocolType = |
| getTransferProtocolFromUri(*url); |
| |
| std::optional<TransferProtocol> paramTransferProtocolType = |
| getTransferProtocolFromParam(actionParams.transferProtocolType); |
| |
| // ImageUrl does not contain valid protocol type |
| if (uriTransferProtocolType && |
| *uriTransferProtocolType == TransferProtocol::invalid) |
| { |
| BMCWEB_LOG_ERROR("Request action parameter ImageUrl must " |
| "contain specified protocol type from list: " |
| "(smb, https)."); |
| |
| messages::resourceAtUriInUnknownFormat(asyncResp->res, *url); |
| |
| return; |
| } |
| |
| // transferProtocolType should contain value from list |
| if (paramTransferProtocolType && |
| *paramTransferProtocolType == TransferProtocol::invalid) |
| { |
| BMCWEB_LOG_ERROR("Request action parameter TransferProtocolType " |
| "must be provided with value from list: " |
| "(CIFS, HTTPS)."); |
| |
| messages::propertyValueNotInList( |
| asyncResp->res, actionParams.transferProtocolType.value_or(""), |
| "TransferProtocolType"); |
| return; |
| } |
| |
| // valid transfer protocol not provided either with URI nor param |
| if (!uriTransferProtocolType && !paramTransferProtocolType) |
| { |
| BMCWEB_LOG_ERROR("Request action parameter ImageUrl must " |
| "contain specified protocol type or param " |
| "TransferProtocolType must be provided."); |
| |
| messages::resourceAtUriInUnknownFormat(asyncResp->res, *url); |
| |
| return; |
| } |
| |
| // valid transfer protocol provided both with URI and param |
| if (paramTransferProtocolType && uriTransferProtocolType) |
| { |
| // check if protocol is the same for URI and param |
| if (*paramTransferProtocolType != *uriTransferProtocolType) |
| { |
| BMCWEB_LOG_ERROR("Request action parameter " |
| "TransferProtocolType must contain the " |
| "same protocol type as protocol type " |
| "provided with param imageUrl."); |
| |
| messages::actionParameterValueTypeError( |
| asyncResp->res, actionParams.transferProtocolType.value_or(""), |
| "TransferProtocolType", "InsertMedia"); |
| |
| return; |
| } |
| } |
| |
| // validation passed, add protocol to URI if needed |
| if (!uriTransferProtocolType && paramTransferProtocolType) |
| { |
| actionParams.imageUrl = getUriWithTransferProtocol( |
| *actionParams.imageUrl, *paramTransferProtocolType); |
| } |
| |
| if (!actionParams.userName) |
| { |
| actionParams.userName = ""; |
| } |
| |
| if (!actionParams.password) |
| { |
| actionParams.password = ""; |
| } |
| |
| doMountVmLegacy(asyncResp, service, resName, *actionParams.imageUrl, |
| !(actionParams.writeProtected.value_or(false)), |
| std::move(*actionParams.userName), |
| std::move(*actionParams.password)); |
| } |
| |
| /** |
| * @brief Function transceives data with dbus directly. |
| * |
| * All BMC state properties will be retrieved before sending reset request. |
| */ |
| inline void doEjectAction(const std::shared_ptr<bmcweb::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"); |
| } |
| } |
| |
| inline void handleManagersVirtualMediaActionInsertPost( |
| crow::App& app, const crow::Request& req, |
| const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, |
| const std::string& name, const std::string& resName) |
| { |
| if (!redfish::setUpRedfishRoute(app, req, asyncResp)) |
| { |
| return; |
| } |
| |
| constexpr std::string_view action = "VirtualMedia.InsertMedia"; |
| if (name != "bmc") |
| { |
| messages::resourceNotFound(asyncResp->res, action, resName); |
| |
| return; |
| } |
| InsertMediaActionParams actionParams; |
| |
| // Read obligatory parameters (url of image) |
| if (!json_util::readJsonAction( |
| req, asyncResp->res, "Image", actionParams.imageUrl, |
| "WriteProtected", actionParams.writeProtected, "UserName", |
| actionParams.userName, "Password", actionParams.password, |
| "Inserted", actionParams.inserted, "TransferMethod", |
| actionParams.transferMethod, "TransferProtocolType", |
| actionParams.transferProtocolType)) |
| { |
| return; |
| } |
| |
| dbus::utility::getDbusObject( |
| "/xyz/openbmc_project/VirtualMedia", {}, |
| [asyncResp, action, actionParams, |
| resName](const boost::system::error_code& ec, |
| const dbus::utility::MapperGetObject& getObjectType) mutable { |
| if (ec) |
| { |
| BMCWEB_LOG_ERROR("ObjectMapper::GetObject call failed: {}", ec); |
| messages::resourceNotFound(asyncResp->res, action, resName); |
| |
| return; |
| } |
| |
| std::string service = getObjectType.begin()->first; |
| BMCWEB_LOG_DEBUG("GetObjectType: {}", service); |
| |
| sdbusplus::message::object_path path( |
| "/xyz/openbmc_project/VirtualMedia"); |
| dbus::utility::getManagedObjects( |
| service, path, |
| [service, resName, action, actionParams, asyncResp]( |
| const boost::system::error_code& ec2, |
| const dbus::utility::ManagedObjectType& subtree) mutable { |
| if (ec2) |
| { |
| // Not possible in proxy mode |
| BMCWEB_LOG_DEBUG("InsertMedia not " |
| "allowed in proxy mode"); |
| messages::resourceNotFound(asyncResp->res, action, |
| resName); |
| |
| return; |
| } |
| for (const auto& object : subtree) |
| { |
| VmMode mode = |
| parseObjectPathAndGetMode(object.first, resName); |
| if (mode == VmMode::Legacy) |
| { |
| validateParams(asyncResp, service, resName, |
| actionParams); |
| |
| return; |
| } |
| } |
| BMCWEB_LOG_DEBUG("Parent item not found"); |
| messages::resourceNotFound(asyncResp->res, "VirtualMedia", |
| resName); |
| }); |
| }); |
| } |
| |
| inline void handleManagersVirtualMediaActionEject( |
| crow::App& app, const crow::Request& req, |
| const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, |
| const std::string& managerName, const std::string& resName) |
| { |
| if (!redfish::setUpRedfishRoute(app, req, asyncResp)) |
| { |
| return; |
| } |
| |
| constexpr std::string_view action = "VirtualMedia.EjectMedia"; |
| if (managerName != "bmc") |
| { |
| messages::resourceNotFound(asyncResp->res, action, resName); |
| |
| return; |
| } |
| |
| dbus::utility::getDbusObject( |
| "/xyz/openbmc_project/VirtualMedia", {}, |
| [asyncResp, action, |
| resName](const boost::system::error_code& ec2, |
| const dbus::utility::MapperGetObject& getObjectType) { |
| if (ec2) |
| { |
| BMCWEB_LOG_ERROR("ObjectMapper::GetObject call failed: {}", |
| ec2); |
| messages::internalError(asyncResp->res); |
| |
| return; |
| } |
| std::string service = getObjectType.begin()->first; |
| BMCWEB_LOG_DEBUG("GetObjectType: {}", service); |
| |
| sdbusplus::message::object_path path( |
| "/xyz/openbmc_project/VirtualMedia"); |
| dbus::utility::getManagedObjects( |
| service, path, |
| [resName, service, action, |
| asyncResp](const boost::system::error_code& ec, |
| const dbus::utility::ManagedObjectType& subtree) { |
| if (ec) |
| { |
| BMCWEB_LOG_ERROR("ObjectMapper : No Service found"); |
| messages::resourceNotFound(asyncResp->res, action, |
| resName); |
| return; |
| } |
| |
| for (const auto& object : subtree) |
| { |
| VmMode mode = |
| parseObjectPathAndGetMode(object.first, resName); |
| if (mode != VmMode::Invalid) |
| { |
| doEjectAction(asyncResp, service, resName, |
| mode == VmMode::Legacy); |
| return; |
| } |
| } |
| BMCWEB_LOG_DEBUG("Parent item not found"); |
| messages::resourceNotFound(asyncResp->res, "VirtualMedia", |
| resName); |
| }); |
| }); |
| } |
| |
| inline void handleManagersVirtualMediaCollectionGet( |
| crow::App& app, const crow::Request& req, |
| const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, |
| const std::string& name) |
| { |
| if (!redfish::setUpRedfishRoute(app, req, asyncResp)) |
| { |
| return; |
| } |
| if (name != "bmc") |
| { |
| messages::resourceNotFound(asyncResp->res, "VirtualMedia", name); |
| |
| return; |
| } |
| |
| asyncResp->res.jsonValue["@odata.type"] = |
| "#VirtualMediaCollection.VirtualMediaCollection"; |
| asyncResp->res.jsonValue["Name"] = "Virtual Media Services"; |
| asyncResp->res.jsonValue["@odata.id"] = |
| boost::urls::format("/redfish/v1/Managers/{}/VirtualMedia", name); |
| |
| dbus::utility::getDbusObject( |
| "/xyz/openbmc_project/VirtualMedia", {}, |
| [asyncResp, name](const boost::system::error_code& ec, |
| const dbus::utility::MapperGetObject& getObjectType) { |
| if (ec) |
| { |
| BMCWEB_LOG_ERROR("ObjectMapper::GetObject call failed: {}", ec); |
| messages::internalError(asyncResp->res); |
| |
| return; |
| } |
| std::string service = getObjectType.begin()->first; |
| BMCWEB_LOG_DEBUG("GetObjectType: {}", service); |
| |
| getVmResourceList(asyncResp, service, name); |
| }); |
| } |
| |
| inline void |
| handleVirtualMediaGet(crow::App& app, const crow::Request& req, |
| const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, |
| const std::string& name, const std::string& resName) |
| { |
| if (!redfish::setUpRedfishRoute(app, req, asyncResp)) |
| { |
| return; |
| } |
| if (name != "bmc") |
| { |
| messages::resourceNotFound(asyncResp->res, "VirtualMedia", resName); |
| |
| return; |
| } |
| |
| dbus::utility::getDbusObject( |
| "/xyz/openbmc_project/VirtualMedia", {}, |
| [asyncResp, name, |
| resName](const boost::system::error_code& ec, |
| const dbus::utility::MapperGetObject& getObjectType) { |
| if (ec) |
| { |
| BMCWEB_LOG_ERROR("ObjectMapper::GetObject call failed: {}", ec); |
| messages::internalError(asyncResp->res); |
| |
| return; |
| } |
| std::string service = getObjectType.begin()->first; |
| BMCWEB_LOG_DEBUG("GetObjectType: {}", service); |
| |
| getVmData(asyncResp, service, name, resName); |
| }); |
| } |
| |
| inline void requestNBDVirtualMediaRoutes(App& app) |
| { |
| BMCWEB_ROUTE( |
| app, |
| "/redfish/v1/Managers/<str>/VirtualMedia/<str>/Actions/VirtualMedia.InsertMedia") |
| .privileges(redfish::privileges::postVirtualMedia) |
| .methods(boost::beast::http::verb::post)(std::bind_front( |
| handleManagersVirtualMediaActionInsertPost, std::ref(app))); |
| |
| BMCWEB_ROUTE( |
| app, |
| "/redfish/v1/Managers/<str>/VirtualMedia/<str>/Actions/VirtualMedia.EjectMedia") |
| .privileges(redfish::privileges::postVirtualMedia) |
| .methods(boost::beast::http::verb::post)(std::bind_front( |
| handleManagersVirtualMediaActionEject, std::ref(app))); |
| |
| BMCWEB_ROUTE(app, "/redfish/v1/Managers/<str>/VirtualMedia/") |
| .privileges(redfish::privileges::getVirtualMediaCollection) |
| .methods(boost::beast::http::verb::get)(std::bind_front( |
| handleManagersVirtualMediaCollectionGet, std::ref(app))); |
| |
| BMCWEB_ROUTE(app, "/redfish/v1/Managers/<str>/VirtualMedia/<str>/") |
| .privileges(redfish::privileges::getVirtualMedia) |
| .methods(boost::beast::http::verb::get)( |
| std::bind_front(handleVirtualMediaGet, std::ref(app))); |
| } |
| |
| } // namespace redfish |