blob: e9697785e4ae172fb9fda23213afd29aa7ea3b4e [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;
Ed Tanous2dfd18e2020-12-18 00:41:31 +0000206 std::string path = object.first.filename();
207 if (path.empty())
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200208 {
209 continue;
210 }
211
Ed Tanous2dfd18e2020-12-18 00:41:31 +0000212 item["@odata.id"] =
AppaRao Puli788ca502021-02-23 12:01:16 +0000213 "/redfish/v1/Managers/" + name + "/VirtualMedia/" + path;
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200214
215 members.emplace_back(std::move(item));
216 }
217 aResp->res.jsonValue["Members@odata.count"] = members.size();
218 },
219 service, "/xyz/openbmc_project/VirtualMedia",
220 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
221}
222
223/**
224 * @brief Fills data for specific resource
225 */
Ed Tanous81ce6092020-12-17 16:54:55 +0000226static void getVmData(const std::shared_ptr<AsyncResp>& aResp,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500227 const std::string& service, const std::string& name,
228 const std::string& resName)
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200229{
230 BMCWEB_LOG_DEBUG << "Get Virtual Media resource data.";
231
232 crow::connections::systemBus->async_method_call(
233 [resName, name, aResp](const boost::system::error_code ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500234 ManagedObjectType& subtree) {
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200235 if (ec)
236 {
237 BMCWEB_LOG_DEBUG << "DBUS response error";
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200238
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200239 return;
240 }
241
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500242 for (auto& item : subtree)
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200243 {
Ed Tanous2dfd18e2020-12-18 00:41:31 +0000244 std::string thispath = item.first.filename();
245 if (thispath.empty())
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200246 {
247 continue;
248 }
249
Ed Tanous2dfd18e2020-12-18 00:41:31 +0000250 if (thispath != resName)
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200251 {
252 continue;
253 }
254
255 aResp->res.jsonValue = vmItemTemplate(name, resName);
256
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200257 // Check if dbus path is Legacy type
Ed Tanous2dfd18e2020-12-18 00:41:31 +0000258 if (thispath.find("VirtualMedia/Legacy") != std::string::npos)
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200259 {
260 aResp->res.jsonValue["Actions"]["#VirtualMedia.InsertMedia"]
261 ["target"] =
262 "/redfish/v1/Managers/" + name + "/VirtualMedia/" +
263 resName + "/Actions/VirtualMedia.InsertMedia";
264 }
265
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200266 vmParseInterfaceObject(item.second, aResp);
267
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200268 aResp->res.jsonValue["Actions"]["#VirtualMedia.EjectMedia"]
269 ["target"] =
270 "/redfish/v1/Managers/" + name + "/VirtualMedia/" +
271 resName + "/Actions/VirtualMedia.EjectMedia";
272
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200273 return;
274 }
275
276 messages::resourceNotFound(
Przemyslaw Czarnowskid04ba322020-01-21 12:41:56 +0100277 aResp->res, "#VirtualMedia.v1_3_0.VirtualMedia", resName);
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200278 },
279 service, "/xyz/openbmc_project/VirtualMedia",
280 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
281}
282
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200283/**
284 @brief InsertMedia action class
285 */
286class VirtualMediaActionInsertMedia : public Node
287{
288 public:
Ed Tanous52cc1122020-07-18 13:51:21 -0700289 VirtualMediaActionInsertMedia(App& app) :
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200290 Node(app,
291 "/redfish/v1/Managers/<str>/VirtualMedia/<str>/Actions/"
292 "VirtualMedia.InsertMedia",
293 std::string(), std::string())
294 {
295 entityPrivileges = {
296 {boost::beast::http::verb::get, {{"Login"}}},
297 {boost::beast::http::verb::head, {{"Login"}}},
298 {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
299 {boost::beast::http::verb::put, {{"ConfigureManager"}}},
300 {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
301 {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
302 }
303
304 private:
305 /**
Agata Olenderc6f4e012020-03-11 15:19:07 +0100306 * @brief Transfer protocols supported for InsertMedia action.
307 *
308 */
309 enum class TransferProtocol
310 {
311 https,
312 smb,
313 invalid
314 };
315
316 /**
317 * @brief Function extracts transfer protocol type from URI.
318 *
319 */
320 std::optional<TransferProtocol>
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500321 getTransferProtocolFromUri(const std::string& imageUri)
Agata Olenderc6f4e012020-03-11 15:19:07 +0100322 {
Anna Platash9e319cf2020-11-17 10:18:31 +0100323 try
Agata Olenderc6f4e012020-03-11 15:19:07 +0100324 {
Anna Platash9e319cf2020-11-17 10:18:31 +0100325 std::string_view scheme = boost::urls::url_view(imageUri).scheme();
326 if (scheme == "smb")
327 {
328 return TransferProtocol::smb;
329 }
Ed Tanous81ce6092020-12-17 16:54:55 +0000330 if (scheme == "https")
Anna Platash9e319cf2020-11-17 10:18:31 +0100331 {
332 return TransferProtocol::https;
333 }
334 else if (!scheme.empty())
335 {
336 return TransferProtocol::invalid;
337 }
Agata Olenderc6f4e012020-03-11 15:19:07 +0100338 }
Anna Platash9e319cf2020-11-17 10:18:31 +0100339 catch (std::exception& p)
Agata Olenderc6f4e012020-03-11 15:19:07 +0100340 {
Anna Platash9e319cf2020-11-17 10:18:31 +0100341 BMCWEB_LOG_ERROR << p.what();
Agata Olenderc6f4e012020-03-11 15:19:07 +0100342 }
Anna Platash9e319cf2020-11-17 10:18:31 +0100343
344 return {};
Agata Olenderc6f4e012020-03-11 15:19:07 +0100345 }
346
347 /**
348 * @brief Function convert transfer protocol from string param.
349 *
350 */
351 std::optional<TransferProtocol> getTransferProtocolFromParam(
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500352 const std::optional<std::string>& transferProtocolType)
Agata Olenderc6f4e012020-03-11 15:19:07 +0100353 {
354 if (transferProtocolType == std::nullopt)
355 {
356 return {};
357 }
358
359 if (*transferProtocolType == "CIFS")
360 {
361 return TransferProtocol::smb;
362 }
363
364 if (*transferProtocolType == "HTTPS")
365 {
366 return TransferProtocol::https;
367 }
368
369 return TransferProtocol::invalid;
370 }
371
372 /**
373 * @brief Function extends URI with transfer protocol type.
374 *
375 */
Ed Tanous81ce6092020-12-17 16:54:55 +0000376 std::string
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500377 getUriWithTransferProtocol(const std::string& imageUri,
378 const TransferProtocol& transferProtocol)
Agata Olenderc6f4e012020-03-11 15:19:07 +0100379 {
380 if (transferProtocol == TransferProtocol::smb)
381 {
382 return "smb://" + imageUri;
383 }
384
385 if (transferProtocol == TransferProtocol::https)
386 {
387 return "https://" + imageUri;
388 }
389
390 return imageUri;
391 }
392
393 /**
394 * @brief Function validate parameters of insert media request.
395 *
396 */
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500397 bool validateParams(crow::Response& res, std::string& imageUrl,
398 const std::optional<bool>& inserted,
399 const std::optional<std::string>& transferMethod,
400 const std::optional<std::string>& transferProtocolType)
Agata Olenderc6f4e012020-03-11 15:19:07 +0100401 {
402 BMCWEB_LOG_DEBUG << "Validation started";
403 // required param imageUrl must not be empty
404 if (imageUrl.empty())
405 {
406 BMCWEB_LOG_ERROR << "Request action parameter Image is empty.";
407
408 messages::propertyValueFormatError(res, "<empty>", "Image");
409
410 return false;
411 }
412
413 // optional param inserted must be true
414 if ((inserted != std::nullopt) && (*inserted != true))
415 {
416 BMCWEB_LOG_ERROR
417 << "Request action optional parameter Inserted must be true.";
418
419 messages::actionParameterNotSupported(res, "Inserted",
420 "InsertMedia");
421
422 return false;
423 }
424
425 // optional param transferMethod must be stream
426 if ((transferMethod != std::nullopt) && (*transferMethod != "Stream"))
427 {
428 BMCWEB_LOG_ERROR << "Request action optional parameter "
429 "TransferMethod must be Stream.";
430
431 messages::actionParameterNotSupported(res, "TransferMethod",
432 "InsertMedia");
433
434 return false;
435 }
436
437 std::optional<TransferProtocol> uriTransferProtocolType =
438 getTransferProtocolFromUri(imageUrl);
439
440 std::optional<TransferProtocol> paramTransferProtocolType =
441 getTransferProtocolFromParam(transferProtocolType);
442
443 // ImageUrl does not contain valid protocol type
444 if (*uriTransferProtocolType == TransferProtocol::invalid)
445 {
446 BMCWEB_LOG_ERROR << "Request action parameter ImageUrl must "
447 "contain specified protocol type from list: "
448 "(smb, https).";
449
450 messages::resourceAtUriInUnknownFormat(res, imageUrl);
451
452 return false;
453 }
454
455 // transferProtocolType should contain value from list
456 if (*paramTransferProtocolType == TransferProtocol::invalid)
457 {
458 BMCWEB_LOG_ERROR << "Request action parameter TransferProtocolType "
459 "must be provided with value from list: "
460 "(CIFS, HTTPS).";
461
462 messages::propertyValueNotInList(res, *transferProtocolType,
463 "TransferProtocolType");
464 return false;
465 }
466
467 // valid transfer protocol not provided either with URI nor param
468 if ((uriTransferProtocolType == std::nullopt) &&
469 (paramTransferProtocolType == std::nullopt))
470 {
471 BMCWEB_LOG_ERROR << "Request action parameter ImageUrl must "
472 "contain specified protocol type or param "
473 "TransferProtocolType must be provided.";
474
475 messages::resourceAtUriInUnknownFormat(res, imageUrl);
476
477 return false;
478 }
479
480 // valid transfer protocol provided both with URI and param
481 if ((paramTransferProtocolType != std::nullopt) &&
482 (uriTransferProtocolType != std::nullopt))
483 {
484 // check if protocol is the same for URI and param
485 if (*paramTransferProtocolType != *uriTransferProtocolType)
486 {
487 BMCWEB_LOG_ERROR << "Request action parameter "
488 "TransferProtocolType must contain the "
489 "same protocol type as protocol type "
490 "provided with param imageUrl.";
491
492 messages::actionParameterValueTypeError(
493 res, *transferProtocolType, "TransferProtocolType",
494 "InsertMedia");
495
496 return false;
497 }
498 }
499
500 // validation passed
501 // add protocol to URI if needed
502 if (uriTransferProtocolType == std::nullopt)
503 {
504 imageUrl = getUriWithTransferProtocol(imageUrl,
505 *paramTransferProtocolType);
506 }
507
508 return true;
509 }
510
511 /**
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200512 * @brief Function handles POST method request.
513 *
514 * Analyzes POST body message before sends Reset request data to dbus.
515 */
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500516 void doPost(crow::Response& res, const crow::Request& req,
517 const std::vector<std::string>& params) override
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200518 {
519 auto aResp = std::make_shared<AsyncResp>(res);
520
521 if (params.size() != 2)
522 {
523 messages::internalError(res);
524 return;
525 }
526
527 // take resource name from URL
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500528 const std::string& resName = params[1];
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200529
530 if (params[0] != "bmc")
531 {
532 messages::resourceNotFound(res, "VirtualMedia.Insert", resName);
533
534 return;
535 }
536
537 crow::connections::systemBus->async_method_call(
538 [this, aResp{std::move(aResp)}, req,
539 resName](const boost::system::error_code ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500540 const GetObjectType& getObjectType) {
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200541 if (ec)
542 {
543 BMCWEB_LOG_ERROR << "ObjectMapper::GetObject call failed: "
544 << ec;
545 messages::internalError(aResp->res);
546
547 return;
548 }
549 std::string service = getObjectType.begin()->first;
550 BMCWEB_LOG_DEBUG << "GetObjectType: " << service;
551
552 crow::connections::systemBus->async_method_call(
Ed Tanous81ce6092020-12-17 16:54:55 +0000553 [this, service, resName, req,
554 aResp{aResp}](const boost::system::error_code ec,
555 ManagedObjectType& subtree) {
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200556 if (ec)
557 {
558 BMCWEB_LOG_DEBUG << "DBUS response error";
559
560 return;
561 }
562
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500563 for (const auto& object : subtree)
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200564 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500565 const std::string& path =
566 static_cast<const std::string&>(object.first);
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200567
Ed Tanousf23b7292020-10-15 09:41:17 -0700568 std::size_t lastIndex = path.rfind('/');
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200569 if (lastIndex == std::string::npos)
570 {
571 continue;
572 }
573
574 lastIndex += 1;
575
576 if (path.substr(lastIndex) == resName)
577 {
578 lastIndex = path.rfind("Proxy");
579 if (lastIndex != std::string::npos)
580 {
581 // Not possible in proxy mode
582 BMCWEB_LOG_DEBUG << "InsertMedia not "
583 "allowed in proxy mode";
584 messages::resourceNotFound(
585 aResp->res, "VirtualMedia.InsertMedia",
586 resName);
587
588 return;
589 }
590
591 lastIndex = path.rfind("Legacy");
Agata Olenderc6f4e012020-03-11 15:19:07 +0100592 if (lastIndex == std::string::npos)
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200593 {
Agata Olenderc6f4e012020-03-11 15:19:07 +0100594 continue;
595 }
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200596
Agata Olenderc6f4e012020-03-11 15:19:07 +0100597 // Legacy mode
598 std::string imageUrl;
599 std::optional<std::string> userName;
600 std::optional<std::string> password;
601 std::optional<std::string> transferMethod;
602 std::optional<std::string> transferProtocolType;
603 std::optional<bool> writeProtected = true;
604 std::optional<bool> inserted;
Adrian Ambrożewiczd6da5be2020-01-13 18:31:01 +0100605
Gunnar Mills4e0453b2020-07-08 14:00:30 -0500606 // Read obligatory parameters (url of image)
Agata Olenderc6f4e012020-03-11 15:19:07 +0100607 if (!json_util::readJson(
608 req, aResp->res, "Image", imageUrl,
609 "WriteProtected", writeProtected,
610 "UserName", userName, "Password",
611 password, "Inserted", inserted,
612 "TransferMethod", transferMethod,
613 "TransferProtocolType",
614 transferProtocolType))
615 {
616 BMCWEB_LOG_DEBUG << "Image is not provided";
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200617 return;
618 }
Agata Olenderc6f4e012020-03-11 15:19:07 +0100619
620 bool paramsValid = validateParams(
621 aResp->res, imageUrl, inserted,
622 transferMethod, transferProtocolType);
623
624 if (paramsValid == false)
625 {
626 return;
627 }
628
629 // manager is irrelevant for VirtualMedia dbus
630 // calls
Ed Tanous81ce6092020-12-17 16:54:55 +0000631 doMountVmLegacy(aResp, service, resName,
632 imageUrl, !(*writeProtected),
633 std::move(*userName),
634 std::move(*password));
Agata Olenderc6f4e012020-03-11 15:19:07 +0100635
636 return;
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200637 }
638 }
639 BMCWEB_LOG_DEBUG << "Parent item not found";
640 messages::resourceNotFound(aResp->res, "VirtualMedia",
641 resName);
642 },
643 service, "/xyz/openbmc_project/VirtualMedia",
644 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
645 },
646 "xyz.openbmc_project.ObjectMapper",
647 "/xyz/openbmc_project/object_mapper",
648 "xyz.openbmc_project.ObjectMapper", "GetObject",
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500649 "/xyz/openbmc_project/VirtualMedia", std::array<const char*, 0>());
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200650 }
651
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500652 template <typename T>
653 static void secureCleanup(T& value)
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100654 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500655 auto raw = const_cast<typename T::value_type*>(value.data());
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100656 explicit_bzero(raw, value.size() * sizeof(*raw));
657 }
658
659 class Credentials
660 {
661 public:
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500662 Credentials(std::string&& user, std::string&& password) :
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100663 userBuf(std::move(user)), passBuf(std::move(password))
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500664 {}
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100665
666 ~Credentials()
667 {
668 secureCleanup(userBuf);
669 secureCleanup(passBuf);
670 }
671
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500672 const std::string& user()
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100673 {
674 return userBuf;
675 }
676
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500677 const std::string& password()
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100678 {
679 return passBuf;
680 }
681
682 private:
683 Credentials() = delete;
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500684 Credentials(const Credentials&) = delete;
685 Credentials& operator=(const Credentials&) = delete;
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100686
687 std::string userBuf;
688 std::string passBuf;
689 };
690
691 class CredentialsProvider
692 {
693 public:
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500694 template <typename T>
695 struct Deleter
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100696 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500697 void operator()(T* buff) const
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100698 {
699 if (buff)
700 {
701 secureCleanup(*buff);
702 delete buff;
703 }
704 }
705 };
706
707 using Buffer = std::vector<char>;
708 using SecureBuffer = std::unique_ptr<Buffer, Deleter<Buffer>>;
709 // Using explicit definition instead of std::function to avoid implicit
710 // conversions eg. stack copy instead of reference
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500711 using FormatterFunc = void(const std::string& username,
712 const std::string& password, Buffer& dest);
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100713
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500714 CredentialsProvider(std::string&& user, std::string&& password) :
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100715 credentials(std::move(user), std::move(password))
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500716 {}
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100717
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500718 const std::string& user()
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100719 {
720 return credentials.user();
721 }
722
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500723 const std::string& password()
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100724 {
725 return credentials.password();
726 }
727
Ed Tanous81ce6092020-12-17 16:54:55 +0000728 SecureBuffer pack(FormatterFunc formatter)
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100729 {
730 SecureBuffer packed{new Buffer{}};
731 if (formatter)
732 {
733 formatter(credentials.user(), credentials.password(), *packed);
734 }
735
736 return packed;
737 }
738
739 private:
740 Credentials credentials;
741 };
742
743 // Wrapper for boost::async_pipe ensuring proper pipe cleanup
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500744 template <typename Buffer>
745 class Pipe
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100746 {
747 public:
748 using unix_fd = sdbusplus::message::unix_fd;
749
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500750 Pipe(boost::asio::io_context& io, Buffer&& buffer) :
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100751 impl(io), buffer{std::move(buffer)}
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500752 {}
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100753
754 ~Pipe()
755 {
756 // Named pipe needs to be explicitly removed
757 impl.close();
758 }
759
760 unix_fd fd()
761 {
762 return unix_fd{impl.native_source()};
763 }
764
765 template <typename WriteHandler>
Ed Tanous81ce6092020-12-17 16:54:55 +0000766 void asyncWrite(WriteHandler&& handler)
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100767 {
768 impl.async_write_some(data(), std::forward<WriteHandler>(handler));
769 }
770
771 private:
772 // Specialization for pointer types
773 template <typename B = Buffer>
774 typename std::enable_if<boost::has_dereference<B>::value,
775 boost::asio::const_buffer>::type
776 data()
777 {
778 return boost::asio::buffer(*buffer);
779 }
780
781 template <typename B = Buffer>
782 typename std::enable_if<!boost::has_dereference<B>::value,
783 boost::asio::const_buffer>::type
784 data()
785 {
786 return boost::asio::buffer(buffer);
787 }
788
789 const std::string name;
790 boost::process::async_pipe impl;
791 Buffer buffer;
792 };
793
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200794 /**
795 * @brief Function transceives data with dbus directly.
796 *
797 * All BMC state properties will be retrieved before sending reset request.
798 */
Ed Tanous81ce6092020-12-17 16:54:55 +0000799 void doMountVmLegacy(const std::shared_ptr<AsyncResp>& asyncResp,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500800 const std::string& service, const std::string& name,
801 const std::string& imageUrl, const bool rw,
802 std::string&& userName, std::string&& password)
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200803 {
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100804 using SecurePipe = Pipe<CredentialsProvider::SecureBuffer>;
805 constexpr const size_t secretLimit = 1024;
806
807 std::shared_ptr<SecurePipe> secretPipe;
808 std::variant<int, SecurePipe::unix_fd> unixFd = -1;
809
810 if (!userName.empty() || !password.empty())
811 {
812 // Encapsulate in safe buffer
813 CredentialsProvider credentials(std::move(userName),
814 std::move(password));
815
816 // Payload must contain data + NULL delimiters
817 if (credentials.user().size() + credentials.password().size() + 2 >
818 secretLimit)
819 {
820 BMCWEB_LOG_ERROR << "Credentials too long to handle";
821 messages::unrecognizedRequestBody(asyncResp->res);
822 return;
823 }
824
825 // Pack secret
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500826 auto secret = credentials.pack([](const auto& user,
827 const auto& pass, auto& buff) {
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100828 std::copy(user.begin(), user.end(), std::back_inserter(buff));
829 buff.push_back('\0');
830 std::copy(pass.begin(), pass.end(), std::back_inserter(buff));
831 buff.push_back('\0');
832 });
833
834 // Open pipe
835 secretPipe = std::make_shared<SecurePipe>(
836 crow::connections::systemBus->get_io_context(),
837 std::move(secret));
838 unixFd = secretPipe->fd();
839
840 // Pass secret over pipe
Ed Tanous81ce6092020-12-17 16:54:55 +0000841 secretPipe->asyncWrite(
Vikram Bodireddyf5b16f02020-08-26 14:54:51 +0530842 [asyncResp](const boost::system::error_code& ec, std::size_t) {
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100843 if (ec)
844 {
845 BMCWEB_LOG_ERROR << "Failed to pass secret: " << ec;
846 messages::internalError(asyncResp->res);
847 }
848 });
849 }
850
Adrian Ambrożewiczd6da5be2020-01-13 18:31:01 +0100851 crow::connections::systemBus->async_method_call(
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100852 [asyncResp, secretPipe](const boost::system::error_code ec,
853 bool success) {
Adrian Ambrożewiczd6da5be2020-01-13 18:31:01 +0100854 if (ec)
855 {
856 BMCWEB_LOG_ERROR << "Bad D-Bus request error: " << ec;
857 messages::internalError(asyncResp->res);
858 }
859 else if (!success)
860 {
861 BMCWEB_LOG_ERROR << "Service responded with error";
862 messages::generalError(asyncResp->res);
863 }
864 },
865 service, "/xyz/openbmc_project/VirtualMedia/Legacy/" + name,
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100866 "xyz.openbmc_project.VirtualMedia.Legacy", "Mount", imageUrl, rw,
867 unixFd);
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200868 }
869};
870
871/**
872 @brief EjectMedia action class
873 */
874class VirtualMediaActionEjectMedia : public Node
875{
876 public:
Ed Tanous52cc1122020-07-18 13:51:21 -0700877 VirtualMediaActionEjectMedia(App& app) :
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200878 Node(app,
879 "/redfish/v1/Managers/<str>/VirtualMedia/<str>/Actions/"
880 "VirtualMedia.EjectMedia",
881 std::string(), std::string())
882 {
883 entityPrivileges = {
884 {boost::beast::http::verb::get, {{"Login"}}},
885 {boost::beast::http::verb::head, {{"Login"}}},
886 {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
887 {boost::beast::http::verb::put, {{"ConfigureManager"}}},
888 {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
889 {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
890 }
891
892 private:
893 /**
894 * @brief Function handles POST method request.
895 *
896 * Analyzes POST body message before sends Reset request data to dbus.
897 */
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500898 void doPost(crow::Response& res, const crow::Request& req,
899 const std::vector<std::string>& params) override
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200900 {
901 auto aResp = std::make_shared<AsyncResp>(res);
902
903 if (params.size() != 2)
904 {
905 messages::internalError(res);
906 return;
907 }
908
909 // take resource name from URL
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500910 const std::string& resName = params[1];
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200911
912 if (params[0] != "bmc")
913 {
914 messages::resourceNotFound(res, "VirtualMedia.Eject", resName);
915
916 return;
917 }
918
919 crow::connections::systemBus->async_method_call(
920 [this, aResp{std::move(aResp)}, req,
921 resName](const boost::system::error_code ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500922 const GetObjectType& getObjectType) {
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200923 if (ec)
924 {
925 BMCWEB_LOG_ERROR << "ObjectMapper::GetObject call failed: "
926 << ec;
927 messages::internalError(aResp->res);
928
929 return;
930 }
931 std::string service = getObjectType.begin()->first;
932 BMCWEB_LOG_DEBUG << "GetObjectType: " << service;
933
934 crow::connections::systemBus->async_method_call(
Ed Tanous81ce6092020-12-17 16:54:55 +0000935 [this, resName, service, req,
936 aResp{aResp}](const boost::system::error_code ec,
937 ManagedObjectType& subtree) {
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200938 if (ec)
939 {
940 BMCWEB_LOG_DEBUG << "DBUS response error";
941
942 return;
943 }
944
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500945 for (const auto& object : subtree)
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200946 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500947 const std::string& path =
948 static_cast<const std::string&>(object.first);
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200949
Ed Tanousf23b7292020-10-15 09:41:17 -0700950 std::size_t lastIndex = path.rfind('/');
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200951 if (lastIndex == std::string::npos)
952 {
953 continue;
954 }
955
956 lastIndex += 1;
957
958 if (path.substr(lastIndex) == resName)
959 {
960 lastIndex = path.rfind("Proxy");
961 if (lastIndex != std::string::npos)
962 {
963 // Proxy mode
Ed Tanous81ce6092020-12-17 16:54:55 +0000964 doVmAction(aResp, service, resName, false);
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200965 }
966
967 lastIndex = path.rfind("Legacy");
968 if (lastIndex != std::string::npos)
969 {
970 // Legacy mode
Ed Tanous81ce6092020-12-17 16:54:55 +0000971 doVmAction(aResp, service, resName, true);
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200972 }
973
974 return;
975 }
976 }
977 BMCWEB_LOG_DEBUG << "Parent item not found";
978 messages::resourceNotFound(aResp->res, "VirtualMedia",
979 resName);
980 },
981 service, "/xyz/openbmc_project/VirtualMedia",
982 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
983 },
984 "xyz.openbmc_project.ObjectMapper",
985 "/xyz/openbmc_project/object_mapper",
986 "xyz.openbmc_project.ObjectMapper", "GetObject",
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500987 "/xyz/openbmc_project/VirtualMedia", std::array<const char*, 0>());
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200988 }
989
990 /**
991 * @brief Function transceives data with dbus directly.
992 *
993 * All BMC state properties will be retrieved before sending reset request.
994 */
Ed Tanous81ce6092020-12-17 16:54:55 +0000995 void doVmAction(const std::shared_ptr<AsyncResp>& asyncResp,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500996 const std::string& service, const std::string& name,
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200997 bool legacy)
998 {
999
1000 // Legacy mount requires parameter with image
1001 if (legacy)
1002 {
1003 crow::connections::systemBus->async_method_call(
1004 [asyncResp](const boost::system::error_code ec) {
1005 if (ec)
1006 {
1007 BMCWEB_LOG_ERROR << "Bad D-Bus request error: " << ec;
1008
1009 messages::internalError(asyncResp->res);
1010 return;
1011 }
1012 },
1013 service, "/xyz/openbmc_project/VirtualMedia/Legacy/" + name,
1014 "xyz.openbmc_project.VirtualMedia.Legacy", "Unmount");
1015 }
1016 else // proxy
1017 {
1018 crow::connections::systemBus->async_method_call(
1019 [asyncResp](const boost::system::error_code ec) {
1020 if (ec)
1021 {
1022 BMCWEB_LOG_ERROR << "Bad D-Bus request error: " << ec;
1023
1024 messages::internalError(asyncResp->res);
1025 return;
1026 }
1027 },
1028 service, "/xyz/openbmc_project/VirtualMedia/Proxy/" + name,
1029 "xyz.openbmc_project.VirtualMedia.Proxy", "Unmount");
1030 }
1031 }
1032};
1033
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +02001034class VirtualMediaCollection : public Node
1035{
1036 public:
1037 /*
1038 * Default Constructor
1039 */
Ed Tanous52cc1122020-07-18 13:51:21 -07001040 VirtualMediaCollection(App& app) :
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +02001041 Node(app, "/redfish/v1/Managers/<str>/VirtualMedia/", std::string())
1042 {
1043 entityPrivileges = {
1044 {boost::beast::http::verb::get, {{"Login"}}},
1045 {boost::beast::http::verb::head, {{"Login"}}},
1046 {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
1047 {boost::beast::http::verb::put, {{"ConfigureManager"}}},
1048 {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
1049 {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
1050 }
1051
1052 private:
1053 /**
1054 * Functions triggers appropriate requests on DBus
1055 */
Vikram Bodireddyf5b16f02020-08-26 14:54:51 +05301056 void doGet(crow::Response& res, const crow::Request&,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001057 const std::vector<std::string>& params) override
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +02001058 {
1059 auto asyncResp = std::make_shared<AsyncResp>(res);
1060
1061 // Check if there is required param, truly entering this shall be
1062 // impossible
1063 if (params.size() != 1)
1064 {
1065 messages::internalError(res);
1066
1067 return;
1068 }
1069
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001070 const std::string& name = params[0];
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +02001071
1072 if (name != "bmc")
1073 {
1074 messages::resourceNotFound(asyncResp->res, "VirtualMedia", name);
1075
1076 return;
1077 }
1078
1079 res.jsonValue["@odata.type"] =
1080 "#VirtualMediaCollection.VirtualMediaCollection";
1081 res.jsonValue["Name"] = "Virtual Media Services";
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +02001082 res.jsonValue["@odata.id"] =
Przemyslaw Czarnowskid6c414f2020-07-08 15:17:31 +02001083 "/redfish/v1/Managers/" + name + "/VirtualMedia";
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +02001084
1085 crow::connections::systemBus->async_method_call(
1086 [asyncResp, name](const boost::system::error_code ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001087 const GetObjectType& getObjectType) {
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +02001088 if (ec)
1089 {
1090 BMCWEB_LOG_ERROR << "ObjectMapper::GetObject call failed: "
1091 << ec;
1092 messages::internalError(asyncResp->res);
1093
1094 return;
1095 }
1096 std::string service = getObjectType.begin()->first;
1097 BMCWEB_LOG_DEBUG << "GetObjectType: " << service;
1098
1099 getVmResourceList(asyncResp, service, name);
1100 },
1101 "xyz.openbmc_project.ObjectMapper",
1102 "/xyz/openbmc_project/object_mapper",
1103 "xyz.openbmc_project.ObjectMapper", "GetObject",
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001104 "/xyz/openbmc_project/VirtualMedia", std::array<const char*, 0>());
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +02001105 }
1106};
1107
1108class VirtualMedia : public Node
1109{
1110 public:
1111 /*
1112 * Default Constructor
1113 */
Ed Tanous52cc1122020-07-18 13:51:21 -07001114 VirtualMedia(App& app) :
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +02001115 Node(app, "/redfish/v1/Managers/<str>/VirtualMedia/<str>/",
1116 std::string(), std::string())
1117 {
1118 entityPrivileges = {
1119 {boost::beast::http::verb::get, {{"Login"}}},
1120 {boost::beast::http::verb::head, {{"Login"}}},
1121 {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
1122 {boost::beast::http::verb::put, {{"ConfigureManager"}}},
1123 {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
1124 {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
1125 }
1126
1127 private:
1128 /**
1129 * Functions triggers appropriate requests on DBus
1130 */
Vikram Bodireddyf5b16f02020-08-26 14:54:51 +05301131 void doGet(crow::Response& res, const crow::Request&,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001132 const std::vector<std::string>& params) override
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +02001133 {
1134 // Check if there is required param, truly entering this shall be
1135 // impossible
1136 if (params.size() != 2)
1137 {
1138 messages::internalError(res);
1139
1140 res.end();
1141 return;
1142 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001143 const std::string& name = params[0];
1144 const std::string& resName = params[1];
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +02001145
1146 auto asyncResp = std::make_shared<AsyncResp>(res);
1147
1148 if (name != "bmc")
1149 {
1150 messages::resourceNotFound(asyncResp->res, "VirtualMedia", resName);
1151
1152 return;
1153 }
1154
1155 crow::connections::systemBus->async_method_call(
1156 [asyncResp, name, resName](const boost::system::error_code ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001157 const GetObjectType& getObjectType) {
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +02001158 if (ec)
1159 {
1160 BMCWEB_LOG_ERROR << "ObjectMapper::GetObject call failed: "
1161 << ec;
1162 messages::internalError(asyncResp->res);
1163
1164 return;
1165 }
1166 std::string service = getObjectType.begin()->first;
1167 BMCWEB_LOG_DEBUG << "GetObjectType: " << service;
1168
1169 getVmData(asyncResp, service, name, resName);
1170 },
1171 "xyz.openbmc_project.ObjectMapper",
1172 "/xyz/openbmc_project/object_mapper",
1173 "xyz.openbmc_project.ObjectMapper", "GetObject",
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001174 "/xyz/openbmc_project/VirtualMedia", std::array<const char*, 0>());
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +02001175 }
1176};
1177
1178} // namespace redfish