1107077deSPrzemyslaw Czarnowski /* 2107077deSPrzemyslaw Czarnowski // Copyright (c) 2018 Intel Corporation 3107077deSPrzemyslaw Czarnowski // 4107077deSPrzemyslaw Czarnowski // Licensed under the Apache License, Version 2.0 (the "License"); 5107077deSPrzemyslaw Czarnowski // you may not use this file except in compliance with the License. 6107077deSPrzemyslaw Czarnowski // You may obtain a copy of the License at 7107077deSPrzemyslaw Czarnowski // 8107077deSPrzemyslaw Czarnowski // http://www.apache.org/licenses/LICENSE-2.0 9107077deSPrzemyslaw Czarnowski // 10107077deSPrzemyslaw Czarnowski // Unless required by applicable law or agreed to in writing, software 11107077deSPrzemyslaw Czarnowski // distributed under the License is distributed on an "AS IS" BASIS, 12107077deSPrzemyslaw Czarnowski // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13107077deSPrzemyslaw Czarnowski // See the License for the specific language governing permissions and 14107077deSPrzemyslaw Czarnowski // limitations under the License. 15107077deSPrzemyslaw Czarnowski */ 16107077deSPrzemyslaw Czarnowski #pragma once 17107077deSPrzemyslaw Czarnowski 18107077deSPrzemyslaw Czarnowski #include <boost/container/flat_map.hpp> 19*988fb7b2SAdrian Ambrożewicz #include <boost/process/async_pipe.hpp> 20*988fb7b2SAdrian Ambrożewicz #include <boost/type_traits/has_dereference.hpp> 21107077deSPrzemyslaw Czarnowski #include <node.hpp> 22107077deSPrzemyslaw Czarnowski #include <utils/json_utils.hpp> 23107077deSPrzemyslaw Czarnowski // for GetObjectType and ManagedObjectType 24e13c2760SPrzemyslaw Czarnowski #include <account_service.hpp> 25107077deSPrzemyslaw Czarnowski 26107077deSPrzemyslaw Czarnowski namespace redfish 27107077deSPrzemyslaw Czarnowski 28107077deSPrzemyslaw Czarnowski { 29107077deSPrzemyslaw Czarnowski 30107077deSPrzemyslaw Czarnowski /** 31107077deSPrzemyslaw Czarnowski * @brief Read all known properties from VM object interfaces 32107077deSPrzemyslaw Czarnowski */ 33107077deSPrzemyslaw Czarnowski static void vmParseInterfaceObject(const DbusInterfaceType &interface, 34107077deSPrzemyslaw Czarnowski std::shared_ptr<AsyncResp> aResp) 35107077deSPrzemyslaw Czarnowski { 36107077deSPrzemyslaw Czarnowski const auto mountPointIface = 37107077deSPrzemyslaw Czarnowski interface.find("xyz.openbmc_project.VirtualMedia.MountPoint"); 38107077deSPrzemyslaw Czarnowski if (mountPointIface == interface.cend()) 39107077deSPrzemyslaw Czarnowski { 40107077deSPrzemyslaw Czarnowski BMCWEB_LOG_DEBUG << "Interface MountPoint not found"; 41107077deSPrzemyslaw Czarnowski return; 42107077deSPrzemyslaw Czarnowski } 43107077deSPrzemyslaw Czarnowski 44107077deSPrzemyslaw Czarnowski const auto processIface = 45107077deSPrzemyslaw Czarnowski interface.find("xyz.openbmc_project.VirtualMedia.Process"); 46107077deSPrzemyslaw Czarnowski if (processIface == interface.cend()) 47107077deSPrzemyslaw Czarnowski { 48107077deSPrzemyslaw Czarnowski BMCWEB_LOG_DEBUG << "Interface Process not found"; 49107077deSPrzemyslaw Czarnowski return; 50107077deSPrzemyslaw Czarnowski } 51107077deSPrzemyslaw Czarnowski 52107077deSPrzemyslaw Czarnowski const auto endpointIdProperty = mountPointIface->second.find("EndpointId"); 53107077deSPrzemyslaw Czarnowski if (endpointIdProperty == mountPointIface->second.cend()) 54107077deSPrzemyslaw Czarnowski { 55107077deSPrzemyslaw Czarnowski BMCWEB_LOG_DEBUG << "Property EndpointId not found"; 56107077deSPrzemyslaw Czarnowski return; 57107077deSPrzemyslaw Czarnowski } 58107077deSPrzemyslaw Czarnowski 59107077deSPrzemyslaw Czarnowski const auto activeProperty = processIface->second.find("Active"); 60107077deSPrzemyslaw Czarnowski if (activeProperty == processIface->second.cend()) 61107077deSPrzemyslaw Czarnowski { 62107077deSPrzemyslaw Czarnowski BMCWEB_LOG_DEBUG << "Property Active not found"; 63107077deSPrzemyslaw Czarnowski return; 64107077deSPrzemyslaw Czarnowski } 65107077deSPrzemyslaw Czarnowski 66107077deSPrzemyslaw Czarnowski const bool *activeValue = std::get_if<bool>(&activeProperty->second); 67107077deSPrzemyslaw Czarnowski if (!activeValue) 68107077deSPrzemyslaw Czarnowski { 69107077deSPrzemyslaw Czarnowski BMCWEB_LOG_DEBUG << "Value Active not found"; 70107077deSPrzemyslaw Czarnowski return; 71107077deSPrzemyslaw Czarnowski } 72107077deSPrzemyslaw Czarnowski 73107077deSPrzemyslaw Czarnowski const std::string *endpointIdValue = 74107077deSPrzemyslaw Czarnowski std::get_if<std::string>(&endpointIdProperty->second); 75107077deSPrzemyslaw Czarnowski if (endpointIdValue) 76107077deSPrzemyslaw Czarnowski { 77107077deSPrzemyslaw Czarnowski if (!endpointIdValue->empty()) 78107077deSPrzemyslaw Czarnowski { 79107077deSPrzemyslaw Czarnowski // Proxy mode 80d04ba325SPrzemyslaw Czarnowski aResp->res.jsonValue["Oem"]["OpenBMC"]["WebSocketEndpoint"] = 81d04ba325SPrzemyslaw Czarnowski *endpointIdValue; 82107077deSPrzemyslaw Czarnowski aResp->res.jsonValue["TransferProtocolType"] = "OEM"; 83107077deSPrzemyslaw Czarnowski aResp->res.jsonValue["Inserted"] = *activeValue; 84107077deSPrzemyslaw Czarnowski if (*activeValue == true) 85107077deSPrzemyslaw Czarnowski { 86107077deSPrzemyslaw Czarnowski aResp->res.jsonValue["ConnectedVia"] = "Applet"; 87107077deSPrzemyslaw Czarnowski } 88107077deSPrzemyslaw Czarnowski } 89107077deSPrzemyslaw Czarnowski else 90107077deSPrzemyslaw Czarnowski { 91107077deSPrzemyslaw Czarnowski // Legacy mode 92107077deSPrzemyslaw Czarnowski const auto imageUrlProperty = 93107077deSPrzemyslaw Czarnowski mountPointIface->second.find("ImageURL"); 94107077deSPrzemyslaw Czarnowski if (imageUrlProperty != processIface->second.cend()) 95107077deSPrzemyslaw Czarnowski { 96107077deSPrzemyslaw Czarnowski const std::string *imageUrlValue = 97107077deSPrzemyslaw Czarnowski std::get_if<std::string>(&imageUrlProperty->second); 98107077deSPrzemyslaw Czarnowski if (imageUrlValue && !imageUrlValue->empty()) 99107077deSPrzemyslaw Czarnowski { 100107077deSPrzemyslaw Czarnowski aResp->res.jsonValue["ImageName"] = *imageUrlValue; 101107077deSPrzemyslaw Czarnowski aResp->res.jsonValue["Inserted"] = *activeValue; 102107077deSPrzemyslaw Czarnowski if (*activeValue == true) 103107077deSPrzemyslaw Czarnowski { 104107077deSPrzemyslaw Czarnowski aResp->res.jsonValue["ConnectedVia"] = "URI"; 105107077deSPrzemyslaw Czarnowski } 106107077deSPrzemyslaw Czarnowski } 107107077deSPrzemyslaw Czarnowski } 108107077deSPrzemyslaw Czarnowski } 109107077deSPrzemyslaw Czarnowski } 110107077deSPrzemyslaw Czarnowski } 111107077deSPrzemyslaw Czarnowski 112107077deSPrzemyslaw Czarnowski /** 113107077deSPrzemyslaw Czarnowski * @brief Fill template for Virtual Media Item. 114107077deSPrzemyslaw Czarnowski */ 115107077deSPrzemyslaw Czarnowski static nlohmann::json vmItemTemplate(const std::string &name, 116107077deSPrzemyslaw Czarnowski const std::string &resName) 117107077deSPrzemyslaw Czarnowski { 118107077deSPrzemyslaw Czarnowski nlohmann::json item; 119107077deSPrzemyslaw Czarnowski item["@odata.id"] = 120107077deSPrzemyslaw Czarnowski "/redfish/v1/Managers/" + name + "/VirtualMedia/" + resName; 121d04ba325SPrzemyslaw Czarnowski item["@odata.type"] = "#VirtualMedia.v1_3_0.VirtualMedia"; 122107077deSPrzemyslaw Czarnowski item["Name"] = "Virtual Removable Media"; 123107077deSPrzemyslaw Czarnowski item["Id"] = resName; 124107077deSPrzemyslaw Czarnowski item["Image"] = nullptr; 125107077deSPrzemyslaw Czarnowski item["Inserted"] = nullptr; 126107077deSPrzemyslaw Czarnowski item["ImageName"] = nullptr; 127107077deSPrzemyslaw Czarnowski item["WriteProtected"] = true; 128107077deSPrzemyslaw Czarnowski item["ConnectedVia"] = "NotConnected"; 129107077deSPrzemyslaw Czarnowski item["MediaTypes"] = {"CD", "USBStick"}; 130107077deSPrzemyslaw Czarnowski item["TransferMethod"] = "Stream"; 131107077deSPrzemyslaw Czarnowski item["TransferProtocolType"] = nullptr; 132d04ba325SPrzemyslaw Czarnowski item["Oem"]["OpenBmc"]["WebSocketEndpoint"] = nullptr; 133d04ba325SPrzemyslaw Czarnowski item["Oem"]["OpenBMC"]["@odata.type"] = 134d04ba325SPrzemyslaw Czarnowski "#OemVirtualMedia.v1_0_0.VirtualMedia"; 135107077deSPrzemyslaw Czarnowski 136107077deSPrzemyslaw Czarnowski return item; 137107077deSPrzemyslaw Czarnowski } 138107077deSPrzemyslaw Czarnowski 139107077deSPrzemyslaw Czarnowski /** 140107077deSPrzemyslaw Czarnowski * @brief Fills collection data 141107077deSPrzemyslaw Czarnowski */ 142107077deSPrzemyslaw Czarnowski static void getVmResourceList(std::shared_ptr<AsyncResp> aResp, 143107077deSPrzemyslaw Czarnowski const std::string &service, 144107077deSPrzemyslaw Czarnowski const std::string &name) 145107077deSPrzemyslaw Czarnowski { 146107077deSPrzemyslaw Czarnowski BMCWEB_LOG_DEBUG << "Get available Virtual Media resources."; 147107077deSPrzemyslaw Czarnowski crow::connections::systemBus->async_method_call( 148107077deSPrzemyslaw Czarnowski [name, aResp{std::move(aResp)}](const boost::system::error_code ec, 149107077deSPrzemyslaw Czarnowski ManagedObjectType &subtree) { 150107077deSPrzemyslaw Czarnowski if (ec) 151107077deSPrzemyslaw Czarnowski { 152107077deSPrzemyslaw Czarnowski BMCWEB_LOG_DEBUG << "DBUS response error"; 153107077deSPrzemyslaw Czarnowski return; 154107077deSPrzemyslaw Czarnowski } 155107077deSPrzemyslaw Czarnowski nlohmann::json &members = aResp->res.jsonValue["Members"]; 156107077deSPrzemyslaw Czarnowski members = nlohmann::json::array(); 157107077deSPrzemyslaw Czarnowski 158107077deSPrzemyslaw Czarnowski for (const auto &object : subtree) 159107077deSPrzemyslaw Czarnowski { 160107077deSPrzemyslaw Czarnowski nlohmann::json item; 161107077deSPrzemyslaw Czarnowski const std::string &path = 162107077deSPrzemyslaw Czarnowski static_cast<const std::string &>(object.first); 163107077deSPrzemyslaw Czarnowski std::size_t lastIndex = path.rfind("/"); 164107077deSPrzemyslaw Czarnowski if (lastIndex == std::string::npos) 165107077deSPrzemyslaw Czarnowski { 166107077deSPrzemyslaw Czarnowski continue; 167107077deSPrzemyslaw Czarnowski } 168107077deSPrzemyslaw Czarnowski 169107077deSPrzemyslaw Czarnowski lastIndex += 1; 170107077deSPrzemyslaw Czarnowski 171107077deSPrzemyslaw Czarnowski item["@odata.id"] = "/redfish/v1/Managers/" + name + 172107077deSPrzemyslaw Czarnowski "/VirtualMedia/" + path.substr(lastIndex); 173107077deSPrzemyslaw Czarnowski 174107077deSPrzemyslaw Czarnowski members.emplace_back(std::move(item)); 175107077deSPrzemyslaw Czarnowski } 176107077deSPrzemyslaw Czarnowski aResp->res.jsonValue["Members@odata.count"] = members.size(); 177107077deSPrzemyslaw Czarnowski }, 178107077deSPrzemyslaw Czarnowski service, "/xyz/openbmc_project/VirtualMedia", 179107077deSPrzemyslaw Czarnowski "org.freedesktop.DBus.ObjectManager", "GetManagedObjects"); 180107077deSPrzemyslaw Czarnowski } 181107077deSPrzemyslaw Czarnowski 182107077deSPrzemyslaw Czarnowski /** 183107077deSPrzemyslaw Czarnowski * @brief Fills data for specific resource 184107077deSPrzemyslaw Czarnowski */ 185107077deSPrzemyslaw Czarnowski static void getVmData(std::shared_ptr<AsyncResp> aResp, 186107077deSPrzemyslaw Czarnowski const std::string &service, const std::string &name, 187107077deSPrzemyslaw Czarnowski const std::string &resName) 188107077deSPrzemyslaw Czarnowski { 189107077deSPrzemyslaw Czarnowski BMCWEB_LOG_DEBUG << "Get Virtual Media resource data."; 190107077deSPrzemyslaw Czarnowski 191107077deSPrzemyslaw Czarnowski crow::connections::systemBus->async_method_call( 192107077deSPrzemyslaw Czarnowski [resName, name, aResp](const boost::system::error_code ec, 193107077deSPrzemyslaw Czarnowski ManagedObjectType &subtree) { 194107077deSPrzemyslaw Czarnowski if (ec) 195107077deSPrzemyslaw Czarnowski { 196107077deSPrzemyslaw Czarnowski BMCWEB_LOG_DEBUG << "DBUS response error"; 197e13c2760SPrzemyslaw Czarnowski 198107077deSPrzemyslaw Czarnowski return; 199107077deSPrzemyslaw Czarnowski } 200107077deSPrzemyslaw Czarnowski 201107077deSPrzemyslaw Czarnowski for (auto &item : subtree) 202107077deSPrzemyslaw Czarnowski { 203107077deSPrzemyslaw Czarnowski const std::string &path = 204107077deSPrzemyslaw Czarnowski static_cast<const std::string &>(item.first); 205107077deSPrzemyslaw Czarnowski 206107077deSPrzemyslaw Czarnowski std::size_t lastItem = path.rfind("/"); 207107077deSPrzemyslaw Czarnowski if (lastItem == std::string::npos) 208107077deSPrzemyslaw Czarnowski { 209107077deSPrzemyslaw Czarnowski continue; 210107077deSPrzemyslaw Czarnowski } 211107077deSPrzemyslaw Czarnowski 212107077deSPrzemyslaw Czarnowski if (path.substr(lastItem + 1) != resName) 213107077deSPrzemyslaw Czarnowski { 214107077deSPrzemyslaw Czarnowski continue; 215107077deSPrzemyslaw Czarnowski } 216107077deSPrzemyslaw Czarnowski 217107077deSPrzemyslaw Czarnowski aResp->res.jsonValue = vmItemTemplate(name, resName); 218107077deSPrzemyslaw Czarnowski 219e13c2760SPrzemyslaw Czarnowski // Check if dbus path is Legacy type 220e13c2760SPrzemyslaw Czarnowski if (path.find("VirtualMedia/Legacy") != std::string::npos) 221e13c2760SPrzemyslaw Czarnowski { 222e13c2760SPrzemyslaw Czarnowski aResp->res.jsonValue["Actions"]["#VirtualMedia.InsertMedia"] 223e13c2760SPrzemyslaw Czarnowski ["target"] = 224e13c2760SPrzemyslaw Czarnowski "/redfish/v1/Managers/" + name + "/VirtualMedia/" + 225e13c2760SPrzemyslaw Czarnowski resName + "/Actions/VirtualMedia.InsertMedia"; 226e13c2760SPrzemyslaw Czarnowski } 227e13c2760SPrzemyslaw Czarnowski 228107077deSPrzemyslaw Czarnowski vmParseInterfaceObject(item.second, aResp); 229107077deSPrzemyslaw Czarnowski 230e13c2760SPrzemyslaw Czarnowski aResp->res.jsonValue["Actions"]["#VirtualMedia.EjectMedia"] 231e13c2760SPrzemyslaw Czarnowski ["target"] = 232e13c2760SPrzemyslaw Czarnowski "/redfish/v1/Managers/" + name + "/VirtualMedia/" + 233e13c2760SPrzemyslaw Czarnowski resName + "/Actions/VirtualMedia.EjectMedia"; 234e13c2760SPrzemyslaw Czarnowski 235107077deSPrzemyslaw Czarnowski return; 236107077deSPrzemyslaw Czarnowski } 237107077deSPrzemyslaw Czarnowski 238107077deSPrzemyslaw Czarnowski messages::resourceNotFound( 239d04ba325SPrzemyslaw Czarnowski aResp->res, "#VirtualMedia.v1_3_0.VirtualMedia", resName); 240107077deSPrzemyslaw Czarnowski }, 241107077deSPrzemyslaw Czarnowski service, "/xyz/openbmc_project/VirtualMedia", 242107077deSPrzemyslaw Czarnowski "org.freedesktop.DBus.ObjectManager", "GetManagedObjects"); 243107077deSPrzemyslaw Czarnowski } 244107077deSPrzemyslaw Czarnowski 245e13c2760SPrzemyslaw Czarnowski /** 246e13c2760SPrzemyslaw Czarnowski @brief InsertMedia action class 247e13c2760SPrzemyslaw Czarnowski */ 248e13c2760SPrzemyslaw Czarnowski class VirtualMediaActionInsertMedia : public Node 249e13c2760SPrzemyslaw Czarnowski { 250e13c2760SPrzemyslaw Czarnowski public: 251e13c2760SPrzemyslaw Czarnowski VirtualMediaActionInsertMedia(CrowApp &app) : 252e13c2760SPrzemyslaw Czarnowski Node(app, 253e13c2760SPrzemyslaw Czarnowski "/redfish/v1/Managers/<str>/VirtualMedia/<str>/Actions/" 254e13c2760SPrzemyslaw Czarnowski "VirtualMedia.InsertMedia", 255e13c2760SPrzemyslaw Czarnowski std::string(), std::string()) 256e13c2760SPrzemyslaw Czarnowski { 257e13c2760SPrzemyslaw Czarnowski entityPrivileges = { 258e13c2760SPrzemyslaw Czarnowski {boost::beast::http::verb::get, {{"Login"}}}, 259e13c2760SPrzemyslaw Czarnowski {boost::beast::http::verb::head, {{"Login"}}}, 260e13c2760SPrzemyslaw Czarnowski {boost::beast::http::verb::patch, {{"ConfigureManager"}}}, 261e13c2760SPrzemyslaw Czarnowski {boost::beast::http::verb::put, {{"ConfigureManager"}}}, 262e13c2760SPrzemyslaw Czarnowski {boost::beast::http::verb::delete_, {{"ConfigureManager"}}}, 263e13c2760SPrzemyslaw Czarnowski {boost::beast::http::verb::post, {{"ConfigureManager"}}}}; 264e13c2760SPrzemyslaw Czarnowski } 265e13c2760SPrzemyslaw Czarnowski 266e13c2760SPrzemyslaw Czarnowski private: 267e13c2760SPrzemyslaw Czarnowski /** 268e13c2760SPrzemyslaw Czarnowski * @brief Function handles POST method request. 269e13c2760SPrzemyslaw Czarnowski * 270e13c2760SPrzemyslaw Czarnowski * Analyzes POST body message before sends Reset request data to dbus. 271e13c2760SPrzemyslaw Czarnowski */ 272e13c2760SPrzemyslaw Czarnowski void doPost(crow::Response &res, const crow::Request &req, 273e13c2760SPrzemyslaw Czarnowski const std::vector<std::string> ¶ms) override 274e13c2760SPrzemyslaw Czarnowski { 275e13c2760SPrzemyslaw Czarnowski auto aResp = std::make_shared<AsyncResp>(res); 276e13c2760SPrzemyslaw Czarnowski 277e13c2760SPrzemyslaw Czarnowski if (params.size() != 2) 278e13c2760SPrzemyslaw Czarnowski { 279e13c2760SPrzemyslaw Czarnowski messages::internalError(res); 280e13c2760SPrzemyslaw Czarnowski return; 281e13c2760SPrzemyslaw Czarnowski } 282e13c2760SPrzemyslaw Czarnowski 283e13c2760SPrzemyslaw Czarnowski // take resource name from URL 284e13c2760SPrzemyslaw Czarnowski const std::string &resName = params[1]; 285e13c2760SPrzemyslaw Czarnowski 286e13c2760SPrzemyslaw Czarnowski if (params[0] != "bmc") 287e13c2760SPrzemyslaw Czarnowski { 288e13c2760SPrzemyslaw Czarnowski messages::resourceNotFound(res, "VirtualMedia.Insert", resName); 289e13c2760SPrzemyslaw Czarnowski 290e13c2760SPrzemyslaw Czarnowski return; 291e13c2760SPrzemyslaw Czarnowski } 292e13c2760SPrzemyslaw Czarnowski 293e13c2760SPrzemyslaw Czarnowski crow::connections::systemBus->async_method_call( 294e13c2760SPrzemyslaw Czarnowski [this, aResp{std::move(aResp)}, req, 295e13c2760SPrzemyslaw Czarnowski resName](const boost::system::error_code ec, 296e13c2760SPrzemyslaw Czarnowski const GetObjectType &getObjectType) { 297e13c2760SPrzemyslaw Czarnowski if (ec) 298e13c2760SPrzemyslaw Czarnowski { 299e13c2760SPrzemyslaw Czarnowski BMCWEB_LOG_ERROR << "ObjectMapper::GetObject call failed: " 300e13c2760SPrzemyslaw Czarnowski << ec; 301e13c2760SPrzemyslaw Czarnowski messages::internalError(aResp->res); 302e13c2760SPrzemyslaw Czarnowski 303e13c2760SPrzemyslaw Czarnowski return; 304e13c2760SPrzemyslaw Czarnowski } 305e13c2760SPrzemyslaw Czarnowski std::string service = getObjectType.begin()->first; 306e13c2760SPrzemyslaw Czarnowski BMCWEB_LOG_DEBUG << "GetObjectType: " << service; 307e13c2760SPrzemyslaw Czarnowski 308e13c2760SPrzemyslaw Czarnowski crow::connections::systemBus->async_method_call( 309e13c2760SPrzemyslaw Czarnowski [this, service, resName, req, aResp{std::move(aResp)}]( 310e13c2760SPrzemyslaw Czarnowski const boost::system::error_code ec, 311e13c2760SPrzemyslaw Czarnowski ManagedObjectType &subtree) { 312e13c2760SPrzemyslaw Czarnowski if (ec) 313e13c2760SPrzemyslaw Czarnowski { 314e13c2760SPrzemyslaw Czarnowski BMCWEB_LOG_DEBUG << "DBUS response error"; 315e13c2760SPrzemyslaw Czarnowski 316e13c2760SPrzemyslaw Czarnowski return; 317e13c2760SPrzemyslaw Czarnowski } 318e13c2760SPrzemyslaw Czarnowski 319e13c2760SPrzemyslaw Czarnowski for (const auto &object : subtree) 320e13c2760SPrzemyslaw Czarnowski { 321e13c2760SPrzemyslaw Czarnowski const std::string &path = 322e13c2760SPrzemyslaw Czarnowski static_cast<const std::string &>(object.first); 323e13c2760SPrzemyslaw Czarnowski 324e13c2760SPrzemyslaw Czarnowski std::size_t lastIndex = path.rfind("/"); 325e13c2760SPrzemyslaw Czarnowski if (lastIndex == std::string::npos) 326e13c2760SPrzemyslaw Czarnowski { 327e13c2760SPrzemyslaw Czarnowski continue; 328e13c2760SPrzemyslaw Czarnowski } 329e13c2760SPrzemyslaw Czarnowski 330e13c2760SPrzemyslaw Czarnowski lastIndex += 1; 331e13c2760SPrzemyslaw Czarnowski 332e13c2760SPrzemyslaw Czarnowski if (path.substr(lastIndex) == resName) 333e13c2760SPrzemyslaw Czarnowski { 334e13c2760SPrzemyslaw Czarnowski lastIndex = path.rfind("Proxy"); 335e13c2760SPrzemyslaw Czarnowski if (lastIndex != std::string::npos) 336e13c2760SPrzemyslaw Czarnowski { 337e13c2760SPrzemyslaw Czarnowski // Not possible in proxy mode 338e13c2760SPrzemyslaw Czarnowski BMCWEB_LOG_DEBUG << "InsertMedia not " 339e13c2760SPrzemyslaw Czarnowski "allowed in proxy mode"; 340e13c2760SPrzemyslaw Czarnowski messages::resourceNotFound( 341e13c2760SPrzemyslaw Czarnowski aResp->res, "VirtualMedia.InsertMedia", 342e13c2760SPrzemyslaw Czarnowski resName); 343e13c2760SPrzemyslaw Czarnowski 344e13c2760SPrzemyslaw Czarnowski return; 345e13c2760SPrzemyslaw Czarnowski } 346e13c2760SPrzemyslaw Czarnowski 347e13c2760SPrzemyslaw Czarnowski lastIndex = path.rfind("Legacy"); 348e13c2760SPrzemyslaw Czarnowski if (lastIndex != std::string::npos) 349e13c2760SPrzemyslaw Czarnowski { 350e13c2760SPrzemyslaw Czarnowski // Legacy mode 351e13c2760SPrzemyslaw Czarnowski std::string imageUrl; 352*988fb7b2SAdrian Ambrożewicz std::string userName; 353*988fb7b2SAdrian Ambrożewicz std::string password; 354d6da5bebSAdrian Ambrożewicz bool writeProtected; 355e13c2760SPrzemyslaw Czarnowski 356e13c2760SPrzemyslaw Czarnowski // Read obligatory paramters (url of image) 357d6da5bebSAdrian Ambrożewicz if (!json_util::readJson( 358d6da5bebSAdrian Ambrożewicz req, aResp->res, "Image", imageUrl, 359*988fb7b2SAdrian Ambrożewicz "WriteProtected", writeProtected, 360*988fb7b2SAdrian Ambrożewicz "UserName", userName, "Password", 361*988fb7b2SAdrian Ambrożewicz password)) 362d6da5bebSAdrian Ambrożewicz 363e13c2760SPrzemyslaw Czarnowski { 364e13c2760SPrzemyslaw Czarnowski BMCWEB_LOG_DEBUG 365e13c2760SPrzemyslaw Czarnowski << "Image is not provided"; 366e13c2760SPrzemyslaw Czarnowski return; 367e13c2760SPrzemyslaw Czarnowski } 368e13c2760SPrzemyslaw Czarnowski 369e13c2760SPrzemyslaw Czarnowski // must not be empty 370e13c2760SPrzemyslaw Czarnowski if (imageUrl.size() == 0) 371e13c2760SPrzemyslaw Czarnowski { 372e13c2760SPrzemyslaw Czarnowski BMCWEB_LOG_ERROR 373e13c2760SPrzemyslaw Czarnowski << "Request action parameter " 374e13c2760SPrzemyslaw Czarnowski "Image is empty."; 375e13c2760SPrzemyslaw Czarnowski messages::propertyValueFormatError( 376e13c2760SPrzemyslaw Czarnowski aResp->res, "<empty>", "Image"); 377e13c2760SPrzemyslaw Czarnowski 378e13c2760SPrzemyslaw Czarnowski return; 379e13c2760SPrzemyslaw Czarnowski } 380e13c2760SPrzemyslaw Czarnowski 381e13c2760SPrzemyslaw Czarnowski // manager is irrelevant for VirtualMedia 382e13c2760SPrzemyslaw Czarnowski // dbus calls 383d6da5bebSAdrian Ambrożewicz doMountVmLegacy(std::move(aResp), service, 384d6da5bebSAdrian Ambrożewicz resName, imageUrl, 385*988fb7b2SAdrian Ambrożewicz !writeProtected, 386*988fb7b2SAdrian Ambrożewicz std::move(userName), 387*988fb7b2SAdrian Ambrożewicz std::move(password)); 388e13c2760SPrzemyslaw Czarnowski 389e13c2760SPrzemyslaw Czarnowski return; 390e13c2760SPrzemyslaw Czarnowski } 391e13c2760SPrzemyslaw Czarnowski } 392e13c2760SPrzemyslaw Czarnowski } 393e13c2760SPrzemyslaw Czarnowski BMCWEB_LOG_DEBUG << "Parent item not found"; 394e13c2760SPrzemyslaw Czarnowski messages::resourceNotFound(aResp->res, "VirtualMedia", 395e13c2760SPrzemyslaw Czarnowski resName); 396e13c2760SPrzemyslaw Czarnowski }, 397e13c2760SPrzemyslaw Czarnowski service, "/xyz/openbmc_project/VirtualMedia", 398e13c2760SPrzemyslaw Czarnowski "org.freedesktop.DBus.ObjectManager", "GetManagedObjects"); 399e13c2760SPrzemyslaw Czarnowski }, 400e13c2760SPrzemyslaw Czarnowski "xyz.openbmc_project.ObjectMapper", 401e13c2760SPrzemyslaw Czarnowski "/xyz/openbmc_project/object_mapper", 402e13c2760SPrzemyslaw Czarnowski "xyz.openbmc_project.ObjectMapper", "GetObject", 403e13c2760SPrzemyslaw Czarnowski "/xyz/openbmc_project/VirtualMedia", std::array<const char *, 0>()); 404e13c2760SPrzemyslaw Czarnowski } 405e13c2760SPrzemyslaw Czarnowski 406*988fb7b2SAdrian Ambrożewicz template <typename T> static void secureCleanup(T &value) 407*988fb7b2SAdrian Ambrożewicz { 408*988fb7b2SAdrian Ambrożewicz auto raw = const_cast<typename T::value_type *>(value.data()); 409*988fb7b2SAdrian Ambrożewicz explicit_bzero(raw, value.size() * sizeof(*raw)); 410*988fb7b2SAdrian Ambrożewicz } 411*988fb7b2SAdrian Ambrożewicz 412*988fb7b2SAdrian Ambrożewicz class Credentials 413*988fb7b2SAdrian Ambrożewicz { 414*988fb7b2SAdrian Ambrożewicz public: 415*988fb7b2SAdrian Ambrożewicz Credentials(std::string &&user, std::string &&password) : 416*988fb7b2SAdrian Ambrożewicz userBuf(std::move(user)), passBuf(std::move(password)) 417*988fb7b2SAdrian Ambrożewicz { 418*988fb7b2SAdrian Ambrożewicz } 419*988fb7b2SAdrian Ambrożewicz 420*988fb7b2SAdrian Ambrożewicz ~Credentials() 421*988fb7b2SAdrian Ambrożewicz { 422*988fb7b2SAdrian Ambrożewicz secureCleanup(userBuf); 423*988fb7b2SAdrian Ambrożewicz secureCleanup(passBuf); 424*988fb7b2SAdrian Ambrożewicz } 425*988fb7b2SAdrian Ambrożewicz 426*988fb7b2SAdrian Ambrożewicz const std::string &user() 427*988fb7b2SAdrian Ambrożewicz { 428*988fb7b2SAdrian Ambrożewicz return userBuf; 429*988fb7b2SAdrian Ambrożewicz } 430*988fb7b2SAdrian Ambrożewicz 431*988fb7b2SAdrian Ambrożewicz const std::string &password() 432*988fb7b2SAdrian Ambrożewicz { 433*988fb7b2SAdrian Ambrożewicz return passBuf; 434*988fb7b2SAdrian Ambrożewicz } 435*988fb7b2SAdrian Ambrożewicz 436*988fb7b2SAdrian Ambrożewicz private: 437*988fb7b2SAdrian Ambrożewicz Credentials() = delete; 438*988fb7b2SAdrian Ambrożewicz Credentials(const Credentials &) = delete; 439*988fb7b2SAdrian Ambrożewicz Credentials &operator=(const Credentials &) = delete; 440*988fb7b2SAdrian Ambrożewicz 441*988fb7b2SAdrian Ambrożewicz std::string userBuf; 442*988fb7b2SAdrian Ambrożewicz std::string passBuf; 443*988fb7b2SAdrian Ambrożewicz }; 444*988fb7b2SAdrian Ambrożewicz 445*988fb7b2SAdrian Ambrożewicz class CredentialsProvider 446*988fb7b2SAdrian Ambrożewicz { 447*988fb7b2SAdrian Ambrożewicz public: 448*988fb7b2SAdrian Ambrożewicz template <typename T> struct Deleter 449*988fb7b2SAdrian Ambrożewicz { 450*988fb7b2SAdrian Ambrożewicz void operator()(T *buff) const 451*988fb7b2SAdrian Ambrożewicz { 452*988fb7b2SAdrian Ambrożewicz if (buff) 453*988fb7b2SAdrian Ambrożewicz { 454*988fb7b2SAdrian Ambrożewicz secureCleanup(*buff); 455*988fb7b2SAdrian Ambrożewicz delete buff; 456*988fb7b2SAdrian Ambrożewicz } 457*988fb7b2SAdrian Ambrożewicz } 458*988fb7b2SAdrian Ambrożewicz }; 459*988fb7b2SAdrian Ambrożewicz 460*988fb7b2SAdrian Ambrożewicz using Buffer = std::vector<char>; 461*988fb7b2SAdrian Ambrożewicz using SecureBuffer = std::unique_ptr<Buffer, Deleter<Buffer>>; 462*988fb7b2SAdrian Ambrożewicz // Using explicit definition instead of std::function to avoid implicit 463*988fb7b2SAdrian Ambrożewicz // conversions eg. stack copy instead of reference 464*988fb7b2SAdrian Ambrożewicz using FormatterFunc = void(const std::string &username, 465*988fb7b2SAdrian Ambrożewicz const std::string &password, Buffer &dest); 466*988fb7b2SAdrian Ambrożewicz 467*988fb7b2SAdrian Ambrożewicz CredentialsProvider(std::string &&user, std::string &&password) : 468*988fb7b2SAdrian Ambrożewicz credentials(std::move(user), std::move(password)) 469*988fb7b2SAdrian Ambrożewicz { 470*988fb7b2SAdrian Ambrożewicz } 471*988fb7b2SAdrian Ambrożewicz 472*988fb7b2SAdrian Ambrożewicz const std::string &user() 473*988fb7b2SAdrian Ambrożewicz { 474*988fb7b2SAdrian Ambrożewicz return credentials.user(); 475*988fb7b2SAdrian Ambrożewicz } 476*988fb7b2SAdrian Ambrożewicz 477*988fb7b2SAdrian Ambrożewicz const std::string &password() 478*988fb7b2SAdrian Ambrożewicz { 479*988fb7b2SAdrian Ambrożewicz return credentials.password(); 480*988fb7b2SAdrian Ambrożewicz } 481*988fb7b2SAdrian Ambrożewicz 482*988fb7b2SAdrian Ambrożewicz SecureBuffer pack(const FormatterFunc formatter) 483*988fb7b2SAdrian Ambrożewicz { 484*988fb7b2SAdrian Ambrożewicz SecureBuffer packed{new Buffer{}}; 485*988fb7b2SAdrian Ambrożewicz if (formatter) 486*988fb7b2SAdrian Ambrożewicz { 487*988fb7b2SAdrian Ambrożewicz formatter(credentials.user(), credentials.password(), *packed); 488*988fb7b2SAdrian Ambrożewicz } 489*988fb7b2SAdrian Ambrożewicz 490*988fb7b2SAdrian Ambrożewicz return packed; 491*988fb7b2SAdrian Ambrożewicz } 492*988fb7b2SAdrian Ambrożewicz 493*988fb7b2SAdrian Ambrożewicz private: 494*988fb7b2SAdrian Ambrożewicz Credentials credentials; 495*988fb7b2SAdrian Ambrożewicz }; 496*988fb7b2SAdrian Ambrożewicz 497*988fb7b2SAdrian Ambrożewicz // Wrapper for boost::async_pipe ensuring proper pipe cleanup 498*988fb7b2SAdrian Ambrożewicz template <typename Buffer> class Pipe 499*988fb7b2SAdrian Ambrożewicz { 500*988fb7b2SAdrian Ambrożewicz public: 501*988fb7b2SAdrian Ambrożewicz using unix_fd = sdbusplus::message::unix_fd; 502*988fb7b2SAdrian Ambrożewicz 503*988fb7b2SAdrian Ambrożewicz Pipe(boost::asio::io_context &io, Buffer &&buffer) : 504*988fb7b2SAdrian Ambrożewicz impl(io), buffer{std::move(buffer)} 505*988fb7b2SAdrian Ambrożewicz { 506*988fb7b2SAdrian Ambrożewicz } 507*988fb7b2SAdrian Ambrożewicz 508*988fb7b2SAdrian Ambrożewicz ~Pipe() 509*988fb7b2SAdrian Ambrożewicz { 510*988fb7b2SAdrian Ambrożewicz // Named pipe needs to be explicitly removed 511*988fb7b2SAdrian Ambrożewicz impl.close(); 512*988fb7b2SAdrian Ambrożewicz } 513*988fb7b2SAdrian Ambrożewicz 514*988fb7b2SAdrian Ambrożewicz unix_fd fd() 515*988fb7b2SAdrian Ambrożewicz { 516*988fb7b2SAdrian Ambrożewicz return unix_fd{impl.native_source()}; 517*988fb7b2SAdrian Ambrożewicz } 518*988fb7b2SAdrian Ambrożewicz 519*988fb7b2SAdrian Ambrożewicz template <typename WriteHandler> 520*988fb7b2SAdrian Ambrożewicz void async_write(WriteHandler &&handler) 521*988fb7b2SAdrian Ambrożewicz { 522*988fb7b2SAdrian Ambrożewicz impl.async_write_some(data(), std::forward<WriteHandler>(handler)); 523*988fb7b2SAdrian Ambrożewicz } 524*988fb7b2SAdrian Ambrożewicz 525*988fb7b2SAdrian Ambrożewicz private: 526*988fb7b2SAdrian Ambrożewicz // Specialization for pointer types 527*988fb7b2SAdrian Ambrożewicz template <typename B = Buffer> 528*988fb7b2SAdrian Ambrożewicz typename std::enable_if<boost::has_dereference<B>::value, 529*988fb7b2SAdrian Ambrożewicz boost::asio::const_buffer>::type 530*988fb7b2SAdrian Ambrożewicz data() 531*988fb7b2SAdrian Ambrożewicz { 532*988fb7b2SAdrian Ambrożewicz return boost::asio::buffer(*buffer); 533*988fb7b2SAdrian Ambrożewicz } 534*988fb7b2SAdrian Ambrożewicz 535*988fb7b2SAdrian Ambrożewicz template <typename B = Buffer> 536*988fb7b2SAdrian Ambrożewicz typename std::enable_if<!boost::has_dereference<B>::value, 537*988fb7b2SAdrian Ambrożewicz boost::asio::const_buffer>::type 538*988fb7b2SAdrian Ambrożewicz data() 539*988fb7b2SAdrian Ambrożewicz { 540*988fb7b2SAdrian Ambrożewicz return boost::asio::buffer(buffer); 541*988fb7b2SAdrian Ambrożewicz } 542*988fb7b2SAdrian Ambrożewicz 543*988fb7b2SAdrian Ambrożewicz const std::string name; 544*988fb7b2SAdrian Ambrożewicz boost::process::async_pipe impl; 545*988fb7b2SAdrian Ambrożewicz Buffer buffer; 546*988fb7b2SAdrian Ambrożewicz }; 547*988fb7b2SAdrian Ambrożewicz 548e13c2760SPrzemyslaw Czarnowski /** 549e13c2760SPrzemyslaw Czarnowski * @brief Function transceives data with dbus directly. 550e13c2760SPrzemyslaw Czarnowski * 551e13c2760SPrzemyslaw Czarnowski * All BMC state properties will be retrieved before sending reset request. 552e13c2760SPrzemyslaw Czarnowski */ 553d6da5bebSAdrian Ambrożewicz void doMountVmLegacy(std::shared_ptr<AsyncResp> asyncResp, 554e13c2760SPrzemyslaw Czarnowski const std::string &service, const std::string &name, 555*988fb7b2SAdrian Ambrożewicz const std::string &imageUrl, const bool rw, 556*988fb7b2SAdrian Ambrożewicz std::string &&userName, std::string &&password) 557e13c2760SPrzemyslaw Czarnowski { 558*988fb7b2SAdrian Ambrożewicz using SecurePipe = Pipe<CredentialsProvider::SecureBuffer>; 559*988fb7b2SAdrian Ambrożewicz constexpr const size_t secretLimit = 1024; 560*988fb7b2SAdrian Ambrożewicz 561*988fb7b2SAdrian Ambrożewicz std::shared_ptr<SecurePipe> secretPipe; 562*988fb7b2SAdrian Ambrożewicz std::variant<int, SecurePipe::unix_fd> unixFd = -1; 563*988fb7b2SAdrian Ambrożewicz 564*988fb7b2SAdrian Ambrożewicz if (!userName.empty() || !password.empty()) 565*988fb7b2SAdrian Ambrożewicz { 566*988fb7b2SAdrian Ambrożewicz // Encapsulate in safe buffer 567*988fb7b2SAdrian Ambrożewicz CredentialsProvider credentials(std::move(userName), 568*988fb7b2SAdrian Ambrożewicz std::move(password)); 569*988fb7b2SAdrian Ambrożewicz 570*988fb7b2SAdrian Ambrożewicz // Payload must contain data + NULL delimiters 571*988fb7b2SAdrian Ambrożewicz if (credentials.user().size() + credentials.password().size() + 2 > 572*988fb7b2SAdrian Ambrożewicz secretLimit) 573*988fb7b2SAdrian Ambrożewicz { 574*988fb7b2SAdrian Ambrożewicz BMCWEB_LOG_ERROR << "Credentials too long to handle"; 575*988fb7b2SAdrian Ambrożewicz messages::unrecognizedRequestBody(asyncResp->res); 576*988fb7b2SAdrian Ambrożewicz return; 577*988fb7b2SAdrian Ambrożewicz } 578*988fb7b2SAdrian Ambrożewicz 579*988fb7b2SAdrian Ambrożewicz // Pack secret 580*988fb7b2SAdrian Ambrożewicz auto secret = credentials.pack([](const auto &user, 581*988fb7b2SAdrian Ambrożewicz const auto &pass, auto &buff) { 582*988fb7b2SAdrian Ambrożewicz std::copy(user.begin(), user.end(), std::back_inserter(buff)); 583*988fb7b2SAdrian Ambrożewicz buff.push_back('\0'); 584*988fb7b2SAdrian Ambrożewicz std::copy(pass.begin(), pass.end(), std::back_inserter(buff)); 585*988fb7b2SAdrian Ambrożewicz buff.push_back('\0'); 586*988fb7b2SAdrian Ambrożewicz }); 587*988fb7b2SAdrian Ambrożewicz 588*988fb7b2SAdrian Ambrożewicz // Open pipe 589*988fb7b2SAdrian Ambrożewicz secretPipe = std::make_shared<SecurePipe>( 590*988fb7b2SAdrian Ambrożewicz crow::connections::systemBus->get_io_context(), 591*988fb7b2SAdrian Ambrożewicz std::move(secret)); 592*988fb7b2SAdrian Ambrożewicz unixFd = secretPipe->fd(); 593*988fb7b2SAdrian Ambrożewicz 594*988fb7b2SAdrian Ambrożewicz // Pass secret over pipe 595*988fb7b2SAdrian Ambrożewicz secretPipe->async_write( 596*988fb7b2SAdrian Ambrożewicz [asyncResp](const boost::system::error_code &ec, 597*988fb7b2SAdrian Ambrożewicz std::size_t size) { 598*988fb7b2SAdrian Ambrożewicz if (ec) 599*988fb7b2SAdrian Ambrożewicz { 600*988fb7b2SAdrian Ambrożewicz BMCWEB_LOG_ERROR << "Failed to pass secret: " << ec; 601*988fb7b2SAdrian Ambrożewicz messages::internalError(asyncResp->res); 602*988fb7b2SAdrian Ambrożewicz } 603*988fb7b2SAdrian Ambrożewicz }); 604*988fb7b2SAdrian Ambrożewicz } 605*988fb7b2SAdrian Ambrożewicz 606e13c2760SPrzemyslaw Czarnowski crow::connections::systemBus->async_method_call( 607*988fb7b2SAdrian Ambrożewicz [asyncResp, secretPipe](const boost::system::error_code ec, 608*988fb7b2SAdrian Ambrożewicz bool success) { 609e13c2760SPrzemyslaw Czarnowski if (ec) 610e13c2760SPrzemyslaw Czarnowski { 611e13c2760SPrzemyslaw Czarnowski BMCWEB_LOG_ERROR << "Bad D-Bus request error: " << ec; 612e13c2760SPrzemyslaw Czarnowski messages::internalError(asyncResp->res); 613d6da5bebSAdrian Ambrożewicz } 614d6da5bebSAdrian Ambrożewicz else if (!success) 615d6da5bebSAdrian Ambrożewicz { 616d6da5bebSAdrian Ambrożewicz BMCWEB_LOG_ERROR << "Service responded with error"; 617d6da5bebSAdrian Ambrożewicz messages::generalError(asyncResp->res); 618e13c2760SPrzemyslaw Czarnowski } 619e13c2760SPrzemyslaw Czarnowski }, 620e13c2760SPrzemyslaw Czarnowski service, "/xyz/openbmc_project/VirtualMedia/Legacy/" + name, 621*988fb7b2SAdrian Ambrożewicz "xyz.openbmc_project.VirtualMedia.Legacy", "Mount", imageUrl, rw, 622*988fb7b2SAdrian Ambrożewicz unixFd); 623e13c2760SPrzemyslaw Czarnowski } 624e13c2760SPrzemyslaw Czarnowski }; 625e13c2760SPrzemyslaw Czarnowski 626e13c2760SPrzemyslaw Czarnowski /** 627e13c2760SPrzemyslaw Czarnowski @brief EjectMedia action class 628e13c2760SPrzemyslaw Czarnowski */ 629e13c2760SPrzemyslaw Czarnowski class VirtualMediaActionEjectMedia : public Node 630e13c2760SPrzemyslaw Czarnowski { 631e13c2760SPrzemyslaw Czarnowski public: 632e13c2760SPrzemyslaw Czarnowski VirtualMediaActionEjectMedia(CrowApp &app) : 633e13c2760SPrzemyslaw Czarnowski Node(app, 634e13c2760SPrzemyslaw Czarnowski "/redfish/v1/Managers/<str>/VirtualMedia/<str>/Actions/" 635e13c2760SPrzemyslaw Czarnowski "VirtualMedia.EjectMedia", 636e13c2760SPrzemyslaw Czarnowski std::string(), std::string()) 637e13c2760SPrzemyslaw Czarnowski { 638e13c2760SPrzemyslaw Czarnowski entityPrivileges = { 639e13c2760SPrzemyslaw Czarnowski {boost::beast::http::verb::get, {{"Login"}}}, 640e13c2760SPrzemyslaw Czarnowski {boost::beast::http::verb::head, {{"Login"}}}, 641e13c2760SPrzemyslaw Czarnowski {boost::beast::http::verb::patch, {{"ConfigureManager"}}}, 642e13c2760SPrzemyslaw Czarnowski {boost::beast::http::verb::put, {{"ConfigureManager"}}}, 643e13c2760SPrzemyslaw Czarnowski {boost::beast::http::verb::delete_, {{"ConfigureManager"}}}, 644e13c2760SPrzemyslaw Czarnowski {boost::beast::http::verb::post, {{"ConfigureManager"}}}}; 645e13c2760SPrzemyslaw Czarnowski } 646e13c2760SPrzemyslaw Czarnowski 647e13c2760SPrzemyslaw Czarnowski private: 648e13c2760SPrzemyslaw Czarnowski /** 649e13c2760SPrzemyslaw Czarnowski * @brief Function handles POST method request. 650e13c2760SPrzemyslaw Czarnowski * 651e13c2760SPrzemyslaw Czarnowski * Analyzes POST body message before sends Reset request data to dbus. 652e13c2760SPrzemyslaw Czarnowski */ 653e13c2760SPrzemyslaw Czarnowski void doPost(crow::Response &res, const crow::Request &req, 654e13c2760SPrzemyslaw Czarnowski const std::vector<std::string> ¶ms) override 655e13c2760SPrzemyslaw Czarnowski { 656e13c2760SPrzemyslaw Czarnowski auto aResp = std::make_shared<AsyncResp>(res); 657e13c2760SPrzemyslaw Czarnowski 658e13c2760SPrzemyslaw Czarnowski if (params.size() != 2) 659e13c2760SPrzemyslaw Czarnowski { 660e13c2760SPrzemyslaw Czarnowski messages::internalError(res); 661e13c2760SPrzemyslaw Czarnowski return; 662e13c2760SPrzemyslaw Czarnowski } 663e13c2760SPrzemyslaw Czarnowski 664e13c2760SPrzemyslaw Czarnowski // take resource name from URL 665e13c2760SPrzemyslaw Czarnowski const std::string &resName = params[1]; 666e13c2760SPrzemyslaw Czarnowski 667e13c2760SPrzemyslaw Czarnowski if (params[0] != "bmc") 668e13c2760SPrzemyslaw Czarnowski { 669e13c2760SPrzemyslaw Czarnowski messages::resourceNotFound(res, "VirtualMedia.Eject", resName); 670e13c2760SPrzemyslaw Czarnowski 671e13c2760SPrzemyslaw Czarnowski return; 672e13c2760SPrzemyslaw Czarnowski } 673e13c2760SPrzemyslaw Czarnowski 674e13c2760SPrzemyslaw Czarnowski crow::connections::systemBus->async_method_call( 675e13c2760SPrzemyslaw Czarnowski [this, aResp{std::move(aResp)}, req, 676e13c2760SPrzemyslaw Czarnowski resName](const boost::system::error_code ec, 677e13c2760SPrzemyslaw Czarnowski const GetObjectType &getObjectType) { 678e13c2760SPrzemyslaw Czarnowski if (ec) 679e13c2760SPrzemyslaw Czarnowski { 680e13c2760SPrzemyslaw Czarnowski BMCWEB_LOG_ERROR << "ObjectMapper::GetObject call failed: " 681e13c2760SPrzemyslaw Czarnowski << ec; 682e13c2760SPrzemyslaw Czarnowski messages::internalError(aResp->res); 683e13c2760SPrzemyslaw Czarnowski 684e13c2760SPrzemyslaw Czarnowski return; 685e13c2760SPrzemyslaw Czarnowski } 686e13c2760SPrzemyslaw Czarnowski std::string service = getObjectType.begin()->first; 687e13c2760SPrzemyslaw Czarnowski BMCWEB_LOG_DEBUG << "GetObjectType: " << service; 688e13c2760SPrzemyslaw Czarnowski 689e13c2760SPrzemyslaw Czarnowski crow::connections::systemBus->async_method_call( 690e13c2760SPrzemyslaw Czarnowski [this, resName, service, req, aResp{std::move(aResp)}]( 691e13c2760SPrzemyslaw Czarnowski const boost::system::error_code ec, 692e13c2760SPrzemyslaw Czarnowski ManagedObjectType &subtree) { 693e13c2760SPrzemyslaw Czarnowski if (ec) 694e13c2760SPrzemyslaw Czarnowski { 695e13c2760SPrzemyslaw Czarnowski BMCWEB_LOG_DEBUG << "DBUS response error"; 696e13c2760SPrzemyslaw Czarnowski 697e13c2760SPrzemyslaw Czarnowski return; 698e13c2760SPrzemyslaw Czarnowski } 699e13c2760SPrzemyslaw Czarnowski 700e13c2760SPrzemyslaw Czarnowski for (const auto &object : subtree) 701e13c2760SPrzemyslaw Czarnowski { 702e13c2760SPrzemyslaw Czarnowski const std::string &path = 703e13c2760SPrzemyslaw Czarnowski static_cast<const std::string &>(object.first); 704e13c2760SPrzemyslaw Czarnowski 705e13c2760SPrzemyslaw Czarnowski std::size_t lastIndex = path.rfind("/"); 706e13c2760SPrzemyslaw Czarnowski if (lastIndex == std::string::npos) 707e13c2760SPrzemyslaw Czarnowski { 708e13c2760SPrzemyslaw Czarnowski continue; 709e13c2760SPrzemyslaw Czarnowski } 710e13c2760SPrzemyslaw Czarnowski 711e13c2760SPrzemyslaw Czarnowski lastIndex += 1; 712e13c2760SPrzemyslaw Czarnowski 713e13c2760SPrzemyslaw Czarnowski if (path.substr(lastIndex) == resName) 714e13c2760SPrzemyslaw Czarnowski { 715e13c2760SPrzemyslaw Czarnowski lastIndex = path.rfind("Proxy"); 716e13c2760SPrzemyslaw Czarnowski if (lastIndex != std::string::npos) 717e13c2760SPrzemyslaw Czarnowski { 718e13c2760SPrzemyslaw Czarnowski // Proxy mode 719e13c2760SPrzemyslaw Czarnowski doVmAction(std::move(aResp), service, 720e13c2760SPrzemyslaw Czarnowski resName, false); 721e13c2760SPrzemyslaw Czarnowski } 722e13c2760SPrzemyslaw Czarnowski 723e13c2760SPrzemyslaw Czarnowski lastIndex = path.rfind("Legacy"); 724e13c2760SPrzemyslaw Czarnowski if (lastIndex != std::string::npos) 725e13c2760SPrzemyslaw Czarnowski { 726e13c2760SPrzemyslaw Czarnowski // Legacy mode 727e13c2760SPrzemyslaw Czarnowski doVmAction(std::move(aResp), service, 728e13c2760SPrzemyslaw Czarnowski resName, true); 729e13c2760SPrzemyslaw Czarnowski } 730e13c2760SPrzemyslaw Czarnowski 731e13c2760SPrzemyslaw Czarnowski return; 732e13c2760SPrzemyslaw Czarnowski } 733e13c2760SPrzemyslaw Czarnowski } 734e13c2760SPrzemyslaw Czarnowski BMCWEB_LOG_DEBUG << "Parent item not found"; 735e13c2760SPrzemyslaw Czarnowski messages::resourceNotFound(aResp->res, "VirtualMedia", 736e13c2760SPrzemyslaw Czarnowski resName); 737e13c2760SPrzemyslaw Czarnowski }, 738e13c2760SPrzemyslaw Czarnowski service, "/xyz/openbmc_project/VirtualMedia", 739e13c2760SPrzemyslaw Czarnowski "org.freedesktop.DBus.ObjectManager", "GetManagedObjects"); 740e13c2760SPrzemyslaw Czarnowski }, 741e13c2760SPrzemyslaw Czarnowski "xyz.openbmc_project.ObjectMapper", 742e13c2760SPrzemyslaw Czarnowski "/xyz/openbmc_project/object_mapper", 743e13c2760SPrzemyslaw Czarnowski "xyz.openbmc_project.ObjectMapper", "GetObject", 744e13c2760SPrzemyslaw Czarnowski "/xyz/openbmc_project/VirtualMedia", std::array<const char *, 0>()); 745e13c2760SPrzemyslaw Czarnowski } 746e13c2760SPrzemyslaw Czarnowski 747e13c2760SPrzemyslaw Czarnowski /** 748e13c2760SPrzemyslaw Czarnowski * @brief Function transceives data with dbus directly. 749e13c2760SPrzemyslaw Czarnowski * 750e13c2760SPrzemyslaw Czarnowski * All BMC state properties will be retrieved before sending reset request. 751e13c2760SPrzemyslaw Czarnowski */ 752e13c2760SPrzemyslaw Czarnowski void doVmAction(std::shared_ptr<AsyncResp> asyncResp, 753e13c2760SPrzemyslaw Czarnowski const std::string &service, const std::string &name, 754e13c2760SPrzemyslaw Czarnowski bool legacy) 755e13c2760SPrzemyslaw Czarnowski { 756e13c2760SPrzemyslaw Czarnowski 757e13c2760SPrzemyslaw Czarnowski // Legacy mount requires parameter with image 758e13c2760SPrzemyslaw Czarnowski if (legacy) 759e13c2760SPrzemyslaw Czarnowski { 760e13c2760SPrzemyslaw Czarnowski crow::connections::systemBus->async_method_call( 761e13c2760SPrzemyslaw Czarnowski [asyncResp](const boost::system::error_code ec) { 762e13c2760SPrzemyslaw Czarnowski if (ec) 763e13c2760SPrzemyslaw Czarnowski { 764e13c2760SPrzemyslaw Czarnowski BMCWEB_LOG_ERROR << "Bad D-Bus request error: " << ec; 765e13c2760SPrzemyslaw Czarnowski 766e13c2760SPrzemyslaw Czarnowski messages::internalError(asyncResp->res); 767e13c2760SPrzemyslaw Czarnowski return; 768e13c2760SPrzemyslaw Czarnowski } 769e13c2760SPrzemyslaw Czarnowski }, 770e13c2760SPrzemyslaw Czarnowski service, "/xyz/openbmc_project/VirtualMedia/Legacy/" + name, 771e13c2760SPrzemyslaw Czarnowski "xyz.openbmc_project.VirtualMedia.Legacy", "Unmount"); 772e13c2760SPrzemyslaw Czarnowski } 773e13c2760SPrzemyslaw Czarnowski else // proxy 774e13c2760SPrzemyslaw Czarnowski { 775e13c2760SPrzemyslaw Czarnowski crow::connections::systemBus->async_method_call( 776e13c2760SPrzemyslaw Czarnowski [asyncResp](const boost::system::error_code ec) { 777e13c2760SPrzemyslaw Czarnowski if (ec) 778e13c2760SPrzemyslaw Czarnowski { 779e13c2760SPrzemyslaw Czarnowski BMCWEB_LOG_ERROR << "Bad D-Bus request error: " << ec; 780e13c2760SPrzemyslaw Czarnowski 781e13c2760SPrzemyslaw Czarnowski messages::internalError(asyncResp->res); 782e13c2760SPrzemyslaw Czarnowski return; 783e13c2760SPrzemyslaw Czarnowski } 784e13c2760SPrzemyslaw Czarnowski }, 785e13c2760SPrzemyslaw Czarnowski service, "/xyz/openbmc_project/VirtualMedia/Proxy/" + name, 786e13c2760SPrzemyslaw Czarnowski "xyz.openbmc_project.VirtualMedia.Proxy", "Unmount"); 787e13c2760SPrzemyslaw Czarnowski } 788e13c2760SPrzemyslaw Czarnowski } 789e13c2760SPrzemyslaw Czarnowski }; 790e13c2760SPrzemyslaw Czarnowski 791107077deSPrzemyslaw Czarnowski class VirtualMediaCollection : public Node 792107077deSPrzemyslaw Czarnowski { 793107077deSPrzemyslaw Czarnowski public: 794107077deSPrzemyslaw Czarnowski /* 795107077deSPrzemyslaw Czarnowski * Default Constructor 796107077deSPrzemyslaw Czarnowski */ 797107077deSPrzemyslaw Czarnowski VirtualMediaCollection(CrowApp &app) : 798107077deSPrzemyslaw Czarnowski Node(app, "/redfish/v1/Managers/<str>/VirtualMedia/", std::string()) 799107077deSPrzemyslaw Czarnowski { 800107077deSPrzemyslaw Czarnowski entityPrivileges = { 801107077deSPrzemyslaw Czarnowski {boost::beast::http::verb::get, {{"Login"}}}, 802107077deSPrzemyslaw Czarnowski {boost::beast::http::verb::head, {{"Login"}}}, 803107077deSPrzemyslaw Czarnowski {boost::beast::http::verb::patch, {{"ConfigureManager"}}}, 804107077deSPrzemyslaw Czarnowski {boost::beast::http::verb::put, {{"ConfigureManager"}}}, 805107077deSPrzemyslaw Czarnowski {boost::beast::http::verb::delete_, {{"ConfigureManager"}}}, 806107077deSPrzemyslaw Czarnowski {boost::beast::http::verb::post, {{"ConfigureManager"}}}}; 807107077deSPrzemyslaw Czarnowski } 808107077deSPrzemyslaw Czarnowski 809107077deSPrzemyslaw Czarnowski private: 810107077deSPrzemyslaw Czarnowski /** 811107077deSPrzemyslaw Czarnowski * Functions triggers appropriate requests on DBus 812107077deSPrzemyslaw Czarnowski */ 813107077deSPrzemyslaw Czarnowski void doGet(crow::Response &res, const crow::Request &req, 814107077deSPrzemyslaw Czarnowski const std::vector<std::string> ¶ms) override 815107077deSPrzemyslaw Czarnowski { 816107077deSPrzemyslaw Czarnowski auto asyncResp = std::make_shared<AsyncResp>(res); 817107077deSPrzemyslaw Czarnowski 818107077deSPrzemyslaw Czarnowski // Check if there is required param, truly entering this shall be 819107077deSPrzemyslaw Czarnowski // impossible 820107077deSPrzemyslaw Czarnowski if (params.size() != 1) 821107077deSPrzemyslaw Czarnowski { 822107077deSPrzemyslaw Czarnowski messages::internalError(res); 823107077deSPrzemyslaw Czarnowski 824107077deSPrzemyslaw Czarnowski return; 825107077deSPrzemyslaw Czarnowski } 826107077deSPrzemyslaw Czarnowski 827107077deSPrzemyslaw Czarnowski const std::string &name = params[0]; 828107077deSPrzemyslaw Czarnowski 829107077deSPrzemyslaw Czarnowski if (name != "bmc") 830107077deSPrzemyslaw Czarnowski { 831107077deSPrzemyslaw Czarnowski messages::resourceNotFound(asyncResp->res, "VirtualMedia", name); 832107077deSPrzemyslaw Czarnowski 833107077deSPrzemyslaw Czarnowski return; 834107077deSPrzemyslaw Czarnowski } 835107077deSPrzemyslaw Czarnowski 836107077deSPrzemyslaw Czarnowski res.jsonValue["@odata.type"] = 837107077deSPrzemyslaw Czarnowski "#VirtualMediaCollection.VirtualMediaCollection"; 838107077deSPrzemyslaw Czarnowski res.jsonValue["Name"] = "Virtual Media Services"; 839107077deSPrzemyslaw Czarnowski res.jsonValue["@odata.id"] = 840107077deSPrzemyslaw Czarnowski "/redfish/v1/Managers/" + name + "/VirtualMedia/"; 841107077deSPrzemyslaw Czarnowski 842107077deSPrzemyslaw Czarnowski crow::connections::systemBus->async_method_call( 843107077deSPrzemyslaw Czarnowski [asyncResp, name](const boost::system::error_code ec, 844107077deSPrzemyslaw Czarnowski const GetObjectType &getObjectType) { 845107077deSPrzemyslaw Czarnowski if (ec) 846107077deSPrzemyslaw Czarnowski { 847107077deSPrzemyslaw Czarnowski BMCWEB_LOG_ERROR << "ObjectMapper::GetObject call failed: " 848107077deSPrzemyslaw Czarnowski << ec; 849107077deSPrzemyslaw Czarnowski messages::internalError(asyncResp->res); 850107077deSPrzemyslaw Czarnowski 851107077deSPrzemyslaw Czarnowski return; 852107077deSPrzemyslaw Czarnowski } 853107077deSPrzemyslaw Czarnowski std::string service = getObjectType.begin()->first; 854107077deSPrzemyslaw Czarnowski BMCWEB_LOG_DEBUG << "GetObjectType: " << service; 855107077deSPrzemyslaw Czarnowski 856107077deSPrzemyslaw Czarnowski getVmResourceList(asyncResp, service, name); 857107077deSPrzemyslaw Czarnowski }, 858107077deSPrzemyslaw Czarnowski "xyz.openbmc_project.ObjectMapper", 859107077deSPrzemyslaw Czarnowski "/xyz/openbmc_project/object_mapper", 860107077deSPrzemyslaw Czarnowski "xyz.openbmc_project.ObjectMapper", "GetObject", 861107077deSPrzemyslaw Czarnowski "/xyz/openbmc_project/VirtualMedia", std::array<const char *, 0>()); 862107077deSPrzemyslaw Czarnowski } 863107077deSPrzemyslaw Czarnowski }; 864107077deSPrzemyslaw Czarnowski 865107077deSPrzemyslaw Czarnowski class VirtualMedia : public Node 866107077deSPrzemyslaw Czarnowski { 867107077deSPrzemyslaw Czarnowski public: 868107077deSPrzemyslaw Czarnowski /* 869107077deSPrzemyslaw Czarnowski * Default Constructor 870107077deSPrzemyslaw Czarnowski */ 871107077deSPrzemyslaw Czarnowski VirtualMedia(CrowApp &app) : 872107077deSPrzemyslaw Czarnowski Node(app, "/redfish/v1/Managers/<str>/VirtualMedia/<str>/", 873107077deSPrzemyslaw Czarnowski std::string(), std::string()) 874107077deSPrzemyslaw Czarnowski { 875107077deSPrzemyslaw Czarnowski entityPrivileges = { 876107077deSPrzemyslaw Czarnowski {boost::beast::http::verb::get, {{"Login"}}}, 877107077deSPrzemyslaw Czarnowski {boost::beast::http::verb::head, {{"Login"}}}, 878107077deSPrzemyslaw Czarnowski {boost::beast::http::verb::patch, {{"ConfigureManager"}}}, 879107077deSPrzemyslaw Czarnowski {boost::beast::http::verb::put, {{"ConfigureManager"}}}, 880107077deSPrzemyslaw Czarnowski {boost::beast::http::verb::delete_, {{"ConfigureManager"}}}, 881107077deSPrzemyslaw Czarnowski {boost::beast::http::verb::post, {{"ConfigureManager"}}}}; 882107077deSPrzemyslaw Czarnowski } 883107077deSPrzemyslaw Czarnowski 884107077deSPrzemyslaw Czarnowski private: 885107077deSPrzemyslaw Czarnowski /** 886107077deSPrzemyslaw Czarnowski * Functions triggers appropriate requests on DBus 887107077deSPrzemyslaw Czarnowski */ 888107077deSPrzemyslaw Czarnowski void doGet(crow::Response &res, const crow::Request &req, 889107077deSPrzemyslaw Czarnowski const std::vector<std::string> ¶ms) override 890107077deSPrzemyslaw Czarnowski { 891107077deSPrzemyslaw Czarnowski // Check if there is required param, truly entering this shall be 892107077deSPrzemyslaw Czarnowski // impossible 893107077deSPrzemyslaw Czarnowski if (params.size() != 2) 894107077deSPrzemyslaw Czarnowski { 895107077deSPrzemyslaw Czarnowski messages::internalError(res); 896107077deSPrzemyslaw Czarnowski 897107077deSPrzemyslaw Czarnowski res.end(); 898107077deSPrzemyslaw Czarnowski return; 899107077deSPrzemyslaw Czarnowski } 900107077deSPrzemyslaw Czarnowski const std::string &name = params[0]; 901107077deSPrzemyslaw Czarnowski const std::string &resName = params[1]; 902107077deSPrzemyslaw Czarnowski 903107077deSPrzemyslaw Czarnowski auto asyncResp = std::make_shared<AsyncResp>(res); 904107077deSPrzemyslaw Czarnowski 905107077deSPrzemyslaw Czarnowski if (name != "bmc") 906107077deSPrzemyslaw Czarnowski { 907107077deSPrzemyslaw Czarnowski messages::resourceNotFound(asyncResp->res, "VirtualMedia", resName); 908107077deSPrzemyslaw Czarnowski 909107077deSPrzemyslaw Czarnowski return; 910107077deSPrzemyslaw Czarnowski } 911107077deSPrzemyslaw Czarnowski 912107077deSPrzemyslaw Czarnowski crow::connections::systemBus->async_method_call( 913107077deSPrzemyslaw Czarnowski [asyncResp, name, resName](const boost::system::error_code ec, 914107077deSPrzemyslaw Czarnowski const GetObjectType &getObjectType) { 915107077deSPrzemyslaw Czarnowski if (ec) 916107077deSPrzemyslaw Czarnowski { 917107077deSPrzemyslaw Czarnowski BMCWEB_LOG_ERROR << "ObjectMapper::GetObject call failed: " 918107077deSPrzemyslaw Czarnowski << ec; 919107077deSPrzemyslaw Czarnowski messages::internalError(asyncResp->res); 920107077deSPrzemyslaw Czarnowski 921107077deSPrzemyslaw Czarnowski return; 922107077deSPrzemyslaw Czarnowski } 923107077deSPrzemyslaw Czarnowski std::string service = getObjectType.begin()->first; 924107077deSPrzemyslaw Czarnowski BMCWEB_LOG_DEBUG << "GetObjectType: " << service; 925107077deSPrzemyslaw Czarnowski 926107077deSPrzemyslaw Czarnowski getVmData(asyncResp, service, name, resName); 927107077deSPrzemyslaw Czarnowski }, 928107077deSPrzemyslaw Czarnowski "xyz.openbmc_project.ObjectMapper", 929107077deSPrzemyslaw Czarnowski "/xyz/openbmc_project/object_mapper", 930107077deSPrzemyslaw Czarnowski "xyz.openbmc_project.ObjectMapper", "GetObject", 931107077deSPrzemyslaw Czarnowski "/xyz/openbmc_project/VirtualMedia", std::array<const char *, 0>()); 932107077deSPrzemyslaw Czarnowski } 933107077deSPrzemyslaw Czarnowski }; 934107077deSPrzemyslaw Czarnowski 935107077deSPrzemyslaw Czarnowski } // namespace redfish 936