blob: fb3b25e2b8ec716ba81281576adc79f5d71a7ff8 [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
Anthony Wilson95a3eca2019-06-11 10:44:47 -050018#include "node.hpp"
19
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +010020#include <boost/algorithm/string/predicate.hpp>
21#include <boost/algorithm/string/split.hpp>
22#include <boost/container/flat_map.hpp>
23#include <boost/range/algorithm/replace_copy_if.hpp>
Ed Tanous9e27a222019-10-24 13:46:39 -070024#include <cmath>
Ed Tanous1abe55e2018-09-05 08:30:59 -070025#include <dbus_singleton.hpp>
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +053026#include <utils/json_utils.hpp>
Ed Tanousabf2add2019-01-22 16:40:12 -080027#include <variant>
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +010028
Ed Tanous1abe55e2018-09-05 08:30:59 -070029namespace redfish
30{
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +010031
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +010032using GetSubTreeType = std::vector<
33 std::pair<std::string,
34 std::vector<std::pair<std::string, std::vector<std::string>>>>>;
35
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -050036using SensorVariant =
37 std::variant<int64_t, double, uint32_t, bool, std::string>;
Ed Tanousaa2e59c2018-04-12 12:17:20 -070038
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +010039using ManagedObjectsVectorType = std::vector<std::pair<
Ed Tanousaa2e59c2018-04-12 12:17:20 -070040 sdbusplus::message::object_path,
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +010041 boost::container::flat_map<
Ed Tanousaa2e59c2018-04-12 12:17:20 -070042 std::string, boost::container::flat_map<std::string, SensorVariant>>>>;
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +010043
44/**
Kowalski, Kamil588c3f02018-04-03 14:55:27 +020045 * SensorsAsyncResp
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +010046 * Gathers data needed for response processing after async calls are done
47 */
Ed Tanous1abe55e2018-09-05 08:30:59 -070048class SensorsAsyncResp
49{
50 public:
Ed Tanous271584a2019-07-09 16:24:22 -070051 SensorsAsyncResp(crow::Response& response, const std::string& chassisIdIn,
52 const std::vector<const char*> typesIn,
Ed Tanous2474adf2018-09-05 16:31:16 -070053 const std::string& subNode) :
Ed Tanous43b761d2019-02-13 20:10:56 -080054 res(response),
Ed Tanous271584a2019-07-09 16:24:22 -070055 chassisId(chassisIdIn), types(typesIn), chassisSubNode(subNode)
Ed Tanous1abe55e2018-09-05 08:30:59 -070056 {
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +010057 }
Kowalski, Kamil588c3f02018-04-03 14:55:27 +020058
Ed Tanous1abe55e2018-09-05 08:30:59 -070059 ~SensorsAsyncResp()
60 {
61 if (res.result() == boost::beast::http::status::internal_server_error)
62 {
63 // Reset the json object to clear out any data that made it in
64 // before the error happened todo(ed) handle error condition with
65 // proper code
66 res.jsonValue = nlohmann::json::object();
67 }
68 res.end();
69 }
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +010070
Ed Tanous1abe55e2018-09-05 08:30:59 -070071 crow::Response& res;
72 std::string chassisId{};
73 const std::vector<const char*> types;
Ed Tanous2474adf2018-09-05 16:31:16 -070074 std::string chassisSubNode{};
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +010075};
76
77/**
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -050078 * D-Bus inventory item associated with one or more sensors.
79 */
80class InventoryItem
81{
82 public:
83 InventoryItem(const std::string& objPath) :
84 objectPath(objPath), name(), isPresent(true), isFunctional(true),
85 isPowerSupply(false), manufacturer(), model(), partNumber(),
86 serialNumber(), sensors()
87 {
88 // Set inventory item name to last node of object path
89 auto pos = objectPath.rfind('/');
90 if ((pos != std::string::npos) && ((pos + 1) < objectPath.size()))
91 {
92 name = objectPath.substr(pos + 1);
93 }
94 }
95
96 std::string objectPath;
97 std::string name;
98 bool isPresent;
99 bool isFunctional;
100 bool isPowerSupply;
101 std::string manufacturer;
102 std::string model;
103 std::string partNumber;
104 std::string serialNumber;
105 std::set<std::string> sensors;
106};
107
108/**
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +0530109 * @brief Get objects with connection necessary for sensors
Kowalski, Kamil588c3f02018-04-03 14:55:27 +0200110 * @param SensorsAsyncResp Pointer to object holding response data
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100111 * @param sensorNames Sensors retrieved from chassis
112 * @param callback Callback for processing gathered connections
113 */
114template <typename Callback>
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +0530115void getObjectsWithConnection(
116 std::shared_ptr<SensorsAsyncResp> SensorsAsyncResp,
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700117 const std::shared_ptr<boost::container::flat_set<std::string>> sensorNames,
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +0530118 Callback&& callback)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700119{
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +0530120 BMCWEB_LOG_DEBUG << "getObjectsWithConnection enter";
Ed Tanous1abe55e2018-09-05 08:30:59 -0700121 const std::string path = "/xyz/openbmc_project/sensors";
122 const std::array<std::string, 1> interfaces = {
123 "xyz.openbmc_project.Sensor.Value"};
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100124
Ed Tanous1abe55e2018-09-05 08:30:59 -0700125 // Response handler for parsing objects subtree
126 auto respHandler = [callback{std::move(callback)}, SensorsAsyncResp,
127 sensorNames](const boost::system::error_code ec,
128 const GetSubTreeType& subtree) {
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +0530129 BMCWEB_LOG_DEBUG << "getObjectsWithConnection resp_handler enter";
Ed Tanous1abe55e2018-09-05 08:30:59 -0700130 if (ec)
131 {
Ed Tanous5f7d88c2018-11-14 14:08:56 -0800132 messages::internalError(SensorsAsyncResp->res);
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +0530133 BMCWEB_LOG_ERROR
134 << "getObjectsWithConnection resp_handler: Dbus error " << ec;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700135 return;
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100136 }
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100137
Ed Tanous1abe55e2018-09-05 08:30:59 -0700138 BMCWEB_LOG_DEBUG << "Found " << subtree.size() << " subtrees";
139
140 // Make unique list of connections only for requested sensor types and
141 // found in the chassis
142 boost::container::flat_set<std::string> connections;
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +0530143 std::set<std::pair<std::string, std::string>> objectsWithConnection;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700144 // Intrinsic to avoid malloc. Most systems will have < 8 sensor
145 // producers
146 connections.reserve(8);
147
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700148 BMCWEB_LOG_DEBUG << "sensorNames list count: " << sensorNames->size();
149 for (const std::string& tsensor : *sensorNames)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700150 {
151 BMCWEB_LOG_DEBUG << "Sensor to find: " << tsensor;
152 }
153
154 for (const std::pair<
155 std::string,
156 std::vector<std::pair<std::string, std::vector<std::string>>>>&
157 object : subtree)
158 {
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700159 if (sensorNames->find(object.first) != sensorNames->end())
Ed Tanous1abe55e2018-09-05 08:30:59 -0700160 {
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700161 for (const std::pair<std::string, std::vector<std::string>>&
162 objData : object.second)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700163 {
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700164 BMCWEB_LOG_DEBUG << "Adding connection: " << objData.first;
165 connections.insert(objData.first);
166 objectsWithConnection.insert(
167 std::make_pair(object.first, objData.first));
Ed Tanous1abe55e2018-09-05 08:30:59 -0700168 }
169 }
170 }
171 BMCWEB_LOG_DEBUG << "Found " << connections.size() << " connections";
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +0530172 callback(std::move(connections), std::move(objectsWithConnection));
173 BMCWEB_LOG_DEBUG << "getObjectsWithConnection resp_handler exit";
Ed Tanous1abe55e2018-09-05 08:30:59 -0700174 };
Ed Tanous1abe55e2018-09-05 08:30:59 -0700175 // Make call to ObjectMapper to find all sensors objects
176 crow::connections::systemBus->async_method_call(
177 std::move(respHandler), "xyz.openbmc_project.ObjectMapper",
178 "/xyz/openbmc_project/object_mapper",
179 "xyz.openbmc_project.ObjectMapper", "GetSubTree", path, 2, interfaces);
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +0530180 BMCWEB_LOG_DEBUG << "getObjectsWithConnection exit";
181}
182
183/**
184 * @brief Create connections necessary for sensors
185 * @param SensorsAsyncResp Pointer to object holding response data
186 * @param sensorNames Sensors retrieved from chassis
187 * @param callback Callback for processing gathered connections
188 */
189template <typename Callback>
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700190void getConnections(
191 std::shared_ptr<SensorsAsyncResp> SensorsAsyncResp,
192 const std::shared_ptr<boost::container::flat_set<std::string>> sensorNames,
193 Callback&& callback)
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +0530194{
195 auto objectsWithConnectionCb =
196 [callback](const boost::container::flat_set<std::string>& connections,
197 const std::set<std::pair<std::string, std::string>>&
198 objectsWithConnection) {
199 callback(std::move(connections));
200 };
201 getObjectsWithConnection(SensorsAsyncResp, sensorNames,
202 std::move(objectsWithConnectionCb));
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100203}
204
205/**
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700206 * @brief Shrinks the list of sensors for processing
207 * @param SensorsAysncResp The class holding the Redfish response
208 * @param allSensors A list of all the sensors associated to the
209 * chassis element (i.e. baseboard, front panel, etc...)
210 * @param activeSensors A list that is a reduction of the incoming
211 * allSensors list. Eliminate Thermal sensors when a Power request is
212 * made, and eliminate Power sensors when a Thermal request is made.
213 */
214void reduceSensorList(
215 std::shared_ptr<SensorsAsyncResp> SensorsAsyncResp,
216 const std::vector<std::string>* allSensors,
217 std::shared_ptr<boost::container::flat_set<std::string>> activeSensors)
218{
219 if (SensorsAsyncResp == nullptr)
220 {
221 return;
222 }
223 if ((allSensors == nullptr) || (activeSensors == nullptr))
224 {
225 messages::resourceNotFound(
226 SensorsAsyncResp->res, SensorsAsyncResp->chassisSubNode,
227 SensorsAsyncResp->chassisSubNode == "Thermal" ? "Temperatures"
228 : "Voltages");
229
230 return;
231 }
232 if (allSensors->empty())
233 {
234 // Nothing to do, the activeSensors object is also empty
235 return;
236 }
237
238 for (const char* type : SensorsAsyncResp->types)
239 {
240 for (const std::string& sensor : *allSensors)
241 {
242 if (boost::starts_with(sensor, type))
243 {
244 activeSensors->emplace(sensor);
245 }
246 }
247 }
248}
249
250/**
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100251 * @brief Retrieves requested chassis sensors and redundancy data from DBus .
Kowalski, Kamil588c3f02018-04-03 14:55:27 +0200252 * @param SensorsAsyncResp Pointer to object holding response data
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100253 * @param callback Callback for next step in gathered sensor processing
254 */
255template <typename Callback>
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700256void getChassis(std::shared_ptr<SensorsAsyncResp> sensorsAsyncResp,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700257 Callback&& callback)
258{
259 BMCWEB_LOG_DEBUG << "getChassis enter";
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500260 const std::array<const char*, 2> interfaces = {
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700261 "xyz.openbmc_project.Inventory.Item.Board",
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500262 "xyz.openbmc_project.Inventory.Item.Chassis"};
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700263 auto respHandler = [callback{std::move(callback)}, sensorsAsyncResp](
264 const boost::system::error_code ec,
265 const std::vector<std::string>& chassisPaths) {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700266 BMCWEB_LOG_DEBUG << "getChassis respHandler enter";
267 if (ec)
268 {
269 BMCWEB_LOG_ERROR << "getChassis respHandler DBUS error: " << ec;
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700270 messages::internalError(sensorsAsyncResp->res);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700271 return;
272 }
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100273
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700274 const std::string* chassisPath = nullptr;
275 std::string chassisName;
276 for (const std::string& chassis : chassisPaths)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700277 {
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700278 std::size_t lastPos = chassis.rfind("/");
279 if (lastPos == std::string::npos)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700280 {
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700281 BMCWEB_LOG_ERROR << "Failed to find '/' in " << chassis;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700282 continue;
283 }
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700284 chassisName = chassis.substr(lastPos + 1);
285 if (chassisName == sensorsAsyncResp->chassisId)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700286 {
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700287 chassisPath = &chassis;
288 break;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700289 }
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700290 }
291 if (chassisPath == nullptr)
292 {
293 messages::resourceNotFound(sensorsAsyncResp->res, "Chassis",
294 sensorsAsyncResp->chassisId);
295 return;
296 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700297
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700298 const std::string& chassisSubNode = sensorsAsyncResp->chassisSubNode;
299 if (chassisSubNode == "Power")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700300 {
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700301 sensorsAsyncResp->res.jsonValue["@odata.type"] =
302 "#Power.v1_5_2.Power";
Ed Tanous1abe55e2018-09-05 08:30:59 -0700303 }
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700304 else if (chassisSubNode == "Thermal")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700305 {
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700306 sensorsAsyncResp->res.jsonValue["@odata.type"] =
307 "#Thermal.v1_4_0.Thermal";
Jennifer Lee4f9a2132019-03-04 12:45:19 -0800308 sensorsAsyncResp->res.jsonValue["Fans"] = nlohmann::json::array();
309 sensorsAsyncResp->res.jsonValue["Temperatures"] =
310 nlohmann::json::array();
Ed Tanous1abe55e2018-09-05 08:30:59 -0700311 }
Anthony Wilson95a3eca2019-06-11 10:44:47 -0500312 else if (chassisSubNode == "Sensors")
313 {
314 sensorsAsyncResp->res.jsonValue["@odata.type"] =
315 "#SensorCollection.SensorCollection";
316 sensorsAsyncResp->res.jsonValue["@odata.context"] =
317 "/redfish/v1/$metadata#SensorCollection.SensorCollection";
318 sensorsAsyncResp->res.jsonValue["Description"] =
319 "Collection of Sensors for this Chassis";
320 sensorsAsyncResp->res.jsonValue["Members"] =
321 nlohmann::json::array();
322 sensorsAsyncResp->res.jsonValue["Members@odata.count"] = 0;
323 }
324
325 if (chassisSubNode != "Sensors")
326 {
327 sensorsAsyncResp->res.jsonValue["Id"] = chassisSubNode;
328 sensorsAsyncResp->res.jsonValue["@odata.context"] =
329 "/redfish/v1/$metadata#" + chassisSubNode + "." +
330 chassisSubNode;
331 }
332
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700333 sensorsAsyncResp->res.jsonValue["@odata.id"] =
334 "/redfish/v1/Chassis/" + sensorsAsyncResp->chassisId + "/" +
335 chassisSubNode;
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700336 sensorsAsyncResp->res.jsonValue["Name"] = chassisSubNode;
337
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500338 // Get the list of all sensors for this Chassis element
339 std::string sensorPath = *chassisPath + "/all_sensors";
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700340 crow::connections::systemBus->async_method_call(
341 [sensorsAsyncResp, callback{std::move(callback)}](
Ed Tanous271584a2019-07-09 16:24:22 -0700342 const boost::system::error_code& e,
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700343 const std::variant<std::vector<std::string>>&
344 variantEndpoints) {
Ed Tanous271584a2019-07-09 16:24:22 -0700345 if (e)
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700346 {
Ed Tanous271584a2019-07-09 16:24:22 -0700347 if (e.value() != EBADR)
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700348 {
349 messages::internalError(sensorsAsyncResp->res);
350 return;
351 }
352 }
353 const std::vector<std::string>* nodeSensorList =
354 std::get_if<std::vector<std::string>>(&(variantEndpoints));
355 if (nodeSensorList == nullptr)
356 {
357 messages::resourceNotFound(
358 sensorsAsyncResp->res, sensorsAsyncResp->chassisSubNode,
359 sensorsAsyncResp->chassisSubNode == "Thermal"
360 ? "Temperatures"
Anthony Wilson95a3eca2019-06-11 10:44:47 -0500361 : sensorsAsyncResp->chassisSubNode == "Power"
362 ? "Voltages"
363 : "Sensors");
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700364 return;
365 }
366 const std::shared_ptr<boost::container::flat_set<std::string>>
367 culledSensorList = std::make_shared<
368 boost::container::flat_set<std::string>>();
369 reduceSensorList(sensorsAsyncResp, nodeSensorList,
370 culledSensorList);
371 callback(culledSensorList);
372 },
373 "xyz.openbmc_project.ObjectMapper", sensorPath,
374 "org.freedesktop.DBus.Properties", "Get",
375 "xyz.openbmc_project.Association", "endpoints");
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100376 };
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100377
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700378 // Get the Chassis Collection
Ed Tanous1abe55e2018-09-05 08:30:59 -0700379 crow::connections::systemBus->async_method_call(
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700380 respHandler, "xyz.openbmc_project.ObjectMapper",
381 "/xyz/openbmc_project/object_mapper",
382 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths",
Ed Tanous271584a2019-07-09 16:24:22 -0700383 "/xyz/openbmc_project/inventory", 0, interfaces);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700384 BMCWEB_LOG_DEBUG << "getChassis exit";
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100385}
386
387/**
Shawn McCarneyde629b62019-03-08 10:42:51 -0600388 * @brief Finds all DBus object paths that implement ObjectManager.
389 *
390 * Creates a mapping from the associated connection name to the object path.
391 *
392 * Finds the object paths asynchronously. Invokes callback when information has
393 * been obtained.
394 *
395 * The callback must have the following signature:
396 * @code
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500397 * callback(std::shared_ptr<boost::container::flat_map<std::string,
398 * std::string>> objectMgrPaths)
Shawn McCarneyde629b62019-03-08 10:42:51 -0600399 * @endcode
400 *
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700401 * @param sensorsAsyncResp Pointer to object holding response data.
Shawn McCarneyde629b62019-03-08 10:42:51 -0600402 * @param callback Callback to invoke when object paths obtained.
403 */
404template <typename Callback>
405void getObjectManagerPaths(std::shared_ptr<SensorsAsyncResp> SensorsAsyncResp,
406 Callback&& callback)
407{
408 BMCWEB_LOG_DEBUG << "getObjectManagerPaths enter";
409 const std::array<std::string, 1> interfaces = {
410 "org.freedesktop.DBus.ObjectManager"};
411
412 // Response handler for GetSubTree DBus method
413 auto respHandler = [callback{std::move(callback)},
414 SensorsAsyncResp](const boost::system::error_code ec,
415 const GetSubTreeType& subtree) {
416 BMCWEB_LOG_DEBUG << "getObjectManagerPaths respHandler enter";
417 if (ec)
418 {
419 messages::internalError(SensorsAsyncResp->res);
420 BMCWEB_LOG_ERROR << "getObjectManagerPaths respHandler: DBus error "
421 << ec;
422 return;
423 }
424
425 // Loop over returned object paths
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500426 std::shared_ptr<boost::container::flat_map<std::string, std::string>>
427 objectMgrPaths = std::make_shared<
428 boost::container::flat_map<std::string, std::string>>();
Shawn McCarneyde629b62019-03-08 10:42:51 -0600429 for (const std::pair<
430 std::string,
431 std::vector<std::pair<std::string, std::vector<std::string>>>>&
432 object : subtree)
433 {
434 // Loop over connections for current object path
435 const std::string& objectPath = object.first;
436 for (const std::pair<std::string, std::vector<std::string>>&
437 objData : object.second)
438 {
439 // Add mapping from connection to object path
440 const std::string& connection = objData.first;
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500441 (*objectMgrPaths)[connection] = objectPath;
Shawn McCarneyde629b62019-03-08 10:42:51 -0600442 BMCWEB_LOG_DEBUG << "Added mapping " << connection << " -> "
443 << objectPath;
444 }
445 }
Shawn McCarney8fb49dd2019-06-12 17:47:00 -0500446 callback(objectMgrPaths);
Shawn McCarneyde629b62019-03-08 10:42:51 -0600447 BMCWEB_LOG_DEBUG << "getObjectManagerPaths respHandler exit";
448 };
449
450 // Query mapper for all DBus object paths that implement ObjectManager
451 crow::connections::systemBus->async_method_call(
452 std::move(respHandler), "xyz.openbmc_project.ObjectMapper",
453 "/xyz/openbmc_project/object_mapper",
Ed Tanous271584a2019-07-09 16:24:22 -0700454 "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/", 0, interfaces);
Shawn McCarneyde629b62019-03-08 10:42:51 -0600455 BMCWEB_LOG_DEBUG << "getObjectManagerPaths exit";
456}
457
458/**
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500459 * @brief Returns the Redfish State value for the specified inventory item.
460 * @param inventoryItem D-Bus inventory item associated with a sensor.
461 * @return State value for inventory item.
James Feist34dd1792019-05-17 14:10:54 -0700462 */
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500463static std::string getState(const InventoryItem* inventoryItem)
464{
465 if ((inventoryItem != nullptr) && !(inventoryItem->isPresent))
466 {
467 return "Absent";
468 }
James Feist34dd1792019-05-17 14:10:54 -0700469
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500470 return "Enabled";
471}
472
473/**
474 * @brief Returns the Redfish Health value for the specified sensor.
475 * @param sensorJson Sensor JSON object.
476 * @param interfacesDict Map of all sensor interfaces.
477 * @param inventoryItem D-Bus inventory item associated with the sensor. Will
478 * be nullptr if no associated inventory item was found.
479 * @return Health value for sensor.
480 */
James Feist34dd1792019-05-17 14:10:54 -0700481static std::string getHealth(
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500482 nlohmann::json& sensorJson,
James Feist34dd1792019-05-17 14:10:54 -0700483 const boost::container::flat_map<
484 std::string, boost::container::flat_map<std::string, SensorVariant>>&
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500485 interfacesDict,
486 const InventoryItem* inventoryItem)
James Feist34dd1792019-05-17 14:10:54 -0700487{
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500488 // Get current health value (if any) in the sensor JSON object. Some JSON
489 // objects contain multiple sensors (such as PowerSupplies). We want to set
490 // the overall health to be the most severe of any of the sensors.
491 std::string currentHealth;
492 auto statusIt = sensorJson.find("Status");
493 if (statusIt != sensorJson.end())
494 {
495 auto healthIt = statusIt->find("Health");
496 if (healthIt != statusIt->end())
497 {
498 std::string* health = healthIt->get_ptr<std::string*>();
499 if (health != nullptr)
500 {
501 currentHealth = *health;
502 }
503 }
504 }
505
506 // If current health in JSON object is already Critical, return that. This
507 // should override the sensor health, which might be less severe.
508 if (currentHealth == "Critical")
509 {
510 return "Critical";
511 }
512
513 // Check if sensor has critical threshold alarm
James Feist34dd1792019-05-17 14:10:54 -0700514 auto criticalThresholdIt =
515 interfacesDict.find("xyz.openbmc_project.Sensor.Threshold.Critical");
516 if (criticalThresholdIt != interfacesDict.end())
517 {
518 auto thresholdHighIt =
519 criticalThresholdIt->second.find("CriticalAlarmHigh");
520 auto thresholdLowIt =
521 criticalThresholdIt->second.find("CriticalAlarmLow");
522 if (thresholdHighIt != criticalThresholdIt->second.end())
523 {
524 const bool* asserted = std::get_if<bool>(&thresholdHighIt->second);
525 if (asserted == nullptr)
526 {
527 BMCWEB_LOG_ERROR << "Illegal sensor threshold";
528 }
529 else if (*asserted)
530 {
531 return "Critical";
532 }
533 }
534 if (thresholdLowIt != criticalThresholdIt->second.end())
535 {
536 const bool* asserted = std::get_if<bool>(&thresholdLowIt->second);
537 if (asserted == nullptr)
538 {
539 BMCWEB_LOG_ERROR << "Illegal sensor threshold";
540 }
541 else if (*asserted)
542 {
543 return "Critical";
544 }
545 }
546 }
547
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500548 // Check if associated inventory item is not functional
549 if ((inventoryItem != nullptr) && !(inventoryItem->isFunctional))
550 {
551 return "Critical";
552 }
553
554 // If current health in JSON object is already Warning, return that. This
555 // should override the sensor status, which might be less severe.
556 if (currentHealth == "Warning")
557 {
558 return "Warning";
559 }
560
561 // Check if sensor has warning threshold alarm
James Feist34dd1792019-05-17 14:10:54 -0700562 auto warningThresholdIt =
563 interfacesDict.find("xyz.openbmc_project.Sensor.Threshold.Warning");
564 if (warningThresholdIt != interfacesDict.end())
565 {
566 auto thresholdHighIt =
567 warningThresholdIt->second.find("WarningAlarmHigh");
568 auto thresholdLowIt =
569 warningThresholdIt->second.find("WarningAlarmLow");
570 if (thresholdHighIt != warningThresholdIt->second.end())
571 {
572 const bool* asserted = std::get_if<bool>(&thresholdHighIt->second);
573 if (asserted == nullptr)
574 {
575 BMCWEB_LOG_ERROR << "Illegal sensor threshold";
576 }
577 else if (*asserted)
578 {
579 return "Warning";
580 }
581 }
582 if (thresholdLowIt != warningThresholdIt->second.end())
583 {
584 const bool* asserted = std::get_if<bool>(&thresholdLowIt->second);
585 if (asserted == nullptr)
586 {
587 BMCWEB_LOG_ERROR << "Illegal sensor threshold";
588 }
589 else if (*asserted)
590 {
591 return "Warning";
592 }
593 }
594 }
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500595
James Feist34dd1792019-05-17 14:10:54 -0700596 return "OK";
597}
598
599/**
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100600 * @brief Builds a json sensor representation of a sensor.
601 * @param sensorName The name of the sensor to be built
Gunnar Mills274fad52018-06-13 15:45:36 -0500602 * @param sensorType The type (temperature, fan_tach, etc) of the sensor to
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100603 * build
Anthony Wilson95a3eca2019-06-11 10:44:47 -0500604 * @param sensorSchema The schema (Power, Thermal, etc) being associated with
605 * the sensor to build
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100606 * @param interfacesDict A dictionary of the interfaces and properties of said
607 * interfaces to be built from
608 * @param sensor_json The json object to fill
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500609 * @param inventoryItem D-Bus inventory item associated with the sensor. Will
610 * be nullptr if no associated inventory item was found.
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100611 */
612void objectInterfacesToJson(
613 const std::string& sensorName, const std::string& sensorType,
Anthony Wilson95a3eca2019-06-11 10:44:47 -0500614 const std::string& sensorSchema,
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100615 const boost::container::flat_map<
Ed Tanousaa2e59c2018-04-12 12:17:20 -0700616 std::string, boost::container::flat_map<std::string, SensorVariant>>&
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100617 interfacesDict,
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500618 nlohmann::json& sensor_json, InventoryItem* inventoryItem)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700619{
620 // We need a value interface before we can do anything with it
621 auto valueIt = interfacesDict.find("xyz.openbmc_project.Sensor.Value");
622 if (valueIt == interfacesDict.end())
623 {
624 BMCWEB_LOG_ERROR << "Sensor doesn't have a value interface";
625 return;
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100626 }
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100627
Ed Tanous1abe55e2018-09-05 08:30:59 -0700628 // Assume values exist as is (10^0 == 1) if no scale exists
629 int64_t scaleMultiplier = 0;
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100630
Ed Tanous1abe55e2018-09-05 08:30:59 -0700631 auto scaleIt = valueIt->second.find("Scale");
632 // If a scale exists, pull value as int64, and use the scaling.
633 if (scaleIt != valueIt->second.end())
634 {
Ed Tanousabf2add2019-01-22 16:40:12 -0800635 const int64_t* int64Value = std::get_if<int64_t>(&scaleIt->second);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700636 if (int64Value != nullptr)
637 {
638 scaleMultiplier = *int64Value;
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100639 }
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100640 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700641
Anthony Wilson95a3eca2019-06-11 10:44:47 -0500642 if (sensorSchema == "Sensors")
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500643 {
Anthony Wilson95a3eca2019-06-11 10:44:47 -0500644 // For sensors in SensorCollection we set Id instead of MemberId,
645 // including power sensors.
646 sensor_json["Id"] = sensorName;
647 sensor_json["Name"] = boost::replace_all_copy(sensorName, "_", " ");
648 }
649 else if (sensorType != "power")
650 {
651 // Set MemberId and Name for non-power sensors. For PowerSupplies and
652 // PowerControl, those properties have more general values because
653 // multiple sensors can be stored in the same JSON object.
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500654 sensor_json["MemberId"] = sensorName;
655 sensor_json["Name"] = boost::replace_all_copy(sensorName, "_", " ");
656 }
Ed Tanouse742b6c2019-05-03 15:06:53 -0700657
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500658 sensor_json["Status"]["State"] = getState(inventoryItem);
659 sensor_json["Status"]["Health"] =
660 getHealth(sensor_json, interfacesDict, inventoryItem);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700661
662 // Parameter to set to override the type we get from dbus, and force it to
663 // int, regardless of what is available. This is used for schemas like fan,
664 // that require integers, not floats.
665 bool forceToInt = false;
666
Anthony Wilson3929aca2019-07-19 15:42:33 -0500667 nlohmann::json::json_pointer unit("/Reading");
Anthony Wilson95a3eca2019-06-11 10:44:47 -0500668 if (sensorSchema == "Sensors")
669 {
670 sensor_json["@odata.type"] = "#Sensor.v1_0_0.Sensor";
671 sensor_json["@odata.context"] = "/redfish/v1/$metadata#Sensor.Sensor";
672 if (sensorType == "power")
673 {
674 sensor_json["ReadingUnits"] = "Watts";
675 }
676 else if (sensorType == "current")
677 {
678 sensor_json["ReadingUnits"] = "Amperes";
679 }
680 }
681 else if (sensorType == "temperature")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700682 {
Anthony Wilson3929aca2019-07-19 15:42:33 -0500683 unit = "/ReadingCelsius"_json_pointer;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700684 sensor_json["@odata.type"] = "#Thermal.v1_3_0.Temperature";
685 // TODO(ed) Documentation says that path should be type fan_tach,
686 // implementation seems to implement fan
687 }
688 else if (sensorType == "fan" || sensorType == "fan_tach")
689 {
Anthony Wilson3929aca2019-07-19 15:42:33 -0500690 unit = "/Reading"_json_pointer;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700691 sensor_json["ReadingUnits"] = "RPM";
692 sensor_json["@odata.type"] = "#Thermal.v1_3_0.Fan";
693 forceToInt = true;
694 }
Ed Tanous6f6d0d32018-10-12 11:16:43 -0700695 else if (sensorType == "fan_pwm")
696 {
Anthony Wilson3929aca2019-07-19 15:42:33 -0500697 unit = "/Reading"_json_pointer;
Ed Tanous6f6d0d32018-10-12 11:16:43 -0700698 sensor_json["ReadingUnits"] = "Percent";
699 sensor_json["@odata.type"] = "#Thermal.v1_3_0.Fan";
700 forceToInt = true;
701 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700702 else if (sensorType == "voltage")
703 {
Anthony Wilson3929aca2019-07-19 15:42:33 -0500704 unit = "/ReadingVolts"_json_pointer;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700705 sensor_json["@odata.type"] = "#Power.v1_0_0.Voltage";
706 }
Ed Tanous2474adf2018-09-05 16:31:16 -0700707 else if (sensorType == "power")
708 {
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700709 std::string sensorNameLower =
710 boost::algorithm::to_lower_copy(sensorName);
711
Eddie James028f7eb2019-05-17 21:24:36 +0000712 if (!sensorName.compare("total_power"))
713 {
Gunnar Mills7ab06f42019-07-02 13:07:16 -0500714 sensor_json["@odata.type"] = "#Power.v1_0_0.PowerControl";
715 // Put multiple "sensors" into a single PowerControl, so have
716 // generic names for MemberId and Name. Follows Redfish mockup.
717 sensor_json["MemberId"] = "0";
718 sensor_json["Name"] = "Chassis Power Control";
Anthony Wilson3929aca2019-07-19 15:42:33 -0500719 unit = "/PowerConsumedWatts"_json_pointer;
Eddie James028f7eb2019-05-17 21:24:36 +0000720 }
721 else if (sensorNameLower.find("input") != std::string::npos)
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700722 {
Anthony Wilson3929aca2019-07-19 15:42:33 -0500723 unit = "/PowerInputWatts"_json_pointer;
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700724 }
725 else
726 {
Anthony Wilson3929aca2019-07-19 15:42:33 -0500727 unit = "/PowerOutputWatts"_json_pointer;
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700728 }
Ed Tanous2474adf2018-09-05 16:31:16 -0700729 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700730 else
731 {
732 BMCWEB_LOG_ERROR << "Redfish cannot map object type for " << sensorName;
733 return;
734 }
735 // Map of dbus interface name, dbus property name and redfish property_name
Anthony Wilson3929aca2019-07-19 15:42:33 -0500736 std::vector<
737 std::tuple<const char*, const char*, nlohmann::json::json_pointer>>
738 properties;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700739 properties.reserve(7);
740
741 properties.emplace_back("xyz.openbmc_project.Sensor.Value", "Value", unit);
Shawn McCarneyde629b62019-03-08 10:42:51 -0600742
Anthony Wilson3929aca2019-07-19 15:42:33 -0500743 if (sensorSchema == "Sensors")
744 {
745 properties.emplace_back(
746 "xyz.openbmc_project.Sensor.Threshold.Warning", "WarningHigh",
747 "/Thresholds/UpperCaution/Reading"_json_pointer);
748 properties.emplace_back(
749 "xyz.openbmc_project.Sensor.Threshold.Warning", "WarningLow",
750 "/Thresholds/LowerCaution/Reading"_json_pointer);
751 properties.emplace_back(
752 "xyz.openbmc_project.Sensor.Threshold.Critical", "CriticalHigh",
753 "/Thresholds/UpperCritical/Reading"_json_pointer);
754 properties.emplace_back(
755 "xyz.openbmc_project.Sensor.Threshold.Critical", "CriticalLow",
756 "/Thresholds/LowerCritical/Reading"_json_pointer);
757 }
758 else if (sensorType != "power")
Shawn McCarneyde629b62019-03-08 10:42:51 -0600759 {
760 properties.emplace_back("xyz.openbmc_project.Sensor.Threshold.Warning",
Anthony Wilson3929aca2019-07-19 15:42:33 -0500761 "WarningHigh",
762 "/UpperThresholdNonCritical"_json_pointer);
Shawn McCarneyde629b62019-03-08 10:42:51 -0600763 properties.emplace_back("xyz.openbmc_project.Sensor.Threshold.Warning",
Anthony Wilson3929aca2019-07-19 15:42:33 -0500764 "WarningLow",
765 "/LowerThresholdNonCritical"_json_pointer);
Shawn McCarneyde629b62019-03-08 10:42:51 -0600766 properties.emplace_back("xyz.openbmc_project.Sensor.Threshold.Critical",
Anthony Wilson3929aca2019-07-19 15:42:33 -0500767 "CriticalHigh",
768 "/UpperThresholdCritical"_json_pointer);
Shawn McCarneyde629b62019-03-08 10:42:51 -0600769 properties.emplace_back("xyz.openbmc_project.Sensor.Threshold.Critical",
Anthony Wilson3929aca2019-07-19 15:42:33 -0500770 "CriticalLow",
771 "/LowerThresholdCritical"_json_pointer);
Shawn McCarneyde629b62019-03-08 10:42:51 -0600772 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700773
Ed Tanous2474adf2018-09-05 16:31:16 -0700774 // TODO Need to get UpperThresholdFatal and LowerThresholdFatal
775
Anthony Wilson95a3eca2019-06-11 10:44:47 -0500776 if (sensorSchema == "Sensors")
777 {
778 properties.emplace_back("xyz.openbmc_project.Sensor.Value", "MinValue",
Anthony Wilson3929aca2019-07-19 15:42:33 -0500779 "/ReadingRangeMin"_json_pointer);
Anthony Wilson95a3eca2019-06-11 10:44:47 -0500780 properties.emplace_back("xyz.openbmc_project.Sensor.Value", "MaxValue",
Anthony Wilson3929aca2019-07-19 15:42:33 -0500781 "/ReadingRangeMax"_json_pointer);
Anthony Wilson95a3eca2019-06-11 10:44:47 -0500782 }
783 else if (sensorType == "temperature")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700784 {
785 properties.emplace_back("xyz.openbmc_project.Sensor.Value", "MinValue",
Anthony Wilson3929aca2019-07-19 15:42:33 -0500786 "/MinReadingRangeTemp"_json_pointer);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700787 properties.emplace_back("xyz.openbmc_project.Sensor.Value", "MaxValue",
Anthony Wilson3929aca2019-07-19 15:42:33 -0500788 "/MaxReadingRangeTemp"_json_pointer);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700789 }
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500790 else if (sensorType != "power")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700791 {
792 properties.emplace_back("xyz.openbmc_project.Sensor.Value", "MinValue",
Anthony Wilson3929aca2019-07-19 15:42:33 -0500793 "/MinReadingRange"_json_pointer);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700794 properties.emplace_back("xyz.openbmc_project.Sensor.Value", "MaxValue",
Anthony Wilson3929aca2019-07-19 15:42:33 -0500795 "/MaxReadingRange"_json_pointer);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700796 }
797
Anthony Wilson3929aca2019-07-19 15:42:33 -0500798 for (const std::tuple<const char*, const char*,
799 nlohmann::json::json_pointer>& p : properties)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700800 {
801 auto interfaceProperties = interfacesDict.find(std::get<0>(p));
802 if (interfaceProperties != interfacesDict.end())
803 {
Ed Tanous271584a2019-07-09 16:24:22 -0700804 auto thisValueIt = interfaceProperties->second.find(std::get<1>(p));
805 if (thisValueIt != interfaceProperties->second.end())
Ed Tanous1abe55e2018-09-05 08:30:59 -0700806 {
Ed Tanous271584a2019-07-09 16:24:22 -0700807 const SensorVariant& valueVariant = thisValueIt->second;
Anthony Wilson3929aca2019-07-19 15:42:33 -0500808
809 // The property we want to set may be nested json, so use
810 // a json_pointer for easy indexing into the json structure.
811 const nlohmann::json::json_pointer& key = std::get<2>(p);
812
Ed Tanous1abe55e2018-09-05 08:30:59 -0700813 // Attempt to pull the int64 directly
Ed Tanousabf2add2019-01-22 16:40:12 -0800814 const int64_t* int64Value = std::get_if<int64_t>(&valueVariant);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700815
Ed Tanousabf2add2019-01-22 16:40:12 -0800816 const double* doubleValue = std::get_if<double>(&valueVariant);
Eddie James028f7eb2019-05-17 21:24:36 +0000817 const uint32_t* uValue = std::get_if<uint32_t>(&valueVariant);
Ed Tanous6f6d0d32018-10-12 11:16:43 -0700818 double temp = 0.0;
819 if (int64Value != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700820 {
Ed Tanous271584a2019-07-09 16:24:22 -0700821 temp = static_cast<double>(*int64Value);
Ed Tanous6f6d0d32018-10-12 11:16:43 -0700822 }
823 else if (doubleValue != nullptr)
824 {
825 temp = *doubleValue;
826 }
Eddie James028f7eb2019-05-17 21:24:36 +0000827 else if (uValue != nullptr)
828 {
829 temp = *uValue;
830 }
Ed Tanous6f6d0d32018-10-12 11:16:43 -0700831 else
832 {
833 BMCWEB_LOG_ERROR
834 << "Got value interface that wasn't int or double";
835 continue;
836 }
837 temp = temp * std::pow(10, scaleMultiplier);
838 if (forceToInt)
839 {
Anthony Wilson3929aca2019-07-19 15:42:33 -0500840 sensor_json[key] = static_cast<int64_t>(temp);
Ed Tanous6f6d0d32018-10-12 11:16:43 -0700841 }
842 else
843 {
Anthony Wilson3929aca2019-07-19 15:42:33 -0500844 sensor_json[key] = temp;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700845 }
846 }
847 }
848 }
849 BMCWEB_LOG_DEBUG << "Added sensor " << sensorName;
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +0100850}
851
James Feist8bd25cc2019-03-15 15:14:00 -0700852static void
853 populateFanRedundancy(std::shared_ptr<SensorsAsyncResp> sensorsAsyncResp)
854{
855 crow::connections::systemBus->async_method_call(
856 [sensorsAsyncResp](const boost::system::error_code ec,
857 const GetSubTreeType& resp) {
858 if (ec)
859 {
860 return; // don't have to have this interface
861 }
Ed Tanouse278c182019-03-13 16:23:37 -0700862 for (const std::pair<std::string,
863 std::vector<std::pair<
864 std::string, std::vector<std::string>>>>&
865 pathPair : resp)
James Feist8bd25cc2019-03-15 15:14:00 -0700866 {
Ed Tanouse278c182019-03-13 16:23:37 -0700867 const std::string& path = pathPair.first;
868 const std::vector<
869 std::pair<std::string, std::vector<std::string>>>& objDict =
870 pathPair.second;
James Feist8bd25cc2019-03-15 15:14:00 -0700871 if (objDict.empty())
872 {
873 continue; // this should be impossible
874 }
875
876 const std::string& owner = objDict.begin()->first;
877 crow::connections::systemBus->async_method_call(
878 [path, owner,
Ed Tanous271584a2019-07-09 16:24:22 -0700879 sensorsAsyncResp](const boost::system::error_code e,
James Feist8bd25cc2019-03-15 15:14:00 -0700880 std::variant<std::vector<std::string>>
881 variantEndpoints) {
Ed Tanous271584a2019-07-09 16:24:22 -0700882 if (e)
James Feist8bd25cc2019-03-15 15:14:00 -0700883 {
884 return; // if they don't have an association we
885 // can't tell what chassis is
886 }
887 // verify part of the right chassis
888 auto endpoints = std::get_if<std::vector<std::string>>(
889 &variantEndpoints);
890
891 if (endpoints == nullptr)
892 {
893 BMCWEB_LOG_ERROR << "Invalid association interface";
894 messages::internalError(sensorsAsyncResp->res);
895 return;
896 }
897
898 auto found = std::find_if(
899 endpoints->begin(), endpoints->end(),
900 [sensorsAsyncResp](const std::string& entry) {
901 return entry.find(
902 sensorsAsyncResp->chassisId) !=
903 std::string::npos;
904 });
905
906 if (found == endpoints->end())
907 {
908 return;
909 }
910 crow::connections::systemBus->async_method_call(
911 [path, sensorsAsyncResp](
Ed Tanous271584a2019-07-09 16:24:22 -0700912 const boost::system::error_code& err,
James Feist8bd25cc2019-03-15 15:14:00 -0700913 const boost::container::flat_map<
914 std::string,
915 std::variant<uint8_t,
916 std::vector<std::string>,
917 std::string>>& ret) {
Ed Tanous271584a2019-07-09 16:24:22 -0700918 if (err)
James Feist8bd25cc2019-03-15 15:14:00 -0700919 {
920 return; // don't have to have this
921 // interface
922 }
923 auto findFailures = ret.find("AllowedFailures");
924 auto findCollection = ret.find("Collection");
925 auto findStatus = ret.find("Status");
926
927 if (findFailures == ret.end() ||
928 findCollection == ret.end() ||
929 findStatus == ret.end())
930 {
931 BMCWEB_LOG_ERROR
932 << "Invalid redundancy interface";
933 messages::internalError(
934 sensorsAsyncResp->res);
935 return;
936 }
937
938 auto allowedFailures = std::get_if<uint8_t>(
939 &(findFailures->second));
940 auto collection =
941 std::get_if<std::vector<std::string>>(
942 &(findCollection->second));
943 auto status = std::get_if<std::string>(
944 &(findStatus->second));
945
946 if (allowedFailures == nullptr ||
947 collection == nullptr || status == nullptr)
948 {
949
950 BMCWEB_LOG_ERROR
951 << "Invalid redundancy interface "
952 "types";
953 messages::internalError(
954 sensorsAsyncResp->res);
955 return;
956 }
957 size_t lastSlash = path.rfind("/");
958 if (lastSlash == std::string::npos)
959 {
960 // this should be impossible
961 messages::internalError(
962 sensorsAsyncResp->res);
963 return;
964 }
965 std::string name = path.substr(lastSlash + 1);
966 std::replace(name.begin(), name.end(), '_',
967 ' ');
968
969 std::string health;
970
971 if (boost::ends_with(*status, "Full"))
972 {
973 health = "OK";
974 }
975 else if (boost::ends_with(*status, "Degraded"))
976 {
977 health = "Warning";
978 }
979 else
980 {
981 health = "Critical";
982 }
983 std::vector<nlohmann::json> redfishCollection;
984 const auto& fanRedfish =
985 sensorsAsyncResp->res.jsonValue["Fans"];
986 for (const std::string& item : *collection)
987 {
988 lastSlash = item.rfind("/");
989 // make a copy as collection is const
990 std::string itemName =
991 item.substr(lastSlash + 1);
992 /*
993 todo(ed): merge patch that fixes the names
994 std::replace(itemName.begin(),
995 itemName.end(), '_', ' ');*/
996 auto schemaItem = std::find_if(
997 fanRedfish.begin(), fanRedfish.end(),
998 [itemName](const nlohmann::json& fan) {
999 return fan["MemberId"] == itemName;
1000 });
1001 if (schemaItem != fanRedfish.end())
1002 {
1003 redfishCollection.push_back(
1004 {{"@odata.id",
1005 (*schemaItem)["@odata.id"]}});
1006 }
1007 else
1008 {
1009 BMCWEB_LOG_ERROR
1010 << "failed to find fan in schema";
1011 messages::internalError(
1012 sensorsAsyncResp->res);
1013 return;
1014 }
1015 }
1016
Ed Tanous271584a2019-07-09 16:24:22 -07001017 nlohmann::json& jResp =
1018 sensorsAsyncResp->res
1019 .jsonValue["Redundancy"];
1020 jResp.push_back(
James Feist8bd25cc2019-03-15 15:14:00 -07001021 {{"@odata.id",
AppaRao Puli717794d2019-10-18 22:54:53 +05301022 "/redfish/v1/Chassis/" +
James Feist8bd25cc2019-03-15 15:14:00 -07001023 sensorsAsyncResp->chassisId + "/" +
1024 sensorsAsyncResp->chassisSubNode +
1025 "#/Redundancy/" +
Ed Tanous271584a2019-07-09 16:24:22 -07001026 std::to_string(jResp.size())},
James Feist8bd25cc2019-03-15 15:14:00 -07001027 {"@odata.type",
1028 "#Redundancy.v1_3_2.Redundancy"},
1029 {"MinNumNeeded",
1030 collection->size() - *allowedFailures},
1031 {"MemberId", name},
1032 {"Mode", "N+m"},
1033 {"Name", name},
1034 {"RedundancySet", redfishCollection},
1035 {"Status",
1036 {{"Health", health},
1037 {"State", "Enabled"}}}});
1038 },
1039 owner, path, "org.freedesktop.DBus.Properties",
1040 "GetAll",
1041 "xyz.openbmc_project.Control.FanRedundancy");
1042 },
James Feist02e92e32019-06-26 12:07:05 -07001043 "xyz.openbmc_project.ObjectMapper", path + "/chassis",
James Feist8bd25cc2019-03-15 15:14:00 -07001044 "org.freedesktop.DBus.Properties", "Get",
1045 "xyz.openbmc_project.Association", "endpoints");
1046 }
1047 },
1048 "xyz.openbmc_project.ObjectMapper",
1049 "/xyz/openbmc_project/object_mapper",
1050 "xyz.openbmc_project.ObjectMapper", "GetSubTree",
1051 "/xyz/openbmc_project/control", 2,
1052 std::array<const char*, 1>{
1053 "xyz.openbmc_project.Control.FanRedundancy"});
1054}
1055
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07001056void sortJSONResponse(std::shared_ptr<SensorsAsyncResp> SensorsAsyncResp)
1057{
1058 nlohmann::json& response = SensorsAsyncResp->res.jsonValue;
1059 std::array<std::string, 2> sensorHeaders{"Temperatures", "Fans"};
1060 if (SensorsAsyncResp->chassisSubNode == "Power")
1061 {
1062 sensorHeaders = {"Voltages", "PowerSupplies"};
1063 }
1064 for (const std::string& sensorGroup : sensorHeaders)
1065 {
1066 nlohmann::json::iterator entry = response.find(sensorGroup);
1067 if (entry != response.end())
1068 {
1069 std::sort(entry->begin(), entry->end(),
1070 [](nlohmann::json& c1, nlohmann::json& c2) {
1071 return c1["Name"] < c2["Name"];
1072 });
1073
1074 // add the index counts to the end of each entry
1075 size_t count = 0;
1076 for (nlohmann::json& sensorJson : *entry)
1077 {
1078 nlohmann::json::iterator odata = sensorJson.find("@odata.id");
1079 if (odata == sensorJson.end())
1080 {
1081 continue;
1082 }
1083 std::string* value = odata->get_ptr<std::string*>();
1084 if (value != nullptr)
1085 {
1086 *value += std::to_string(count);
1087 count++;
1088 }
1089 }
1090 }
1091 }
1092}
1093
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +01001094/**
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001095 * @brief Finds the inventory item with the specified object path.
1096 * @param inventoryItems D-Bus inventory items associated with sensors.
1097 * @param invItemObjPath D-Bus object path of inventory item.
1098 * @return Inventory item within vector, or nullptr if no match found.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001099 */
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001100static InventoryItem* findInventoryItem(
1101 std::shared_ptr<std::vector<InventoryItem>> inventoryItems,
1102 const std::string& invItemObjPath)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001103{
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001104 for (InventoryItem& inventoryItem : *inventoryItems)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001105 {
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001106 if (inventoryItem.objectPath == invItemObjPath)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001107 {
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001108 return &inventoryItem;
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001109 }
1110 }
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001111 return nullptr;
1112}
1113
1114/**
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001115 * @brief Finds the inventory item associated with the specified sensor.
1116 * @param inventoryItems D-Bus inventory items associated with sensors.
1117 * @param sensorObjPath D-Bus object path of sensor.
1118 * @return Inventory item within vector, or nullptr if no match found.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001119 */
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001120static InventoryItem* findInventoryItemForSensor(
1121 std::shared_ptr<std::vector<InventoryItem>> inventoryItems,
1122 const std::string& sensorObjPath)
1123{
1124 for (InventoryItem& inventoryItem : *inventoryItems)
1125 {
1126 if (inventoryItem.sensors.count(sensorObjPath) > 0)
1127 {
1128 return &inventoryItem;
1129 }
1130 }
1131 return nullptr;
1132}
1133
1134/**
1135 * @brief Adds inventory item and associated sensor to specified vector.
1136 *
1137 * Adds a new InventoryItem to the vector if necessary. Searches for an
1138 * existing InventoryItem with the specified object path. If not found, one is
1139 * added to the vector.
1140 *
1141 * Next, the specified sensor is added to the set of sensors associated with the
1142 * InventoryItem.
1143 *
1144 * @param inventoryItems D-Bus inventory items associated with sensors.
1145 * @param invItemObjPath D-Bus object path of inventory item.
1146 * @param sensorObjPath D-Bus object path of sensor
1147 */
1148static void
1149 addInventoryItem(std::shared_ptr<std::vector<InventoryItem>> inventoryItems,
1150 const std::string& invItemObjPath,
1151 const std::string& sensorObjPath)
1152{
1153 // Look for inventory item in vector
1154 InventoryItem* inventoryItem =
1155 findInventoryItem(inventoryItems, invItemObjPath);
1156
1157 // If inventory item doesn't exist in vector, add it
1158 if (inventoryItem == nullptr)
1159 {
1160 inventoryItems->emplace_back(invItemObjPath);
1161 inventoryItem = &(inventoryItems->back());
1162 }
1163
1164 // Add sensor to set of sensors associated with inventory item
1165 inventoryItem->sensors.emplace(sensorObjPath);
1166}
1167
1168/**
1169 * @brief Stores D-Bus data in the specified inventory item.
1170 *
1171 * Finds D-Bus data in the specified map of interfaces. Stores the data in the
1172 * specified InventoryItem.
1173 *
1174 * This data is later used to provide sensor property values in the JSON
1175 * response.
1176 *
1177 * @param inventoryItem Inventory item where data will be stored.
1178 * @param interfacesDict Map containing D-Bus interfaces and their properties
1179 * for the specified inventory item.
1180 */
1181static void storeInventoryItemData(
1182 InventoryItem& inventoryItem,
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001183 const boost::container::flat_map<
1184 std::string, boost::container::flat_map<std::string, SensorVariant>>&
1185 interfacesDict)
1186{
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001187 // Get properties from Inventory.Item interface
1188 auto interfaceIt =
1189 interfacesDict.find("xyz.openbmc_project.Inventory.Item");
1190 if (interfaceIt != interfacesDict.end())
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001191 {
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001192 auto propertyIt = interfaceIt->second.find("Present");
1193 if (propertyIt != interfaceIt->second.end())
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001194 {
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001195 const bool* value = std::get_if<bool>(&propertyIt->second);
1196 if (value != nullptr)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001197 {
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001198 inventoryItem.isPresent = *value;
1199 }
1200 }
1201 }
1202
1203 // Check if Inventory.Item.PowerSupply interface is present
1204 interfaceIt =
1205 interfacesDict.find("xyz.openbmc_project.Inventory.Item.PowerSupply");
1206 if (interfaceIt != interfacesDict.end())
1207 {
1208 inventoryItem.isPowerSupply = true;
1209 }
1210
1211 // Get properties from Inventory.Decorator.Asset interface
1212 interfaceIt =
1213 interfacesDict.find("xyz.openbmc_project.Inventory.Decorator.Asset");
1214 if (interfaceIt != interfacesDict.end())
1215 {
1216 auto propertyIt = interfaceIt->second.find("Manufacturer");
1217 if (propertyIt != interfaceIt->second.end())
1218 {
1219 const std::string* value =
1220 std::get_if<std::string>(&propertyIt->second);
1221 if (value != nullptr)
1222 {
1223 inventoryItem.manufacturer = *value;
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001224 }
1225 }
1226
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001227 propertyIt = interfaceIt->second.find("Model");
1228 if (propertyIt != interfaceIt->second.end())
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001229 {
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001230 const std::string* value =
1231 std::get_if<std::string>(&propertyIt->second);
1232 if (value != nullptr)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001233 {
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001234 inventoryItem.model = *value;
1235 }
1236 }
1237
1238 propertyIt = interfaceIt->second.find("PartNumber");
1239 if (propertyIt != interfaceIt->second.end())
1240 {
1241 const std::string* value =
1242 std::get_if<std::string>(&propertyIt->second);
1243 if (value != nullptr)
1244 {
1245 inventoryItem.partNumber = *value;
1246 }
1247 }
1248
1249 propertyIt = interfaceIt->second.find("SerialNumber");
1250 if (propertyIt != interfaceIt->second.end())
1251 {
1252 const std::string* value =
1253 std::get_if<std::string>(&propertyIt->second);
1254 if (value != nullptr)
1255 {
1256 inventoryItem.serialNumber = *value;
1257 }
1258 }
1259 }
1260
1261 // Get properties from State.Decorator.OperationalStatus interface
1262 interfaceIt = interfacesDict.find(
1263 "xyz.openbmc_project.State.Decorator.OperationalStatus");
1264 if (interfaceIt != interfacesDict.end())
1265 {
1266 auto propertyIt = interfaceIt->second.find("Functional");
1267 if (propertyIt != interfaceIt->second.end())
1268 {
1269 const bool* value = std::get_if<bool>(&propertyIt->second);
1270 if (value != nullptr)
1271 {
1272 inventoryItem.isFunctional = *value;
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001273 }
1274 }
1275 }
1276}
1277
1278/**
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001279 * @brief Gets D-Bus data for inventory items associated with sensors.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001280 *
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001281 * Uses the specified connections (services) to obtain D-Bus data for inventory
1282 * items associated with sensors. Stores the resulting data in the
1283 * inventoryItems vector.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001284 *
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001285 * This data is later used to provide sensor property values in the JSON
1286 * response.
1287 *
1288 * Finds the inventory item data asynchronously. Invokes callback when data has
1289 * been obtained.
1290 *
1291 * The callback must have the following signature:
1292 * @code
1293 * callback(std::shared_ptr<std::vector<InventoryItem>> inventoryItems)
1294 * @endcode
1295 *
1296 * This function is called recursively, obtaining data asynchronously from one
1297 * connection in each call. This ensures the callback is not invoked until the
1298 * last asynchronous function has completed.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001299 *
1300 * @param sensorsAsyncResp Pointer to object holding response data.
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001301 * @param inventoryItems D-Bus inventory items associated with sensors.
1302 * @param invConnections Connections that provide data for the inventory items.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001303 * @param objectMgrPaths Mappings from connection name to DBus object path that
1304 * implements ObjectManager.
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001305 * @param callback Callback to invoke when inventory data has been obtained.
1306 * @param invConnectionsIndex Current index in invConnections. Only specified
1307 * in recursive calls to this function.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001308 */
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001309template <typename Callback>
1310static void getInventoryItemsData(
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001311 std::shared_ptr<SensorsAsyncResp> sensorsAsyncResp,
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001312 std::shared_ptr<std::vector<InventoryItem>> inventoryItems,
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001313 std::shared_ptr<boost::container::flat_set<std::string>> invConnections,
1314 std::shared_ptr<boost::container::flat_map<std::string, std::string>>
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001315 objectMgrPaths,
Ed Tanous271584a2019-07-09 16:24:22 -07001316 Callback&& callback, size_t invConnectionsIndex = 0)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001317{
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001318 BMCWEB_LOG_DEBUG << "getInventoryItemsData enter";
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001319
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001320 // If no more connections left, call callback
1321 if (invConnectionsIndex >= invConnections->size())
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001322 {
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001323 callback(inventoryItems);
1324 BMCWEB_LOG_DEBUG << "getInventoryItemsData exit";
1325 return;
1326 }
1327
1328 // Get inventory item data from current connection
1329 auto it = invConnections->nth(invConnectionsIndex);
1330 if (it != invConnections->end())
1331 {
1332 const std::string& invConnection = *it;
1333
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001334 // Response handler for GetManagedObjects
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001335 auto respHandler = [sensorsAsyncResp, inventoryItems, invConnections,
1336 objectMgrPaths, callback{std::move(callback)},
1337 invConnectionsIndex](
1338 const boost::system::error_code ec,
1339 ManagedObjectsVectorType& resp) {
1340 BMCWEB_LOG_DEBUG << "getInventoryItemsData respHandler enter";
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001341 if (ec)
1342 {
1343 BMCWEB_LOG_ERROR
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001344 << "getInventoryItemsData respHandler DBus error " << ec;
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001345 messages::internalError(sensorsAsyncResp->res);
1346 return;
1347 }
1348
1349 // Loop through returned object paths
1350 for (const auto& objDictEntry : resp)
1351 {
1352 const std::string& objPath =
1353 static_cast<const std::string&>(objDictEntry.first);
1354
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001355 // If this object path is one of the specified inventory items
1356 InventoryItem* inventoryItem =
1357 findInventoryItem(inventoryItems, objPath);
1358 if (inventoryItem != nullptr)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001359 {
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001360 // Store inventory data in InventoryItem
1361 storeInventoryItemData(*inventoryItem, objDictEntry.second);
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001362 }
1363 }
1364
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001365 // Recurse to get inventory item data from next connection
1366 getInventoryItemsData(sensorsAsyncResp, inventoryItems,
1367 invConnections, objectMgrPaths,
1368 std::move(callback), invConnectionsIndex + 1);
1369
1370 BMCWEB_LOG_DEBUG << "getInventoryItemsData respHandler exit";
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001371 };
1372
1373 // Find DBus object path that implements ObjectManager for the current
1374 // connection. If no mapping found, default to "/".
1375 auto iter = objectMgrPaths->find(invConnection);
1376 const std::string& objectMgrPath =
1377 (iter != objectMgrPaths->end()) ? iter->second : "/";
1378 BMCWEB_LOG_DEBUG << "ObjectManager path for " << invConnection << " is "
1379 << objectMgrPath;
1380
1381 // Get all object paths and their interfaces for current connection
1382 crow::connections::systemBus->async_method_call(
1383 std::move(respHandler), invConnection, objectMgrPath,
1384 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
1385 }
1386
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001387 BMCWEB_LOG_DEBUG << "getInventoryItemsData exit";
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001388}
1389
1390/**
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001391 * @brief Gets connections that provide D-Bus data for inventory items.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001392 *
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001393 * Gets the D-Bus connections (services) that provide data for the inventory
1394 * items that are associated with sensors.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001395 *
1396 * Finds the connections asynchronously. Invokes callback when information has
1397 * been obtained.
1398 *
1399 * The callback must have the following signature:
1400 * @code
1401 * callback(std::shared_ptr<boost::container::flat_set<std::string>>
1402 * invConnections)
1403 * @endcode
1404 *
1405 * @param sensorsAsyncResp Pointer to object holding response data.
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001406 * @param inventoryItems D-Bus inventory items associated with sensors.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001407 * @param callback Callback to invoke when connections have been obtained.
1408 */
1409template <typename Callback>
1410static void getInventoryItemsConnections(
1411 std::shared_ptr<SensorsAsyncResp> sensorsAsyncResp,
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001412 std::shared_ptr<std::vector<InventoryItem>> inventoryItems,
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001413 Callback&& callback)
1414{
1415 BMCWEB_LOG_DEBUG << "getInventoryItemsConnections enter";
1416
1417 const std::string path = "/xyz/openbmc_project/inventory";
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001418 const std::array<std::string, 4> interfaces = {
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001419 "xyz.openbmc_project.Inventory.Item",
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001420 "xyz.openbmc_project.Inventory.Item.PowerSupply",
1421 "xyz.openbmc_project.Inventory.Decorator.Asset",
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001422 "xyz.openbmc_project.State.Decorator.OperationalStatus"};
1423
1424 // Response handler for parsing output from GetSubTree
1425 auto respHandler = [callback{std::move(callback)}, sensorsAsyncResp,
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001426 inventoryItems](const boost::system::error_code ec,
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001427 const GetSubTreeType& subtree) {
1428 BMCWEB_LOG_DEBUG << "getInventoryItemsConnections respHandler enter";
1429 if (ec)
1430 {
1431 messages::internalError(sensorsAsyncResp->res);
1432 BMCWEB_LOG_ERROR
1433 << "getInventoryItemsConnections respHandler DBus error " << ec;
1434 return;
1435 }
1436
1437 // Make unique list of connections for desired inventory items
1438 std::shared_ptr<boost::container::flat_set<std::string>>
1439 invConnections =
1440 std::make_shared<boost::container::flat_set<std::string>>();
1441 invConnections->reserve(8);
1442
1443 // Loop through objects from GetSubTree
1444 for (const std::pair<
1445 std::string,
1446 std::vector<std::pair<std::string, std::vector<std::string>>>>&
1447 object : subtree)
1448 {
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001449 // Check if object path is one of the specified inventory items
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001450 const std::string& objPath = object.first;
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001451 if (findInventoryItem(inventoryItems, objPath) != nullptr)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001452 {
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001453 // Store all connections to inventory item
1454 for (const std::pair<std::string, std::vector<std::string>>&
1455 objData : object.second)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001456 {
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001457 const std::string& invConnection = objData.first;
1458 invConnections->insert(invConnection);
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001459 }
1460 }
1461 }
1462 callback(invConnections);
1463 BMCWEB_LOG_DEBUG << "getInventoryItemsConnections respHandler exit";
1464 };
1465
1466 // Make call to ObjectMapper to find all inventory items
1467 crow::connections::systemBus->async_method_call(
1468 std::move(respHandler), "xyz.openbmc_project.ObjectMapper",
1469 "/xyz/openbmc_project/object_mapper",
1470 "xyz.openbmc_project.ObjectMapper", "GetSubTree", path, 0, interfaces);
1471 BMCWEB_LOG_DEBUG << "getInventoryItemsConnections exit";
1472}
1473
1474/**
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001475 * @brief Gets associations from sensors to inventory items.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001476 *
1477 * Looks for ObjectMapper associations from the specified sensors to related
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001478 * inventory items.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001479 *
1480 * Finds the inventory items asynchronously. Invokes callback when information
1481 * has been obtained.
1482 *
1483 * The callback must have the following signature:
1484 * @code
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001485 * callback(std::shared_ptr<std::vector<InventoryItem>> inventoryItems)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001486 * @endcode
1487 *
1488 * @param sensorsAsyncResp Pointer to object holding response data.
1489 * @param sensorNames All sensors within the current chassis.
1490 * @param objectMgrPaths Mappings from connection name to DBus object path that
1491 * implements ObjectManager.
1492 * @param callback Callback to invoke when inventory items have been obtained.
1493 */
1494template <typename Callback>
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001495static void getInventoryItemAssociations(
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001496 std::shared_ptr<SensorsAsyncResp> sensorsAsyncResp,
1497 const std::shared_ptr<boost::container::flat_set<std::string>> sensorNames,
1498 std::shared_ptr<boost::container::flat_map<std::string, std::string>>
1499 objectMgrPaths,
1500 Callback&& callback)
1501{
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001502 BMCWEB_LOG_DEBUG << "getInventoryItemAssociations enter";
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001503
1504 // Response handler for GetManagedObjects
1505 auto respHandler = [callback{std::move(callback)}, sensorsAsyncResp,
1506 sensorNames](const boost::system::error_code ec,
1507 dbus::utility::ManagedObjectType& resp) {
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001508 BMCWEB_LOG_DEBUG << "getInventoryItemAssociations respHandler enter";
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001509 if (ec)
1510 {
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001511 BMCWEB_LOG_ERROR
1512 << "getInventoryItemAssociations respHandler DBus error " << ec;
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001513 messages::internalError(sensorsAsyncResp->res);
1514 return;
1515 }
1516
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001517 // Create vector to hold list of inventory items
1518 std::shared_ptr<std::vector<InventoryItem>> inventoryItems =
1519 std::make_shared<std::vector<InventoryItem>>();
1520
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001521 // Loop through returned object paths
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001522 std::string sensorAssocPath;
1523 sensorAssocPath.reserve(128); // avoid memory allocations
1524 for (const auto& objDictEntry : resp)
1525 {
1526 const std::string& objPath =
1527 static_cast<const std::string&>(objDictEntry.first);
1528 const boost::container::flat_map<
1529 std::string, boost::container::flat_map<
1530 std::string, dbus::utility::DbusVariantType>>&
1531 interfacesDict = objDictEntry.second;
1532
1533 // If path is inventory association for one of the specified sensors
1534 for (const std::string& sensorName : *sensorNames)
1535 {
1536 sensorAssocPath = sensorName;
1537 sensorAssocPath += "/inventory";
1538 if (objPath == sensorAssocPath)
1539 {
1540 // Get Association interface for object path
1541 auto assocIt =
1542 interfacesDict.find("xyz.openbmc_project.Association");
1543 if (assocIt != interfacesDict.end())
1544 {
1545 // Get inventory item from end point
1546 auto endpointsIt = assocIt->second.find("endpoints");
1547 if (endpointsIt != assocIt->second.end())
1548 {
1549 const std::vector<std::string>* endpoints =
1550 std::get_if<std::vector<std::string>>(
1551 &endpointsIt->second);
1552 if ((endpoints != nullptr) && !endpoints->empty())
1553 {
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001554 // Add inventory item to vector
1555 const std::string& invItemPath =
1556 endpoints->front();
1557 addInventoryItem(inventoryItems, invItemPath,
1558 sensorName);
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001559 }
1560 }
1561 }
1562 break;
1563 }
1564 }
1565 }
1566
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001567 callback(inventoryItems);
1568 BMCWEB_LOG_DEBUG << "getInventoryItemAssociations respHandler exit";
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001569 };
1570
1571 // Find DBus object path that implements ObjectManager for ObjectMapper
1572 std::string connection = "xyz.openbmc_project.ObjectMapper";
1573 auto iter = objectMgrPaths->find(connection);
1574 const std::string& objectMgrPath =
1575 (iter != objectMgrPaths->end()) ? iter->second : "/";
1576 BMCWEB_LOG_DEBUG << "ObjectManager path for " << connection << " is "
1577 << objectMgrPath;
1578
1579 // Call GetManagedObjects on the ObjectMapper to get all associations
1580 crow::connections::systemBus->async_method_call(
1581 std::move(respHandler), connection, objectMgrPath,
1582 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
1583
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001584 BMCWEB_LOG_DEBUG << "getInventoryItemAssociations exit";
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001585}
1586
1587/**
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001588 * @brief Gets inventory items associated with sensors.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001589 *
1590 * Finds the inventory items that are associated with the specified sensors.
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001591 * Then gets D-Bus data for the inventory items, such as presence and VPD.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001592 *
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001593 * This data is later used to provide sensor property values in the JSON
1594 * response.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001595 *
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001596 * Finds the inventory items asynchronously. Invokes callback when the
1597 * inventory items have been obtained.
1598 *
1599 * The callback must have the following signature:
1600 * @code
1601 * callback(std::shared_ptr<std::vector<InventoryItem>> inventoryItems)
1602 * @endcode
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001603 *
1604 * @param sensorsAsyncResp Pointer to object holding response data.
1605 * @param sensorNames All sensors within the current chassis.
1606 * @param objectMgrPaths Mappings from connection name to DBus object path that
1607 * implements ObjectManager.
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001608 * @param callback Callback to invoke when inventory items have been obtained.
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001609 */
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001610template <typename Callback>
1611static void getInventoryItems(
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001612 std::shared_ptr<SensorsAsyncResp> sensorsAsyncResp,
1613 const std::shared_ptr<boost::container::flat_set<std::string>> sensorNames,
1614 std::shared_ptr<boost::container::flat_map<std::string, std::string>>
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001615 objectMgrPaths,
1616 Callback&& callback)
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001617{
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001618 BMCWEB_LOG_DEBUG << "getInventoryItems enter";
1619 auto getInventoryItemAssociationsCb =
1620 [sensorsAsyncResp, objectMgrPaths, callback{std::move(callback)}](
1621 std::shared_ptr<std::vector<InventoryItem>> inventoryItems) {
1622 BMCWEB_LOG_DEBUG << "getInventoryItemAssociationsCb enter";
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001623 auto getInventoryItemsConnectionsCb =
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001624 [sensorsAsyncResp, inventoryItems, objectMgrPaths,
1625 callback{std::move(callback)}](
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001626 std::shared_ptr<boost::container::flat_set<std::string>>
1627 invConnections) {
1628 BMCWEB_LOG_DEBUG << "getInventoryItemsConnectionsCb enter";
1629
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001630 // Get inventory item data from connections
1631 getInventoryItemsData(sensorsAsyncResp, inventoryItems,
1632 invConnections, objectMgrPaths,
1633 std::move(callback));
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001634
1635 BMCWEB_LOG_DEBUG << "getInventoryItemsConnectionsCb exit";
1636 };
1637
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001638 // Get connections that provide inventory item data
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001639 getInventoryItemsConnections(
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001640 sensorsAsyncResp, inventoryItems,
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001641 std::move(getInventoryItemsConnectionsCb));
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001642 BMCWEB_LOG_DEBUG << "getInventoryItemAssociationsCb exit";
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001643 };
1644
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001645 // Get associations from sensors to inventory items
1646 getInventoryItemAssociations(sensorsAsyncResp, sensorNames, objectMgrPaths,
1647 std::move(getInventoryItemAssociationsCb));
1648 BMCWEB_LOG_DEBUG << "getInventoryItems exit";
1649}
1650
1651/**
1652 * @brief Returns JSON PowerSupply object for the specified inventory item.
1653 *
1654 * Searches for a JSON PowerSupply object that matches the specified inventory
1655 * item. If one is not found, a new PowerSupply object is added to the JSON
1656 * array.
1657 *
1658 * Multiple sensors are often associated with one power supply inventory item.
1659 * As a result, multiple sensor values are stored in one JSON PowerSupply
1660 * object.
1661 *
1662 * @param powerSupplyArray JSON array containing Redfish PowerSupply objects.
1663 * @param inventoryItem Inventory item for the power supply.
1664 * @param chassisId Chassis that contains the power supply.
1665 * @return JSON PowerSupply object for the specified inventory item.
1666 */
1667static nlohmann::json& getPowerSupply(nlohmann::json& powerSupplyArray,
1668 const InventoryItem& inventoryItem,
1669 const std::string& chassisId)
1670{
1671 // Check if matching PowerSupply object already exists in JSON array
1672 for (nlohmann::json& powerSupply : powerSupplyArray)
1673 {
1674 if (powerSupply["MemberId"] == inventoryItem.name)
1675 {
1676 return powerSupply;
1677 }
1678 }
1679
1680 // Add new PowerSupply object to JSON array
1681 powerSupplyArray.push_back({});
1682 nlohmann::json& powerSupply = powerSupplyArray.back();
1683 powerSupply["@odata.id"] =
1684 "/redfish/v1/Chassis/" + chassisId + "/Power#/PowerSupplies/";
1685 powerSupply["MemberId"] = inventoryItem.name;
1686 powerSupply["Name"] = boost::replace_all_copy(inventoryItem.name, "_", " ");
1687 powerSupply["Manufacturer"] = inventoryItem.manufacturer;
1688 powerSupply["Model"] = inventoryItem.model;
1689 powerSupply["PartNumber"] = inventoryItem.partNumber;
1690 powerSupply["SerialNumber"] = inventoryItem.serialNumber;
1691 powerSupply["Status"]["State"] = getState(&inventoryItem);
1692
1693 const char* health = inventoryItem.isFunctional ? "OK" : "Critical";
1694 powerSupply["Status"]["Health"] = health;
1695
1696 return powerSupply;
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001697}
1698
1699/**
Shawn McCarneyde629b62019-03-08 10:42:51 -06001700 * @brief Gets the values of the specified sensors.
1701 *
1702 * Stores the results as JSON in the SensorsAsyncResp.
1703 *
1704 * Gets the sensor values asynchronously. Stores the results later when the
1705 * information has been obtained.
1706 *
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001707 * The sensorNames set contains all requested sensors for the current chassis.
Shawn McCarneyde629b62019-03-08 10:42:51 -06001708 *
1709 * To minimize the number of DBus calls, the DBus method
1710 * org.freedesktop.DBus.ObjectManager.GetManagedObjects() is used to get the
1711 * values of all sensors provided by a connection (service).
1712 *
1713 * The connections set contains all the connections that provide sensor values.
1714 *
1715 * The objectMgrPaths map contains mappings from a connection name to the
1716 * corresponding DBus object path that implements ObjectManager.
1717 *
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001718 * The InventoryItem vector contains D-Bus inventory items associated with the
1719 * sensors. Inventory item data is needed for some Redfish sensor properties.
1720 *
Shawn McCarneyde629b62019-03-08 10:42:51 -06001721 * @param SensorsAsyncResp Pointer to object holding response data.
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001722 * @param sensorNames All requested sensors within the current chassis.
Shawn McCarneyde629b62019-03-08 10:42:51 -06001723 * @param connections Connections that provide sensor values.
1724 * @param objectMgrPaths Mappings from connection name to DBus object path that
1725 * implements ObjectManager.
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001726 * @param inventoryItems Inventory items associated with the sensors.
Shawn McCarneyde629b62019-03-08 10:42:51 -06001727 */
1728void getSensorData(
1729 std::shared_ptr<SensorsAsyncResp> SensorsAsyncResp,
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07001730 const std::shared_ptr<boost::container::flat_set<std::string>> sensorNames,
Shawn McCarneyde629b62019-03-08 10:42:51 -06001731 const boost::container::flat_set<std::string>& connections,
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001732 std::shared_ptr<boost::container::flat_map<std::string, std::string>>
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001733 objectMgrPaths,
1734 std::shared_ptr<std::vector<InventoryItem>> inventoryItems)
Shawn McCarneyde629b62019-03-08 10:42:51 -06001735{
1736 BMCWEB_LOG_DEBUG << "getSensorData enter";
1737 // Get managed objects from all services exposing sensors
1738 for (const std::string& connection : connections)
1739 {
1740 // Response handler to process managed objects
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001741 auto getManagedObjectsCb = [SensorsAsyncResp, sensorNames,
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001742 inventoryItems](
Shawn McCarneyde629b62019-03-08 10:42:51 -06001743 const boost::system::error_code ec,
1744 ManagedObjectsVectorType& resp) {
1745 BMCWEB_LOG_DEBUG << "getManagedObjectsCb enter";
1746 if (ec)
1747 {
1748 BMCWEB_LOG_ERROR << "getManagedObjectsCb DBUS error: " << ec;
1749 messages::internalError(SensorsAsyncResp->res);
1750 return;
1751 }
1752 // Go through all objects and update response with sensor data
1753 for (const auto& objDictEntry : resp)
1754 {
1755 const std::string& objPath =
1756 static_cast<const std::string&>(objDictEntry.first);
1757 BMCWEB_LOG_DEBUG << "getManagedObjectsCb parsing object "
1758 << objPath;
1759
Shawn McCarneyde629b62019-03-08 10:42:51 -06001760 std::vector<std::string> split;
1761 // Reserve space for
1762 // /xyz/openbmc_project/sensors/<name>/<subname>
1763 split.reserve(6);
1764 boost::algorithm::split(split, objPath, boost::is_any_of("/"));
1765 if (split.size() < 6)
1766 {
1767 BMCWEB_LOG_ERROR << "Got path that isn't long enough "
1768 << objPath;
1769 continue;
1770 }
1771 // These indexes aren't intuitive, as boost::split puts an empty
1772 // string at the beginning
1773 const std::string& sensorType = split[4];
1774 const std::string& sensorName = split[5];
1775 BMCWEB_LOG_DEBUG << "sensorName " << sensorName
1776 << " sensorType " << sensorType;
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07001777 if (sensorNames->find(objPath) == sensorNames->end())
Shawn McCarneyde629b62019-03-08 10:42:51 -06001778 {
1779 BMCWEB_LOG_ERROR << sensorName << " not in sensor list ";
1780 continue;
1781 }
1782
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001783 // Find inventory item (if any) associated with sensor
1784 InventoryItem* inventoryItem =
1785 findInventoryItemForSensor(inventoryItems, objPath);
1786
Anthony Wilson95a3eca2019-06-11 10:44:47 -05001787 const std::string& sensorSchema =
1788 SensorsAsyncResp->chassisSubNode;
1789
1790 nlohmann::json* sensorJson = nullptr;
1791
1792 if (sensorSchema == "Sensors")
Shawn McCarneyde629b62019-03-08 10:42:51 -06001793 {
Anthony Wilson95a3eca2019-06-11 10:44:47 -05001794 SensorsAsyncResp->res.jsonValue["@odata.id"] =
1795 "/redfish/v1/Chassis/" + SensorsAsyncResp->chassisId +
1796 "/" + SensorsAsyncResp->chassisSubNode + "/" +
1797 sensorName;
1798 sensorJson = &(SensorsAsyncResp->res.jsonValue);
Shawn McCarneyde629b62019-03-08 10:42:51 -06001799 }
1800 else
1801 {
Ed Tanous271584a2019-07-09 16:24:22 -07001802 std::string fieldName;
Anthony Wilson95a3eca2019-06-11 10:44:47 -05001803 if (sensorType == "temperature")
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001804 {
Anthony Wilson95a3eca2019-06-11 10:44:47 -05001805 fieldName = "Temperatures";
1806 }
1807 else if (sensorType == "fan" || sensorType == "fan_tach" ||
1808 sensorType == "fan_pwm")
1809 {
1810 fieldName = "Fans";
1811 }
1812 else if (sensorType == "voltage")
1813 {
1814 fieldName = "Voltages";
1815 }
1816 else if (sensorType == "power")
1817 {
1818 if (!sensorName.compare("total_power"))
1819 {
1820 fieldName = "PowerControl";
1821 }
1822 else if ((inventoryItem != nullptr) &&
1823 (inventoryItem->isPowerSupply))
1824 {
1825 fieldName = "PowerSupplies";
1826 }
1827 else
1828 {
1829 // Other power sensors are in SensorCollection
1830 continue;
1831 }
1832 }
1833 else
1834 {
1835 BMCWEB_LOG_ERROR << "Unsure how to handle sensorType "
1836 << sensorType;
1837 continue;
1838 }
1839
1840 nlohmann::json& tempArray =
1841 SensorsAsyncResp->res.jsonValue[fieldName];
1842 if (fieldName == "PowerControl")
1843 {
1844 if (tempArray.empty())
1845 {
1846 // Put multiple "sensors" into a single
1847 // PowerControl. Follows MemberId naming and
1848 // naming in power.hpp.
1849 tempArray.push_back(
1850 {{"@odata.id",
1851 "/redfish/v1/Chassis/" +
1852 SensorsAsyncResp->chassisId + "/" +
1853 SensorsAsyncResp->chassisSubNode + "#/" +
1854 fieldName + "/0"}});
1855 }
1856 sensorJson = &(tempArray.back());
1857 }
1858 else if (fieldName == "PowerSupplies")
1859 {
1860 if (inventoryItem != nullptr)
1861 {
1862 sensorJson =
1863 &(getPowerSupply(tempArray, *inventoryItem,
1864 SensorsAsyncResp->chassisId));
1865 }
1866 }
1867 else
1868 {
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001869 tempArray.push_back(
1870 {{"@odata.id",
1871 "/redfish/v1/Chassis/" +
1872 SensorsAsyncResp->chassisId + "/" +
1873 SensorsAsyncResp->chassisSubNode + "#/" +
Anthony Wilson95a3eca2019-06-11 10:44:47 -05001874 fieldName + "/"}});
1875 sensorJson = &(tempArray.back());
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001876 }
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07001877 }
Shawn McCarneyde629b62019-03-08 10:42:51 -06001878
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001879 if (sensorJson != nullptr)
1880 {
1881 objectInterfacesToJson(sensorName, sensorType,
Anthony Wilson95a3eca2019-06-11 10:44:47 -05001882 SensorsAsyncResp->chassisSubNode,
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -05001883 objDictEntry.second, *sensorJson,
1884 inventoryItem);
1885 }
Shawn McCarneyde629b62019-03-08 10:42:51 -06001886 }
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07001887 if (SensorsAsyncResp.use_count() == 1)
James Feist8bd25cc2019-03-15 15:14:00 -07001888 {
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07001889 sortJSONResponse(SensorsAsyncResp);
1890 if (SensorsAsyncResp->chassisSubNode == "Thermal")
1891 {
1892 populateFanRedundancy(SensorsAsyncResp);
1893 }
James Feist8bd25cc2019-03-15 15:14:00 -07001894 }
Shawn McCarneyde629b62019-03-08 10:42:51 -06001895 BMCWEB_LOG_DEBUG << "getManagedObjectsCb exit";
1896 };
1897
1898 // Find DBus object path that implements ObjectManager for the current
1899 // connection. If no mapping found, default to "/".
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001900 auto iter = objectMgrPaths->find(connection);
Shawn McCarneyde629b62019-03-08 10:42:51 -06001901 const std::string& objectMgrPath =
Shawn McCarney8fb49dd2019-06-12 17:47:00 -05001902 (iter != objectMgrPaths->end()) ? iter->second : "/";
Shawn McCarneyde629b62019-03-08 10:42:51 -06001903 BMCWEB_LOG_DEBUG << "ObjectManager path for " << connection << " is "
1904 << objectMgrPath;
1905
1906 crow::connections::systemBus->async_method_call(
1907 getManagedObjectsCb, connection, objectMgrPath,
1908 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
1909 };
1910 BMCWEB_LOG_DEBUG << "getSensorData exit";
1911}
1912
Anthony Wilson95a3eca2019-06-11 10:44:47 -05001913void processSensorList(
1914 std::shared_ptr<SensorsAsyncResp> SensorsAsyncResp,
1915 std::shared_ptr<boost::container::flat_set<std::string>> sensorNames)
1916{
1917 auto getConnectionCb =
1918 [SensorsAsyncResp, sensorNames](
1919 const boost::container::flat_set<std::string>& connections) {
1920 BMCWEB_LOG_DEBUG << "getConnectionCb enter";
1921 auto getObjectManagerPathsCb =
1922 [SensorsAsyncResp, sensorNames, connections](
1923 std::shared_ptr<
1924 boost::container::flat_map<std::string, std::string>>
1925 objectMgrPaths) {
1926 BMCWEB_LOG_DEBUG << "getObjectManagerPathsCb enter";
1927 auto getInventoryItemsCb =
1928 [SensorsAsyncResp, sensorNames, connections,
1929 objectMgrPaths](
1930 std::shared_ptr<std::vector<InventoryItem>>
1931 inventoryItems) {
1932 BMCWEB_LOG_DEBUG << "getInventoryItemsCb enter";
1933 // Get sensor data and store results in JSON
1934 getSensorData(SensorsAsyncResp, sensorNames,
1935 connections, objectMgrPaths,
1936 inventoryItems);
1937 BMCWEB_LOG_DEBUG << "getInventoryItemsCb exit";
1938 };
1939
1940 // Get inventory items associated with sensors
1941 getInventoryItems(SensorsAsyncResp, sensorNames,
1942 objectMgrPaths,
1943 std::move(getInventoryItemsCb));
1944
1945 BMCWEB_LOG_DEBUG << "getObjectManagerPathsCb exit";
1946 };
1947
1948 // Get mapping from connection names to the DBus object
1949 // paths that implement the ObjectManager interface
1950 getObjectManagerPaths(SensorsAsyncResp,
1951 std::move(getObjectManagerPathsCb));
1952 BMCWEB_LOG_DEBUG << "getConnectionCb exit";
1953 };
1954
1955 // Get set of connections that provide sensor values
1956 getConnections(SensorsAsyncResp, sensorNames, std::move(getConnectionCb));
1957}
1958
Shawn McCarneyde629b62019-03-08 10:42:51 -06001959/**
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +01001960 * @brief Entry point for retrieving sensors data related to requested
1961 * chassis.
Kowalski, Kamil588c3f02018-04-03 14:55:27 +02001962 * @param SensorsAsyncResp Pointer to object holding response data
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +01001963 */
Ed Tanous1abe55e2018-09-05 08:30:59 -07001964void getChassisData(std::shared_ptr<SensorsAsyncResp> SensorsAsyncResp)
1965{
1966 BMCWEB_LOG_DEBUG << "getChassisData enter";
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07001967 auto getChassisCb =
1968 [SensorsAsyncResp](
1969 std::shared_ptr<boost::container::flat_set<std::string>>
1970 sensorNames) {
1971 BMCWEB_LOG_DEBUG << "getChassisCb enter";
Anthony Wilson95a3eca2019-06-11 10:44:47 -05001972 processSensorList(SensorsAsyncResp, sensorNames);
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07001973 BMCWEB_LOG_DEBUG << "getChassisCb exit";
1974 };
Jennifer Lee4f9a2132019-03-04 12:45:19 -08001975 SensorsAsyncResp->res.jsonValue["Redundancy"] = nlohmann::json::array();
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +01001976
Shawn McCarney26f03892019-05-03 13:20:24 -05001977 // Get set of sensors in chassis
Ed Tanous1abe55e2018-09-05 08:30:59 -07001978 getChassis(SensorsAsyncResp, std::move(getChassisCb));
1979 BMCWEB_LOG_DEBUG << "getChassisData exit";
Ed Tanous271584a2019-07-09 16:24:22 -07001980}
Lewanczyk, Dawid08777fb2018-03-22 23:33:49 +01001981
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05301982/**
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07001983 * @brief Find the requested sensorName in the list of all sensors supplied by
1984 * the chassis node
1985 *
1986 * @param sensorName The sensor name supplied in the PATCH request
1987 * @param sensorsList The list of sensors managed by the chassis node
1988 * @param sensorsModified The list of sensors that were found as a result of
1989 * repeated calls to this function
1990 */
1991bool findSensorNameUsingSensorPath(
Richard Marian Thomaiyar0a86feb2019-05-27 23:16:40 +05301992 std::string_view sensorName,
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07001993 boost::container::flat_set<std::string>& sensorsList,
1994 boost::container::flat_set<std::string>& sensorsModified)
1995{
Richard Marian Thomaiyar0a86feb2019-05-27 23:16:40 +05301996 for (std::string_view chassisSensor : sensorsList)
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07001997 {
Richard Marian Thomaiyar0a86feb2019-05-27 23:16:40 +05301998 std::size_t pos = chassisSensor.rfind("/");
1999 if (pos >= (chassisSensor.size() - 1))
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07002000 {
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07002001 continue;
2002 }
Richard Marian Thomaiyar0a86feb2019-05-27 23:16:40 +05302003 std::string_view thisSensorName = chassisSensor.substr(pos + 1);
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07002004 if (thisSensorName == sensorName)
2005 {
2006 sensorsModified.emplace(chassisSensor);
2007 return true;
2008 }
2009 }
2010 return false;
2011}
2012
2013/**
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302014 * @brief Entry point for overriding sensor values of given sensor
2015 *
2016 * @param res response object
2017 * @param req request object
2018 * @param params parameter passed for CRUD
2019 * @param typeList TypeList of sensors for the resource queried
2020 * @param chassisSubNode Chassis Node for which the query has to happen
2021 */
2022void setSensorOverride(crow::Response& res, const crow::Request& req,
2023 const std::vector<std::string>& params,
Ed Tanous85e14242019-06-27 15:04:09 -07002024 const std::vector<const char*> typeList,
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302025 const std::string& chassisSubNode)
2026{
2027
2028 // TODO: Need to figure out dynamic way to restrict patch (Set Sensor
2029 // override) based on another d-bus announcement to be more generic.
2030 if (params.size() != 1)
2031 {
2032 messages::internalError(res);
2033 res.end();
2034 return;
2035 }
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302036
2037 std::unordered_map<std::string, std::vector<nlohmann::json>> allCollections;
2038 std::optional<std::vector<nlohmann::json>> temperatureCollections;
2039 std::optional<std::vector<nlohmann::json>> fanCollections;
2040 std::vector<nlohmann::json> voltageCollections;
2041 BMCWEB_LOG_INFO << "setSensorOverride for subNode" << chassisSubNode
2042 << "\n";
2043
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302044 if (chassisSubNode == "Thermal")
2045 {
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302046 if (!json_util::readJson(req, res, "Temperatures",
2047 temperatureCollections, "Fans",
2048 fanCollections))
2049 {
2050 return;
2051 }
2052 if (!temperatureCollections && !fanCollections)
2053 {
2054 messages::resourceNotFound(res, "Thermal",
2055 "Temperatures / Voltages");
2056 res.end();
2057 return;
2058 }
2059 if (temperatureCollections)
2060 {
2061 allCollections.emplace("Temperatures",
2062 *std::move(temperatureCollections));
2063 }
2064 if (fanCollections)
2065 {
2066 allCollections.emplace("Fans", *std::move(fanCollections));
2067 }
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302068 }
2069 else if (chassisSubNode == "Power")
2070 {
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302071 if (!json_util::readJson(req, res, "Voltages", voltageCollections))
2072 {
2073 return;
2074 }
2075 allCollections.emplace("Voltages", std::move(voltageCollections));
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302076 }
2077 else
2078 {
2079 res.result(boost::beast::http::status::not_found);
2080 res.end();
2081 return;
2082 }
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302083
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302084 const char* propertyValueName;
2085 std::unordered_map<std::string, std::pair<double, std::string>> overrideMap;
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302086 std::string memberId;
2087 double value;
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302088 for (auto& collectionItems : allCollections)
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302089 {
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302090 if (collectionItems.first == "Temperatures")
2091 {
2092 propertyValueName = "ReadingCelsius";
2093 }
2094 else if (collectionItems.first == "Fans")
2095 {
2096 propertyValueName = "Reading";
2097 }
2098 else
2099 {
2100 propertyValueName = "ReadingVolts";
2101 }
2102 for (auto& item : collectionItems.second)
2103 {
2104 if (!json_util::readJson(item, res, "MemberId", memberId,
2105 propertyValueName, value))
2106 {
2107 return;
2108 }
2109 overrideMap.emplace(memberId,
2110 std::make_pair(value, collectionItems.first));
2111 }
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302112 }
2113 const std::string& chassisName = params[0];
2114 auto sensorAsyncResp = std::make_shared<SensorsAsyncResp>(
2115 res, chassisName, typeList, chassisSubNode);
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07002116 auto getChassisSensorListCb = [sensorAsyncResp,
2117 overrideMap](const std::shared_ptr<
2118 boost::container::flat_set<
2119 std::string>>
2120 sensorsList) {
2121 // Match sensor names in the PATCH request to those managed by the
2122 // chassis node
2123 const std::shared_ptr<boost::container::flat_set<std::string>>
2124 sensorNames =
2125 std::make_shared<boost::container::flat_set<std::string>>();
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302126 for (const auto& item : overrideMap)
2127 {
2128 const auto& sensor = item.first;
Johnathan Mantey49c53ac2019-05-02 09:22:38 -07002129 if (!findSensorNameUsingSensorPath(sensor, *sensorsList,
2130 *sensorNames))
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302131 {
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302132 BMCWEB_LOG_INFO << "Unable to find memberId " << item.first;
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302133 messages::resourceNotFound(sensorAsyncResp->res,
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302134 item.second.second, item.first);
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302135 return;
2136 }
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302137 }
2138 // Get the connection to which the memberId belongs
2139 auto getObjectsWithConnectionCb =
2140 [sensorAsyncResp, overrideMap](
2141 const boost::container::flat_set<std::string>& connections,
2142 const std::set<std::pair<std::string, std::string>>&
2143 objectsWithConnection) {
2144 if (objectsWithConnection.size() != overrideMap.size())
2145 {
2146 BMCWEB_LOG_INFO
2147 << "Unable to find all objects with proper connection "
2148 << objectsWithConnection.size() << " requested "
2149 << overrideMap.size() << "\n";
2150 messages::resourceNotFound(
2151 sensorAsyncResp->res,
2152 sensorAsyncResp->chassisSubNode == "Thermal"
2153 ? "Temperatures"
2154 : "Voltages",
2155 "Count");
2156 return;
2157 }
2158 for (const auto& item : objectsWithConnection)
2159 {
2160
2161 auto lastPos = item.first.rfind('/');
2162 if (lastPos == std::string::npos)
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302163 {
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302164 messages::internalError(sensorAsyncResp->res);
2165 return;
2166 }
2167 std::string sensorName = item.first.substr(lastPos + 1);
2168
2169 const auto& iterator = overrideMap.find(sensorName);
2170 if (iterator == overrideMap.end())
2171 {
2172 BMCWEB_LOG_INFO << "Unable to find sensor object"
2173 << item.first << "\n";
2174 messages::internalError(sensorAsyncResp->res);
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302175 return;
2176 }
2177 crow::connections::systemBus->async_method_call(
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302178 [sensorAsyncResp](const boost::system::error_code ec) {
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302179 if (ec)
2180 {
2181 BMCWEB_LOG_DEBUG
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302182 << "setOverrideValueStatus DBUS error: "
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302183 << ec;
2184 messages::internalError(sensorAsyncResp->res);
2185 return;
2186 }
2187 },
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302188 item.second, item.first,
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302189 "org.freedesktop.DBus.Properties", "Set",
2190 "xyz.openbmc_project.Sensor.Value", "Value",
Richard Marian Thomaiyarf65af9e2019-02-13 23:35:05 +05302191 sdbusplus::message::variant<double>(
2192 iterator->second.first));
2193 }
2194 };
2195 // Get object with connection for the given sensor name
2196 getObjectsWithConnection(sensorAsyncResp, sensorNames,
2197 std::move(getObjectsWithConnectionCb));
2198 };
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +05302199 // get full sensor list for the given chassisId and cross verify the sensor.
2200 getChassis(sensorAsyncResp, std::move(getChassisSensorListCb));
2201}
2202
Anthony Wilson95a3eca2019-06-11 10:44:47 -05002203class SensorCollection : public Node
2204{
2205 public:
2206 SensorCollection(CrowApp& app) :
2207 Node(app, "/redfish/v1/Chassis/<str>/Sensors", std::string())
2208 {
2209 entityPrivileges = {
2210 {boost::beast::http::verb::get, {{"Login"}}},
2211 {boost::beast::http::verb::head, {{"Login"}}},
2212 {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
2213 {boost::beast::http::verb::put, {{"ConfigureManager"}}},
2214 {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
2215 {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
2216 }
2217
2218 private:
2219 std::vector<const char*> typeList = {
2220 "/xyz/openbmc_project/sensors/power",
2221 "/xyz/openbmc_project/sensors/current"};
2222 void doGet(crow::Response& res, const crow::Request& req,
2223 const std::vector<std::string>& params) override
2224 {
2225 BMCWEB_LOG_DEBUG << "SensorCollection doGet enter";
2226 if (params.size() != 1)
2227 {
2228 BMCWEB_LOG_DEBUG << "SensorCollection doGet param size < 1";
2229 messages::internalError(res);
2230 res.end();
2231 return;
2232 }
2233
2234 const std::string& chassisId = params[0];
2235 std::shared_ptr<SensorsAsyncResp> asyncResp =
2236 std::make_shared<SensorsAsyncResp>(res, chassisId, typeList,
2237 "Sensors");
2238
2239 auto getChassisCb =
2240 [asyncResp](std::shared_ptr<boost::container::flat_set<std::string>>
2241 sensorNames) {
2242 BMCWEB_LOG_DEBUG << "getChassisCb enter";
2243
2244 nlohmann::json& entriesArray =
2245 asyncResp->res.jsonValue["Members"];
2246 for (auto& sensor : *sensorNames)
2247 {
2248 BMCWEB_LOG_DEBUG << "Adding sensor: " << sensor;
2249
2250 std::size_t lastPos = sensor.rfind("/");
2251 if (lastPos == std::string::npos ||
2252 lastPos + 1 >= sensor.size())
2253 {
2254 BMCWEB_LOG_ERROR << "Invalid sensor path: " << sensor;
2255 messages::internalError(asyncResp->res);
2256 return;
2257 }
2258 std::string sensorName = sensor.substr(lastPos + 1);
2259 entriesArray.push_back(
2260 {{"@odata.id",
2261 "/redfish/v1/Chassis/" + asyncResp->chassisId + "/" +
2262 asyncResp->chassisSubNode + "/" + sensorName}});
2263 }
2264
2265 asyncResp->res.jsonValue["Members@odata.count"] =
2266 entriesArray.size();
2267 BMCWEB_LOG_DEBUG << "getChassisCb exit";
2268 };
2269
2270 // Get set of sensors in chassis
2271 getChassis(asyncResp, std::move(getChassisCb));
2272 BMCWEB_LOG_DEBUG << "SensorCollection doGet exit";
2273 }
2274};
2275
2276class Sensor : public Node
2277{
2278 public:
2279 Sensor(CrowApp& app) :
2280 Node(app, "/redfish/v1/Chassis/<str>/Sensors/<str>/", std::string(),
2281 std::string())
2282 {
2283 entityPrivileges = {
2284 {boost::beast::http::verb::get, {{"Login"}}},
2285 {boost::beast::http::verb::head, {{"Login"}}},
2286 {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
2287 {boost::beast::http::verb::put, {{"ConfigureManager"}}},
2288 {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
2289 {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
2290 }
2291
2292 private:
2293 void doGet(crow::Response& res, const crow::Request& req,
2294 const std::vector<std::string>& params) override
2295 {
2296 BMCWEB_LOG_DEBUG << "Sensor doGet enter";
2297 if (params.size() != 2)
2298 {
2299 BMCWEB_LOG_DEBUG << "Sensor doGet param size < 2";
2300 messages::internalError(res);
2301 res.end();
2302 return;
2303 }
2304 const std::string& chassisId = params[0];
2305 std::shared_ptr<SensorsAsyncResp> asyncResp =
2306 std::make_shared<SensorsAsyncResp>(
2307 res, chassisId, std::vector<const char*>(), "Sensors");
2308
2309 const std::string& sensorName = params[1];
2310 const std::array<const char*, 1> interfaces = {
2311 "xyz.openbmc_project.Sensor.Value"};
2312
2313 // Get a list of all of the sensors that implement Sensor.Value
2314 // and get the path and service name associated with the sensor
2315 crow::connections::systemBus->async_method_call(
2316 [asyncResp, sensorName](const boost::system::error_code ec,
2317 const GetSubTreeType& subtree) {
2318 BMCWEB_LOG_DEBUG << "respHandler1 enter";
2319 if (ec)
2320 {
2321 messages::internalError(asyncResp->res);
2322 BMCWEB_LOG_ERROR << "Sensor getSensorPaths resp_handler: "
2323 << "Dbus error " << ec;
2324 return;
2325 }
2326
2327 GetSubTreeType::const_iterator it = std::find_if(
2328 subtree.begin(), subtree.end(),
2329 [sensorName](
2330 const std::pair<
2331 std::string,
2332 std::vector<std::pair<std::string,
2333 std::vector<std::string>>>>&
2334 object) {
2335 std::string_view sensor = object.first;
2336 std::size_t lastPos = sensor.rfind("/");
2337 if (lastPos == std::string::npos ||
2338 lastPos + 1 >= sensor.size())
2339 {
2340 BMCWEB_LOG_ERROR << "Invalid sensor path: "
2341 << sensor;
2342 return false;
2343 }
2344 std::string_view name = sensor.substr(lastPos + 1);
2345
2346 return name == sensorName;
2347 });
2348
2349 if (it == subtree.end())
2350 {
2351 BMCWEB_LOG_ERROR << "Could not find path for sensor: "
2352 << sensorName;
2353 messages::resourceNotFound(asyncResp->res, "Sensor",
2354 sensorName);
2355 return;
2356 }
2357 std::string_view sensorPath = (*it).first;
2358 BMCWEB_LOG_DEBUG << "Found sensor path for sensor '"
2359 << sensorName << "': " << sensorPath;
2360
2361 const std::shared_ptr<boost::container::flat_set<std::string>>
2362 sensorList = std::make_shared<
2363 boost::container::flat_set<std::string>>();
2364
2365 sensorList->emplace(sensorPath);
2366 processSensorList(asyncResp, sensorList);
2367 BMCWEB_LOG_DEBUG << "respHandler1 exit";
2368 },
2369 "xyz.openbmc_project.ObjectMapper",
2370 "/xyz/openbmc_project/object_mapper",
2371 "xyz.openbmc_project.ObjectMapper", "GetSubTree",
2372 "/xyz/openbmc_project/sensors", 2, interfaces);
2373 }
2374};
2375
Ed Tanous1abe55e2018-09-05 08:30:59 -07002376} // namespace redfish