summaryrefslogtreecommitdiff
path: root/redfish-core/lib/update_service.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'redfish-core/lib/update_service.hpp')
-rw-r--r--redfish-core/lib/update_service.hpp660
1 files changed, 492 insertions, 168 deletions
diff --git a/redfish-core/lib/update_service.hpp b/redfish-core/lib/update_service.hpp
index 6895cb4949..23b5a3cad8 100644
--- a/redfish-core/lib/update_service.hpp
+++ b/redfish-core/lib/update_service.hpp
@@ -32,6 +32,8 @@
#include "utils/json_utils.hpp"
#include "utils/sw_utils.hpp"
+#include <sys/mman.h>
+
#include <boost/system/error_code.hpp>
#include <boost/url/format.hpp>
#include <sdbusplus/asio/property.hpp>
@@ -39,10 +41,16 @@
#include <sdbusplus/unpack_properties.hpp>
#include <array>
+#include <cstddef>
#include <filesystem>
+#include <functional>
+#include <iterator>
+#include <memory>
#include <optional>
#include <string>
#include <string_view>
+#include <unordered_map>
+#include <vector>
namespace redfish
{
@@ -59,6 +67,41 @@ static bool fwUpdateInProgress = false;
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
static std::unique_ptr<boost::asio::steady_timer> fwAvailableTimer;
+struct MemoryFileDescriptor
+{
+ int fd = -1;
+
+ explicit MemoryFileDescriptor(const std::string& filename) :
+ fd(memfd_create(filename.c_str(), 0))
+ {}
+
+ MemoryFileDescriptor(const MemoryFileDescriptor&) = default;
+ MemoryFileDescriptor(MemoryFileDescriptor&& other) noexcept : fd(other.fd)
+ {
+ other.fd = -1;
+ }
+ MemoryFileDescriptor& operator=(const MemoryFileDescriptor&) = delete;
+ MemoryFileDescriptor& operator=(MemoryFileDescriptor&&) = default;
+
+ ~MemoryFileDescriptor()
+ {
+ if (fd != -1)
+ {
+ close(fd);
+ }
+ }
+
+ bool rewind() const
+ {
+ if (lseek(fd, 0, SEEK_SET) == -1)
+ {
+ BMCWEB_LOG_ERROR("Failed to seek to beginning of image memfd");
+ return false;
+ }
+ return true;
+ }
+};
+
inline void cleanUp()
{
fwUpdateInProgress = false;
@@ -83,6 +126,121 @@ inline void activateImage(const std::string& objPath,
});
}
+inline bool handleCreateTask(const boost::system::error_code& ec2,
+ sdbusplus::message_t& msg,
+ const std::shared_ptr<task::TaskData>& taskData)
+{
+ if (ec2)
+ {
+ return task::completed;
+ }
+
+ std::string iface;
+ dbus::utility::DBusPropertiesMap values;
+
+ std::string index = std::to_string(taskData->index);
+ msg.read(iface, values);
+
+ if (iface == "xyz.openbmc_project.Software.Activation")
+ {
+ const std::string* state = nullptr;
+ for (const auto& property : values)
+ {
+ if (property.first == "Activation")
+ {
+ state = std::get_if<std::string>(&property.second);
+ if (state == nullptr)
+ {
+ taskData->messages.emplace_back(messages::internalError());
+ return task::completed;
+ }
+ }
+ }
+
+ if (state == nullptr)
+ {
+ return !task::completed;
+ }
+
+ if (state->ends_with("Invalid") || state->ends_with("Failed"))
+ {
+ taskData->state = "Exception";
+ taskData->status = "Warning";
+ taskData->messages.emplace_back(messages::taskAborted(index));
+ return task::completed;
+ }
+
+ if (state->ends_with("Staged"))
+ {
+ taskData->state = "Stopping";
+ taskData->messages.emplace_back(messages::taskPaused(index));
+
+ // its staged, set a long timer to
+ // allow them time to complete the
+ // update (probably cycle the
+ // system) if this expires then
+ // task will be canceled
+ taskData->extendTimer(std::chrono::hours(5));
+ return !task::completed;
+ }
+
+ if (state->ends_with("Active"))
+ {
+ taskData->messages.emplace_back(messages::taskCompletedOK(index));
+ taskData->state = "Completed";
+ return task::completed;
+ }
+ }
+ else if (iface == "xyz.openbmc_project.Software.ActivationProgress")
+ {
+ const uint8_t* progress = nullptr;
+ for (const auto& property : values)
+ {
+ if (property.first == "Progress")
+ {
+ progress = std::get_if<uint8_t>(&property.second);
+ if (progress == nullptr)
+ {
+ taskData->messages.emplace_back(messages::internalError());
+ return task::completed;
+ }
+ }
+ }
+
+ if (progress == nullptr)
+ {
+ return !task::completed;
+ }
+ taskData->percentComplete = *progress;
+ taskData->messages.emplace_back(
+ messages::taskProgressChanged(index, *progress));
+
+ // if we're getting status updates it's
+ // still alive, update timer
+ taskData->extendTimer(std::chrono::minutes(5));
+ }
+
+ // as firmware update often results in a
+ // reboot, the task may never "complete"
+ // unless it is an error
+
+ return !task::completed;
+}
+
+inline void createTask(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
+ task::Payload&& payload,
+ const sdbusplus::message::object_path& objPath)
+{
+ std::shared_ptr<task::TaskData> task = task::TaskData::createTask(
+ std::bind_front(handleCreateTask),
+ "type='signal',interface='org.freedesktop.DBus.Properties',"
+ "member='PropertiesChanged',path='" +
+ objPath.str + "'");
+ task->startTimer(std::chrono::minutes(5));
+ task->populateResp(asyncResp->res);
+ task->payload.emplace(std::move(payload));
+}
+
// Note that asyncResp can be either a valid pointer or nullptr. If nullptr
// then no asyncResp updates will occur
static void
@@ -142,125 +300,7 @@ static void
activateImage(objPath.str, objInfo[0].first);
if (asyncResp)
{
- std::shared_ptr<task::TaskData> task =
- task::TaskData::createTask(
- [](const boost::system::error_code& ec2,
- sdbusplus::message_t& msg,
- const std::shared_ptr<task::TaskData>&
- taskData) {
- if (ec2)
- {
- return task::completed;
- }
-
- std::string iface;
- dbus::utility::DBusPropertiesMap values;
-
- std::string index = std::to_string(taskData->index);
- msg.read(iface, values);
-
- if (iface == "xyz.openbmc_project.Software.Activation")
- {
- const std::string* state = nullptr;
- for (const auto& property : values)
- {
- if (property.first == "Activation")
- {
- state = std::get_if<std::string>(
- &property.second);
- if (state == nullptr)
- {
- taskData->messages.emplace_back(
- messages::internalError());
- return task::completed;
- }
- }
- }
-
- if (state == nullptr)
- {
- return !task::completed;
- }
-
- if (state->ends_with("Invalid") ||
- state->ends_with("Failed"))
- {
- taskData->state = "Exception";
- taskData->status = "Warning";
- taskData->messages.emplace_back(
- messages::taskAborted(index));
- return task::completed;
- }
-
- if (state->ends_with("Staged"))
- {
- taskData->state = "Stopping";
- taskData->messages.emplace_back(
- messages::taskPaused(index));
-
- // its staged, set a long timer to
- // allow them time to complete the
- // update (probably cycle the
- // system) if this expires then
- // task will be canceled
- taskData->extendTimer(std::chrono::hours(5));
- return !task::completed;
- }
-
- if (state->ends_with("Active"))
- {
- taskData->messages.emplace_back(
- messages::taskCompletedOK(index));
- taskData->state = "Completed";
- return task::completed;
- }
- }
- else if (
- iface ==
- "xyz.openbmc_project.Software.ActivationProgress")
- {
- const uint8_t* progress = nullptr;
- for (const auto& property : values)
- {
- if (property.first == "Progress")
- {
- progress =
- std::get_if<uint8_t>(&property.second);
- if (progress == nullptr)
- {
- taskData->messages.emplace_back(
- messages::internalError());
- return task::completed;
- }
- }
- }
-
- if (progress == nullptr)
- {
- return !task::completed;
- }
- taskData->percentComplete = *progress;
- taskData->messages.emplace_back(
- messages::taskProgressChanged(index,
- *progress));
-
- // if we're getting status updates it's
- // still alive, update timer
- taskData->extendTimer(std::chrono::minutes(5));
- }
-
- // as firmware update often results in a
- // reboot, the task may never "complete"
- // unless it is an error
-
- return !task::completed;
- },
- "type='signal',interface='org.freedesktop.DBus.Properties',"
- "member='PropertiesChanged',path='" +
- objPath.str + "'");
- task->startTimer(std::chrono::minutes(5));
- task->populateResp(asyncResp->res);
- task->payload.emplace(std::move(payload));
+ createTask(asyncResp, std::move(payload), objPath);
}
fwUpdateInProgress = false;
});
@@ -464,11 +504,15 @@ inline std::optional<boost::urls::url>
res, imageURI, "ImageURI", "UpdateService.SimpleUpdate");
return std::nullopt;
}
- // OpenBMC currently only supports TFTP
+ // OpenBMC currently only supports TFTP or HTTPS
if (*transferProtocol == "TFTP")
{
imageURI = "tftp://" + imageURI;
}
+ else if (*transferProtocol == "HTTPS")
+ {
+ imageURI = "https://" + imageURI;
+ }
else
{
messages::actionParameterNotSupported(res, "TransferProtocol",
@@ -499,6 +543,14 @@ inline std::optional<boost::urls::url>
return std::nullopt;
}
}
+ else if (url->scheme() == "https")
+ {
+ // Empty paths default to "/"
+ if (url->encoded_path().empty())
+ {
+ url->set_encoded_path("/");
+ }
+ }
else
{
messages::actionParameterNotSupported(res, "ImageURI", imageURI);
@@ -515,15 +567,23 @@ inline std::optional<boost::urls::url>
return *url;
}
+inline void doHttpsUpdate(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
+ const boost::urls::url_view_base& url)
+{
+ messages::actionParameterNotSupported(asyncResp->res, "ImageURI",
+ url.buffer());
+}
+
inline void doTftpUpdate(const crow::Request& req,
const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
const boost::urls::url_view_base& url)
{
-#ifndef BMCWEB_INSECURE_ENABLE_REDFISH_FW_TFTP_UPDATE
- messages::actionParameterNotSupported(asyncResp->res, "ImageURI",
- url.buffer());
- return;
-#endif
+ if (!BMCWEB_INSECURE_TFTP_UPDATE)
+ {
+ messages::actionParameterNotSupported(asyncResp->res, "ImageURI",
+ url.buffer());
+ return;
+ }
std::string path(url.encoded_path());
if (path.size() < 2)
@@ -606,6 +666,10 @@ inline void handleUpdateServiceSimpleUpdateAction(
{
doTftpUpdate(req, asyncResp, *url);
}
+ else if (url->scheme() == "https")
+ {
+ doHttpsUpdate(asyncResp, *url);
+ }
else
{
messages::actionParameterNotSupported(asyncResp->res, "ImageURI",
@@ -636,10 +700,10 @@ inline void uploadImageFile(crow::Response& res, std::string_view body)
}
}
-inline void setApplyTime(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
- const std::string& applyTime)
+// Convert the Request Apply Time to the D-Bus value
+inline bool convertApplyTime(crow::Response& res, const std::string& applyTime,
+ std::string& applyTimeNewVal)
{
- std::string applyTimeNewVal;
if (applyTime == "Immediate")
{
applyTimeNewVal =
@@ -652,10 +716,21 @@ inline void setApplyTime(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
}
else
{
- BMCWEB_LOG_INFO(
- "ApplyTime value is not in the list of acceptable values");
- messages::propertyValueNotInList(asyncResp->res, applyTime,
- "ApplyTime");
+ BMCWEB_LOG_WARNING(
+ "ApplyTime value {} is not in the list of acceptable values",
+ applyTime);
+ messages::propertyValueNotInList(res, applyTime, "ApplyTime");
+ return false;
+ }
+ return true;
+}
+
+inline void setApplyTime(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
+ const std::string& applyTime)
+{
+ std::string applyTimeNewVal;
+ if (!convertApplyTime(asyncResp->res, applyTime, applyTimeNewVal))
+ {
return;
}
@@ -666,22 +741,54 @@ inline void setApplyTime(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
"RequestedApplyTime", "ApplyTime", applyTimeNewVal);
}
-inline void
- updateMultipartContext(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
- const crow::Request& req,
- const MultipartParser& parser)
+struct MultiPartUpdateParameters
+{
+ std::optional<std::string> applyTime;
+ std::string uploadData;
+ std::vector<std::string> targets;
+};
+
+inline std::optional<std::string>
+ processUrl(boost::system::result<boost::urls::url_view>& url)
+{
+ if (!url)
+ {
+ return std::nullopt;
+ }
+ if (crow::utility::readUrlSegments(*url, "redfish", "v1", "Managers",
+ BMCWEB_REDFISH_MANAGER_URI_NAME))
+ {
+ return std::make_optional(std::string(BMCWEB_REDFISH_MANAGER_URI_NAME));
+ }
+ if constexpr (!BMCWEB_REDFISH_UPDATESERVICE_USE_DBUS)
+ {
+ return std::nullopt;
+ }
+ std::string firmwareId;
+ if (!crow::utility::readUrlSegments(*url, "redfish", "v1", "UpdateService",
+ "FirmwareInventory",
+ std::ref(firmwareId)))
+ {
+ return std::nullopt;
+ }
+
+ return std::make_optional(firmwareId);
+}
+
+inline std::optional<MultiPartUpdateParameters>
+ extractMultipartUpdateParameters(
+ const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
+ MultipartParser parser)
{
- const std::string* uploadData = nullptr;
- std::optional<std::string> applyTime = "OnReset";
- bool targetFound = false;
- for (const FormPart& formpart : parser.mime_fields)
+ MultiPartUpdateParameters multiRet;
+ for (FormPart& formpart : parser.mime_fields)
{
boost::beast::http::fields::const_iterator it =
formpart.fields.find("Content-Disposition");
if (it == formpart.fields.end())
{
BMCWEB_LOG_ERROR("Couldn't find Content-Disposition");
- return;
+ return std::nullopt;
}
BMCWEB_LOG_INFO("Parsing value {}", it->value());
@@ -702,63 +809,277 @@ inline void
if (param.second == "UpdateParameters")
{
- std::vector<std::string> targets;
+ std::vector<std::string> tempTargets;
nlohmann::json content =
nlohmann::json::parse(formpart.content);
nlohmann::json::object_t* obj =
content.get_ptr<nlohmann::json::object_t*>();
if (obj == nullptr)
{
- messages::propertyValueFormatError(asyncResp->res, targets,
- "UpdateParameters");
- return;
+ messages::propertyValueTypeError(
+ asyncResp->res, formpart.content, "UpdateParameters");
+ return std::nullopt;
}
if (!json_util::readJsonObject(
- *obj, asyncResp->res, "Targets", targets,
- "@Redfish.OperationApplyTime", applyTime))
+ *obj, asyncResp->res, "Targets", tempTargets,
+ "@Redfish.OperationApplyTime", multiRet.applyTime))
{
- return;
+ return std::nullopt;
}
- if (targets.size() != 1)
+
+ for (size_t urlIndex = 0; urlIndex < tempTargets.size();
+ urlIndex++)
{
- messages::propertyValueFormatError(asyncResp->res, targets,
- "Targets");
- return;
+ const std::string& target = tempTargets[urlIndex];
+ boost::system::result<boost::urls::url_view> url =
+ boost::urls::parse_origin_form(target);
+ auto res = processUrl(url);
+ if (!res.has_value())
+ {
+ messages::propertyValueFormatError(
+ asyncResp->res, target,
+ std::format("Targets/{}", urlIndex));
+ return std::nullopt;
+ }
+ multiRet.targets.emplace_back(res.value());
}
- if (targets[0] != "/redfish/v1/Managers/bmc")
+ if (multiRet.targets.size() != 1)
{
- messages::propertyValueNotInList(asyncResp->res, targets[0],
- "Targets/0");
- return;
+ messages::propertyValueFormatError(
+ asyncResp->res, multiRet.targets, "Targets");
+ return std::nullopt;
}
- targetFound = true;
}
else if (param.second == "UpdateFile")
{
- uploadData = &(formpart.content);
+ multiRet.uploadData = std::move(formpart.content);
}
}
}
- if (uploadData == nullptr)
+ if (multiRet.uploadData.empty())
{
BMCWEB_LOG_ERROR("Upload data is NULL");
messages::propertyMissing(asyncResp->res, "UpdateFile");
+ return std::nullopt;
+ }
+ if (multiRet.targets.empty())
+ {
+ messages::propertyMissing(asyncResp->res, "Targets");
+ return std::nullopt;
+ }
+ return multiRet;
+}
+
+inline void
+ handleStartUpdate(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
+ task::Payload payload, const std::string& objectPath,
+ const boost::system::error_code& ec,
+ const sdbusplus::message::object_path& retPath)
+{
+ if (ec)
+ {
+ BMCWEB_LOG_ERROR("error_code = {}", ec);
+ BMCWEB_LOG_ERROR("error msg = {}", ec.message());
+ messages::internalError(asyncResp->res);
+ return;
+ }
+
+ BMCWEB_LOG_INFO("Call to StartUpdate Success, retPath = {}", retPath.str);
+ createTask(asyncResp, std::move(payload), objectPath);
+}
+
+inline void startUpdate(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
+ task::Payload payload,
+ const MemoryFileDescriptor& memfd,
+ const std::string& applyTime,
+ const std::string& objectPath,
+ const std::string& serviceName)
+{
+ crow::connections::systemBus->async_method_call(
+ [asyncResp, payload = std::move(payload),
+ objectPath](const boost::system::error_code& ec1,
+ const sdbusplus::message::object_path& retPath) mutable {
+ handleStartUpdate(asyncResp, std::move(payload), objectPath, ec1,
+ retPath);
+ },
+ serviceName, objectPath, "xyz.openbmc_project.Software.Update",
+ "StartUpdate", sdbusplus::message::unix_fd(memfd.fd), applyTime);
+}
+
+inline void getAssociatedUpdateInterface(
+ const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, task::Payload payload,
+ const MemoryFileDescriptor& memfd, const std::string& applyTime,
+ const boost::system::error_code& ec,
+ const dbus::utility::MapperGetSubTreeResponse& subtree)
+{
+ if (ec)
+ {
+ BMCWEB_LOG_ERROR("error_code = {}", ec);
+ BMCWEB_LOG_ERROR("error msg = {}", ec.message());
+ messages::internalError(asyncResp->res);
return;
}
- if (!targetFound)
+ BMCWEB_LOG_DEBUG("Found {} startUpdate subtree paths", subtree.size());
+
+ if (subtree.size() > 1)
{
- messages::propertyMissing(asyncResp->res, "targets");
+ BMCWEB_LOG_ERROR("Found more than one startUpdate subtree paths");
+ messages::internalError(asyncResp->res);
return;
}
- setApplyTime(asyncResp, *applyTime);
+ auto objectPath = subtree[0].first;
+ auto serviceName = subtree[0].second[0].first;
- // Setup callback for when new software detected
- monitorForSoftwareAvailable(asyncResp, req, "/redfish/v1/UpdateService");
+ BMCWEB_LOG_DEBUG("Found objectPath {} serviceName {}", objectPath,
+ serviceName);
+ startUpdate(asyncResp, std::move(payload), memfd, applyTime, objectPath,
+ serviceName);
+}
- uploadImageFile(asyncResp->res, *uploadData);
+inline void
+ getSwInfo(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
+ task::Payload payload, MemoryFileDescriptor memfd,
+ const std::string& applyTime, const std::string& target,
+ const boost::system::error_code& ec,
+ const dbus::utility::MapperGetSubTreePathsResponse& subtree)
+{
+ using SwInfoMap =
+ std::unordered_map<std::string, sdbusplus::message::object_path>;
+ SwInfoMap swInfoMap;
+
+ if (ec)
+ {
+ BMCWEB_LOG_ERROR("error_code = {}", ec);
+ BMCWEB_LOG_ERROR("error msg = {}", ec.message());
+ messages::internalError(asyncResp->res);
+ return;
+ }
+ BMCWEB_LOG_DEBUG("Found {} software version paths", subtree.size());
+
+ for (const auto& objectPath : subtree)
+ {
+ sdbusplus::message::object_path path(objectPath);
+ std::string swId = path.filename();
+ swInfoMap.emplace(swId, path);
+ }
+
+ auto swEntry = swInfoMap.find(target);
+ if (swEntry == swInfoMap.end())
+ {
+ BMCWEB_LOG_WARNING("No valid DBus path for Target URI {}", target);
+ messages::propertyValueFormatError(asyncResp->res, target, "Targets");
+ return;
+ }
+
+ BMCWEB_LOG_DEBUG("Found software version path {}", swEntry->second.str);
+
+ sdbusplus::message::object_path swObjectPath = swEntry->second /
+ "software_version";
+ constexpr std::array<std::string_view, 1> interfaces = {
+ "xyz.openbmc_project.Software.Update"};
+ dbus::utility::getAssociatedSubTree(
+ swObjectPath,
+ sdbusplus::message::object_path("/xyz/openbmc_project/software"), 0,
+ interfaces,
+ [asyncResp, payload = std::move(payload), memfd = std::move(memfd),
+ applyTime](
+ const boost::system::error_code& ec1,
+ const dbus::utility::MapperGetSubTreeResponse& subtree1) mutable {
+ getAssociatedUpdateInterface(asyncResp, std::move(payload), memfd,
+ applyTime, ec1, subtree1);
+ });
+}
+
+inline void
+ processUpdateRequest(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
+ const crow::Request& req, std::string_view body,
+ const std::string& applyTime,
+ std::vector<std::string>& targets)
+{
+ std::string applyTimeNewVal;
+
+ if (!convertApplyTime(asyncResp->res, applyTime, applyTimeNewVal))
+ {
+ return;
+ }
+
+ MemoryFileDescriptor memfd("update-image");
+ if (memfd.fd == -1)
+ {
+ BMCWEB_LOG_ERROR("Failed to create image memfd");
+ messages::internalError(asyncResp->res);
+ return;
+ }
+ if (write(memfd.fd, body.data(), body.length()) !=
+ static_cast<ssize_t>(body.length()))
+ {
+ BMCWEB_LOG_ERROR("Failed to write to image memfd");
+ messages::internalError(asyncResp->res);
+ return;
+ }
+ if (!memfd.rewind())
+ {
+ messages::internalError(asyncResp->res);
+ return;
+ }
+
+ task::Payload payload(req);
+ if (!targets.empty() && targets[0] == BMCWEB_REDFISH_MANAGER_URI_NAME)
+ {
+ startUpdate(asyncResp, std::move(payload), memfd, applyTimeNewVal,
+ "/xyz/openbmc_project/software/bmc",
+ "xyz.openbmc_project.Software.Manager");
+ }
+ else
+ {
+ constexpr std::array<std::string_view, 1> interfaces = {
+ "xyz.openbmc_project.Software.Version"};
+ dbus::utility::getSubTreePaths(
+ "/xyz/openbmc_project/software", 1, interfaces,
+ [asyncResp, payload = std::move(payload), memfd = std::move(memfd),
+ applyTimeNewVal,
+ targets](const boost::system::error_code& ec,
+ const dbus::utility::MapperGetSubTreePathsResponse&
+ subtree) mutable {
+ getSwInfo(asyncResp, std::move(payload), std::move(memfd),
+ applyTimeNewVal, targets[0], ec, subtree);
+ });
+ }
+}
+
+inline void
+ updateMultipartContext(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
+ const crow::Request& req, MultipartParser&& parser)
+{
+ std::optional<MultiPartUpdateParameters> multipart =
+ extractMultipartUpdateParameters(asyncResp, std::move(parser));
+ if (!multipart)
+ {
+ return;
+ }
+ if (!multipart->applyTime)
+ {
+ multipart->applyTime = "OnReset";
+ }
+
+ if constexpr (BMCWEB_REDFISH_UPDATESERVICE_USE_DBUS)
+ {
+ processUpdateRequest(asyncResp, req, multipart->uploadData,
+ *multipart->applyTime, multipart->targets);
+ }
+ else
+ {
+ setApplyTime(asyncResp, *multipart->applyTime);
+
+ // Setup callback for when new software detected
+ monitorForSoftwareAvailable(asyncResp, req,
+ "/redfish/v1/UpdateService");
+
+ uploadImageFile(asyncResp->res, multipart->uploadData);
+ }
}
inline void
@@ -797,7 +1118,7 @@ inline void
return;
}
- updateMultipartContext(asyncResp, req, parser);
+ updateMultipartContext(asyncResp, req, std::move(parser));
}
else
{
@@ -841,6 +1162,7 @@ inline void
"/redfish/v1/UpdateService/Actions/UpdateService.SimpleUpdate";
nlohmann::json::array_t allowed;
+ allowed.emplace_back(update_service::TransferProtocolType::HTTPS);
if constexpr (BMCWEB_INSECURE_PUSH_STYLE_NOTIFICATION)
{
@@ -936,7 +1258,8 @@ inline void getRelatedItems(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
{
nlohmann::json& relatedItem = asyncResp->res.jsonValue["RelatedItem"];
nlohmann::json::object_t item;
- item["@odata.id"] = "/redfish/v1/Managers/bmc";
+ item["@odata.id"] = boost::urls::format(
+ "/redfish/v1/Managers/{}", BMCWEB_REDFISH_MANAGER_URI_NAME);
relatedItem.emplace_back(std::move(item));
asyncResp->res.jsonValue["RelatedItem@odata.count"] =
relatedItem.size();
@@ -945,7 +1268,8 @@ inline void getRelatedItems(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
{
nlohmann::json& relatedItem = asyncResp->res.jsonValue["RelatedItem"];
nlohmann::json::object_t item;
- item["@odata.id"] = "/redfish/v1/Systems/system/Bios";
+ item["@odata.id"] = std::format("/redfish/v1/Systems/{}/Bios",
+ BMCWEB_REDFISH_SYSTEM_URI_NAME);
relatedItem.emplace_back(std::move(item));
asyncResp->res.jsonValue["RelatedItem@odata.count"] =
relatedItem.size();