Add Redundancy to Thermal Schema
This looks for the FanRedundancy Interface
https://github.com/openbmc/phosphor-dbus-interfaces/blob/master/xyz/openbmc_project/Control/FanRedundancy.interface.yaml
and an association to type inventory. Using these it adds
Redundancy to the thermal schema.
Tested: Passes Redfish schema validator
Change-Id: Iffa32e445bd57234afeb5c682c9502c5daa227c1
Signed-off-by: James Feist <james.feist@linux.intel.com>
diff --git a/redfish-core/lib/sensors.hpp b/redfish-core/lib/sensors.hpp
index 376c7e4..bbed047 100644
--- a/redfish-core/lib/sensors.hpp
+++ b/redfish-core/lib/sensors.hpp
@@ -578,6 +578,202 @@
BMCWEB_LOG_DEBUG << "Added sensor " << sensorName;
}
+static void
+ populateFanRedundancy(std::shared_ptr<SensorsAsyncResp> sensorsAsyncResp)
+{
+ crow::connections::systemBus->async_method_call(
+ [sensorsAsyncResp](const boost::system::error_code ec,
+ const GetSubTreeType& resp) {
+ if (ec)
+ {
+ return; // don't have to have this interface
+ }
+ for (const auto& [path, objDict] : resp)
+ {
+ if (objDict.empty())
+ {
+ continue; // this should be impossible
+ }
+
+ const std::string& owner = objDict.begin()->first;
+ crow::connections::systemBus->async_method_call(
+ [path, owner,
+ sensorsAsyncResp](const boost::system::error_code ec,
+ std::variant<std::vector<std::string>>
+ variantEndpoints) {
+ if (ec)
+ {
+ return; // if they don't have an association we
+ // can't tell what chassis is
+ }
+ // verify part of the right chassis
+ auto endpoints = std::get_if<std::vector<std::string>>(
+ &variantEndpoints);
+
+ if (endpoints == nullptr)
+ {
+ BMCWEB_LOG_ERROR << "Invalid association interface";
+ messages::internalError(sensorsAsyncResp->res);
+ return;
+ }
+
+ auto found = std::find_if(
+ endpoints->begin(), endpoints->end(),
+ [sensorsAsyncResp](const std::string& entry) {
+ return entry.find(
+ sensorsAsyncResp->chassisId) !=
+ std::string::npos;
+ });
+
+ if (found == endpoints->end())
+ {
+ return;
+ }
+ crow::connections::systemBus->async_method_call(
+ [path, sensorsAsyncResp](
+ const boost::system::error_code ec,
+ const boost::container::flat_map<
+ std::string,
+ std::variant<uint8_t,
+ std::vector<std::string>,
+ std::string>>& ret) {
+ if (ec)
+ {
+ return; // don't have to have this
+ // interface
+ }
+ auto findFailures = ret.find("AllowedFailures");
+ auto findCollection = ret.find("Collection");
+ auto findStatus = ret.find("Status");
+
+ if (findFailures == ret.end() ||
+ findCollection == ret.end() ||
+ findStatus == ret.end())
+ {
+ BMCWEB_LOG_ERROR
+ << "Invalid redundancy interface";
+ messages::internalError(
+ sensorsAsyncResp->res);
+ return;
+ }
+
+ auto allowedFailures = std::get_if<uint8_t>(
+ &(findFailures->second));
+ auto collection =
+ std::get_if<std::vector<std::string>>(
+ &(findCollection->second));
+ auto status = std::get_if<std::string>(
+ &(findStatus->second));
+
+ if (allowedFailures == nullptr ||
+ collection == nullptr || status == nullptr)
+ {
+
+ BMCWEB_LOG_ERROR
+ << "Invalid redundancy interface "
+ "types";
+ messages::internalError(
+ sensorsAsyncResp->res);
+ return;
+ }
+ size_t lastSlash = path.rfind("/");
+ if (lastSlash == std::string::npos)
+ {
+ // this should be impossible
+ messages::internalError(
+ sensorsAsyncResp->res);
+ return;
+ }
+ std::string name = path.substr(lastSlash + 1);
+ std::replace(name.begin(), name.end(), '_',
+ ' ');
+
+ std::string health;
+
+ if (boost::ends_with(*status, "Full"))
+ {
+ health = "OK";
+ }
+ else if (boost::ends_with(*status, "Degraded"))
+ {
+ health = "Warning";
+ }
+ else
+ {
+ health = "Critical";
+ }
+ std::vector<nlohmann::json> redfishCollection;
+ const auto& fanRedfish =
+ sensorsAsyncResp->res.jsonValue["Fans"];
+ for (const std::string& item : *collection)
+ {
+ lastSlash = item.rfind("/");
+ // make a copy as collection is const
+ std::string itemName =
+ item.substr(lastSlash + 1);
+ /*
+ todo(ed): merge patch that fixes the names
+ std::replace(itemName.begin(),
+ itemName.end(), '_', ' ');*/
+ auto schemaItem = std::find_if(
+ fanRedfish.begin(), fanRedfish.end(),
+ [itemName](const nlohmann::json& fan) {
+ return fan["MemberId"] == itemName;
+ });
+ if (schemaItem != fanRedfish.end())
+ {
+ redfishCollection.push_back(
+ {{"@odata.id",
+ (*schemaItem)["@odata.id"]}});
+ }
+ else
+ {
+ BMCWEB_LOG_ERROR
+ << "failed to find fan in schema";
+ messages::internalError(
+ sensorsAsyncResp->res);
+ return;
+ }
+ }
+
+ auto& resp = sensorsAsyncResp->res
+ .jsonValue["Redundancy"];
+ resp.push_back(
+ {{"@odata.id",
+ "/refish/v1/Chassis/" +
+ sensorsAsyncResp->chassisId + "/" +
+ sensorsAsyncResp->chassisSubNode +
+ "#/Redundancy/" +
+ std::to_string(resp.size())},
+ {"@odata.type",
+ "#Redundancy.v1_3_2.Redundancy"},
+ {"MinNumNeeded",
+ collection->size() - *allowedFailures},
+ {"MemberId", name},
+ {"Mode", "N+m"},
+ {"Name", name},
+ {"RedundancySet", redfishCollection},
+ {"Status",
+ {{"Health", health},
+ {"State", "Enabled"}}}});
+ },
+ owner, path, "org.freedesktop.DBus.Properties",
+ "GetAll",
+ "xyz.openbmc_project.Control.FanRedundancy");
+ },
+ "xyz.openbmc_project.ObjectMapper", path + "/inventory",
+ "org.freedesktop.DBus.Properties", "Get",
+ "xyz.openbmc_project.Association", "endpoints");
+ }
+ },
+ "xyz.openbmc_project.ObjectMapper",
+ "/xyz/openbmc_project/object_mapper",
+ "xyz.openbmc_project.ObjectMapper", "GetSubTree",
+ "/xyz/openbmc_project/control", 2,
+ std::array<const char*, 1>{
+ "xyz.openbmc_project.Control.FanRedundancy"});
+}
+
/**
* @brief Gets the values of the specified sensors.
*
@@ -705,6 +901,11 @@
objectInterfacesToJson(sensorName, sensorType,
objDictEntry.second, sensorJson);
}
+ if (SensorsAsyncResp.use_count() == 1 &&
+ SensorsAsyncResp->chassisSubNode == "Thermal")
+ {
+ populateFanRedundancy(SensorsAsyncResp);
+ }
BMCWEB_LOG_DEBUG << "getManagedObjectsCb exit";
};