fw-inventory: Provide BiosVersion in system obj
Created a new fw_utils.hpp to reduce more indentation code in
systems.hpp and also as a base for some future refactoring for common
use cases to access firmware information.
Tested:
- Verified RedfishServiceValidator.py shows no new errors
VERBO - ComputerSystem.v1_0_0.ComputerSystem:BiosVersion
VERBO - value: IBM-witherspoon-OP9-v2.0.10-2.22 <class 'str'>
VERBO - has Type: Edm.String Edm.String
VERBO - is Optional
VERBO - permission OData.Permission/Read
VERBO - Success
- BiosVersion now correctly returned in data
$ curl -k -H "X-Auth-Token: $TOKEN" -X GET https://${BMC_IP}/redfish/v1/Systems/system
{
"@odata.context": "/redfish/v1/$metadata#ComputerSystem.ComputerSystem",
"@odata.id": "/redfish/v1/Systems/system",
"@odata.type": "#ComputerSystem.v1_5_1.ComputerSystem",
"Actions": {
"#ComputerSystem.Reset": {
"ResetType@Redfish.AllowableValues": [
"On",
"ForceOff",
"GracefulRestart",
"GracefulShutdown"
],
"target": "/redfish/v1/Systems/system/Actions/ComputerSystem.Reset"
}
},
"BiosVersion": "IBM-witherspoon-OP9-v2.0.10-2.22",
...
}
Change-Id: I2d7792c724f88aa13bd7b40c0d7f70dd4aa1c807
Signed-off-by: Andrew Geissler <geissonator@yahoo.com>
diff --git a/redfish-core/include/utils/fw_utils.hpp b/redfish-core/include/utils/fw_utils.hpp
new file mode 100644
index 0000000..18773ae
--- /dev/null
+++ b/redfish-core/include/utils/fw_utils.hpp
@@ -0,0 +1,190 @@
+#pragma once
+#include <async_resp.hpp>
+#include <string>
+
+namespace redfish
+{
+namespace fw_util
+{
+/* @brief String that indicates a bios firmware instance */
+constexpr const char *biosPurpose =
+ "xyz.openbmc_project.Software.Version.VersionPurpose.Host";
+
+/* @brief String that indicates a BMC firmware instance */
+constexpr const char *bmcPurpose =
+ "xyz.openbmc_project.Software.Version.VersionPurpose.BMC";
+
+/**
+ * @brief Put fw version of input type into async response json structure
+ *
+ * @param[i,o] aResp Async response object
+ * @param[i] fwVersionPurpose Indicates what target to look for
+ * @param[i] jsonIdxStr Index in aResp->res.jsonValue to write fw ver
+ *
+ * @return void
+ */
+void getActiveFwVersion(std::shared_ptr<AsyncResp> aResp,
+ const std::string &fwVersionPurpose,
+ const std::string &jsonIdxStr)
+{
+ // Get active FW images
+ crow::connections::systemBus->async_method_call(
+ [aResp, fwVersionPurpose,
+ jsonIdxStr](const boost::system::error_code ec,
+ const std::variant<std::vector<std::string>> &resp) {
+ if (ec)
+ {
+ BMCWEB_LOG_ERROR << "error_code = " << ec;
+ BMCWEB_LOG_ERROR << "error msg = " << ec.message();
+ messages::internalError(aResp->res);
+ return;
+ }
+ const std::vector<std::string> *functionalFw =
+ std::get_if<std::vector<std::string>>(&resp);
+ if ((functionalFw == nullptr) || (functionalFw->size() == 0))
+ {
+ BMCWEB_LOG_ERROR << "Zero functional software in system";
+ messages::internalError(aResp->res);
+ return;
+ }
+ // example functionalFw:
+ // v as 2 "/xyz/openbmc_project/software/ace821ef"
+ // "/xyz/openbmc_project/software/230fb078"
+ for (auto &fw : *functionalFw)
+ {
+ // if can't parse fw id then return
+ std::string::size_type idPos = fw.rfind("/");
+ if (idPos == std::string::npos)
+ {
+ messages::internalError(aResp->res);
+ BMCWEB_LOG_DEBUG << "Can't parse firmware ID!!";
+ return;
+ }
+ idPos++;
+ if (idPos >= fw.size())
+ {
+ messages::internalError(aResp->res);
+ BMCWEB_LOG_DEBUG << "Invalid firmware ID";
+ return;
+ }
+ std::string swId = fw.substr(idPos);
+
+ // Now find service that hosts it
+ crow::connections::systemBus->async_method_call(
+ [aResp, fw, swId, fwVersionPurpose, jsonIdxStr](
+ const boost::system::error_code ec,
+ const std::vector<std::pair<
+ std::string, std::vector<std::string>>> &objInfo) {
+ if (ec)
+ {
+ BMCWEB_LOG_DEBUG << "error_code = " << ec;
+ BMCWEB_LOG_DEBUG << "error msg = " << ec.message();
+ messages::internalError(aResp->res);
+ return;
+ }
+ // Example objInfo
+ // a{sas} 1 "org.open_power.Software.Host.Updater" 10
+ // "org.freedesktop.DBus.Introspectable"
+ // "org.freedesktop.DBus.Peer"
+ // "org.freedesktop.DBus.Properties"
+ // "org.openbmc.Associations"
+ // "xyz.openbmc_project.Common.FilePath"
+ // "xyz.openbmc_project.Object.Delete"
+ // "xyz.openbmc_project.Software.Activation"
+ // "xyz.openbmc_project.Software.ExtendedVersion"
+ // "xyz.openbmc_project.Software.RedundancyPriority"
+ // "xyz.openbmc_project.Software.Version"
+
+ // Ensure we only got one service back
+ if (objInfo.size() != 1)
+ {
+ BMCWEB_LOG_ERROR << "Invalid Object Size "
+ << objInfo.size();
+ messages::internalError(aResp->res);
+ return;
+ }
+
+ // Now grab its version info
+ crow::connections::systemBus->async_method_call(
+ [aResp, swId, fwVersionPurpose, jsonIdxStr](
+ const boost::system::error_code ec,
+ const boost::container::flat_map<
+ std::string, VariantType> &propertiesList) {
+ if (ec)
+ {
+ BMCWEB_LOG_ERROR << "error_code = " << ec;
+ BMCWEB_LOG_ERROR << "error msg = "
+ << ec.message();
+ messages::internalError(aResp->res);
+ return;
+ }
+ // example propertiesList
+ // a{sv} 2 "Version" s
+ // "IBM-witherspoon-OP9-v2.0.10-2.22" "Purpose"
+ // s
+ // "xyz.openbmc_project.Software.Version.VersionPurpose.Host"
+
+ boost::container::flat_map<
+ std::string, VariantType>::const_iterator
+ it = propertiesList.find("Purpose");
+ if (it == propertiesList.end())
+ {
+ BMCWEB_LOG_DEBUG
+ << "Can't find property \"Purpose\"!";
+ messages::internalError(aResp->res);
+ return;
+ }
+ const std::string *swInvPurpose =
+ std::get_if<std::string>(&it->second);
+ if (swInvPurpose == nullptr)
+ {
+ BMCWEB_LOG_DEBUG << "wrong types for "
+ "property \"Purpose\"!";
+ messages::internalError(aResp->res);
+ return;
+ }
+
+ if (*swInvPurpose != fwVersionPurpose)
+ {
+ // Not purpose we're looking for
+ return;
+ }
+ it = propertiesList.find("Version");
+ if (it == propertiesList.end())
+ {
+ BMCWEB_LOG_DEBUG
+ << "Can't find property \"Version\"!";
+ messages::internalError(aResp->res);
+ return;
+ }
+ const std::string *version =
+ std::get_if<std::string>(&it->second);
+ if (version == nullptr)
+ {
+ BMCWEB_LOG_DEBUG
+ << "Error getting fw version";
+ messages::internalError(aResp->res);
+ return;
+ }
+ aResp->res.jsonValue[jsonIdxStr] = *version;
+ },
+ objInfo[0].first, fw,
+ "org.freedesktop.DBus.Properties", "GetAll",
+ "xyz.openbmc_project.Software.Version");
+ },
+ "xyz.openbmc_project.ObjectMapper",
+ "/xyz/openbmc_project/object_mapper",
+ "xyz.openbmc_project.ObjectMapper", "GetObject", fw,
+ std::array<const char *, 1>{
+ "xyz.openbmc_project.Software.Activation"});
+ }
+ },
+ "xyz.openbmc_project.ObjectMapper",
+ "/xyz/openbmc_project/software/functional",
+ "org.freedesktop.DBus.Properties", "Get",
+ "xyz.openbmc_project.Association", "endpoints");
+
+ return;
+}
+} // namespace fw_util
+} // namespace redfish
diff --git a/redfish-core/lib/systems.hpp b/redfish-core/lib/systems.hpp
index 255c094..236767c 100644
--- a/redfish-core/lib/systems.hpp
+++ b/redfish-core/lib/systems.hpp
@@ -17,6 +17,7 @@
#include <boost/container/flat_map.hpp>
#include <node.hpp>
+#include <utils/fw_utils.hpp>
#include <utils/json_utils.hpp>
#include <variant>
@@ -192,19 +193,6 @@
VariantType>
&property : properties)
{
- if (property.first == "BIOSVer")
- {
- const std::string *value =
- sdbusplus::message::variant_ns::
- get_if<std::string>(
- &property.second);
- if (value != nullptr)
- {
- aResp->res
- .jsonValue["BiosVersion"] =
- *value;
- }
- }
if (property.first == "UUID")
{
const std::string *value =
@@ -277,6 +265,10 @@
aResp->res.jsonValue["Name"] = "system";
aResp->res.jsonValue["Id"] =
aResp->res.jsonValue["SerialNumber"];
+ // Grab the bios version
+ fw_util::getActiveFwVersion(
+ aResp, fw_util::biosPurpose,
+ "BiosVersion");
},
connection.first, path,
"org.freedesktop.DBus.Properties", "GetAll",