blob: 18b2db00dfb7359342feee8268a0ac5bd5a7859d [file] [log] [blame]
Jennifer Lee729dae72018-04-24 15:59:34 -07001/*
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 "node.hpp"
Ed Tanous1abe55e2018-09-05 08:30:59 -070019
Jennifer Lee729dae72018-04-24 15:59:34 -070020#include <boost/container/flat_map.hpp>
Andrew Geissler87d84722019-02-28 14:28:39 -060021#include <utils/fw_utils.hpp>
Gunnar Mills1214b7e2020-06-04 10:11:30 -050022
Ed Tanousabf2add2019-01-22 16:40:12 -080023#include <variant>
Jennifer Lee729dae72018-04-24 15:59:34 -070024
Ed Tanous1abe55e2018-09-05 08:30:59 -070025namespace redfish
26{
Ed Tanous27826b52018-10-29 11:40:58 -070027
Andrew Geissler0e7de462019-03-04 19:11:54 -060028// Match signals added on software path
Jennifer Leeacb7cfb2018-06-07 16:08:15 -070029static std::unique_ptr<sdbusplus::bus::match::match> fwUpdateMatcher;
James Feist4cde5d92020-06-11 10:39:55 -070030static std::unique_ptr<sdbusplus::bus::match::match> fwUpdateErrorMatcher;
Andrew Geissler0e7de462019-03-04 19:11:54 -060031// Only allow one update at a time
32static bool fwUpdateInProgress = false;
Andrew Geissler86adcd62019-04-18 10:58:05 -050033// Timer for software available
Ed Tanous271584a2019-07-09 16:24:22 -070034static std::unique_ptr<boost::asio::steady_timer> fwAvailableTimer;
Andrew Geissler86adcd62019-04-18 10:58:05 -050035
36static void cleanUp()
37{
38 fwUpdateInProgress = false;
39 fwUpdateMatcher = nullptr;
James Feist4cde5d92020-06-11 10:39:55 -070040 fwUpdateErrorMatcher = nullptr;
Andrew Geissler86adcd62019-04-18 10:58:05 -050041}
Gunnar Mills1214b7e2020-06-04 10:11:30 -050042static void activateImage(const std::string& objPath,
43 const std::string& service)
Andrew Geissler86adcd62019-04-18 10:58:05 -050044{
45 BMCWEB_LOG_DEBUG << "Activate image for " << objPath << " " << service;
46 crow::connections::systemBus->async_method_call(
Ed Tanous81ce6092020-12-17 16:54:55 +000047 [](const boost::system::error_code errorCode) {
48 if (errorCode)
Andrew Geissler86adcd62019-04-18 10:58:05 -050049 {
Ed Tanous81ce6092020-12-17 16:54:55 +000050 BMCWEB_LOG_DEBUG << "error_code = " << errorCode;
51 BMCWEB_LOG_DEBUG << "error msg = " << errorCode.message();
Andrew Geissler86adcd62019-04-18 10:58:05 -050052 }
53 },
54 service, objPath, "org.freedesktop.DBus.Properties", "Set",
55 "xyz.openbmc_project.Software.Activation", "RequestedActivation",
56 std::variant<std::string>(
57 "xyz.openbmc_project.Software.Activation.RequestedActivations."
58 "Active"));
59}
Andrew Geissler0554c982019-04-23 14:40:12 -050060
61// Note that asyncResp can be either a valid pointer or nullptr. If nullptr
62// then no asyncResp updates will occur
Ed Tanousb5a76932020-09-29 16:16:58 -070063static void softwareInterfaceAdded(const std::shared_ptr<AsyncResp>& asyncResp,
Gunnar Mills1214b7e2020-06-04 10:11:30 -050064 sdbusplus::message::message& m,
65 const crow::Request& req)
Andrew Geissler86adcd62019-04-18 10:58:05 -050066{
67 std::vector<std::pair<
68 std::string,
69 std::vector<std::pair<std::string, std::variant<std::string>>>>>
70 interfacesProperties;
71
72 sdbusplus::message::object_path objPath;
73
74 m.read(objPath, interfacesProperties);
75
76 BMCWEB_LOG_DEBUG << "obj path = " << objPath.str;
Gunnar Mills1214b7e2020-06-04 10:11:30 -050077 for (auto& interface : interfacesProperties)
Andrew Geissler86adcd62019-04-18 10:58:05 -050078 {
79 BMCWEB_LOG_DEBUG << "interface = " << interface.first;
80
81 if (interface.first == "xyz.openbmc_project.Software.Activation")
82 {
Andrew Geissler86adcd62019-04-18 10:58:05 -050083 // Retrieve service and activate
84 crow::connections::systemBus->async_method_call(
James Feistfe306722020-03-12 16:32:08 -070085 [objPath, asyncResp,
Ed Tanous81ce6092020-12-17 16:54:55 +000086 req](const boost::system::error_code errorCode,
James Feistfe306722020-03-12 16:32:08 -070087 const std::vector<std::pair<
Gunnar Mills1214b7e2020-06-04 10:11:30 -050088 std::string, std::vector<std::string>>>& objInfo) {
Ed Tanous81ce6092020-12-17 16:54:55 +000089 if (errorCode)
Andrew Geissler86adcd62019-04-18 10:58:05 -050090 {
Ed Tanous81ce6092020-12-17 16:54:55 +000091 BMCWEB_LOG_DEBUG << "error_code = " << errorCode;
Andrew Geissler86adcd62019-04-18 10:58:05 -050092 BMCWEB_LOG_DEBUG << "error msg = "
Ed Tanous81ce6092020-12-17 16:54:55 +000093 << errorCode.message();
Andrew Geissler0554c982019-04-23 14:40:12 -050094 if (asyncResp)
95 {
96 messages::internalError(asyncResp->res);
97 }
Andrew Geissler86adcd62019-04-18 10:58:05 -050098 cleanUp();
99 return;
100 }
101 // Ensure we only got one service back
102 if (objInfo.size() != 1)
103 {
104 BMCWEB_LOG_ERROR << "Invalid Object Size "
105 << objInfo.size();
Andrew Geissler0554c982019-04-23 14:40:12 -0500106 if (asyncResp)
107 {
108 messages::internalError(asyncResp->res);
109 }
Andrew Geissler86adcd62019-04-18 10:58:05 -0500110 cleanUp();
111 return;
112 }
113 // cancel timer only when
114 // xyz.openbmc_project.Software.Activation interface
115 // is added
116 fwAvailableTimer = nullptr;
117
118 activateImage(objPath.str, objInfo[0].first);
Andrew Geissler0554c982019-04-23 14:40:12 -0500119 if (asyncResp)
120 {
James Feist32898ce2020-03-10 16:16:52 -0700121 std::shared_ptr<task::TaskData> task =
122 task::TaskData::createTask(
123 [](boost::system::error_code ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500124 sdbusplus::message::message& msg,
125 const std::shared_ptr<task::TaskData>&
126 taskData) {
James Feist32898ce2020-03-10 16:16:52 -0700127 if (ec)
128 {
129 return task::completed;
130 }
131
132 std::string iface;
133 boost::container::flat_map<
James Feistfd9ab9e2020-05-19 13:48:07 -0700134 std::string,
135 std::variant<std::string, uint8_t>>
James Feist32898ce2020-03-10 16:16:52 -0700136 values;
James Feist32898ce2020-03-10 16:16:52 -0700137
James Feiste5d50062020-05-11 17:29:00 -0700138 std::string index =
139 std::to_string(taskData->index);
James Feistfd9ab9e2020-05-19 13:48:07 -0700140 msg.read(iface, values);
James Feiste5d50062020-05-11 17:29:00 -0700141
James Feistfd9ab9e2020-05-19 13:48:07 -0700142 if (iface == "xyz.openbmc_project.Software."
143 "Activation")
James Feist32898ce2020-03-10 16:16:52 -0700144 {
James Feistfd9ab9e2020-05-19 13:48:07 -0700145 auto findActivation =
146 values.find("Activation");
147 if (findActivation == values.end())
148 {
149 return !task::completed;
150 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500151 std::string* state =
James Feistfd9ab9e2020-05-19 13:48:07 -0700152 std::get_if<std::string>(
153 &(findActivation->second));
154
155 if (state == nullptr)
156 {
157 taskData->messages.emplace_back(
158 messages::internalError());
159 return task::completed;
160 }
161
162 if (boost::ends_with(*state,
163 "Invalid") ||
164 boost::ends_with(*state, "Failed"))
165 {
166 taskData->state = "Exception";
167 taskData->status = "Warning";
168 taskData->messages.emplace_back(
169 messages::taskAborted(index));
170 return task::completed;
171 }
172
173 if (boost::ends_with(*state, "Staged"))
174 {
175 taskData->state = "Stopping";
176 taskData->messages.emplace_back(
177 messages::taskPaused(index));
178
179 // its staged, set a long timer to
180 // allow them time to complete the
181 // update (probably cycle the
182 // system) if this expires then
183 // task will be cancelled
184 taskData->extendTimer(
185 std::chrono::hours(5));
186 return !task::completed;
187 }
188
189 if (boost::ends_with(*state, "Active"))
190 {
191 taskData->messages.emplace_back(
192 messages::taskCompletedOK(
193 index));
194 taskData->state = "Completed";
195 return task::completed;
196 }
James Feist32898ce2020-03-10 16:16:52 -0700197 }
James Feistfd9ab9e2020-05-19 13:48:07 -0700198 else if (iface ==
199 "xyz.openbmc_project.Software."
200 "ActivationProgress")
James Feist32898ce2020-03-10 16:16:52 -0700201 {
James Feistfd9ab9e2020-05-19 13:48:07 -0700202 auto findProgress =
203 values.find("Progress");
204 if (findProgress == values.end())
205 {
206 return !task::completed;
207 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500208 uint8_t* progress =
James Feistfd9ab9e2020-05-19 13:48:07 -0700209 std::get_if<uint8_t>(
210 &(findProgress->second));
James Feist32898ce2020-03-10 16:16:52 -0700211
James Feistfd9ab9e2020-05-19 13:48:07 -0700212 if (progress == nullptr)
213 {
214 taskData->messages.emplace_back(
215 messages::internalError());
216 return task::completed;
217 }
George Liu6868ff52021-01-02 11:37:41 +0800218 taskData->percentComplete =
219 static_cast<int>(*progress);
James Feist32898ce2020-03-10 16:16:52 -0700220 taskData->messages.emplace_back(
James Feistfd9ab9e2020-05-19 13:48:07 -0700221 messages::taskProgressChanged(
222 index, static_cast<size_t>(
223 *progress)));
224
225 // if we're getting status updates it's
226 // still alive, update timer
227 taskData->extendTimer(
228 std::chrono::minutes(5));
James Feist32898ce2020-03-10 16:16:52 -0700229 }
230
231 // as firmware update often results in a
232 // reboot, the task may never "complete"
233 // unless it is an error
234
235 return !task::completed;
236 },
237 "type='signal',interface='org.freedesktop.DBus."
238 "Properties',"
James Feistfd9ab9e2020-05-19 13:48:07 -0700239 "member='PropertiesChanged',path='" +
James Feist32898ce2020-03-10 16:16:52 -0700240 objPath.str + "'");
241 task->startTimer(std::chrono::minutes(5));
242 task->populateResp(asyncResp->res);
James Feistfe306722020-03-12 16:32:08 -0700243 task->payload.emplace(req);
Andrew Geissler0554c982019-04-23 14:40:12 -0500244 }
Andrew Geissler86adcd62019-04-18 10:58:05 -0500245 fwUpdateInProgress = false;
246 },
247 "xyz.openbmc_project.ObjectMapper",
248 "/xyz/openbmc_project/object_mapper",
249 "xyz.openbmc_project.ObjectMapper", "GetObject", objPath.str,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500250 std::array<const char*, 1>{
Andrew Geissler86adcd62019-04-18 10:58:05 -0500251 "xyz.openbmc_project.Software.Activation"});
252 }
253 }
254}
255
Andrew Geissler0554c982019-04-23 14:40:12 -0500256// Note that asyncResp can be either a valid pointer or nullptr. If nullptr
257// then no asyncResp updates will occur
Ed Tanousb5a76932020-09-29 16:16:58 -0700258static void monitorForSoftwareAvailable(
259 const std::shared_ptr<AsyncResp>& asyncResp, const crow::Request& req,
260 const std::string& url, int timeoutTimeSeconds = 10)
Andrew Geissler86adcd62019-04-18 10:58:05 -0500261{
262 // Only allow one FW update at a time
263 if (fwUpdateInProgress != false)
264 {
Andrew Geissler0554c982019-04-23 14:40:12 -0500265 if (asyncResp)
266 {
Andrew Geissler0554c982019-04-23 14:40:12 -0500267 messages::serviceTemporarilyUnavailable(asyncResp->res, "30");
268 }
Andrew Geissler86adcd62019-04-18 10:58:05 -0500269 return;
270 }
271
Andrew Geissler0554c982019-04-23 14:40:12 -0500272 fwAvailableTimer =
Ed Tanous271584a2019-07-09 16:24:22 -0700273 std::make_unique<boost::asio::steady_timer>(*req.ioService);
Andrew Geissler86adcd62019-04-18 10:58:05 -0500274
Ed Tanous271584a2019-07-09 16:24:22 -0700275 fwAvailableTimer->expires_after(std::chrono::seconds(timeoutTimeSeconds));
Andrew Geissler86adcd62019-04-18 10:58:05 -0500276
277 fwAvailableTimer->async_wait(
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500278 [asyncResp](const boost::system::error_code& ec) {
Andrew Geissler86adcd62019-04-18 10:58:05 -0500279 cleanUp();
280 if (ec == boost::asio::error::operation_aborted)
281 {
282 // expected, we were canceled before the timer completed.
283 return;
284 }
285 BMCWEB_LOG_ERROR
286 << "Timed out waiting for firmware object being created";
287 BMCWEB_LOG_ERROR
288 << "FW image may has already been uploaded to server";
289 if (ec)
290 {
291 BMCWEB_LOG_ERROR << "Async_wait failed" << ec;
292 return;
293 }
Andrew Geissler0554c982019-04-23 14:40:12 -0500294 if (asyncResp)
295 {
296 redfish::messages::internalError(asyncResp->res);
297 }
Andrew Geissler86adcd62019-04-18 10:58:05 -0500298 });
299
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500300 auto callback = [asyncResp, req](sdbusplus::message::message& m) {
Andrew Geissler86adcd62019-04-18 10:58:05 -0500301 BMCWEB_LOG_DEBUG << "Match fired";
James Feistfe306722020-03-12 16:32:08 -0700302 softwareInterfaceAdded(asyncResp, m, req);
Andrew Geissler86adcd62019-04-18 10:58:05 -0500303 };
304
305 fwUpdateInProgress = true;
306
307 fwUpdateMatcher = std::make_unique<sdbusplus::bus::match::match>(
308 *crow::connections::systemBus,
309 "interface='org.freedesktop.DBus.ObjectManager',type='signal',"
310 "member='InterfacesAdded',path='/xyz/openbmc_project/software'",
311 callback);
James Feist4cde5d92020-06-11 10:39:55 -0700312
313 fwUpdateErrorMatcher = std::make_unique<sdbusplus::bus::match::match>(
314 *crow::connections::systemBus,
315 "type='signal',member='PropertiesChanged',path_namespace='/xyz/"
316 "openbmc_project/logging/entry',"
317 "arg0='xyz.openbmc_project.Logging.Entry'",
318 [asyncResp, url](sdbusplus::message::message& m) {
319 BMCWEB_LOG_DEBUG << "Error Match fired";
320 boost::container::flat_map<std::string, std::variant<std::string>>
321 values;
322 std::string objName;
323 m.read(objName, values);
324 auto find = values.find("Message");
325 if (find == values.end())
326 {
327 return;
328 }
329 std::string* type = std::get_if<std::string>(&(find->second));
330 if (type == nullptr)
331 {
332 return; // if this was our message, timeout will cover it
333 }
Gunnar Mills88b3dd12020-11-20 14:26:04 -0600334 if (!boost::starts_with(*type, "xyz.openbmc_project.Software"))
James Feist4cde5d92020-06-11 10:39:55 -0700335 {
336 return;
337 }
338 if (*type ==
339 "xyz.openbmc_project.Software.Image.Error.UnTarFailure")
340 {
341 redfish::messages::invalidUpload(asyncResp->res, url,
342 "Invalid archive");
343 }
344 else if (*type == "xyz.openbmc_project.Software.Image.Error."
345 "ManifestFileFailure")
346 {
347 redfish::messages::invalidUpload(asyncResp->res, url,
348 "Invalid manifest");
349 }
350 else if (*type ==
351 "xyz.openbmc_project.Software.Image.Error.ImageFailure")
352 {
353 redfish::messages::invalidUpload(asyncResp->res, url,
354 "Invalid image format");
355 }
Gunnar Mills88b3dd12020-11-20 14:26:04 -0600356 else if (*type == "xyz.openbmc_project.Software.Version.Error."
357 "AlreadyExists")
358 {
359
360 redfish::messages::invalidUpload(
361 asyncResp->res, url, "Image version already exists");
362
363 redfish::messages::resourceAlreadyExists(
364 asyncResp->res, "UpdateService.v1_4_0.UpdateService",
365 "Version", "uploaded version");
366 }
James Feist4cde5d92020-06-11 10:39:55 -0700367 else if (*type ==
368 "xyz.openbmc_project.Software.Image.Error.BusyFailure")
369 {
370 redfish::messages::resourceExhaustion(asyncResp->res, url);
371 }
372 else
373 {
374 redfish::messages::internalError(asyncResp->res);
375 }
376 fwAvailableTimer = nullptr;
377 });
Andrew Geissler86adcd62019-04-18 10:58:05 -0500378}
Jennifer Lee729dae72018-04-24 15:59:34 -0700379
Andrew Geissler0554c982019-04-23 14:40:12 -0500380/**
381 * UpdateServiceActionsSimpleUpdate class supports handle POST method for
382 * SimpleUpdate action.
383 */
384class UpdateServiceActionsSimpleUpdate : public Node
385{
386 public:
Ed Tanous52cc1122020-07-18 13:51:21 -0700387 UpdateServiceActionsSimpleUpdate(App& app) :
Andrew Geissler0554c982019-04-23 14:40:12 -0500388 Node(app,
389 "/redfish/v1/UpdateService/Actions/UpdateService.SimpleUpdate/")
390 {
391 entityPrivileges = {
392 {boost::beast::http::verb::get, {{"Login"}}},
393 {boost::beast::http::verb::head, {{"Login"}}},
394 {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
395 {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
396 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
397 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
398 }
399
400 private:
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500401 void doPost(crow::Response& res, const crow::Request& req,
Ed Tanouscb13a392020-07-25 19:02:03 +0000402 const std::vector<std::string>&) override
Andrew Geissler0554c982019-04-23 14:40:12 -0500403 {
404 std::optional<std::string> transferProtocol;
405 std::string imageURI;
406 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
407
408 BMCWEB_LOG_DEBUG << "Enter UpdateService.SimpleUpdate doPost";
409
410 // User can pass in both TransferProtocol and ImageURI parameters or
Gunnar Mills4e0453b2020-07-08 14:00:30 -0500411 // they can pass in just the ImageURI with the transfer protocol
412 // embedded within it.
Andrew Geissler0554c982019-04-23 14:40:12 -0500413 // 1) TransferProtocol:TFTP ImageURI:1.1.1.1/myfile.bin
414 // 2) ImageURI:tftp://1.1.1.1/myfile.bin
415
416 if (!json_util::readJson(req, asyncResp->res, "TransferProtocol",
417 transferProtocol, "ImageURI", imageURI))
418 {
419 BMCWEB_LOG_DEBUG
420 << "Missing TransferProtocol or ImageURI parameter";
421 return;
422 }
423 if (!transferProtocol)
424 {
425 // Must be option 2
426 // Verify ImageURI has transfer protocol in it
Ed Tanousf23b7292020-10-15 09:41:17 -0700427 size_t separator = imageURI.find(':');
Andrew Geissler0554c982019-04-23 14:40:12 -0500428 if ((separator == std::string::npos) ||
429 ((separator + 1) > imageURI.size()))
430 {
431 messages::actionParameterValueTypeError(
432 asyncResp->res, imageURI, "ImageURI",
433 "UpdateService.SimpleUpdate");
434 BMCWEB_LOG_ERROR << "ImageURI missing transfer protocol: "
435 << imageURI;
436 return;
437 }
438 transferProtocol = imageURI.substr(0, separator);
439 // Ensure protocol is upper case for a common comparison path below
440 boost::to_upper(*transferProtocol);
441 BMCWEB_LOG_DEBUG << "Encoded transfer protocol "
442 << *transferProtocol;
443
444 // Adjust imageURI to not have the protocol on it for parsing
445 // below
446 // ex. tftp://1.1.1.1/myfile.bin -> 1.1.1.1/myfile.bin
447 imageURI = imageURI.substr(separator + 3);
448 BMCWEB_LOG_DEBUG << "Adjusted imageUri " << imageURI;
449 }
450
451 // OpenBMC currently only supports TFTP
452 if (*transferProtocol != "TFTP")
453 {
454 messages::actionParameterNotSupported(asyncResp->res,
455 "TransferProtocol",
456 "UpdateService.SimpleUpdate");
457 BMCWEB_LOG_ERROR << "Request incorrect protocol parameter: "
458 << *transferProtocol;
459 return;
460 }
461
462 // Format should be <IP or Hostname>/<file> for imageURI
Ed Tanousf23b7292020-10-15 09:41:17 -0700463 size_t separator = imageURI.find('/');
Andrew Geissler0554c982019-04-23 14:40:12 -0500464 if ((separator == std::string::npos) ||
465 ((separator + 1) > imageURI.size()))
466 {
467 messages::actionParameterValueTypeError(
468 asyncResp->res, imageURI, "ImageURI",
469 "UpdateService.SimpleUpdate");
470 BMCWEB_LOG_ERROR << "Invalid ImageURI: " << imageURI;
471 return;
472 }
473
474 std::string tftpServer = imageURI.substr(0, separator);
475 std::string fwFile = imageURI.substr(separator + 1);
476 BMCWEB_LOG_DEBUG << "Server: " << tftpServer + " File: " << fwFile;
477
478 // Setup callback for when new software detected
Gunnar Mills2618d5e2020-08-18 13:04:27 -0500479 // Give TFTP 10 minutes to complete
James Feist4cde5d92020-06-11 10:39:55 -0700480 monitorForSoftwareAvailable(
Albert Zhangd7a596b2021-01-20 16:39:12 +0800481 asyncResp, req,
James Feist4cde5d92020-06-11 10:39:55 -0700482 "/redfish/v1/UpdateService/Actions/UpdateService.SimpleUpdate",
Gunnar Mills2618d5e2020-08-18 13:04:27 -0500483 600);
Andrew Geissler0554c982019-04-23 14:40:12 -0500484
Gunnar Mills2618d5e2020-08-18 13:04:27 -0500485 // TFTP can take up to 10 minutes depending on image size and
Andrew Geissler0554c982019-04-23 14:40:12 -0500486 // connection speed. Return to caller as soon as the TFTP operation
487 // has been started. The callback above will ensure the activate
488 // is started once the download has completed
489 redfish::messages::success(asyncResp->res);
490
491 // Call TFTP service
492 crow::connections::systemBus->async_method_call(
493 [](const boost::system::error_code ec) {
494 if (ec)
495 {
496 // messages::internalError(asyncResp->res);
497 cleanUp();
498 BMCWEB_LOG_DEBUG << "error_code = " << ec;
499 BMCWEB_LOG_DEBUG << "error msg = " << ec.message();
500 }
501 else
502 {
503 BMCWEB_LOG_DEBUG << "Call to DownloaViaTFTP Success";
504 }
505 },
506 "xyz.openbmc_project.Software.Download",
507 "/xyz/openbmc_project/software", "xyz.openbmc_project.Common.TFTP",
508 "DownloadViaTFTP", fwFile, tftpServer);
509
510 BMCWEB_LOG_DEBUG << "Exit UpdateService.SimpleUpdate doPost";
511 }
512};
513
Ed Tanous1abe55e2018-09-05 08:30:59 -0700514class UpdateService : public Node
515{
516 public:
Ed Tanous52cc1122020-07-18 13:51:21 -0700517 UpdateService(App& app) : Node(app, "/redfish/v1/UpdateService/")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700518 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700519 entityPrivileges = {
520 {boost::beast::http::verb::get, {{"Login"}}},
521 {boost::beast::http::verb::head, {{"Login"}}},
522 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
523 {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
524 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
525 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
Jennifer Leeacb7cfb2018-06-07 16:08:15 -0700526 }
Jennifer Leeacb7cfb2018-06-07 16:08:15 -0700527
Ed Tanous1abe55e2018-09-05 08:30:59 -0700528 private:
Ed Tanouscb13a392020-07-25 19:02:03 +0000529 void doGet(crow::Response& res, const crow::Request&,
530 const std::vector<std::string>&) override
Ed Tanous1abe55e2018-09-05 08:30:59 -0700531 {
Jayashankar Padath274dfe62019-08-23 12:30:57 +0530532 std::shared_ptr<AsyncResp> aResp = std::make_shared<AsyncResp>(res);
533 res.jsonValue["@odata.type"] = "#UpdateService.v1_4_0.UpdateService";
Ed Tanous0f74e642018-11-12 15:17:05 -0800534 res.jsonValue["@odata.id"] = "/redfish/v1/UpdateService";
Ed Tanous0f74e642018-11-12 15:17:05 -0800535 res.jsonValue["Id"] = "UpdateService";
536 res.jsonValue["Description"] = "Service for Software Update";
537 res.jsonValue["Name"] = "Update Service";
538 res.jsonValue["HttpPushUri"] = "/redfish/v1/UpdateService";
539 // UpdateService cannot be disabled
540 res.jsonValue["ServiceEnabled"] = true;
541 res.jsonValue["FirmwareInventory"] = {
542 {"@odata.id", "/redfish/v1/UpdateService/FirmwareInventory"}};
Andrew Geissler0554c982019-04-23 14:40:12 -0500543#ifdef BMCWEB_INSECURE_ENABLE_REDFISH_FW_TFTP_UPDATE
544 // Update Actions object.
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500545 nlohmann::json& updateSvcSimpleUpdate =
Andrew Geissler0554c982019-04-23 14:40:12 -0500546 res.jsonValue["Actions"]["#UpdateService.SimpleUpdate"];
547 updateSvcSimpleUpdate["target"] =
548 "/redfish/v1/UpdateService/Actions/UpdateService.SimpleUpdate";
549 updateSvcSimpleUpdate["TransferProtocol@Redfish.AllowableValues"] = {
550 "TFTP"};
551#endif
Jayashankar Padath274dfe62019-08-23 12:30:57 +0530552 // Get the current ApplyTime value
553 crow::connections::systemBus->async_method_call(
554 [aResp](const boost::system::error_code ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500555 const std::variant<std::string>& applyTime) {
Jayashankar Padath274dfe62019-08-23 12:30:57 +0530556 if (ec)
557 {
558 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
559 messages::internalError(aResp->res);
560 return;
561 }
562
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500563 const std::string* s = std::get_if<std::string>(&applyTime);
Jayashankar Padath274dfe62019-08-23 12:30:57 +0530564 if (s == nullptr)
565 {
566 return;
567 }
568 // Store the ApplyTime Value
569 if (*s == "xyz.openbmc_project.Software.ApplyTime."
570 "RequestedApplyTimes.Immediate")
571 {
572 aResp->res.jsonValue["HttpPushUriOptions"]
573 ["HttpPushUriApplyTime"]["ApplyTime"] =
574 "Immediate";
575 }
576 else if (*s == "xyz.openbmc_project.Software.ApplyTime."
577 "RequestedApplyTimes.OnReset")
578 {
579 aResp->res.jsonValue["HttpPushUriOptions"]
580 ["HttpPushUriApplyTime"]["ApplyTime"] =
581 "OnReset";
582 }
583 },
584 "xyz.openbmc_project.Settings",
585 "/xyz/openbmc_project/software/apply_time",
586 "org.freedesktop.DBus.Properties", "Get",
587 "xyz.openbmc_project.Software.ApplyTime", "RequestedApplyTime");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700588 }
Andrew Geissler0e7de462019-03-04 19:11:54 -0600589
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500590 void doPatch(crow::Response& res, const crow::Request& req,
Ed Tanouscb13a392020-07-25 19:02:03 +0000591 const std::vector<std::string>&) override
Jayashankar Padathfa1a5a32019-05-28 23:54:37 +0530592 {
593 BMCWEB_LOG_DEBUG << "doPatch...";
594
595 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
Jayashankar Padathfa1a5a32019-05-28 23:54:37 +0530596
Jayashankar Padath274dfe62019-08-23 12:30:57 +0530597 std::optional<nlohmann::json> pushUriOptions;
598 if (!json_util::readJson(req, res, "HttpPushUriOptions",
599 pushUriOptions))
Jayashankar Padathfa1a5a32019-05-28 23:54:37 +0530600 {
601 return;
602 }
603
Jayashankar Padath274dfe62019-08-23 12:30:57 +0530604 if (pushUriOptions)
Jayashankar Padathfa1a5a32019-05-28 23:54:37 +0530605 {
Jayashankar Padath274dfe62019-08-23 12:30:57 +0530606 std::optional<nlohmann::json> pushUriApplyTime;
607 if (!json_util::readJson(*pushUriOptions, res,
608 "HttpPushUriApplyTime", pushUriApplyTime))
Jayashankar Padathfa1a5a32019-05-28 23:54:37 +0530609 {
Jayashankar Padath274dfe62019-08-23 12:30:57 +0530610 return;
Jayashankar Padathfa1a5a32019-05-28 23:54:37 +0530611 }
612
Jayashankar Padath274dfe62019-08-23 12:30:57 +0530613 if (pushUriApplyTime)
614 {
615 std::optional<std::string> applyTime;
616 if (!json_util::readJson(*pushUriApplyTime, res, "ApplyTime",
617 applyTime))
618 {
619 return;
620 }
621
622 if (applyTime)
623 {
624 std::string applyTimeNewVal;
625 if (applyTime == "Immediate")
Jayashankar Padathfa1a5a32019-05-28 23:54:37 +0530626 {
Jayashankar Padath274dfe62019-08-23 12:30:57 +0530627 applyTimeNewVal =
628 "xyz.openbmc_project.Software.ApplyTime."
629 "RequestedApplyTimes.Immediate";
630 }
631 else if (applyTime == "OnReset")
632 {
633 applyTimeNewVal =
634 "xyz.openbmc_project.Software.ApplyTime."
635 "RequestedApplyTimes.OnReset";
636 }
637 else
638 {
639 BMCWEB_LOG_INFO
640 << "ApplyTime value is not in the list of "
641 "acceptable values";
642 messages::propertyValueNotInList(
643 asyncResp->res, *applyTime, "ApplyTime");
Jayashankar Padathfa1a5a32019-05-28 23:54:37 +0530644 return;
645 }
Jayashankar Padath274dfe62019-08-23 12:30:57 +0530646
647 // Set the requested image apply time value
648 crow::connections::systemBus->async_method_call(
649 [asyncResp](const boost::system::error_code ec) {
650 if (ec)
651 {
652 BMCWEB_LOG_ERROR << "D-Bus responses error: "
653 << ec;
654 messages::internalError(asyncResp->res);
655 return;
656 }
657 messages::success(asyncResp->res);
658 },
659 "xyz.openbmc_project.Settings",
660 "/xyz/openbmc_project/software/apply_time",
661 "org.freedesktop.DBus.Properties", "Set",
662 "xyz.openbmc_project.Software.ApplyTime",
663 "RequestedApplyTime",
664 std::variant<std::string>{applyTimeNewVal});
665 }
666 }
Jayashankar Padathfa1a5a32019-05-28 23:54:37 +0530667 }
668 }
669
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500670 void doPost(crow::Response& res, const crow::Request& req,
Ed Tanouscb13a392020-07-25 19:02:03 +0000671 const std::vector<std::string>&) override
Ed Tanous1abe55e2018-09-05 08:30:59 -0700672 {
673 BMCWEB_LOG_DEBUG << "doPost...";
Jennifer Leeacb7cfb2018-06-07 16:08:15 -0700674
Andrew Geissler0e7de462019-03-04 19:11:54 -0600675 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700676
Andrew Geissler86adcd62019-04-18 10:58:05 -0500677 // Setup callback for when new software detected
James Feist4cde5d92020-06-11 10:39:55 -0700678 monitorForSoftwareAvailable(asyncResp, req,
679 "/redfish/v1/UpdateService");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700680
681 std::string filepath(
682 "/tmp/images/" +
683 boost::uuids::to_string(boost::uuids::random_generator()()));
684 BMCWEB_LOG_DEBUG << "Writing file to " << filepath;
685 std::ofstream out(filepath, std::ofstream::out | std::ofstream::binary |
686 std::ofstream::trunc);
687 out << req.body;
688 out.close();
689 BMCWEB_LOG_DEBUG << "file upload complete!!";
690 }
Jennifer Lee729dae72018-04-24 15:59:34 -0700691};
Ed Tanousc711bf82018-07-30 16:31:33 -0700692
Ed Tanous1abe55e2018-09-05 08:30:59 -0700693class SoftwareInventoryCollection : public Node
694{
695 public:
Ed Tanous52cc1122020-07-18 13:51:21 -0700696 SoftwareInventoryCollection(App& app) :
Ed Tanous1abe55e2018-09-05 08:30:59 -0700697 Node(app, "/redfish/v1/UpdateService/FirmwareInventory/")
698 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700699 entityPrivileges = {
700 {boost::beast::http::verb::get, {{"Login"}}},
701 {boost::beast::http::verb::head, {{"Login"}}},
702 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
703 {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
704 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
705 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
Jennifer Lee729dae72018-04-24 15:59:34 -0700706 }
Jennifer Lee729dae72018-04-24 15:59:34 -0700707
Ed Tanous1abe55e2018-09-05 08:30:59 -0700708 private:
Ed Tanouscb13a392020-07-25 19:02:03 +0000709 void doGet(crow::Response& res, const crow::Request&,
710 const std::vector<std::string>&) override
Ed Tanous1abe55e2018-09-05 08:30:59 -0700711 {
712 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
Ed Tanous0f74e642018-11-12 15:17:05 -0800713 res.jsonValue["@odata.type"] =
714 "#SoftwareInventoryCollection.SoftwareInventoryCollection";
715 res.jsonValue["@odata.id"] =
716 "/redfish/v1/UpdateService/FirmwareInventory";
Ed Tanous0f74e642018-11-12 15:17:05 -0800717 res.jsonValue["Name"] = "Software Inventory Collection";
Ed Tanousc711bf82018-07-30 16:31:33 -0700718
Ed Tanous1abe55e2018-09-05 08:30:59 -0700719 crow::connections::systemBus->async_method_call(
720 [asyncResp](
721 const boost::system::error_code ec,
722 const std::vector<std::pair<
723 std::string, std::vector<std::pair<
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500724 std::string, std::vector<std::string>>>>>&
725 subtree) {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700726 if (ec)
727 {
Jason M. Billsf12894f2018-10-09 12:45:45 -0700728 messages::internalError(asyncResp->res);
Ed Tanousc711bf82018-07-30 16:31:33 -0700729 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700730 }
731 asyncResp->res.jsonValue["Members"] = nlohmann::json::array();
732 asyncResp->res.jsonValue["Members@odata.count"] = 0;
Jennifer Lee6c4eb9d2018-05-22 10:58:31 -0700733
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500734 for (auto& obj : subtree)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700735 {
Ed Tanous2dfd18e2020-12-18 00:41:31 +0000736 sdbusplus::message::object_path path(obj.first);
737 std::string swId = path.filename();
738 if (swId.empty())
Jennifer Leef4b65ab2018-09-18 12:00:13 -0700739 {
Jason M. Billsf12894f2018-10-09 12:45:45 -0700740 messages::internalError(asyncResp->res);
Jennifer Leef4b65ab2018-09-18 12:00:13 -0700741 BMCWEB_LOG_DEBUG << "Can't parse firmware ID!!";
742 return;
743 }
Jennifer Leef4b65ab2018-09-18 12:00:13 -0700744
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500745 nlohmann::json& members =
Andrew Geisslere0dd8052019-06-18 16:05:10 -0500746 asyncResp->res.jsonValue["Members"];
747 members.push_back(
748 {{"@odata.id", "/redfish/v1/UpdateService/"
749 "FirmwareInventory/" +
750 swId}});
751 asyncResp->res.jsonValue["Members@odata.count"] =
752 members.size();
Ed Tanous1abe55e2018-09-05 08:30:59 -0700753 }
754 },
Andrew Geissler2830a9c2020-01-06 10:18:11 -0600755 // Note that only firmware levels associated with a device are
756 // stored under /xyz/openbmc_project/software therefore to ensure
757 // only real FirmwareInventory items are returned, this full object
758 // path must be used here as input to mapper
Ed Tanous1abe55e2018-09-05 08:30:59 -0700759 "xyz.openbmc_project.ObjectMapper",
760 "/xyz/openbmc_project/object_mapper",
Andrew Geissler2830a9c2020-01-06 10:18:11 -0600761 "xyz.openbmc_project.ObjectMapper", "GetSubTree",
762 "/xyz/openbmc_project/software", static_cast<int32_t>(0),
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500763 std::array<const char*, 1>{"xyz.openbmc_project.Software.Version"});
Ed Tanous1abe55e2018-09-05 08:30:59 -0700764 }
Jennifer Lee729dae72018-04-24 15:59:34 -0700765};
766
Ed Tanous1abe55e2018-09-05 08:30:59 -0700767class SoftwareInventory : public Node
768{
769 public:
Ed Tanous52cc1122020-07-18 13:51:21 -0700770 SoftwareInventory(App& app) :
Ed Tanous1abe55e2018-09-05 08:30:59 -0700771 Node(app, "/redfish/v1/UpdateService/FirmwareInventory/<str>/",
772 std::string())
773 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700774 entityPrivileges = {
775 {boost::beast::http::verb::get, {{"Login"}}},
776 {boost::beast::http::verb::head, {{"Login"}}},
777 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
778 {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
779 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
780 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
781 }
782
783 private:
Andrew Geissler87d84722019-02-28 14:28:39 -0600784 /* Fill related item links (i.e. bmc, bios) in for inventory */
Ed Tanousb5a76932020-09-29 16:16:58 -0700785 static void getRelatedItems(const std::shared_ptr<AsyncResp>& aResp,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500786 const std::string& purpose)
Andrew Geissler87d84722019-02-28 14:28:39 -0600787 {
788 if (purpose == fw_util::bmcPurpose)
789 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500790 nlohmann::json& members = aResp->res.jsonValue["RelatedItem"];
Andrew Geissler87d84722019-02-28 14:28:39 -0600791 members.push_back({{"@odata.id", "/redfish/v1/Managers/bmc"}});
792 aResp->res.jsonValue["Members@odata.count"] = members.size();
793 }
794 else if (purpose == fw_util::biosPurpose)
795 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500796 nlohmann::json& members = aResp->res.jsonValue["RelatedItem"];
Gunnar Millsf723d732020-02-26 11:20:49 -0600797 members.push_back(
798 {{"@odata.id", "/redfish/v1/Systems/system/Bios"}});
799 aResp->res.jsonValue["Members@odata.count"] = members.size();
Andrew Geissler87d84722019-02-28 14:28:39 -0600800 }
801 else
802 {
803 BMCWEB_LOG_ERROR << "Unknown software purpose " << purpose;
804 }
805 }
806
Ed Tanouscb13a392020-07-25 19:02:03 +0000807 void doGet(crow::Response& res, const crow::Request&,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500808 const std::vector<std::string>& params) override
Ed Tanous1abe55e2018-09-05 08:30:59 -0700809 {
810 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700811
812 if (params.size() != 1)
813 {
Jason M. Billsf12894f2018-10-09 12:45:45 -0700814 messages::internalError(res);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700815 res.end();
816 return;
817 }
818
Ed Tanous3ae837c2018-08-07 14:41:19 -0700819 std::shared_ptr<std::string> swId =
Ed Tanous1abe55e2018-09-05 08:30:59 -0700820 std::make_shared<std::string>(params[0]);
821
822 res.jsonValue["@odata.id"] =
Ed Tanous3ae837c2018-08-07 14:41:19 -0700823 "/redfish/v1/UpdateService/FirmwareInventory/" + *swId;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700824
825 crow::connections::systemBus->async_method_call(
Ed Tanous3ae837c2018-08-07 14:41:19 -0700826 [asyncResp, swId](
Ed Tanous1abe55e2018-09-05 08:30:59 -0700827 const boost::system::error_code ec,
828 const std::vector<std::pair<
829 std::string, std::vector<std::pair<
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500830 std::string, std::vector<std::string>>>>>&
831 subtree) {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700832 BMCWEB_LOG_DEBUG << "doGet callback...";
833 if (ec)
834 {
Jason M. Billsf12894f2018-10-09 12:45:45 -0700835 messages::internalError(asyncResp->res);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700836 return;
837 }
838
Andrew Geissler69132282019-07-01 11:00:35 -0500839 // Ensure we find our input swId, otherwise return an error
840 bool found = false;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700841 for (const std::pair<
842 std::string,
843 std::vector<
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500844 std::pair<std::string, std::vector<std::string>>>>&
845 obj : subtree)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700846 {
Ed Tanous3ae837c2018-08-07 14:41:19 -0700847 if (boost::ends_with(obj.first, *swId) != true)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700848 {
849 continue;
850 }
851
Jennifer Leef4b65ab2018-09-18 12:00:13 -0700852 if (obj.second.size() < 1)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700853 {
854 continue;
855 }
856
Andrew Geissler69132282019-07-01 11:00:35 -0500857 found = true;
Andrew Geisslere0dd8052019-06-18 16:05:10 -0500858 fw_util::getFwStatus(asyncResp, swId, obj.second[0].first);
859
Ed Tanous1abe55e2018-09-05 08:30:59 -0700860 crow::connections::systemBus->async_method_call(
861 [asyncResp,
Ed Tanous81ce6092020-12-17 16:54:55 +0000862 swId](const boost::system::error_code errorCode,
Ed Tanous3ae837c2018-08-07 14:41:19 -0700863 const boost::container::flat_map<
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500864 std::string, VariantType>& propertiesList) {
Ed Tanous81ce6092020-12-17 16:54:55 +0000865 if (errorCode)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700866 {
Jason M. Billsf12894f2018-10-09 12:45:45 -0700867 messages::internalError(asyncResp->res);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700868 return;
869 }
870 boost::container::flat_map<
871 std::string, VariantType>::const_iterator it =
872 propertiesList.find("Purpose");
873 if (it == propertiesList.end())
874 {
875 BMCWEB_LOG_DEBUG
876 << "Can't find property \"Purpose\"!";
Jason M. Billsf12894f2018-10-09 12:45:45 -0700877 messages::propertyMissing(asyncResp->res,
878 "Purpose");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700879 return;
880 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500881 const std::string* swInvPurpose =
Ed Tanousabf2add2019-01-22 16:40:12 -0800882 std::get_if<std::string>(&it->second);
Ed Tanous3ae837c2018-08-07 14:41:19 -0700883 if (swInvPurpose == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700884 {
885 BMCWEB_LOG_DEBUG
886 << "wrong types for property\"Purpose\"!";
Jason M. Billsf12894f2018-10-09 12:45:45 -0700887 messages::propertyValueTypeError(asyncResp->res,
888 "", "Purpose");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700889 return;
890 }
891
Ed Tanous3ae837c2018-08-07 14:41:19 -0700892 BMCWEB_LOG_DEBUG << "swInvPurpose = "
893 << *swInvPurpose;
Jennifer Leef4b65ab2018-09-18 12:00:13 -0700894 it = propertiesList.find("Version");
895 if (it == propertiesList.end())
Ed Tanous1abe55e2018-09-05 08:30:59 -0700896 {
Jennifer Leef4b65ab2018-09-18 12:00:13 -0700897 BMCWEB_LOG_DEBUG
898 << "Can't find property \"Version\"!";
Jason M. Billsf12894f2018-10-09 12:45:45 -0700899 messages::propertyMissing(asyncResp->res,
900 "Version");
Jennifer Leef4b65ab2018-09-18 12:00:13 -0700901 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700902 }
Jennifer Leef4b65ab2018-09-18 12:00:13 -0700903
904 BMCWEB_LOG_DEBUG << "Version found!";
905
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500906 const std::string* version =
Ed Tanousabf2add2019-01-22 16:40:12 -0800907 std::get_if<std::string>(&it->second);
Jennifer Leef4b65ab2018-09-18 12:00:13 -0700908
909 if (version == nullptr)
910 {
911 BMCWEB_LOG_DEBUG
912 << "Can't find property \"Version\"!";
Jason M. Billsf12894f2018-10-09 12:45:45 -0700913
914 messages::propertyValueTypeError(asyncResp->res,
915 "", "Version");
Jennifer Leef4b65ab2018-09-18 12:00:13 -0700916 return;
917 }
918 asyncResp->res.jsonValue["Version"] = *version;
919 asyncResp->res.jsonValue["Id"] = *swId;
Andrew Geissler54daabe2019-02-13 13:54:15 -0600920
921 // swInvPurpose is of format:
922 // xyz.openbmc_project.Software.Version.VersionPurpose.ABC
James Feiste2e96772019-10-03 10:51:43 -0700923 // Translate this to "ABC image"
Ed Tanousf23b7292020-10-15 09:41:17 -0700924 size_t endDesc = swInvPurpose->rfind('.');
Andrew Geissler54daabe2019-02-13 13:54:15 -0600925 if (endDesc == std::string::npos)
926 {
927 messages::internalError(asyncResp->res);
928 return;
929 }
930 endDesc++;
931 if (endDesc >= swInvPurpose->size())
932 {
933 messages::internalError(asyncResp->res);
934 return;
935 }
936
937 std::string formatDesc =
938 swInvPurpose->substr(endDesc);
939 asyncResp->res.jsonValue["Description"] =
James Feiste2e96772019-10-03 10:51:43 -0700940 formatDesc + " image";
Andrew Geissler87d84722019-02-28 14:28:39 -0600941 getRelatedItems(asyncResp, *swInvPurpose);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700942 },
943 obj.second[0].first, obj.first,
944 "org.freedesktop.DBus.Properties", "GetAll",
945 "xyz.openbmc_project.Software.Version");
946 }
Andrew Geissler69132282019-07-01 11:00:35 -0500947 if (!found)
948 {
949 BMCWEB_LOG_ERROR << "Input swID " + *swId + " not found!";
950 messages::resourceMissingAtURI(
951 asyncResp->res,
952 "/redfish/v1/UpdateService/FirmwareInventory/" + *swId);
953 return;
954 }
Ayushi Smriti4e68c452019-09-04 14:37:55 +0530955 asyncResp->res.jsonValue["@odata.type"] =
956 "#SoftwareInventory.v1_1_0.SoftwareInventory";
Ayushi Smriti4e68c452019-09-04 14:37:55 +0530957 asyncResp->res.jsonValue["Name"] = "Software Inventory";
Ayushi Smriti4e68c452019-09-04 14:37:55 +0530958 asyncResp->res.jsonValue["Status"]["HealthRollup"] = "OK";
AppaRao Puli3f8a7432020-01-29 02:36:32 +0530959
960 asyncResp->res.jsonValue["Updateable"] = false;
961 fw_util::getFwUpdateableStatus(asyncResp, swId);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700962 },
963 "xyz.openbmc_project.ObjectMapper",
964 "/xyz/openbmc_project/object_mapper",
Ed Tanous271584a2019-07-09 16:24:22 -0700965 "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/",
966 static_cast<int32_t>(0),
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500967 std::array<const char*, 1>{"xyz.openbmc_project.Software.Version"});
Ed Tanous1abe55e2018-09-05 08:30:59 -0700968 }
969};
970
971} // namespace redfish