blob: 6efcab57668e9fcf627549399dd9b0dea1bb0609 [file] [log] [blame]
Ed Tanous40e9b922024-09-10 13:50:16 -07001// SPDX-License-Identifier: Apache-2.0
2// SPDX-FileCopyrightText: Copyright OpenBMC Authors
3// SPDX-FileCopyrightText: Copyright 2018 Intel Corporation
Jennifer Lee729dae72018-04-24 15:59:34 -07004#pragma once
5
Tejas Patild61e5192021-06-04 15:49:35 +05306#include "bmcweb_config.h"
7
Ed Tanous3ccb3ad2023-01-13 17:40:03 -08008#include "app.hpp"
Ed Tanousd7857202025-01-28 15:32:26 -08009#include "async_resp.hpp"
10#include "dbus_singleton.hpp"
Ed Tanous3ccb3ad2023-01-13 17:40:03 -080011#include "dbus_utility.hpp"
Ed Tanous5b904292024-04-16 11:10:17 -070012#include "error_messages.hpp"
Ed Tanousd7857202025-01-28 15:32:26 -080013#include "generated/enums/resource.hpp"
Ed Tanous757178a2024-04-03 14:32:38 -070014#include "generated/enums/update_service.hpp"
Ed Tanousd7857202025-01-28 15:32:26 -080015#include "http_request.hpp"
16#include "http_response.hpp"
17#include "logging.hpp"
George Liu0ed80c82020-05-12 16:06:27 +080018#include "multipart_parser.hpp"
Ed Tanous2c6ffdb2023-06-28 11:28:38 -070019#include "ossl_random.hpp"
Ed Tanous3ccb3ad2023-01-13 17:40:03 -080020#include "query.hpp"
21#include "registries/privilege_registry.hpp"
Ed Tanousd7857202025-01-28 15:32:26 -080022#include "str_utility.hpp"
Ed Tanousa8e884f2023-01-13 17:40:03 -080023#include "task.hpp"
Ed Tanous5b904292024-04-16 11:10:17 -070024#include "task_messages.hpp"
Ed Tanousd7857202025-01-28 15:32:26 -080025#include "utility.hpp"
John Edward Broadbent08d81ad2022-05-17 20:00:23 -070026#include "utils/collection.hpp"
Ed Tanous3ccb3ad2023-01-13 17:40:03 -080027#include "utils/dbus_utils.hpp"
Ed Tanous5b904292024-04-16 11:10:17 -070028#include "utils/json_utils.hpp"
Ed Tanous3ccb3ad2023-01-13 17:40:03 -080029#include "utils/sw_utils.hpp"
30
Jagpal Singh Gillde0c9602024-04-29 17:30:21 -070031#include <sys/mman.h>
Ed Tanousd7857202025-01-28 15:32:26 -080032#include <unistd.h>
Jagpal Singh Gillde0c9602024-04-29 17:30:21 -070033
Ed Tanousd7857202025-01-28 15:32:26 -080034#include <boost/asio/error.hpp>
35#include <boost/asio/steady_timer.hpp>
36#include <boost/beast/http/fields.hpp>
37#include <boost/beast/http/status.hpp>
38#include <boost/beast/http/verb.hpp>
George Liue99073f2022-12-09 11:06:16 +080039#include <boost/system/error_code.hpp>
Ed Tanousd7857202025-01-28 15:32:26 -080040#include <boost/system/result.hpp>
Ed Tanousef4c65b2023-04-24 15:28:50 -070041#include <boost/url/format.hpp>
Ed Tanousd7857202025-01-28 15:32:26 -080042#include <boost/url/parse.hpp>
43#include <boost/url/url.hpp>
44#include <boost/url/url_view.hpp>
45#include <boost/url/url_view_base.hpp>
Jonathan Doman1e1e5982021-06-11 09:36:17 -070046#include <sdbusplus/asio/property.hpp>
Ed Tanous3ccb3ad2023-01-13 17:40:03 -080047#include <sdbusplus/bus/match.hpp>
Ed Tanousd7857202025-01-28 15:32:26 -080048#include <sdbusplus/message.hpp>
49#include <sdbusplus/message/native_types.hpp>
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +020050#include <sdbusplus/unpack_properties.hpp>
Gunnar Mills1214b7e2020-06-04 10:11:30 -050051
George Liu2b731192023-01-11 16:27:13 +080052#include <array>
Ed Tanousd7857202025-01-28 15:32:26 -080053#include <chrono>
Jagpal Singh Gillde0c9602024-04-29 17:30:21 -070054#include <cstddef>
Ed Tanousd7857202025-01-28 15:32:26 -080055#include <cstdint>
56#include <cstdio>
George Liu0ed80c82020-05-12 16:06:27 +080057#include <filesystem>
Ed Tanousd7857202025-01-28 15:32:26 -080058#include <format>
59#include <fstream>
Jagpal Singh Gillc71b6c92024-04-29 16:50:53 -070060#include <functional>
Jagpal Singh Gillef93eab2024-04-17 16:06:14 -070061#include <memory>
Ed Tanous7cb59f62022-05-05 11:48:31 -070062#include <optional>
63#include <string>
George Liu2b731192023-01-11 16:27:13 +080064#include <string_view>
Jagpal Singh Gillde0c9602024-04-29 17:30:21 -070065#include <unordered_map>
Ed Tanousd7857202025-01-28 15:32:26 -080066#include <utility>
67#include <variant>
Jagpal Singh Gillef93eab2024-04-17 16:06:14 -070068#include <vector>
George Liu2b731192023-01-11 16:27:13 +080069
Ed Tanous1abe55e2018-09-05 08:30:59 -070070namespace redfish
71{
Ed Tanous27826b52018-10-29 11:40:58 -070072
Andrew Geissler0e7de462019-03-04 19:11:54 -060073// Match signals added on software path
Ed Tanouscf9e4172022-12-21 09:30:16 -080074// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
Patrick Williams59d494e2022-07-22 19:26:55 -050075static std::unique_ptr<sdbusplus::bus::match_t> fwUpdateMatcher;
Ed Tanouscf9e4172022-12-21 09:30:16 -080076// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
Patrick Williams59d494e2022-07-22 19:26:55 -050077static std::unique_ptr<sdbusplus::bus::match_t> fwUpdateErrorMatcher;
Andrew Geissler0e7de462019-03-04 19:11:54 -060078// Only allow one update at a time
Ed Tanouscf9e4172022-12-21 09:30:16 -080079// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
Andrew Geissler0e7de462019-03-04 19:11:54 -060080static bool fwUpdateInProgress = false;
Andrew Geissler86adcd62019-04-18 10:58:05 -050081// Timer for software available
Ed Tanouscf9e4172022-12-21 09:30:16 -080082// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
Ed Tanous271584a2019-07-09 16:24:22 -070083static std::unique_ptr<boost::asio::steady_timer> fwAvailableTimer;
Andrew Geissler86adcd62019-04-18 10:58:05 -050084
Jagpal Singh Gillde0c9602024-04-29 17:30:21 -070085struct MemoryFileDescriptor
86{
87 int fd = -1;
88
89 explicit MemoryFileDescriptor(const std::string& filename) :
90 fd(memfd_create(filename.c_str(), 0))
91 {}
92
93 MemoryFileDescriptor(const MemoryFileDescriptor&) = default;
94 MemoryFileDescriptor(MemoryFileDescriptor&& other) noexcept : fd(other.fd)
95 {
96 other.fd = -1;
97 }
98 MemoryFileDescriptor& operator=(const MemoryFileDescriptor&) = delete;
99 MemoryFileDescriptor& operator=(MemoryFileDescriptor&&) = default;
100
101 ~MemoryFileDescriptor()
102 {
103 if (fd != -1)
104 {
105 close(fd);
106 }
107 }
108
109 bool rewind() const
110 {
111 if (lseek(fd, 0, SEEK_SET) == -1)
112 {
113 BMCWEB_LOG_ERROR("Failed to seek to beginning of image memfd");
114 return false;
115 }
116 return true;
117 }
118};
119
Ed Tanousdf254f22024-04-01 13:25:46 -0700120inline void cleanUp()
Andrew Geissler86adcd62019-04-18 10:58:05 -0500121{
122 fwUpdateInProgress = false;
123 fwUpdateMatcher = nullptr;
James Feist4cde5d92020-06-11 10:39:55 -0700124 fwUpdateErrorMatcher = nullptr;
Andrew Geissler86adcd62019-04-18 10:58:05 -0500125}
Ed Tanousdf254f22024-04-01 13:25:46 -0700126
127inline void activateImage(const std::string& objPath,
128 const std::string& service)
Andrew Geissler86adcd62019-04-18 10:58:05 -0500129{
Ed Tanous62598e32023-07-17 17:06:25 -0700130 BMCWEB_LOG_DEBUG("Activate image for {} {}", objPath, service);
George Liu9ae226f2023-06-21 17:56:46 +0800131 sdbusplus::asio::setProperty(
132 *crow::connections::systemBus, service, objPath,
133 "xyz.openbmc_project.Software.Activation", "RequestedActivation",
134 "xyz.openbmc_project.Software.Activation.RequestedActivations.Active",
Ed Tanous8b242752023-06-27 17:17:13 -0700135 [](const boost::system::error_code& ec) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400136 if (ec)
137 {
138 BMCWEB_LOG_DEBUG("error_code = {}", ec);
139 BMCWEB_LOG_DEBUG("error msg = {}", ec.message());
140 }
141 });
Andrew Geissler86adcd62019-04-18 10:58:05 -0500142}
Andrew Geissler0554c982019-04-23 14:40:12 -0500143
Jagpal Singh Gillc71b6c92024-04-29 16:50:53 -0700144inline bool handleCreateTask(const boost::system::error_code& ec2,
145 sdbusplus::message_t& msg,
146 const std::shared_ptr<task::TaskData>& taskData)
147{
148 if (ec2)
149 {
150 return task::completed;
151 }
152
153 std::string iface;
154 dbus::utility::DBusPropertiesMap values;
155
156 std::string index = std::to_string(taskData->index);
157 msg.read(iface, values);
158
159 if (iface == "xyz.openbmc_project.Software.Activation")
160 {
161 const std::string* state = nullptr;
162 for (const auto& property : values)
163 {
164 if (property.first == "Activation")
165 {
166 state = std::get_if<std::string>(&property.second);
167 if (state == nullptr)
168 {
169 taskData->messages.emplace_back(messages::internalError());
170 return task::completed;
171 }
172 }
173 }
174
175 if (state == nullptr)
176 {
177 return !task::completed;
178 }
179
180 if (state->ends_with("Invalid") || state->ends_with("Failed"))
181 {
182 taskData->state = "Exception";
183 taskData->status = "Warning";
184 taskData->messages.emplace_back(messages::taskAborted(index));
185 return task::completed;
186 }
187
188 if (state->ends_with("Staged"))
189 {
190 taskData->state = "Stopping";
191 taskData->messages.emplace_back(messages::taskPaused(index));
192
193 // its staged, set a long timer to
194 // allow them time to complete the
195 // update (probably cycle the
196 // system) if this expires then
197 // task will be canceled
198 taskData->extendTimer(std::chrono::hours(5));
199 return !task::completed;
200 }
201
202 if (state->ends_with("Active"))
203 {
204 taskData->messages.emplace_back(messages::taskCompletedOK(index));
205 taskData->state = "Completed";
206 return task::completed;
207 }
208 }
209 else if (iface == "xyz.openbmc_project.Software.ActivationProgress")
210 {
211 const uint8_t* progress = nullptr;
212 for (const auto& property : values)
213 {
214 if (property.first == "Progress")
215 {
216 progress = std::get_if<uint8_t>(&property.second);
217 if (progress == nullptr)
218 {
219 taskData->messages.emplace_back(messages::internalError());
220 return task::completed;
221 }
222 }
223 }
224
225 if (progress == nullptr)
226 {
227 return !task::completed;
228 }
229 taskData->percentComplete = *progress;
230 taskData->messages.emplace_back(
231 messages::taskProgressChanged(index, *progress));
232
233 // if we're getting status updates it's
234 // still alive, update timer
235 taskData->extendTimer(std::chrono::minutes(5));
236 }
237
238 // as firmware update often results in a
239 // reboot, the task may never "complete"
240 // unless it is an error
241
242 return !task::completed;
243}
244
245inline void createTask(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
246 task::Payload&& payload,
247 const sdbusplus::message::object_path& objPath)
248{
249 std::shared_ptr<task::TaskData> task = task::TaskData::createTask(
250 std::bind_front(handleCreateTask),
251 "type='signal',interface='org.freedesktop.DBus.Properties',"
252 "member='PropertiesChanged',path='" +
253 objPath.str + "'");
254 task->startTimer(std::chrono::minutes(5));
255 task->populateResp(asyncResp->res);
256 task->payload.emplace(std::move(payload));
257}
258
Andrew Geissler0554c982019-04-23 14:40:12 -0500259// Note that asyncResp can be either a valid pointer or nullptr. If nullptr
260// then no asyncResp updates will occur
Patrick Williams504af5a2025-02-03 14:29:03 -0500261inline void softwareInterfaceAdded(
262 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
263 sdbusplus::message_t& m, task::Payload&& payload)
Andrew Geissler86adcd62019-04-18 10:58:05 -0500264{
Michael Shen80f79a42023-08-24 13:41:53 +0000265 dbus::utility::DBusInterfacesMap interfacesProperties;
Andrew Geissler86adcd62019-04-18 10:58:05 -0500266
267 sdbusplus::message::object_path objPath;
268
269 m.read(objPath, interfacesProperties);
270
Ed Tanous62598e32023-07-17 17:06:25 -0700271 BMCWEB_LOG_DEBUG("obj path = {}", objPath.str);
Ed Tanouse3eb3d62022-12-21 11:56:07 -0800272 for (const auto& interface : interfacesProperties)
Andrew Geissler86adcd62019-04-18 10:58:05 -0500273 {
Ed Tanous62598e32023-07-17 17:06:25 -0700274 BMCWEB_LOG_DEBUG("interface = {}", interface.first);
Andrew Geissler86adcd62019-04-18 10:58:05 -0500275
276 if (interface.first == "xyz.openbmc_project.Software.Activation")
277 {
Andrew Geissler86adcd62019-04-18 10:58:05 -0500278 // Retrieve service and activate
George Liu2b731192023-01-11 16:27:13 +0800279 constexpr std::array<std::string_view, 1> interfaces = {
280 "xyz.openbmc_project.Software.Activation"};
281 dbus::utility::getDbusObject(
282 objPath.str, interfaces,
Ed Tanousa3e65892021-09-16 14:13:20 -0700283 [objPath, asyncResp, payload(std::move(payload))](
Ed Tanous8b242752023-06-27 17:17:13 -0700284 const boost::system::error_code& ec,
Ed Tanousa3e65892021-09-16 14:13:20 -0700285 const std::vector<
286 std::pair<std::string, std::vector<std::string>>>&
287 objInfo) mutable {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400288 if (ec)
Andrew Geissler0554c982019-04-23 14:40:12 -0500289 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400290 BMCWEB_LOG_DEBUG("error_code = {}", ec);
291 BMCWEB_LOG_DEBUG("error msg = {}", ec.message());
292 if (asyncResp)
293 {
294 messages::internalError(asyncResp->res);
295 }
296 cleanUp();
297 return;
Ed Tanous002d39b2022-05-31 08:59:27 -0700298 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400299 // Ensure we only got one service back
300 if (objInfo.size() != 1)
Ed Tanous002d39b2022-05-31 08:59:27 -0700301 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400302 BMCWEB_LOG_ERROR("Invalid Object Size {}",
303 objInfo.size());
304 if (asyncResp)
305 {
306 messages::internalError(asyncResp->res);
307 }
308 cleanUp();
309 return;
Ed Tanous002d39b2022-05-31 08:59:27 -0700310 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400311 // cancel timer only when
312 // xyz.openbmc_project.Software.Activation interface
313 // is added
314 fwAvailableTimer = nullptr;
Ed Tanous002d39b2022-05-31 08:59:27 -0700315
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400316 activateImage(objPath.str, objInfo[0].first);
317 if (asyncResp)
318 {
319 createTask(asyncResp, std::move(payload), objPath);
320 }
321 fwUpdateInProgress = false;
322 });
Patrick Williams62bafc02022-09-08 17:35:35 -0500323
324 break;
Andrew Geissler86adcd62019-04-18 10:58:05 -0500325 }
326 }
327}
328
Myung Bae8549b952023-08-16 15:18:19 -0400329inline void afterAvailbleTimerAsyncWait(
330 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
331 const boost::system::error_code& ec)
332{
333 cleanUp();
334 if (ec == boost::asio::error::operation_aborted)
335 {
336 // expected, we were canceled before the timer completed.
337 return;
338 }
339 BMCWEB_LOG_ERROR("Timed out waiting for firmware object being created");
340 BMCWEB_LOG_ERROR("FW image may has already been uploaded to server");
341 if (ec)
342 {
343 BMCWEB_LOG_ERROR("Async_wait failed{}", ec);
344 return;
345 }
346 if (asyncResp)
347 {
348 redfish::messages::internalError(asyncResp->res);
349 }
350}
351
Patrick Williams504af5a2025-02-03 14:29:03 -0500352inline void handleUpdateErrorType(
353 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, const std::string& url,
354 const std::string& type)
Myung Bae8549b952023-08-16 15:18:19 -0400355{
Ed Tanousc87294a2024-11-16 22:17:12 -0800356 // NOLINTBEGIN(bugprone-branch-clone)
Myung Bae8549b952023-08-16 15:18:19 -0400357 if (type == "xyz.openbmc_project.Software.Image.Error.UnTarFailure")
358 {
Ed Tanous48fb20b2024-11-17 11:51:13 -0800359 messages::missingOrMalformedPart(asyncResp->res);
Myung Bae8549b952023-08-16 15:18:19 -0400360 }
361 else if (type ==
362 "xyz.openbmc_project.Software.Image.Error.ManifestFileFailure")
363 {
Ed Tanous48fb20b2024-11-17 11:51:13 -0800364 messages::missingOrMalformedPart(asyncResp->res);
Myung Bae8549b952023-08-16 15:18:19 -0400365 }
366 else if (type == "xyz.openbmc_project.Software.Image.Error.ImageFailure")
367 {
Ed Tanous48fb20b2024-11-17 11:51:13 -0800368 messages::missingOrMalformedPart(asyncResp->res);
Myung Bae8549b952023-08-16 15:18:19 -0400369 }
370 else if (type == "xyz.openbmc_project.Software.Version.Error.AlreadyExists")
371 {
Ed Tanousc87294a2024-11-16 22:17:12 -0800372 messages::resourceAlreadyExists(asyncResp->res, "UpdateService",
373 "Version", "uploaded version");
Myung Bae8549b952023-08-16 15:18:19 -0400374 }
375 else if (type == "xyz.openbmc_project.Software.Image.Error.BusyFailure")
376 {
Ed Tanous48fb20b2024-11-17 11:51:13 -0800377 messages::serviceTemporarilyUnavailable(asyncResp->res, url);
Myung Bae8549b952023-08-16 15:18:19 -0400378 }
Myung Bae4034a652023-08-17 08:47:35 -0400379 else if (type == "xyz.openbmc_project.Software.Version.Error.Incompatible")
Myung Bae8549b952023-08-16 15:18:19 -0400380 {
Ed Tanousc87294a2024-11-16 22:17:12 -0800381 messages::internalError(asyncResp->res);
Myung Bae4034a652023-08-17 08:47:35 -0400382 }
383 else if (type ==
384 "xyz.openbmc_project.Software.Version.Error.ExpiredAccessKey")
385 {
Ed Tanousc87294a2024-11-16 22:17:12 -0800386 messages::internalError(asyncResp->res);
Myung Bae4034a652023-08-17 08:47:35 -0400387 }
388 else if (type ==
389 "xyz.openbmc_project.Software.Version.Error.InvalidSignature")
390 {
Ed Tanous48fb20b2024-11-17 11:51:13 -0800391 messages::missingOrMalformedPart(asyncResp->res);
Myung Bae4034a652023-08-17 08:47:35 -0400392 }
393 else if (type ==
394 "xyz.openbmc_project.Software.Image.Error.InternalFailure" ||
395 type == "xyz.openbmc_project.Software.Version.Error.HostFile")
396 {
397 BMCWEB_LOG_ERROR("Software Image Error type={}", type);
Ed Tanous48fb20b2024-11-17 11:51:13 -0800398 messages::internalError(asyncResp->res);
Myung Bae8549b952023-08-16 15:18:19 -0400399 }
Myung Bae4034a652023-08-17 08:47:35 -0400400 else
401 {
402 // Unrelated error types. Ignored
403 BMCWEB_LOG_INFO("Non-Software-related Error type={}. Ignored", type);
404 return;
405 }
Ed Tanousc87294a2024-11-16 22:17:12 -0800406 // NOLINTEND(bugprone-branch-clone)
Myung Bae4034a652023-08-17 08:47:35 -0400407 // Clear the timer
408 fwAvailableTimer = nullptr;
Myung Bae8549b952023-08-16 15:18:19 -0400409}
410
Patrick Williams504af5a2025-02-03 14:29:03 -0500411inline void afterUpdateErrorMatcher(
412 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, const std::string& url,
413 sdbusplus::message_t& m)
Myung Bae8549b952023-08-16 15:18:19 -0400414{
Michael Shen80f79a42023-08-24 13:41:53 +0000415 dbus::utility::DBusInterfacesMap interfacesProperties;
Myung Bae8549b952023-08-16 15:18:19 -0400416 sdbusplus::message::object_path objPath;
417 m.read(objPath, interfacesProperties);
418 BMCWEB_LOG_DEBUG("obj path = {}", objPath.str);
419 for (const std::pair<std::string, dbus::utility::DBusPropertiesMap>&
420 interface : interfacesProperties)
421 {
422 if (interface.first == "xyz.openbmc_project.Logging.Entry")
423 {
424 for (const std::pair<std::string, dbus::utility::DbusVariantType>&
425 value : interface.second)
426 {
427 if (value.first != "Message")
428 {
429 continue;
430 }
431 const std::string* type =
432 std::get_if<std::string>(&value.second);
433 if (type == nullptr)
434 {
435 // if this was our message, timeout will cover it
436 return;
437 }
Myung Bae8549b952023-08-16 15:18:19 -0400438 handleUpdateErrorType(asyncResp, url, *type);
439 }
440 }
441 }
442}
443
Andrew Geissler0554c982019-04-23 14:40:12 -0500444// Note that asyncResp can be either a valid pointer or nullptr. If nullptr
445// then no asyncResp updates will occur
Ed Tanousf5139332024-04-03 13:25:04 -0700446inline void monitorForSoftwareAvailable(
zhanghch058d1b46d2021-04-01 11:18:24 +0800447 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
448 const crow::Request& req, const std::string& url,
Gunnar Mills5d138942022-09-07 10:26:21 -0500449 int timeoutTimeSeconds = 25)
Andrew Geissler86adcd62019-04-18 10:58:05 -0500450{
451 // Only allow one FW update at a time
Ed Tanouse05aec52022-01-25 10:28:56 -0800452 if (fwUpdateInProgress)
Andrew Geissler86adcd62019-04-18 10:58:05 -0500453 {
Andrew Geissler0554c982019-04-23 14:40:12 -0500454 if (asyncResp)
455 {
Andrew Geissler0554c982019-04-23 14:40:12 -0500456 messages::serviceTemporarilyUnavailable(asyncResp->res, "30");
457 }
Andrew Geissler86adcd62019-04-18 10:58:05 -0500458 return;
459 }
460
Ed Tanous8e8245d2024-04-11 22:21:38 -0700461 if (req.ioService == nullptr)
462 {
463 messages::internalError(asyncResp->res);
464 return;
465 }
466
Andrew Geissler0554c982019-04-23 14:40:12 -0500467 fwAvailableTimer =
Ed Tanous271584a2019-07-09 16:24:22 -0700468 std::make_unique<boost::asio::steady_timer>(*req.ioService);
Andrew Geissler86adcd62019-04-18 10:58:05 -0500469
Ed Tanous271584a2019-07-09 16:24:22 -0700470 fwAvailableTimer->expires_after(std::chrono::seconds(timeoutTimeSeconds));
Andrew Geissler86adcd62019-04-18 10:58:05 -0500471
472 fwAvailableTimer->async_wait(
Myung Bae8549b952023-08-16 15:18:19 -0400473 std::bind_front(afterAvailbleTimerAsyncWait, asyncResp));
474
Ed Tanousa3e65892021-09-16 14:13:20 -0700475 task::Payload payload(req);
Patrick Williams59d494e2022-07-22 19:26:55 -0500476 auto callback = [asyncResp, payload](sdbusplus::message_t& m) mutable {
Ed Tanous62598e32023-07-17 17:06:25 -0700477 BMCWEB_LOG_DEBUG("Match fired");
Ed Tanousa3e65892021-09-16 14:13:20 -0700478 softwareInterfaceAdded(asyncResp, m, std::move(payload));
Andrew Geissler86adcd62019-04-18 10:58:05 -0500479 };
480
481 fwUpdateInProgress = true;
482
Patrick Williams59d494e2022-07-22 19:26:55 -0500483 fwUpdateMatcher = std::make_unique<sdbusplus::bus::match_t>(
Andrew Geissler86adcd62019-04-18 10:58:05 -0500484 *crow::connections::systemBus,
485 "interface='org.freedesktop.DBus.ObjectManager',type='signal',"
486 "member='InterfacesAdded',path='/xyz/openbmc_project/software'",
487 callback);
James Feist4cde5d92020-06-11 10:39:55 -0700488
Patrick Williams59d494e2022-07-22 19:26:55 -0500489 fwUpdateErrorMatcher = std::make_unique<sdbusplus::bus::match_t>(
James Feist4cde5d92020-06-11 10:39:55 -0700490 *crow::connections::systemBus,
Brian Mae1cc4822021-12-01 17:05:54 +0800491 "interface='org.freedesktop.DBus.ObjectManager',type='signal',"
492 "member='InterfacesAdded',"
493 "path='/xyz/openbmc_project/logging'",
Myung Bae8549b952023-08-16 15:18:19 -0400494 std::bind_front(afterUpdateErrorMatcher, asyncResp, url));
Andrew Geissler86adcd62019-04-18 10:58:05 -0500495}
Jennifer Lee729dae72018-04-24 15:59:34 -0700496
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400497inline std::optional<boost::urls::url> parseSimpleUpdateUrl(
498 std::string imageURI, std::optional<std::string> transferProtocol,
499 crow::Response& res)
Ed Tanousf86bcc82023-08-25 09:34:07 -0700500{
501 if (imageURI.find("://") == std::string::npos)
502 {
503 if (imageURI.starts_with("/"))
504 {
505 messages::actionParameterValueTypeError(
506 res, imageURI, "ImageURI", "UpdateService.SimpleUpdate");
507 return std::nullopt;
508 }
509 if (!transferProtocol)
510 {
511 messages::actionParameterValueTypeError(
512 res, imageURI, "ImageURI", "UpdateService.SimpleUpdate");
513 return std::nullopt;
514 }
Ed Tanous6a371402024-12-03 14:01:25 -0800515 // OpenBMC currently only supports HTTPS
516 if (*transferProtocol == "HTTPS")
Ed Tanouse5cf7772024-04-03 13:45:31 -0700517 {
518 imageURI = "https://" + imageURI;
519 }
Ed Tanous757178a2024-04-03 14:32:38 -0700520 else
Ed Tanousf86bcc82023-08-25 09:34:07 -0700521 {
522 messages::actionParameterNotSupported(res, "TransferProtocol",
523 *transferProtocol);
524 BMCWEB_LOG_ERROR("Request incorrect protocol parameter: {}",
525 *transferProtocol);
526 return std::nullopt;
527 }
Ed Tanousf86bcc82023-08-25 09:34:07 -0700528 }
529
530 boost::system::result<boost::urls::url> url =
531 boost::urls::parse_absolute_uri(imageURI);
532 if (!url)
533 {
534 messages::actionParameterValueTypeError(res, imageURI, "ImageURI",
535 "UpdateService.SimpleUpdate");
536
537 return std::nullopt;
538 }
539 url->normalize();
540
Ed Tanous757178a2024-04-03 14:32:38 -0700541 if (url->scheme() == "tftp")
542 {
543 if (url->encoded_path().size() < 2)
544 {
545 messages::actionParameterNotSupported(res, "ImageURI",
546 url->buffer());
547 return std::nullopt;
548 }
549 }
Ed Tanouse5cf7772024-04-03 13:45:31 -0700550 else if (url->scheme() == "https")
551 {
552 // Empty paths default to "/"
553 if (url->encoded_path().empty())
554 {
555 url->set_encoded_path("/");
556 }
557 }
Ed Tanous757178a2024-04-03 14:32:38 -0700558 else
Ed Tanousf86bcc82023-08-25 09:34:07 -0700559 {
560 messages::actionParameterNotSupported(res, "ImageURI", imageURI);
561 return std::nullopt;
562 }
Ed Tanous757178a2024-04-03 14:32:38 -0700563
564 if (url->encoded_path().empty())
Ed Tanousf86bcc82023-08-25 09:34:07 -0700565 {
Ed Tanous757178a2024-04-03 14:32:38 -0700566 messages::actionParameterValueTypeError(res, imageURI, "ImageURI",
567 "UpdateService.SimpleUpdate");
Ed Tanousf86bcc82023-08-25 09:34:07 -0700568 return std::nullopt;
569 }
Ed Tanous757178a2024-04-03 14:32:38 -0700570
571 return *url;
Ed Tanousf86bcc82023-08-25 09:34:07 -0700572}
573
Ed Tanouse5cf7772024-04-03 13:45:31 -0700574inline void doHttpsUpdate(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
575 const boost::urls::url_view_base& url)
576{
577 messages::actionParameterNotSupported(asyncResp->res, "ImageURI",
578 url.buffer());
579}
580
Ed Tanousf5139332024-04-03 13:25:04 -0700581inline void handleUpdateServiceSimpleUpdateAction(
582 crow::App& app, const crow::Request& req,
583 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
Andrew Geissler0554c982019-04-23 14:40:12 -0500584{
Ed Tanousf5139332024-04-03 13:25:04 -0700585 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
586 {
587 return;
588 }
589
590 std::optional<std::string> transferProtocol;
591 std::string imageURI;
592
593 BMCWEB_LOG_DEBUG("Enter UpdateService.SimpleUpdate doPost");
594
595 // User can pass in both TransferProtocol and ImageURI parameters or
596 // they can pass in just the ImageURI with the transfer protocol
597 // embedded within it.
598 // 1) TransferProtocol:TFTP ImageURI:1.1.1.1/myfile.bin
599 // 2) ImageURI:tftp://1.1.1.1/myfile.bin
600
Patrick Williams504af5a2025-02-03 14:29:03 -0500601 if (!json_util::readJsonAction( //
602 req, asyncResp->res, //
603 "ImageURI", imageURI, //
Myung Baeafc474a2024-10-09 00:53:29 -0700604 "TransferProtocol", transferProtocol //
605 ))
Ed Tanousf5139332024-04-03 13:25:04 -0700606 {
607 BMCWEB_LOG_DEBUG("Missing TransferProtocol or ImageURI parameter");
608 return;
609 }
610
Ed Tanous757178a2024-04-03 14:32:38 -0700611 std::optional<boost::urls::url> url =
612 parseSimpleUpdateUrl(imageURI, transferProtocol, asyncResp->res);
613 if (!url)
Ed Tanousf5139332024-04-03 13:25:04 -0700614 {
615 return;
616 }
Jagpal Singh Gill4e338b22024-06-14 14:24:56 -0700617 if (url->scheme() == "https")
Ed Tanouse5cf7772024-04-03 13:45:31 -0700618 {
619 doHttpsUpdate(asyncResp, *url);
620 }
Ed Tanous757178a2024-04-03 14:32:38 -0700621 else
622 {
623 messages::actionParameterNotSupported(asyncResp->res, "ImageURI",
624 url->buffer());
625 return;
626 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700627
Ed Tanousf5139332024-04-03 13:25:04 -0700628 BMCWEB_LOG_DEBUG("Exit UpdateService.SimpleUpdate doPost");
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700629}
630
George Liu0ed80c82020-05-12 16:06:27 +0800631inline void uploadImageFile(crow::Response& res, std::string_view body)
632{
Ed Tanous2c6ffdb2023-06-28 11:28:38 -0700633 std::filesystem::path filepath("/tmp/images/" + bmcweb::getRandomUUID());
634
Ed Tanous62598e32023-07-17 17:06:25 -0700635 BMCWEB_LOG_DEBUG("Writing file to {}", filepath.string());
George Liu0ed80c82020-05-12 16:06:27 +0800636 std::ofstream out(filepath, std::ofstream::out | std::ofstream::binary |
637 std::ofstream::trunc);
638 // set the permission of the file to 640
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400639 std::filesystem::perms permission =
640 std::filesystem::perms::owner_read | std::filesystem::perms::group_read;
George Liu0ed80c82020-05-12 16:06:27 +0800641 std::filesystem::permissions(filepath, permission);
642 out << body;
643
644 if (out.bad())
645 {
646 messages::internalError(res);
647 cleanUp();
648 }
649}
650
Jagpal Singh Gillde0c9602024-04-29 17:30:21 -0700651// Convert the Request Apply Time to the D-Bus value
652inline bool convertApplyTime(crow::Response& res, const std::string& applyTime,
653 std::string& applyTimeNewVal)
654{
655 if (applyTime == "Immediate")
656 {
657 applyTimeNewVal =
Jagpal Singh Gill049079f2024-06-02 18:11:13 -0700658 "xyz.openbmc_project.Software.ApplyTime.RequestedApplyTimes.Immediate";
Jagpal Singh Gillde0c9602024-04-29 17:30:21 -0700659 }
660 else if (applyTime == "OnReset")
661 {
662 applyTimeNewVal =
Jagpal Singh Gill049079f2024-06-02 18:11:13 -0700663 "xyz.openbmc_project.Software.ApplyTime.RequestedApplyTimes.OnReset";
Jagpal Singh Gillde0c9602024-04-29 17:30:21 -0700664 }
665 else
666 {
667 BMCWEB_LOG_WARNING(
668 "ApplyTime value {} is not in the list of acceptable values",
669 applyTime);
670 messages::propertyValueNotInList(res, applyTime, "ApplyTime");
671 return false;
672 }
673 return true;
674}
675
George Liu0ed80c82020-05-12 16:06:27 +0800676inline void setApplyTime(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
677 const std::string& applyTime)
678{
679 std::string applyTimeNewVal;
Jagpal Singh Gill049079f2024-06-02 18:11:13 -0700680 if (!convertApplyTime(asyncResp->res, applyTime, applyTimeNewVal))
George Liu0ed80c82020-05-12 16:06:27 +0800681 {
George Liu0ed80c82020-05-12 16:06:27 +0800682 return;
683 }
684
Ginu Georgee93abac2024-06-14 17:35:27 +0530685 setDbusProperty(asyncResp, "ApplyTime", "xyz.openbmc_project.Settings",
Ed Tanousd02aad32024-02-13 14:43:34 -0800686 sdbusplus::message::object_path(
687 "/xyz/openbmc_project/software/apply_time"),
688 "xyz.openbmc_project.Software.ApplyTime",
Ginu Georgee93abac2024-06-14 17:35:27 +0530689 "RequestedApplyTime", applyTimeNewVal);
George Liu0ed80c82020-05-12 16:06:27 +0800690}
691
Jagpal Singh Gillef93eab2024-04-17 16:06:14 -0700692struct MultiPartUpdateParameters
George Liu0ed80c82020-05-12 16:06:27 +0800693{
Jagpal Singh Gillef93eab2024-04-17 16:06:14 -0700694 std::optional<std::string> applyTime;
695 std::string uploadData;
Jagpal Singh Gillde0c9602024-04-29 17:30:21 -0700696 std::vector<std::string> targets;
Jagpal Singh Gillef93eab2024-04-17 16:06:14 -0700697};
698
Patrick Williams504af5a2025-02-03 14:29:03 -0500699inline std::optional<std::string> processUrl(
700 boost::system::result<boost::urls::url_view>& url)
Jagpal Singh Gillde0c9602024-04-29 17:30:21 -0700701{
702 if (!url)
703 {
704 return std::nullopt;
705 }
706 if (crow::utility::readUrlSegments(*url, "redfish", "v1", "Managers",
707 BMCWEB_REDFISH_MANAGER_URI_NAME))
708 {
709 return std::make_optional(std::string(BMCWEB_REDFISH_MANAGER_URI_NAME));
710 }
711 if constexpr (!BMCWEB_REDFISH_UPDATESERVICE_USE_DBUS)
712 {
713 return std::nullopt;
714 }
715 std::string firmwareId;
716 if (!crow::utility::readUrlSegments(*url, "redfish", "v1", "UpdateService",
717 "FirmwareInventory",
718 std::ref(firmwareId)))
719 {
720 return std::nullopt;
721 }
722
723 return std::make_optional(firmwareId);
724}
725
Jagpal Singh Gillef93eab2024-04-17 16:06:14 -0700726inline std::optional<MultiPartUpdateParameters>
727 extractMultipartUpdateParameters(
728 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
729 MultipartParser parser)
730{
731 MultiPartUpdateParameters multiRet;
732 for (FormPart& formpart : parser.mime_fields)
George Liu0ed80c82020-05-12 16:06:27 +0800733 {
734 boost::beast::http::fields::const_iterator it =
735 formpart.fields.find("Content-Disposition");
736 if (it == formpart.fields.end())
737 {
Ed Tanous62598e32023-07-17 17:06:25 -0700738 BMCWEB_LOG_ERROR("Couldn't find Content-Disposition");
Jagpal Singh Gillef93eab2024-04-17 16:06:14 -0700739 return std::nullopt;
George Liu0ed80c82020-05-12 16:06:27 +0800740 }
Ed Tanous62598e32023-07-17 17:06:25 -0700741 BMCWEB_LOG_INFO("Parsing value {}", it->value());
George Liu0ed80c82020-05-12 16:06:27 +0800742
743 // The construction parameters of param_list must start with `;`
744 size_t index = it->value().find(';');
745 if (index == std::string::npos)
746 {
747 continue;
748 }
749
Patrick Williams89492a12023-05-10 07:51:34 -0500750 for (const auto& param :
George Liu0ed80c82020-05-12 16:06:27 +0800751 boost::beast::http::param_list{it->value().substr(index)})
752 {
753 if (param.first != "name" || param.second.empty())
754 {
755 continue;
756 }
757
758 if (param.second == "UpdateParameters")
759 {
Jagpal Singh Gillef93eab2024-04-17 16:06:14 -0700760 std::vector<std::string> tempTargets;
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400761 nlohmann::json content =
762 nlohmann::json::parse(formpart.content, nullptr, false);
Ed Tanousac1e1242024-07-10 22:10:14 -0700763 if (content.is_discarded())
764 {
765 return std::nullopt;
766 }
Ed Tanous7cb59f62022-05-05 11:48:31 -0700767 nlohmann::json::object_t* obj =
768 content.get_ptr<nlohmann::json::object_t*>();
769 if (obj == nullptr)
770 {
Jagpal Singh Gillef93eab2024-04-17 16:06:14 -0700771 messages::propertyValueTypeError(
772 asyncResp->res, formpart.content, "UpdateParameters");
773 return std::nullopt;
Ed Tanous7cb59f62022-05-05 11:48:31 -0700774 }
775
Patrick Williams504af5a2025-02-03 14:29:03 -0500776 if (!json_util::readJsonObject( //
777 *obj, asyncResp->res, //
Myung Baeafc474a2024-10-09 00:53:29 -0700778 "@Redfish.OperationApplyTime", multiRet.applyTime, //
Patrick Williams504af5a2025-02-03 14:29:03 -0500779 "Targets", tempTargets //
Myung Baeafc474a2024-10-09 00:53:29 -0700780 ))
George Liu0ed80c82020-05-12 16:06:27 +0800781 {
Jagpal Singh Gillef93eab2024-04-17 16:06:14 -0700782 return std::nullopt;
George Liu0ed80c82020-05-12 16:06:27 +0800783 }
Jagpal Singh Gillef93eab2024-04-17 16:06:14 -0700784
785 for (size_t urlIndex = 0; urlIndex < tempTargets.size();
786 urlIndex++)
George Liu0ed80c82020-05-12 16:06:27 +0800787 {
Jagpal Singh Gillef93eab2024-04-17 16:06:14 -0700788 const std::string& target = tempTargets[urlIndex];
789 boost::system::result<boost::urls::url_view> url =
790 boost::urls::parse_origin_form(target);
Jagpal Singh Gillde0c9602024-04-29 17:30:21 -0700791 auto res = processUrl(url);
792 if (!res.has_value())
Jagpal Singh Gillef93eab2024-04-17 16:06:14 -0700793 {
794 messages::propertyValueFormatError(
795 asyncResp->res, target,
796 std::format("Targets/{}", urlIndex));
797 return std::nullopt;
798 }
Jagpal Singh Gillde0c9602024-04-29 17:30:21 -0700799 multiRet.targets.emplace_back(res.value());
George Liu0ed80c82020-05-12 16:06:27 +0800800 }
Jagpal Singh Gillef93eab2024-04-17 16:06:14 -0700801 if (multiRet.targets.size() != 1)
George Liu0ed80c82020-05-12 16:06:27 +0800802 {
Jagpal Singh Gillef93eab2024-04-17 16:06:14 -0700803 messages::propertyValueFormatError(
804 asyncResp->res, multiRet.targets, "Targets");
805 return std::nullopt;
George Liu0ed80c82020-05-12 16:06:27 +0800806 }
George Liu0ed80c82020-05-12 16:06:27 +0800807 }
808 else if (param.second == "UpdateFile")
809 {
Jagpal Singh Gillef93eab2024-04-17 16:06:14 -0700810 multiRet.uploadData = std::move(formpart.content);
George Liu0ed80c82020-05-12 16:06:27 +0800811 }
812 }
813 }
814
Jagpal Singh Gillef93eab2024-04-17 16:06:14 -0700815 if (multiRet.uploadData.empty())
George Liu0ed80c82020-05-12 16:06:27 +0800816 {
Ed Tanous62598e32023-07-17 17:06:25 -0700817 BMCWEB_LOG_ERROR("Upload data is NULL");
George Liu0ed80c82020-05-12 16:06:27 +0800818 messages::propertyMissing(asyncResp->res, "UpdateFile");
Jagpal Singh Gillef93eab2024-04-17 16:06:14 -0700819 return std::nullopt;
820 }
821 if (multiRet.targets.empty())
822 {
823 messages::propertyMissing(asyncResp->res, "Targets");
824 return std::nullopt;
825 }
826 return multiRet;
827}
828
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400829inline void handleStartUpdate(
830 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, task::Payload payload,
831 const std::string& objectPath, const boost::system::error_code& ec,
832 const sdbusplus::message::object_path& retPath)
Jagpal Singh Gillde0c9602024-04-29 17:30:21 -0700833{
834 if (ec)
835 {
836 BMCWEB_LOG_ERROR("error_code = {}", ec);
837 BMCWEB_LOG_ERROR("error msg = {}", ec.message());
838 messages::internalError(asyncResp->res);
839 return;
840 }
841
Jagpal Singh Gill587090c2024-08-12 00:24:16 -0700842 BMCWEB_LOG_INFO("Call to StartUpdate on {} Success, retPath = {}",
843 objectPath, retPath.str);
844 createTask(asyncResp, std::move(payload), retPath);
Jagpal Singh Gillde0c9602024-04-29 17:30:21 -0700845}
846
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400847inline void startUpdate(
848 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, task::Payload payload,
849 const MemoryFileDescriptor& memfd, const std::string& applyTime,
850 const std::string& objectPath, const std::string& serviceName)
Jagpal Singh Gillde0c9602024-04-29 17:30:21 -0700851{
852 crow::connections::systemBus->async_method_call(
853 [asyncResp, payload = std::move(payload),
854 objectPath](const boost::system::error_code& ec1,
855 const sdbusplus::message::object_path& retPath) mutable {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400856 handleStartUpdate(asyncResp, std::move(payload), objectPath, ec1,
857 retPath);
858 },
Jagpal Singh Gillde0c9602024-04-29 17:30:21 -0700859 serviceName, objectPath, "xyz.openbmc_project.Software.Update",
860 "StartUpdate", sdbusplus::message::unix_fd(memfd.fd), applyTime);
861}
862
Jagpal Singh Gill08f61d52024-07-17 15:17:22 -0700863inline void getSwInfo(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
864 task::Payload payload, const MemoryFileDescriptor& memfd,
865 const std::string& applyTime, const std::string& target,
866 const boost::system::error_code& ec,
867 const dbus::utility::MapperGetSubTreeResponse& subtree)
Jagpal Singh Gillde0c9602024-04-29 17:30:21 -0700868{
Jagpal Singh Gill08f61d52024-07-17 15:17:22 -0700869 using SwInfoMap = std::unordered_map<
870 std::string, std::pair<sdbusplus::message::object_path, std::string>>;
Jagpal Singh Gillde0c9602024-04-29 17:30:21 -0700871 SwInfoMap swInfoMap;
872
873 if (ec)
874 {
875 BMCWEB_LOG_ERROR("error_code = {}", ec);
876 BMCWEB_LOG_ERROR("error msg = {}", ec.message());
877 messages::internalError(asyncResp->res);
878 return;
879 }
880 BMCWEB_LOG_DEBUG("Found {} software version paths", subtree.size());
881
Jagpal Singh Gill08f61d52024-07-17 15:17:22 -0700882 for (const auto& entry : subtree)
Jagpal Singh Gillde0c9602024-04-29 17:30:21 -0700883 {
Jagpal Singh Gill08f61d52024-07-17 15:17:22 -0700884 sdbusplus::message::object_path path(entry.first);
Jagpal Singh Gillde0c9602024-04-29 17:30:21 -0700885 std::string swId = path.filename();
Jagpal Singh Gill08f61d52024-07-17 15:17:22 -0700886 swInfoMap.emplace(swId, make_pair(path, entry.second[0].first));
Jagpal Singh Gillde0c9602024-04-29 17:30:21 -0700887 }
888
889 auto swEntry = swInfoMap.find(target);
890 if (swEntry == swInfoMap.end())
891 {
892 BMCWEB_LOG_WARNING("No valid DBus path for Target URI {}", target);
893 messages::propertyValueFormatError(asyncResp->res, target, "Targets");
894 return;
895 }
896
Jagpal Singh Gill08f61d52024-07-17 15:17:22 -0700897 BMCWEB_LOG_DEBUG("Found software version path {} serviceName {}",
898 swEntry->second.first.str, swEntry->second.second);
Jagpal Singh Gillde0c9602024-04-29 17:30:21 -0700899
Jagpal Singh Gill08f61d52024-07-17 15:17:22 -0700900 startUpdate(asyncResp, std::move(payload), memfd, applyTime,
901 swEntry->second.first.str, swEntry->second.second);
902}
903
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400904inline void handleBMCUpdate(
905 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, task::Payload payload,
906 const MemoryFileDescriptor& memfd, const std::string& applyTime,
907 const boost::system::error_code& ec,
908 const dbus::utility::MapperEndPoints& functionalSoftware)
Jagpal Singh Gill08f61d52024-07-17 15:17:22 -0700909{
910 if (ec)
911 {
912 BMCWEB_LOG_ERROR("error_code = {}", ec);
913 BMCWEB_LOG_ERROR("error msg = {}", ec.message());
914 messages::internalError(asyncResp->res);
915 return;
916 }
917 if (functionalSoftware.size() != 1)
918 {
919 BMCWEB_LOG_ERROR("Found {} functional software endpoints",
920 functionalSoftware.size());
921 messages::internalError(asyncResp->res);
922 return;
923 }
924
925 startUpdate(asyncResp, std::move(payload), memfd, applyTime,
926 functionalSoftware[0], "xyz.openbmc_project.Software.Manager");
Jagpal Singh Gillde0c9602024-04-29 17:30:21 -0700927}
928
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400929inline void processUpdateRequest(
930 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
931 task::Payload&& payload, std::string_view body,
932 const std::string& applyTime, std::vector<std::string>& targets)
Jagpal Singh Gillde0c9602024-04-29 17:30:21 -0700933{
Jagpal Singh Gillde0c9602024-04-29 17:30:21 -0700934 MemoryFileDescriptor memfd("update-image");
935 if (memfd.fd == -1)
936 {
937 BMCWEB_LOG_ERROR("Failed to create image memfd");
938 messages::internalError(asyncResp->res);
939 return;
940 }
941 if (write(memfd.fd, body.data(), body.length()) !=
942 static_cast<ssize_t>(body.length()))
943 {
944 BMCWEB_LOG_ERROR("Failed to write to image memfd");
945 messages::internalError(asyncResp->res);
946 return;
947 }
948 if (!memfd.rewind())
949 {
950 messages::internalError(asyncResp->res);
951 return;
952 }
953
Jagpal Singh Gillde0c9602024-04-29 17:30:21 -0700954 if (!targets.empty() && targets[0] == BMCWEB_REDFISH_MANAGER_URI_NAME)
955 {
Jagpal Singh Gill08f61d52024-07-17 15:17:22 -0700956 dbus::utility::getAssociationEndPoints(
Jagpal Singh Gill89449bb2024-08-12 16:17:58 -0700957 "/xyz/openbmc_project/software/bmc/updateable",
Jagpal Singh Gill08f61d52024-07-17 15:17:22 -0700958 [asyncResp, payload = std::move(payload), memfd = std::move(memfd),
959 applyTime](
960 const boost::system::error_code& ec,
961 const dbus::utility::MapperEndPoints& objectPaths) mutable {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400962 handleBMCUpdate(asyncResp, std::move(payload), memfd, applyTime,
963 ec, objectPaths);
964 });
Jagpal Singh Gillde0c9602024-04-29 17:30:21 -0700965 }
966 else
967 {
968 constexpr std::array<std::string_view, 1> interfaces = {
969 "xyz.openbmc_project.Software.Version"};
Jagpal Singh Gill08f61d52024-07-17 15:17:22 -0700970 dbus::utility::getSubTree(
Jagpal Singh Gillde0c9602024-04-29 17:30:21 -0700971 "/xyz/openbmc_project/software", 1, interfaces,
972 [asyncResp, payload = std::move(payload), memfd = std::move(memfd),
Jagpal Singh Gill08f61d52024-07-17 15:17:22 -0700973 applyTime, targets](const boost::system::error_code& ec,
974 const dbus::utility::MapperGetSubTreeResponse&
975 subtree) mutable {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400976 getSwInfo(asyncResp, std::move(payload), memfd, applyTime,
977 targets[0], ec, subtree);
978 });
Jagpal Singh Gillde0c9602024-04-29 17:30:21 -0700979 }
980}
981
Patrick Williams504af5a2025-02-03 14:29:03 -0500982inline void updateMultipartContext(
983 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
984 const crow::Request& req, MultipartParser&& parser)
Jagpal Singh Gillef93eab2024-04-17 16:06:14 -0700985{
986 std::optional<MultiPartUpdateParameters> multipart =
987 extractMultipartUpdateParameters(asyncResp, std::move(parser));
988 if (!multipart)
989 {
George Liu0ed80c82020-05-12 16:06:27 +0800990 return;
991 }
Jagpal Singh Gillef93eab2024-04-17 16:06:14 -0700992 if (!multipart->applyTime)
George Liu0ed80c82020-05-12 16:06:27 +0800993 {
Jagpal Singh Gillef93eab2024-04-17 16:06:14 -0700994 multipart->applyTime = "OnReset";
George Liu0ed80c82020-05-12 16:06:27 +0800995 }
996
Jagpal Singh Gillde0c9602024-04-29 17:30:21 -0700997 if constexpr (BMCWEB_REDFISH_UPDATESERVICE_USE_DBUS)
998 {
Jagpal Singh Gill9dae4de2024-06-02 23:43:56 -0700999 std::string applyTimeNewVal;
1000 if (!convertApplyTime(asyncResp->res, *multipart->applyTime,
1001 applyTimeNewVal))
1002 {
1003 return;
1004 }
1005 task::Payload payload(req);
1006
1007 processUpdateRequest(asyncResp, std::move(payload),
1008 multipart->uploadData, applyTimeNewVal,
1009 multipart->targets);
Jagpal Singh Gillde0c9602024-04-29 17:30:21 -07001010 }
1011 else
1012 {
1013 setApplyTime(asyncResp, *multipart->applyTime);
George Liu0ed80c82020-05-12 16:06:27 +08001014
Jagpal Singh Gillde0c9602024-04-29 17:30:21 -07001015 // Setup callback for when new software detected
1016 monitorForSoftwareAvailable(asyncResp, req,
1017 "/redfish/v1/UpdateService");
Ed Tanous6b54e4e2024-04-10 08:58:48 -07001018
Jagpal Singh Gillde0c9602024-04-29 17:30:21 -07001019 uploadImageFile(asyncResp->res, multipart->uploadData);
1020 }
George Liu0ed80c82020-05-12 16:06:27 +08001021}
1022
Jagpal Singh Gill9dae4de2024-06-02 23:43:56 -07001023inline void doHTTPUpdate(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1024 const crow::Request& req)
1025{
1026 if constexpr (BMCWEB_REDFISH_UPDATESERVICE_USE_DBUS)
1027 {
1028 task::Payload payload(req);
1029 // HTTP push only supports BMC updates (with ApplyTime as immediate) for
1030 // backwards compatibility. Specific component updates will be handled
1031 // through Multipart form HTTP push.
1032 std::vector<std::string> targets;
1033 targets.emplace_back(BMCWEB_REDFISH_MANAGER_URI_NAME);
1034
1035 processUpdateRequest(
1036 asyncResp, std::move(payload), req.body(),
1037 "xyz.openbmc_project.Software.ApplyTime.RequestedApplyTimes.Immediate",
1038 targets);
1039 }
1040 else
1041 {
1042 // Setup callback for when new software detected
1043 monitorForSoftwareAvailable(asyncResp, req,
1044 "/redfish/v1/UpdateService");
1045
1046 uploadImageFile(asyncResp->res, req.body());
1047 }
1048}
1049
Patrick Williams504af5a2025-02-03 14:29:03 -05001050inline void handleUpdateServicePost(
1051 App& app, const crow::Request& req,
1052 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
Ed Tanousc2051d12022-05-11 12:21:55 -07001053{
Carson Labrado3ba00072022-06-06 19:40:56 +00001054 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanousc2051d12022-05-11 12:21:55 -07001055 {
1056 return;
1057 }
Ninad Palsuleb33a4322023-06-09 09:19:18 -05001058 std::string_view contentType = req.getHeaderValue("Content-Type");
Ed Tanousc2051d12022-05-11 12:21:55 -07001059
Ed Tanous62598e32023-07-17 17:06:25 -07001060 BMCWEB_LOG_DEBUG("doPost: contentType={}", contentType);
Ed Tanousc2051d12022-05-11 12:21:55 -07001061
Ninad Palsuleb33a4322023-06-09 09:19:18 -05001062 // Make sure that content type is application/octet-stream or
1063 // multipart/form-data
Ed Tanous18f8f602023-07-18 10:07:23 -07001064 if (bmcweb::asciiIEquals(contentType, "application/octet-stream"))
George Liu0ed80c82020-05-12 16:06:27 +08001065 {
Jagpal Singh Gill9dae4de2024-06-02 23:43:56 -07001066 doHTTPUpdate(asyncResp, req);
George Liu0ed80c82020-05-12 16:06:27 +08001067 }
Ninad Palsuleb33a4322023-06-09 09:19:18 -05001068 else if (contentType.starts_with("multipart/form-data"))
George Liu0ed80c82020-05-12 16:06:27 +08001069 {
Ninad Palsuleb33a4322023-06-09 09:19:18 -05001070 MultipartParser parser;
1071
Ninad Palsuleb33a4322023-06-09 09:19:18 -05001072 ParserError ec = parser.parse(req);
1073 if (ec != ParserError::PARSER_SUCCESS)
1074 {
1075 // handle error
Ed Tanous62598e32023-07-17 17:06:25 -07001076 BMCWEB_LOG_ERROR("MIME parse failed, ec : {}",
1077 static_cast<int>(ec));
Ninad Palsuleb33a4322023-06-09 09:19:18 -05001078 messages::internalError(asyncResp->res);
1079 return;
1080 }
Ed Tanous6b54e4e2024-04-10 08:58:48 -07001081
Jagpal Singh Gillef93eab2024-04-17 16:06:14 -07001082 updateMultipartContext(asyncResp, req, std::move(parser));
George Liu0ed80c82020-05-12 16:06:27 +08001083 }
Ninad Palsuleb33a4322023-06-09 09:19:18 -05001084 else
1085 {
Ed Tanous62598e32023-07-17 17:06:25 -07001086 BMCWEB_LOG_DEBUG("Bad content type specified:{}", contentType);
Ninad Palsuleb33a4322023-06-09 09:19:18 -05001087 asyncResp->res.result(boost::beast::http::status::bad_request);
1088 }
Ed Tanousc2051d12022-05-11 12:21:55 -07001089}
1090
Patrick Williams504af5a2025-02-03 14:29:03 -05001091inline void handleUpdateServiceGet(
1092 App& app, const crow::Request& req,
1093 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001094{
Ed Tanousf5139332024-04-03 13:25:04 -07001095 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1096 {
1097 return;
1098 }
1099 asyncResp->res.jsonValue["@odata.type"] =
1100 "#UpdateService.v1_11_1.UpdateService";
1101 asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/UpdateService";
1102 asyncResp->res.jsonValue["Id"] = "UpdateService";
1103 asyncResp->res.jsonValue["Description"] = "Service for Software Update";
1104 asyncResp->res.jsonValue["Name"] = "Update Service";
Ed Tanous4dc23f32022-05-11 11:32:19 -07001105
Ed Tanousf5139332024-04-03 13:25:04 -07001106 asyncResp->res.jsonValue["HttpPushUri"] =
1107 "/redfish/v1/UpdateService/update";
1108 asyncResp->res.jsonValue["MultipartHttpPushUri"] =
1109 "/redfish/v1/UpdateService/update";
Ed Tanous4dc23f32022-05-11 11:32:19 -07001110
Ed Tanousf5139332024-04-03 13:25:04 -07001111 // UpdateService cannot be disabled
1112 asyncResp->res.jsonValue["ServiceEnabled"] = true;
1113 asyncResp->res.jsonValue["FirmwareInventory"]["@odata.id"] =
1114 "/redfish/v1/UpdateService/FirmwareInventory";
1115 // Get the MaxImageSizeBytes
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001116 asyncResp->res.jsonValue["MaxImageSizeBytes"] =
1117 BMCWEB_HTTP_BODY_LIMIT * 1024 * 1024;
Tejas Patild61e5192021-06-04 15:49:35 +05301118
Ed Tanous6a371402024-12-03 14:01:25 -08001119 if constexpr (BMCWEB_REDFISH_ALLOW_SIMPLE_UPDATE)
Ed Tanous25b54db2024-04-17 15:40:31 -07001120 {
Ed Tanous6a371402024-12-03 14:01:25 -08001121 // Update Actions object.
1122 nlohmann::json& updateSvcSimpleUpdate =
1123 asyncResp->res.jsonValue["Actions"]["#UpdateService.SimpleUpdate"];
1124 updateSvcSimpleUpdate["target"] =
1125 "/redfish/v1/UpdateService/Actions/UpdateService.SimpleUpdate";
Ed Tanous757178a2024-04-03 14:32:38 -07001126
Ed Tanous6a371402024-12-03 14:01:25 -08001127 nlohmann::json::array_t allowed;
1128 allowed.emplace_back(update_service::TransferProtocolType::HTTPS);
1129 updateSvcSimpleUpdate["TransferProtocol@Redfish.AllowableValues"] =
1130 std::move(allowed);
1131 }
Ed Tanous757178a2024-04-03 14:32:38 -07001132
Ed Tanous539d8c62024-06-19 14:38:27 -07001133 asyncResp->res
1134 .jsonValue["HttpPushUriOptions"]["HttpPushUriApplyTime"]["ApplyTime"] =
1135 update_service::ApplyTime::Immediate;
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001136}
Ed Tanousf5139332024-04-03 13:25:04 -07001137
1138inline void handleUpdateServiceFirmwareInventoryCollectionGet(
1139 App& app, const crow::Request& req,
1140 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
1141{
1142 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1143 {
1144 return;
1145 }
1146 asyncResp->res.jsonValue["@odata.type"] =
1147 "#SoftwareInventoryCollection.SoftwareInventoryCollection";
1148 asyncResp->res.jsonValue["@odata.id"] =
1149 "/redfish/v1/UpdateService/FirmwareInventory";
1150 asyncResp->res.jsonValue["Name"] = "Software Inventory Collection";
1151 const std::array<const std::string_view, 1> iface = {
1152 "xyz.openbmc_project.Software.Version"};
1153
1154 redfish::collection_util::getCollectionMembers(
1155 asyncResp,
1156 boost::urls::url("/redfish/v1/UpdateService/FirmwareInventory"), iface,
1157 "/xyz/openbmc_project/software");
1158}
1159
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001160/* Fill related item links (i.e. bmc, bios) in for inventory */
Ed Tanousf5139332024-04-03 13:25:04 -07001161inline void getRelatedItems(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1162 const std::string& purpose)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001163{
Willy Tueee00132022-06-14 14:53:17 -07001164 if (purpose == sw_util::bmcPurpose)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001165 {
Ed Tanousac106bf2023-06-07 09:24:59 -07001166 nlohmann::json& relatedItem = asyncResp->res.jsonValue["RelatedItem"];
Ed Tanous14766872022-03-15 10:44:42 -07001167 nlohmann::json::object_t item;
Ed Tanous253f11b2024-05-16 09:38:31 -07001168 item["@odata.id"] = boost::urls::format(
1169 "/redfish/v1/Managers/{}", BMCWEB_REDFISH_MANAGER_URI_NAME);
Patrick Williamsb2ba3072023-05-12 10:27:39 -05001170 relatedItem.emplace_back(std::move(item));
Ed Tanousac106bf2023-06-07 09:24:59 -07001171 asyncResp->res.jsonValue["RelatedItem@odata.count"] =
1172 relatedItem.size();
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001173 }
Willy Tueee00132022-06-14 14:53:17 -07001174 else if (purpose == sw_util::biosPurpose)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001175 {
Ed Tanousac106bf2023-06-07 09:24:59 -07001176 nlohmann::json& relatedItem = asyncResp->res.jsonValue["RelatedItem"];
Ed Tanous14766872022-03-15 10:44:42 -07001177 nlohmann::json::object_t item;
Ed Tanous253f11b2024-05-16 09:38:31 -07001178 item["@odata.id"] = std::format("/redfish/v1/Systems/{}/Bios",
1179 BMCWEB_REDFISH_SYSTEM_URI_NAME);
Patrick Williamsb2ba3072023-05-12 10:27:39 -05001180 relatedItem.emplace_back(std::move(item));
Ed Tanousac106bf2023-06-07 09:24:59 -07001181 asyncResp->res.jsonValue["RelatedItem@odata.count"] =
1182 relatedItem.size();
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001183 }
1184 else
1185 {
Carson Labradobf2dded2023-08-10 00:37:06 +00001186 BMCWEB_LOG_DEBUG("Unknown software purpose {}", purpose);
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001187 }
1188}
1189
Patrick Williams504af5a2025-02-03 14:29:03 -05001190inline void getSoftwareVersion(
1191 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1192 const std::string& service, const std::string& path,
1193 const std::string& swId)
Willy Tuaf246602022-06-14 15:51:53 -07001194{
Ed Tanousdeae6a72024-11-11 21:58:57 -08001195 dbus::utility::getAllProperties(
1196 service, path, "xyz.openbmc_project.Software.Version",
Willy Tuaf246602022-06-14 15:51:53 -07001197 [asyncResp,
Ed Tanous8b242752023-06-27 17:17:13 -07001198 swId](const boost::system::error_code& ec,
Willy Tuaf246602022-06-14 15:51:53 -07001199 const dbus::utility::DBusPropertiesMap& propertiesList) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001200 if (ec)
1201 {
1202 messages::internalError(asyncResp->res);
1203 return;
1204 }
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +02001205
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001206 const std::string* swInvPurpose = nullptr;
1207 const std::string* version = nullptr;
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +02001208
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001209 const bool success = sdbusplus::unpackPropertiesNoThrow(
1210 dbus_utils::UnpackErrorPrinter(), propertiesList, "Purpose",
1211 swInvPurpose, "Version", version);
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +02001212
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001213 if (!success)
1214 {
1215 messages::internalError(asyncResp->res);
1216 return;
1217 }
Willy Tuaf246602022-06-14 15:51:53 -07001218
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001219 if (swInvPurpose == nullptr)
1220 {
1221 BMCWEB_LOG_DEBUG("Can't find property \"Purpose\"!");
1222 messages::internalError(asyncResp->res);
1223 return;
1224 }
Willy Tuaf246602022-06-14 15:51:53 -07001225
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001226 BMCWEB_LOG_DEBUG("swInvPurpose = {}", *swInvPurpose);
Willy Tuaf246602022-06-14 15:51:53 -07001227
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001228 if (version == nullptr)
1229 {
1230 BMCWEB_LOG_DEBUG("Can't find property \"Version\"!");
Willy Tuaf246602022-06-14 15:51:53 -07001231
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001232 messages::internalError(asyncResp->res);
Willy Tuaf246602022-06-14 15:51:53 -07001233
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001234 return;
1235 }
1236 asyncResp->res.jsonValue["Version"] = *version;
1237 asyncResp->res.jsonValue["Id"] = swId;
Willy Tuaf246602022-06-14 15:51:53 -07001238
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001239 // swInvPurpose is of format:
1240 // xyz.openbmc_project.Software.Version.VersionPurpose.ABC
1241 // Translate this to "ABC image"
1242 size_t endDesc = swInvPurpose->rfind('.');
1243 if (endDesc == std::string::npos)
1244 {
1245 messages::internalError(asyncResp->res);
1246 return;
1247 }
1248 endDesc++;
1249 if (endDesc >= swInvPurpose->size())
1250 {
1251 messages::internalError(asyncResp->res);
1252 return;
1253 }
Willy Tuaf246602022-06-14 15:51:53 -07001254
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001255 std::string formatDesc = swInvPurpose->substr(endDesc);
1256 asyncResp->res.jsonValue["Description"] = formatDesc + " image";
1257 getRelatedItems(asyncResp, *swInvPurpose);
1258 });
Willy Tuaf246602022-06-14 15:51:53 -07001259}
1260
Ed Tanousf5139332024-04-03 13:25:04 -07001261inline void handleUpdateServiceFirmwareInventoryGet(
1262 App& app, const crow::Request& req,
1263 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1264 const std::string& param)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001265{
Ed Tanousf5139332024-04-03 13:25:04 -07001266 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1267 {
1268 return;
1269 }
1270 std::shared_ptr<std::string> swId = std::make_shared<std::string>(param);
1271
1272 asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
1273 "/redfish/v1/UpdateService/FirmwareInventory/{}", *swId);
1274
1275 constexpr std::array<std::string_view, 1> interfaces = {
1276 "xyz.openbmc_project.Software.Version"};
1277 dbus::utility::getSubTree(
1278 "/", 0, interfaces,
1279 [asyncResp,
1280 swId](const boost::system::error_code& ec,
1281 const dbus::utility::MapperGetSubTreeResponse& subtree) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001282 BMCWEB_LOG_DEBUG("doGet callback...");
1283 if (ec)
Ed Tanous45ca1b82022-03-25 13:07:27 -07001284 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001285 messages::internalError(asyncResp->res);
1286 return;
Ed Tanous45ca1b82022-03-25 13:07:27 -07001287 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001288
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001289 // Ensure we find our input swId, otherwise return an error
1290 bool found = false;
1291 for (const std::pair<std::string,
1292 std::vector<std::pair<
1293 std::string, std::vector<std::string>>>>&
1294 obj : subtree)
Ed Tanous002d39b2022-05-31 08:59:27 -07001295 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001296 if (!obj.first.ends_with(*swId))
1297 {
1298 continue;
1299 }
1300
1301 if (obj.second.empty())
1302 {
1303 continue;
1304 }
1305
1306 found = true;
1307 sw_util::getSwStatus(asyncResp, swId, obj.second[0].first);
1308 getSoftwareVersion(asyncResp, obj.second[0].first, obj.first,
1309 *swId);
Ed Tanous002d39b2022-05-31 08:59:27 -07001310 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001311 if (!found)
1312 {
1313 BMCWEB_LOG_WARNING("Input swID {} not found!", *swId);
1314 messages::resourceMissingAtURI(
1315 asyncResp->res,
1316 boost::urls::format(
1317 "/redfish/v1/UpdateService/FirmwareInventory/{}",
1318 *swId));
1319 return;
1320 }
1321 asyncResp->res.jsonValue["@odata.type"] =
1322 "#SoftwareInventory.v1_1_0.SoftwareInventory";
1323 asyncResp->res.jsonValue["Name"] = "Software Inventory";
1324 asyncResp->res.jsonValue["Status"]["HealthRollup"] =
1325 resource::Health::OK;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001326
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001327 asyncResp->res.jsonValue["Updateable"] = false;
1328 sw_util::getSwUpdatableStatus(asyncResp, swId);
1329 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001330}
Ed Tanous1abe55e2018-09-05 08:30:59 -07001331
Ed Tanousf5139332024-04-03 13:25:04 -07001332inline void requestRoutesUpdateService(App& app)
1333{
Ed Tanous6a371402024-12-03 14:01:25 -08001334 if constexpr (BMCWEB_REDFISH_ALLOW_SIMPLE_UPDATE)
1335 {
1336 BMCWEB_ROUTE(
1337 app,
1338 "/redfish/v1/UpdateService/Actions/UpdateService.SimpleUpdate/")
1339 .privileges(redfish::privileges::postUpdateService)
1340 .methods(boost::beast::http::verb::post)(std::bind_front(
1341 handleUpdateServiceSimpleUpdateAction, std::ref(app)));
1342 }
Ed Tanousf5139332024-04-03 13:25:04 -07001343 BMCWEB_ROUTE(app, "/redfish/v1/UpdateService/FirmwareInventory/<str>/")
1344 .privileges(redfish::privileges::getSoftwareInventory)
1345 .methods(boost::beast::http::verb::get)(std::bind_front(
1346 handleUpdateServiceFirmwareInventoryGet, std::ref(app)));
1347
1348 BMCWEB_ROUTE(app, "/redfish/v1/UpdateService/")
1349 .privileges(redfish::privileges::getUpdateService)
1350 .methods(boost::beast::http::verb::get)(
1351 std::bind_front(handleUpdateServiceGet, std::ref(app)));
1352
Ed Tanousf5139332024-04-03 13:25:04 -07001353 BMCWEB_ROUTE(app, "/redfish/v1/UpdateService/update/")
1354 .privileges(redfish::privileges::postUpdateService)
1355 .methods(boost::beast::http::verb::post)(
1356 std::bind_front(handleUpdateServicePost, std::ref(app)));
1357
1358 BMCWEB_ROUTE(app, "/redfish/v1/UpdateService/FirmwareInventory/")
1359 .privileges(redfish::privileges::getSoftwareInventoryCollection)
1360 .methods(boost::beast::http::verb::get)(std::bind_front(
1361 handleUpdateServiceFirmwareInventoryCollectionGet, std::ref(app)));
1362}
1363
Ed Tanous1abe55e2018-09-05 08:30:59 -07001364} // namespace redfish