summaryrefslogtreecommitdiff
path: root/redfish-core/lib
diff options
context:
space:
mode:
authorAnthony Wilson <wilsonan@us.ibm.com>2019-08-01 00:34:17 +0300
committerAndrew Geissler <geissonator@yahoo.com>2019-11-19 00:06:07 +0300
commitd500549b209761e46791458b49ce2fee5c8b682b (patch)
tree79261a3df9e9ff66ee0245cd08ef933afba174ac /redfish-core/lib
parentf847a198a016c1932177dee62f9a21c6efa6644e (diff)
downloadbmcweb-d500549b209761e46791458b49ce2fee5c8b682b.tar.xz
bmcweb: Add IndicatorLED property to sensors
Added support for the IndicatorLED property for physical leds associated with Thermal and Power sensors. Testing: Verified output on a witherspoon. No new errors in redfish validation. Change-Id: I4e49b3c1769742e49f57c6c1b77a82511cdc8b99 Signed-off-by: Anthony Wilson <wilsonan@us.ibm.com>
Diffstat (limited to 'redfish-core/lib')
-rw-r--r--redfish-core/lib/sensors.hpp327
1 files changed, 321 insertions, 6 deletions
diff --git a/redfish-core/lib/sensors.hpp b/redfish-core/lib/sensors.hpp
index fb3b25e2b8..c900863f13 100644
--- a/redfish-core/lib/sensors.hpp
+++ b/redfish-core/lib/sensors.hpp
@@ -75,6 +75,17 @@ class SensorsAsyncResp
};
/**
+ * Possible states for physical inventory leds
+ */
+enum class LedState
+{
+ OFF,
+ ON,
+ BLINK,
+ UNKNOWN
+};
+
+/**
* D-Bus inventory item associated with one or more sensors.
*/
class InventoryItem
@@ -83,7 +94,8 @@ class InventoryItem
InventoryItem(const std::string& objPath) :
objectPath(objPath), name(), isPresent(true), isFunctional(true),
isPowerSupply(false), manufacturer(), model(), partNumber(),
- serialNumber(), sensors()
+ serialNumber(), sensors(), ledObjectPath(""),
+ ledState(LedState::UNKNOWN)
{
// Set inventory item name to last node of object path
auto pos = objectPath.rfind('/');
@@ -103,6 +115,8 @@ class InventoryItem
std::string partNumber;
std::string serialNumber;
std::set<std::string> sensors;
+ std::string ledObjectPath;
+ LedState ledState;
};
/**
@@ -596,6 +610,28 @@ static std::string getHealth(
return "OK";
}
+static void setLedState(nlohmann::json& sensorJson,
+ const InventoryItem* inventoryItem)
+{
+ if (inventoryItem != nullptr && !inventoryItem->ledObjectPath.empty())
+ {
+ switch (inventoryItem->ledState)
+ {
+ case LedState::OFF:
+ sensorJson["IndicatorLED"] = "Off";
+ break;
+ case LedState::ON:
+ sensorJson["IndicatorLED"] = "Lit";
+ break;
+ case LedState::BLINK:
+ sensorJson["IndicatorLED"] = "Blinking";
+ break;
+ default:
+ break;
+ }
+ }
+}
+
/**
* @brief Builds a json sensor representation of a sensor.
* @param sensorName The name of the sensor to be built
@@ -690,6 +726,7 @@ void objectInterfacesToJson(
unit = "/Reading"_json_pointer;
sensor_json["ReadingUnits"] = "RPM";
sensor_json["@odata.type"] = "#Thermal.v1_3_0.Fan";
+ setLedState(sensor_json, inventoryItem);
forceToInt = true;
}
else if (sensorType == "fan_pwm")
@@ -697,6 +734,7 @@ void objectInterfacesToJson(
unit = "/Reading"_json_pointer;
sensor_json["ReadingUnits"] = "Percent";
sensor_json["@odata.type"] = "#Thermal.v1_3_0.Fan";
+ setLedState(sensor_json, inventoryItem);
forceToInt = true;
}
else if (sensorType == "voltage")
@@ -1132,6 +1170,26 @@ static InventoryItem* findInventoryItemForSensor(
}
/**
+ * @brief Finds the inventory item associated with the specified led path.
+ * @param inventoryItems D-Bus inventory items associated with sensors.
+ * @param ledObjPath D-Bus object path of led.
+ * @return Inventory item within vector, or nullptr if no match found.
+ */
+inline InventoryItem*
+ findInventoryItemForLed(std::vector<InventoryItem>& inventoryItems,
+ const std::string& ledObjPath)
+{
+ for (InventoryItem& inventoryItem : inventoryItems)
+ {
+ if (inventoryItem.ledObjectPath == ledObjPath)
+ {
+ return &inventoryItem;
+ }
+ }
+ return nullptr;
+}
+
+/**
* @brief Adds inventory item and associated sensor to specified vector.
*
* Adds a new InventoryItem to the vector if necessary. Searches for an
@@ -1290,7 +1348,7 @@ static void storeInventoryItemData(
*
* The callback must have the following signature:
* @code
- * callback(std::shared_ptr<std::vector<InventoryItem>> inventoryItems)
+ * callback(void)
* @endcode
*
* This function is called recursively, obtaining data asynchronously from one
@@ -1320,7 +1378,7 @@ static void getInventoryItemsData(
// If no more connections left, call callback
if (invConnectionsIndex >= invConnections->size())
{
- callback(inventoryItems);
+ callback();
BMCWEB_LOG_DEBUG << "getInventoryItemsData exit";
return;
}
@@ -1459,6 +1517,7 @@ static void getInventoryItemsConnections(
}
}
}
+
callback(invConnections);
BMCWEB_LOG_DEBUG << "getInventoryItemsConnections respHandler exit";
};
@@ -1475,7 +1534,8 @@ static void getInventoryItemsConnections(
* @brief Gets associations from sensors to inventory items.
*
* Looks for ObjectMapper associations from the specified sensors to related
- * inventory items.
+ * inventory items. Then finds the associations from those inventory items to
+ * their LEDs, if any.
*
* Finds the inventory items asynchronously. Invokes callback when information
* has been obtained.
@@ -1564,6 +1624,49 @@ static void getInventoryItemAssociations(
}
}
+ // Now loop through the returned object paths again, this time to
+ // find the leds associated with the inventory items we just found
+ std::string inventoryAssocPath;
+ inventoryAssocPath.reserve(128); // avoid memory allocations
+ for (const auto& objDictEntry : resp)
+ {
+ const std::string& objPath =
+ static_cast<const std::string&>(objDictEntry.first);
+ const boost::container::flat_map<
+ std::string, boost::container::flat_map<
+ std::string, dbus::utility::DbusVariantType>>&
+ interfacesDict = objDictEntry.second;
+
+ for (InventoryItem& inventoryItem : *inventoryItems)
+ {
+ inventoryAssocPath = inventoryItem.objectPath;
+ inventoryAssocPath += "/leds";
+ if (objPath == inventoryAssocPath)
+ {
+ // Get Association interface for object path
+ auto assocIt =
+ interfacesDict.find("xyz.openbmc_project.Association");
+ if (assocIt != interfacesDict.end())
+ {
+ // Get inventory item from end point
+ auto endpointsIt = assocIt->second.find("endpoints");
+ if (endpointsIt != assocIt->second.end())
+ {
+ const std::vector<std::string>* endpoints =
+ std::get_if<std::vector<std::string>>(
+ &endpointsIt->second);
+ if ((endpoints != nullptr) && !endpoints->empty())
+ {
+ // Store LED path in inventory item
+ const std::string& ledPath = endpoints->front();
+ inventoryItem.ledObjectPath = ledPath;
+ }
+ }
+ }
+ break;
+ }
+ }
+ }
callback(inventoryItems);
BMCWEB_LOG_DEBUG << "getInventoryItemAssociations respHandler exit";
};
@@ -1585,6 +1688,209 @@ static void getInventoryItemAssociations(
}
/**
+ * @brief Gets D-Bus data for inventory item leds associated with sensors.
+ *
+ * Uses the specified connections (services) to obtain D-Bus data for inventory
+ * item leds associated with sensors. Stores the resulting data in the
+ * inventoryItems vector.
+ *
+ * This data is later used to provide sensor property values in the JSON
+ * response.
+ *
+ * Finds the inventory item led data asynchronously. Invokes callback when data
+ * has been obtained.
+ *
+ * The callback must have the following signature:
+ * @code
+ * callback(std::shared_ptr<std::vector<InventoryItem>> inventoryItems)
+ * @endcode
+ *
+ * This function is called recursively, obtaining data asynchronously from one
+ * connection in each call. This ensures the callback is not invoked until the
+ * last asynchronous function has completed.
+ *
+ * @param sensorsAsyncResp Pointer to object holding response data.
+ * @param inventoryItems D-Bus inventory items associated with sensors.
+ * @param ledConnections Connections that provide data for the inventory leds.
+ * @param callback Callback to invoke when inventory data has been obtained.
+ * @param ledConnectionsIndex Current index in ledConnections. Only specified
+ * in recursive calls to this function.
+ */
+template <typename Callback>
+void getInventoryLedData(
+ std::shared_ptr<SensorsAsyncResp> sensorsAsyncResp,
+ std::shared_ptr<std::vector<InventoryItem>> inventoryItems,
+ std::shared_ptr<boost::container::flat_map<std::string, std::string>>
+ ledConnections,
+ Callback&& callback, size_t ledConnectionsIndex = 0)
+{
+ BMCWEB_LOG_DEBUG << "getInventoryLedData enter";
+
+ // If no more connections left, call callback
+ if (ledConnectionsIndex >= ledConnections->size())
+ {
+ callback(inventoryItems);
+ BMCWEB_LOG_DEBUG << "getInventoryLedData exit";
+ return;
+ }
+
+ // Get inventory item data from current connection
+ auto it = ledConnections->nth(ledConnectionsIndex);
+ if (it != ledConnections->end())
+ {
+ const std::string& ledPath = (*it).first;
+ const std::string& ledConnection = (*it).second;
+ // Response handler for Get State property
+ auto respHandler =
+ [sensorsAsyncResp, inventoryItems, ledConnections, ledPath,
+ callback{std::move(callback)},
+ ledConnectionsIndex](const boost::system::error_code ec,
+ const std::variant<std::string>& ledState) {
+ BMCWEB_LOG_DEBUG << "getInventoryLedData respHandler enter";
+ if (ec)
+ {
+ BMCWEB_LOG_ERROR
+ << "getInventoryLedData respHandler DBus error " << ec;
+ messages::internalError(sensorsAsyncResp->res);
+ return;
+ }
+
+ const std::string* state = std::get_if<std::string>(&ledState);
+ if (state != nullptr)
+ {
+ BMCWEB_LOG_DEBUG << "Led state: " << *state;
+ // Find inventory item with this LED object path
+ InventoryItem* inventoryItem =
+ findInventoryItemForLed(*inventoryItems, ledPath);
+ if (inventoryItem != nullptr)
+ {
+ // Store LED state in InventoryItem
+ if (boost::ends_with(*state, "On"))
+ {
+ inventoryItem->ledState = LedState::ON;
+ }
+ else if (boost::ends_with(*state, "Blink"))
+ {
+ inventoryItem->ledState = LedState::BLINK;
+ }
+ else if (boost::ends_with(*state, "Off"))
+ {
+ inventoryItem->ledState = LedState::OFF;
+ }
+ else
+ {
+ inventoryItem->ledState = LedState::UNKNOWN;
+ }
+ }
+ }
+ else
+ {
+ BMCWEB_LOG_DEBUG << "Failed to find State data for LED: "
+ << ledPath;
+ }
+
+ // Recurse to get LED data from next connection
+ getInventoryLedData(sensorsAsyncResp, inventoryItems,
+ ledConnections, std::move(callback),
+ ledConnectionsIndex + 1);
+
+ BMCWEB_LOG_DEBUG << "getInventoryLedData respHandler exit";
+ };
+
+ // Get the State property for the current LED
+ crow::connections::systemBus->async_method_call(
+ std::move(respHandler), ledConnection, ledPath,
+ "org.freedesktop.DBus.Properties", "Get",
+ "xyz.openbmc_project.Led.Physical", "State");
+ }
+
+ BMCWEB_LOG_DEBUG << "getInventoryLedData exit";
+}
+
+/**
+ * @brief Gets LED data for LEDs associated with given inventory items.
+ *
+ * Gets the D-Bus connections (services) that provide LED data for the LEDs
+ * associated with the specified inventory items. Then gets the LED data from
+ * each connection and stores it in the inventory item.
+ *
+ * This data is later used to provide sensor property values in the JSON
+ * response.
+ *
+ * Finds the LED data asynchronously. Invokes callback when information has
+ * been obtained.
+ *
+ * The callback must have the following signature:
+ * @code
+ * callback(std::shared_ptr<std::vector<InventoryItem>> inventoryItems)
+ * @endcode
+ *
+ * @param sensorsAsyncResp Pointer to object holding response data.
+ * @param inventoryItems D-Bus inventory items associated with sensors.
+ * @param callback Callback to invoke when inventory items have been obtained.
+ */
+template <typename Callback>
+void getInventoryLeds(
+ std::shared_ptr<SensorsAsyncResp> sensorsAsyncResp,
+ std::shared_ptr<std::vector<InventoryItem>> inventoryItems,
+ Callback&& callback)
+{
+ BMCWEB_LOG_DEBUG << "getInventoryLeds enter";
+
+ const std::string path = "/xyz/openbmc_project";
+ const std::array<std::string, 1> interfaces = {
+ "xyz.openbmc_project.Led.Physical"};
+
+ // Response handler for parsing output from GetSubTree
+ auto respHandler = [callback{std::move(callback)}, sensorsAsyncResp,
+ inventoryItems](const boost::system::error_code ec,
+ const GetSubTreeType& subtree) {
+ BMCWEB_LOG_DEBUG << "getInventoryLeds respHandler enter";
+ if (ec)
+ {
+ messages::internalError(sensorsAsyncResp->res);
+ BMCWEB_LOG_ERROR << "getInventoryLeds respHandler DBus error "
+ << ec;
+ return;
+ }
+
+ // Build map of LED object paths to connections
+ std::shared_ptr<boost::container::flat_map<std::string, std::string>>
+ ledConnections = std::make_shared<
+ boost::container::flat_map<std::string, std::string>>();
+
+ // Loop through objects from GetSubTree
+ for (const std::pair<
+ std::string,
+ std::vector<std::pair<std::string, std::vector<std::string>>>>&
+ object : subtree)
+ {
+ // Check if object path is LED for one of the specified inventory
+ // items
+ const std::string& ledPath = object.first;
+ if (findInventoryItemForLed(*inventoryItems, ledPath) != nullptr)
+ {
+ // Add mapping from ledPath to connection
+ const std::string& connection = object.second.begin()->first;
+ (*ledConnections)[ledPath] = connection;
+ BMCWEB_LOG_DEBUG << "Added mapping " << ledPath << " -> "
+ << connection;
+ }
+ }
+
+ getInventoryLedData(sensorsAsyncResp, inventoryItems, ledConnections,
+ std::move(callback));
+ BMCWEB_LOG_DEBUG << "getInventoryLeds respHandler exit";
+ };
+ // Make call to ObjectMapper to find all inventory items
+ crow::connections::systemBus->async_method_call(
+ std::move(respHandler), "xyz.openbmc_project.ObjectMapper",
+ "/xyz/openbmc_project/object_mapper",
+ "xyz.openbmc_project.ObjectMapper", "GetSubTree", path, 0, interfaces);
+ BMCWEB_LOG_DEBUG << "getInventoryLeds exit";
+}
+
+/**
* @brief Gets inventory items associated with sensors.
*
* Finds the inventory items that are associated with the specified sensors.
@@ -1626,12 +1932,20 @@ static void getInventoryItems(
std::shared_ptr<boost::container::flat_set<std::string>>
invConnections) {
BMCWEB_LOG_DEBUG << "getInventoryItemsConnectionsCb enter";
+ auto getInventoryItemsDataCb =
+ [sensorsAsyncResp, inventoryItems,
+ callback{std::move(callback)}]() {
+ BMCWEB_LOG_DEBUG << "getInventoryItemsDataCb enter";
+ // Find led connections and get the data
+ getInventoryLeds(sensorsAsyncResp, inventoryItems,
+ std::move(callback));
+ BMCWEB_LOG_DEBUG << "getInventoryItemsDataCb exit";
+ };
// Get inventory item data from connections
getInventoryItemsData(sensorsAsyncResp, inventoryItems,
invConnections, objectMgrPaths,
- std::move(callback));
-
+ std::move(getInventoryItemsDataCb));
BMCWEB_LOG_DEBUG << "getInventoryItemsConnectionsCb exit";
};
@@ -1688,6 +2002,7 @@ static nlohmann::json& getPowerSupply(nlohmann::json& powerSupplyArray,
powerSupply["Model"] = inventoryItem.model;
powerSupply["PartNumber"] = inventoryItem.partNumber;
powerSupply["SerialNumber"] = inventoryItem.serialNumber;
+ setLedState(powerSupply, &inventoryItem);
powerSupply["Status"]["State"] = getState(&inventoryItem);
const char* health = inventoryItem.isFunctional ? "OK" : "Critical";