blob: dc1b0a02d88d628915e9bf6966d88fd5a9e1db9b [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
Ed Tanous3ccb3ad2023-01-13 17:40:03 -080018#include "app.hpp"
19#include "dbus_singleton.hpp"
George Liu7a1dbc42022-12-07 16:03:22 +080020#include "dbus_utility.hpp"
Ed Tanous539d8c62024-06-19 14:38:27 -070021#include "generated/enums/redundancy.hpp"
Matt Simmeringaaf08ac2023-10-04 08:41:01 -070022#include "generated/enums/resource.hpp"
Ed Tanous3ccb3ad2023-01-13 17:40:03 -080023#include "query.hpp"
24#include "registries/privilege_registry.hpp"
Ed Tanous50ebd4a2023-01-19 19:03:17 -080025#include "str_utility.hpp"
Ed Tanous3ccb3ad2023-01-13 17:40:03 -080026#include "utils/dbus_utils.hpp"
27#include "utils/json_utils.hpp"
28#include "utils/query_param.hpp"
Janet Adkins1516c212024-08-14 13:22:41 -050029#include "utils/sensor_utils.hpp"
Ed Tanous0ec8b832022-03-14 14:56:47 -070030
George Liue99073f2022-12-09 11:06:16 +080031#include <boost/system/error_code.hpp>
Ed Tanousef4c65b2023-04-24 15:28:50 -070032#include <boost/url/format.hpp>
Jonathan Doman1e1e5982021-06-11 09:36:17 -070033#include <sdbusplus/asio/property.hpp>
Krzysztof Grobelny86d89ed2022-08-29 14:49:20 +020034#include <sdbusplus/unpack_properties.hpp>
Gunnar Mills1214b7e2020-06-04 10:11:30 -050035
George Liu7a1dbc42022-12-07 16:03:22 +080036#include <array>
Gunnar Mills1214b7e2020-06-04 10:11:30 -050037#include <cmath>
Nan Zhoufe04d492022-06-22 17:10:41 +000038#include <iterator>
Ed Tanous283860f2022-08-29 14:08:50 -070039#include <limits>
Nan Zhoufe04d492022-06-22 17:10:41 +000040#include <map>
Ed Tanous3544d2a2023-08-06 18:12:20 -070041#include <ranges>
Nan Zhoufe04d492022-06-22 17:10:41 +000042#include <set>
Ed Tanous18f8f602023-07-18 10:07:23 -070043#include <string>
George Liu7a1dbc42022-12-07 16:03:22 +080044#include <string_view>
Ed Tanousb5a76932020-09-29 16:16:58 -070045#include <utility>
Ed Tanousabf2add2019-01-22 16:40:12 -080046#include <variant>
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +010047
Ed Tanous1abe55e2018-09-05 08:30:59 -070048namespace redfish
49{
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +010050
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +020051namespace sensors
52{
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +020053
Ed Tanous02da7c52022-02-27 00:09:02 -080054// clang-format off
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +020055namespace dbus
56{
Ed Tanouscf9e4172022-12-21 09:30:16 -080057constexpr auto powerPaths = std::to_array<std::string_view>({
Ed Tanous02da7c52022-02-27 00:09:02 -080058 "/xyz/openbmc_project/sensors/voltage",
59 "/xyz/openbmc_project/sensors/power"
60});
Wludzik, Jozefc2bf7f92021-03-08 14:35:54 +000061
Ed Tanous25b54db2024-04-17 15:40:31 -070062constexpr auto getSensorPaths(){
63 if constexpr(BMCWEB_REDFISH_NEW_POWERSUBSYSTEM_THERMALSUBSYSTEM){
64 return std::to_array<std::string_view>({
65 "/xyz/openbmc_project/sensors/power",
66 "/xyz/openbmc_project/sensors/current",
67 "/xyz/openbmc_project/sensors/airflow",
68 "/xyz/openbmc_project/sensors/humidity",
69 "/xyz/openbmc_project/sensors/voltage",
70 "/xyz/openbmc_project/sensors/fan_tach",
71 "/xyz/openbmc_project/sensors/temperature",
72 "/xyz/openbmc_project/sensors/fan_pwm",
73 "/xyz/openbmc_project/sensors/altitude",
74 "/xyz/openbmc_project/sensors/energy",
75 "/xyz/openbmc_project/sensors/utilization"});
76 } else {
77 return std::to_array<std::string_view>({"/xyz/openbmc_project/sensors/power",
78 "/xyz/openbmc_project/sensors/current",
79 "/xyz/openbmc_project/sensors/airflow",
80 "/xyz/openbmc_project/sensors/humidity",
81 "/xyz/openbmc_project/sensors/utilization"});
82}
83}
84
85constexpr auto sensorPaths = getSensorPaths();
Ed Tanous02da7c52022-02-27 00:09:02 -080086
Ed Tanouscf9e4172022-12-21 09:30:16 -080087constexpr auto thermalPaths = std::to_array<std::string_view>({
Ed Tanous02da7c52022-02-27 00:09:02 -080088 "/xyz/openbmc_project/sensors/fan_tach",
89 "/xyz/openbmc_project/sensors/temperature",
90 "/xyz/openbmc_project/sensors/fan_pwm"
91});
92
Wludzik, Jozefc2bf7f92021-03-08 14:35:54 +000093} // namespace dbus
Ed Tanous02da7c52022-02-27 00:09:02 -080094// clang-format on
95
Janet Adkins0c728b42024-08-29 11:09:10 -050096constexpr std::string_view powerNodeStr = sensor_utils::chassisSubNodeToString(
97 sensor_utils::ChassisSubNode::powerNode);
98constexpr std::string_view sensorsNodeStr =
99 sensor_utils::chassisSubNodeToString(
100 sensor_utils::ChassisSubNode::sensorsNode);
101constexpr std::string_view thermalNodeStr =
102 sensor_utils::chassisSubNodeToString(
103 sensor_utils::ChassisSubNode::thermalNode);
104
Ed Tanouscf9e4172022-12-21 09:30:16 -0800105using sensorPair =
106 std::pair<std::string_view, std::span<const std::string_view>>;
Ed Tanous02da7c52022-02-27 00:09:02 -0800107static constexpr std::array<sensorPair, 3> paths = {
Janet Adkins0c728b42024-08-29 11:09:10 -0500108 {{sensors::powerNodeStr, dbus::powerPaths},
109 {sensors::sensorsNodeStr, dbus::sensorPaths},
110 {sensors::thermalNodeStr, dbus::thermalPaths}}};
Wludzik, Jozefc2bf7f92021-03-08 14:35:54 +0000111
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200112} // namespace sensors
113
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100114/**
Kowalski, Kamil588c3f02018-04-03 14:55:27 +0200115 * SensorsAsyncResp
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100116 * Gathers data needed for response processing after async calls are done
117 */
Ed Tanous1abe55e2018-09-05 08:30:59 -0700118class SensorsAsyncResp
119{
120 public:
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200121 using DataCompleteCb = std::function<void(
122 const boost::beast::http::status status,
Nan Zhoufe04d492022-06-22 17:10:41 +0000123 const std::map<std::string, std::string>& uriToDbus)>;
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200124
125 struct SensorData
126 {
127 const std::string name;
128 std::string uri;
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200129 const std::string dbusPath;
130 };
131
Ed Tanous8a592812022-06-04 09:06:59 -0700132 SensorsAsyncResp(const std::shared_ptr<bmcweb::AsyncResp>& asyncRespIn,
zhanghch058d1b46d2021-04-01 11:18:24 +0800133 const std::string& chassisIdIn,
Ed Tanouscf9e4172022-12-21 09:30:16 -0800134 std::span<const std::string_view> typesIn,
Ed Tanous02da7c52022-02-27 00:09:02 -0800135 std::string_view subNode) :
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400136 asyncResp(asyncRespIn), chassisId(chassisIdIn), types(typesIn),
137 chassisSubNode(subNode), efficientExpand(false)
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500138 {}
Kowalski, Kamil588c3f02018-04-03 14:55:27 +0200139
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200140 // Store extra data about sensor mapping and return it in callback
Ed Tanous8a592812022-06-04 09:06:59 -0700141 SensorsAsyncResp(const std::shared_ptr<bmcweb::AsyncResp>& asyncRespIn,
zhanghch058d1b46d2021-04-01 11:18:24 +0800142 const std::string& chassisIdIn,
Ed Tanouscf9e4172022-12-21 09:30:16 -0800143 std::span<const std::string_view> typesIn,
Ed Tanous02da7c52022-02-27 00:09:02 -0800144 std::string_view subNode,
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200145 DataCompleteCb&& creationComplete) :
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400146 asyncResp(asyncRespIn), chassisId(chassisIdIn), types(typesIn),
147 chassisSubNode(subNode), efficientExpand(false),
148 metadata{std::vector<SensorData>()},
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200149 dataComplete{std::move(creationComplete)}
150 {}
151
Nan Zhou928fefb2022-03-28 08:45:00 -0700152 // sensor collections expand
Ed Tanous8a592812022-06-04 09:06:59 -0700153 SensorsAsyncResp(const std::shared_ptr<bmcweb::AsyncResp>& asyncRespIn,
Nan Zhou928fefb2022-03-28 08:45:00 -0700154 const std::string& chassisIdIn,
Ed Tanouscf9e4172022-12-21 09:30:16 -0800155 std::span<const std::string_view> typesIn,
Ed Tanous8a592812022-06-04 09:06:59 -0700156 const std::string_view& subNode, bool efficientExpandIn) :
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400157 asyncResp(asyncRespIn), chassisId(chassisIdIn), types(typesIn),
158 chassisSubNode(subNode), efficientExpand(efficientExpandIn)
Nan Zhou928fefb2022-03-28 08:45:00 -0700159 {}
160
Ed Tanous1abe55e2018-09-05 08:30:59 -0700161 ~SensorsAsyncResp()
162 {
zhanghch058d1b46d2021-04-01 11:18:24 +0800163 if (asyncResp->res.result() ==
164 boost::beast::http::status::internal_server_error)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700165 {
166 // Reset the json object to clear out any data that made it in
167 // before the error happened todo(ed) handle error condition with
168 // proper code
zhanghch058d1b46d2021-04-01 11:18:24 +0800169 asyncResp->res.jsonValue = nlohmann::json::object();
Ed Tanous1abe55e2018-09-05 08:30:59 -0700170 }
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200171
172 if (dataComplete && metadata)
173 {
Nan Zhoufe04d492022-06-22 17:10:41 +0000174 std::map<std::string, std::string> map;
zhanghch058d1b46d2021-04-01 11:18:24 +0800175 if (asyncResp->res.result() == boost::beast::http::status::ok)
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200176 {
177 for (auto& sensor : *metadata)
178 {
Ed Tanousc1d019a2022-08-06 09:36:06 -0700179 map.emplace(sensor.uri, sensor.dbusPath);
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200180 }
181 }
zhanghch058d1b46d2021-04-01 11:18:24 +0800182 dataComplete(asyncResp->res.result(), map);
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200183 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700184 }
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100185
Ed Tanousecd6a3a2022-01-07 09:18:40 -0800186 SensorsAsyncResp(const SensorsAsyncResp&) = delete;
187 SensorsAsyncResp(SensorsAsyncResp&&) = delete;
188 SensorsAsyncResp& operator=(const SensorsAsyncResp&) = delete;
189 SensorsAsyncResp& operator=(SensorsAsyncResp&&) = delete;
190
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200191 void addMetadata(const nlohmann::json& sensorObject,
Ed Tanousc1d019a2022-08-06 09:36:06 -0700192 const std::string& dbusPath)
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200193 {
194 if (metadata)
195 {
Ed Tanousc1d019a2022-08-06 09:36:06 -0700196 metadata->emplace_back(SensorData{
197 sensorObject["Name"], sensorObject["@odata.id"], dbusPath});
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200198 }
199 }
200
201 void updateUri(const std::string& name, const std::string& uri)
202 {
203 if (metadata)
204 {
205 for (auto& sensor : *metadata)
206 {
207 if (sensor.name == name)
208 {
209 sensor.uri = uri;
210 }
211 }
212 }
213 }
214
zhanghch058d1b46d2021-04-01 11:18:24 +0800215 const std::shared_ptr<bmcweb::AsyncResp> asyncResp;
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200216 const std::string chassisId;
Ed Tanouscf9e4172022-12-21 09:30:16 -0800217 const std::span<const std::string_view> types;
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200218 const std::string chassisSubNode;
Nan Zhou928fefb2022-03-28 08:45:00 -0700219 const bool efficientExpand;
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +0200220
221 private:
222 std::optional<std::vector<SensorData>> metadata;
223 DataCompleteCb dataComplete;
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100224};
225
Janet Adkinsc9563602024-08-28 11:37:46 -0500226using InventoryItem = sensor_utils::InventoryItem;
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500227
228/**
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +0530229 * @brief Get objects with connection necessary for sensors
Kowalski, Kamil588c3f02018-04-03 14:55:27 +0200230 * @param SensorsAsyncResp Pointer to object holding response data
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100231 * @param sensorNames Sensors retrieved from chassis
232 * @param callback Callback for processing gathered connections
233 */
234template <typename Callback>
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +0530235void getObjectsWithConnection(
Ed Tanous81ce6092020-12-17 16:54:55 +0000236 const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
Nan Zhoufe04d492022-06-22 17:10:41 +0000237 const std::shared_ptr<std::set<std::string>>& sensorNames,
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +0530238 Callback&& callback)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700239{
Ed Tanous62598e32023-07-17 17:06:25 -0700240 BMCWEB_LOG_DEBUG("getObjectsWithConnection enter");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700241 const std::string path = "/xyz/openbmc_project/sensors";
George Liue99073f2022-12-09 11:06:16 +0800242 constexpr std::array<std::string_view, 1> interfaces = {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700243 "xyz.openbmc_project.Sensor.Value"};
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100244
George Liue99073f2022-12-09 11:06:16 +0800245 // Make call to ObjectMapper to find all sensors objects
246 dbus::utility::getSubTree(
247 path, 2, interfaces,
Ed Tanous8cb2c022024-03-27 16:31:46 -0700248 [callback = std::forward<Callback>(callback), sensorsAsyncResp,
George Liue99073f2022-12-09 11:06:16 +0800249 sensorNames](const boost::system::error_code& ec,
Ed Tanous002d39b2022-05-31 08:59:27 -0700250 const dbus::utility::MapperGetSubTreeResponse& subtree) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400251 // Response handler for parsing objects subtree
252 BMCWEB_LOG_DEBUG("getObjectsWithConnection resp_handler enter");
253 if (ec)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700254 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400255 messages::internalError(sensorsAsyncResp->asyncResp->res);
256 BMCWEB_LOG_ERROR(
257 "getObjectsWithConnection resp_handler: Dbus error {}", ec);
258 return;
259 }
260
261 BMCWEB_LOG_DEBUG("Found {} subtrees", subtree.size());
262
263 // Make unique list of connections only for requested sensor types
264 // and found in the chassis
265 std::set<std::string> connections;
266 std::set<std::pair<std::string, std::string>> objectsWithConnection;
267
268 BMCWEB_LOG_DEBUG("sensorNames list count: {}", sensorNames->size());
269 for (const std::string& tsensor : *sensorNames)
270 {
271 BMCWEB_LOG_DEBUG("Sensor to find: {}", tsensor);
272 }
273
274 for (const std::pair<std::string,
275 std::vector<std::pair<
276 std::string, std::vector<std::string>>>>&
277 object : subtree)
278 {
279 if (sensorNames->find(object.first) != sensorNames->end())
Ed Tanous1abe55e2018-09-05 08:30:59 -0700280 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400281 for (const std::pair<std::string, std::vector<std::string>>&
282 objData : object.second)
283 {
284 BMCWEB_LOG_DEBUG("Adding connection: {}",
285 objData.first);
286 connections.insert(objData.first);
287 objectsWithConnection.insert(
288 std::make_pair(object.first, objData.first));
289 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700290 }
291 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400292 BMCWEB_LOG_DEBUG("Found {} connections", connections.size());
293 callback(std::move(connections), std::move(objectsWithConnection));
294 BMCWEB_LOG_DEBUG("getObjectsWithConnection resp_handler exit");
295 });
Ed Tanous62598e32023-07-17 17:06:25 -0700296 BMCWEB_LOG_DEBUG("getObjectsWithConnection exit");
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +0530297}
298
299/**
300 * @brief Create connections necessary for sensors
301 * @param SensorsAsyncResp Pointer to object holding response data
302 * @param sensorNames Sensors retrieved from chassis
303 * @param callback Callback for processing gathered connections
304 */
305template <typename Callback>
Nan Zhoufe04d492022-06-22 17:10:41 +0000306void getConnections(std::shared_ptr<SensorsAsyncResp> sensorsAsyncResp,
307 const std::shared_ptr<std::set<std::string>> sensorNames,
308 Callback&& callback)
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +0530309{
310 auto objectsWithConnectionCb =
Ed Tanous8cb2c022024-03-27 16:31:46 -0700311 [callback = std::forward<Callback>(callback)](
312 const std::set<std::string>& connections,
313 const std::set<std::pair<std::string, std::string>>&
314 /*objectsWithConnection*/) { callback(connections); };
Ed Tanous81ce6092020-12-17 16:54:55 +0000315 getObjectsWithConnection(sensorsAsyncResp, sensorNames,
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +0530316 std::move(objectsWithConnectionCb));
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100317}
318
319/**
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700320 * @brief Shrinks the list of sensors for processing
321 * @param SensorsAysncResp The class holding the Redfish response
322 * @param allSensors A list of all the sensors associated to the
323 * chassis element (i.e. baseboard, front panel, etc...)
324 * @param activeSensors A list that is a reduction of the incoming
325 * allSensors list. Eliminate Thermal sensors when a Power request is
326 * made, and eliminate Power sensors when a Thermal request is made.
327 */
Ed Tanous23a21a12020-07-25 04:45:05 +0000328inline void reduceSensorList(
Ed Tanous7f1cc262022-08-09 13:33:57 -0700329 crow::Response& res, std::string_view chassisSubNode,
Ed Tanouscf9e4172022-12-21 09:30:16 -0800330 std::span<const std::string_view> sensorTypes,
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700331 const std::vector<std::string>* allSensors,
Nan Zhoufe04d492022-06-22 17:10:41 +0000332 const std::shared_ptr<std::set<std::string>>& activeSensors)
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700333{
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700334 if ((allSensors == nullptr) || (activeSensors == nullptr))
335 {
Ed Tanous7f1cc262022-08-09 13:33:57 -0700336 messages::resourceNotFound(res, chassisSubNode,
Janet Adkins0c728b42024-08-29 11:09:10 -0500337 chassisSubNode == sensors::thermalNodeStr
Ed Tanous7f1cc262022-08-09 13:33:57 -0700338 ? "Temperatures"
339 : "Voltages");
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700340
341 return;
342 }
343 if (allSensors->empty())
344 {
345 // Nothing to do, the activeSensors object is also empty
346 return;
347 }
348
Ed Tanous7f1cc262022-08-09 13:33:57 -0700349 for (std::string_view type : sensorTypes)
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700350 {
351 for (const std::string& sensor : *allSensors)
352 {
Ed Tanous11ba3972022-07-11 09:50:41 -0700353 if (sensor.starts_with(type))
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700354 {
355 activeSensors->emplace(sensor);
356 }
357 }
358 }
359}
360
Ed Tanous7f1cc262022-08-09 13:33:57 -0700361/*
362 *Populates the top level collection for a given subnode. Populates
363 *SensorCollection, Power, or Thermal schemas.
364 *
365 * */
366inline void populateChassisNode(nlohmann::json& jsonValue,
367 std::string_view chassisSubNode)
368{
Janet Adkins0c728b42024-08-29 11:09:10 -0500369 if (chassisSubNode == sensors::powerNodeStr)
Ed Tanous7f1cc262022-08-09 13:33:57 -0700370 {
371 jsonValue["@odata.type"] = "#Power.v1_5_2.Power";
372 }
Janet Adkins0c728b42024-08-29 11:09:10 -0500373 else if (chassisSubNode == sensors::thermalNodeStr)
Ed Tanous7f1cc262022-08-09 13:33:57 -0700374 {
375 jsonValue["@odata.type"] = "#Thermal.v1_4_0.Thermal";
376 jsonValue["Fans"] = nlohmann::json::array();
377 jsonValue["Temperatures"] = nlohmann::json::array();
378 }
Janet Adkins0c728b42024-08-29 11:09:10 -0500379 else if (chassisSubNode == sensors::sensorsNodeStr)
Ed Tanous7f1cc262022-08-09 13:33:57 -0700380 {
381 jsonValue["@odata.type"] = "#SensorCollection.SensorCollection";
382 jsonValue["Description"] = "Collection of Sensors for this Chassis";
383 jsonValue["Members"] = nlohmann::json::array();
384 jsonValue["Members@odata.count"] = 0;
385 }
386
Janet Adkins0c728b42024-08-29 11:09:10 -0500387 if (chassisSubNode != sensors::sensorsNodeStr)
Ed Tanous7f1cc262022-08-09 13:33:57 -0700388 {
389 jsonValue["Id"] = chassisSubNode;
390 }
391 jsonValue["Name"] = chassisSubNode;
392}
393
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700394/**
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100395 * @brief Retrieves requested chassis sensors and redundancy data from DBus .
Kowalski, Kamil588c3f02018-04-03 14:55:27 +0200396 * @param SensorsAsyncResp Pointer to object holding response data
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100397 * @param callback Callback for next step in gathered sensor processing
398 */
399template <typename Callback>
Ed Tanous7f1cc262022-08-09 13:33:57 -0700400void getChassis(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
401 std::string_view chassisId, std::string_view chassisSubNode,
Ed Tanouscf9e4172022-12-21 09:30:16 -0800402 std::span<const std::string_view> sensorTypes,
403 Callback&& callback)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700404{
Ed Tanous62598e32023-07-17 17:06:25 -0700405 BMCWEB_LOG_DEBUG("getChassis enter");
George Liu7a1dbc42022-12-07 16:03:22 +0800406 constexpr std::array<std::string_view, 2> interfaces = {
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700407 "xyz.openbmc_project.Inventory.Item.Board",
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500408 "xyz.openbmc_project.Inventory.Item.Chassis"};
George Liu7a1dbc42022-12-07 16:03:22 +0800409
410 // Get the Chassis Collection
411 dbus::utility::getSubTreePaths(
412 "/xyz/openbmc_project/inventory", 0, interfaces,
Ed Tanous8cb2c022024-03-27 16:31:46 -0700413 [callback = std::forward<Callback>(callback), asyncResp,
Ed Tanous7f1cc262022-08-09 13:33:57 -0700414 chassisIdStr{std::string(chassisId)},
415 chassisSubNode{std::string(chassisSubNode)}, sensorTypes](
George Liu7a1dbc42022-12-07 16:03:22 +0800416 const boost::system::error_code& ec,
Ed Tanous002d39b2022-05-31 08:59:27 -0700417 const dbus::utility::MapperGetSubTreePathsResponse& chassisPaths) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400418 BMCWEB_LOG_DEBUG("getChassis respHandler enter");
419 if (ec)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700420 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400421 BMCWEB_LOG_ERROR("getChassis respHandler DBUS error: {}", ec);
422 messages::internalError(asyncResp->res);
423 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700424 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400425 const std::string* chassisPath = nullptr;
426 for (const std::string& chassis : chassisPaths)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700427 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400428 sdbusplus::message::object_path path(chassis);
429 std::string chassisName = path.filename();
430 if (chassisName.empty())
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700431 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400432 BMCWEB_LOG_ERROR("Failed to find '/' in {}", chassis);
433 continue;
434 }
435 if (chassisName == chassisIdStr)
436 {
437 chassisPath = &chassis;
438 break;
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700439 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700440 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400441 if (chassisPath == nullptr)
442 {
443 messages::resourceNotFound(asyncResp->res, "Chassis",
444 chassisIdStr);
445 return;
446 }
447 populateChassisNode(asyncResp->res.jsonValue, chassisSubNode);
448
449 asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
450 "/redfish/v1/Chassis/{}/{}", chassisIdStr, chassisSubNode);
451
452 // Get the list of all sensors for this Chassis element
453 std::string sensorPath = *chassisPath + "/all_sensors";
454 dbus::utility::getAssociationEndPoints(
455 sensorPath,
456 [asyncResp, chassisSubNode, sensorTypes,
457 callback = std::forward<const Callback>(callback)](
458 const boost::system::error_code& ec2,
459 const dbus::utility::MapperEndPoints& nodeSensorList) {
460 if (ec2)
461 {
462 if (ec2.value() != EBADR)
463 {
464 messages::internalError(asyncResp->res);
465 return;
466 }
467 }
468 const std::shared_ptr<std::set<std::string>>
469 culledSensorList =
470 std::make_shared<std::set<std::string>>();
471 reduceSensorList(asyncResp->res, chassisSubNode,
472 sensorTypes, &nodeSensorList,
473 culledSensorList);
474 BMCWEB_LOG_DEBUG("Finishing with {}",
475 culledSensorList->size());
476 callback(culledSensorList);
477 });
George Liu7a1dbc42022-12-07 16:03:22 +0800478 });
Ed Tanous62598e32023-07-17 17:06:25 -0700479 BMCWEB_LOG_DEBUG("getChassis exit");
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100480}
481
482/**
Ed Tanous1d7c0052022-08-09 12:32:26 -0700483 * @brief Builds a json sensor representation of a sensor.
484 * @param sensorName The name of the sensor to be built
485 * @param sensorType The type (temperature, fan_tach, etc) of the sensor to
486 * build
Ed Tanous8ece0e42024-01-02 13:16:50 -0800487 * @param chassisSubNode The subnode (thermal, sensor, etc) of the sensor
Ed Tanous1d7c0052022-08-09 12:32:26 -0700488 * @param interfacesDict A dictionary of the interfaces and properties of said
489 * interfaces to be built from
490 * @param sensorJson The json object to fill
491 * @param inventoryItem D-Bus inventory item associated with the sensor. Will
492 * be nullptr if no associated inventory item was found.
493 */
494inline void objectInterfacesToJson(
495 const std::string& sensorName, const std::string& sensorType,
Janet Adkins0c728b42024-08-29 11:09:10 -0500496 const sensor_utils::ChassisSubNode chassisSubNode,
Michael Shen80f79a42023-08-24 13:41:53 +0000497 const dbus::utility::DBusInterfacesMap& interfacesDict,
Ed Tanous1d7c0052022-08-09 12:32:26 -0700498 nlohmann::json& sensorJson, InventoryItem* inventoryItem)
499{
Ed Tanous1d7c0052022-08-09 12:32:26 -0700500 for (const auto& [interface, valuesDict] : interfacesDict)
501 {
Janet Adkinsc9563602024-08-28 11:37:46 -0500502 sensor_utils::objectPropertiesToJson(
503 sensorName, sensorType, chassisSubNode, valuesDict, sensorJson,
504 inventoryItem);
Ed Tanous1d7c0052022-08-09 12:32:26 -0700505 }
Ed Tanous62598e32023-07-17 17:06:25 -0700506 BMCWEB_LOG_DEBUG("Added sensor {}", sensorName);
Ed Tanous1d7c0052022-08-09 12:32:26 -0700507}
508
Ed Tanousb5a76932020-09-29 16:16:58 -0700509inline void populateFanRedundancy(
510 const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp)
James Feist8bd25cc2019-03-15 15:14:00 -0700511{
George Liue99073f2022-12-09 11:06:16 +0800512 constexpr std::array<std::string_view, 1> interfaces = {
513 "xyz.openbmc_project.Control.FanRedundancy"};
514 dbus::utility::getSubTree(
515 "/xyz/openbmc_project/control", 2, interfaces,
Ed Tanousb9d36b42022-02-26 21:42:46 -0800516 [sensorsAsyncResp](
George Liue99073f2022-12-09 11:06:16 +0800517 const boost::system::error_code& ec,
Ed Tanousb9d36b42022-02-26 21:42:46 -0800518 const dbus::utility::MapperGetSubTreeResponse& resp) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400519 if (ec)
James Feist8bd25cc2019-03-15 15:14:00 -0700520 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400521 return; // don't have to have this interface
James Feist8bd25cc2019-03-15 15:14:00 -0700522 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400523 for (const std::pair<std::string, dbus::utility::MapperServiceMap>&
524 pathPair : resp)
525 {
526 const std::string& path = pathPair.first;
527 const dbus::utility::MapperServiceMap& objDict =
528 pathPair.second;
529 if (objDict.empty())
James Feist8bd25cc2019-03-15 15:14:00 -0700530 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400531 continue; // this should be impossible
James Feist8bd25cc2019-03-15 15:14:00 -0700532 }
533
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400534 const std::string& owner = objDict.begin()->first;
535 dbus::utility::getAssociationEndPoints(
536 path + "/chassis",
537 [path, owner, sensorsAsyncResp](
538 const boost::system::error_code& ec2,
539 const dbus::utility::MapperEndPoints& endpoints) {
540 if (ec2)
James Feist8bd25cc2019-03-15 15:14:00 -0700541 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400542 return; // if they don't have an association we
543 // can't tell what chassis is
James Feist8bd25cc2019-03-15 15:14:00 -0700544 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400545 auto found = std::ranges::find_if(
546 endpoints,
547 [sensorsAsyncResp](const std::string& entry) {
548 return entry.find(
549 sensorsAsyncResp->chassisId) !=
550 std::string::npos;
551 });
552
553 if (found == endpoints.end())
James Feist8bd25cc2019-03-15 15:14:00 -0700554 {
555 return;
556 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400557 sdbusplus::asio::getAllProperties(
558 *crow::connections::systemBus, owner, path,
559 "xyz.openbmc_project.Control.FanRedundancy",
560 [path, sensorsAsyncResp](
561 const boost::system::error_code& ec3,
562 const dbus::utility::DBusPropertiesMap& ret) {
563 if (ec3)
564 {
565 return; // don't have to have this
566 // interface
567 }
James Feist8bd25cc2019-03-15 15:14:00 -0700568
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400569 const uint8_t* allowedFailures = nullptr;
570 const std::vector<std::string>* collection =
571 nullptr;
572 const std::string* status = nullptr;
James Feist8bd25cc2019-03-15 15:14:00 -0700573
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400574 const bool success =
575 sdbusplus::unpackPropertiesNoThrow(
576 dbus_utils::UnpackErrorPrinter(), ret,
577 "AllowedFailures", allowedFailures,
578 "Collection", collection, "Status",
579 status);
James Feist8bd25cc2019-03-15 15:14:00 -0700580
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400581 if (!success)
582 {
583 messages::internalError(
584 sensorsAsyncResp->asyncResp->res);
585 return;
586 }
587
588 if (allowedFailures == nullptr ||
589 collection == nullptr || status == nullptr)
590 {
591 BMCWEB_LOG_ERROR(
592 "Invalid redundancy interface");
593 messages::internalError(
594 sensorsAsyncResp->asyncResp->res);
595 return;
596 }
597
598 sdbusplus::message::object_path objectPath(
599 path);
600 std::string name = objectPath.filename();
601 if (name.empty())
602 {
603 // this should be impossible
604 messages::internalError(
605 sensorsAsyncResp->asyncResp->res);
606 return;
607 }
608 std::ranges::replace(name, '_', ' ');
609
610 std::string health;
611
612 if (status->ends_with("Full"))
613 {
614 health = "OK";
615 }
616 else if (status->ends_with("Degraded"))
617 {
618 health = "Warning";
619 }
620 else
621 {
622 health = "Critical";
623 }
624 nlohmann::json::array_t redfishCollection;
625 const auto& fanRedfish =
626 sensorsAsyncResp->asyncResp->res
627 .jsonValue["Fans"];
628 for (const std::string& item : *collection)
629 {
630 sdbusplus::message::object_path itemPath(
631 item);
632 std::string itemName = itemPath.filename();
633 if (itemName.empty())
634 {
635 continue;
636 }
637 /*
638 todo(ed): merge patch that fixes the names
639 std::replace(itemName.begin(),
640 itemName.end(), '_', ' ');*/
641 auto schemaItem = std::ranges::find_if(
642 fanRedfish,
643 [itemName](const nlohmann::json& fan) {
644 return fan["Name"] == itemName;
645 });
646 if (schemaItem != fanRedfish.end())
647 {
648 nlohmann::json::object_t collectionId;
649 collectionId["@odata.id"] =
650 (*schemaItem)["@odata.id"];
651 redfishCollection.emplace_back(
652 std::move(collectionId));
653 }
654 else
655 {
656 BMCWEB_LOG_ERROR(
657 "failed to find fan in schema");
658 messages::internalError(
659 sensorsAsyncResp->asyncResp->res);
660 return;
661 }
662 }
663
664 size_t minNumNeeded =
665 collection->empty()
666 ? 0
667 : collection->size() - *allowedFailures;
668 nlohmann::json& jResp =
669 sensorsAsyncResp->asyncResp->res
670 .jsonValue["Redundancy"];
671
672 nlohmann::json::object_t redundancy;
673 boost::urls::url url = boost::urls::format(
674 "/redfish/v1/Chassis/{}/{}",
675 sensorsAsyncResp->chassisId,
676 sensorsAsyncResp->chassisSubNode);
677 url.set_fragment(
678 ("/Redundancy"_json_pointer / jResp.size())
679 .to_string());
680 redundancy["@odata.id"] = std::move(url);
681 redundancy["@odata.type"] =
682 "#Redundancy.v1_3_2.Redundancy";
683 redundancy["MinNumNeeded"] = minNumNeeded;
684 redundancy["Mode"] =
685 redundancy::RedundancyType::NPlusM;
686 redundancy["Name"] = name;
687 redundancy["RedundancySet"] = redfishCollection;
688 redundancy["Status"]["Health"] = health;
689 redundancy["Status"]["State"] =
690 resource::State::Enabled;
691
692 jResp.emplace_back(std::move(redundancy));
693 });
694 });
695 }
696 });
James Feist8bd25cc2019-03-15 15:14:00 -0700697}
698
Ed Tanousb5a76932020-09-29 16:16:58 -0700699inline void
Ed Tanous81ce6092020-12-17 16:54:55 +0000700 sortJSONResponse(const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp)
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700701{
zhanghch058d1b46d2021-04-01 11:18:24 +0800702 nlohmann::json& response = sensorsAsyncResp->asyncResp->res.jsonValue;
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700703 std::array<std::string, 2> sensorHeaders{"Temperatures", "Fans"};
Janet Adkins0c728b42024-08-29 11:09:10 -0500704 if (sensorsAsyncResp->chassisSubNode == sensors::powerNodeStr)
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700705 {
706 sensorHeaders = {"Voltages", "PowerSupplies"};
707 }
708 for (const std::string& sensorGroup : sensorHeaders)
709 {
710 nlohmann::json::iterator entry = response.find(sensorGroup);
711 if (entry != response.end())
712 {
713 std::sort(entry->begin(), entry->end(),
Ed Tanous02cad962022-06-30 16:50:15 -0700714 [](const nlohmann::json& c1, const nlohmann::json& c2) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400715 return c1["Name"] < c2["Name"];
716 });
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700717
718 // add the index counts to the end of each entry
719 size_t count = 0;
720 for (nlohmann::json& sensorJson : *entry)
721 {
722 nlohmann::json::iterator odata = sensorJson.find("@odata.id");
723 if (odata == sensorJson.end())
724 {
725 continue;
726 }
727 std::string* value = odata->get_ptr<std::string*>();
728 if (value != nullptr)
729 {
Willy Tueddfc432022-09-26 16:46:38 +0000730 *value += "/" + std::to_string(count);
George Liu3e35c762023-03-08 16:56:38 +0800731 sensorJson["MemberId"] = std::to_string(count);
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700732 count++;
Ed Tanous81ce6092020-12-17 16:54:55 +0000733 sensorsAsyncResp->updateUri(sensorJson["Name"], *value);
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700734 }
735 }
736 }
737 }
738}
739
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100740/**
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500741 * @brief Finds the inventory item with the specified object path.
742 * @param inventoryItems D-Bus inventory items associated with sensors.
743 * @param invItemObjPath D-Bus object path of inventory item.
744 * @return Inventory item within vector, or nullptr if no match found.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500745 */
Ed Tanous23a21a12020-07-25 04:45:05 +0000746inline InventoryItem* findInventoryItem(
Ed Tanousb5a76932020-09-29 16:16:58 -0700747 const std::shared_ptr<std::vector<InventoryItem>>& inventoryItems,
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500748 const std::string& invItemObjPath)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500749{
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500750 for (InventoryItem& inventoryItem : *inventoryItems)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500751 {
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500752 if (inventoryItem.objectPath == invItemObjPath)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500753 {
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500754 return &inventoryItem;
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500755 }
756 }
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500757 return nullptr;
758}
759
760/**
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500761 * @brief Finds the inventory item associated with the specified sensor.
762 * @param inventoryItems D-Bus inventory items associated with sensors.
763 * @param sensorObjPath D-Bus object path of sensor.
764 * @return Inventory item within vector, or nullptr if no match found.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500765 */
Ed Tanous23a21a12020-07-25 04:45:05 +0000766inline InventoryItem* findInventoryItemForSensor(
Ed Tanousb5a76932020-09-29 16:16:58 -0700767 const std::shared_ptr<std::vector<InventoryItem>>& inventoryItems,
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500768 const std::string& sensorObjPath)
769{
770 for (InventoryItem& inventoryItem : *inventoryItems)
771 {
Ed Tanousdb0d36e2023-06-30 10:37:05 -0700772 if (inventoryItem.sensors.contains(sensorObjPath))
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500773 {
774 return &inventoryItem;
775 }
776 }
777 return nullptr;
778}
779
780/**
Anthony Wilsond5005492019-07-31 16:34:17 -0500781 * @brief Finds the inventory item associated with the specified led path.
782 * @param inventoryItems D-Bus inventory items associated with sensors.
783 * @param ledObjPath D-Bus object path of led.
784 * @return Inventory item within vector, or nullptr if no match found.
785 */
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400786inline InventoryItem* findInventoryItemForLed(
787 std::vector<InventoryItem>& inventoryItems, const std::string& ledObjPath)
Anthony Wilsond5005492019-07-31 16:34:17 -0500788{
789 for (InventoryItem& inventoryItem : inventoryItems)
790 {
791 if (inventoryItem.ledObjectPath == ledObjPath)
792 {
793 return &inventoryItem;
794 }
795 }
796 return nullptr;
797}
798
799/**
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500800 * @brief Adds inventory item and associated sensor to specified vector.
801 *
802 * Adds a new InventoryItem to the vector if necessary. Searches for an
803 * existing InventoryItem with the specified object path. If not found, one is
804 * added to the vector.
805 *
806 * Next, the specified sensor is added to the set of sensors associated with the
807 * InventoryItem.
808 *
809 * @param inventoryItems D-Bus inventory items associated with sensors.
810 * @param invItemObjPath D-Bus object path of inventory item.
811 * @param sensorObjPath D-Bus object path of sensor
812 */
Ed Tanousb5a76932020-09-29 16:16:58 -0700813inline void addInventoryItem(
814 const std::shared_ptr<std::vector<InventoryItem>>& inventoryItems,
815 const std::string& invItemObjPath, const std::string& sensorObjPath)
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500816{
817 // Look for inventory item in vector
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400818 InventoryItem* inventoryItem =
819 findInventoryItem(inventoryItems, invItemObjPath);
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500820
821 // If inventory item doesn't exist in vector, add it
822 if (inventoryItem == nullptr)
823 {
824 inventoryItems->emplace_back(invItemObjPath);
825 inventoryItem = &(inventoryItems->back());
826 }
827
828 // Add sensor to set of sensors associated with inventory item
829 inventoryItem->sensors.emplace(sensorObjPath);
830}
831
832/**
833 * @brief Stores D-Bus data in the specified inventory item.
834 *
835 * Finds D-Bus data in the specified map of interfaces. Stores the data in the
836 * specified InventoryItem.
837 *
838 * This data is later used to provide sensor property values in the JSON
839 * response.
840 *
841 * @param inventoryItem Inventory item where data will be stored.
842 * @param interfacesDict Map containing D-Bus interfaces and their properties
843 * for the specified inventory item.
844 */
Ed Tanous23a21a12020-07-25 04:45:05 +0000845inline void storeInventoryItemData(
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500846 InventoryItem& inventoryItem,
Michael Shen80f79a42023-08-24 13:41:53 +0000847 const dbus::utility::DBusInterfacesMap& interfacesDict)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500848{
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500849 // Get properties from Inventory.Item interface
Ed Tanous711ac7a2021-12-20 09:34:41 -0800850
Ed Tanous9eb808c2022-01-25 10:19:23 -0800851 for (const auto& [interface, values] : interfacesDict)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500852 {
Ed Tanous711ac7a2021-12-20 09:34:41 -0800853 if (interface == "xyz.openbmc_project.Inventory.Item")
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500854 {
Ed Tanous9eb808c2022-01-25 10:19:23 -0800855 for (const auto& [name, dbusValue] : values)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500856 {
Ed Tanous711ac7a2021-12-20 09:34:41 -0800857 if (name == "Present")
858 {
859 const bool* value = std::get_if<bool>(&dbusValue);
860 if (value != nullptr)
861 {
862 inventoryItem.isPresent = *value;
863 }
864 }
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500865 }
866 }
Ed Tanous711ac7a2021-12-20 09:34:41 -0800867 // Check if Inventory.Item.PowerSupply interface is present
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500868
Ed Tanous711ac7a2021-12-20 09:34:41 -0800869 if (interface == "xyz.openbmc_project.Inventory.Item.PowerSupply")
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500870 {
Ed Tanous711ac7a2021-12-20 09:34:41 -0800871 inventoryItem.isPowerSupply = true;
872 }
873
874 // Get properties from Inventory.Decorator.Asset interface
875 if (interface == "xyz.openbmc_project.Inventory.Decorator.Asset")
876 {
Ed Tanous9eb808c2022-01-25 10:19:23 -0800877 for (const auto& [name, dbusValue] : values)
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500878 {
Ed Tanous711ac7a2021-12-20 09:34:41 -0800879 if (name == "Manufacturer")
880 {
881 const std::string* value =
882 std::get_if<std::string>(&dbusValue);
883 if (value != nullptr)
884 {
885 inventoryItem.manufacturer = *value;
886 }
887 }
888 if (name == "Model")
889 {
890 const std::string* value =
891 std::get_if<std::string>(&dbusValue);
892 if (value != nullptr)
893 {
894 inventoryItem.model = *value;
895 }
896 }
897 if (name == "SerialNumber")
898 {
899 const std::string* value =
900 std::get_if<std::string>(&dbusValue);
901 if (value != nullptr)
902 {
903 inventoryItem.serialNumber = *value;
904 }
905 }
906 if (name == "PartNumber")
907 {
908 const std::string* value =
909 std::get_if<std::string>(&dbusValue);
910 if (value != nullptr)
911 {
912 inventoryItem.partNumber = *value;
913 }
914 }
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500915 }
916 }
917
Ed Tanous711ac7a2021-12-20 09:34:41 -0800918 if (interface ==
919 "xyz.openbmc_project.State.Decorator.OperationalStatus")
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500920 {
Ed Tanous9eb808c2022-01-25 10:19:23 -0800921 for (const auto& [name, dbusValue] : values)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500922 {
Ed Tanous711ac7a2021-12-20 09:34:41 -0800923 if (name == "Functional")
924 {
925 const bool* value = std::get_if<bool>(&dbusValue);
926 if (value != nullptr)
927 {
928 inventoryItem.isFunctional = *value;
929 }
930 }
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500931 }
932 }
933 }
934}
935
936/**
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500937 * @brief Gets D-Bus data for inventory items associated with sensors.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500938 *
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500939 * Uses the specified connections (services) to obtain D-Bus data for inventory
940 * items associated with sensors. Stores the resulting data in the
941 * inventoryItems vector.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500942 *
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500943 * This data is later used to provide sensor property values in the JSON
944 * response.
945 *
946 * Finds the inventory item data asynchronously. Invokes callback when data has
947 * been obtained.
948 *
949 * The callback must have the following signature:
950 * @code
Anthony Wilsond5005492019-07-31 16:34:17 -0500951 * callback(void)
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500952 * @endcode
953 *
954 * This function is called recursively, obtaining data asynchronously from one
955 * connection in each call. This ensures the callback is not invoked until the
956 * last asynchronous function has completed.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500957 *
958 * @param sensorsAsyncResp Pointer to object holding response data.
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500959 * @param inventoryItems D-Bus inventory items associated with sensors.
960 * @param invConnections Connections that provide data for the inventory items.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500961 * implements ObjectManager.
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500962 * @param callback Callback to invoke when inventory data has been obtained.
963 * @param invConnectionsIndex Current index in invConnections. Only specified
964 * in recursive calls to this function.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500965 */
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500966template <typename Callback>
967static void getInventoryItemsData(
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500968 std::shared_ptr<SensorsAsyncResp> sensorsAsyncResp,
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500969 std::shared_ptr<std::vector<InventoryItem>> inventoryItems,
Ed Tanousd0090732022-10-04 17:22:56 -0700970 std::shared_ptr<std::set<std::string>> invConnections, Callback&& callback,
971 size_t invConnectionsIndex = 0)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500972{
Ed Tanous62598e32023-07-17 17:06:25 -0700973 BMCWEB_LOG_DEBUG("getInventoryItemsData enter");
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500974
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500975 // If no more connections left, call callback
976 if (invConnectionsIndex >= invConnections->size())
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500977 {
Anthony Wilsond5005492019-07-31 16:34:17 -0500978 callback();
Ed Tanous62598e32023-07-17 17:06:25 -0700979 BMCWEB_LOG_DEBUG("getInventoryItemsData exit");
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500980 return;
981 }
982
983 // Get inventory item data from current connection
Nan Zhoufe04d492022-06-22 17:10:41 +0000984 auto it = invConnections->begin();
985 std::advance(it, invConnectionsIndex);
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500986 if (it != invConnections->end())
987 {
988 const std::string& invConnection = *it;
989
George Liu5eb468d2023-06-20 17:03:24 +0800990 // Get all object paths and their interfaces for current connection
991 sdbusplus::message::object_path path("/xyz/openbmc_project/inventory");
992 dbus::utility::getManagedObjects(
993 invConnection, path,
994 [sensorsAsyncResp, inventoryItems, invConnections,
Ed Tanous8cb2c022024-03-27 16:31:46 -0700995 callback = std::forward<Callback>(callback), invConnectionsIndex](
George Liu5eb468d2023-06-20 17:03:24 +0800996 const boost::system::error_code& ec,
997 const dbus::utility::ManagedObjectType& resp) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400998 BMCWEB_LOG_DEBUG("getInventoryItemsData respHandler enter");
999 if (ec)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001000 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001001 BMCWEB_LOG_ERROR(
1002 "getInventoryItemsData respHandler DBus error {}", ec);
1003 messages::internalError(sensorsAsyncResp->asyncResp->res);
1004 return;
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001005 }
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001006
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001007 // Loop through returned object paths
1008 for (const auto& objDictEntry : resp)
1009 {
1010 const std::string& objPath =
1011 static_cast<const std::string&>(objDictEntry.first);
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001012
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001013 // If this object path is one of the specified inventory
1014 // items
1015 InventoryItem* inventoryItem =
1016 findInventoryItem(inventoryItems, objPath);
1017 if (inventoryItem != nullptr)
1018 {
1019 // Store inventory data in InventoryItem
1020 storeInventoryItemData(*inventoryItem,
1021 objDictEntry.second);
1022 }
1023 }
1024
1025 // Recurse to get inventory item data from next connection
1026 getInventoryItemsData(sensorsAsyncResp, inventoryItems,
1027 invConnections, std::move(callback),
1028 invConnectionsIndex + 1);
1029
1030 BMCWEB_LOG_DEBUG("getInventoryItemsData respHandler exit");
1031 });
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001032 }
1033
Ed Tanous62598e32023-07-17 17:06:25 -07001034 BMCWEB_LOG_DEBUG("getInventoryItemsData exit");
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001035}
1036
1037/**
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001038 * @brief Gets connections that provide D-Bus data for inventory items.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001039 *
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001040 * Gets the D-Bus connections (services) that provide data for the inventory
1041 * items that are associated with sensors.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001042 *
1043 * Finds the connections asynchronously. Invokes callback when information has
1044 * been obtained.
1045 *
1046 * The callback must have the following signature:
1047 * @code
Nan Zhoufe04d492022-06-22 17:10:41 +00001048 * callback(std::shared_ptr<std::set<std::string>> invConnections)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001049 * @endcode
1050 *
1051 * @param sensorsAsyncResp Pointer to object holding response data.
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001052 * @param inventoryItems D-Bus inventory items associated with sensors.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001053 * @param callback Callback to invoke when connections have been obtained.
1054 */
1055template <typename Callback>
1056static void getInventoryItemsConnections(
Ed Tanousb5a76932020-09-29 16:16:58 -07001057 const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
1058 const std::shared_ptr<std::vector<InventoryItem>>& inventoryItems,
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001059 Callback&& callback)
1060{
Ed Tanous62598e32023-07-17 17:06:25 -07001061 BMCWEB_LOG_DEBUG("getInventoryItemsConnections enter");
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001062
1063 const std::string path = "/xyz/openbmc_project/inventory";
George Liue99073f2022-12-09 11:06:16 +08001064 constexpr std::array<std::string_view, 4> interfaces = {
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001065 "xyz.openbmc_project.Inventory.Item",
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001066 "xyz.openbmc_project.Inventory.Item.PowerSupply",
1067 "xyz.openbmc_project.Inventory.Decorator.Asset",
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001068 "xyz.openbmc_project.State.Decorator.OperationalStatus"};
1069
George Liue99073f2022-12-09 11:06:16 +08001070 // Make call to ObjectMapper to find all inventory items
1071 dbus::utility::getSubTree(
1072 path, 0, interfaces,
Ed Tanous8cb2c022024-03-27 16:31:46 -07001073 [callback = std::forward<Callback>(callback), sensorsAsyncResp,
Ed Tanous002d39b2022-05-31 08:59:27 -07001074 inventoryItems](
George Liue99073f2022-12-09 11:06:16 +08001075 const boost::system::error_code& ec,
Ed Tanous002d39b2022-05-31 08:59:27 -07001076 const dbus::utility::MapperGetSubTreeResponse& subtree) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001077 // Response handler for parsing output from GetSubTree
1078 BMCWEB_LOG_DEBUG("getInventoryItemsConnections respHandler enter");
1079 if (ec)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001080 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001081 messages::internalError(sensorsAsyncResp->asyncResp->res);
1082 BMCWEB_LOG_ERROR(
1083 "getInventoryItemsConnections respHandler DBus error {}",
1084 ec);
1085 return;
1086 }
1087
1088 // Make unique list of connections for desired inventory items
1089 std::shared_ptr<std::set<std::string>> invConnections =
1090 std::make_shared<std::set<std::string>>();
1091
1092 // Loop through objects from GetSubTree
1093 for (const std::pair<std::string,
1094 std::vector<std::pair<
1095 std::string, std::vector<std::string>>>>&
1096 object : subtree)
1097 {
1098 // Check if object path is one of the specified inventory items
1099 const std::string& objPath = object.first;
1100 if (findInventoryItem(inventoryItems, objPath) != nullptr)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001101 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001102 // Store all connections to inventory item
1103 for (const std::pair<std::string, std::vector<std::string>>&
1104 objData : object.second)
1105 {
1106 const std::string& invConnection = objData.first;
1107 invConnections->insert(invConnection);
1108 }
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001109 }
1110 }
Anthony Wilsond5005492019-07-31 16:34:17 -05001111
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001112 callback(invConnections);
1113 BMCWEB_LOG_DEBUG("getInventoryItemsConnections respHandler exit");
1114 });
Ed Tanous62598e32023-07-17 17:06:25 -07001115 BMCWEB_LOG_DEBUG("getInventoryItemsConnections exit");
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001116}
1117
1118/**
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001119 * @brief Gets associations from sensors to inventory items.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001120 *
1121 * Looks for ObjectMapper associations from the specified sensors to related
Anthony Wilsond5005492019-07-31 16:34:17 -05001122 * inventory items. Then finds the associations from those inventory items to
1123 * their LEDs, if any.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001124 *
1125 * Finds the inventory items asynchronously. Invokes callback when information
1126 * has been obtained.
1127 *
1128 * The callback must have the following signature:
1129 * @code
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001130 * callback(std::shared_ptr<std::vector<InventoryItem>> inventoryItems)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001131 * @endcode
1132 *
1133 * @param sensorsAsyncResp Pointer to object holding response data.
1134 * @param sensorNames All sensors within the current chassis.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001135 * implements ObjectManager.
1136 * @param callback Callback to invoke when inventory items have been obtained.
1137 */
1138template <typename Callback>
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001139static void getInventoryItemAssociations(
Ed Tanousb5a76932020-09-29 16:16:58 -07001140 const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
Nan Zhoufe04d492022-06-22 17:10:41 +00001141 const std::shared_ptr<std::set<std::string>>& sensorNames,
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001142 Callback&& callback)
1143{
Ed Tanous62598e32023-07-17 17:06:25 -07001144 BMCWEB_LOG_DEBUG("getInventoryItemAssociations enter");
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001145
George Liu5eb468d2023-06-20 17:03:24 +08001146 // Call GetManagedObjects on the ObjectMapper to get all associations
1147 sdbusplus::message::object_path path("/");
1148 dbus::utility::getManagedObjects(
1149 "xyz.openbmc_project.ObjectMapper", path,
Ed Tanous8cb2c022024-03-27 16:31:46 -07001150 [callback = std::forward<Callback>(callback), sensorsAsyncResp,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08001151 sensorNames](const boost::system::error_code& ec,
Ed Tanous02cad962022-06-30 16:50:15 -07001152 const dbus::utility::ManagedObjectType& resp) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001153 BMCWEB_LOG_DEBUG("getInventoryItemAssociations respHandler enter");
1154 if (ec)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001155 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001156 BMCWEB_LOG_ERROR(
1157 "getInventoryItemAssociations respHandler DBus error {}",
1158 ec);
1159 messages::internalError(sensorsAsyncResp->asyncResp->res);
1160 return;
1161 }
1162
1163 // Create vector to hold list of inventory items
1164 std::shared_ptr<std::vector<InventoryItem>> inventoryItems =
1165 std::make_shared<std::vector<InventoryItem>>();
1166
1167 // Loop through returned object paths
1168 std::string sensorAssocPath;
1169 sensorAssocPath.reserve(128); // avoid memory allocations
1170 for (const auto& objDictEntry : resp)
1171 {
1172 const std::string& objPath =
1173 static_cast<const std::string&>(objDictEntry.first);
1174
1175 // If path is inventory association for one of the specified
1176 // sensors
1177 for (const std::string& sensorName : *sensorNames)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001178 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001179 sensorAssocPath = sensorName;
1180 sensorAssocPath += "/inventory";
1181 if (objPath == sensorAssocPath)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001182 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001183 // Get Association interface for object path
1184 for (const auto& [interface, values] :
1185 objDictEntry.second)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001186 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001187 if (interface == "xyz.openbmc_project.Association")
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001188 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001189 for (const auto& [valueName, value] : values)
Ed Tanous711ac7a2021-12-20 09:34:41 -08001190 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001191 if (valueName == "endpoints")
Ed Tanous711ac7a2021-12-20 09:34:41 -08001192 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001193 const std::vector<std::string>*
1194 endpoints = std::get_if<
1195 std::vector<std::string>>(
1196 &value);
1197 if ((endpoints != nullptr) &&
1198 !endpoints->empty())
1199 {
1200 // Add inventory item to vector
1201 const std::string& invItemPath =
1202 endpoints->front();
1203 addInventoryItem(inventoryItems,
1204 invItemPath,
1205 sensorName);
1206 }
Ed Tanous711ac7a2021-12-20 09:34:41 -08001207 }
1208 }
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001209 }
1210 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001211 break;
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001212 }
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001213 }
1214 }
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001215
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001216 // Now loop through the returned object paths again, this time to
1217 // find the leds associated with the inventory items we just found
1218 std::string inventoryAssocPath;
1219 inventoryAssocPath.reserve(128); // avoid memory allocations
1220 for (const auto& objDictEntry : resp)
Anthony Wilsond5005492019-07-31 16:34:17 -05001221 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001222 const std::string& objPath =
1223 static_cast<const std::string&>(objDictEntry.first);
1224
1225 for (InventoryItem& inventoryItem : *inventoryItems)
Anthony Wilsond5005492019-07-31 16:34:17 -05001226 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001227 inventoryAssocPath = inventoryItem.objectPath;
1228 inventoryAssocPath += "/leds";
1229 if (objPath == inventoryAssocPath)
Anthony Wilsond5005492019-07-31 16:34:17 -05001230 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001231 for (const auto& [interface, values] :
1232 objDictEntry.second)
Anthony Wilsond5005492019-07-31 16:34:17 -05001233 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001234 if (interface == "xyz.openbmc_project.Association")
Anthony Wilsond5005492019-07-31 16:34:17 -05001235 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001236 for (const auto& [valueName, value] : values)
Ed Tanous711ac7a2021-12-20 09:34:41 -08001237 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001238 if (valueName == "endpoints")
Ed Tanous711ac7a2021-12-20 09:34:41 -08001239 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001240 const std::vector<std::string>*
1241 endpoints = std::get_if<
1242 std::vector<std::string>>(
1243 &value);
1244 if ((endpoints != nullptr) &&
1245 !endpoints->empty())
1246 {
1247 // Add inventory item to vector
1248 // Store LED path in inventory item
1249 const std::string& ledPath =
1250 endpoints->front();
1251 inventoryItem.ledObjectPath =
1252 ledPath;
1253 }
Ed Tanous711ac7a2021-12-20 09:34:41 -08001254 }
1255 }
Anthony Wilsond5005492019-07-31 16:34:17 -05001256 }
1257 }
Ed Tanous711ac7a2021-12-20 09:34:41 -08001258
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001259 break;
1260 }
Anthony Wilsond5005492019-07-31 16:34:17 -05001261 }
1262 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001263 callback(inventoryItems);
1264 BMCWEB_LOG_DEBUG("getInventoryItemAssociations respHandler exit");
1265 });
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001266
Ed Tanous62598e32023-07-17 17:06:25 -07001267 BMCWEB_LOG_DEBUG("getInventoryItemAssociations exit");
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001268}
1269
1270/**
Anthony Wilsond5005492019-07-31 16:34:17 -05001271 * @brief Gets D-Bus data for inventory item leds associated with sensors.
1272 *
1273 * Uses the specified connections (services) to obtain D-Bus data for inventory
1274 * item leds associated with sensors. Stores the resulting data in the
1275 * inventoryItems vector.
1276 *
1277 * This data is later used to provide sensor property values in the JSON
1278 * response.
1279 *
1280 * Finds the inventory item led data asynchronously. Invokes callback when data
1281 * has been obtained.
1282 *
1283 * The callback must have the following signature:
1284 * @code
Gunnar Mills42cbe532019-08-15 15:26:54 -05001285 * callback()
Anthony Wilsond5005492019-07-31 16:34:17 -05001286 * @endcode
1287 *
1288 * This function is called recursively, obtaining data asynchronously from one
1289 * connection in each call. This ensures the callback is not invoked until the
1290 * last asynchronous function has completed.
1291 *
1292 * @param sensorsAsyncResp Pointer to object holding response data.
1293 * @param inventoryItems D-Bus inventory items associated with sensors.
1294 * @param ledConnections Connections that provide data for the inventory leds.
1295 * @param callback Callback to invoke when inventory data has been obtained.
1296 * @param ledConnectionsIndex Current index in ledConnections. Only specified
1297 * in recursive calls to this function.
1298 */
1299template <typename Callback>
1300void getInventoryLedData(
1301 std::shared_ptr<SensorsAsyncResp> sensorsAsyncResp,
1302 std::shared_ptr<std::vector<InventoryItem>> inventoryItems,
Nan Zhoufe04d492022-06-22 17:10:41 +00001303 std::shared_ptr<std::map<std::string, std::string>> ledConnections,
Anthony Wilsond5005492019-07-31 16:34:17 -05001304 Callback&& callback, size_t ledConnectionsIndex = 0)
1305{
Ed Tanous62598e32023-07-17 17:06:25 -07001306 BMCWEB_LOG_DEBUG("getInventoryLedData enter");
Anthony Wilsond5005492019-07-31 16:34:17 -05001307
1308 // If no more connections left, call callback
1309 if (ledConnectionsIndex >= ledConnections->size())
1310 {
Gunnar Mills42cbe532019-08-15 15:26:54 -05001311 callback();
Ed Tanous62598e32023-07-17 17:06:25 -07001312 BMCWEB_LOG_DEBUG("getInventoryLedData exit");
Anthony Wilsond5005492019-07-31 16:34:17 -05001313 return;
1314 }
1315
1316 // Get inventory item data from current connection
Nan Zhoufe04d492022-06-22 17:10:41 +00001317 auto it = ledConnections->begin();
1318 std::advance(it, ledConnectionsIndex);
Anthony Wilsond5005492019-07-31 16:34:17 -05001319 if (it != ledConnections->end())
1320 {
1321 const std::string& ledPath = (*it).first;
1322 const std::string& ledConnection = (*it).second;
1323 // Response handler for Get State property
Jonathan Doman1e1e5982021-06-11 09:36:17 -07001324 auto respHandler =
1325 [sensorsAsyncResp, inventoryItems, ledConnections, ledPath,
Ed Tanous8cb2c022024-03-27 16:31:46 -07001326 callback = std::forward<Callback>(callback), ledConnectionsIndex](
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08001327 const boost::system::error_code& ec, const std::string& state) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001328 BMCWEB_LOG_DEBUG("getInventoryLedData respHandler enter");
1329 if (ec)
1330 {
1331 BMCWEB_LOG_ERROR(
1332 "getInventoryLedData respHandler DBus error {}", ec);
1333 messages::internalError(sensorsAsyncResp->asyncResp->res);
1334 return;
1335 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001336
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001337 BMCWEB_LOG_DEBUG("Led state: {}", state);
1338 // Find inventory item with this LED object path
1339 InventoryItem* inventoryItem =
1340 findInventoryItemForLed(*inventoryItems, ledPath);
1341 if (inventoryItem != nullptr)
Jonathan Doman1e1e5982021-06-11 09:36:17 -07001342 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001343 // Store LED state in InventoryItem
1344 if (state.ends_with("On"))
1345 {
Janet Adkinsc9563602024-08-28 11:37:46 -05001346 inventoryItem->ledState = sensor_utils::LedState::ON;
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001347 }
1348 else if (state.ends_with("Blink"))
1349 {
Janet Adkinsc9563602024-08-28 11:37:46 -05001350 inventoryItem->ledState = sensor_utils::LedState::BLINK;
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001351 }
1352 else if (state.ends_with("Off"))
1353 {
Janet Adkinsc9563602024-08-28 11:37:46 -05001354 inventoryItem->ledState = sensor_utils::LedState::OFF;
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001355 }
1356 else
1357 {
Janet Adkinsc9563602024-08-28 11:37:46 -05001358 inventoryItem->ledState =
1359 sensor_utils::LedState::UNKNOWN;
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001360 }
Jonathan Doman1e1e5982021-06-11 09:36:17 -07001361 }
Anthony Wilsond5005492019-07-31 16:34:17 -05001362
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001363 // Recurse to get LED data from next connection
1364 getInventoryLedData(sensorsAsyncResp, inventoryItems,
1365 ledConnections, std::move(callback),
1366 ledConnectionsIndex + 1);
Anthony Wilsond5005492019-07-31 16:34:17 -05001367
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001368 BMCWEB_LOG_DEBUG("getInventoryLedData respHandler exit");
1369 };
Anthony Wilsond5005492019-07-31 16:34:17 -05001370
1371 // Get the State property for the current LED
Jonathan Doman1e1e5982021-06-11 09:36:17 -07001372 sdbusplus::asio::getProperty<std::string>(
1373 *crow::connections::systemBus, ledConnection, ledPath,
1374 "xyz.openbmc_project.Led.Physical", "State",
1375 std::move(respHandler));
Anthony Wilsond5005492019-07-31 16:34:17 -05001376 }
1377
Ed Tanous62598e32023-07-17 17:06:25 -07001378 BMCWEB_LOG_DEBUG("getInventoryLedData exit");
Anthony Wilsond5005492019-07-31 16:34:17 -05001379}
1380
1381/**
1382 * @brief Gets LED data for LEDs associated with given inventory items.
1383 *
1384 * Gets the D-Bus connections (services) that provide LED data for the LEDs
1385 * associated with the specified inventory items. Then gets the LED data from
1386 * each connection and stores it in the inventory item.
1387 *
1388 * This data is later used to provide sensor property values in the JSON
1389 * response.
1390 *
1391 * Finds the LED data asynchronously. Invokes callback when information has
1392 * been obtained.
1393 *
1394 * The callback must have the following signature:
1395 * @code
Gunnar Mills42cbe532019-08-15 15:26:54 -05001396 * callback()
Anthony Wilsond5005492019-07-31 16:34:17 -05001397 * @endcode
1398 *
1399 * @param sensorsAsyncResp Pointer to object holding response data.
1400 * @param inventoryItems D-Bus inventory items associated with sensors.
1401 * @param callback Callback to invoke when inventory items have been obtained.
1402 */
1403template <typename Callback>
1404void getInventoryLeds(
1405 std::shared_ptr<SensorsAsyncResp> sensorsAsyncResp,
1406 std::shared_ptr<std::vector<InventoryItem>> inventoryItems,
1407 Callback&& callback)
1408{
Ed Tanous62598e32023-07-17 17:06:25 -07001409 BMCWEB_LOG_DEBUG("getInventoryLeds enter");
Anthony Wilsond5005492019-07-31 16:34:17 -05001410
1411 const std::string path = "/xyz/openbmc_project";
George Liue99073f2022-12-09 11:06:16 +08001412 constexpr std::array<std::string_view, 1> interfaces = {
Anthony Wilsond5005492019-07-31 16:34:17 -05001413 "xyz.openbmc_project.Led.Physical"};
1414
George Liue99073f2022-12-09 11:06:16 +08001415 // Make call to ObjectMapper to find all inventory items
1416 dbus::utility::getSubTree(
1417 path, 0, interfaces,
Ed Tanous8cb2c022024-03-27 16:31:46 -07001418 [callback = std::forward<Callback>(callback), sensorsAsyncResp,
Ed Tanous002d39b2022-05-31 08:59:27 -07001419 inventoryItems](
George Liue99073f2022-12-09 11:06:16 +08001420 const boost::system::error_code& ec,
Ed Tanous002d39b2022-05-31 08:59:27 -07001421 const dbus::utility::MapperGetSubTreeResponse& subtree) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001422 // Response handler for parsing output from GetSubTree
1423 BMCWEB_LOG_DEBUG("getInventoryLeds respHandler enter");
1424 if (ec)
Anthony Wilsond5005492019-07-31 16:34:17 -05001425 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001426 messages::internalError(sensorsAsyncResp->asyncResp->res);
1427 BMCWEB_LOG_ERROR("getInventoryLeds respHandler DBus error {}",
1428 ec);
1429 return;
Anthony Wilsond5005492019-07-31 16:34:17 -05001430 }
Anthony Wilsond5005492019-07-31 16:34:17 -05001431
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001432 // Build map of LED object paths to connections
1433 std::shared_ptr<std::map<std::string, std::string>> ledConnections =
1434 std::make_shared<std::map<std::string, std::string>>();
1435
1436 // Loop through objects from GetSubTree
1437 for (const std::pair<std::string,
1438 std::vector<std::pair<
1439 std::string, std::vector<std::string>>>>&
1440 object : subtree)
1441 {
1442 // Check if object path is LED for one of the specified
1443 // inventory items
1444 const std::string& ledPath = object.first;
1445 if (findInventoryItemForLed(*inventoryItems, ledPath) !=
1446 nullptr)
1447 {
1448 // Add mapping from ledPath to connection
1449 const std::string& connection =
1450 object.second.begin()->first;
1451 (*ledConnections)[ledPath] = connection;
1452 BMCWEB_LOG_DEBUG("Added mapping {} -> {}", ledPath,
1453 connection);
1454 }
1455 }
1456
1457 getInventoryLedData(sensorsAsyncResp, inventoryItems,
1458 ledConnections, std::move(callback));
1459 BMCWEB_LOG_DEBUG("getInventoryLeds respHandler exit");
1460 });
Ed Tanous62598e32023-07-17 17:06:25 -07001461 BMCWEB_LOG_DEBUG("getInventoryLeds exit");
Anthony Wilsond5005492019-07-31 16:34:17 -05001462}
1463
1464/**
Gunnar Mills42cbe532019-08-15 15:26:54 -05001465 * @brief Gets D-Bus data for Power Supply Attributes such as EfficiencyPercent
1466 *
1467 * Uses the specified connections (services) (currently assumes just one) to
1468 * obtain D-Bus data for Power Supply Attributes. Stores the resulting data in
1469 * the inventoryItems vector. Only stores data in Power Supply inventoryItems.
1470 *
1471 * This data is later used to provide sensor property values in the JSON
1472 * response.
1473 *
1474 * Finds the Power Supply Attributes data asynchronously. Invokes callback
1475 * when data has been obtained.
1476 *
1477 * The callback must have the following signature:
1478 * @code
1479 * callback(std::shared_ptr<std::vector<InventoryItem>> inventoryItems)
1480 * @endcode
1481 *
1482 * @param sensorsAsyncResp Pointer to object holding response data.
1483 * @param inventoryItems D-Bus inventory items associated with sensors.
1484 * @param psAttributesConnections Connections that provide data for the Power
1485 * Supply Attributes
1486 * @param callback Callback to invoke when data has been obtained.
1487 */
1488template <typename Callback>
1489void getPowerSupplyAttributesData(
Ed Tanousb5a76932020-09-29 16:16:58 -07001490 const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
Gunnar Mills42cbe532019-08-15 15:26:54 -05001491 std::shared_ptr<std::vector<InventoryItem>> inventoryItems,
Nan Zhoufe04d492022-06-22 17:10:41 +00001492 const std::map<std::string, std::string>& psAttributesConnections,
Gunnar Mills42cbe532019-08-15 15:26:54 -05001493 Callback&& callback)
1494{
Ed Tanous62598e32023-07-17 17:06:25 -07001495 BMCWEB_LOG_DEBUG("getPowerSupplyAttributesData enter");
Gunnar Mills42cbe532019-08-15 15:26:54 -05001496
1497 if (psAttributesConnections.empty())
1498 {
Ed Tanous62598e32023-07-17 17:06:25 -07001499 BMCWEB_LOG_DEBUG("Can't find PowerSupplyAttributes, no connections!");
Gunnar Mills42cbe532019-08-15 15:26:54 -05001500 callback(inventoryItems);
1501 return;
1502 }
1503
1504 // Assuming just one connection (service) for now
Nan Zhoufe04d492022-06-22 17:10:41 +00001505 auto it = psAttributesConnections.begin();
Gunnar Mills42cbe532019-08-15 15:26:54 -05001506
1507 const std::string& psAttributesPath = (*it).first;
1508 const std::string& psAttributesConnection = (*it).second;
1509
1510 // Response handler for Get DeratingFactor property
Patrick Williams5a39f772023-10-20 11:20:21 -05001511 auto respHandler = [sensorsAsyncResp, inventoryItems,
Ed Tanous8cb2c022024-03-27 16:31:46 -07001512 callback = std::forward<Callback>(callback)](
Patrick Williams5a39f772023-10-20 11:20:21 -05001513 const boost::system::error_code& ec,
1514 const uint32_t value) {
Ed Tanous62598e32023-07-17 17:06:25 -07001515 BMCWEB_LOG_DEBUG("getPowerSupplyAttributesData respHandler enter");
Gunnar Mills42cbe532019-08-15 15:26:54 -05001516 if (ec)
1517 {
Ed Tanous62598e32023-07-17 17:06:25 -07001518 BMCWEB_LOG_ERROR(
1519 "getPowerSupplyAttributesData respHandler DBus error {}", ec);
zhanghch058d1b46d2021-04-01 11:18:24 +08001520 messages::internalError(sensorsAsyncResp->asyncResp->res);
Gunnar Mills42cbe532019-08-15 15:26:54 -05001521 return;
1522 }
1523
Ed Tanous62598e32023-07-17 17:06:25 -07001524 BMCWEB_LOG_DEBUG("PS EfficiencyPercent value: {}", value);
Jonathan Doman1e1e5982021-06-11 09:36:17 -07001525 // Store value in Power Supply Inventory Items
1526 for (InventoryItem& inventoryItem : *inventoryItems)
Gunnar Mills42cbe532019-08-15 15:26:54 -05001527 {
Ed Tanous55f79e62022-01-25 11:26:16 -08001528 if (inventoryItem.isPowerSupply)
Gunnar Mills42cbe532019-08-15 15:26:54 -05001529 {
Jonathan Doman1e1e5982021-06-11 09:36:17 -07001530 inventoryItem.powerSupplyEfficiencyPercent =
1531 static_cast<int>(value);
Gunnar Mills42cbe532019-08-15 15:26:54 -05001532 }
1533 }
Gunnar Mills42cbe532019-08-15 15:26:54 -05001534
Ed Tanous62598e32023-07-17 17:06:25 -07001535 BMCWEB_LOG_DEBUG("getPowerSupplyAttributesData respHandler exit");
Gunnar Mills42cbe532019-08-15 15:26:54 -05001536 callback(inventoryItems);
1537 };
1538
1539 // Get the DeratingFactor property for the PowerSupplyAttributes
1540 // Currently only property on the interface/only one we care about
Jonathan Doman1e1e5982021-06-11 09:36:17 -07001541 sdbusplus::asio::getProperty<uint32_t>(
1542 *crow::connections::systemBus, psAttributesConnection, psAttributesPath,
1543 "xyz.openbmc_project.Control.PowerSupplyAttributes", "DeratingFactor",
1544 std::move(respHandler));
Gunnar Mills42cbe532019-08-15 15:26:54 -05001545
Ed Tanous62598e32023-07-17 17:06:25 -07001546 BMCWEB_LOG_DEBUG("getPowerSupplyAttributesData exit");
Gunnar Mills42cbe532019-08-15 15:26:54 -05001547}
1548
1549/**
1550 * @brief Gets the Power Supply Attributes such as EfficiencyPercent
1551 *
1552 * Gets the D-Bus connection (service) that provides Power Supply Attributes
1553 * data. Then gets the Power Supply Attributes data from the connection
1554 * (currently just assumes 1 connection) and stores the data in the inventory
1555 * item.
1556 *
1557 * This data is later used to provide sensor property values in the JSON
1558 * response. DeratingFactor on D-Bus is mapped to EfficiencyPercent on Redfish.
1559 *
1560 * Finds the Power Supply Attributes data asynchronously. Invokes callback
1561 * when information has been obtained.
1562 *
1563 * The callback must have the following signature:
1564 * @code
1565 * callback(std::shared_ptr<std::vector<InventoryItem>> inventoryItems)
1566 * @endcode
1567 *
1568 * @param sensorsAsyncResp Pointer to object holding response data.
1569 * @param inventoryItems D-Bus inventory items associated with sensors.
1570 * @param callback Callback to invoke when data has been obtained.
1571 */
1572template <typename Callback>
1573void getPowerSupplyAttributes(
1574 std::shared_ptr<SensorsAsyncResp> sensorsAsyncResp,
1575 std::shared_ptr<std::vector<InventoryItem>> inventoryItems,
1576 Callback&& callback)
1577{
Ed Tanous62598e32023-07-17 17:06:25 -07001578 BMCWEB_LOG_DEBUG("getPowerSupplyAttributes enter");
Gunnar Mills42cbe532019-08-15 15:26:54 -05001579
1580 // Only need the power supply attributes when the Power Schema
Janet Adkins0c728b42024-08-29 11:09:10 -05001581 if (sensorsAsyncResp->chassisSubNode != sensors::powerNodeStr)
Gunnar Mills42cbe532019-08-15 15:26:54 -05001582 {
Ed Tanous62598e32023-07-17 17:06:25 -07001583 BMCWEB_LOG_DEBUG("getPowerSupplyAttributes exit since not Power");
Gunnar Mills42cbe532019-08-15 15:26:54 -05001584 callback(inventoryItems);
1585 return;
1586 }
1587
George Liue99073f2022-12-09 11:06:16 +08001588 constexpr std::array<std::string_view, 1> interfaces = {
Gunnar Mills42cbe532019-08-15 15:26:54 -05001589 "xyz.openbmc_project.Control.PowerSupplyAttributes"};
1590
George Liue99073f2022-12-09 11:06:16 +08001591 // Make call to ObjectMapper to find the PowerSupplyAttributes service
1592 dbus::utility::getSubTree(
1593 "/xyz/openbmc_project", 0, interfaces,
Ed Tanous8cb2c022024-03-27 16:31:46 -07001594 [callback = std::forward<Callback>(callback), sensorsAsyncResp,
Ed Tanousb9d36b42022-02-26 21:42:46 -08001595 inventoryItems](
George Liue99073f2022-12-09 11:06:16 +08001596 const boost::system::error_code& ec,
Ed Tanousb9d36b42022-02-26 21:42:46 -08001597 const dbus::utility::MapperGetSubTreeResponse& subtree) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001598 // Response handler for parsing output from GetSubTree
1599 BMCWEB_LOG_DEBUG("getPowerSupplyAttributes respHandler enter");
1600 if (ec)
1601 {
1602 messages::internalError(sensorsAsyncResp->asyncResp->res);
1603 BMCWEB_LOG_ERROR(
1604 "getPowerSupplyAttributes respHandler DBus error {}", ec);
1605 return;
1606 }
1607 if (subtree.empty())
1608 {
1609 BMCWEB_LOG_DEBUG("Can't find Power Supply Attributes!");
1610 callback(inventoryItems);
1611 return;
1612 }
Gunnar Mills42cbe532019-08-15 15:26:54 -05001613
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001614 // Currently we only support 1 power supply attribute, use this for
1615 // all the power supplies. Build map of object path to connection.
1616 // Assume just 1 connection and 1 path for now.
1617 std::map<std::string, std::string> psAttributesConnections;
Gunnar Mills42cbe532019-08-15 15:26:54 -05001618
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001619 if (subtree[0].first.empty() || subtree[0].second.empty())
1620 {
1621 BMCWEB_LOG_DEBUG("Power Supply Attributes mapper error!");
1622 callback(inventoryItems);
1623 return;
1624 }
Gunnar Mills42cbe532019-08-15 15:26:54 -05001625
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001626 const std::string& psAttributesPath = subtree[0].first;
1627 const std::string& connection = subtree[0].second.begin()->first;
Gunnar Mills42cbe532019-08-15 15:26:54 -05001628
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001629 if (connection.empty())
1630 {
1631 BMCWEB_LOG_DEBUG("Power Supply Attributes mapper error!");
1632 callback(inventoryItems);
1633 return;
1634 }
Gunnar Mills42cbe532019-08-15 15:26:54 -05001635
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001636 psAttributesConnections[psAttributesPath] = connection;
1637 BMCWEB_LOG_DEBUG("Added mapping {} -> {}", psAttributesPath,
1638 connection);
Gunnar Mills42cbe532019-08-15 15:26:54 -05001639
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001640 getPowerSupplyAttributesData(sensorsAsyncResp, inventoryItems,
1641 psAttributesConnections,
1642 std::move(callback));
1643 BMCWEB_LOG_DEBUG("getPowerSupplyAttributes respHandler exit");
1644 });
Ed Tanous62598e32023-07-17 17:06:25 -07001645 BMCWEB_LOG_DEBUG("getPowerSupplyAttributes exit");
Gunnar Mills42cbe532019-08-15 15:26:54 -05001646}
1647
1648/**
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001649 * @brief Gets inventory items associated with sensors.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001650 *
1651 * Finds the inventory items that are associated with the specified sensors.
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001652 * Then gets D-Bus data for the inventory items, such as presence and VPD.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001653 *
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001654 * This data is later used to provide sensor property values in the JSON
1655 * response.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001656 *
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001657 * Finds the inventory items asynchronously. Invokes callback when the
1658 * inventory items have been obtained.
1659 *
1660 * The callback must have the following signature:
1661 * @code
1662 * callback(std::shared_ptr<std::vector<InventoryItem>> inventoryItems)
1663 * @endcode
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001664 *
1665 * @param sensorsAsyncResp Pointer to object holding response data.
1666 * @param sensorNames All sensors within the current chassis.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001667 * implements ObjectManager.
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001668 * @param callback Callback to invoke when inventory items have been obtained.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001669 */
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001670template <typename Callback>
Ed Tanousd0090732022-10-04 17:22:56 -07001671static void
1672 getInventoryItems(std::shared_ptr<SensorsAsyncResp> sensorsAsyncResp,
1673 const std::shared_ptr<std::set<std::string>> sensorNames,
1674 Callback&& callback)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001675{
Ed Tanous62598e32023-07-17 17:06:25 -07001676 BMCWEB_LOG_DEBUG("getInventoryItems enter");
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001677 auto getInventoryItemAssociationsCb =
Ed Tanous8cb2c022024-03-27 16:31:46 -07001678 [sensorsAsyncResp, callback = std::forward<Callback>(callback)](
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001679 std::shared_ptr<std::vector<InventoryItem>> inventoryItems) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001680 BMCWEB_LOG_DEBUG("getInventoryItemAssociationsCb enter");
1681 auto getInventoryItemsConnectionsCb =
1682 [sensorsAsyncResp, inventoryItems,
1683 callback = std::forward<const Callback>(callback)](
1684 std::shared_ptr<std::set<std::string>> invConnections) {
1685 BMCWEB_LOG_DEBUG("getInventoryItemsConnectionsCb enter");
1686 auto getInventoryItemsDataCb =
1687 [sensorsAsyncResp, inventoryItems,
1688 callback{std::move(callback)}]() {
1689 BMCWEB_LOG_DEBUG("getInventoryItemsDataCb enter");
Gunnar Mills42cbe532019-08-15 15:26:54 -05001690
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001691 auto getInventoryLedsCb =
1692 [sensorsAsyncResp, inventoryItems,
1693 callback{std::move(callback)}]() {
1694 BMCWEB_LOG_DEBUG(
1695 "getInventoryLedsCb enter");
1696 // Find Power Supply Attributes and get the
1697 // data
1698 getPowerSupplyAttributes(
1699 sensorsAsyncResp, inventoryItems,
1700 std::move(callback));
1701 BMCWEB_LOG_DEBUG("getInventoryLedsCb exit");
1702 };
1703
1704 // Find led connections and get the data
1705 getInventoryLeds(sensorsAsyncResp, inventoryItems,
1706 std::move(getInventoryLedsCb));
1707 BMCWEB_LOG_DEBUG("getInventoryItemsDataCb exit");
1708 };
1709
1710 // Get inventory item data from connections
1711 getInventoryItemsData(sensorsAsyncResp, inventoryItems,
1712 invConnections,
1713 std::move(getInventoryItemsDataCb));
1714 BMCWEB_LOG_DEBUG("getInventoryItemsConnectionsCb exit");
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001715 };
1716
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001717 // Get connections that provide inventory item data
1718 getInventoryItemsConnections(
1719 sensorsAsyncResp, inventoryItems,
1720 std::move(getInventoryItemsConnectionsCb));
1721 BMCWEB_LOG_DEBUG("getInventoryItemAssociationsCb exit");
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001722 };
1723
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001724 // Get associations from sensors to inventory items
Ed Tanousd0090732022-10-04 17:22:56 -07001725 getInventoryItemAssociations(sensorsAsyncResp, sensorNames,
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001726 std::move(getInventoryItemAssociationsCb));
Ed Tanous62598e32023-07-17 17:06:25 -07001727 BMCWEB_LOG_DEBUG("getInventoryItems exit");
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001728}
1729
1730/**
1731 * @brief Returns JSON PowerSupply object for the specified inventory item.
1732 *
1733 * Searches for a JSON PowerSupply object that matches the specified inventory
1734 * item. If one is not found, a new PowerSupply object is added to the JSON
1735 * array.
1736 *
1737 * Multiple sensors are often associated with one power supply inventory item.
1738 * As a result, multiple sensor values are stored in one JSON PowerSupply
1739 * object.
1740 *
1741 * @param powerSupplyArray JSON array containing Redfish PowerSupply objects.
1742 * @param inventoryItem Inventory item for the power supply.
1743 * @param chassisId Chassis that contains the power supply.
1744 * @return JSON PowerSupply object for the specified inventory item.
1745 */
Ed Tanous23a21a12020-07-25 04:45:05 +00001746inline nlohmann::json& getPowerSupply(nlohmann::json& powerSupplyArray,
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001747 const InventoryItem& inventoryItem,
1748 const std::string& chassisId)
1749{
Ed Tanous18f8f602023-07-18 10:07:23 -07001750 std::string nameS;
Alexander Hansen6f4bd292024-03-08 17:04:54 +01001751 nameS.resize(inventoryItem.name.size());
Ed Tanous18f8f602023-07-18 10:07:23 -07001752 std::ranges::replace_copy(inventoryItem.name, nameS.begin(), '_', ' ');
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001753 // Check if matching PowerSupply object already exists in JSON array
1754 for (nlohmann::json& powerSupply : powerSupplyArray)
1755 {
Ed Tanous18f8f602023-07-18 10:07:23 -07001756 nlohmann::json::iterator nameIt = powerSupply.find("Name");
1757 if (nameIt == powerSupply.end())
1758 {
1759 continue;
1760 }
1761 const std::string* name = nameIt->get_ptr<std::string*>();
1762 if (name == nullptr)
1763 {
1764 continue;
1765 }
1766 if (nameS == *name)
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001767 {
1768 return powerSupply;
1769 }
1770 }
1771
1772 // Add new PowerSupply object to JSON array
1773 powerSupplyArray.push_back({});
1774 nlohmann::json& powerSupply = powerSupplyArray.back();
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001775 boost::urls::url url =
1776 boost::urls::format("/redfish/v1/Chassis/{}/Power", chassisId);
Willy Tueddfc432022-09-26 16:46:38 +00001777 url.set_fragment(("/PowerSupplies"_json_pointer).to_string());
1778 powerSupply["@odata.id"] = std::move(url);
Ed Tanous18f8f602023-07-18 10:07:23 -07001779 std::string escaped;
Alexander Hansen6f4bd292024-03-08 17:04:54 +01001780 escaped.resize(inventoryItem.name.size());
Ed Tanous18f8f602023-07-18 10:07:23 -07001781 std::ranges::replace_copy(inventoryItem.name, escaped.begin(), '_', ' ');
1782 powerSupply["Name"] = std::move(escaped);
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001783 powerSupply["Manufacturer"] = inventoryItem.manufacturer;
1784 powerSupply["Model"] = inventoryItem.model;
1785 powerSupply["PartNumber"] = inventoryItem.partNumber;
1786 powerSupply["SerialNumber"] = inventoryItem.serialNumber;
Janet Adkinsc9563602024-08-28 11:37:46 -05001787 sensor_utils::setLedState(powerSupply, &inventoryItem);
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001788
Gunnar Mills42cbe532019-08-15 15:26:54 -05001789 if (inventoryItem.powerSupplyEfficiencyPercent >= 0)
1790 {
1791 powerSupply["EfficiencyPercent"] =
1792 inventoryItem.powerSupplyEfficiencyPercent;
1793 }
1794
Janet Adkinsc9563602024-08-28 11:37:46 -05001795 powerSupply["Status"]["State"] =
1796 sensor_utils::getState(&inventoryItem, true);
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001797 const char* health = inventoryItem.isFunctional ? "OK" : "Critical";
1798 powerSupply["Status"]["Health"] = health;
1799
1800 return powerSupply;
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001801}
1802
1803/**
Shawn McCarneyde629b62019-03-08 10:42:51 -06001804 * @brief Gets the values of the specified sensors.
1805 *
1806 * Stores the results as JSON in the SensorsAsyncResp.
1807 *
1808 * Gets the sensor values asynchronously. Stores the results later when the
1809 * information has been obtained.
1810 *
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001811 * The sensorNames set contains all requested sensors for the current chassis.
Shawn McCarneyde629b62019-03-08 10:42:51 -06001812 *
1813 * To minimize the number of DBus calls, the DBus method
1814 * org.freedesktop.DBus.ObjectManager.GetManagedObjects() is used to get the
1815 * values of all sensors provided by a connection (service).
1816 *
1817 * The connections set contains all the connections that provide sensor values.
1818 *
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001819 * The InventoryItem vector contains D-Bus inventory items associated with the
1820 * sensors. Inventory item data is needed for some Redfish sensor properties.
1821 *
Shawn McCarneyde629b62019-03-08 10:42:51 -06001822 * @param SensorsAsyncResp Pointer to object holding response data.
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001823 * @param sensorNames All requested sensors within the current chassis.
Shawn McCarneyde629b62019-03-08 10:42:51 -06001824 * @param connections Connections that provide sensor values.
Shawn McCarneyde629b62019-03-08 10:42:51 -06001825 * implements ObjectManager.
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001826 * @param inventoryItems Inventory items associated with the sensors.
Shawn McCarneyde629b62019-03-08 10:42:51 -06001827 */
Ed Tanous23a21a12020-07-25 04:45:05 +00001828inline void getSensorData(
Ed Tanous81ce6092020-12-17 16:54:55 +00001829 const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
Nan Zhoufe04d492022-06-22 17:10:41 +00001830 const std::shared_ptr<std::set<std::string>>& sensorNames,
1831 const std::set<std::string>& connections,
Ed Tanousb5a76932020-09-29 16:16:58 -07001832 const std::shared_ptr<std::vector<InventoryItem>>& inventoryItems)
Shawn McCarneyde629b62019-03-08 10:42:51 -06001833{
Ed Tanous62598e32023-07-17 17:06:25 -07001834 BMCWEB_LOG_DEBUG("getSensorData enter");
Shawn McCarneyde629b62019-03-08 10:42:51 -06001835 // Get managed objects from all services exposing sensors
1836 for (const std::string& connection : connections)
1837 {
George Liu5eb468d2023-06-20 17:03:24 +08001838 sdbusplus::message::object_path sensorPath(
1839 "/xyz/openbmc_project/sensors");
1840 dbus::utility::getManagedObjects(
1841 connection, sensorPath,
Ed Tanous002d39b2022-05-31 08:59:27 -07001842 [sensorsAsyncResp, sensorNames,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08001843 inventoryItems](const boost::system::error_code& ec,
Ed Tanous02cad962022-06-30 16:50:15 -07001844 const dbus::utility::ManagedObjectType& resp) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001845 BMCWEB_LOG_DEBUG("getManagedObjectsCb enter");
1846 if (ec)
Shawn McCarneyde629b62019-03-08 10:42:51 -06001847 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001848 BMCWEB_LOG_ERROR("getManagedObjectsCb DBUS error: {}", ec);
1849 messages::internalError(sensorsAsyncResp->asyncResp->res);
1850 return;
1851 }
Janet Adkins0c728b42024-08-29 11:09:10 -05001852 auto chassisSubNode = sensor_utils::chassisSubNodeFromString(
1853 sensorsAsyncResp->chassisSubNode);
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001854 // Go through all objects and update response with sensor data
1855 for (const auto& objDictEntry : resp)
1856 {
1857 const std::string& objPath =
1858 static_cast<const std::string&>(objDictEntry.first);
1859 BMCWEB_LOG_DEBUG("getManagedObjectsCb parsing object {}",
Ed Tanous62598e32023-07-17 17:06:25 -07001860 objPath);
Shawn McCarneyde629b62019-03-08 10:42:51 -06001861
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001862 std::vector<std::string> split;
1863 // Reserve space for
1864 // /xyz/openbmc_project/sensors/<name>/<subname>
1865 split.reserve(6);
1866 // NOLINTNEXTLINE
1867 bmcweb::split(split, objPath, '/');
1868 if (split.size() < 6)
Nan Zhou928fefb2022-03-28 08:45:00 -07001869 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001870 BMCWEB_LOG_ERROR("Got path that isn't long enough {}",
1871 objPath);
1872 continue;
Nan Zhou928fefb2022-03-28 08:45:00 -07001873 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001874 // These indexes aren't intuitive, as split puts an empty
1875 // string at the beginning
1876 const std::string& sensorType = split[4];
1877 const std::string& sensorName = split[5];
1878 BMCWEB_LOG_DEBUG("sensorName {} sensorType {}", sensorName,
1879 sensorType);
1880 if (sensorNames->find(objPath) == sensorNames->end())
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001881 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001882 BMCWEB_LOG_DEBUG("{} not in sensor list ", sensorName);
Anthony Wilson95a3eca2019-06-11 10:44:47 -05001883 continue;
1884 }
1885
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001886 // Find inventory item (if any) associated with sensor
1887 InventoryItem* inventoryItem =
1888 findInventoryItemForSensor(inventoryItems, objPath);
1889
1890 const std::string& sensorSchema =
1891 sensorsAsyncResp->chassisSubNode;
1892
1893 nlohmann::json* sensorJson = nullptr;
1894
Janet Adkins0c728b42024-08-29 11:09:10 -05001895 if (sensorSchema == sensors::sensorsNodeStr &&
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001896 !sensorsAsyncResp->efficientExpand)
Nan Zhou928fefb2022-03-28 08:45:00 -07001897 {
Janet Adkins1516c212024-08-14 13:22:41 -05001898 std::string sensorId =
1899 redfish::sensor_utils::getSensorId(sensorName,
1900 sensorType);
Ed Tanous677bb752022-09-15 10:52:19 -07001901
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001902 sensorsAsyncResp->asyncResp->res
1903 .jsonValue["@odata.id"] = boost::urls::format(
Ed Tanousef4c65b2023-04-24 15:28:50 -07001904 "/redfish/v1/Chassis/{}/{}/{}",
Ed Tanous677bb752022-09-15 10:52:19 -07001905 sensorsAsyncResp->chassisId,
1906 sensorsAsyncResp->chassisSubNode, sensorId);
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001907 sensorJson =
1908 &(sensorsAsyncResp->asyncResp->res.jsonValue);
Nan Zhou928fefb2022-03-28 08:45:00 -07001909 }
Anthony Wilson95a3eca2019-06-11 10:44:47 -05001910 else
1911 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001912 std::string fieldName;
1913 if (sensorsAsyncResp->efficientExpand)
1914 {
1915 fieldName = "Members";
1916 }
1917 else if (sensorType == "temperature")
1918 {
1919 fieldName = "Temperatures";
1920 }
1921 else if (sensorType == "fan" ||
1922 sensorType == "fan_tach" ||
1923 sensorType == "fan_pwm")
1924 {
1925 fieldName = "Fans";
1926 }
1927 else if (sensorType == "voltage")
1928 {
1929 fieldName = "Voltages";
1930 }
1931 else if (sensorType == "power")
1932 {
1933 if (sensorName == "total_power")
1934 {
1935 fieldName = "PowerControl";
1936 }
1937 else if ((inventoryItem != nullptr) &&
1938 (inventoryItem->isPowerSupply))
1939 {
1940 fieldName = "PowerSupplies";
1941 }
1942 else
1943 {
1944 // Other power sensors are in SensorCollection
1945 continue;
1946 }
1947 }
1948 else
1949 {
1950 BMCWEB_LOG_ERROR(
1951 "Unsure how to handle sensorType {}",
1952 sensorType);
1953 continue;
1954 }
1955
1956 nlohmann::json& tempArray =
1957 sensorsAsyncResp->asyncResp->res
1958 .jsonValue[fieldName];
1959 if (fieldName == "PowerControl")
1960 {
1961 if (tempArray.empty())
1962 {
1963 // Put multiple "sensors" into a single
1964 // PowerControl. Follows MemberId naming and
1965 // naming in power.hpp.
1966 nlohmann::json::object_t power;
1967 boost::urls::url url = boost::urls::format(
1968 "/redfish/v1/Chassis/{}/{}",
1969 sensorsAsyncResp->chassisId,
1970 sensorsAsyncResp->chassisSubNode);
1971 url.set_fragment(
1972 (""_json_pointer / fieldName / "0")
1973 .to_string());
1974 power["@odata.id"] = std::move(url);
1975 tempArray.emplace_back(std::move(power));
1976 }
1977 sensorJson = &(tempArray.back());
1978 }
1979 else if (fieldName == "PowerSupplies")
1980 {
1981 if (inventoryItem != nullptr)
1982 {
1983 sensorJson = &(getPowerSupply(
1984 tempArray, *inventoryItem,
1985 sensorsAsyncResp->chassisId));
1986 }
1987 }
1988 else if (fieldName == "Members")
1989 {
Janet Adkins1516c212024-08-14 13:22:41 -05001990 std::string sensorId =
1991 redfish::sensor_utils::getSensorId(sensorName,
1992 sensorType);
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001993
1994 nlohmann::json::object_t member;
1995 member["@odata.id"] = boost::urls::format(
1996 "/redfish/v1/Chassis/{}/{}/{}",
1997 sensorsAsyncResp->chassisId,
1998 sensorsAsyncResp->chassisSubNode, sensorId);
1999 tempArray.emplace_back(std::move(member));
2000 sensorJson = &(tempArray.back());
2001 }
2002 else
2003 {
2004 nlohmann::json::object_t member;
2005 boost::urls::url url = boost::urls::format(
2006 "/redfish/v1/Chassis/{}/{}",
2007 sensorsAsyncResp->chassisId,
2008 sensorsAsyncResp->chassisSubNode);
2009 url.set_fragment(
2010 (""_json_pointer / fieldName).to_string());
2011 member["@odata.id"] = std::move(url);
2012 tempArray.emplace_back(std::move(member));
2013 sensorJson = &(tempArray.back());
2014 }
2015 }
2016
2017 if (sensorJson != nullptr)
2018 {
Janet Adkins0c728b42024-08-29 11:09:10 -05002019 objectInterfacesToJson(
2020 sensorName, sensorType, chassisSubNode,
2021 objDictEntry.second, *sensorJson, inventoryItem);
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002022
2023 std::string path = "/xyz/openbmc_project/sensors/";
2024 path += sensorType;
2025 path += "/";
2026 path += sensorName;
2027 sensorsAsyncResp->addMetadata(*sensorJson, path);
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05002028 }
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07002029 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002030 if (sensorsAsyncResp.use_count() == 1)
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05002031 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002032 sortJSONResponse(sensorsAsyncResp);
Janet Adkins0c728b42024-08-29 11:09:10 -05002033 if (chassisSubNode ==
2034 sensor_utils::ChassisSubNode::sensorsNode &&
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002035 sensorsAsyncResp->efficientExpand)
2036 {
2037 sensorsAsyncResp->asyncResp->res
2038 .jsonValue["Members@odata.count"] =
2039 sensorsAsyncResp->asyncResp->res
2040 .jsonValue["Members"]
2041 .size();
2042 }
Janet Adkins0c728b42024-08-29 11:09:10 -05002043 else if (chassisSubNode ==
2044 sensor_utils::ChassisSubNode::thermalNode)
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002045 {
2046 populateFanRedundancy(sensorsAsyncResp);
2047 }
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05002048 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002049 BMCWEB_LOG_DEBUG("getManagedObjectsCb exit");
2050 });
Ed Tanous23a21a12020-07-25 04:45:05 +00002051 }
Ed Tanous62598e32023-07-17 17:06:25 -07002052 BMCWEB_LOG_DEBUG("getSensorData exit");
Shawn McCarneyde629b62019-03-08 10:42:51 -06002053}
2054
Nan Zhoufe04d492022-06-22 17:10:41 +00002055inline void
2056 processSensorList(const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
2057 const std::shared_ptr<std::set<std::string>>& sensorNames)
Anthony Wilson95a3eca2019-06-11 10:44:47 -05002058{
Nan Zhoufe04d492022-06-22 17:10:41 +00002059 auto getConnectionCb = [sensorsAsyncResp, sensorNames](
2060 const std::set<std::string>& connections) {
Ed Tanous62598e32023-07-17 17:06:25 -07002061 BMCWEB_LOG_DEBUG("getConnectionCb enter");
Ed Tanousd0090732022-10-04 17:22:56 -07002062 auto getInventoryItemsCb =
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002063 [sensorsAsyncResp, sensorNames, connections](
2064 const std::shared_ptr<std::vector<InventoryItem>>&
2065 inventoryItems) {
2066 BMCWEB_LOG_DEBUG("getInventoryItemsCb enter");
2067 // Get sensor data and store results in JSON
2068 getSensorData(sensorsAsyncResp, sensorNames, connections,
2069 inventoryItems);
2070 BMCWEB_LOG_DEBUG("getInventoryItemsCb exit");
2071 };
Anthony Wilson95a3eca2019-06-11 10:44:47 -05002072
Ed Tanousd0090732022-10-04 17:22:56 -07002073 // Get inventory items associated with sensors
2074 getInventoryItems(sensorsAsyncResp, sensorNames,
2075 std::move(getInventoryItemsCb));
2076
Ed Tanous62598e32023-07-17 17:06:25 -07002077 BMCWEB_LOG_DEBUG("getConnectionCb exit");
Ed Tanous002d39b2022-05-31 08:59:27 -07002078 };
2079
Anthony Wilson95a3eca2019-06-11 10:44:47 -05002080 // Get set of connections that provide sensor values
Ed Tanous81ce6092020-12-17 16:54:55 +00002081 getConnections(sensorsAsyncResp, sensorNames, std::move(getConnectionCb));
Anthony Wilson95a3eca2019-06-11 10:44:47 -05002082}
2083
Shawn McCarneyde629b62019-03-08 10:42:51 -06002084/**
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +01002085 * @brief Entry point for retrieving sensors data related to requested
2086 * chassis.
Kowalski, Kamil588c3f02018-04-03 14:55:27 +02002087 * @param SensorsAsyncResp Pointer to object holding response data
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +01002088 */
Ed Tanousb5a76932020-09-29 16:16:58 -07002089inline void
Ed Tanous81ce6092020-12-17 16:54:55 +00002090 getChassisData(const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp)
Ed Tanous1abe55e2018-09-05 08:30:59 -07002091{
Ed Tanous62598e32023-07-17 17:06:25 -07002092 BMCWEB_LOG_DEBUG("getChassisData enter");
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07002093 auto getChassisCb =
Ed Tanous81ce6092020-12-17 16:54:55 +00002094 [sensorsAsyncResp](
Nan Zhoufe04d492022-06-22 17:10:41 +00002095 const std::shared_ptr<std::set<std::string>>& sensorNames) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002096 BMCWEB_LOG_DEBUG("getChassisCb enter");
2097 processSensorList(sensorsAsyncResp, sensorNames);
2098 BMCWEB_LOG_DEBUG("getChassisCb exit");
2099 };
Nan Zhou928fefb2022-03-28 08:45:00 -07002100 // SensorCollection doesn't contain the Redundancy property
Janet Adkins0c728b42024-08-29 11:09:10 -05002101 if (sensorsAsyncResp->chassisSubNode != sensors::sensorsNodeStr)
Nan Zhou928fefb2022-03-28 08:45:00 -07002102 {
2103 sensorsAsyncResp->asyncResp->res.jsonValue["Redundancy"] =
2104 nlohmann::json::array();
2105 }
Shawn McCarney26f03892019-05-03 13:20:24 -05002106 // Get set of sensors in chassis
Ed Tanous7f1cc262022-08-09 13:33:57 -07002107 getChassis(sensorsAsyncResp->asyncResp, sensorsAsyncResp->chassisId,
2108 sensorsAsyncResp->chassisSubNode, sensorsAsyncResp->types,
2109 std::move(getChassisCb));
Ed Tanous62598e32023-07-17 17:06:25 -07002110 BMCWEB_LOG_DEBUG("getChassisData exit");
Ed Tanous271584a2019-07-09 16:24:22 -07002111}
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +01002112
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302113/**
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07002114 * @brief Find the requested sensorName in the list of all sensors supplied by
2115 * the chassis node
2116 *
2117 * @param sensorName The sensor name supplied in the PATCH request
2118 * @param sensorsList The list of sensors managed by the chassis node
2119 * @param sensorsModified The list of sensors that were found as a result of
2120 * repeated calls to this function
2121 */
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002122inline bool findSensorNameUsingSensorPath(
2123 std::string_view sensorName, const std::set<std::string>& sensorsList,
2124 std::set<std::string>& sensorsModified)
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07002125{
Nan Zhoufe04d492022-06-22 17:10:41 +00002126 for (const auto& chassisSensor : sensorsList)
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07002127 {
George Liu28aa8de2021-02-01 15:13:30 +08002128 sdbusplus::message::object_path path(chassisSensor);
Ed Tanousb00dcc22021-02-23 12:52:50 -08002129 std::string thisSensorName = path.filename();
George Liu28aa8de2021-02-01 15:13:30 +08002130 if (thisSensorName.empty())
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07002131 {
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07002132 continue;
2133 }
2134 if (thisSensorName == sensorName)
2135 {
2136 sensorsModified.emplace(chassisSensor);
2137 return true;
2138 }
2139 }
2140 return false;
2141}
2142
2143/**
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302144 * @brief Entry point for overriding sensor values of given sensor
2145 *
zhanghch058d1b46d2021-04-01 11:18:24 +08002146 * @param sensorAsyncResp response object
Carol Wang4bb3dc32019-10-17 18:15:02 +08002147 * @param allCollections Collections extract from sensors' request patch info
jayaprakash Mutyala91e130a2020-03-04 22:26:38 +00002148 * @param chassisSubNode Chassis Node for which the query has to happen
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302149 */
Ed Tanous23a21a12020-07-25 04:45:05 +00002150inline void setSensorsOverride(
Ed Tanousb5a76932020-09-29 16:16:58 -07002151 const std::shared_ptr<SensorsAsyncResp>& sensorAsyncResp,
Ed Tanous08850572024-03-06 15:09:17 -08002152 std::unordered_map<std::string, std::vector<nlohmann::json::object_t>>&
jayaprakash Mutyala397fd612020-02-06 23:33:34 +00002153 allCollections)
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302154{
Ed Tanous62598e32023-07-17 17:06:25 -07002155 BMCWEB_LOG_INFO("setSensorsOverride for subNode{}",
2156 sensorAsyncResp->chassisSubNode);
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302157
Ed Tanousd02aad32024-02-13 14:43:34 -08002158 std::string_view propertyValueName;
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302159 std::unordered_map<std::string, std::pair<double, std::string>> overrideMap;
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302160 std::string memberId;
Ed Tanous543f4402022-01-06 13:12:53 -08002161 double value = 0.0;
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302162 for (auto& collectionItems : allCollections)
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302163 {
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302164 if (collectionItems.first == "Temperatures")
2165 {
2166 propertyValueName = "ReadingCelsius";
2167 }
2168 else if (collectionItems.first == "Fans")
2169 {
2170 propertyValueName = "Reading";
2171 }
2172 else
2173 {
2174 propertyValueName = "ReadingVolts";
2175 }
2176 for (auto& item : collectionItems.second)
2177 {
Ed Tanous08850572024-03-06 15:09:17 -08002178 if (!json_util::readJsonObject(
2179 item, sensorAsyncResp->asyncResp->res, "MemberId", memberId,
2180 propertyValueName, value))
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302181 {
2182 return;
2183 }
2184 overrideMap.emplace(memberId,
2185 std::make_pair(value, collectionItems.first));
2186 }
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302187 }
Carol Wang4bb3dc32019-10-17 18:15:02 +08002188
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002189 auto getChassisSensorListCb = [sensorAsyncResp, overrideMap,
2190 propertyValueNameStr =
2191 std::string(propertyValueName)](
2192 const std::shared_ptr<
2193 std::set<std::string>>& sensorsList) {
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07002194 // Match sensor names in the PATCH request to those managed by the
2195 // chassis node
Nan Zhoufe04d492022-06-22 17:10:41 +00002196 const std::shared_ptr<std::set<std::string>> sensorNames =
2197 std::make_shared<std::set<std::string>>();
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302198 for (const auto& item : overrideMap)
2199 {
2200 const auto& sensor = item.first;
Ed Tanousc71d6122022-11-29 14:10:32 -08002201 std::pair<std::string, std::string> sensorNameType =
Janet Adkins1516c212024-08-14 13:22:41 -05002202 redfish::sensor_utils::splitSensorNameAndType(sensor);
Ed Tanousc71d6122022-11-29 14:10:32 -08002203 if (!findSensorNameUsingSensorPath(sensorNameType.second,
2204 *sensorsList, *sensorNames))
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302205 {
Ed Tanous62598e32023-07-17 17:06:25 -07002206 BMCWEB_LOG_INFO("Unable to find memberId {}", item.first);
zhanghch058d1b46d2021-04-01 11:18:24 +08002207 messages::resourceNotFound(sensorAsyncResp->asyncResp->res,
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302208 item.second.second, item.first);
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302209 return;
2210 }
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302211 }
2212 // Get the connection to which the memberId belongs
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002213 auto getObjectsWithConnectionCb = [sensorAsyncResp, overrideMap,
2214 propertyValueNameStr](
2215 const std::set<
2216 std::string>& /*connections*/,
2217 const std::set<std::pair<
2218 std::string, std::string>>&
2219 objectsWithConnection) {
Jayaprakash Mutyala4f277b52021-12-08 22:46:49 +00002220 if (objectsWithConnection.size() != overrideMap.size())
2221 {
Ed Tanous62598e32023-07-17 17:06:25 -07002222 BMCWEB_LOG_INFO(
2223 "Unable to find all objects with proper connection {} requested {}",
2224 objectsWithConnection.size(), overrideMap.size());
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002225 messages::resourceNotFound(
2226 sensorAsyncResp->asyncResp->res,
Janet Adkins0c728b42024-08-29 11:09:10 -05002227 sensorAsyncResp->chassisSubNode == sensors::thermalNodeStr
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002228 ? "Temperatures"
2229 : "Voltages",
2230 "Count");
Jayaprakash Mutyala4f277b52021-12-08 22:46:49 +00002231 return;
2232 }
2233 for (const auto& item : objectsWithConnection)
2234 {
2235 sdbusplus::message::object_path path(item.first);
2236 std::string sensorName = path.filename();
2237 if (sensorName.empty())
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302238 {
Jayaprakash Mutyala4f277b52021-12-08 22:46:49 +00002239 messages::internalError(sensorAsyncResp->asyncResp->res);
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302240 return;
2241 }
Janet Adkins1516c212024-08-14 13:22:41 -05002242 std::string id = redfish::sensor_utils::getSensorId(
2243 sensorName, path.parent_path().filename());
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302244
Ban Feng3f5eb752023-06-29 09:19:20 +08002245 const auto& iterator = overrideMap.find(id);
Jayaprakash Mutyala4f277b52021-12-08 22:46:49 +00002246 if (iterator == overrideMap.end())
2247 {
Ed Tanous62598e32023-07-17 17:06:25 -07002248 BMCWEB_LOG_INFO("Unable to find sensor object{}",
2249 item.first);
Jayaprakash Mutyala4f277b52021-12-08 22:46:49 +00002250 messages::internalError(sensorAsyncResp->asyncResp->res);
2251 return;
2252 }
Ginu Georgee93abac2024-06-14 17:35:27 +05302253 setDbusProperty(sensorAsyncResp->asyncResp,
2254 propertyValueNameStr, item.second, item.first,
2255 "xyz.openbmc_project.Sensor.Value", "Value",
Ed Tanousd02aad32024-02-13 14:43:34 -08002256 iterator->second.first);
Jayaprakash Mutyala4f277b52021-12-08 22:46:49 +00002257 }
2258 };
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302259 // Get object with connection for the given sensor name
2260 getObjectsWithConnection(sensorAsyncResp, sensorNames,
2261 std::move(getObjectsWithConnectionCb));
2262 };
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302263 // get full sensor list for the given chassisId and cross verify the sensor.
Ed Tanous7f1cc262022-08-09 13:33:57 -07002264 getChassis(sensorAsyncResp->asyncResp, sensorAsyncResp->chassisId,
2265 sensorAsyncResp->chassisSubNode, sensorAsyncResp->types,
2266 std::move(getChassisSensorListCb));
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302267}
2268
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +02002269/**
2270 * @brief Retrieves mapping of Redfish URIs to sensor value property to D-Bus
2271 * path of the sensor.
2272 *
2273 * Function builds valid Redfish response for sensor query of given chassis and
2274 * node. It then builds metadata about Redfish<->D-Bus correlations and provides
2275 * it to caller in a callback.
2276 *
2277 * @param chassis Chassis for which retrieval should be performed
Janet Adkinsc9563602024-08-28 11:37:46 -05002278 * @param node Node (group) of sensors. See sensor_utils::node for supported
2279 * values
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +02002280 * @param mapComplete Callback to be called with retrieval result
2281 */
Ed Tanous931edc72023-11-01 12:09:07 -07002282template <typename Callback>
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002283inline void retrieveUriToDbusMap(
2284 const std::string& chassis, const std::string& node, Callback&& mapComplete)
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +02002285{
Ed Tanous02da7c52022-02-27 00:09:02 -08002286 decltype(sensors::paths)::const_iterator pathIt =
2287 std::find_if(sensors::paths.cbegin(), sensors::paths.cend(),
2288 [&node](auto&& val) { return val.first == node; });
2289 if (pathIt == sensors::paths.cend())
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +02002290 {
Ed Tanous62598e32023-07-17 17:06:25 -07002291 BMCWEB_LOG_ERROR("Wrong node provided : {}", node);
Ed Tanous6804b5c2023-10-31 14:50:03 -07002292 std::map<std::string, std::string> noop;
2293 mapComplete(boost::beast::http::status::bad_request, noop);
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +02002294 return;
2295 }
Krzysztof Grobelnyd51e0722021-04-16 13:15:21 +00002296
Nan Zhou72374eb2022-01-27 17:06:51 -08002297 auto asyncResp = std::make_shared<bmcweb::AsyncResp>();
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002298 auto callback =
2299 [asyncResp, mapCompleteCb = std::forward<Callback>(mapComplete)](
2300 const boost::beast::http::status status,
2301 const std::map<std::string, std::string>& uriToDbus) {
2302 mapCompleteCb(status, uriToDbus);
2303 };
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +02002304
2305 auto resp = std::make_shared<SensorsAsyncResp>(
Krzysztof Grobelnyd51e0722021-04-16 13:15:21 +00002306 asyncResp, chassis, pathIt->second, node, std::move(callback));
Adrian Ambrożewicza0ec28b2020-04-10 14:47:28 +02002307 getChassisData(resp);
2308}
2309
Nan Zhoubacb2162022-04-06 11:28:32 -07002310namespace sensors
2311{
Nan Zhou928fefb2022-03-28 08:45:00 -07002312
Nan Zhoubacb2162022-04-06 11:28:32 -07002313inline void getChassisCallback(
Ed Tanousc1d019a2022-08-06 09:36:06 -07002314 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2315 std::string_view chassisId, std::string_view chassisSubNode,
Nan Zhoufe04d492022-06-22 17:10:41 +00002316 const std::shared_ptr<std::set<std::string>>& sensorNames)
Nan Zhoubacb2162022-04-06 11:28:32 -07002317{
Ed Tanous62598e32023-07-17 17:06:25 -07002318 BMCWEB_LOG_DEBUG("getChassisCallback enter ");
Nan Zhoubacb2162022-04-06 11:28:32 -07002319
Ed Tanousc1d019a2022-08-06 09:36:06 -07002320 nlohmann::json& entriesArray = asyncResp->res.jsonValue["Members"];
2321 for (const std::string& sensor : *sensorNames)
Nan Zhoubacb2162022-04-06 11:28:32 -07002322 {
Ed Tanous62598e32023-07-17 17:06:25 -07002323 BMCWEB_LOG_DEBUG("Adding sensor: {}", sensor);
Nan Zhoubacb2162022-04-06 11:28:32 -07002324
2325 sdbusplus::message::object_path path(sensor);
2326 std::string sensorName = path.filename();
2327 if (sensorName.empty())
2328 {
Ed Tanous62598e32023-07-17 17:06:25 -07002329 BMCWEB_LOG_ERROR("Invalid sensor path: {}", sensor);
Ed Tanousc1d019a2022-08-06 09:36:06 -07002330 messages::internalError(asyncResp->res);
Nan Zhoubacb2162022-04-06 11:28:32 -07002331 return;
2332 }
Ed Tanousc1d019a2022-08-06 09:36:06 -07002333 std::string type = path.parent_path().filename();
Janet Adkins1516c212024-08-14 13:22:41 -05002334 std::string id = redfish::sensor_utils::getSensorId(sensorName, type);
Ed Tanousc1d019a2022-08-06 09:36:06 -07002335
Ed Tanous14766872022-03-15 10:44:42 -07002336 nlohmann::json::object_t member;
Ed Tanousef4c65b2023-04-24 15:28:50 -07002337 member["@odata.id"] = boost::urls::format(
2338 "/redfish/v1/Chassis/{}/{}/{}", chassisId, chassisSubNode, id);
Ed Tanousc1d019a2022-08-06 09:36:06 -07002339
Patrick Williamsb2ba3072023-05-12 10:27:39 -05002340 entriesArray.emplace_back(std::move(member));
Nan Zhoubacb2162022-04-06 11:28:32 -07002341 }
2342
Ed Tanousc1d019a2022-08-06 09:36:06 -07002343 asyncResp->res.jsonValue["Members@odata.count"] = entriesArray.size();
Ed Tanous62598e32023-07-17 17:06:25 -07002344 BMCWEB_LOG_DEBUG("getChassisCallback exit");
Nan Zhoubacb2162022-04-06 11:28:32 -07002345}
Nan Zhoue6bd8462022-06-01 04:35:35 +00002346
Ed Tanousac106bf2023-06-07 09:24:59 -07002347inline void handleSensorCollectionGet(
2348 App& app, const crow::Request& req,
2349 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2350 const std::string& chassisId)
Nan Zhoude167a62022-06-01 04:47:45 +00002351{
2352 query_param::QueryCapabilities capabilities = {
2353 .canDelegateExpandLevel = 1,
2354 };
2355 query_param::Query delegatedQuery;
Ed Tanousac106bf2023-06-07 09:24:59 -07002356 if (!redfish::setUpRedfishRouteWithDelegation(app, req, asyncResp,
Nan Zhoude167a62022-06-01 04:47:45 +00002357 delegatedQuery, capabilities))
2358 {
2359 return;
2360 }
2361
2362 if (delegatedQuery.expandType != query_param::ExpandType::None)
2363 {
2364 // we perform efficient expand.
Ed Tanousac106bf2023-06-07 09:24:59 -07002365 auto sensorsAsyncResp = std::make_shared<SensorsAsyncResp>(
2366 asyncResp, chassisId, sensors::dbus::sensorPaths,
Janet Adkins0c728b42024-08-29 11:09:10 -05002367 sensors::sensorsNodeStr,
Nan Zhoude167a62022-06-01 04:47:45 +00002368 /*efficientExpand=*/true);
Ed Tanousac106bf2023-06-07 09:24:59 -07002369 getChassisData(sensorsAsyncResp);
Nan Zhoude167a62022-06-01 04:47:45 +00002370
Ed Tanous62598e32023-07-17 17:06:25 -07002371 BMCWEB_LOG_DEBUG(
2372 "SensorCollection doGet exit via efficient expand handler");
Nan Zhoude167a62022-06-01 04:47:45 +00002373 return;
Ed Tanous0bad3202022-06-02 13:53:59 -07002374 }
Nan Zhoude167a62022-06-01 04:47:45 +00002375
Nan Zhoude167a62022-06-01 04:47:45 +00002376 // We get all sensors as hyperlinkes in the chassis (this
2377 // implies we reply on the default query parameters handler)
Janet Adkins0c728b42024-08-29 11:09:10 -05002378 getChassis(asyncResp, chassisId, sensors::sensorsNodeStr, dbus::sensorPaths,
Ed Tanousac106bf2023-06-07 09:24:59 -07002379 std::bind_front(sensors::getChassisCallback, asyncResp,
Janet Adkins0c728b42024-08-29 11:09:10 -05002380 chassisId, sensors::sensorsNodeStr));
Ed Tanousc1d019a2022-08-06 09:36:06 -07002381}
Ed Tanous7f1cc262022-08-09 13:33:57 -07002382
Ed Tanousc1d019a2022-08-06 09:36:06 -07002383inline void
2384 getSensorFromDbus(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2385 const std::string& sensorPath,
2386 const ::dbus::utility::MapperGetObject& mapperResponse)
2387{
2388 if (mapperResponse.size() != 1)
2389 {
2390 messages::internalError(asyncResp->res);
2391 return;
2392 }
2393 const auto& valueIface = *mapperResponse.begin();
2394 const std::string& connectionName = valueIface.first;
Ed Tanous62598e32023-07-17 17:06:25 -07002395 BMCWEB_LOG_DEBUG("Looking up {}", connectionName);
2396 BMCWEB_LOG_DEBUG("Path {}", sensorPath);
Krzysztof Grobelnyc1343bf2022-08-31 13:15:26 +02002397
2398 sdbusplus::asio::getAllProperties(
2399 *crow::connections::systemBus, connectionName, sensorPath, "",
Ed Tanousc1d019a2022-08-06 09:36:06 -07002400 [asyncResp,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08002401 sensorPath](const boost::system::error_code& ec,
Ed Tanousc1d019a2022-08-06 09:36:06 -07002402 const ::dbus::utility::DBusPropertiesMap& valuesDict) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002403 if (ec)
2404 {
2405 messages::internalError(asyncResp->res);
2406 return;
2407 }
2408 sdbusplus::message::object_path path(sensorPath);
2409 std::string name = path.filename();
2410 path = path.parent_path();
2411 std::string type = path.filename();
Janet Adkinsc9563602024-08-28 11:37:46 -05002412 sensor_utils::objectPropertiesToJson(
Janet Adkins0c728b42024-08-29 11:09:10 -05002413 name, type, sensor_utils::ChassisSubNode::sensorsNode,
2414 valuesDict, asyncResp->res.jsonValue, nullptr);
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002415 });
Nan Zhoude167a62022-06-01 04:47:45 +00002416}
2417
Nan Zhoue6bd8462022-06-01 04:35:35 +00002418inline void handleSensorGet(App& app, const crow::Request& req,
Ed Tanousc1d019a2022-08-06 09:36:06 -07002419 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous677bb752022-09-15 10:52:19 -07002420 const std::string& chassisId,
Ed Tanousc1d019a2022-08-06 09:36:06 -07002421 const std::string& sensorId)
Nan Zhoue6bd8462022-06-01 04:35:35 +00002422{
Ed Tanousc1d019a2022-08-06 09:36:06 -07002423 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Nan Zhoue6bd8462022-06-01 04:35:35 +00002424 {
2425 return;
2426 }
Ed Tanousc71d6122022-11-29 14:10:32 -08002427 std::pair<std::string, std::string> nameType =
Janet Adkins1516c212024-08-14 13:22:41 -05002428 redfish::sensor_utils::splitSensorNameAndType(sensorId);
Ed Tanousc71d6122022-11-29 14:10:32 -08002429 if (nameType.first.empty() || nameType.second.empty())
Ed Tanousc1d019a2022-08-06 09:36:06 -07002430 {
2431 messages::resourceNotFound(asyncResp->res, sensorId, "Sensor");
2432 return;
2433 }
Ed Tanousc71d6122022-11-29 14:10:32 -08002434
Ed Tanousef4c65b2023-04-24 15:28:50 -07002435 asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
2436 "/redfish/v1/Chassis/{}/Sensors/{}", chassisId, sensorId);
Ed Tanousc1d019a2022-08-06 09:36:06 -07002437
Ed Tanous62598e32023-07-17 17:06:25 -07002438 BMCWEB_LOG_DEBUG("Sensor doGet enter");
Nan Zhoue6bd8462022-06-01 04:35:35 +00002439
George Liu2b731192023-01-11 16:27:13 +08002440 constexpr std::array<std::string_view, 1> interfaces = {
Nan Zhoue6bd8462022-06-01 04:35:35 +00002441 "xyz.openbmc_project.Sensor.Value"};
Ed Tanousc71d6122022-11-29 14:10:32 -08002442 std::string sensorPath = "/xyz/openbmc_project/sensors/" + nameType.first +
2443 '/' + nameType.second;
Nan Zhoue6bd8462022-06-01 04:35:35 +00002444 // Get a list of all of the sensors that implement Sensor.Value
2445 // and get the path and service name associated with the sensor
George Liu2b731192023-01-11 16:27:13 +08002446 ::dbus::utility::getDbusObject(
2447 sensorPath, interfaces,
Myung Baeaec0ec32023-05-31 15:10:01 -05002448 [asyncResp, sensorId,
George Liu2b731192023-01-11 16:27:13 +08002449 sensorPath](const boost::system::error_code& ec,
Ed Tanousc1d019a2022-08-06 09:36:06 -07002450 const ::dbus::utility::MapperGetObject& subtree) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002451 BMCWEB_LOG_DEBUG("respHandler1 enter");
2452 if (ec == boost::system::errc::io_error)
2453 {
2454 BMCWEB_LOG_WARNING("Sensor not found from getSensorPaths");
2455 messages::resourceNotFound(asyncResp->res, sensorId, "Sensor");
2456 return;
2457 }
2458 if (ec)
2459 {
2460 messages::internalError(asyncResp->res);
2461 BMCWEB_LOG_ERROR(
2462 "Sensor getSensorPaths resp_handler: Dbus error {}", ec);
2463 return;
2464 }
2465 getSensorFromDbus(asyncResp, sensorPath, subtree);
2466 BMCWEB_LOG_DEBUG("respHandler1 exit");
2467 });
Nan Zhoue6bd8462022-06-01 04:35:35 +00002468}
2469
Nan Zhoubacb2162022-04-06 11:28:32 -07002470} // namespace sensors
2471
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002472inline void requestRoutesSensorCollection(App& app)
Anthony Wilson95a3eca2019-06-11 10:44:47 -05002473{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002474 BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/Sensors/")
Ed Tanoused398212021-06-09 17:05:54 -07002475 .privileges(redfish::privileges::getSensorCollection)
Ed Tanous002d39b2022-05-31 08:59:27 -07002476 .methods(boost::beast::http::verb::get)(
Nan Zhoude167a62022-06-01 04:47:45 +00002477 std::bind_front(sensors::handleSensorCollectionGet, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002478}
Anthony Wilson95a3eca2019-06-11 10:44:47 -05002479
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002480inline void requestRoutesSensor(App& app)
2481{
2482 BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/Sensors/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07002483 .privileges(redfish::privileges::getSensor)
Ed Tanous002d39b2022-05-31 08:59:27 -07002484 .methods(boost::beast::http::verb::get)(
Nan Zhoue6bd8462022-06-01 04:35:35 +00002485 std::bind_front(sensors::handleSensorGet, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002486}
Anthony Wilson95a3eca2019-06-11 10:44:47 -05002487
Ed Tanous1abe55e2018-09-05 08:30:59 -07002488} // namespace redfish