blob: ce40f67b65c9642b602d10ca838fc2e34878c6b8 [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
John Edward Broadbent7e860f12021-04-08 15:57:16 -070018#include <app.hpp>
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +020019#include <boost/container/flat_map.hpp>
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +010020#include <boost/process/async_pipe.hpp>
21#include <boost/type_traits/has_dereference.hpp>
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +020022#include <node.hpp>
23#include <utils/json_utils.hpp>
24// for GetObjectType and ManagedObjectType
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +020025#include <account_service.hpp>
Anna Platash9e319cf2020-11-17 10:18:31 +010026#include <boost/url/url_view.hpp>
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +020027
28namespace redfish
29
30{
Anna Platash9e319cf2020-11-17 10:18:31 +010031/**
32 * @brief Function extracts transfer protocol name from URI.
33 */
34static std::string getTransferProtocolTypeFromUri(const std::string& imageUri)
35{
36 try
37 {
38 std::string_view scheme = boost::urls::url_view(imageUri).scheme();
39 if (scheme == "smb")
40 {
41 return "CIFS";
42 }
43 else if (scheme == "https")
44 {
45 return "HTTPS";
46 }
47 }
48 catch (std::exception& p)
49 {
50 BMCWEB_LOG_ERROR << p.what();
51 }
52 return "None";
53}
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +020054
55/**
56 * @brief Read all known properties from VM object interfaces
57 */
zhanghch058d1b46d2021-04-01 11:18:24 +080058static void
59 vmParseInterfaceObject(const DbusInterfaceType& interface,
60 const std::shared_ptr<bmcweb::AsyncResp>& aResp)
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +020061{
62 const auto mountPointIface =
63 interface.find("xyz.openbmc_project.VirtualMedia.MountPoint");
64 if (mountPointIface == interface.cend())
65 {
66 BMCWEB_LOG_DEBUG << "Interface MountPoint not found";
67 return;
68 }
69
70 const auto processIface =
71 interface.find("xyz.openbmc_project.VirtualMedia.Process");
72 if (processIface == interface.cend())
73 {
74 BMCWEB_LOG_DEBUG << "Interface Process not found";
75 return;
76 }
77
78 const auto endpointIdProperty = mountPointIface->second.find("EndpointId");
79 if (endpointIdProperty == mountPointIface->second.cend())
80 {
81 BMCWEB_LOG_DEBUG << "Property EndpointId not found";
82 return;
83 }
84
85 const auto activeProperty = processIface->second.find("Active");
86 if (activeProperty == processIface->second.cend())
87 {
88 BMCWEB_LOG_DEBUG << "Property Active not found";
89 return;
90 }
91
Gunnar Mills1214b7e2020-06-04 10:11:30 -050092 const bool* activeValue = std::get_if<bool>(&activeProperty->second);
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +020093 if (!activeValue)
94 {
95 BMCWEB_LOG_DEBUG << "Value Active not found";
96 return;
97 }
98
Gunnar Mills1214b7e2020-06-04 10:11:30 -050099 const std::string* endpointIdValue =
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200100 std::get_if<std::string>(&endpointIdProperty->second);
101 if (endpointIdValue)
102 {
103 if (!endpointIdValue->empty())
104 {
105 // Proxy mode
Przemyslaw Czarnowskid04ba322020-01-21 12:41:56 +0100106 aResp->res.jsonValue["Oem"]["OpenBMC"]["WebSocketEndpoint"] =
107 *endpointIdValue;
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200108 aResp->res.jsonValue["TransferProtocolType"] = "OEM";
109 aResp->res.jsonValue["Inserted"] = *activeValue;
110 if (*activeValue == true)
111 {
112 aResp->res.jsonValue["ConnectedVia"] = "Applet";
113 }
114 }
115 else
116 {
117 // Legacy mode
Anna Platash9e319cf2020-11-17 10:18:31 +0100118 for (const auto& property : mountPointIface->second)
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200119 {
Anna Platash9e319cf2020-11-17 10:18:31 +0100120 if (property.first == "ImageURL")
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200121 {
Anna Platash9e319cf2020-11-17 10:18:31 +0100122 const std::string* imageUrlValue =
123 std::get_if<std::string>(&property.second);
124 if (imageUrlValue && !imageUrlValue->empty())
Przemyslaw Czarnowskida4784d2020-11-06 09:58:25 +0100125 {
Anna Platash9e319cf2020-11-17 10:18:31 +0100126 std::filesystem::path filePath = *imageUrlValue;
127 if (!filePath.has_filename())
128 {
129 // this will handle https share, which not
130 // necessarily has to have filename given.
131 aResp->res.jsonValue["ImageName"] = "";
132 }
133 else
134 {
135 aResp->res.jsonValue["ImageName"] =
136 filePath.filename();
137 }
Przemyslaw Czarnowskida4784d2020-11-06 09:58:25 +0100138
Anna Platash9e319cf2020-11-17 10:18:31 +0100139 aResp->res.jsonValue["Image"] = *imageUrlValue;
140 aResp->res.jsonValue["Inserted"] = *activeValue;
141 aResp->res.jsonValue["TransferProtocolType"] =
142 getTransferProtocolTypeFromUri(*imageUrlValue);
143
144 if (*activeValue == true)
145 {
146 aResp->res.jsonValue["ConnectedVia"] = "URI";
147 }
148 }
149 }
150 else if (property.first == "WriteProtected")
151 {
152 const bool* writeProtectedValue =
153 std::get_if<bool>(&property.second);
154 if (writeProtectedValue)
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200155 {
Anna Platash9e319cf2020-11-17 10:18:31 +0100156 aResp->res.jsonValue["WriteProtected"] =
157 *writeProtectedValue;
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200158 }
159 }
160 }
161 }
162 }
163}
164
165/**
166 * @brief Fill template for Virtual Media Item.
167 */
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500168static nlohmann::json vmItemTemplate(const std::string& name,
169 const std::string& resName)
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200170{
171 nlohmann::json item;
172 item["@odata.id"] =
173 "/redfish/v1/Managers/" + name + "/VirtualMedia/" + resName;
Przemyslaw Czarnowskid04ba322020-01-21 12:41:56 +0100174 item["@odata.type"] = "#VirtualMedia.v1_3_0.VirtualMedia";
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200175 item["Name"] = "Virtual Removable Media";
176 item["Id"] = resName;
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200177 item["WriteProtected"] = true;
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200178 item["MediaTypes"] = {"CD", "USBStick"};
179 item["TransferMethod"] = "Stream";
Przemyslaw Czarnowskid04ba322020-01-21 12:41:56 +0100180 item["Oem"]["OpenBMC"]["@odata.type"] =
181 "#OemVirtualMedia.v1_0_0.VirtualMedia";
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200182
183 return item;
184}
185
186/**
187 * @brief Fills collection data
188 */
zhanghch058d1b46d2021-04-01 11:18:24 +0800189static void getVmResourceList(std::shared_ptr<bmcweb::AsyncResp> aResp,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500190 const std::string& service,
191 const std::string& name)
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200192{
193 BMCWEB_LOG_DEBUG << "Get available Virtual Media resources.";
194 crow::connections::systemBus->async_method_call(
195 [name, aResp{std::move(aResp)}](const boost::system::error_code ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500196 ManagedObjectType& subtree) {
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200197 if (ec)
198 {
199 BMCWEB_LOG_DEBUG << "DBUS response error";
200 return;
201 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500202 nlohmann::json& members = aResp->res.jsonValue["Members"];
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200203 members = nlohmann::json::array();
204
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500205 for (const auto& object : subtree)
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200206 {
207 nlohmann::json item;
Ed Tanous2dfd18e2020-12-18 00:41:31 +0000208 std::string path = object.first.filename();
209 if (path.empty())
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200210 {
211 continue;
212 }
213
Ed Tanous2dfd18e2020-12-18 00:41:31 +0000214 item["@odata.id"] =
AppaRao Puli788ca502021-02-23 12:01:16 +0000215 "/redfish/v1/Managers/" + name + "/VirtualMedia/" + path;
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200216
217 members.emplace_back(std::move(item));
218 }
219 aResp->res.jsonValue["Members@odata.count"] = members.size();
220 },
221 service, "/xyz/openbmc_project/VirtualMedia",
222 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
223}
224
225/**
226 * @brief Fills data for specific resource
227 */
zhanghch058d1b46d2021-04-01 11:18:24 +0800228static void getVmData(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500229 const std::string& service, const std::string& name,
230 const std::string& resName)
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200231{
232 BMCWEB_LOG_DEBUG << "Get Virtual Media resource data.";
233
234 crow::connections::systemBus->async_method_call(
235 [resName, name, aResp](const boost::system::error_code ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500236 ManagedObjectType& subtree) {
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200237 if (ec)
238 {
239 BMCWEB_LOG_DEBUG << "DBUS response error";
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200240
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200241 return;
242 }
243
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500244 for (auto& item : subtree)
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200245 {
Ed Tanous2dfd18e2020-12-18 00:41:31 +0000246 std::string thispath = item.first.filename();
247 if (thispath.empty())
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200248 {
249 continue;
250 }
251
Ed Tanous2dfd18e2020-12-18 00:41:31 +0000252 if (thispath != resName)
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200253 {
254 continue;
255 }
256
Przemyslaw Czarnowski1a6258d2021-04-14 11:02:46 +0200257 // "Legacy"/"Proxy"
258 auto mode = item.first.parent_path();
259 // "VirtualMedia"
260 auto type = mode.parent_path();
261 if (mode.filename().empty() || type.filename().empty())
262 {
263 continue;
264 }
265
266 if (type.filename() != "VirtualMedia")
267 {
268 continue;
269 }
270
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200271 aResp->res.jsonValue = vmItemTemplate(name, resName);
272
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200273 // Check if dbus path is Legacy type
Przemyslaw Czarnowski1a6258d2021-04-14 11:02:46 +0200274 if (mode.filename() == "Legacy")
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200275 {
276 aResp->res.jsonValue["Actions"]["#VirtualMedia.InsertMedia"]
277 ["target"] =
278 "/redfish/v1/Managers/" + name + "/VirtualMedia/" +
279 resName + "/Actions/VirtualMedia.InsertMedia";
280 }
281
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200282 vmParseInterfaceObject(item.second, aResp);
283
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200284 aResp->res.jsonValue["Actions"]["#VirtualMedia.EjectMedia"]
285 ["target"] =
286 "/redfish/v1/Managers/" + name + "/VirtualMedia/" +
287 resName + "/Actions/VirtualMedia.EjectMedia";
288
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200289 return;
290 }
291
292 messages::resourceNotFound(
Przemyslaw Czarnowskid04ba322020-01-21 12:41:56 +0100293 aResp->res, "#VirtualMedia.v1_3_0.VirtualMedia", resName);
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200294 },
295 service, "/xyz/openbmc_project/VirtualMedia",
296 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
297}
298
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200299/**
300 @brief InsertMedia action class
301 */
302class VirtualMediaActionInsertMedia : public Node
303{
304 public:
Ed Tanous52cc1122020-07-18 13:51:21 -0700305 VirtualMediaActionInsertMedia(App& app) :
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200306 Node(app,
307 "/redfish/v1/Managers/<str>/VirtualMedia/<str>/Actions/"
308 "VirtualMedia.InsertMedia",
309 std::string(), std::string())
310 {
311 entityPrivileges = {
312 {boost::beast::http::verb::get, {{"Login"}}},
313 {boost::beast::http::verb::head, {{"Login"}}},
314 {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
315 {boost::beast::http::verb::put, {{"ConfigureManager"}}},
316 {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
317 {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
318 }
319
320 private:
321 /**
Agata Olenderc6f4e012020-03-11 15:19:07 +0100322 * @brief Transfer protocols supported for InsertMedia action.
323 *
324 */
325 enum class TransferProtocol
326 {
327 https,
328 smb,
329 invalid
330 };
331
332 /**
333 * @brief Function extracts transfer protocol type from URI.
334 *
335 */
336 std::optional<TransferProtocol>
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500337 getTransferProtocolFromUri(const std::string& imageUri)
Agata Olenderc6f4e012020-03-11 15:19:07 +0100338 {
Anna Platash9e319cf2020-11-17 10:18:31 +0100339 try
Agata Olenderc6f4e012020-03-11 15:19:07 +0100340 {
Anna Platash9e319cf2020-11-17 10:18:31 +0100341 std::string_view scheme = boost::urls::url_view(imageUri).scheme();
342 if (scheme == "smb")
343 {
344 return TransferProtocol::smb;
345 }
Ed Tanous81ce6092020-12-17 16:54:55 +0000346 if (scheme == "https")
Anna Platash9e319cf2020-11-17 10:18:31 +0100347 {
348 return TransferProtocol::https;
349 }
350 else if (!scheme.empty())
351 {
352 return TransferProtocol::invalid;
353 }
Agata Olenderc6f4e012020-03-11 15:19:07 +0100354 }
Anna Platash9e319cf2020-11-17 10:18:31 +0100355 catch (std::exception& p)
Agata Olenderc6f4e012020-03-11 15:19:07 +0100356 {
Anna Platash9e319cf2020-11-17 10:18:31 +0100357 BMCWEB_LOG_ERROR << p.what();
Agata Olenderc6f4e012020-03-11 15:19:07 +0100358 }
Anna Platash9e319cf2020-11-17 10:18:31 +0100359
360 return {};
Agata Olenderc6f4e012020-03-11 15:19:07 +0100361 }
362
363 /**
364 * @brief Function convert transfer protocol from string param.
365 *
366 */
367 std::optional<TransferProtocol> getTransferProtocolFromParam(
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500368 const std::optional<std::string>& transferProtocolType)
Agata Olenderc6f4e012020-03-11 15:19:07 +0100369 {
370 if (transferProtocolType == std::nullopt)
371 {
372 return {};
373 }
374
375 if (*transferProtocolType == "CIFS")
376 {
377 return TransferProtocol::smb;
378 }
379
380 if (*transferProtocolType == "HTTPS")
381 {
382 return TransferProtocol::https;
383 }
384
385 return TransferProtocol::invalid;
386 }
387
388 /**
389 * @brief Function extends URI with transfer protocol type.
390 *
391 */
Ed Tanous81ce6092020-12-17 16:54:55 +0000392 std::string
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500393 getUriWithTransferProtocol(const std::string& imageUri,
394 const TransferProtocol& transferProtocol)
Agata Olenderc6f4e012020-03-11 15:19:07 +0100395 {
396 if (transferProtocol == TransferProtocol::smb)
397 {
398 return "smb://" + imageUri;
399 }
400
401 if (transferProtocol == TransferProtocol::https)
402 {
403 return "https://" + imageUri;
404 }
405
406 return imageUri;
407 }
408
409 /**
410 * @brief Function validate parameters of insert media request.
411 *
412 */
zhanghch058d1b46d2021-04-01 11:18:24 +0800413 bool validateParams(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
414 std::string& imageUrl,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500415 const std::optional<bool>& inserted,
416 const std::optional<std::string>& transferMethod,
417 const std::optional<std::string>& transferProtocolType)
Agata Olenderc6f4e012020-03-11 15:19:07 +0100418 {
419 BMCWEB_LOG_DEBUG << "Validation started";
420 // required param imageUrl must not be empty
421 if (imageUrl.empty())
422 {
423 BMCWEB_LOG_ERROR << "Request action parameter Image is empty.";
424
zhanghch058d1b46d2021-04-01 11:18:24 +0800425 messages::propertyValueFormatError(asyncResp->res, "<empty>",
426 "Image");
Agata Olenderc6f4e012020-03-11 15:19:07 +0100427
428 return false;
429 }
430
431 // optional param inserted must be true
432 if ((inserted != std::nullopt) && (*inserted != true))
433 {
434 BMCWEB_LOG_ERROR
435 << "Request action optional parameter Inserted must be true.";
436
zhanghch058d1b46d2021-04-01 11:18:24 +0800437 messages::actionParameterNotSupported(asyncResp->res, "Inserted",
Agata Olenderc6f4e012020-03-11 15:19:07 +0100438 "InsertMedia");
439
440 return false;
441 }
442
443 // optional param transferMethod must be stream
444 if ((transferMethod != std::nullopt) && (*transferMethod != "Stream"))
445 {
446 BMCWEB_LOG_ERROR << "Request action optional parameter "
447 "TransferMethod must be Stream.";
448
zhanghch058d1b46d2021-04-01 11:18:24 +0800449 messages::actionParameterNotSupported(
450 asyncResp->res, "TransferMethod", "InsertMedia");
Agata Olenderc6f4e012020-03-11 15:19:07 +0100451
452 return false;
453 }
454
455 std::optional<TransferProtocol> uriTransferProtocolType =
456 getTransferProtocolFromUri(imageUrl);
457
458 std::optional<TransferProtocol> paramTransferProtocolType =
459 getTransferProtocolFromParam(transferProtocolType);
460
461 // ImageUrl does not contain valid protocol type
462 if (*uriTransferProtocolType == TransferProtocol::invalid)
463 {
464 BMCWEB_LOG_ERROR << "Request action parameter ImageUrl must "
465 "contain specified protocol type from list: "
466 "(smb, https).";
467
zhanghch058d1b46d2021-04-01 11:18:24 +0800468 messages::resourceAtUriInUnknownFormat(asyncResp->res, imageUrl);
Agata Olenderc6f4e012020-03-11 15:19:07 +0100469
470 return false;
471 }
472
473 // transferProtocolType should contain value from list
474 if (*paramTransferProtocolType == TransferProtocol::invalid)
475 {
476 BMCWEB_LOG_ERROR << "Request action parameter TransferProtocolType "
477 "must be provided with value from list: "
478 "(CIFS, HTTPS).";
479
zhanghch058d1b46d2021-04-01 11:18:24 +0800480 messages::propertyValueNotInList(
481 asyncResp->res, *transferProtocolType, "TransferProtocolType");
Agata Olenderc6f4e012020-03-11 15:19:07 +0100482 return false;
483 }
484
485 // valid transfer protocol not provided either with URI nor param
486 if ((uriTransferProtocolType == std::nullopt) &&
487 (paramTransferProtocolType == std::nullopt))
488 {
489 BMCWEB_LOG_ERROR << "Request action parameter ImageUrl must "
490 "contain specified protocol type or param "
491 "TransferProtocolType must be provided.";
492
zhanghch058d1b46d2021-04-01 11:18:24 +0800493 messages::resourceAtUriInUnknownFormat(asyncResp->res, imageUrl);
Agata Olenderc6f4e012020-03-11 15:19:07 +0100494
495 return false;
496 }
497
498 // valid transfer protocol provided both with URI and param
499 if ((paramTransferProtocolType != std::nullopt) &&
500 (uriTransferProtocolType != std::nullopt))
501 {
502 // check if protocol is the same for URI and param
503 if (*paramTransferProtocolType != *uriTransferProtocolType)
504 {
505 BMCWEB_LOG_ERROR << "Request action parameter "
506 "TransferProtocolType must contain the "
507 "same protocol type as protocol type "
508 "provided with param imageUrl.";
509
510 messages::actionParameterValueTypeError(
zhanghch058d1b46d2021-04-01 11:18:24 +0800511 asyncResp->res, *transferProtocolType,
512 "TransferProtocolType", "InsertMedia");
Agata Olenderc6f4e012020-03-11 15:19:07 +0100513
514 return false;
515 }
516 }
517
518 // validation passed
519 // add protocol to URI if needed
520 if (uriTransferProtocolType == std::nullopt)
521 {
522 imageUrl = getUriWithTransferProtocol(imageUrl,
523 *paramTransferProtocolType);
524 }
525
526 return true;
527 }
528
529 /**
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200530 * @brief Function handles POST method request.
531 *
532 * Analyzes POST body message before sends Reset request data to dbus.
533 */
zhanghch058d1b46d2021-04-01 11:18:24 +0800534 void doPost(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
535 const crow::Request& req,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500536 const std::vector<std::string>& params) override
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200537 {
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200538 if (params.size() != 2)
539 {
zhanghch058d1b46d2021-04-01 11:18:24 +0800540 messages::internalError(asyncResp->res);
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200541 return;
542 }
543
544 // take resource name from URL
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500545 const std::string& resName = params[1];
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200546
547 if (params[0] != "bmc")
548 {
zhanghch058d1b46d2021-04-01 11:18:24 +0800549 messages::resourceNotFound(asyncResp->res, "VirtualMedia.Insert",
550 resName);
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200551
552 return;
553 }
554
555 crow::connections::systemBus->async_method_call(
zhanghch058d1b46d2021-04-01 11:18:24 +0800556 [this, asyncResp, req,
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200557 resName](const boost::system::error_code ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500558 const GetObjectType& getObjectType) {
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200559 if (ec)
560 {
561 BMCWEB_LOG_ERROR << "ObjectMapper::GetObject call failed: "
562 << ec;
zhanghch058d1b46d2021-04-01 11:18:24 +0800563 messages::internalError(asyncResp->res);
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200564
565 return;
566 }
567 std::string service = getObjectType.begin()->first;
568 BMCWEB_LOG_DEBUG << "GetObjectType: " << service;
569
570 crow::connections::systemBus->async_method_call(
Ed Tanous81ce6092020-12-17 16:54:55 +0000571 [this, service, resName, req,
zhanghch058d1b46d2021-04-01 11:18:24 +0800572 asyncResp](const boost::system::error_code ec,
573 ManagedObjectType& subtree) {
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200574 if (ec)
575 {
576 BMCWEB_LOG_DEBUG << "DBUS response error";
577
578 return;
579 }
580
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500581 for (const auto& object : subtree)
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200582 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500583 const std::string& path =
584 static_cast<const std::string&>(object.first);
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200585
Ed Tanousf23b7292020-10-15 09:41:17 -0700586 std::size_t lastIndex = path.rfind('/');
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200587 if (lastIndex == std::string::npos)
588 {
589 continue;
590 }
591
592 lastIndex += 1;
593
594 if (path.substr(lastIndex) == resName)
595 {
596 lastIndex = path.rfind("Proxy");
597 if (lastIndex != std::string::npos)
598 {
599 // Not possible in proxy mode
600 BMCWEB_LOG_DEBUG << "InsertMedia not "
601 "allowed in proxy mode";
602 messages::resourceNotFound(
zhanghch058d1b46d2021-04-01 11:18:24 +0800603 asyncResp->res,
604 "VirtualMedia.InsertMedia", resName);
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200605
606 return;
607 }
608
609 lastIndex = path.rfind("Legacy");
Agata Olenderc6f4e012020-03-11 15:19:07 +0100610 if (lastIndex == std::string::npos)
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200611 {
Agata Olenderc6f4e012020-03-11 15:19:07 +0100612 continue;
613 }
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200614
Agata Olenderc6f4e012020-03-11 15:19:07 +0100615 // Legacy mode
616 std::string imageUrl;
617 std::optional<std::string> userName;
618 std::optional<std::string> password;
619 std::optional<std::string> transferMethod;
620 std::optional<std::string> transferProtocolType;
621 std::optional<bool> writeProtected = true;
622 std::optional<bool> inserted;
Adrian Ambrożewiczd6da5be2020-01-13 18:31:01 +0100623
Gunnar Mills4e0453b2020-07-08 14:00:30 -0500624 // Read obligatory parameters (url of image)
Agata Olenderc6f4e012020-03-11 15:19:07 +0100625 if (!json_util::readJson(
zhanghch058d1b46d2021-04-01 11:18:24 +0800626 req, asyncResp->res, "Image", imageUrl,
Agata Olenderc6f4e012020-03-11 15:19:07 +0100627 "WriteProtected", writeProtected,
628 "UserName", userName, "Password",
629 password, "Inserted", inserted,
630 "TransferMethod", transferMethod,
631 "TransferProtocolType",
632 transferProtocolType))
633 {
634 BMCWEB_LOG_DEBUG << "Image is not provided";
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200635 return;
636 }
Agata Olenderc6f4e012020-03-11 15:19:07 +0100637
638 bool paramsValid = validateParams(
zhanghch058d1b46d2021-04-01 11:18:24 +0800639 asyncResp->res, imageUrl, inserted,
Agata Olenderc6f4e012020-03-11 15:19:07 +0100640 transferMethod, transferProtocolType);
641
642 if (paramsValid == false)
643 {
644 return;
645 }
646
647 // manager is irrelevant for VirtualMedia dbus
648 // calls
zhanghch058d1b46d2021-04-01 11:18:24 +0800649 doMountVmLegacy(asyncResp, service, resName,
Ed Tanous81ce6092020-12-17 16:54:55 +0000650 imageUrl, !(*writeProtected),
651 std::move(*userName),
652 std::move(*password));
Agata Olenderc6f4e012020-03-11 15:19:07 +0100653
654 return;
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200655 }
656 }
657 BMCWEB_LOG_DEBUG << "Parent item not found";
zhanghch058d1b46d2021-04-01 11:18:24 +0800658 messages::resourceNotFound(asyncResp->res,
659 "VirtualMedia", resName);
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200660 },
661 service, "/xyz/openbmc_project/VirtualMedia",
662 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
663 },
664 "xyz.openbmc_project.ObjectMapper",
665 "/xyz/openbmc_project/object_mapper",
666 "xyz.openbmc_project.ObjectMapper", "GetObject",
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500667 "/xyz/openbmc_project/VirtualMedia", std::array<const char*, 0>());
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200668 }
669
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500670 template <typename T>
671 static void secureCleanup(T& value)
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100672 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500673 auto raw = const_cast<typename T::value_type*>(value.data());
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100674 explicit_bzero(raw, value.size() * sizeof(*raw));
675 }
676
677 class Credentials
678 {
679 public:
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500680 Credentials(std::string&& user, std::string&& password) :
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100681 userBuf(std::move(user)), passBuf(std::move(password))
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500682 {}
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100683
684 ~Credentials()
685 {
686 secureCleanup(userBuf);
687 secureCleanup(passBuf);
688 }
689
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500690 const std::string& user()
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100691 {
692 return userBuf;
693 }
694
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500695 const std::string& password()
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100696 {
697 return passBuf;
698 }
699
700 private:
701 Credentials() = delete;
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500702 Credentials(const Credentials&) = delete;
703 Credentials& operator=(const Credentials&) = delete;
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100704
705 std::string userBuf;
706 std::string passBuf;
707 };
708
709 class CredentialsProvider
710 {
711 public:
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500712 template <typename T>
713 struct Deleter
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100714 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500715 void operator()(T* buff) const
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100716 {
717 if (buff)
718 {
719 secureCleanup(*buff);
720 delete buff;
721 }
722 }
723 };
724
725 using Buffer = std::vector<char>;
726 using SecureBuffer = std::unique_ptr<Buffer, Deleter<Buffer>>;
727 // Using explicit definition instead of std::function to avoid implicit
728 // conversions eg. stack copy instead of reference
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500729 using FormatterFunc = void(const std::string& username,
730 const std::string& password, Buffer& dest);
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100731
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500732 CredentialsProvider(std::string&& user, std::string&& password) :
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100733 credentials(std::move(user), std::move(password))
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500734 {}
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100735
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500736 const std::string& user()
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100737 {
738 return credentials.user();
739 }
740
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500741 const std::string& password()
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100742 {
743 return credentials.password();
744 }
745
Ed Tanous81ce6092020-12-17 16:54:55 +0000746 SecureBuffer pack(FormatterFunc formatter)
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100747 {
748 SecureBuffer packed{new Buffer{}};
749 if (formatter)
750 {
751 formatter(credentials.user(), credentials.password(), *packed);
752 }
753
754 return packed;
755 }
756
757 private:
758 Credentials credentials;
759 };
760
761 // Wrapper for boost::async_pipe ensuring proper pipe cleanup
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500762 template <typename Buffer>
763 class Pipe
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100764 {
765 public:
766 using unix_fd = sdbusplus::message::unix_fd;
767
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500768 Pipe(boost::asio::io_context& io, Buffer&& buffer) :
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100769 impl(io), buffer{std::move(buffer)}
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500770 {}
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100771
772 ~Pipe()
773 {
774 // Named pipe needs to be explicitly removed
775 impl.close();
776 }
777
778 unix_fd fd()
779 {
780 return unix_fd{impl.native_source()};
781 }
782
783 template <typename WriteHandler>
Ed Tanous81ce6092020-12-17 16:54:55 +0000784 void asyncWrite(WriteHandler&& handler)
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100785 {
786 impl.async_write_some(data(), std::forward<WriteHandler>(handler));
787 }
788
789 private:
790 // Specialization for pointer types
791 template <typename B = Buffer>
792 typename std::enable_if<boost::has_dereference<B>::value,
793 boost::asio::const_buffer>::type
794 data()
795 {
796 return boost::asio::buffer(*buffer);
797 }
798
799 template <typename B = Buffer>
800 typename std::enable_if<!boost::has_dereference<B>::value,
801 boost::asio::const_buffer>::type
802 data()
803 {
804 return boost::asio::buffer(buffer);
805 }
806
807 const std::string name;
808 boost::process::async_pipe impl;
809 Buffer buffer;
810 };
811
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200812 /**
813 * @brief Function transceives data with dbus directly.
814 *
815 * All BMC state properties will be retrieved before sending reset request.
816 */
zhanghch058d1b46d2021-04-01 11:18:24 +0800817 void doMountVmLegacy(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500818 const std::string& service, const std::string& name,
819 const std::string& imageUrl, const bool rw,
820 std::string&& userName, std::string&& password)
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200821 {
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100822 using SecurePipe = Pipe<CredentialsProvider::SecureBuffer>;
823 constexpr const size_t secretLimit = 1024;
824
825 std::shared_ptr<SecurePipe> secretPipe;
826 std::variant<int, SecurePipe::unix_fd> unixFd = -1;
827
828 if (!userName.empty() || !password.empty())
829 {
830 // Encapsulate in safe buffer
831 CredentialsProvider credentials(std::move(userName),
832 std::move(password));
833
834 // Payload must contain data + NULL delimiters
835 if (credentials.user().size() + credentials.password().size() + 2 >
836 secretLimit)
837 {
838 BMCWEB_LOG_ERROR << "Credentials too long to handle";
839 messages::unrecognizedRequestBody(asyncResp->res);
840 return;
841 }
842
843 // Pack secret
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500844 auto secret = credentials.pack([](const auto& user,
845 const auto& pass, auto& buff) {
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100846 std::copy(user.begin(), user.end(), std::back_inserter(buff));
847 buff.push_back('\0');
848 std::copy(pass.begin(), pass.end(), std::back_inserter(buff));
849 buff.push_back('\0');
850 });
851
852 // Open pipe
853 secretPipe = std::make_shared<SecurePipe>(
854 crow::connections::systemBus->get_io_context(),
855 std::move(secret));
856 unixFd = secretPipe->fd();
857
858 // Pass secret over pipe
Ed Tanous81ce6092020-12-17 16:54:55 +0000859 secretPipe->asyncWrite(
Vikram Bodireddyf5b16f02020-08-26 14:54:51 +0530860 [asyncResp](const boost::system::error_code& ec, std::size_t) {
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100861 if (ec)
862 {
863 BMCWEB_LOG_ERROR << "Failed to pass secret: " << ec;
864 messages::internalError(asyncResp->res);
865 }
866 });
867 }
868
Adrian Ambrożewiczd6da5be2020-01-13 18:31:01 +0100869 crow::connections::systemBus->async_method_call(
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100870 [asyncResp, secretPipe](const boost::system::error_code ec,
871 bool success) {
Adrian Ambrożewiczd6da5be2020-01-13 18:31:01 +0100872 if (ec)
873 {
874 BMCWEB_LOG_ERROR << "Bad D-Bus request error: " << ec;
875 messages::internalError(asyncResp->res);
876 }
877 else if (!success)
878 {
879 BMCWEB_LOG_ERROR << "Service responded with error";
880 messages::generalError(asyncResp->res);
881 }
882 },
883 service, "/xyz/openbmc_project/VirtualMedia/Legacy/" + name,
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100884 "xyz.openbmc_project.VirtualMedia.Legacy", "Mount", imageUrl, rw,
885 unixFd);
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200886 }
887};
888
889/**
890 @brief EjectMedia action class
891 */
892class VirtualMediaActionEjectMedia : public Node
893{
894 public:
Ed Tanous52cc1122020-07-18 13:51:21 -0700895 VirtualMediaActionEjectMedia(App& app) :
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200896 Node(app,
897 "/redfish/v1/Managers/<str>/VirtualMedia/<str>/Actions/"
898 "VirtualMedia.EjectMedia",
899 std::string(), std::string())
900 {
901 entityPrivileges = {
902 {boost::beast::http::verb::get, {{"Login"}}},
903 {boost::beast::http::verb::head, {{"Login"}}},
904 {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
905 {boost::beast::http::verb::put, {{"ConfigureManager"}}},
906 {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
907 {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
908 }
909
910 private:
911 /**
912 * @brief Function handles POST method request.
913 *
914 * Analyzes POST body message before sends Reset request data to dbus.
915 */
zhanghch058d1b46d2021-04-01 11:18:24 +0800916 void doPost(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
917 const crow::Request& req,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500918 const std::vector<std::string>& params) override
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200919 {
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200920 if (params.size() != 2)
921 {
zhanghch058d1b46d2021-04-01 11:18:24 +0800922 messages::internalError(asyncResp->res);
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200923 return;
924 }
925
926 // take resource name from URL
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500927 const std::string& resName = params[1];
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200928
929 if (params[0] != "bmc")
930 {
zhanghch058d1b46d2021-04-01 11:18:24 +0800931 messages::resourceNotFound(asyncResp->res, "VirtualMedia.Eject",
932 resName);
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200933
934 return;
935 }
936
937 crow::connections::systemBus->async_method_call(
zhanghch058d1b46d2021-04-01 11:18:24 +0800938 [this, asyncResp{std::move(asyncResp)}, req,
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200939 resName](const boost::system::error_code ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500940 const GetObjectType& getObjectType) {
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200941 if (ec)
942 {
943 BMCWEB_LOG_ERROR << "ObjectMapper::GetObject call failed: "
944 << ec;
zhanghch058d1b46d2021-04-01 11:18:24 +0800945 messages::internalError(asyncResp->res);
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200946
947 return;
948 }
949 std::string service = getObjectType.begin()->first;
950 BMCWEB_LOG_DEBUG << "GetObjectType: " << service;
951
952 crow::connections::systemBus->async_method_call(
Ed Tanous81ce6092020-12-17 16:54:55 +0000953 [this, resName, service, req,
zhanghch058d1b46d2021-04-01 11:18:24 +0800954 asyncResp{asyncResp}](const boost::system::error_code ec,
955 ManagedObjectType& subtree) {
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200956 if (ec)
957 {
958 BMCWEB_LOG_DEBUG << "DBUS response error";
959
960 return;
961 }
962
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500963 for (const auto& object : subtree)
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200964 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500965 const std::string& path =
966 static_cast<const std::string&>(object.first);
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200967
Ed Tanousf23b7292020-10-15 09:41:17 -0700968 std::size_t lastIndex = path.rfind('/');
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200969 if (lastIndex == std::string::npos)
970 {
971 continue;
972 }
973
974 lastIndex += 1;
975
976 if (path.substr(lastIndex) == resName)
977 {
978 lastIndex = path.rfind("Proxy");
979 if (lastIndex != std::string::npos)
980 {
981 // Proxy mode
zhanghch058d1b46d2021-04-01 11:18:24 +0800982 doVmAction(asyncResp, service, resName,
983 false);
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200984 }
985
986 lastIndex = path.rfind("Legacy");
987 if (lastIndex != std::string::npos)
988 {
989 // Legacy mode
zhanghch058d1b46d2021-04-01 11:18:24 +0800990 doVmAction(asyncResp, service, resName,
991 true);
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200992 }
993
994 return;
995 }
996 }
997 BMCWEB_LOG_DEBUG << "Parent item not found";
zhanghch058d1b46d2021-04-01 11:18:24 +0800998 messages::resourceNotFound(asyncResp->res,
999 "VirtualMedia", resName);
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +02001000 },
1001 service, "/xyz/openbmc_project/VirtualMedia",
1002 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
1003 },
1004 "xyz.openbmc_project.ObjectMapper",
1005 "/xyz/openbmc_project/object_mapper",
1006 "xyz.openbmc_project.ObjectMapper", "GetObject",
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001007 "/xyz/openbmc_project/VirtualMedia", std::array<const char*, 0>());
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +02001008 }
1009
1010 /**
1011 * @brief Function transceives data with dbus directly.
1012 *
1013 * All BMC state properties will be retrieved before sending reset request.
1014 */
zhanghch058d1b46d2021-04-01 11:18:24 +08001015 void doVmAction(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001016 const std::string& service, const std::string& name,
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +02001017 bool legacy)
1018 {
1019
1020 // Legacy mount requires parameter with image
1021 if (legacy)
1022 {
1023 crow::connections::systemBus->async_method_call(
1024 [asyncResp](const boost::system::error_code ec) {
1025 if (ec)
1026 {
1027 BMCWEB_LOG_ERROR << "Bad D-Bus request error: " << ec;
1028
1029 messages::internalError(asyncResp->res);
1030 return;
1031 }
1032 },
1033 service, "/xyz/openbmc_project/VirtualMedia/Legacy/" + name,
1034 "xyz.openbmc_project.VirtualMedia.Legacy", "Unmount");
1035 }
1036 else // proxy
1037 {
1038 crow::connections::systemBus->async_method_call(
1039 [asyncResp](const boost::system::error_code ec) {
1040 if (ec)
1041 {
1042 BMCWEB_LOG_ERROR << "Bad D-Bus request error: " << ec;
1043
1044 messages::internalError(asyncResp->res);
1045 return;
1046 }
1047 },
1048 service, "/xyz/openbmc_project/VirtualMedia/Proxy/" + name,
1049 "xyz.openbmc_project.VirtualMedia.Proxy", "Unmount");
1050 }
1051 }
1052};
1053
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +02001054class VirtualMediaCollection : public Node
1055{
1056 public:
1057 /*
1058 * Default Constructor
1059 */
Ed Tanous52cc1122020-07-18 13:51:21 -07001060 VirtualMediaCollection(App& app) :
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +02001061 Node(app, "/redfish/v1/Managers/<str>/VirtualMedia/", std::string())
1062 {
1063 entityPrivileges = {
1064 {boost::beast::http::verb::get, {{"Login"}}},
1065 {boost::beast::http::verb::head, {{"Login"}}},
1066 {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
1067 {boost::beast::http::verb::put, {{"ConfigureManager"}}},
1068 {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
1069 {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
1070 }
1071
1072 private:
1073 /**
1074 * Functions triggers appropriate requests on DBus
1075 */
zhanghch058d1b46d2021-04-01 11:18:24 +08001076 void doGet(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1077 const crow::Request&,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001078 const std::vector<std::string>& params) override
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +02001079 {
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +02001080
1081 // Check if there is required param, truly entering this shall be
1082 // impossible
1083 if (params.size() != 1)
1084 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001085 messages::internalError(asyncResp->res);
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +02001086
1087 return;
1088 }
1089
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001090 const std::string& name = params[0];
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +02001091
1092 if (name != "bmc")
1093 {
1094 messages::resourceNotFound(asyncResp->res, "VirtualMedia", name);
1095
1096 return;
1097 }
1098
zhanghch058d1b46d2021-04-01 11:18:24 +08001099 asyncResp->res.jsonValue["@odata.type"] =
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +02001100 "#VirtualMediaCollection.VirtualMediaCollection";
zhanghch058d1b46d2021-04-01 11:18:24 +08001101 asyncResp->res.jsonValue["Name"] = "Virtual Media Services";
1102 asyncResp->res.jsonValue["@odata.id"] =
Przemyslaw Czarnowskid6c414f2020-07-08 15:17:31 +02001103 "/redfish/v1/Managers/" + name + "/VirtualMedia";
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +02001104
1105 crow::connections::systemBus->async_method_call(
1106 [asyncResp, name](const boost::system::error_code ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001107 const GetObjectType& getObjectType) {
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +02001108 if (ec)
1109 {
1110 BMCWEB_LOG_ERROR << "ObjectMapper::GetObject call failed: "
1111 << ec;
1112 messages::internalError(asyncResp->res);
1113
1114 return;
1115 }
1116 std::string service = getObjectType.begin()->first;
1117 BMCWEB_LOG_DEBUG << "GetObjectType: " << service;
1118
1119 getVmResourceList(asyncResp, service, name);
1120 },
1121 "xyz.openbmc_project.ObjectMapper",
1122 "/xyz/openbmc_project/object_mapper",
1123 "xyz.openbmc_project.ObjectMapper", "GetObject",
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001124 "/xyz/openbmc_project/VirtualMedia", std::array<const char*, 0>());
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +02001125 }
1126};
1127
1128class VirtualMedia : public Node
1129{
1130 public:
1131 /*
1132 * Default Constructor
1133 */
Ed Tanous52cc1122020-07-18 13:51:21 -07001134 VirtualMedia(App& app) :
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +02001135 Node(app, "/redfish/v1/Managers/<str>/VirtualMedia/<str>/",
1136 std::string(), std::string())
1137 {
1138 entityPrivileges = {
1139 {boost::beast::http::verb::get, {{"Login"}}},
1140 {boost::beast::http::verb::head, {{"Login"}}},
1141 {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
1142 {boost::beast::http::verb::put, {{"ConfigureManager"}}},
1143 {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
1144 {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
1145 }
1146
1147 private:
1148 /**
1149 * Functions triggers appropriate requests on DBus
1150 */
zhanghch058d1b46d2021-04-01 11:18:24 +08001151 void doGet(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1152 const crow::Request&,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001153 const std::vector<std::string>& params) override
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +02001154 {
1155 // Check if there is required param, truly entering this shall be
1156 // impossible
1157 if (params.size() != 2)
1158 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001159 messages::internalError(asyncResp->res);
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +02001160 return;
1161 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001162 const std::string& name = params[0];
1163 const std::string& resName = params[1];
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +02001164
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +02001165 if (name != "bmc")
1166 {
1167 messages::resourceNotFound(asyncResp->res, "VirtualMedia", resName);
1168
1169 return;
1170 }
1171
1172 crow::connections::systemBus->async_method_call(
1173 [asyncResp, name, resName](const boost::system::error_code ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001174 const GetObjectType& getObjectType) {
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +02001175 if (ec)
1176 {
1177 BMCWEB_LOG_ERROR << "ObjectMapper::GetObject call failed: "
1178 << ec;
1179 messages::internalError(asyncResp->res);
1180
1181 return;
1182 }
1183 std::string service = getObjectType.begin()->first;
1184 BMCWEB_LOG_DEBUG << "GetObjectType: " << service;
1185
1186 getVmData(asyncResp, service, name, resName);
1187 },
1188 "xyz.openbmc_project.ObjectMapper",
1189 "/xyz/openbmc_project/object_mapper",
1190 "xyz.openbmc_project.ObjectMapper", "GetObject",
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001191 "/xyz/openbmc_project/VirtualMedia", std::array<const char*, 0>());
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +02001192 }
1193};
1194
1195} // namespace redfish