blob: 9667c71132fd539c38e9695dcad1f2e9a4521862 [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
256 aResp->res.jsonValue = vmItemTemplate(name, resName);
257
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200258 // Check if dbus path is Legacy type
Ed Tanous2dfd18e2020-12-18 00:41:31 +0000259 if (thispath.find("VirtualMedia/Legacy") != std::string::npos)
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200260 {
261 aResp->res.jsonValue["Actions"]["#VirtualMedia.InsertMedia"]
262 ["target"] =
263 "/redfish/v1/Managers/" + name + "/VirtualMedia/" +
264 resName + "/Actions/VirtualMedia.InsertMedia";
265 }
266
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200267 vmParseInterfaceObject(item.second, aResp);
268
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200269 aResp->res.jsonValue["Actions"]["#VirtualMedia.EjectMedia"]
270 ["target"] =
271 "/redfish/v1/Managers/" + name + "/VirtualMedia/" +
272 resName + "/Actions/VirtualMedia.EjectMedia";
273
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200274 return;
275 }
276
277 messages::resourceNotFound(
Przemyslaw Czarnowskid04ba322020-01-21 12:41:56 +0100278 aResp->res, "#VirtualMedia.v1_3_0.VirtualMedia", resName);
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200279 },
280 service, "/xyz/openbmc_project/VirtualMedia",
281 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
282}
283
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200284/**
285 @brief InsertMedia action class
286 */
287class VirtualMediaActionInsertMedia : public Node
288{
289 public:
Ed Tanous52cc1122020-07-18 13:51:21 -0700290 VirtualMediaActionInsertMedia(App& app) :
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200291 Node(app,
292 "/redfish/v1/Managers/<str>/VirtualMedia/<str>/Actions/"
293 "VirtualMedia.InsertMedia",
294 std::string(), std::string())
295 {
296 entityPrivileges = {
297 {boost::beast::http::verb::get, {{"Login"}}},
298 {boost::beast::http::verb::head, {{"Login"}}},
299 {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
300 {boost::beast::http::verb::put, {{"ConfigureManager"}}},
301 {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
302 {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
303 }
304
305 private:
306 /**
Agata Olenderc6f4e012020-03-11 15:19:07 +0100307 * @brief Transfer protocols supported for InsertMedia action.
308 *
309 */
310 enum class TransferProtocol
311 {
312 https,
313 smb,
314 invalid
315 };
316
317 /**
318 * @brief Function extracts transfer protocol type from URI.
319 *
320 */
321 std::optional<TransferProtocol>
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500322 getTransferProtocolFromUri(const std::string& imageUri)
Agata Olenderc6f4e012020-03-11 15:19:07 +0100323 {
Anna Platash9e319cf2020-11-17 10:18:31 +0100324 try
Agata Olenderc6f4e012020-03-11 15:19:07 +0100325 {
Anna Platash9e319cf2020-11-17 10:18:31 +0100326 std::string_view scheme = boost::urls::url_view(imageUri).scheme();
327 if (scheme == "smb")
328 {
329 return TransferProtocol::smb;
330 }
Ed Tanous81ce6092020-12-17 16:54:55 +0000331 if (scheme == "https")
Anna Platash9e319cf2020-11-17 10:18:31 +0100332 {
333 return TransferProtocol::https;
334 }
335 else if (!scheme.empty())
336 {
337 return TransferProtocol::invalid;
338 }
Agata Olenderc6f4e012020-03-11 15:19:07 +0100339 }
Anna Platash9e319cf2020-11-17 10:18:31 +0100340 catch (std::exception& p)
Agata Olenderc6f4e012020-03-11 15:19:07 +0100341 {
Anna Platash9e319cf2020-11-17 10:18:31 +0100342 BMCWEB_LOG_ERROR << p.what();
Agata Olenderc6f4e012020-03-11 15:19:07 +0100343 }
Anna Platash9e319cf2020-11-17 10:18:31 +0100344
345 return {};
Agata Olenderc6f4e012020-03-11 15:19:07 +0100346 }
347
348 /**
349 * @brief Function convert transfer protocol from string param.
350 *
351 */
352 std::optional<TransferProtocol> getTransferProtocolFromParam(
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500353 const std::optional<std::string>& transferProtocolType)
Agata Olenderc6f4e012020-03-11 15:19:07 +0100354 {
355 if (transferProtocolType == std::nullopt)
356 {
357 return {};
358 }
359
360 if (*transferProtocolType == "CIFS")
361 {
362 return TransferProtocol::smb;
363 }
364
365 if (*transferProtocolType == "HTTPS")
366 {
367 return TransferProtocol::https;
368 }
369
370 return TransferProtocol::invalid;
371 }
372
373 /**
374 * @brief Function extends URI with transfer protocol type.
375 *
376 */
Ed Tanous81ce6092020-12-17 16:54:55 +0000377 std::string
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500378 getUriWithTransferProtocol(const std::string& imageUri,
379 const TransferProtocol& transferProtocol)
Agata Olenderc6f4e012020-03-11 15:19:07 +0100380 {
381 if (transferProtocol == TransferProtocol::smb)
382 {
383 return "smb://" + imageUri;
384 }
385
386 if (transferProtocol == TransferProtocol::https)
387 {
388 return "https://" + imageUri;
389 }
390
391 return imageUri;
392 }
393
394 /**
395 * @brief Function validate parameters of insert media request.
396 *
397 */
zhanghch058d1b46d2021-04-01 11:18:24 +0800398 bool validateParams(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
399 std::string& imageUrl,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500400 const std::optional<bool>& inserted,
401 const std::optional<std::string>& transferMethod,
402 const std::optional<std::string>& transferProtocolType)
Agata Olenderc6f4e012020-03-11 15:19:07 +0100403 {
404 BMCWEB_LOG_DEBUG << "Validation started";
405 // required param imageUrl must not be empty
406 if (imageUrl.empty())
407 {
408 BMCWEB_LOG_ERROR << "Request action parameter Image is empty.";
409
zhanghch058d1b46d2021-04-01 11:18:24 +0800410 messages::propertyValueFormatError(asyncResp->res, "<empty>",
411 "Image");
Agata Olenderc6f4e012020-03-11 15:19:07 +0100412
413 return false;
414 }
415
416 // optional param inserted must be true
417 if ((inserted != std::nullopt) && (*inserted != true))
418 {
419 BMCWEB_LOG_ERROR
420 << "Request action optional parameter Inserted must be true.";
421
zhanghch058d1b46d2021-04-01 11:18:24 +0800422 messages::actionParameterNotSupported(asyncResp->res, "Inserted",
Agata Olenderc6f4e012020-03-11 15:19:07 +0100423 "InsertMedia");
424
425 return false;
426 }
427
428 // optional param transferMethod must be stream
429 if ((transferMethod != std::nullopt) && (*transferMethod != "Stream"))
430 {
431 BMCWEB_LOG_ERROR << "Request action optional parameter "
432 "TransferMethod must be Stream.";
433
zhanghch058d1b46d2021-04-01 11:18:24 +0800434 messages::actionParameterNotSupported(
435 asyncResp->res, "TransferMethod", "InsertMedia");
Agata Olenderc6f4e012020-03-11 15:19:07 +0100436
437 return false;
438 }
439
440 std::optional<TransferProtocol> uriTransferProtocolType =
441 getTransferProtocolFromUri(imageUrl);
442
443 std::optional<TransferProtocol> paramTransferProtocolType =
444 getTransferProtocolFromParam(transferProtocolType);
445
446 // ImageUrl does not contain valid protocol type
447 if (*uriTransferProtocolType == TransferProtocol::invalid)
448 {
449 BMCWEB_LOG_ERROR << "Request action parameter ImageUrl must "
450 "contain specified protocol type from list: "
451 "(smb, https).";
452
zhanghch058d1b46d2021-04-01 11:18:24 +0800453 messages::resourceAtUriInUnknownFormat(asyncResp->res, imageUrl);
Agata Olenderc6f4e012020-03-11 15:19:07 +0100454
455 return false;
456 }
457
458 // transferProtocolType should contain value from list
459 if (*paramTransferProtocolType == TransferProtocol::invalid)
460 {
461 BMCWEB_LOG_ERROR << "Request action parameter TransferProtocolType "
462 "must be provided with value from list: "
463 "(CIFS, HTTPS).";
464
zhanghch058d1b46d2021-04-01 11:18:24 +0800465 messages::propertyValueNotInList(
466 asyncResp->res, *transferProtocolType, "TransferProtocolType");
Agata Olenderc6f4e012020-03-11 15:19:07 +0100467 return false;
468 }
469
470 // valid transfer protocol not provided either with URI nor param
471 if ((uriTransferProtocolType == std::nullopt) &&
472 (paramTransferProtocolType == std::nullopt))
473 {
474 BMCWEB_LOG_ERROR << "Request action parameter ImageUrl must "
475 "contain specified protocol type or param "
476 "TransferProtocolType must be provided.";
477
zhanghch058d1b46d2021-04-01 11:18:24 +0800478 messages::resourceAtUriInUnknownFormat(asyncResp->res, imageUrl);
Agata Olenderc6f4e012020-03-11 15:19:07 +0100479
480 return false;
481 }
482
483 // valid transfer protocol provided both with URI and param
484 if ((paramTransferProtocolType != std::nullopt) &&
485 (uriTransferProtocolType != std::nullopt))
486 {
487 // check if protocol is the same for URI and param
488 if (*paramTransferProtocolType != *uriTransferProtocolType)
489 {
490 BMCWEB_LOG_ERROR << "Request action parameter "
491 "TransferProtocolType must contain the "
492 "same protocol type as protocol type "
493 "provided with param imageUrl.";
494
495 messages::actionParameterValueTypeError(
zhanghch058d1b46d2021-04-01 11:18:24 +0800496 asyncResp->res, *transferProtocolType,
497 "TransferProtocolType", "InsertMedia");
Agata Olenderc6f4e012020-03-11 15:19:07 +0100498
499 return false;
500 }
501 }
502
503 // validation passed
504 // add protocol to URI if needed
505 if (uriTransferProtocolType == std::nullopt)
506 {
507 imageUrl = getUriWithTransferProtocol(imageUrl,
508 *paramTransferProtocolType);
509 }
510
511 return true;
512 }
513
514 /**
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200515 * @brief Function handles POST method request.
516 *
517 * Analyzes POST body message before sends Reset request data to dbus.
518 */
zhanghch058d1b46d2021-04-01 11:18:24 +0800519 void doPost(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
520 const crow::Request& req,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500521 const std::vector<std::string>& params) override
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200522 {
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200523 if (params.size() != 2)
524 {
zhanghch058d1b46d2021-04-01 11:18:24 +0800525 messages::internalError(asyncResp->res);
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200526 return;
527 }
528
529 // take resource name from URL
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500530 const std::string& resName = params[1];
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200531
532 if (params[0] != "bmc")
533 {
zhanghch058d1b46d2021-04-01 11:18:24 +0800534 messages::resourceNotFound(asyncResp->res, "VirtualMedia.Insert",
535 resName);
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200536
537 return;
538 }
539
540 crow::connections::systemBus->async_method_call(
zhanghch058d1b46d2021-04-01 11:18:24 +0800541 [this, asyncResp, req,
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200542 resName](const boost::system::error_code ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500543 const GetObjectType& getObjectType) {
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200544 if (ec)
545 {
546 BMCWEB_LOG_ERROR << "ObjectMapper::GetObject call failed: "
547 << ec;
zhanghch058d1b46d2021-04-01 11:18:24 +0800548 messages::internalError(asyncResp->res);
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200549
550 return;
551 }
552 std::string service = getObjectType.begin()->first;
553 BMCWEB_LOG_DEBUG << "GetObjectType: " << service;
554
555 crow::connections::systemBus->async_method_call(
Ed Tanous81ce6092020-12-17 16:54:55 +0000556 [this, service, resName, req,
zhanghch058d1b46d2021-04-01 11:18:24 +0800557 asyncResp](const boost::system::error_code ec,
558 ManagedObjectType& subtree) {
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200559 if (ec)
560 {
561 BMCWEB_LOG_DEBUG << "DBUS response error";
562
563 return;
564 }
565
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500566 for (const auto& object : subtree)
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200567 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500568 const std::string& path =
569 static_cast<const std::string&>(object.first);
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200570
Ed Tanousf23b7292020-10-15 09:41:17 -0700571 std::size_t lastIndex = path.rfind('/');
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200572 if (lastIndex == std::string::npos)
573 {
574 continue;
575 }
576
577 lastIndex += 1;
578
579 if (path.substr(lastIndex) == resName)
580 {
581 lastIndex = path.rfind("Proxy");
582 if (lastIndex != std::string::npos)
583 {
584 // Not possible in proxy mode
585 BMCWEB_LOG_DEBUG << "InsertMedia not "
586 "allowed in proxy mode";
587 messages::resourceNotFound(
zhanghch058d1b46d2021-04-01 11:18:24 +0800588 asyncResp->res,
589 "VirtualMedia.InsertMedia", resName);
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200590
591 return;
592 }
593
594 lastIndex = path.rfind("Legacy");
Agata Olenderc6f4e012020-03-11 15:19:07 +0100595 if (lastIndex == std::string::npos)
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200596 {
Agata Olenderc6f4e012020-03-11 15:19:07 +0100597 continue;
598 }
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200599
Agata Olenderc6f4e012020-03-11 15:19:07 +0100600 // Legacy mode
601 std::string imageUrl;
602 std::optional<std::string> userName;
603 std::optional<std::string> password;
604 std::optional<std::string> transferMethod;
605 std::optional<std::string> transferProtocolType;
606 std::optional<bool> writeProtected = true;
607 std::optional<bool> inserted;
Adrian Ambrożewiczd6da5be2020-01-13 18:31:01 +0100608
Gunnar Mills4e0453b2020-07-08 14:00:30 -0500609 // Read obligatory parameters (url of image)
Agata Olenderc6f4e012020-03-11 15:19:07 +0100610 if (!json_util::readJson(
zhanghch058d1b46d2021-04-01 11:18:24 +0800611 req, asyncResp->res, "Image", imageUrl,
Agata Olenderc6f4e012020-03-11 15:19:07 +0100612 "WriteProtected", writeProtected,
613 "UserName", userName, "Password",
614 password, "Inserted", inserted,
615 "TransferMethod", transferMethod,
616 "TransferProtocolType",
617 transferProtocolType))
618 {
619 BMCWEB_LOG_DEBUG << "Image is not provided";
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200620 return;
621 }
Agata Olenderc6f4e012020-03-11 15:19:07 +0100622
623 bool paramsValid = validateParams(
zhanghch058d1b46d2021-04-01 11:18:24 +0800624 asyncResp->res, imageUrl, inserted,
Agata Olenderc6f4e012020-03-11 15:19:07 +0100625 transferMethod, transferProtocolType);
626
627 if (paramsValid == false)
628 {
629 return;
630 }
631
632 // manager is irrelevant for VirtualMedia dbus
633 // calls
zhanghch058d1b46d2021-04-01 11:18:24 +0800634 doMountVmLegacy(asyncResp, service, resName,
Ed Tanous81ce6092020-12-17 16:54:55 +0000635 imageUrl, !(*writeProtected),
636 std::move(*userName),
637 std::move(*password));
Agata Olenderc6f4e012020-03-11 15:19:07 +0100638
639 return;
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200640 }
641 }
642 BMCWEB_LOG_DEBUG << "Parent item not found";
zhanghch058d1b46d2021-04-01 11:18:24 +0800643 messages::resourceNotFound(asyncResp->res,
644 "VirtualMedia", resName);
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200645 },
646 service, "/xyz/openbmc_project/VirtualMedia",
647 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
648 },
649 "xyz.openbmc_project.ObjectMapper",
650 "/xyz/openbmc_project/object_mapper",
651 "xyz.openbmc_project.ObjectMapper", "GetObject",
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500652 "/xyz/openbmc_project/VirtualMedia", std::array<const char*, 0>());
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200653 }
654
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500655 template <typename T>
656 static void secureCleanup(T& value)
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100657 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500658 auto raw = const_cast<typename T::value_type*>(value.data());
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100659 explicit_bzero(raw, value.size() * sizeof(*raw));
660 }
661
662 class Credentials
663 {
664 public:
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500665 Credentials(std::string&& user, std::string&& password) :
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100666 userBuf(std::move(user)), passBuf(std::move(password))
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500667 {}
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100668
669 ~Credentials()
670 {
671 secureCleanup(userBuf);
672 secureCleanup(passBuf);
673 }
674
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500675 const std::string& user()
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100676 {
677 return userBuf;
678 }
679
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500680 const std::string& password()
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100681 {
682 return passBuf;
683 }
684
685 private:
686 Credentials() = delete;
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500687 Credentials(const Credentials&) = delete;
688 Credentials& operator=(const Credentials&) = delete;
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100689
690 std::string userBuf;
691 std::string passBuf;
692 };
693
694 class CredentialsProvider
695 {
696 public:
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500697 template <typename T>
698 struct Deleter
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100699 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500700 void operator()(T* buff) const
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100701 {
702 if (buff)
703 {
704 secureCleanup(*buff);
705 delete buff;
706 }
707 }
708 };
709
710 using Buffer = std::vector<char>;
711 using SecureBuffer = std::unique_ptr<Buffer, Deleter<Buffer>>;
712 // Using explicit definition instead of std::function to avoid implicit
713 // conversions eg. stack copy instead of reference
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500714 using FormatterFunc = void(const std::string& username,
715 const std::string& password, Buffer& dest);
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100716
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500717 CredentialsProvider(std::string&& user, std::string&& password) :
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100718 credentials(std::move(user), std::move(password))
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500719 {}
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100720
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500721 const std::string& user()
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100722 {
723 return credentials.user();
724 }
725
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500726 const std::string& password()
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100727 {
728 return credentials.password();
729 }
730
Ed Tanous81ce6092020-12-17 16:54:55 +0000731 SecureBuffer pack(FormatterFunc formatter)
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100732 {
733 SecureBuffer packed{new Buffer{}};
734 if (formatter)
735 {
736 formatter(credentials.user(), credentials.password(), *packed);
737 }
738
739 return packed;
740 }
741
742 private:
743 Credentials credentials;
744 };
745
746 // Wrapper for boost::async_pipe ensuring proper pipe cleanup
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500747 template <typename Buffer>
748 class Pipe
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100749 {
750 public:
751 using unix_fd = sdbusplus::message::unix_fd;
752
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500753 Pipe(boost::asio::io_context& io, Buffer&& buffer) :
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100754 impl(io), buffer{std::move(buffer)}
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500755 {}
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100756
757 ~Pipe()
758 {
759 // Named pipe needs to be explicitly removed
760 impl.close();
761 }
762
763 unix_fd fd()
764 {
765 return unix_fd{impl.native_source()};
766 }
767
768 template <typename WriteHandler>
Ed Tanous81ce6092020-12-17 16:54:55 +0000769 void asyncWrite(WriteHandler&& handler)
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100770 {
771 impl.async_write_some(data(), std::forward<WriteHandler>(handler));
772 }
773
774 private:
775 // Specialization for pointer types
776 template <typename B = Buffer>
777 typename std::enable_if<boost::has_dereference<B>::value,
778 boost::asio::const_buffer>::type
779 data()
780 {
781 return boost::asio::buffer(*buffer);
782 }
783
784 template <typename B = Buffer>
785 typename std::enable_if<!boost::has_dereference<B>::value,
786 boost::asio::const_buffer>::type
787 data()
788 {
789 return boost::asio::buffer(buffer);
790 }
791
792 const std::string name;
793 boost::process::async_pipe impl;
794 Buffer buffer;
795 };
796
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200797 /**
798 * @brief Function transceives data with dbus directly.
799 *
800 * All BMC state properties will be retrieved before sending reset request.
801 */
zhanghch058d1b46d2021-04-01 11:18:24 +0800802 void doMountVmLegacy(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500803 const std::string& service, const std::string& name,
804 const std::string& imageUrl, const bool rw,
805 std::string&& userName, std::string&& password)
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200806 {
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100807 using SecurePipe = Pipe<CredentialsProvider::SecureBuffer>;
808 constexpr const size_t secretLimit = 1024;
809
810 std::shared_ptr<SecurePipe> secretPipe;
811 std::variant<int, SecurePipe::unix_fd> unixFd = -1;
812
813 if (!userName.empty() || !password.empty())
814 {
815 // Encapsulate in safe buffer
816 CredentialsProvider credentials(std::move(userName),
817 std::move(password));
818
819 // Payload must contain data + NULL delimiters
820 if (credentials.user().size() + credentials.password().size() + 2 >
821 secretLimit)
822 {
823 BMCWEB_LOG_ERROR << "Credentials too long to handle";
824 messages::unrecognizedRequestBody(asyncResp->res);
825 return;
826 }
827
828 // Pack secret
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500829 auto secret = credentials.pack([](const auto& user,
830 const auto& pass, auto& buff) {
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100831 std::copy(user.begin(), user.end(), std::back_inserter(buff));
832 buff.push_back('\0');
833 std::copy(pass.begin(), pass.end(), std::back_inserter(buff));
834 buff.push_back('\0');
835 });
836
837 // Open pipe
838 secretPipe = std::make_shared<SecurePipe>(
839 crow::connections::systemBus->get_io_context(),
840 std::move(secret));
841 unixFd = secretPipe->fd();
842
843 // Pass secret over pipe
Ed Tanous81ce6092020-12-17 16:54:55 +0000844 secretPipe->asyncWrite(
Vikram Bodireddyf5b16f02020-08-26 14:54:51 +0530845 [asyncResp](const boost::system::error_code& ec, std::size_t) {
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100846 if (ec)
847 {
848 BMCWEB_LOG_ERROR << "Failed to pass secret: " << ec;
849 messages::internalError(asyncResp->res);
850 }
851 });
852 }
853
Adrian Ambrożewiczd6da5be2020-01-13 18:31:01 +0100854 crow::connections::systemBus->async_method_call(
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100855 [asyncResp, secretPipe](const boost::system::error_code ec,
856 bool success) {
Adrian Ambrożewiczd6da5be2020-01-13 18:31:01 +0100857 if (ec)
858 {
859 BMCWEB_LOG_ERROR << "Bad D-Bus request error: " << ec;
860 messages::internalError(asyncResp->res);
861 }
862 else if (!success)
863 {
864 BMCWEB_LOG_ERROR << "Service responded with error";
865 messages::generalError(asyncResp->res);
866 }
867 },
868 service, "/xyz/openbmc_project/VirtualMedia/Legacy/" + name,
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100869 "xyz.openbmc_project.VirtualMedia.Legacy", "Mount", imageUrl, rw,
870 unixFd);
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200871 }
872};
873
874/**
875 @brief EjectMedia action class
876 */
877class VirtualMediaActionEjectMedia : public Node
878{
879 public:
Ed Tanous52cc1122020-07-18 13:51:21 -0700880 VirtualMediaActionEjectMedia(App& app) :
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200881 Node(app,
882 "/redfish/v1/Managers/<str>/VirtualMedia/<str>/Actions/"
883 "VirtualMedia.EjectMedia",
884 std::string(), std::string())
885 {
886 entityPrivileges = {
887 {boost::beast::http::verb::get, {{"Login"}}},
888 {boost::beast::http::verb::head, {{"Login"}}},
889 {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
890 {boost::beast::http::verb::put, {{"ConfigureManager"}}},
891 {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
892 {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
893 }
894
895 private:
896 /**
897 * @brief Function handles POST method request.
898 *
899 * Analyzes POST body message before sends Reset request data to dbus.
900 */
zhanghch058d1b46d2021-04-01 11:18:24 +0800901 void doPost(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
902 const crow::Request& req,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500903 const std::vector<std::string>& params) override
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200904 {
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200905 if (params.size() != 2)
906 {
zhanghch058d1b46d2021-04-01 11:18:24 +0800907 messages::internalError(asyncResp->res);
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200908 return;
909 }
910
911 // take resource name from URL
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500912 const std::string& resName = params[1];
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200913
914 if (params[0] != "bmc")
915 {
zhanghch058d1b46d2021-04-01 11:18:24 +0800916 messages::resourceNotFound(asyncResp->res, "VirtualMedia.Eject",
917 resName);
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200918
919 return;
920 }
921
922 crow::connections::systemBus->async_method_call(
zhanghch058d1b46d2021-04-01 11:18:24 +0800923 [this, asyncResp{std::move(asyncResp)}, req,
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200924 resName](const boost::system::error_code ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500925 const GetObjectType& getObjectType) {
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200926 if (ec)
927 {
928 BMCWEB_LOG_ERROR << "ObjectMapper::GetObject call failed: "
929 << ec;
zhanghch058d1b46d2021-04-01 11:18:24 +0800930 messages::internalError(asyncResp->res);
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200931
932 return;
933 }
934 std::string service = getObjectType.begin()->first;
935 BMCWEB_LOG_DEBUG << "GetObjectType: " << service;
936
937 crow::connections::systemBus->async_method_call(
Ed Tanous81ce6092020-12-17 16:54:55 +0000938 [this, resName, service, req,
zhanghch058d1b46d2021-04-01 11:18:24 +0800939 asyncResp{asyncResp}](const boost::system::error_code ec,
940 ManagedObjectType& subtree) {
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200941 if (ec)
942 {
943 BMCWEB_LOG_DEBUG << "DBUS response error";
944
945 return;
946 }
947
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500948 for (const auto& object : subtree)
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200949 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500950 const std::string& path =
951 static_cast<const std::string&>(object.first);
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200952
Ed Tanousf23b7292020-10-15 09:41:17 -0700953 std::size_t lastIndex = path.rfind('/');
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200954 if (lastIndex == std::string::npos)
955 {
956 continue;
957 }
958
959 lastIndex += 1;
960
961 if (path.substr(lastIndex) == resName)
962 {
963 lastIndex = path.rfind("Proxy");
964 if (lastIndex != std::string::npos)
965 {
966 // Proxy mode
zhanghch058d1b46d2021-04-01 11:18:24 +0800967 doVmAction(asyncResp, service, resName,
968 false);
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200969 }
970
971 lastIndex = path.rfind("Legacy");
972 if (lastIndex != std::string::npos)
973 {
974 // Legacy mode
zhanghch058d1b46d2021-04-01 11:18:24 +0800975 doVmAction(asyncResp, service, resName,
976 true);
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200977 }
978
979 return;
980 }
981 }
982 BMCWEB_LOG_DEBUG << "Parent item not found";
zhanghch058d1b46d2021-04-01 11:18:24 +0800983 messages::resourceNotFound(asyncResp->res,
984 "VirtualMedia", resName);
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200985 },
986 service, "/xyz/openbmc_project/VirtualMedia",
987 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
988 },
989 "xyz.openbmc_project.ObjectMapper",
990 "/xyz/openbmc_project/object_mapper",
991 "xyz.openbmc_project.ObjectMapper", "GetObject",
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500992 "/xyz/openbmc_project/VirtualMedia", std::array<const char*, 0>());
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200993 }
994
995 /**
996 * @brief Function transceives data with dbus directly.
997 *
998 * All BMC state properties will be retrieved before sending reset request.
999 */
zhanghch058d1b46d2021-04-01 11:18:24 +08001000 void doVmAction(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001001 const std::string& service, const std::string& name,
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +02001002 bool legacy)
1003 {
1004
1005 // Legacy mount requires parameter with image
1006 if (legacy)
1007 {
1008 crow::connections::systemBus->async_method_call(
1009 [asyncResp](const boost::system::error_code ec) {
1010 if (ec)
1011 {
1012 BMCWEB_LOG_ERROR << "Bad D-Bus request error: " << ec;
1013
1014 messages::internalError(asyncResp->res);
1015 return;
1016 }
1017 },
1018 service, "/xyz/openbmc_project/VirtualMedia/Legacy/" + name,
1019 "xyz.openbmc_project.VirtualMedia.Legacy", "Unmount");
1020 }
1021 else // proxy
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/Proxy/" + name,
1034 "xyz.openbmc_project.VirtualMedia.Proxy", "Unmount");
1035 }
1036 }
1037};
1038
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +02001039class VirtualMediaCollection : public Node
1040{
1041 public:
1042 /*
1043 * Default Constructor
1044 */
Ed Tanous52cc1122020-07-18 13:51:21 -07001045 VirtualMediaCollection(App& app) :
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +02001046 Node(app, "/redfish/v1/Managers/<str>/VirtualMedia/", std::string())
1047 {
1048 entityPrivileges = {
1049 {boost::beast::http::verb::get, {{"Login"}}},
1050 {boost::beast::http::verb::head, {{"Login"}}},
1051 {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
1052 {boost::beast::http::verb::put, {{"ConfigureManager"}}},
1053 {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
1054 {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
1055 }
1056
1057 private:
1058 /**
1059 * Functions triggers appropriate requests on DBus
1060 */
zhanghch058d1b46d2021-04-01 11:18:24 +08001061 void doGet(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1062 const crow::Request&,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001063 const std::vector<std::string>& params) override
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +02001064 {
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +02001065
1066 // Check if there is required param, truly entering this shall be
1067 // impossible
1068 if (params.size() != 1)
1069 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001070 messages::internalError(asyncResp->res);
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +02001071
1072 return;
1073 }
1074
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001075 const std::string& name = params[0];
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +02001076
1077 if (name != "bmc")
1078 {
1079 messages::resourceNotFound(asyncResp->res, "VirtualMedia", name);
1080
1081 return;
1082 }
1083
zhanghch058d1b46d2021-04-01 11:18:24 +08001084 asyncResp->res.jsonValue["@odata.type"] =
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +02001085 "#VirtualMediaCollection.VirtualMediaCollection";
zhanghch058d1b46d2021-04-01 11:18:24 +08001086 asyncResp->res.jsonValue["Name"] = "Virtual Media Services";
1087 asyncResp->res.jsonValue["@odata.id"] =
Przemyslaw Czarnowskid6c414f2020-07-08 15:17:31 +02001088 "/redfish/v1/Managers/" + name + "/VirtualMedia";
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +02001089
1090 crow::connections::systemBus->async_method_call(
1091 [asyncResp, name](const boost::system::error_code ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001092 const GetObjectType& getObjectType) {
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +02001093 if (ec)
1094 {
1095 BMCWEB_LOG_ERROR << "ObjectMapper::GetObject call failed: "
1096 << ec;
1097 messages::internalError(asyncResp->res);
1098
1099 return;
1100 }
1101 std::string service = getObjectType.begin()->first;
1102 BMCWEB_LOG_DEBUG << "GetObjectType: " << service;
1103
1104 getVmResourceList(asyncResp, service, name);
1105 },
1106 "xyz.openbmc_project.ObjectMapper",
1107 "/xyz/openbmc_project/object_mapper",
1108 "xyz.openbmc_project.ObjectMapper", "GetObject",
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001109 "/xyz/openbmc_project/VirtualMedia", std::array<const char*, 0>());
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +02001110 }
1111};
1112
1113class VirtualMedia : public Node
1114{
1115 public:
1116 /*
1117 * Default Constructor
1118 */
Ed Tanous52cc1122020-07-18 13:51:21 -07001119 VirtualMedia(App& app) :
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +02001120 Node(app, "/redfish/v1/Managers/<str>/VirtualMedia/<str>/",
1121 std::string(), std::string())
1122 {
1123 entityPrivileges = {
1124 {boost::beast::http::verb::get, {{"Login"}}},
1125 {boost::beast::http::verb::head, {{"Login"}}},
1126 {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
1127 {boost::beast::http::verb::put, {{"ConfigureManager"}}},
1128 {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
1129 {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
1130 }
1131
1132 private:
1133 /**
1134 * Functions triggers appropriate requests on DBus
1135 */
zhanghch058d1b46d2021-04-01 11:18:24 +08001136 void doGet(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1137 const crow::Request&,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001138 const std::vector<std::string>& params) override
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +02001139 {
1140 // Check if there is required param, truly entering this shall be
1141 // impossible
1142 if (params.size() != 2)
1143 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001144 messages::internalError(asyncResp->res);
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +02001145 return;
1146 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001147 const std::string& name = params[0];
1148 const std::string& resName = params[1];
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +02001149
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +02001150 if (name != "bmc")
1151 {
1152 messages::resourceNotFound(asyncResp->res, "VirtualMedia", resName);
1153
1154 return;
1155 }
1156
1157 crow::connections::systemBus->async_method_call(
1158 [asyncResp, name, resName](const boost::system::error_code ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001159 const GetObjectType& getObjectType) {
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +02001160 if (ec)
1161 {
1162 BMCWEB_LOG_ERROR << "ObjectMapper::GetObject call failed: "
1163 << ec;
1164 messages::internalError(asyncResp->res);
1165
1166 return;
1167 }
1168 std::string service = getObjectType.begin()->first;
1169 BMCWEB_LOG_DEBUG << "GetObjectType: " << service;
1170
1171 getVmData(asyncResp, service, name, resName);
1172 },
1173 "xyz.openbmc_project.ObjectMapper",
1174 "/xyz/openbmc_project/object_mapper",
1175 "xyz.openbmc_project.ObjectMapper", "GetObject",
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001176 "/xyz/openbmc_project/VirtualMedia", std::array<const char*, 0>());
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +02001177 }
1178};
1179
1180} // namespace redfish