blob: 685ee5c3bf84f966e5ba443b147a823d34549819 [file] [log] [blame]
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +02001/*
2// Copyright (c) 2018 Intel Corporation
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15*/
16#pragma once
17
18#include <boost/container/flat_map.hpp>
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +010019#include <boost/process/async_pipe.hpp>
20#include <boost/type_traits/has_dereference.hpp>
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +020021#include <node.hpp>
22#include <utils/json_utils.hpp>
23// for GetObjectType and ManagedObjectType
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +020024#include <account_service.hpp>
Anna Platash9e319cf2020-11-17 10:18:31 +010025#include <boost/url/url_view.hpp>
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +020026
27namespace redfish
28
29{
Anna Platash9e319cf2020-11-17 10:18:31 +010030/**
31 * @brief Function extracts transfer protocol name from URI.
32 */
33static std::string getTransferProtocolTypeFromUri(const std::string& imageUri)
34{
35 try
36 {
37 std::string_view scheme = boost::urls::url_view(imageUri).scheme();
38 if (scheme == "smb")
39 {
40 return "CIFS";
41 }
42 else if (scheme == "https")
43 {
44 return "HTTPS";
45 }
46 }
47 catch (std::exception& p)
48 {
49 BMCWEB_LOG_ERROR << p.what();
50 }
51 return "None";
52}
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +020053
54/**
55 * @brief Read all known properties from VM object interfaces
56 */
zhanghch058d1b46d2021-04-01 11:18:24 +080057static void
58 vmParseInterfaceObject(const DbusInterfaceType& interface,
59 const std::shared_ptr<bmcweb::AsyncResp>& aResp)
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +020060{
61 const auto mountPointIface =
62 interface.find("xyz.openbmc_project.VirtualMedia.MountPoint");
63 if (mountPointIface == interface.cend())
64 {
65 BMCWEB_LOG_DEBUG << "Interface MountPoint not found";
66 return;
67 }
68
69 const auto processIface =
70 interface.find("xyz.openbmc_project.VirtualMedia.Process");
71 if (processIface == interface.cend())
72 {
73 BMCWEB_LOG_DEBUG << "Interface Process not found";
74 return;
75 }
76
77 const auto endpointIdProperty = mountPointIface->second.find("EndpointId");
78 if (endpointIdProperty == mountPointIface->second.cend())
79 {
80 BMCWEB_LOG_DEBUG << "Property EndpointId not found";
81 return;
82 }
83
84 const auto activeProperty = processIface->second.find("Active");
85 if (activeProperty == processIface->second.cend())
86 {
87 BMCWEB_LOG_DEBUG << "Property Active not found";
88 return;
89 }
90
Gunnar Mills1214b7e2020-06-04 10:11:30 -050091 const bool* activeValue = std::get_if<bool>(&activeProperty->second);
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +020092 if (!activeValue)
93 {
94 BMCWEB_LOG_DEBUG << "Value Active not found";
95 return;
96 }
97
Gunnar Mills1214b7e2020-06-04 10:11:30 -050098 const std::string* endpointIdValue =
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +020099 std::get_if<std::string>(&endpointIdProperty->second);
100 if (endpointIdValue)
101 {
102 if (!endpointIdValue->empty())
103 {
104 // Proxy mode
Przemyslaw Czarnowskid04ba322020-01-21 12:41:56 +0100105 aResp->res.jsonValue["Oem"]["OpenBMC"]["WebSocketEndpoint"] =
106 *endpointIdValue;
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200107 aResp->res.jsonValue["TransferProtocolType"] = "OEM";
108 aResp->res.jsonValue["Inserted"] = *activeValue;
109 if (*activeValue == true)
110 {
111 aResp->res.jsonValue["ConnectedVia"] = "Applet";
112 }
113 }
114 else
115 {
116 // Legacy mode
Anna Platash9e319cf2020-11-17 10:18:31 +0100117 for (const auto& property : mountPointIface->second)
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200118 {
Anna Platash9e319cf2020-11-17 10:18:31 +0100119 if (property.first == "ImageURL")
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200120 {
Anna Platash9e319cf2020-11-17 10:18:31 +0100121 const std::string* imageUrlValue =
122 std::get_if<std::string>(&property.second);
123 if (imageUrlValue && !imageUrlValue->empty())
Przemyslaw Czarnowskida4784d2020-11-06 09:58:25 +0100124 {
Anna Platash9e319cf2020-11-17 10:18:31 +0100125 std::filesystem::path filePath = *imageUrlValue;
126 if (!filePath.has_filename())
127 {
128 // this will handle https share, which not
129 // necessarily has to have filename given.
130 aResp->res.jsonValue["ImageName"] = "";
131 }
132 else
133 {
134 aResp->res.jsonValue["ImageName"] =
135 filePath.filename();
136 }
Przemyslaw Czarnowskida4784d2020-11-06 09:58:25 +0100137
Anna Platash9e319cf2020-11-17 10:18:31 +0100138 aResp->res.jsonValue["Image"] = *imageUrlValue;
139 aResp->res.jsonValue["Inserted"] = *activeValue;
140 aResp->res.jsonValue["TransferProtocolType"] =
141 getTransferProtocolTypeFromUri(*imageUrlValue);
142
143 if (*activeValue == true)
144 {
145 aResp->res.jsonValue["ConnectedVia"] = "URI";
146 }
147 }
148 }
149 else if (property.first == "WriteProtected")
150 {
151 const bool* writeProtectedValue =
152 std::get_if<bool>(&property.second);
153 if (writeProtectedValue)
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200154 {
Anna Platash9e319cf2020-11-17 10:18:31 +0100155 aResp->res.jsonValue["WriteProtected"] =
156 *writeProtectedValue;
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200157 }
158 }
159 }
160 }
161 }
162}
163
164/**
165 * @brief Fill template for Virtual Media Item.
166 */
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500167static nlohmann::json vmItemTemplate(const std::string& name,
168 const std::string& resName)
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200169{
170 nlohmann::json item;
171 item["@odata.id"] =
172 "/redfish/v1/Managers/" + name + "/VirtualMedia/" + resName;
Przemyslaw Czarnowskid04ba322020-01-21 12:41:56 +0100173 item["@odata.type"] = "#VirtualMedia.v1_3_0.VirtualMedia";
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200174 item["Name"] = "Virtual Removable Media";
175 item["Id"] = resName;
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200176 item["WriteProtected"] = true;
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200177 item["MediaTypes"] = {"CD", "USBStick"};
178 item["TransferMethod"] = "Stream";
Przemyslaw Czarnowskid04ba322020-01-21 12:41:56 +0100179 item["Oem"]["OpenBMC"]["@odata.type"] =
180 "#OemVirtualMedia.v1_0_0.VirtualMedia";
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200181
182 return item;
183}
184
185/**
186 * @brief Fills collection data
187 */
zhanghch058d1b46d2021-04-01 11:18:24 +0800188static void getVmResourceList(std::shared_ptr<bmcweb::AsyncResp> aResp,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500189 const std::string& service,
190 const std::string& name)
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200191{
192 BMCWEB_LOG_DEBUG << "Get available Virtual Media resources.";
193 crow::connections::systemBus->async_method_call(
194 [name, aResp{std::move(aResp)}](const boost::system::error_code ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500195 ManagedObjectType& subtree) {
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200196 if (ec)
197 {
198 BMCWEB_LOG_DEBUG << "DBUS response error";
199 return;
200 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500201 nlohmann::json& members = aResp->res.jsonValue["Members"];
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200202 members = nlohmann::json::array();
203
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500204 for (const auto& object : subtree)
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200205 {
206 nlohmann::json item;
Ed Tanous2dfd18e2020-12-18 00:41:31 +0000207 std::string path = object.first.filename();
208 if (path.empty())
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200209 {
210 continue;
211 }
212
Ed Tanous2dfd18e2020-12-18 00:41:31 +0000213 item["@odata.id"] =
AppaRao Puli788ca502021-02-23 12:01:16 +0000214 "/redfish/v1/Managers/" + name + "/VirtualMedia/" + path;
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200215
216 members.emplace_back(std::move(item));
217 }
218 aResp->res.jsonValue["Members@odata.count"] = members.size();
219 },
220 service, "/xyz/openbmc_project/VirtualMedia",
221 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
222}
223
224/**
225 * @brief Fills data for specific resource
226 */
zhanghch058d1b46d2021-04-01 11:18:24 +0800227static void getVmData(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500228 const std::string& service, const std::string& name,
229 const std::string& resName)
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200230{
231 BMCWEB_LOG_DEBUG << "Get Virtual Media resource data.";
232
233 crow::connections::systemBus->async_method_call(
234 [resName, name, aResp](const boost::system::error_code ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500235 ManagedObjectType& subtree) {
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200236 if (ec)
237 {
238 BMCWEB_LOG_DEBUG << "DBUS response error";
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200239
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200240 return;
241 }
242
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500243 for (auto& item : subtree)
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200244 {
Ed Tanous2dfd18e2020-12-18 00:41:31 +0000245 std::string thispath = item.first.filename();
246 if (thispath.empty())
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200247 {
248 continue;
249 }
250
Ed Tanous2dfd18e2020-12-18 00:41:31 +0000251 if (thispath != resName)
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200252 {
253 continue;
254 }
255
Przemyslaw Czarnowski1a6258d2021-04-14 11:02:46 +0200256 // "Legacy"/"Proxy"
257 auto mode = item.first.parent_path();
258 // "VirtualMedia"
259 auto type = mode.parent_path();
260 if (mode.filename().empty() || type.filename().empty())
261 {
262 continue;
263 }
264
265 if (type.filename() != "VirtualMedia")
266 {
267 continue;
268 }
269
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200270 aResp->res.jsonValue = vmItemTemplate(name, resName);
271
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200272 // Check if dbus path is Legacy type
Przemyslaw Czarnowski1a6258d2021-04-14 11:02:46 +0200273 if (mode.filename() == "Legacy")
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200274 {
275 aResp->res.jsonValue["Actions"]["#VirtualMedia.InsertMedia"]
276 ["target"] =
277 "/redfish/v1/Managers/" + name + "/VirtualMedia/" +
278 resName + "/Actions/VirtualMedia.InsertMedia";
279 }
280
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200281 vmParseInterfaceObject(item.second, aResp);
282
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200283 aResp->res.jsonValue["Actions"]["#VirtualMedia.EjectMedia"]
284 ["target"] =
285 "/redfish/v1/Managers/" + name + "/VirtualMedia/" +
286 resName + "/Actions/VirtualMedia.EjectMedia";
287
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200288 return;
289 }
290
291 messages::resourceNotFound(
Przemyslaw Czarnowskid04ba322020-01-21 12:41:56 +0100292 aResp->res, "#VirtualMedia.v1_3_0.VirtualMedia", resName);
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200293 },
294 service, "/xyz/openbmc_project/VirtualMedia",
295 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
296}
297
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200298/**
299 @brief InsertMedia action class
300 */
301class VirtualMediaActionInsertMedia : public Node
302{
303 public:
Ed Tanous52cc1122020-07-18 13:51:21 -0700304 VirtualMediaActionInsertMedia(App& app) :
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200305 Node(app,
306 "/redfish/v1/Managers/<str>/VirtualMedia/<str>/Actions/"
307 "VirtualMedia.InsertMedia",
308 std::string(), std::string())
309 {
310 entityPrivileges = {
311 {boost::beast::http::verb::get, {{"Login"}}},
312 {boost::beast::http::verb::head, {{"Login"}}},
313 {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
314 {boost::beast::http::verb::put, {{"ConfigureManager"}}},
315 {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
316 {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
317 }
318
319 private:
320 /**
Agata Olenderc6f4e012020-03-11 15:19:07 +0100321 * @brief Transfer protocols supported for InsertMedia action.
322 *
323 */
324 enum class TransferProtocol
325 {
326 https,
327 smb,
328 invalid
329 };
330
331 /**
332 * @brief Function extracts transfer protocol type from URI.
333 *
334 */
335 std::optional<TransferProtocol>
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500336 getTransferProtocolFromUri(const std::string& imageUri)
Agata Olenderc6f4e012020-03-11 15:19:07 +0100337 {
Anna Platash9e319cf2020-11-17 10:18:31 +0100338 try
Agata Olenderc6f4e012020-03-11 15:19:07 +0100339 {
Anna Platash9e319cf2020-11-17 10:18:31 +0100340 std::string_view scheme = boost::urls::url_view(imageUri).scheme();
341 if (scheme == "smb")
342 {
343 return TransferProtocol::smb;
344 }
Ed Tanous81ce6092020-12-17 16:54:55 +0000345 if (scheme == "https")
Anna Platash9e319cf2020-11-17 10:18:31 +0100346 {
347 return TransferProtocol::https;
348 }
349 else if (!scheme.empty())
350 {
351 return TransferProtocol::invalid;
352 }
Agata Olenderc6f4e012020-03-11 15:19:07 +0100353 }
Anna Platash9e319cf2020-11-17 10:18:31 +0100354 catch (std::exception& p)
Agata Olenderc6f4e012020-03-11 15:19:07 +0100355 {
Anna Platash9e319cf2020-11-17 10:18:31 +0100356 BMCWEB_LOG_ERROR << p.what();
Agata Olenderc6f4e012020-03-11 15:19:07 +0100357 }
Anna Platash9e319cf2020-11-17 10:18:31 +0100358
359 return {};
Agata Olenderc6f4e012020-03-11 15:19:07 +0100360 }
361
362 /**
363 * @brief Function convert transfer protocol from string param.
364 *
365 */
366 std::optional<TransferProtocol> getTransferProtocolFromParam(
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500367 const std::optional<std::string>& transferProtocolType)
Agata Olenderc6f4e012020-03-11 15:19:07 +0100368 {
369 if (transferProtocolType == std::nullopt)
370 {
371 return {};
372 }
373
374 if (*transferProtocolType == "CIFS")
375 {
376 return TransferProtocol::smb;
377 }
378
379 if (*transferProtocolType == "HTTPS")
380 {
381 return TransferProtocol::https;
382 }
383
384 return TransferProtocol::invalid;
385 }
386
387 /**
388 * @brief Function extends URI with transfer protocol type.
389 *
390 */
Ed Tanous81ce6092020-12-17 16:54:55 +0000391 std::string
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500392 getUriWithTransferProtocol(const std::string& imageUri,
393 const TransferProtocol& transferProtocol)
Agata Olenderc6f4e012020-03-11 15:19:07 +0100394 {
395 if (transferProtocol == TransferProtocol::smb)
396 {
397 return "smb://" + imageUri;
398 }
399
400 if (transferProtocol == TransferProtocol::https)
401 {
402 return "https://" + imageUri;
403 }
404
405 return imageUri;
406 }
407
408 /**
409 * @brief Function validate parameters of insert media request.
410 *
411 */
zhanghch058d1b46d2021-04-01 11:18:24 +0800412 bool validateParams(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
413 std::string& imageUrl,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500414 const std::optional<bool>& inserted,
415 const std::optional<std::string>& transferMethod,
416 const std::optional<std::string>& transferProtocolType)
Agata Olenderc6f4e012020-03-11 15:19:07 +0100417 {
418 BMCWEB_LOG_DEBUG << "Validation started";
419 // required param imageUrl must not be empty
420 if (imageUrl.empty())
421 {
422 BMCWEB_LOG_ERROR << "Request action parameter Image is empty.";
423
zhanghch058d1b46d2021-04-01 11:18:24 +0800424 messages::propertyValueFormatError(asyncResp->res, "<empty>",
425 "Image");
Agata Olenderc6f4e012020-03-11 15:19:07 +0100426
427 return false;
428 }
429
430 // optional param inserted must be true
431 if ((inserted != std::nullopt) && (*inserted != true))
432 {
433 BMCWEB_LOG_ERROR
434 << "Request action optional parameter Inserted must be true.";
435
zhanghch058d1b46d2021-04-01 11:18:24 +0800436 messages::actionParameterNotSupported(asyncResp->res, "Inserted",
Agata Olenderc6f4e012020-03-11 15:19:07 +0100437 "InsertMedia");
438
439 return false;
440 }
441
442 // optional param transferMethod must be stream
443 if ((transferMethod != std::nullopt) && (*transferMethod != "Stream"))
444 {
445 BMCWEB_LOG_ERROR << "Request action optional parameter "
446 "TransferMethod must be Stream.";
447
zhanghch058d1b46d2021-04-01 11:18:24 +0800448 messages::actionParameterNotSupported(
449 asyncResp->res, "TransferMethod", "InsertMedia");
Agata Olenderc6f4e012020-03-11 15:19:07 +0100450
451 return false;
452 }
453
454 std::optional<TransferProtocol> uriTransferProtocolType =
455 getTransferProtocolFromUri(imageUrl);
456
457 std::optional<TransferProtocol> paramTransferProtocolType =
458 getTransferProtocolFromParam(transferProtocolType);
459
460 // ImageUrl does not contain valid protocol type
461 if (*uriTransferProtocolType == TransferProtocol::invalid)
462 {
463 BMCWEB_LOG_ERROR << "Request action parameter ImageUrl must "
464 "contain specified protocol type from list: "
465 "(smb, https).";
466
zhanghch058d1b46d2021-04-01 11:18:24 +0800467 messages::resourceAtUriInUnknownFormat(asyncResp->res, imageUrl);
Agata Olenderc6f4e012020-03-11 15:19:07 +0100468
469 return false;
470 }
471
472 // transferProtocolType should contain value from list
473 if (*paramTransferProtocolType == TransferProtocol::invalid)
474 {
475 BMCWEB_LOG_ERROR << "Request action parameter TransferProtocolType "
476 "must be provided with value from list: "
477 "(CIFS, HTTPS).";
478
zhanghch058d1b46d2021-04-01 11:18:24 +0800479 messages::propertyValueNotInList(
480 asyncResp->res, *transferProtocolType, "TransferProtocolType");
Agata Olenderc6f4e012020-03-11 15:19:07 +0100481 return false;
482 }
483
484 // valid transfer protocol not provided either with URI nor param
485 if ((uriTransferProtocolType == std::nullopt) &&
486 (paramTransferProtocolType == std::nullopt))
487 {
488 BMCWEB_LOG_ERROR << "Request action parameter ImageUrl must "
489 "contain specified protocol type or param "
490 "TransferProtocolType must be provided.";
491
zhanghch058d1b46d2021-04-01 11:18:24 +0800492 messages::resourceAtUriInUnknownFormat(asyncResp->res, imageUrl);
Agata Olenderc6f4e012020-03-11 15:19:07 +0100493
494 return false;
495 }
496
497 // valid transfer protocol provided both with URI and param
498 if ((paramTransferProtocolType != std::nullopt) &&
499 (uriTransferProtocolType != std::nullopt))
500 {
501 // check if protocol is the same for URI and param
502 if (*paramTransferProtocolType != *uriTransferProtocolType)
503 {
504 BMCWEB_LOG_ERROR << "Request action parameter "
505 "TransferProtocolType must contain the "
506 "same protocol type as protocol type "
507 "provided with param imageUrl.";
508
509 messages::actionParameterValueTypeError(
zhanghch058d1b46d2021-04-01 11:18:24 +0800510 asyncResp->res, *transferProtocolType,
511 "TransferProtocolType", "InsertMedia");
Agata Olenderc6f4e012020-03-11 15:19:07 +0100512
513 return false;
514 }
515 }
516
517 // validation passed
518 // add protocol to URI if needed
519 if (uriTransferProtocolType == std::nullopt)
520 {
521 imageUrl = getUriWithTransferProtocol(imageUrl,
522 *paramTransferProtocolType);
523 }
524
525 return true;
526 }
527
528 /**
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200529 * @brief Function handles POST method request.
530 *
531 * Analyzes POST body message before sends Reset request data to dbus.
532 */
zhanghch058d1b46d2021-04-01 11:18:24 +0800533 void doPost(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
534 const crow::Request& req,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500535 const std::vector<std::string>& params) override
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200536 {
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200537 if (params.size() != 2)
538 {
zhanghch058d1b46d2021-04-01 11:18:24 +0800539 messages::internalError(asyncResp->res);
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200540 return;
541 }
542
543 // take resource name from URL
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500544 const std::string& resName = params[1];
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200545
546 if (params[0] != "bmc")
547 {
zhanghch058d1b46d2021-04-01 11:18:24 +0800548 messages::resourceNotFound(asyncResp->res, "VirtualMedia.Insert",
549 resName);
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200550
551 return;
552 }
553
554 crow::connections::systemBus->async_method_call(
zhanghch058d1b46d2021-04-01 11:18:24 +0800555 [this, asyncResp, req,
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200556 resName](const boost::system::error_code ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500557 const GetObjectType& getObjectType) {
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200558 if (ec)
559 {
560 BMCWEB_LOG_ERROR << "ObjectMapper::GetObject call failed: "
561 << ec;
zhanghch058d1b46d2021-04-01 11:18:24 +0800562 messages::internalError(asyncResp->res);
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200563
564 return;
565 }
566 std::string service = getObjectType.begin()->first;
567 BMCWEB_LOG_DEBUG << "GetObjectType: " << service;
568
569 crow::connections::systemBus->async_method_call(
Ed Tanous81ce6092020-12-17 16:54:55 +0000570 [this, service, resName, req,
zhanghch058d1b46d2021-04-01 11:18:24 +0800571 asyncResp](const boost::system::error_code ec,
572 ManagedObjectType& subtree) {
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200573 if (ec)
574 {
575 BMCWEB_LOG_DEBUG << "DBUS response error";
576
577 return;
578 }
579
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500580 for (const auto& object : subtree)
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200581 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500582 const std::string& path =
583 static_cast<const std::string&>(object.first);
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200584
Ed Tanousf23b7292020-10-15 09:41:17 -0700585 std::size_t lastIndex = path.rfind('/');
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200586 if (lastIndex == std::string::npos)
587 {
588 continue;
589 }
590
591 lastIndex += 1;
592
593 if (path.substr(lastIndex) == resName)
594 {
595 lastIndex = path.rfind("Proxy");
596 if (lastIndex != std::string::npos)
597 {
598 // Not possible in proxy mode
599 BMCWEB_LOG_DEBUG << "InsertMedia not "
600 "allowed in proxy mode";
601 messages::resourceNotFound(
zhanghch058d1b46d2021-04-01 11:18:24 +0800602 asyncResp->res,
603 "VirtualMedia.InsertMedia", resName);
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200604
605 return;
606 }
607
608 lastIndex = path.rfind("Legacy");
Agata Olenderc6f4e012020-03-11 15:19:07 +0100609 if (lastIndex == std::string::npos)
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200610 {
Agata Olenderc6f4e012020-03-11 15:19:07 +0100611 continue;
612 }
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200613
Agata Olenderc6f4e012020-03-11 15:19:07 +0100614 // Legacy mode
615 std::string imageUrl;
616 std::optional<std::string> userName;
617 std::optional<std::string> password;
618 std::optional<std::string> transferMethod;
619 std::optional<std::string> transferProtocolType;
620 std::optional<bool> writeProtected = true;
621 std::optional<bool> inserted;
Adrian Ambrożewiczd6da5be2020-01-13 18:31:01 +0100622
Gunnar Mills4e0453b2020-07-08 14:00:30 -0500623 // Read obligatory parameters (url of image)
Agata Olenderc6f4e012020-03-11 15:19:07 +0100624 if (!json_util::readJson(
zhanghch058d1b46d2021-04-01 11:18:24 +0800625 req, asyncResp->res, "Image", imageUrl,
Agata Olenderc6f4e012020-03-11 15:19:07 +0100626 "WriteProtected", writeProtected,
627 "UserName", userName, "Password",
628 password, "Inserted", inserted,
629 "TransferMethod", transferMethod,
630 "TransferProtocolType",
631 transferProtocolType))
632 {
633 BMCWEB_LOG_DEBUG << "Image is not provided";
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200634 return;
635 }
Agata Olenderc6f4e012020-03-11 15:19:07 +0100636
637 bool paramsValid = validateParams(
zhanghch058d1b46d2021-04-01 11:18:24 +0800638 asyncResp->res, imageUrl, inserted,
Agata Olenderc6f4e012020-03-11 15:19:07 +0100639 transferMethod, transferProtocolType);
640
641 if (paramsValid == false)
642 {
643 return;
644 }
645
646 // manager is irrelevant for VirtualMedia dbus
647 // calls
zhanghch058d1b46d2021-04-01 11:18:24 +0800648 doMountVmLegacy(asyncResp, service, resName,
Ed Tanous81ce6092020-12-17 16:54:55 +0000649 imageUrl, !(*writeProtected),
650 std::move(*userName),
651 std::move(*password));
Agata Olenderc6f4e012020-03-11 15:19:07 +0100652
653 return;
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200654 }
655 }
656 BMCWEB_LOG_DEBUG << "Parent item not found";
zhanghch058d1b46d2021-04-01 11:18:24 +0800657 messages::resourceNotFound(asyncResp->res,
658 "VirtualMedia", resName);
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200659 },
660 service, "/xyz/openbmc_project/VirtualMedia",
661 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
662 },
663 "xyz.openbmc_project.ObjectMapper",
664 "/xyz/openbmc_project/object_mapper",
665 "xyz.openbmc_project.ObjectMapper", "GetObject",
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500666 "/xyz/openbmc_project/VirtualMedia", std::array<const char*, 0>());
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200667 }
668
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500669 template <typename T>
670 static void secureCleanup(T& value)
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100671 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500672 auto raw = const_cast<typename T::value_type*>(value.data());
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100673 explicit_bzero(raw, value.size() * sizeof(*raw));
674 }
675
676 class Credentials
677 {
678 public:
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500679 Credentials(std::string&& user, std::string&& password) :
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100680 userBuf(std::move(user)), passBuf(std::move(password))
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500681 {}
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100682
683 ~Credentials()
684 {
685 secureCleanup(userBuf);
686 secureCleanup(passBuf);
687 }
688
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500689 const std::string& user()
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100690 {
691 return userBuf;
692 }
693
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500694 const std::string& password()
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100695 {
696 return passBuf;
697 }
698
699 private:
700 Credentials() = delete;
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500701 Credentials(const Credentials&) = delete;
702 Credentials& operator=(const Credentials&) = delete;
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100703
704 std::string userBuf;
705 std::string passBuf;
706 };
707
708 class CredentialsProvider
709 {
710 public:
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500711 template <typename T>
712 struct Deleter
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100713 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500714 void operator()(T* buff) const
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100715 {
716 if (buff)
717 {
718 secureCleanup(*buff);
719 delete buff;
720 }
721 }
722 };
723
724 using Buffer = std::vector<char>;
725 using SecureBuffer = std::unique_ptr<Buffer, Deleter<Buffer>>;
726 // Using explicit definition instead of std::function to avoid implicit
727 // conversions eg. stack copy instead of reference
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500728 using FormatterFunc = void(const std::string& username,
729 const std::string& password, Buffer& dest);
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100730
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500731 CredentialsProvider(std::string&& user, std::string&& password) :
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100732 credentials(std::move(user), std::move(password))
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500733 {}
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100734
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500735 const std::string& user()
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100736 {
737 return credentials.user();
738 }
739
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500740 const std::string& password()
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100741 {
742 return credentials.password();
743 }
744
Ed Tanous81ce6092020-12-17 16:54:55 +0000745 SecureBuffer pack(FormatterFunc formatter)
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100746 {
747 SecureBuffer packed{new Buffer{}};
748 if (formatter)
749 {
750 formatter(credentials.user(), credentials.password(), *packed);
751 }
752
753 return packed;
754 }
755
756 private:
757 Credentials credentials;
758 };
759
760 // Wrapper for boost::async_pipe ensuring proper pipe cleanup
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500761 template <typename Buffer>
762 class Pipe
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100763 {
764 public:
765 using unix_fd = sdbusplus::message::unix_fd;
766
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500767 Pipe(boost::asio::io_context& io, Buffer&& buffer) :
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100768 impl(io), buffer{std::move(buffer)}
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500769 {}
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100770
771 ~Pipe()
772 {
773 // Named pipe needs to be explicitly removed
774 impl.close();
775 }
776
777 unix_fd fd()
778 {
779 return unix_fd{impl.native_source()};
780 }
781
782 template <typename WriteHandler>
Ed Tanous81ce6092020-12-17 16:54:55 +0000783 void asyncWrite(WriteHandler&& handler)
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100784 {
785 impl.async_write_some(data(), std::forward<WriteHandler>(handler));
786 }
787
788 private:
789 // Specialization for pointer types
790 template <typename B = Buffer>
791 typename std::enable_if<boost::has_dereference<B>::value,
792 boost::asio::const_buffer>::type
793 data()
794 {
795 return boost::asio::buffer(*buffer);
796 }
797
798 template <typename B = Buffer>
799 typename std::enable_if<!boost::has_dereference<B>::value,
800 boost::asio::const_buffer>::type
801 data()
802 {
803 return boost::asio::buffer(buffer);
804 }
805
806 const std::string name;
807 boost::process::async_pipe impl;
808 Buffer buffer;
809 };
810
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200811 /**
812 * @brief Function transceives data with dbus directly.
813 *
814 * All BMC state properties will be retrieved before sending reset request.
815 */
zhanghch058d1b46d2021-04-01 11:18:24 +0800816 void doMountVmLegacy(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500817 const std::string& service, const std::string& name,
818 const std::string& imageUrl, const bool rw,
819 std::string&& userName, std::string&& password)
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200820 {
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100821 using SecurePipe = Pipe<CredentialsProvider::SecureBuffer>;
822 constexpr const size_t secretLimit = 1024;
823
824 std::shared_ptr<SecurePipe> secretPipe;
825 std::variant<int, SecurePipe::unix_fd> unixFd = -1;
826
827 if (!userName.empty() || !password.empty())
828 {
829 // Encapsulate in safe buffer
830 CredentialsProvider credentials(std::move(userName),
831 std::move(password));
832
833 // Payload must contain data + NULL delimiters
834 if (credentials.user().size() + credentials.password().size() + 2 >
835 secretLimit)
836 {
837 BMCWEB_LOG_ERROR << "Credentials too long to handle";
838 messages::unrecognizedRequestBody(asyncResp->res);
839 return;
840 }
841
842 // Pack secret
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500843 auto secret = credentials.pack([](const auto& user,
844 const auto& pass, auto& buff) {
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100845 std::copy(user.begin(), user.end(), std::back_inserter(buff));
846 buff.push_back('\0');
847 std::copy(pass.begin(), pass.end(), std::back_inserter(buff));
848 buff.push_back('\0');
849 });
850
851 // Open pipe
852 secretPipe = std::make_shared<SecurePipe>(
853 crow::connections::systemBus->get_io_context(),
854 std::move(secret));
855 unixFd = secretPipe->fd();
856
857 // Pass secret over pipe
Ed Tanous81ce6092020-12-17 16:54:55 +0000858 secretPipe->asyncWrite(
Vikram Bodireddyf5b16f02020-08-26 14:54:51 +0530859 [asyncResp](const boost::system::error_code& ec, std::size_t) {
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100860 if (ec)
861 {
862 BMCWEB_LOG_ERROR << "Failed to pass secret: " << ec;
863 messages::internalError(asyncResp->res);
864 }
865 });
866 }
867
Adrian Ambrożewiczd6da5be2020-01-13 18:31:01 +0100868 crow::connections::systemBus->async_method_call(
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100869 [asyncResp, secretPipe](const boost::system::error_code ec,
870 bool success) {
Adrian Ambrożewiczd6da5be2020-01-13 18:31:01 +0100871 if (ec)
872 {
873 BMCWEB_LOG_ERROR << "Bad D-Bus request error: " << ec;
874 messages::internalError(asyncResp->res);
875 }
876 else if (!success)
877 {
878 BMCWEB_LOG_ERROR << "Service responded with error";
879 messages::generalError(asyncResp->res);
880 }
881 },
882 service, "/xyz/openbmc_project/VirtualMedia/Legacy/" + name,
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100883 "xyz.openbmc_project.VirtualMedia.Legacy", "Mount", imageUrl, rw,
884 unixFd);
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200885 }
886};
887
888/**
889 @brief EjectMedia action class
890 */
891class VirtualMediaActionEjectMedia : public Node
892{
893 public:
Ed Tanous52cc1122020-07-18 13:51:21 -0700894 VirtualMediaActionEjectMedia(App& app) :
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200895 Node(app,
896 "/redfish/v1/Managers/<str>/VirtualMedia/<str>/Actions/"
897 "VirtualMedia.EjectMedia",
898 std::string(), std::string())
899 {
900 entityPrivileges = {
901 {boost::beast::http::verb::get, {{"Login"}}},
902 {boost::beast::http::verb::head, {{"Login"}}},
903 {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
904 {boost::beast::http::verb::put, {{"ConfigureManager"}}},
905 {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
906 {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
907 }
908
909 private:
910 /**
911 * @brief Function handles POST method request.
912 *
913 * Analyzes POST body message before sends Reset request data to dbus.
914 */
zhanghch058d1b46d2021-04-01 11:18:24 +0800915 void doPost(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
916 const crow::Request& req,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500917 const std::vector<std::string>& params) override
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200918 {
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200919 if (params.size() != 2)
920 {
zhanghch058d1b46d2021-04-01 11:18:24 +0800921 messages::internalError(asyncResp->res);
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200922 return;
923 }
924
925 // take resource name from URL
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500926 const std::string& resName = params[1];
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200927
928 if (params[0] != "bmc")
929 {
zhanghch058d1b46d2021-04-01 11:18:24 +0800930 messages::resourceNotFound(asyncResp->res, "VirtualMedia.Eject",
931 resName);
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200932
933 return;
934 }
935
936 crow::connections::systemBus->async_method_call(
zhanghch058d1b46d2021-04-01 11:18:24 +0800937 [this, asyncResp{std::move(asyncResp)}, req,
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200938 resName](const boost::system::error_code ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500939 const GetObjectType& getObjectType) {
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200940 if (ec)
941 {
942 BMCWEB_LOG_ERROR << "ObjectMapper::GetObject call failed: "
943 << ec;
zhanghch058d1b46d2021-04-01 11:18:24 +0800944 messages::internalError(asyncResp->res);
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200945
946 return;
947 }
948 std::string service = getObjectType.begin()->first;
949 BMCWEB_LOG_DEBUG << "GetObjectType: " << service;
950
951 crow::connections::systemBus->async_method_call(
Ed Tanous81ce6092020-12-17 16:54:55 +0000952 [this, resName, service, req,
zhanghch058d1b46d2021-04-01 11:18:24 +0800953 asyncResp{asyncResp}](const boost::system::error_code ec,
954 ManagedObjectType& subtree) {
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200955 if (ec)
956 {
957 BMCWEB_LOG_DEBUG << "DBUS response error";
958
959 return;
960 }
961
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500962 for (const auto& object : subtree)
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200963 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500964 const std::string& path =
965 static_cast<const std::string&>(object.first);
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200966
Ed Tanousf23b7292020-10-15 09:41:17 -0700967 std::size_t lastIndex = path.rfind('/');
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200968 if (lastIndex == std::string::npos)
969 {
970 continue;
971 }
972
973 lastIndex += 1;
974
975 if (path.substr(lastIndex) == resName)
976 {
977 lastIndex = path.rfind("Proxy");
978 if (lastIndex != std::string::npos)
979 {
980 // Proxy mode
zhanghch058d1b46d2021-04-01 11:18:24 +0800981 doVmAction(asyncResp, service, resName,
982 false);
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200983 }
984
985 lastIndex = path.rfind("Legacy");
986 if (lastIndex != std::string::npos)
987 {
988 // Legacy mode
zhanghch058d1b46d2021-04-01 11:18:24 +0800989 doVmAction(asyncResp, service, resName,
990 true);
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200991 }
992
993 return;
994 }
995 }
996 BMCWEB_LOG_DEBUG << "Parent item not found";
zhanghch058d1b46d2021-04-01 11:18:24 +0800997 messages::resourceNotFound(asyncResp->res,
998 "VirtualMedia", resName);
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200999 },
1000 service, "/xyz/openbmc_project/VirtualMedia",
1001 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
1002 },
1003 "xyz.openbmc_project.ObjectMapper",
1004 "/xyz/openbmc_project/object_mapper",
1005 "xyz.openbmc_project.ObjectMapper", "GetObject",
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001006 "/xyz/openbmc_project/VirtualMedia", std::array<const char*, 0>());
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +02001007 }
1008
1009 /**
1010 * @brief Function transceives data with dbus directly.
1011 *
1012 * All BMC state properties will be retrieved before sending reset request.
1013 */
zhanghch058d1b46d2021-04-01 11:18:24 +08001014 void doVmAction(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001015 const std::string& service, const std::string& name,
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +02001016 bool legacy)
1017 {
1018
1019 // Legacy mount requires parameter with image
1020 if (legacy)
1021 {
1022 crow::connections::systemBus->async_method_call(
1023 [asyncResp](const boost::system::error_code ec) {
1024 if (ec)
1025 {
1026 BMCWEB_LOG_ERROR << "Bad D-Bus request error: " << ec;
1027
1028 messages::internalError(asyncResp->res);
1029 return;
1030 }
1031 },
1032 service, "/xyz/openbmc_project/VirtualMedia/Legacy/" + name,
1033 "xyz.openbmc_project.VirtualMedia.Legacy", "Unmount");
1034 }
1035 else // proxy
1036 {
1037 crow::connections::systemBus->async_method_call(
1038 [asyncResp](const boost::system::error_code ec) {
1039 if (ec)
1040 {
1041 BMCWEB_LOG_ERROR << "Bad D-Bus request error: " << ec;
1042
1043 messages::internalError(asyncResp->res);
1044 return;
1045 }
1046 },
1047 service, "/xyz/openbmc_project/VirtualMedia/Proxy/" + name,
1048 "xyz.openbmc_project.VirtualMedia.Proxy", "Unmount");
1049 }
1050 }
1051};
1052
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +02001053class VirtualMediaCollection : public Node
1054{
1055 public:
1056 /*
1057 * Default Constructor
1058 */
Ed Tanous52cc1122020-07-18 13:51:21 -07001059 VirtualMediaCollection(App& app) :
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +02001060 Node(app, "/redfish/v1/Managers/<str>/VirtualMedia/", std::string())
1061 {
1062 entityPrivileges = {
1063 {boost::beast::http::verb::get, {{"Login"}}},
1064 {boost::beast::http::verb::head, {{"Login"}}},
1065 {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
1066 {boost::beast::http::verb::put, {{"ConfigureManager"}}},
1067 {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
1068 {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
1069 }
1070
1071 private:
1072 /**
1073 * Functions triggers appropriate requests on DBus
1074 */
zhanghch058d1b46d2021-04-01 11:18:24 +08001075 void doGet(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1076 const crow::Request&,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001077 const std::vector<std::string>& params) override
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +02001078 {
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +02001079
1080 // Check if there is required param, truly entering this shall be
1081 // impossible
1082 if (params.size() != 1)
1083 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001084 messages::internalError(asyncResp->res);
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +02001085
1086 return;
1087 }
1088
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001089 const std::string& name = params[0];
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +02001090
1091 if (name != "bmc")
1092 {
1093 messages::resourceNotFound(asyncResp->res, "VirtualMedia", name);
1094
1095 return;
1096 }
1097
zhanghch058d1b46d2021-04-01 11:18:24 +08001098 asyncResp->res.jsonValue["@odata.type"] =
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +02001099 "#VirtualMediaCollection.VirtualMediaCollection";
zhanghch058d1b46d2021-04-01 11:18:24 +08001100 asyncResp->res.jsonValue["Name"] = "Virtual Media Services";
1101 asyncResp->res.jsonValue["@odata.id"] =
Przemyslaw Czarnowskid6c414f2020-07-08 15:17:31 +02001102 "/redfish/v1/Managers/" + name + "/VirtualMedia";
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +02001103
1104 crow::connections::systemBus->async_method_call(
1105 [asyncResp, name](const boost::system::error_code ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001106 const GetObjectType& getObjectType) {
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +02001107 if (ec)
1108 {
1109 BMCWEB_LOG_ERROR << "ObjectMapper::GetObject call failed: "
1110 << ec;
1111 messages::internalError(asyncResp->res);
1112
1113 return;
1114 }
1115 std::string service = getObjectType.begin()->first;
1116 BMCWEB_LOG_DEBUG << "GetObjectType: " << service;
1117
1118 getVmResourceList(asyncResp, service, name);
1119 },
1120 "xyz.openbmc_project.ObjectMapper",
1121 "/xyz/openbmc_project/object_mapper",
1122 "xyz.openbmc_project.ObjectMapper", "GetObject",
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001123 "/xyz/openbmc_project/VirtualMedia", std::array<const char*, 0>());
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +02001124 }
1125};
1126
1127class VirtualMedia : public Node
1128{
1129 public:
1130 /*
1131 * Default Constructor
1132 */
Ed Tanous52cc1122020-07-18 13:51:21 -07001133 VirtualMedia(App& app) :
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +02001134 Node(app, "/redfish/v1/Managers/<str>/VirtualMedia/<str>/",
1135 std::string(), std::string())
1136 {
1137 entityPrivileges = {
1138 {boost::beast::http::verb::get, {{"Login"}}},
1139 {boost::beast::http::verb::head, {{"Login"}}},
1140 {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
1141 {boost::beast::http::verb::put, {{"ConfigureManager"}}},
1142 {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
1143 {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
1144 }
1145
1146 private:
1147 /**
1148 * Functions triggers appropriate requests on DBus
1149 */
zhanghch058d1b46d2021-04-01 11:18:24 +08001150 void doGet(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1151 const crow::Request&,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001152 const std::vector<std::string>& params) override
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +02001153 {
1154 // Check if there is required param, truly entering this shall be
1155 // impossible
1156 if (params.size() != 2)
1157 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001158 messages::internalError(asyncResp->res);
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +02001159 return;
1160 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001161 const std::string& name = params[0];
1162 const std::string& resName = params[1];
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +02001163
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +02001164 if (name != "bmc")
1165 {
1166 messages::resourceNotFound(asyncResp->res, "VirtualMedia", resName);
1167
1168 return;
1169 }
1170
1171 crow::connections::systemBus->async_method_call(
1172 [asyncResp, name, resName](const boost::system::error_code ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001173 const GetObjectType& getObjectType) {
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +02001174 if (ec)
1175 {
1176 BMCWEB_LOG_ERROR << "ObjectMapper::GetObject call failed: "
1177 << ec;
1178 messages::internalError(asyncResp->res);
1179
1180 return;
1181 }
1182 std::string service = getObjectType.begin()->first;
1183 BMCWEB_LOG_DEBUG << "GetObjectType: " << service;
1184
1185 getVmData(asyncResp, service, name, resName);
1186 },
1187 "xyz.openbmc_project.ObjectMapper",
1188 "/xyz/openbmc_project/object_mapper",
1189 "xyz.openbmc_project.ObjectMapper", "GetObject",
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001190 "/xyz/openbmc_project/VirtualMedia", std::array<const char*, 0>());
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +02001191 }
1192};
1193
1194} // namespace redfish