blob: fd4f53fa681a6575d4fd82ed5a39b1009cc70691 [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
Tejas Patild61e5192021-06-04 15:49:35 +053018#include "bmcweb_config.h"
19
John Edward Broadbent7e860f12021-04-08 15:57:16 -070020#include <app.hpp>
Ed Tanous168e20c2021-12-13 14:39:53 -080021#include <dbus_utility.hpp>
Ed Tanous45ca1b82022-03-25 13:07:27 -070022#include <query.hpp>
Ed Tanoused398212021-06-09 17:05:54 -070023#include <registries/privilege_registry.hpp>
Jonathan Doman1e1e5982021-06-11 09:36:17 -070024#include <sdbusplus/asio/property.hpp>
Willy Tueee00132022-06-14 14:53:17 -070025#include <utils/sw_utils.hpp>
Gunnar Mills1214b7e2020-06-04 10:11:30 -050026
Ed Tanous1abe55e2018-09-05 08:30:59 -070027namespace redfish
28{
Ed Tanous27826b52018-10-29 11:40:58 -070029
Andrew Geissler0e7de462019-03-04 19:11:54 -060030// Match signals added on software path
Patrick Williams59d494e2022-07-22 19:26:55 -050031static std::unique_ptr<sdbusplus::bus::match_t> fwUpdateMatcher;
32static std::unique_ptr<sdbusplus::bus::match_t> fwUpdateErrorMatcher;
Andrew Geissler0e7de462019-03-04 19:11:54 -060033// Only allow one update at a time
34static bool fwUpdateInProgress = false;
Andrew Geissler86adcd62019-04-18 10:58:05 -050035// Timer for software available
Ed Tanous271584a2019-07-09 16:24:22 -070036static std::unique_ptr<boost::asio::steady_timer> fwAvailableTimer;
Andrew Geissler86adcd62019-04-18 10:58:05 -050037
John Edward Broadbent7e860f12021-04-08 15:57:16 -070038inline static void cleanUp()
Andrew Geissler86adcd62019-04-18 10:58:05 -050039{
40 fwUpdateInProgress = false;
41 fwUpdateMatcher = nullptr;
James Feist4cde5d92020-06-11 10:39:55 -070042 fwUpdateErrorMatcher = nullptr;
Andrew Geissler86adcd62019-04-18 10:58:05 -050043}
John Edward Broadbent7e860f12021-04-08 15:57:16 -070044inline static void activateImage(const std::string& objPath,
45 const std::string& service)
Andrew Geissler86adcd62019-04-18 10:58:05 -050046{
47 BMCWEB_LOG_DEBUG << "Activate image for " << objPath << " " << service;
48 crow::connections::systemBus->async_method_call(
Ed Tanous81ce6092020-12-17 16:54:55 +000049 [](const boost::system::error_code errorCode) {
Ed Tanous002d39b2022-05-31 08:59:27 -070050 if (errorCode)
51 {
52 BMCWEB_LOG_DEBUG << "error_code = " << errorCode;
53 BMCWEB_LOG_DEBUG << "error msg = " << errorCode.message();
54 }
Andrew Geissler86adcd62019-04-18 10:58:05 -050055 },
56 service, objPath, "org.freedesktop.DBus.Properties", "Set",
57 "xyz.openbmc_project.Software.Activation", "RequestedActivation",
Ed Tanous168e20c2021-12-13 14:39:53 -080058 dbus::utility::DbusVariantType(
George Liu0fda0f12021-11-16 10:06:17 +080059 "xyz.openbmc_project.Software.Activation.RequestedActivations.Active"));
Andrew Geissler86adcd62019-04-18 10:58:05 -050060}
Andrew Geissler0554c982019-04-23 14:40:12 -050061
62// Note that asyncResp can be either a valid pointer or nullptr. If nullptr
63// then no asyncResp updates will occur
zhanghch058d1b46d2021-04-01 11:18:24 +080064static void
65 softwareInterfaceAdded(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Patrick Williams59d494e2022-07-22 19:26:55 -050066 sdbusplus::message_t& m, task::Payload&& payload)
Andrew Geissler86adcd62019-04-18 10:58:05 -050067{
Ed Tanousb9d36b42022-02-26 21:42:46 -080068 dbus::utility::DBusInteracesMap interfacesProperties;
Andrew Geissler86adcd62019-04-18 10:58:05 -050069
70 sdbusplus::message::object_path objPath;
71
72 m.read(objPath, interfacesProperties);
73
74 BMCWEB_LOG_DEBUG << "obj path = " << objPath.str;
Gunnar Mills1214b7e2020-06-04 10:11:30 -050075 for (auto& interface : interfacesProperties)
Andrew Geissler86adcd62019-04-18 10:58:05 -050076 {
77 BMCWEB_LOG_DEBUG << "interface = " << interface.first;
78
79 if (interface.first == "xyz.openbmc_project.Software.Activation")
80 {
Andrew Geissler86adcd62019-04-18 10:58:05 -050081 // Retrieve service and activate
82 crow::connections::systemBus->async_method_call(
Ed Tanousa3e65892021-09-16 14:13:20 -070083 [objPath, asyncResp, payload(std::move(payload))](
84 const boost::system::error_code errorCode,
85 const std::vector<
86 std::pair<std::string, std::vector<std::string>>>&
87 objInfo) mutable {
Ed Tanous002d39b2022-05-31 08:59:27 -070088 if (errorCode)
89 {
90 BMCWEB_LOG_DEBUG << "error_code = " << errorCode;
91 BMCWEB_LOG_DEBUG << "error msg = " << errorCode.message();
Andrew Geissler0554c982019-04-23 14:40:12 -050092 if (asyncResp)
93 {
Ed Tanous002d39b2022-05-31 08:59:27 -070094 messages::internalError(asyncResp->res);
95 }
96 cleanUp();
97 return;
98 }
99 // Ensure we only got one service back
100 if (objInfo.size() != 1)
101 {
102 BMCWEB_LOG_ERROR << "Invalid Object Size "
103 << objInfo.size();
104 if (asyncResp)
105 {
106 messages::internalError(asyncResp->res);
107 }
108 cleanUp();
109 return;
110 }
111 // cancel timer only when
112 // xyz.openbmc_project.Software.Activation interface
113 // is added
114 fwAvailableTimer = nullptr;
115
116 activateImage(objPath.str, objInfo[0].first);
117 if (asyncResp)
118 {
119 std::shared_ptr<task::TaskData> task =
120 task::TaskData::createTask(
121 [](boost::system::error_code ec,
Patrick Williams59d494e2022-07-22 19:26:55 -0500122 sdbusplus::message_t& msg,
Ed Tanous002d39b2022-05-31 08:59:27 -0700123 const std::shared_ptr<task::TaskData>&
124 taskData) {
125 if (ec)
126 {
127 return task::completed;
128 }
129
130 std::string iface;
131 dbus::utility::DBusPropertiesMap values;
132
133 std::string index = std::to_string(taskData->index);
134 msg.read(iface, values);
135
136 if (iface == "xyz.openbmc_project.Software.Activation")
137 {
138 std::string* state = nullptr;
139 for (const auto& property : values)
140 {
141 if (property.first == "Activation")
142 {
Ed Tanous8a592812022-06-04 09:06:59 -0700143 const std::string* activationState =
Ed Tanous002d39b2022-05-31 08:59:27 -0700144 std::get_if<std::string>(
145 &property.second);
Ed Tanous8a592812022-06-04 09:06:59 -0700146 if (activationState == nullptr)
James Feist32898ce2020-03-10 16:16:52 -0700147 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700148 taskData->messages.emplace_back(
149 messages::internalError());
James Feist32898ce2020-03-10 16:16:52 -0700150 return task::completed;
151 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700152 }
153 }
James Feist32898ce2020-03-10 16:16:52 -0700154
Ed Tanous002d39b2022-05-31 08:59:27 -0700155 if (state == nullptr)
156 {
157 return !task::completed;
158 }
James Feist32898ce2020-03-10 16:16:52 -0700159
Ed Tanous11ba3972022-07-11 09:50:41 -0700160 if (state->ends_with("Invalid") ||
161 state->ends_with("Failed"))
Ed Tanous002d39b2022-05-31 08:59:27 -0700162 {
163 taskData->state = "Exception";
164 taskData->status = "Warning";
165 taskData->messages.emplace_back(
166 messages::taskAborted(index));
167 return task::completed;
168 }
James Feiste5d50062020-05-11 17:29:00 -0700169
Ed Tanous11ba3972022-07-11 09:50:41 -0700170 if (state->ends_with("Staged"))
Ed Tanous002d39b2022-05-31 08:59:27 -0700171 {
172 taskData->state = "Stopping";
173 taskData->messages.emplace_back(
174 messages::taskPaused(index));
175
176 // its staged, set a long timer to
177 // allow them time to complete the
178 // update (probably cycle the
179 // system) if this expires then
180 // task will be cancelled
181 taskData->extendTimer(std::chrono::hours(5));
182 return !task::completed;
183 }
184
Ed Tanous11ba3972022-07-11 09:50:41 -0700185 if (state->ends_with("Active"))
Ed Tanous002d39b2022-05-31 08:59:27 -0700186 {
187 taskData->messages.emplace_back(
188 messages::taskCompletedOK(index));
189 taskData->state = "Completed";
190 return task::completed;
191 }
192 }
193 else if (
194 iface ==
195 "xyz.openbmc_project.Software.ActivationProgress")
196 {
197
198 const uint8_t* progress = nullptr;
199 for (const auto& property : values)
200 {
201 if (property.first == "Progress")
202 {
Ed Tanous8a592812022-06-04 09:06:59 -0700203 const std::string* progressStr =
Ed Tanous002d39b2022-05-31 08:59:27 -0700204 std::get_if<std::string>(
205 &property.second);
Ed Tanous8a592812022-06-04 09:06:59 -0700206 if (progressStr == nullptr)
James Feist32898ce2020-03-10 16:16:52 -0700207 {
James Feist32898ce2020-03-10 16:16:52 -0700208 taskData->messages.emplace_back(
Ed Tanous002d39b2022-05-31 08:59:27 -0700209 messages::internalError());
210 return task::completed;
James Feist32898ce2020-03-10 16:16:52 -0700211 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700212 }
213 }
James Feist32898ce2020-03-10 16:16:52 -0700214
Ed Tanous002d39b2022-05-31 08:59:27 -0700215 if (progress == nullptr)
216 {
217 return !task::completed;
218 }
219 taskData->percentComplete =
220 static_cast<int>(*progress);
221 taskData->messages.emplace_back(
222 messages::taskProgressChanged(
223 index, static_cast<size_t>(*progress)));
James Feist32898ce2020-03-10 16:16:52 -0700224
Ed Tanous002d39b2022-05-31 08:59:27 -0700225 // if we're getting status updates it's
226 // still alive, update timer
227 taskData->extendTimer(std::chrono::minutes(5));
228 }
229
230 // as firmware update often results in a
231 // reboot, the task may never "complete"
232 // unless it is an error
233
234 return !task::completed;
235 },
236 "type='signal',interface='org.freedesktop.DBus.Properties',"
237 "member='PropertiesChanged',path='" +
238 objPath.str + "'");
239 task->startTimer(std::chrono::minutes(5));
240 task->populateResp(asyncResp->res);
241 task->payload.emplace(std::move(payload));
242 }
243 fwUpdateInProgress = false;
Andrew Geissler86adcd62019-04-18 10:58:05 -0500244 },
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(
zhanghch058d1b46d2021-04-01 11:18:24 +0800257 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
258 const crow::Request& req, const std::string& url,
259 int timeoutTimeSeconds = 10)
Andrew Geissler86adcd62019-04-18 10:58:05 -0500260{
261 // Only allow one FW update at a time
Ed Tanouse05aec52022-01-25 10:28:56 -0800262 if (fwUpdateInProgress)
Andrew Geissler86adcd62019-04-18 10:58:05 -0500263 {
Andrew Geissler0554c982019-04-23 14:40:12 -0500264 if (asyncResp)
265 {
Andrew Geissler0554c982019-04-23 14:40:12 -0500266 messages::serviceTemporarilyUnavailable(asyncResp->res, "30");
267 }
Andrew Geissler86adcd62019-04-18 10:58:05 -0500268 return;
269 }
270
Andrew Geissler0554c982019-04-23 14:40:12 -0500271 fwAvailableTimer =
Ed Tanous271584a2019-07-09 16:24:22 -0700272 std::make_unique<boost::asio::steady_timer>(*req.ioService);
Andrew Geissler86adcd62019-04-18 10:58:05 -0500273
Ed Tanous271584a2019-07-09 16:24:22 -0700274 fwAvailableTimer->expires_after(std::chrono::seconds(timeoutTimeSeconds));
Andrew Geissler86adcd62019-04-18 10:58:05 -0500275
276 fwAvailableTimer->async_wait(
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500277 [asyncResp](const boost::system::error_code& ec) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700278 cleanUp();
279 if (ec == boost::asio::error::operation_aborted)
280 {
281 // expected, we were canceled before the timer completed.
282 return;
283 }
284 BMCWEB_LOG_ERROR
285 << "Timed out waiting for firmware object being created";
286 BMCWEB_LOG_ERROR << "FW image may has already been uploaded to server";
287 if (ec)
288 {
289 BMCWEB_LOG_ERROR << "Async_wait failed" << ec;
290 return;
291 }
292 if (asyncResp)
293 {
294 redfish::messages::internalError(asyncResp->res);
295 }
296 });
Ed Tanousa3e65892021-09-16 14:13:20 -0700297 task::Payload payload(req);
Patrick Williams59d494e2022-07-22 19:26:55 -0500298 auto callback = [asyncResp, payload](sdbusplus::message_t& m) mutable {
Andrew Geissler86adcd62019-04-18 10:58:05 -0500299 BMCWEB_LOG_DEBUG << "Match fired";
Ed Tanousa3e65892021-09-16 14:13:20 -0700300 softwareInterfaceAdded(asyncResp, m, std::move(payload));
Andrew Geissler86adcd62019-04-18 10:58:05 -0500301 };
302
303 fwUpdateInProgress = true;
304
Patrick Williams59d494e2022-07-22 19:26:55 -0500305 fwUpdateMatcher = std::make_unique<sdbusplus::bus::match_t>(
Andrew Geissler86adcd62019-04-18 10:58:05 -0500306 *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
Patrick Williams59d494e2022-07-22 19:26:55 -0500311 fwUpdateErrorMatcher = std::make_unique<sdbusplus::bus::match_t>(
James Feist4cde5d92020-06-11 10:39:55 -0700312 *crow::connections::systemBus,
Brian Mae1cc4822021-12-01 17:05:54 +0800313 "interface='org.freedesktop.DBus.ObjectManager',type='signal',"
314 "member='InterfacesAdded',"
315 "path='/xyz/openbmc_project/logging'",
Patrick Williams59d494e2022-07-22 19:26:55 -0500316 [asyncResp, url](sdbusplus::message_t& m) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700317 std::vector<std::pair<std::string, dbus::utility::DBusPropertiesMap>>
318 interfacesProperties;
319 sdbusplus::message::object_path objPath;
320 m.read(objPath, interfacesProperties);
321 BMCWEB_LOG_DEBUG << "obj path = " << objPath.str;
322 for (const std::pair<std::string, dbus::utility::DBusPropertiesMap>&
323 interface : interfacesProperties)
324 {
325 if (interface.first == "xyz.openbmc_project.Logging.Entry")
James Feist4cde5d92020-06-11 10:39:55 -0700326 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700327 for (const std::pair<std::string,
328 dbus::utility::DbusVariantType>& value :
329 interface.second)
Brian Mae1cc4822021-12-01 17:05:54 +0800330 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700331 if (value.first != "Message")
Brian Mae1cc4822021-12-01 17:05:54 +0800332 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700333 continue;
334 }
335 const std::string* type =
336 std::get_if<std::string>(&value.second);
337 if (type == nullptr)
338 {
339 // if this was our message, timeout will cover it
340 return;
341 }
342 fwAvailableTimer = nullptr;
343 if (*type ==
344 "xyz.openbmc_project.Software.Image.Error.UnTarFailure")
345 {
346 redfish::messages::invalidUpload(asyncResp->res, url,
347 "Invalid archive");
348 }
349 else if (*type ==
350 "xyz.openbmc_project.Software.Image.Error."
351 "ManifestFileFailure")
352 {
353 redfish::messages::invalidUpload(asyncResp->res, url,
354 "Invalid manifest");
355 }
356 else if (
357 *type ==
358 "xyz.openbmc_project.Software.Image.Error.ImageFailure")
359 {
360 redfish::messages::invalidUpload(
361 asyncResp->res, url, "Invalid image format");
362 }
363 else if (
364 *type ==
365 "xyz.openbmc_project.Software.Version.Error.AlreadyExists")
366 {
367 redfish::messages::invalidUpload(
368 asyncResp->res, url,
369 "Image version already exists");
Gunnar Mills88b3dd12020-11-20 14:26:04 -0600370
Ed Tanous002d39b2022-05-31 08:59:27 -0700371 redfish::messages::resourceAlreadyExists(
Jiaqing Zhaod8a5d5d2022-08-05 16:21:51 +0800372 asyncResp->res, "UpdateService", "Version",
Ed Tanous002d39b2022-05-31 08:59:27 -0700373 "uploaded version");
374 }
375 else if (
376 *type ==
377 "xyz.openbmc_project.Software.Image.Error.BusyFailure")
378 {
379 redfish::messages::resourceExhaustion(asyncResp->res,
380 url);
381 }
382 else
383 {
384 redfish::messages::internalError(asyncResp->res);
Brian Mae1cc4822021-12-01 17:05:54 +0800385 }
386 }
Gunnar Mills88b3dd12020-11-20 14:26:04 -0600387 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700388 }
James Feist4cde5d92020-06-11 10:39:55 -0700389 });
Andrew Geissler86adcd62019-04-18 10:58:05 -0500390}
Jennifer Lee729dae72018-04-24 15:59:34 -0700391
Andrew Geissler0554c982019-04-23 14:40:12 -0500392/**
393 * UpdateServiceActionsSimpleUpdate class supports handle POST method for
394 * SimpleUpdate action.
395 */
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700396inline void requestRoutesUpdateServiceActionsSimpleUpdate(App& app)
Andrew Geissler0554c982019-04-23 14:40:12 -0500397{
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700398 BMCWEB_ROUTE(
399 app, "/redfish/v1/UpdateService/Actions/UpdateService.SimpleUpdate/")
Ed Tanoused398212021-06-09 17:05:54 -0700400 .privileges(redfish::privileges::postUpdateService)
Ed Tanous002d39b2022-05-31 08:59:27 -0700401 .methods(boost::beast::http::verb::post)(
402 [&app](const crow::Request& req,
403 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Carson Labrado3ba00072022-06-06 19:40:56 +0000404 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -0700405 {
406 return;
407 }
Ed Tanous45ca1b82022-03-25 13:07:27 -0700408
Ed Tanous002d39b2022-05-31 08:59:27 -0700409 std::optional<std::string> transferProtocol;
410 std::string imageURI;
Andrew Geissler0554c982019-04-23 14:40:12 -0500411
Ed Tanous002d39b2022-05-31 08:59:27 -0700412 BMCWEB_LOG_DEBUG << "Enter UpdateService.SimpleUpdate doPost";
Andrew Geissler0554c982019-04-23 14:40:12 -0500413
Ed Tanous002d39b2022-05-31 08:59:27 -0700414 // User can pass in both TransferProtocol and ImageURI parameters or
415 // they can pass in just the ImageURI with the transfer protocol
416 // embedded within it.
417 // 1) TransferProtocol:TFTP ImageURI:1.1.1.1/myfile.bin
418 // 2) ImageURI:tftp://1.1.1.1/myfile.bin
Andrew Geissler0554c982019-04-23 14:40:12 -0500419
Ed Tanous002d39b2022-05-31 08:59:27 -0700420 if (!json_util::readJsonAction(req, asyncResp->res, "TransferProtocol",
421 transferProtocol, "ImageURI", imageURI))
422 {
423 BMCWEB_LOG_DEBUG
424 << "Missing TransferProtocol or ImageURI parameter";
425 return;
426 }
427 if (!transferProtocol)
428 {
429 // Must be option 2
430 // Verify ImageURI has transfer protocol in it
431 size_t separator = imageURI.find(':');
Andrew Geissler0554c982019-04-23 14:40:12 -0500432 if ((separator == std::string::npos) ||
433 ((separator + 1) > imageURI.size()))
434 {
435 messages::actionParameterValueTypeError(
436 asyncResp->res, imageURI, "ImageURI",
437 "UpdateService.SimpleUpdate");
Ed Tanous002d39b2022-05-31 08:59:27 -0700438 BMCWEB_LOG_ERROR << "ImageURI missing transfer protocol: "
439 << imageURI;
Jayashankar Padath274dfe62019-08-23 12:30:57 +0530440 return;
Jayashankar Padathfa1a5a32019-05-28 23:54:37 +0530441 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700442 transferProtocol = imageURI.substr(0, separator);
443 // Ensure protocol is upper case for a common comparison path
444 // below
445 boost::to_upper(*transferProtocol);
446 BMCWEB_LOG_DEBUG << "Encoded transfer protocol "
447 << *transferProtocol;
Jayashankar Padathfa1a5a32019-05-28 23:54:37 +0530448
Ed Tanous002d39b2022-05-31 08:59:27 -0700449 // Adjust imageURI to not have the protocol on it for parsing
450 // below
451 // ex. tftp://1.1.1.1/myfile.bin -> 1.1.1.1/myfile.bin
452 imageURI = imageURI.substr(separator + 3);
453 BMCWEB_LOG_DEBUG << "Adjusted imageUri " << imageURI;
454 }
Jayashankar Padath274dfe62019-08-23 12:30:57 +0530455
Ed Tanous002d39b2022-05-31 08:59:27 -0700456 // OpenBMC currently only supports TFTP
457 if (*transferProtocol != "TFTP")
458 {
459 messages::actionParameterNotSupported(asyncResp->res,
460 "TransferProtocol",
461 "UpdateService.SimpleUpdate");
462 BMCWEB_LOG_ERROR << "Request incorrect protocol parameter: "
463 << *transferProtocol;
464 return;
465 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700466
Ed Tanous002d39b2022-05-31 08:59:27 -0700467 // Format should be <IP or Hostname>/<file> for imageURI
468 size_t separator = imageURI.find('/');
469 if ((separator == std::string::npos) ||
470 ((separator + 1) > imageURI.size()))
471 {
472 messages::actionParameterValueTypeError(
473 asyncResp->res, imageURI, "ImageURI",
474 "UpdateService.SimpleUpdate");
475 BMCWEB_LOG_ERROR << "Invalid ImageURI: " << imageURI;
476 return;
477 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700478
Ed Tanous002d39b2022-05-31 08:59:27 -0700479 std::string tftpServer = imageURI.substr(0, separator);
480 std::string fwFile = imageURI.substr(separator + 1);
481 BMCWEB_LOG_DEBUG << "Server: " << tftpServer + " File: " << fwFile;
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700482
Ed Tanous002d39b2022-05-31 08:59:27 -0700483 // Setup callback for when new software detected
484 // Give TFTP 10 minutes to complete
485 monitorForSoftwareAvailable(
486 asyncResp, req,
487 "/redfish/v1/UpdateService/Actions/UpdateService.SimpleUpdate",
488 600);
489
490 // TFTP can take up to 10 minutes depending on image size and
491 // connection speed. Return to caller as soon as the TFTP operation
492 // has been started. The callback above will ensure the activate
493 // is started once the download has completed
494 redfish::messages::success(asyncResp->res);
495
496 // Call TFTP service
497 crow::connections::systemBus->async_method_call(
498 [](const boost::system::error_code ec) {
499 if (ec)
500 {
501 // messages::internalError(asyncResp->res);
502 cleanUp();
503 BMCWEB_LOG_DEBUG << "error_code = " << ec;
504 BMCWEB_LOG_DEBUG << "error msg = " << ec.message();
505 }
506 else
507 {
508 BMCWEB_LOG_DEBUG << "Call to DownloaViaTFTP Success";
509 }
510 },
511 "xyz.openbmc_project.Software.Download",
512 "/xyz/openbmc_project/software", "xyz.openbmc_project.Common.TFTP",
513 "DownloadViaTFTP", fwFile, tftpServer);
514
515 BMCWEB_LOG_DEBUG << "Exit UpdateService.SimpleUpdate doPost";
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700516 });
517}
518
Ed Tanousc2051d12022-05-11 12:21:55 -0700519inline void
520 handleUpdateServicePost(App& app, const crow::Request& req,
521 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
522{
Carson Labrado3ba00072022-06-06 19:40:56 +0000523 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanousc2051d12022-05-11 12:21:55 -0700524 {
525 return;
526 }
527 BMCWEB_LOG_DEBUG << "doPost...";
528
529 // Setup callback for when new software detected
530 monitorForSoftwareAvailable(asyncResp, req, "/redfish/v1/UpdateService");
531
532 std::string filepath(
533 "/tmp/images/" +
534 boost::uuids::to_string(boost::uuids::random_generator()()));
535 BMCWEB_LOG_DEBUG << "Writing file to " << filepath;
536 std::ofstream out(filepath, std::ofstream::out | std::ofstream::binary |
537 std::ofstream::trunc);
538 out << req.body;
539 out.close();
540 BMCWEB_LOG_DEBUG << "file upload complete!!";
541}
542
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700543inline void requestRoutesUpdateService(App& app)
544{
545 BMCWEB_ROUTE(app, "/redfish/v1/UpdateService/")
Ed Tanoused398212021-06-09 17:05:54 -0700546 .privileges(redfish::privileges::getUpdateService)
Ed Tanous002d39b2022-05-31 08:59:27 -0700547 .methods(boost::beast::http::verb::get)(
548 [&app](const crow::Request& req,
549 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Carson Labrado3ba00072022-06-06 19:40:56 +0000550 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -0700551 {
552 return;
553 }
554 asyncResp->res.jsonValue["@odata.type"] =
555 "#UpdateService.v1_5_0.UpdateService";
556 asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/UpdateService";
557 asyncResp->res.jsonValue["Id"] = "UpdateService";
558 asyncResp->res.jsonValue["Description"] = "Service for Software Update";
559 asyncResp->res.jsonValue["Name"] = "Update Service";
Ed Tanous4dc23f32022-05-11 11:32:19 -0700560
Ed Tanous32ca38a2022-05-11 12:36:59 -0700561#ifdef BMCWEB_ENABLE_REDFISH_UPDATESERVICE_OLD_POST_URL
Ed Tanous002d39b2022-05-31 08:59:27 -0700562 // See note about later on in this file about why this is neccesary
563 // This is "Wrong" per the standard, but is done temporarily to
564 // avoid noise in failing tests as people transition to having this
565 // option disabled
566 asyncResp->res.addHeader(boost::beast::http::field::allow,
567 "GET, PATCH, HEAD");
Ed Tanous32ca38a2022-05-11 12:36:59 -0700568#endif
569
Ed Tanous002d39b2022-05-31 08:59:27 -0700570 asyncResp->res.jsonValue["HttpPushUri"] =
571 "/redfish/v1/UpdateService/update";
Ed Tanous4dc23f32022-05-11 11:32:19 -0700572
Ed Tanous002d39b2022-05-31 08:59:27 -0700573 // UpdateService cannot be disabled
574 asyncResp->res.jsonValue["ServiceEnabled"] = true;
575 asyncResp->res.jsonValue["FirmwareInventory"]["@odata.id"] =
576 "/redfish/v1/UpdateService/FirmwareInventory";
577 // Get the MaxImageSizeBytes
578 asyncResp->res.jsonValue["MaxImageSizeBytes"] =
579 bmcwebHttpReqBodyLimitMb * 1024 * 1024;
Tejas Patild61e5192021-06-04 15:49:35 +0530580
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700581#ifdef BMCWEB_INSECURE_ENABLE_REDFISH_FW_TFTP_UPDATE
Ed Tanous002d39b2022-05-31 08:59:27 -0700582 // Update Actions object.
583 nlohmann::json& updateSvcSimpleUpdate =
584 asyncResp->res.jsonValue["Actions"]["#UpdateService.SimpleUpdate"];
585 updateSvcSimpleUpdate["target"] =
586 "/redfish/v1/UpdateService/Actions/UpdateService.SimpleUpdate";
587 updateSvcSimpleUpdate["TransferProtocol@Redfish.AllowableValues"] = {
588 "TFTP"};
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700589#endif
Ed Tanous002d39b2022-05-31 08:59:27 -0700590 // Get the current ApplyTime value
591 sdbusplus::asio::getProperty<std::string>(
592 *crow::connections::systemBus, "xyz.openbmc_project.Settings",
593 "/xyz/openbmc_project/software/apply_time",
594 "xyz.openbmc_project.Software.ApplyTime", "RequestedApplyTime",
595 [asyncResp](const boost::system::error_code ec,
596 const std::string& applyTime) {
597 if (ec)
598 {
599 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
600 messages::internalError(asyncResp->res);
601 return;
602 }
Jayashankar Padath274dfe62019-08-23 12:30:57 +0530603
Ed Tanous002d39b2022-05-31 08:59:27 -0700604 // Store the ApplyTime Value
605 if (applyTime == "xyz.openbmc_project.Software.ApplyTime."
606 "RequestedApplyTimes.Immediate")
607 {
608 asyncResp->res.jsonValue["HttpPushUriOptions"]
609 ["HttpPushUriApplyTime"]["ApplyTime"] =
610 "Immediate";
611 }
612 else if (applyTime == "xyz.openbmc_project.Software.ApplyTime."
613 "RequestedApplyTimes.OnReset")
614 {
615 asyncResp->res.jsonValue["HttpPushUriOptions"]
616 ["HttpPushUriApplyTime"]["ApplyTime"] =
617 "OnReset";
618 }
619 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700620 });
621 BMCWEB_ROUTE(app, "/redfish/v1/UpdateService/")
Ed Tanoused398212021-06-09 17:05:54 -0700622 .privileges(redfish::privileges::patchUpdateService)
Ed Tanous002d39b2022-05-31 08:59:27 -0700623 .methods(boost::beast::http::verb::patch)(
624 [&app](const crow::Request& req,
625 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Carson Labrado3ba00072022-06-06 19:40:56 +0000626 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -0700627 {
628 return;
629 }
630 BMCWEB_LOG_DEBUG << "doPatch...";
Jayashankar Padathfa1a5a32019-05-28 23:54:37 +0530631
Ed Tanous002d39b2022-05-31 08:59:27 -0700632 std::optional<nlohmann::json> pushUriOptions;
633 if (!json_util::readJsonPatch(req, asyncResp->res, "HttpPushUriOptions",
634 pushUriOptions))
635 {
636 return;
637 }
638
639 if (pushUriOptions)
640 {
641 std::optional<nlohmann::json> pushUriApplyTime;
642 if (!json_util::readJson(*pushUriOptions, asyncResp->res,
643 "HttpPushUriApplyTime", pushUriApplyTime))
George Liu0fda0f12021-11-16 10:06:17 +0800644 {
645 return;
646 }
647
Ed Tanous002d39b2022-05-31 08:59:27 -0700648 if (pushUriApplyTime)
George Liu0fda0f12021-11-16 10:06:17 +0800649 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700650 std::optional<std::string> applyTime;
651 if (!json_util::readJson(*pushUriApplyTime, asyncResp->res,
652 "ApplyTime", applyTime))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700653 {
Ed Tanousc711bf82018-07-30 16:31:33 -0700654 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700655 }
Jennifer Lee6c4eb9d2018-05-22 10:58:31 -0700656
Ed Tanous002d39b2022-05-31 08:59:27 -0700657 if (applyTime)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700658 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700659 std::string applyTimeNewVal;
660 if (applyTime == "Immediate")
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700661 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700662 applyTimeNewVal =
663 "xyz.openbmc_project.Software.ApplyTime.RequestedApplyTimes.Immediate";
664 }
665 else if (applyTime == "OnReset")
666 {
667 applyTimeNewVal =
668 "xyz.openbmc_project.Software.ApplyTime.RequestedApplyTimes.OnReset";
669 }
670 else
671 {
672 BMCWEB_LOG_INFO
673 << "ApplyTime value is not in the list of acceptable values";
674 messages::propertyValueNotInList(
675 asyncResp->res, *applyTime, "ApplyTime");
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700676 return;
677 }
678
Ed Tanous002d39b2022-05-31 08:59:27 -0700679 // Set the requested image apply time value
680 crow::connections::systemBus->async_method_call(
681 [asyncResp](const boost::system::error_code ec) {
682 if (ec)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700683 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700684 BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec;
685 messages::internalError(asyncResp->res);
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700686 return;
687 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700688 messages::success(asyncResp->res);
689 },
690 "xyz.openbmc_project.Settings",
691 "/xyz/openbmc_project/software/apply_time",
692 "org.freedesktop.DBus.Properties", "Set",
693 "xyz.openbmc_project.Software.ApplyTime",
694 "RequestedApplyTime",
695 dbus::utility::DbusVariantType{applyTimeNewVal});
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700696 }
George Liu0fda0f12021-11-16 10:06:17 +0800697 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700698 }
George Liu0fda0f12021-11-16 10:06:17 +0800699 });
Ed Tanousc2051d12022-05-11 12:21:55 -0700700
Ed Tanous4dc23f32022-05-11 11:32:19 -0700701// The "old" behavior of the update service URI causes redfish-service validator
702// failures when the Allow header is supported, given that in the spec,
703// UpdateService does not allow POST. in openbmc, we unfortunately reused that
704// resource as our HttpPushUri as well. A number of services, including the
705// openbmc tests, and documentation have hardcoded that erroneous API, instead
706// of relying on HttpPushUri as the spec requires. This option will exist
707// temporarily to allow the old behavior until Q4 2022, at which time it will be
708// removed.
709#ifdef BMCWEB_ENABLE_REDFISH_UPDATESERVICE_OLD_POST_URL
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700710 BMCWEB_ROUTE(app, "/redfish/v1/UpdateService/")
Ed Tanoused398212021-06-09 17:05:54 -0700711 .privileges(redfish::privileges::postUpdateService)
Ed Tanous002d39b2022-05-31 08:59:27 -0700712 .methods(boost::beast::http::verb::post)(
713 [&app](const crow::Request& req,
714 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
715 asyncResp->res.addHeader(
716 boost::beast::http::field::warning,
717 "299 - \"POST to /redfish/v1/UpdateService is deprecated. Use "
718 "the value contained within HttpPushUri.\"");
719 handleUpdateServicePost(app, req, asyncResp);
Ed Tanous4dc23f32022-05-11 11:32:19 -0700720 });
721#endif
722 BMCWEB_ROUTE(app, "/redfish/v1/UpdateService/update/")
723 .privileges(redfish::privileges::postUpdateService)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700724 .methods(boost::beast::http::verb::post)(
Ed Tanousc2051d12022-05-11 12:21:55 -0700725 std::bind_front(handleUpdateServicePost, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700726}
727
728inline void requestRoutesSoftwareInventoryCollection(App& app)
729{
730 BMCWEB_ROUTE(app, "/redfish/v1/UpdateService/FirmwareInventory/")
Ed Tanoused398212021-06-09 17:05:54 -0700731 .privileges(redfish::privileges::getSoftwareInventoryCollection)
Ed Tanous14766872022-03-15 10:44:42 -0700732 .methods(boost::beast::http::verb::get)(
733 [&app](const crow::Request& req,
734 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Carson Labrado3ba00072022-06-06 19:40:56 +0000735 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -0700736 {
737 return;
738 }
739 asyncResp->res.jsonValue["@odata.type"] =
740 "#SoftwareInventoryCollection.SoftwareInventoryCollection";
741 asyncResp->res.jsonValue["@odata.id"] =
742 "/redfish/v1/UpdateService/FirmwareInventory";
743 asyncResp->res.jsonValue["Name"] = "Software Inventory Collection";
744
745 crow::connections::systemBus->async_method_call(
746 [asyncResp](
747 const boost::system::error_code ec,
748 const dbus::utility::MapperGetSubTreeResponse& subtree) {
749 if (ec)
750 {
751 messages::internalError(asyncResp->res);
752 return;
753 }
754 asyncResp->res.jsonValue["Members"] = nlohmann::json::array();
755 asyncResp->res.jsonValue["Members@odata.count"] = 0;
756
757 for (const auto& obj : subtree)
758 {
759 sdbusplus::message::object_path path(obj.first);
760 std::string swId = path.filename();
761 if (swId.empty())
Ed Tanous14766872022-03-15 10:44:42 -0700762 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700763 messages::internalError(asyncResp->res);
764 BMCWEB_LOG_DEBUG << "Can't parse firmware ID!!";
Ed Tanous14766872022-03-15 10:44:42 -0700765 return;
766 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700767
Ed Tanous002d39b2022-05-31 08:59:27 -0700768 nlohmann::json& members = asyncResp->res.jsonValue["Members"];
769 nlohmann::json::object_t member;
770 member["@odata.id"] =
771 "/redfish/v1/UpdateService/FirmwareInventory/" + swId;
772 members.push_back(std::move(member));
773 asyncResp->res.jsonValue["Members@odata.count"] =
774 members.size();
775 }
776 },
777 // Note that only firmware levels associated with a device
778 // are stored under /xyz/openbmc_project/software therefore
779 // to ensure only real FirmwareInventory items are returned,
780 // this full object path must be used here as input to
781 // mapper
782 "xyz.openbmc_project.ObjectMapper",
783 "/xyz/openbmc_project/object_mapper",
784 "xyz.openbmc_project.ObjectMapper", "GetSubTree",
785 "/xyz/openbmc_project/software", static_cast<int32_t>(0),
786 std::array<const char*, 1>{"xyz.openbmc_project.Software.Version"});
787 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700788}
789/* Fill related item links (i.e. bmc, bios) in for inventory */
790inline static void
791 getRelatedItems(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
792 const std::string& purpose)
793{
Willy Tueee00132022-06-14 14:53:17 -0700794 if (purpose == sw_util::bmcPurpose)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700795 {
796 nlohmann::json& relatedItem = aResp->res.jsonValue["RelatedItem"];
Ed Tanous14766872022-03-15 10:44:42 -0700797 nlohmann::json::object_t item;
798 item["@odata.id"] = "/redfish/v1/Managers/bmc";
799 relatedItem.push_back(std::move(item));
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700800 aResp->res.jsonValue["RelatedItem@odata.count"] = relatedItem.size();
801 }
Willy Tueee00132022-06-14 14:53:17 -0700802 else if (purpose == sw_util::biosPurpose)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700803 {
804 nlohmann::json& relatedItem = aResp->res.jsonValue["RelatedItem"];
Ed Tanous14766872022-03-15 10:44:42 -0700805 nlohmann::json::object_t item;
806 item["@odata.id"] = "/redfish/v1/Systems/system/Bios";
807 relatedItem.push_back(std::move(item));
Jiaqing Zhao1a6e51a2022-01-19 19:20:24 +0800808 aResp->res.jsonValue["RelatedItem@odata.count"] = relatedItem.size();
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700809 }
810 else
811 {
812 BMCWEB_LOG_ERROR << "Unknown software purpose " << purpose;
813 }
814}
815
Willy Tuaf246602022-06-14 15:51:53 -0700816inline void
817 getSoftwareVersion(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
818 const std::string& service, const std::string& path,
819 const std::string& swId)
820{
821 crow::connections::systemBus->async_method_call(
822 [asyncResp,
823 swId](const boost::system::error_code errorCode,
824 const dbus::utility::DBusPropertiesMap& propertiesList) {
825 if (errorCode)
826 {
827 messages::internalError(asyncResp->res);
828 return;
829 }
830 const std::string* swInvPurpose = nullptr;
831 const std::string* version = nullptr;
832 for (const auto& property : propertiesList)
833 {
834 if (property.first == "Purpose")
835 {
836 swInvPurpose = std::get_if<std::string>(&property.second);
837 }
838 else if (property.first == "Version")
839 {
840 version = std::get_if<std::string>(&property.second);
841 }
842 }
843
844 if (swInvPurpose == nullptr)
845 {
846 BMCWEB_LOG_DEBUG << "Can't find property \"Purpose\"!";
847 messages::internalError(asyncResp->res);
848 return;
849 }
850
851 BMCWEB_LOG_DEBUG << "swInvPurpose = " << *swInvPurpose;
852
853 if (version == nullptr)
854 {
855 BMCWEB_LOG_DEBUG << "Can't find property \"Version\"!";
856
857 messages::internalError(asyncResp->res);
858
859 return;
860 }
861 asyncResp->res.jsonValue["Version"] = *version;
862 asyncResp->res.jsonValue["Id"] = swId;
863
864 // swInvPurpose is of format:
865 // xyz.openbmc_project.Software.Version.VersionPurpose.ABC
866 // Translate this to "ABC image"
867 size_t endDesc = swInvPurpose->rfind('.');
868 if (endDesc == std::string::npos)
869 {
870 messages::internalError(asyncResp->res);
871 return;
872 }
873 endDesc++;
874 if (endDesc >= swInvPurpose->size())
875 {
876 messages::internalError(asyncResp->res);
877 return;
878 }
879
880 std::string formatDesc = swInvPurpose->substr(endDesc);
881 asyncResp->res.jsonValue["Description"] = formatDesc + " image";
882 getRelatedItems(asyncResp, *swInvPurpose);
883 },
884 service, path, "org.freedesktop.DBus.Properties", "GetAll",
885 "xyz.openbmc_project.Software.Version");
886}
887
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700888inline void requestRoutesSoftwareInventory(App& app)
889{
890 BMCWEB_ROUTE(app, "/redfish/v1/UpdateService/FirmwareInventory/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -0700891 .privileges(redfish::privileges::getSoftwareInventory)
Ed Tanous002d39b2022-05-31 08:59:27 -0700892 .methods(boost::beast::http::verb::get)(
893 [&app](const crow::Request& req,
894 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
895 const std::string& param) {
Carson Labrado3ba00072022-06-06 19:40:56 +0000896 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -0700897 {
898 return;
899 }
900 std::shared_ptr<std::string> swId =
901 std::make_shared<std::string>(param);
902
903 asyncResp->res.jsonValue["@odata.id"] =
904 "/redfish/v1/UpdateService/FirmwareInventory/" + *swId;
905
906 crow::connections::systemBus->async_method_call(
907 [asyncResp,
908 swId](const boost::system::error_code ec,
909 const dbus::utility::MapperGetSubTreeResponse& subtree) {
910 BMCWEB_LOG_DEBUG << "doGet callback...";
911 if (ec)
Ed Tanous45ca1b82022-03-25 13:07:27 -0700912 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700913 messages::internalError(asyncResp->res);
Ed Tanous45ca1b82022-03-25 13:07:27 -0700914 return;
915 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700916
Ed Tanous002d39b2022-05-31 08:59:27 -0700917 // Ensure we find our input swId, otherwise return an error
918 bool found = false;
919 for (const std::pair<std::string,
920 std::vector<std::pair<
921 std::string, std::vector<std::string>>>>&
922 obj : subtree)
923 {
Ed Tanous11ba3972022-07-11 09:50:41 -0700924 if (!obj.first.ends_with(*swId))
Ed Tanous002d39b2022-05-31 08:59:27 -0700925 {
926 continue;
927 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700928
Ed Tanous002d39b2022-05-31 08:59:27 -0700929 if (obj.second.empty())
930 {
931 continue;
932 }
933
934 found = true;
Willy Tueee00132022-06-14 14:53:17 -0700935 sw_util::getSwStatus(asyncResp, swId, obj.second[0].first);
Willy Tuaf246602022-06-14 15:51:53 -0700936 getSoftwareVersion(asyncResp, obj.second[0].first, obj.first,
937 *swId);
Ed Tanous002d39b2022-05-31 08:59:27 -0700938 }
939 if (!found)
940 {
941 BMCWEB_LOG_ERROR << "Input swID " << *swId << " not found!";
942 messages::resourceMissingAtURI(
943 asyncResp->res, crow::utility::urlFromPieces(
944 "redfish", "v1", "UpdateService",
945 "FirmwareInventory", *swId));
946 return;
947 }
948 asyncResp->res.jsonValue["@odata.type"] =
949 "#SoftwareInventory.v1_1_0.SoftwareInventory";
950 asyncResp->res.jsonValue["Name"] = "Software Inventory";
951 asyncResp->res.jsonValue["Status"]["HealthRollup"] = "OK";
Ed Tanous1abe55e2018-09-05 08:30:59 -0700952
Ed Tanous002d39b2022-05-31 08:59:27 -0700953 asyncResp->res.jsonValue["Updateable"] = false;
Willy Tueee00132022-06-14 14:53:17 -0700954 sw_util::getSwUpdatableStatus(asyncResp, swId);
Ed Tanous002d39b2022-05-31 08:59:27 -0700955 },
956 "xyz.openbmc_project.ObjectMapper",
957 "/xyz/openbmc_project/object_mapper",
958 "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/",
959 static_cast<int32_t>(0),
960 std::array<const char*, 1>{"xyz.openbmc_project.Software.Version"});
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700961 });
962}
Ed Tanous1abe55e2018-09-05 08:30:59 -0700963
964} // namespace redfish