blob: 95a8881ab2e8031b934a0b28b4167a2f9cc2fac8 [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 */
Gunnar Mills1214b7e2020-06-04 10:11:30 -050057static void vmParseInterfaceObject(const DbusInterfaceType& interface,
Ed Tanous81ce6092020-12-17 16:54:55 +000058 const std::shared_ptr<AsyncResp>& aResp)
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +020059{
60 const auto mountPointIface =
61 interface.find("xyz.openbmc_project.VirtualMedia.MountPoint");
62 if (mountPointIface == interface.cend())
63 {
64 BMCWEB_LOG_DEBUG << "Interface MountPoint not found";
65 return;
66 }
67
68 const auto processIface =
69 interface.find("xyz.openbmc_project.VirtualMedia.Process");
70 if (processIface == interface.cend())
71 {
72 BMCWEB_LOG_DEBUG << "Interface Process not found";
73 return;
74 }
75
76 const auto endpointIdProperty = mountPointIface->second.find("EndpointId");
77 if (endpointIdProperty == mountPointIface->second.cend())
78 {
79 BMCWEB_LOG_DEBUG << "Property EndpointId not found";
80 return;
81 }
82
83 const auto activeProperty = processIface->second.find("Active");
84 if (activeProperty == processIface->second.cend())
85 {
86 BMCWEB_LOG_DEBUG << "Property Active not found";
87 return;
88 }
89
Gunnar Mills1214b7e2020-06-04 10:11:30 -050090 const bool* activeValue = std::get_if<bool>(&activeProperty->second);
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +020091 if (!activeValue)
92 {
93 BMCWEB_LOG_DEBUG << "Value Active not found";
94 return;
95 }
96
Gunnar Mills1214b7e2020-06-04 10:11:30 -050097 const std::string* endpointIdValue =
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +020098 std::get_if<std::string>(&endpointIdProperty->second);
99 if (endpointIdValue)
100 {
101 if (!endpointIdValue->empty())
102 {
103 // Proxy mode
Przemyslaw Czarnowskid04ba322020-01-21 12:41:56 +0100104 aResp->res.jsonValue["Oem"]["OpenBMC"]["WebSocketEndpoint"] =
105 *endpointIdValue;
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200106 aResp->res.jsonValue["TransferProtocolType"] = "OEM";
107 aResp->res.jsonValue["Inserted"] = *activeValue;
108 if (*activeValue == true)
109 {
110 aResp->res.jsonValue["ConnectedVia"] = "Applet";
111 }
112 }
113 else
114 {
115 // Legacy mode
Anna Platash9e319cf2020-11-17 10:18:31 +0100116 for (const auto& property : mountPointIface->second)
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200117 {
Anna Platash9e319cf2020-11-17 10:18:31 +0100118 if (property.first == "ImageURL")
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200119 {
Anna Platash9e319cf2020-11-17 10:18:31 +0100120 const std::string* imageUrlValue =
121 std::get_if<std::string>(&property.second);
122 if (imageUrlValue && !imageUrlValue->empty())
Przemyslaw Czarnowskida4784d2020-11-06 09:58:25 +0100123 {
Anna Platash9e319cf2020-11-17 10:18:31 +0100124 std::filesystem::path filePath = *imageUrlValue;
125 if (!filePath.has_filename())
126 {
127 // this will handle https share, which not
128 // necessarily has to have filename given.
129 aResp->res.jsonValue["ImageName"] = "";
130 }
131 else
132 {
133 aResp->res.jsonValue["ImageName"] =
134 filePath.filename();
135 }
Przemyslaw Czarnowskida4784d2020-11-06 09:58:25 +0100136
Anna Platash9e319cf2020-11-17 10:18:31 +0100137 aResp->res.jsonValue["Image"] = *imageUrlValue;
138 aResp->res.jsonValue["Inserted"] = *activeValue;
139 aResp->res.jsonValue["TransferProtocolType"] =
140 getTransferProtocolTypeFromUri(*imageUrlValue);
141
142 if (*activeValue == true)
143 {
144 aResp->res.jsonValue["ConnectedVia"] = "URI";
145 }
146 }
147 }
148 else if (property.first == "WriteProtected")
149 {
150 const bool* writeProtectedValue =
151 std::get_if<bool>(&property.second);
152 if (writeProtectedValue)
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200153 {
Anna Platash9e319cf2020-11-17 10:18:31 +0100154 aResp->res.jsonValue["WriteProtected"] =
155 *writeProtectedValue;
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200156 }
157 }
158 }
159 }
160 }
161}
162
163/**
164 * @brief Fill template for Virtual Media Item.
165 */
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500166static nlohmann::json vmItemTemplate(const std::string& name,
167 const std::string& resName)
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200168{
169 nlohmann::json item;
170 item["@odata.id"] =
171 "/redfish/v1/Managers/" + name + "/VirtualMedia/" + resName;
Przemyslaw Czarnowskid04ba322020-01-21 12:41:56 +0100172 item["@odata.type"] = "#VirtualMedia.v1_3_0.VirtualMedia";
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200173 item["Name"] = "Virtual Removable Media";
174 item["Id"] = resName;
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200175 item["WriteProtected"] = true;
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200176 item["MediaTypes"] = {"CD", "USBStick"};
177 item["TransferMethod"] = "Stream";
Przemyslaw Czarnowskid04ba322020-01-21 12:41:56 +0100178 item["Oem"]["OpenBMC"]["@odata.type"] =
179 "#OemVirtualMedia.v1_0_0.VirtualMedia";
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200180
181 return item;
182}
183
184/**
185 * @brief Fills collection data
186 */
187static void getVmResourceList(std::shared_ptr<AsyncResp> aResp,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500188 const std::string& service,
189 const std::string& name)
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200190{
191 BMCWEB_LOG_DEBUG << "Get available Virtual Media resources.";
192 crow::connections::systemBus->async_method_call(
193 [name, aResp{std::move(aResp)}](const boost::system::error_code ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500194 ManagedObjectType& subtree) {
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200195 if (ec)
196 {
197 BMCWEB_LOG_DEBUG << "DBUS response error";
198 return;
199 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500200 nlohmann::json& members = aResp->res.jsonValue["Members"];
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200201 members = nlohmann::json::array();
202
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500203 for (const auto& object : subtree)
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200204 {
205 nlohmann::json item;
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500206 const std::string& path =
207 static_cast<const std::string&>(object.first);
Ed Tanousf23b7292020-10-15 09:41:17 -0700208 std::size_t lastIndex = path.rfind('/');
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200209 if (lastIndex == std::string::npos)
210 {
211 continue;
212 }
213
214 lastIndex += 1;
215
216 item["@odata.id"] = "/redfish/v1/Managers/" + name +
217 "/VirtualMedia/" + path.substr(lastIndex);
218
219 members.emplace_back(std::move(item));
220 }
221 aResp->res.jsonValue["Members@odata.count"] = members.size();
222 },
223 service, "/xyz/openbmc_project/VirtualMedia",
224 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
225}
226
227/**
228 * @brief Fills data for specific resource
229 */
Ed Tanous81ce6092020-12-17 16:54:55 +0000230static void getVmData(const std::shared_ptr<AsyncResp>& aResp,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500231 const std::string& service, const std::string& name,
232 const std::string& resName)
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200233{
234 BMCWEB_LOG_DEBUG << "Get Virtual Media resource data.";
235
236 crow::connections::systemBus->async_method_call(
237 [resName, name, aResp](const boost::system::error_code ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500238 ManagedObjectType& subtree) {
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200239 if (ec)
240 {
241 BMCWEB_LOG_DEBUG << "DBUS response error";
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200242
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200243 return;
244 }
245
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500246 for (auto& item : subtree)
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200247 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500248 const std::string& path =
249 static_cast<const std::string&>(item.first);
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200250
Ed Tanousf23b7292020-10-15 09:41:17 -0700251 std::size_t lastItem = path.rfind('/');
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200252 if (lastItem == std::string::npos)
253 {
254 continue;
255 }
256
257 if (path.substr(lastItem + 1) != resName)
258 {
259 continue;
260 }
261
262 aResp->res.jsonValue = vmItemTemplate(name, resName);
263
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200264 // Check if dbus path is Legacy type
265 if (path.find("VirtualMedia/Legacy") != std::string::npos)
266 {
267 aResp->res.jsonValue["Actions"]["#VirtualMedia.InsertMedia"]
268 ["target"] =
269 "/redfish/v1/Managers/" + name + "/VirtualMedia/" +
270 resName + "/Actions/VirtualMedia.InsertMedia";
271 }
272
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200273 vmParseInterfaceObject(item.second, aResp);
274
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200275 aResp->res.jsonValue["Actions"]["#VirtualMedia.EjectMedia"]
276 ["target"] =
277 "/redfish/v1/Managers/" + name + "/VirtualMedia/" +
278 resName + "/Actions/VirtualMedia.EjectMedia";
279
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200280 return;
281 }
282
283 messages::resourceNotFound(
Przemyslaw Czarnowskid04ba322020-01-21 12:41:56 +0100284 aResp->res, "#VirtualMedia.v1_3_0.VirtualMedia", resName);
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200285 },
286 service, "/xyz/openbmc_project/VirtualMedia",
287 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
288}
289
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200290/**
291 @brief InsertMedia action class
292 */
293class VirtualMediaActionInsertMedia : public Node
294{
295 public:
Ed Tanous52cc1122020-07-18 13:51:21 -0700296 VirtualMediaActionInsertMedia(App& app) :
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200297 Node(app,
298 "/redfish/v1/Managers/<str>/VirtualMedia/<str>/Actions/"
299 "VirtualMedia.InsertMedia",
300 std::string(), std::string())
301 {
302 entityPrivileges = {
303 {boost::beast::http::verb::get, {{"Login"}}},
304 {boost::beast::http::verb::head, {{"Login"}}},
305 {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
306 {boost::beast::http::verb::put, {{"ConfigureManager"}}},
307 {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
308 {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
309 }
310
311 private:
312 /**
Agata Olenderc6f4e012020-03-11 15:19:07 +0100313 * @brief Transfer protocols supported for InsertMedia action.
314 *
315 */
316 enum class TransferProtocol
317 {
318 https,
319 smb,
320 invalid
321 };
322
323 /**
324 * @brief Function extracts transfer protocol type from URI.
325 *
326 */
327 std::optional<TransferProtocol>
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500328 getTransferProtocolFromUri(const std::string& imageUri)
Agata Olenderc6f4e012020-03-11 15:19:07 +0100329 {
Anna Platash9e319cf2020-11-17 10:18:31 +0100330 try
Agata Olenderc6f4e012020-03-11 15:19:07 +0100331 {
Anna Platash9e319cf2020-11-17 10:18:31 +0100332 std::string_view scheme = boost::urls::url_view(imageUri).scheme();
333 if (scheme == "smb")
334 {
335 return TransferProtocol::smb;
336 }
Ed Tanous81ce6092020-12-17 16:54:55 +0000337 if (scheme == "https")
Anna Platash9e319cf2020-11-17 10:18:31 +0100338 {
339 return TransferProtocol::https;
340 }
341 else if (!scheme.empty())
342 {
343 return TransferProtocol::invalid;
344 }
Agata Olenderc6f4e012020-03-11 15:19:07 +0100345 }
Anna Platash9e319cf2020-11-17 10:18:31 +0100346 catch (std::exception& p)
Agata Olenderc6f4e012020-03-11 15:19:07 +0100347 {
Anna Platash9e319cf2020-11-17 10:18:31 +0100348 BMCWEB_LOG_ERROR << p.what();
Agata Olenderc6f4e012020-03-11 15:19:07 +0100349 }
Anna Platash9e319cf2020-11-17 10:18:31 +0100350
351 return {};
Agata Olenderc6f4e012020-03-11 15:19:07 +0100352 }
353
354 /**
355 * @brief Function convert transfer protocol from string param.
356 *
357 */
358 std::optional<TransferProtocol> getTransferProtocolFromParam(
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500359 const std::optional<std::string>& transferProtocolType)
Agata Olenderc6f4e012020-03-11 15:19:07 +0100360 {
361 if (transferProtocolType == std::nullopt)
362 {
363 return {};
364 }
365
366 if (*transferProtocolType == "CIFS")
367 {
368 return TransferProtocol::smb;
369 }
370
371 if (*transferProtocolType == "HTTPS")
372 {
373 return TransferProtocol::https;
374 }
375
376 return TransferProtocol::invalid;
377 }
378
379 /**
380 * @brief Function extends URI with transfer protocol type.
381 *
382 */
Ed Tanous81ce6092020-12-17 16:54:55 +0000383 std::string
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500384 getUriWithTransferProtocol(const std::string& imageUri,
385 const TransferProtocol& transferProtocol)
Agata Olenderc6f4e012020-03-11 15:19:07 +0100386 {
387 if (transferProtocol == TransferProtocol::smb)
388 {
389 return "smb://" + imageUri;
390 }
391
392 if (transferProtocol == TransferProtocol::https)
393 {
394 return "https://" + imageUri;
395 }
396
397 return imageUri;
398 }
399
400 /**
401 * @brief Function validate parameters of insert media request.
402 *
403 */
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500404 bool validateParams(crow::Response& res, std::string& imageUrl,
405 const std::optional<bool>& inserted,
406 const std::optional<std::string>& transferMethod,
407 const std::optional<std::string>& transferProtocolType)
Agata Olenderc6f4e012020-03-11 15:19:07 +0100408 {
409 BMCWEB_LOG_DEBUG << "Validation started";
410 // required param imageUrl must not be empty
411 if (imageUrl.empty())
412 {
413 BMCWEB_LOG_ERROR << "Request action parameter Image is empty.";
414
415 messages::propertyValueFormatError(res, "<empty>", "Image");
416
417 return false;
418 }
419
420 // optional param inserted must be true
421 if ((inserted != std::nullopt) && (*inserted != true))
422 {
423 BMCWEB_LOG_ERROR
424 << "Request action optional parameter Inserted must be true.";
425
426 messages::actionParameterNotSupported(res, "Inserted",
427 "InsertMedia");
428
429 return false;
430 }
431
432 // optional param transferMethod must be stream
433 if ((transferMethod != std::nullopt) && (*transferMethod != "Stream"))
434 {
435 BMCWEB_LOG_ERROR << "Request action optional parameter "
436 "TransferMethod must be Stream.";
437
438 messages::actionParameterNotSupported(res, "TransferMethod",
439 "InsertMedia");
440
441 return false;
442 }
443
444 std::optional<TransferProtocol> uriTransferProtocolType =
445 getTransferProtocolFromUri(imageUrl);
446
447 std::optional<TransferProtocol> paramTransferProtocolType =
448 getTransferProtocolFromParam(transferProtocolType);
449
450 // ImageUrl does not contain valid protocol type
451 if (*uriTransferProtocolType == TransferProtocol::invalid)
452 {
453 BMCWEB_LOG_ERROR << "Request action parameter ImageUrl must "
454 "contain specified protocol type from list: "
455 "(smb, https).";
456
457 messages::resourceAtUriInUnknownFormat(res, imageUrl);
458
459 return false;
460 }
461
462 // transferProtocolType should contain value from list
463 if (*paramTransferProtocolType == TransferProtocol::invalid)
464 {
465 BMCWEB_LOG_ERROR << "Request action parameter TransferProtocolType "
466 "must be provided with value from list: "
467 "(CIFS, HTTPS).";
468
469 messages::propertyValueNotInList(res, *transferProtocolType,
470 "TransferProtocolType");
471 return false;
472 }
473
474 // valid transfer protocol not provided either with URI nor param
475 if ((uriTransferProtocolType == std::nullopt) &&
476 (paramTransferProtocolType == std::nullopt))
477 {
478 BMCWEB_LOG_ERROR << "Request action parameter ImageUrl must "
479 "contain specified protocol type or param "
480 "TransferProtocolType must be provided.";
481
482 messages::resourceAtUriInUnknownFormat(res, imageUrl);
483
484 return false;
485 }
486
487 // valid transfer protocol provided both with URI and param
488 if ((paramTransferProtocolType != std::nullopt) &&
489 (uriTransferProtocolType != std::nullopt))
490 {
491 // check if protocol is the same for URI and param
492 if (*paramTransferProtocolType != *uriTransferProtocolType)
493 {
494 BMCWEB_LOG_ERROR << "Request action parameter "
495 "TransferProtocolType must contain the "
496 "same protocol type as protocol type "
497 "provided with param imageUrl.";
498
499 messages::actionParameterValueTypeError(
500 res, *transferProtocolType, "TransferProtocolType",
501 "InsertMedia");
502
503 return false;
504 }
505 }
506
507 // validation passed
508 // add protocol to URI if needed
509 if (uriTransferProtocolType == std::nullopt)
510 {
511 imageUrl = getUriWithTransferProtocol(imageUrl,
512 *paramTransferProtocolType);
513 }
514
515 return true;
516 }
517
518 /**
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200519 * @brief Function handles POST method request.
520 *
521 * Analyzes POST body message before sends Reset request data to dbus.
522 */
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500523 void doPost(crow::Response& res, const crow::Request& req,
524 const std::vector<std::string>& params) override
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200525 {
526 auto aResp = std::make_shared<AsyncResp>(res);
527
528 if (params.size() != 2)
529 {
530 messages::internalError(res);
531 return;
532 }
533
534 // take resource name from URL
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500535 const std::string& resName = params[1];
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200536
537 if (params[0] != "bmc")
538 {
539 messages::resourceNotFound(res, "VirtualMedia.Insert", resName);
540
541 return;
542 }
543
544 crow::connections::systemBus->async_method_call(
545 [this, aResp{std::move(aResp)}, req,
546 resName](const boost::system::error_code ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500547 const GetObjectType& getObjectType) {
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200548 if (ec)
549 {
550 BMCWEB_LOG_ERROR << "ObjectMapper::GetObject call failed: "
551 << ec;
552 messages::internalError(aResp->res);
553
554 return;
555 }
556 std::string service = getObjectType.begin()->first;
557 BMCWEB_LOG_DEBUG << "GetObjectType: " << service;
558
559 crow::connections::systemBus->async_method_call(
Ed Tanous81ce6092020-12-17 16:54:55 +0000560 [this, service, resName, req,
561 aResp{aResp}](const boost::system::error_code ec,
562 ManagedObjectType& subtree) {
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200563 if (ec)
564 {
565 BMCWEB_LOG_DEBUG << "DBUS response error";
566
567 return;
568 }
569
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500570 for (const auto& object : subtree)
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200571 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500572 const std::string& path =
573 static_cast<const std::string&>(object.first);
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200574
Ed Tanousf23b7292020-10-15 09:41:17 -0700575 std::size_t lastIndex = path.rfind('/');
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200576 if (lastIndex == std::string::npos)
577 {
578 continue;
579 }
580
581 lastIndex += 1;
582
583 if (path.substr(lastIndex) == resName)
584 {
585 lastIndex = path.rfind("Proxy");
586 if (lastIndex != std::string::npos)
587 {
588 // Not possible in proxy mode
589 BMCWEB_LOG_DEBUG << "InsertMedia not "
590 "allowed in proxy mode";
591 messages::resourceNotFound(
592 aResp->res, "VirtualMedia.InsertMedia",
593 resName);
594
595 return;
596 }
597
598 lastIndex = path.rfind("Legacy");
Agata Olenderc6f4e012020-03-11 15:19:07 +0100599 if (lastIndex == std::string::npos)
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200600 {
Agata Olenderc6f4e012020-03-11 15:19:07 +0100601 continue;
602 }
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200603
Agata Olenderc6f4e012020-03-11 15:19:07 +0100604 // Legacy mode
605 std::string imageUrl;
606 std::optional<std::string> userName;
607 std::optional<std::string> password;
608 std::optional<std::string> transferMethod;
609 std::optional<std::string> transferProtocolType;
610 std::optional<bool> writeProtected = true;
611 std::optional<bool> inserted;
Adrian Ambrożewiczd6da5be2020-01-13 18:31:01 +0100612
Gunnar Mills4e0453b2020-07-08 14:00:30 -0500613 // Read obligatory parameters (url of image)
Agata Olenderc6f4e012020-03-11 15:19:07 +0100614 if (!json_util::readJson(
615 req, aResp->res, "Image", imageUrl,
616 "WriteProtected", writeProtected,
617 "UserName", userName, "Password",
618 password, "Inserted", inserted,
619 "TransferMethod", transferMethod,
620 "TransferProtocolType",
621 transferProtocolType))
622 {
623 BMCWEB_LOG_DEBUG << "Image is not provided";
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200624 return;
625 }
Agata Olenderc6f4e012020-03-11 15:19:07 +0100626
627 bool paramsValid = validateParams(
628 aResp->res, imageUrl, inserted,
629 transferMethod, transferProtocolType);
630
631 if (paramsValid == false)
632 {
633 return;
634 }
635
636 // manager is irrelevant for VirtualMedia dbus
637 // calls
Ed Tanous81ce6092020-12-17 16:54:55 +0000638 doMountVmLegacy(aResp, service, resName,
639 imageUrl, !(*writeProtected),
640 std::move(*userName),
641 std::move(*password));
Agata Olenderc6f4e012020-03-11 15:19:07 +0100642
643 return;
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200644 }
645 }
646 BMCWEB_LOG_DEBUG << "Parent item not found";
647 messages::resourceNotFound(aResp->res, "VirtualMedia",
648 resName);
649 },
650 service, "/xyz/openbmc_project/VirtualMedia",
651 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
652 },
653 "xyz.openbmc_project.ObjectMapper",
654 "/xyz/openbmc_project/object_mapper",
655 "xyz.openbmc_project.ObjectMapper", "GetObject",
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500656 "/xyz/openbmc_project/VirtualMedia", std::array<const char*, 0>());
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200657 }
658
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500659 template <typename T>
660 static void secureCleanup(T& value)
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100661 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500662 auto raw = const_cast<typename T::value_type*>(value.data());
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100663 explicit_bzero(raw, value.size() * sizeof(*raw));
664 }
665
666 class Credentials
667 {
668 public:
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500669 Credentials(std::string&& user, std::string&& password) :
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100670 userBuf(std::move(user)), passBuf(std::move(password))
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500671 {}
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100672
673 ~Credentials()
674 {
675 secureCleanup(userBuf);
676 secureCleanup(passBuf);
677 }
678
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500679 const std::string& user()
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100680 {
681 return userBuf;
682 }
683
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500684 const std::string& password()
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100685 {
686 return passBuf;
687 }
688
689 private:
690 Credentials() = delete;
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500691 Credentials(const Credentials&) = delete;
692 Credentials& operator=(const Credentials&) = delete;
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100693
694 std::string userBuf;
695 std::string passBuf;
696 };
697
698 class CredentialsProvider
699 {
700 public:
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500701 template <typename T>
702 struct Deleter
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100703 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500704 void operator()(T* buff) const
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100705 {
706 if (buff)
707 {
708 secureCleanup(*buff);
709 delete buff;
710 }
711 }
712 };
713
714 using Buffer = std::vector<char>;
715 using SecureBuffer = std::unique_ptr<Buffer, Deleter<Buffer>>;
716 // Using explicit definition instead of std::function to avoid implicit
717 // conversions eg. stack copy instead of reference
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500718 using FormatterFunc = void(const std::string& username,
719 const std::string& password, Buffer& dest);
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100720
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500721 CredentialsProvider(std::string&& user, std::string&& password) :
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100722 credentials(std::move(user), std::move(password))
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500723 {}
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100724
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500725 const std::string& user()
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100726 {
727 return credentials.user();
728 }
729
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500730 const std::string& password()
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100731 {
732 return credentials.password();
733 }
734
Ed Tanous81ce6092020-12-17 16:54:55 +0000735 SecureBuffer pack(FormatterFunc formatter)
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100736 {
737 SecureBuffer packed{new Buffer{}};
738 if (formatter)
739 {
740 formatter(credentials.user(), credentials.password(), *packed);
741 }
742
743 return packed;
744 }
745
746 private:
747 Credentials credentials;
748 };
749
750 // Wrapper for boost::async_pipe ensuring proper pipe cleanup
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500751 template <typename Buffer>
752 class Pipe
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100753 {
754 public:
755 using unix_fd = sdbusplus::message::unix_fd;
756
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500757 Pipe(boost::asio::io_context& io, Buffer&& buffer) :
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100758 impl(io), buffer{std::move(buffer)}
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500759 {}
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100760
761 ~Pipe()
762 {
763 // Named pipe needs to be explicitly removed
764 impl.close();
765 }
766
767 unix_fd fd()
768 {
769 return unix_fd{impl.native_source()};
770 }
771
772 template <typename WriteHandler>
Ed Tanous81ce6092020-12-17 16:54:55 +0000773 void asyncWrite(WriteHandler&& handler)
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100774 {
775 impl.async_write_some(data(), std::forward<WriteHandler>(handler));
776 }
777
778 private:
779 // Specialization for pointer types
780 template <typename B = Buffer>
781 typename std::enable_if<boost::has_dereference<B>::value,
782 boost::asio::const_buffer>::type
783 data()
784 {
785 return boost::asio::buffer(*buffer);
786 }
787
788 template <typename B = Buffer>
789 typename std::enable_if<!boost::has_dereference<B>::value,
790 boost::asio::const_buffer>::type
791 data()
792 {
793 return boost::asio::buffer(buffer);
794 }
795
796 const std::string name;
797 boost::process::async_pipe impl;
798 Buffer buffer;
799 };
800
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200801 /**
802 * @brief Function transceives data with dbus directly.
803 *
804 * All BMC state properties will be retrieved before sending reset request.
805 */
Ed Tanous81ce6092020-12-17 16:54:55 +0000806 void doMountVmLegacy(const std::shared_ptr<AsyncResp>& asyncResp,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500807 const std::string& service, const std::string& name,
808 const std::string& imageUrl, const bool rw,
809 std::string&& userName, std::string&& password)
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200810 {
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100811 using SecurePipe = Pipe<CredentialsProvider::SecureBuffer>;
812 constexpr const size_t secretLimit = 1024;
813
814 std::shared_ptr<SecurePipe> secretPipe;
815 std::variant<int, SecurePipe::unix_fd> unixFd = -1;
816
817 if (!userName.empty() || !password.empty())
818 {
819 // Encapsulate in safe buffer
820 CredentialsProvider credentials(std::move(userName),
821 std::move(password));
822
823 // Payload must contain data + NULL delimiters
824 if (credentials.user().size() + credentials.password().size() + 2 >
825 secretLimit)
826 {
827 BMCWEB_LOG_ERROR << "Credentials too long to handle";
828 messages::unrecognizedRequestBody(asyncResp->res);
829 return;
830 }
831
832 // Pack secret
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500833 auto secret = credentials.pack([](const auto& user,
834 const auto& pass, auto& buff) {
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100835 std::copy(user.begin(), user.end(), std::back_inserter(buff));
836 buff.push_back('\0');
837 std::copy(pass.begin(), pass.end(), std::back_inserter(buff));
838 buff.push_back('\0');
839 });
840
841 // Open pipe
842 secretPipe = std::make_shared<SecurePipe>(
843 crow::connections::systemBus->get_io_context(),
844 std::move(secret));
845 unixFd = secretPipe->fd();
846
847 // Pass secret over pipe
Ed Tanous81ce6092020-12-17 16:54:55 +0000848 secretPipe->asyncWrite(
Vikram Bodireddyf5b16f02020-08-26 14:54:51 +0530849 [asyncResp](const boost::system::error_code& ec, std::size_t) {
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100850 if (ec)
851 {
852 BMCWEB_LOG_ERROR << "Failed to pass secret: " << ec;
853 messages::internalError(asyncResp->res);
854 }
855 });
856 }
857
Adrian Ambrożewiczd6da5be2020-01-13 18:31:01 +0100858 crow::connections::systemBus->async_method_call(
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100859 [asyncResp, secretPipe](const boost::system::error_code ec,
860 bool success) {
Adrian Ambrożewiczd6da5be2020-01-13 18:31:01 +0100861 if (ec)
862 {
863 BMCWEB_LOG_ERROR << "Bad D-Bus request error: " << ec;
864 messages::internalError(asyncResp->res);
865 }
866 else if (!success)
867 {
868 BMCWEB_LOG_ERROR << "Service responded with error";
869 messages::generalError(asyncResp->res);
870 }
871 },
872 service, "/xyz/openbmc_project/VirtualMedia/Legacy/" + name,
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100873 "xyz.openbmc_project.VirtualMedia.Legacy", "Mount", imageUrl, rw,
874 unixFd);
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200875 }
876};
877
878/**
879 @brief EjectMedia action class
880 */
881class VirtualMediaActionEjectMedia : public Node
882{
883 public:
Ed Tanous52cc1122020-07-18 13:51:21 -0700884 VirtualMediaActionEjectMedia(App& app) :
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200885 Node(app,
886 "/redfish/v1/Managers/<str>/VirtualMedia/<str>/Actions/"
887 "VirtualMedia.EjectMedia",
888 std::string(), std::string())
889 {
890 entityPrivileges = {
891 {boost::beast::http::verb::get, {{"Login"}}},
892 {boost::beast::http::verb::head, {{"Login"}}},
893 {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
894 {boost::beast::http::verb::put, {{"ConfigureManager"}}},
895 {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
896 {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
897 }
898
899 private:
900 /**
901 * @brief Function handles POST method request.
902 *
903 * Analyzes POST body message before sends Reset request data to dbus.
904 */
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500905 void doPost(crow::Response& res, const crow::Request& req,
906 const std::vector<std::string>& params) override
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200907 {
908 auto aResp = std::make_shared<AsyncResp>(res);
909
910 if (params.size() != 2)
911 {
912 messages::internalError(res);
913 return;
914 }
915
916 // take resource name from URL
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500917 const std::string& resName = params[1];
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200918
919 if (params[0] != "bmc")
920 {
921 messages::resourceNotFound(res, "VirtualMedia.Eject", resName);
922
923 return;
924 }
925
926 crow::connections::systemBus->async_method_call(
927 [this, aResp{std::move(aResp)}, req,
928 resName](const boost::system::error_code ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500929 const GetObjectType& getObjectType) {
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200930 if (ec)
931 {
932 BMCWEB_LOG_ERROR << "ObjectMapper::GetObject call failed: "
933 << ec;
934 messages::internalError(aResp->res);
935
936 return;
937 }
938 std::string service = getObjectType.begin()->first;
939 BMCWEB_LOG_DEBUG << "GetObjectType: " << service;
940
941 crow::connections::systemBus->async_method_call(
Ed Tanous81ce6092020-12-17 16:54:55 +0000942 [this, resName, service, req,
943 aResp{aResp}](const boost::system::error_code ec,
944 ManagedObjectType& subtree) {
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200945 if (ec)
946 {
947 BMCWEB_LOG_DEBUG << "DBUS response error";
948
949 return;
950 }
951
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500952 for (const auto& object : subtree)
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200953 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500954 const std::string& path =
955 static_cast<const std::string&>(object.first);
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200956
Ed Tanousf23b7292020-10-15 09:41:17 -0700957 std::size_t lastIndex = path.rfind('/');
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200958 if (lastIndex == std::string::npos)
959 {
960 continue;
961 }
962
963 lastIndex += 1;
964
965 if (path.substr(lastIndex) == resName)
966 {
967 lastIndex = path.rfind("Proxy");
968 if (lastIndex != std::string::npos)
969 {
970 // Proxy mode
Ed Tanous81ce6092020-12-17 16:54:55 +0000971 doVmAction(aResp, service, resName, false);
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200972 }
973
974 lastIndex = path.rfind("Legacy");
975 if (lastIndex != std::string::npos)
976 {
977 // Legacy mode
Ed Tanous81ce6092020-12-17 16:54:55 +0000978 doVmAction(aResp, service, resName, true);
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200979 }
980
981 return;
982 }
983 }
984 BMCWEB_LOG_DEBUG << "Parent item not found";
985 messages::resourceNotFound(aResp->res, "VirtualMedia",
986 resName);
987 },
988 service, "/xyz/openbmc_project/VirtualMedia",
989 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
990 },
991 "xyz.openbmc_project.ObjectMapper",
992 "/xyz/openbmc_project/object_mapper",
993 "xyz.openbmc_project.ObjectMapper", "GetObject",
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500994 "/xyz/openbmc_project/VirtualMedia", std::array<const char*, 0>());
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200995 }
996
997 /**
998 * @brief Function transceives data with dbus directly.
999 *
1000 * All BMC state properties will be retrieved before sending reset request.
1001 */
Ed Tanous81ce6092020-12-17 16:54:55 +00001002 void doVmAction(const std::shared_ptr<AsyncResp>& asyncResp,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001003 const std::string& service, const std::string& name,
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +02001004 bool legacy)
1005 {
1006
1007 // Legacy mount requires parameter with image
1008 if (legacy)
1009 {
1010 crow::connections::systemBus->async_method_call(
1011 [asyncResp](const boost::system::error_code ec) {
1012 if (ec)
1013 {
1014 BMCWEB_LOG_ERROR << "Bad D-Bus request error: " << ec;
1015
1016 messages::internalError(asyncResp->res);
1017 return;
1018 }
1019 },
1020 service, "/xyz/openbmc_project/VirtualMedia/Legacy/" + name,
1021 "xyz.openbmc_project.VirtualMedia.Legacy", "Unmount");
1022 }
1023 else // proxy
1024 {
1025 crow::connections::systemBus->async_method_call(
1026 [asyncResp](const boost::system::error_code ec) {
1027 if (ec)
1028 {
1029 BMCWEB_LOG_ERROR << "Bad D-Bus request error: " << ec;
1030
1031 messages::internalError(asyncResp->res);
1032 return;
1033 }
1034 },
1035 service, "/xyz/openbmc_project/VirtualMedia/Proxy/" + name,
1036 "xyz.openbmc_project.VirtualMedia.Proxy", "Unmount");
1037 }
1038 }
1039};
1040
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +02001041class VirtualMediaCollection : public Node
1042{
1043 public:
1044 /*
1045 * Default Constructor
1046 */
Ed Tanous52cc1122020-07-18 13:51:21 -07001047 VirtualMediaCollection(App& app) :
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +02001048 Node(app, "/redfish/v1/Managers/<str>/VirtualMedia/", std::string())
1049 {
1050 entityPrivileges = {
1051 {boost::beast::http::verb::get, {{"Login"}}},
1052 {boost::beast::http::verb::head, {{"Login"}}},
1053 {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
1054 {boost::beast::http::verb::put, {{"ConfigureManager"}}},
1055 {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
1056 {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
1057 }
1058
1059 private:
1060 /**
1061 * Functions triggers appropriate requests on DBus
1062 */
Vikram Bodireddyf5b16f02020-08-26 14:54:51 +05301063 void doGet(crow::Response& res, const crow::Request&,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001064 const std::vector<std::string>& params) override
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +02001065 {
1066 auto asyncResp = std::make_shared<AsyncResp>(res);
1067
1068 // Check if there is required param, truly entering this shall be
1069 // impossible
1070 if (params.size() != 1)
1071 {
1072 messages::internalError(res);
1073
1074 return;
1075 }
1076
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001077 const std::string& name = params[0];
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +02001078
1079 if (name != "bmc")
1080 {
1081 messages::resourceNotFound(asyncResp->res, "VirtualMedia", name);
1082
1083 return;
1084 }
1085
1086 res.jsonValue["@odata.type"] =
1087 "#VirtualMediaCollection.VirtualMediaCollection";
1088 res.jsonValue["Name"] = "Virtual Media Services";
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +02001089 res.jsonValue["@odata.id"] =
Przemyslaw Czarnowskid6c414f2020-07-08 15:17:31 +02001090 "/redfish/v1/Managers/" + name + "/VirtualMedia";
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +02001091
1092 crow::connections::systemBus->async_method_call(
1093 [asyncResp, name](const boost::system::error_code ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001094 const GetObjectType& getObjectType) {
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +02001095 if (ec)
1096 {
1097 BMCWEB_LOG_ERROR << "ObjectMapper::GetObject call failed: "
1098 << ec;
1099 messages::internalError(asyncResp->res);
1100
1101 return;
1102 }
1103 std::string service = getObjectType.begin()->first;
1104 BMCWEB_LOG_DEBUG << "GetObjectType: " << service;
1105
1106 getVmResourceList(asyncResp, service, name);
1107 },
1108 "xyz.openbmc_project.ObjectMapper",
1109 "/xyz/openbmc_project/object_mapper",
1110 "xyz.openbmc_project.ObjectMapper", "GetObject",
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001111 "/xyz/openbmc_project/VirtualMedia", std::array<const char*, 0>());
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +02001112 }
1113};
1114
1115class VirtualMedia : public Node
1116{
1117 public:
1118 /*
1119 * Default Constructor
1120 */
Ed Tanous52cc1122020-07-18 13:51:21 -07001121 VirtualMedia(App& app) :
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +02001122 Node(app, "/redfish/v1/Managers/<str>/VirtualMedia/<str>/",
1123 std::string(), std::string())
1124 {
1125 entityPrivileges = {
1126 {boost::beast::http::verb::get, {{"Login"}}},
1127 {boost::beast::http::verb::head, {{"Login"}}},
1128 {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
1129 {boost::beast::http::verb::put, {{"ConfigureManager"}}},
1130 {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
1131 {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
1132 }
1133
1134 private:
1135 /**
1136 * Functions triggers appropriate requests on DBus
1137 */
Vikram Bodireddyf5b16f02020-08-26 14:54:51 +05301138 void doGet(crow::Response& res, const crow::Request&,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001139 const std::vector<std::string>& params) override
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +02001140 {
1141 // Check if there is required param, truly entering this shall be
1142 // impossible
1143 if (params.size() != 2)
1144 {
1145 messages::internalError(res);
1146
1147 res.end();
1148 return;
1149 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001150 const std::string& name = params[0];
1151 const std::string& resName = params[1];
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +02001152
1153 auto asyncResp = std::make_shared<AsyncResp>(res);
1154
1155 if (name != "bmc")
1156 {
1157 messages::resourceNotFound(asyncResp->res, "VirtualMedia", resName);
1158
1159 return;
1160 }
1161
1162 crow::connections::systemBus->async_method_call(
1163 [asyncResp, name, resName](const boost::system::error_code ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001164 const GetObjectType& getObjectType) {
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +02001165 if (ec)
1166 {
1167 BMCWEB_LOG_ERROR << "ObjectMapper::GetObject call failed: "
1168 << ec;
1169 messages::internalError(asyncResp->res);
1170
1171 return;
1172 }
1173 std::string service = getObjectType.begin()->first;
1174 BMCWEB_LOG_DEBUG << "GetObjectType: " << service;
1175
1176 getVmData(asyncResp, service, name, resName);
1177 },
1178 "xyz.openbmc_project.ObjectMapper",
1179 "/xyz/openbmc_project/object_mapper",
1180 "xyz.openbmc_project.ObjectMapper", "GetObject",
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001181 "/xyz/openbmc_project/VirtualMedia", std::array<const char*, 0>());
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +02001182 }
1183};
1184
1185} // namespace redfish