blob: ab99dc306a14f2ab7e8c07c386bd0c081069892d [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"});
Patrick Williams62bafc02022-09-08 17:35:35 -0500252
253 break;
Andrew Geissler86adcd62019-04-18 10:58:05 -0500254 }
255 }
256}
257
Andrew Geissler0554c982019-04-23 14:40:12 -0500258// Note that asyncResp can be either a valid pointer or nullptr. If nullptr
259// then no asyncResp updates will occur
Ed Tanousb5a76932020-09-29 16:16:58 -0700260static void monitorForSoftwareAvailable(
zhanghch058d1b46d2021-04-01 11:18:24 +0800261 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
262 const crow::Request& req, const std::string& url,
263 int timeoutTimeSeconds = 10)
Andrew Geissler86adcd62019-04-18 10:58:05 -0500264{
265 // Only allow one FW update at a time
Ed Tanouse05aec52022-01-25 10:28:56 -0800266 if (fwUpdateInProgress)
Andrew Geissler86adcd62019-04-18 10:58:05 -0500267 {
Andrew Geissler0554c982019-04-23 14:40:12 -0500268 if (asyncResp)
269 {
Andrew Geissler0554c982019-04-23 14:40:12 -0500270 messages::serviceTemporarilyUnavailable(asyncResp->res, "30");
271 }
Andrew Geissler86adcd62019-04-18 10:58:05 -0500272 return;
273 }
274
Andrew Geissler0554c982019-04-23 14:40:12 -0500275 fwAvailableTimer =
Ed Tanous271584a2019-07-09 16:24:22 -0700276 std::make_unique<boost::asio::steady_timer>(*req.ioService);
Andrew Geissler86adcd62019-04-18 10:58:05 -0500277
Ed Tanous271584a2019-07-09 16:24:22 -0700278 fwAvailableTimer->expires_after(std::chrono::seconds(timeoutTimeSeconds));
Andrew Geissler86adcd62019-04-18 10:58:05 -0500279
280 fwAvailableTimer->async_wait(
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500281 [asyncResp](const boost::system::error_code& ec) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700282 cleanUp();
283 if (ec == boost::asio::error::operation_aborted)
284 {
285 // expected, we were canceled before the timer completed.
286 return;
287 }
288 BMCWEB_LOG_ERROR
289 << "Timed out waiting for firmware object being created";
290 BMCWEB_LOG_ERROR << "FW image may has already been uploaded to server";
291 if (ec)
292 {
293 BMCWEB_LOG_ERROR << "Async_wait failed" << ec;
294 return;
295 }
296 if (asyncResp)
297 {
298 redfish::messages::internalError(asyncResp->res);
299 }
300 });
Ed Tanousa3e65892021-09-16 14:13:20 -0700301 task::Payload payload(req);
Patrick Williams59d494e2022-07-22 19:26:55 -0500302 auto callback = [asyncResp, payload](sdbusplus::message_t& m) mutable {
Andrew Geissler86adcd62019-04-18 10:58:05 -0500303 BMCWEB_LOG_DEBUG << "Match fired";
Ed Tanousa3e65892021-09-16 14:13:20 -0700304 softwareInterfaceAdded(asyncResp, m, std::move(payload));
Andrew Geissler86adcd62019-04-18 10:58:05 -0500305 };
306
307 fwUpdateInProgress = true;
308
Patrick Williams59d494e2022-07-22 19:26:55 -0500309 fwUpdateMatcher = std::make_unique<sdbusplus::bus::match_t>(
Andrew Geissler86adcd62019-04-18 10:58:05 -0500310 *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
Patrick Williams59d494e2022-07-22 19:26:55 -0500315 fwUpdateErrorMatcher = std::make_unique<sdbusplus::bus::match_t>(
James Feist4cde5d92020-06-11 10:39:55 -0700316 *crow::connections::systemBus,
Brian Mae1cc4822021-12-01 17:05:54 +0800317 "interface='org.freedesktop.DBus.ObjectManager',type='signal',"
318 "member='InterfacesAdded',"
319 "path='/xyz/openbmc_project/logging'",
Patrick Williams59d494e2022-07-22 19:26:55 -0500320 [asyncResp, url](sdbusplus::message_t& m) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700321 std::vector<std::pair<std::string, dbus::utility::DBusPropertiesMap>>
322 interfacesProperties;
323 sdbusplus::message::object_path objPath;
324 m.read(objPath, interfacesProperties);
325 BMCWEB_LOG_DEBUG << "obj path = " << objPath.str;
326 for (const std::pair<std::string, dbus::utility::DBusPropertiesMap>&
327 interface : interfacesProperties)
328 {
329 if (interface.first == "xyz.openbmc_project.Logging.Entry")
James Feist4cde5d92020-06-11 10:39:55 -0700330 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700331 for (const std::pair<std::string,
332 dbus::utility::DbusVariantType>& value :
333 interface.second)
Brian Mae1cc4822021-12-01 17:05:54 +0800334 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700335 if (value.first != "Message")
Brian Mae1cc4822021-12-01 17:05:54 +0800336 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700337 continue;
338 }
339 const std::string* type =
340 std::get_if<std::string>(&value.second);
341 if (type == nullptr)
342 {
343 // if this was our message, timeout will cover it
344 return;
345 }
346 fwAvailableTimer = nullptr;
347 if (*type ==
348 "xyz.openbmc_project.Software.Image.Error.UnTarFailure")
349 {
350 redfish::messages::invalidUpload(asyncResp->res, url,
351 "Invalid archive");
352 }
353 else if (*type ==
354 "xyz.openbmc_project.Software.Image.Error."
355 "ManifestFileFailure")
356 {
357 redfish::messages::invalidUpload(asyncResp->res, url,
358 "Invalid manifest");
359 }
360 else if (
361 *type ==
362 "xyz.openbmc_project.Software.Image.Error.ImageFailure")
363 {
364 redfish::messages::invalidUpload(
365 asyncResp->res, url, "Invalid image format");
366 }
367 else if (
368 *type ==
369 "xyz.openbmc_project.Software.Version.Error.AlreadyExists")
370 {
371 redfish::messages::invalidUpload(
372 asyncResp->res, url,
373 "Image version already exists");
Gunnar Mills88b3dd12020-11-20 14:26:04 -0600374
Ed Tanous002d39b2022-05-31 08:59:27 -0700375 redfish::messages::resourceAlreadyExists(
Jiaqing Zhaod8a5d5d2022-08-05 16:21:51 +0800376 asyncResp->res, "UpdateService", "Version",
Ed Tanous002d39b2022-05-31 08:59:27 -0700377 "uploaded version");
378 }
379 else if (
380 *type ==
381 "xyz.openbmc_project.Software.Image.Error.BusyFailure")
382 {
383 redfish::messages::resourceExhaustion(asyncResp->res,
384 url);
385 }
386 else
387 {
388 redfish::messages::internalError(asyncResp->res);
Brian Mae1cc4822021-12-01 17:05:54 +0800389 }
390 }
Gunnar Mills88b3dd12020-11-20 14:26:04 -0600391 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700392 }
James Feist4cde5d92020-06-11 10:39:55 -0700393 });
Andrew Geissler86adcd62019-04-18 10:58:05 -0500394}
Jennifer Lee729dae72018-04-24 15:59:34 -0700395
Andrew Geissler0554c982019-04-23 14:40:12 -0500396/**
397 * UpdateServiceActionsSimpleUpdate class supports handle POST method for
398 * SimpleUpdate action.
399 */
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700400inline void requestRoutesUpdateServiceActionsSimpleUpdate(App& app)
Andrew Geissler0554c982019-04-23 14:40:12 -0500401{
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700402 BMCWEB_ROUTE(
403 app, "/redfish/v1/UpdateService/Actions/UpdateService.SimpleUpdate/")
Ed Tanoused398212021-06-09 17:05:54 -0700404 .privileges(redfish::privileges::postUpdateService)
Ed Tanous002d39b2022-05-31 08:59:27 -0700405 .methods(boost::beast::http::verb::post)(
406 [&app](const crow::Request& req,
407 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Carson Labrado3ba00072022-06-06 19:40:56 +0000408 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -0700409 {
410 return;
411 }
Ed Tanous45ca1b82022-03-25 13:07:27 -0700412
Ed Tanous002d39b2022-05-31 08:59:27 -0700413 std::optional<std::string> transferProtocol;
414 std::string imageURI;
Andrew Geissler0554c982019-04-23 14:40:12 -0500415
Ed Tanous002d39b2022-05-31 08:59:27 -0700416 BMCWEB_LOG_DEBUG << "Enter UpdateService.SimpleUpdate doPost";
Andrew Geissler0554c982019-04-23 14:40:12 -0500417
Ed Tanous002d39b2022-05-31 08:59:27 -0700418 // User can pass in both TransferProtocol and ImageURI parameters or
419 // they can pass in just the ImageURI with the transfer protocol
420 // embedded within it.
421 // 1) TransferProtocol:TFTP ImageURI:1.1.1.1/myfile.bin
422 // 2) ImageURI:tftp://1.1.1.1/myfile.bin
Andrew Geissler0554c982019-04-23 14:40:12 -0500423
Ed Tanous002d39b2022-05-31 08:59:27 -0700424 if (!json_util::readJsonAction(req, asyncResp->res, "TransferProtocol",
425 transferProtocol, "ImageURI", imageURI))
426 {
427 BMCWEB_LOG_DEBUG
428 << "Missing TransferProtocol or ImageURI parameter";
429 return;
430 }
431 if (!transferProtocol)
432 {
433 // Must be option 2
434 // Verify ImageURI has transfer protocol in it
435 size_t separator = imageURI.find(':');
Andrew Geissler0554c982019-04-23 14:40:12 -0500436 if ((separator == std::string::npos) ||
437 ((separator + 1) > imageURI.size()))
438 {
439 messages::actionParameterValueTypeError(
440 asyncResp->res, imageURI, "ImageURI",
441 "UpdateService.SimpleUpdate");
Ed Tanous002d39b2022-05-31 08:59:27 -0700442 BMCWEB_LOG_ERROR << "ImageURI missing transfer protocol: "
443 << imageURI;
Jayashankar Padath274dfe62019-08-23 12:30:57 +0530444 return;
Jayashankar Padathfa1a5a32019-05-28 23:54:37 +0530445 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700446 transferProtocol = imageURI.substr(0, separator);
447 // Ensure protocol is upper case for a common comparison path
448 // below
449 boost::to_upper(*transferProtocol);
450 BMCWEB_LOG_DEBUG << "Encoded transfer protocol "
451 << *transferProtocol;
Jayashankar Padathfa1a5a32019-05-28 23:54:37 +0530452
Ed Tanous002d39b2022-05-31 08:59:27 -0700453 // Adjust imageURI to not have the protocol on it for parsing
454 // below
455 // ex. tftp://1.1.1.1/myfile.bin -> 1.1.1.1/myfile.bin
456 imageURI = imageURI.substr(separator + 3);
457 BMCWEB_LOG_DEBUG << "Adjusted imageUri " << imageURI;
458 }
Jayashankar Padath274dfe62019-08-23 12:30:57 +0530459
Ed Tanous002d39b2022-05-31 08:59:27 -0700460 // OpenBMC currently only supports TFTP
461 if (*transferProtocol != "TFTP")
462 {
463 messages::actionParameterNotSupported(asyncResp->res,
464 "TransferProtocol",
465 "UpdateService.SimpleUpdate");
466 BMCWEB_LOG_ERROR << "Request incorrect protocol parameter: "
467 << *transferProtocol;
468 return;
469 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700470
Ed Tanous002d39b2022-05-31 08:59:27 -0700471 // Format should be <IP or Hostname>/<file> for imageURI
472 size_t separator = imageURI.find('/');
473 if ((separator == std::string::npos) ||
474 ((separator + 1) > imageURI.size()))
475 {
476 messages::actionParameterValueTypeError(
477 asyncResp->res, imageURI, "ImageURI",
478 "UpdateService.SimpleUpdate");
479 BMCWEB_LOG_ERROR << "Invalid ImageURI: " << imageURI;
480 return;
481 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700482
Ed Tanous002d39b2022-05-31 08:59:27 -0700483 std::string tftpServer = imageURI.substr(0, separator);
484 std::string fwFile = imageURI.substr(separator + 1);
485 BMCWEB_LOG_DEBUG << "Server: " << tftpServer + " File: " << fwFile;
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700486
Ed Tanous002d39b2022-05-31 08:59:27 -0700487 // Setup callback for when new software detected
488 // Give TFTP 10 minutes to complete
489 monitorForSoftwareAvailable(
490 asyncResp, req,
491 "/redfish/v1/UpdateService/Actions/UpdateService.SimpleUpdate",
492 600);
493
494 // TFTP can take up to 10 minutes depending on image size and
495 // connection speed. Return to caller as soon as the TFTP operation
496 // has been started. The callback above will ensure the activate
497 // is started once the download has completed
498 redfish::messages::success(asyncResp->res);
499
500 // Call TFTP service
501 crow::connections::systemBus->async_method_call(
502 [](const boost::system::error_code ec) {
503 if (ec)
504 {
505 // messages::internalError(asyncResp->res);
506 cleanUp();
507 BMCWEB_LOG_DEBUG << "error_code = " << ec;
508 BMCWEB_LOG_DEBUG << "error msg = " << ec.message();
509 }
510 else
511 {
512 BMCWEB_LOG_DEBUG << "Call to DownloaViaTFTP Success";
513 }
514 },
515 "xyz.openbmc_project.Software.Download",
516 "/xyz/openbmc_project/software", "xyz.openbmc_project.Common.TFTP",
517 "DownloadViaTFTP", fwFile, tftpServer);
518
519 BMCWEB_LOG_DEBUG << "Exit UpdateService.SimpleUpdate doPost";
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700520 });
521}
522
Ed Tanousc2051d12022-05-11 12:21:55 -0700523inline void
524 handleUpdateServicePost(App& app, const crow::Request& req,
525 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
526{
Carson Labrado3ba00072022-06-06 19:40:56 +0000527 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanousc2051d12022-05-11 12:21:55 -0700528 {
529 return;
530 }
531 BMCWEB_LOG_DEBUG << "doPost...";
532
533 // Setup callback for when new software detected
534 monitorForSoftwareAvailable(asyncResp, req, "/redfish/v1/UpdateService");
535
536 std::string filepath(
537 "/tmp/images/" +
538 boost::uuids::to_string(boost::uuids::random_generator()()));
539 BMCWEB_LOG_DEBUG << "Writing file to " << filepath;
540 std::ofstream out(filepath, std::ofstream::out | std::ofstream::binary |
541 std::ofstream::trunc);
542 out << req.body;
543 out.close();
544 BMCWEB_LOG_DEBUG << "file upload complete!!";
545}
546
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700547inline void requestRoutesUpdateService(App& app)
548{
549 BMCWEB_ROUTE(app, "/redfish/v1/UpdateService/")
Ed Tanoused398212021-06-09 17:05:54 -0700550 .privileges(redfish::privileges::getUpdateService)
Ed Tanous002d39b2022-05-31 08:59:27 -0700551 .methods(boost::beast::http::verb::get)(
552 [&app](const crow::Request& req,
553 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Carson Labrado3ba00072022-06-06 19:40:56 +0000554 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -0700555 {
556 return;
557 }
558 asyncResp->res.jsonValue["@odata.type"] =
559 "#UpdateService.v1_5_0.UpdateService";
560 asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/UpdateService";
561 asyncResp->res.jsonValue["Id"] = "UpdateService";
562 asyncResp->res.jsonValue["Description"] = "Service for Software Update";
563 asyncResp->res.jsonValue["Name"] = "Update Service";
Ed Tanous4dc23f32022-05-11 11:32:19 -0700564
Ed Tanous32ca38a2022-05-11 12:36:59 -0700565#ifdef BMCWEB_ENABLE_REDFISH_UPDATESERVICE_OLD_POST_URL
Ed Tanous002d39b2022-05-31 08:59:27 -0700566 // See note about later on in this file about why this is neccesary
567 // This is "Wrong" per the standard, but is done temporarily to
568 // avoid noise in failing tests as people transition to having this
569 // option disabled
570 asyncResp->res.addHeader(boost::beast::http::field::allow,
571 "GET, PATCH, HEAD");
Ed Tanous32ca38a2022-05-11 12:36:59 -0700572#endif
573
Ed Tanous002d39b2022-05-31 08:59:27 -0700574 asyncResp->res.jsonValue["HttpPushUri"] =
575 "/redfish/v1/UpdateService/update";
Ed Tanous4dc23f32022-05-11 11:32:19 -0700576
Ed Tanous002d39b2022-05-31 08:59:27 -0700577 // UpdateService cannot be disabled
578 asyncResp->res.jsonValue["ServiceEnabled"] = true;
579 asyncResp->res.jsonValue["FirmwareInventory"]["@odata.id"] =
580 "/redfish/v1/UpdateService/FirmwareInventory";
581 // Get the MaxImageSizeBytes
582 asyncResp->res.jsonValue["MaxImageSizeBytes"] =
583 bmcwebHttpReqBodyLimitMb * 1024 * 1024;
Tejas Patild61e5192021-06-04 15:49:35 +0530584
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700585#ifdef BMCWEB_INSECURE_ENABLE_REDFISH_FW_TFTP_UPDATE
Ed Tanous002d39b2022-05-31 08:59:27 -0700586 // Update Actions object.
587 nlohmann::json& updateSvcSimpleUpdate =
588 asyncResp->res.jsonValue["Actions"]["#UpdateService.SimpleUpdate"];
589 updateSvcSimpleUpdate["target"] =
590 "/redfish/v1/UpdateService/Actions/UpdateService.SimpleUpdate";
591 updateSvcSimpleUpdate["TransferProtocol@Redfish.AllowableValues"] = {
592 "TFTP"};
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700593#endif
Ed Tanous002d39b2022-05-31 08:59:27 -0700594 // Get the current ApplyTime value
595 sdbusplus::asio::getProperty<std::string>(
596 *crow::connections::systemBus, "xyz.openbmc_project.Settings",
597 "/xyz/openbmc_project/software/apply_time",
598 "xyz.openbmc_project.Software.ApplyTime", "RequestedApplyTime",
599 [asyncResp](const boost::system::error_code ec,
600 const std::string& applyTime) {
601 if (ec)
602 {
603 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
604 messages::internalError(asyncResp->res);
605 return;
606 }
Jayashankar Padath274dfe62019-08-23 12:30:57 +0530607
Ed Tanous002d39b2022-05-31 08:59:27 -0700608 // Store the ApplyTime Value
609 if (applyTime == "xyz.openbmc_project.Software.ApplyTime."
610 "RequestedApplyTimes.Immediate")
611 {
612 asyncResp->res.jsonValue["HttpPushUriOptions"]
613 ["HttpPushUriApplyTime"]["ApplyTime"] =
614 "Immediate";
615 }
616 else if (applyTime == "xyz.openbmc_project.Software.ApplyTime."
617 "RequestedApplyTimes.OnReset")
618 {
619 asyncResp->res.jsonValue["HttpPushUriOptions"]
620 ["HttpPushUriApplyTime"]["ApplyTime"] =
621 "OnReset";
622 }
623 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700624 });
625 BMCWEB_ROUTE(app, "/redfish/v1/UpdateService/")
Ed Tanoused398212021-06-09 17:05:54 -0700626 .privileges(redfish::privileges::patchUpdateService)
Ed Tanous002d39b2022-05-31 08:59:27 -0700627 .methods(boost::beast::http::verb::patch)(
628 [&app](const crow::Request& req,
629 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Carson Labrado3ba00072022-06-06 19:40:56 +0000630 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -0700631 {
632 return;
633 }
634 BMCWEB_LOG_DEBUG << "doPatch...";
Jayashankar Padathfa1a5a32019-05-28 23:54:37 +0530635
Ed Tanous002d39b2022-05-31 08:59:27 -0700636 std::optional<nlohmann::json> pushUriOptions;
637 if (!json_util::readJsonPatch(req, asyncResp->res, "HttpPushUriOptions",
638 pushUriOptions))
639 {
640 return;
641 }
642
643 if (pushUriOptions)
644 {
645 std::optional<nlohmann::json> pushUriApplyTime;
646 if (!json_util::readJson(*pushUriOptions, asyncResp->res,
647 "HttpPushUriApplyTime", pushUriApplyTime))
George Liu0fda0f12021-11-16 10:06:17 +0800648 {
649 return;
650 }
651
Ed Tanous002d39b2022-05-31 08:59:27 -0700652 if (pushUriApplyTime)
George Liu0fda0f12021-11-16 10:06:17 +0800653 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700654 std::optional<std::string> applyTime;
655 if (!json_util::readJson(*pushUriApplyTime, asyncResp->res,
656 "ApplyTime", applyTime))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700657 {
Ed Tanousc711bf82018-07-30 16:31:33 -0700658 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700659 }
Jennifer Lee6c4eb9d2018-05-22 10:58:31 -0700660
Ed Tanous002d39b2022-05-31 08:59:27 -0700661 if (applyTime)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700662 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700663 std::string applyTimeNewVal;
664 if (applyTime == "Immediate")
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700665 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700666 applyTimeNewVal =
667 "xyz.openbmc_project.Software.ApplyTime.RequestedApplyTimes.Immediate";
668 }
669 else if (applyTime == "OnReset")
670 {
671 applyTimeNewVal =
672 "xyz.openbmc_project.Software.ApplyTime.RequestedApplyTimes.OnReset";
673 }
674 else
675 {
676 BMCWEB_LOG_INFO
677 << "ApplyTime value is not in the list of acceptable values";
678 messages::propertyValueNotInList(
679 asyncResp->res, *applyTime, "ApplyTime");
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700680 return;
681 }
682
Ed Tanous002d39b2022-05-31 08:59:27 -0700683 // Set the requested image apply time value
684 crow::connections::systemBus->async_method_call(
685 [asyncResp](const boost::system::error_code ec) {
686 if (ec)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700687 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700688 BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec;
689 messages::internalError(asyncResp->res);
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700690 return;
691 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700692 messages::success(asyncResp->res);
693 },
694 "xyz.openbmc_project.Settings",
695 "/xyz/openbmc_project/software/apply_time",
696 "org.freedesktop.DBus.Properties", "Set",
697 "xyz.openbmc_project.Software.ApplyTime",
698 "RequestedApplyTime",
699 dbus::utility::DbusVariantType{applyTimeNewVal});
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700700 }
George Liu0fda0f12021-11-16 10:06:17 +0800701 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700702 }
George Liu0fda0f12021-11-16 10:06:17 +0800703 });
Ed Tanousc2051d12022-05-11 12:21:55 -0700704
Ed Tanous4dc23f32022-05-11 11:32:19 -0700705// The "old" behavior of the update service URI causes redfish-service validator
706// failures when the Allow header is supported, given that in the spec,
707// UpdateService does not allow POST. in openbmc, we unfortunately reused that
708// resource as our HttpPushUri as well. A number of services, including the
709// openbmc tests, and documentation have hardcoded that erroneous API, instead
710// of relying on HttpPushUri as the spec requires. This option will exist
711// temporarily to allow the old behavior until Q4 2022, at which time it will be
712// removed.
713#ifdef BMCWEB_ENABLE_REDFISH_UPDATESERVICE_OLD_POST_URL
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700714 BMCWEB_ROUTE(app, "/redfish/v1/UpdateService/")
Ed Tanoused398212021-06-09 17:05:54 -0700715 .privileges(redfish::privileges::postUpdateService)
Ed Tanous002d39b2022-05-31 08:59:27 -0700716 .methods(boost::beast::http::verb::post)(
717 [&app](const crow::Request& req,
718 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
719 asyncResp->res.addHeader(
720 boost::beast::http::field::warning,
721 "299 - \"POST to /redfish/v1/UpdateService is deprecated. Use "
722 "the value contained within HttpPushUri.\"");
723 handleUpdateServicePost(app, req, asyncResp);
Ed Tanous4dc23f32022-05-11 11:32:19 -0700724 });
725#endif
726 BMCWEB_ROUTE(app, "/redfish/v1/UpdateService/update/")
727 .privileges(redfish::privileges::postUpdateService)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700728 .methods(boost::beast::http::verb::post)(
Ed Tanousc2051d12022-05-11 12:21:55 -0700729 std::bind_front(handleUpdateServicePost, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700730}
731
732inline void requestRoutesSoftwareInventoryCollection(App& app)
733{
734 BMCWEB_ROUTE(app, "/redfish/v1/UpdateService/FirmwareInventory/")
Ed Tanoused398212021-06-09 17:05:54 -0700735 .privileges(redfish::privileges::getSoftwareInventoryCollection)
Ed Tanous14766872022-03-15 10:44:42 -0700736 .methods(boost::beast::http::verb::get)(
737 [&app](const crow::Request& req,
738 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Carson Labrado3ba00072022-06-06 19:40:56 +0000739 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -0700740 {
741 return;
742 }
743 asyncResp->res.jsonValue["@odata.type"] =
744 "#SoftwareInventoryCollection.SoftwareInventoryCollection";
745 asyncResp->res.jsonValue["@odata.id"] =
746 "/redfish/v1/UpdateService/FirmwareInventory";
747 asyncResp->res.jsonValue["Name"] = "Software Inventory Collection";
748
749 crow::connections::systemBus->async_method_call(
750 [asyncResp](
751 const boost::system::error_code ec,
752 const dbus::utility::MapperGetSubTreeResponse& subtree) {
753 if (ec)
754 {
755 messages::internalError(asyncResp->res);
756 return;
757 }
758 asyncResp->res.jsonValue["Members"] = nlohmann::json::array();
759 asyncResp->res.jsonValue["Members@odata.count"] = 0;
760
761 for (const auto& obj : subtree)
762 {
763 sdbusplus::message::object_path path(obj.first);
764 std::string swId = path.filename();
765 if (swId.empty())
Ed Tanous14766872022-03-15 10:44:42 -0700766 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700767 messages::internalError(asyncResp->res);
768 BMCWEB_LOG_DEBUG << "Can't parse firmware ID!!";
Ed Tanous14766872022-03-15 10:44:42 -0700769 return;
770 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700771
Ed Tanous002d39b2022-05-31 08:59:27 -0700772 nlohmann::json& members = asyncResp->res.jsonValue["Members"];
773 nlohmann::json::object_t member;
774 member["@odata.id"] =
775 "/redfish/v1/UpdateService/FirmwareInventory/" + swId;
776 members.push_back(std::move(member));
777 asyncResp->res.jsonValue["Members@odata.count"] =
778 members.size();
779 }
780 },
781 // Note that only firmware levels associated with a device
782 // are stored under /xyz/openbmc_project/software therefore
783 // to ensure only real FirmwareInventory items are returned,
784 // this full object path must be used here as input to
785 // mapper
786 "xyz.openbmc_project.ObjectMapper",
787 "/xyz/openbmc_project/object_mapper",
788 "xyz.openbmc_project.ObjectMapper", "GetSubTree",
789 "/xyz/openbmc_project/software", static_cast<int32_t>(0),
790 std::array<const char*, 1>{"xyz.openbmc_project.Software.Version"});
791 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700792}
793/* Fill related item links (i.e. bmc, bios) in for inventory */
794inline static void
795 getRelatedItems(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
796 const std::string& purpose)
797{
Willy Tueee00132022-06-14 14:53:17 -0700798 if (purpose == sw_util::bmcPurpose)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700799 {
800 nlohmann::json& relatedItem = aResp->res.jsonValue["RelatedItem"];
Ed Tanous14766872022-03-15 10:44:42 -0700801 nlohmann::json::object_t item;
802 item["@odata.id"] = "/redfish/v1/Managers/bmc";
803 relatedItem.push_back(std::move(item));
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700804 aResp->res.jsonValue["RelatedItem@odata.count"] = relatedItem.size();
805 }
Willy Tueee00132022-06-14 14:53:17 -0700806 else if (purpose == sw_util::biosPurpose)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700807 {
808 nlohmann::json& relatedItem = aResp->res.jsonValue["RelatedItem"];
Ed Tanous14766872022-03-15 10:44:42 -0700809 nlohmann::json::object_t item;
810 item["@odata.id"] = "/redfish/v1/Systems/system/Bios";
811 relatedItem.push_back(std::move(item));
Jiaqing Zhao1a6e51a2022-01-19 19:20:24 +0800812 aResp->res.jsonValue["RelatedItem@odata.count"] = relatedItem.size();
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700813 }
814 else
815 {
816 BMCWEB_LOG_ERROR << "Unknown software purpose " << purpose;
817 }
818}
819
Willy Tuaf246602022-06-14 15:51:53 -0700820inline void
821 getSoftwareVersion(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
822 const std::string& service, const std::string& path,
823 const std::string& swId)
824{
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +0200825 sdbusplus::asio::getAllProperties(
826 *crow::connections::systemBus, service, path,
827 "xyz.openbmc_project.Software.Version",
Willy Tuaf246602022-06-14 15:51:53 -0700828 [asyncResp,
829 swId](const boost::system::error_code errorCode,
830 const dbus::utility::DBusPropertiesMap& propertiesList) {
831 if (errorCode)
832 {
833 messages::internalError(asyncResp->res);
834 return;
835 }
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +0200836
Willy Tuaf246602022-06-14 15:51:53 -0700837 const std::string* swInvPurpose = nullptr;
838 const std::string* version = nullptr;
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +0200839
840 const bool success = sdbusplus::unpackPropertiesNoThrow(
841 dbus_utils::UnpackErrorPrinter(), propertiesList, "Purpose",
842 swInvPurpose, "Version", version);
843
844 if (!success)
Willy Tuaf246602022-06-14 15:51:53 -0700845 {
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +0200846 messages::internalError(asyncResp->res);
847 return;
Willy Tuaf246602022-06-14 15:51:53 -0700848 }
849
850 if (swInvPurpose == nullptr)
851 {
852 BMCWEB_LOG_DEBUG << "Can't find property \"Purpose\"!";
853 messages::internalError(asyncResp->res);
854 return;
855 }
856
857 BMCWEB_LOG_DEBUG << "swInvPurpose = " << *swInvPurpose;
858
859 if (version == nullptr)
860 {
861 BMCWEB_LOG_DEBUG << "Can't find property \"Version\"!";
862
863 messages::internalError(asyncResp->res);
864
865 return;
866 }
867 asyncResp->res.jsonValue["Version"] = *version;
868 asyncResp->res.jsonValue["Id"] = swId;
869
870 // swInvPurpose is of format:
871 // xyz.openbmc_project.Software.Version.VersionPurpose.ABC
872 // Translate this to "ABC image"
873 size_t endDesc = swInvPurpose->rfind('.');
874 if (endDesc == std::string::npos)
875 {
876 messages::internalError(asyncResp->res);
877 return;
878 }
879 endDesc++;
880 if (endDesc >= swInvPurpose->size())
881 {
882 messages::internalError(asyncResp->res);
883 return;
884 }
885
886 std::string formatDesc = swInvPurpose->substr(endDesc);
887 asyncResp->res.jsonValue["Description"] = formatDesc + " image";
888 getRelatedItems(asyncResp, *swInvPurpose);
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +0200889 });
Willy Tuaf246602022-06-14 15:51:53 -0700890}
891
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700892inline void requestRoutesSoftwareInventory(App& app)
893{
894 BMCWEB_ROUTE(app, "/redfish/v1/UpdateService/FirmwareInventory/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -0700895 .privileges(redfish::privileges::getSoftwareInventory)
Ed Tanous002d39b2022-05-31 08:59:27 -0700896 .methods(boost::beast::http::verb::get)(
897 [&app](const crow::Request& req,
898 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
899 const std::string& param) {
Carson Labrado3ba00072022-06-06 19:40:56 +0000900 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -0700901 {
902 return;
903 }
904 std::shared_ptr<std::string> swId =
905 std::make_shared<std::string>(param);
906
907 asyncResp->res.jsonValue["@odata.id"] =
908 "/redfish/v1/UpdateService/FirmwareInventory/" + *swId;
909
910 crow::connections::systemBus->async_method_call(
911 [asyncResp,
912 swId](const boost::system::error_code ec,
913 const dbus::utility::MapperGetSubTreeResponse& subtree) {
914 BMCWEB_LOG_DEBUG << "doGet callback...";
915 if (ec)
Ed Tanous45ca1b82022-03-25 13:07:27 -0700916 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700917 messages::internalError(asyncResp->res);
Ed Tanous45ca1b82022-03-25 13:07:27 -0700918 return;
919 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700920
Ed Tanous002d39b2022-05-31 08:59:27 -0700921 // Ensure we find our input swId, otherwise return an error
922 bool found = false;
923 for (const std::pair<std::string,
924 std::vector<std::pair<
925 std::string, std::vector<std::string>>>>&
926 obj : subtree)
927 {
Ed Tanous11ba3972022-07-11 09:50:41 -0700928 if (!obj.first.ends_with(*swId))
Ed Tanous002d39b2022-05-31 08:59:27 -0700929 {
930 continue;
931 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700932
Ed Tanous002d39b2022-05-31 08:59:27 -0700933 if (obj.second.empty())
934 {
935 continue;
936 }
937
938 found = true;
Willy Tueee00132022-06-14 14:53:17 -0700939 sw_util::getSwStatus(asyncResp, swId, obj.second[0].first);
Willy Tuaf246602022-06-14 15:51:53 -0700940 getSoftwareVersion(asyncResp, obj.second[0].first, obj.first,
941 *swId);
Ed Tanous002d39b2022-05-31 08:59:27 -0700942 }
943 if (!found)
944 {
945 BMCWEB_LOG_ERROR << "Input swID " << *swId << " not found!";
946 messages::resourceMissingAtURI(
947 asyncResp->res, crow::utility::urlFromPieces(
948 "redfish", "v1", "UpdateService",
949 "FirmwareInventory", *swId));
950 return;
951 }
952 asyncResp->res.jsonValue["@odata.type"] =
953 "#SoftwareInventory.v1_1_0.SoftwareInventory";
954 asyncResp->res.jsonValue["Name"] = "Software Inventory";
955 asyncResp->res.jsonValue["Status"]["HealthRollup"] = "OK";
Ed Tanous1abe55e2018-09-05 08:30:59 -0700956
Ed Tanous002d39b2022-05-31 08:59:27 -0700957 asyncResp->res.jsonValue["Updateable"] = false;
Willy Tueee00132022-06-14 14:53:17 -0700958 sw_util::getSwUpdatableStatus(asyncResp, swId);
Ed Tanous002d39b2022-05-31 08:59:27 -0700959 },
960 "xyz.openbmc_project.ObjectMapper",
961 "/xyz/openbmc_project/object_mapper",
962 "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/",
963 static_cast<int32_t>(0),
964 std::array<const char*, 1>{"xyz.openbmc_project.Software.Version"});
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700965 });
966}
Ed Tanous1abe55e2018-09-05 08:30:59 -0700967
968} // namespace redfish