blob: c390cd7908b3dc01eccee49e69cf9c527521fe17 [file] [log] [blame]
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +01001/*
2// Copyright (c) 2018 Intel Corporation
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15*/
16#pragma once
17
18#include <math.h>
Ed Tanous1abe55e2018-09-05 08:30:59 -070019
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +010020#include <boost/algorithm/string/predicate.hpp>
21#include <boost/algorithm/string/split.hpp>
22#include <boost/container/flat_map.hpp>
23#include <boost/range/algorithm/replace_copy_if.hpp>
Ed Tanous1abe55e2018-09-05 08:30:59 -070024#include <dbus_singleton.hpp>
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +010025
Ed Tanous1abe55e2018-09-05 08:30:59 -070026namespace redfish
27{
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +010028
Ed Tanousd76323e2018-08-07 14:35:40 -070029constexpr const char* dbusSensorPrefix = "/xyz/openbmc_project/sensors/";
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +010030
31using GetSubTreeType = std::vector<
32 std::pair<std::string,
33 std::vector<std::pair<std::string, std::vector<std::string>>>>>;
34
Ed Tanousaa2e59c2018-04-12 12:17:20 -070035using SensorVariant = sdbusplus::message::variant<int64_t, double>;
36
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +010037using ManagedObjectsVectorType = std::vector<std::pair<
Ed Tanousaa2e59c2018-04-12 12:17:20 -070038 sdbusplus::message::object_path,
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +010039 boost::container::flat_map<
Ed Tanousaa2e59c2018-04-12 12:17:20 -070040 std::string, boost::container::flat_map<std::string, SensorVariant>>>>;
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +010041
42/**
Kowalski, Kamil588c3f02018-04-03 14:55:27 +020043 * SensorsAsyncResp
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +010044 * Gathers data needed for response processing after async calls are done
45 */
Ed Tanous1abe55e2018-09-05 08:30:59 -070046class SensorsAsyncResp
47{
48 public:
49 SensorsAsyncResp(crow::Response& response, const std::string& chassisId,
50 const std::initializer_list<const char*> types) :
51 res(response),
52 chassisId(chassisId), types(types)
53 {
54 res.jsonValue["@odata.id"] =
55 "/redfish/v1/Chassis/" + chassisId + "/Thermal";
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +010056 }
Kowalski, Kamil588c3f02018-04-03 14:55:27 +020057
Ed Tanous1abe55e2018-09-05 08:30:59 -070058 ~SensorsAsyncResp()
59 {
60 if (res.result() == boost::beast::http::status::internal_server_error)
61 {
62 // Reset the json object to clear out any data that made it in
63 // before the error happened todo(ed) handle error condition with
64 // proper code
65 res.jsonValue = nlohmann::json::object();
66 }
67 res.end();
68 }
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +010069
Ed Tanous1abe55e2018-09-05 08:30:59 -070070 void setErrorStatus()
71 {
72 res.result(boost::beast::http::status::internal_server_error);
73 }
74
75 crow::Response& res;
76 std::string chassisId{};
77 const std::vector<const char*> types;
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +010078};
79
80/**
81 * @brief Creates connections necessary for chassis sensors
Kowalski, Kamil588c3f02018-04-03 14:55:27 +020082 * @param SensorsAsyncResp Pointer to object holding response data
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +010083 * @param sensorNames Sensors retrieved from chassis
84 * @param callback Callback for processing gathered connections
85 */
86template <typename Callback>
Kowalski, Kamil588c3f02018-04-03 14:55:27 +020087void getConnections(std::shared_ptr<SensorsAsyncResp> SensorsAsyncResp,
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +010088 const boost::container::flat_set<std::string>& sensorNames,
Ed Tanous1abe55e2018-09-05 08:30:59 -070089 Callback&& callback)
90{
91 BMCWEB_LOG_DEBUG << "getConnections enter";
92 const std::string path = "/xyz/openbmc_project/sensors";
93 const std::array<std::string, 1> interfaces = {
94 "xyz.openbmc_project.Sensor.Value"};
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +010095
Ed Tanous1abe55e2018-09-05 08:30:59 -070096 // Response handler for parsing objects subtree
97 auto respHandler = [callback{std::move(callback)}, SensorsAsyncResp,
98 sensorNames](const boost::system::error_code ec,
99 const GetSubTreeType& subtree) {
100 BMCWEB_LOG_DEBUG << "getConnections resp_handler enter";
101 if (ec)
102 {
103 SensorsAsyncResp->setErrorStatus();
104 BMCWEB_LOG_ERROR << "getConnections resp_handler: Dbus error "
105 << ec;
106 return;
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100107 }
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100108
Ed Tanous1abe55e2018-09-05 08:30:59 -0700109 BMCWEB_LOG_DEBUG << "Found " << subtree.size() << " subtrees";
110
111 // Make unique list of connections only for requested sensor types and
112 // found in the chassis
113 boost::container::flat_set<std::string> connections;
114 // Intrinsic to avoid malloc. Most systems will have < 8 sensor
115 // producers
116 connections.reserve(8);
117
118 BMCWEB_LOG_DEBUG << "sensorNames list count: " << sensorNames.size();
119 for (const std::string& tsensor : sensorNames)
120 {
121 BMCWEB_LOG_DEBUG << "Sensor to find: " << tsensor;
122 }
123
124 for (const std::pair<
125 std::string,
126 std::vector<std::pair<std::string, std::vector<std::string>>>>&
127 object : subtree)
128 {
129 for (const char* type : SensorsAsyncResp->types)
130 {
131 if (boost::starts_with(object.first, type))
132 {
133 auto lastPos = object.first.rfind('/');
134 if (lastPos != std::string::npos)
135 {
136 std::string sensorName =
137 object.first.substr(lastPos + 1);
138
139 if (sensorNames.find(sensorName) != sensorNames.end())
140 {
141 // For each Connection name
142 for (const std::pair<std::string,
143 std::vector<std::string>>&
144 objData : object.second)
145 {
146 BMCWEB_LOG_DEBUG << "Adding connection: "
147 << objData.first;
148 connections.insert(objData.first);
149 }
150 }
151 }
152 break;
153 }
154 }
155 }
156 BMCWEB_LOG_DEBUG << "Found " << connections.size() << " connections";
157 callback(std::move(connections));
158 BMCWEB_LOG_DEBUG << "getConnections resp_handler exit";
159 };
160
161 // Make call to ObjectMapper to find all sensors objects
162 crow::connections::systemBus->async_method_call(
163 std::move(respHandler), "xyz.openbmc_project.ObjectMapper",
164 "/xyz/openbmc_project/object_mapper",
165 "xyz.openbmc_project.ObjectMapper", "GetSubTree", path, 2, interfaces);
166 BMCWEB_LOG_DEBUG << "getConnections exit";
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100167}
168
169/**
170 * @brief Retrieves requested chassis sensors and redundancy data from DBus .
Kowalski, Kamil588c3f02018-04-03 14:55:27 +0200171 * @param SensorsAsyncResp Pointer to object holding response data
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100172 * @param callback Callback for next step in gathered sensor processing
173 */
174template <typename Callback>
Kowalski, Kamil588c3f02018-04-03 14:55:27 +0200175void getChassis(std::shared_ptr<SensorsAsyncResp> SensorsAsyncResp,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700176 Callback&& callback)
177{
178 BMCWEB_LOG_DEBUG << "getChassis enter";
179 // Process response from EntityManager and extract chassis data
180 auto respHandler = [callback{std::move(callback)},
181 SensorsAsyncResp](const boost::system::error_code ec,
182 ManagedObjectsVectorType& resp) {
183 BMCWEB_LOG_DEBUG << "getChassis respHandler enter";
184 if (ec)
185 {
186 BMCWEB_LOG_ERROR << "getChassis respHandler DBUS error: " << ec;
187 SensorsAsyncResp->setErrorStatus();
188 return;
189 }
190 boost::container::flat_set<std::string> sensorNames;
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100191
Ed Tanous1abe55e2018-09-05 08:30:59 -0700192 // SensorsAsyncResp->chassisId
193 bool foundChassis = false;
194 std::vector<std::string> split;
195 // Reserve space for
196 // /xyz/openbmc_project/inventory/<name>/<subname> + 3 subnames
197 split.reserve(8);
Ed Tanousdaf36e22018-04-20 16:01:36 -0700198
Ed Tanous1abe55e2018-09-05 08:30:59 -0700199 for (const auto& objDictEntry : resp)
200 {
201 const std::string& objectPath =
202 static_cast<const std::string&>(objDictEntry.first);
203 boost::algorithm::split(split, objectPath, boost::is_any_of("/"));
204 if (split.size() < 2)
205 {
206 BMCWEB_LOG_ERROR << "Got path that isn't long enough "
207 << objectPath;
208 split.clear();
209 continue;
210 }
211 const std::string& sensorName = split.end()[-1];
212 const std::string& chassisName = split.end()[-2];
Ed Tanousdaf36e22018-04-20 16:01:36 -0700213
Ed Tanous1abe55e2018-09-05 08:30:59 -0700214 if (chassisName != SensorsAsyncResp->chassisId)
215 {
216 split.clear();
217 continue;
218 }
219 BMCWEB_LOG_DEBUG << "New sensor: " << sensorName;
220 foundChassis = true;
221 sensorNames.emplace(sensorName);
222 split.clear();
223 };
224 BMCWEB_LOG_DEBUG << "Found " << sensorNames.size() << " Sensor names";
225
226 if (!foundChassis)
227 {
228 BMCWEB_LOG_INFO << "Unable to find chassis named "
229 << SensorsAsyncResp->chassisId;
230 SensorsAsyncResp->res.result(boost::beast::http::status::not_found);
231 }
232 else
233 {
234 callback(sensorNames);
235 }
236 BMCWEB_LOG_DEBUG << "getChassis respHandler exit";
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100237 };
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100238
Ed Tanous1abe55e2018-09-05 08:30:59 -0700239 // Make call to EntityManager to find all chassis objects
240 crow::connections::systemBus->async_method_call(
241 respHandler, "xyz.openbmc_project.EntityManager", "/",
242 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
243 BMCWEB_LOG_DEBUG << "getChassis exit";
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100244}
245
246/**
247 * @brief Builds a json sensor representation of a sensor.
248 * @param sensorName The name of the sensor to be built
Gunnar Mills274fad52018-06-13 15:45:36 -0500249 * @param sensorType The type (temperature, fan_tach, etc) of the sensor to
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100250 * build
251 * @param interfacesDict A dictionary of the interfaces and properties of said
252 * interfaces to be built from
253 * @param sensor_json The json object to fill
254 */
255void objectInterfacesToJson(
256 const std::string& sensorName, const std::string& sensorType,
257 const boost::container::flat_map<
Ed Tanousaa2e59c2018-04-12 12:17:20 -0700258 std::string, boost::container::flat_map<std::string, SensorVariant>>&
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100259 interfacesDict,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700260 nlohmann::json& sensor_json)
261{
262 // We need a value interface before we can do anything with it
263 auto valueIt = interfacesDict.find("xyz.openbmc_project.Sensor.Value");
264 if (valueIt == interfacesDict.end())
265 {
266 BMCWEB_LOG_ERROR << "Sensor doesn't have a value interface";
267 return;
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100268 }
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100269
Ed Tanous1abe55e2018-09-05 08:30:59 -0700270 // Assume values exist as is (10^0 == 1) if no scale exists
271 int64_t scaleMultiplier = 0;
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100272
Ed Tanous1abe55e2018-09-05 08:30:59 -0700273 auto scaleIt = valueIt->second.find("Scale");
274 // If a scale exists, pull value as int64, and use the scaling.
275 if (scaleIt != valueIt->second.end())
276 {
277 const int64_t* int64Value =
278 mapbox::getPtr<const int64_t>(scaleIt->second);
279 if (int64Value != nullptr)
280 {
281 scaleMultiplier = *int64Value;
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100282 }
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100283 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700284
285 sensor_json["MemberId"] = sensorName;
286 sensor_json["Name"] = sensorName;
287 sensor_json["Status"]["State"] = "Enabled";
288 sensor_json["Status"]["Health"] = "OK";
289
290 // Parameter to set to override the type we get from dbus, and force it to
291 // int, regardless of what is available. This is used for schemas like fan,
292 // that require integers, not floats.
293 bool forceToInt = false;
294
295 const char* unit = "Reading";
296 if (sensorType == "temperature")
297 {
298 unit = "ReadingCelsius";
299 sensor_json["@odata.type"] = "#Thermal.v1_3_0.Temperature";
300 // TODO(ed) Documentation says that path should be type fan_tach,
301 // implementation seems to implement fan
302 }
303 else if (sensorType == "fan" || sensorType == "fan_tach")
304 {
305 unit = "Reading";
306 sensor_json["ReadingUnits"] = "RPM";
307 sensor_json["@odata.type"] = "#Thermal.v1_3_0.Fan";
308 forceToInt = true;
309 }
310 else if (sensorType == "voltage")
311 {
312 unit = "ReadingVolts";
313 sensor_json["@odata.type"] = "#Power.v1_0_0.Voltage";
314 }
315 else
316 {
317 BMCWEB_LOG_ERROR << "Redfish cannot map object type for " << sensorName;
318 return;
319 }
320 // Map of dbus interface name, dbus property name and redfish property_name
321 std::vector<std::tuple<const char*, const char*, const char*>> properties;
322 properties.reserve(7);
323
324 properties.emplace_back("xyz.openbmc_project.Sensor.Value", "Value", unit);
325 properties.emplace_back("xyz.openbmc_project.Sensor.Threshold.Warning",
326 "WarningHigh", "UpperThresholdNonCritical");
327 properties.emplace_back("xyz.openbmc_project.Sensor.Threshold.Warning",
328 "WarningLow", "LowerThresholdNonCritical");
329 properties.emplace_back("xyz.openbmc_project.Sensor.Threshold.Critical",
330 "CriticalHigh", "UpperThresholdCritical");
331 properties.emplace_back("xyz.openbmc_project.Sensor.Threshold.Critical",
332 "CriticalLow", "LowerThresholdCritical");
333
334 if (sensorType == "temperature")
335 {
336 properties.emplace_back("xyz.openbmc_project.Sensor.Value", "MinValue",
337 "MinReadingRangeTemp");
338 properties.emplace_back("xyz.openbmc_project.Sensor.Value", "MaxValue",
339 "MaxReadingRangeTemp");
340 }
341 else
342 {
343 properties.emplace_back("xyz.openbmc_project.Sensor.Value", "MinValue",
344 "MinReadingRange");
345 properties.emplace_back("xyz.openbmc_project.Sensor.Value", "MaxValue",
346 "MaxReadingRange");
347 }
348
349 for (const std::tuple<const char*, const char*, const char*>& p :
350 properties)
351 {
352 auto interfaceProperties = interfacesDict.find(std::get<0>(p));
353 if (interfaceProperties != interfacesDict.end())
354 {
355 auto valueIt = interfaceProperties->second.find(std::get<1>(p));
356 if (valueIt != interfaceProperties->second.end())
357 {
358 const SensorVariant& valueVariant = valueIt->second;
359 nlohmann::json& valueIt = sensor_json[std::get<2>(p)];
360
361 // Attempt to pull the int64 directly
362 const int64_t* int64Value =
363 mapbox::getPtr<const int64_t>(valueVariant);
364
365 if (int64Value != nullptr)
366 {
367 if (forceToInt || scaleMultiplier >= 0)
368 {
369 valueIt = *int64Value * std::pow(10, scaleMultiplier);
370 }
371 else
372 {
373 valueIt =
374 *int64Value *
375 std::pow(10, static_cast<double>(scaleMultiplier));
376 }
377 }
378 // Attempt to pull the float directly
379 const double* doubleValue =
380 mapbox::getPtr<const double>(valueVariant);
381
382 if (doubleValue != nullptr)
383 {
384 if (!forceToInt)
385 {
386 valueIt =
387 *doubleValue *
388 std::pow(10, static_cast<double>(scaleMultiplier));
389 }
390 else
391 {
392 valueIt = static_cast<int64_t>(
393 *doubleValue * std::pow(10, scaleMultiplier));
394 }
395 }
396 }
397 }
398 }
399 BMCWEB_LOG_DEBUG << "Added sensor " << sensorName;
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100400}
401
402/**
403 * @brief Entry point for retrieving sensors data related to requested
404 * chassis.
Kowalski, Kamil588c3f02018-04-03 14:55:27 +0200405 * @param SensorsAsyncResp Pointer to object holding response data
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100406 */
Ed Tanous1abe55e2018-09-05 08:30:59 -0700407void getChassisData(std::shared_ptr<SensorsAsyncResp> SensorsAsyncResp)
408{
409 BMCWEB_LOG_DEBUG << "getChassisData enter";
410 auto getChassisCb = [&, SensorsAsyncResp](
411 boost::container::flat_set<std::string>&
412 sensorNames) {
413 BMCWEB_LOG_DEBUG << "getChassisCb enter";
414 auto getConnectionCb =
415 [&, SensorsAsyncResp, sensorNames](
416 const boost::container::flat_set<std::string>& connections) {
417 BMCWEB_LOG_DEBUG << "getConnectionCb enter";
418 // Get managed objects from all services exposing sensors
419 for (const std::string& connection : connections)
420 {
421 // Response handler to process managed objects
422 auto getManagedObjectsCb =
423 [&, SensorsAsyncResp,
424 sensorNames](const boost::system::error_code ec,
425 ManagedObjectsVectorType& resp) {
426 BMCWEB_LOG_DEBUG << "getManagedObjectsCb enter";
427 if (ec)
428 {
429 BMCWEB_LOG_ERROR
430 << "getManagedObjectsCb DBUS error: " << ec;
431 SensorsAsyncResp->setErrorStatus();
432 return;
433 }
434 // Go through all objects and update response with
435 // sensor data
436 for (const auto& objDictEntry : resp)
437 {
438 const std::string& objPath =
439 static_cast<const std::string&>(
440 objDictEntry.first);
441 BMCWEB_LOG_DEBUG
442 << "getManagedObjectsCb parsing object "
443 << objPath;
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100444
Ed Tanous1abe55e2018-09-05 08:30:59 -0700445 std::vector<std::string> split;
446 // Reserve space for
447 // /xyz/openbmc_project/sensors/<name>/<subname>
448 split.reserve(6);
449 boost::algorithm::split(split, objPath,
450 boost::is_any_of("/"));
451 if (split.size() < 6)
452 {
453 BMCWEB_LOG_ERROR
454 << "Got path that isn't long enough "
455 << objPath;
456 continue;
457 }
458 // These indexes aren't intuitive, as
459 // boost::split puts an empty string at the
460 // beggining
461 const std::string& sensorType = split[4];
462 const std::string& sensorName = split[5];
463 BMCWEB_LOG_DEBUG << "sensorName " << sensorName
464 << " sensorType "
465 << sensorType;
466 if (sensorNames.find(sensorName) ==
467 sensorNames.end())
468 {
469 BMCWEB_LOG_ERROR << sensorName
470 << " not in sensor list ";
471 continue;
472 }
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100473
Ed Tanous1abe55e2018-09-05 08:30:59 -0700474 const char* fieldName = nullptr;
475 if (sensorType == "temperature")
476 {
477 fieldName = "Temperatures";
478 }
479 else if (sensorType == "fan" ||
480 sensorType == "fan_tach")
481 {
482 fieldName = "Fans";
483 }
484 else if (sensorType == "voltage")
485 {
486 fieldName = "Voltages";
487 }
488 else if (sensorType == "current")
489 {
490 fieldName = "PowerSupply";
491 }
492 else if (sensorType == "power")
493 {
494 fieldName = "PowerSupply";
495 }
496 else
497 {
498 BMCWEB_LOG_ERROR
499 << "Unsure how to handle sensorType "
500 << sensorType;
501 continue;
502 }
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100503
Ed Tanous1abe55e2018-09-05 08:30:59 -0700504 nlohmann::json& tempArray =
505 SensorsAsyncResp->res.jsonValue[fieldName];
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100506
Ed Tanous1abe55e2018-09-05 08:30:59 -0700507 // Create the array if it doesn't yet exist
508 if (tempArray.is_array() == false)
509 {
510 tempArray = nlohmann::json::array();
511 }
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100512
Ed Tanous1abe55e2018-09-05 08:30:59 -0700513 tempArray.push_back(
514 {{"@odata.id",
515 "/redfish/v1/Chassis/" +
516 SensorsAsyncResp->chassisId +
517 "/Thermal#/" + sensorName}});
518 nlohmann::json& sensorJson = tempArray.back();
519 objectInterfacesToJson(sensorName, sensorType,
520 objDictEntry.second,
521 sensorJson);
522 }
523 BMCWEB_LOG_DEBUG << "getManagedObjectsCb exit";
524 };
525 crow::connections::systemBus->async_method_call(
526 getManagedObjectsCb, connection, "/",
527 "org.freedesktop.DBus.ObjectManager",
528 "GetManagedObjects");
529 };
530 BMCWEB_LOG_DEBUG << "getConnectionCb exit";
Kowalski, Kamil588c3f02018-04-03 14:55:27 +0200531 };
Ed Tanous1abe55e2018-09-05 08:30:59 -0700532 // get connections and then pass it to get sensors
533 getConnections(SensorsAsyncResp, sensorNames,
534 std::move(getConnectionCb));
535 BMCWEB_LOG_DEBUG << "getChassisCb exit";
536 };
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100537
Ed Tanous1abe55e2018-09-05 08:30:59 -0700538 // get chassis information related to sensors
539 getChassis(SensorsAsyncResp, std::move(getChassisCb));
540 BMCWEB_LOG_DEBUG << "getChassisData exit";
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100541};
542
Ed Tanous1abe55e2018-09-05 08:30:59 -0700543} // namespace redfish