blob: 3d29f2859b60a1e11240c266910febf64bf13d10 [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
Ed Tanous3ccb3ad2023-01-13 17:40:03 -080020#include "app.hpp"
21#include "dbus_utility.hpp"
22#include "query.hpp"
23#include "registries/privilege_registry.hpp"
24#include "utils/dbus_utils.hpp"
25#include "utils/sw_utils.hpp"
26
George Liue99073f2022-12-09 11:06:16 +080027#include <boost/system/error_code.hpp>
Jonathan Doman1e1e5982021-06-11 09:36:17 -070028#include <sdbusplus/asio/property.hpp>
Ed Tanous3ccb3ad2023-01-13 17:40:03 -080029#include <sdbusplus/bus/match.hpp>
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +020030#include <sdbusplus/unpack_properties.hpp>
Gunnar Mills1214b7e2020-06-04 10:11:30 -050031
George Liu2b731192023-01-11 16:27:13 +080032#include <array>
33#include <string_view>
34
Ed Tanous1abe55e2018-09-05 08:30:59 -070035namespace redfish
36{
Ed Tanous27826b52018-10-29 11:40:58 -070037
Andrew Geissler0e7de462019-03-04 19:11:54 -060038// Match signals added on software path
Ed Tanouscf9e4172022-12-21 09:30:16 -080039// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
Patrick Williams59d494e2022-07-22 19:26:55 -050040static std::unique_ptr<sdbusplus::bus::match_t> fwUpdateMatcher;
Ed Tanouscf9e4172022-12-21 09:30:16 -080041// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
Patrick Williams59d494e2022-07-22 19:26:55 -050042static std::unique_ptr<sdbusplus::bus::match_t> fwUpdateErrorMatcher;
Andrew Geissler0e7de462019-03-04 19:11:54 -060043// Only allow one update at a time
Ed Tanouscf9e4172022-12-21 09:30:16 -080044// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
Andrew Geissler0e7de462019-03-04 19:11:54 -060045static bool fwUpdateInProgress = false;
Andrew Geissler86adcd62019-04-18 10:58:05 -050046// Timer for software available
Ed Tanouscf9e4172022-12-21 09:30:16 -080047// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
Ed Tanous271584a2019-07-09 16:24:22 -070048static std::unique_ptr<boost::asio::steady_timer> fwAvailableTimer;
Andrew Geissler86adcd62019-04-18 10:58:05 -050049
John Edward Broadbent7e860f12021-04-08 15:57:16 -070050inline static void cleanUp()
Andrew Geissler86adcd62019-04-18 10:58:05 -050051{
52 fwUpdateInProgress = false;
53 fwUpdateMatcher = nullptr;
James Feist4cde5d92020-06-11 10:39:55 -070054 fwUpdateErrorMatcher = nullptr;
Andrew Geissler86adcd62019-04-18 10:58:05 -050055}
John Edward Broadbent7e860f12021-04-08 15:57:16 -070056inline static void activateImage(const std::string& objPath,
57 const std::string& service)
Andrew Geissler86adcd62019-04-18 10:58:05 -050058{
59 BMCWEB_LOG_DEBUG << "Activate image for " << objPath << " " << service;
60 crow::connections::systemBus->async_method_call(
Ed Tanous81ce6092020-12-17 16:54:55 +000061 [](const boost::system::error_code errorCode) {
Ed Tanous002d39b2022-05-31 08:59:27 -070062 if (errorCode)
63 {
64 BMCWEB_LOG_DEBUG << "error_code = " << errorCode;
65 BMCWEB_LOG_DEBUG << "error msg = " << errorCode.message();
66 }
Andrew Geissler86adcd62019-04-18 10:58:05 -050067 },
68 service, objPath, "org.freedesktop.DBus.Properties", "Set",
69 "xyz.openbmc_project.Software.Activation", "RequestedActivation",
Ed Tanous168e20c2021-12-13 14:39:53 -080070 dbus::utility::DbusVariantType(
George Liu0fda0f12021-11-16 10:06:17 +080071 "xyz.openbmc_project.Software.Activation.RequestedActivations.Active"));
Andrew Geissler86adcd62019-04-18 10:58:05 -050072}
Andrew Geissler0554c982019-04-23 14:40:12 -050073
74// Note that asyncResp can be either a valid pointer or nullptr. If nullptr
75// then no asyncResp updates will occur
zhanghch058d1b46d2021-04-01 11:18:24 +080076static void
77 softwareInterfaceAdded(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Patrick Williams59d494e2022-07-22 19:26:55 -050078 sdbusplus::message_t& m, task::Payload&& payload)
Andrew Geissler86adcd62019-04-18 10:58:05 -050079{
Ed Tanousb9d36b42022-02-26 21:42:46 -080080 dbus::utility::DBusInteracesMap interfacesProperties;
Andrew Geissler86adcd62019-04-18 10:58:05 -050081
82 sdbusplus::message::object_path objPath;
83
84 m.read(objPath, interfacesProperties);
85
86 BMCWEB_LOG_DEBUG << "obj path = " << objPath.str;
Ed Tanouse3eb3d62022-12-21 11:56:07 -080087 for (const auto& interface : interfacesProperties)
Andrew Geissler86adcd62019-04-18 10:58:05 -050088 {
89 BMCWEB_LOG_DEBUG << "interface = " << interface.first;
90
91 if (interface.first == "xyz.openbmc_project.Software.Activation")
92 {
Andrew Geissler86adcd62019-04-18 10:58:05 -050093 // Retrieve service and activate
George Liu2b731192023-01-11 16:27:13 +080094 constexpr std::array<std::string_view, 1> interfaces = {
95 "xyz.openbmc_project.Software.Activation"};
96 dbus::utility::getDbusObject(
97 objPath.str, interfaces,
Ed Tanousa3e65892021-09-16 14:13:20 -070098 [objPath, asyncResp, payload(std::move(payload))](
George Liu2b731192023-01-11 16:27:13 +080099 const boost::system::error_code& errorCode,
Ed Tanousa3e65892021-09-16 14:13:20 -0700100 const std::vector<
101 std::pair<std::string, std::vector<std::string>>>&
102 objInfo) mutable {
Ed Tanous002d39b2022-05-31 08:59:27 -0700103 if (errorCode)
104 {
105 BMCWEB_LOG_DEBUG << "error_code = " << errorCode;
106 BMCWEB_LOG_DEBUG << "error msg = " << errorCode.message();
Andrew Geissler0554c982019-04-23 14:40:12 -0500107 if (asyncResp)
108 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700109 messages::internalError(asyncResp->res);
110 }
111 cleanUp();
112 return;
113 }
114 // Ensure we only got one service back
115 if (objInfo.size() != 1)
116 {
117 BMCWEB_LOG_ERROR << "Invalid Object Size "
118 << objInfo.size();
119 if (asyncResp)
120 {
121 messages::internalError(asyncResp->res);
122 }
123 cleanUp();
124 return;
125 }
126 // cancel timer only when
127 // xyz.openbmc_project.Software.Activation interface
128 // is added
129 fwAvailableTimer = nullptr;
130
131 activateImage(objPath.str, objInfo[0].first);
132 if (asyncResp)
133 {
134 std::shared_ptr<task::TaskData> task =
135 task::TaskData::createTask(
136 [](boost::system::error_code ec,
Patrick Williams59d494e2022-07-22 19:26:55 -0500137 sdbusplus::message_t& msg,
Ed Tanous002d39b2022-05-31 08:59:27 -0700138 const std::shared_ptr<task::TaskData>&
139 taskData) {
140 if (ec)
141 {
142 return task::completed;
143 }
144
145 std::string iface;
146 dbus::utility::DBusPropertiesMap values;
147
148 std::string index = std::to_string(taskData->index);
149 msg.read(iface, values);
150
151 if (iface == "xyz.openbmc_project.Software.Activation")
152 {
Gayathri Leburu0fb5b502022-11-17 04:51:55 +0000153 const std::string* state = nullptr;
Ed Tanous002d39b2022-05-31 08:59:27 -0700154 for (const auto& property : values)
155 {
156 if (property.first == "Activation")
157 {
Gayathri Leburu0fb5b502022-11-17 04:51:55 +0000158 state = std::get_if<std::string>(
159 &property.second);
160 if (state == nullptr)
James Feist32898ce2020-03-10 16:16:52 -0700161 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700162 taskData->messages.emplace_back(
163 messages::internalError());
James Feist32898ce2020-03-10 16:16:52 -0700164 return task::completed;
165 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700166 }
167 }
James Feist32898ce2020-03-10 16:16:52 -0700168
Ed Tanous002d39b2022-05-31 08:59:27 -0700169 if (state == nullptr)
170 {
171 return !task::completed;
172 }
James Feist32898ce2020-03-10 16:16:52 -0700173
Ed Tanous11ba3972022-07-11 09:50:41 -0700174 if (state->ends_with("Invalid") ||
175 state->ends_with("Failed"))
Ed Tanous002d39b2022-05-31 08:59:27 -0700176 {
177 taskData->state = "Exception";
178 taskData->status = "Warning";
179 taskData->messages.emplace_back(
180 messages::taskAborted(index));
181 return task::completed;
182 }
James Feiste5d50062020-05-11 17:29:00 -0700183
Ed Tanous11ba3972022-07-11 09:50:41 -0700184 if (state->ends_with("Staged"))
Ed Tanous002d39b2022-05-31 08:59:27 -0700185 {
186 taskData->state = "Stopping";
187 taskData->messages.emplace_back(
188 messages::taskPaused(index));
189
190 // its staged, set a long timer to
191 // allow them time to complete the
192 // update (probably cycle the
193 // system) if this expires then
194 // task will be cancelled
195 taskData->extendTimer(std::chrono::hours(5));
196 return !task::completed;
197 }
198
Ed Tanous11ba3972022-07-11 09:50:41 -0700199 if (state->ends_with("Active"))
Ed Tanous002d39b2022-05-31 08:59:27 -0700200 {
201 taskData->messages.emplace_back(
202 messages::taskCompletedOK(index));
203 taskData->state = "Completed";
204 return task::completed;
205 }
206 }
207 else if (
208 iface ==
209 "xyz.openbmc_project.Software.ActivationProgress")
210 {
211
212 const uint8_t* progress = nullptr;
213 for (const auto& property : values)
214 {
215 if (property.first == "Progress")
216 {
Gayathri Leburu0fb5b502022-11-17 04:51:55 +0000217 progress =
218 std::get_if<uint8_t>(&property.second);
219 if (progress == nullptr)
James Feist32898ce2020-03-10 16:16:52 -0700220 {
James Feist32898ce2020-03-10 16:16:52 -0700221 taskData->messages.emplace_back(
Ed Tanous002d39b2022-05-31 08:59:27 -0700222 messages::internalError());
223 return task::completed;
James Feist32898ce2020-03-10 16:16:52 -0700224 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700225 }
226 }
James Feist32898ce2020-03-10 16:16:52 -0700227
Ed Tanous002d39b2022-05-31 08:59:27 -0700228 if (progress == nullptr)
229 {
230 return !task::completed;
231 }
Gayathri Leburu0fb5b502022-11-17 04:51:55 +0000232 taskData->percentComplete = *progress;
Ed Tanous002d39b2022-05-31 08:59:27 -0700233 taskData->messages.emplace_back(
Gayathri Leburu0fb5b502022-11-17 04:51:55 +0000234 messages::taskProgressChanged(index,
235 *progress));
James Feist32898ce2020-03-10 16:16:52 -0700236
Ed Tanous002d39b2022-05-31 08:59:27 -0700237 // if we're getting status updates it's
238 // still alive, update timer
239 taskData->extendTimer(std::chrono::minutes(5));
240 }
241
242 // as firmware update often results in a
243 // reboot, the task may never "complete"
244 // unless it is an error
245
246 return !task::completed;
247 },
248 "type='signal',interface='org.freedesktop.DBus.Properties',"
249 "member='PropertiesChanged',path='" +
250 objPath.str + "'");
251 task->startTimer(std::chrono::minutes(5));
252 task->populateResp(asyncResp->res);
253 task->payload.emplace(std::move(payload));
254 }
255 fwUpdateInProgress = false;
George Liu2b731192023-01-11 16:27:13 +0800256 });
Patrick Williams62bafc02022-09-08 17:35:35 -0500257
258 break;
Andrew Geissler86adcd62019-04-18 10:58:05 -0500259 }
260 }
261}
262
Andrew Geissler0554c982019-04-23 14:40:12 -0500263// Note that asyncResp can be either a valid pointer or nullptr. If nullptr
264// then no asyncResp updates will occur
Ed Tanousb5a76932020-09-29 16:16:58 -0700265static void monitorForSoftwareAvailable(
zhanghch058d1b46d2021-04-01 11:18:24 +0800266 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
267 const crow::Request& req, const std::string& url,
Gunnar Mills5d138942022-09-07 10:26:21 -0500268 int timeoutTimeSeconds = 25)
Andrew Geissler86adcd62019-04-18 10:58:05 -0500269{
270 // Only allow one FW update at a time
Ed Tanouse05aec52022-01-25 10:28:56 -0800271 if (fwUpdateInProgress)
Andrew Geissler86adcd62019-04-18 10:58:05 -0500272 {
Andrew Geissler0554c982019-04-23 14:40:12 -0500273 if (asyncResp)
274 {
Andrew Geissler0554c982019-04-23 14:40:12 -0500275 messages::serviceTemporarilyUnavailable(asyncResp->res, "30");
276 }
Andrew Geissler86adcd62019-04-18 10:58:05 -0500277 return;
278 }
279
Andrew Geissler0554c982019-04-23 14:40:12 -0500280 fwAvailableTimer =
Ed Tanous271584a2019-07-09 16:24:22 -0700281 std::make_unique<boost::asio::steady_timer>(*req.ioService);
Andrew Geissler86adcd62019-04-18 10:58:05 -0500282
Ed Tanous271584a2019-07-09 16:24:22 -0700283 fwAvailableTimer->expires_after(std::chrono::seconds(timeoutTimeSeconds));
Andrew Geissler86adcd62019-04-18 10:58:05 -0500284
285 fwAvailableTimer->async_wait(
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500286 [asyncResp](const boost::system::error_code& ec) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700287 cleanUp();
288 if (ec == boost::asio::error::operation_aborted)
289 {
290 // expected, we were canceled before the timer completed.
291 return;
292 }
293 BMCWEB_LOG_ERROR
294 << "Timed out waiting for firmware object being created";
295 BMCWEB_LOG_ERROR << "FW image may has already been uploaded to server";
296 if (ec)
297 {
298 BMCWEB_LOG_ERROR << "Async_wait failed" << ec;
299 return;
300 }
301 if (asyncResp)
302 {
303 redfish::messages::internalError(asyncResp->res);
304 }
305 });
Ed Tanousa3e65892021-09-16 14:13:20 -0700306 task::Payload payload(req);
Patrick Williams59d494e2022-07-22 19:26:55 -0500307 auto callback = [asyncResp, payload](sdbusplus::message_t& m) mutable {
Andrew Geissler86adcd62019-04-18 10:58:05 -0500308 BMCWEB_LOG_DEBUG << "Match fired";
Ed Tanousa3e65892021-09-16 14:13:20 -0700309 softwareInterfaceAdded(asyncResp, m, std::move(payload));
Andrew Geissler86adcd62019-04-18 10:58:05 -0500310 };
311
312 fwUpdateInProgress = true;
313
Patrick Williams59d494e2022-07-22 19:26:55 -0500314 fwUpdateMatcher = std::make_unique<sdbusplus::bus::match_t>(
Andrew Geissler86adcd62019-04-18 10:58:05 -0500315 *crow::connections::systemBus,
316 "interface='org.freedesktop.DBus.ObjectManager',type='signal',"
317 "member='InterfacesAdded',path='/xyz/openbmc_project/software'",
318 callback);
James Feist4cde5d92020-06-11 10:39:55 -0700319
Patrick Williams59d494e2022-07-22 19:26:55 -0500320 fwUpdateErrorMatcher = std::make_unique<sdbusplus::bus::match_t>(
James Feist4cde5d92020-06-11 10:39:55 -0700321 *crow::connections::systemBus,
Brian Mae1cc4822021-12-01 17:05:54 +0800322 "interface='org.freedesktop.DBus.ObjectManager',type='signal',"
323 "member='InterfacesAdded',"
324 "path='/xyz/openbmc_project/logging'",
Patrick Williams59d494e2022-07-22 19:26:55 -0500325 [asyncResp, url](sdbusplus::message_t& m) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700326 std::vector<std::pair<std::string, dbus::utility::DBusPropertiesMap>>
327 interfacesProperties;
328 sdbusplus::message::object_path objPath;
329 m.read(objPath, interfacesProperties);
330 BMCWEB_LOG_DEBUG << "obj path = " << objPath.str;
331 for (const std::pair<std::string, dbus::utility::DBusPropertiesMap>&
332 interface : interfacesProperties)
333 {
334 if (interface.first == "xyz.openbmc_project.Logging.Entry")
James Feist4cde5d92020-06-11 10:39:55 -0700335 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700336 for (const std::pair<std::string,
337 dbus::utility::DbusVariantType>& value :
338 interface.second)
Brian Mae1cc4822021-12-01 17:05:54 +0800339 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700340 if (value.first != "Message")
Brian Mae1cc4822021-12-01 17:05:54 +0800341 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700342 continue;
343 }
344 const std::string* type =
345 std::get_if<std::string>(&value.second);
346 if (type == nullptr)
347 {
348 // if this was our message, timeout will cover it
349 return;
350 }
351 fwAvailableTimer = nullptr;
352 if (*type ==
353 "xyz.openbmc_project.Software.Image.Error.UnTarFailure")
354 {
355 redfish::messages::invalidUpload(asyncResp->res, url,
356 "Invalid archive");
357 }
358 else if (*type ==
359 "xyz.openbmc_project.Software.Image.Error."
360 "ManifestFileFailure")
361 {
362 redfish::messages::invalidUpload(asyncResp->res, url,
363 "Invalid manifest");
364 }
365 else if (
366 *type ==
367 "xyz.openbmc_project.Software.Image.Error.ImageFailure")
368 {
369 redfish::messages::invalidUpload(
370 asyncResp->res, url, "Invalid image format");
371 }
372 else if (
373 *type ==
374 "xyz.openbmc_project.Software.Version.Error.AlreadyExists")
375 {
376 redfish::messages::invalidUpload(
377 asyncResp->res, url,
378 "Image version already exists");
Gunnar Mills88b3dd12020-11-20 14:26:04 -0600379
Ed Tanous002d39b2022-05-31 08:59:27 -0700380 redfish::messages::resourceAlreadyExists(
Jiaqing Zhaod8a5d5d2022-08-05 16:21:51 +0800381 asyncResp->res, "UpdateService", "Version",
Ed Tanous002d39b2022-05-31 08:59:27 -0700382 "uploaded version");
383 }
384 else if (
385 *type ==
386 "xyz.openbmc_project.Software.Image.Error.BusyFailure")
387 {
388 redfish::messages::resourceExhaustion(asyncResp->res,
389 url);
390 }
391 else
392 {
393 redfish::messages::internalError(asyncResp->res);
Brian Mae1cc4822021-12-01 17:05:54 +0800394 }
395 }
Gunnar Mills88b3dd12020-11-20 14:26:04 -0600396 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700397 }
James Feist4cde5d92020-06-11 10:39:55 -0700398 });
Andrew Geissler86adcd62019-04-18 10:58:05 -0500399}
Jennifer Lee729dae72018-04-24 15:59:34 -0700400
Andrew Geissler0554c982019-04-23 14:40:12 -0500401/**
402 * UpdateServiceActionsSimpleUpdate class supports handle POST method for
403 * SimpleUpdate action.
404 */
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700405inline void requestRoutesUpdateServiceActionsSimpleUpdate(App& app)
Andrew Geissler0554c982019-04-23 14:40:12 -0500406{
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700407 BMCWEB_ROUTE(
408 app, "/redfish/v1/UpdateService/Actions/UpdateService.SimpleUpdate/")
Ed Tanoused398212021-06-09 17:05:54 -0700409 .privileges(redfish::privileges::postUpdateService)
Ed Tanous002d39b2022-05-31 08:59:27 -0700410 .methods(boost::beast::http::verb::post)(
411 [&app](const crow::Request& req,
412 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Carson Labrado3ba00072022-06-06 19:40:56 +0000413 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -0700414 {
415 return;
416 }
Ed Tanous45ca1b82022-03-25 13:07:27 -0700417
Ed Tanous002d39b2022-05-31 08:59:27 -0700418 std::optional<std::string> transferProtocol;
419 std::string imageURI;
Andrew Geissler0554c982019-04-23 14:40:12 -0500420
Ed Tanous002d39b2022-05-31 08:59:27 -0700421 BMCWEB_LOG_DEBUG << "Enter UpdateService.SimpleUpdate doPost";
Andrew Geissler0554c982019-04-23 14:40:12 -0500422
Ed Tanous002d39b2022-05-31 08:59:27 -0700423 // User can pass in both TransferProtocol and ImageURI parameters or
424 // they can pass in just the ImageURI with the transfer protocol
425 // embedded within it.
426 // 1) TransferProtocol:TFTP ImageURI:1.1.1.1/myfile.bin
427 // 2) ImageURI:tftp://1.1.1.1/myfile.bin
Andrew Geissler0554c982019-04-23 14:40:12 -0500428
Ed Tanous002d39b2022-05-31 08:59:27 -0700429 if (!json_util::readJsonAction(req, asyncResp->res, "TransferProtocol",
430 transferProtocol, "ImageURI", imageURI))
431 {
432 BMCWEB_LOG_DEBUG
433 << "Missing TransferProtocol or ImageURI parameter";
434 return;
435 }
436 if (!transferProtocol)
437 {
438 // Must be option 2
439 // Verify ImageURI has transfer protocol in it
440 size_t separator = imageURI.find(':');
Andrew Geissler0554c982019-04-23 14:40:12 -0500441 if ((separator == std::string::npos) ||
442 ((separator + 1) > imageURI.size()))
443 {
444 messages::actionParameterValueTypeError(
445 asyncResp->res, imageURI, "ImageURI",
446 "UpdateService.SimpleUpdate");
Ed Tanous002d39b2022-05-31 08:59:27 -0700447 BMCWEB_LOG_ERROR << "ImageURI missing transfer protocol: "
448 << imageURI;
Jayashankar Padath274dfe62019-08-23 12:30:57 +0530449 return;
Jayashankar Padathfa1a5a32019-05-28 23:54:37 +0530450 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700451 transferProtocol = imageURI.substr(0, separator);
452 // Ensure protocol is upper case for a common comparison path
453 // below
454 boost::to_upper(*transferProtocol);
455 BMCWEB_LOG_DEBUG << "Encoded transfer protocol "
456 << *transferProtocol;
Jayashankar Padathfa1a5a32019-05-28 23:54:37 +0530457
Ed Tanous002d39b2022-05-31 08:59:27 -0700458 // Adjust imageURI to not have the protocol on it for parsing
459 // below
460 // ex. tftp://1.1.1.1/myfile.bin -> 1.1.1.1/myfile.bin
461 imageURI = imageURI.substr(separator + 3);
462 BMCWEB_LOG_DEBUG << "Adjusted imageUri " << imageURI;
463 }
Jayashankar Padath274dfe62019-08-23 12:30:57 +0530464
Ed Tanous002d39b2022-05-31 08:59:27 -0700465 // OpenBMC currently only supports TFTP
466 if (*transferProtocol != "TFTP")
467 {
468 messages::actionParameterNotSupported(asyncResp->res,
469 "TransferProtocol",
470 "UpdateService.SimpleUpdate");
471 BMCWEB_LOG_ERROR << "Request incorrect protocol parameter: "
472 << *transferProtocol;
473 return;
474 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700475
Ed Tanous002d39b2022-05-31 08:59:27 -0700476 // Format should be <IP or Hostname>/<file> for imageURI
477 size_t separator = imageURI.find('/');
478 if ((separator == std::string::npos) ||
479 ((separator + 1) > imageURI.size()))
480 {
481 messages::actionParameterValueTypeError(
482 asyncResp->res, imageURI, "ImageURI",
483 "UpdateService.SimpleUpdate");
484 BMCWEB_LOG_ERROR << "Invalid ImageURI: " << imageURI;
485 return;
486 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700487
Ed Tanous002d39b2022-05-31 08:59:27 -0700488 std::string tftpServer = imageURI.substr(0, separator);
489 std::string fwFile = imageURI.substr(separator + 1);
490 BMCWEB_LOG_DEBUG << "Server: " << tftpServer + " File: " << fwFile;
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700491
Ed Tanous002d39b2022-05-31 08:59:27 -0700492 // Setup callback for when new software detected
493 // Give TFTP 10 minutes to complete
494 monitorForSoftwareAvailable(
495 asyncResp, req,
496 "/redfish/v1/UpdateService/Actions/UpdateService.SimpleUpdate",
497 600);
498
499 // TFTP can take up to 10 minutes depending on image size and
500 // connection speed. Return to caller as soon as the TFTP operation
501 // has been started. The callback above will ensure the activate
502 // is started once the download has completed
503 redfish::messages::success(asyncResp->res);
504
505 // Call TFTP service
506 crow::connections::systemBus->async_method_call(
507 [](const boost::system::error_code ec) {
508 if (ec)
509 {
510 // messages::internalError(asyncResp->res);
511 cleanUp();
512 BMCWEB_LOG_DEBUG << "error_code = " << ec;
513 BMCWEB_LOG_DEBUG << "error msg = " << ec.message();
514 }
515 else
516 {
517 BMCWEB_LOG_DEBUG << "Call to DownloaViaTFTP Success";
518 }
519 },
520 "xyz.openbmc_project.Software.Download",
521 "/xyz/openbmc_project/software", "xyz.openbmc_project.Common.TFTP",
522 "DownloadViaTFTP", fwFile, tftpServer);
523
524 BMCWEB_LOG_DEBUG << "Exit UpdateService.SimpleUpdate doPost";
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700525 });
526}
527
Ed Tanousc2051d12022-05-11 12:21:55 -0700528inline void
529 handleUpdateServicePost(App& app, const crow::Request& req,
530 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
531{
Carson Labrado3ba00072022-06-06 19:40:56 +0000532 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanousc2051d12022-05-11 12:21:55 -0700533 {
534 return;
535 }
536 BMCWEB_LOG_DEBUG << "doPost...";
537
538 // Setup callback for when new software detected
539 monitorForSoftwareAvailable(asyncResp, req, "/redfish/v1/UpdateService");
540
541 std::string filepath(
542 "/tmp/images/" +
543 boost::uuids::to_string(boost::uuids::random_generator()()));
544 BMCWEB_LOG_DEBUG << "Writing file to " << filepath;
545 std::ofstream out(filepath, std::ofstream::out | std::ofstream::binary |
546 std::ofstream::trunc);
547 out << req.body;
548 out.close();
549 BMCWEB_LOG_DEBUG << "file upload complete!!";
550}
551
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700552inline void requestRoutesUpdateService(App& app)
553{
554 BMCWEB_ROUTE(app, "/redfish/v1/UpdateService/")
Ed Tanoused398212021-06-09 17:05:54 -0700555 .privileges(redfish::privileges::getUpdateService)
Ed Tanous002d39b2022-05-31 08:59:27 -0700556 .methods(boost::beast::http::verb::get)(
557 [&app](const crow::Request& req,
558 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Carson Labrado3ba00072022-06-06 19:40:56 +0000559 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -0700560 {
561 return;
562 }
563 asyncResp->res.jsonValue["@odata.type"] =
564 "#UpdateService.v1_5_0.UpdateService";
565 asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/UpdateService";
566 asyncResp->res.jsonValue["Id"] = "UpdateService";
567 asyncResp->res.jsonValue["Description"] = "Service for Software Update";
568 asyncResp->res.jsonValue["Name"] = "Update Service";
Ed Tanous4dc23f32022-05-11 11:32:19 -0700569
Ed Tanous32ca38a2022-05-11 12:36:59 -0700570#ifdef BMCWEB_ENABLE_REDFISH_UPDATESERVICE_OLD_POST_URL
Ed Tanous002d39b2022-05-31 08:59:27 -0700571 // See note about later on in this file about why this is neccesary
572 // This is "Wrong" per the standard, but is done temporarily to
573 // avoid noise in failing tests as people transition to having this
574 // option disabled
575 asyncResp->res.addHeader(boost::beast::http::field::allow,
576 "GET, PATCH, HEAD");
Ed Tanous32ca38a2022-05-11 12:36:59 -0700577#endif
578
Ed Tanous002d39b2022-05-31 08:59:27 -0700579 asyncResp->res.jsonValue["HttpPushUri"] =
580 "/redfish/v1/UpdateService/update";
Ed Tanous4dc23f32022-05-11 11:32:19 -0700581
Ed Tanous002d39b2022-05-31 08:59:27 -0700582 // UpdateService cannot be disabled
583 asyncResp->res.jsonValue["ServiceEnabled"] = true;
584 asyncResp->res.jsonValue["FirmwareInventory"]["@odata.id"] =
585 "/redfish/v1/UpdateService/FirmwareInventory";
586 // Get the MaxImageSizeBytes
587 asyncResp->res.jsonValue["MaxImageSizeBytes"] =
588 bmcwebHttpReqBodyLimitMb * 1024 * 1024;
Tejas Patild61e5192021-06-04 15:49:35 +0530589
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700590#ifdef BMCWEB_INSECURE_ENABLE_REDFISH_FW_TFTP_UPDATE
Ed Tanous002d39b2022-05-31 08:59:27 -0700591 // Update Actions object.
592 nlohmann::json& updateSvcSimpleUpdate =
593 asyncResp->res.jsonValue["Actions"]["#UpdateService.SimpleUpdate"];
594 updateSvcSimpleUpdate["target"] =
595 "/redfish/v1/UpdateService/Actions/UpdateService.SimpleUpdate";
596 updateSvcSimpleUpdate["TransferProtocol@Redfish.AllowableValues"] = {
597 "TFTP"};
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700598#endif
Ed Tanous002d39b2022-05-31 08:59:27 -0700599 // Get the current ApplyTime value
600 sdbusplus::asio::getProperty<std::string>(
601 *crow::connections::systemBus, "xyz.openbmc_project.Settings",
602 "/xyz/openbmc_project/software/apply_time",
603 "xyz.openbmc_project.Software.ApplyTime", "RequestedApplyTime",
604 [asyncResp](const boost::system::error_code ec,
605 const std::string& applyTime) {
606 if (ec)
607 {
608 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
609 messages::internalError(asyncResp->res);
610 return;
611 }
Jayashankar Padath274dfe62019-08-23 12:30:57 +0530612
Ed Tanous002d39b2022-05-31 08:59:27 -0700613 // Store the ApplyTime Value
614 if (applyTime == "xyz.openbmc_project.Software.ApplyTime."
615 "RequestedApplyTimes.Immediate")
616 {
617 asyncResp->res.jsonValue["HttpPushUriOptions"]
618 ["HttpPushUriApplyTime"]["ApplyTime"] =
619 "Immediate";
620 }
621 else if (applyTime == "xyz.openbmc_project.Software.ApplyTime."
622 "RequestedApplyTimes.OnReset")
623 {
624 asyncResp->res.jsonValue["HttpPushUriOptions"]
625 ["HttpPushUriApplyTime"]["ApplyTime"] =
626 "OnReset";
627 }
628 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700629 });
630 BMCWEB_ROUTE(app, "/redfish/v1/UpdateService/")
Ed Tanoused398212021-06-09 17:05:54 -0700631 .privileges(redfish::privileges::patchUpdateService)
Ed Tanous002d39b2022-05-31 08:59:27 -0700632 .methods(boost::beast::http::verb::patch)(
633 [&app](const crow::Request& req,
634 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Carson Labrado3ba00072022-06-06 19:40:56 +0000635 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -0700636 {
637 return;
638 }
639 BMCWEB_LOG_DEBUG << "doPatch...";
Jayashankar Padathfa1a5a32019-05-28 23:54:37 +0530640
Ed Tanous002d39b2022-05-31 08:59:27 -0700641 std::optional<nlohmann::json> pushUriOptions;
642 if (!json_util::readJsonPatch(req, asyncResp->res, "HttpPushUriOptions",
643 pushUriOptions))
644 {
645 return;
646 }
647
648 if (pushUriOptions)
649 {
650 std::optional<nlohmann::json> pushUriApplyTime;
651 if (!json_util::readJson(*pushUriOptions, asyncResp->res,
652 "HttpPushUriApplyTime", pushUriApplyTime))
George Liu0fda0f12021-11-16 10:06:17 +0800653 {
654 return;
655 }
656
Ed Tanous002d39b2022-05-31 08:59:27 -0700657 if (pushUriApplyTime)
George Liu0fda0f12021-11-16 10:06:17 +0800658 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700659 std::optional<std::string> applyTime;
660 if (!json_util::readJson(*pushUriApplyTime, asyncResp->res,
661 "ApplyTime", applyTime))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700662 {
Ed Tanousc711bf82018-07-30 16:31:33 -0700663 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700664 }
Jennifer Lee6c4eb9d2018-05-22 10:58:31 -0700665
Ed Tanous002d39b2022-05-31 08:59:27 -0700666 if (applyTime)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700667 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700668 std::string applyTimeNewVal;
669 if (applyTime == "Immediate")
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700670 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700671 applyTimeNewVal =
672 "xyz.openbmc_project.Software.ApplyTime.RequestedApplyTimes.Immediate";
673 }
674 else if (applyTime == "OnReset")
675 {
676 applyTimeNewVal =
677 "xyz.openbmc_project.Software.ApplyTime.RequestedApplyTimes.OnReset";
678 }
679 else
680 {
681 BMCWEB_LOG_INFO
682 << "ApplyTime value is not in the list of acceptable values";
683 messages::propertyValueNotInList(
684 asyncResp->res, *applyTime, "ApplyTime");
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700685 return;
686 }
687
Ed Tanous002d39b2022-05-31 08:59:27 -0700688 // Set the requested image apply time value
689 crow::connections::systemBus->async_method_call(
690 [asyncResp](const boost::system::error_code ec) {
691 if (ec)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700692 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700693 BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec;
694 messages::internalError(asyncResp->res);
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700695 return;
696 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700697 messages::success(asyncResp->res);
698 },
699 "xyz.openbmc_project.Settings",
700 "/xyz/openbmc_project/software/apply_time",
701 "org.freedesktop.DBus.Properties", "Set",
702 "xyz.openbmc_project.Software.ApplyTime",
703 "RequestedApplyTime",
704 dbus::utility::DbusVariantType{applyTimeNewVal});
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700705 }
George Liu0fda0f12021-11-16 10:06:17 +0800706 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700707 }
George Liu0fda0f12021-11-16 10:06:17 +0800708 });
Ed Tanousc2051d12022-05-11 12:21:55 -0700709
Ed Tanous4dc23f32022-05-11 11:32:19 -0700710// The "old" behavior of the update service URI causes redfish-service validator
711// failures when the Allow header is supported, given that in the spec,
712// UpdateService does not allow POST. in openbmc, we unfortunately reused that
713// resource as our HttpPushUri as well. A number of services, including the
714// openbmc tests, and documentation have hardcoded that erroneous API, instead
715// of relying on HttpPushUri as the spec requires. This option will exist
716// temporarily to allow the old behavior until Q4 2022, at which time it will be
717// removed.
718#ifdef BMCWEB_ENABLE_REDFISH_UPDATESERVICE_OLD_POST_URL
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700719 BMCWEB_ROUTE(app, "/redfish/v1/UpdateService/")
Ed Tanoused398212021-06-09 17:05:54 -0700720 .privileges(redfish::privileges::postUpdateService)
Ed Tanous002d39b2022-05-31 08:59:27 -0700721 .methods(boost::beast::http::verb::post)(
722 [&app](const crow::Request& req,
723 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
724 asyncResp->res.addHeader(
725 boost::beast::http::field::warning,
726 "299 - \"POST to /redfish/v1/UpdateService is deprecated. Use "
727 "the value contained within HttpPushUri.\"");
728 handleUpdateServicePost(app, req, asyncResp);
Ed Tanous4dc23f32022-05-11 11:32:19 -0700729 });
730#endif
731 BMCWEB_ROUTE(app, "/redfish/v1/UpdateService/update/")
732 .privileges(redfish::privileges::postUpdateService)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700733 .methods(boost::beast::http::verb::post)(
Ed Tanousc2051d12022-05-11 12:21:55 -0700734 std::bind_front(handleUpdateServicePost, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700735}
736
737inline void requestRoutesSoftwareInventoryCollection(App& app)
738{
739 BMCWEB_ROUTE(app, "/redfish/v1/UpdateService/FirmwareInventory/")
Ed Tanoused398212021-06-09 17:05:54 -0700740 .privileges(redfish::privileges::getSoftwareInventoryCollection)
Ed Tanous14766872022-03-15 10:44:42 -0700741 .methods(boost::beast::http::verb::get)(
742 [&app](const crow::Request& req,
743 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Carson Labrado3ba00072022-06-06 19:40:56 +0000744 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -0700745 {
746 return;
747 }
748 asyncResp->res.jsonValue["@odata.type"] =
749 "#SoftwareInventoryCollection.SoftwareInventoryCollection";
750 asyncResp->res.jsonValue["@odata.id"] =
751 "/redfish/v1/UpdateService/FirmwareInventory";
752 asyncResp->res.jsonValue["Name"] = "Software Inventory Collection";
753
George Liue99073f2022-12-09 11:06:16 +0800754 // Note that only firmware levels associated with a device
755 // are stored under /xyz/openbmc_project/software therefore
756 // to ensure only real FirmwareInventory items are returned,
757 // this full object path must be used here as input to
758 // mapper
759 constexpr std::array<std::string_view, 1> interfaces = {
760 "xyz.openbmc_project.Software.Version"};
761 dbus::utility::getSubTree(
762 "/xyz/openbmc_project/software", 0, interfaces,
Ed Tanous002d39b2022-05-31 08:59:27 -0700763 [asyncResp](
George Liue99073f2022-12-09 11:06:16 +0800764 const boost::system::error_code& ec,
Ed Tanous002d39b2022-05-31 08:59:27 -0700765 const dbus::utility::MapperGetSubTreeResponse& subtree) {
766 if (ec)
767 {
768 messages::internalError(asyncResp->res);
769 return;
770 }
771 asyncResp->res.jsonValue["Members"] = nlohmann::json::array();
772 asyncResp->res.jsonValue["Members@odata.count"] = 0;
773
774 for (const auto& obj : subtree)
775 {
776 sdbusplus::message::object_path path(obj.first);
777 std::string swId = path.filename();
778 if (swId.empty())
Ed Tanous14766872022-03-15 10:44:42 -0700779 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700780 messages::internalError(asyncResp->res);
781 BMCWEB_LOG_DEBUG << "Can't parse firmware ID!!";
Ed Tanous14766872022-03-15 10:44:42 -0700782 return;
783 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700784
Ed Tanous002d39b2022-05-31 08:59:27 -0700785 nlohmann::json& members = asyncResp->res.jsonValue["Members"];
786 nlohmann::json::object_t member;
787 member["@odata.id"] =
788 "/redfish/v1/UpdateService/FirmwareInventory/" + swId;
789 members.push_back(std::move(member));
790 asyncResp->res.jsonValue["Members@odata.count"] =
791 members.size();
792 }
George Liue99073f2022-12-09 11:06:16 +0800793 });
Ed Tanous002d39b2022-05-31 08:59:27 -0700794 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700795}
796/* Fill related item links (i.e. bmc, bios) in for inventory */
797inline static void
798 getRelatedItems(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
799 const std::string& purpose)
800{
Willy Tueee00132022-06-14 14:53:17 -0700801 if (purpose == sw_util::bmcPurpose)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700802 {
803 nlohmann::json& relatedItem = aResp->res.jsonValue["RelatedItem"];
Ed Tanous14766872022-03-15 10:44:42 -0700804 nlohmann::json::object_t item;
805 item["@odata.id"] = "/redfish/v1/Managers/bmc";
806 relatedItem.push_back(std::move(item));
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700807 aResp->res.jsonValue["RelatedItem@odata.count"] = relatedItem.size();
808 }
Willy Tueee00132022-06-14 14:53:17 -0700809 else if (purpose == sw_util::biosPurpose)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700810 {
811 nlohmann::json& relatedItem = aResp->res.jsonValue["RelatedItem"];
Ed Tanous14766872022-03-15 10:44:42 -0700812 nlohmann::json::object_t item;
813 item["@odata.id"] = "/redfish/v1/Systems/system/Bios";
814 relatedItem.push_back(std::move(item));
Jiaqing Zhao1a6e51a2022-01-19 19:20:24 +0800815 aResp->res.jsonValue["RelatedItem@odata.count"] = relatedItem.size();
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700816 }
817 else
818 {
819 BMCWEB_LOG_ERROR << "Unknown software purpose " << purpose;
820 }
821}
822
Willy Tuaf246602022-06-14 15:51:53 -0700823inline void
824 getSoftwareVersion(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
825 const std::string& service, const std::string& path,
826 const std::string& swId)
827{
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +0200828 sdbusplus::asio::getAllProperties(
829 *crow::connections::systemBus, service, path,
830 "xyz.openbmc_project.Software.Version",
Willy Tuaf246602022-06-14 15:51:53 -0700831 [asyncResp,
832 swId](const boost::system::error_code errorCode,
833 const dbus::utility::DBusPropertiesMap& propertiesList) {
834 if (errorCode)
835 {
836 messages::internalError(asyncResp->res);
837 return;
838 }
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +0200839
Willy Tuaf246602022-06-14 15:51:53 -0700840 const std::string* swInvPurpose = nullptr;
841 const std::string* version = nullptr;
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +0200842
843 const bool success = sdbusplus::unpackPropertiesNoThrow(
844 dbus_utils::UnpackErrorPrinter(), propertiesList, "Purpose",
845 swInvPurpose, "Version", version);
846
847 if (!success)
Willy Tuaf246602022-06-14 15:51:53 -0700848 {
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +0200849 messages::internalError(asyncResp->res);
850 return;
Willy Tuaf246602022-06-14 15:51:53 -0700851 }
852
853 if (swInvPurpose == nullptr)
854 {
855 BMCWEB_LOG_DEBUG << "Can't find property \"Purpose\"!";
856 messages::internalError(asyncResp->res);
857 return;
858 }
859
860 BMCWEB_LOG_DEBUG << "swInvPurpose = " << *swInvPurpose;
861
862 if (version == nullptr)
863 {
864 BMCWEB_LOG_DEBUG << "Can't find property \"Version\"!";
865
866 messages::internalError(asyncResp->res);
867
868 return;
869 }
870 asyncResp->res.jsonValue["Version"] = *version;
871 asyncResp->res.jsonValue["Id"] = swId;
872
873 // swInvPurpose is of format:
874 // xyz.openbmc_project.Software.Version.VersionPurpose.ABC
875 // Translate this to "ABC image"
876 size_t endDesc = swInvPurpose->rfind('.');
877 if (endDesc == std::string::npos)
878 {
879 messages::internalError(asyncResp->res);
880 return;
881 }
882 endDesc++;
883 if (endDesc >= swInvPurpose->size())
884 {
885 messages::internalError(asyncResp->res);
886 return;
887 }
888
889 std::string formatDesc = swInvPurpose->substr(endDesc);
890 asyncResp->res.jsonValue["Description"] = formatDesc + " image";
891 getRelatedItems(asyncResp, *swInvPurpose);
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +0200892 });
Willy Tuaf246602022-06-14 15:51:53 -0700893}
894
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700895inline void requestRoutesSoftwareInventory(App& app)
896{
897 BMCWEB_ROUTE(app, "/redfish/v1/UpdateService/FirmwareInventory/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -0700898 .privileges(redfish::privileges::getSoftwareInventory)
Ed Tanous002d39b2022-05-31 08:59:27 -0700899 .methods(boost::beast::http::verb::get)(
900 [&app](const crow::Request& req,
901 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
902 const std::string& param) {
Carson Labrado3ba00072022-06-06 19:40:56 +0000903 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -0700904 {
905 return;
906 }
907 std::shared_ptr<std::string> swId =
908 std::make_shared<std::string>(param);
909
910 asyncResp->res.jsonValue["@odata.id"] =
911 "/redfish/v1/UpdateService/FirmwareInventory/" + *swId;
912
George Liue99073f2022-12-09 11:06:16 +0800913 constexpr std::array<std::string_view, 1> interfaces = {
914 "xyz.openbmc_project.Software.Version"};
915 dbus::utility::getSubTree(
916 "/", 0, interfaces,
Ed Tanous002d39b2022-05-31 08:59:27 -0700917 [asyncResp,
George Liue99073f2022-12-09 11:06:16 +0800918 swId](const boost::system::error_code& ec,
Ed Tanous002d39b2022-05-31 08:59:27 -0700919 const dbus::utility::MapperGetSubTreeResponse& subtree) {
920 BMCWEB_LOG_DEBUG << "doGet callback...";
921 if (ec)
Ed Tanous45ca1b82022-03-25 13:07:27 -0700922 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700923 messages::internalError(asyncResp->res);
Ed Tanous45ca1b82022-03-25 13:07:27 -0700924 return;
925 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700926
Ed Tanous002d39b2022-05-31 08:59:27 -0700927 // Ensure we find our input swId, otherwise return an error
928 bool found = false;
929 for (const std::pair<std::string,
930 std::vector<std::pair<
931 std::string, std::vector<std::string>>>>&
932 obj : subtree)
933 {
Ed Tanous11ba3972022-07-11 09:50:41 -0700934 if (!obj.first.ends_with(*swId))
Ed Tanous002d39b2022-05-31 08:59:27 -0700935 {
936 continue;
937 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700938
Ed Tanous002d39b2022-05-31 08:59:27 -0700939 if (obj.second.empty())
940 {
941 continue;
942 }
943
944 found = true;
Willy Tueee00132022-06-14 14:53:17 -0700945 sw_util::getSwStatus(asyncResp, swId, obj.second[0].first);
Willy Tuaf246602022-06-14 15:51:53 -0700946 getSoftwareVersion(asyncResp, obj.second[0].first, obj.first,
947 *swId);
Ed Tanous002d39b2022-05-31 08:59:27 -0700948 }
949 if (!found)
950 {
951 BMCWEB_LOG_ERROR << "Input swID " << *swId << " not found!";
952 messages::resourceMissingAtURI(
953 asyncResp->res, crow::utility::urlFromPieces(
954 "redfish", "v1", "UpdateService",
955 "FirmwareInventory", *swId));
956 return;
957 }
958 asyncResp->res.jsonValue["@odata.type"] =
959 "#SoftwareInventory.v1_1_0.SoftwareInventory";
960 asyncResp->res.jsonValue["Name"] = "Software Inventory";
961 asyncResp->res.jsonValue["Status"]["HealthRollup"] = "OK";
Ed Tanous1abe55e2018-09-05 08:30:59 -0700962
Ed Tanous002d39b2022-05-31 08:59:27 -0700963 asyncResp->res.jsonValue["Updateable"] = false;
Willy Tueee00132022-06-14 14:53:17 -0700964 sw_util::getSwUpdatableStatus(asyncResp, swId);
George Liue99073f2022-12-09 11:06:16 +0800965 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700966 });
967}
Ed Tanous1abe55e2018-09-05 08:30:59 -0700968
969} // namespace redfish