blob: f95e91dc46e136ee321c6ffa6e2a928da077cbf2 [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["@odata.context"] = "/redfish/v1/$metadata#VirtualMedia.VirtualMedia";
121 item["Name"] = "Virtual Removable Media";
122 item["Id"] = resName;
123 item["Image"] = nullptr;
124 item["Inserted"] = nullptr;
125 item["ImageName"] = nullptr;
126 item["WriteProtected"] = true;
127 item["ConnectedVia"] = "NotConnected";
128 item["MediaTypes"] = {"CD", "USBStick"};
129 item["TransferMethod"] = "Stream";
130 item["TransferProtocolType"] = nullptr;
Przemyslaw Czarnowskid04ba322020-01-21 12:41:56 +0100131 item["Oem"]["OpenBmc"]["WebSocketEndpoint"] = nullptr;
132 item["Oem"]["OpenBMC"]["@odata.type"] =
133 "#OemVirtualMedia.v1_0_0.VirtualMedia";
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200134
135 return item;
136}
137
138/**
139 * @brief Fills collection data
140 */
141static void getVmResourceList(std::shared_ptr<AsyncResp> aResp,
142 const std::string &service,
143 const std::string &name)
144{
145 BMCWEB_LOG_DEBUG << "Get available Virtual Media resources.";
146 crow::connections::systemBus->async_method_call(
147 [name, aResp{std::move(aResp)}](const boost::system::error_code ec,
148 ManagedObjectType &subtree) {
149 if (ec)
150 {
151 BMCWEB_LOG_DEBUG << "DBUS response error";
152 return;
153 }
154 nlohmann::json &members = aResp->res.jsonValue["Members"];
155 members = nlohmann::json::array();
156
157 for (const auto &object : subtree)
158 {
159 nlohmann::json item;
160 const std::string &path =
161 static_cast<const std::string &>(object.first);
162 std::size_t lastIndex = path.rfind("/");
163 if (lastIndex == std::string::npos)
164 {
165 continue;
166 }
167
168 lastIndex += 1;
169
170 item["@odata.id"] = "/redfish/v1/Managers/" + name +
171 "/VirtualMedia/" + path.substr(lastIndex);
172
173 members.emplace_back(std::move(item));
174 }
175 aResp->res.jsonValue["Members@odata.count"] = members.size();
176 },
177 service, "/xyz/openbmc_project/VirtualMedia",
178 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
179}
180
181/**
182 * @brief Fills data for specific resource
183 */
184static void getVmData(std::shared_ptr<AsyncResp> aResp,
185 const std::string &service, const std::string &name,
186 const std::string &resName)
187{
188 BMCWEB_LOG_DEBUG << "Get Virtual Media resource data.";
189
190 crow::connections::systemBus->async_method_call(
191 [resName, name, aResp](const boost::system::error_code ec,
192 ManagedObjectType &subtree) {
193 if (ec)
194 {
195 BMCWEB_LOG_DEBUG << "DBUS response error";
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200196
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200197 return;
198 }
199
200 for (auto &item : subtree)
201 {
202 const std::string &path =
203 static_cast<const std::string &>(item.first);
204
205 std::size_t lastItem = path.rfind("/");
206 if (lastItem == std::string::npos)
207 {
208 continue;
209 }
210
211 if (path.substr(lastItem + 1) != resName)
212 {
213 continue;
214 }
215
216 aResp->res.jsonValue = vmItemTemplate(name, resName);
217
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200218 // Check if dbus path is Legacy type
219 if (path.find("VirtualMedia/Legacy") != std::string::npos)
220 {
221 aResp->res.jsonValue["Actions"]["#VirtualMedia.InsertMedia"]
222 ["target"] =
223 "/redfish/v1/Managers/" + name + "/VirtualMedia/" +
224 resName + "/Actions/VirtualMedia.InsertMedia";
225 }
226
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200227 vmParseInterfaceObject(item.second, aResp);
228
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200229 aResp->res.jsonValue["Actions"]["#VirtualMedia.EjectMedia"]
230 ["target"] =
231 "/redfish/v1/Managers/" + name + "/VirtualMedia/" +
232 resName + "/Actions/VirtualMedia.EjectMedia";
233
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200234 return;
235 }
236
237 messages::resourceNotFound(
Przemyslaw Czarnowskid04ba322020-01-21 12:41:56 +0100238 aResp->res, "#VirtualMedia.v1_3_0.VirtualMedia", resName);
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200239 },
240 service, "/xyz/openbmc_project/VirtualMedia",
241 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
242}
243
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200244/**
245 @brief InsertMedia action class
246 */
247class VirtualMediaActionInsertMedia : public Node
248{
249 public:
250 VirtualMediaActionInsertMedia(CrowApp &app) :
251 Node(app,
252 "/redfish/v1/Managers/<str>/VirtualMedia/<str>/Actions/"
253 "VirtualMedia.InsertMedia",
254 std::string(), std::string())
255 {
256 entityPrivileges = {
257 {boost::beast::http::verb::get, {{"Login"}}},
258 {boost::beast::http::verb::head, {{"Login"}}},
259 {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
260 {boost::beast::http::verb::put, {{"ConfigureManager"}}},
261 {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
262 {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
263 }
264
265 private:
266 /**
267 * @brief Function handles POST method request.
268 *
269 * Analyzes POST body message before sends Reset request data to dbus.
270 */
271 void doPost(crow::Response &res, const crow::Request &req,
272 const std::vector<std::string> &params) override
273 {
274 auto aResp = std::make_shared<AsyncResp>(res);
275
276 if (params.size() != 2)
277 {
278 messages::internalError(res);
279 return;
280 }
281
282 // take resource name from URL
283 const std::string &resName = params[1];
284
285 if (params[0] != "bmc")
286 {
287 messages::resourceNotFound(res, "VirtualMedia.Insert", resName);
288
289 return;
290 }
291
292 crow::connections::systemBus->async_method_call(
293 [this, aResp{std::move(aResp)}, req,
294 resName](const boost::system::error_code ec,
295 const GetObjectType &getObjectType) {
296 if (ec)
297 {
298 BMCWEB_LOG_ERROR << "ObjectMapper::GetObject call failed: "
299 << ec;
300 messages::internalError(aResp->res);
301
302 return;
303 }
304 std::string service = getObjectType.begin()->first;
305 BMCWEB_LOG_DEBUG << "GetObjectType: " << service;
306
307 crow::connections::systemBus->async_method_call(
308 [this, service, resName, req, aResp{std::move(aResp)}](
309 const boost::system::error_code ec,
310 ManagedObjectType &subtree) {
311 if (ec)
312 {
313 BMCWEB_LOG_DEBUG << "DBUS response error";
314
315 return;
316 }
317
318 for (const auto &object : subtree)
319 {
320 const std::string &path =
321 static_cast<const std::string &>(object.first);
322
323 std::size_t lastIndex = path.rfind("/");
324 if (lastIndex == std::string::npos)
325 {
326 continue;
327 }
328
329 lastIndex += 1;
330
331 if (path.substr(lastIndex) == resName)
332 {
333 lastIndex = path.rfind("Proxy");
334 if (lastIndex != std::string::npos)
335 {
336 // Not possible in proxy mode
337 BMCWEB_LOG_DEBUG << "InsertMedia not "
338 "allowed in proxy mode";
339 messages::resourceNotFound(
340 aResp->res, "VirtualMedia.InsertMedia",
341 resName);
342
343 return;
344 }
345
346 lastIndex = path.rfind("Legacy");
347 if (lastIndex != std::string::npos)
348 {
349 // Legacy mode
350 std::string imageUrl;
351
352 // Read obligatory paramters (url of image)
353 if (!json_util::readJson(req, aResp->res,
354 "Image", imageUrl))
355 {
356 BMCWEB_LOG_DEBUG
357 << "Image is not provided";
358 return;
359 }
360
361 // must not be empty
362 if (imageUrl.size() == 0)
363 {
364 BMCWEB_LOG_ERROR
365 << "Request action parameter "
366 "Image is empty.";
367 messages::propertyValueFormatError(
368 aResp->res, "<empty>", "Image");
369
370 return;
371 }
372
373 // manager is irrelevant for VirtualMedia
374 // dbus calls
375 doVmAction(std::move(aResp), service,
376 resName, true, imageUrl);
377
378 return;
379 }
380 }
381 }
382 BMCWEB_LOG_DEBUG << "Parent item not found";
383 messages::resourceNotFound(aResp->res, "VirtualMedia",
384 resName);
385 },
386 service, "/xyz/openbmc_project/VirtualMedia",
387 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
388 },
389 "xyz.openbmc_project.ObjectMapper",
390 "/xyz/openbmc_project/object_mapper",
391 "xyz.openbmc_project.ObjectMapper", "GetObject",
392 "/xyz/openbmc_project/VirtualMedia", std::array<const char *, 0>());
393 }
394
395 /**
396 * @brief Function transceives data with dbus directly.
397 *
398 * All BMC state properties will be retrieved before sending reset request.
399 */
400 void doVmAction(std::shared_ptr<AsyncResp> asyncResp,
401 const std::string &service, const std::string &name,
402 bool legacy, const std::string &imageUrl)
403 {
404
405 // Legacy mount requires parameter with image
406 if (legacy)
407 {
408 crow::connections::systemBus->async_method_call(
409 [asyncResp](const boost::system::error_code ec) {
410 if (ec)
411 {
412 BMCWEB_LOG_ERROR << "Bad D-Bus request error: " << ec;
413 messages::internalError(asyncResp->res);
414
415 return;
416 }
417 },
418 service, "/xyz/openbmc_project/VirtualMedia/Legacy/" + name,
419 "xyz.openbmc_project.VirtualMedia.Legacy", "Mount", imageUrl);
420 }
421 else // proxy
422 {
423 crow::connections::systemBus->async_method_call(
424 [asyncResp](const boost::system::error_code ec) {
425 if (ec)
426 {
427 BMCWEB_LOG_ERROR << "Bad D-Bus request error: " << ec;
428 messages::internalError(asyncResp->res);
429
430 return;
431 }
432 },
433 service, "/xyz/openbmc_project/VirtualMedia/Proxy/" + name,
434 "xyz.openbmc_project.VirtualMedia.Proxy", "Mount");
435 }
436 }
437};
438
439/**
440 @brief EjectMedia action class
441 */
442class VirtualMediaActionEjectMedia : public Node
443{
444 public:
445 VirtualMediaActionEjectMedia(CrowApp &app) :
446 Node(app,
447 "/redfish/v1/Managers/<str>/VirtualMedia/<str>/Actions/"
448 "VirtualMedia.EjectMedia",
449 std::string(), std::string())
450 {
451 entityPrivileges = {
452 {boost::beast::http::verb::get, {{"Login"}}},
453 {boost::beast::http::verb::head, {{"Login"}}},
454 {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
455 {boost::beast::http::verb::put, {{"ConfigureManager"}}},
456 {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
457 {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
458 }
459
460 private:
461 /**
462 * @brief Function handles POST method request.
463 *
464 * Analyzes POST body message before sends Reset request data to dbus.
465 */
466 void doPost(crow::Response &res, const crow::Request &req,
467 const std::vector<std::string> &params) override
468 {
469 auto aResp = std::make_shared<AsyncResp>(res);
470
471 if (params.size() != 2)
472 {
473 messages::internalError(res);
474 return;
475 }
476
477 // take resource name from URL
478 const std::string &resName = params[1];
479
480 if (params[0] != "bmc")
481 {
482 messages::resourceNotFound(res, "VirtualMedia.Eject", resName);
483
484 return;
485 }
486
487 crow::connections::systemBus->async_method_call(
488 [this, aResp{std::move(aResp)}, req,
489 resName](const boost::system::error_code ec,
490 const GetObjectType &getObjectType) {
491 if (ec)
492 {
493 BMCWEB_LOG_ERROR << "ObjectMapper::GetObject call failed: "
494 << ec;
495 messages::internalError(aResp->res);
496
497 return;
498 }
499 std::string service = getObjectType.begin()->first;
500 BMCWEB_LOG_DEBUG << "GetObjectType: " << service;
501
502 crow::connections::systemBus->async_method_call(
503 [this, resName, service, req, aResp{std::move(aResp)}](
504 const boost::system::error_code ec,
505 ManagedObjectType &subtree) {
506 if (ec)
507 {
508 BMCWEB_LOG_DEBUG << "DBUS response error";
509
510 return;
511 }
512
513 for (const auto &object : subtree)
514 {
515 const std::string &path =
516 static_cast<const std::string &>(object.first);
517
518 std::size_t lastIndex = path.rfind("/");
519 if (lastIndex == std::string::npos)
520 {
521 continue;
522 }
523
524 lastIndex += 1;
525
526 if (path.substr(lastIndex) == resName)
527 {
528 lastIndex = path.rfind("Proxy");
529 if (lastIndex != std::string::npos)
530 {
531 // Proxy mode
532 doVmAction(std::move(aResp), service,
533 resName, false);
534 }
535
536 lastIndex = path.rfind("Legacy");
537 if (lastIndex != std::string::npos)
538 {
539 // Legacy mode
540 doVmAction(std::move(aResp), service,
541 resName, true);
542 }
543
544 return;
545 }
546 }
547 BMCWEB_LOG_DEBUG << "Parent item not found";
548 messages::resourceNotFound(aResp->res, "VirtualMedia",
549 resName);
550 },
551 service, "/xyz/openbmc_project/VirtualMedia",
552 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
553 },
554 "xyz.openbmc_project.ObjectMapper",
555 "/xyz/openbmc_project/object_mapper",
556 "xyz.openbmc_project.ObjectMapper", "GetObject",
557 "/xyz/openbmc_project/VirtualMedia", std::array<const char *, 0>());
558 }
559
560 /**
561 * @brief Function transceives data with dbus directly.
562 *
563 * All BMC state properties will be retrieved before sending reset request.
564 */
565 void doVmAction(std::shared_ptr<AsyncResp> asyncResp,
566 const std::string &service, const std::string &name,
567 bool legacy)
568 {
569
570 // Legacy mount requires parameter with image
571 if (legacy)
572 {
573 crow::connections::systemBus->async_method_call(
574 [asyncResp](const boost::system::error_code ec) {
575 if (ec)
576 {
577 BMCWEB_LOG_ERROR << "Bad D-Bus request error: " << ec;
578
579 messages::internalError(asyncResp->res);
580 return;
581 }
582 },
583 service, "/xyz/openbmc_project/VirtualMedia/Legacy/" + name,
584 "xyz.openbmc_project.VirtualMedia.Legacy", "Unmount");
585 }
586 else // proxy
587 {
588 crow::connections::systemBus->async_method_call(
589 [asyncResp](const boost::system::error_code ec) {
590 if (ec)
591 {
592 BMCWEB_LOG_ERROR << "Bad D-Bus request error: " << ec;
593
594 messages::internalError(asyncResp->res);
595 return;
596 }
597 },
598 service, "/xyz/openbmc_project/VirtualMedia/Proxy/" + name,
599 "xyz.openbmc_project.VirtualMedia.Proxy", "Unmount");
600 }
601 }
602};
603
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200604class VirtualMediaCollection : public Node
605{
606 public:
607 /*
608 * Default Constructor
609 */
610 VirtualMediaCollection(CrowApp &app) :
611 Node(app, "/redfish/v1/Managers/<str>/VirtualMedia/", std::string())
612 {
613 entityPrivileges = {
614 {boost::beast::http::verb::get, {{"Login"}}},
615 {boost::beast::http::verb::head, {{"Login"}}},
616 {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
617 {boost::beast::http::verb::put, {{"ConfigureManager"}}},
618 {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
619 {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
620 }
621
622 private:
623 /**
624 * Functions triggers appropriate requests on DBus
625 */
626 void doGet(crow::Response &res, const crow::Request &req,
627 const std::vector<std::string> &params) override
628 {
629 auto asyncResp = std::make_shared<AsyncResp>(res);
630
631 // Check if there is required param, truly entering this shall be
632 // impossible
633 if (params.size() != 1)
634 {
635 messages::internalError(res);
636
637 return;
638 }
639
640 const std::string &name = params[0];
641
642 if (name != "bmc")
643 {
644 messages::resourceNotFound(asyncResp->res, "VirtualMedia", name);
645
646 return;
647 }
648
649 res.jsonValue["@odata.type"] =
650 "#VirtualMediaCollection.VirtualMediaCollection";
651 res.jsonValue["Name"] = "Virtual Media Services";
652 res.jsonValue["@odata.context"] =
653 "/redfish/v1/"
654 "$metadata#VirtualMediaCollection.VirtualMediaCollection";
655 res.jsonValue["@odata.id"] =
656 "/redfish/v1/Managers/" + name + "/VirtualMedia/";
657
658 crow::connections::systemBus->async_method_call(
659 [asyncResp, name](const boost::system::error_code ec,
660 const GetObjectType &getObjectType) {
661 if (ec)
662 {
663 BMCWEB_LOG_ERROR << "ObjectMapper::GetObject call failed: "
664 << ec;
665 messages::internalError(asyncResp->res);
666
667 return;
668 }
669 std::string service = getObjectType.begin()->first;
670 BMCWEB_LOG_DEBUG << "GetObjectType: " << service;
671
672 getVmResourceList(asyncResp, service, name);
673 },
674 "xyz.openbmc_project.ObjectMapper",
675 "/xyz/openbmc_project/object_mapper",
676 "xyz.openbmc_project.ObjectMapper", "GetObject",
677 "/xyz/openbmc_project/VirtualMedia", std::array<const char *, 0>());
678 }
679};
680
681class VirtualMedia : public Node
682{
683 public:
684 /*
685 * Default Constructor
686 */
687 VirtualMedia(CrowApp &app) :
688 Node(app, "/redfish/v1/Managers/<str>/VirtualMedia/<str>/",
689 std::string(), std::string())
690 {
691 entityPrivileges = {
692 {boost::beast::http::verb::get, {{"Login"}}},
693 {boost::beast::http::verb::head, {{"Login"}}},
694 {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
695 {boost::beast::http::verb::put, {{"ConfigureManager"}}},
696 {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
697 {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
698 }
699
700 private:
701 /**
702 * Functions triggers appropriate requests on DBus
703 */
704 void doGet(crow::Response &res, const crow::Request &req,
705 const std::vector<std::string> &params) override
706 {
707 // Check if there is required param, truly entering this shall be
708 // impossible
709 if (params.size() != 2)
710 {
711 messages::internalError(res);
712
713 res.end();
714 return;
715 }
716 const std::string &name = params[0];
717 const std::string &resName = params[1];
718
719 auto asyncResp = std::make_shared<AsyncResp>(res);
720
721 if (name != "bmc")
722 {
723 messages::resourceNotFound(asyncResp->res, "VirtualMedia", resName);
724
725 return;
726 }
727
728 crow::connections::systemBus->async_method_call(
729 [asyncResp, name, resName](const boost::system::error_code ec,
730 const GetObjectType &getObjectType) {
731 if (ec)
732 {
733 BMCWEB_LOG_ERROR << "ObjectMapper::GetObject call failed: "
734 << ec;
735 messages::internalError(asyncResp->res);
736
737 return;
738 }
739 std::string service = getObjectType.begin()->first;
740 BMCWEB_LOG_DEBUG << "GetObjectType: " << service;
741
742 getVmData(asyncResp, service, name, resName);
743 },
744 "xyz.openbmc_project.ObjectMapper",
745 "/xyz/openbmc_project/object_mapper",
746 "xyz.openbmc_project.ObjectMapper", "GetObject",
747 "/xyz/openbmc_project/VirtualMedia", std::array<const char *, 0>());
748 }
749};
750
751} // namespace redfish