blob: ddb8b30a6c04d76a7d217979524527d084fc7ff4 [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(
47 [](const boost::system::error_code error_code) {
48 if (error_code)
49 {
50 BMCWEB_LOG_DEBUG << "error_code = " << error_code;
51 BMCWEB_LOG_DEBUG << "error msg = " << error_code.message();
52 }
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,
86 req](const boost::system::error_code error_code,
87 const std::vector<std::pair<
Gunnar Mills1214b7e2020-06-04 10:11:30 -050088 std::string, std::vector<std::string>>>& objInfo) {
Andrew Geissler86adcd62019-04-18 10:58:05 -050089 if (error_code)
90 {
91 BMCWEB_LOG_DEBUG << "error_code = " << error_code;
92 BMCWEB_LOG_DEBUG << "error msg = "
93 << error_code.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 }
James Feist32898ce2020-03-10 16:16:52 -0700218 taskData->messages.emplace_back(
James Feistfd9ab9e2020-05-19 13:48:07 -0700219 messages::taskProgressChanged(
220 index, static_cast<size_t>(
221 *progress)));
222
223 // if we're getting status updates it's
224 // still alive, update timer
225 taskData->extendTimer(
226 std::chrono::minutes(5));
James Feist32898ce2020-03-10 16:16:52 -0700227 }
228
229 // as firmware update often results in a
230 // reboot, the task may never "complete"
231 // unless it is an error
232
233 return !task::completed;
234 },
235 "type='signal',interface='org.freedesktop.DBus."
236 "Properties',"
James Feistfd9ab9e2020-05-19 13:48:07 -0700237 "member='PropertiesChanged',path='" +
James Feist32898ce2020-03-10 16:16:52 -0700238 objPath.str + "'");
239 task->startTimer(std::chrono::minutes(5));
240 task->populateResp(asyncResp->res);
James Feistfe306722020-03-12 16:32:08 -0700241 task->payload.emplace(req);
Andrew Geissler0554c982019-04-23 14:40:12 -0500242 }
Andrew Geissler86adcd62019-04-18 10:58:05 -0500243 fwUpdateInProgress = false;
244 },
245 "xyz.openbmc_project.ObjectMapper",
246 "/xyz/openbmc_project/object_mapper",
247 "xyz.openbmc_project.ObjectMapper", "GetObject", objPath.str,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500248 std::array<const char*, 1>{
Andrew Geissler86adcd62019-04-18 10:58:05 -0500249 "xyz.openbmc_project.Software.Activation"});
250 }
251 }
252}
253
Andrew Geissler0554c982019-04-23 14:40:12 -0500254// Note that asyncResp can be either a valid pointer or nullptr. If nullptr
255// then no asyncResp updates will occur
Ed Tanousb5a76932020-09-29 16:16:58 -0700256static void monitorForSoftwareAvailable(
257 const std::shared_ptr<AsyncResp>& asyncResp, const crow::Request& req,
258 const std::string& url, int timeoutTimeSeconds = 10)
Andrew Geissler86adcd62019-04-18 10:58:05 -0500259{
260 // Only allow one FW update at a time
261 if (fwUpdateInProgress != false)
262 {
Andrew Geissler0554c982019-04-23 14:40:12 -0500263 if (asyncResp)
264 {
Andrew Geissler0554c982019-04-23 14:40:12 -0500265 messages::serviceTemporarilyUnavailable(asyncResp->res, "30");
266 }
Andrew Geissler86adcd62019-04-18 10:58:05 -0500267 return;
268 }
269
Andrew Geissler0554c982019-04-23 14:40:12 -0500270 fwAvailableTimer =
Ed Tanous271584a2019-07-09 16:24:22 -0700271 std::make_unique<boost::asio::steady_timer>(*req.ioService);
Andrew Geissler86adcd62019-04-18 10:58:05 -0500272
Ed Tanous271584a2019-07-09 16:24:22 -0700273 fwAvailableTimer->expires_after(std::chrono::seconds(timeoutTimeSeconds));
Andrew Geissler86adcd62019-04-18 10:58:05 -0500274
275 fwAvailableTimer->async_wait(
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500276 [asyncResp](const boost::system::error_code& ec) {
Andrew Geissler86adcd62019-04-18 10:58:05 -0500277 cleanUp();
278 if (ec == boost::asio::error::operation_aborted)
279 {
280 // expected, we were canceled before the timer completed.
281 return;
282 }
283 BMCWEB_LOG_ERROR
284 << "Timed out waiting for firmware object being created";
285 BMCWEB_LOG_ERROR
286 << "FW image may has already been uploaded to server";
287 if (ec)
288 {
289 BMCWEB_LOG_ERROR << "Async_wait failed" << ec;
290 return;
291 }
Andrew Geissler0554c982019-04-23 14:40:12 -0500292 if (asyncResp)
293 {
294 redfish::messages::internalError(asyncResp->res);
295 }
Andrew Geissler86adcd62019-04-18 10:58:05 -0500296 });
297
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500298 auto callback = [asyncResp, req](sdbusplus::message::message& m) {
Andrew Geissler86adcd62019-04-18 10:58:05 -0500299 BMCWEB_LOG_DEBUG << "Match fired";
James Feistfe306722020-03-12 16:32:08 -0700300 softwareInterfaceAdded(asyncResp, m, req);
Andrew Geissler86adcd62019-04-18 10:58:05 -0500301 };
302
303 fwUpdateInProgress = true;
304
305 fwUpdateMatcher = std::make_unique<sdbusplus::bus::match::match>(
306 *crow::connections::systemBus,
307 "interface='org.freedesktop.DBus.ObjectManager',type='signal',"
308 "member='InterfacesAdded',path='/xyz/openbmc_project/software'",
309 callback);
James Feist4cde5d92020-06-11 10:39:55 -0700310
311 fwUpdateErrorMatcher = std::make_unique<sdbusplus::bus::match::match>(
312 *crow::connections::systemBus,
313 "type='signal',member='PropertiesChanged',path_namespace='/xyz/"
314 "openbmc_project/logging/entry',"
315 "arg0='xyz.openbmc_project.Logging.Entry'",
316 [asyncResp, url](sdbusplus::message::message& m) {
317 BMCWEB_LOG_DEBUG << "Error Match fired";
318 boost::container::flat_map<std::string, std::variant<std::string>>
319 values;
320 std::string objName;
321 m.read(objName, values);
322 auto find = values.find("Message");
323 if (find == values.end())
324 {
325 return;
326 }
327 std::string* type = std::get_if<std::string>(&(find->second));
328 if (type == nullptr)
329 {
330 return; // if this was our message, timeout will cover it
331 }
332 if (!boost::starts_with(*type,
333 "xyz.openbmc_project.Software.Image.Error"))
334 {
335 return;
336 }
337 if (*type ==
338 "xyz.openbmc_project.Software.Image.Error.UnTarFailure")
339 {
340 redfish::messages::invalidUpload(asyncResp->res, url,
341 "Invalid archive");
342 }
343 else if (*type == "xyz.openbmc_project.Software.Image.Error."
344 "ManifestFileFailure")
345 {
346 redfish::messages::invalidUpload(asyncResp->res, url,
347 "Invalid manifest");
348 }
349 else if (*type ==
350 "xyz.openbmc_project.Software.Image.Error.ImageFailure")
351 {
352 redfish::messages::invalidUpload(asyncResp->res, url,
353 "Invalid image format");
354 }
355 else if (*type ==
356 "xyz.openbmc_project.Software.Image.Error.BusyFailure")
357 {
358 redfish::messages::resourceExhaustion(asyncResp->res, url);
359 }
360 else
361 {
362 redfish::messages::internalError(asyncResp->res);
363 }
364 fwAvailableTimer = nullptr;
365 });
Andrew Geissler86adcd62019-04-18 10:58:05 -0500366}
Jennifer Lee729dae72018-04-24 15:59:34 -0700367
Andrew Geissler0554c982019-04-23 14:40:12 -0500368/**
369 * UpdateServiceActionsSimpleUpdate class supports handle POST method for
370 * SimpleUpdate action.
371 */
372class UpdateServiceActionsSimpleUpdate : public Node
373{
374 public:
Ed Tanous52cc1122020-07-18 13:51:21 -0700375 UpdateServiceActionsSimpleUpdate(App& app) :
Andrew Geissler0554c982019-04-23 14:40:12 -0500376 Node(app,
377 "/redfish/v1/UpdateService/Actions/UpdateService.SimpleUpdate/")
378 {
379 entityPrivileges = {
380 {boost::beast::http::verb::get, {{"Login"}}},
381 {boost::beast::http::verb::head, {{"Login"}}},
382 {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
383 {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
384 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
385 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
386 }
387
388 private:
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500389 void doPost(crow::Response& res, const crow::Request& req,
Ed Tanouscb13a392020-07-25 19:02:03 +0000390 const std::vector<std::string>&) override
Andrew Geissler0554c982019-04-23 14:40:12 -0500391 {
392 std::optional<std::string> transferProtocol;
393 std::string imageURI;
394 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
395
396 BMCWEB_LOG_DEBUG << "Enter UpdateService.SimpleUpdate doPost";
397
398 // User can pass in both TransferProtocol and ImageURI parameters or
Gunnar Mills4e0453b2020-07-08 14:00:30 -0500399 // they can pass in just the ImageURI with the transfer protocol
400 // embedded within it.
Andrew Geissler0554c982019-04-23 14:40:12 -0500401 // 1) TransferProtocol:TFTP ImageURI:1.1.1.1/myfile.bin
402 // 2) ImageURI:tftp://1.1.1.1/myfile.bin
403
404 if (!json_util::readJson(req, asyncResp->res, "TransferProtocol",
405 transferProtocol, "ImageURI", imageURI))
406 {
407 BMCWEB_LOG_DEBUG
408 << "Missing TransferProtocol or ImageURI parameter";
409 return;
410 }
411 if (!transferProtocol)
412 {
413 // Must be option 2
414 // Verify ImageURI has transfer protocol in it
Ed Tanousf23b7292020-10-15 09:41:17 -0700415 size_t separator = imageURI.find(':');
Andrew Geissler0554c982019-04-23 14:40:12 -0500416 if ((separator == std::string::npos) ||
417 ((separator + 1) > imageURI.size()))
418 {
419 messages::actionParameterValueTypeError(
420 asyncResp->res, imageURI, "ImageURI",
421 "UpdateService.SimpleUpdate");
422 BMCWEB_LOG_ERROR << "ImageURI missing transfer protocol: "
423 << imageURI;
424 return;
425 }
426 transferProtocol = imageURI.substr(0, separator);
427 // Ensure protocol is upper case for a common comparison path below
428 boost::to_upper(*transferProtocol);
429 BMCWEB_LOG_DEBUG << "Encoded transfer protocol "
430 << *transferProtocol;
431
432 // Adjust imageURI to not have the protocol on it for parsing
433 // below
434 // ex. tftp://1.1.1.1/myfile.bin -> 1.1.1.1/myfile.bin
435 imageURI = imageURI.substr(separator + 3);
436 BMCWEB_LOG_DEBUG << "Adjusted imageUri " << imageURI;
437 }
438
439 // OpenBMC currently only supports TFTP
440 if (*transferProtocol != "TFTP")
441 {
442 messages::actionParameterNotSupported(asyncResp->res,
443 "TransferProtocol",
444 "UpdateService.SimpleUpdate");
445 BMCWEB_LOG_ERROR << "Request incorrect protocol parameter: "
446 << *transferProtocol;
447 return;
448 }
449
450 // Format should be <IP or Hostname>/<file> for imageURI
Ed Tanousf23b7292020-10-15 09:41:17 -0700451 size_t separator = imageURI.find('/');
Andrew Geissler0554c982019-04-23 14:40:12 -0500452 if ((separator == std::string::npos) ||
453 ((separator + 1) > imageURI.size()))
454 {
455 messages::actionParameterValueTypeError(
456 asyncResp->res, imageURI, "ImageURI",
457 "UpdateService.SimpleUpdate");
458 BMCWEB_LOG_ERROR << "Invalid ImageURI: " << imageURI;
459 return;
460 }
461
462 std::string tftpServer = imageURI.substr(0, separator);
463 std::string fwFile = imageURI.substr(separator + 1);
464 BMCWEB_LOG_DEBUG << "Server: " << tftpServer + " File: " << fwFile;
465
466 // Setup callback for when new software detected
Gunnar Mills2618d5e2020-08-18 13:04:27 -0500467 // Give TFTP 10 minutes to complete
James Feist4cde5d92020-06-11 10:39:55 -0700468 monitorForSoftwareAvailable(
469 nullptr, req,
470 "/redfish/v1/UpdateService/Actions/UpdateService.SimpleUpdate",
Gunnar Mills2618d5e2020-08-18 13:04:27 -0500471 600);
Andrew Geissler0554c982019-04-23 14:40:12 -0500472
Gunnar Mills2618d5e2020-08-18 13:04:27 -0500473 // TFTP can take up to 10 minutes depending on image size and
Andrew Geissler0554c982019-04-23 14:40:12 -0500474 // connection speed. Return to caller as soon as the TFTP operation
475 // has been started. The callback above will ensure the activate
476 // is started once the download has completed
477 redfish::messages::success(asyncResp->res);
478
479 // Call TFTP service
480 crow::connections::systemBus->async_method_call(
481 [](const boost::system::error_code ec) {
482 if (ec)
483 {
484 // messages::internalError(asyncResp->res);
485 cleanUp();
486 BMCWEB_LOG_DEBUG << "error_code = " << ec;
487 BMCWEB_LOG_DEBUG << "error msg = " << ec.message();
488 }
489 else
490 {
491 BMCWEB_LOG_DEBUG << "Call to DownloaViaTFTP Success";
492 }
493 },
494 "xyz.openbmc_project.Software.Download",
495 "/xyz/openbmc_project/software", "xyz.openbmc_project.Common.TFTP",
496 "DownloadViaTFTP", fwFile, tftpServer);
497
498 BMCWEB_LOG_DEBUG << "Exit UpdateService.SimpleUpdate doPost";
499 }
500};
501
Ed Tanous1abe55e2018-09-05 08:30:59 -0700502class UpdateService : public Node
503{
504 public:
Ed Tanous52cc1122020-07-18 13:51:21 -0700505 UpdateService(App& app) : Node(app, "/redfish/v1/UpdateService/")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700506 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700507 entityPrivileges = {
508 {boost::beast::http::verb::get, {{"Login"}}},
509 {boost::beast::http::verb::head, {{"Login"}}},
510 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
511 {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
512 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
513 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
Jennifer Leeacb7cfb2018-06-07 16:08:15 -0700514 }
Jennifer Leeacb7cfb2018-06-07 16:08:15 -0700515
Ed Tanous1abe55e2018-09-05 08:30:59 -0700516 private:
Ed Tanouscb13a392020-07-25 19:02:03 +0000517 void doGet(crow::Response& res, const crow::Request&,
518 const std::vector<std::string>&) override
Ed Tanous1abe55e2018-09-05 08:30:59 -0700519 {
Jayashankar Padath274dfe62019-08-23 12:30:57 +0530520 std::shared_ptr<AsyncResp> aResp = std::make_shared<AsyncResp>(res);
521 res.jsonValue["@odata.type"] = "#UpdateService.v1_4_0.UpdateService";
Ed Tanous0f74e642018-11-12 15:17:05 -0800522 res.jsonValue["@odata.id"] = "/redfish/v1/UpdateService";
Ed Tanous0f74e642018-11-12 15:17:05 -0800523 res.jsonValue["Id"] = "UpdateService";
524 res.jsonValue["Description"] = "Service for Software Update";
525 res.jsonValue["Name"] = "Update Service";
526 res.jsonValue["HttpPushUri"] = "/redfish/v1/UpdateService";
527 // UpdateService cannot be disabled
528 res.jsonValue["ServiceEnabled"] = true;
529 res.jsonValue["FirmwareInventory"] = {
530 {"@odata.id", "/redfish/v1/UpdateService/FirmwareInventory"}};
Andrew Geissler0554c982019-04-23 14:40:12 -0500531#ifdef BMCWEB_INSECURE_ENABLE_REDFISH_FW_TFTP_UPDATE
532 // Update Actions object.
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500533 nlohmann::json& updateSvcSimpleUpdate =
Andrew Geissler0554c982019-04-23 14:40:12 -0500534 res.jsonValue["Actions"]["#UpdateService.SimpleUpdate"];
535 updateSvcSimpleUpdate["target"] =
536 "/redfish/v1/UpdateService/Actions/UpdateService.SimpleUpdate";
537 updateSvcSimpleUpdate["TransferProtocol@Redfish.AllowableValues"] = {
538 "TFTP"};
539#endif
Jayashankar Padath274dfe62019-08-23 12:30:57 +0530540 // Get the current ApplyTime value
541 crow::connections::systemBus->async_method_call(
542 [aResp](const boost::system::error_code ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500543 const std::variant<std::string>& applyTime) {
Jayashankar Padath274dfe62019-08-23 12:30:57 +0530544 if (ec)
545 {
546 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
547 messages::internalError(aResp->res);
548 return;
549 }
550
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500551 const std::string* s = std::get_if<std::string>(&applyTime);
Jayashankar Padath274dfe62019-08-23 12:30:57 +0530552 if (s == nullptr)
553 {
554 return;
555 }
556 // Store the ApplyTime Value
557 if (*s == "xyz.openbmc_project.Software.ApplyTime."
558 "RequestedApplyTimes.Immediate")
559 {
560 aResp->res.jsonValue["HttpPushUriOptions"]
561 ["HttpPushUriApplyTime"]["ApplyTime"] =
562 "Immediate";
563 }
564 else if (*s == "xyz.openbmc_project.Software.ApplyTime."
565 "RequestedApplyTimes.OnReset")
566 {
567 aResp->res.jsonValue["HttpPushUriOptions"]
568 ["HttpPushUriApplyTime"]["ApplyTime"] =
569 "OnReset";
570 }
571 },
572 "xyz.openbmc_project.Settings",
573 "/xyz/openbmc_project/software/apply_time",
574 "org.freedesktop.DBus.Properties", "Get",
575 "xyz.openbmc_project.Software.ApplyTime", "RequestedApplyTime");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700576 }
Andrew Geissler0e7de462019-03-04 19:11:54 -0600577
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500578 void doPatch(crow::Response& res, const crow::Request& req,
Ed Tanouscb13a392020-07-25 19:02:03 +0000579 const std::vector<std::string>&) override
Jayashankar Padathfa1a5a32019-05-28 23:54:37 +0530580 {
581 BMCWEB_LOG_DEBUG << "doPatch...";
582
583 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
Jayashankar Padathfa1a5a32019-05-28 23:54:37 +0530584
Jayashankar Padath274dfe62019-08-23 12:30:57 +0530585 std::optional<nlohmann::json> pushUriOptions;
586 if (!json_util::readJson(req, res, "HttpPushUriOptions",
587 pushUriOptions))
Jayashankar Padathfa1a5a32019-05-28 23:54:37 +0530588 {
589 return;
590 }
591
Jayashankar Padath274dfe62019-08-23 12:30:57 +0530592 if (pushUriOptions)
Jayashankar Padathfa1a5a32019-05-28 23:54:37 +0530593 {
Jayashankar Padath274dfe62019-08-23 12:30:57 +0530594 std::optional<nlohmann::json> pushUriApplyTime;
595 if (!json_util::readJson(*pushUriOptions, res,
596 "HttpPushUriApplyTime", pushUriApplyTime))
Jayashankar Padathfa1a5a32019-05-28 23:54:37 +0530597 {
Jayashankar Padath274dfe62019-08-23 12:30:57 +0530598 return;
Jayashankar Padathfa1a5a32019-05-28 23:54:37 +0530599 }
600
Jayashankar Padath274dfe62019-08-23 12:30:57 +0530601 if (pushUriApplyTime)
602 {
603 std::optional<std::string> applyTime;
604 if (!json_util::readJson(*pushUriApplyTime, res, "ApplyTime",
605 applyTime))
606 {
607 return;
608 }
609
610 if (applyTime)
611 {
612 std::string applyTimeNewVal;
613 if (applyTime == "Immediate")
Jayashankar Padathfa1a5a32019-05-28 23:54:37 +0530614 {
Jayashankar Padath274dfe62019-08-23 12:30:57 +0530615 applyTimeNewVal =
616 "xyz.openbmc_project.Software.ApplyTime."
617 "RequestedApplyTimes.Immediate";
618 }
619 else if (applyTime == "OnReset")
620 {
621 applyTimeNewVal =
622 "xyz.openbmc_project.Software.ApplyTime."
623 "RequestedApplyTimes.OnReset";
624 }
625 else
626 {
627 BMCWEB_LOG_INFO
628 << "ApplyTime value is not in the list of "
629 "acceptable values";
630 messages::propertyValueNotInList(
631 asyncResp->res, *applyTime, "ApplyTime");
Jayashankar Padathfa1a5a32019-05-28 23:54:37 +0530632 return;
633 }
Jayashankar Padath274dfe62019-08-23 12:30:57 +0530634
635 // Set the requested image apply time value
636 crow::connections::systemBus->async_method_call(
637 [asyncResp](const boost::system::error_code ec) {
638 if (ec)
639 {
640 BMCWEB_LOG_ERROR << "D-Bus responses error: "
641 << ec;
642 messages::internalError(asyncResp->res);
643 return;
644 }
645 messages::success(asyncResp->res);
646 },
647 "xyz.openbmc_project.Settings",
648 "/xyz/openbmc_project/software/apply_time",
649 "org.freedesktop.DBus.Properties", "Set",
650 "xyz.openbmc_project.Software.ApplyTime",
651 "RequestedApplyTime",
652 std::variant<std::string>{applyTimeNewVal});
653 }
654 }
Jayashankar Padathfa1a5a32019-05-28 23:54:37 +0530655 }
656 }
657
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500658 void doPost(crow::Response& res, const crow::Request& req,
Ed Tanouscb13a392020-07-25 19:02:03 +0000659 const std::vector<std::string>&) override
Ed Tanous1abe55e2018-09-05 08:30:59 -0700660 {
661 BMCWEB_LOG_DEBUG << "doPost...";
Jennifer Leeacb7cfb2018-06-07 16:08:15 -0700662
Andrew Geissler0e7de462019-03-04 19:11:54 -0600663 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700664
Andrew Geissler86adcd62019-04-18 10:58:05 -0500665 // Setup callback for when new software detected
James Feist4cde5d92020-06-11 10:39:55 -0700666 monitorForSoftwareAvailable(asyncResp, req,
667 "/redfish/v1/UpdateService");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700668
669 std::string filepath(
670 "/tmp/images/" +
671 boost::uuids::to_string(boost::uuids::random_generator()()));
672 BMCWEB_LOG_DEBUG << "Writing file to " << filepath;
673 std::ofstream out(filepath, std::ofstream::out | std::ofstream::binary |
674 std::ofstream::trunc);
675 out << req.body;
676 out.close();
677 BMCWEB_LOG_DEBUG << "file upload complete!!";
678 }
Jennifer Lee729dae72018-04-24 15:59:34 -0700679};
Ed Tanousc711bf82018-07-30 16:31:33 -0700680
Ed Tanous1abe55e2018-09-05 08:30:59 -0700681class SoftwareInventoryCollection : public Node
682{
683 public:
Ed Tanous52cc1122020-07-18 13:51:21 -0700684 SoftwareInventoryCollection(App& app) :
Ed Tanous1abe55e2018-09-05 08:30:59 -0700685 Node(app, "/redfish/v1/UpdateService/FirmwareInventory/")
686 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700687 entityPrivileges = {
688 {boost::beast::http::verb::get, {{"Login"}}},
689 {boost::beast::http::verb::head, {{"Login"}}},
690 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
691 {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
692 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
693 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
Jennifer Lee729dae72018-04-24 15:59:34 -0700694 }
Jennifer Lee729dae72018-04-24 15:59:34 -0700695
Ed Tanous1abe55e2018-09-05 08:30:59 -0700696 private:
Ed Tanouscb13a392020-07-25 19:02:03 +0000697 void doGet(crow::Response& res, const crow::Request&,
698 const std::vector<std::string>&) override
Ed Tanous1abe55e2018-09-05 08:30:59 -0700699 {
700 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
Ed Tanous0f74e642018-11-12 15:17:05 -0800701 res.jsonValue["@odata.type"] =
702 "#SoftwareInventoryCollection.SoftwareInventoryCollection";
703 res.jsonValue["@odata.id"] =
704 "/redfish/v1/UpdateService/FirmwareInventory";
Ed Tanous0f74e642018-11-12 15:17:05 -0800705 res.jsonValue["Name"] = "Software Inventory Collection";
Ed Tanousc711bf82018-07-30 16:31:33 -0700706
Ed Tanous1abe55e2018-09-05 08:30:59 -0700707 crow::connections::systemBus->async_method_call(
708 [asyncResp](
709 const boost::system::error_code ec,
710 const std::vector<std::pair<
711 std::string, std::vector<std::pair<
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500712 std::string, std::vector<std::string>>>>>&
713 subtree) {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700714 if (ec)
715 {
Jason M. Billsf12894f2018-10-09 12:45:45 -0700716 messages::internalError(asyncResp->res);
Ed Tanousc711bf82018-07-30 16:31:33 -0700717 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700718 }
719 asyncResp->res.jsonValue["Members"] = nlohmann::json::array();
720 asyncResp->res.jsonValue["Members@odata.count"] = 0;
Jennifer Lee6c4eb9d2018-05-22 10:58:31 -0700721
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500722 for (auto& obj : subtree)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700723 {
Jennifer Leef4b65ab2018-09-18 12:00:13 -0700724 // if can't parse fw id then return
Ed Tanous27826b52018-10-29 11:40:58 -0700725 std::size_t idPos;
Ed Tanousf23b7292020-10-15 09:41:17 -0700726 if ((idPos = obj.first.rfind('/')) == std::string::npos)
Jennifer Leef4b65ab2018-09-18 12:00:13 -0700727 {
Jason M. Billsf12894f2018-10-09 12:45:45 -0700728 messages::internalError(asyncResp->res);
Jennifer Leef4b65ab2018-09-18 12:00:13 -0700729 BMCWEB_LOG_DEBUG << "Can't parse firmware ID!!";
730 return;
731 }
Jennifer Leef4b65ab2018-09-18 12:00:13 -0700732 std::string swId = obj.first.substr(idPos + 1);
733
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500734 nlohmann::json& members =
Andrew Geisslere0dd8052019-06-18 16:05:10 -0500735 asyncResp->res.jsonValue["Members"];
736 members.push_back(
737 {{"@odata.id", "/redfish/v1/UpdateService/"
738 "FirmwareInventory/" +
739 swId}});
740 asyncResp->res.jsonValue["Members@odata.count"] =
741 members.size();
Ed Tanous1abe55e2018-09-05 08:30:59 -0700742 }
743 },
Andrew Geissler2830a9c2020-01-06 10:18:11 -0600744 // Note that only firmware levels associated with a device are
745 // stored under /xyz/openbmc_project/software therefore to ensure
746 // only real FirmwareInventory items are returned, this full object
747 // path must be used here as input to mapper
Ed Tanous1abe55e2018-09-05 08:30:59 -0700748 "xyz.openbmc_project.ObjectMapper",
749 "/xyz/openbmc_project/object_mapper",
Andrew Geissler2830a9c2020-01-06 10:18:11 -0600750 "xyz.openbmc_project.ObjectMapper", "GetSubTree",
751 "/xyz/openbmc_project/software", static_cast<int32_t>(0),
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500752 std::array<const char*, 1>{"xyz.openbmc_project.Software.Version"});
Ed Tanous1abe55e2018-09-05 08:30:59 -0700753 }
Jennifer Lee729dae72018-04-24 15:59:34 -0700754};
755
Ed Tanous1abe55e2018-09-05 08:30:59 -0700756class SoftwareInventory : public Node
757{
758 public:
Ed Tanous52cc1122020-07-18 13:51:21 -0700759 SoftwareInventory(App& app) :
Ed Tanous1abe55e2018-09-05 08:30:59 -0700760 Node(app, "/redfish/v1/UpdateService/FirmwareInventory/<str>/",
761 std::string())
762 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700763 entityPrivileges = {
764 {boost::beast::http::verb::get, {{"Login"}}},
765 {boost::beast::http::verb::head, {{"Login"}}},
766 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
767 {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
768 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
769 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
770 }
771
772 private:
Andrew Geissler87d84722019-02-28 14:28:39 -0600773 /* Fill related item links (i.e. bmc, bios) in for inventory */
Ed Tanousb5a76932020-09-29 16:16:58 -0700774 static void getRelatedItems(const std::shared_ptr<AsyncResp>& aResp,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500775 const std::string& purpose)
Andrew Geissler87d84722019-02-28 14:28:39 -0600776 {
777 if (purpose == fw_util::bmcPurpose)
778 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500779 nlohmann::json& members = aResp->res.jsonValue["RelatedItem"];
Andrew Geissler87d84722019-02-28 14:28:39 -0600780 members.push_back({{"@odata.id", "/redfish/v1/Managers/bmc"}});
781 aResp->res.jsonValue["Members@odata.count"] = members.size();
782 }
783 else if (purpose == fw_util::biosPurpose)
784 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500785 nlohmann::json& members = aResp->res.jsonValue["RelatedItem"];
Gunnar Millsf723d732020-02-26 11:20:49 -0600786 members.push_back(
787 {{"@odata.id", "/redfish/v1/Systems/system/Bios"}});
788 aResp->res.jsonValue["Members@odata.count"] = members.size();
Andrew Geissler87d84722019-02-28 14:28:39 -0600789 }
790 else
791 {
792 BMCWEB_LOG_ERROR << "Unknown software purpose " << purpose;
793 }
794 }
795
Ed Tanouscb13a392020-07-25 19:02:03 +0000796 void doGet(crow::Response& res, const crow::Request&,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500797 const std::vector<std::string>& params) override
Ed Tanous1abe55e2018-09-05 08:30:59 -0700798 {
799 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700800
801 if (params.size() != 1)
802 {
Jason M. Billsf12894f2018-10-09 12:45:45 -0700803 messages::internalError(res);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700804 res.end();
805 return;
806 }
807
Ed Tanous3ae837c2018-08-07 14:41:19 -0700808 std::shared_ptr<std::string> swId =
Ed Tanous1abe55e2018-09-05 08:30:59 -0700809 std::make_shared<std::string>(params[0]);
810
811 res.jsonValue["@odata.id"] =
Ed Tanous3ae837c2018-08-07 14:41:19 -0700812 "/redfish/v1/UpdateService/FirmwareInventory/" + *swId;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700813
814 crow::connections::systemBus->async_method_call(
Ed Tanous3ae837c2018-08-07 14:41:19 -0700815 [asyncResp, swId](
Ed Tanous1abe55e2018-09-05 08:30:59 -0700816 const boost::system::error_code ec,
817 const std::vector<std::pair<
818 std::string, std::vector<std::pair<
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500819 std::string, std::vector<std::string>>>>>&
820 subtree) {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700821 BMCWEB_LOG_DEBUG << "doGet callback...";
822 if (ec)
823 {
Jason M. Billsf12894f2018-10-09 12:45:45 -0700824 messages::internalError(asyncResp->res);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700825 return;
826 }
827
Andrew Geissler69132282019-07-01 11:00:35 -0500828 // Ensure we find our input swId, otherwise return an error
829 bool found = false;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700830 for (const std::pair<
831 std::string,
832 std::vector<
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500833 std::pair<std::string, std::vector<std::string>>>>&
834 obj : subtree)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700835 {
Ed Tanous3ae837c2018-08-07 14:41:19 -0700836 if (boost::ends_with(obj.first, *swId) != true)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700837 {
838 continue;
839 }
840
Jennifer Leef4b65ab2018-09-18 12:00:13 -0700841 if (obj.second.size() < 1)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700842 {
843 continue;
844 }
845
Andrew Geissler69132282019-07-01 11:00:35 -0500846 found = true;
Andrew Geisslere0dd8052019-06-18 16:05:10 -0500847 fw_util::getFwStatus(asyncResp, swId, obj.second[0].first);
848
Ed Tanous1abe55e2018-09-05 08:30:59 -0700849 crow::connections::systemBus->async_method_call(
850 [asyncResp,
Ed Tanous3ae837c2018-08-07 14:41:19 -0700851 swId](const boost::system::error_code error_code,
852 const boost::container::flat_map<
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500853 std::string, VariantType>& propertiesList) {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700854 if (error_code)
855 {
Jason M. Billsf12894f2018-10-09 12:45:45 -0700856 messages::internalError(asyncResp->res);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700857 return;
858 }
859 boost::container::flat_map<
860 std::string, VariantType>::const_iterator it =
861 propertiesList.find("Purpose");
862 if (it == propertiesList.end())
863 {
864 BMCWEB_LOG_DEBUG
865 << "Can't find property \"Purpose\"!";
Jason M. Billsf12894f2018-10-09 12:45:45 -0700866 messages::propertyMissing(asyncResp->res,
867 "Purpose");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700868 return;
869 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500870 const std::string* swInvPurpose =
Ed Tanousabf2add2019-01-22 16:40:12 -0800871 std::get_if<std::string>(&it->second);
Ed Tanous3ae837c2018-08-07 14:41:19 -0700872 if (swInvPurpose == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700873 {
874 BMCWEB_LOG_DEBUG
875 << "wrong types for property\"Purpose\"!";
Jason M. Billsf12894f2018-10-09 12:45:45 -0700876 messages::propertyValueTypeError(asyncResp->res,
877 "", "Purpose");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700878 return;
879 }
880
Ed Tanous3ae837c2018-08-07 14:41:19 -0700881 BMCWEB_LOG_DEBUG << "swInvPurpose = "
882 << *swInvPurpose;
Jennifer Leef4b65ab2018-09-18 12:00:13 -0700883 it = propertiesList.find("Version");
884 if (it == propertiesList.end())
Ed Tanous1abe55e2018-09-05 08:30:59 -0700885 {
Jennifer Leef4b65ab2018-09-18 12:00:13 -0700886 BMCWEB_LOG_DEBUG
887 << "Can't find property \"Version\"!";
Jason M. Billsf12894f2018-10-09 12:45:45 -0700888 messages::propertyMissing(asyncResp->res,
889 "Version");
Jennifer Leef4b65ab2018-09-18 12:00:13 -0700890 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700891 }
Jennifer Leef4b65ab2018-09-18 12:00:13 -0700892
893 BMCWEB_LOG_DEBUG << "Version found!";
894
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500895 const std::string* version =
Ed Tanousabf2add2019-01-22 16:40:12 -0800896 std::get_if<std::string>(&it->second);
Jennifer Leef4b65ab2018-09-18 12:00:13 -0700897
898 if (version == nullptr)
899 {
900 BMCWEB_LOG_DEBUG
901 << "Can't find property \"Version\"!";
Jason M. Billsf12894f2018-10-09 12:45:45 -0700902
903 messages::propertyValueTypeError(asyncResp->res,
904 "", "Version");
Jennifer Leef4b65ab2018-09-18 12:00:13 -0700905 return;
906 }
907 asyncResp->res.jsonValue["Version"] = *version;
908 asyncResp->res.jsonValue["Id"] = *swId;
Andrew Geissler54daabe2019-02-13 13:54:15 -0600909
910 // swInvPurpose is of format:
911 // xyz.openbmc_project.Software.Version.VersionPurpose.ABC
James Feiste2e96772019-10-03 10:51:43 -0700912 // Translate this to "ABC image"
Ed Tanousf23b7292020-10-15 09:41:17 -0700913 size_t endDesc = swInvPurpose->rfind('.');
Andrew Geissler54daabe2019-02-13 13:54:15 -0600914 if (endDesc == std::string::npos)
915 {
916 messages::internalError(asyncResp->res);
917 return;
918 }
919 endDesc++;
920 if (endDesc >= swInvPurpose->size())
921 {
922 messages::internalError(asyncResp->res);
923 return;
924 }
925
926 std::string formatDesc =
927 swInvPurpose->substr(endDesc);
928 asyncResp->res.jsonValue["Description"] =
James Feiste2e96772019-10-03 10:51:43 -0700929 formatDesc + " image";
Andrew Geissler87d84722019-02-28 14:28:39 -0600930 getRelatedItems(asyncResp, *swInvPurpose);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700931 },
932 obj.second[0].first, obj.first,
933 "org.freedesktop.DBus.Properties", "GetAll",
934 "xyz.openbmc_project.Software.Version");
935 }
Andrew Geissler69132282019-07-01 11:00:35 -0500936 if (!found)
937 {
938 BMCWEB_LOG_ERROR << "Input swID " + *swId + " not found!";
939 messages::resourceMissingAtURI(
940 asyncResp->res,
941 "/redfish/v1/UpdateService/FirmwareInventory/" + *swId);
942 return;
943 }
Ayushi Smriti4e68c452019-09-04 14:37:55 +0530944 asyncResp->res.jsonValue["@odata.type"] =
945 "#SoftwareInventory.v1_1_0.SoftwareInventory";
Ayushi Smriti4e68c452019-09-04 14:37:55 +0530946 asyncResp->res.jsonValue["Name"] = "Software Inventory";
Ayushi Smriti4e68c452019-09-04 14:37:55 +0530947 asyncResp->res.jsonValue["Status"]["HealthRollup"] = "OK";
AppaRao Puli3f8a7432020-01-29 02:36:32 +0530948
949 asyncResp->res.jsonValue["Updateable"] = false;
950 fw_util::getFwUpdateableStatus(asyncResp, swId);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700951 },
952 "xyz.openbmc_project.ObjectMapper",
953 "/xyz/openbmc_project/object_mapper",
Ed Tanous271584a2019-07-09 16:24:22 -0700954 "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/",
955 static_cast<int32_t>(0),
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500956 std::array<const char*, 1>{"xyz.openbmc_project.Software.Version"});
Ed Tanous1abe55e2018-09-05 08:30:59 -0700957 }
958};
959
960} // namespace redfish