summaryrefslogtreecommitdiff
path: root/redfish-core/lib/sensors.hpp
diff options
context:
space:
mode:
authorAdrian Ambrożewicz <adrian.ambrozewicz@linux.intel.com>2020-04-10 15:47:28 +0300
committerAdrian Ambrożewicz <adrian.ambrozewicz@linux.intel.com>2020-06-26 17:49:26 +0300
commita0ec28b671391473a6dbe1258fb5216311861396 (patch)
treebb500f2387b784f728a0b06006c1a115a677202b /redfish-core/lib/sensors.hpp
parent4bf2b03324acbacce3eb948e6b00a7c8f1f2d756 (diff)
downloadbmcweb-a0ec28b671391473a6dbe1258fb5216311861396.tar.xz
Enable retrieving mapping of Redfish URI to D-Bus sensor path
Background: Change is necessary to support TelemetryService implementation. TelemetryService specifies its own resource type for data - MetricDefinition. In principle - MetricDefinition might point to Redfish Sensor in the system. Each MetricDefinition requires MetricProperty - URI to specific property in resource wih the value. This change allows retrieving such data alongside corresponding D-Bus sensor to be used as source of Metrics value. This change: Function was implemented to allow retrieving mapping of Redfish URI paths to D-Bus sensors in the system. Some minor refactoring in regards to SensorsAsyncResponse were also introduced to enhance code locality. Idea for the changes was to be the least intrusive if possible, as retrieving sensors in the system requires lots of processing. Existing logic was used and left intact. Utilizing existing logic required to 'fake' a HTTP request to traverse the sensors in the system and build the response. It's crucial to use exact logic of building Redfish nodes representation, as goal of the function is to retrieve exact Redfish URI for sensor value. Extra parameter was introduced to SensorsAsyncResp - callback to be called when sensor data will be fully determined. After processing is complete caller is notified with the outcome (success or failure) and map<URI:D-Bus sensor>. Testing: - all positive cases (3 chassis, 3 subnodes) in the system, one of obtained mappings looked like the following: { /redfish/v1/Chassis/WP_Baseboard/Power#/Voltages/3/ReadingVolts : /xyz/openbmc_project/sensors/voltage/P1V8_PCH } - negative cases (wrong chassis, wrong subnode) - callback with error status was called - RedfishServiceValidator passed Signed-off-by: Adrian Ambrożewicz <adrian.ambrozewicz@linux.intel.com> Change-Id: I4389eb3df275126974168d1bb9af33dbf5cdb5b7
Diffstat (limited to 'redfish-core/lib/sensors.hpp')
-rw-r--r--redfish-core/lib/sensors.hpp205
1 files changed, 170 insertions, 35 deletions
diff --git a/redfish-core/lib/sensors.hpp b/redfish-core/lib/sensors.hpp
index f5ad839f7d..212a4a4125 100644
--- a/redfish-core/lib/sensors.hpp
+++ b/redfish-core/lib/sensors.hpp
@@ -42,6 +42,33 @@ using ManagedObjectsVectorType = std::vector<std::pair<
boost::container::flat_map<
std::string, boost::container::flat_map<std::string, SensorVariant>>>>;
+namespace sensors
+{
+namespace node
+{
+static constexpr std::string_view power = "Power";
+static constexpr std::string_view sensors = "Sensors";
+static constexpr std::string_view thermal = "Thermal";
+} // namespace node
+
+namespace dbus
+{
+static const boost::container::flat_map<std::string_view,
+ std::vector<const char*>>
+ types = {{node::power,
+ {"/xyz/openbmc_project/sensors/voltage",
+ "/xyz/openbmc_project/sensors/power"}},
+ {node::sensors,
+ {"/xyz/openbmc_project/sensors/power",
+ "/xyz/openbmc_project/sensors/current",
+ "/xyz/openbmc_project/sensors/utilization"}},
+ {node::thermal,
+ {"/xyz/openbmc_project/sensors/fan_tach",
+ "/xyz/openbmc_project/sensors/temperature",
+ "/xyz/openbmc_project/sensors/fan_pwm"}}};
+}
+} // namespace sensors
+
/**
* SensorsAsyncResp
* Gathers data needed for response processing after async calls are done
@@ -49,13 +76,36 @@ using ManagedObjectsVectorType = std::vector<std::pair<
class SensorsAsyncResp
{
public:
+ using DataCompleteCb = std::function<void(
+ const boost::beast::http::status status,
+ const boost::container::flat_map<std::string, std::string>& uriToDbus)>;
+
+ struct SensorData
+ {
+ const std::string name;
+ std::string uri;
+ const std::string valueKey;
+ const std::string dbusPath;
+ };
+
SensorsAsyncResp(crow::Response& response, const std::string& chassisIdIn,
const std::vector<const char*> typesIn,
- const std::string& subNode) :
+ const std::string_view& subNode) :
res(response),
chassisId(chassisIdIn), types(typesIn), chassisSubNode(subNode)
{}
+ // Store extra data about sensor mapping and return it in callback
+ SensorsAsyncResp(crow::Response& response, const std::string& chassisIdIn,
+ const std::vector<const char*> typesIn,
+ const std::string_view& subNode,
+ DataCompleteCb&& creationComplete) :
+ res(response),
+ chassisId(chassisIdIn), types(typesIn),
+ chassisSubNode(subNode), metadata{std::vector<SensorData>()},
+ dataComplete{std::move(creationComplete)}
+ {}
+
~SensorsAsyncResp()
{
if (res.result() == boost::beast::http::status::internal_server_error)
@@ -65,13 +115,57 @@ class SensorsAsyncResp
// proper code
res.jsonValue = nlohmann::json::object();
}
+
+ if (dataComplete && metadata)
+ {
+ boost::container::flat_map<std::string, std::string> map;
+ if (res.result() == boost::beast::http::status::ok)
+ {
+ for (auto& sensor : *metadata)
+ {
+ map.insert(std::make_pair(sensor.uri + sensor.valueKey,
+ sensor.dbusPath));
+ }
+ }
+ dataComplete(res.result(), map);
+ }
+
res.end();
}
+ void addMetadata(const nlohmann::json& sensorObject,
+ const std::string& valueKey, const std::string& dbusPath)
+ {
+ if (metadata)
+ {
+ metadata->emplace_back(SensorData{sensorObject["Name"],
+ sensorObject["@odata.id"],
+ valueKey, dbusPath});
+ }
+ }
+
+ void updateUri(const std::string& name, const std::string& uri)
+ {
+ if (metadata)
+ {
+ for (auto& sensor : *metadata)
+ {
+ if (sensor.name == name)
+ {
+ sensor.uri = uri;
+ }
+ }
+ }
+ }
+
crow::Response& res;
- std::string chassisId{};
+ const std::string chassisId;
const std::vector<const char*> types;
- std::string chassisSubNode{};
+ const std::string chassisSubNode;
+
+ private:
+ std::optional<std::vector<SensorData>> metadata;
+ DataCompleteCb dataComplete;
};
/**
@@ -239,8 +333,9 @@ void reduceSensorList(
{
messages::resourceNotFound(
SensorsAsyncResp->res, SensorsAsyncResp->chassisSubNode,
- SensorsAsyncResp->chassisSubNode == "Thermal" ? "Temperatures"
- : "Voltages");
+ SensorsAsyncResp->chassisSubNode == sensors::node::thermal
+ ? "Temperatures"
+ : "Voltages");
return;
}
@@ -367,12 +462,12 @@ void getChassis(std::shared_ptr<SensorsAsyncResp> sensorsAsyncResp,
}
const std::string& chassisSubNode = sensorsAsyncResp->chassisSubNode;
- if (chassisSubNode == "Power")
+ if (chassisSubNode == sensors::node::power)
{
sensorsAsyncResp->res.jsonValue["@odata.type"] =
"#Power.v1_5_2.Power";
}
- else if (chassisSubNode == "Thermal")
+ else if (chassisSubNode == sensors::node::thermal)
{
sensorsAsyncResp->res.jsonValue["@odata.type"] =
"#Thermal.v1_4_0.Thermal";
@@ -380,7 +475,7 @@ void getChassis(std::shared_ptr<SensorsAsyncResp> sensorsAsyncResp,
sensorsAsyncResp->res.jsonValue["Temperatures"] =
nlohmann::json::array();
}
- else if (chassisSubNode == "Sensors")
+ else if (chassisSubNode == sensors::node::sensors)
{
sensorsAsyncResp->res.jsonValue["@odata.type"] =
"#SensorCollection.SensorCollection";
@@ -391,7 +486,7 @@ void getChassis(std::shared_ptr<SensorsAsyncResp> sensorsAsyncResp,
sensorsAsyncResp->res.jsonValue["Members@odata.count"] = 0;
}
- if (chassisSubNode != "Sensors")
+ if (chassisSubNode != sensors::node::sensors)
{
sensorsAsyncResp->res.jsonValue["Id"] = chassisSubNode;
}
@@ -422,9 +517,11 @@ void getChassis(std::shared_ptr<SensorsAsyncResp> sensorsAsyncResp,
{
messages::resourceNotFound(
sensorsAsyncResp->res, sensorsAsyncResp->chassisSubNode,
- sensorsAsyncResp->chassisSubNode == "Thermal"
+ sensorsAsyncResp->chassisSubNode ==
+ sensors::node::thermal
? "Temperatures"
- : sensorsAsyncResp->chassisSubNode == "Power"
+ : sensorsAsyncResp->chassisSubNode ==
+ sensors::node::power
? "Voltages"
: "Sensors");
return;
@@ -689,8 +786,7 @@ static void setLedState(nlohmann::json& sensorJson,
* @param sensorName The name of the sensor to be built
* @param sensorType The type (temperature, fan_tach, etc) of the sensor to
* build
- * @param sensorSchema The schema (Power, Thermal, etc) being associated with
- * the sensor to build
+ * @param sensorsAsyncResp Sensor metadata
* @param interfacesDict A dictionary of the interfaces and properties of said
* interfaces to be built from
* @param sensor_json The json object to fill
@@ -699,7 +795,7 @@ static void setLedState(nlohmann::json& sensorJson,
*/
void objectInterfacesToJson(
const std::string& sensorName, const std::string& sensorType,
- const std::string& sensorSchema,
+ std::shared_ptr<SensorsAsyncResp> sensorsAsyncResp,
const boost::container::flat_map<
std::string, boost::container::flat_map<std::string, SensorVariant>>&
interfacesDict,
@@ -727,7 +823,7 @@ void objectInterfacesToJson(
}
}
- if (sensorSchema == "Sensors")
+ if (sensorsAsyncResp->chassisSubNode == sensors::node::sensors)
{
// For sensors in SensorCollection we set Id instead of MemberId,
// including power sensors.
@@ -753,7 +849,7 @@ void objectInterfacesToJson(
bool forceToInt = false;
nlohmann::json::json_pointer unit("/Reading");
- if (sensorSchema == "Sensors")
+ if (sensorsAsyncResp->chassisSubNode == sensors::node::sensors)
{
sensor_json["@odata.type"] = "#Sensor.v1_0_0.Sensor";
if (sensorType == "power")
@@ -833,7 +929,7 @@ void objectInterfacesToJson(
properties.emplace_back("xyz.openbmc_project.Sensor.Value", "Value", unit);
- if (sensorSchema == "Sensors")
+ if (sensorsAsyncResp->chassisSubNode == sensors::node::sensors)
{
properties.emplace_back(
"xyz.openbmc_project.Sensor.Threshold.Warning", "WarningHigh",
@@ -866,7 +962,7 @@ void objectInterfacesToJson(
// TODO Need to get UpperThresholdFatal and LowerThresholdFatal
- if (sensorSchema == "Sensors")
+ if (sensorsAsyncResp->chassisSubNode == sensors::node::sensors)
{
properties.emplace_back("xyz.openbmc_project.Sensor.Value", "MinValue",
"/ReadingRangeMin"_json_pointer);
@@ -939,6 +1035,11 @@ void objectInterfacesToJson(
}
}
}
+
+ sensorsAsyncResp->addMetadata(sensor_json, unit.to_string(),
+ "/xyz/openbmc_project/sensors/" + sensorType +
+ "/" + sensorName);
+
BMCWEB_LOG_DEBUG << "Added sensor " << sensorName;
}
@@ -1150,7 +1251,7 @@ void sortJSONResponse(std::shared_ptr<SensorsAsyncResp> SensorsAsyncResp)
{
nlohmann::json& response = SensorsAsyncResp->res.jsonValue;
std::array<std::string, 2> sensorHeaders{"Temperatures", "Fans"};
- if (SensorsAsyncResp->chassisSubNode == "Power")
+ if (SensorsAsyncResp->chassisSubNode == sensors::node::power)
{
sensorHeaders = {"Voltages", "PowerSupplies"};
}
@@ -1178,6 +1279,7 @@ void sortJSONResponse(std::shared_ptr<SensorsAsyncResp> SensorsAsyncResp)
{
*value += std::to_string(count);
count++;
+ SensorsAsyncResp->updateUri(sensorJson["Name"], *value);
}
}
}
@@ -2072,7 +2174,7 @@ void getPowerSupplyAttributes(
BMCWEB_LOG_DEBUG << "getPowerSupplyAttributes enter";
// Only need the power supply attributes when the Power Schema
- if (sensorsAsyncResp->chassisSubNode != "Power")
+ if (sensorsAsyncResp->chassisSubNode != sensors::node::power)
{
BMCWEB_LOG_DEBUG << "getPowerSupplyAttributes exit since not Power";
callback(inventoryItems);
@@ -2375,7 +2477,7 @@ void getSensorData(
nlohmann::json* sensorJson = nullptr;
- if (sensorSchema == "Sensors")
+ if (sensorSchema == sensors::node::sensors)
{
SensorsAsyncResp->res.jsonValue["@odata.id"] =
"/redfish/v1/Chassis/" + SensorsAsyncResp->chassisId +
@@ -2464,16 +2566,15 @@ void getSensorData(
if (sensorJson != nullptr)
{
- objectInterfacesToJson(sensorName, sensorType,
- SensorsAsyncResp->chassisSubNode,
- objDictEntry.second, *sensorJson,
- inventoryItem);
+ objectInterfacesToJson(
+ sensorName, sensorType, SensorsAsyncResp,
+ objDictEntry.second, *sensorJson, inventoryItem);
}
}
if (SensorsAsyncResp.use_count() == 1)
{
sortJSONResponse(SensorsAsyncResp);
- if (SensorsAsyncResp->chassisSubNode == "Thermal")
+ if (SensorsAsyncResp->chassisSubNode == sensors::node::thermal)
{
populateFanRedundancy(SensorsAsyncResp);
}
@@ -2677,7 +2778,8 @@ void setSensorsOverride(
<< overrideMap.size() << "\n";
messages::resourceNotFound(
sensorAsyncResp->res,
- sensorAsyncResp->chassisSubNode == "Thermal"
+ sensorAsyncResp->chassisSubNode ==
+ sensors::node::thermal
? "Temperatures"
: "Voltages",
"Count");
@@ -2855,6 +2957,41 @@ void checkAndDoSensorsOverride(
"xyz.openbmc_project.ObjectMapper", "GetSubTree", "/", 5, interfaces);
}
+/**
+ * @brief Retrieves mapping of Redfish URIs to sensor value property to D-Bus
+ * path of the sensor.
+ *
+ * Function builds valid Redfish response for sensor query of given chassis and
+ * node. It then builds metadata about Redfish<->D-Bus correlations and provides
+ * it to caller in a callback.
+ *
+ * @param chassis Chassis for which retrieval should be performed
+ * @param node Node (group) of sensors. See sensors::node for supported values
+ * @param mapComplete Callback to be called with retrieval result
+ */
+void retrieveUriToDbusMap(const std::string& chassis, const std::string& node,
+ SensorsAsyncResp::DataCompleteCb&& mapComplete)
+{
+ auto typesIt = sensors::dbus::types.find(node);
+ if (typesIt == sensors::dbus::types.end())
+ {
+ BMCWEB_LOG_ERROR << "Wrong node provided : " << node;
+ mapComplete(boost::beast::http::status::bad_request, {});
+ return;
+ }
+
+ auto respBuffer = std::make_shared<crow::Response>();
+ auto callback =
+ [respBuffer, mapCompleteCb{std::move(mapComplete)}](
+ const boost::beast::http::status status,
+ const boost::container::flat_map<std::string, std::string>&
+ uriToDbus) { mapCompleteCb(status, uriToDbus); };
+
+ auto resp = std::make_shared<SensorsAsyncResp>(
+ *respBuffer, chassis, typesIt->second, node, std::move(callback));
+ getChassisData(resp);
+}
+
class SensorCollection : public Node
{
public:
@@ -2871,10 +3008,6 @@ class SensorCollection : public Node
}
private:
- std::vector<const char*> typeList = {
- "/xyz/openbmc_project/sensors/power",
- "/xyz/openbmc_project/sensors/current",
- "/xyz/openbmc_project/sensors/utilization"};
void doGet(crow::Response& res, const crow::Request& req,
const std::vector<std::string>& params) override
{
@@ -2889,8 +3022,9 @@ class SensorCollection : public Node
const std::string& chassisId = params[0];
std::shared_ptr<SensorsAsyncResp> asyncResp =
- std::make_shared<SensorsAsyncResp>(res, chassisId, typeList,
- "Sensors");
+ std::make_shared<SensorsAsyncResp>(
+ res, chassisId, sensors::dbus::types.at(sensors::node::sensors),
+ sensors::node::sensors);
auto getChassisCb =
[asyncResp](std::shared_ptr<boost::container::flat_set<std::string>>
@@ -2959,8 +3093,9 @@ class Sensor : public Node
}
const std::string& chassisId = params[0];
std::shared_ptr<SensorsAsyncResp> asyncResp =
- std::make_shared<SensorsAsyncResp>(
- res, chassisId, std::vector<const char*>(), "Sensors");
+ std::make_shared<SensorsAsyncResp>(res, chassisId,
+ std::vector<const char*>(),
+ sensors::node::sensors);
const std::string& sensorName = params[1];
const std::array<const char*, 1> interfaces = {