blob: 89c4c7dbc587ab70eec7adec462fdb8d74bd3b53 [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"
Ed Tanous5b904292024-04-16 11:10:17 -070022#include "error_messages.hpp"
Ed Tanous757178a2024-04-03 14:32:38 -070023#include "generated/enums/update_service.hpp"
George Liu0ed80c82020-05-12 16:06:27 +080024#include "multipart_parser.hpp"
Ed Tanous2c6ffdb2023-06-28 11:28:38 -070025#include "ossl_random.hpp"
Ed Tanous3ccb3ad2023-01-13 17:40:03 -080026#include "query.hpp"
27#include "registries/privilege_registry.hpp"
Ed Tanousa8e884f2023-01-13 17:40:03 -080028#include "task.hpp"
Ed Tanous5b904292024-04-16 11:10:17 -070029#include "task_messages.hpp"
John Edward Broadbent08d81ad2022-05-17 20:00:23 -070030#include "utils/collection.hpp"
Ed Tanous3ccb3ad2023-01-13 17:40:03 -080031#include "utils/dbus_utils.hpp"
Ed Tanous5b904292024-04-16 11:10:17 -070032#include "utils/json_utils.hpp"
Ed Tanous3ccb3ad2023-01-13 17:40:03 -080033#include "utils/sw_utils.hpp"
34
Jagpal Singh Gillde0c9602024-04-29 17:30:21 -070035#include <sys/mman.h>
36
George Liue99073f2022-12-09 11:06:16 +080037#include <boost/system/error_code.hpp>
Ed Tanousef4c65b2023-04-24 15:28:50 -070038#include <boost/url/format.hpp>
Jonathan Doman1e1e5982021-06-11 09:36:17 -070039#include <sdbusplus/asio/property.hpp>
Ed Tanous3ccb3ad2023-01-13 17:40:03 -080040#include <sdbusplus/bus/match.hpp>
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +020041#include <sdbusplus/unpack_properties.hpp>
Gunnar Mills1214b7e2020-06-04 10:11:30 -050042
George Liu2b731192023-01-11 16:27:13 +080043#include <array>
Jagpal Singh Gillde0c9602024-04-29 17:30:21 -070044#include <cstddef>
George Liu0ed80c82020-05-12 16:06:27 +080045#include <filesystem>
Jagpal Singh Gillc71b6c92024-04-29 16:50:53 -070046#include <functional>
Jagpal Singh Gillde0c9602024-04-29 17:30:21 -070047#include <iterator>
Jagpal Singh Gillef93eab2024-04-17 16:06:14 -070048#include <memory>
Ed Tanous7cb59f62022-05-05 11:48:31 -070049#include <optional>
50#include <string>
George Liu2b731192023-01-11 16:27:13 +080051#include <string_view>
Jagpal Singh Gillde0c9602024-04-29 17:30:21 -070052#include <unordered_map>
Jagpal Singh Gillef93eab2024-04-17 16:06:14 -070053#include <vector>
George Liu2b731192023-01-11 16:27:13 +080054
Ed Tanous1abe55e2018-09-05 08:30:59 -070055namespace redfish
56{
Ed Tanous27826b52018-10-29 11:40:58 -070057
Andrew Geissler0e7de462019-03-04 19:11:54 -060058// Match signals added on software path
Ed Tanouscf9e4172022-12-21 09:30:16 -080059// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
Patrick Williams59d494e2022-07-22 19:26:55 -050060static std::unique_ptr<sdbusplus::bus::match_t> fwUpdateMatcher;
Ed Tanouscf9e4172022-12-21 09:30:16 -080061// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
Patrick Williams59d494e2022-07-22 19:26:55 -050062static std::unique_ptr<sdbusplus::bus::match_t> fwUpdateErrorMatcher;
Andrew Geissler0e7de462019-03-04 19:11:54 -060063// Only allow one update at a time
Ed Tanouscf9e4172022-12-21 09:30:16 -080064// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
Andrew Geissler0e7de462019-03-04 19:11:54 -060065static bool fwUpdateInProgress = false;
Andrew Geissler86adcd62019-04-18 10:58:05 -050066// Timer for software available
Ed Tanouscf9e4172022-12-21 09:30:16 -080067// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
Ed Tanous271584a2019-07-09 16:24:22 -070068static std::unique_ptr<boost::asio::steady_timer> fwAvailableTimer;
Andrew Geissler86adcd62019-04-18 10:58:05 -050069
Jagpal Singh Gillde0c9602024-04-29 17:30:21 -070070struct MemoryFileDescriptor
71{
72 int fd = -1;
73
74 explicit MemoryFileDescriptor(const std::string& filename) :
75 fd(memfd_create(filename.c_str(), 0))
76 {}
77
78 MemoryFileDescriptor(const MemoryFileDescriptor&) = default;
79 MemoryFileDescriptor(MemoryFileDescriptor&& other) noexcept : fd(other.fd)
80 {
81 other.fd = -1;
82 }
83 MemoryFileDescriptor& operator=(const MemoryFileDescriptor&) = delete;
84 MemoryFileDescriptor& operator=(MemoryFileDescriptor&&) = default;
85
86 ~MemoryFileDescriptor()
87 {
88 if (fd != -1)
89 {
90 close(fd);
91 }
92 }
93
94 bool rewind() const
95 {
96 if (lseek(fd, 0, SEEK_SET) == -1)
97 {
98 BMCWEB_LOG_ERROR("Failed to seek to beginning of image memfd");
99 return false;
100 }
101 return true;
102 }
103};
104
Ed Tanousdf254f22024-04-01 13:25:46 -0700105inline void cleanUp()
Andrew Geissler86adcd62019-04-18 10:58:05 -0500106{
107 fwUpdateInProgress = false;
108 fwUpdateMatcher = nullptr;
James Feist4cde5d92020-06-11 10:39:55 -0700109 fwUpdateErrorMatcher = nullptr;
Andrew Geissler86adcd62019-04-18 10:58:05 -0500110}
Ed Tanousdf254f22024-04-01 13:25:46 -0700111
112inline void activateImage(const std::string& objPath,
113 const std::string& service)
Andrew Geissler86adcd62019-04-18 10:58:05 -0500114{
Ed Tanous62598e32023-07-17 17:06:25 -0700115 BMCWEB_LOG_DEBUG("Activate image for {} {}", objPath, service);
George Liu9ae226f2023-06-21 17:56:46 +0800116 sdbusplus::asio::setProperty(
117 *crow::connections::systemBus, service, objPath,
118 "xyz.openbmc_project.Software.Activation", "RequestedActivation",
119 "xyz.openbmc_project.Software.Activation.RequestedActivations.Active",
Ed Tanous8b242752023-06-27 17:17:13 -0700120 [](const boost::system::error_code& ec) {
121 if (ec)
Ed Tanous002d39b2022-05-31 08:59:27 -0700122 {
Ed Tanous62598e32023-07-17 17:06:25 -0700123 BMCWEB_LOG_DEBUG("error_code = {}", ec);
124 BMCWEB_LOG_DEBUG("error msg = {}", ec.message());
Ed Tanous002d39b2022-05-31 08:59:27 -0700125 }
Patrick Williams5a39f772023-10-20 11:20:21 -0500126 });
Andrew Geissler86adcd62019-04-18 10:58:05 -0500127}
Andrew Geissler0554c982019-04-23 14:40:12 -0500128
Jagpal Singh Gillc71b6c92024-04-29 16:50:53 -0700129inline bool handleCreateTask(const boost::system::error_code& ec2,
130 sdbusplus::message_t& msg,
131 const std::shared_ptr<task::TaskData>& taskData)
132{
133 if (ec2)
134 {
135 return task::completed;
136 }
137
138 std::string iface;
139 dbus::utility::DBusPropertiesMap values;
140
141 std::string index = std::to_string(taskData->index);
142 msg.read(iface, values);
143
144 if (iface == "xyz.openbmc_project.Software.Activation")
145 {
146 const std::string* state = nullptr;
147 for (const auto& property : values)
148 {
149 if (property.first == "Activation")
150 {
151 state = std::get_if<std::string>(&property.second);
152 if (state == nullptr)
153 {
154 taskData->messages.emplace_back(messages::internalError());
155 return task::completed;
156 }
157 }
158 }
159
160 if (state == nullptr)
161 {
162 return !task::completed;
163 }
164
165 if (state->ends_with("Invalid") || state->ends_with("Failed"))
166 {
167 taskData->state = "Exception";
168 taskData->status = "Warning";
169 taskData->messages.emplace_back(messages::taskAborted(index));
170 return task::completed;
171 }
172
173 if (state->ends_with("Staged"))
174 {
175 taskData->state = "Stopping";
176 taskData->messages.emplace_back(messages::taskPaused(index));
177
178 // its staged, set a long timer to
179 // allow them time to complete the
180 // update (probably cycle the
181 // system) if this expires then
182 // task will be canceled
183 taskData->extendTimer(std::chrono::hours(5));
184 return !task::completed;
185 }
186
187 if (state->ends_with("Active"))
188 {
189 taskData->messages.emplace_back(messages::taskCompletedOK(index));
190 taskData->state = "Completed";
191 return task::completed;
192 }
193 }
194 else if (iface == "xyz.openbmc_project.Software.ActivationProgress")
195 {
196 const uint8_t* progress = nullptr;
197 for (const auto& property : values)
198 {
199 if (property.first == "Progress")
200 {
201 progress = std::get_if<uint8_t>(&property.second);
202 if (progress == nullptr)
203 {
204 taskData->messages.emplace_back(messages::internalError());
205 return task::completed;
206 }
207 }
208 }
209
210 if (progress == nullptr)
211 {
212 return !task::completed;
213 }
214 taskData->percentComplete = *progress;
215 taskData->messages.emplace_back(
216 messages::taskProgressChanged(index, *progress));
217
218 // if we're getting status updates it's
219 // still alive, update timer
220 taskData->extendTimer(std::chrono::minutes(5));
221 }
222
223 // as firmware update often results in a
224 // reboot, the task may never "complete"
225 // unless it is an error
226
227 return !task::completed;
228}
229
230inline void createTask(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
231 task::Payload&& payload,
232 const sdbusplus::message::object_path& objPath)
233{
234 std::shared_ptr<task::TaskData> task = task::TaskData::createTask(
235 std::bind_front(handleCreateTask),
236 "type='signal',interface='org.freedesktop.DBus.Properties',"
237 "member='PropertiesChanged',path='" +
238 objPath.str + "'");
239 task->startTimer(std::chrono::minutes(5));
240 task->populateResp(asyncResp->res);
241 task->payload.emplace(std::move(payload));
242}
243
Andrew Geissler0554c982019-04-23 14:40:12 -0500244// Note that asyncResp can be either a valid pointer or nullptr. If nullptr
245// then no asyncResp updates will occur
zhanghch058d1b46d2021-04-01 11:18:24 +0800246static void
247 softwareInterfaceAdded(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Patrick Williams59d494e2022-07-22 19:26:55 -0500248 sdbusplus::message_t& m, task::Payload&& payload)
Andrew Geissler86adcd62019-04-18 10:58:05 -0500249{
Michael Shen80f79a42023-08-24 13:41:53 +0000250 dbus::utility::DBusInterfacesMap interfacesProperties;
Andrew Geissler86adcd62019-04-18 10:58:05 -0500251
252 sdbusplus::message::object_path objPath;
253
254 m.read(objPath, interfacesProperties);
255
Ed Tanous62598e32023-07-17 17:06:25 -0700256 BMCWEB_LOG_DEBUG("obj path = {}", objPath.str);
Ed Tanouse3eb3d62022-12-21 11:56:07 -0800257 for (const auto& interface : interfacesProperties)
Andrew Geissler86adcd62019-04-18 10:58:05 -0500258 {
Ed Tanous62598e32023-07-17 17:06:25 -0700259 BMCWEB_LOG_DEBUG("interface = {}", interface.first);
Andrew Geissler86adcd62019-04-18 10:58:05 -0500260
261 if (interface.first == "xyz.openbmc_project.Software.Activation")
262 {
Andrew Geissler86adcd62019-04-18 10:58:05 -0500263 // Retrieve service and activate
George Liu2b731192023-01-11 16:27:13 +0800264 constexpr std::array<std::string_view, 1> interfaces = {
265 "xyz.openbmc_project.Software.Activation"};
266 dbus::utility::getDbusObject(
267 objPath.str, interfaces,
Ed Tanousa3e65892021-09-16 14:13:20 -0700268 [objPath, asyncResp, payload(std::move(payload))](
Ed Tanous8b242752023-06-27 17:17:13 -0700269 const boost::system::error_code& ec,
Ed Tanousa3e65892021-09-16 14:13:20 -0700270 const std::vector<
271 std::pair<std::string, std::vector<std::string>>>&
272 objInfo) mutable {
Ed Tanous8b242752023-06-27 17:17:13 -0700273 if (ec)
Ed Tanous002d39b2022-05-31 08:59:27 -0700274 {
Ed Tanous62598e32023-07-17 17:06:25 -0700275 BMCWEB_LOG_DEBUG("error_code = {}", ec);
276 BMCWEB_LOG_DEBUG("error msg = {}", ec.message());
Andrew Geissler0554c982019-04-23 14:40:12 -0500277 if (asyncResp)
278 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700279 messages::internalError(asyncResp->res);
280 }
281 cleanUp();
282 return;
283 }
284 // Ensure we only got one service back
285 if (objInfo.size() != 1)
286 {
Ed Tanous62598e32023-07-17 17:06:25 -0700287 BMCWEB_LOG_ERROR("Invalid Object Size {}", objInfo.size());
Ed Tanous002d39b2022-05-31 08:59:27 -0700288 if (asyncResp)
289 {
290 messages::internalError(asyncResp->res);
291 }
292 cleanUp();
293 return;
294 }
295 // cancel timer only when
296 // xyz.openbmc_project.Software.Activation interface
297 // is added
298 fwAvailableTimer = nullptr;
299
300 activateImage(objPath.str, objInfo[0].first);
301 if (asyncResp)
302 {
Jagpal Singh Gillc71b6c92024-04-29 16:50:53 -0700303 createTask(asyncResp, std::move(payload), objPath);
Ed Tanous002d39b2022-05-31 08:59:27 -0700304 }
305 fwUpdateInProgress = false;
Patrick Williams5a39f772023-10-20 11:20:21 -0500306 });
Patrick Williams62bafc02022-09-08 17:35:35 -0500307
308 break;
Andrew Geissler86adcd62019-04-18 10:58:05 -0500309 }
310 }
311}
312
Myung Bae8549b952023-08-16 15:18:19 -0400313inline void afterAvailbleTimerAsyncWait(
314 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
315 const boost::system::error_code& ec)
316{
317 cleanUp();
318 if (ec == boost::asio::error::operation_aborted)
319 {
320 // expected, we were canceled before the timer completed.
321 return;
322 }
323 BMCWEB_LOG_ERROR("Timed out waiting for firmware object being created");
324 BMCWEB_LOG_ERROR("FW image may has already been uploaded to server");
325 if (ec)
326 {
327 BMCWEB_LOG_ERROR("Async_wait failed{}", ec);
328 return;
329 }
330 if (asyncResp)
331 {
332 redfish::messages::internalError(asyncResp->res);
333 }
334}
335
336inline void
337 handleUpdateErrorType(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
338 const std::string& url, const std::string& type)
339{
340 if (type == "xyz.openbmc_project.Software.Image.Error.UnTarFailure")
341 {
342 redfish::messages::invalidUpload(asyncResp->res, url,
343 "Invalid archive");
344 }
345 else if (type ==
346 "xyz.openbmc_project.Software.Image.Error.ManifestFileFailure")
347 {
348 redfish::messages::invalidUpload(asyncResp->res, url,
349 "Invalid manifest");
350 }
351 else if (type == "xyz.openbmc_project.Software.Image.Error.ImageFailure")
352 {
353 redfish::messages::invalidUpload(asyncResp->res, url,
354 "Invalid image format");
355 }
356 else if (type == "xyz.openbmc_project.Software.Version.Error.AlreadyExists")
357 {
358 redfish::messages::invalidUpload(asyncResp->res, url,
359 "Image version already exists");
360
361 redfish::messages::resourceAlreadyExists(
362 asyncResp->res, "UpdateService", "Version", "uploaded version");
363 }
364 else if (type == "xyz.openbmc_project.Software.Image.Error.BusyFailure")
365 {
366 redfish::messages::resourceExhaustion(asyncResp->res, url);
367 }
Myung Bae4034a652023-08-17 08:47:35 -0400368 else if (type == "xyz.openbmc_project.Software.Version.Error.Incompatible")
Myung Bae8549b952023-08-16 15:18:19 -0400369 {
Myung Bae4034a652023-08-17 08:47:35 -0400370 redfish::messages::invalidUpload(asyncResp->res, url,
371 "Incompatible image version");
372 }
373 else if (type ==
374 "xyz.openbmc_project.Software.Version.Error.ExpiredAccessKey")
375 {
376 redfish::messages::invalidUpload(asyncResp->res, url,
377 "Update Access Key Expired");
378 }
379 else if (type ==
380 "xyz.openbmc_project.Software.Version.Error.InvalidSignature")
381 {
382 redfish::messages::invalidUpload(asyncResp->res, url,
383 "Invalid image signature");
384 }
385 else if (type ==
386 "xyz.openbmc_project.Software.Image.Error.InternalFailure" ||
387 type == "xyz.openbmc_project.Software.Version.Error.HostFile")
388 {
389 BMCWEB_LOG_ERROR("Software Image Error type={}", type);
Myung Bae8549b952023-08-16 15:18:19 -0400390 redfish::messages::internalError(asyncResp->res);
391 }
Myung Bae4034a652023-08-17 08:47:35 -0400392 else
393 {
394 // Unrelated error types. Ignored
395 BMCWEB_LOG_INFO("Non-Software-related Error type={}. Ignored", type);
396 return;
397 }
398 // Clear the timer
399 fwAvailableTimer = nullptr;
Myung Bae8549b952023-08-16 15:18:19 -0400400}
401
402inline void
403 afterUpdateErrorMatcher(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
404 const std::string& url, sdbusplus::message_t& m)
405{
Michael Shen80f79a42023-08-24 13:41:53 +0000406 dbus::utility::DBusInterfacesMap interfacesProperties;
Myung Bae8549b952023-08-16 15:18:19 -0400407 sdbusplus::message::object_path objPath;
408 m.read(objPath, interfacesProperties);
409 BMCWEB_LOG_DEBUG("obj path = {}", objPath.str);
410 for (const std::pair<std::string, dbus::utility::DBusPropertiesMap>&
411 interface : interfacesProperties)
412 {
413 if (interface.first == "xyz.openbmc_project.Logging.Entry")
414 {
415 for (const std::pair<std::string, dbus::utility::DbusVariantType>&
416 value : interface.second)
417 {
418 if (value.first != "Message")
419 {
420 continue;
421 }
422 const std::string* type =
423 std::get_if<std::string>(&value.second);
424 if (type == nullptr)
425 {
426 // if this was our message, timeout will cover it
427 return;
428 }
Myung Bae8549b952023-08-16 15:18:19 -0400429 handleUpdateErrorType(asyncResp, url, *type);
430 }
431 }
432 }
433}
434
Andrew Geissler0554c982019-04-23 14:40:12 -0500435// Note that asyncResp can be either a valid pointer or nullptr. If nullptr
436// then no asyncResp updates will occur
Ed Tanousf5139332024-04-03 13:25:04 -0700437inline void monitorForSoftwareAvailable(
zhanghch058d1b46d2021-04-01 11:18:24 +0800438 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
439 const crow::Request& req, const std::string& url,
Gunnar Mills5d138942022-09-07 10:26:21 -0500440 int timeoutTimeSeconds = 25)
Andrew Geissler86adcd62019-04-18 10:58:05 -0500441{
442 // Only allow one FW update at a time
Ed Tanouse05aec52022-01-25 10:28:56 -0800443 if (fwUpdateInProgress)
Andrew Geissler86adcd62019-04-18 10:58:05 -0500444 {
Andrew Geissler0554c982019-04-23 14:40:12 -0500445 if (asyncResp)
446 {
Andrew Geissler0554c982019-04-23 14:40:12 -0500447 messages::serviceTemporarilyUnavailable(asyncResp->res, "30");
448 }
Andrew Geissler86adcd62019-04-18 10:58:05 -0500449 return;
450 }
451
Ed Tanous8e8245d2024-04-11 22:21:38 -0700452 if (req.ioService == nullptr)
453 {
454 messages::internalError(asyncResp->res);
455 return;
456 }
457
Andrew Geissler0554c982019-04-23 14:40:12 -0500458 fwAvailableTimer =
Ed Tanous271584a2019-07-09 16:24:22 -0700459 std::make_unique<boost::asio::steady_timer>(*req.ioService);
Andrew Geissler86adcd62019-04-18 10:58:05 -0500460
Ed Tanous271584a2019-07-09 16:24:22 -0700461 fwAvailableTimer->expires_after(std::chrono::seconds(timeoutTimeSeconds));
Andrew Geissler86adcd62019-04-18 10:58:05 -0500462
463 fwAvailableTimer->async_wait(
Myung Bae8549b952023-08-16 15:18:19 -0400464 std::bind_front(afterAvailbleTimerAsyncWait, asyncResp));
465
Ed Tanousa3e65892021-09-16 14:13:20 -0700466 task::Payload payload(req);
Patrick Williams59d494e2022-07-22 19:26:55 -0500467 auto callback = [asyncResp, payload](sdbusplus::message_t& m) mutable {
Ed Tanous62598e32023-07-17 17:06:25 -0700468 BMCWEB_LOG_DEBUG("Match fired");
Ed Tanousa3e65892021-09-16 14:13:20 -0700469 softwareInterfaceAdded(asyncResp, m, std::move(payload));
Andrew Geissler86adcd62019-04-18 10:58:05 -0500470 };
471
472 fwUpdateInProgress = true;
473
Patrick Williams59d494e2022-07-22 19:26:55 -0500474 fwUpdateMatcher = std::make_unique<sdbusplus::bus::match_t>(
Andrew Geissler86adcd62019-04-18 10:58:05 -0500475 *crow::connections::systemBus,
476 "interface='org.freedesktop.DBus.ObjectManager',type='signal',"
477 "member='InterfacesAdded',path='/xyz/openbmc_project/software'",
478 callback);
James Feist4cde5d92020-06-11 10:39:55 -0700479
Patrick Williams59d494e2022-07-22 19:26:55 -0500480 fwUpdateErrorMatcher = std::make_unique<sdbusplus::bus::match_t>(
James Feist4cde5d92020-06-11 10:39:55 -0700481 *crow::connections::systemBus,
Brian Mae1cc4822021-12-01 17:05:54 +0800482 "interface='org.freedesktop.DBus.ObjectManager',type='signal',"
483 "member='InterfacesAdded',"
484 "path='/xyz/openbmc_project/logging'",
Myung Bae8549b952023-08-16 15:18:19 -0400485 std::bind_front(afterUpdateErrorMatcher, asyncResp, url));
Andrew Geissler86adcd62019-04-18 10:58:05 -0500486}
Jennifer Lee729dae72018-04-24 15:59:34 -0700487
Ed Tanous757178a2024-04-03 14:32:38 -0700488inline std::optional<boost::urls::url>
489 parseSimpleUpdateUrl(std::string imageURI,
490 std::optional<std::string> transferProtocol,
491 crow::Response& res)
Ed Tanousf86bcc82023-08-25 09:34:07 -0700492{
493 if (imageURI.find("://") == std::string::npos)
494 {
495 if (imageURI.starts_with("/"))
496 {
497 messages::actionParameterValueTypeError(
498 res, imageURI, "ImageURI", "UpdateService.SimpleUpdate");
499 return std::nullopt;
500 }
501 if (!transferProtocol)
502 {
503 messages::actionParameterValueTypeError(
504 res, imageURI, "ImageURI", "UpdateService.SimpleUpdate");
505 return std::nullopt;
506 }
Ed Tanouse5cf7772024-04-03 13:45:31 -0700507 // OpenBMC currently only supports TFTP or HTTPS
Ed Tanous757178a2024-04-03 14:32:38 -0700508 if (*transferProtocol == "TFTP")
509 {
510 imageURI = "tftp://" + imageURI;
511 }
Ed Tanouse5cf7772024-04-03 13:45:31 -0700512 else if (*transferProtocol == "HTTPS")
513 {
514 imageURI = "https://" + imageURI;
515 }
Ed Tanous757178a2024-04-03 14:32:38 -0700516 else
Ed Tanousf86bcc82023-08-25 09:34:07 -0700517 {
518 messages::actionParameterNotSupported(res, "TransferProtocol",
519 *transferProtocol);
520 BMCWEB_LOG_ERROR("Request incorrect protocol parameter: {}",
521 *transferProtocol);
522 return std::nullopt;
523 }
Ed Tanousf86bcc82023-08-25 09:34:07 -0700524 }
525
526 boost::system::result<boost::urls::url> url =
527 boost::urls::parse_absolute_uri(imageURI);
528 if (!url)
529 {
530 messages::actionParameterValueTypeError(res, imageURI, "ImageURI",
531 "UpdateService.SimpleUpdate");
532
533 return std::nullopt;
534 }
535 url->normalize();
536
Ed Tanous757178a2024-04-03 14:32:38 -0700537 if (url->scheme() == "tftp")
538 {
539 if (url->encoded_path().size() < 2)
540 {
541 messages::actionParameterNotSupported(res, "ImageURI",
542 url->buffer());
543 return std::nullopt;
544 }
545 }
Ed Tanouse5cf7772024-04-03 13:45:31 -0700546 else if (url->scheme() == "https")
547 {
548 // Empty paths default to "/"
549 if (url->encoded_path().empty())
550 {
551 url->set_encoded_path("/");
552 }
553 }
Ed Tanous757178a2024-04-03 14:32:38 -0700554 else
Ed Tanousf86bcc82023-08-25 09:34:07 -0700555 {
556 messages::actionParameterNotSupported(res, "ImageURI", imageURI);
557 return std::nullopt;
558 }
Ed Tanous757178a2024-04-03 14:32:38 -0700559
560 if (url->encoded_path().empty())
Ed Tanousf86bcc82023-08-25 09:34:07 -0700561 {
Ed Tanous757178a2024-04-03 14:32:38 -0700562 messages::actionParameterValueTypeError(res, imageURI, "ImageURI",
563 "UpdateService.SimpleUpdate");
Ed Tanousf86bcc82023-08-25 09:34:07 -0700564 return std::nullopt;
565 }
Ed Tanous757178a2024-04-03 14:32:38 -0700566
567 return *url;
Ed Tanousf86bcc82023-08-25 09:34:07 -0700568}
569
Ed Tanouse5cf7772024-04-03 13:45:31 -0700570inline void doHttpsUpdate(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
571 const boost::urls::url_view_base& url)
572{
573 messages::actionParameterNotSupported(asyncResp->res, "ImageURI",
574 url.buffer());
575}
576
Ed Tanous6b0f66b2024-04-03 13:38:21 -0700577inline void doTftpUpdate(const crow::Request& req,
578 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous757178a2024-04-03 14:32:38 -0700579 const boost::urls::url_view_base& url)
Ed Tanous6b0f66b2024-04-03 13:38:21 -0700580{
Ed Tanousc72503f2024-05-06 14:57:13 -0700581 if (!BMCWEB_INSECURE_TFTP_UPDATE)
582 {
583 messages::actionParameterNotSupported(asyncResp->res, "ImageURI",
584 url.buffer());
585 return;
586 }
Ed Tanous757178a2024-04-03 14:32:38 -0700587
588 std::string path(url.encoded_path());
589 if (path.size() < 2)
590 {
591 messages::actionParameterNotSupported(asyncResp->res, "ImageURI",
592 url.buffer());
593 return;
594 }
595 // TFTP expects a path without a /
596 path.erase(0, 1);
597 std::string host(url.encoded_host_and_port());
598 BMCWEB_LOG_DEBUG("Server: {} File: {}", host, path);
Ed Tanous6b0f66b2024-04-03 13:38:21 -0700599
600 // Setup callback for when new software detected
601 // Give TFTP 10 minutes to complete
602 monitorForSoftwareAvailable(
603 asyncResp, req,
604 "/redfish/v1/UpdateService/Actions/UpdateService.SimpleUpdate", 600);
605
606 // TFTP can take up to 10 minutes depending on image size and
607 // connection speed. Return to caller as soon as the TFTP operation
608 // has been started. The callback above will ensure the activate
609 // is started once the download has completed
610 redfish::messages::success(asyncResp->res);
611
612 // Call TFTP service
613 crow::connections::systemBus->async_method_call(
614 [](const boost::system::error_code& ec) {
615 if (ec)
616 {
617 // messages::internalError(asyncResp->res);
618 cleanUp();
619 BMCWEB_LOG_DEBUG("error_code = {}", ec);
620 BMCWEB_LOG_DEBUG("error msg = {}", ec.message());
621 }
622 else
623 {
624 BMCWEB_LOG_DEBUG("Call to DownloaViaTFTP Success");
625 }
626 },
627 "xyz.openbmc_project.Software.Download",
628 "/xyz/openbmc_project/software", "xyz.openbmc_project.Common.TFTP",
Ed Tanous757178a2024-04-03 14:32:38 -0700629 "DownloadViaTFTP", path, host);
Ed Tanous6b0f66b2024-04-03 13:38:21 -0700630}
631
Ed Tanousf5139332024-04-03 13:25:04 -0700632inline void handleUpdateServiceSimpleUpdateAction(
633 crow::App& app, const crow::Request& req,
634 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
Andrew Geissler0554c982019-04-23 14:40:12 -0500635{
Ed Tanousf5139332024-04-03 13:25:04 -0700636 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
637 {
638 return;
639 }
640
641 std::optional<std::string> transferProtocol;
642 std::string imageURI;
643
644 BMCWEB_LOG_DEBUG("Enter UpdateService.SimpleUpdate doPost");
645
646 // User can pass in both TransferProtocol and ImageURI parameters or
647 // they can pass in just the ImageURI with the transfer protocol
648 // embedded within it.
649 // 1) TransferProtocol:TFTP ImageURI:1.1.1.1/myfile.bin
650 // 2) ImageURI:tftp://1.1.1.1/myfile.bin
651
652 if (!json_util::readJsonAction(req, asyncResp->res, "TransferProtocol",
653 transferProtocol, "ImageURI", imageURI))
654 {
655 BMCWEB_LOG_DEBUG("Missing TransferProtocol or ImageURI parameter");
656 return;
657 }
658
Ed Tanous757178a2024-04-03 14:32:38 -0700659 std::optional<boost::urls::url> url =
660 parseSimpleUpdateUrl(imageURI, transferProtocol, asyncResp->res);
661 if (!url)
Ed Tanousf5139332024-04-03 13:25:04 -0700662 {
663 return;
664 }
Ed Tanous757178a2024-04-03 14:32:38 -0700665 if (url->scheme() == "tftp")
666 {
667 doTftpUpdate(req, asyncResp, *url);
668 }
Ed Tanouse5cf7772024-04-03 13:45:31 -0700669 else if (url->scheme() == "https")
670 {
671 doHttpsUpdate(asyncResp, *url);
672 }
Ed Tanous757178a2024-04-03 14:32:38 -0700673 else
674 {
675 messages::actionParameterNotSupported(asyncResp->res, "ImageURI",
676 url->buffer());
677 return;
678 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700679
Ed Tanousf5139332024-04-03 13:25:04 -0700680 BMCWEB_LOG_DEBUG("Exit UpdateService.SimpleUpdate doPost");
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700681}
682
George Liu0ed80c82020-05-12 16:06:27 +0800683inline void uploadImageFile(crow::Response& res, std::string_view body)
684{
Ed Tanous2c6ffdb2023-06-28 11:28:38 -0700685 std::filesystem::path filepath("/tmp/images/" + bmcweb::getRandomUUID());
686
Ed Tanous62598e32023-07-17 17:06:25 -0700687 BMCWEB_LOG_DEBUG("Writing file to {}", filepath.string());
George Liu0ed80c82020-05-12 16:06:27 +0800688 std::ofstream out(filepath, std::ofstream::out | std::ofstream::binary |
689 std::ofstream::trunc);
690 // set the permission of the file to 640
Patrick Williams89492a12023-05-10 07:51:34 -0500691 std::filesystem::perms permission = std::filesystem::perms::owner_read |
692 std::filesystem::perms::group_read;
George Liu0ed80c82020-05-12 16:06:27 +0800693 std::filesystem::permissions(filepath, permission);
694 out << body;
695
696 if (out.bad())
697 {
698 messages::internalError(res);
699 cleanUp();
700 }
701}
702
Jagpal Singh Gillde0c9602024-04-29 17:30:21 -0700703// Convert the Request Apply Time to the D-Bus value
704inline bool convertApplyTime(crow::Response& res, const std::string& applyTime,
705 std::string& applyTimeNewVal)
706{
707 if (applyTime == "Immediate")
708 {
709 applyTimeNewVal =
710 "xyz.openbmc_project.Software.Update.ApplyTimes.Immediate";
711 }
712 else if (applyTime == "OnReset")
713 {
714 applyTimeNewVal =
715 "xyz.openbmc_project.Software.Update.ApplyTimes.OnReset";
716 }
717 else
718 {
719 BMCWEB_LOG_WARNING(
720 "ApplyTime value {} is not in the list of acceptable values",
721 applyTime);
722 messages::propertyValueNotInList(res, applyTime, "ApplyTime");
723 return false;
724 }
725 return true;
726}
727
George Liu0ed80c82020-05-12 16:06:27 +0800728inline void setApplyTime(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
729 const std::string& applyTime)
730{
731 std::string applyTimeNewVal;
732 if (applyTime == "Immediate")
733 {
734 applyTimeNewVal =
735 "xyz.openbmc_project.Software.ApplyTime.RequestedApplyTimes.Immediate";
736 }
737 else if (applyTime == "OnReset")
738 {
739 applyTimeNewVal =
740 "xyz.openbmc_project.Software.ApplyTime.RequestedApplyTimes.OnReset";
741 }
742 else
743 {
Ed Tanous62598e32023-07-17 17:06:25 -0700744 BMCWEB_LOG_INFO(
745 "ApplyTime value is not in the list of acceptable values");
George Liu0ed80c82020-05-12 16:06:27 +0800746 messages::propertyValueNotInList(asyncResp->res, applyTime,
747 "ApplyTime");
748 return;
749 }
750
Ed Tanousd02aad32024-02-13 14:43:34 -0800751 setDbusProperty(asyncResp, "xyz.openbmc_project.Settings",
752 sdbusplus::message::object_path(
753 "/xyz/openbmc_project/software/apply_time"),
754 "xyz.openbmc_project.Software.ApplyTime",
755 "RequestedApplyTime", "ApplyTime", applyTimeNewVal);
George Liu0ed80c82020-05-12 16:06:27 +0800756}
757
Jagpal Singh Gillef93eab2024-04-17 16:06:14 -0700758struct MultiPartUpdateParameters
George Liu0ed80c82020-05-12 16:06:27 +0800759{
Jagpal Singh Gillef93eab2024-04-17 16:06:14 -0700760 std::optional<std::string> applyTime;
761 std::string uploadData;
Jagpal Singh Gillde0c9602024-04-29 17:30:21 -0700762 std::vector<std::string> targets;
Jagpal Singh Gillef93eab2024-04-17 16:06:14 -0700763};
764
Jagpal Singh Gillde0c9602024-04-29 17:30:21 -0700765inline std::optional<std::string>
766 processUrl(boost::system::result<boost::urls::url_view>& url)
767{
768 if (!url)
769 {
770 return std::nullopt;
771 }
772 if (crow::utility::readUrlSegments(*url, "redfish", "v1", "Managers",
773 BMCWEB_REDFISH_MANAGER_URI_NAME))
774 {
775 return std::make_optional(std::string(BMCWEB_REDFISH_MANAGER_URI_NAME));
776 }
777 if constexpr (!BMCWEB_REDFISH_UPDATESERVICE_USE_DBUS)
778 {
779 return std::nullopt;
780 }
781 std::string firmwareId;
782 if (!crow::utility::readUrlSegments(*url, "redfish", "v1", "UpdateService",
783 "FirmwareInventory",
784 std::ref(firmwareId)))
785 {
786 return std::nullopt;
787 }
788
789 return std::make_optional(firmwareId);
790}
791
Jagpal Singh Gillef93eab2024-04-17 16:06:14 -0700792inline std::optional<MultiPartUpdateParameters>
793 extractMultipartUpdateParameters(
794 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
795 MultipartParser parser)
796{
797 MultiPartUpdateParameters multiRet;
798 for (FormPart& formpart : parser.mime_fields)
George Liu0ed80c82020-05-12 16:06:27 +0800799 {
800 boost::beast::http::fields::const_iterator it =
801 formpart.fields.find("Content-Disposition");
802 if (it == formpart.fields.end())
803 {
Ed Tanous62598e32023-07-17 17:06:25 -0700804 BMCWEB_LOG_ERROR("Couldn't find Content-Disposition");
Jagpal Singh Gillef93eab2024-04-17 16:06:14 -0700805 return std::nullopt;
George Liu0ed80c82020-05-12 16:06:27 +0800806 }
Ed Tanous62598e32023-07-17 17:06:25 -0700807 BMCWEB_LOG_INFO("Parsing value {}", it->value());
George Liu0ed80c82020-05-12 16:06:27 +0800808
809 // The construction parameters of param_list must start with `;`
810 size_t index = it->value().find(';');
811 if (index == std::string::npos)
812 {
813 continue;
814 }
815
Patrick Williams89492a12023-05-10 07:51:34 -0500816 for (const auto& param :
George Liu0ed80c82020-05-12 16:06:27 +0800817 boost::beast::http::param_list{it->value().substr(index)})
818 {
819 if (param.first != "name" || param.second.empty())
820 {
821 continue;
822 }
823
824 if (param.second == "UpdateParameters")
825 {
Jagpal Singh Gillef93eab2024-04-17 16:06:14 -0700826 std::vector<std::string> tempTargets;
George Liu0ed80c82020-05-12 16:06:27 +0800827 nlohmann::json content =
828 nlohmann::json::parse(formpart.content);
Ed Tanous7cb59f62022-05-05 11:48:31 -0700829 nlohmann::json::object_t* obj =
830 content.get_ptr<nlohmann::json::object_t*>();
831 if (obj == nullptr)
832 {
Jagpal Singh Gillef93eab2024-04-17 16:06:14 -0700833 messages::propertyValueTypeError(
834 asyncResp->res, formpart.content, "UpdateParameters");
835 return std::nullopt;
Ed Tanous7cb59f62022-05-05 11:48:31 -0700836 }
837
838 if (!json_util::readJsonObject(
Jagpal Singh Gillef93eab2024-04-17 16:06:14 -0700839 *obj, asyncResp->res, "Targets", tempTargets,
840 "@Redfish.OperationApplyTime", multiRet.applyTime))
George Liu0ed80c82020-05-12 16:06:27 +0800841 {
Jagpal Singh Gillef93eab2024-04-17 16:06:14 -0700842 return std::nullopt;
George Liu0ed80c82020-05-12 16:06:27 +0800843 }
Jagpal Singh Gillef93eab2024-04-17 16:06:14 -0700844
845 for (size_t urlIndex = 0; urlIndex < tempTargets.size();
846 urlIndex++)
George Liu0ed80c82020-05-12 16:06:27 +0800847 {
Jagpal Singh Gillef93eab2024-04-17 16:06:14 -0700848 const std::string& target = tempTargets[urlIndex];
849 boost::system::result<boost::urls::url_view> url =
850 boost::urls::parse_origin_form(target);
Jagpal Singh Gillde0c9602024-04-29 17:30:21 -0700851 auto res = processUrl(url);
852 if (!res.has_value())
Jagpal Singh Gillef93eab2024-04-17 16:06:14 -0700853 {
854 messages::propertyValueFormatError(
855 asyncResp->res, target,
856 std::format("Targets/{}", urlIndex));
857 return std::nullopt;
858 }
Jagpal Singh Gillde0c9602024-04-29 17:30:21 -0700859 multiRet.targets.emplace_back(res.value());
George Liu0ed80c82020-05-12 16:06:27 +0800860 }
Jagpal Singh Gillef93eab2024-04-17 16:06:14 -0700861 if (multiRet.targets.size() != 1)
George Liu0ed80c82020-05-12 16:06:27 +0800862 {
Jagpal Singh Gillef93eab2024-04-17 16:06:14 -0700863 messages::propertyValueFormatError(
864 asyncResp->res, multiRet.targets, "Targets");
865 return std::nullopt;
George Liu0ed80c82020-05-12 16:06:27 +0800866 }
George Liu0ed80c82020-05-12 16:06:27 +0800867 }
868 else if (param.second == "UpdateFile")
869 {
Jagpal Singh Gillef93eab2024-04-17 16:06:14 -0700870 multiRet.uploadData = std::move(formpart.content);
George Liu0ed80c82020-05-12 16:06:27 +0800871 }
872 }
873 }
874
Jagpal Singh Gillef93eab2024-04-17 16:06:14 -0700875 if (multiRet.uploadData.empty())
George Liu0ed80c82020-05-12 16:06:27 +0800876 {
Ed Tanous62598e32023-07-17 17:06:25 -0700877 BMCWEB_LOG_ERROR("Upload data is NULL");
George Liu0ed80c82020-05-12 16:06:27 +0800878 messages::propertyMissing(asyncResp->res, "UpdateFile");
Jagpal Singh Gillef93eab2024-04-17 16:06:14 -0700879 return std::nullopt;
880 }
881 if (multiRet.targets.empty())
882 {
883 messages::propertyMissing(asyncResp->res, "Targets");
884 return std::nullopt;
885 }
886 return multiRet;
887}
888
889inline void
Jagpal Singh Gillde0c9602024-04-29 17:30:21 -0700890 handleStartUpdate(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
891 task::Payload payload, const std::string& objectPath,
892 const boost::system::error_code& ec,
893 const sdbusplus::message::object_path& retPath)
894{
895 if (ec)
896 {
897 BMCWEB_LOG_ERROR("error_code = {}", ec);
898 BMCWEB_LOG_ERROR("error msg = {}", ec.message());
899 messages::internalError(asyncResp->res);
900 return;
901 }
902
903 BMCWEB_LOG_INFO("Call to StartUpdate Success, retPath = {}", retPath.str);
904 createTask(asyncResp, std::move(payload), objectPath);
905}
906
907inline void startUpdate(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
908 task::Payload payload,
909 const MemoryFileDescriptor& memfd,
910 const std::string& applyTime,
911 const std::string& objectPath,
912 const std::string& serviceName)
913{
914 crow::connections::systemBus->async_method_call(
915 [asyncResp, payload = std::move(payload),
916 objectPath](const boost::system::error_code& ec1,
917 const sdbusplus::message::object_path& retPath) mutable {
918 handleStartUpdate(asyncResp, std::move(payload), objectPath, ec1,
919 retPath);
920 },
921 serviceName, objectPath, "xyz.openbmc_project.Software.Update",
922 "StartUpdate", sdbusplus::message::unix_fd(memfd.fd), applyTime);
923}
924
925inline void getAssociatedUpdateInterface(
926 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, task::Payload payload,
927 const MemoryFileDescriptor& memfd, const std::string& applyTime,
928 const boost::system::error_code& ec,
929 const dbus::utility::MapperGetSubTreeResponse& subtree)
930{
931 if (ec)
932 {
933 BMCWEB_LOG_ERROR("error_code = {}", ec);
934 BMCWEB_LOG_ERROR("error msg = {}", ec.message());
935 messages::internalError(asyncResp->res);
936 return;
937 }
938 BMCWEB_LOG_DEBUG("Found {} startUpdate subtree paths", subtree.size());
939
940 if (subtree.size() > 1)
941 {
942 BMCWEB_LOG_ERROR("Found more than one startUpdate subtree paths");
943 messages::internalError(asyncResp->res);
944 return;
945 }
946
947 auto objectPath = subtree[0].first;
948 auto serviceName = subtree[0].second[0].first;
949
950 BMCWEB_LOG_DEBUG("Found objectPath {} serviceName {}", objectPath,
951 serviceName);
952 startUpdate(asyncResp, std::move(payload), memfd, applyTime, objectPath,
953 serviceName);
954}
955
956inline void
957 getSwInfo(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
958 task::Payload payload, MemoryFileDescriptor memfd,
959 const std::string& applyTime, const std::string& target,
960 const boost::system::error_code& ec,
961 const dbus::utility::MapperGetSubTreePathsResponse& subtree)
962{
963 using SwInfoMap =
964 std::unordered_map<std::string, sdbusplus::message::object_path>;
965 SwInfoMap swInfoMap;
966
967 if (ec)
968 {
969 BMCWEB_LOG_ERROR("error_code = {}", ec);
970 BMCWEB_LOG_ERROR("error msg = {}", ec.message());
971 messages::internalError(asyncResp->res);
972 return;
973 }
974 BMCWEB_LOG_DEBUG("Found {} software version paths", subtree.size());
975
976 for (const auto& objectPath : subtree)
977 {
978 sdbusplus::message::object_path path(objectPath);
979 std::string swId = path.filename();
980 swInfoMap.emplace(swId, path);
981 }
982
983 auto swEntry = swInfoMap.find(target);
984 if (swEntry == swInfoMap.end())
985 {
986 BMCWEB_LOG_WARNING("No valid DBus path for Target URI {}", target);
987 messages::propertyValueFormatError(asyncResp->res, target, "Targets");
988 return;
989 }
990
991 BMCWEB_LOG_DEBUG("Found software version path {}", swEntry->second.str);
992
993 sdbusplus::message::object_path swObjectPath = swEntry->second /
994 "software_version";
995 constexpr std::array<std::string_view, 1> interfaces = {
996 "xyz.openbmc_project.Software.Update"};
997 dbus::utility::getAssociatedSubTree(
998 swObjectPath,
999 sdbusplus::message::object_path("/xyz/openbmc_project/software"), 0,
1000 interfaces,
1001 [asyncResp, payload = std::move(payload), memfd = std::move(memfd),
1002 applyTime](
1003 const boost::system::error_code& ec1,
1004 const dbus::utility::MapperGetSubTreeResponse& subtree1) mutable {
1005 getAssociatedUpdateInterface(asyncResp, std::move(payload), memfd,
1006 applyTime, ec1, subtree1);
1007 });
1008}
1009
1010inline void
1011 processUpdateRequest(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1012 const crow::Request& req, std::string_view body,
1013 const std::string& applyTime,
1014 std::vector<std::string>& targets)
1015{
1016 std::string applyTimeNewVal;
1017
1018 if (!convertApplyTime(asyncResp->res, applyTime, applyTimeNewVal))
1019 {
1020 return;
1021 }
1022
1023 MemoryFileDescriptor memfd("update-image");
1024 if (memfd.fd == -1)
1025 {
1026 BMCWEB_LOG_ERROR("Failed to create image memfd");
1027 messages::internalError(asyncResp->res);
1028 return;
1029 }
1030 if (write(memfd.fd, body.data(), body.length()) !=
1031 static_cast<ssize_t>(body.length()))
1032 {
1033 BMCWEB_LOG_ERROR("Failed to write to image memfd");
1034 messages::internalError(asyncResp->res);
1035 return;
1036 }
1037 if (!memfd.rewind())
1038 {
1039 messages::internalError(asyncResp->res);
1040 return;
1041 }
1042
1043 task::Payload payload(req);
1044 if (!targets.empty() && targets[0] == BMCWEB_REDFISH_MANAGER_URI_NAME)
1045 {
1046 startUpdate(asyncResp, std::move(payload), memfd, applyTimeNewVal,
1047 "/xyz/openbmc_project/software/bmc",
1048 "xyz.openbmc_project.Software.Manager");
1049 }
1050 else
1051 {
1052 constexpr std::array<std::string_view, 1> interfaces = {
1053 "xyz.openbmc_project.Software.Version"};
1054 dbus::utility::getSubTreePaths(
1055 "/xyz/openbmc_project/software", 1, interfaces,
1056 [asyncResp, payload = std::move(payload), memfd = std::move(memfd),
1057 applyTimeNewVal,
1058 targets](const boost::system::error_code& ec,
1059 const dbus::utility::MapperGetSubTreePathsResponse&
1060 subtree) mutable {
1061 getSwInfo(asyncResp, std::move(payload), std::move(memfd),
1062 applyTimeNewVal, targets[0], ec, subtree);
1063 });
1064 }
1065}
1066
1067inline void
Jagpal Singh Gillef93eab2024-04-17 16:06:14 -07001068 updateMultipartContext(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1069 const crow::Request& req, MultipartParser&& parser)
1070{
1071 std::optional<MultiPartUpdateParameters> multipart =
1072 extractMultipartUpdateParameters(asyncResp, std::move(parser));
1073 if (!multipart)
1074 {
George Liu0ed80c82020-05-12 16:06:27 +08001075 return;
1076 }
Jagpal Singh Gillef93eab2024-04-17 16:06:14 -07001077 if (!multipart->applyTime)
George Liu0ed80c82020-05-12 16:06:27 +08001078 {
Jagpal Singh Gillef93eab2024-04-17 16:06:14 -07001079 multipart->applyTime = "OnReset";
George Liu0ed80c82020-05-12 16:06:27 +08001080 }
1081
Jagpal Singh Gillde0c9602024-04-29 17:30:21 -07001082 if constexpr (BMCWEB_REDFISH_UPDATESERVICE_USE_DBUS)
1083 {
1084 processUpdateRequest(asyncResp, req, multipart->uploadData,
1085 *multipart->applyTime, multipart->targets);
1086 }
1087 else
1088 {
1089 setApplyTime(asyncResp, *multipart->applyTime);
George Liu0ed80c82020-05-12 16:06:27 +08001090
Jagpal Singh Gillde0c9602024-04-29 17:30:21 -07001091 // Setup callback for when new software detected
1092 monitorForSoftwareAvailable(asyncResp, req,
1093 "/redfish/v1/UpdateService");
Ed Tanous6b54e4e2024-04-10 08:58:48 -07001094
Jagpal Singh Gillde0c9602024-04-29 17:30:21 -07001095 uploadImageFile(asyncResp->res, multipart->uploadData);
1096 }
George Liu0ed80c82020-05-12 16:06:27 +08001097}
1098
Ed Tanousc2051d12022-05-11 12:21:55 -07001099inline void
1100 handleUpdateServicePost(App& app, const crow::Request& req,
1101 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
1102{
Carson Labrado3ba00072022-06-06 19:40:56 +00001103 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanousc2051d12022-05-11 12:21:55 -07001104 {
1105 return;
1106 }
Ninad Palsuleb33a4322023-06-09 09:19:18 -05001107 std::string_view contentType = req.getHeaderValue("Content-Type");
Ed Tanousc2051d12022-05-11 12:21:55 -07001108
Ed Tanous62598e32023-07-17 17:06:25 -07001109 BMCWEB_LOG_DEBUG("doPost: contentType={}", contentType);
Ed Tanousc2051d12022-05-11 12:21:55 -07001110
Ninad Palsuleb33a4322023-06-09 09:19:18 -05001111 // Make sure that content type is application/octet-stream or
1112 // multipart/form-data
Ed Tanous18f8f602023-07-18 10:07:23 -07001113 if (bmcweb::asciiIEquals(contentType, "application/octet-stream"))
George Liu0ed80c82020-05-12 16:06:27 +08001114 {
Ninad Palsuleb33a4322023-06-09 09:19:18 -05001115 // Setup callback for when new software detected
1116 monitorForSoftwareAvailable(asyncResp, req,
1117 "/redfish/v1/UpdateService");
1118
George Liu0ed80c82020-05-12 16:06:27 +08001119 uploadImageFile(asyncResp->res, req.body());
George Liu0ed80c82020-05-12 16:06:27 +08001120 }
Ninad Palsuleb33a4322023-06-09 09:19:18 -05001121 else if (contentType.starts_with("multipart/form-data"))
George Liu0ed80c82020-05-12 16:06:27 +08001122 {
Ninad Palsuleb33a4322023-06-09 09:19:18 -05001123 MultipartParser parser;
1124
Ninad Palsuleb33a4322023-06-09 09:19:18 -05001125 ParserError ec = parser.parse(req);
1126 if (ec != ParserError::PARSER_SUCCESS)
1127 {
1128 // handle error
Ed Tanous62598e32023-07-17 17:06:25 -07001129 BMCWEB_LOG_ERROR("MIME parse failed, ec : {}",
1130 static_cast<int>(ec));
Ninad Palsuleb33a4322023-06-09 09:19:18 -05001131 messages::internalError(asyncResp->res);
1132 return;
1133 }
Ed Tanous6b54e4e2024-04-10 08:58:48 -07001134
Jagpal Singh Gillef93eab2024-04-17 16:06:14 -07001135 updateMultipartContext(asyncResp, req, std::move(parser));
George Liu0ed80c82020-05-12 16:06:27 +08001136 }
Ninad Palsuleb33a4322023-06-09 09:19:18 -05001137 else
1138 {
Ed Tanous62598e32023-07-17 17:06:25 -07001139 BMCWEB_LOG_DEBUG("Bad content type specified:{}", contentType);
Ninad Palsuleb33a4322023-06-09 09:19:18 -05001140 asyncResp->res.result(boost::beast::http::status::bad_request);
1141 }
Ed Tanousc2051d12022-05-11 12:21:55 -07001142}
1143
Ed Tanousf5139332024-04-03 13:25:04 -07001144inline void
1145 handleUpdateServiceGet(App& app, const crow::Request& req,
1146 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001147{
Ed Tanousf5139332024-04-03 13:25:04 -07001148 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1149 {
1150 return;
1151 }
1152 asyncResp->res.jsonValue["@odata.type"] =
1153 "#UpdateService.v1_11_1.UpdateService";
1154 asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/UpdateService";
1155 asyncResp->res.jsonValue["Id"] = "UpdateService";
1156 asyncResp->res.jsonValue["Description"] = "Service for Software Update";
1157 asyncResp->res.jsonValue["Name"] = "Update Service";
Ed Tanous4dc23f32022-05-11 11:32:19 -07001158
Ed Tanousf5139332024-04-03 13:25:04 -07001159 asyncResp->res.jsonValue["HttpPushUri"] =
1160 "/redfish/v1/UpdateService/update";
1161 asyncResp->res.jsonValue["MultipartHttpPushUri"] =
1162 "/redfish/v1/UpdateService/update";
Ed Tanous4dc23f32022-05-11 11:32:19 -07001163
Ed Tanousf5139332024-04-03 13:25:04 -07001164 // UpdateService cannot be disabled
1165 asyncResp->res.jsonValue["ServiceEnabled"] = true;
1166 asyncResp->res.jsonValue["FirmwareInventory"]["@odata.id"] =
1167 "/redfish/v1/UpdateService/FirmwareInventory";
1168 // Get the MaxImageSizeBytes
Ed Tanous25b54db2024-04-17 15:40:31 -07001169 asyncResp->res.jsonValue["MaxImageSizeBytes"] = BMCWEB_HTTP_BODY_LIMIT *
Ed Tanousf5139332024-04-03 13:25:04 -07001170 1024 * 1024;
Tejas Patild61e5192021-06-04 15:49:35 +05301171
Ed Tanousf5139332024-04-03 13:25:04 -07001172 // Update Actions object.
1173 nlohmann::json& updateSvcSimpleUpdate =
1174 asyncResp->res.jsonValue["Actions"]["#UpdateService.SimpleUpdate"];
1175 updateSvcSimpleUpdate["target"] =
1176 "/redfish/v1/UpdateService/Actions/UpdateService.SimpleUpdate";
Ed Tanous757178a2024-04-03 14:32:38 -07001177
1178 nlohmann::json::array_t allowed;
Ed Tanouse5cf7772024-04-03 13:45:31 -07001179 allowed.emplace_back(update_service::TransferProtocolType::HTTPS);
Ed Tanous757178a2024-04-03 14:32:38 -07001180
Ed Tanous25b54db2024-04-17 15:40:31 -07001181 if constexpr (BMCWEB_INSECURE_PUSH_STYLE_NOTIFICATION)
1182 {
1183 allowed.emplace_back(update_service::TransferProtocolType::TFTP);
1184 }
Ed Tanous757178a2024-04-03 14:32:38 -07001185
1186 updateSvcSimpleUpdate["TransferProtocol@Redfish.AllowableValues"] =
1187 std::move(allowed);
1188
Ed Tanousf5139332024-04-03 13:25:04 -07001189 // Get the current ApplyTime value
1190 sdbusplus::asio::getProperty<std::string>(
1191 *crow::connections::systemBus, "xyz.openbmc_project.Settings",
1192 "/xyz/openbmc_project/software/apply_time",
1193 "xyz.openbmc_project.Software.ApplyTime", "RequestedApplyTime",
1194 [asyncResp](const boost::system::error_code& ec,
1195 const std::string& applyTime) {
1196 if (ec)
Ed Tanous002d39b2022-05-31 08:59:27 -07001197 {
Ed Tanousf5139332024-04-03 13:25:04 -07001198 BMCWEB_LOG_DEBUG("DBUS response error {}", ec);
1199 messages::internalError(asyncResp->res);
Ed Tanous002d39b2022-05-31 08:59:27 -07001200 return;
1201 }
1202
Ed Tanousf5139332024-04-03 13:25:04 -07001203 // Store the ApplyTime Value
1204 if (applyTime == "xyz.openbmc_project.Software.ApplyTime."
1205 "RequestedApplyTimes.Immediate")
Ed Tanous002d39b2022-05-31 08:59:27 -07001206 {
Ed Tanousf5139332024-04-03 13:25:04 -07001207 asyncResp->res.jsonValue["HttpPushUriOptions"]
1208 ["HttpPushUriApplyTime"]["ApplyTime"] =
1209 "Immediate";
1210 }
1211 else if (applyTime == "xyz.openbmc_project.Software.ApplyTime."
1212 "RequestedApplyTimes.OnReset")
1213 {
1214 asyncResp->res.jsonValue["HttpPushUriOptions"]
1215 ["HttpPushUriApplyTime"]["ApplyTime"] =
1216 "OnReset";
Ed Tanous002d39b2022-05-31 08:59:27 -07001217 }
Patrick Williams5a39f772023-10-20 11:20:21 -05001218 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001219}
1220
Ed Tanousf5139332024-04-03 13:25:04 -07001221inline void handleUpdateServicePatch(
1222 App& app, const crow::Request& req,
1223 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001224{
Ed Tanousf5139332024-04-03 13:25:04 -07001225 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1226 {
1227 return;
1228 }
1229 BMCWEB_LOG_DEBUG("doPatch...");
Ed Tanous002d39b2022-05-31 08:59:27 -07001230
Ed Tanousf5139332024-04-03 13:25:04 -07001231 std::optional<std::string> applyTime;
1232 if (!json_util::readJsonPatch(
1233 req, asyncResp->res,
1234 "HttpPushUriOptions/HttpPushUriApplyTime/ApplyTime", applyTime))
1235 {
1236 return;
1237 }
1238
1239 if (applyTime)
1240 {
1241 setApplyTime(asyncResp, *applyTime);
1242 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001243}
Ed Tanousf5139332024-04-03 13:25:04 -07001244
1245inline void handleUpdateServiceFirmwareInventoryCollectionGet(
1246 App& app, const crow::Request& req,
1247 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
1248{
1249 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1250 {
1251 return;
1252 }
1253 asyncResp->res.jsonValue["@odata.type"] =
1254 "#SoftwareInventoryCollection.SoftwareInventoryCollection";
1255 asyncResp->res.jsonValue["@odata.id"] =
1256 "/redfish/v1/UpdateService/FirmwareInventory";
1257 asyncResp->res.jsonValue["Name"] = "Software Inventory Collection";
1258 const std::array<const std::string_view, 1> iface = {
1259 "xyz.openbmc_project.Software.Version"};
1260
1261 redfish::collection_util::getCollectionMembers(
1262 asyncResp,
1263 boost::urls::url("/redfish/v1/UpdateService/FirmwareInventory"), iface,
1264 "/xyz/openbmc_project/software");
1265}
1266
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001267/* Fill related item links (i.e. bmc, bios) in for inventory */
Ed Tanousf5139332024-04-03 13:25:04 -07001268inline void getRelatedItems(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1269 const std::string& purpose)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001270{
Willy Tueee00132022-06-14 14:53:17 -07001271 if (purpose == sw_util::bmcPurpose)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001272 {
Ed Tanousac106bf2023-06-07 09:24:59 -07001273 nlohmann::json& relatedItem = asyncResp->res.jsonValue["RelatedItem"];
Ed Tanous14766872022-03-15 10:44:42 -07001274 nlohmann::json::object_t item;
Ed Tanous253f11b2024-05-16 09:38:31 -07001275 item["@odata.id"] = boost::urls::format(
1276 "/redfish/v1/Managers/{}", BMCWEB_REDFISH_MANAGER_URI_NAME);
Patrick Williamsb2ba3072023-05-12 10:27:39 -05001277 relatedItem.emplace_back(std::move(item));
Ed Tanousac106bf2023-06-07 09:24:59 -07001278 asyncResp->res.jsonValue["RelatedItem@odata.count"] =
1279 relatedItem.size();
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001280 }
Willy Tueee00132022-06-14 14:53:17 -07001281 else if (purpose == sw_util::biosPurpose)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001282 {
Ed Tanousac106bf2023-06-07 09:24:59 -07001283 nlohmann::json& relatedItem = asyncResp->res.jsonValue["RelatedItem"];
Ed Tanous14766872022-03-15 10:44:42 -07001284 nlohmann::json::object_t item;
Ed Tanous253f11b2024-05-16 09:38:31 -07001285 item["@odata.id"] = std::format("/redfish/v1/Systems/{}/Bios",
1286 BMCWEB_REDFISH_SYSTEM_URI_NAME);
Patrick Williamsb2ba3072023-05-12 10:27:39 -05001287 relatedItem.emplace_back(std::move(item));
Ed Tanousac106bf2023-06-07 09:24:59 -07001288 asyncResp->res.jsonValue["RelatedItem@odata.count"] =
1289 relatedItem.size();
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001290 }
1291 else
1292 {
Carson Labradobf2dded2023-08-10 00:37:06 +00001293 BMCWEB_LOG_DEBUG("Unknown software purpose {}", purpose);
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001294 }
1295}
1296
Willy Tuaf246602022-06-14 15:51:53 -07001297inline void
1298 getSoftwareVersion(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1299 const std::string& service, const std::string& path,
1300 const std::string& swId)
1301{
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +02001302 sdbusplus::asio::getAllProperties(
1303 *crow::connections::systemBus, service, path,
1304 "xyz.openbmc_project.Software.Version",
Willy Tuaf246602022-06-14 15:51:53 -07001305 [asyncResp,
Ed Tanous8b242752023-06-27 17:17:13 -07001306 swId](const boost::system::error_code& ec,
Willy Tuaf246602022-06-14 15:51:53 -07001307 const dbus::utility::DBusPropertiesMap& propertiesList) {
Ed Tanous8b242752023-06-27 17:17:13 -07001308 if (ec)
Willy Tuaf246602022-06-14 15:51:53 -07001309 {
1310 messages::internalError(asyncResp->res);
1311 return;
1312 }
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +02001313
Willy Tuaf246602022-06-14 15:51:53 -07001314 const std::string* swInvPurpose = nullptr;
1315 const std::string* version = nullptr;
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +02001316
1317 const bool success = sdbusplus::unpackPropertiesNoThrow(
1318 dbus_utils::UnpackErrorPrinter(), propertiesList, "Purpose",
1319 swInvPurpose, "Version", version);
1320
1321 if (!success)
Willy Tuaf246602022-06-14 15:51:53 -07001322 {
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +02001323 messages::internalError(asyncResp->res);
1324 return;
Willy Tuaf246602022-06-14 15:51:53 -07001325 }
1326
1327 if (swInvPurpose == nullptr)
1328 {
Ed Tanous62598e32023-07-17 17:06:25 -07001329 BMCWEB_LOG_DEBUG("Can't find property \"Purpose\"!");
Willy Tuaf246602022-06-14 15:51:53 -07001330 messages::internalError(asyncResp->res);
1331 return;
1332 }
1333
Ed Tanous62598e32023-07-17 17:06:25 -07001334 BMCWEB_LOG_DEBUG("swInvPurpose = {}", *swInvPurpose);
Willy Tuaf246602022-06-14 15:51:53 -07001335
1336 if (version == nullptr)
1337 {
Ed Tanous62598e32023-07-17 17:06:25 -07001338 BMCWEB_LOG_DEBUG("Can't find property \"Version\"!");
Willy Tuaf246602022-06-14 15:51:53 -07001339
1340 messages::internalError(asyncResp->res);
1341
1342 return;
1343 }
1344 asyncResp->res.jsonValue["Version"] = *version;
1345 asyncResp->res.jsonValue["Id"] = swId;
1346
1347 // swInvPurpose is of format:
1348 // xyz.openbmc_project.Software.Version.VersionPurpose.ABC
1349 // Translate this to "ABC image"
1350 size_t endDesc = swInvPurpose->rfind('.');
1351 if (endDesc == std::string::npos)
1352 {
1353 messages::internalError(asyncResp->res);
1354 return;
1355 }
1356 endDesc++;
1357 if (endDesc >= swInvPurpose->size())
1358 {
1359 messages::internalError(asyncResp->res);
1360 return;
1361 }
1362
1363 std::string formatDesc = swInvPurpose->substr(endDesc);
1364 asyncResp->res.jsonValue["Description"] = formatDesc + " image";
1365 getRelatedItems(asyncResp, *swInvPurpose);
Patrick Williams5a39f772023-10-20 11:20:21 -05001366 });
Willy Tuaf246602022-06-14 15:51:53 -07001367}
1368
Ed Tanousf5139332024-04-03 13:25:04 -07001369inline void handleUpdateServiceFirmwareInventoryGet(
1370 App& app, const crow::Request& req,
1371 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1372 const std::string& param)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001373{
Ed Tanousf5139332024-04-03 13:25:04 -07001374 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1375 {
1376 return;
1377 }
1378 std::shared_ptr<std::string> swId = std::make_shared<std::string>(param);
1379
1380 asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
1381 "/redfish/v1/UpdateService/FirmwareInventory/{}", *swId);
1382
1383 constexpr std::array<std::string_view, 1> interfaces = {
1384 "xyz.openbmc_project.Software.Version"};
1385 dbus::utility::getSubTree(
1386 "/", 0, interfaces,
1387 [asyncResp,
1388 swId](const boost::system::error_code& ec,
1389 const dbus::utility::MapperGetSubTreeResponse& subtree) {
1390 BMCWEB_LOG_DEBUG("doGet callback...");
1391 if (ec)
Ed Tanous002d39b2022-05-31 08:59:27 -07001392 {
Ed Tanousf5139332024-04-03 13:25:04 -07001393 messages::internalError(asyncResp->res);
Ed Tanous002d39b2022-05-31 08:59:27 -07001394 return;
1395 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001396
Ed Tanousf5139332024-04-03 13:25:04 -07001397 // Ensure we find our input swId, otherwise return an error
1398 bool found = false;
1399 for (const std::pair<
1400 std::string,
1401 std::vector<std::pair<std::string, std::vector<std::string>>>>&
1402 obj : subtree)
1403 {
1404 if (!obj.first.ends_with(*swId))
Ed Tanous45ca1b82022-03-25 13:07:27 -07001405 {
Ed Tanousf5139332024-04-03 13:25:04 -07001406 continue;
Ed Tanous45ca1b82022-03-25 13:07:27 -07001407 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001408
Ed Tanousf5139332024-04-03 13:25:04 -07001409 if (obj.second.empty())
Ed Tanous002d39b2022-05-31 08:59:27 -07001410 {
Ed Tanousf5139332024-04-03 13:25:04 -07001411 continue;
Ed Tanous002d39b2022-05-31 08:59:27 -07001412 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001413
Ed Tanousf5139332024-04-03 13:25:04 -07001414 found = true;
1415 sw_util::getSwStatus(asyncResp, swId, obj.second[0].first);
1416 getSoftwareVersion(asyncResp, obj.second[0].first, obj.first,
1417 *swId);
1418 }
1419 if (!found)
1420 {
1421 BMCWEB_LOG_WARNING("Input swID {} not found!", *swId);
1422 messages::resourceMissingAtURI(
1423 asyncResp->res,
1424 boost::urls::format(
1425 "/redfish/v1/UpdateService/FirmwareInventory/{}", *swId));
1426 return;
1427 }
1428 asyncResp->res.jsonValue["@odata.type"] =
1429 "#SoftwareInventory.v1_1_0.SoftwareInventory";
1430 asyncResp->res.jsonValue["Name"] = "Software Inventory";
1431 asyncResp->res.jsonValue["Status"]["HealthRollup"] = "OK";
1432
1433 asyncResp->res.jsonValue["Updateable"] = false;
1434 sw_util::getSwUpdatableStatus(asyncResp, swId);
Patrick Williams5a39f772023-10-20 11:20:21 -05001435 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001436}
Ed Tanous1abe55e2018-09-05 08:30:59 -07001437
Ed Tanousf5139332024-04-03 13:25:04 -07001438inline void requestRoutesUpdateService(App& app)
1439{
1440 BMCWEB_ROUTE(
1441 app, "/redfish/v1/UpdateService/Actions/UpdateService.SimpleUpdate/")
1442 .privileges(redfish::privileges::postUpdateService)
1443 .methods(boost::beast::http::verb::post)(std::bind_front(
1444 handleUpdateServiceSimpleUpdateAction, std::ref(app)));
1445
1446 BMCWEB_ROUTE(app, "/redfish/v1/UpdateService/FirmwareInventory/<str>/")
1447 .privileges(redfish::privileges::getSoftwareInventory)
1448 .methods(boost::beast::http::verb::get)(std::bind_front(
1449 handleUpdateServiceFirmwareInventoryGet, std::ref(app)));
1450
1451 BMCWEB_ROUTE(app, "/redfish/v1/UpdateService/")
1452 .privileges(redfish::privileges::getUpdateService)
1453 .methods(boost::beast::http::verb::get)(
1454 std::bind_front(handleUpdateServiceGet, std::ref(app)));
1455
1456 BMCWEB_ROUTE(app, "/redfish/v1/UpdateService/")
1457 .privileges(redfish::privileges::patchUpdateService)
1458 .methods(boost::beast::http::verb::patch)(
1459 std::bind_front(handleUpdateServicePatch, std::ref(app)));
1460
1461 BMCWEB_ROUTE(app, "/redfish/v1/UpdateService/update/")
1462 .privileges(redfish::privileges::postUpdateService)
1463 .methods(boost::beast::http::verb::post)(
1464 std::bind_front(handleUpdateServicePost, std::ref(app)));
1465
1466 BMCWEB_ROUTE(app, "/redfish/v1/UpdateService/FirmwareInventory/")
1467 .privileges(redfish::privileges::getSoftwareInventoryCollection)
1468 .methods(boost::beast::http::verb::get)(std::bind_front(
1469 handleUpdateServiceFirmwareInventoryCollectionGet, std::ref(app)));
1470}
1471
Ed Tanous1abe55e2018-09-05 08:30:59 -07001472} // namespace redfish