blob: e3e6bbb2bd1a72b9e409a6f6843ac863bc4f6325 [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
Andrew Geissler86adcd62019-04-18 10:58:05 -050063static void softwareInterfaceAdded(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 {
83 // Found our interface, disable callbacks
84 fwUpdateMatcher = nullptr;
85
86 // Retrieve service and activate
87 crow::connections::systemBus->async_method_call(
James Feistfe306722020-03-12 16:32:08 -070088 [objPath, asyncResp,
89 req](const boost::system::error_code error_code,
90 const std::vector<std::pair<
Gunnar Mills1214b7e2020-06-04 10:11:30 -050091 std::string, std::vector<std::string>>>& objInfo) {
Andrew Geissler86adcd62019-04-18 10:58:05 -050092 if (error_code)
93 {
94 BMCWEB_LOG_DEBUG << "error_code = " << error_code;
95 BMCWEB_LOG_DEBUG << "error msg = "
96 << error_code.message();
Andrew Geissler0554c982019-04-23 14:40:12 -050097 if (asyncResp)
98 {
99 messages::internalError(asyncResp->res);
100 }
Andrew Geissler86adcd62019-04-18 10:58:05 -0500101 cleanUp();
102 return;
103 }
104 // Ensure we only got one service back
105 if (objInfo.size() != 1)
106 {
107 BMCWEB_LOG_ERROR << "Invalid Object Size "
108 << objInfo.size();
Andrew Geissler0554c982019-04-23 14:40:12 -0500109 if (asyncResp)
110 {
111 messages::internalError(asyncResp->res);
112 }
Andrew Geissler86adcd62019-04-18 10:58:05 -0500113 cleanUp();
114 return;
115 }
116 // cancel timer only when
117 // xyz.openbmc_project.Software.Activation interface
118 // is added
119 fwAvailableTimer = nullptr;
120
121 activateImage(objPath.str, objInfo[0].first);
Andrew Geissler0554c982019-04-23 14:40:12 -0500122 if (asyncResp)
123 {
James Feist32898ce2020-03-10 16:16:52 -0700124 std::shared_ptr<task::TaskData> task =
125 task::TaskData::createTask(
126 [](boost::system::error_code ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500127 sdbusplus::message::message& msg,
128 const std::shared_ptr<task::TaskData>&
129 taskData) {
James Feist32898ce2020-03-10 16:16:52 -0700130 if (ec)
131 {
132 return task::completed;
133 }
134
135 std::string iface;
136 boost::container::flat_map<
James Feistfd9ab9e2020-05-19 13:48:07 -0700137 std::string,
138 std::variant<std::string, uint8_t>>
James Feist32898ce2020-03-10 16:16:52 -0700139 values;
James Feist32898ce2020-03-10 16:16:52 -0700140
James Feiste5d50062020-05-11 17:29:00 -0700141 std::string index =
142 std::to_string(taskData->index);
James Feistfd9ab9e2020-05-19 13:48:07 -0700143 msg.read(iface, values);
James Feiste5d50062020-05-11 17:29:00 -0700144
James Feistfd9ab9e2020-05-19 13:48:07 -0700145 if (iface == "xyz.openbmc_project.Software."
146 "Activation")
James Feist32898ce2020-03-10 16:16:52 -0700147 {
James Feistfd9ab9e2020-05-19 13:48:07 -0700148 auto findActivation =
149 values.find("Activation");
150 if (findActivation == values.end())
151 {
152 return !task::completed;
153 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500154 std::string* state =
James Feistfd9ab9e2020-05-19 13:48:07 -0700155 std::get_if<std::string>(
156 &(findActivation->second));
157
158 if (state == nullptr)
159 {
160 taskData->messages.emplace_back(
161 messages::internalError());
162 return task::completed;
163 }
164
165 if (boost::ends_with(*state,
166 "Invalid") ||
167 boost::ends_with(*state, "Failed"))
168 {
169 taskData->state = "Exception";
170 taskData->status = "Warning";
171 taskData->messages.emplace_back(
172 messages::taskAborted(index));
173 return task::completed;
174 }
175
176 if (boost::ends_with(*state, "Staged"))
177 {
178 taskData->state = "Stopping";
179 taskData->messages.emplace_back(
180 messages::taskPaused(index));
181
182 // its staged, set a long timer to
183 // allow them time to complete the
184 // update (probably cycle the
185 // system) if this expires then
186 // task will be cancelled
187 taskData->extendTimer(
188 std::chrono::hours(5));
189 return !task::completed;
190 }
191
192 if (boost::ends_with(*state, "Active"))
193 {
194 taskData->messages.emplace_back(
195 messages::taskCompletedOK(
196 index));
197 taskData->state = "Completed";
198 return task::completed;
199 }
James Feist32898ce2020-03-10 16:16:52 -0700200 }
James Feistfd9ab9e2020-05-19 13:48:07 -0700201 else if (iface ==
202 "xyz.openbmc_project.Software."
203 "ActivationProgress")
James Feist32898ce2020-03-10 16:16:52 -0700204 {
James Feistfd9ab9e2020-05-19 13:48:07 -0700205 auto findProgress =
206 values.find("Progress");
207 if (findProgress == values.end())
208 {
209 return !task::completed;
210 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500211 uint8_t* progress =
James Feistfd9ab9e2020-05-19 13:48:07 -0700212 std::get_if<uint8_t>(
213 &(findProgress->second));
James Feist32898ce2020-03-10 16:16:52 -0700214
James Feistfd9ab9e2020-05-19 13:48:07 -0700215 if (progress == nullptr)
216 {
217 taskData->messages.emplace_back(
218 messages::internalError());
219 return task::completed;
220 }
James Feist32898ce2020-03-10 16:16:52 -0700221 taskData->messages.emplace_back(
James Feistfd9ab9e2020-05-19 13:48:07 -0700222 messages::taskProgressChanged(
223 index, static_cast<size_t>(
224 *progress)));
225
226 // if we're getting status updates it's
227 // still alive, update timer
228 taskData->extendTimer(
229 std::chrono::minutes(5));
James Feist32898ce2020-03-10 16:16:52 -0700230 }
231
232 // as firmware update often results in a
233 // reboot, the task may never "complete"
234 // unless it is an error
235
236 return !task::completed;
237 },
238 "type='signal',interface='org.freedesktop.DBus."
239 "Properties',"
James Feistfd9ab9e2020-05-19 13:48:07 -0700240 "member='PropertiesChanged',path='" +
James Feist32898ce2020-03-10 16:16:52 -0700241 objPath.str + "'");
242 task->startTimer(std::chrono::minutes(5));
243 task->populateResp(asyncResp->res);
James Feistfe306722020-03-12 16:32:08 -0700244 task->payload.emplace(req);
Andrew Geissler0554c982019-04-23 14:40:12 -0500245 }
Andrew Geissler86adcd62019-04-18 10:58:05 -0500246 fwUpdateInProgress = false;
247 },
248 "xyz.openbmc_project.ObjectMapper",
249 "/xyz/openbmc_project/object_mapper",
250 "xyz.openbmc_project.ObjectMapper", "GetObject", objPath.str,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500251 std::array<const char*, 1>{
Andrew Geissler86adcd62019-04-18 10:58:05 -0500252 "xyz.openbmc_project.Software.Activation"});
253 }
254 }
255}
256
Andrew Geissler0554c982019-04-23 14:40:12 -0500257// Note that asyncResp can be either a valid pointer or nullptr. If nullptr
258// then no asyncResp updates will occur
Andrew Geissler86adcd62019-04-18 10:58:05 -0500259static void monitorForSoftwareAvailable(std::shared_ptr<AsyncResp> asyncResp,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500260 const crow::Request& req,
James Feist4cde5d92020-06-11 10:39:55 -0700261 const std::string& url,
Chalapathi Venkataramashetty3cb3b112020-08-19 19:50:30 +0000262 int timeoutTimeSeconds = 10)
Andrew Geissler86adcd62019-04-18 10:58:05 -0500263{
264 // Only allow one FW update at a time
265 if (fwUpdateInProgress != false)
266 {
Andrew Geissler0554c982019-04-23 14:40:12 -0500267 if (asyncResp)
268 {
Andrew Geissler0554c982019-04-23 14:40:12 -0500269 messages::serviceTemporarilyUnavailable(asyncResp->res, "30");
270 }
Andrew Geissler86adcd62019-04-18 10:58:05 -0500271 return;
272 }
273
Andrew Geissler0554c982019-04-23 14:40:12 -0500274 fwAvailableTimer =
Ed Tanous271584a2019-07-09 16:24:22 -0700275 std::make_unique<boost::asio::steady_timer>(*req.ioService);
Andrew Geissler86adcd62019-04-18 10:58:05 -0500276
Ed Tanous271584a2019-07-09 16:24:22 -0700277 fwAvailableTimer->expires_after(std::chrono::seconds(timeoutTimeSeconds));
Andrew Geissler86adcd62019-04-18 10:58:05 -0500278
279 fwAvailableTimer->async_wait(
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500280 [asyncResp](const boost::system::error_code& ec) {
Andrew Geissler86adcd62019-04-18 10:58:05 -0500281 cleanUp();
282 if (ec == boost::asio::error::operation_aborted)
283 {
284 // expected, we were canceled before the timer completed.
285 return;
286 }
287 BMCWEB_LOG_ERROR
288 << "Timed out waiting for firmware object being created";
289 BMCWEB_LOG_ERROR
290 << "FW image may has already been uploaded to server";
291 if (ec)
292 {
293 BMCWEB_LOG_ERROR << "Async_wait failed" << ec;
294 return;
295 }
Andrew Geissler0554c982019-04-23 14:40:12 -0500296 if (asyncResp)
297 {
298 redfish::messages::internalError(asyncResp->res);
299 }
Andrew Geissler86adcd62019-04-18 10:58:05 -0500300 });
301
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500302 auto callback = [asyncResp, req](sdbusplus::message::message& m) {
Andrew Geissler86adcd62019-04-18 10:58:05 -0500303 BMCWEB_LOG_DEBUG << "Match fired";
James Feistfe306722020-03-12 16:32:08 -0700304 softwareInterfaceAdded(asyncResp, m, req);
Andrew Geissler86adcd62019-04-18 10:58:05 -0500305 };
306
307 fwUpdateInProgress = true;
308
309 fwUpdateMatcher = std::make_unique<sdbusplus::bus::match::match>(
310 *crow::connections::systemBus,
311 "interface='org.freedesktop.DBus.ObjectManager',type='signal',"
312 "member='InterfacesAdded',path='/xyz/openbmc_project/software'",
313 callback);
James Feist4cde5d92020-06-11 10:39:55 -0700314
315 fwUpdateErrorMatcher = std::make_unique<sdbusplus::bus::match::match>(
316 *crow::connections::systemBus,
317 "type='signal',member='PropertiesChanged',path_namespace='/xyz/"
318 "openbmc_project/logging/entry',"
319 "arg0='xyz.openbmc_project.Logging.Entry'",
320 [asyncResp, url](sdbusplus::message::message& m) {
321 BMCWEB_LOG_DEBUG << "Error Match fired";
322 boost::container::flat_map<std::string, std::variant<std::string>>
323 values;
324 std::string objName;
325 m.read(objName, values);
326 auto find = values.find("Message");
327 if (find == values.end())
328 {
329 return;
330 }
331 std::string* type = std::get_if<std::string>(&(find->second));
332 if (type == nullptr)
333 {
334 return; // if this was our message, timeout will cover it
335 }
336 if (!boost::starts_with(*type,
337 "xyz.openbmc_project.Software.Image.Error"))
338 {
339 return;
340 }
341 if (*type ==
342 "xyz.openbmc_project.Software.Image.Error.UnTarFailure")
343 {
344 redfish::messages::invalidUpload(asyncResp->res, url,
345 "Invalid archive");
346 }
347 else if (*type == "xyz.openbmc_project.Software.Image.Error."
348 "ManifestFileFailure")
349 {
350 redfish::messages::invalidUpload(asyncResp->res, url,
351 "Invalid manifest");
352 }
353 else if (*type ==
354 "xyz.openbmc_project.Software.Image.Error.ImageFailure")
355 {
356 redfish::messages::invalidUpload(asyncResp->res, url,
357 "Invalid image format");
358 }
359 else if (*type ==
360 "xyz.openbmc_project.Software.Image.Error.BusyFailure")
361 {
362 redfish::messages::resourceExhaustion(asyncResp->res, url);
363 }
364 else
365 {
366 redfish::messages::internalError(asyncResp->res);
367 }
368 fwAvailableTimer = nullptr;
369 });
Andrew Geissler86adcd62019-04-18 10:58:05 -0500370}
Jennifer Lee729dae72018-04-24 15:59:34 -0700371
Andrew Geissler0554c982019-04-23 14:40:12 -0500372/**
373 * UpdateServiceActionsSimpleUpdate class supports handle POST method for
374 * SimpleUpdate action.
375 */
376class UpdateServiceActionsSimpleUpdate : public Node
377{
378 public:
Ed Tanous52cc1122020-07-18 13:51:21 -0700379 UpdateServiceActionsSimpleUpdate(App& app) :
Andrew Geissler0554c982019-04-23 14:40:12 -0500380 Node(app,
381 "/redfish/v1/UpdateService/Actions/UpdateService.SimpleUpdate/")
382 {
383 entityPrivileges = {
384 {boost::beast::http::verb::get, {{"Login"}}},
385 {boost::beast::http::verb::head, {{"Login"}}},
386 {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
387 {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
388 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
389 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
390 }
391
392 private:
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500393 void doPost(crow::Response& res, const crow::Request& req,
Ed Tanouscb13a392020-07-25 19:02:03 +0000394 const std::vector<std::string>&) override
Andrew Geissler0554c982019-04-23 14:40:12 -0500395 {
396 std::optional<std::string> transferProtocol;
397 std::string imageURI;
398 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
399
400 BMCWEB_LOG_DEBUG << "Enter UpdateService.SimpleUpdate doPost";
401
402 // User can pass in both TransferProtocol and ImageURI parameters or
Gunnar Mills4e0453b2020-07-08 14:00:30 -0500403 // they can pass in just the ImageURI with the transfer protocol
404 // embedded within it.
Andrew Geissler0554c982019-04-23 14:40:12 -0500405 // 1) TransferProtocol:TFTP ImageURI:1.1.1.1/myfile.bin
406 // 2) ImageURI:tftp://1.1.1.1/myfile.bin
407
408 if (!json_util::readJson(req, asyncResp->res, "TransferProtocol",
409 transferProtocol, "ImageURI", imageURI))
410 {
411 BMCWEB_LOG_DEBUG
412 << "Missing TransferProtocol or ImageURI parameter";
413 return;
414 }
415 if (!transferProtocol)
416 {
417 // Must be option 2
418 // Verify ImageURI has transfer protocol in it
419 size_t separator = imageURI.find(":");
420 if ((separator == std::string::npos) ||
421 ((separator + 1) > imageURI.size()))
422 {
423 messages::actionParameterValueTypeError(
424 asyncResp->res, imageURI, "ImageURI",
425 "UpdateService.SimpleUpdate");
426 BMCWEB_LOG_ERROR << "ImageURI missing transfer protocol: "
427 << imageURI;
428 return;
429 }
430 transferProtocol = imageURI.substr(0, separator);
431 // Ensure protocol is upper case for a common comparison path below
432 boost::to_upper(*transferProtocol);
433 BMCWEB_LOG_DEBUG << "Encoded transfer protocol "
434 << *transferProtocol;
435
436 // Adjust imageURI to not have the protocol on it for parsing
437 // below
438 // ex. tftp://1.1.1.1/myfile.bin -> 1.1.1.1/myfile.bin
439 imageURI = imageURI.substr(separator + 3);
440 BMCWEB_LOG_DEBUG << "Adjusted imageUri " << imageURI;
441 }
442
443 // OpenBMC currently only supports TFTP
444 if (*transferProtocol != "TFTP")
445 {
446 messages::actionParameterNotSupported(asyncResp->res,
447 "TransferProtocol",
448 "UpdateService.SimpleUpdate");
449 BMCWEB_LOG_ERROR << "Request incorrect protocol parameter: "
450 << *transferProtocol;
451 return;
452 }
453
454 // Format should be <IP or Hostname>/<file> for imageURI
455 size_t separator = imageURI.find("/");
456 if ((separator == std::string::npos) ||
457 ((separator + 1) > imageURI.size()))
458 {
459 messages::actionParameterValueTypeError(
460 asyncResp->res, imageURI, "ImageURI",
461 "UpdateService.SimpleUpdate");
462 BMCWEB_LOG_ERROR << "Invalid ImageURI: " << imageURI;
463 return;
464 }
465
466 std::string tftpServer = imageURI.substr(0, separator);
467 std::string fwFile = imageURI.substr(separator + 1);
468 BMCWEB_LOG_DEBUG << "Server: " << tftpServer + " File: " << fwFile;
469
470 // Setup callback for when new software detected
Gunnar Mills2618d5e2020-08-18 13:04:27 -0500471 // Give TFTP 10 minutes to complete
James Feist4cde5d92020-06-11 10:39:55 -0700472 monitorForSoftwareAvailable(
473 nullptr, req,
474 "/redfish/v1/UpdateService/Actions/UpdateService.SimpleUpdate",
Gunnar Mills2618d5e2020-08-18 13:04:27 -0500475 600);
Andrew Geissler0554c982019-04-23 14:40:12 -0500476
Gunnar Mills2618d5e2020-08-18 13:04:27 -0500477 // TFTP can take up to 10 minutes depending on image size and
Andrew Geissler0554c982019-04-23 14:40:12 -0500478 // connection speed. Return to caller as soon as the TFTP operation
479 // has been started. The callback above will ensure the activate
480 // is started once the download has completed
481 redfish::messages::success(asyncResp->res);
482
483 // Call TFTP service
484 crow::connections::systemBus->async_method_call(
485 [](const boost::system::error_code ec) {
486 if (ec)
487 {
488 // messages::internalError(asyncResp->res);
489 cleanUp();
490 BMCWEB_LOG_DEBUG << "error_code = " << ec;
491 BMCWEB_LOG_DEBUG << "error msg = " << ec.message();
492 }
493 else
494 {
495 BMCWEB_LOG_DEBUG << "Call to DownloaViaTFTP Success";
496 }
497 },
498 "xyz.openbmc_project.Software.Download",
499 "/xyz/openbmc_project/software", "xyz.openbmc_project.Common.TFTP",
500 "DownloadViaTFTP", fwFile, tftpServer);
501
502 BMCWEB_LOG_DEBUG << "Exit UpdateService.SimpleUpdate doPost";
503 }
504};
505
Ed Tanous1abe55e2018-09-05 08:30:59 -0700506class UpdateService : public Node
507{
508 public:
Ed Tanous52cc1122020-07-18 13:51:21 -0700509 UpdateService(App& app) : Node(app, "/redfish/v1/UpdateService/")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700510 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700511 entityPrivileges = {
512 {boost::beast::http::verb::get, {{"Login"}}},
513 {boost::beast::http::verb::head, {{"Login"}}},
514 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
515 {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
516 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
517 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
Jennifer Leeacb7cfb2018-06-07 16:08:15 -0700518 }
Jennifer Leeacb7cfb2018-06-07 16:08:15 -0700519
Ed Tanous1abe55e2018-09-05 08:30:59 -0700520 private:
Ed Tanouscb13a392020-07-25 19:02:03 +0000521 void doGet(crow::Response& res, const crow::Request&,
522 const std::vector<std::string>&) override
Ed Tanous1abe55e2018-09-05 08:30:59 -0700523 {
Jayashankar Padath274dfe62019-08-23 12:30:57 +0530524 std::shared_ptr<AsyncResp> aResp = std::make_shared<AsyncResp>(res);
525 res.jsonValue["@odata.type"] = "#UpdateService.v1_4_0.UpdateService";
Ed Tanous0f74e642018-11-12 15:17:05 -0800526 res.jsonValue["@odata.id"] = "/redfish/v1/UpdateService";
Ed Tanous0f74e642018-11-12 15:17:05 -0800527 res.jsonValue["Id"] = "UpdateService";
528 res.jsonValue["Description"] = "Service for Software Update";
529 res.jsonValue["Name"] = "Update Service";
530 res.jsonValue["HttpPushUri"] = "/redfish/v1/UpdateService";
531 // UpdateService cannot be disabled
532 res.jsonValue["ServiceEnabled"] = true;
533 res.jsonValue["FirmwareInventory"] = {
534 {"@odata.id", "/redfish/v1/UpdateService/FirmwareInventory"}};
Andrew Geissler0554c982019-04-23 14:40:12 -0500535#ifdef BMCWEB_INSECURE_ENABLE_REDFISH_FW_TFTP_UPDATE
536 // Update Actions object.
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500537 nlohmann::json& updateSvcSimpleUpdate =
Andrew Geissler0554c982019-04-23 14:40:12 -0500538 res.jsonValue["Actions"]["#UpdateService.SimpleUpdate"];
539 updateSvcSimpleUpdate["target"] =
540 "/redfish/v1/UpdateService/Actions/UpdateService.SimpleUpdate";
541 updateSvcSimpleUpdate["TransferProtocol@Redfish.AllowableValues"] = {
542 "TFTP"};
543#endif
Jayashankar Padath274dfe62019-08-23 12:30:57 +0530544 // Get the current ApplyTime value
545 crow::connections::systemBus->async_method_call(
546 [aResp](const boost::system::error_code ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500547 const std::variant<std::string>& applyTime) {
Jayashankar Padath274dfe62019-08-23 12:30:57 +0530548 if (ec)
549 {
550 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
551 messages::internalError(aResp->res);
552 return;
553 }
554
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500555 const std::string* s = std::get_if<std::string>(&applyTime);
Jayashankar Padath274dfe62019-08-23 12:30:57 +0530556 if (s == nullptr)
557 {
558 return;
559 }
560 // Store the ApplyTime Value
561 if (*s == "xyz.openbmc_project.Software.ApplyTime."
562 "RequestedApplyTimes.Immediate")
563 {
564 aResp->res.jsonValue["HttpPushUriOptions"]
565 ["HttpPushUriApplyTime"]["ApplyTime"] =
566 "Immediate";
567 }
568 else if (*s == "xyz.openbmc_project.Software.ApplyTime."
569 "RequestedApplyTimes.OnReset")
570 {
571 aResp->res.jsonValue["HttpPushUriOptions"]
572 ["HttpPushUriApplyTime"]["ApplyTime"] =
573 "OnReset";
574 }
575 },
576 "xyz.openbmc_project.Settings",
577 "/xyz/openbmc_project/software/apply_time",
578 "org.freedesktop.DBus.Properties", "Get",
579 "xyz.openbmc_project.Software.ApplyTime", "RequestedApplyTime");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700580 }
Andrew Geissler0e7de462019-03-04 19:11:54 -0600581
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500582 void doPatch(crow::Response& res, const crow::Request& req,
Ed Tanouscb13a392020-07-25 19:02:03 +0000583 const std::vector<std::string>&) override
Jayashankar Padathfa1a5a32019-05-28 23:54:37 +0530584 {
585 BMCWEB_LOG_DEBUG << "doPatch...";
586
587 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
Jayashankar Padathfa1a5a32019-05-28 23:54:37 +0530588
Jayashankar Padath274dfe62019-08-23 12:30:57 +0530589 std::optional<nlohmann::json> pushUriOptions;
590 if (!json_util::readJson(req, res, "HttpPushUriOptions",
591 pushUriOptions))
Jayashankar Padathfa1a5a32019-05-28 23:54:37 +0530592 {
593 return;
594 }
595
Jayashankar Padath274dfe62019-08-23 12:30:57 +0530596 if (pushUriOptions)
Jayashankar Padathfa1a5a32019-05-28 23:54:37 +0530597 {
Jayashankar Padath274dfe62019-08-23 12:30:57 +0530598 std::optional<nlohmann::json> pushUriApplyTime;
599 if (!json_util::readJson(*pushUriOptions, res,
600 "HttpPushUriApplyTime", pushUriApplyTime))
Jayashankar Padathfa1a5a32019-05-28 23:54:37 +0530601 {
Jayashankar Padath274dfe62019-08-23 12:30:57 +0530602 return;
Jayashankar Padathfa1a5a32019-05-28 23:54:37 +0530603 }
604
Jayashankar Padath274dfe62019-08-23 12:30:57 +0530605 if (pushUriApplyTime)
606 {
607 std::optional<std::string> applyTime;
608 if (!json_util::readJson(*pushUriApplyTime, res, "ApplyTime",
609 applyTime))
610 {
611 return;
612 }
613
614 if (applyTime)
615 {
616 std::string applyTimeNewVal;
617 if (applyTime == "Immediate")
Jayashankar Padathfa1a5a32019-05-28 23:54:37 +0530618 {
Jayashankar Padath274dfe62019-08-23 12:30:57 +0530619 applyTimeNewVal =
620 "xyz.openbmc_project.Software.ApplyTime."
621 "RequestedApplyTimes.Immediate";
622 }
623 else if (applyTime == "OnReset")
624 {
625 applyTimeNewVal =
626 "xyz.openbmc_project.Software.ApplyTime."
627 "RequestedApplyTimes.OnReset";
628 }
629 else
630 {
631 BMCWEB_LOG_INFO
632 << "ApplyTime value is not in the list of "
633 "acceptable values";
634 messages::propertyValueNotInList(
635 asyncResp->res, *applyTime, "ApplyTime");
Jayashankar Padathfa1a5a32019-05-28 23:54:37 +0530636 return;
637 }
Jayashankar Padath274dfe62019-08-23 12:30:57 +0530638
639 // Set the requested image apply time value
640 crow::connections::systemBus->async_method_call(
641 [asyncResp](const boost::system::error_code ec) {
642 if (ec)
643 {
644 BMCWEB_LOG_ERROR << "D-Bus responses error: "
645 << ec;
646 messages::internalError(asyncResp->res);
647 return;
648 }
649 messages::success(asyncResp->res);
650 },
651 "xyz.openbmc_project.Settings",
652 "/xyz/openbmc_project/software/apply_time",
653 "org.freedesktop.DBus.Properties", "Set",
654 "xyz.openbmc_project.Software.ApplyTime",
655 "RequestedApplyTime",
656 std::variant<std::string>{applyTimeNewVal});
657 }
658 }
Jayashankar Padathfa1a5a32019-05-28 23:54:37 +0530659 }
660 }
661
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500662 void doPost(crow::Response& res, const crow::Request& req,
Ed Tanouscb13a392020-07-25 19:02:03 +0000663 const std::vector<std::string>&) override
Ed Tanous1abe55e2018-09-05 08:30:59 -0700664 {
665 BMCWEB_LOG_DEBUG << "doPost...";
Jennifer Leeacb7cfb2018-06-07 16:08:15 -0700666
Andrew Geissler0e7de462019-03-04 19:11:54 -0600667 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700668
Andrew Geissler86adcd62019-04-18 10:58:05 -0500669 // Setup callback for when new software detected
James Feist4cde5d92020-06-11 10:39:55 -0700670 monitorForSoftwareAvailable(asyncResp, req,
671 "/redfish/v1/UpdateService");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700672
673 std::string filepath(
674 "/tmp/images/" +
675 boost::uuids::to_string(boost::uuids::random_generator()()));
676 BMCWEB_LOG_DEBUG << "Writing file to " << filepath;
677 std::ofstream out(filepath, std::ofstream::out | std::ofstream::binary |
678 std::ofstream::trunc);
679 out << req.body;
680 out.close();
681 BMCWEB_LOG_DEBUG << "file upload complete!!";
682 }
Jennifer Lee729dae72018-04-24 15:59:34 -0700683};
Ed Tanousc711bf82018-07-30 16:31:33 -0700684
Ed Tanous1abe55e2018-09-05 08:30:59 -0700685class SoftwareInventoryCollection : public Node
686{
687 public:
Ed Tanous52cc1122020-07-18 13:51:21 -0700688 SoftwareInventoryCollection(App& app) :
Ed Tanous1abe55e2018-09-05 08:30:59 -0700689 Node(app, "/redfish/v1/UpdateService/FirmwareInventory/")
690 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700691 entityPrivileges = {
692 {boost::beast::http::verb::get, {{"Login"}}},
693 {boost::beast::http::verb::head, {{"Login"}}},
694 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
695 {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
696 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
697 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
Jennifer Lee729dae72018-04-24 15:59:34 -0700698 }
Jennifer Lee729dae72018-04-24 15:59:34 -0700699
Ed Tanous1abe55e2018-09-05 08:30:59 -0700700 private:
Ed Tanouscb13a392020-07-25 19:02:03 +0000701 void doGet(crow::Response& res, const crow::Request&,
702 const std::vector<std::string>&) override
Ed Tanous1abe55e2018-09-05 08:30:59 -0700703 {
704 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
Ed Tanous0f74e642018-11-12 15:17:05 -0800705 res.jsonValue["@odata.type"] =
706 "#SoftwareInventoryCollection.SoftwareInventoryCollection";
707 res.jsonValue["@odata.id"] =
708 "/redfish/v1/UpdateService/FirmwareInventory";
Ed Tanous0f74e642018-11-12 15:17:05 -0800709 res.jsonValue["Name"] = "Software Inventory Collection";
Ed Tanousc711bf82018-07-30 16:31:33 -0700710
Ed Tanous1abe55e2018-09-05 08:30:59 -0700711 crow::connections::systemBus->async_method_call(
712 [asyncResp](
713 const boost::system::error_code ec,
714 const std::vector<std::pair<
715 std::string, std::vector<std::pair<
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500716 std::string, std::vector<std::string>>>>>&
717 subtree) {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700718 if (ec)
719 {
Jason M. Billsf12894f2018-10-09 12:45:45 -0700720 messages::internalError(asyncResp->res);
Ed Tanousc711bf82018-07-30 16:31:33 -0700721 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700722 }
723 asyncResp->res.jsonValue["Members"] = nlohmann::json::array();
724 asyncResp->res.jsonValue["Members@odata.count"] = 0;
Jennifer Lee6c4eb9d2018-05-22 10:58:31 -0700725
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500726 for (auto& obj : subtree)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700727 {
Jennifer Leef4b65ab2018-09-18 12:00:13 -0700728 // if can't parse fw id then return
Ed Tanous27826b52018-10-29 11:40:58 -0700729 std::size_t idPos;
730 if ((idPos = obj.first.rfind("/")) == std::string::npos)
Jennifer Leef4b65ab2018-09-18 12:00:13 -0700731 {
Jason M. Billsf12894f2018-10-09 12:45:45 -0700732 messages::internalError(asyncResp->res);
Jennifer Leef4b65ab2018-09-18 12:00:13 -0700733 BMCWEB_LOG_DEBUG << "Can't parse firmware ID!!";
734 return;
735 }
Jennifer Leef4b65ab2018-09-18 12:00:13 -0700736 std::string swId = obj.first.substr(idPos + 1);
737
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500738 nlohmann::json& members =
Andrew Geisslere0dd8052019-06-18 16:05:10 -0500739 asyncResp->res.jsonValue["Members"];
740 members.push_back(
741 {{"@odata.id", "/redfish/v1/UpdateService/"
742 "FirmwareInventory/" +
743 swId}});
744 asyncResp->res.jsonValue["Members@odata.count"] =
745 members.size();
Ed Tanous1abe55e2018-09-05 08:30:59 -0700746 }
747 },
Andrew Geissler2830a9c2020-01-06 10:18:11 -0600748 // Note that only firmware levels associated with a device are
749 // stored under /xyz/openbmc_project/software therefore to ensure
750 // only real FirmwareInventory items are returned, this full object
751 // path must be used here as input to mapper
Ed Tanous1abe55e2018-09-05 08:30:59 -0700752 "xyz.openbmc_project.ObjectMapper",
753 "/xyz/openbmc_project/object_mapper",
Andrew Geissler2830a9c2020-01-06 10:18:11 -0600754 "xyz.openbmc_project.ObjectMapper", "GetSubTree",
755 "/xyz/openbmc_project/software", static_cast<int32_t>(0),
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500756 std::array<const char*, 1>{"xyz.openbmc_project.Software.Version"});
Ed Tanous1abe55e2018-09-05 08:30:59 -0700757 }
Jennifer Lee729dae72018-04-24 15:59:34 -0700758};
759
Ed Tanous1abe55e2018-09-05 08:30:59 -0700760class SoftwareInventory : public Node
761{
762 public:
Ed Tanous52cc1122020-07-18 13:51:21 -0700763 SoftwareInventory(App& app) :
Ed Tanous1abe55e2018-09-05 08:30:59 -0700764 Node(app, "/redfish/v1/UpdateService/FirmwareInventory/<str>/",
765 std::string())
766 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700767 entityPrivileges = {
768 {boost::beast::http::verb::get, {{"Login"}}},
769 {boost::beast::http::verb::head, {{"Login"}}},
770 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
771 {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
772 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
773 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
774 }
775
776 private:
Andrew Geissler87d84722019-02-28 14:28:39 -0600777 /* Fill related item links (i.e. bmc, bios) in for inventory */
778 static void getRelatedItems(std::shared_ptr<AsyncResp> aResp,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500779 const std::string& purpose)
Andrew Geissler87d84722019-02-28 14:28:39 -0600780 {
781 if (purpose == fw_util::bmcPurpose)
782 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500783 nlohmann::json& members = aResp->res.jsonValue["RelatedItem"];
Andrew Geissler87d84722019-02-28 14:28:39 -0600784 members.push_back({{"@odata.id", "/redfish/v1/Managers/bmc"}});
785 aResp->res.jsonValue["Members@odata.count"] = members.size();
786 }
787 else if (purpose == fw_util::biosPurpose)
788 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500789 nlohmann::json& members = aResp->res.jsonValue["RelatedItem"];
Gunnar Millsf723d732020-02-26 11:20:49 -0600790 members.push_back(
791 {{"@odata.id", "/redfish/v1/Systems/system/Bios"}});
792 aResp->res.jsonValue["Members@odata.count"] = members.size();
Andrew Geissler87d84722019-02-28 14:28:39 -0600793 }
794 else
795 {
796 BMCWEB_LOG_ERROR << "Unknown software purpose " << purpose;
797 }
798 }
799
Ed Tanouscb13a392020-07-25 19:02:03 +0000800 void doGet(crow::Response& res, const crow::Request&,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500801 const std::vector<std::string>& params) override
Ed Tanous1abe55e2018-09-05 08:30:59 -0700802 {
803 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700804
805 if (params.size() != 1)
806 {
Jason M. Billsf12894f2018-10-09 12:45:45 -0700807 messages::internalError(res);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700808 res.end();
809 return;
810 }
811
Ed Tanous3ae837c2018-08-07 14:41:19 -0700812 std::shared_ptr<std::string> swId =
Ed Tanous1abe55e2018-09-05 08:30:59 -0700813 std::make_shared<std::string>(params[0]);
814
815 res.jsonValue["@odata.id"] =
Ed Tanous3ae837c2018-08-07 14:41:19 -0700816 "/redfish/v1/UpdateService/FirmwareInventory/" + *swId;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700817
818 crow::connections::systemBus->async_method_call(
Ed Tanous3ae837c2018-08-07 14:41:19 -0700819 [asyncResp, swId](
Ed Tanous1abe55e2018-09-05 08:30:59 -0700820 const boost::system::error_code ec,
821 const std::vector<std::pair<
822 std::string, std::vector<std::pair<
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500823 std::string, std::vector<std::string>>>>>&
824 subtree) {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700825 BMCWEB_LOG_DEBUG << "doGet callback...";
826 if (ec)
827 {
Jason M. Billsf12894f2018-10-09 12:45:45 -0700828 messages::internalError(asyncResp->res);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700829 return;
830 }
831
Andrew Geissler69132282019-07-01 11:00:35 -0500832 // Ensure we find our input swId, otherwise return an error
833 bool found = false;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700834 for (const std::pair<
835 std::string,
836 std::vector<
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500837 std::pair<std::string, std::vector<std::string>>>>&
838 obj : subtree)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700839 {
Ed Tanous3ae837c2018-08-07 14:41:19 -0700840 if (boost::ends_with(obj.first, *swId) != true)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700841 {
842 continue;
843 }
844
Jennifer Leef4b65ab2018-09-18 12:00:13 -0700845 if (obj.second.size() < 1)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700846 {
847 continue;
848 }
849
Andrew Geissler69132282019-07-01 11:00:35 -0500850 found = true;
Andrew Geisslere0dd8052019-06-18 16:05:10 -0500851 fw_util::getFwStatus(asyncResp, swId, obj.second[0].first);
852
Ed Tanous1abe55e2018-09-05 08:30:59 -0700853 crow::connections::systemBus->async_method_call(
854 [asyncResp,
Ed Tanous3ae837c2018-08-07 14:41:19 -0700855 swId](const boost::system::error_code error_code,
856 const boost::container::flat_map<
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500857 std::string, VariantType>& propertiesList) {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700858 if (error_code)
859 {
Jason M. Billsf12894f2018-10-09 12:45:45 -0700860 messages::internalError(asyncResp->res);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700861 return;
862 }
863 boost::container::flat_map<
864 std::string, VariantType>::const_iterator it =
865 propertiesList.find("Purpose");
866 if (it == propertiesList.end())
867 {
868 BMCWEB_LOG_DEBUG
869 << "Can't find property \"Purpose\"!";
Jason M. Billsf12894f2018-10-09 12:45:45 -0700870 messages::propertyMissing(asyncResp->res,
871 "Purpose");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700872 return;
873 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500874 const std::string* swInvPurpose =
Ed Tanousabf2add2019-01-22 16:40:12 -0800875 std::get_if<std::string>(&it->second);
Ed Tanous3ae837c2018-08-07 14:41:19 -0700876 if (swInvPurpose == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700877 {
878 BMCWEB_LOG_DEBUG
879 << "wrong types for property\"Purpose\"!";
Jason M. Billsf12894f2018-10-09 12:45:45 -0700880 messages::propertyValueTypeError(asyncResp->res,
881 "", "Purpose");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700882 return;
883 }
884
Ed Tanous3ae837c2018-08-07 14:41:19 -0700885 BMCWEB_LOG_DEBUG << "swInvPurpose = "
886 << *swInvPurpose;
Jennifer Leef4b65ab2018-09-18 12:00:13 -0700887 it = propertiesList.find("Version");
888 if (it == propertiesList.end())
Ed Tanous1abe55e2018-09-05 08:30:59 -0700889 {
Jennifer Leef4b65ab2018-09-18 12:00:13 -0700890 BMCWEB_LOG_DEBUG
891 << "Can't find property \"Version\"!";
Jason M. Billsf12894f2018-10-09 12:45:45 -0700892 messages::propertyMissing(asyncResp->res,
893 "Version");
Jennifer Leef4b65ab2018-09-18 12:00:13 -0700894 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700895 }
Jennifer Leef4b65ab2018-09-18 12:00:13 -0700896
897 BMCWEB_LOG_DEBUG << "Version found!";
898
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500899 const std::string* version =
Ed Tanousabf2add2019-01-22 16:40:12 -0800900 std::get_if<std::string>(&it->second);
Jennifer Leef4b65ab2018-09-18 12:00:13 -0700901
902 if (version == nullptr)
903 {
904 BMCWEB_LOG_DEBUG
905 << "Can't find property \"Version\"!";
Jason M. Billsf12894f2018-10-09 12:45:45 -0700906
907 messages::propertyValueTypeError(asyncResp->res,
908 "", "Version");
Jennifer Leef4b65ab2018-09-18 12:00:13 -0700909 return;
910 }
911 asyncResp->res.jsonValue["Version"] = *version;
912 asyncResp->res.jsonValue["Id"] = *swId;
Andrew Geissler54daabe2019-02-13 13:54:15 -0600913
914 // swInvPurpose is of format:
915 // xyz.openbmc_project.Software.Version.VersionPurpose.ABC
James Feiste2e96772019-10-03 10:51:43 -0700916 // Translate this to "ABC image"
Andrew Geissler54daabe2019-02-13 13:54:15 -0600917 size_t endDesc = swInvPurpose->rfind(".");
918 if (endDesc == std::string::npos)
919 {
920 messages::internalError(asyncResp->res);
921 return;
922 }
923 endDesc++;
924 if (endDesc >= swInvPurpose->size())
925 {
926 messages::internalError(asyncResp->res);
927 return;
928 }
929
930 std::string formatDesc =
931 swInvPurpose->substr(endDesc);
932 asyncResp->res.jsonValue["Description"] =
James Feiste2e96772019-10-03 10:51:43 -0700933 formatDesc + " image";
Andrew Geissler87d84722019-02-28 14:28:39 -0600934 getRelatedItems(asyncResp, *swInvPurpose);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700935 },
936 obj.second[0].first, obj.first,
937 "org.freedesktop.DBus.Properties", "GetAll",
938 "xyz.openbmc_project.Software.Version");
939 }
Andrew Geissler69132282019-07-01 11:00:35 -0500940 if (!found)
941 {
942 BMCWEB_LOG_ERROR << "Input swID " + *swId + " not found!";
943 messages::resourceMissingAtURI(
944 asyncResp->res,
945 "/redfish/v1/UpdateService/FirmwareInventory/" + *swId);
946 return;
947 }
Ayushi Smriti4e68c452019-09-04 14:37:55 +0530948 asyncResp->res.jsonValue["@odata.type"] =
949 "#SoftwareInventory.v1_1_0.SoftwareInventory";
Ayushi Smriti4e68c452019-09-04 14:37:55 +0530950 asyncResp->res.jsonValue["Name"] = "Software Inventory";
Ayushi Smriti4e68c452019-09-04 14:37:55 +0530951 asyncResp->res.jsonValue["Status"]["HealthRollup"] = "OK";
AppaRao Puli3f8a7432020-01-29 02:36:32 +0530952
953 asyncResp->res.jsonValue["Updateable"] = false;
954 fw_util::getFwUpdateableStatus(asyncResp, swId);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700955 },
956 "xyz.openbmc_project.ObjectMapper",
957 "/xyz/openbmc_project/object_mapper",
Ed Tanous271584a2019-07-09 16:24:22 -0700958 "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/",
959 static_cast<int32_t>(0),
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500960 std::array<const char*, 1>{"xyz.openbmc_project.Software.Version"});
Ed Tanous1abe55e2018-09-05 08:30:59 -0700961 }
962};
963
964} // namespace redfish