Update Service: Change error message based on error logs
THis adds support for better error responses based on
the logs generated by phosphor-software-manager.
Tested: Got 400 error with different messages based
on failure type
{
"error": {
"@Message.ExtendedInfo": [
{
"@odata.type": "/redfish/v1/$metadata#Message.v1_0_0.Message",
"Message": "Invalid file uploaded to /redfish/v1/UpdateService: Invalid archive.",
"MessageArgs": [
"/redfish/v1/UpdateService",
"invalid archive"
],
"MessageId": "OpenBMC.0.1.0.InvalidUpload",
"Resolution": "None.",
"Severity": "Warning"
}
],
"code": "OpenBMC.0.1.0.InvalidUpload",
"message": "Invalid file uploaded to /redfish/v1/UpdateService: Invalid archive."
}
}
{
"error": {
"@Message.ExtendedInfo": [
{
"@odata.type": "/redfish/v1/$metadata#Message.v1_0_0.Message",
"Message": "Invalid file uploaded to /redfish/v1/UpdateService: Invalid image format.",
"MessageArgs": [
"/redfish/v1/UpdateService",
"invalid image format"
],
"MessageId": "OpenBMC.0.1.0.InvalidUpload",
"Resolution": "None.",
"Severity": "Warning"
}
],
"code": "OpenBMC.0.1.0.InvalidUpload",
"message": "Invalid file uploaded to /redfish/v1/UpdateService: Invalid image format."
}
}
{
"error": {
"@Message.ExtendedInfo": [
{
"@odata.type": "#Message.v1_0_0.Message",
"Message": "The resource /redfish/v1/UpdateService was unable to satisfy the request due to unavailability of resources.",
"MessageArgs": [
"/redfish/v1/UpdateService"
],
"MessageId": "Base.1.4.0.ResourceExhaustion",
"Resolution": "Ensure that the resources are available and resubmit the request.",
"Severity": "Critical"
}
],
"code": "Base.1.4.0.ResourceExhaustion",
"message": "The resource /redfish/v1/UpdateService was unable to satisfy the request due to unavailability of resources."
}
}
Change-Id: Ida9a23c10aedbf9a48c96f4050a04e06bddff284
Signed-off-by: James Feist <james.feist@linux.intel.com>
diff --git a/redfish-core/include/error_messages.hpp b/redfish-core/include/error_messages.hpp
index ca921e9..0243be9 100644
--- a/redfish-core/include/error_messages.hpp
+++ b/redfish-core/include/error_messages.hpp
@@ -775,6 +775,18 @@
* @returns Message PasswordChangeRequired formatted to JSON */
void passwordChangeRequired(crow::Response& res, const std::string& arg1);
+/**
+ * @brief Formats InvalidUpload message into JSON
+ * Message body: Invalid file uploaded to %1: %2.*
+ * @param[in] arg1 Parameter of message that will replace %1 in its body.
+ * @param[in] arg2 Parameter of message that will replace %2 in its body.
+ *
+ * @returns Message InvalidUpload formatted to JSON */
+nlohmann::json invalidUpload(const std::string& arg1, const std::string& arg2);
+
+void invalidUpload(crow::Response& res, const std::string& arg1,
+ const std::string& arg2);
+
} // namespace messages
} // namespace redfish
diff --git a/redfish-core/include/registries/openbmc_message_registry.hpp b/redfish-core/include/registries/openbmc_message_registry.hpp
index 0856370..17b2070 100644
--- a/redfish-core/include/registries/openbmc_message_registry.hpp
+++ b/redfish-core/include/registries/openbmc_message_registry.hpp
@@ -29,7 +29,7 @@
"0.1.0",
"OpenBMC",
};
-constexpr std::array<MessageEntry, 181> registry = {
+constexpr std::array<MessageEntry, 182> registry = {
MessageEntry{
"ADDDCCorrectable",
{
@@ -453,6 +453,15 @@
{"string"},
"None.",
}},
+ MessageEntry{"InvalidUpload",
+ {
+ "Indicates that the uploaded file was invalid.",
+ "Invalid file uploaded to %1: %2.",
+ "Warning",
+ 2,
+ {"string", "string"},
+ "None.",
+ }},
MessageEntry{
"InventoryAdded",
{
diff --git a/redfish-core/lib/update_service.hpp b/redfish-core/lib/update_service.hpp
index fcb880e..8dae2fb 100644
--- a/redfish-core/lib/update_service.hpp
+++ b/redfish-core/lib/update_service.hpp
@@ -27,6 +27,7 @@
// Match signals added on software path
static std::unique_ptr<sdbusplus::bus::match::match> fwUpdateMatcher;
+static std::unique_ptr<sdbusplus::bus::match::match> fwUpdateErrorMatcher;
// Only allow one update at a time
static bool fwUpdateInProgress = false;
// Timer for software available
@@ -36,6 +37,7 @@
{
fwUpdateInProgress = false;
fwUpdateMatcher = nullptr;
+ fwUpdateErrorMatcher = nullptr;
}
static void activateImage(const std::string& objPath,
const std::string& service)
@@ -256,6 +258,7 @@
// then no asyncResp updates will occur
static void monitorForSoftwareAvailable(std::shared_ptr<AsyncResp> asyncResp,
const crow::Request& req,
+ const std::string& url,
int timeoutTimeSeconds = 5)
{
// Only allow one FW update at a time
@@ -308,6 +311,62 @@
"interface='org.freedesktop.DBus.ObjectManager',type='signal',"
"member='InterfacesAdded',path='/xyz/openbmc_project/software'",
callback);
+
+ fwUpdateErrorMatcher = std::make_unique<sdbusplus::bus::match::match>(
+ *crow::connections::systemBus,
+ "type='signal',member='PropertiesChanged',path_namespace='/xyz/"
+ "openbmc_project/logging/entry',"
+ "arg0='xyz.openbmc_project.Logging.Entry'",
+ [asyncResp, url](sdbusplus::message::message& m) {
+ BMCWEB_LOG_DEBUG << "Error Match fired";
+ boost::container::flat_map<std::string, std::variant<std::string>>
+ values;
+ std::string objName;
+ m.read(objName, values);
+ auto find = values.find("Message");
+ if (find == values.end())
+ {
+ return;
+ }
+ std::string* type = std::get_if<std::string>(&(find->second));
+ if (type == nullptr)
+ {
+ return; // if this was our message, timeout will cover it
+ }
+ if (!boost::starts_with(*type,
+ "xyz.openbmc_project.Software.Image.Error"))
+ {
+ return;
+ }
+ if (*type ==
+ "xyz.openbmc_project.Software.Image.Error.UnTarFailure")
+ {
+ redfish::messages::invalidUpload(asyncResp->res, url,
+ "Invalid archive");
+ }
+ else if (*type == "xyz.openbmc_project.Software.Image.Error."
+ "ManifestFileFailure")
+ {
+ redfish::messages::invalidUpload(asyncResp->res, url,
+ "Invalid manifest");
+ }
+ else if (*type ==
+ "xyz.openbmc_project.Software.Image.Error.ImageFailure")
+ {
+ redfish::messages::invalidUpload(asyncResp->res, url,
+ "Invalid image format");
+ }
+ else if (*type ==
+ "xyz.openbmc_project.Software.Image.Error.BusyFailure")
+ {
+ redfish::messages::resourceExhaustion(asyncResp->res, url);
+ }
+ else
+ {
+ redfish::messages::internalError(asyncResp->res);
+ }
+ fwAvailableTimer = nullptr;
+ });
}
/**
@@ -410,7 +469,10 @@
// Setup callback for when new software detected
// Give TFTP 2 minutes to complete
- monitorForSoftwareAvailable(nullptr, req, 120);
+ monitorForSoftwareAvailable(
+ nullptr, req,
+ "/redfish/v1/UpdateService/Actions/UpdateService.SimpleUpdate",
+ 120);
// TFTP can take up to 2 minutes depending on image size and
// connection speed. Return to caller as soon as the TFTP operation
@@ -605,7 +667,8 @@
std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
// Setup callback for when new software detected
- monitorForSoftwareAvailable(asyncResp, req);
+ monitorForSoftwareAvailable(asyncResp, req,
+ "/redfish/v1/UpdateService");
std::string filepath(
"/tmp/images/" +
diff --git a/redfish-core/src/error_messages.cpp b/redfish-core/src/error_messages.cpp
index 4be2687..160b73f 100644
--- a/redfish-core/src/error_messages.cpp
+++ b/redfish-core/src/error_messages.cpp
@@ -1725,6 +1725,31 @@
"provided."}});
}
+void invalidUpload(crow::Response& res, const std::string& arg1,
+ const std::string& arg2)
+{
+ res.result(boost::beast::http::status::bad_request);
+ addMessageToErrorJson(res.jsonValue, invalidUpload(arg1, arg2));
+}
+
+/**
+ * @internal
+ * @brief Formats Invalid File message into JSON
+ *
+ * See header file for more information
+ * @endinternal
+ */
+nlohmann::json invalidUpload(const std::string& arg1, const std::string& arg2)
+{
+ return nlohmann::json{
+ {"@odata.type", "/redfish/v1/$metadata#Message.v1_0_0.Message"},
+ {"MessageId", "OpenBMC.0.1.0.InvalidUpload"},
+ {"Message", "Invalid file uploaded to " + arg1 + ": " + arg2 + "."},
+ {"MessageArgs", {arg1, arg2}},
+ {"Severity", "Warning"},
+ {"Resolution", "None."}};
+}
+
} // namespace messages
} // namespace redfish