blob: 224d48e430959622d2548d52b1188f4980fa355a [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 {
Gayathri Leburu0fb5b502022-11-17 04:51:55 +0000140 const std::string* state = nullptr;
Ed Tanous002d39b2022-05-31 08:59:27 -0700141 for (const auto& property : values)
142 {
143 if (property.first == "Activation")
144 {
Gayathri Leburu0fb5b502022-11-17 04:51:55 +0000145 state = std::get_if<std::string>(
146 &property.second);
147 if (state == nullptr)
James Feist32898ce2020-03-10 16:16:52 -0700148 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700149 taskData->messages.emplace_back(
150 messages::internalError());
James Feist32898ce2020-03-10 16:16:52 -0700151 return task::completed;
152 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700153 }
154 }
James Feist32898ce2020-03-10 16:16:52 -0700155
Ed Tanous002d39b2022-05-31 08:59:27 -0700156 if (state == nullptr)
157 {
158 return !task::completed;
159 }
James Feist32898ce2020-03-10 16:16:52 -0700160
Ed Tanous11ba3972022-07-11 09:50:41 -0700161 if (state->ends_with("Invalid") ||
162 state->ends_with("Failed"))
Ed Tanous002d39b2022-05-31 08:59:27 -0700163 {
164 taskData->state = "Exception";
165 taskData->status = "Warning";
166 taskData->messages.emplace_back(
167 messages::taskAborted(index));
168 return task::completed;
169 }
James Feiste5d50062020-05-11 17:29:00 -0700170
Ed Tanous11ba3972022-07-11 09:50:41 -0700171 if (state->ends_with("Staged"))
Ed Tanous002d39b2022-05-31 08:59:27 -0700172 {
173 taskData->state = "Stopping";
174 taskData->messages.emplace_back(
175 messages::taskPaused(index));
176
177 // its staged, set a long timer to
178 // allow them time to complete the
179 // update (probably cycle the
180 // system) if this expires then
181 // task will be cancelled
182 taskData->extendTimer(std::chrono::hours(5));
183 return !task::completed;
184 }
185
Ed Tanous11ba3972022-07-11 09:50:41 -0700186 if (state->ends_with("Active"))
Ed Tanous002d39b2022-05-31 08:59:27 -0700187 {
188 taskData->messages.emplace_back(
189 messages::taskCompletedOK(index));
190 taskData->state = "Completed";
191 return task::completed;
192 }
193 }
194 else if (
195 iface ==
196 "xyz.openbmc_project.Software.ActivationProgress")
197 {
198
199 const uint8_t* progress = nullptr;
200 for (const auto& property : values)
201 {
202 if (property.first == "Progress")
203 {
Gayathri Leburu0fb5b502022-11-17 04:51:55 +0000204 progress =
205 std::get_if<uint8_t>(&property.second);
206 if (progress == 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 }
Gayathri Leburu0fb5b502022-11-17 04:51:55 +0000219 taskData->percentComplete = *progress;
Ed Tanous002d39b2022-05-31 08:59:27 -0700220 taskData->messages.emplace_back(
Gayathri Leburu0fb5b502022-11-17 04:51:55 +0000221 messages::taskProgressChanged(index,
222 *progress));
James Feist32898ce2020-03-10 16:16:52 -0700223
Ed Tanous002d39b2022-05-31 08:59:27 -0700224 // if we're getting status updates it's
225 // still alive, update timer
226 taskData->extendTimer(std::chrono::minutes(5));
227 }
228
229 // as firmware update often results in a
230 // reboot, the task may never "complete"
231 // unless it is an error
232
233 return !task::completed;
234 },
235 "type='signal',interface='org.freedesktop.DBus.Properties',"
236 "member='PropertiesChanged',path='" +
237 objPath.str + "'");
238 task->startTimer(std::chrono::minutes(5));
239 task->populateResp(asyncResp->res);
240 task->payload.emplace(std::move(payload));
241 }
242 fwUpdateInProgress = false;
Andrew Geissler86adcd62019-04-18 10:58:05 -0500243 },
244 "xyz.openbmc_project.ObjectMapper",
245 "/xyz/openbmc_project/object_mapper",
246 "xyz.openbmc_project.ObjectMapper", "GetObject", objPath.str,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500247 std::array<const char*, 1>{
Andrew Geissler86adcd62019-04-18 10:58:05 -0500248 "xyz.openbmc_project.Software.Activation"});
Patrick Williams62bafc02022-09-08 17:35:35 -0500249
250 break;
Andrew Geissler86adcd62019-04-18 10:58:05 -0500251 }
252 }
253}
254
Andrew Geissler0554c982019-04-23 14:40:12 -0500255// Note that asyncResp can be either a valid pointer or nullptr. If nullptr
256// then no asyncResp updates will occur
Ed Tanousb5a76932020-09-29 16:16:58 -0700257static void monitorForSoftwareAvailable(
zhanghch058d1b46d2021-04-01 11:18:24 +0800258 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
259 const crow::Request& req, const std::string& url,
Gunnar Mills5d138942022-09-07 10:26:21 -0500260 int timeoutTimeSeconds = 25)
Andrew Geissler86adcd62019-04-18 10:58:05 -0500261{
262 // Only allow one FW update at a time
Ed Tanouse05aec52022-01-25 10:28:56 -0800263 if (fwUpdateInProgress)
Andrew Geissler86adcd62019-04-18 10:58:05 -0500264 {
Andrew Geissler0554c982019-04-23 14:40:12 -0500265 if (asyncResp)
266 {
Andrew Geissler0554c982019-04-23 14:40:12 -0500267 messages::serviceTemporarilyUnavailable(asyncResp->res, "30");
268 }
Andrew Geissler86adcd62019-04-18 10:58:05 -0500269 return;
270 }
271
Andrew Geissler0554c982019-04-23 14:40:12 -0500272 fwAvailableTimer =
Ed Tanous271584a2019-07-09 16:24:22 -0700273 std::make_unique<boost::asio::steady_timer>(*req.ioService);
Andrew Geissler86adcd62019-04-18 10:58:05 -0500274
Ed Tanous271584a2019-07-09 16:24:22 -0700275 fwAvailableTimer->expires_after(std::chrono::seconds(timeoutTimeSeconds));
Andrew Geissler86adcd62019-04-18 10:58:05 -0500276
277 fwAvailableTimer->async_wait(
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500278 [asyncResp](const boost::system::error_code& ec) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700279 cleanUp();
280 if (ec == boost::asio::error::operation_aborted)
281 {
282 // expected, we were canceled before the timer completed.
283 return;
284 }
285 BMCWEB_LOG_ERROR
286 << "Timed out waiting for firmware object being created";
287 BMCWEB_LOG_ERROR << "FW image may has already been uploaded to server";
288 if (ec)
289 {
290 BMCWEB_LOG_ERROR << "Async_wait failed" << ec;
291 return;
292 }
293 if (asyncResp)
294 {
295 redfish::messages::internalError(asyncResp->res);
296 }
297 });
Ed Tanousa3e65892021-09-16 14:13:20 -0700298 task::Payload payload(req);
Patrick Williams59d494e2022-07-22 19:26:55 -0500299 auto callback = [asyncResp, payload](sdbusplus::message_t& m) mutable {
Andrew Geissler86adcd62019-04-18 10:58:05 -0500300 BMCWEB_LOG_DEBUG << "Match fired";
Ed Tanousa3e65892021-09-16 14:13:20 -0700301 softwareInterfaceAdded(asyncResp, m, std::move(payload));
Andrew Geissler86adcd62019-04-18 10:58:05 -0500302 };
303
304 fwUpdateInProgress = true;
305
Patrick Williams59d494e2022-07-22 19:26:55 -0500306 fwUpdateMatcher = std::make_unique<sdbusplus::bus::match_t>(
Andrew Geissler86adcd62019-04-18 10:58:05 -0500307 *crow::connections::systemBus,
308 "interface='org.freedesktop.DBus.ObjectManager',type='signal',"
309 "member='InterfacesAdded',path='/xyz/openbmc_project/software'",
310 callback);
James Feist4cde5d92020-06-11 10:39:55 -0700311
Patrick Williams59d494e2022-07-22 19:26:55 -0500312 fwUpdateErrorMatcher = std::make_unique<sdbusplus::bus::match_t>(
James Feist4cde5d92020-06-11 10:39:55 -0700313 *crow::connections::systemBus,
Brian Mae1cc4822021-12-01 17:05:54 +0800314 "interface='org.freedesktop.DBus.ObjectManager',type='signal',"
315 "member='InterfacesAdded',"
316 "path='/xyz/openbmc_project/logging'",
Patrick Williams59d494e2022-07-22 19:26:55 -0500317 [asyncResp, url](sdbusplus::message_t& m) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700318 std::vector<std::pair<std::string, dbus::utility::DBusPropertiesMap>>
319 interfacesProperties;
320 sdbusplus::message::object_path objPath;
321 m.read(objPath, interfacesProperties);
322 BMCWEB_LOG_DEBUG << "obj path = " << objPath.str;
323 for (const std::pair<std::string, dbus::utility::DBusPropertiesMap>&
324 interface : interfacesProperties)
325 {
326 if (interface.first == "xyz.openbmc_project.Logging.Entry")
James Feist4cde5d92020-06-11 10:39:55 -0700327 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700328 for (const std::pair<std::string,
329 dbus::utility::DbusVariantType>& value :
330 interface.second)
Brian Mae1cc4822021-12-01 17:05:54 +0800331 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700332 if (value.first != "Message")
Brian Mae1cc4822021-12-01 17:05:54 +0800333 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700334 continue;
335 }
336 const std::string* type =
337 std::get_if<std::string>(&value.second);
338 if (type == nullptr)
339 {
340 // if this was our message, timeout will cover it
341 return;
342 }
343 fwAvailableTimer = nullptr;
344 if (*type ==
345 "xyz.openbmc_project.Software.Image.Error.UnTarFailure")
346 {
347 redfish::messages::invalidUpload(asyncResp->res, url,
348 "Invalid archive");
349 }
350 else if (*type ==
351 "xyz.openbmc_project.Software.Image.Error."
352 "ManifestFileFailure")
353 {
354 redfish::messages::invalidUpload(asyncResp->res, url,
355 "Invalid manifest");
356 }
357 else if (
358 *type ==
359 "xyz.openbmc_project.Software.Image.Error.ImageFailure")
360 {
361 redfish::messages::invalidUpload(
362 asyncResp->res, url, "Invalid image format");
363 }
364 else if (
365 *type ==
366 "xyz.openbmc_project.Software.Version.Error.AlreadyExists")
367 {
368 redfish::messages::invalidUpload(
369 asyncResp->res, url,
370 "Image version already exists");
Gunnar Mills88b3dd12020-11-20 14:26:04 -0600371
Ed Tanous002d39b2022-05-31 08:59:27 -0700372 redfish::messages::resourceAlreadyExists(
Jiaqing Zhaod8a5d5d2022-08-05 16:21:51 +0800373 asyncResp->res, "UpdateService", "Version",
Ed Tanous002d39b2022-05-31 08:59:27 -0700374 "uploaded version");
375 }
376 else if (
377 *type ==
378 "xyz.openbmc_project.Software.Image.Error.BusyFailure")
379 {
380 redfish::messages::resourceExhaustion(asyncResp->res,
381 url);
382 }
383 else
384 {
385 redfish::messages::internalError(asyncResp->res);
Brian Mae1cc4822021-12-01 17:05:54 +0800386 }
387 }
Gunnar Mills88b3dd12020-11-20 14:26:04 -0600388 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700389 }
James Feist4cde5d92020-06-11 10:39:55 -0700390 });
Andrew Geissler86adcd62019-04-18 10:58:05 -0500391}
Jennifer Lee729dae72018-04-24 15:59:34 -0700392
Andrew Geissler0554c982019-04-23 14:40:12 -0500393/**
394 * UpdateServiceActionsSimpleUpdate class supports handle POST method for
395 * SimpleUpdate action.
396 */
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700397inline void requestRoutesUpdateServiceActionsSimpleUpdate(App& app)
Andrew Geissler0554c982019-04-23 14:40:12 -0500398{
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700399 BMCWEB_ROUTE(
400 app, "/redfish/v1/UpdateService/Actions/UpdateService.SimpleUpdate/")
Ed Tanoused398212021-06-09 17:05:54 -0700401 .privileges(redfish::privileges::postUpdateService)
Ed Tanous002d39b2022-05-31 08:59:27 -0700402 .methods(boost::beast::http::verb::post)(
403 [&app](const crow::Request& req,
404 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Carson Labrado3ba00072022-06-06 19:40:56 +0000405 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -0700406 {
407 return;
408 }
Ed Tanous45ca1b82022-03-25 13:07:27 -0700409
Ed Tanous002d39b2022-05-31 08:59:27 -0700410 std::optional<std::string> transferProtocol;
411 std::string imageURI;
Andrew Geissler0554c982019-04-23 14:40:12 -0500412
Ed Tanous002d39b2022-05-31 08:59:27 -0700413 BMCWEB_LOG_DEBUG << "Enter UpdateService.SimpleUpdate doPost";
Andrew Geissler0554c982019-04-23 14:40:12 -0500414
Ed Tanous002d39b2022-05-31 08:59:27 -0700415 // User can pass in both TransferProtocol and ImageURI parameters or
416 // they can pass in just the ImageURI with the transfer protocol
417 // embedded within it.
418 // 1) TransferProtocol:TFTP ImageURI:1.1.1.1/myfile.bin
419 // 2) ImageURI:tftp://1.1.1.1/myfile.bin
Andrew Geissler0554c982019-04-23 14:40:12 -0500420
Ed Tanous002d39b2022-05-31 08:59:27 -0700421 if (!json_util::readJsonAction(req, asyncResp->res, "TransferProtocol",
422 transferProtocol, "ImageURI", imageURI))
423 {
424 BMCWEB_LOG_DEBUG
425 << "Missing TransferProtocol or ImageURI parameter";
426 return;
427 }
428 if (!transferProtocol)
429 {
430 // Must be option 2
431 // Verify ImageURI has transfer protocol in it
432 size_t separator = imageURI.find(':');
Andrew Geissler0554c982019-04-23 14:40:12 -0500433 if ((separator == std::string::npos) ||
434 ((separator + 1) > imageURI.size()))
435 {
436 messages::actionParameterValueTypeError(
437 asyncResp->res, imageURI, "ImageURI",
438 "UpdateService.SimpleUpdate");
Ed Tanous002d39b2022-05-31 08:59:27 -0700439 BMCWEB_LOG_ERROR << "ImageURI missing transfer protocol: "
440 << imageURI;
Jayashankar Padath274dfe62019-08-23 12:30:57 +0530441 return;
Jayashankar Padathfa1a5a32019-05-28 23:54:37 +0530442 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700443 transferProtocol = imageURI.substr(0, separator);
444 // Ensure protocol is upper case for a common comparison path
445 // below
446 boost::to_upper(*transferProtocol);
447 BMCWEB_LOG_DEBUG << "Encoded transfer protocol "
448 << *transferProtocol;
Jayashankar Padathfa1a5a32019-05-28 23:54:37 +0530449
Ed Tanous002d39b2022-05-31 08:59:27 -0700450 // Adjust imageURI to not have the protocol on it for parsing
451 // below
452 // ex. tftp://1.1.1.1/myfile.bin -> 1.1.1.1/myfile.bin
453 imageURI = imageURI.substr(separator + 3);
454 BMCWEB_LOG_DEBUG << "Adjusted imageUri " << imageURI;
455 }
Jayashankar Padath274dfe62019-08-23 12:30:57 +0530456
Ed Tanous002d39b2022-05-31 08:59:27 -0700457 // OpenBMC currently only supports TFTP
458 if (*transferProtocol != "TFTP")
459 {
460 messages::actionParameterNotSupported(asyncResp->res,
461 "TransferProtocol",
462 "UpdateService.SimpleUpdate");
463 BMCWEB_LOG_ERROR << "Request incorrect protocol parameter: "
464 << *transferProtocol;
465 return;
466 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700467
Ed Tanous002d39b2022-05-31 08:59:27 -0700468 // Format should be <IP or Hostname>/<file> for imageURI
469 size_t separator = imageURI.find('/');
470 if ((separator == std::string::npos) ||
471 ((separator + 1) > imageURI.size()))
472 {
473 messages::actionParameterValueTypeError(
474 asyncResp->res, imageURI, "ImageURI",
475 "UpdateService.SimpleUpdate");
476 BMCWEB_LOG_ERROR << "Invalid ImageURI: " << imageURI;
477 return;
478 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700479
Ed Tanous002d39b2022-05-31 08:59:27 -0700480 std::string tftpServer = imageURI.substr(0, separator);
481 std::string fwFile = imageURI.substr(separator + 1);
482 BMCWEB_LOG_DEBUG << "Server: " << tftpServer + " File: " << fwFile;
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700483
Ed Tanous002d39b2022-05-31 08:59:27 -0700484 // Setup callback for when new software detected
485 // Give TFTP 10 minutes to complete
486 monitorForSoftwareAvailable(
487 asyncResp, req,
488 "/redfish/v1/UpdateService/Actions/UpdateService.SimpleUpdate",
489 600);
490
491 // TFTP can take up to 10 minutes depending on image size and
492 // connection speed. Return to caller as soon as the TFTP operation
493 // has been started. The callback above will ensure the activate
494 // is started once the download has completed
495 redfish::messages::success(asyncResp->res);
496
497 // Call TFTP service
498 crow::connections::systemBus->async_method_call(
499 [](const boost::system::error_code ec) {
500 if (ec)
501 {
502 // messages::internalError(asyncResp->res);
503 cleanUp();
504 BMCWEB_LOG_DEBUG << "error_code = " << ec;
505 BMCWEB_LOG_DEBUG << "error msg = " << ec.message();
506 }
507 else
508 {
509 BMCWEB_LOG_DEBUG << "Call to DownloaViaTFTP Success";
510 }
511 },
512 "xyz.openbmc_project.Software.Download",
513 "/xyz/openbmc_project/software", "xyz.openbmc_project.Common.TFTP",
514 "DownloadViaTFTP", fwFile, tftpServer);
515
516 BMCWEB_LOG_DEBUG << "Exit UpdateService.SimpleUpdate doPost";
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700517 });
518}
519
Ed Tanousc2051d12022-05-11 12:21:55 -0700520inline void
521 handleUpdateServicePost(App& app, const crow::Request& req,
522 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
523{
Carson Labrado3ba00072022-06-06 19:40:56 +0000524 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanousc2051d12022-05-11 12:21:55 -0700525 {
526 return;
527 }
528 BMCWEB_LOG_DEBUG << "doPost...";
529
530 // Setup callback for when new software detected
531 monitorForSoftwareAvailable(asyncResp, req, "/redfish/v1/UpdateService");
532
533 std::string filepath(
534 "/tmp/images/" +
535 boost::uuids::to_string(boost::uuids::random_generator()()));
536 BMCWEB_LOG_DEBUG << "Writing file to " << filepath;
537 std::ofstream out(filepath, std::ofstream::out | std::ofstream::binary |
538 std::ofstream::trunc);
539 out << req.body;
540 out.close();
541 BMCWEB_LOG_DEBUG << "file upload complete!!";
542}
543
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700544inline void requestRoutesUpdateService(App& app)
545{
546 BMCWEB_ROUTE(app, "/redfish/v1/UpdateService/")
Ed Tanoused398212021-06-09 17:05:54 -0700547 .privileges(redfish::privileges::getUpdateService)
Ed Tanous002d39b2022-05-31 08:59:27 -0700548 .methods(boost::beast::http::verb::get)(
549 [&app](const crow::Request& req,
550 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Carson Labrado3ba00072022-06-06 19:40:56 +0000551 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -0700552 {
553 return;
554 }
555 asyncResp->res.jsonValue["@odata.type"] =
556 "#UpdateService.v1_5_0.UpdateService";
557 asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/UpdateService";
558 asyncResp->res.jsonValue["Id"] = "UpdateService";
559 asyncResp->res.jsonValue["Description"] = "Service for Software Update";
560 asyncResp->res.jsonValue["Name"] = "Update Service";
Ed Tanous4dc23f32022-05-11 11:32:19 -0700561
Ed Tanous32ca38a2022-05-11 12:36:59 -0700562#ifdef BMCWEB_ENABLE_REDFISH_UPDATESERVICE_OLD_POST_URL
Ed Tanous002d39b2022-05-31 08:59:27 -0700563 // See note about later on in this file about why this is neccesary
564 // This is "Wrong" per the standard, but is done temporarily to
565 // avoid noise in failing tests as people transition to having this
566 // option disabled
567 asyncResp->res.addHeader(boost::beast::http::field::allow,
568 "GET, PATCH, HEAD");
Ed Tanous32ca38a2022-05-11 12:36:59 -0700569#endif
570
Ed Tanous002d39b2022-05-31 08:59:27 -0700571 asyncResp->res.jsonValue["HttpPushUri"] =
572 "/redfish/v1/UpdateService/update";
Ed Tanous4dc23f32022-05-11 11:32:19 -0700573
Ed Tanous002d39b2022-05-31 08:59:27 -0700574 // UpdateService cannot be disabled
575 asyncResp->res.jsonValue["ServiceEnabled"] = true;
576 asyncResp->res.jsonValue["FirmwareInventory"]["@odata.id"] =
577 "/redfish/v1/UpdateService/FirmwareInventory";
578 // Get the MaxImageSizeBytes
579 asyncResp->res.jsonValue["MaxImageSizeBytes"] =
580 bmcwebHttpReqBodyLimitMb * 1024 * 1024;
Tejas Patild61e5192021-06-04 15:49:35 +0530581
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700582#ifdef BMCWEB_INSECURE_ENABLE_REDFISH_FW_TFTP_UPDATE
Ed Tanous002d39b2022-05-31 08:59:27 -0700583 // Update Actions object.
584 nlohmann::json& updateSvcSimpleUpdate =
585 asyncResp->res.jsonValue["Actions"]["#UpdateService.SimpleUpdate"];
586 updateSvcSimpleUpdate["target"] =
587 "/redfish/v1/UpdateService/Actions/UpdateService.SimpleUpdate";
588 updateSvcSimpleUpdate["TransferProtocol@Redfish.AllowableValues"] = {
589 "TFTP"};
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700590#endif
Ed Tanous002d39b2022-05-31 08:59:27 -0700591 // Get the current ApplyTime value
592 sdbusplus::asio::getProperty<std::string>(
593 *crow::connections::systemBus, "xyz.openbmc_project.Settings",
594 "/xyz/openbmc_project/software/apply_time",
595 "xyz.openbmc_project.Software.ApplyTime", "RequestedApplyTime",
596 [asyncResp](const boost::system::error_code ec,
597 const std::string& applyTime) {
598 if (ec)
599 {
600 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
601 messages::internalError(asyncResp->res);
602 return;
603 }
Jayashankar Padath274dfe62019-08-23 12:30:57 +0530604
Ed Tanous002d39b2022-05-31 08:59:27 -0700605 // Store the ApplyTime Value
606 if (applyTime == "xyz.openbmc_project.Software.ApplyTime."
607 "RequestedApplyTimes.Immediate")
608 {
609 asyncResp->res.jsonValue["HttpPushUriOptions"]
610 ["HttpPushUriApplyTime"]["ApplyTime"] =
611 "Immediate";
612 }
613 else if (applyTime == "xyz.openbmc_project.Software.ApplyTime."
614 "RequestedApplyTimes.OnReset")
615 {
616 asyncResp->res.jsonValue["HttpPushUriOptions"]
617 ["HttpPushUriApplyTime"]["ApplyTime"] =
618 "OnReset";
619 }
620 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700621 });
622 BMCWEB_ROUTE(app, "/redfish/v1/UpdateService/")
Ed Tanoused398212021-06-09 17:05:54 -0700623 .privileges(redfish::privileges::patchUpdateService)
Ed Tanous002d39b2022-05-31 08:59:27 -0700624 .methods(boost::beast::http::verb::patch)(
625 [&app](const crow::Request& req,
626 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Carson Labrado3ba00072022-06-06 19:40:56 +0000627 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -0700628 {
629 return;
630 }
631 BMCWEB_LOG_DEBUG << "doPatch...";
Jayashankar Padathfa1a5a32019-05-28 23:54:37 +0530632
Ed Tanous002d39b2022-05-31 08:59:27 -0700633 std::optional<nlohmann::json> pushUriOptions;
634 if (!json_util::readJsonPatch(req, asyncResp->res, "HttpPushUriOptions",
635 pushUriOptions))
636 {
637 return;
638 }
639
640 if (pushUriOptions)
641 {
642 std::optional<nlohmann::json> pushUriApplyTime;
643 if (!json_util::readJson(*pushUriOptions, asyncResp->res,
644 "HttpPushUriApplyTime", pushUriApplyTime))
George Liu0fda0f12021-11-16 10:06:17 +0800645 {
646 return;
647 }
648
Ed Tanous002d39b2022-05-31 08:59:27 -0700649 if (pushUriApplyTime)
George Liu0fda0f12021-11-16 10:06:17 +0800650 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700651 std::optional<std::string> applyTime;
652 if (!json_util::readJson(*pushUriApplyTime, asyncResp->res,
653 "ApplyTime", applyTime))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700654 {
Ed Tanousc711bf82018-07-30 16:31:33 -0700655 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700656 }
Jennifer Lee6c4eb9d2018-05-22 10:58:31 -0700657
Ed Tanous002d39b2022-05-31 08:59:27 -0700658 if (applyTime)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700659 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700660 std::string applyTimeNewVal;
661 if (applyTime == "Immediate")
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700662 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700663 applyTimeNewVal =
664 "xyz.openbmc_project.Software.ApplyTime.RequestedApplyTimes.Immediate";
665 }
666 else if (applyTime == "OnReset")
667 {
668 applyTimeNewVal =
669 "xyz.openbmc_project.Software.ApplyTime.RequestedApplyTimes.OnReset";
670 }
671 else
672 {
673 BMCWEB_LOG_INFO
674 << "ApplyTime value is not in the list of acceptable values";
675 messages::propertyValueNotInList(
676 asyncResp->res, *applyTime, "ApplyTime");
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700677 return;
678 }
679
Ed Tanous002d39b2022-05-31 08:59:27 -0700680 // Set the requested image apply time value
681 crow::connections::systemBus->async_method_call(
682 [asyncResp](const boost::system::error_code ec) {
683 if (ec)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700684 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700685 BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec;
686 messages::internalError(asyncResp->res);
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700687 return;
688 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700689 messages::success(asyncResp->res);
690 },
691 "xyz.openbmc_project.Settings",
692 "/xyz/openbmc_project/software/apply_time",
693 "org.freedesktop.DBus.Properties", "Set",
694 "xyz.openbmc_project.Software.ApplyTime",
695 "RequestedApplyTime",
696 dbus::utility::DbusVariantType{applyTimeNewVal});
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700697 }
George Liu0fda0f12021-11-16 10:06:17 +0800698 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700699 }
George Liu0fda0f12021-11-16 10:06:17 +0800700 });
Ed Tanousc2051d12022-05-11 12:21:55 -0700701
Ed Tanous4dc23f32022-05-11 11:32:19 -0700702// The "old" behavior of the update service URI causes redfish-service validator
703// failures when the Allow header is supported, given that in the spec,
704// UpdateService does not allow POST. in openbmc, we unfortunately reused that
705// resource as our HttpPushUri as well. A number of services, including the
706// openbmc tests, and documentation have hardcoded that erroneous API, instead
707// of relying on HttpPushUri as the spec requires. This option will exist
708// temporarily to allow the old behavior until Q4 2022, at which time it will be
709// removed.
710#ifdef BMCWEB_ENABLE_REDFISH_UPDATESERVICE_OLD_POST_URL
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700711 BMCWEB_ROUTE(app, "/redfish/v1/UpdateService/")
Ed Tanoused398212021-06-09 17:05:54 -0700712 .privileges(redfish::privileges::postUpdateService)
Ed Tanous002d39b2022-05-31 08:59:27 -0700713 .methods(boost::beast::http::verb::post)(
714 [&app](const crow::Request& req,
715 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
716 asyncResp->res.addHeader(
717 boost::beast::http::field::warning,
718 "299 - \"POST to /redfish/v1/UpdateService is deprecated. Use "
719 "the value contained within HttpPushUri.\"");
720 handleUpdateServicePost(app, req, asyncResp);
Ed Tanous4dc23f32022-05-11 11:32:19 -0700721 });
722#endif
723 BMCWEB_ROUTE(app, "/redfish/v1/UpdateService/update/")
724 .privileges(redfish::privileges::postUpdateService)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700725 .methods(boost::beast::http::verb::post)(
Ed Tanousc2051d12022-05-11 12:21:55 -0700726 std::bind_front(handleUpdateServicePost, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700727}
728
729inline void requestRoutesSoftwareInventoryCollection(App& app)
730{
731 BMCWEB_ROUTE(app, "/redfish/v1/UpdateService/FirmwareInventory/")
Ed Tanoused398212021-06-09 17:05:54 -0700732 .privileges(redfish::privileges::getSoftwareInventoryCollection)
Ed Tanous14766872022-03-15 10:44:42 -0700733 .methods(boost::beast::http::verb::get)(
734 [&app](const crow::Request& req,
735 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Carson Labrado3ba00072022-06-06 19:40:56 +0000736 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -0700737 {
738 return;
739 }
740 asyncResp->res.jsonValue["@odata.type"] =
741 "#SoftwareInventoryCollection.SoftwareInventoryCollection";
742 asyncResp->res.jsonValue["@odata.id"] =
743 "/redfish/v1/UpdateService/FirmwareInventory";
744 asyncResp->res.jsonValue["Name"] = "Software Inventory Collection";
745
746 crow::connections::systemBus->async_method_call(
747 [asyncResp](
748 const boost::system::error_code ec,
749 const dbus::utility::MapperGetSubTreeResponse& subtree) {
750 if (ec)
751 {
752 messages::internalError(asyncResp->res);
753 return;
754 }
755 asyncResp->res.jsonValue["Members"] = nlohmann::json::array();
756 asyncResp->res.jsonValue["Members@odata.count"] = 0;
757
758 for (const auto& obj : subtree)
759 {
760 sdbusplus::message::object_path path(obj.first);
761 std::string swId = path.filename();
762 if (swId.empty())
Ed Tanous14766872022-03-15 10:44:42 -0700763 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700764 messages::internalError(asyncResp->res);
765 BMCWEB_LOG_DEBUG << "Can't parse firmware ID!!";
Ed Tanous14766872022-03-15 10:44:42 -0700766 return;
767 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700768
Ed Tanous002d39b2022-05-31 08:59:27 -0700769 nlohmann::json& members = asyncResp->res.jsonValue["Members"];
770 nlohmann::json::object_t member;
771 member["@odata.id"] =
772 "/redfish/v1/UpdateService/FirmwareInventory/" + swId;
773 members.push_back(std::move(member));
774 asyncResp->res.jsonValue["Members@odata.count"] =
775 members.size();
776 }
777 },
778 // Note that only firmware levels associated with a device
779 // are stored under /xyz/openbmc_project/software therefore
780 // to ensure only real FirmwareInventory items are returned,
781 // this full object path must be used here as input to
782 // mapper
783 "xyz.openbmc_project.ObjectMapper",
784 "/xyz/openbmc_project/object_mapper",
785 "xyz.openbmc_project.ObjectMapper", "GetSubTree",
786 "/xyz/openbmc_project/software", static_cast<int32_t>(0),
787 std::array<const char*, 1>{"xyz.openbmc_project.Software.Version"});
788 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700789}
790/* Fill related item links (i.e. bmc, bios) in for inventory */
791inline static void
792 getRelatedItems(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
793 const std::string& purpose)
794{
Willy Tueee00132022-06-14 14:53:17 -0700795 if (purpose == sw_util::bmcPurpose)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700796 {
797 nlohmann::json& relatedItem = aResp->res.jsonValue["RelatedItem"];
Ed Tanous14766872022-03-15 10:44:42 -0700798 nlohmann::json::object_t item;
799 item["@odata.id"] = "/redfish/v1/Managers/bmc";
800 relatedItem.push_back(std::move(item));
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700801 aResp->res.jsonValue["RelatedItem@odata.count"] = relatedItem.size();
802 }
Willy Tueee00132022-06-14 14:53:17 -0700803 else if (purpose == sw_util::biosPurpose)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700804 {
805 nlohmann::json& relatedItem = aResp->res.jsonValue["RelatedItem"];
Ed Tanous14766872022-03-15 10:44:42 -0700806 nlohmann::json::object_t item;
807 item["@odata.id"] = "/redfish/v1/Systems/system/Bios";
808 relatedItem.push_back(std::move(item));
Jiaqing Zhao1a6e51a2022-01-19 19:20:24 +0800809 aResp->res.jsonValue["RelatedItem@odata.count"] = relatedItem.size();
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700810 }
811 else
812 {
813 BMCWEB_LOG_ERROR << "Unknown software purpose " << purpose;
814 }
815}
816
Willy Tuaf246602022-06-14 15:51:53 -0700817inline void
818 getSoftwareVersion(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
819 const std::string& service, const std::string& path,
820 const std::string& swId)
821{
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +0200822 sdbusplus::asio::getAllProperties(
823 *crow::connections::systemBus, service, path,
824 "xyz.openbmc_project.Software.Version",
Willy Tuaf246602022-06-14 15:51:53 -0700825 [asyncResp,
826 swId](const boost::system::error_code errorCode,
827 const dbus::utility::DBusPropertiesMap& propertiesList) {
828 if (errorCode)
829 {
830 messages::internalError(asyncResp->res);
831 return;
832 }
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +0200833
Willy Tuaf246602022-06-14 15:51:53 -0700834 const std::string* swInvPurpose = nullptr;
835 const std::string* version = nullptr;
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +0200836
837 const bool success = sdbusplus::unpackPropertiesNoThrow(
838 dbus_utils::UnpackErrorPrinter(), propertiesList, "Purpose",
839 swInvPurpose, "Version", version);
840
841 if (!success)
Willy Tuaf246602022-06-14 15:51:53 -0700842 {
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +0200843 messages::internalError(asyncResp->res);
844 return;
Willy Tuaf246602022-06-14 15:51:53 -0700845 }
846
847 if (swInvPurpose == nullptr)
848 {
849 BMCWEB_LOG_DEBUG << "Can't find property \"Purpose\"!";
850 messages::internalError(asyncResp->res);
851 return;
852 }
853
854 BMCWEB_LOG_DEBUG << "swInvPurpose = " << *swInvPurpose;
855
856 if (version == nullptr)
857 {
858 BMCWEB_LOG_DEBUG << "Can't find property \"Version\"!";
859
860 messages::internalError(asyncResp->res);
861
862 return;
863 }
864 asyncResp->res.jsonValue["Version"] = *version;
865 asyncResp->res.jsonValue["Id"] = swId;
866
867 // swInvPurpose is of format:
868 // xyz.openbmc_project.Software.Version.VersionPurpose.ABC
869 // Translate this to "ABC image"
870 size_t endDesc = swInvPurpose->rfind('.');
871 if (endDesc == std::string::npos)
872 {
873 messages::internalError(asyncResp->res);
874 return;
875 }
876 endDesc++;
877 if (endDesc >= swInvPurpose->size())
878 {
879 messages::internalError(asyncResp->res);
880 return;
881 }
882
883 std::string formatDesc = swInvPurpose->substr(endDesc);
884 asyncResp->res.jsonValue["Description"] = formatDesc + " image";
885 getRelatedItems(asyncResp, *swInvPurpose);
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +0200886 });
Willy Tuaf246602022-06-14 15:51:53 -0700887}
888
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700889inline void requestRoutesSoftwareInventory(App& app)
890{
891 BMCWEB_ROUTE(app, "/redfish/v1/UpdateService/FirmwareInventory/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -0700892 .privileges(redfish::privileges::getSoftwareInventory)
Ed Tanous002d39b2022-05-31 08:59:27 -0700893 .methods(boost::beast::http::verb::get)(
894 [&app](const crow::Request& req,
895 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
896 const std::string& param) {
Carson Labrado3ba00072022-06-06 19:40:56 +0000897 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -0700898 {
899 return;
900 }
901 std::shared_ptr<std::string> swId =
902 std::make_shared<std::string>(param);
903
904 asyncResp->res.jsonValue["@odata.id"] =
905 "/redfish/v1/UpdateService/FirmwareInventory/" + *swId;
906
907 crow::connections::systemBus->async_method_call(
908 [asyncResp,
909 swId](const boost::system::error_code ec,
910 const dbus::utility::MapperGetSubTreeResponse& subtree) {
911 BMCWEB_LOG_DEBUG << "doGet callback...";
912 if (ec)
Ed Tanous45ca1b82022-03-25 13:07:27 -0700913 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700914 messages::internalError(asyncResp->res);
Ed Tanous45ca1b82022-03-25 13:07:27 -0700915 return;
916 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700917
Ed Tanous002d39b2022-05-31 08:59:27 -0700918 // Ensure we find our input swId, otherwise return an error
919 bool found = false;
920 for (const std::pair<std::string,
921 std::vector<std::pair<
922 std::string, std::vector<std::string>>>>&
923 obj : subtree)
924 {
Ed Tanous11ba3972022-07-11 09:50:41 -0700925 if (!obj.first.ends_with(*swId))
Ed Tanous002d39b2022-05-31 08:59:27 -0700926 {
927 continue;
928 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700929
Ed Tanous002d39b2022-05-31 08:59:27 -0700930 if (obj.second.empty())
931 {
932 continue;
933 }
934
935 found = true;
Willy Tueee00132022-06-14 14:53:17 -0700936 sw_util::getSwStatus(asyncResp, swId, obj.second[0].first);
Willy Tuaf246602022-06-14 15:51:53 -0700937 getSoftwareVersion(asyncResp, obj.second[0].first, obj.first,
938 *swId);
Ed Tanous002d39b2022-05-31 08:59:27 -0700939 }
940 if (!found)
941 {
942 BMCWEB_LOG_ERROR << "Input swID " << *swId << " not found!";
943 messages::resourceMissingAtURI(
944 asyncResp->res, crow::utility::urlFromPieces(
945 "redfish", "v1", "UpdateService",
946 "FirmwareInventory", *swId));
947 return;
948 }
949 asyncResp->res.jsonValue["@odata.type"] =
950 "#SoftwareInventory.v1_1_0.SoftwareInventory";
951 asyncResp->res.jsonValue["Name"] = "Software Inventory";
952 asyncResp->res.jsonValue["Status"]["HealthRollup"] = "OK";
Ed Tanous1abe55e2018-09-05 08:30:59 -0700953
Ed Tanous002d39b2022-05-31 08:59:27 -0700954 asyncResp->res.jsonValue["Updateable"] = false;
Willy Tueee00132022-06-14 14:53:17 -0700955 sw_util::getSwUpdatableStatus(asyncResp, swId);
Ed Tanous002d39b2022-05-31 08:59:27 -0700956 },
957 "xyz.openbmc_project.ObjectMapper",
958 "/xyz/openbmc_project/object_mapper",
959 "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/",
960 static_cast<int32_t>(0),
961 std::array<const char*, 1>{"xyz.openbmc_project.Software.Version"});
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700962 });
963}
Ed Tanous1abe55e2018-09-05 08:30:59 -0700964
965} // namespace redfish