diff options
author | Anthony Wilson <wilsonan@us.ibm.com> | 2019-08-01 00:34:17 +0300 |
---|---|---|
committer | Andrew Geissler <geissonator@yahoo.com> | 2019-11-19 00:06:07 +0300 |
commit | d500549b209761e46791458b49ce2fee5c8b682b (patch) | |
tree | 79261a3df9e9ff66ee0245cd08ef933afba174ac /redfish-core | |
parent | f847a198a016c1932177dee62f9a21c6efa6644e (diff) | |
download | bmcweb-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')
-rw-r--r-- | redfish-core/lib/sensors.hpp | 327 |
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"; |