Health / Rollup Support
Look for associations for inventory and compare the
inventory warning / critical and global warning / critical
to get HealthRollup and Health respectively.
Tested:
Used sensor override to set BMC temp to Upper critical
and saw:
{
"@odata.context": "/redfish/v1/$metadata#Chassis.Chassis",
"@odata.id": "/redfish/v1/Chassis/WFP_Baseboard",
"@odata.type": "#Chassis.v1_4_0.Chassis",
"ChassisType": "RackMount",
"Id": "WFP_Baseboard",
"Links": {
"ComputerSystems": [
{
"@odata.id": "/redfish/v1/Systems/system"
}
],
"ManagedBy": [
{
"@odata.id": "/redfish/v1/Managers/bmc"
}
]
},
"Manufacturer": "Intel Corporation",
"Model": "S2600WFT",
"Name": "WFP_Baseboard",
"PartNumber": "123456789",
"Power": {
"@odata.id": "/redfish/v1/Chassis/WFP_Baseboard/Power"
},
"PowerState": "Off",
"SerialNumber": "123454321",
"Status": {
"Health": "Warning",
"HealthRollup": "Critical",
"State": "StandbyOffline"
},
"Thermal": {
"@odata.id": "/redfish/v1/Chassis/WFP_Baseboard/Thermal"
}
}
Change-Id: Idd9e832db18bb4769f1452fe243d68339a6f844d
Signed-off-by: James Feist <james.feist@linux.intel.com>
diff --git a/redfish-core/lib/chassis.hpp b/redfish-core/lib/chassis.hpp
index ae3201a..4426402 100644
--- a/redfish-core/lib/chassis.hpp
+++ b/redfish-core/lib/chassis.hpp
@@ -15,6 +15,7 @@
*/
#pragma once
+#include "health.hpp"
#include "node.hpp"
#include <boost/container/flat_map.hpp>
@@ -291,6 +292,30 @@
continue;
}
+ auto health = std::make_shared<HealthPopulate>(asyncResp);
+
+ crow::connections::systemBus->async_method_call(
+ [health](const boost::system::error_code ec,
+ std::variant<std::vector<std::string>> &resp) {
+ if (ec)
+ {
+ return; // no sensors = no failures
+ }
+ std::vector<std::string> *data =
+ std::get_if<std::vector<std::string>>(&resp);
+ if (data == nullptr)
+ {
+ return;
+ }
+ health->inventory = std::move(*data);
+ },
+ "xyz.openbmc_project.ObjectMapper",
+ path + "/all_sensors",
+ "org.freedesktop.DBus.Properties", "Get",
+ "xyz.openbmc_project.Association", "endpoints");
+
+ health->populate();
+
if (connectionNames.size() < 1)
{
BMCWEB_LOG_ERROR << "Only got "
@@ -347,7 +372,6 @@
{"@odata.id", "/redfish/v1/Chassis/" +
chassisId + "/Power"}};
asyncResp->res.jsonValue["Status"] = {
- {"Health", "OK"},
{"State", "Enabled"},
};
diff --git a/redfish-core/lib/health.hpp b/redfish-core/lib/health.hpp
new file mode 100644
index 0000000..da4f2d9
--- /dev/null
+++ b/redfish-core/lib/health.hpp
@@ -0,0 +1,194 @@
+/*
+// Copyright (c) 2019 Intel Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+#pragma once
+
+#include "async_resp.hpp"
+
+#include <boost/algorithm/string/predicate.hpp>
+#include <boost/container/flat_set.hpp>
+#include <dbus_singleton.hpp>
+#include <variant>
+
+namespace redfish
+{
+
+struct HealthPopulate : std::enable_shared_from_this<HealthPopulate>
+{
+ HealthPopulate(const std::shared_ptr<AsyncResp> &asyncResp) :
+ asyncResp(asyncResp)
+ {
+ }
+
+ ~HealthPopulate()
+ {
+ nlohmann::json &health = asyncResp->res.jsonValue["Status"]["Health"];
+ nlohmann::json &rollup =
+ asyncResp->res.jsonValue["Status"]["HealthRollup"];
+
+ health = "OK";
+ rollup = "OK";
+
+ for (const auto &[path, interfaces] : statuses)
+ {
+ bool isChild = false;
+
+ // managers inventory is all the inventory, don't skip any
+ if (!isManagersHealth)
+ {
+
+ // We only want to look at this association if either the path
+ // of this association is an inventory item, or one of the
+ // endpoints in this association is a child
+
+ for (const std::string &child : inventory)
+ {
+ if (boost::starts_with(path.str, child))
+ {
+ isChild = true;
+ break;
+ }
+ }
+ if (!isChild)
+ {
+ auto assocIt =
+ interfaces.find("xyz.openbmc_project.Association");
+ if (assocIt == interfaces.end())
+ {
+ continue;
+ }
+ auto endpointsIt = assocIt->second.find("endpoints");
+ if (endpointsIt == assocIt->second.end())
+ {
+ BMCWEB_LOG_ERROR << "Illegal association at "
+ << path.str;
+ continue;
+ }
+ const std::vector<std::string> *endpoints =
+ std::get_if<std::vector<std::string>>(
+ &endpointsIt->second);
+ if (endpoints == nullptr)
+ {
+ BMCWEB_LOG_ERROR << "Illegal association at "
+ << path.str;
+ continue;
+ }
+ bool containsChild = false;
+ for (const std::string &endpoint : *endpoints)
+ {
+ if (std::find(inventory.begin(), inventory.end(),
+ endpoint) != inventory.end())
+ {
+ containsChild = true;
+ break;
+ }
+ }
+ if (!containsChild)
+ {
+ continue;
+ }
+ }
+ }
+
+ if (boost::starts_with(path.str, globalInventoryPath) &&
+ boost::ends_with(path.str, "critical"))
+ {
+ health = "Critical";
+ rollup = "Critical";
+ return;
+ }
+ else if (boost::starts_with(path.str, globalInventoryPath) &&
+ boost::ends_with(path.str, "warning"))
+ {
+ health = "Warning";
+ if (rollup != "Critical")
+ {
+ rollup = "Warning";
+ }
+ }
+ else if (boost::ends_with(path.str, "critical"))
+ {
+ rollup = "Critical";
+ }
+ else if (boost::ends_with(path.str, "warning"))
+ {
+ if (rollup != "Critical")
+ {
+ rollup = "Warning";
+ }
+ }
+ }
+ }
+
+ void populate()
+ {
+ getAllStatusAssociations();
+ getGlobalPath();
+ }
+
+ void getGlobalPath()
+ {
+ std::shared_ptr<HealthPopulate> self = shared_from_this();
+ crow::connections::systemBus->async_method_call(
+ [self](const boost::system::error_code ec,
+ std::vector<std::string> &resp) {
+ if (ec || resp.size() != 1)
+ {
+ // no global item, or too many
+ return;
+ }
+ self->globalInventoryPath = std::move(resp[0]);
+ },
+ "xyz.openbmc_project.ObjectMapper",
+ "/xyz/openbmc_project/object_mapper",
+ "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", "/",
+ int32_t(0),
+ std::array<const char *, 1>{
+ "xyz.openbmc_project.Inventory.Item.Global"});
+ }
+
+ void getAllStatusAssociations()
+ {
+ std::shared_ptr<HealthPopulate> self = shared_from_this();
+ crow::connections::systemBus->async_method_call(
+ [self](const boost::system::error_code ec,
+ dbus::utility::ManagedObjectType &resp) {
+ if (ec)
+ {
+ return;
+ }
+ for (auto it = resp.begin(); it != resp.end();)
+ {
+ if (boost::ends_with(it->first.str, "critical") ||
+ boost::ends_with(it->first.str, "warning"))
+ {
+ it++;
+ continue;
+ }
+ it = resp.erase(it);
+ }
+ self->statuses = std::move(resp);
+ },
+ "xyz.openbmc_project.ObjectMapper", "/",
+ "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
+ }
+
+ std::shared_ptr<AsyncResp> asyncResp;
+ std::vector<std::string> inventory;
+ bool isManagersHealth = false;
+ dbus::utility::ManagedObjectType statuses;
+ std::string globalInventoryPath = "-"; // default to illegal dbus path
+};
+} // namespace redfish
\ No newline at end of file
diff --git a/redfish-core/lib/managers.hpp b/redfish-core/lib/managers.hpp
index bb9a6ac..60f8856 100644
--- a/redfish-core/lib/managers.hpp
+++ b/redfish-core/lib/managers.hpp
@@ -15,6 +15,7 @@
*/
#pragma once
+#include "health.hpp"
#include "node.hpp"
#include "redfish_util.hpp"
@@ -1522,6 +1523,10 @@
std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
+ auto health = std::make_shared<HealthPopulate>(asyncResp);
+ health->isManagersHealth = true;
+ health->populate();
+
crow::connections::systemBus->async_method_call(
[asyncResp](const boost::system::error_code ec,
const dbus::utility::ManagedObjectType& resp) {
diff --git a/redfish-core/lib/systems.hpp b/redfish-core/lib/systems.hpp
index 6ea5f2e..f28ab92 100644
--- a/redfish-core/lib/systems.hpp
+++ b/redfish-core/lib/systems.hpp
@@ -15,6 +15,7 @@
*/
#pragma once
+#include "health.hpp"
#include "redfish_util.hpp"
#include <boost/container/flat_map.hpp>
@@ -1215,6 +1216,29 @@
};
auto asyncResp = std::make_shared<AsyncResp>(res);
+ constexpr const std::array<const char *, 2> inventoryForSystems = {
+ "xyz.openbmc_project.Inventory.Item.Dimm",
+ "xyz.openbmc_project.Inventory.Item.Cpu"};
+
+ auto health = std::make_shared<HealthPopulate>(asyncResp);
+ crow::connections::systemBus->async_method_call(
+ [health](const boost::system::error_code ec,
+ std::vector<std::string> &resp) {
+ if (ec)
+ {
+ // no inventory
+ return;
+ }
+
+ health->inventory = std::move(resp);
+ },
+ "xyz.openbmc_project.ObjectMapper",
+ "/xyz/openbmc_project/object_mapper",
+ "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", "/",
+ int32_t(0), inventoryForSystems);
+
+ health->populate();
+
getMainChassisId(asyncResp, [](const std::string &chassisId,
std::shared_ptr<AsyncResp> aRsp) {
aRsp->res.jsonValue["Links"]["Chassis"] = {