blob: c12da70cc20570850c1e2896f1250bd7a916ccc8 [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
22#include <../lib/account_service.hpp>
23
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
78 aResp->res.jsonValue["Oem"]["WebSocketEndpoint"] = *endpointIdValue;
79 aResp->res.jsonValue["TransferProtocolType"] = "OEM";
80 aResp->res.jsonValue["Inserted"] = *activeValue;
81 if (*activeValue == true)
82 {
83 aResp->res.jsonValue["ConnectedVia"] = "Applet";
84 }
85 }
86 else
87 {
88 // Legacy mode
89 const auto imageUrlProperty =
90 mountPointIface->second.find("ImageURL");
91 if (imageUrlProperty != processIface->second.cend())
92 {
93 const std::string *imageUrlValue =
94 std::get_if<std::string>(&imageUrlProperty->second);
95 if (imageUrlValue && !imageUrlValue->empty())
96 {
97 aResp->res.jsonValue["ImageName"] = *imageUrlValue;
98 aResp->res.jsonValue["Inserted"] = *activeValue;
99 if (*activeValue == true)
100 {
101 aResp->res.jsonValue["ConnectedVia"] = "URI";
102 }
103 }
104 }
105 }
106 }
107}
108
109/**
110 * @brief Fill template for Virtual Media Item.
111 */
112static nlohmann::json vmItemTemplate(const std::string &name,
113 const std::string &resName)
114{
115 nlohmann::json item;
116 item["@odata.id"] =
117 "/redfish/v1/Managers/" + name + "/VirtualMedia/" + resName;
118 item["@odata.type"] = "#VirtualMedia.v1_1_0.VirtualMedia";
119 item["@odata.context"] = "/redfish/v1/$metadata#VirtualMedia.VirtualMedia";
120 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;
130 item["Oem"]["WebSocketEndpoint"] = nullptr;
131
132 return item;
133}
134
135/**
136 * @brief Fills collection data
137 */
138static void getVmResourceList(std::shared_ptr<AsyncResp> aResp,
139 const std::string &service,
140 const std::string &name)
141{
142 BMCWEB_LOG_DEBUG << "Get available Virtual Media resources.";
143 crow::connections::systemBus->async_method_call(
144 [name, aResp{std::move(aResp)}](const boost::system::error_code ec,
145 ManagedObjectType &subtree) {
146 if (ec)
147 {
148 BMCWEB_LOG_DEBUG << "DBUS response error";
149 return;
150 }
151 nlohmann::json &members = aResp->res.jsonValue["Members"];
152 members = nlohmann::json::array();
153
154 for (const auto &object : subtree)
155 {
156 nlohmann::json item;
157 const std::string &path =
158 static_cast<const std::string &>(object.first);
159 std::size_t lastIndex = path.rfind("/");
160 if (lastIndex == std::string::npos)
161 {
162 continue;
163 }
164
165 lastIndex += 1;
166
167 item["@odata.id"] = "/redfish/v1/Managers/" + name +
168 "/VirtualMedia/" + path.substr(lastIndex);
169
170 members.emplace_back(std::move(item));
171 }
172 aResp->res.jsonValue["Members@odata.count"] = members.size();
173 },
174 service, "/xyz/openbmc_project/VirtualMedia",
175 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
176}
177
178/**
179 * @brief Fills data for specific resource
180 */
181static void getVmData(std::shared_ptr<AsyncResp> aResp,
182 const std::string &service, const std::string &name,
183 const std::string &resName)
184{
185 BMCWEB_LOG_DEBUG << "Get Virtual Media resource data.";
186
187 crow::connections::systemBus->async_method_call(
188 [resName, name, aResp](const boost::system::error_code ec,
189 ManagedObjectType &subtree) {
190 if (ec)
191 {
192 BMCWEB_LOG_DEBUG << "DBUS response error";
193 return;
194 }
195
196 for (auto &item : subtree)
197 {
198 const std::string &path =
199 static_cast<const std::string &>(item.first);
200
201 std::size_t lastItem = path.rfind("/");
202 if (lastItem == std::string::npos)
203 {
204 continue;
205 }
206
207 if (path.substr(lastItem + 1) != resName)
208 {
209 continue;
210 }
211
212 aResp->res.jsonValue = vmItemTemplate(name, resName);
213
214 vmParseInterfaceObject(item.second, aResp);
215
216 return;
217 }
218
219 messages::resourceNotFound(
220 aResp->res, "#VirtualMedia.v1_1_0.VirtualMedia", resName);
221 },
222 service, "/xyz/openbmc_project/VirtualMedia",
223 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
224}
225
226class VirtualMediaCollection : public Node
227{
228 public:
229 /*
230 * Default Constructor
231 */
232 VirtualMediaCollection(CrowApp &app) :
233 Node(app, "/redfish/v1/Managers/<str>/VirtualMedia/", std::string())
234 {
235 entityPrivileges = {
236 {boost::beast::http::verb::get, {{"Login"}}},
237 {boost::beast::http::verb::head, {{"Login"}}},
238 {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
239 {boost::beast::http::verb::put, {{"ConfigureManager"}}},
240 {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
241 {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
242 }
243
244 private:
245 /**
246 * Functions triggers appropriate requests on DBus
247 */
248 void doGet(crow::Response &res, const crow::Request &req,
249 const std::vector<std::string> &params) override
250 {
251 auto asyncResp = std::make_shared<AsyncResp>(res);
252
253 // Check if there is required param, truly entering this shall be
254 // impossible
255 if (params.size() != 1)
256 {
257 messages::internalError(res);
258
259 return;
260 }
261
262 const std::string &name = params[0];
263
264 if (name != "bmc")
265 {
266 messages::resourceNotFound(asyncResp->res, "VirtualMedia", name);
267
268 return;
269 }
270
271 res.jsonValue["@odata.type"] =
272 "#VirtualMediaCollection.VirtualMediaCollection";
273 res.jsonValue["Name"] = "Virtual Media Services";
274 res.jsonValue["@odata.context"] =
275 "/redfish/v1/"
276 "$metadata#VirtualMediaCollection.VirtualMediaCollection";
277 res.jsonValue["@odata.id"] =
278 "/redfish/v1/Managers/" + name + "/VirtualMedia/";
279
280 crow::connections::systemBus->async_method_call(
281 [asyncResp, name](const boost::system::error_code ec,
282 const GetObjectType &getObjectType) {
283 if (ec)
284 {
285 BMCWEB_LOG_ERROR << "ObjectMapper::GetObject call failed: "
286 << ec;
287 messages::internalError(asyncResp->res);
288
289 return;
290 }
291 std::string service = getObjectType.begin()->first;
292 BMCWEB_LOG_DEBUG << "GetObjectType: " << service;
293
294 getVmResourceList(asyncResp, service, name);
295 },
296 "xyz.openbmc_project.ObjectMapper",
297 "/xyz/openbmc_project/object_mapper",
298 "xyz.openbmc_project.ObjectMapper", "GetObject",
299 "/xyz/openbmc_project/VirtualMedia", std::array<const char *, 0>());
300 }
301};
302
303class VirtualMedia : public Node
304{
305 public:
306 /*
307 * Default Constructor
308 */
309 VirtualMedia(CrowApp &app) :
310 Node(app, "/redfish/v1/Managers/<str>/VirtualMedia/<str>/",
311 std::string(), std::string())
312 {
313 entityPrivileges = {
314 {boost::beast::http::verb::get, {{"Login"}}},
315 {boost::beast::http::verb::head, {{"Login"}}},
316 {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
317 {boost::beast::http::verb::put, {{"ConfigureManager"}}},
318 {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
319 {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
320 }
321
322 private:
323 /**
324 * Functions triggers appropriate requests on DBus
325 */
326 void doGet(crow::Response &res, const crow::Request &req,
327 const std::vector<std::string> &params) override
328 {
329 // Check if there is required param, truly entering this shall be
330 // impossible
331 if (params.size() != 2)
332 {
333 messages::internalError(res);
334
335 res.end();
336 return;
337 }
338 const std::string &name = params[0];
339 const std::string &resName = params[1];
340
341 auto asyncResp = std::make_shared<AsyncResp>(res);
342
343 if (name != "bmc")
344 {
345 messages::resourceNotFound(asyncResp->res, "VirtualMedia", resName);
346
347 return;
348 }
349
350 crow::connections::systemBus->async_method_call(
351 [asyncResp, name, resName](const boost::system::error_code ec,
352 const GetObjectType &getObjectType) {
353 if (ec)
354 {
355 BMCWEB_LOG_ERROR << "ObjectMapper::GetObject call failed: "
356 << ec;
357 messages::internalError(asyncResp->res);
358
359 return;
360 }
361 std::string service = getObjectType.begin()->first;
362 BMCWEB_LOG_DEBUG << "GetObjectType: " << service;
363
364 getVmData(asyncResp, service, name, resName);
365 },
366 "xyz.openbmc_project.ObjectMapper",
367 "/xyz/openbmc_project/object_mapper",
368 "xyz.openbmc_project.ObjectMapper", "GetObject",
369 "/xyz/openbmc_project/VirtualMedia", std::array<const char *, 0>());
370 }
371};
372
373} // namespace redfish