blob: a76ff50c0be6d8eb27a1b4acee46a8d733552eb4 [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>
19#include <node.hpp>
20#include <utils/json_utils.hpp>
21// for GetObjectType and ManagedObjectType
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +020022#include <account_service.hpp>
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +020023
24namespace redfish
25
26{
27
28/**
29 * @brief Read all known properties from VM object interfaces
30 */
31static void vmParseInterfaceObject(const DbusInterfaceType &interface,
32 std::shared_ptr<AsyncResp> aResp)
33{
34 const auto mountPointIface =
35 interface.find("xyz.openbmc_project.VirtualMedia.MountPoint");
36 if (mountPointIface == interface.cend())
37 {
38 BMCWEB_LOG_DEBUG << "Interface MountPoint not found";
39 return;
40 }
41
42 const auto processIface =
43 interface.find("xyz.openbmc_project.VirtualMedia.Process");
44 if (processIface == interface.cend())
45 {
46 BMCWEB_LOG_DEBUG << "Interface Process not found";
47 return;
48 }
49
50 const auto endpointIdProperty = mountPointIface->second.find("EndpointId");
51 if (endpointIdProperty == mountPointIface->second.cend())
52 {
53 BMCWEB_LOG_DEBUG << "Property EndpointId not found";
54 return;
55 }
56
57 const auto activeProperty = processIface->second.find("Active");
58 if (activeProperty == processIface->second.cend())
59 {
60 BMCWEB_LOG_DEBUG << "Property Active not found";
61 return;
62 }
63
64 const bool *activeValue = std::get_if<bool>(&activeProperty->second);
65 if (!activeValue)
66 {
67 BMCWEB_LOG_DEBUG << "Value Active not found";
68 return;
69 }
70
71 const std::string *endpointIdValue =
72 std::get_if<std::string>(&endpointIdProperty->second);
73 if (endpointIdValue)
74 {
75 if (!endpointIdValue->empty())
76 {
77 // Proxy mode
Przemyslaw Czarnowskid04ba322020-01-21 12:41:56 +010078 aResp->res.jsonValue["Oem"]["OpenBMC"]["WebSocketEndpoint"] =
79 *endpointIdValue;
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +020080 aResp->res.jsonValue["TransferProtocolType"] = "OEM";
81 aResp->res.jsonValue["Inserted"] = *activeValue;
82 if (*activeValue == true)
83 {
84 aResp->res.jsonValue["ConnectedVia"] = "Applet";
85 }
86 }
87 else
88 {
89 // Legacy mode
90 const auto imageUrlProperty =
91 mountPointIface->second.find("ImageURL");
92 if (imageUrlProperty != processIface->second.cend())
93 {
94 const std::string *imageUrlValue =
95 std::get_if<std::string>(&imageUrlProperty->second);
96 if (imageUrlValue && !imageUrlValue->empty())
97 {
98 aResp->res.jsonValue["ImageName"] = *imageUrlValue;
99 aResp->res.jsonValue["Inserted"] = *activeValue;
100 if (*activeValue == true)
101 {
102 aResp->res.jsonValue["ConnectedVia"] = "URI";
103 }
104 }
105 }
106 }
107 }
108}
109
110/**
111 * @brief Fill template for Virtual Media Item.
112 */
113static nlohmann::json vmItemTemplate(const std::string &name,
114 const std::string &resName)
115{
116 nlohmann::json item;
117 item["@odata.id"] =
118 "/redfish/v1/Managers/" + name + "/VirtualMedia/" + resName;
Przemyslaw Czarnowskid04ba322020-01-21 12:41:56 +0100119 item["@odata.type"] = "#VirtualMedia.v1_3_0.VirtualMedia";
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200120 item["Name"] = "Virtual Removable Media";
121 item["Id"] = resName;
122 item["Image"] = nullptr;
123 item["Inserted"] = nullptr;
124 item["ImageName"] = nullptr;
125 item["WriteProtected"] = true;
126 item["ConnectedVia"] = "NotConnected";
127 item["MediaTypes"] = {"CD", "USBStick"};
128 item["TransferMethod"] = "Stream";
129 item["TransferProtocolType"] = nullptr;
Przemyslaw Czarnowskid04ba322020-01-21 12:41:56 +0100130 item["Oem"]["OpenBmc"]["WebSocketEndpoint"] = nullptr;
131 item["Oem"]["OpenBMC"]["@odata.type"] =
132 "#OemVirtualMedia.v1_0_0.VirtualMedia";
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200133
134 return item;
135}
136
137/**
138 * @brief Fills collection data
139 */
140static void getVmResourceList(std::shared_ptr<AsyncResp> aResp,
141 const std::string &service,
142 const std::string &name)
143{
144 BMCWEB_LOG_DEBUG << "Get available Virtual Media resources.";
145 crow::connections::systemBus->async_method_call(
146 [name, aResp{std::move(aResp)}](const boost::system::error_code ec,
147 ManagedObjectType &subtree) {
148 if (ec)
149 {
150 BMCWEB_LOG_DEBUG << "DBUS response error";
151 return;
152 }
153 nlohmann::json &members = aResp->res.jsonValue["Members"];
154 members = nlohmann::json::array();
155
156 for (const auto &object : subtree)
157 {
158 nlohmann::json item;
159 const std::string &path =
160 static_cast<const std::string &>(object.first);
161 std::size_t lastIndex = path.rfind("/");
162 if (lastIndex == std::string::npos)
163 {
164 continue;
165 }
166
167 lastIndex += 1;
168
169 item["@odata.id"] = "/redfish/v1/Managers/" + name +
170 "/VirtualMedia/" + path.substr(lastIndex);
171
172 members.emplace_back(std::move(item));
173 }
174 aResp->res.jsonValue["Members@odata.count"] = members.size();
175 },
176 service, "/xyz/openbmc_project/VirtualMedia",
177 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
178}
179
180/**
181 * @brief Fills data for specific resource
182 */
183static void getVmData(std::shared_ptr<AsyncResp> aResp,
184 const std::string &service, const std::string &name,
185 const std::string &resName)
186{
187 BMCWEB_LOG_DEBUG << "Get Virtual Media resource data.";
188
189 crow::connections::systemBus->async_method_call(
190 [resName, name, aResp](const boost::system::error_code ec,
191 ManagedObjectType &subtree) {
192 if (ec)
193 {
194 BMCWEB_LOG_DEBUG << "DBUS response error";
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200195
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200196 return;
197 }
198
199 for (auto &item : subtree)
200 {
201 const std::string &path =
202 static_cast<const std::string &>(item.first);
203
204 std::size_t lastItem = path.rfind("/");
205 if (lastItem == std::string::npos)
206 {
207 continue;
208 }
209
210 if (path.substr(lastItem + 1) != resName)
211 {
212 continue;
213 }
214
215 aResp->res.jsonValue = vmItemTemplate(name, resName);
216
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200217 // Check if dbus path is Legacy type
218 if (path.find("VirtualMedia/Legacy") != std::string::npos)
219 {
220 aResp->res.jsonValue["Actions"]["#VirtualMedia.InsertMedia"]
221 ["target"] =
222 "/redfish/v1/Managers/" + name + "/VirtualMedia/" +
223 resName + "/Actions/VirtualMedia.InsertMedia";
224 }
225
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200226 vmParseInterfaceObject(item.second, aResp);
227
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200228 aResp->res.jsonValue["Actions"]["#VirtualMedia.EjectMedia"]
229 ["target"] =
230 "/redfish/v1/Managers/" + name + "/VirtualMedia/" +
231 resName + "/Actions/VirtualMedia.EjectMedia";
232
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200233 return;
234 }
235
236 messages::resourceNotFound(
Przemyslaw Czarnowskid04ba322020-01-21 12:41:56 +0100237 aResp->res, "#VirtualMedia.v1_3_0.VirtualMedia", resName);
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200238 },
239 service, "/xyz/openbmc_project/VirtualMedia",
240 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
241}
242
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200243/**
244 @brief InsertMedia action class
245 */
246class VirtualMediaActionInsertMedia : public Node
247{
248 public:
249 VirtualMediaActionInsertMedia(CrowApp &app) :
250 Node(app,
251 "/redfish/v1/Managers/<str>/VirtualMedia/<str>/Actions/"
252 "VirtualMedia.InsertMedia",
253 std::string(), std::string())
254 {
255 entityPrivileges = {
256 {boost::beast::http::verb::get, {{"Login"}}},
257 {boost::beast::http::verb::head, {{"Login"}}},
258 {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
259 {boost::beast::http::verb::put, {{"ConfigureManager"}}},
260 {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
261 {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
262 }
263
264 private:
265 /**
266 * @brief Function handles POST method request.
267 *
268 * Analyzes POST body message before sends Reset request data to dbus.
269 */
270 void doPost(crow::Response &res, const crow::Request &req,
271 const std::vector<std::string> &params) override
272 {
273 auto aResp = std::make_shared<AsyncResp>(res);
274
275 if (params.size() != 2)
276 {
277 messages::internalError(res);
278 return;
279 }
280
281 // take resource name from URL
282 const std::string &resName = params[1];
283
284 if (params[0] != "bmc")
285 {
286 messages::resourceNotFound(res, "VirtualMedia.Insert", resName);
287
288 return;
289 }
290
291 crow::connections::systemBus->async_method_call(
292 [this, aResp{std::move(aResp)}, req,
293 resName](const boost::system::error_code ec,
294 const GetObjectType &getObjectType) {
295 if (ec)
296 {
297 BMCWEB_LOG_ERROR << "ObjectMapper::GetObject call failed: "
298 << ec;
299 messages::internalError(aResp->res);
300
301 return;
302 }
303 std::string service = getObjectType.begin()->first;
304 BMCWEB_LOG_DEBUG << "GetObjectType: " << service;
305
306 crow::connections::systemBus->async_method_call(
307 [this, service, resName, req, aResp{std::move(aResp)}](
308 const boost::system::error_code ec,
309 ManagedObjectType &subtree) {
310 if (ec)
311 {
312 BMCWEB_LOG_DEBUG << "DBUS response error";
313
314 return;
315 }
316
317 for (const auto &object : subtree)
318 {
319 const std::string &path =
320 static_cast<const std::string &>(object.first);
321
322 std::size_t lastIndex = path.rfind("/");
323 if (lastIndex == std::string::npos)
324 {
325 continue;
326 }
327
328 lastIndex += 1;
329
330 if (path.substr(lastIndex) == resName)
331 {
332 lastIndex = path.rfind("Proxy");
333 if (lastIndex != std::string::npos)
334 {
335 // Not possible in proxy mode
336 BMCWEB_LOG_DEBUG << "InsertMedia not "
337 "allowed in proxy mode";
338 messages::resourceNotFound(
339 aResp->res, "VirtualMedia.InsertMedia",
340 resName);
341
342 return;
343 }
344
345 lastIndex = path.rfind("Legacy");
346 if (lastIndex != std::string::npos)
347 {
348 // Legacy mode
349 std::string imageUrl;
Adrian Ambrożewiczd6da5be2020-01-13 18:31:01 +0100350 bool writeProtected;
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200351
352 // Read obligatory paramters (url of image)
Adrian Ambrożewiczd6da5be2020-01-13 18:31:01 +0100353 if (!json_util::readJson(
354 req, aResp->res, "Image", imageUrl,
355 "WriteProtected", writeProtected))
356
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200357 {
358 BMCWEB_LOG_DEBUG
359 << "Image is not provided";
360 return;
361 }
362
363 // must not be empty
364 if (imageUrl.size() == 0)
365 {
366 BMCWEB_LOG_ERROR
367 << "Request action parameter "
368 "Image is empty.";
369 messages::propertyValueFormatError(
370 aResp->res, "<empty>", "Image");
371
372 return;
373 }
374
375 // manager is irrelevant for VirtualMedia
376 // dbus calls
Adrian Ambrożewiczd6da5be2020-01-13 18:31:01 +0100377 doMountVmLegacy(std::move(aResp), service,
378 resName, imageUrl,
379 !writeProtected);
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200380
381 return;
382 }
383 }
384 }
385 BMCWEB_LOG_DEBUG << "Parent item not found";
386 messages::resourceNotFound(aResp->res, "VirtualMedia",
387 resName);
388 },
389 service, "/xyz/openbmc_project/VirtualMedia",
390 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
391 },
392 "xyz.openbmc_project.ObjectMapper",
393 "/xyz/openbmc_project/object_mapper",
394 "xyz.openbmc_project.ObjectMapper", "GetObject",
395 "/xyz/openbmc_project/VirtualMedia", std::array<const char *, 0>());
396 }
397
398 /**
399 * @brief Function transceives data with dbus directly.
400 *
401 * All BMC state properties will be retrieved before sending reset request.
402 */
Adrian Ambrożewiczd6da5be2020-01-13 18:31:01 +0100403 void doMountVmLegacy(std::shared_ptr<AsyncResp> asyncResp,
404 const std::string &service, const std::string &name,
405 const std::string &imageUrl, const bool rw)
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200406 {
Adrian Ambrożewiczd6da5be2020-01-13 18:31:01 +0100407 crow::connections::systemBus->async_method_call(
408 [asyncResp](const boost::system::error_code ec, bool success) {
409 if (ec)
410 {
411 BMCWEB_LOG_ERROR << "Bad D-Bus request error: " << ec;
412 messages::internalError(asyncResp->res);
413 }
414 else if (!success)
415 {
416 BMCWEB_LOG_ERROR << "Service responded with error";
417 messages::generalError(asyncResp->res);
418 }
419 },
420 service, "/xyz/openbmc_project/VirtualMedia/Legacy/" + name,
421 "xyz.openbmc_project.VirtualMedia.Legacy", "Mount", imageUrl, rw);
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200422 }
423};
424
425/**
426 @brief EjectMedia action class
427 */
428class VirtualMediaActionEjectMedia : public Node
429{
430 public:
431 VirtualMediaActionEjectMedia(CrowApp &app) :
432 Node(app,
433 "/redfish/v1/Managers/<str>/VirtualMedia/<str>/Actions/"
434 "VirtualMedia.EjectMedia",
435 std::string(), std::string())
436 {
437 entityPrivileges = {
438 {boost::beast::http::verb::get, {{"Login"}}},
439 {boost::beast::http::verb::head, {{"Login"}}},
440 {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
441 {boost::beast::http::verb::put, {{"ConfigureManager"}}},
442 {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
443 {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
444 }
445
446 private:
447 /**
448 * @brief Function handles POST method request.
449 *
450 * Analyzes POST body message before sends Reset request data to dbus.
451 */
452 void doPost(crow::Response &res, const crow::Request &req,
453 const std::vector<std::string> &params) override
454 {
455 auto aResp = std::make_shared<AsyncResp>(res);
456
457 if (params.size() != 2)
458 {
459 messages::internalError(res);
460 return;
461 }
462
463 // take resource name from URL
464 const std::string &resName = params[1];
465
466 if (params[0] != "bmc")
467 {
468 messages::resourceNotFound(res, "VirtualMedia.Eject", resName);
469
470 return;
471 }
472
473 crow::connections::systemBus->async_method_call(
474 [this, aResp{std::move(aResp)}, req,
475 resName](const boost::system::error_code ec,
476 const GetObjectType &getObjectType) {
477 if (ec)
478 {
479 BMCWEB_LOG_ERROR << "ObjectMapper::GetObject call failed: "
480 << ec;
481 messages::internalError(aResp->res);
482
483 return;
484 }
485 std::string service = getObjectType.begin()->first;
486 BMCWEB_LOG_DEBUG << "GetObjectType: " << service;
487
488 crow::connections::systemBus->async_method_call(
489 [this, resName, service, req, aResp{std::move(aResp)}](
490 const boost::system::error_code ec,
491 ManagedObjectType &subtree) {
492 if (ec)
493 {
494 BMCWEB_LOG_DEBUG << "DBUS response error";
495
496 return;
497 }
498
499 for (const auto &object : subtree)
500 {
501 const std::string &path =
502 static_cast<const std::string &>(object.first);
503
504 std::size_t lastIndex = path.rfind("/");
505 if (lastIndex == std::string::npos)
506 {
507 continue;
508 }
509
510 lastIndex += 1;
511
512 if (path.substr(lastIndex) == resName)
513 {
514 lastIndex = path.rfind("Proxy");
515 if (lastIndex != std::string::npos)
516 {
517 // Proxy mode
518 doVmAction(std::move(aResp), service,
519 resName, false);
520 }
521
522 lastIndex = path.rfind("Legacy");
523 if (lastIndex != std::string::npos)
524 {
525 // Legacy mode
526 doVmAction(std::move(aResp), service,
527 resName, true);
528 }
529
530 return;
531 }
532 }
533 BMCWEB_LOG_DEBUG << "Parent item not found";
534 messages::resourceNotFound(aResp->res, "VirtualMedia",
535 resName);
536 },
537 service, "/xyz/openbmc_project/VirtualMedia",
538 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
539 },
540 "xyz.openbmc_project.ObjectMapper",
541 "/xyz/openbmc_project/object_mapper",
542 "xyz.openbmc_project.ObjectMapper", "GetObject",
543 "/xyz/openbmc_project/VirtualMedia", std::array<const char *, 0>());
544 }
545
546 /**
547 * @brief Function transceives data with dbus directly.
548 *
549 * All BMC state properties will be retrieved before sending reset request.
550 */
551 void doVmAction(std::shared_ptr<AsyncResp> asyncResp,
552 const std::string &service, const std::string &name,
553 bool legacy)
554 {
555
556 // Legacy mount requires parameter with image
557 if (legacy)
558 {
559 crow::connections::systemBus->async_method_call(
560 [asyncResp](const boost::system::error_code ec) {
561 if (ec)
562 {
563 BMCWEB_LOG_ERROR << "Bad D-Bus request error: " << ec;
564
565 messages::internalError(asyncResp->res);
566 return;
567 }
568 },
569 service, "/xyz/openbmc_project/VirtualMedia/Legacy/" + name,
570 "xyz.openbmc_project.VirtualMedia.Legacy", "Unmount");
571 }
572 else // proxy
573 {
574 crow::connections::systemBus->async_method_call(
575 [asyncResp](const boost::system::error_code ec) {
576 if (ec)
577 {
578 BMCWEB_LOG_ERROR << "Bad D-Bus request error: " << ec;
579
580 messages::internalError(asyncResp->res);
581 return;
582 }
583 },
584 service, "/xyz/openbmc_project/VirtualMedia/Proxy/" + name,
585 "xyz.openbmc_project.VirtualMedia.Proxy", "Unmount");
586 }
587 }
588};
589
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200590class VirtualMediaCollection : public Node
591{
592 public:
593 /*
594 * Default Constructor
595 */
596 VirtualMediaCollection(CrowApp &app) :
597 Node(app, "/redfish/v1/Managers/<str>/VirtualMedia/", std::string())
598 {
599 entityPrivileges = {
600 {boost::beast::http::verb::get, {{"Login"}}},
601 {boost::beast::http::verb::head, {{"Login"}}},
602 {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
603 {boost::beast::http::verb::put, {{"ConfigureManager"}}},
604 {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
605 {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
606 }
607
608 private:
609 /**
610 * Functions triggers appropriate requests on DBus
611 */
612 void doGet(crow::Response &res, const crow::Request &req,
613 const std::vector<std::string> &params) override
614 {
615 auto asyncResp = std::make_shared<AsyncResp>(res);
616
617 // Check if there is required param, truly entering this shall be
618 // impossible
619 if (params.size() != 1)
620 {
621 messages::internalError(res);
622
623 return;
624 }
625
626 const std::string &name = params[0];
627
628 if (name != "bmc")
629 {
630 messages::resourceNotFound(asyncResp->res, "VirtualMedia", name);
631
632 return;
633 }
634
635 res.jsonValue["@odata.type"] =
636 "#VirtualMediaCollection.VirtualMediaCollection";
637 res.jsonValue["Name"] = "Virtual Media Services";
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200638 res.jsonValue["@odata.id"] =
639 "/redfish/v1/Managers/" + name + "/VirtualMedia/";
640
641 crow::connections::systemBus->async_method_call(
642 [asyncResp, name](const boost::system::error_code ec,
643 const GetObjectType &getObjectType) {
644 if (ec)
645 {
646 BMCWEB_LOG_ERROR << "ObjectMapper::GetObject call failed: "
647 << ec;
648 messages::internalError(asyncResp->res);
649
650 return;
651 }
652 std::string service = getObjectType.begin()->first;
653 BMCWEB_LOG_DEBUG << "GetObjectType: " << service;
654
655 getVmResourceList(asyncResp, service, name);
656 },
657 "xyz.openbmc_project.ObjectMapper",
658 "/xyz/openbmc_project/object_mapper",
659 "xyz.openbmc_project.ObjectMapper", "GetObject",
660 "/xyz/openbmc_project/VirtualMedia", std::array<const char *, 0>());
661 }
662};
663
664class VirtualMedia : public Node
665{
666 public:
667 /*
668 * Default Constructor
669 */
670 VirtualMedia(CrowApp &app) :
671 Node(app, "/redfish/v1/Managers/<str>/VirtualMedia/<str>/",
672 std::string(), std::string())
673 {
674 entityPrivileges = {
675 {boost::beast::http::verb::get, {{"Login"}}},
676 {boost::beast::http::verb::head, {{"Login"}}},
677 {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
678 {boost::beast::http::verb::put, {{"ConfigureManager"}}},
679 {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
680 {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
681 }
682
683 private:
684 /**
685 * Functions triggers appropriate requests on DBus
686 */
687 void doGet(crow::Response &res, const crow::Request &req,
688 const std::vector<std::string> &params) override
689 {
690 // Check if there is required param, truly entering this shall be
691 // impossible
692 if (params.size() != 2)
693 {
694 messages::internalError(res);
695
696 res.end();
697 return;
698 }
699 const std::string &name = params[0];
700 const std::string &resName = params[1];
701
702 auto asyncResp = std::make_shared<AsyncResp>(res);
703
704 if (name != "bmc")
705 {
706 messages::resourceNotFound(asyncResp->res, "VirtualMedia", resName);
707
708 return;
709 }
710
711 crow::connections::systemBus->async_method_call(
712 [asyncResp, name, resName](const boost::system::error_code ec,
713 const GetObjectType &getObjectType) {
714 if (ec)
715 {
716 BMCWEB_LOG_ERROR << "ObjectMapper::GetObject call failed: "
717 << ec;
718 messages::internalError(asyncResp->res);
719
720 return;
721 }
722 std::string service = getObjectType.begin()->first;
723 BMCWEB_LOG_DEBUG << "GetObjectType: " << service;
724
725 getVmData(asyncResp, service, name, resName);
726 },
727 "xyz.openbmc_project.ObjectMapper",
728 "/xyz/openbmc_project/object_mapper",
729 "xyz.openbmc_project.ObjectMapper", "GetObject",
730 "/xyz/openbmc_project/VirtualMedia", std::array<const char *, 0>());
731 }
732};
733
734} // namespace redfish