summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGeorge Liu <liuxiwei@inspur.com>2020-05-12 11:06:27 +0300
committerGeorge Liu <liuxiwei@inspur.com>2023-03-24 09:41:34 +0300
commit0ed80c8ce93a38eca6951ffad5c3143a3a720053 (patch)
tree4cb6dbaf356058c80979319780dc861d81b2363e
parent6c3e94511027133db407f9e1c3c628927ec1332f (diff)
downloadbmcweb-0ed80c8ce93a38eca6951ffad5c3143a3a720053.tar.xz
UpdateService: Support for MultipartHttpPushUri
Since a service support the MultipartHttpPushUri property within the UpdateService resource, so add a new MultipartHttpPushUri property, This property shall contain a URI used to perform a Redfish Specification-defined Multipart HTTP or HTTPS POST of a software image for the purpose of installing software contained within the image, and use the requirements of a multipart/form-data to request body for HTTP push software update. Tested: curl -k -H "X-Auth-Token: $token" -H "Content-Type: multipart/form-data" -F 'UpdateParameters={"Targets":["/redfish/v1/Managers/bmc"], "@Redfish.OperationApplyTime":"Immediate"};type=application/json' -F 'UpdateFile=@obmc-phosphor-image.static.mtd.tar;type=application/ octet-stream' https://${bmc}/redfish/v1/UpdateService/update { "@odata.id": "/redfish/v1/TaskService/Tasks/0", "@odata.type": "#Task.v1_4_3.Task", "Id": "0", "TaskState": "Running", "TaskStatus": "OK" } Passed the validator: Signed-off-by: George Liu <liuxiwei@inspur.com> Change-Id: Ie1ea0594337efdb073270aba6918389c4381a2b3
-rw-r--r--redfish-core/lib/update_service.hpp214
1 files changed, 167 insertions, 47 deletions
diff --git a/redfish-core/lib/update_service.hpp b/redfish-core/lib/update_service.hpp
index 0d4c1b70b5..650ba95622 100644
--- a/redfish-core/lib/update_service.hpp
+++ b/redfish-core/lib/update_service.hpp
@@ -19,6 +19,7 @@
#include "app.hpp"
#include "dbus_utility.hpp"
+#include "multipart_parser.hpp"
#include "query.hpp"
#include "registries/privilege_registry.hpp"
#include "task.hpp"
@@ -32,6 +33,7 @@
#include <sdbusplus/unpack_properties.hpp>
#include <array>
+#include <filesystem>
#include <string_view>
namespace redfish
@@ -527,6 +529,150 @@ inline void requestRoutesUpdateServiceActionsSimpleUpdate(App& app)
});
}
+inline void uploadImageFile(crow::Response& res, std::string_view body)
+{
+ std::filesystem::path filepath(
+ "/tmp/images/" +
+ boost::uuids::to_string(boost::uuids::random_generator()()));
+ BMCWEB_LOG_DEBUG << "Writing file to " << filepath;
+ std::ofstream out(filepath, std::ofstream::out | std::ofstream::binary |
+ std::ofstream::trunc);
+ // set the permission of the file to 640
+ std::filesystem::perms permission =
+ std::filesystem::perms::owner_read | std::filesystem::perms::group_read;
+ std::filesystem::permissions(filepath, permission);
+ out << body;
+
+ if (out.bad())
+ {
+ messages::internalError(res);
+ cleanUp();
+ }
+}
+
+inline void setApplyTime(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
+ const std::string& applyTime)
+{
+ std::string applyTimeNewVal;
+ if (applyTime == "Immediate")
+ {
+ applyTimeNewVal =
+ "xyz.openbmc_project.Software.ApplyTime.RequestedApplyTimes.Immediate";
+ }
+ else if (applyTime == "OnReset")
+ {
+ applyTimeNewVal =
+ "xyz.openbmc_project.Software.ApplyTime.RequestedApplyTimes.OnReset";
+ }
+ else
+ {
+ BMCWEB_LOG_INFO
+ << "ApplyTime value is not in the list of acceptable values";
+ messages::propertyValueNotInList(asyncResp->res, applyTime,
+ "ApplyTime");
+ return;
+ }
+
+ // Set the requested image apply time value
+ crow::connections::systemBus->async_method_call(
+ [asyncResp](const boost::system::error_code ec) {
+ if (ec)
+ {
+ BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec;
+ messages::internalError(asyncResp->res);
+ return;
+ }
+ messages::success(asyncResp->res);
+ },
+ "xyz.openbmc_project.Settings",
+ "/xyz/openbmc_project/software/apply_time",
+ "org.freedesktop.DBus.Properties", "Set",
+ "xyz.openbmc_project.Software.ApplyTime", "RequestedApplyTime",
+ dbus::utility::DbusVariantType{applyTimeNewVal});
+}
+
+inline void
+ updateMultipartContext(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
+ const MultipartParser& parser)
+{
+ const std::string* uploadData = nullptr;
+ std::optional<std::string> applyTime = "OnReset";
+ bool targetFound = false;
+ for (const 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;
+ }
+ BMCWEB_LOG_INFO << "Parsing value " << it->value();
+
+ // The construction parameters of param_list must start with `;`
+ size_t index = it->value().find(';');
+ if (index == std::string::npos)
+ {
+ continue;
+ }
+
+ for (auto const& param :
+ boost::beast::http::param_list{it->value().substr(index)})
+ {
+ if (param.first != "name" || param.second.empty())
+ {
+ continue;
+ }
+
+ if (param.second == "UpdateParameters")
+ {
+ std::vector<std::string> targets;
+ nlohmann::json content =
+ nlohmann::json::parse(formpart.content);
+ if (!json_util::readJson(content, asyncResp->res, "Targets",
+ targets, "@Redfish.OperationApplyTime",
+ applyTime))
+ {
+ return;
+ }
+ if (targets.size() != 1)
+ {
+ messages::propertyValueFormatError(asyncResp->res,
+ "Targets", "");
+ return;
+ }
+ if (targets[0] != "/redfish/v1/Managers/bmc")
+ {
+ messages::propertyValueNotInList(asyncResp->res,
+ "Targets/0", targets[0]);
+ return;
+ }
+ targetFound = true;
+ }
+ else if (param.second == "UpdateFile")
+ {
+ uploadData = &(formpart.content);
+ }
+ }
+ }
+
+ if (uploadData == nullptr)
+ {
+ BMCWEB_LOG_ERROR << "Upload data is NULL";
+ messages::propertyMissing(asyncResp->res, "UpdateFile");
+ return;
+ }
+ if (!targetFound)
+ {
+ messages::propertyMissing(asyncResp->res, "targets");
+ return;
+ }
+
+ setApplyTime(asyncResp, *applyTime);
+
+ uploadImageFile(asyncResp->res, *uploadData);
+}
+
inline void
handleUpdateServicePost(App& app, const crow::Request& req,
const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
@@ -540,15 +686,23 @@ inline void
// Setup callback for when new software detected
monitorForSoftwareAvailable(asyncResp, req, "/redfish/v1/UpdateService");
- std::string filepath(
- "/tmp/images/" +
- boost::uuids::to_string(boost::uuids::random_generator()()));
- BMCWEB_LOG_DEBUG << "Writing file to " << filepath;
- std::ofstream out(filepath, std::ofstream::out | std::ofstream::binary |
- std::ofstream::trunc);
- out << req.body();
- out.close();
- BMCWEB_LOG_DEBUG << "file upload complete!!";
+ MultipartParser parser;
+ ParserError ec = parser.parse(req);
+ if (ec == ParserError::ERROR_BOUNDARY_FORMAT)
+ {
+ // If the request didnt' contain boundary information, assume it was a
+ // POST binary payload.
+ uploadImageFile(asyncResp->res, req.body());
+ return;
+ }
+ if (ec != ParserError::PARSER_SUCCESS)
+ {
+ // handle error
+ BMCWEB_LOG_ERROR << "MIME parse failed, ec : " << static_cast<int>(ec);
+ messages::internalError(asyncResp->res);
+ return;
+ }
+ updateMultipartContext(asyncResp, parser);
}
inline void requestRoutesUpdateService(App& app)
@@ -563,7 +717,7 @@ inline void requestRoutesUpdateService(App& app)
return;
}
asyncResp->res.jsonValue["@odata.type"] =
- "#UpdateService.v1_5_0.UpdateService";
+ "#UpdateService.v1_11_1.UpdateService";
asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/UpdateService";
asyncResp->res.jsonValue["Id"] = "UpdateService";
asyncResp->res.jsonValue["Description"] = "Service for Software Update";
@@ -580,6 +734,8 @@ inline void requestRoutesUpdateService(App& app)
asyncResp->res.jsonValue["HttpPushUri"] =
"/redfish/v1/UpdateService/update";
+ asyncResp->res.jsonValue["MultipartHttpPushUri"] =
+ "/redfish/v1/UpdateService/update";
// UpdateService cannot be disabled
asyncResp->res.jsonValue["ServiceEnabled"] = true;
@@ -667,43 +823,7 @@ inline void requestRoutesUpdateService(App& app)
if (applyTime)
{
- std::string applyTimeNewVal;
- if (applyTime == "Immediate")
- {
- applyTimeNewVal =
- "xyz.openbmc_project.Software.ApplyTime.RequestedApplyTimes.Immediate";
- }
- else if (applyTime == "OnReset")
- {
- applyTimeNewVal =
- "xyz.openbmc_project.Software.ApplyTime.RequestedApplyTimes.OnReset";
- }
- else
- {
- BMCWEB_LOG_INFO
- << "ApplyTime value is not in the list of acceptable values";
- messages::propertyValueNotInList(
- asyncResp->res, *applyTime, "ApplyTime");
- return;
- }
-
- // Set the requested image apply time value
- crow::connections::systemBus->async_method_call(
- [asyncResp](const boost::system::error_code& ec) {
- if (ec)
- {
- BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec;
- messages::internalError(asyncResp->res);
- return;
- }
- messages::success(asyncResp->res);
- },
- "xyz.openbmc_project.Settings",
- "/xyz/openbmc_project/software/apply_time",
- "org.freedesktop.DBus.Properties", "Set",
- "xyz.openbmc_project.Software.ApplyTime",
- "RequestedApplyTime",
- dbus::utility::DbusVariantType{applyTimeNewVal});
+ setApplyTime(asyncResp, *applyTime);
}
}
}