blob: cb7ea15381e29c08300931d8bf7bddd32e21d430 [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
John Edward Broadbent7e860f12021-04-08 15:57:16 -070018#include <app.hpp>
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +010019#include <boost/algorithm/string/predicate.hpp>
20#include <boost/algorithm/string/split.hpp>
21#include <boost/container/flat_map.hpp>
22#include <boost/range/algorithm/replace_copy_if.hpp>
Ed Tanous1abe55e2018-09-05 08:30:59 -070023#include <dbus_singleton.hpp>
Ed Tanoused398212021-06-09 17:05:54 -070024#include <registries/privilege_registry.hpp>
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +053025#include <utils/json_utils.hpp>
Gunnar Mills1214b7e2020-06-04 10:11:30 -050026
27#include <cmath>
Ed Tanousb5a76932020-09-29 16:16:58 -070028#include <utility>
Ed Tanousabf2add2019-01-22 16:40:12 -080029#include <variant>
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +010030
Ed Tanous1abe55e2018-09-05 08:30:59 -070031namespace redfish
32{
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +010033
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +010034using GetSubTreeType = std::vector<
35 std::pair<std::string,
36 std::vector<std::pair<std::string, std::vector<std::string>>>>>;
37
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -050038using SensorVariant =
39 std::variant<int64_t, double, uint32_t, bool, std::string>;
Ed Tanousaa2e59c2018-04-12 12:17:20 -070040
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +010041using ManagedObjectsVectorType = std::vector<std::pair<
Ed Tanousaa2e59c2018-04-12 12:17:20 -070042 sdbusplus::message::object_path,
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +010043 boost::container::flat_map<
Ed Tanousaa2e59c2018-04-12 12:17:20 -070044 std::string, boost::container::flat_map<std::string, SensorVariant>>>>;
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +010045
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +020046namespace sensors
47{
48namespace node
49{
50static constexpr std::string_view power = "Power";
51static constexpr std::string_view sensors = "Sensors";
52static constexpr std::string_view thermal = "Thermal";
53} // namespace node
54
55namespace dbus
56{
Wludzik, Jozefc2bf7f92021-03-08 14:35:54 +000057
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +020058static const boost::container::flat_map<std::string_view,
59 std::vector<const char*>>
Wludzik, Jozefc2bf7f92021-03-08 14:35:54 +000060 paths = {{node::power,
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +020061 {"/xyz/openbmc_project/sensors/voltage",
62 "/xyz/openbmc_project/sensors/power"}},
63 {node::sensors,
64 {"/xyz/openbmc_project/sensors/power",
65 "/xyz/openbmc_project/sensors/current",
Basheer Ahmed Muddebihal70886902021-07-22 02:11:17 -070066 "/xyz/openbmc_project/sensors/airflow",
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +020067 "/xyz/openbmc_project/sensors/utilization"}},
68 {node::thermal,
69 {"/xyz/openbmc_project/sensors/fan_tach",
70 "/xyz/openbmc_project/sensors/temperature",
71 "/xyz/openbmc_project/sensors/fan_pwm"}}};
Wludzik, Jozefc2bf7f92021-03-08 14:35:54 +000072} // namespace dbus
73
74inline const char* toReadingType(const std::string& sensorType)
75{
76 if (sensorType == "voltage")
77 {
78 return "Voltage";
79 }
80 if (sensorType == "power")
81 {
82 return "Power";
83 }
84 if (sensorType == "current")
85 {
86 return "Current";
87 }
88 if (sensorType == "fan_tach")
89 {
90 return "Rotational";
91 }
92 if (sensorType == "temperature")
93 {
94 return "Temperature";
95 }
96 if (sensorType == "fan_pwm" || sensorType == "utilization")
97 {
98 return "Percent";
99 }
100 if (sensorType == "altitude")
101 {
102 return "Altitude";
103 }
104 if (sensorType == "airflow")
105 {
106 return "AirFlow";
107 }
108 if (sensorType == "energy")
109 {
110 return "EnergyJoules";
111 }
112 return "";
113}
114
115inline const char* toReadingUnits(const std::string& sensorType)
116{
117 if (sensorType == "voltage")
118 {
119 return "V";
120 }
121 if (sensorType == "power")
122 {
123 return "W";
124 }
125 if (sensorType == "current")
126 {
127 return "A";
128 }
129 if (sensorType == "fan_tach")
130 {
131 return "RPM";
132 }
133 if (sensorType == "temperature")
134 {
135 return "Cel";
136 }
137 if (sensorType == "fan_pwm" || sensorType == "utilization")
138 {
139 return "%";
140 }
141 if (sensorType == "altitude")
142 {
143 return "m";
144 }
145 if (sensorType == "airflow")
146 {
147 return "cft_i/min";
148 }
149 if (sensorType == "energy")
150 {
151 return "J";
152 }
153 return "";
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200154}
155} // namespace sensors
156
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100157/**
Kowalski, Kamil588c3f02018-04-03 14:55:27 +0200158 * SensorsAsyncResp
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100159 * Gathers data needed for response processing after async calls are done
160 */
Ed Tanous1abe55e2018-09-05 08:30:59 -0700161class SensorsAsyncResp
162{
163 public:
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200164 using DataCompleteCb = std::function<void(
165 const boost::beast::http::status status,
166 const boost::container::flat_map<std::string, std::string>& uriToDbus)>;
167
168 struct SensorData
169 {
170 const std::string name;
171 std::string uri;
172 const std::string valueKey;
173 const std::string dbusPath;
174 };
175
zhanghch058d1b46d2021-04-01 11:18:24 +0800176 SensorsAsyncResp(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
177 const std::string& chassisIdIn,
Ed Tanousb5a76932020-09-29 16:16:58 -0700178 const std::vector<const char*>& typesIn,
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200179 const std::string_view& subNode) :
zhanghch058d1b46d2021-04-01 11:18:24 +0800180 asyncResp(asyncResp),
Ed Tanous271584a2019-07-09 16:24:22 -0700181 chassisId(chassisIdIn), types(typesIn), chassisSubNode(subNode)
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500182 {}
Kowalski, Kamil588c3f02018-04-03 14:55:27 +0200183
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200184 // Store extra data about sensor mapping and return it in callback
zhanghch058d1b46d2021-04-01 11:18:24 +0800185 SensorsAsyncResp(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
186 const std::string& chassisIdIn,
Ed Tanousb5a76932020-09-29 16:16:58 -0700187 const std::vector<const char*>& typesIn,
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200188 const std::string_view& subNode,
189 DataCompleteCb&& creationComplete) :
zhanghch058d1b46d2021-04-01 11:18:24 +0800190 asyncResp(asyncResp),
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200191 chassisId(chassisIdIn), types(typesIn),
192 chassisSubNode(subNode), metadata{std::vector<SensorData>()},
193 dataComplete{std::move(creationComplete)}
194 {}
195
Ed Tanous1abe55e2018-09-05 08:30:59 -0700196 ~SensorsAsyncResp()
197 {
zhanghch058d1b46d2021-04-01 11:18:24 +0800198 if (asyncResp->res.result() ==
199 boost::beast::http::status::internal_server_error)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700200 {
201 // Reset the json object to clear out any data that made it in
202 // before the error happened todo(ed) handle error condition with
203 // proper code
zhanghch058d1b46d2021-04-01 11:18:24 +0800204 asyncResp->res.jsonValue = nlohmann::json::object();
Ed Tanous1abe55e2018-09-05 08:30:59 -0700205 }
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200206
207 if (dataComplete && metadata)
208 {
209 boost::container::flat_map<std::string, std::string> map;
zhanghch058d1b46d2021-04-01 11:18:24 +0800210 if (asyncResp->res.result() == boost::beast::http::status::ok)
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200211 {
212 for (auto& sensor : *metadata)
213 {
214 map.insert(std::make_pair(sensor.uri + sensor.valueKey,
215 sensor.dbusPath));
216 }
217 }
zhanghch058d1b46d2021-04-01 11:18:24 +0800218 dataComplete(asyncResp->res.result(), map);
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200219 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700220 }
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100221
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200222 void addMetadata(const nlohmann::json& sensorObject,
223 const std::string& valueKey, const std::string& dbusPath)
224 {
225 if (metadata)
226 {
227 metadata->emplace_back(SensorData{sensorObject["Name"],
228 sensorObject["@odata.id"],
229 valueKey, dbusPath});
230 }
231 }
232
233 void updateUri(const std::string& name, const std::string& uri)
234 {
235 if (metadata)
236 {
237 for (auto& sensor : *metadata)
238 {
239 if (sensor.name == name)
240 {
241 sensor.uri = uri;
242 }
243 }
244 }
245 }
246
zhanghch058d1b46d2021-04-01 11:18:24 +0800247 const std::shared_ptr<bmcweb::AsyncResp> asyncResp;
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200248 const std::string chassisId;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700249 const std::vector<const char*> types;
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200250 const std::string chassisSubNode;
251
252 private:
253 std::optional<std::vector<SensorData>> metadata;
254 DataCompleteCb dataComplete;
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100255};
256
257/**
Anthony Wilsond5005492019-07-31 16:34:17 -0500258 * Possible states for physical inventory leds
259 */
260enum class LedState
261{
262 OFF,
263 ON,
264 BLINK,
265 UNKNOWN
266};
267
268/**
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500269 * D-Bus inventory item associated with one or more sensors.
270 */
271class InventoryItem
272{
273 public:
274 InventoryItem(const std::string& objPath) :
275 objectPath(objPath), name(), isPresent(true), isFunctional(true),
Gunnar Mills42cbe532019-08-15 15:26:54 -0500276 isPowerSupply(false), powerSupplyEfficiencyPercent(-1), manufacturer(),
277 model(), partNumber(), serialNumber(), sensors(), ledObjectPath(""),
Anthony Wilsond5005492019-07-31 16:34:17 -0500278 ledState(LedState::UNKNOWN)
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500279 {
280 // Set inventory item name to last node of object path
George Liu28aa8de2021-02-01 15:13:30 +0800281 sdbusplus::message::object_path path(objectPath);
282 name = path.filename();
283 if (name.empty())
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500284 {
George Liu28aa8de2021-02-01 15:13:30 +0800285 BMCWEB_LOG_ERROR << "Failed to find '/' in " << objectPath;
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500286 }
287 }
288
289 std::string objectPath;
290 std::string name;
291 bool isPresent;
292 bool isFunctional;
293 bool isPowerSupply;
Gunnar Mills42cbe532019-08-15 15:26:54 -0500294 int powerSupplyEfficiencyPercent;
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500295 std::string manufacturer;
296 std::string model;
297 std::string partNumber;
298 std::string serialNumber;
299 std::set<std::string> sensors;
Anthony Wilsond5005492019-07-31 16:34:17 -0500300 std::string ledObjectPath;
301 LedState ledState;
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500302};
303
304/**
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +0530305 * @brief Get objects with connection necessary for sensors
Kowalski, Kamil588c3f02018-04-03 14:55:27 +0200306 * @param SensorsAsyncResp Pointer to object holding response data
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100307 * @param sensorNames Sensors retrieved from chassis
308 * @param callback Callback for processing gathered connections
309 */
310template <typename Callback>
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +0530311void getObjectsWithConnection(
Ed Tanous81ce6092020-12-17 16:54:55 +0000312 const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
Ed Tanousb5a76932020-09-29 16:16:58 -0700313 const std::shared_ptr<boost::container::flat_set<std::string>>& sensorNames,
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +0530314 Callback&& callback)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700315{
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +0530316 BMCWEB_LOG_DEBUG << "getObjectsWithConnection enter";
Ed Tanous1abe55e2018-09-05 08:30:59 -0700317 const std::string path = "/xyz/openbmc_project/sensors";
318 const std::array<std::string, 1> interfaces = {
319 "xyz.openbmc_project.Sensor.Value"};
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100320
Ed Tanous1abe55e2018-09-05 08:30:59 -0700321 // Response handler for parsing objects subtree
Ed Tanous81ce6092020-12-17 16:54:55 +0000322 auto respHandler = [callback{std::move(callback)}, sensorsAsyncResp,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700323 sensorNames](const boost::system::error_code ec,
324 const GetSubTreeType& subtree) {
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +0530325 BMCWEB_LOG_DEBUG << "getObjectsWithConnection resp_handler enter";
Ed Tanous1abe55e2018-09-05 08:30:59 -0700326 if (ec)
327 {
zhanghch058d1b46d2021-04-01 11:18:24 +0800328 messages::internalError(sensorsAsyncResp->asyncResp->res);
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +0530329 BMCWEB_LOG_ERROR
330 << "getObjectsWithConnection resp_handler: Dbus error " << ec;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700331 return;
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100332 }
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100333
Ed Tanous1abe55e2018-09-05 08:30:59 -0700334 BMCWEB_LOG_DEBUG << "Found " << subtree.size() << " subtrees";
335
336 // Make unique list of connections only for requested sensor types and
337 // found in the chassis
338 boost::container::flat_set<std::string> connections;
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +0530339 std::set<std::pair<std::string, std::string>> objectsWithConnection;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700340 // Intrinsic to avoid malloc. Most systems will have < 8 sensor
341 // producers
342 connections.reserve(8);
343
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700344 BMCWEB_LOG_DEBUG << "sensorNames list count: " << sensorNames->size();
345 for (const std::string& tsensor : *sensorNames)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700346 {
347 BMCWEB_LOG_DEBUG << "Sensor to find: " << tsensor;
348 }
349
350 for (const std::pair<
351 std::string,
352 std::vector<std::pair<std::string, std::vector<std::string>>>>&
353 object : subtree)
354 {
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700355 if (sensorNames->find(object.first) != sensorNames->end())
Ed Tanous1abe55e2018-09-05 08:30:59 -0700356 {
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700357 for (const std::pair<std::string, std::vector<std::string>>&
358 objData : object.second)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700359 {
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700360 BMCWEB_LOG_DEBUG << "Adding connection: " << objData.first;
361 connections.insert(objData.first);
362 objectsWithConnection.insert(
363 std::make_pair(object.first, objData.first));
Ed Tanous1abe55e2018-09-05 08:30:59 -0700364 }
365 }
366 }
367 BMCWEB_LOG_DEBUG << "Found " << connections.size() << " connections";
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +0530368 callback(std::move(connections), std::move(objectsWithConnection));
369 BMCWEB_LOG_DEBUG << "getObjectsWithConnection resp_handler exit";
Ed Tanous1abe55e2018-09-05 08:30:59 -0700370 };
Ed Tanous1abe55e2018-09-05 08:30:59 -0700371 // Make call to ObjectMapper to find all sensors objects
372 crow::connections::systemBus->async_method_call(
373 std::move(respHandler), "xyz.openbmc_project.ObjectMapper",
374 "/xyz/openbmc_project/object_mapper",
375 "xyz.openbmc_project.ObjectMapper", "GetSubTree", path, 2, interfaces);
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +0530376 BMCWEB_LOG_DEBUG << "getObjectsWithConnection exit";
377}
378
379/**
380 * @brief Create connections necessary for sensors
381 * @param SensorsAsyncResp Pointer to object holding response data
382 * @param sensorNames Sensors retrieved from chassis
383 * @param callback Callback for processing gathered connections
384 */
385template <typename Callback>
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700386void getConnections(
Ed Tanous81ce6092020-12-17 16:54:55 +0000387 std::shared_ptr<SensorsAsyncResp> sensorsAsyncResp,
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700388 const std::shared_ptr<boost::container::flat_set<std::string>> sensorNames,
389 Callback&& callback)
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +0530390{
391 auto objectsWithConnectionCb =
392 [callback](const boost::container::flat_set<std::string>& connections,
393 const std::set<std::pair<std::string, std::string>>&
Ed Tanous3174e4d2020-10-07 11:41:22 -0700394 /*objectsWithConnection*/) { callback(connections); };
Ed Tanous81ce6092020-12-17 16:54:55 +0000395 getObjectsWithConnection(sensorsAsyncResp, sensorNames,
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +0530396 std::move(objectsWithConnectionCb));
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100397}
398
399/**
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700400 * @brief Shrinks the list of sensors for processing
401 * @param SensorsAysncResp The class holding the Redfish response
402 * @param allSensors A list of all the sensors associated to the
403 * chassis element (i.e. baseboard, front panel, etc...)
404 * @param activeSensors A list that is a reduction of the incoming
405 * allSensors list. Eliminate Thermal sensors when a Power request is
406 * made, and eliminate Power sensors when a Thermal request is made.
407 */
Ed Tanous23a21a12020-07-25 04:45:05 +0000408inline void reduceSensorList(
Ed Tanous81ce6092020-12-17 16:54:55 +0000409 const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700410 const std::vector<std::string>* allSensors,
Ed Tanousb5a76932020-09-29 16:16:58 -0700411 const std::shared_ptr<boost::container::flat_set<std::string>>&
412 activeSensors)
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700413{
Ed Tanous81ce6092020-12-17 16:54:55 +0000414 if (sensorsAsyncResp == nullptr)
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700415 {
416 return;
417 }
418 if ((allSensors == nullptr) || (activeSensors == nullptr))
419 {
420 messages::resourceNotFound(
zhanghch058d1b46d2021-04-01 11:18:24 +0800421 sensorsAsyncResp->asyncResp->res, sensorsAsyncResp->chassisSubNode,
Ed Tanous81ce6092020-12-17 16:54:55 +0000422 sensorsAsyncResp->chassisSubNode == sensors::node::thermal
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200423 ? "Temperatures"
424 : "Voltages");
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700425
426 return;
427 }
428 if (allSensors->empty())
429 {
430 // Nothing to do, the activeSensors object is also empty
431 return;
432 }
433
Ed Tanous81ce6092020-12-17 16:54:55 +0000434 for (const char* type : sensorsAsyncResp->types)
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700435 {
436 for (const std::string& sensor : *allSensors)
437 {
438 if (boost::starts_with(sensor, type))
439 {
440 activeSensors->emplace(sensor);
441 }
442 }
443 }
444}
445
446/**
Carol Wang4bb3dc32019-10-17 18:15:02 +0800447 * @brief Retrieves valid chassis path
448 * @param asyncResp Pointer to object holding response data
449 * @param callback Callback for next step to get valid chassis path
450 */
451template <typename Callback>
Ed Tanousb5a76932020-09-29 16:16:58 -0700452void getValidChassisPath(const std::shared_ptr<SensorsAsyncResp>& asyncResp,
Carol Wang4bb3dc32019-10-17 18:15:02 +0800453 Callback&& callback)
454{
455 BMCWEB_LOG_DEBUG << "checkChassisId enter";
456 const std::array<const char*, 2> interfaces = {
457 "xyz.openbmc_project.Inventory.Item.Board",
458 "xyz.openbmc_project.Inventory.Item.Chassis"};
459
460 auto respHandler =
461 [callback{std::move(callback)},
462 asyncResp](const boost::system::error_code ec,
463 const std::vector<std::string>& chassisPaths) mutable {
464 BMCWEB_LOG_DEBUG << "getValidChassisPath respHandler enter";
465 if (ec)
466 {
467 BMCWEB_LOG_ERROR
468 << "getValidChassisPath respHandler DBUS error: " << ec;
zhanghch058d1b46d2021-04-01 11:18:24 +0800469 messages::internalError(asyncResp->asyncResp->res);
Carol Wang4bb3dc32019-10-17 18:15:02 +0800470 return;
471 }
472
473 std::optional<std::string> chassisPath;
474 std::string chassisName;
475 for (const std::string& chassis : chassisPaths)
476 {
George Liu28aa8de2021-02-01 15:13:30 +0800477 sdbusplus::message::object_path path(chassis);
478 chassisName = path.filename();
479 if (chassisName.empty())
Carol Wang4bb3dc32019-10-17 18:15:02 +0800480 {
481 BMCWEB_LOG_ERROR << "Failed to find '/' in " << chassis;
482 continue;
483 }
Carol Wang4bb3dc32019-10-17 18:15:02 +0800484 if (chassisName == asyncResp->chassisId)
485 {
486 chassisPath = chassis;
487 break;
488 }
489 }
490 callback(chassisPath);
491 };
492
493 // Get the Chassis Collection
494 crow::connections::systemBus->async_method_call(
495 respHandler, "xyz.openbmc_project.ObjectMapper",
496 "/xyz/openbmc_project/object_mapper",
497 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths",
498 "/xyz/openbmc_project/inventory", 0, interfaces);
499 BMCWEB_LOG_DEBUG << "checkChassisId exit";
500}
501
502/**
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100503 * @brief Retrieves requested chassis sensors and redundancy data from DBus .
Kowalski, Kamil588c3f02018-04-03 14:55:27 +0200504 * @param SensorsAsyncResp Pointer to object holding response data
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100505 * @param callback Callback for next step in gathered sensor processing
506 */
507template <typename Callback>
Ed Tanousb5a76932020-09-29 16:16:58 -0700508void getChassis(const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700509 Callback&& callback)
510{
511 BMCWEB_LOG_DEBUG << "getChassis enter";
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500512 const std::array<const char*, 2> interfaces = {
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700513 "xyz.openbmc_project.Inventory.Item.Board",
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500514 "xyz.openbmc_project.Inventory.Item.Chassis"};
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700515 auto respHandler = [callback{std::move(callback)}, sensorsAsyncResp](
516 const boost::system::error_code ec,
517 const std::vector<std::string>& chassisPaths) {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700518 BMCWEB_LOG_DEBUG << "getChassis respHandler enter";
519 if (ec)
520 {
521 BMCWEB_LOG_ERROR << "getChassis respHandler DBUS error: " << ec;
zhanghch058d1b46d2021-04-01 11:18:24 +0800522 messages::internalError(sensorsAsyncResp->asyncResp->res);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700523 return;
524 }
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100525
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700526 const std::string* chassisPath = nullptr;
527 std::string chassisName;
528 for (const std::string& chassis : chassisPaths)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700529 {
George Liu28aa8de2021-02-01 15:13:30 +0800530 sdbusplus::message::object_path path(chassis);
531 chassisName = path.filename();
532 if (chassisName.empty())
Ed Tanous1abe55e2018-09-05 08:30:59 -0700533 {
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700534 BMCWEB_LOG_ERROR << "Failed to find '/' in " << chassis;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700535 continue;
536 }
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700537 if (chassisName == sensorsAsyncResp->chassisId)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700538 {
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700539 chassisPath = &chassis;
540 break;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700541 }
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700542 }
543 if (chassisPath == nullptr)
544 {
zhanghch058d1b46d2021-04-01 11:18:24 +0800545 messages::resourceNotFound(sensorsAsyncResp->asyncResp->res,
546 "Chassis", sensorsAsyncResp->chassisId);
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700547 return;
548 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700549
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700550 const std::string& chassisSubNode = sensorsAsyncResp->chassisSubNode;
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200551 if (chassisSubNode == sensors::node::power)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700552 {
zhanghch058d1b46d2021-04-01 11:18:24 +0800553 sensorsAsyncResp->asyncResp->res.jsonValue["@odata.type"] =
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700554 "#Power.v1_5_2.Power";
Ed Tanous1abe55e2018-09-05 08:30:59 -0700555 }
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200556 else if (chassisSubNode == sensors::node::thermal)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700557 {
zhanghch058d1b46d2021-04-01 11:18:24 +0800558 sensorsAsyncResp->asyncResp->res.jsonValue["@odata.type"] =
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700559 "#Thermal.v1_4_0.Thermal";
zhanghch058d1b46d2021-04-01 11:18:24 +0800560 sensorsAsyncResp->asyncResp->res.jsonValue["Fans"] =
561 nlohmann::json::array();
562 sensorsAsyncResp->asyncResp->res.jsonValue["Temperatures"] =
Jennifer Lee4f9a2132019-03-04 12:45:19 -0800563 nlohmann::json::array();
Ed Tanous1abe55e2018-09-05 08:30:59 -0700564 }
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200565 else if (chassisSubNode == sensors::node::sensors)
Anthony Wilson95a3eca2019-06-11 10:44:47 -0500566 {
zhanghch058d1b46d2021-04-01 11:18:24 +0800567 sensorsAsyncResp->asyncResp->res.jsonValue["@odata.type"] =
Anthony Wilson95a3eca2019-06-11 10:44:47 -0500568 "#SensorCollection.SensorCollection";
zhanghch058d1b46d2021-04-01 11:18:24 +0800569 sensorsAsyncResp->asyncResp->res.jsonValue["Description"] =
Anthony Wilson95a3eca2019-06-11 10:44:47 -0500570 "Collection of Sensors for this Chassis";
zhanghch058d1b46d2021-04-01 11:18:24 +0800571 sensorsAsyncResp->asyncResp->res.jsonValue["Members"] =
Anthony Wilson95a3eca2019-06-11 10:44:47 -0500572 nlohmann::json::array();
zhanghch058d1b46d2021-04-01 11:18:24 +0800573 sensorsAsyncResp->asyncResp->res.jsonValue["Members@odata.count"] =
574 0;
Anthony Wilson95a3eca2019-06-11 10:44:47 -0500575 }
576
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200577 if (chassisSubNode != sensors::node::sensors)
Anthony Wilson95a3eca2019-06-11 10:44:47 -0500578 {
zhanghch058d1b46d2021-04-01 11:18:24 +0800579 sensorsAsyncResp->asyncResp->res.jsonValue["Id"] = chassisSubNode;
Anthony Wilson95a3eca2019-06-11 10:44:47 -0500580 }
581
zhanghch058d1b46d2021-04-01 11:18:24 +0800582 sensorsAsyncResp->asyncResp->res.jsonValue["@odata.id"] =
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700583 "/redfish/v1/Chassis/" + sensorsAsyncResp->chassisId + "/" +
584 chassisSubNode;
zhanghch058d1b46d2021-04-01 11:18:24 +0800585 sensorsAsyncResp->asyncResp->res.jsonValue["Name"] = chassisSubNode;
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500586 // Get the list of all sensors for this Chassis element
587 std::string sensorPath = *chassisPath + "/all_sensors";
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700588 crow::connections::systemBus->async_method_call(
589 [sensorsAsyncResp, callback{std::move(callback)}](
Ed Tanous271584a2019-07-09 16:24:22 -0700590 const boost::system::error_code& e,
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700591 const std::variant<std::vector<std::string>>&
592 variantEndpoints) {
Ed Tanous271584a2019-07-09 16:24:22 -0700593 if (e)
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700594 {
Ed Tanous271584a2019-07-09 16:24:22 -0700595 if (e.value() != EBADR)
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700596 {
zhanghch058d1b46d2021-04-01 11:18:24 +0800597 messages::internalError(
598 sensorsAsyncResp->asyncResp->res);
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700599 return;
600 }
601 }
602 const std::vector<std::string>* nodeSensorList =
603 std::get_if<std::vector<std::string>>(&(variantEndpoints));
604 if (nodeSensorList == nullptr)
605 {
606 messages::resourceNotFound(
zhanghch058d1b46d2021-04-01 11:18:24 +0800607 sensorsAsyncResp->asyncResp->res,
608 sensorsAsyncResp->chassisSubNode,
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200609 sensorsAsyncResp->chassisSubNode ==
610 sensors::node::thermal
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700611 ? "Temperatures"
Patrick Williams738c1e62021-02-22 17:14:25 -0600612 : sensorsAsyncResp->chassisSubNode ==
613 sensors::node::power
614 ? "Voltages"
615 : "Sensors");
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700616 return;
617 }
618 const std::shared_ptr<boost::container::flat_set<std::string>>
619 culledSensorList = std::make_shared<
620 boost::container::flat_set<std::string>>();
621 reduceSensorList(sensorsAsyncResp, nodeSensorList,
622 culledSensorList);
623 callback(culledSensorList);
624 },
625 "xyz.openbmc_project.ObjectMapper", sensorPath,
626 "org.freedesktop.DBus.Properties", "Get",
627 "xyz.openbmc_project.Association", "endpoints");
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100628 };
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100629
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700630 // Get the Chassis Collection
Ed Tanous1abe55e2018-09-05 08:30:59 -0700631 crow::connections::systemBus->async_method_call(
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700632 respHandler, "xyz.openbmc_project.ObjectMapper",
633 "/xyz/openbmc_project/object_mapper",
634 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths",
Ed Tanous271584a2019-07-09 16:24:22 -0700635 "/xyz/openbmc_project/inventory", 0, interfaces);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700636 BMCWEB_LOG_DEBUG << "getChassis exit";
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100637}
638
639/**
Shawn McCarneyde629b62019-03-08 10:42:51 -0600640 * @brief Finds all DBus object paths that implement ObjectManager.
641 *
642 * Creates a mapping from the associated connection name to the object path.
643 *
644 * Finds the object paths asynchronously. Invokes callback when information has
645 * been obtained.
646 *
647 * The callback must have the following signature:
648 * @code
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500649 * callback(std::shared_ptr<boost::container::flat_map<std::string,
650 * std::string>> objectMgrPaths)
Shawn McCarneyde629b62019-03-08 10:42:51 -0600651 * @endcode
652 *
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700653 * @param sensorsAsyncResp Pointer to object holding response data.
Shawn McCarneyde629b62019-03-08 10:42:51 -0600654 * @param callback Callback to invoke when object paths obtained.
655 */
656template <typename Callback>
Ed Tanousb5a76932020-09-29 16:16:58 -0700657void getObjectManagerPaths(
Ed Tanous81ce6092020-12-17 16:54:55 +0000658 const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
Ed Tanousb5a76932020-09-29 16:16:58 -0700659 Callback&& callback)
Shawn McCarneyde629b62019-03-08 10:42:51 -0600660{
661 BMCWEB_LOG_DEBUG << "getObjectManagerPaths enter";
662 const std::array<std::string, 1> interfaces = {
663 "org.freedesktop.DBus.ObjectManager"};
664
665 // Response handler for GetSubTree DBus method
666 auto respHandler = [callback{std::move(callback)},
Ed Tanous81ce6092020-12-17 16:54:55 +0000667 sensorsAsyncResp](const boost::system::error_code ec,
Shawn McCarneyde629b62019-03-08 10:42:51 -0600668 const GetSubTreeType& subtree) {
669 BMCWEB_LOG_DEBUG << "getObjectManagerPaths respHandler enter";
670 if (ec)
671 {
zhanghch058d1b46d2021-04-01 11:18:24 +0800672 messages::internalError(sensorsAsyncResp->asyncResp->res);
Shawn McCarneyde629b62019-03-08 10:42:51 -0600673 BMCWEB_LOG_ERROR << "getObjectManagerPaths respHandler: DBus error "
674 << ec;
675 return;
676 }
677
678 // Loop over returned object paths
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500679 std::shared_ptr<boost::container::flat_map<std::string, std::string>>
680 objectMgrPaths = std::make_shared<
681 boost::container::flat_map<std::string, std::string>>();
Shawn McCarneyde629b62019-03-08 10:42:51 -0600682 for (const std::pair<
683 std::string,
684 std::vector<std::pair<std::string, std::vector<std::string>>>>&
685 object : subtree)
686 {
687 // Loop over connections for current object path
688 const std::string& objectPath = object.first;
689 for (const std::pair<std::string, std::vector<std::string>>&
690 objData : object.second)
691 {
692 // Add mapping from connection to object path
693 const std::string& connection = objData.first;
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500694 (*objectMgrPaths)[connection] = objectPath;
Shawn McCarneyde629b62019-03-08 10:42:51 -0600695 BMCWEB_LOG_DEBUG << "Added mapping " << connection << " -> "
696 << objectPath;
697 }
698 }
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500699 callback(objectMgrPaths);
Shawn McCarneyde629b62019-03-08 10:42:51 -0600700 BMCWEB_LOG_DEBUG << "getObjectManagerPaths respHandler exit";
701 };
702
703 // Query mapper for all DBus object paths that implement ObjectManager
704 crow::connections::systemBus->async_method_call(
705 std::move(respHandler), "xyz.openbmc_project.ObjectMapper",
706 "/xyz/openbmc_project/object_mapper",
Ed Tanous271584a2019-07-09 16:24:22 -0700707 "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/", 0, interfaces);
Shawn McCarneyde629b62019-03-08 10:42:51 -0600708 BMCWEB_LOG_DEBUG << "getObjectManagerPaths exit";
709}
710
711/**
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500712 * @brief Returns the Redfish State value for the specified inventory item.
713 * @param inventoryItem D-Bus inventory item associated with a sensor.
714 * @return State value for inventory item.
James Feist34dd1792019-05-17 14:10:54 -0700715 */
Ed Tanous23a21a12020-07-25 04:45:05 +0000716inline std::string getState(const InventoryItem* inventoryItem)
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500717{
718 if ((inventoryItem != nullptr) && !(inventoryItem->isPresent))
719 {
720 return "Absent";
721 }
James Feist34dd1792019-05-17 14:10:54 -0700722
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500723 return "Enabled";
724}
725
726/**
727 * @brief Returns the Redfish Health value for the specified sensor.
728 * @param sensorJson Sensor JSON object.
729 * @param interfacesDict Map of all sensor interfaces.
730 * @param inventoryItem D-Bus inventory item associated with the sensor. Will
731 * be nullptr if no associated inventory item was found.
732 * @return Health value for sensor.
733 */
Ed Tanous23a21a12020-07-25 04:45:05 +0000734inline std::string getHealth(
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500735 nlohmann::json& sensorJson,
James Feist34dd1792019-05-17 14:10:54 -0700736 const boost::container::flat_map<
737 std::string, boost::container::flat_map<std::string, SensorVariant>>&
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500738 interfacesDict,
739 const InventoryItem* inventoryItem)
James Feist34dd1792019-05-17 14:10:54 -0700740{
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500741 // Get current health value (if any) in the sensor JSON object. Some JSON
742 // objects contain multiple sensors (such as PowerSupplies). We want to set
743 // the overall health to be the most severe of any of the sensors.
744 std::string currentHealth;
745 auto statusIt = sensorJson.find("Status");
746 if (statusIt != sensorJson.end())
747 {
748 auto healthIt = statusIt->find("Health");
749 if (healthIt != statusIt->end())
750 {
751 std::string* health = healthIt->get_ptr<std::string*>();
752 if (health != nullptr)
753 {
754 currentHealth = *health;
755 }
756 }
757 }
758
759 // If current health in JSON object is already Critical, return that. This
760 // should override the sensor health, which might be less severe.
761 if (currentHealth == "Critical")
762 {
763 return "Critical";
764 }
765
766 // Check if sensor has critical threshold alarm
James Feist34dd1792019-05-17 14:10:54 -0700767 auto criticalThresholdIt =
768 interfacesDict.find("xyz.openbmc_project.Sensor.Threshold.Critical");
769 if (criticalThresholdIt != interfacesDict.end())
770 {
771 auto thresholdHighIt =
772 criticalThresholdIt->second.find("CriticalAlarmHigh");
773 auto thresholdLowIt =
774 criticalThresholdIt->second.find("CriticalAlarmLow");
775 if (thresholdHighIt != criticalThresholdIt->second.end())
776 {
777 const bool* asserted = std::get_if<bool>(&thresholdHighIt->second);
778 if (asserted == nullptr)
779 {
780 BMCWEB_LOG_ERROR << "Illegal sensor threshold";
781 }
782 else if (*asserted)
783 {
784 return "Critical";
785 }
786 }
787 if (thresholdLowIt != criticalThresholdIt->second.end())
788 {
789 const bool* asserted = std::get_if<bool>(&thresholdLowIt->second);
790 if (asserted == nullptr)
791 {
792 BMCWEB_LOG_ERROR << "Illegal sensor threshold";
793 }
794 else if (*asserted)
795 {
796 return "Critical";
797 }
798 }
799 }
800
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500801 // Check if associated inventory item is not functional
802 if ((inventoryItem != nullptr) && !(inventoryItem->isFunctional))
803 {
804 return "Critical";
805 }
806
807 // If current health in JSON object is already Warning, return that. This
808 // should override the sensor status, which might be less severe.
809 if (currentHealth == "Warning")
810 {
811 return "Warning";
812 }
813
814 // Check if sensor has warning threshold alarm
James Feist34dd1792019-05-17 14:10:54 -0700815 auto warningThresholdIt =
816 interfacesDict.find("xyz.openbmc_project.Sensor.Threshold.Warning");
817 if (warningThresholdIt != interfacesDict.end())
818 {
819 auto thresholdHighIt =
820 warningThresholdIt->second.find("WarningAlarmHigh");
821 auto thresholdLowIt =
822 warningThresholdIt->second.find("WarningAlarmLow");
823 if (thresholdHighIt != warningThresholdIt->second.end())
824 {
825 const bool* asserted = std::get_if<bool>(&thresholdHighIt->second);
826 if (asserted == nullptr)
827 {
828 BMCWEB_LOG_ERROR << "Illegal sensor threshold";
829 }
830 else if (*asserted)
831 {
832 return "Warning";
833 }
834 }
835 if (thresholdLowIt != warningThresholdIt->second.end())
836 {
837 const bool* asserted = std::get_if<bool>(&thresholdLowIt->second);
838 if (asserted == nullptr)
839 {
840 BMCWEB_LOG_ERROR << "Illegal sensor threshold";
841 }
842 else if (*asserted)
843 {
844 return "Warning";
845 }
846 }
847 }
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500848
James Feist34dd1792019-05-17 14:10:54 -0700849 return "OK";
850}
851
Ed Tanous23a21a12020-07-25 04:45:05 +0000852inline void setLedState(nlohmann::json& sensorJson,
Anthony Wilsond5005492019-07-31 16:34:17 -0500853 const InventoryItem* inventoryItem)
854{
855 if (inventoryItem != nullptr && !inventoryItem->ledObjectPath.empty())
856 {
857 switch (inventoryItem->ledState)
858 {
859 case LedState::OFF:
860 sensorJson["IndicatorLED"] = "Off";
861 break;
862 case LedState::ON:
863 sensorJson["IndicatorLED"] = "Lit";
864 break;
865 case LedState::BLINK:
866 sensorJson["IndicatorLED"] = "Blinking";
867 break;
Ed Tanous23a21a12020-07-25 04:45:05 +0000868 case LedState::UNKNOWN:
Anthony Wilsond5005492019-07-31 16:34:17 -0500869 break;
870 }
871 }
872}
873
James Feist34dd1792019-05-17 14:10:54 -0700874/**
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100875 * @brief Builds a json sensor representation of a sensor.
876 * @param sensorName The name of the sensor to be built
Gunnar Mills274fad52018-06-13 15:45:36 -0500877 * @param sensorType The type (temperature, fan_tach, etc) of the sensor to
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100878 * build
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200879 * @param sensorsAsyncResp Sensor metadata
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100880 * @param interfacesDict A dictionary of the interfaces and properties of said
881 * interfaces to be built from
882 * @param sensor_json The json object to fill
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500883 * @param inventoryItem D-Bus inventory item associated with the sensor. Will
884 * be nullptr if no associated inventory item was found.
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100885 */
Ed Tanous23a21a12020-07-25 04:45:05 +0000886inline void objectInterfacesToJson(
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100887 const std::string& sensorName, const std::string& sensorType,
Ed Tanousb5a76932020-09-29 16:16:58 -0700888 const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100889 const boost::container::flat_map<
Ed Tanousaa2e59c2018-04-12 12:17:20 -0700890 std::string, boost::container::flat_map<std::string, SensorVariant>>&
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100891 interfacesDict,
Ed Tanous81ce6092020-12-17 16:54:55 +0000892 nlohmann::json& sensorJson, InventoryItem* inventoryItem)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700893{
894 // We need a value interface before we can do anything with it
895 auto valueIt = interfacesDict.find("xyz.openbmc_project.Sensor.Value");
896 if (valueIt == interfacesDict.end())
897 {
898 BMCWEB_LOG_ERROR << "Sensor doesn't have a value interface";
899 return;
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100900 }
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100901
Ed Tanous1abe55e2018-09-05 08:30:59 -0700902 // Assume values exist as is (10^0 == 1) if no scale exists
903 int64_t scaleMultiplier = 0;
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100904
Ed Tanous1abe55e2018-09-05 08:30:59 -0700905 auto scaleIt = valueIt->second.find("Scale");
906 // If a scale exists, pull value as int64, and use the scaling.
907 if (scaleIt != valueIt->second.end())
908 {
Ed Tanousabf2add2019-01-22 16:40:12 -0800909 const int64_t* int64Value = std::get_if<int64_t>(&scaleIt->second);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700910 if (int64Value != nullptr)
911 {
912 scaleMultiplier = *int64Value;
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100913 }
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100914 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700915
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200916 if (sensorsAsyncResp->chassisSubNode == sensors::node::sensors)
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500917 {
Anthony Wilson95a3eca2019-06-11 10:44:47 -0500918 // For sensors in SensorCollection we set Id instead of MemberId,
919 // including power sensors.
Ed Tanous81ce6092020-12-17 16:54:55 +0000920 sensorJson["Id"] = sensorName;
921 sensorJson["Name"] = boost::replace_all_copy(sensorName, "_", " ");
Anthony Wilson95a3eca2019-06-11 10:44:47 -0500922 }
923 else if (sensorType != "power")
924 {
925 // Set MemberId and Name for non-power sensors. For PowerSupplies and
926 // PowerControl, those properties have more general values because
927 // multiple sensors can be stored in the same JSON object.
Ed Tanous81ce6092020-12-17 16:54:55 +0000928 sensorJson["MemberId"] = sensorName;
929 sensorJson["Name"] = boost::replace_all_copy(sensorName, "_", " ");
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500930 }
Ed Tanouse742b6c2019-05-03 15:06:53 -0700931
Ed Tanous81ce6092020-12-17 16:54:55 +0000932 sensorJson["Status"]["State"] = getState(inventoryItem);
933 sensorJson["Status"]["Health"] =
934 getHealth(sensorJson, interfacesDict, inventoryItem);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700935
936 // Parameter to set to override the type we get from dbus, and force it to
937 // int, regardless of what is available. This is used for schemas like fan,
938 // that require integers, not floats.
939 bool forceToInt = false;
940
Anthony Wilson3929aca2019-07-19 15:42:33 -0500941 nlohmann::json::json_pointer unit("/Reading");
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200942 if (sensorsAsyncResp->chassisSubNode == sensors::node::sensors)
Anthony Wilson95a3eca2019-06-11 10:44:47 -0500943 {
Ed Tanous81ce6092020-12-17 16:54:55 +0000944 sensorJson["@odata.type"] = "#Sensor.v1_0_0.Sensor";
Wludzik, Jozefc2bf7f92021-03-08 14:35:54 +0000945
946 const std::string& readingType = sensors::toReadingType(sensorType);
947 if (readingType.empty())
Anthony Wilson95a3eca2019-06-11 10:44:47 -0500948 {
Wludzik, Jozefc2bf7f92021-03-08 14:35:54 +0000949 BMCWEB_LOG_ERROR << "Redfish cannot map reading type for "
950 << sensorType;
Anthony Wilson95a3eca2019-06-11 10:44:47 -0500951 }
Wludzik, Jozefc2bf7f92021-03-08 14:35:54 +0000952 else
Anthony Wilson95a3eca2019-06-11 10:44:47 -0500953 {
Wludzik, Jozefc2bf7f92021-03-08 14:35:54 +0000954 sensorJson["ReadingType"] = readingType;
Anthony Wilson95a3eca2019-06-11 10:44:47 -0500955 }
Wludzik, Jozefc2bf7f92021-03-08 14:35:54 +0000956
957 const std::string& readingUnits = sensors::toReadingUnits(sensorType);
958 if (readingUnits.empty())
Adrian Ambrożewiczf8ede152020-06-02 13:26:33 +0200959 {
Wludzik, Jozefc2bf7f92021-03-08 14:35:54 +0000960 BMCWEB_LOG_ERROR << "Redfish cannot map reading unit for "
961 << sensorType;
962 }
963 else
964 {
965 sensorJson["ReadingUnits"] = readingUnits;
Adrian Ambrożewiczf8ede152020-06-02 13:26:33 +0200966 }
Anthony Wilson95a3eca2019-06-11 10:44:47 -0500967 }
968 else if (sensorType == "temperature")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700969 {
Anthony Wilson3929aca2019-07-19 15:42:33 -0500970 unit = "/ReadingCelsius"_json_pointer;
Ed Tanous81ce6092020-12-17 16:54:55 +0000971 sensorJson["@odata.type"] = "#Thermal.v1_3_0.Temperature";
Ed Tanous1abe55e2018-09-05 08:30:59 -0700972 // TODO(ed) Documentation says that path should be type fan_tach,
973 // implementation seems to implement fan
974 }
975 else if (sensorType == "fan" || sensorType == "fan_tach")
976 {
Anthony Wilson3929aca2019-07-19 15:42:33 -0500977 unit = "/Reading"_json_pointer;
Ed Tanous81ce6092020-12-17 16:54:55 +0000978 sensorJson["ReadingUnits"] = "RPM";
979 sensorJson["@odata.type"] = "#Thermal.v1_3_0.Fan";
980 setLedState(sensorJson, inventoryItem);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700981 forceToInt = true;
982 }
Ed Tanous6f6d0d32018-10-12 11:16:43 -0700983 else if (sensorType == "fan_pwm")
984 {
Anthony Wilson3929aca2019-07-19 15:42:33 -0500985 unit = "/Reading"_json_pointer;
Ed Tanous81ce6092020-12-17 16:54:55 +0000986 sensorJson["ReadingUnits"] = "Percent";
987 sensorJson["@odata.type"] = "#Thermal.v1_3_0.Fan";
988 setLedState(sensorJson, inventoryItem);
Ed Tanous6f6d0d32018-10-12 11:16:43 -0700989 forceToInt = true;
990 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700991 else if (sensorType == "voltage")
992 {
Anthony Wilson3929aca2019-07-19 15:42:33 -0500993 unit = "/ReadingVolts"_json_pointer;
Ed Tanous81ce6092020-12-17 16:54:55 +0000994 sensorJson["@odata.type"] = "#Power.v1_0_0.Voltage";
Ed Tanous1abe55e2018-09-05 08:30:59 -0700995 }
Ed Tanous2474adf2018-09-05 16:31:16 -0700996 else if (sensorType == "power")
997 {
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700998 std::string sensorNameLower =
999 boost::algorithm::to_lower_copy(sensorName);
1000
Eddie James028f7eb2019-05-17 21:24:36 +00001001 if (!sensorName.compare("total_power"))
1002 {
Ed Tanous81ce6092020-12-17 16:54:55 +00001003 sensorJson["@odata.type"] = "#Power.v1_0_0.PowerControl";
Gunnar Mills7ab06f42019-07-02 13:07:16 -05001004 // Put multiple "sensors" into a single PowerControl, so have
1005 // generic names for MemberId and Name. Follows Redfish mockup.
Ed Tanous81ce6092020-12-17 16:54:55 +00001006 sensorJson["MemberId"] = "0";
1007 sensorJson["Name"] = "Chassis Power Control";
Anthony Wilson3929aca2019-07-19 15:42:33 -05001008 unit = "/PowerConsumedWatts"_json_pointer;
Eddie James028f7eb2019-05-17 21:24:36 +00001009 }
1010 else if (sensorNameLower.find("input") != std::string::npos)
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07001011 {
Anthony Wilson3929aca2019-07-19 15:42:33 -05001012 unit = "/PowerInputWatts"_json_pointer;
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07001013 }
1014 else
1015 {
Anthony Wilson3929aca2019-07-19 15:42:33 -05001016 unit = "/PowerOutputWatts"_json_pointer;
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07001017 }
Ed Tanous2474adf2018-09-05 16:31:16 -07001018 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001019 else
1020 {
1021 BMCWEB_LOG_ERROR << "Redfish cannot map object type for " << sensorName;
1022 return;
1023 }
1024 // Map of dbus interface name, dbus property name and redfish property_name
Anthony Wilson3929aca2019-07-19 15:42:33 -05001025 std::vector<
1026 std::tuple<const char*, const char*, nlohmann::json::json_pointer>>
1027 properties;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001028 properties.reserve(7);
1029
1030 properties.emplace_back("xyz.openbmc_project.Sensor.Value", "Value", unit);
Shawn McCarneyde629b62019-03-08 10:42:51 -06001031
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +02001032 if (sensorsAsyncResp->chassisSubNode == sensors::node::sensors)
Anthony Wilson3929aca2019-07-19 15:42:33 -05001033 {
1034 properties.emplace_back(
1035 "xyz.openbmc_project.Sensor.Threshold.Warning", "WarningHigh",
1036 "/Thresholds/UpperCaution/Reading"_json_pointer);
1037 properties.emplace_back(
1038 "xyz.openbmc_project.Sensor.Threshold.Warning", "WarningLow",
1039 "/Thresholds/LowerCaution/Reading"_json_pointer);
1040 properties.emplace_back(
1041 "xyz.openbmc_project.Sensor.Threshold.Critical", "CriticalHigh",
1042 "/Thresholds/UpperCritical/Reading"_json_pointer);
1043 properties.emplace_back(
1044 "xyz.openbmc_project.Sensor.Threshold.Critical", "CriticalLow",
1045 "/Thresholds/LowerCritical/Reading"_json_pointer);
1046 }
1047 else if (sensorType != "power")
Shawn McCarneyde629b62019-03-08 10:42:51 -06001048 {
1049 properties.emplace_back("xyz.openbmc_project.Sensor.Threshold.Warning",
Anthony Wilson3929aca2019-07-19 15:42:33 -05001050 "WarningHigh",
1051 "/UpperThresholdNonCritical"_json_pointer);
Shawn McCarneyde629b62019-03-08 10:42:51 -06001052 properties.emplace_back("xyz.openbmc_project.Sensor.Threshold.Warning",
Anthony Wilson3929aca2019-07-19 15:42:33 -05001053 "WarningLow",
1054 "/LowerThresholdNonCritical"_json_pointer);
Shawn McCarneyde629b62019-03-08 10:42:51 -06001055 properties.emplace_back("xyz.openbmc_project.Sensor.Threshold.Critical",
Anthony Wilson3929aca2019-07-19 15:42:33 -05001056 "CriticalHigh",
1057 "/UpperThresholdCritical"_json_pointer);
Shawn McCarneyde629b62019-03-08 10:42:51 -06001058 properties.emplace_back("xyz.openbmc_project.Sensor.Threshold.Critical",
Anthony Wilson3929aca2019-07-19 15:42:33 -05001059 "CriticalLow",
1060 "/LowerThresholdCritical"_json_pointer);
Shawn McCarneyde629b62019-03-08 10:42:51 -06001061 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001062
Ed Tanous2474adf2018-09-05 16:31:16 -07001063 // TODO Need to get UpperThresholdFatal and LowerThresholdFatal
1064
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +02001065 if (sensorsAsyncResp->chassisSubNode == sensors::node::sensors)
Anthony Wilson95a3eca2019-06-11 10:44:47 -05001066 {
1067 properties.emplace_back("xyz.openbmc_project.Sensor.Value", "MinValue",
Anthony Wilson3929aca2019-07-19 15:42:33 -05001068 "/ReadingRangeMin"_json_pointer);
Anthony Wilson95a3eca2019-06-11 10:44:47 -05001069 properties.emplace_back("xyz.openbmc_project.Sensor.Value", "MaxValue",
Anthony Wilson3929aca2019-07-19 15:42:33 -05001070 "/ReadingRangeMax"_json_pointer);
Anthony Wilson95a3eca2019-06-11 10:44:47 -05001071 }
1072 else if (sensorType == "temperature")
Ed Tanous1abe55e2018-09-05 08:30:59 -07001073 {
1074 properties.emplace_back("xyz.openbmc_project.Sensor.Value", "MinValue",
Anthony Wilson3929aca2019-07-19 15:42:33 -05001075 "/MinReadingRangeTemp"_json_pointer);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001076 properties.emplace_back("xyz.openbmc_project.Sensor.Value", "MaxValue",
Anthony Wilson3929aca2019-07-19 15:42:33 -05001077 "/MaxReadingRangeTemp"_json_pointer);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001078 }
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001079 else if (sensorType != "power")
Ed Tanous1abe55e2018-09-05 08:30:59 -07001080 {
1081 properties.emplace_back("xyz.openbmc_project.Sensor.Value", "MinValue",
Anthony Wilson3929aca2019-07-19 15:42:33 -05001082 "/MinReadingRange"_json_pointer);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001083 properties.emplace_back("xyz.openbmc_project.Sensor.Value", "MaxValue",
Anthony Wilson3929aca2019-07-19 15:42:33 -05001084 "/MaxReadingRange"_json_pointer);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001085 }
1086
Anthony Wilson3929aca2019-07-19 15:42:33 -05001087 for (const std::tuple<const char*, const char*,
1088 nlohmann::json::json_pointer>& p : properties)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001089 {
1090 auto interfaceProperties = interfacesDict.find(std::get<0>(p));
1091 if (interfaceProperties != interfacesDict.end())
1092 {
Ed Tanous271584a2019-07-09 16:24:22 -07001093 auto thisValueIt = interfaceProperties->second.find(std::get<1>(p));
1094 if (thisValueIt != interfaceProperties->second.end())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001095 {
Ed Tanous271584a2019-07-09 16:24:22 -07001096 const SensorVariant& valueVariant = thisValueIt->second;
Anthony Wilson3929aca2019-07-19 15:42:33 -05001097
1098 // The property we want to set may be nested json, so use
1099 // a json_pointer for easy indexing into the json structure.
1100 const nlohmann::json::json_pointer& key = std::get<2>(p);
1101
Ed Tanous1abe55e2018-09-05 08:30:59 -07001102 // Attempt to pull the int64 directly
Ed Tanousabf2add2019-01-22 16:40:12 -08001103 const int64_t* int64Value = std::get_if<int64_t>(&valueVariant);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001104
Ed Tanousabf2add2019-01-22 16:40:12 -08001105 const double* doubleValue = std::get_if<double>(&valueVariant);
Eddie James028f7eb2019-05-17 21:24:36 +00001106 const uint32_t* uValue = std::get_if<uint32_t>(&valueVariant);
Ed Tanous6f6d0d32018-10-12 11:16:43 -07001107 double temp = 0.0;
1108 if (int64Value != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001109 {
Ed Tanous271584a2019-07-09 16:24:22 -07001110 temp = static_cast<double>(*int64Value);
Ed Tanous6f6d0d32018-10-12 11:16:43 -07001111 }
1112 else if (doubleValue != nullptr)
1113 {
1114 temp = *doubleValue;
1115 }
Eddie James028f7eb2019-05-17 21:24:36 +00001116 else if (uValue != nullptr)
1117 {
1118 temp = *uValue;
1119 }
Ed Tanous6f6d0d32018-10-12 11:16:43 -07001120 else
1121 {
1122 BMCWEB_LOG_ERROR
1123 << "Got value interface that wasn't int or double";
1124 continue;
1125 }
1126 temp = temp * std::pow(10, scaleMultiplier);
1127 if (forceToInt)
1128 {
Ed Tanous81ce6092020-12-17 16:54:55 +00001129 sensorJson[key] = static_cast<int64_t>(temp);
Ed Tanous6f6d0d32018-10-12 11:16:43 -07001130 }
1131 else
1132 {
Ed Tanous81ce6092020-12-17 16:54:55 +00001133 sensorJson[key] = temp;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001134 }
1135 }
1136 }
1137 }
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +02001138
Ed Tanous81ce6092020-12-17 16:54:55 +00001139 sensorsAsyncResp->addMetadata(sensorJson, unit.to_string(),
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +02001140 "/xyz/openbmc_project/sensors/" + sensorType +
1141 "/" + sensorName);
1142
Ed Tanous1abe55e2018-09-05 08:30:59 -07001143 BMCWEB_LOG_DEBUG << "Added sensor " << sensorName;
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +01001144}
1145
Ed Tanousb5a76932020-09-29 16:16:58 -07001146inline void populateFanRedundancy(
1147 const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp)
James Feist8bd25cc2019-03-15 15:14:00 -07001148{
1149 crow::connections::systemBus->async_method_call(
1150 [sensorsAsyncResp](const boost::system::error_code ec,
1151 const GetSubTreeType& resp) {
1152 if (ec)
1153 {
1154 return; // don't have to have this interface
1155 }
Ed Tanouse278c182019-03-13 16:23:37 -07001156 for (const std::pair<std::string,
1157 std::vector<std::pair<
1158 std::string, std::vector<std::string>>>>&
1159 pathPair : resp)
James Feist8bd25cc2019-03-15 15:14:00 -07001160 {
Ed Tanouse278c182019-03-13 16:23:37 -07001161 const std::string& path = pathPair.first;
1162 const std::vector<
1163 std::pair<std::string, std::vector<std::string>>>& objDict =
1164 pathPair.second;
James Feist8bd25cc2019-03-15 15:14:00 -07001165 if (objDict.empty())
1166 {
1167 continue; // this should be impossible
1168 }
1169
1170 const std::string& owner = objDict.begin()->first;
1171 crow::connections::systemBus->async_method_call(
1172 [path, owner,
Ed Tanous271584a2019-07-09 16:24:22 -07001173 sensorsAsyncResp](const boost::system::error_code e,
James Feist8bd25cc2019-03-15 15:14:00 -07001174 std::variant<std::vector<std::string>>
1175 variantEndpoints) {
Ed Tanous271584a2019-07-09 16:24:22 -07001176 if (e)
James Feist8bd25cc2019-03-15 15:14:00 -07001177 {
1178 return; // if they don't have an association we
1179 // can't tell what chassis is
1180 }
1181 // verify part of the right chassis
1182 auto endpoints = std::get_if<std::vector<std::string>>(
1183 &variantEndpoints);
1184
1185 if (endpoints == nullptr)
1186 {
1187 BMCWEB_LOG_ERROR << "Invalid association interface";
zhanghch058d1b46d2021-04-01 11:18:24 +08001188 messages::internalError(
1189 sensorsAsyncResp->asyncResp->res);
James Feist8bd25cc2019-03-15 15:14:00 -07001190 return;
1191 }
1192
1193 auto found = std::find_if(
1194 endpoints->begin(), endpoints->end(),
1195 [sensorsAsyncResp](const std::string& entry) {
1196 return entry.find(
1197 sensorsAsyncResp->chassisId) !=
1198 std::string::npos;
1199 });
1200
1201 if (found == endpoints->end())
1202 {
1203 return;
1204 }
1205 crow::connections::systemBus->async_method_call(
1206 [path, sensorsAsyncResp](
Ed Tanous271584a2019-07-09 16:24:22 -07001207 const boost::system::error_code& err,
James Feist8bd25cc2019-03-15 15:14:00 -07001208 const boost::container::flat_map<
1209 std::string,
1210 std::variant<uint8_t,
1211 std::vector<std::string>,
1212 std::string>>& ret) {
Ed Tanous271584a2019-07-09 16:24:22 -07001213 if (err)
James Feist8bd25cc2019-03-15 15:14:00 -07001214 {
1215 return; // don't have to have this
1216 // interface
1217 }
1218 auto findFailures = ret.find("AllowedFailures");
1219 auto findCollection = ret.find("Collection");
1220 auto findStatus = ret.find("Status");
1221
1222 if (findFailures == ret.end() ||
1223 findCollection == ret.end() ||
1224 findStatus == ret.end())
1225 {
1226 BMCWEB_LOG_ERROR
1227 << "Invalid redundancy interface";
1228 messages::internalError(
zhanghch058d1b46d2021-04-01 11:18:24 +08001229 sensorsAsyncResp->asyncResp->res);
James Feist8bd25cc2019-03-15 15:14:00 -07001230 return;
1231 }
1232
1233 auto allowedFailures = std::get_if<uint8_t>(
1234 &(findFailures->second));
1235 auto collection =
1236 std::get_if<std::vector<std::string>>(
1237 &(findCollection->second));
1238 auto status = std::get_if<std::string>(
1239 &(findStatus->second));
1240
1241 if (allowedFailures == nullptr ||
1242 collection == nullptr || status == nullptr)
1243 {
1244
1245 BMCWEB_LOG_ERROR
1246 << "Invalid redundancy interface "
1247 "types";
1248 messages::internalError(
zhanghch058d1b46d2021-04-01 11:18:24 +08001249 sensorsAsyncResp->asyncResp->res);
James Feist8bd25cc2019-03-15 15:14:00 -07001250 return;
1251 }
George Liu28aa8de2021-02-01 15:13:30 +08001252 sdbusplus::message::object_path objectPath(
1253 path);
1254 std::string name = objectPath.filename();
1255 if (name.empty())
James Feist8bd25cc2019-03-15 15:14:00 -07001256 {
1257 // this should be impossible
1258 messages::internalError(
zhanghch058d1b46d2021-04-01 11:18:24 +08001259 sensorsAsyncResp->asyncResp->res);
James Feist8bd25cc2019-03-15 15:14:00 -07001260 return;
1261 }
James Feist8bd25cc2019-03-15 15:14:00 -07001262 std::replace(name.begin(), name.end(), '_',
1263 ' ');
1264
1265 std::string health;
1266
1267 if (boost::ends_with(*status, "Full"))
1268 {
1269 health = "OK";
1270 }
1271 else if (boost::ends_with(*status, "Degraded"))
1272 {
1273 health = "Warning";
1274 }
1275 else
1276 {
1277 health = "Critical";
1278 }
1279 std::vector<nlohmann::json> redfishCollection;
1280 const auto& fanRedfish =
zhanghch058d1b46d2021-04-01 11:18:24 +08001281 sensorsAsyncResp->asyncResp->res
1282 .jsonValue["Fans"];
James Feist8bd25cc2019-03-15 15:14:00 -07001283 for (const std::string& item : *collection)
1284 {
George Liu28aa8de2021-02-01 15:13:30 +08001285 sdbusplus::message::object_path path(item);
1286 std::string itemName = path.filename();
1287 if (itemName.empty())
1288 {
1289 continue;
1290 }
James Feist8bd25cc2019-03-15 15:14:00 -07001291 /*
1292 todo(ed): merge patch that fixes the names
1293 std::replace(itemName.begin(),
1294 itemName.end(), '_', ' ');*/
1295 auto schemaItem = std::find_if(
1296 fanRedfish.begin(), fanRedfish.end(),
1297 [itemName](const nlohmann::json& fan) {
1298 return fan["MemberId"] == itemName;
1299 });
1300 if (schemaItem != fanRedfish.end())
1301 {
1302 redfishCollection.push_back(
1303 {{"@odata.id",
1304 (*schemaItem)["@odata.id"]}});
1305 }
1306 else
1307 {
1308 BMCWEB_LOG_ERROR
1309 << "failed to find fan in schema";
1310 messages::internalError(
zhanghch058d1b46d2021-04-01 11:18:24 +08001311 sensorsAsyncResp->asyncResp->res);
James Feist8bd25cc2019-03-15 15:14:00 -07001312 return;
1313 }
1314 }
1315
Kuiying Wang3e9e72e2020-07-07 10:18:32 +08001316 size_t minNumNeeded =
1317 collection->size() > 0
1318 ? collection->size() - *allowedFailures
1319 : 0;
Ed Tanous271584a2019-07-09 16:24:22 -07001320 nlohmann::json& jResp =
zhanghch058d1b46d2021-04-01 11:18:24 +08001321 sensorsAsyncResp->asyncResp->res
Ed Tanous271584a2019-07-09 16:24:22 -07001322 .jsonValue["Redundancy"];
1323 jResp.push_back(
James Feist8bd25cc2019-03-15 15:14:00 -07001324 {{"@odata.id",
AppaRao Puli717794d2019-10-18 22:54:53 +05301325 "/redfish/v1/Chassis/" +
James Feist8bd25cc2019-03-15 15:14:00 -07001326 sensorsAsyncResp->chassisId + "/" +
1327 sensorsAsyncResp->chassisSubNode +
1328 "#/Redundancy/" +
Ed Tanous271584a2019-07-09 16:24:22 -07001329 std::to_string(jResp.size())},
James Feist8bd25cc2019-03-15 15:14:00 -07001330 {"@odata.type",
1331 "#Redundancy.v1_3_2.Redundancy"},
Kuiying Wang3e9e72e2020-07-07 10:18:32 +08001332 {"MinNumNeeded", minNumNeeded},
James Feist8bd25cc2019-03-15 15:14:00 -07001333 {"MemberId", name},
1334 {"Mode", "N+m"},
1335 {"Name", name},
1336 {"RedundancySet", redfishCollection},
1337 {"Status",
1338 {{"Health", health},
1339 {"State", "Enabled"}}}});
1340 },
1341 owner, path, "org.freedesktop.DBus.Properties",
1342 "GetAll",
1343 "xyz.openbmc_project.Control.FanRedundancy");
1344 },
James Feist02e92e32019-06-26 12:07:05 -07001345 "xyz.openbmc_project.ObjectMapper", path + "/chassis",
James Feist8bd25cc2019-03-15 15:14:00 -07001346 "org.freedesktop.DBus.Properties", "Get",
1347 "xyz.openbmc_project.Association", "endpoints");
1348 }
1349 },
1350 "xyz.openbmc_project.ObjectMapper",
1351 "/xyz/openbmc_project/object_mapper",
1352 "xyz.openbmc_project.ObjectMapper", "GetSubTree",
1353 "/xyz/openbmc_project/control", 2,
1354 std::array<const char*, 1>{
1355 "xyz.openbmc_project.Control.FanRedundancy"});
1356}
1357
Ed Tanousb5a76932020-09-29 16:16:58 -07001358inline void
Ed Tanous81ce6092020-12-17 16:54:55 +00001359 sortJSONResponse(const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp)
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07001360{
zhanghch058d1b46d2021-04-01 11:18:24 +08001361 nlohmann::json& response = sensorsAsyncResp->asyncResp->res.jsonValue;
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07001362 std::array<std::string, 2> sensorHeaders{"Temperatures", "Fans"};
Ed Tanous81ce6092020-12-17 16:54:55 +00001363 if (sensorsAsyncResp->chassisSubNode == sensors::node::power)
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07001364 {
1365 sensorHeaders = {"Voltages", "PowerSupplies"};
1366 }
1367 for (const std::string& sensorGroup : sensorHeaders)
1368 {
1369 nlohmann::json::iterator entry = response.find(sensorGroup);
1370 if (entry != response.end())
1371 {
1372 std::sort(entry->begin(), entry->end(),
1373 [](nlohmann::json& c1, nlohmann::json& c2) {
1374 return c1["Name"] < c2["Name"];
1375 });
1376
1377 // add the index counts to the end of each entry
1378 size_t count = 0;
1379 for (nlohmann::json& sensorJson : *entry)
1380 {
1381 nlohmann::json::iterator odata = sensorJson.find("@odata.id");
1382 if (odata == sensorJson.end())
1383 {
1384 continue;
1385 }
1386 std::string* value = odata->get_ptr<std::string*>();
1387 if (value != nullptr)
1388 {
1389 *value += std::to_string(count);
1390 count++;
Ed Tanous81ce6092020-12-17 16:54:55 +00001391 sensorsAsyncResp->updateUri(sensorJson["Name"], *value);
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07001392 }
1393 }
1394 }
1395 }
1396}
1397
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +01001398/**
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001399 * @brief Finds the inventory item with the specified object path.
1400 * @param inventoryItems D-Bus inventory items associated with sensors.
1401 * @param invItemObjPath D-Bus object path of inventory item.
1402 * @return Inventory item within vector, or nullptr if no match found.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001403 */
Ed Tanous23a21a12020-07-25 04:45:05 +00001404inline InventoryItem* findInventoryItem(
Ed Tanousb5a76932020-09-29 16:16:58 -07001405 const std::shared_ptr<std::vector<InventoryItem>>& inventoryItems,
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001406 const std::string& invItemObjPath)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001407{
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001408 for (InventoryItem& inventoryItem : *inventoryItems)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001409 {
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001410 if (inventoryItem.objectPath == invItemObjPath)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001411 {
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001412 return &inventoryItem;
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001413 }
1414 }
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001415 return nullptr;
1416}
1417
1418/**
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001419 * @brief Finds the inventory item associated with the specified sensor.
1420 * @param inventoryItems D-Bus inventory items associated with sensors.
1421 * @param sensorObjPath D-Bus object path of sensor.
1422 * @return Inventory item within vector, or nullptr if no match found.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001423 */
Ed Tanous23a21a12020-07-25 04:45:05 +00001424inline InventoryItem* findInventoryItemForSensor(
Ed Tanousb5a76932020-09-29 16:16:58 -07001425 const std::shared_ptr<std::vector<InventoryItem>>& inventoryItems,
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001426 const std::string& sensorObjPath)
1427{
1428 for (InventoryItem& inventoryItem : *inventoryItems)
1429 {
1430 if (inventoryItem.sensors.count(sensorObjPath) > 0)
1431 {
1432 return &inventoryItem;
1433 }
1434 }
1435 return nullptr;
1436}
1437
1438/**
Anthony Wilsond5005492019-07-31 16:34:17 -05001439 * @brief Finds the inventory item associated with the specified led path.
1440 * @param inventoryItems D-Bus inventory items associated with sensors.
1441 * @param ledObjPath D-Bus object path of led.
1442 * @return Inventory item within vector, or nullptr if no match found.
1443 */
1444inline InventoryItem*
1445 findInventoryItemForLed(std::vector<InventoryItem>& inventoryItems,
1446 const std::string& ledObjPath)
1447{
1448 for (InventoryItem& inventoryItem : inventoryItems)
1449 {
1450 if (inventoryItem.ledObjectPath == ledObjPath)
1451 {
1452 return &inventoryItem;
1453 }
1454 }
1455 return nullptr;
1456}
1457
1458/**
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001459 * @brief Adds inventory item and associated sensor to specified vector.
1460 *
1461 * Adds a new InventoryItem to the vector if necessary. Searches for an
1462 * existing InventoryItem with the specified object path. If not found, one is
1463 * added to the vector.
1464 *
1465 * Next, the specified sensor is added to the set of sensors associated with the
1466 * InventoryItem.
1467 *
1468 * @param inventoryItems D-Bus inventory items associated with sensors.
1469 * @param invItemObjPath D-Bus object path of inventory item.
1470 * @param sensorObjPath D-Bus object path of sensor
1471 */
Ed Tanousb5a76932020-09-29 16:16:58 -07001472inline void addInventoryItem(
1473 const std::shared_ptr<std::vector<InventoryItem>>& inventoryItems,
1474 const std::string& invItemObjPath, const std::string& sensorObjPath)
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001475{
1476 // Look for inventory item in vector
1477 InventoryItem* inventoryItem =
1478 findInventoryItem(inventoryItems, invItemObjPath);
1479
1480 // If inventory item doesn't exist in vector, add it
1481 if (inventoryItem == nullptr)
1482 {
1483 inventoryItems->emplace_back(invItemObjPath);
1484 inventoryItem = &(inventoryItems->back());
1485 }
1486
1487 // Add sensor to set of sensors associated with inventory item
1488 inventoryItem->sensors.emplace(sensorObjPath);
1489}
1490
1491/**
1492 * @brief Stores D-Bus data in the specified inventory item.
1493 *
1494 * Finds D-Bus data in the specified map of interfaces. Stores the data in the
1495 * specified InventoryItem.
1496 *
1497 * This data is later used to provide sensor property values in the JSON
1498 * response.
1499 *
1500 * @param inventoryItem Inventory item where data will be stored.
1501 * @param interfacesDict Map containing D-Bus interfaces and their properties
1502 * for the specified inventory item.
1503 */
Ed Tanous23a21a12020-07-25 04:45:05 +00001504inline void storeInventoryItemData(
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001505 InventoryItem& inventoryItem,
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001506 const boost::container::flat_map<
1507 std::string, boost::container::flat_map<std::string, SensorVariant>>&
1508 interfacesDict)
1509{
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001510 // Get properties from Inventory.Item interface
1511 auto interfaceIt =
1512 interfacesDict.find("xyz.openbmc_project.Inventory.Item");
1513 if (interfaceIt != interfacesDict.end())
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001514 {
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001515 auto propertyIt = interfaceIt->second.find("Present");
1516 if (propertyIt != interfaceIt->second.end())
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001517 {
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001518 const bool* value = std::get_if<bool>(&propertyIt->second);
1519 if (value != nullptr)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001520 {
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001521 inventoryItem.isPresent = *value;
1522 }
1523 }
1524 }
1525
1526 // Check if Inventory.Item.PowerSupply interface is present
1527 interfaceIt =
1528 interfacesDict.find("xyz.openbmc_project.Inventory.Item.PowerSupply");
1529 if (interfaceIt != interfacesDict.end())
1530 {
1531 inventoryItem.isPowerSupply = true;
1532 }
1533
1534 // Get properties from Inventory.Decorator.Asset interface
1535 interfaceIt =
1536 interfacesDict.find("xyz.openbmc_project.Inventory.Decorator.Asset");
1537 if (interfaceIt != interfacesDict.end())
1538 {
1539 auto propertyIt = interfaceIt->second.find("Manufacturer");
1540 if (propertyIt != interfaceIt->second.end())
1541 {
1542 const std::string* value =
1543 std::get_if<std::string>(&propertyIt->second);
1544 if (value != nullptr)
1545 {
1546 inventoryItem.manufacturer = *value;
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001547 }
1548 }
1549
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001550 propertyIt = interfaceIt->second.find("Model");
1551 if (propertyIt != interfaceIt->second.end())
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001552 {
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001553 const std::string* value =
1554 std::get_if<std::string>(&propertyIt->second);
1555 if (value != nullptr)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001556 {
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001557 inventoryItem.model = *value;
1558 }
1559 }
1560
1561 propertyIt = interfaceIt->second.find("PartNumber");
1562 if (propertyIt != interfaceIt->second.end())
1563 {
1564 const std::string* value =
1565 std::get_if<std::string>(&propertyIt->second);
1566 if (value != nullptr)
1567 {
1568 inventoryItem.partNumber = *value;
1569 }
1570 }
1571
1572 propertyIt = interfaceIt->second.find("SerialNumber");
1573 if (propertyIt != interfaceIt->second.end())
1574 {
1575 const std::string* value =
1576 std::get_if<std::string>(&propertyIt->second);
1577 if (value != nullptr)
1578 {
1579 inventoryItem.serialNumber = *value;
1580 }
1581 }
1582 }
1583
1584 // Get properties from State.Decorator.OperationalStatus interface
1585 interfaceIt = interfacesDict.find(
1586 "xyz.openbmc_project.State.Decorator.OperationalStatus");
1587 if (interfaceIt != interfacesDict.end())
1588 {
1589 auto propertyIt = interfaceIt->second.find("Functional");
1590 if (propertyIt != interfaceIt->second.end())
1591 {
1592 const bool* value = std::get_if<bool>(&propertyIt->second);
1593 if (value != nullptr)
1594 {
1595 inventoryItem.isFunctional = *value;
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001596 }
1597 }
1598 }
1599}
1600
1601/**
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001602 * @brief Gets D-Bus data for inventory items associated with sensors.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001603 *
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001604 * Uses the specified connections (services) to obtain D-Bus data for inventory
1605 * items associated with sensors. Stores the resulting data in the
1606 * inventoryItems vector.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001607 *
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001608 * This data is later used to provide sensor property values in the JSON
1609 * response.
1610 *
1611 * Finds the inventory item data asynchronously. Invokes callback when data has
1612 * been obtained.
1613 *
1614 * The callback must have the following signature:
1615 * @code
Anthony Wilsond5005492019-07-31 16:34:17 -05001616 * callback(void)
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001617 * @endcode
1618 *
1619 * This function is called recursively, obtaining data asynchronously from one
1620 * connection in each call. This ensures the callback is not invoked until the
1621 * last asynchronous function has completed.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001622 *
1623 * @param sensorsAsyncResp Pointer to object holding response data.
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001624 * @param inventoryItems D-Bus inventory items associated with sensors.
1625 * @param invConnections Connections that provide data for the inventory items.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001626 * @param objectMgrPaths Mappings from connection name to DBus object path that
1627 * implements ObjectManager.
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001628 * @param callback Callback to invoke when inventory data has been obtained.
1629 * @param invConnectionsIndex Current index in invConnections. Only specified
1630 * in recursive calls to this function.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001631 */
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001632template <typename Callback>
1633static void getInventoryItemsData(
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001634 std::shared_ptr<SensorsAsyncResp> sensorsAsyncResp,
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001635 std::shared_ptr<std::vector<InventoryItem>> inventoryItems,
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001636 std::shared_ptr<boost::container::flat_set<std::string>> invConnections,
1637 std::shared_ptr<boost::container::flat_map<std::string, std::string>>
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001638 objectMgrPaths,
Ed Tanous271584a2019-07-09 16:24:22 -07001639 Callback&& callback, size_t invConnectionsIndex = 0)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001640{
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001641 BMCWEB_LOG_DEBUG << "getInventoryItemsData enter";
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001642
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001643 // If no more connections left, call callback
1644 if (invConnectionsIndex >= invConnections->size())
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001645 {
Anthony Wilsond5005492019-07-31 16:34:17 -05001646 callback();
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001647 BMCWEB_LOG_DEBUG << "getInventoryItemsData exit";
1648 return;
1649 }
1650
1651 // Get inventory item data from current connection
1652 auto it = invConnections->nth(invConnectionsIndex);
1653 if (it != invConnections->end())
1654 {
1655 const std::string& invConnection = *it;
1656
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001657 // Response handler for GetManagedObjects
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001658 auto respHandler = [sensorsAsyncResp, inventoryItems, invConnections,
1659 objectMgrPaths, callback{std::move(callback)},
1660 invConnectionsIndex](
1661 const boost::system::error_code ec,
1662 ManagedObjectsVectorType& resp) {
1663 BMCWEB_LOG_DEBUG << "getInventoryItemsData respHandler enter";
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001664 if (ec)
1665 {
1666 BMCWEB_LOG_ERROR
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001667 << "getInventoryItemsData respHandler DBus error " << ec;
zhanghch058d1b46d2021-04-01 11:18:24 +08001668 messages::internalError(sensorsAsyncResp->asyncResp->res);
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001669 return;
1670 }
1671
1672 // Loop through returned object paths
1673 for (const auto& objDictEntry : resp)
1674 {
1675 const std::string& objPath =
1676 static_cast<const std::string&>(objDictEntry.first);
1677
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001678 // If this object path is one of the specified inventory items
1679 InventoryItem* inventoryItem =
1680 findInventoryItem(inventoryItems, objPath);
1681 if (inventoryItem != nullptr)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001682 {
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001683 // Store inventory data in InventoryItem
1684 storeInventoryItemData(*inventoryItem, objDictEntry.second);
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001685 }
1686 }
1687
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001688 // Recurse to get inventory item data from next connection
1689 getInventoryItemsData(sensorsAsyncResp, inventoryItems,
1690 invConnections, objectMgrPaths,
1691 std::move(callback), invConnectionsIndex + 1);
1692
1693 BMCWEB_LOG_DEBUG << "getInventoryItemsData respHandler exit";
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001694 };
1695
1696 // Find DBus object path that implements ObjectManager for the current
1697 // connection. If no mapping found, default to "/".
1698 auto iter = objectMgrPaths->find(invConnection);
1699 const std::string& objectMgrPath =
1700 (iter != objectMgrPaths->end()) ? iter->second : "/";
1701 BMCWEB_LOG_DEBUG << "ObjectManager path for " << invConnection << " is "
1702 << objectMgrPath;
1703
1704 // Get all object paths and their interfaces for current connection
1705 crow::connections::systemBus->async_method_call(
1706 std::move(respHandler), invConnection, objectMgrPath,
1707 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
1708 }
1709
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001710 BMCWEB_LOG_DEBUG << "getInventoryItemsData exit";
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001711}
1712
1713/**
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001714 * @brief Gets connections that provide D-Bus data for inventory items.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001715 *
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001716 * Gets the D-Bus connections (services) that provide data for the inventory
1717 * items that are associated with sensors.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001718 *
1719 * Finds the connections asynchronously. Invokes callback when information has
1720 * been obtained.
1721 *
1722 * The callback must have the following signature:
1723 * @code
1724 * callback(std::shared_ptr<boost::container::flat_set<std::string>>
1725 * invConnections)
1726 * @endcode
1727 *
1728 * @param sensorsAsyncResp Pointer to object holding response data.
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001729 * @param inventoryItems D-Bus inventory items associated with sensors.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001730 * @param callback Callback to invoke when connections have been obtained.
1731 */
1732template <typename Callback>
1733static void getInventoryItemsConnections(
Ed Tanousb5a76932020-09-29 16:16:58 -07001734 const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
1735 const std::shared_ptr<std::vector<InventoryItem>>& inventoryItems,
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001736 Callback&& callback)
1737{
1738 BMCWEB_LOG_DEBUG << "getInventoryItemsConnections enter";
1739
1740 const std::string path = "/xyz/openbmc_project/inventory";
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001741 const std::array<std::string, 4> interfaces = {
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001742 "xyz.openbmc_project.Inventory.Item",
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001743 "xyz.openbmc_project.Inventory.Item.PowerSupply",
1744 "xyz.openbmc_project.Inventory.Decorator.Asset",
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001745 "xyz.openbmc_project.State.Decorator.OperationalStatus"};
1746
1747 // Response handler for parsing output from GetSubTree
1748 auto respHandler = [callback{std::move(callback)}, sensorsAsyncResp,
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001749 inventoryItems](const boost::system::error_code ec,
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001750 const GetSubTreeType& subtree) {
1751 BMCWEB_LOG_DEBUG << "getInventoryItemsConnections respHandler enter";
1752 if (ec)
1753 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001754 messages::internalError(sensorsAsyncResp->asyncResp->res);
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001755 BMCWEB_LOG_ERROR
1756 << "getInventoryItemsConnections respHandler DBus error " << ec;
1757 return;
1758 }
1759
1760 // Make unique list of connections for desired inventory items
1761 std::shared_ptr<boost::container::flat_set<std::string>>
1762 invConnections =
1763 std::make_shared<boost::container::flat_set<std::string>>();
1764 invConnections->reserve(8);
1765
1766 // Loop through objects from GetSubTree
1767 for (const std::pair<
1768 std::string,
1769 std::vector<std::pair<std::string, std::vector<std::string>>>>&
1770 object : subtree)
1771 {
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001772 // Check if object path is one of the specified inventory items
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001773 const std::string& objPath = object.first;
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001774 if (findInventoryItem(inventoryItems, objPath) != nullptr)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001775 {
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001776 // Store all connections to inventory item
1777 for (const std::pair<std::string, std::vector<std::string>>&
1778 objData : object.second)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001779 {
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001780 const std::string& invConnection = objData.first;
1781 invConnections->insert(invConnection);
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001782 }
1783 }
1784 }
Anthony Wilsond5005492019-07-31 16:34:17 -05001785
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001786 callback(invConnections);
1787 BMCWEB_LOG_DEBUG << "getInventoryItemsConnections respHandler exit";
1788 };
1789
1790 // Make call to ObjectMapper to find all inventory items
1791 crow::connections::systemBus->async_method_call(
1792 std::move(respHandler), "xyz.openbmc_project.ObjectMapper",
1793 "/xyz/openbmc_project/object_mapper",
1794 "xyz.openbmc_project.ObjectMapper", "GetSubTree", path, 0, interfaces);
1795 BMCWEB_LOG_DEBUG << "getInventoryItemsConnections exit";
1796}
1797
1798/**
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001799 * @brief Gets associations from sensors to inventory items.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001800 *
1801 * Looks for ObjectMapper associations from the specified sensors to related
Anthony Wilsond5005492019-07-31 16:34:17 -05001802 * inventory items. Then finds the associations from those inventory items to
1803 * their LEDs, if any.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001804 *
1805 * Finds the inventory items asynchronously. Invokes callback when information
1806 * has been obtained.
1807 *
1808 * The callback must have the following signature:
1809 * @code
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001810 * callback(std::shared_ptr<std::vector<InventoryItem>> inventoryItems)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001811 * @endcode
1812 *
1813 * @param sensorsAsyncResp Pointer to object holding response data.
1814 * @param sensorNames All sensors within the current chassis.
1815 * @param objectMgrPaths Mappings from connection name to DBus object path that
1816 * implements ObjectManager.
1817 * @param callback Callback to invoke when inventory items have been obtained.
1818 */
1819template <typename Callback>
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001820static void getInventoryItemAssociations(
Ed Tanousb5a76932020-09-29 16:16:58 -07001821 const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
1822 const std::shared_ptr<boost::container::flat_set<std::string>>& sensorNames,
1823 const std::shared_ptr<boost::container::flat_map<std::string, std::string>>&
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001824 objectMgrPaths,
1825 Callback&& callback)
1826{
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001827 BMCWEB_LOG_DEBUG << "getInventoryItemAssociations enter";
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001828
1829 // Response handler for GetManagedObjects
1830 auto respHandler = [callback{std::move(callback)}, sensorsAsyncResp,
1831 sensorNames](const boost::system::error_code ec,
1832 dbus::utility::ManagedObjectType& resp) {
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001833 BMCWEB_LOG_DEBUG << "getInventoryItemAssociations respHandler enter";
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001834 if (ec)
1835 {
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001836 BMCWEB_LOG_ERROR
1837 << "getInventoryItemAssociations respHandler DBus error " << ec;
zhanghch058d1b46d2021-04-01 11:18:24 +08001838 messages::internalError(sensorsAsyncResp->asyncResp->res);
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001839 return;
1840 }
1841
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001842 // Create vector to hold list of inventory items
1843 std::shared_ptr<std::vector<InventoryItem>> inventoryItems =
1844 std::make_shared<std::vector<InventoryItem>>();
1845
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001846 // Loop through returned object paths
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001847 std::string sensorAssocPath;
1848 sensorAssocPath.reserve(128); // avoid memory allocations
1849 for (const auto& objDictEntry : resp)
1850 {
1851 const std::string& objPath =
1852 static_cast<const std::string&>(objDictEntry.first);
1853 const boost::container::flat_map<
1854 std::string, boost::container::flat_map<
1855 std::string, dbus::utility::DbusVariantType>>&
1856 interfacesDict = objDictEntry.second;
1857
1858 // If path is inventory association for one of the specified sensors
1859 for (const std::string& sensorName : *sensorNames)
1860 {
1861 sensorAssocPath = sensorName;
1862 sensorAssocPath += "/inventory";
1863 if (objPath == sensorAssocPath)
1864 {
1865 // Get Association interface for object path
1866 auto assocIt =
1867 interfacesDict.find("xyz.openbmc_project.Association");
1868 if (assocIt != interfacesDict.end())
1869 {
1870 // Get inventory item from end point
1871 auto endpointsIt = assocIt->second.find("endpoints");
1872 if (endpointsIt != assocIt->second.end())
1873 {
1874 const std::vector<std::string>* endpoints =
1875 std::get_if<std::vector<std::string>>(
1876 &endpointsIt->second);
1877 if ((endpoints != nullptr) && !endpoints->empty())
1878 {
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001879 // Add inventory item to vector
1880 const std::string& invItemPath =
1881 endpoints->front();
1882 addInventoryItem(inventoryItems, invItemPath,
1883 sensorName);
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001884 }
1885 }
1886 }
1887 break;
1888 }
1889 }
1890 }
1891
Anthony Wilsond5005492019-07-31 16:34:17 -05001892 // Now loop through the returned object paths again, this time to
1893 // find the leds associated with the inventory items we just found
1894 std::string inventoryAssocPath;
1895 inventoryAssocPath.reserve(128); // avoid memory allocations
1896 for (const auto& objDictEntry : resp)
1897 {
1898 const std::string& objPath =
1899 static_cast<const std::string&>(objDictEntry.first);
1900 const boost::container::flat_map<
1901 std::string, boost::container::flat_map<
1902 std::string, dbus::utility::DbusVariantType>>&
1903 interfacesDict = objDictEntry.second;
1904
1905 for (InventoryItem& inventoryItem : *inventoryItems)
1906 {
1907 inventoryAssocPath = inventoryItem.objectPath;
1908 inventoryAssocPath += "/leds";
1909 if (objPath == inventoryAssocPath)
1910 {
1911 // Get Association interface for object path
1912 auto assocIt =
1913 interfacesDict.find("xyz.openbmc_project.Association");
1914 if (assocIt != interfacesDict.end())
1915 {
1916 // Get inventory item from end point
1917 auto endpointsIt = assocIt->second.find("endpoints");
1918 if (endpointsIt != assocIt->second.end())
1919 {
1920 const std::vector<std::string>* endpoints =
1921 std::get_if<std::vector<std::string>>(
1922 &endpointsIt->second);
1923 if ((endpoints != nullptr) && !endpoints->empty())
1924 {
1925 // Store LED path in inventory item
1926 const std::string& ledPath = endpoints->front();
1927 inventoryItem.ledObjectPath = ledPath;
1928 }
1929 }
1930 }
1931 break;
1932 }
1933 }
1934 }
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001935 callback(inventoryItems);
1936 BMCWEB_LOG_DEBUG << "getInventoryItemAssociations respHandler exit";
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001937 };
1938
1939 // Find DBus object path that implements ObjectManager for ObjectMapper
1940 std::string connection = "xyz.openbmc_project.ObjectMapper";
1941 auto iter = objectMgrPaths->find(connection);
1942 const std::string& objectMgrPath =
1943 (iter != objectMgrPaths->end()) ? iter->second : "/";
1944 BMCWEB_LOG_DEBUG << "ObjectManager path for " << connection << " is "
1945 << objectMgrPath;
1946
1947 // Call GetManagedObjects on the ObjectMapper to get all associations
1948 crow::connections::systemBus->async_method_call(
1949 std::move(respHandler), connection, objectMgrPath,
1950 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
1951
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001952 BMCWEB_LOG_DEBUG << "getInventoryItemAssociations exit";
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001953}
1954
1955/**
Anthony Wilsond5005492019-07-31 16:34:17 -05001956 * @brief Gets D-Bus data for inventory item leds associated with sensors.
1957 *
1958 * Uses the specified connections (services) to obtain D-Bus data for inventory
1959 * item leds associated with sensors. Stores the resulting data in the
1960 * inventoryItems vector.
1961 *
1962 * This data is later used to provide sensor property values in the JSON
1963 * response.
1964 *
1965 * Finds the inventory item led data asynchronously. Invokes callback when data
1966 * has been obtained.
1967 *
1968 * The callback must have the following signature:
1969 * @code
Gunnar Mills42cbe532019-08-15 15:26:54 -05001970 * callback()
Anthony Wilsond5005492019-07-31 16:34:17 -05001971 * @endcode
1972 *
1973 * This function is called recursively, obtaining data asynchronously from one
1974 * connection in each call. This ensures the callback is not invoked until the
1975 * last asynchronous function has completed.
1976 *
1977 * @param sensorsAsyncResp Pointer to object holding response data.
1978 * @param inventoryItems D-Bus inventory items associated with sensors.
1979 * @param ledConnections Connections that provide data for the inventory leds.
1980 * @param callback Callback to invoke when inventory data has been obtained.
1981 * @param ledConnectionsIndex Current index in ledConnections. Only specified
1982 * in recursive calls to this function.
1983 */
1984template <typename Callback>
1985void getInventoryLedData(
1986 std::shared_ptr<SensorsAsyncResp> sensorsAsyncResp,
1987 std::shared_ptr<std::vector<InventoryItem>> inventoryItems,
1988 std::shared_ptr<boost::container::flat_map<std::string, std::string>>
1989 ledConnections,
1990 Callback&& callback, size_t ledConnectionsIndex = 0)
1991{
1992 BMCWEB_LOG_DEBUG << "getInventoryLedData enter";
1993
1994 // If no more connections left, call callback
1995 if (ledConnectionsIndex >= ledConnections->size())
1996 {
Gunnar Mills42cbe532019-08-15 15:26:54 -05001997 callback();
Anthony Wilsond5005492019-07-31 16:34:17 -05001998 BMCWEB_LOG_DEBUG << "getInventoryLedData exit";
1999 return;
2000 }
2001
2002 // Get inventory item data from current connection
2003 auto it = ledConnections->nth(ledConnectionsIndex);
2004 if (it != ledConnections->end())
2005 {
2006 const std::string& ledPath = (*it).first;
2007 const std::string& ledConnection = (*it).second;
2008 // Response handler for Get State property
2009 auto respHandler =
2010 [sensorsAsyncResp, inventoryItems, ledConnections, ledPath,
2011 callback{std::move(callback)},
2012 ledConnectionsIndex](const boost::system::error_code ec,
2013 const std::variant<std::string>& ledState) {
2014 BMCWEB_LOG_DEBUG << "getInventoryLedData respHandler enter";
2015 if (ec)
2016 {
2017 BMCWEB_LOG_ERROR
2018 << "getInventoryLedData respHandler DBus error " << ec;
zhanghch058d1b46d2021-04-01 11:18:24 +08002019 messages::internalError(sensorsAsyncResp->asyncResp->res);
Anthony Wilsond5005492019-07-31 16:34:17 -05002020 return;
2021 }
2022
2023 const std::string* state = std::get_if<std::string>(&ledState);
2024 if (state != nullptr)
2025 {
2026 BMCWEB_LOG_DEBUG << "Led state: " << *state;
2027 // Find inventory item with this LED object path
2028 InventoryItem* inventoryItem =
2029 findInventoryItemForLed(*inventoryItems, ledPath);
2030 if (inventoryItem != nullptr)
2031 {
2032 // Store LED state in InventoryItem
2033 if (boost::ends_with(*state, "On"))
2034 {
2035 inventoryItem->ledState = LedState::ON;
2036 }
2037 else if (boost::ends_with(*state, "Blink"))
2038 {
2039 inventoryItem->ledState = LedState::BLINK;
2040 }
2041 else if (boost::ends_with(*state, "Off"))
2042 {
2043 inventoryItem->ledState = LedState::OFF;
2044 }
2045 else
2046 {
2047 inventoryItem->ledState = LedState::UNKNOWN;
2048 }
2049 }
2050 }
2051 else
2052 {
2053 BMCWEB_LOG_DEBUG << "Failed to find State data for LED: "
2054 << ledPath;
2055 }
2056
2057 // Recurse to get LED data from next connection
2058 getInventoryLedData(sensorsAsyncResp, inventoryItems,
2059 ledConnections, std::move(callback),
2060 ledConnectionsIndex + 1);
2061
2062 BMCWEB_LOG_DEBUG << "getInventoryLedData respHandler exit";
2063 };
2064
2065 // Get the State property for the current LED
2066 crow::connections::systemBus->async_method_call(
2067 std::move(respHandler), ledConnection, ledPath,
2068 "org.freedesktop.DBus.Properties", "Get",
2069 "xyz.openbmc_project.Led.Physical", "State");
2070 }
2071
2072 BMCWEB_LOG_DEBUG << "getInventoryLedData exit";
2073}
2074
2075/**
2076 * @brief Gets LED data for LEDs associated with given inventory items.
2077 *
2078 * Gets the D-Bus connections (services) that provide LED data for the LEDs
2079 * associated with the specified inventory items. Then gets the LED data from
2080 * each connection and stores it in the inventory item.
2081 *
2082 * This data is later used to provide sensor property values in the JSON
2083 * response.
2084 *
2085 * Finds the LED data asynchronously. Invokes callback when information has
2086 * been obtained.
2087 *
2088 * The callback must have the following signature:
2089 * @code
Gunnar Mills42cbe532019-08-15 15:26:54 -05002090 * callback()
Anthony Wilsond5005492019-07-31 16:34:17 -05002091 * @endcode
2092 *
2093 * @param sensorsAsyncResp Pointer to object holding response data.
2094 * @param inventoryItems D-Bus inventory items associated with sensors.
2095 * @param callback Callback to invoke when inventory items have been obtained.
2096 */
2097template <typename Callback>
2098void getInventoryLeds(
2099 std::shared_ptr<SensorsAsyncResp> sensorsAsyncResp,
2100 std::shared_ptr<std::vector<InventoryItem>> inventoryItems,
2101 Callback&& callback)
2102{
2103 BMCWEB_LOG_DEBUG << "getInventoryLeds enter";
2104
2105 const std::string path = "/xyz/openbmc_project";
2106 const std::array<std::string, 1> interfaces = {
2107 "xyz.openbmc_project.Led.Physical"};
2108
2109 // Response handler for parsing output from GetSubTree
2110 auto respHandler = [callback{std::move(callback)}, sensorsAsyncResp,
2111 inventoryItems](const boost::system::error_code ec,
2112 const GetSubTreeType& subtree) {
2113 BMCWEB_LOG_DEBUG << "getInventoryLeds respHandler enter";
2114 if (ec)
2115 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002116 messages::internalError(sensorsAsyncResp->asyncResp->res);
Anthony Wilsond5005492019-07-31 16:34:17 -05002117 BMCWEB_LOG_ERROR << "getInventoryLeds respHandler DBus error "
2118 << ec;
2119 return;
2120 }
2121
2122 // Build map of LED object paths to connections
2123 std::shared_ptr<boost::container::flat_map<std::string, std::string>>
2124 ledConnections = std::make_shared<
2125 boost::container::flat_map<std::string, std::string>>();
2126
2127 // Loop through objects from GetSubTree
2128 for (const std::pair<
2129 std::string,
2130 std::vector<std::pair<std::string, std::vector<std::string>>>>&
2131 object : subtree)
2132 {
2133 // Check if object path is LED for one of the specified inventory
2134 // items
2135 const std::string& ledPath = object.first;
2136 if (findInventoryItemForLed(*inventoryItems, ledPath) != nullptr)
2137 {
2138 // Add mapping from ledPath to connection
2139 const std::string& connection = object.second.begin()->first;
2140 (*ledConnections)[ledPath] = connection;
2141 BMCWEB_LOG_DEBUG << "Added mapping " << ledPath << " -> "
2142 << connection;
2143 }
2144 }
2145
2146 getInventoryLedData(sensorsAsyncResp, inventoryItems, ledConnections,
2147 std::move(callback));
2148 BMCWEB_LOG_DEBUG << "getInventoryLeds respHandler exit";
2149 };
2150 // Make call to ObjectMapper to find all inventory items
2151 crow::connections::systemBus->async_method_call(
2152 std::move(respHandler), "xyz.openbmc_project.ObjectMapper",
2153 "/xyz/openbmc_project/object_mapper",
2154 "xyz.openbmc_project.ObjectMapper", "GetSubTree", path, 0, interfaces);
2155 BMCWEB_LOG_DEBUG << "getInventoryLeds exit";
2156}
2157
2158/**
Gunnar Mills42cbe532019-08-15 15:26:54 -05002159 * @brief Gets D-Bus data for Power Supply Attributes such as EfficiencyPercent
2160 *
2161 * Uses the specified connections (services) (currently assumes just one) to
2162 * obtain D-Bus data for Power Supply Attributes. Stores the resulting data in
2163 * the inventoryItems vector. Only stores data in Power Supply inventoryItems.
2164 *
2165 * This data is later used to provide sensor property values in the JSON
2166 * response.
2167 *
2168 * Finds the Power Supply Attributes data asynchronously. Invokes callback
2169 * when data has been obtained.
2170 *
2171 * The callback must have the following signature:
2172 * @code
2173 * callback(std::shared_ptr<std::vector<InventoryItem>> inventoryItems)
2174 * @endcode
2175 *
2176 * @param sensorsAsyncResp Pointer to object holding response data.
2177 * @param inventoryItems D-Bus inventory items associated with sensors.
2178 * @param psAttributesConnections Connections that provide data for the Power
2179 * Supply Attributes
2180 * @param callback Callback to invoke when data has been obtained.
2181 */
2182template <typename Callback>
2183void getPowerSupplyAttributesData(
Ed Tanousb5a76932020-09-29 16:16:58 -07002184 const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
Gunnar Mills42cbe532019-08-15 15:26:54 -05002185 std::shared_ptr<std::vector<InventoryItem>> inventoryItems,
2186 const boost::container::flat_map<std::string, std::string>&
2187 psAttributesConnections,
2188 Callback&& callback)
2189{
2190 BMCWEB_LOG_DEBUG << "getPowerSupplyAttributesData enter";
2191
2192 if (psAttributesConnections.empty())
2193 {
2194 BMCWEB_LOG_DEBUG << "Can't find PowerSupplyAttributes, no connections!";
2195 callback(inventoryItems);
2196 return;
2197 }
2198
2199 // Assuming just one connection (service) for now
2200 auto it = psAttributesConnections.nth(0);
2201
2202 const std::string& psAttributesPath = (*it).first;
2203 const std::string& psAttributesConnection = (*it).second;
2204
2205 // Response handler for Get DeratingFactor property
2206 auto respHandler = [sensorsAsyncResp, inventoryItems,
2207 callback{std::move(callback)}](
2208 const boost::system::error_code ec,
2209 const std::variant<uint32_t>& deratingFactor) {
2210 BMCWEB_LOG_DEBUG << "getPowerSupplyAttributesData respHandler enter";
2211 if (ec)
2212 {
2213 BMCWEB_LOG_ERROR
2214 << "getPowerSupplyAttributesData respHandler DBus error " << ec;
zhanghch058d1b46d2021-04-01 11:18:24 +08002215 messages::internalError(sensorsAsyncResp->asyncResp->res);
Gunnar Mills42cbe532019-08-15 15:26:54 -05002216 return;
2217 }
2218
2219 const uint32_t* value = std::get_if<uint32_t>(&deratingFactor);
2220 if (value != nullptr)
2221 {
2222 BMCWEB_LOG_DEBUG << "PS EfficiencyPercent value: " << *value;
2223 // Store value in Power Supply Inventory Items
2224 for (InventoryItem& inventoryItem : *inventoryItems)
2225 {
2226 if (inventoryItem.isPowerSupply == true)
2227 {
2228 inventoryItem.powerSupplyEfficiencyPercent =
2229 static_cast<int>(*value);
2230 }
2231 }
2232 }
2233 else
2234 {
2235 BMCWEB_LOG_DEBUG
2236 << "Failed to find EfficiencyPercent value for PowerSupplies";
2237 }
2238
2239 BMCWEB_LOG_DEBUG << "getPowerSupplyAttributesData respHandler exit";
2240 callback(inventoryItems);
2241 };
2242
2243 // Get the DeratingFactor property for the PowerSupplyAttributes
2244 // Currently only property on the interface/only one we care about
2245 crow::connections::systemBus->async_method_call(
2246 std::move(respHandler), psAttributesConnection, psAttributesPath,
2247 "org.freedesktop.DBus.Properties", "Get",
2248 "xyz.openbmc_project.Control.PowerSupplyAttributes", "DeratingFactor");
2249
2250 BMCWEB_LOG_DEBUG << "getPowerSupplyAttributesData exit";
2251}
2252
2253/**
2254 * @brief Gets the Power Supply Attributes such as EfficiencyPercent
2255 *
2256 * Gets the D-Bus connection (service) that provides Power Supply Attributes
2257 * data. Then gets the Power Supply Attributes data from the connection
2258 * (currently just assumes 1 connection) and stores the data in the inventory
2259 * item.
2260 *
2261 * This data is later used to provide sensor property values in the JSON
2262 * response. DeratingFactor on D-Bus is mapped to EfficiencyPercent on Redfish.
2263 *
2264 * Finds the Power Supply Attributes data asynchronously. Invokes callback
2265 * when information has been obtained.
2266 *
2267 * The callback must have the following signature:
2268 * @code
2269 * callback(std::shared_ptr<std::vector<InventoryItem>> inventoryItems)
2270 * @endcode
2271 *
2272 * @param sensorsAsyncResp Pointer to object holding response data.
2273 * @param inventoryItems D-Bus inventory items associated with sensors.
2274 * @param callback Callback to invoke when data has been obtained.
2275 */
2276template <typename Callback>
2277void getPowerSupplyAttributes(
2278 std::shared_ptr<SensorsAsyncResp> sensorsAsyncResp,
2279 std::shared_ptr<std::vector<InventoryItem>> inventoryItems,
2280 Callback&& callback)
2281{
2282 BMCWEB_LOG_DEBUG << "getPowerSupplyAttributes enter";
2283
2284 // Only need the power supply attributes when the Power Schema
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +02002285 if (sensorsAsyncResp->chassisSubNode != sensors::node::power)
Gunnar Mills42cbe532019-08-15 15:26:54 -05002286 {
2287 BMCWEB_LOG_DEBUG << "getPowerSupplyAttributes exit since not Power";
2288 callback(inventoryItems);
2289 return;
2290 }
2291
2292 const std::array<std::string, 1> interfaces = {
2293 "xyz.openbmc_project.Control.PowerSupplyAttributes"};
2294
2295 // Response handler for parsing output from GetSubTree
2296 auto respHandler = [callback{std::move(callback)}, sensorsAsyncResp,
2297 inventoryItems](const boost::system::error_code ec,
2298 const GetSubTreeType& subtree) {
2299 BMCWEB_LOG_DEBUG << "getPowerSupplyAttributes respHandler enter";
2300 if (ec)
2301 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002302 messages::internalError(sensorsAsyncResp->asyncResp->res);
Gunnar Mills42cbe532019-08-15 15:26:54 -05002303 BMCWEB_LOG_ERROR
2304 << "getPowerSupplyAttributes respHandler DBus error " << ec;
2305 return;
2306 }
2307 if (subtree.size() == 0)
2308 {
2309 BMCWEB_LOG_DEBUG << "Can't find Power Supply Attributes!";
2310 callback(inventoryItems);
2311 return;
2312 }
2313
2314 // Currently we only support 1 power supply attribute, use this for
2315 // all the power supplies. Build map of object path to connection.
2316 // Assume just 1 connection and 1 path for now.
2317 boost::container::flat_map<std::string, std::string>
2318 psAttributesConnections;
2319
2320 if (subtree[0].first.empty() || subtree[0].second.empty())
2321 {
2322 BMCWEB_LOG_DEBUG << "Power Supply Attributes mapper error!";
2323 callback(inventoryItems);
2324 return;
2325 }
2326
2327 const std::string& psAttributesPath = subtree[0].first;
2328 const std::string& connection = subtree[0].second.begin()->first;
2329
2330 if (connection.empty())
2331 {
2332 BMCWEB_LOG_DEBUG << "Power Supply Attributes mapper error!";
2333 callback(inventoryItems);
2334 return;
2335 }
2336
2337 psAttributesConnections[psAttributesPath] = connection;
2338 BMCWEB_LOG_DEBUG << "Added mapping " << psAttributesPath << " -> "
2339 << connection;
2340
2341 getPowerSupplyAttributesData(sensorsAsyncResp, inventoryItems,
2342 psAttributesConnections,
2343 std::move(callback));
2344 BMCWEB_LOG_DEBUG << "getPowerSupplyAttributes respHandler exit";
2345 };
2346 // Make call to ObjectMapper to find the PowerSupplyAttributes service
2347 crow::connections::systemBus->async_method_call(
2348 std::move(respHandler), "xyz.openbmc_project.ObjectMapper",
2349 "/xyz/openbmc_project/object_mapper",
2350 "xyz.openbmc_project.ObjectMapper", "GetSubTree",
2351 "/xyz/openbmc_project", 0, interfaces);
2352 BMCWEB_LOG_DEBUG << "getPowerSupplyAttributes exit";
2353}
2354
2355/**
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05002356 * @brief Gets inventory items associated with sensors.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05002357 *
2358 * Finds the inventory items that are associated with the specified sensors.
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05002359 * Then gets D-Bus data for the inventory items, such as presence and VPD.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05002360 *
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05002361 * This data is later used to provide sensor property values in the JSON
2362 * response.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05002363 *
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05002364 * Finds the inventory items asynchronously. Invokes callback when the
2365 * inventory items have been obtained.
2366 *
2367 * The callback must have the following signature:
2368 * @code
2369 * callback(std::shared_ptr<std::vector<InventoryItem>> inventoryItems)
2370 * @endcode
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05002371 *
2372 * @param sensorsAsyncResp Pointer to object holding response data.
2373 * @param sensorNames All sensors within the current chassis.
2374 * @param objectMgrPaths Mappings from connection name to DBus object path that
2375 * implements ObjectManager.
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05002376 * @param callback Callback to invoke when inventory items have been obtained.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05002377 */
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05002378template <typename Callback>
2379static void getInventoryItems(
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05002380 std::shared_ptr<SensorsAsyncResp> sensorsAsyncResp,
2381 const std::shared_ptr<boost::container::flat_set<std::string>> sensorNames,
2382 std::shared_ptr<boost::container::flat_map<std::string, std::string>>
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05002383 objectMgrPaths,
2384 Callback&& callback)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05002385{
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05002386 BMCWEB_LOG_DEBUG << "getInventoryItems enter";
2387 auto getInventoryItemAssociationsCb =
2388 [sensorsAsyncResp, objectMgrPaths, callback{std::move(callback)}](
2389 std::shared_ptr<std::vector<InventoryItem>> inventoryItems) {
2390 BMCWEB_LOG_DEBUG << "getInventoryItemAssociationsCb enter";
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05002391 auto getInventoryItemsConnectionsCb =
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05002392 [sensorsAsyncResp, inventoryItems, objectMgrPaths,
2393 callback{std::move(callback)}](
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05002394 std::shared_ptr<boost::container::flat_set<std::string>>
2395 invConnections) {
2396 BMCWEB_LOG_DEBUG << "getInventoryItemsConnectionsCb enter";
Anthony Wilsond5005492019-07-31 16:34:17 -05002397 auto getInventoryItemsDataCb =
2398 [sensorsAsyncResp, inventoryItems,
2399 callback{std::move(callback)}]() {
2400 BMCWEB_LOG_DEBUG << "getInventoryItemsDataCb enter";
Gunnar Mills42cbe532019-08-15 15:26:54 -05002401
2402 auto getInventoryLedsCb = [sensorsAsyncResp,
2403 inventoryItems,
2404 callback{std::move(
2405 callback)}]() {
2406 BMCWEB_LOG_DEBUG << "getInventoryLedsCb enter";
2407 // Find Power Supply Attributes and get the data
2408 getPowerSupplyAttributes(sensorsAsyncResp,
2409 inventoryItems,
2410 std::move(callback));
2411 BMCWEB_LOG_DEBUG << "getInventoryLedsCb exit";
2412 };
2413
Anthony Wilsond5005492019-07-31 16:34:17 -05002414 // Find led connections and get the data
2415 getInventoryLeds(sensorsAsyncResp, inventoryItems,
Gunnar Mills42cbe532019-08-15 15:26:54 -05002416 std::move(getInventoryLedsCb));
Anthony Wilsond5005492019-07-31 16:34:17 -05002417 BMCWEB_LOG_DEBUG << "getInventoryItemsDataCb exit";
2418 };
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05002419
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05002420 // Get inventory item data from connections
2421 getInventoryItemsData(sensorsAsyncResp, inventoryItems,
2422 invConnections, objectMgrPaths,
Anthony Wilsond5005492019-07-31 16:34:17 -05002423 std::move(getInventoryItemsDataCb));
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05002424 BMCWEB_LOG_DEBUG << "getInventoryItemsConnectionsCb exit";
2425 };
2426
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05002427 // Get connections that provide inventory item data
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05002428 getInventoryItemsConnections(
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05002429 sensorsAsyncResp, inventoryItems,
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05002430 std::move(getInventoryItemsConnectionsCb));
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05002431 BMCWEB_LOG_DEBUG << "getInventoryItemAssociationsCb exit";
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05002432 };
2433
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05002434 // Get associations from sensors to inventory items
2435 getInventoryItemAssociations(sensorsAsyncResp, sensorNames, objectMgrPaths,
2436 std::move(getInventoryItemAssociationsCb));
2437 BMCWEB_LOG_DEBUG << "getInventoryItems exit";
2438}
2439
2440/**
2441 * @brief Returns JSON PowerSupply object for the specified inventory item.
2442 *
2443 * Searches for a JSON PowerSupply object that matches the specified inventory
2444 * item. If one is not found, a new PowerSupply object is added to the JSON
2445 * array.
2446 *
2447 * Multiple sensors are often associated with one power supply inventory item.
2448 * As a result, multiple sensor values are stored in one JSON PowerSupply
2449 * object.
2450 *
2451 * @param powerSupplyArray JSON array containing Redfish PowerSupply objects.
2452 * @param inventoryItem Inventory item for the power supply.
2453 * @param chassisId Chassis that contains the power supply.
2454 * @return JSON PowerSupply object for the specified inventory item.
2455 */
Ed Tanous23a21a12020-07-25 04:45:05 +00002456inline nlohmann::json& getPowerSupply(nlohmann::json& powerSupplyArray,
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05002457 const InventoryItem& inventoryItem,
2458 const std::string& chassisId)
2459{
2460 // Check if matching PowerSupply object already exists in JSON array
2461 for (nlohmann::json& powerSupply : powerSupplyArray)
2462 {
2463 if (powerSupply["MemberId"] == inventoryItem.name)
2464 {
2465 return powerSupply;
2466 }
2467 }
2468
2469 // Add new PowerSupply object to JSON array
2470 powerSupplyArray.push_back({});
2471 nlohmann::json& powerSupply = powerSupplyArray.back();
2472 powerSupply["@odata.id"] =
2473 "/redfish/v1/Chassis/" + chassisId + "/Power#/PowerSupplies/";
2474 powerSupply["MemberId"] = inventoryItem.name;
2475 powerSupply["Name"] = boost::replace_all_copy(inventoryItem.name, "_", " ");
2476 powerSupply["Manufacturer"] = inventoryItem.manufacturer;
2477 powerSupply["Model"] = inventoryItem.model;
2478 powerSupply["PartNumber"] = inventoryItem.partNumber;
2479 powerSupply["SerialNumber"] = inventoryItem.serialNumber;
Anthony Wilsond5005492019-07-31 16:34:17 -05002480 setLedState(powerSupply, &inventoryItem);
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05002481
Gunnar Mills42cbe532019-08-15 15:26:54 -05002482 if (inventoryItem.powerSupplyEfficiencyPercent >= 0)
2483 {
2484 powerSupply["EfficiencyPercent"] =
2485 inventoryItem.powerSupplyEfficiencyPercent;
2486 }
2487
2488 powerSupply["Status"]["State"] = getState(&inventoryItem);
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05002489 const char* health = inventoryItem.isFunctional ? "OK" : "Critical";
2490 powerSupply["Status"]["Health"] = health;
2491
2492 return powerSupply;
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05002493}
2494
2495/**
Shawn McCarneyde629b62019-03-08 10:42:51 -06002496 * @brief Gets the values of the specified sensors.
2497 *
2498 * Stores the results as JSON in the SensorsAsyncResp.
2499 *
2500 * Gets the sensor values asynchronously. Stores the results later when the
2501 * information has been obtained.
2502 *
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05002503 * The sensorNames set contains all requested sensors for the current chassis.
Shawn McCarneyde629b62019-03-08 10:42:51 -06002504 *
2505 * To minimize the number of DBus calls, the DBus method
2506 * org.freedesktop.DBus.ObjectManager.GetManagedObjects() is used to get the
2507 * values of all sensors provided by a connection (service).
2508 *
2509 * The connections set contains all the connections that provide sensor values.
2510 *
2511 * The objectMgrPaths map contains mappings from a connection name to the
2512 * corresponding DBus object path that implements ObjectManager.
2513 *
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05002514 * The InventoryItem vector contains D-Bus inventory items associated with the
2515 * sensors. Inventory item data is needed for some Redfish sensor properties.
2516 *
Shawn McCarneyde629b62019-03-08 10:42:51 -06002517 * @param SensorsAsyncResp Pointer to object holding response data.
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05002518 * @param sensorNames All requested sensors within the current chassis.
Shawn McCarneyde629b62019-03-08 10:42:51 -06002519 * @param connections Connections that provide sensor values.
2520 * @param objectMgrPaths Mappings from connection name to DBus object path that
2521 * implements ObjectManager.
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05002522 * @param inventoryItems Inventory items associated with the sensors.
Shawn McCarneyde629b62019-03-08 10:42:51 -06002523 */
Ed Tanous23a21a12020-07-25 04:45:05 +00002524inline void getSensorData(
Ed Tanous81ce6092020-12-17 16:54:55 +00002525 const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
Ed Tanousb5a76932020-09-29 16:16:58 -07002526 const std::shared_ptr<boost::container::flat_set<std::string>>& sensorNames,
Shawn McCarneyde629b62019-03-08 10:42:51 -06002527 const boost::container::flat_set<std::string>& connections,
Ed Tanousb5a76932020-09-29 16:16:58 -07002528 const std::shared_ptr<boost::container::flat_map<std::string, std::string>>&
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05002529 objectMgrPaths,
Ed Tanousb5a76932020-09-29 16:16:58 -07002530 const std::shared_ptr<std::vector<InventoryItem>>& inventoryItems)
Shawn McCarneyde629b62019-03-08 10:42:51 -06002531{
2532 BMCWEB_LOG_DEBUG << "getSensorData enter";
2533 // Get managed objects from all services exposing sensors
2534 for (const std::string& connection : connections)
2535 {
2536 // Response handler to process managed objects
Ed Tanous81ce6092020-12-17 16:54:55 +00002537 auto getManagedObjectsCb = [sensorsAsyncResp, sensorNames,
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05002538 inventoryItems](
Shawn McCarneyde629b62019-03-08 10:42:51 -06002539 const boost::system::error_code ec,
2540 ManagedObjectsVectorType& resp) {
2541 BMCWEB_LOG_DEBUG << "getManagedObjectsCb enter";
2542 if (ec)
2543 {
2544 BMCWEB_LOG_ERROR << "getManagedObjectsCb DBUS error: " << ec;
zhanghch058d1b46d2021-04-01 11:18:24 +08002545 messages::internalError(sensorsAsyncResp->asyncResp->res);
Shawn McCarneyde629b62019-03-08 10:42:51 -06002546 return;
2547 }
2548 // Go through all objects and update response with sensor data
2549 for (const auto& objDictEntry : resp)
2550 {
2551 const std::string& objPath =
2552 static_cast<const std::string&>(objDictEntry.first);
2553 BMCWEB_LOG_DEBUG << "getManagedObjectsCb parsing object "
2554 << objPath;
2555
Shawn McCarneyde629b62019-03-08 10:42:51 -06002556 std::vector<std::string> split;
2557 // Reserve space for
2558 // /xyz/openbmc_project/sensors/<name>/<subname>
2559 split.reserve(6);
2560 boost::algorithm::split(split, objPath, boost::is_any_of("/"));
2561 if (split.size() < 6)
2562 {
2563 BMCWEB_LOG_ERROR << "Got path that isn't long enough "
2564 << objPath;
2565 continue;
2566 }
2567 // These indexes aren't intuitive, as boost::split puts an empty
2568 // string at the beginning
2569 const std::string& sensorType = split[4];
2570 const std::string& sensorName = split[5];
2571 BMCWEB_LOG_DEBUG << "sensorName " << sensorName
2572 << " sensorType " << sensorType;
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07002573 if (sensorNames->find(objPath) == sensorNames->end())
Shawn McCarneyde629b62019-03-08 10:42:51 -06002574 {
2575 BMCWEB_LOG_ERROR << sensorName << " not in sensor list ";
2576 continue;
2577 }
2578
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05002579 // Find inventory item (if any) associated with sensor
2580 InventoryItem* inventoryItem =
2581 findInventoryItemForSensor(inventoryItems, objPath);
2582
Anthony Wilson95a3eca2019-06-11 10:44:47 -05002583 const std::string& sensorSchema =
Ed Tanous81ce6092020-12-17 16:54:55 +00002584 sensorsAsyncResp->chassisSubNode;
Anthony Wilson95a3eca2019-06-11 10:44:47 -05002585
2586 nlohmann::json* sensorJson = nullptr;
2587
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +02002588 if (sensorSchema == sensors::node::sensors)
Shawn McCarneyde629b62019-03-08 10:42:51 -06002589 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002590 sensorsAsyncResp->asyncResp->res.jsonValue["@odata.id"] =
Ed Tanous81ce6092020-12-17 16:54:55 +00002591 "/redfish/v1/Chassis/" + sensorsAsyncResp->chassisId +
2592 "/" + sensorsAsyncResp->chassisSubNode + "/" +
Anthony Wilson95a3eca2019-06-11 10:44:47 -05002593 sensorName;
zhanghch058d1b46d2021-04-01 11:18:24 +08002594 sensorJson = &(sensorsAsyncResp->asyncResp->res.jsonValue);
Shawn McCarneyde629b62019-03-08 10:42:51 -06002595 }
2596 else
2597 {
Ed Tanous271584a2019-07-09 16:24:22 -07002598 std::string fieldName;
Anthony Wilson95a3eca2019-06-11 10:44:47 -05002599 if (sensorType == "temperature")
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05002600 {
Anthony Wilson95a3eca2019-06-11 10:44:47 -05002601 fieldName = "Temperatures";
2602 }
2603 else if (sensorType == "fan" || sensorType == "fan_tach" ||
2604 sensorType == "fan_pwm")
2605 {
2606 fieldName = "Fans";
2607 }
2608 else if (sensorType == "voltage")
2609 {
2610 fieldName = "Voltages";
2611 }
2612 else if (sensorType == "power")
2613 {
2614 if (!sensorName.compare("total_power"))
2615 {
2616 fieldName = "PowerControl";
2617 }
2618 else if ((inventoryItem != nullptr) &&
2619 (inventoryItem->isPowerSupply))
2620 {
2621 fieldName = "PowerSupplies";
2622 }
2623 else
2624 {
2625 // Other power sensors are in SensorCollection
2626 continue;
2627 }
2628 }
2629 else
2630 {
2631 BMCWEB_LOG_ERROR << "Unsure how to handle sensorType "
2632 << sensorType;
2633 continue;
2634 }
2635
2636 nlohmann::json& tempArray =
zhanghch058d1b46d2021-04-01 11:18:24 +08002637 sensorsAsyncResp->asyncResp->res.jsonValue[fieldName];
Anthony Wilson95a3eca2019-06-11 10:44:47 -05002638 if (fieldName == "PowerControl")
2639 {
2640 if (tempArray.empty())
2641 {
2642 // Put multiple "sensors" into a single
2643 // PowerControl. Follows MemberId naming and
2644 // naming in power.hpp.
2645 tempArray.push_back(
2646 {{"@odata.id",
2647 "/redfish/v1/Chassis/" +
Ed Tanous81ce6092020-12-17 16:54:55 +00002648 sensorsAsyncResp->chassisId + "/" +
2649 sensorsAsyncResp->chassisSubNode + "#/" +
Anthony Wilson95a3eca2019-06-11 10:44:47 -05002650 fieldName + "/0"}});
2651 }
2652 sensorJson = &(tempArray.back());
2653 }
2654 else if (fieldName == "PowerSupplies")
2655 {
2656 if (inventoryItem != nullptr)
2657 {
2658 sensorJson =
2659 &(getPowerSupply(tempArray, *inventoryItem,
Ed Tanous81ce6092020-12-17 16:54:55 +00002660 sensorsAsyncResp->chassisId));
Anthony Wilson95a3eca2019-06-11 10:44:47 -05002661 }
2662 }
2663 else
2664 {
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05002665 tempArray.push_back(
2666 {{"@odata.id",
2667 "/redfish/v1/Chassis/" +
Ed Tanous81ce6092020-12-17 16:54:55 +00002668 sensorsAsyncResp->chassisId + "/" +
2669 sensorsAsyncResp->chassisSubNode + "#/" +
Anthony Wilson95a3eca2019-06-11 10:44:47 -05002670 fieldName + "/"}});
2671 sensorJson = &(tempArray.back());
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05002672 }
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07002673 }
Shawn McCarneyde629b62019-03-08 10:42:51 -06002674
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05002675 if (sensorJson != nullptr)
2676 {
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +02002677 objectInterfacesToJson(
Ed Tanous81ce6092020-12-17 16:54:55 +00002678 sensorName, sensorType, sensorsAsyncResp,
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +02002679 objDictEntry.second, *sensorJson, inventoryItem);
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05002680 }
Shawn McCarneyde629b62019-03-08 10:42:51 -06002681 }
Ed Tanous81ce6092020-12-17 16:54:55 +00002682 if (sensorsAsyncResp.use_count() == 1)
James Feist8bd25cc2019-03-15 15:14:00 -07002683 {
Ed Tanous81ce6092020-12-17 16:54:55 +00002684 sortJSONResponse(sensorsAsyncResp);
2685 if (sensorsAsyncResp->chassisSubNode == sensors::node::thermal)
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07002686 {
Ed Tanous81ce6092020-12-17 16:54:55 +00002687 populateFanRedundancy(sensorsAsyncResp);
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07002688 }
James Feist8bd25cc2019-03-15 15:14:00 -07002689 }
Shawn McCarneyde629b62019-03-08 10:42:51 -06002690 BMCWEB_LOG_DEBUG << "getManagedObjectsCb exit";
2691 };
2692
2693 // Find DBus object path that implements ObjectManager for the current
2694 // connection. If no mapping found, default to "/".
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05002695 auto iter = objectMgrPaths->find(connection);
Shawn McCarneyde629b62019-03-08 10:42:51 -06002696 const std::string& objectMgrPath =
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05002697 (iter != objectMgrPaths->end()) ? iter->second : "/";
Shawn McCarneyde629b62019-03-08 10:42:51 -06002698 BMCWEB_LOG_DEBUG << "ObjectManager path for " << connection << " is "
2699 << objectMgrPath;
2700
2701 crow::connections::systemBus->async_method_call(
2702 getManagedObjectsCb, connection, objectMgrPath,
2703 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
Ed Tanous23a21a12020-07-25 04:45:05 +00002704 }
Shawn McCarneyde629b62019-03-08 10:42:51 -06002705 BMCWEB_LOG_DEBUG << "getSensorData exit";
2706}
2707
Ed Tanous23a21a12020-07-25 04:45:05 +00002708inline void processSensorList(
Ed Tanous81ce6092020-12-17 16:54:55 +00002709 const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
Ed Tanousb5a76932020-09-29 16:16:58 -07002710 const std::shared_ptr<boost::container::flat_set<std::string>>& sensorNames)
Anthony Wilson95a3eca2019-06-11 10:44:47 -05002711{
2712 auto getConnectionCb =
Ed Tanous81ce6092020-12-17 16:54:55 +00002713 [sensorsAsyncResp, sensorNames](
Anthony Wilson95a3eca2019-06-11 10:44:47 -05002714 const boost::container::flat_set<std::string>& connections) {
2715 BMCWEB_LOG_DEBUG << "getConnectionCb enter";
2716 auto getObjectManagerPathsCb =
Ed Tanous81ce6092020-12-17 16:54:55 +00002717 [sensorsAsyncResp, sensorNames,
Ed Tanousb5a76932020-09-29 16:16:58 -07002718 connections](const std::shared_ptr<boost::container::flat_map<
2719 std::string, std::string>>& objectMgrPaths) {
Anthony Wilson95a3eca2019-06-11 10:44:47 -05002720 BMCWEB_LOG_DEBUG << "getObjectManagerPathsCb enter";
2721 auto getInventoryItemsCb =
Ed Tanous81ce6092020-12-17 16:54:55 +00002722 [sensorsAsyncResp, sensorNames, connections,
Anthony Wilson95a3eca2019-06-11 10:44:47 -05002723 objectMgrPaths](
Ed Tanousf23b7292020-10-15 09:41:17 -07002724 const std::shared_ptr<std::vector<InventoryItem>>&
Anthony Wilson95a3eca2019-06-11 10:44:47 -05002725 inventoryItems) {
2726 BMCWEB_LOG_DEBUG << "getInventoryItemsCb enter";
2727 // Get sensor data and store results in JSON
Ed Tanous81ce6092020-12-17 16:54:55 +00002728 getSensorData(sensorsAsyncResp, sensorNames,
Anthony Wilson95a3eca2019-06-11 10:44:47 -05002729 connections, objectMgrPaths,
Ed Tanousf23b7292020-10-15 09:41:17 -07002730 inventoryItems);
Anthony Wilson95a3eca2019-06-11 10:44:47 -05002731 BMCWEB_LOG_DEBUG << "getInventoryItemsCb exit";
2732 };
2733
2734 // Get inventory items associated with sensors
Ed Tanous81ce6092020-12-17 16:54:55 +00002735 getInventoryItems(sensorsAsyncResp, sensorNames,
Anthony Wilson95a3eca2019-06-11 10:44:47 -05002736 objectMgrPaths,
2737 std::move(getInventoryItemsCb));
2738
2739 BMCWEB_LOG_DEBUG << "getObjectManagerPathsCb exit";
2740 };
2741
2742 // Get mapping from connection names to the DBus object
2743 // paths that implement the ObjectManager interface
Ed Tanous81ce6092020-12-17 16:54:55 +00002744 getObjectManagerPaths(sensorsAsyncResp,
Anthony Wilson95a3eca2019-06-11 10:44:47 -05002745 std::move(getObjectManagerPathsCb));
2746 BMCWEB_LOG_DEBUG << "getConnectionCb exit";
2747 };
2748
2749 // Get set of connections that provide sensor values
Ed Tanous81ce6092020-12-17 16:54:55 +00002750 getConnections(sensorsAsyncResp, sensorNames, std::move(getConnectionCb));
Anthony Wilson95a3eca2019-06-11 10:44:47 -05002751}
2752
Shawn McCarneyde629b62019-03-08 10:42:51 -06002753/**
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +01002754 * @brief Entry point for retrieving sensors data related to requested
2755 * chassis.
Kowalski, Kamil588c3f02018-04-03 14:55:27 +02002756 * @param SensorsAsyncResp Pointer to object holding response data
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +01002757 */
Ed Tanousb5a76932020-09-29 16:16:58 -07002758inline void
Ed Tanous81ce6092020-12-17 16:54:55 +00002759 getChassisData(const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp)
Ed Tanous1abe55e2018-09-05 08:30:59 -07002760{
2761 BMCWEB_LOG_DEBUG << "getChassisData enter";
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07002762 auto getChassisCb =
Ed Tanous81ce6092020-12-17 16:54:55 +00002763 [sensorsAsyncResp](
Ed Tanousf23b7292020-10-15 09:41:17 -07002764 const std::shared_ptr<boost::container::flat_set<std::string>>&
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07002765 sensorNames) {
2766 BMCWEB_LOG_DEBUG << "getChassisCb enter";
Ed Tanous81ce6092020-12-17 16:54:55 +00002767 processSensorList(sensorsAsyncResp, sensorNames);
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07002768 BMCWEB_LOG_DEBUG << "getChassisCb exit";
2769 };
zhanghch058d1b46d2021-04-01 11:18:24 +08002770 sensorsAsyncResp->asyncResp->res.jsonValue["Redundancy"] =
2771 nlohmann::json::array();
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +01002772
Shawn McCarney26f03892019-05-03 13:20:24 -05002773 // Get set of sensors in chassis
Ed Tanous81ce6092020-12-17 16:54:55 +00002774 getChassis(sensorsAsyncResp, std::move(getChassisCb));
Ed Tanous1abe55e2018-09-05 08:30:59 -07002775 BMCWEB_LOG_DEBUG << "getChassisData exit";
Ed Tanous271584a2019-07-09 16:24:22 -07002776}
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +01002777
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302778/**
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07002779 * @brief Find the requested sensorName in the list of all sensors supplied by
2780 * the chassis node
2781 *
2782 * @param sensorName The sensor name supplied in the PATCH request
2783 * @param sensorsList The list of sensors managed by the chassis node
2784 * @param sensorsModified The list of sensors that were found as a result of
2785 * repeated calls to this function
2786 */
Ed Tanous23a21a12020-07-25 04:45:05 +00002787inline bool findSensorNameUsingSensorPath(
Richard Marian Thomaiyar0a86feb2019-05-27 23:16:40 +05302788 std::string_view sensorName,
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07002789 boost::container::flat_set<std::string>& sensorsList,
2790 boost::container::flat_set<std::string>& sensorsModified)
2791{
George Liu28aa8de2021-02-01 15:13:30 +08002792 for (auto& chassisSensor : sensorsList)
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07002793 {
George Liu28aa8de2021-02-01 15:13:30 +08002794 sdbusplus::message::object_path path(chassisSensor);
Ed Tanousb00dcc22021-02-23 12:52:50 -08002795 std::string thisSensorName = path.filename();
George Liu28aa8de2021-02-01 15:13:30 +08002796 if (thisSensorName.empty())
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07002797 {
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07002798 continue;
2799 }
2800 if (thisSensorName == sensorName)
2801 {
2802 sensorsModified.emplace(chassisSensor);
2803 return true;
2804 }
2805 }
2806 return false;
2807}
2808
2809/**
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302810 * @brief Entry point for overriding sensor values of given sensor
2811 *
zhanghch058d1b46d2021-04-01 11:18:24 +08002812 * @param sensorAsyncResp response object
Carol Wang4bb3dc32019-10-17 18:15:02 +08002813 * @param allCollections Collections extract from sensors' request patch info
jayaprakash Mutyala91e130a2020-03-04 22:26:38 +00002814 * @param chassisSubNode Chassis Node for which the query has to happen
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302815 */
Ed Tanous23a21a12020-07-25 04:45:05 +00002816inline void setSensorsOverride(
Ed Tanousb5a76932020-09-29 16:16:58 -07002817 const std::shared_ptr<SensorsAsyncResp>& sensorAsyncResp,
Carol Wang4bb3dc32019-10-17 18:15:02 +08002818 std::unordered_map<std::string, std::vector<nlohmann::json>>&
jayaprakash Mutyala397fd612020-02-06 23:33:34 +00002819 allCollections)
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302820{
jayaprakash Mutyala70d1d0a2020-01-21 23:41:36 +00002821 BMCWEB_LOG_INFO << "setSensorsOverride for subNode"
Carol Wang4bb3dc32019-10-17 18:15:02 +08002822 << sensorAsyncResp->chassisSubNode << "\n";
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302823
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302824 const char* propertyValueName;
2825 std::unordered_map<std::string, std::pair<double, std::string>> overrideMap;
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302826 std::string memberId;
2827 double value;
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302828 for (auto& collectionItems : allCollections)
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302829 {
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302830 if (collectionItems.first == "Temperatures")
2831 {
2832 propertyValueName = "ReadingCelsius";
2833 }
2834 else if (collectionItems.first == "Fans")
2835 {
2836 propertyValueName = "Reading";
2837 }
2838 else
2839 {
2840 propertyValueName = "ReadingVolts";
2841 }
2842 for (auto& item : collectionItems.second)
2843 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002844 if (!json_util::readJson(item, sensorAsyncResp->asyncResp->res,
2845 "MemberId", memberId, propertyValueName,
2846 value))
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302847 {
2848 return;
2849 }
2850 overrideMap.emplace(memberId,
2851 std::make_pair(value, collectionItems.first));
2852 }
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302853 }
Carol Wang4bb3dc32019-10-17 18:15:02 +08002854
Ed Tanousb5a76932020-09-29 16:16:58 -07002855 auto getChassisSensorListCb = [sensorAsyncResp, overrideMap](
2856 const std::shared_ptr<
2857 boost::container::flat_set<
2858 std::string>>& sensorsList) {
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07002859 // Match sensor names in the PATCH request to those managed by the
2860 // chassis node
2861 const std::shared_ptr<boost::container::flat_set<std::string>>
2862 sensorNames =
2863 std::make_shared<boost::container::flat_set<std::string>>();
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302864 for (const auto& item : overrideMap)
2865 {
2866 const auto& sensor = item.first;
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07002867 if (!findSensorNameUsingSensorPath(sensor, *sensorsList,
2868 *sensorNames))
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302869 {
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302870 BMCWEB_LOG_INFO << "Unable to find memberId " << item.first;
zhanghch058d1b46d2021-04-01 11:18:24 +08002871 messages::resourceNotFound(sensorAsyncResp->asyncResp->res,
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302872 item.second.second, item.first);
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302873 return;
2874 }
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302875 }
2876 // Get the connection to which the memberId belongs
2877 auto getObjectsWithConnectionCb =
2878 [sensorAsyncResp, overrideMap](
Ed Tanouscb13a392020-07-25 19:02:03 +00002879 const boost::container::flat_set<std::string>& /*connections*/,
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302880 const std::set<std::pair<std::string, std::string>>&
2881 objectsWithConnection) {
2882 if (objectsWithConnection.size() != overrideMap.size())
2883 {
2884 BMCWEB_LOG_INFO
2885 << "Unable to find all objects with proper connection "
2886 << objectsWithConnection.size() << " requested "
2887 << overrideMap.size() << "\n";
2888 messages::resourceNotFound(
zhanghch058d1b46d2021-04-01 11:18:24 +08002889 sensorAsyncResp->asyncResp->res,
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +02002890 sensorAsyncResp->chassisSubNode ==
2891 sensors::node::thermal
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302892 ? "Temperatures"
2893 : "Voltages",
2894 "Count");
2895 return;
2896 }
2897 for (const auto& item : objectsWithConnection)
2898 {
George Liu28aa8de2021-02-01 15:13:30 +08002899 sdbusplus::message::object_path path(item.first);
2900 std::string sensorName = path.filename();
2901 if (sensorName.empty())
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302902 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002903 messages::internalError(
2904 sensorAsyncResp->asyncResp->res);
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302905 return;
2906 }
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302907
2908 const auto& iterator = overrideMap.find(sensorName);
2909 if (iterator == overrideMap.end())
2910 {
2911 BMCWEB_LOG_INFO << "Unable to find sensor object"
2912 << item.first << "\n";
zhanghch058d1b46d2021-04-01 11:18:24 +08002913 messages::internalError(
2914 sensorAsyncResp->asyncResp->res);
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302915 return;
2916 }
2917 crow::connections::systemBus->async_method_call(
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302918 [sensorAsyncResp](const boost::system::error_code ec) {
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302919 if (ec)
2920 {
2921 BMCWEB_LOG_DEBUG
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302922 << "setOverrideValueStatus DBUS error: "
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302923 << ec;
zhanghch058d1b46d2021-04-01 11:18:24 +08002924 messages::internalError(
2925 sensorAsyncResp->asyncResp->res);
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302926 return;
2927 }
2928 },
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302929 item.second, item.first,
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302930 "org.freedesktop.DBus.Properties", "Set",
2931 "xyz.openbmc_project.Sensor.Value", "Value",
Patrick Williams19bd78d2020-05-13 17:38:24 -05002932 std::variant<double>(iterator->second.first));
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302933 }
2934 };
2935 // Get object with connection for the given sensor name
2936 getObjectsWithConnection(sensorAsyncResp, sensorNames,
2937 std::move(getObjectsWithConnectionCb));
2938 };
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302939 // get full sensor list for the given chassisId and cross verify the sensor.
2940 getChassis(sensorAsyncResp, std::move(getChassisSensorListCb));
2941}
2942
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +02002943/**
2944 * @brief Retrieves mapping of Redfish URIs to sensor value property to D-Bus
2945 * path of the sensor.
2946 *
2947 * Function builds valid Redfish response for sensor query of given chassis and
2948 * node. It then builds metadata about Redfish<->D-Bus correlations and provides
2949 * it to caller in a callback.
2950 *
2951 * @param chassis Chassis for which retrieval should be performed
2952 * @param node Node (group) of sensors. See sensors::node for supported values
2953 * @param mapComplete Callback to be called with retrieval result
2954 */
Ed Tanous23a21a12020-07-25 04:45:05 +00002955inline void retrieveUriToDbusMap(const std::string& chassis,
2956 const std::string& node,
2957 SensorsAsyncResp::DataCompleteCb&& mapComplete)
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +02002958{
Wludzik, Jozefc2bf7f92021-03-08 14:35:54 +00002959 auto pathIt = sensors::dbus::paths.find(node);
2960 if (pathIt == sensors::dbus::paths.end())
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +02002961 {
2962 BMCWEB_LOG_ERROR << "Wrong node provided : " << node;
2963 mapComplete(boost::beast::http::status::bad_request, {});
2964 return;
2965 }
Krzysztof Grobelnyd51e0722021-04-16 13:15:21 +00002966
2967 auto res = std::make_shared<crow::Response>();
2968 auto asyncResp = std::make_shared<bmcweb::AsyncResp>(*res);
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +02002969 auto callback =
Krzysztof Grobelnyd51e0722021-04-16 13:15:21 +00002970 [res, asyncResp, mapCompleteCb{std::move(mapComplete)}](
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +02002971 const boost::beast::http::status status,
2972 const boost::container::flat_map<std::string, std::string>&
2973 uriToDbus) { mapCompleteCb(status, uriToDbus); };
2974
2975 auto resp = std::make_shared<SensorsAsyncResp>(
Krzysztof Grobelnyd51e0722021-04-16 13:15:21 +00002976 asyncResp, chassis, pathIt->second, node, std::move(callback));
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +02002977 getChassisData(resp);
2978}
2979
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002980inline void requestRoutesSensorCollection(App& app)
Anthony Wilson95a3eca2019-06-11 10:44:47 -05002981{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002982 BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/Sensors/")
Ed Tanoused398212021-06-09 17:05:54 -07002983 .privileges(redfish::privileges::getSensorCollection)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002984 .methods(
2985 boost::beast::http::verb::get)([](const crow::Request&,
2986 const std::shared_ptr<
2987 bmcweb::AsyncResp>& aResp,
2988 const std::string& chassisId) {
2989 BMCWEB_LOG_DEBUG << "SensorCollection doGet enter";
Anthony Wilson95a3eca2019-06-11 10:44:47 -05002990
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002991 std::shared_ptr<SensorsAsyncResp> asyncResp =
2992 std::make_shared<SensorsAsyncResp>(
2993 aResp, chassisId,
2994 sensors::dbus::paths.at(sensors::node::sensors),
2995 sensors::node::sensors);
zhanghch058d1b46d2021-04-01 11:18:24 +08002996
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002997 auto getChassisCb =
2998 [asyncResp](
2999 const std::shared_ptr<
3000 boost::container::flat_set<std::string>>& sensorNames) {
3001 BMCWEB_LOG_DEBUG << "getChassisCb enter";
Anthony Wilson95a3eca2019-06-11 10:44:47 -05003002
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003003 nlohmann::json& entriesArray =
3004 asyncResp->asyncResp->res.jsonValue["Members"];
3005 for (auto& sensor : *sensorNames)
Anthony Wilson95a3eca2019-06-11 10:44:47 -05003006 {
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003007 BMCWEB_LOG_DEBUG << "Adding sensor: " << sensor;
Anthony Wilson95a3eca2019-06-11 10:44:47 -05003008
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003009 sdbusplus::message::object_path path(sensor);
3010 std::string sensorName = path.filename();
3011 if (sensorName.empty())
Anthony Wilson95a3eca2019-06-11 10:44:47 -05003012 {
3013 BMCWEB_LOG_ERROR << "Invalid sensor path: "
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003014 << sensor;
3015 messages::internalError(asyncResp->asyncResp->res);
3016 return;
Anthony Wilson95a3eca2019-06-11 10:44:47 -05003017 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003018 entriesArray.push_back(
3019 {{"@odata.id", "/redfish/v1/Chassis/" +
3020 asyncResp->chassisId + "/" +
3021 asyncResp->chassisSubNode + "/" +
3022 sensorName}});
3023 }
Anthony Wilson95a3eca2019-06-11 10:44:47 -05003024
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003025 asyncResp->asyncResp->res.jsonValue["Members@odata.count"] =
3026 entriesArray.size();
3027 BMCWEB_LOG_DEBUG << "getChassisCb exit";
3028 };
Anthony Wilson95a3eca2019-06-11 10:44:47 -05003029
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003030 // Get set of sensors in chassis
3031 getChassis(asyncResp, std::move(getChassisCb));
3032 BMCWEB_LOG_DEBUG << "SensorCollection doGet exit";
3033 });
3034}
Anthony Wilson95a3eca2019-06-11 10:44:47 -05003035
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003036inline void requestRoutesSensor(App& app)
3037{
3038 BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/Sensors/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07003039 .privileges(redfish::privileges::getSensor)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003040 .methods(
3041 boost::beast::http::verb::get)([](const crow::Request&,
3042 const std::shared_ptr<
3043 bmcweb::AsyncResp>& aResp,
3044 const std::string& chassisId,
3045 const std::string& sensorName) {
3046 BMCWEB_LOG_DEBUG << "Sensor doGet enter";
3047 std::shared_ptr<SensorsAsyncResp> asyncResp =
3048 std::make_shared<SensorsAsyncResp>(aResp, chassisId,
3049 std::vector<const char*>(),
3050 sensors::node::sensors);
Anthony Wilson95a3eca2019-06-11 10:44:47 -05003051
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003052 const std::array<const char*, 1> interfaces = {
3053 "xyz.openbmc_project.Sensor.Value"};
3054
3055 // Get a list of all of the sensors that implement Sensor.Value
3056 // and get the path and service name associated with the sensor
3057 crow::connections::systemBus->async_method_call(
3058 [asyncResp, sensorName](const boost::system::error_code ec,
3059 const GetSubTreeType& subtree) {
3060 BMCWEB_LOG_DEBUG << "respHandler1 enter";
3061 if (ec)
3062 {
3063 messages::internalError(asyncResp->asyncResp->res);
3064 BMCWEB_LOG_ERROR
3065 << "Sensor getSensorPaths resp_handler: "
3066 << "Dbus error " << ec;
3067 return;
3068 }
3069
3070 GetSubTreeType::const_iterator it = std::find_if(
3071 subtree.begin(), subtree.end(),
3072 [sensorName](
3073 const std::pair<
3074 std::string,
3075 std::vector<std::pair<
3076 std::string, std::vector<std::string>>>>&
3077 object) {
3078 sdbusplus::message::object_path path(object.first);
3079 std::string name = path.filename();
3080 if (name.empty())
3081 {
3082 BMCWEB_LOG_ERROR << "Invalid sensor path: "
3083 << object.first;
3084 return false;
3085 }
3086
3087 return name == sensorName;
3088 });
3089
3090 if (it == subtree.end())
3091 {
3092 BMCWEB_LOG_ERROR << "Could not find path for sensor: "
3093 << sensorName;
3094 messages::resourceNotFound(asyncResp->asyncResp->res,
3095 "Sensor", sensorName);
3096 return;
3097 }
3098 std::string_view sensorPath = (*it).first;
3099 BMCWEB_LOG_DEBUG << "Found sensor path for sensor '"
3100 << sensorName << "': " << sensorPath;
3101
3102 const std::shared_ptr<
3103 boost::container::flat_set<std::string>>
3104 sensorList = std::make_shared<
3105 boost::container::flat_set<std::string>>();
3106
3107 sensorList->emplace(sensorPath);
3108 processSensorList(asyncResp, sensorList);
3109 BMCWEB_LOG_DEBUG << "respHandler1 exit";
3110 },
3111 "xyz.openbmc_project.ObjectMapper",
3112 "/xyz/openbmc_project/object_mapper",
3113 "xyz.openbmc_project.ObjectMapper", "GetSubTree",
3114 "/xyz/openbmc_project/sensors", 2, interfaces);
3115 });
3116}
Anthony Wilson95a3eca2019-06-11 10:44:47 -05003117
Ed Tanous1abe55e2018-09-05 08:30:59 -07003118} // namespace redfish