blob: 9acf5689c66acf825d2173c30646c4c238ef95e8 [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>
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +020025#include <sdbusplus/unpack_properties.hpp>
26#include <utils/dbus_utils.hpp>
Willy Tueee00132022-06-14 14:53:17 -070027#include <utils/sw_utils.hpp>
Gunnar Mills1214b7e2020-06-04 10:11:30 -050028
Ed Tanous1abe55e2018-09-05 08:30:59 -070029namespace redfish
30{
Ed Tanous27826b52018-10-29 11:40:58 -070031
Andrew Geissler0e7de462019-03-04 19:11:54 -060032// Match signals added on software path
Patrick Williams59d494e2022-07-22 19:26:55 -050033static std::unique_ptr<sdbusplus::bus::match_t> fwUpdateMatcher;
34static std::unique_ptr<sdbusplus::bus::match_t> fwUpdateErrorMatcher;
Andrew Geissler0e7de462019-03-04 19:11:54 -060035// Only allow one update at a time
36static bool fwUpdateInProgress = false;
Andrew Geissler86adcd62019-04-18 10:58:05 -050037// Timer for software available
Ed Tanous271584a2019-07-09 16:24:22 -070038static std::unique_ptr<boost::asio::steady_timer> fwAvailableTimer;
Andrew Geissler86adcd62019-04-18 10:58:05 -050039
John Edward Broadbent7e860f12021-04-08 15:57:16 -070040inline static void cleanUp()
Andrew Geissler86adcd62019-04-18 10:58:05 -050041{
42 fwUpdateInProgress = false;
43 fwUpdateMatcher = nullptr;
James Feist4cde5d92020-06-11 10:39:55 -070044 fwUpdateErrorMatcher = nullptr;
Andrew Geissler86adcd62019-04-18 10:58:05 -050045}
John Edward Broadbent7e860f12021-04-08 15:57:16 -070046inline static void activateImage(const std::string& objPath,
47 const std::string& service)
Andrew Geissler86adcd62019-04-18 10:58:05 -050048{
49 BMCWEB_LOG_DEBUG << "Activate image for " << objPath << " " << service;
50 crow::connections::systemBus->async_method_call(
Ed Tanous81ce6092020-12-17 16:54:55 +000051 [](const boost::system::error_code errorCode) {
Ed Tanous002d39b2022-05-31 08:59:27 -070052 if (errorCode)
53 {
54 BMCWEB_LOG_DEBUG << "error_code = " << errorCode;
55 BMCWEB_LOG_DEBUG << "error msg = " << errorCode.message();
56 }
Andrew Geissler86adcd62019-04-18 10:58:05 -050057 },
58 service, objPath, "org.freedesktop.DBus.Properties", "Set",
59 "xyz.openbmc_project.Software.Activation", "RequestedActivation",
Ed Tanous168e20c2021-12-13 14:39:53 -080060 dbus::utility::DbusVariantType(
George Liu0fda0f12021-11-16 10:06:17 +080061 "xyz.openbmc_project.Software.Activation.RequestedActivations.Active"));
Andrew Geissler86adcd62019-04-18 10:58:05 -050062}
Andrew Geissler0554c982019-04-23 14:40:12 -050063
64// Note that asyncResp can be either a valid pointer or nullptr. If nullptr
65// then no asyncResp updates will occur
zhanghch058d1b46d2021-04-01 11:18:24 +080066static void
67 softwareInterfaceAdded(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Patrick Williams59d494e2022-07-22 19:26:55 -050068 sdbusplus::message_t& m, task::Payload&& payload)
Andrew Geissler86adcd62019-04-18 10:58:05 -050069{
Ed Tanousb9d36b42022-02-26 21:42:46 -080070 dbus::utility::DBusInteracesMap interfacesProperties;
Andrew Geissler86adcd62019-04-18 10:58:05 -050071
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(
Ed Tanousa3e65892021-09-16 14:13:20 -070085 [objPath, asyncResp, payload(std::move(payload))](
86 const boost::system::error_code errorCode,
87 const std::vector<
88 std::pair<std::string, std::vector<std::string>>>&
89 objInfo) mutable {
Ed Tanous002d39b2022-05-31 08:59:27 -070090 if (errorCode)
91 {
92 BMCWEB_LOG_DEBUG << "error_code = " << errorCode;
93 BMCWEB_LOG_DEBUG << "error msg = " << errorCode.message();
Andrew Geissler0554c982019-04-23 14:40:12 -050094 if (asyncResp)
95 {
Ed Tanous002d39b2022-05-31 08:59:27 -070096 messages::internalError(asyncResp->res);
97 }
98 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();
106 if (asyncResp)
107 {
108 messages::internalError(asyncResp->res);
109 }
110 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);
119 if (asyncResp)
120 {
121 std::shared_ptr<task::TaskData> task =
122 task::TaskData::createTask(
123 [](boost::system::error_code ec,
Patrick Williams59d494e2022-07-22 19:26:55 -0500124 sdbusplus::message_t& msg,
Ed Tanous002d39b2022-05-31 08:59:27 -0700125 const std::shared_ptr<task::TaskData>&
126 taskData) {
127 if (ec)
128 {
129 return task::completed;
130 }
131
132 std::string iface;
133 dbus::utility::DBusPropertiesMap values;
134
135 std::string index = std::to_string(taskData->index);
136 msg.read(iface, values);
137
138 if (iface == "xyz.openbmc_project.Software.Activation")
139 {
140 std::string* state = nullptr;
141 for (const auto& property : values)
142 {
143 if (property.first == "Activation")
144 {
Ed Tanous8a592812022-06-04 09:06:59 -0700145 const std::string* activationState =
Ed Tanous002d39b2022-05-31 08:59:27 -0700146 std::get_if<std::string>(
147 &property.second);
Ed Tanous8a592812022-06-04 09:06:59 -0700148 if (activationState == nullptr)
James Feist32898ce2020-03-10 16:16:52 -0700149 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700150 taskData->messages.emplace_back(
151 messages::internalError());
James Feist32898ce2020-03-10 16:16:52 -0700152 return task::completed;
153 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700154 }
155 }
James Feist32898ce2020-03-10 16:16:52 -0700156
Ed Tanous002d39b2022-05-31 08:59:27 -0700157 if (state == nullptr)
158 {
159 return !task::completed;
160 }
James Feist32898ce2020-03-10 16:16:52 -0700161
Ed Tanous11ba3972022-07-11 09:50:41 -0700162 if (state->ends_with("Invalid") ||
163 state->ends_with("Failed"))
Ed Tanous002d39b2022-05-31 08:59:27 -0700164 {
165 taskData->state = "Exception";
166 taskData->status = "Warning";
167 taskData->messages.emplace_back(
168 messages::taskAborted(index));
169 return task::completed;
170 }
James Feiste5d50062020-05-11 17:29:00 -0700171
Ed Tanous11ba3972022-07-11 09:50:41 -0700172 if (state->ends_with("Staged"))
Ed Tanous002d39b2022-05-31 08:59:27 -0700173 {
174 taskData->state = "Stopping";
175 taskData->messages.emplace_back(
176 messages::taskPaused(index));
177
178 // its staged, set a long timer to
179 // allow them time to complete the
180 // update (probably cycle the
181 // system) if this expires then
182 // task will be cancelled
183 taskData->extendTimer(std::chrono::hours(5));
184 return !task::completed;
185 }
186
Ed Tanous11ba3972022-07-11 09:50:41 -0700187 if (state->ends_with("Active"))
Ed Tanous002d39b2022-05-31 08:59:27 -0700188 {
189 taskData->messages.emplace_back(
190 messages::taskCompletedOK(index));
191 taskData->state = "Completed";
192 return task::completed;
193 }
194 }
195 else if (
196 iface ==
197 "xyz.openbmc_project.Software.ActivationProgress")
198 {
199
200 const uint8_t* progress = nullptr;
201 for (const auto& property : values)
202 {
203 if (property.first == "Progress")
204 {
Ed Tanous8a592812022-06-04 09:06:59 -0700205 const std::string* progressStr =
Ed Tanous002d39b2022-05-31 08:59:27 -0700206 std::get_if<std::string>(
207 &property.second);
Ed Tanous8a592812022-06-04 09:06:59 -0700208 if (progressStr == nullptr)
James Feist32898ce2020-03-10 16:16:52 -0700209 {
James Feist32898ce2020-03-10 16:16:52 -0700210 taskData->messages.emplace_back(
Ed Tanous002d39b2022-05-31 08:59:27 -0700211 messages::internalError());
212 return task::completed;
James Feist32898ce2020-03-10 16:16:52 -0700213 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700214 }
215 }
James Feist32898ce2020-03-10 16:16:52 -0700216
Ed Tanous002d39b2022-05-31 08:59:27 -0700217 if (progress == nullptr)
218 {
219 return !task::completed;
220 }
221 taskData->percentComplete =
222 static_cast<int>(*progress);
223 taskData->messages.emplace_back(
224 messages::taskProgressChanged(
225 index, static_cast<size_t>(*progress)));
James Feist32898ce2020-03-10 16:16:52 -0700226
Ed Tanous002d39b2022-05-31 08:59:27 -0700227 // if we're getting status updates it's
228 // still alive, update timer
229 taskData->extendTimer(std::chrono::minutes(5));
230 }
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.Properties',"
239 "member='PropertiesChanged',path='" +
240 objPath.str + "'");
241 task->startTimer(std::chrono::minutes(5));
242 task->populateResp(asyncResp->res);
243 task->payload.emplace(std::move(payload));
244 }
245 fwUpdateInProgress = false;
Andrew Geissler86adcd62019-04-18 10:58:05 -0500246 },
247 "xyz.openbmc_project.ObjectMapper",
248 "/xyz/openbmc_project/object_mapper",
249 "xyz.openbmc_project.ObjectMapper", "GetObject", objPath.str,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500250 std::array<const char*, 1>{
Andrew Geissler86adcd62019-04-18 10:58:05 -0500251 "xyz.openbmc_project.Software.Activation"});
252 }
253 }
254}
255
Andrew Geissler0554c982019-04-23 14:40:12 -0500256// Note that asyncResp can be either a valid pointer or nullptr. If nullptr
257// then no asyncResp updates will occur
Ed Tanousb5a76932020-09-29 16:16:58 -0700258static void monitorForSoftwareAvailable(
zhanghch058d1b46d2021-04-01 11:18:24 +0800259 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
260 const crow::Request& req, const std::string& url,
261 int timeoutTimeSeconds = 10)
Andrew Geissler86adcd62019-04-18 10:58:05 -0500262{
263 // Only allow one FW update at a time
Ed Tanouse05aec52022-01-25 10:28:56 -0800264 if (fwUpdateInProgress)
Andrew Geissler86adcd62019-04-18 10:58:05 -0500265 {
Andrew Geissler0554c982019-04-23 14:40:12 -0500266 if (asyncResp)
267 {
Andrew Geissler0554c982019-04-23 14:40:12 -0500268 messages::serviceTemporarilyUnavailable(asyncResp->res, "30");
269 }
Andrew Geissler86adcd62019-04-18 10:58:05 -0500270 return;
271 }
272
Andrew Geissler0554c982019-04-23 14:40:12 -0500273 fwAvailableTimer =
Ed Tanous271584a2019-07-09 16:24:22 -0700274 std::make_unique<boost::asio::steady_timer>(*req.ioService);
Andrew Geissler86adcd62019-04-18 10:58:05 -0500275
Ed Tanous271584a2019-07-09 16:24:22 -0700276 fwAvailableTimer->expires_after(std::chrono::seconds(timeoutTimeSeconds));
Andrew Geissler86adcd62019-04-18 10:58:05 -0500277
278 fwAvailableTimer->async_wait(
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500279 [asyncResp](const boost::system::error_code& ec) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700280 cleanUp();
281 if (ec == boost::asio::error::operation_aborted)
282 {
283 // expected, we were canceled before the timer completed.
284 return;
285 }
286 BMCWEB_LOG_ERROR
287 << "Timed out waiting for firmware object being created";
288 BMCWEB_LOG_ERROR << "FW image may has already been uploaded to server";
289 if (ec)
290 {
291 BMCWEB_LOG_ERROR << "Async_wait failed" << ec;
292 return;
293 }
294 if (asyncResp)
295 {
296 redfish::messages::internalError(asyncResp->res);
297 }
298 });
Ed Tanousa3e65892021-09-16 14:13:20 -0700299 task::Payload payload(req);
Patrick Williams59d494e2022-07-22 19:26:55 -0500300 auto callback = [asyncResp, payload](sdbusplus::message_t& m) mutable {
Andrew Geissler86adcd62019-04-18 10:58:05 -0500301 BMCWEB_LOG_DEBUG << "Match fired";
Ed Tanousa3e65892021-09-16 14:13:20 -0700302 softwareInterfaceAdded(asyncResp, m, std::move(payload));
Andrew Geissler86adcd62019-04-18 10:58:05 -0500303 };
304
305 fwUpdateInProgress = true;
306
Patrick Williams59d494e2022-07-22 19:26:55 -0500307 fwUpdateMatcher = std::make_unique<sdbusplus::bus::match_t>(
Andrew Geissler86adcd62019-04-18 10:58:05 -0500308 *crow::connections::systemBus,
309 "interface='org.freedesktop.DBus.ObjectManager',type='signal',"
310 "member='InterfacesAdded',path='/xyz/openbmc_project/software'",
311 callback);
James Feist4cde5d92020-06-11 10:39:55 -0700312
Patrick Williams59d494e2022-07-22 19:26:55 -0500313 fwUpdateErrorMatcher = std::make_unique<sdbusplus::bus::match_t>(
James Feist4cde5d92020-06-11 10:39:55 -0700314 *crow::connections::systemBus,
Brian Mae1cc4822021-12-01 17:05:54 +0800315 "interface='org.freedesktop.DBus.ObjectManager',type='signal',"
316 "member='InterfacesAdded',"
317 "path='/xyz/openbmc_project/logging'",
Patrick Williams59d494e2022-07-22 19:26:55 -0500318 [asyncResp, url](sdbusplus::message_t& m) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700319 std::vector<std::pair<std::string, dbus::utility::DBusPropertiesMap>>
320 interfacesProperties;
321 sdbusplus::message::object_path objPath;
322 m.read(objPath, interfacesProperties);
323 BMCWEB_LOG_DEBUG << "obj path = " << objPath.str;
324 for (const std::pair<std::string, dbus::utility::DBusPropertiesMap>&
325 interface : interfacesProperties)
326 {
327 if (interface.first == "xyz.openbmc_project.Logging.Entry")
James Feist4cde5d92020-06-11 10:39:55 -0700328 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700329 for (const std::pair<std::string,
330 dbus::utility::DbusVariantType>& value :
331 interface.second)
Brian Mae1cc4822021-12-01 17:05:54 +0800332 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700333 if (value.first != "Message")
Brian Mae1cc4822021-12-01 17:05:54 +0800334 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700335 continue;
336 }
337 const std::string* type =
338 std::get_if<std::string>(&value.second);
339 if (type == nullptr)
340 {
341 // if this was our message, timeout will cover it
342 return;
343 }
344 fwAvailableTimer = nullptr;
345 if (*type ==
346 "xyz.openbmc_project.Software.Image.Error.UnTarFailure")
347 {
348 redfish::messages::invalidUpload(asyncResp->res, url,
349 "Invalid archive");
350 }
351 else if (*type ==
352 "xyz.openbmc_project.Software.Image.Error."
353 "ManifestFileFailure")
354 {
355 redfish::messages::invalidUpload(asyncResp->res, url,
356 "Invalid manifest");
357 }
358 else if (
359 *type ==
360 "xyz.openbmc_project.Software.Image.Error.ImageFailure")
361 {
362 redfish::messages::invalidUpload(
363 asyncResp->res, url, "Invalid image format");
364 }
365 else if (
366 *type ==
367 "xyz.openbmc_project.Software.Version.Error.AlreadyExists")
368 {
369 redfish::messages::invalidUpload(
370 asyncResp->res, url,
371 "Image version already exists");
Gunnar Mills88b3dd12020-11-20 14:26:04 -0600372
Ed Tanous002d39b2022-05-31 08:59:27 -0700373 redfish::messages::resourceAlreadyExists(
Jiaqing Zhaod8a5d5d2022-08-05 16:21:51 +0800374 asyncResp->res, "UpdateService", "Version",
Ed Tanous002d39b2022-05-31 08:59:27 -0700375 "uploaded version");
376 }
377 else if (
378 *type ==
379 "xyz.openbmc_project.Software.Image.Error.BusyFailure")
380 {
381 redfish::messages::resourceExhaustion(asyncResp->res,
382 url);
383 }
384 else
385 {
386 redfish::messages::internalError(asyncResp->res);
Brian Mae1cc4822021-12-01 17:05:54 +0800387 }
388 }
Gunnar Mills88b3dd12020-11-20 14:26:04 -0600389 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700390 }
James Feist4cde5d92020-06-11 10:39:55 -0700391 });
Andrew Geissler86adcd62019-04-18 10:58:05 -0500392}
Jennifer Lee729dae72018-04-24 15:59:34 -0700393
Andrew Geissler0554c982019-04-23 14:40:12 -0500394/**
395 * UpdateServiceActionsSimpleUpdate class supports handle POST method for
396 * SimpleUpdate action.
397 */
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700398inline void requestRoutesUpdateServiceActionsSimpleUpdate(App& app)
Andrew Geissler0554c982019-04-23 14:40:12 -0500399{
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700400 BMCWEB_ROUTE(
401 app, "/redfish/v1/UpdateService/Actions/UpdateService.SimpleUpdate/")
Ed Tanoused398212021-06-09 17:05:54 -0700402 .privileges(redfish::privileges::postUpdateService)
Ed Tanous002d39b2022-05-31 08:59:27 -0700403 .methods(boost::beast::http::verb::post)(
404 [&app](const crow::Request& req,
405 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Carson Labrado3ba00072022-06-06 19:40:56 +0000406 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -0700407 {
408 return;
409 }
Ed Tanous45ca1b82022-03-25 13:07:27 -0700410
Ed Tanous002d39b2022-05-31 08:59:27 -0700411 std::optional<std::string> transferProtocol;
412 std::string imageURI;
Andrew Geissler0554c982019-04-23 14:40:12 -0500413
Ed Tanous002d39b2022-05-31 08:59:27 -0700414 BMCWEB_LOG_DEBUG << "Enter UpdateService.SimpleUpdate doPost";
Andrew Geissler0554c982019-04-23 14:40:12 -0500415
Ed Tanous002d39b2022-05-31 08:59:27 -0700416 // User can pass in both TransferProtocol and ImageURI parameters or
417 // they can pass in just the ImageURI with the transfer protocol
418 // embedded within it.
419 // 1) TransferProtocol:TFTP ImageURI:1.1.1.1/myfile.bin
420 // 2) ImageURI:tftp://1.1.1.1/myfile.bin
Andrew Geissler0554c982019-04-23 14:40:12 -0500421
Ed Tanous002d39b2022-05-31 08:59:27 -0700422 if (!json_util::readJsonAction(req, asyncResp->res, "TransferProtocol",
423 transferProtocol, "ImageURI", imageURI))
424 {
425 BMCWEB_LOG_DEBUG
426 << "Missing TransferProtocol or ImageURI parameter";
427 return;
428 }
429 if (!transferProtocol)
430 {
431 // Must be option 2
432 // Verify ImageURI has transfer protocol in it
433 size_t separator = imageURI.find(':');
Andrew Geissler0554c982019-04-23 14:40:12 -0500434 if ((separator == std::string::npos) ||
435 ((separator + 1) > imageURI.size()))
436 {
437 messages::actionParameterValueTypeError(
438 asyncResp->res, imageURI, "ImageURI",
439 "UpdateService.SimpleUpdate");
Ed Tanous002d39b2022-05-31 08:59:27 -0700440 BMCWEB_LOG_ERROR << "ImageURI missing transfer protocol: "
441 << imageURI;
Jayashankar Padath274dfe62019-08-23 12:30:57 +0530442 return;
Jayashankar Padathfa1a5a32019-05-28 23:54:37 +0530443 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700444 transferProtocol = imageURI.substr(0, separator);
445 // Ensure protocol is upper case for a common comparison path
446 // below
447 boost::to_upper(*transferProtocol);
448 BMCWEB_LOG_DEBUG << "Encoded transfer protocol "
449 << *transferProtocol;
Jayashankar Padathfa1a5a32019-05-28 23:54:37 +0530450
Ed Tanous002d39b2022-05-31 08:59:27 -0700451 // Adjust imageURI to not have the protocol on it for parsing
452 // below
453 // ex. tftp://1.1.1.1/myfile.bin -> 1.1.1.1/myfile.bin
454 imageURI = imageURI.substr(separator + 3);
455 BMCWEB_LOG_DEBUG << "Adjusted imageUri " << imageURI;
456 }
Jayashankar Padath274dfe62019-08-23 12:30:57 +0530457
Ed Tanous002d39b2022-05-31 08:59:27 -0700458 // OpenBMC currently only supports TFTP
459 if (*transferProtocol != "TFTP")
460 {
461 messages::actionParameterNotSupported(asyncResp->res,
462 "TransferProtocol",
463 "UpdateService.SimpleUpdate");
464 BMCWEB_LOG_ERROR << "Request incorrect protocol parameter: "
465 << *transferProtocol;
466 return;
467 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700468
Ed Tanous002d39b2022-05-31 08:59:27 -0700469 // Format should be <IP or Hostname>/<file> for imageURI
470 size_t separator = imageURI.find('/');
471 if ((separator == std::string::npos) ||
472 ((separator + 1) > imageURI.size()))
473 {
474 messages::actionParameterValueTypeError(
475 asyncResp->res, imageURI, "ImageURI",
476 "UpdateService.SimpleUpdate");
477 BMCWEB_LOG_ERROR << "Invalid ImageURI: " << imageURI;
478 return;
479 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700480
Ed Tanous002d39b2022-05-31 08:59:27 -0700481 std::string tftpServer = imageURI.substr(0, separator);
482 std::string fwFile = imageURI.substr(separator + 1);
483 BMCWEB_LOG_DEBUG << "Server: " << tftpServer + " File: " << fwFile;
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700484
Ed Tanous002d39b2022-05-31 08:59:27 -0700485 // Setup callback for when new software detected
486 // Give TFTP 10 minutes to complete
487 monitorForSoftwareAvailable(
488 asyncResp, req,
489 "/redfish/v1/UpdateService/Actions/UpdateService.SimpleUpdate",
490 600);
491
492 // TFTP can take up to 10 minutes depending on image size and
493 // connection speed. Return to caller as soon as the TFTP operation
494 // has been started. The callback above will ensure the activate
495 // is started once the download has completed
496 redfish::messages::success(asyncResp->res);
497
498 // Call TFTP service
499 crow::connections::systemBus->async_method_call(
500 [](const boost::system::error_code ec) {
501 if (ec)
502 {
503 // messages::internalError(asyncResp->res);
504 cleanUp();
505 BMCWEB_LOG_DEBUG << "error_code = " << ec;
506 BMCWEB_LOG_DEBUG << "error msg = " << ec.message();
507 }
508 else
509 {
510 BMCWEB_LOG_DEBUG << "Call to DownloaViaTFTP Success";
511 }
512 },
513 "xyz.openbmc_project.Software.Download",
514 "/xyz/openbmc_project/software", "xyz.openbmc_project.Common.TFTP",
515 "DownloadViaTFTP", fwFile, tftpServer);
516
517 BMCWEB_LOG_DEBUG << "Exit UpdateService.SimpleUpdate doPost";
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700518 });
519}
520
Ed Tanousc2051d12022-05-11 12:21:55 -0700521inline void
522 handleUpdateServicePost(App& app, const crow::Request& req,
523 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
524{
Carson Labrado3ba00072022-06-06 19:40:56 +0000525 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanousc2051d12022-05-11 12:21:55 -0700526 {
527 return;
528 }
529 BMCWEB_LOG_DEBUG << "doPost...";
530
531 // Setup callback for when new software detected
532 monitorForSoftwareAvailable(asyncResp, req, "/redfish/v1/UpdateService");
533
534 std::string filepath(
535 "/tmp/images/" +
536 boost::uuids::to_string(boost::uuids::random_generator()()));
537 BMCWEB_LOG_DEBUG << "Writing file to " << filepath;
538 std::ofstream out(filepath, std::ofstream::out | std::ofstream::binary |
539 std::ofstream::trunc);
540 out << req.body;
541 out.close();
542 BMCWEB_LOG_DEBUG << "file upload complete!!";
543}
544
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700545inline void requestRoutesUpdateService(App& app)
546{
547 BMCWEB_ROUTE(app, "/redfish/v1/UpdateService/")
Ed Tanoused398212021-06-09 17:05:54 -0700548 .privileges(redfish::privileges::getUpdateService)
Ed Tanous002d39b2022-05-31 08:59:27 -0700549 .methods(boost::beast::http::verb::get)(
550 [&app](const crow::Request& req,
551 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Carson Labrado3ba00072022-06-06 19:40:56 +0000552 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -0700553 {
554 return;
555 }
556 asyncResp->res.jsonValue["@odata.type"] =
557 "#UpdateService.v1_5_0.UpdateService";
558 asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/UpdateService";
559 asyncResp->res.jsonValue["Id"] = "UpdateService";
560 asyncResp->res.jsonValue["Description"] = "Service for Software Update";
561 asyncResp->res.jsonValue["Name"] = "Update Service";
Ed Tanous4dc23f32022-05-11 11:32:19 -0700562
Ed Tanous32ca38a2022-05-11 12:36:59 -0700563#ifdef BMCWEB_ENABLE_REDFISH_UPDATESERVICE_OLD_POST_URL
Ed Tanous002d39b2022-05-31 08:59:27 -0700564 // See note about later on in this file about why this is neccesary
565 // This is "Wrong" per the standard, but is done temporarily to
566 // avoid noise in failing tests as people transition to having this
567 // option disabled
568 asyncResp->res.addHeader(boost::beast::http::field::allow,
569 "GET, PATCH, HEAD");
Ed Tanous32ca38a2022-05-11 12:36:59 -0700570#endif
571
Ed Tanous002d39b2022-05-31 08:59:27 -0700572 asyncResp->res.jsonValue["HttpPushUri"] =
573 "/redfish/v1/UpdateService/update";
Ed Tanous4dc23f32022-05-11 11:32:19 -0700574
Ed Tanous002d39b2022-05-31 08:59:27 -0700575 // UpdateService cannot be disabled
576 asyncResp->res.jsonValue["ServiceEnabled"] = true;
577 asyncResp->res.jsonValue["FirmwareInventory"]["@odata.id"] =
578 "/redfish/v1/UpdateService/FirmwareInventory";
579 // Get the MaxImageSizeBytes
580 asyncResp->res.jsonValue["MaxImageSizeBytes"] =
581 bmcwebHttpReqBodyLimitMb * 1024 * 1024;
Tejas Patild61e5192021-06-04 15:49:35 +0530582
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700583#ifdef BMCWEB_INSECURE_ENABLE_REDFISH_FW_TFTP_UPDATE
Ed Tanous002d39b2022-05-31 08:59:27 -0700584 // Update Actions object.
585 nlohmann::json& updateSvcSimpleUpdate =
586 asyncResp->res.jsonValue["Actions"]["#UpdateService.SimpleUpdate"];
587 updateSvcSimpleUpdate["target"] =
588 "/redfish/v1/UpdateService/Actions/UpdateService.SimpleUpdate";
589 updateSvcSimpleUpdate["TransferProtocol@Redfish.AllowableValues"] = {
590 "TFTP"};
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700591#endif
Ed Tanous002d39b2022-05-31 08:59:27 -0700592 // Get the current ApplyTime value
593 sdbusplus::asio::getProperty<std::string>(
594 *crow::connections::systemBus, "xyz.openbmc_project.Settings",
595 "/xyz/openbmc_project/software/apply_time",
596 "xyz.openbmc_project.Software.ApplyTime", "RequestedApplyTime",
597 [asyncResp](const boost::system::error_code ec,
598 const std::string& applyTime) {
599 if (ec)
600 {
601 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
602 messages::internalError(asyncResp->res);
603 return;
604 }
Jayashankar Padath274dfe62019-08-23 12:30:57 +0530605
Ed Tanous002d39b2022-05-31 08:59:27 -0700606 // Store the ApplyTime Value
607 if (applyTime == "xyz.openbmc_project.Software.ApplyTime."
608 "RequestedApplyTimes.Immediate")
609 {
610 asyncResp->res.jsonValue["HttpPushUriOptions"]
611 ["HttpPushUriApplyTime"]["ApplyTime"] =
612 "Immediate";
613 }
614 else if (applyTime == "xyz.openbmc_project.Software.ApplyTime."
615 "RequestedApplyTimes.OnReset")
616 {
617 asyncResp->res.jsonValue["HttpPushUriOptions"]
618 ["HttpPushUriApplyTime"]["ApplyTime"] =
619 "OnReset";
620 }
621 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700622 });
623 BMCWEB_ROUTE(app, "/redfish/v1/UpdateService/")
Ed Tanoused398212021-06-09 17:05:54 -0700624 .privileges(redfish::privileges::patchUpdateService)
Ed Tanous002d39b2022-05-31 08:59:27 -0700625 .methods(boost::beast::http::verb::patch)(
626 [&app](const crow::Request& req,
627 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Carson Labrado3ba00072022-06-06 19:40:56 +0000628 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -0700629 {
630 return;
631 }
632 BMCWEB_LOG_DEBUG << "doPatch...";
Jayashankar Padathfa1a5a32019-05-28 23:54:37 +0530633
Ed Tanous002d39b2022-05-31 08:59:27 -0700634 std::optional<nlohmann::json> pushUriOptions;
635 if (!json_util::readJsonPatch(req, asyncResp->res, "HttpPushUriOptions",
636 pushUriOptions))
637 {
638 return;
639 }
640
641 if (pushUriOptions)
642 {
643 std::optional<nlohmann::json> pushUriApplyTime;
644 if (!json_util::readJson(*pushUriOptions, asyncResp->res,
645 "HttpPushUriApplyTime", pushUriApplyTime))
George Liu0fda0f12021-11-16 10:06:17 +0800646 {
647 return;
648 }
649
Ed Tanous002d39b2022-05-31 08:59:27 -0700650 if (pushUriApplyTime)
George Liu0fda0f12021-11-16 10:06:17 +0800651 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700652 std::optional<std::string> applyTime;
653 if (!json_util::readJson(*pushUriApplyTime, asyncResp->res,
654 "ApplyTime", applyTime))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700655 {
Ed Tanousc711bf82018-07-30 16:31:33 -0700656 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700657 }
Jennifer Lee6c4eb9d2018-05-22 10:58:31 -0700658
Ed Tanous002d39b2022-05-31 08:59:27 -0700659 if (applyTime)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700660 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700661 std::string applyTimeNewVal;
662 if (applyTime == "Immediate")
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700663 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700664 applyTimeNewVal =
665 "xyz.openbmc_project.Software.ApplyTime.RequestedApplyTimes.Immediate";
666 }
667 else if (applyTime == "OnReset")
668 {
669 applyTimeNewVal =
670 "xyz.openbmc_project.Software.ApplyTime.RequestedApplyTimes.OnReset";
671 }
672 else
673 {
674 BMCWEB_LOG_INFO
675 << "ApplyTime value is not in the list of acceptable values";
676 messages::propertyValueNotInList(
677 asyncResp->res, *applyTime, "ApplyTime");
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700678 return;
679 }
680
Ed Tanous002d39b2022-05-31 08:59:27 -0700681 // Set the requested image apply time value
682 crow::connections::systemBus->async_method_call(
683 [asyncResp](const boost::system::error_code ec) {
684 if (ec)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700685 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700686 BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec;
687 messages::internalError(asyncResp->res);
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700688 return;
689 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700690 messages::success(asyncResp->res);
691 },
692 "xyz.openbmc_project.Settings",
693 "/xyz/openbmc_project/software/apply_time",
694 "org.freedesktop.DBus.Properties", "Set",
695 "xyz.openbmc_project.Software.ApplyTime",
696 "RequestedApplyTime",
697 dbus::utility::DbusVariantType{applyTimeNewVal});
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700698 }
George Liu0fda0f12021-11-16 10:06:17 +0800699 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700700 }
George Liu0fda0f12021-11-16 10:06:17 +0800701 });
Ed Tanousc2051d12022-05-11 12:21:55 -0700702
Ed Tanous4dc23f32022-05-11 11:32:19 -0700703// The "old" behavior of the update service URI causes redfish-service validator
704// failures when the Allow header is supported, given that in the spec,
705// UpdateService does not allow POST. in openbmc, we unfortunately reused that
706// resource as our HttpPushUri as well. A number of services, including the
707// openbmc tests, and documentation have hardcoded that erroneous API, instead
708// of relying on HttpPushUri as the spec requires. This option will exist
709// temporarily to allow the old behavior until Q4 2022, at which time it will be
710// removed.
711#ifdef BMCWEB_ENABLE_REDFISH_UPDATESERVICE_OLD_POST_URL
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700712 BMCWEB_ROUTE(app, "/redfish/v1/UpdateService/")
Ed Tanoused398212021-06-09 17:05:54 -0700713 .privileges(redfish::privileges::postUpdateService)
Ed Tanous002d39b2022-05-31 08:59:27 -0700714 .methods(boost::beast::http::verb::post)(
715 [&app](const crow::Request& req,
716 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
717 asyncResp->res.addHeader(
718 boost::beast::http::field::warning,
719 "299 - \"POST to /redfish/v1/UpdateService is deprecated. Use "
720 "the value contained within HttpPushUri.\"");
721 handleUpdateServicePost(app, req, asyncResp);
Ed Tanous4dc23f32022-05-11 11:32:19 -0700722 });
723#endif
724 BMCWEB_ROUTE(app, "/redfish/v1/UpdateService/update/")
725 .privileges(redfish::privileges::postUpdateService)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700726 .methods(boost::beast::http::verb::post)(
Ed Tanousc2051d12022-05-11 12:21:55 -0700727 std::bind_front(handleUpdateServicePost, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700728}
729
730inline void requestRoutesSoftwareInventoryCollection(App& app)
731{
732 BMCWEB_ROUTE(app, "/redfish/v1/UpdateService/FirmwareInventory/")
Ed Tanoused398212021-06-09 17:05:54 -0700733 .privileges(redfish::privileges::getSoftwareInventoryCollection)
Ed Tanous14766872022-03-15 10:44:42 -0700734 .methods(boost::beast::http::verb::get)(
735 [&app](const crow::Request& req,
736 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Carson Labrado3ba00072022-06-06 19:40:56 +0000737 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -0700738 {
739 return;
740 }
741 asyncResp->res.jsonValue["@odata.type"] =
742 "#SoftwareInventoryCollection.SoftwareInventoryCollection";
743 asyncResp->res.jsonValue["@odata.id"] =
744 "/redfish/v1/UpdateService/FirmwareInventory";
745 asyncResp->res.jsonValue["Name"] = "Software Inventory Collection";
746
747 crow::connections::systemBus->async_method_call(
748 [asyncResp](
749 const boost::system::error_code ec,
750 const dbus::utility::MapperGetSubTreeResponse& subtree) {
751 if (ec)
752 {
753 messages::internalError(asyncResp->res);
754 return;
755 }
756 asyncResp->res.jsonValue["Members"] = nlohmann::json::array();
757 asyncResp->res.jsonValue["Members@odata.count"] = 0;
758
759 for (const auto& obj : subtree)
760 {
761 sdbusplus::message::object_path path(obj.first);
762 std::string swId = path.filename();
763 if (swId.empty())
Ed Tanous14766872022-03-15 10:44:42 -0700764 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700765 messages::internalError(asyncResp->res);
766 BMCWEB_LOG_DEBUG << "Can't parse firmware ID!!";
Ed Tanous14766872022-03-15 10:44:42 -0700767 return;
768 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700769
Ed Tanous002d39b2022-05-31 08:59:27 -0700770 nlohmann::json& members = asyncResp->res.jsonValue["Members"];
771 nlohmann::json::object_t member;
772 member["@odata.id"] =
773 "/redfish/v1/UpdateService/FirmwareInventory/" + swId;
774 members.push_back(std::move(member));
775 asyncResp->res.jsonValue["Members@odata.count"] =
776 members.size();
777 }
778 },
779 // Note that only firmware levels associated with a device
780 // are stored under /xyz/openbmc_project/software therefore
781 // to ensure only real FirmwareInventory items are returned,
782 // this full object path must be used here as input to
783 // mapper
784 "xyz.openbmc_project.ObjectMapper",
785 "/xyz/openbmc_project/object_mapper",
786 "xyz.openbmc_project.ObjectMapper", "GetSubTree",
787 "/xyz/openbmc_project/software", static_cast<int32_t>(0),
788 std::array<const char*, 1>{"xyz.openbmc_project.Software.Version"});
789 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700790}
791/* Fill related item links (i.e. bmc, bios) in for inventory */
792inline static void
793 getRelatedItems(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
794 const std::string& purpose)
795{
Willy Tueee00132022-06-14 14:53:17 -0700796 if (purpose == sw_util::bmcPurpose)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700797 {
798 nlohmann::json& relatedItem = aResp->res.jsonValue["RelatedItem"];
Ed Tanous14766872022-03-15 10:44:42 -0700799 nlohmann::json::object_t item;
800 item["@odata.id"] = "/redfish/v1/Managers/bmc";
801 relatedItem.push_back(std::move(item));
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700802 aResp->res.jsonValue["RelatedItem@odata.count"] = relatedItem.size();
803 }
Willy Tueee00132022-06-14 14:53:17 -0700804 else if (purpose == sw_util::biosPurpose)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700805 {
806 nlohmann::json& relatedItem = aResp->res.jsonValue["RelatedItem"];
Ed Tanous14766872022-03-15 10:44:42 -0700807 nlohmann::json::object_t item;
808 item["@odata.id"] = "/redfish/v1/Systems/system/Bios";
809 relatedItem.push_back(std::move(item));
Jiaqing Zhao1a6e51a2022-01-19 19:20:24 +0800810 aResp->res.jsonValue["RelatedItem@odata.count"] = relatedItem.size();
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700811 }
812 else
813 {
814 BMCWEB_LOG_ERROR << "Unknown software purpose " << purpose;
815 }
816}
817
Willy Tuaf246602022-06-14 15:51:53 -0700818inline void
819 getSoftwareVersion(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
820 const std::string& service, const std::string& path,
821 const std::string& swId)
822{
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +0200823 sdbusplus::asio::getAllProperties(
824 *crow::connections::systemBus, service, path,
825 "xyz.openbmc_project.Software.Version",
Willy Tuaf246602022-06-14 15:51:53 -0700826 [asyncResp,
827 swId](const boost::system::error_code errorCode,
828 const dbus::utility::DBusPropertiesMap& propertiesList) {
829 if (errorCode)
830 {
831 messages::internalError(asyncResp->res);
832 return;
833 }
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +0200834
Willy Tuaf246602022-06-14 15:51:53 -0700835 const std::string* swInvPurpose = nullptr;
836 const std::string* version = nullptr;
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +0200837
838 const bool success = sdbusplus::unpackPropertiesNoThrow(
839 dbus_utils::UnpackErrorPrinter(), propertiesList, "Purpose",
840 swInvPurpose, "Version", version);
841
842 if (!success)
Willy Tuaf246602022-06-14 15:51:53 -0700843 {
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +0200844 messages::internalError(asyncResp->res);
845 return;
Willy Tuaf246602022-06-14 15:51:53 -0700846 }
847
848 if (swInvPurpose == nullptr)
849 {
850 BMCWEB_LOG_DEBUG << "Can't find property \"Purpose\"!";
851 messages::internalError(asyncResp->res);
852 return;
853 }
854
855 BMCWEB_LOG_DEBUG << "swInvPurpose = " << *swInvPurpose;
856
857 if (version == nullptr)
858 {
859 BMCWEB_LOG_DEBUG << "Can't find property \"Version\"!";
860
861 messages::internalError(asyncResp->res);
862
863 return;
864 }
865 asyncResp->res.jsonValue["Version"] = *version;
866 asyncResp->res.jsonValue["Id"] = swId;
867
868 // swInvPurpose is of format:
869 // xyz.openbmc_project.Software.Version.VersionPurpose.ABC
870 // Translate this to "ABC image"
871 size_t endDesc = swInvPurpose->rfind('.');
872 if (endDesc == std::string::npos)
873 {
874 messages::internalError(asyncResp->res);
875 return;
876 }
877 endDesc++;
878 if (endDesc >= swInvPurpose->size())
879 {
880 messages::internalError(asyncResp->res);
881 return;
882 }
883
884 std::string formatDesc = swInvPurpose->substr(endDesc);
885 asyncResp->res.jsonValue["Description"] = formatDesc + " image";
886 getRelatedItems(asyncResp, *swInvPurpose);
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +0200887 });
Willy Tuaf246602022-06-14 15:51:53 -0700888}
889
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700890inline void requestRoutesSoftwareInventory(App& app)
891{
892 BMCWEB_ROUTE(app, "/redfish/v1/UpdateService/FirmwareInventory/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -0700893 .privileges(redfish::privileges::getSoftwareInventory)
Ed Tanous002d39b2022-05-31 08:59:27 -0700894 .methods(boost::beast::http::verb::get)(
895 [&app](const crow::Request& req,
896 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
897 const std::string& param) {
Carson Labrado3ba00072022-06-06 19:40:56 +0000898 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -0700899 {
900 return;
901 }
902 std::shared_ptr<std::string> swId =
903 std::make_shared<std::string>(param);
904
905 asyncResp->res.jsonValue["@odata.id"] =
906 "/redfish/v1/UpdateService/FirmwareInventory/" + *swId;
907
908 crow::connections::systemBus->async_method_call(
909 [asyncResp,
910 swId](const boost::system::error_code ec,
911 const dbus::utility::MapperGetSubTreeResponse& subtree) {
912 BMCWEB_LOG_DEBUG << "doGet callback...";
913 if (ec)
Ed Tanous45ca1b82022-03-25 13:07:27 -0700914 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700915 messages::internalError(asyncResp->res);
Ed Tanous45ca1b82022-03-25 13:07:27 -0700916 return;
917 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700918
Ed Tanous002d39b2022-05-31 08:59:27 -0700919 // Ensure we find our input swId, otherwise return an error
920 bool found = false;
921 for (const std::pair<std::string,
922 std::vector<std::pair<
923 std::string, std::vector<std::string>>>>&
924 obj : subtree)
925 {
Ed Tanous11ba3972022-07-11 09:50:41 -0700926 if (!obj.first.ends_with(*swId))
Ed Tanous002d39b2022-05-31 08:59:27 -0700927 {
928 continue;
929 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700930
Ed Tanous002d39b2022-05-31 08:59:27 -0700931 if (obj.second.empty())
932 {
933 continue;
934 }
935
936 found = true;
Willy Tueee00132022-06-14 14:53:17 -0700937 sw_util::getSwStatus(asyncResp, swId, obj.second[0].first);
Willy Tuaf246602022-06-14 15:51:53 -0700938 getSoftwareVersion(asyncResp, obj.second[0].first, obj.first,
939 *swId);
Ed Tanous002d39b2022-05-31 08:59:27 -0700940 }
941 if (!found)
942 {
943 BMCWEB_LOG_ERROR << "Input swID " << *swId << " not found!";
944 messages::resourceMissingAtURI(
945 asyncResp->res, crow::utility::urlFromPieces(
946 "redfish", "v1", "UpdateService",
947 "FirmwareInventory", *swId));
948 return;
949 }
950 asyncResp->res.jsonValue["@odata.type"] =
951 "#SoftwareInventory.v1_1_0.SoftwareInventory";
952 asyncResp->res.jsonValue["Name"] = "Software Inventory";
953 asyncResp->res.jsonValue["Status"]["HealthRollup"] = "OK";
Ed Tanous1abe55e2018-09-05 08:30:59 -0700954
Ed Tanous002d39b2022-05-31 08:59:27 -0700955 asyncResp->res.jsonValue["Updateable"] = false;
Willy Tueee00132022-06-14 14:53:17 -0700956 sw_util::getSwUpdatableStatus(asyncResp, swId);
Ed Tanous002d39b2022-05-31 08:59:27 -0700957 },
958 "xyz.openbmc_project.ObjectMapper",
959 "/xyz/openbmc_project/object_mapper",
960 "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/",
961 static_cast<int32_t>(0),
962 std::array<const char*, 1>{"xyz.openbmc_project.Software.Version"});
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700963 });
964}
Ed Tanous1abe55e2018-09-05 08:30:59 -0700965
966} // namespace redfish