summaryrefslogtreecommitdiff
path: root/redfish-core/lib/update_service.hpp
diff options
context:
space:
mode:
authorAndrew Geissler <geissonator@yahoo.com>2019-04-23 22:40:12 +0300
committerEd Tanous <ed.tanous@intel.com>2019-06-26 21:20:31 +0300
commit0554c984827c1593663257a842d0cd943ce4f508 (patch)
treeea0369802a2b813710a9ea2a4c4c6d18d9614c95 /redfish-core/lib/update_service.hpp
parente4a4b9a95622b8e1c1bae93718699ad19f4882ac (diff)
downloadbmcweb-0554c984827c1593663257a842d0cd943ce4f508.tar.xz
simpleupdate: Basic support of SimpleUpdate
This is TFTP only since that is all the OpenBMC back end currently supports Design Doc Ref: https://gerrit.openbmc-project.xyz/c/openbmc/docs/+/20700 Tested: 1) Verified BMC image update via new SimpleUpdate interface worked curl -k -H "X-Auth-Token: $TOKEN" -d '{"ImageURI":"XXX.XX.X.X/obmc-phosphor-image-witherspoon.ubi.mtd.tar","TransferProtocol":"TFTP"}' -X POST https://${BMC_IP}/redfish/v1/UpdateService/Actions/UpdateService.SimpleUpdate { "@Message.ExtendedInfo": [ { "@odata.type": "/redfish/v1/$metadata#Message.v1_0_0.Message", "Message": "Successfully Completed Request", "MessageArgs": [], "MessageId": "Base.1.4.0.Success", "Resolution": "None", "Severity": "OK" } ] } 2) Verified encoding the protocol in ImageURI worked curl -k -H "X-Auth-Token: $TOKEN" -X POST https://${BMC_IP}/redfish/v1/UpdateService/Actions/UpdateService.SimpleUpdate -d '{"ImageURI":"tftp://${TFTP_IP}/obmc-phosphor-image-witherspoon.ubi.mtd.tar"}' { "@Message.ExtendedInfo": [ { "@odata.type": "/redfish/v1/$metadata#Message.v1_0_0.Message", "Message": "Successfully Completed Request", "MessageArgs": [], "MessageId": "Base.1.4.0.Success", "Resolution": "None", "Severity": "OK" } ] } Jun 12 20:52:20 witherspoon bmcweb[2470]: (2019-06-12 20:52:20) [DEBUG ] Enter UpdateService.SimpleUpdate doPost Jun 12 20:52:20 witherspoon bmcweb[2470]: (2019-06-12 20:52:20) [DEBUG ] Encoded transfer protocol tftp Jun 12 20:52:20 witherspoon bmcweb[2470]: (2019-06-12 20:52:20) [DEBUG ] Adjusted imageUri ${BMC_IP}/obmc-phosphor-image-witherspoon.ubi.mtd.tar Jun 12 20:52:20 witherspoon bmcweb[2470]: (2019-06-12 20:52:20) [DEBUG ] Server: ${TFTP_IP} File: obmc-phosphor-image-witherspoon.ubi.mtd.tar Jun 12 20:52:20 witherspoon bmcweb[2470]: (2019-06-12 20:52:20) [DEBUG ] Exit UpdateService.SimpleUpdate doPost 3) Verified if no transfer protocol, error returned curl -k -H "X-Auth-Token: $TOKEN" -X POST https://${BMC_IP}/redfish/v1/UpdateService/Actions/UpdateService.SimpleUpdate -d '{"ImageURI":”${TFTP_IP}/obmc-phosphor-image-witherspoon.ubi.mtd.tar"}' { "error": { "@Message.ExtendedInfo": [ { "@odata.type": "/redfish/v1/$metadata#Message.v1_0_0.Message", "Message": "The value ${TFTP_IP}/obmc-phosphor-image-witherspoon.ubi.mtd.tar for the parameter ImageURI in the action UpdateService.SimpleUpdate is of a different type than the parameter can accept.", "MessageArgs": [ “${TFTP_IP}/obmc-phosphor-image-witherspoon.ubi.mtd.tar", "ImageURI", "UpdateService.SimpleUpdate" ], "MessageId": "Base.1.4.0.ActionParameterValueTypeError", "Resolution": "Correct the value for the parameter in the request body and resubmit the request if the operation failed.", "Severity": "Warning" } ], "code": "Base.1.4.0.ActionParameterValueTypeError", "message": "The value ${TFTP_IP}/obmc-phosphor-image-witherspoon.ubi.mtd.tar for the parameter ImageURI in the action UpdateService.SimpleUpdate is of a different type than the parameter can accept." } } 4) Verified no new error in Redfish Validator 5) Verified error return when parameter missing: curl -k -H "X-Auth-Token: $TOKEN" -d '{"TransferProtocol":"TFTP"}' -X POST https://${BMC_IP}/redfish/v1/UpdateService/Actions/UpdateService.SimpleUpdate { "ImageURI@Message.ExtendedInfo": [ { "@odata.type": "/redfish/v1/$metadata#Message.v1_0_0.Message", "Message": "The property ImageURI is a required property and must be included in the request.", "MessageArgs": [ "ImageURI" ], "MessageId": "Base.1.4.0.PropertyMissing", "Resolution": "Ensure that the property is in the request body and has a valid value and resubmit the request if the operation failed.", "Severity": "Warning" } ] } 6) Verified that by default, the new Action is not available Change-Id: I67ea91e181380e6da7ff63a37f02408a318602b7 Signed-off-by: Andrew Geissler <geissonator@yahoo.com>
Diffstat (limited to 'redfish-core/lib/update_service.hpp')
-rw-r--r--redfish-core/lib/update_service.hpp183
1 files changed, 172 insertions, 11 deletions
diff --git a/redfish-core/lib/update_service.hpp b/redfish-core/lib/update_service.hpp
index 06c1965ce2..7e08ec7c46 100644
--- a/redfish-core/lib/update_service.hpp
+++ b/redfish-core/lib/update_service.hpp
@@ -54,6 +54,9 @@ static void activateImage(const std::string &objPath,
"xyz.openbmc_project.Software.Activation.RequestedActivations."
"Active"));
}
+
+// Note that asyncResp can be either a valid pointer or nullptr. If nullptr
+// then no asyncResp updates will occur
static void softwareInterfaceAdded(std::shared_ptr<AsyncResp> asyncResp,
sdbusplus::message::message &m)
{
@@ -87,7 +90,10 @@ static void softwareInterfaceAdded(std::shared_ptr<AsyncResp> asyncResp,
BMCWEB_LOG_DEBUG << "error_code = " << error_code;
BMCWEB_LOG_DEBUG << "error msg = "
<< error_code.message();
- messages::internalError(asyncResp->res);
+ if (asyncResp)
+ {
+ messages::internalError(asyncResp->res);
+ }
cleanUp();
return;
}
@@ -96,7 +102,10 @@ static void softwareInterfaceAdded(std::shared_ptr<AsyncResp> asyncResp,
{
BMCWEB_LOG_ERROR << "Invalid Object Size "
<< objInfo.size();
- messages::internalError(asyncResp->res);
+ if (asyncResp)
+ {
+ messages::internalError(asyncResp->res);
+ }
cleanUp();
return;
}
@@ -106,7 +115,10 @@ static void softwareInterfaceAdded(std::shared_ptr<AsyncResp> asyncResp,
fwAvailableTimer = nullptr;
activateImage(objPath.str, objInfo[0].first);
- redfish::messages::success(asyncResp->res);
+ if (asyncResp)
+ {
+ redfish::messages::success(asyncResp->res);
+ }
fwUpdateInProgress = false;
},
"xyz.openbmc_project.ObjectMapper",
@@ -118,21 +130,28 @@ static void softwareInterfaceAdded(std::shared_ptr<AsyncResp> asyncResp,
}
}
+// Note that asyncResp can be either a valid pointer or nullptr. If nullptr
+// then no asyncResp updates will occur
static void monitorForSoftwareAvailable(std::shared_ptr<AsyncResp> asyncResp,
- const crow::Request &req)
+ const crow::Request &req,
+ int timeoutTimeSeconds = 5)
{
// Only allow one FW update at a time
if (fwUpdateInProgress != false)
{
- asyncResp->res.addHeader("Retry-After", "30");
- messages::serviceTemporarilyUnavailable(asyncResp->res, "30");
+ if (asyncResp)
+ {
+ asyncResp->res.addHeader("Retry-After", "30");
+ messages::serviceTemporarilyUnavailable(asyncResp->res, "30");
+ }
return;
}
- fwAvailableTimer = std::make_unique<boost::asio::deadline_timer>(
- *req.ioService, boost::posix_time::seconds(5));
+ fwAvailableTimer =
+ std::make_unique<boost::asio::deadline_timer>(*req.ioService);
- fwAvailableTimer->expires_from_now(boost::posix_time::seconds(5));
+ fwAvailableTimer->expires_from_now(
+ boost::posix_time::seconds(timeoutTimeSeconds));
fwAvailableTimer->async_wait(
[asyncResp](const boost::system::error_code &ec) {
@@ -151,8 +170,10 @@ static void monitorForSoftwareAvailable(std::shared_ptr<AsyncResp> asyncResp,
BMCWEB_LOG_ERROR << "Async_wait failed" << ec;
return;
}
-
- redfish::messages::internalError(asyncResp->res);
+ if (asyncResp)
+ {
+ redfish::messages::internalError(asyncResp->res);
+ }
});
auto callback = [asyncResp](sdbusplus::message::message &m) {
@@ -169,6 +190,137 @@ static void monitorForSoftwareAvailable(std::shared_ptr<AsyncResp> asyncResp,
callback);
}
+/**
+ * UpdateServiceActionsSimpleUpdate class supports handle POST method for
+ * SimpleUpdate action.
+ */
+class UpdateServiceActionsSimpleUpdate : public Node
+{
+ public:
+ UpdateServiceActionsSimpleUpdate(CrowApp &app) :
+ Node(app,
+ "/redfish/v1/UpdateService/Actions/UpdateService.SimpleUpdate/")
+ {
+ entityPrivileges = {
+ {boost::beast::http::verb::get, {{"Login"}}},
+ {boost::beast::http::verb::head, {{"Login"}}},
+ {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
+ {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
+ {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
+ {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
+ }
+
+ private:
+ void doPost(crow::Response &res, const crow::Request &req,
+ const std::vector<std::string> &params) override
+ {
+ std::optional<std::string> transferProtocol;
+ std::string imageURI;
+ std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
+
+ BMCWEB_LOG_DEBUG << "Enter UpdateService.SimpleUpdate doPost";
+
+ // User can pass in both TransferProtocol and ImageURI parameters or
+ // they can pass in just the ImageURI with the transfer protocl embedded
+ // within it.
+ // 1) TransferProtocol:TFTP ImageURI:1.1.1.1/myfile.bin
+ // 2) ImageURI:tftp://1.1.1.1/myfile.bin
+
+ if (!json_util::readJson(req, asyncResp->res, "TransferProtocol",
+ transferProtocol, "ImageURI", imageURI))
+ {
+ BMCWEB_LOG_DEBUG
+ << "Missing TransferProtocol or ImageURI parameter";
+ return;
+ }
+ if (!transferProtocol)
+ {
+ // Must be option 2
+ // Verify ImageURI has transfer protocol in it
+ size_t separator = imageURI.find(":");
+ if ((separator == std::string::npos) ||
+ ((separator + 1) > imageURI.size()))
+ {
+ messages::actionParameterValueTypeError(
+ asyncResp->res, imageURI, "ImageURI",
+ "UpdateService.SimpleUpdate");
+ BMCWEB_LOG_ERROR << "ImageURI missing transfer protocol: "
+ << imageURI;
+ return;
+ }
+ transferProtocol = imageURI.substr(0, separator);
+ // Ensure protocol is upper case for a common comparison path below
+ boost::to_upper(*transferProtocol);
+ BMCWEB_LOG_DEBUG << "Encoded transfer protocol "
+ << *transferProtocol;
+
+ // Adjust imageURI to not have the protocol on it for parsing
+ // below
+ // ex. tftp://1.1.1.1/myfile.bin -> 1.1.1.1/myfile.bin
+ imageURI = imageURI.substr(separator + 3);
+ BMCWEB_LOG_DEBUG << "Adjusted imageUri " << imageURI;
+ }
+
+ // OpenBMC currently only supports TFTP
+ if (*transferProtocol != "TFTP")
+ {
+ messages::actionParameterNotSupported(asyncResp->res,
+ "TransferProtocol",
+ "UpdateService.SimpleUpdate");
+ BMCWEB_LOG_ERROR << "Request incorrect protocol parameter: "
+ << *transferProtocol;
+ return;
+ }
+
+ // Format should be <IP or Hostname>/<file> for imageURI
+ size_t separator = imageURI.find("/");
+ if ((separator == std::string::npos) ||
+ ((separator + 1) > imageURI.size()))
+ {
+ messages::actionParameterValueTypeError(
+ asyncResp->res, imageURI, "ImageURI",
+ "UpdateService.SimpleUpdate");
+ BMCWEB_LOG_ERROR << "Invalid ImageURI: " << imageURI;
+ return;
+ }
+
+ std::string tftpServer = imageURI.substr(0, separator);
+ std::string fwFile = imageURI.substr(separator + 1);
+ BMCWEB_LOG_DEBUG << "Server: " << tftpServer + " File: " << fwFile;
+
+ // Setup callback for when new software detected
+ // Give TFTP 2 minutes to complete
+ monitorForSoftwareAvailable(nullptr, req, 120);
+
+ // TFTP can take up to 2 minutes depending on image size and
+ // connection speed. Return to caller as soon as the TFTP operation
+ // has been started. The callback above will ensure the activate
+ // is started once the download has completed
+ redfish::messages::success(asyncResp->res);
+
+ // Call TFTP service
+ crow::connections::systemBus->async_method_call(
+ [](const boost::system::error_code ec) {
+ if (ec)
+ {
+ // messages::internalError(asyncResp->res);
+ cleanUp();
+ BMCWEB_LOG_DEBUG << "error_code = " << ec;
+ BMCWEB_LOG_DEBUG << "error msg = " << ec.message();
+ }
+ else
+ {
+ BMCWEB_LOG_DEBUG << "Call to DownloaViaTFTP Success";
+ }
+ },
+ "xyz.openbmc_project.Software.Download",
+ "/xyz/openbmc_project/software", "xyz.openbmc_project.Common.TFTP",
+ "DownloadViaTFTP", fwFile, tftpServer);
+
+ BMCWEB_LOG_DEBUG << "Exit UpdateService.SimpleUpdate doPost";
+ }
+};
+
class UpdateService : public Node
{
public:
@@ -199,6 +351,15 @@ class UpdateService : public Node
res.jsonValue["ServiceEnabled"] = true;
res.jsonValue["FirmwareInventory"] = {
{"@odata.id", "/redfish/v1/UpdateService/FirmwareInventory"}};
+#ifdef BMCWEB_INSECURE_ENABLE_REDFISH_FW_TFTP_UPDATE
+ // Update Actions object.
+ nlohmann::json &updateSvcSimpleUpdate =
+ res.jsonValue["Actions"]["#UpdateService.SimpleUpdate"];
+ updateSvcSimpleUpdate["target"] =
+ "/redfish/v1/UpdateService/Actions/UpdateService.SimpleUpdate";
+ updateSvcSimpleUpdate["TransferProtocol@Redfish.AllowableValues"] = {
+ "TFTP"};
+#endif
res.end();
}