108777fb0SLewanczyk, Dawid /* 208777fb0SLewanczyk, Dawid // Copyright (c) 2018 Intel Corporation 308777fb0SLewanczyk, Dawid // 408777fb0SLewanczyk, Dawid // Licensed under the Apache License, Version 2.0 (the "License"); 508777fb0SLewanczyk, Dawid // you may not use this file except in compliance with the License. 608777fb0SLewanczyk, Dawid // You may obtain a copy of the License at 708777fb0SLewanczyk, Dawid // 808777fb0SLewanczyk, Dawid // http://www.apache.org/licenses/LICENSE-2.0 908777fb0SLewanczyk, Dawid // 1008777fb0SLewanczyk, Dawid // Unless required by applicable law or agreed to in writing, software 1108777fb0SLewanczyk, Dawid // distributed under the License is distributed on an "AS IS" BASIS, 1208777fb0SLewanczyk, Dawid // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1308777fb0SLewanczyk, Dawid // See the License for the specific language governing permissions and 1408777fb0SLewanczyk, Dawid // limitations under the License. 1508777fb0SLewanczyk, Dawid */ 1608777fb0SLewanczyk, Dawid #pragma once 1708777fb0SLewanczyk, Dawid 1808777fb0SLewanczyk, Dawid #include <math.h> 191abe55efSEd Tanous 2008777fb0SLewanczyk, Dawid #include <boost/algorithm/string/predicate.hpp> 2108777fb0SLewanczyk, Dawid #include <boost/algorithm/string/split.hpp> 2208777fb0SLewanczyk, Dawid #include <boost/container/flat_map.hpp> 2308777fb0SLewanczyk, Dawid #include <boost/range/algorithm/replace_copy_if.hpp> 241abe55efSEd Tanous #include <dbus_singleton.hpp> 25413961deSRichard Marian Thomaiyar #include <utils/json_utils.hpp> 26abf2add6SEd Tanous #include <variant> 2708777fb0SLewanczyk, Dawid 281abe55efSEd Tanous namespace redfish 291abe55efSEd Tanous { 3008777fb0SLewanczyk, Dawid 3108777fb0SLewanczyk, Dawid using GetSubTreeType = std::vector< 3208777fb0SLewanczyk, Dawid std::pair<std::string, 3308777fb0SLewanczyk, Dawid std::vector<std::pair<std::string, std::vector<std::string>>>>>; 3408777fb0SLewanczyk, Dawid 35028f7ebcSEddie James using SensorVariant = std::variant<int64_t, double, uint32_t, bool>; 36aa2e59c1SEd Tanous 3708777fb0SLewanczyk, Dawid using ManagedObjectsVectorType = std::vector<std::pair< 38aa2e59c1SEd Tanous sdbusplus::message::object_path, 3908777fb0SLewanczyk, Dawid boost::container::flat_map< 40aa2e59c1SEd Tanous std::string, boost::container::flat_map<std::string, SensorVariant>>>>; 4108777fb0SLewanczyk, Dawid 4208777fb0SLewanczyk, Dawid /** 43588c3f0dSKowalski, Kamil * SensorsAsyncResp 4408777fb0SLewanczyk, Dawid * Gathers data needed for response processing after async calls are done 4508777fb0SLewanczyk, Dawid */ 461abe55efSEd Tanous class SensorsAsyncResp 471abe55efSEd Tanous { 4808777fb0SLewanczyk, Dawid public: 4955c7b7a2SEd Tanous SensorsAsyncResp(crow::Response& response, const std::string& chassisId, 50b01bf299SEd Tanous const std::initializer_list<const char*> types, 512474adfaSEd Tanous const std::string& subNode) : 5243b761d0SEd Tanous res(response), 5343b761d0SEd Tanous chassisId(chassisId), types(types), chassisSubNode(subNode) 541abe55efSEd Tanous { 5508777fb0SLewanczyk, Dawid } 5608777fb0SLewanczyk, Dawid 571abe55efSEd Tanous ~SensorsAsyncResp() 581abe55efSEd Tanous { 591abe55efSEd Tanous if (res.result() == boost::beast::http::status::internal_server_error) 601abe55efSEd Tanous { 611abe55efSEd Tanous // Reset the json object to clear out any data that made it in 621abe55efSEd Tanous // before the error happened todo(ed) handle error condition with 631abe55efSEd Tanous // proper code 6455c7b7a2SEd Tanous res.jsonValue = nlohmann::json::object(); 6508777fb0SLewanczyk, Dawid } 6608777fb0SLewanczyk, Dawid res.end(); 6708777fb0SLewanczyk, Dawid } 68588c3f0dSKowalski, Kamil 6955c7b7a2SEd Tanous crow::Response& res; 70588c3f0dSKowalski, Kamil std::string chassisId{}; 7108777fb0SLewanczyk, Dawid const std::vector<const char*> types; 722474adfaSEd Tanous std::string chassisSubNode{}; 7308777fb0SLewanczyk, Dawid }; 7408777fb0SLewanczyk, Dawid 7508777fb0SLewanczyk, Dawid /** 76413961deSRichard Marian Thomaiyar * @brief Get objects with connection necessary for sensors 77588c3f0dSKowalski, Kamil * @param SensorsAsyncResp Pointer to object holding response data 7808777fb0SLewanczyk, Dawid * @param sensorNames Sensors retrieved from chassis 7908777fb0SLewanczyk, Dawid * @param callback Callback for processing gathered connections 8008777fb0SLewanczyk, Dawid */ 8108777fb0SLewanczyk, Dawid template <typename Callback> 82413961deSRichard Marian Thomaiyar void getObjectsWithConnection( 83413961deSRichard Marian Thomaiyar std::shared_ptr<SensorsAsyncResp> SensorsAsyncResp, 8449c53ac9SJohnathan Mantey const std::shared_ptr<boost::container::flat_set<std::string>> sensorNames, 851abe55efSEd Tanous Callback&& callback) 861abe55efSEd Tanous { 87413961deSRichard Marian Thomaiyar BMCWEB_LOG_DEBUG << "getObjectsWithConnection enter"; 8803b5bae3SJames Feist const std::string path = "/xyz/openbmc_project/sensors"; 8908777fb0SLewanczyk, Dawid const std::array<std::string, 1> interfaces = { 9008777fb0SLewanczyk, Dawid "xyz.openbmc_project.Sensor.Value"}; 9108777fb0SLewanczyk, Dawid 9208777fb0SLewanczyk, Dawid // Response handler for parsing objects subtree 931abe55efSEd Tanous auto respHandler = [callback{std::move(callback)}, SensorsAsyncResp, 941abe55efSEd Tanous sensorNames](const boost::system::error_code ec, 951abe55efSEd Tanous const GetSubTreeType& subtree) { 96413961deSRichard Marian Thomaiyar BMCWEB_LOG_DEBUG << "getObjectsWithConnection resp_handler enter"; 971abe55efSEd Tanous if (ec) 981abe55efSEd Tanous { 995f7d88c4SEd Tanous messages::internalError(SensorsAsyncResp->res); 100413961deSRichard Marian Thomaiyar BMCWEB_LOG_ERROR 101413961deSRichard Marian Thomaiyar << "getObjectsWithConnection resp_handler: Dbus error " << ec; 10208777fb0SLewanczyk, Dawid return; 10308777fb0SLewanczyk, Dawid } 10408777fb0SLewanczyk, Dawid 10555c7b7a2SEd Tanous BMCWEB_LOG_DEBUG << "Found " << subtree.size() << " subtrees"; 10608777fb0SLewanczyk, Dawid 10708777fb0SLewanczyk, Dawid // Make unique list of connections only for requested sensor types and 10808777fb0SLewanczyk, Dawid // found in the chassis 10908777fb0SLewanczyk, Dawid boost::container::flat_set<std::string> connections; 110413961deSRichard Marian Thomaiyar std::set<std::pair<std::string, std::string>> objectsWithConnection; 1111abe55efSEd Tanous // Intrinsic to avoid malloc. Most systems will have < 8 sensor 1121abe55efSEd Tanous // producers 11308777fb0SLewanczyk, Dawid connections.reserve(8); 11408777fb0SLewanczyk, Dawid 11549c53ac9SJohnathan Mantey BMCWEB_LOG_DEBUG << "sensorNames list count: " << sensorNames->size(); 11649c53ac9SJohnathan Mantey for (const std::string& tsensor : *sensorNames) 1171abe55efSEd Tanous { 11855c7b7a2SEd Tanous BMCWEB_LOG_DEBUG << "Sensor to find: " << tsensor; 11908777fb0SLewanczyk, Dawid } 12008777fb0SLewanczyk, Dawid 12108777fb0SLewanczyk, Dawid for (const std::pair< 12208777fb0SLewanczyk, Dawid std::string, 12308777fb0SLewanczyk, Dawid std::vector<std::pair<std::string, std::vector<std::string>>>>& 1241abe55efSEd Tanous object : subtree) 1251abe55efSEd Tanous { 12649c53ac9SJohnathan Mantey if (sensorNames->find(object.first) != sensorNames->end()) 1271abe55efSEd Tanous { 12849c53ac9SJohnathan Mantey for (const std::pair<std::string, std::vector<std::string>>& 1291abe55efSEd Tanous objData : object.second) 1301abe55efSEd Tanous { 13149c53ac9SJohnathan Mantey BMCWEB_LOG_DEBUG << "Adding connection: " << objData.first; 13208777fb0SLewanczyk, Dawid connections.insert(objData.first); 133de629b6eSShawn McCarney objectsWithConnection.insert( 134de629b6eSShawn McCarney std::make_pair(object.first, objData.first)); 13508777fb0SLewanczyk, Dawid } 13608777fb0SLewanczyk, Dawid } 13708777fb0SLewanczyk, Dawid } 13855c7b7a2SEd Tanous BMCWEB_LOG_DEBUG << "Found " << connections.size() << " connections"; 139413961deSRichard Marian Thomaiyar callback(std::move(connections), std::move(objectsWithConnection)); 140413961deSRichard Marian Thomaiyar BMCWEB_LOG_DEBUG << "getObjectsWithConnection resp_handler exit"; 14108777fb0SLewanczyk, Dawid }; 14208777fb0SLewanczyk, Dawid // Make call to ObjectMapper to find all sensors objects 14355c7b7a2SEd Tanous crow::connections::systemBus->async_method_call( 14455c7b7a2SEd Tanous std::move(respHandler), "xyz.openbmc_project.ObjectMapper", 1451abe55efSEd Tanous "/xyz/openbmc_project/object_mapper", 1461abe55efSEd Tanous "xyz.openbmc_project.ObjectMapper", "GetSubTree", path, 2, interfaces); 147413961deSRichard Marian Thomaiyar BMCWEB_LOG_DEBUG << "getObjectsWithConnection exit"; 148413961deSRichard Marian Thomaiyar } 149413961deSRichard Marian Thomaiyar 150413961deSRichard Marian Thomaiyar /** 151413961deSRichard Marian Thomaiyar * @brief Create connections necessary for sensors 152413961deSRichard Marian Thomaiyar * @param SensorsAsyncResp Pointer to object holding response data 153413961deSRichard Marian Thomaiyar * @param sensorNames Sensors retrieved from chassis 154413961deSRichard Marian Thomaiyar * @param callback Callback for processing gathered connections 155413961deSRichard Marian Thomaiyar */ 156413961deSRichard Marian Thomaiyar template <typename Callback> 15749c53ac9SJohnathan Mantey void getConnections( 15849c53ac9SJohnathan Mantey std::shared_ptr<SensorsAsyncResp> SensorsAsyncResp, 15949c53ac9SJohnathan Mantey const std::shared_ptr<boost::container::flat_set<std::string>> sensorNames, 160413961deSRichard Marian Thomaiyar Callback&& callback) 161413961deSRichard Marian Thomaiyar { 162413961deSRichard Marian Thomaiyar auto objectsWithConnectionCb = 163413961deSRichard Marian Thomaiyar [callback](const boost::container::flat_set<std::string>& connections, 164413961deSRichard Marian Thomaiyar const std::set<std::pair<std::string, std::string>>& 165413961deSRichard Marian Thomaiyar objectsWithConnection) { 166413961deSRichard Marian Thomaiyar callback(std::move(connections)); 167413961deSRichard Marian Thomaiyar }; 168413961deSRichard Marian Thomaiyar getObjectsWithConnection(SensorsAsyncResp, sensorNames, 169413961deSRichard Marian Thomaiyar std::move(objectsWithConnectionCb)); 17008777fb0SLewanczyk, Dawid } 17108777fb0SLewanczyk, Dawid 17208777fb0SLewanczyk, Dawid /** 17349c53ac9SJohnathan Mantey * @brief Shrinks the list of sensors for processing 17449c53ac9SJohnathan Mantey * @param SensorsAysncResp The class holding the Redfish response 17549c53ac9SJohnathan Mantey * @param allSensors A list of all the sensors associated to the 17649c53ac9SJohnathan Mantey * chassis element (i.e. baseboard, front panel, etc...) 17749c53ac9SJohnathan Mantey * @param activeSensors A list that is a reduction of the incoming 17849c53ac9SJohnathan Mantey * allSensors list. Eliminate Thermal sensors when a Power request is 17949c53ac9SJohnathan Mantey * made, and eliminate Power sensors when a Thermal request is made. 18049c53ac9SJohnathan Mantey */ 18149c53ac9SJohnathan Mantey void reduceSensorList( 18249c53ac9SJohnathan Mantey std::shared_ptr<SensorsAsyncResp> SensorsAsyncResp, 18349c53ac9SJohnathan Mantey const std::vector<std::string>* allSensors, 18449c53ac9SJohnathan Mantey std::shared_ptr<boost::container::flat_set<std::string>> activeSensors) 18549c53ac9SJohnathan Mantey { 18649c53ac9SJohnathan Mantey if (SensorsAsyncResp == nullptr) 18749c53ac9SJohnathan Mantey { 18849c53ac9SJohnathan Mantey return; 18949c53ac9SJohnathan Mantey } 19049c53ac9SJohnathan Mantey if ((allSensors == nullptr) || (activeSensors == nullptr)) 19149c53ac9SJohnathan Mantey { 19249c53ac9SJohnathan Mantey messages::resourceNotFound( 19349c53ac9SJohnathan Mantey SensorsAsyncResp->res, SensorsAsyncResp->chassisSubNode, 19449c53ac9SJohnathan Mantey SensorsAsyncResp->chassisSubNode == "Thermal" ? "Temperatures" 19549c53ac9SJohnathan Mantey : "Voltages"); 19649c53ac9SJohnathan Mantey 19749c53ac9SJohnathan Mantey return; 19849c53ac9SJohnathan Mantey } 19949c53ac9SJohnathan Mantey if (allSensors->empty()) 20049c53ac9SJohnathan Mantey { 20149c53ac9SJohnathan Mantey // Nothing to do, the activeSensors object is also empty 20249c53ac9SJohnathan Mantey return; 20349c53ac9SJohnathan Mantey } 20449c53ac9SJohnathan Mantey 20549c53ac9SJohnathan Mantey for (const char* type : SensorsAsyncResp->types) 20649c53ac9SJohnathan Mantey { 20749c53ac9SJohnathan Mantey for (const std::string& sensor : *allSensors) 20849c53ac9SJohnathan Mantey { 20949c53ac9SJohnathan Mantey if (boost::starts_with(sensor, type)) 21049c53ac9SJohnathan Mantey { 21149c53ac9SJohnathan Mantey activeSensors->emplace(sensor); 21249c53ac9SJohnathan Mantey } 21349c53ac9SJohnathan Mantey } 21449c53ac9SJohnathan Mantey } 21549c53ac9SJohnathan Mantey } 21649c53ac9SJohnathan Mantey 21749c53ac9SJohnathan Mantey /** 21808777fb0SLewanczyk, Dawid * @brief Retrieves requested chassis sensors and redundancy data from DBus . 219588c3f0dSKowalski, Kamil * @param SensorsAsyncResp Pointer to object holding response data 22008777fb0SLewanczyk, Dawid * @param callback Callback for next step in gathered sensor processing 22108777fb0SLewanczyk, Dawid */ 22208777fb0SLewanczyk, Dawid template <typename Callback> 22349c53ac9SJohnathan Mantey void getChassis(std::shared_ptr<SensorsAsyncResp> sensorsAsyncResp, 2241abe55efSEd Tanous Callback&& callback) 2251abe55efSEd Tanous { 22655c7b7a2SEd Tanous BMCWEB_LOG_DEBUG << "getChassis enter"; 22749c53ac9SJohnathan Mantey const std::array<const char*, 3> interfaces = { 22849c53ac9SJohnathan Mantey "xyz.openbmc_project.Inventory.Item.Board", 22949c53ac9SJohnathan Mantey "xyz.openbmc_project.Inventory.Item.Chassis", 23049c53ac9SJohnathan Mantey "xyz.openbmc_project.Inventory.Item.PowerSupply"}; 23149c53ac9SJohnathan Mantey auto respHandler = [callback{std::move(callback)}, sensorsAsyncResp]( 23249c53ac9SJohnathan Mantey const boost::system::error_code ec, 23349c53ac9SJohnathan Mantey const std::vector<std::string>& chassisPaths) { 23455c7b7a2SEd Tanous BMCWEB_LOG_DEBUG << "getChassis respHandler enter"; 2351abe55efSEd Tanous if (ec) 2361abe55efSEd Tanous { 23755c7b7a2SEd Tanous BMCWEB_LOG_ERROR << "getChassis respHandler DBUS error: " << ec; 23849c53ac9SJohnathan Mantey messages::internalError(sensorsAsyncResp->res); 23908777fb0SLewanczyk, Dawid return; 24008777fb0SLewanczyk, Dawid } 24108777fb0SLewanczyk, Dawid 24249c53ac9SJohnathan Mantey const std::string* chassisPath = nullptr; 24349c53ac9SJohnathan Mantey std::string chassisName; 24449c53ac9SJohnathan Mantey for (const std::string& chassis : chassisPaths) 2451abe55efSEd Tanous { 24649c53ac9SJohnathan Mantey std::size_t lastPos = chassis.rfind("/"); 24749c53ac9SJohnathan Mantey if (lastPos == std::string::npos) 2481abe55efSEd Tanous { 24949c53ac9SJohnathan Mantey BMCWEB_LOG_ERROR << "Failed to find '/' in " << chassis; 250daf36e2eSEd Tanous continue; 251daf36e2eSEd Tanous } 25249c53ac9SJohnathan Mantey chassisName = chassis.substr(lastPos + 1); 25349c53ac9SJohnathan Mantey if (chassisName == sensorsAsyncResp->chassisId) 2541abe55efSEd Tanous { 25549c53ac9SJohnathan Mantey chassisPath = &chassis; 25649c53ac9SJohnathan Mantey break; 257daf36e2eSEd Tanous } 25849c53ac9SJohnathan Mantey } 25949c53ac9SJohnathan Mantey if (chassisPath == nullptr) 2601abe55efSEd Tanous { 26149c53ac9SJohnathan Mantey messages::resourceNotFound(sensorsAsyncResp->res, "Chassis", 26249c53ac9SJohnathan Mantey sensorsAsyncResp->chassisId); 26349c53ac9SJohnathan Mantey return; 2641abe55efSEd Tanous } 26508777fb0SLewanczyk, Dawid 26649c53ac9SJohnathan Mantey const std::string& chassisSubNode = sensorsAsyncResp->chassisSubNode; 26749c53ac9SJohnathan Mantey if (chassisSubNode == "Power") 26849c53ac9SJohnathan Mantey { 26949c53ac9SJohnathan Mantey sensorsAsyncResp->res.jsonValue["@odata.type"] = 27049c53ac9SJohnathan Mantey "#Power.v1_5_2.Power"; 27149c53ac9SJohnathan Mantey } 27249c53ac9SJohnathan Mantey else if (chassisSubNode == "Thermal") 27349c53ac9SJohnathan Mantey { 27449c53ac9SJohnathan Mantey sensorsAsyncResp->res.jsonValue["@odata.type"] = 27549c53ac9SJohnathan Mantey "#Thermal.v1_4_0.Thermal"; 2764f9a2130SJennifer Lee sensorsAsyncResp->res.jsonValue["Fans"] = nlohmann::json::array(); 2774f9a2130SJennifer Lee sensorsAsyncResp->res.jsonValue["Temperatures"] = 2784f9a2130SJennifer Lee nlohmann::json::array(); 27949c53ac9SJohnathan Mantey } 28049c53ac9SJohnathan Mantey sensorsAsyncResp->res.jsonValue["@odata.id"] = 28149c53ac9SJohnathan Mantey "/redfish/v1/Chassis/" + sensorsAsyncResp->chassisId + "/" + 28249c53ac9SJohnathan Mantey chassisSubNode; 28349c53ac9SJohnathan Mantey 28449c53ac9SJohnathan Mantey sensorsAsyncResp->res.jsonValue["@odata.context"] = 28549c53ac9SJohnathan Mantey "/redfish/v1/$metadata#" + chassisSubNode + "." + chassisSubNode; 28649c53ac9SJohnathan Mantey sensorsAsyncResp->res.jsonValue["Id"] = chassisSubNode; 28749c53ac9SJohnathan Mantey sensorsAsyncResp->res.jsonValue["Name"] = chassisSubNode; 28849c53ac9SJohnathan Mantey 289*8fb49dd6SShawn McCarney // Get the list of all sensors for this Chassis element 290*8fb49dd6SShawn McCarney std::string sensorPath = *chassisPath + "/all_sensors"; 29155c7b7a2SEd Tanous crow::connections::systemBus->async_method_call( 29249c53ac9SJohnathan Mantey [sensorsAsyncResp, callback{std::move(callback)}]( 29349c53ac9SJohnathan Mantey const boost::system::error_code ec, 29449c53ac9SJohnathan Mantey const std::variant<std::vector<std::string>>& 29549c53ac9SJohnathan Mantey variantEndpoints) { 29649c53ac9SJohnathan Mantey if (ec) 29749c53ac9SJohnathan Mantey { 29849c53ac9SJohnathan Mantey if (ec.value() != EBADR) 29949c53ac9SJohnathan Mantey { 30049c53ac9SJohnathan Mantey messages::internalError(sensorsAsyncResp->res); 30149c53ac9SJohnathan Mantey return; 30249c53ac9SJohnathan Mantey } 30349c53ac9SJohnathan Mantey } 30449c53ac9SJohnathan Mantey const std::vector<std::string>* nodeSensorList = 30549c53ac9SJohnathan Mantey std::get_if<std::vector<std::string>>(&(variantEndpoints)); 30649c53ac9SJohnathan Mantey if (nodeSensorList == nullptr) 30749c53ac9SJohnathan Mantey { 30849c53ac9SJohnathan Mantey messages::resourceNotFound( 30949c53ac9SJohnathan Mantey sensorsAsyncResp->res, sensorsAsyncResp->chassisSubNode, 31049c53ac9SJohnathan Mantey sensorsAsyncResp->chassisSubNode == "Thermal" 31149c53ac9SJohnathan Mantey ? "Temperatures" 31249c53ac9SJohnathan Mantey : "Voltages"); 31349c53ac9SJohnathan Mantey return; 31449c53ac9SJohnathan Mantey } 31549c53ac9SJohnathan Mantey const std::shared_ptr<boost::container::flat_set<std::string>> 31649c53ac9SJohnathan Mantey culledSensorList = std::make_shared< 31749c53ac9SJohnathan Mantey boost::container::flat_set<std::string>>(); 31849c53ac9SJohnathan Mantey reduceSensorList(sensorsAsyncResp, nodeSensorList, 31949c53ac9SJohnathan Mantey culledSensorList); 32049c53ac9SJohnathan Mantey callback(culledSensorList); 32149c53ac9SJohnathan Mantey }, 32249c53ac9SJohnathan Mantey "xyz.openbmc_project.ObjectMapper", sensorPath, 32349c53ac9SJohnathan Mantey "org.freedesktop.DBus.Properties", "Get", 32449c53ac9SJohnathan Mantey "xyz.openbmc_project.Association", "endpoints"); 32549c53ac9SJohnathan Mantey }; 32649c53ac9SJohnathan Mantey 32749c53ac9SJohnathan Mantey // Get the Chassis Collection 32849c53ac9SJohnathan Mantey crow::connections::systemBus->async_method_call( 32949c53ac9SJohnathan Mantey respHandler, "xyz.openbmc_project.ObjectMapper", 33049c53ac9SJohnathan Mantey "/xyz/openbmc_project/object_mapper", 33149c53ac9SJohnathan Mantey "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", 33249c53ac9SJohnathan Mantey "/xyz/openbmc_project/inventory", int32_t(0), interfaces); 33355c7b7a2SEd Tanous BMCWEB_LOG_DEBUG << "getChassis exit"; 33408777fb0SLewanczyk, Dawid } 33508777fb0SLewanczyk, Dawid 33608777fb0SLewanczyk, Dawid /** 337de629b6eSShawn McCarney * @brief Finds all DBus object paths that implement ObjectManager. 338de629b6eSShawn McCarney * 339de629b6eSShawn McCarney * Creates a mapping from the associated connection name to the object path. 340de629b6eSShawn McCarney * 341de629b6eSShawn McCarney * Finds the object paths asynchronously. Invokes callback when information has 342de629b6eSShawn McCarney * been obtained. 343de629b6eSShawn McCarney * 344de629b6eSShawn McCarney * The callback must have the following signature: 345de629b6eSShawn McCarney * @code 346*8fb49dd6SShawn McCarney * callback(std::shared_ptr<boost::container::flat_map<std::string, 347*8fb49dd6SShawn McCarney * std::string>> objectMgrPaths) 348de629b6eSShawn McCarney * @endcode 349de629b6eSShawn McCarney * 35049c53ac9SJohnathan Mantey * @param sensorsAsyncResp Pointer to object holding response data. 351de629b6eSShawn McCarney * @param callback Callback to invoke when object paths obtained. 352de629b6eSShawn McCarney */ 353de629b6eSShawn McCarney template <typename Callback> 354de629b6eSShawn McCarney void getObjectManagerPaths(std::shared_ptr<SensorsAsyncResp> SensorsAsyncResp, 355de629b6eSShawn McCarney Callback&& callback) 356de629b6eSShawn McCarney { 357de629b6eSShawn McCarney BMCWEB_LOG_DEBUG << "getObjectManagerPaths enter"; 358de629b6eSShawn McCarney const std::array<std::string, 1> interfaces = { 359de629b6eSShawn McCarney "org.freedesktop.DBus.ObjectManager"}; 360de629b6eSShawn McCarney 361de629b6eSShawn McCarney // Response handler for GetSubTree DBus method 362de629b6eSShawn McCarney auto respHandler = [callback{std::move(callback)}, 363de629b6eSShawn McCarney SensorsAsyncResp](const boost::system::error_code ec, 364de629b6eSShawn McCarney const GetSubTreeType& subtree) { 365de629b6eSShawn McCarney BMCWEB_LOG_DEBUG << "getObjectManagerPaths respHandler enter"; 366de629b6eSShawn McCarney if (ec) 367de629b6eSShawn McCarney { 368de629b6eSShawn McCarney messages::internalError(SensorsAsyncResp->res); 369de629b6eSShawn McCarney BMCWEB_LOG_ERROR << "getObjectManagerPaths respHandler: DBus error " 370de629b6eSShawn McCarney << ec; 371de629b6eSShawn McCarney return; 372de629b6eSShawn McCarney } 373de629b6eSShawn McCarney 374de629b6eSShawn McCarney // Loop over returned object paths 375*8fb49dd6SShawn McCarney std::shared_ptr<boost::container::flat_map<std::string, std::string>> 376*8fb49dd6SShawn McCarney objectMgrPaths = std::make_shared< 377*8fb49dd6SShawn McCarney boost::container::flat_map<std::string, std::string>>(); 378de629b6eSShawn McCarney for (const std::pair< 379de629b6eSShawn McCarney std::string, 380de629b6eSShawn McCarney std::vector<std::pair<std::string, std::vector<std::string>>>>& 381de629b6eSShawn McCarney object : subtree) 382de629b6eSShawn McCarney { 383de629b6eSShawn McCarney // Loop over connections for current object path 384de629b6eSShawn McCarney const std::string& objectPath = object.first; 385de629b6eSShawn McCarney for (const std::pair<std::string, std::vector<std::string>>& 386de629b6eSShawn McCarney objData : object.second) 387de629b6eSShawn McCarney { 388de629b6eSShawn McCarney // Add mapping from connection to object path 389de629b6eSShawn McCarney const std::string& connection = objData.first; 390*8fb49dd6SShawn McCarney (*objectMgrPaths)[connection] = objectPath; 391de629b6eSShawn McCarney BMCWEB_LOG_DEBUG << "Added mapping " << connection << " -> " 392de629b6eSShawn McCarney << objectPath; 393de629b6eSShawn McCarney } 394de629b6eSShawn McCarney } 395*8fb49dd6SShawn McCarney callback(objectMgrPaths); 396de629b6eSShawn McCarney BMCWEB_LOG_DEBUG << "getObjectManagerPaths respHandler exit"; 397de629b6eSShawn McCarney }; 398de629b6eSShawn McCarney 399de629b6eSShawn McCarney // Query mapper for all DBus object paths that implement ObjectManager 400de629b6eSShawn McCarney crow::connections::systemBus->async_method_call( 401de629b6eSShawn McCarney std::move(respHandler), "xyz.openbmc_project.ObjectMapper", 402de629b6eSShawn McCarney "/xyz/openbmc_project/object_mapper", 403de629b6eSShawn McCarney "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/", int32_t(0), 404de629b6eSShawn McCarney interfaces); 405de629b6eSShawn McCarney BMCWEB_LOG_DEBUG << "getObjectManagerPaths exit"; 406de629b6eSShawn McCarney } 407de629b6eSShawn McCarney 408de629b6eSShawn McCarney /** 40934dd179eSJames Feist * @brief Retrieves the health from a sensor . 41034dd179eSJames Feist * @param interfacesDict Map of all sensor interfaces 41134dd179eSJames Feist */ 41234dd179eSJames Feist 41334dd179eSJames Feist static std::string getHealth( 41434dd179eSJames Feist const boost::container::flat_map< 41534dd179eSJames Feist std::string, boost::container::flat_map<std::string, SensorVariant>>& 41634dd179eSJames Feist interfacesDict) 41734dd179eSJames Feist { 41834dd179eSJames Feist auto criticalThresholdIt = 41934dd179eSJames Feist interfacesDict.find("xyz.openbmc_project.Sensor.Threshold.Critical"); 42034dd179eSJames Feist if (criticalThresholdIt != interfacesDict.end()) 42134dd179eSJames Feist { 42234dd179eSJames Feist auto thresholdHighIt = 42334dd179eSJames Feist criticalThresholdIt->second.find("CriticalAlarmHigh"); 42434dd179eSJames Feist auto thresholdLowIt = 42534dd179eSJames Feist criticalThresholdIt->second.find("CriticalAlarmLow"); 42634dd179eSJames Feist if (thresholdHighIt != criticalThresholdIt->second.end()) 42734dd179eSJames Feist { 42834dd179eSJames Feist const bool* asserted = std::get_if<bool>(&thresholdHighIt->second); 42934dd179eSJames Feist if (asserted == nullptr) 43034dd179eSJames Feist { 43134dd179eSJames Feist BMCWEB_LOG_ERROR << "Illegal sensor threshold"; 43234dd179eSJames Feist } 43334dd179eSJames Feist else if (*asserted) 43434dd179eSJames Feist { 43534dd179eSJames Feist return "Critical"; 43634dd179eSJames Feist } 43734dd179eSJames Feist } 43834dd179eSJames Feist if (thresholdLowIt != criticalThresholdIt->second.end()) 43934dd179eSJames Feist { 44034dd179eSJames Feist const bool* asserted = std::get_if<bool>(&thresholdLowIt->second); 44134dd179eSJames Feist if (asserted == nullptr) 44234dd179eSJames Feist { 44334dd179eSJames Feist BMCWEB_LOG_ERROR << "Illegal sensor threshold"; 44434dd179eSJames Feist } 44534dd179eSJames Feist else if (*asserted) 44634dd179eSJames Feist { 44734dd179eSJames Feist return "Critical"; 44834dd179eSJames Feist } 44934dd179eSJames Feist } 45034dd179eSJames Feist } 45134dd179eSJames Feist 45234dd179eSJames Feist auto warningThresholdIt = 45334dd179eSJames Feist interfacesDict.find("xyz.openbmc_project.Sensor.Threshold.Warning"); 45434dd179eSJames Feist if (warningThresholdIt != interfacesDict.end()) 45534dd179eSJames Feist { 45634dd179eSJames Feist auto thresholdHighIt = 45734dd179eSJames Feist warningThresholdIt->second.find("WarningAlarmHigh"); 45834dd179eSJames Feist auto thresholdLowIt = 45934dd179eSJames Feist warningThresholdIt->second.find("WarningAlarmLow"); 46034dd179eSJames Feist if (thresholdHighIt != warningThresholdIt->second.end()) 46134dd179eSJames Feist { 46234dd179eSJames Feist const bool* asserted = std::get_if<bool>(&thresholdHighIt->second); 46334dd179eSJames Feist if (asserted == nullptr) 46434dd179eSJames Feist { 46534dd179eSJames Feist BMCWEB_LOG_ERROR << "Illegal sensor threshold"; 46634dd179eSJames Feist } 46734dd179eSJames Feist else if (*asserted) 46834dd179eSJames Feist { 46934dd179eSJames Feist return "Warning"; 47034dd179eSJames Feist } 47134dd179eSJames Feist } 47234dd179eSJames Feist if (thresholdLowIt != warningThresholdIt->second.end()) 47334dd179eSJames Feist { 47434dd179eSJames Feist const bool* asserted = std::get_if<bool>(&thresholdLowIt->second); 47534dd179eSJames Feist if (asserted == nullptr) 47634dd179eSJames Feist { 47734dd179eSJames Feist BMCWEB_LOG_ERROR << "Illegal sensor threshold"; 47834dd179eSJames Feist } 47934dd179eSJames Feist else if (*asserted) 48034dd179eSJames Feist { 48134dd179eSJames Feist return "Warning"; 48234dd179eSJames Feist } 48334dd179eSJames Feist } 48434dd179eSJames Feist } 48534dd179eSJames Feist return "OK"; 48634dd179eSJames Feist } 48734dd179eSJames Feist 48834dd179eSJames Feist /** 48908777fb0SLewanczyk, Dawid * @brief Builds a json sensor representation of a sensor. 49008777fb0SLewanczyk, Dawid * @param sensorName The name of the sensor to be built 491274fad5aSGunnar Mills * @param sensorType The type (temperature, fan_tach, etc) of the sensor to 49208777fb0SLewanczyk, Dawid * build 49308777fb0SLewanczyk, Dawid * @param interfacesDict A dictionary of the interfaces and properties of said 49408777fb0SLewanczyk, Dawid * interfaces to be built from 49508777fb0SLewanczyk, Dawid * @param sensor_json The json object to fill 49608777fb0SLewanczyk, Dawid */ 49708777fb0SLewanczyk, Dawid void objectInterfacesToJson( 49808777fb0SLewanczyk, Dawid const std::string& sensorName, const std::string& sensorType, 49908777fb0SLewanczyk, Dawid const boost::container::flat_map< 500aa2e59c1SEd Tanous std::string, boost::container::flat_map<std::string, SensorVariant>>& 50108777fb0SLewanczyk, Dawid interfacesDict, 5021abe55efSEd Tanous nlohmann::json& sensor_json) 5031abe55efSEd Tanous { 50408777fb0SLewanczyk, Dawid // We need a value interface before we can do anything with it 50555c7b7a2SEd Tanous auto valueIt = interfacesDict.find("xyz.openbmc_project.Sensor.Value"); 5061abe55efSEd Tanous if (valueIt == interfacesDict.end()) 5071abe55efSEd Tanous { 50855c7b7a2SEd Tanous BMCWEB_LOG_ERROR << "Sensor doesn't have a value interface"; 50908777fb0SLewanczyk, Dawid return; 51008777fb0SLewanczyk, Dawid } 51108777fb0SLewanczyk, Dawid 51208777fb0SLewanczyk, Dawid // Assume values exist as is (10^0 == 1) if no scale exists 51308777fb0SLewanczyk, Dawid int64_t scaleMultiplier = 0; 51408777fb0SLewanczyk, Dawid 51555c7b7a2SEd Tanous auto scaleIt = valueIt->second.find("Scale"); 51608777fb0SLewanczyk, Dawid // If a scale exists, pull value as int64, and use the scaling. 5171abe55efSEd Tanous if (scaleIt != valueIt->second.end()) 5181abe55efSEd Tanous { 519abf2add6SEd Tanous const int64_t* int64Value = std::get_if<int64_t>(&scaleIt->second); 5201abe55efSEd Tanous if (int64Value != nullptr) 5211abe55efSEd Tanous { 52208777fb0SLewanczyk, Dawid scaleMultiplier = *int64Value; 52308777fb0SLewanczyk, Dawid } 52408777fb0SLewanczyk, Dawid } 52508777fb0SLewanczyk, Dawid 52608777fb0SLewanczyk, Dawid sensor_json["MemberId"] = sensorName; 527e742b6ccSEd Tanous sensor_json["Name"] = boost::replace_all_copy(sensorName, "_", " "); 528e742b6ccSEd Tanous 52908777fb0SLewanczyk, Dawid sensor_json["Status"]["State"] = "Enabled"; 53034dd179eSJames Feist sensor_json["Status"]["Health"] = getHealth(interfacesDict); 53108777fb0SLewanczyk, Dawid 53208777fb0SLewanczyk, Dawid // Parameter to set to override the type we get from dbus, and force it to 53308777fb0SLewanczyk, Dawid // int, regardless of what is available. This is used for schemas like fan, 53408777fb0SLewanczyk, Dawid // that require integers, not floats. 53508777fb0SLewanczyk, Dawid bool forceToInt = false; 53608777fb0SLewanczyk, Dawid 53708777fb0SLewanczyk, Dawid const char* unit = "Reading"; 5381abe55efSEd Tanous if (sensorType == "temperature") 5391abe55efSEd Tanous { 54008777fb0SLewanczyk, Dawid unit = "ReadingCelsius"; 5417885954aSLewanczyk, Dawid sensor_json["@odata.type"] = "#Thermal.v1_3_0.Temperature"; 54208777fb0SLewanczyk, Dawid // TODO(ed) Documentation says that path should be type fan_tach, 54308777fb0SLewanczyk, Dawid // implementation seems to implement fan 5441abe55efSEd Tanous } 5451abe55efSEd Tanous else if (sensorType == "fan" || sensorType == "fan_tach") 5461abe55efSEd Tanous { 54708777fb0SLewanczyk, Dawid unit = "Reading"; 54808777fb0SLewanczyk, Dawid sensor_json["ReadingUnits"] = "RPM"; 5497885954aSLewanczyk, Dawid sensor_json["@odata.type"] = "#Thermal.v1_3_0.Fan"; 55008777fb0SLewanczyk, Dawid forceToInt = true; 5511abe55efSEd Tanous } 5526f6d0d32SEd Tanous else if (sensorType == "fan_pwm") 5536f6d0d32SEd Tanous { 5546f6d0d32SEd Tanous unit = "Reading"; 5556f6d0d32SEd Tanous sensor_json["ReadingUnits"] = "Percent"; 5566f6d0d32SEd Tanous sensor_json["@odata.type"] = "#Thermal.v1_3_0.Fan"; 5576f6d0d32SEd Tanous forceToInt = true; 5586f6d0d32SEd Tanous } 5591abe55efSEd Tanous else if (sensorType == "voltage") 5601abe55efSEd Tanous { 56108777fb0SLewanczyk, Dawid unit = "ReadingVolts"; 5627885954aSLewanczyk, Dawid sensor_json["@odata.type"] = "#Power.v1_0_0.Voltage"; 5631abe55efSEd Tanous } 5642474adfaSEd Tanous else if (sensorType == "power") 5652474adfaSEd Tanous { 56649c53ac9SJohnathan Mantey std::string sensorNameLower = 56749c53ac9SJohnathan Mantey boost::algorithm::to_lower_copy(sensorName); 56849c53ac9SJohnathan Mantey 569028f7ebcSEddie James if (!sensorName.compare("total_power")) 570028f7ebcSEddie James { 571028f7ebcSEddie James unit = "PowerConsumedWatts"; 572028f7ebcSEddie James } 573028f7ebcSEddie James else if (sensorNameLower.find("input") != std::string::npos) 57449c53ac9SJohnathan Mantey { 57549c53ac9SJohnathan Mantey unit = "PowerInputWatts"; 57649c53ac9SJohnathan Mantey } 57749c53ac9SJohnathan Mantey else 57849c53ac9SJohnathan Mantey { 57949c53ac9SJohnathan Mantey unit = "PowerOutputWatts"; 58049c53ac9SJohnathan Mantey } 5812474adfaSEd Tanous } 5821abe55efSEd Tanous else 5831abe55efSEd Tanous { 58455c7b7a2SEd Tanous BMCWEB_LOG_ERROR << "Redfish cannot map object type for " << sensorName; 58508777fb0SLewanczyk, Dawid return; 58608777fb0SLewanczyk, Dawid } 58708777fb0SLewanczyk, Dawid // Map of dbus interface name, dbus property name and redfish property_name 58808777fb0SLewanczyk, Dawid std::vector<std::tuple<const char*, const char*, const char*>> properties; 58908777fb0SLewanczyk, Dawid properties.reserve(7); 59008777fb0SLewanczyk, Dawid 59108777fb0SLewanczyk, Dawid properties.emplace_back("xyz.openbmc_project.Sensor.Value", "Value", unit); 592de629b6eSShawn McCarney 593de629b6eSShawn McCarney // If sensor type doesn't map to Redfish PowerSupply, add threshold props 594de629b6eSShawn McCarney if ((sensorType != "current") && (sensorType != "power")) 595de629b6eSShawn McCarney { 59608777fb0SLewanczyk, Dawid properties.emplace_back("xyz.openbmc_project.Sensor.Threshold.Warning", 59708777fb0SLewanczyk, Dawid "WarningHigh", "UpperThresholdNonCritical"); 59808777fb0SLewanczyk, Dawid properties.emplace_back("xyz.openbmc_project.Sensor.Threshold.Warning", 59908777fb0SLewanczyk, Dawid "WarningLow", "LowerThresholdNonCritical"); 60008777fb0SLewanczyk, Dawid properties.emplace_back("xyz.openbmc_project.Sensor.Threshold.Critical", 60108777fb0SLewanczyk, Dawid "CriticalHigh", "UpperThresholdCritical"); 60208777fb0SLewanczyk, Dawid properties.emplace_back("xyz.openbmc_project.Sensor.Threshold.Critical", 60308777fb0SLewanczyk, Dawid "CriticalLow", "LowerThresholdCritical"); 604de629b6eSShawn McCarney } 60508777fb0SLewanczyk, Dawid 6062474adfaSEd Tanous // TODO Need to get UpperThresholdFatal and LowerThresholdFatal 6072474adfaSEd Tanous 6081abe55efSEd Tanous if (sensorType == "temperature") 6091abe55efSEd Tanous { 61008777fb0SLewanczyk, Dawid properties.emplace_back("xyz.openbmc_project.Sensor.Value", "MinValue", 61108777fb0SLewanczyk, Dawid "MinReadingRangeTemp"); 61208777fb0SLewanczyk, Dawid properties.emplace_back("xyz.openbmc_project.Sensor.Value", "MaxValue", 61308777fb0SLewanczyk, Dawid "MaxReadingRangeTemp"); 6141abe55efSEd Tanous } 615de629b6eSShawn McCarney else if ((sensorType != "current") && (sensorType != "power")) 6161abe55efSEd Tanous { 617de629b6eSShawn McCarney // Sensor type doesn't map to Redfish PowerSupply; add min/max props 61808777fb0SLewanczyk, Dawid properties.emplace_back("xyz.openbmc_project.Sensor.Value", "MinValue", 61908777fb0SLewanczyk, Dawid "MinReadingRange"); 62008777fb0SLewanczyk, Dawid properties.emplace_back("xyz.openbmc_project.Sensor.Value", "MaxValue", 62108777fb0SLewanczyk, Dawid "MaxReadingRange"); 62208777fb0SLewanczyk, Dawid } 62308777fb0SLewanczyk, Dawid 62408777fb0SLewanczyk, Dawid for (const std::tuple<const char*, const char*, const char*>& p : 6251abe55efSEd Tanous properties) 6261abe55efSEd Tanous { 62708777fb0SLewanczyk, Dawid auto interfaceProperties = interfacesDict.find(std::get<0>(p)); 6281abe55efSEd Tanous if (interfaceProperties != interfacesDict.end()) 6291abe55efSEd Tanous { 630b01bf299SEd Tanous auto valueIt = interfaceProperties->second.find(std::get<1>(p)); 631b01bf299SEd Tanous if (valueIt != interfaceProperties->second.end()) 6321abe55efSEd Tanous { 633b01bf299SEd Tanous const SensorVariant& valueVariant = valueIt->second; 634b01bf299SEd Tanous nlohmann::json& valueIt = sensor_json[std::get<2>(p)]; 63508777fb0SLewanczyk, Dawid // Attempt to pull the int64 directly 636abf2add6SEd Tanous const int64_t* int64Value = std::get_if<int64_t>(&valueVariant); 63708777fb0SLewanczyk, Dawid 638abf2add6SEd Tanous const double* doubleValue = std::get_if<double>(&valueVariant); 639028f7ebcSEddie James const uint32_t* uValue = std::get_if<uint32_t>(&valueVariant); 6406f6d0d32SEd Tanous double temp = 0.0; 6416f6d0d32SEd Tanous if (int64Value != nullptr) 6421abe55efSEd Tanous { 6436f6d0d32SEd Tanous temp = *int64Value; 6446f6d0d32SEd Tanous } 6456f6d0d32SEd Tanous else if (doubleValue != nullptr) 6461abe55efSEd Tanous { 6476f6d0d32SEd Tanous temp = *doubleValue; 6481abe55efSEd Tanous } 649028f7ebcSEddie James else if (uValue != nullptr) 650028f7ebcSEddie James { 651028f7ebcSEddie James temp = *uValue; 652028f7ebcSEddie James } 6531abe55efSEd Tanous else 6541abe55efSEd Tanous { 6556f6d0d32SEd Tanous BMCWEB_LOG_ERROR 6566f6d0d32SEd Tanous << "Got value interface that wasn't int or double"; 6576f6d0d32SEd Tanous continue; 65808777fb0SLewanczyk, Dawid } 6596f6d0d32SEd Tanous temp = temp * std::pow(10, scaleMultiplier); 6606f6d0d32SEd Tanous if (forceToInt) 6616f6d0d32SEd Tanous { 662b01bf299SEd Tanous valueIt = static_cast<int64_t>(temp); 6636f6d0d32SEd Tanous } 6646f6d0d32SEd Tanous else 6656f6d0d32SEd Tanous { 666b01bf299SEd Tanous valueIt = temp; 66708777fb0SLewanczyk, Dawid } 66808777fb0SLewanczyk, Dawid } 66908777fb0SLewanczyk, Dawid } 67008777fb0SLewanczyk, Dawid } 67155c7b7a2SEd Tanous BMCWEB_LOG_DEBUG << "Added sensor " << sensorName; 67208777fb0SLewanczyk, Dawid } 67308777fb0SLewanczyk, Dawid 6748bd25ccdSJames Feist static void 6758bd25ccdSJames Feist populateFanRedundancy(std::shared_ptr<SensorsAsyncResp> sensorsAsyncResp) 6768bd25ccdSJames Feist { 6778bd25ccdSJames Feist crow::connections::systemBus->async_method_call( 6788bd25ccdSJames Feist [sensorsAsyncResp](const boost::system::error_code ec, 6798bd25ccdSJames Feist const GetSubTreeType& resp) { 6808bd25ccdSJames Feist if (ec) 6818bd25ccdSJames Feist { 6828bd25ccdSJames Feist return; // don't have to have this interface 6838bd25ccdSJames Feist } 684e278c18fSEd Tanous for (const std::pair<std::string, 685e278c18fSEd Tanous std::vector<std::pair< 686e278c18fSEd Tanous std::string, std::vector<std::string>>>>& 687e278c18fSEd Tanous pathPair : resp) 6888bd25ccdSJames Feist { 689e278c18fSEd Tanous const std::string& path = pathPair.first; 690e278c18fSEd Tanous const std::vector< 691e278c18fSEd Tanous std::pair<std::string, std::vector<std::string>>>& objDict = 692e278c18fSEd Tanous pathPair.second; 6938bd25ccdSJames Feist if (objDict.empty()) 6948bd25ccdSJames Feist { 6958bd25ccdSJames Feist continue; // this should be impossible 6968bd25ccdSJames Feist } 6978bd25ccdSJames Feist 6988bd25ccdSJames Feist const std::string& owner = objDict.begin()->first; 6998bd25ccdSJames Feist crow::connections::systemBus->async_method_call( 7008bd25ccdSJames Feist [path, owner, 7018bd25ccdSJames Feist sensorsAsyncResp](const boost::system::error_code ec, 7028bd25ccdSJames Feist std::variant<std::vector<std::string>> 7038bd25ccdSJames Feist variantEndpoints) { 7048bd25ccdSJames Feist if (ec) 7058bd25ccdSJames Feist { 7068bd25ccdSJames Feist return; // if they don't have an association we 7078bd25ccdSJames Feist // can't tell what chassis is 7088bd25ccdSJames Feist } 7098bd25ccdSJames Feist // verify part of the right chassis 7108bd25ccdSJames Feist auto endpoints = std::get_if<std::vector<std::string>>( 7118bd25ccdSJames Feist &variantEndpoints); 7128bd25ccdSJames Feist 7138bd25ccdSJames Feist if (endpoints == nullptr) 7148bd25ccdSJames Feist { 7158bd25ccdSJames Feist BMCWEB_LOG_ERROR << "Invalid association interface"; 7168bd25ccdSJames Feist messages::internalError(sensorsAsyncResp->res); 7178bd25ccdSJames Feist return; 7188bd25ccdSJames Feist } 7198bd25ccdSJames Feist 7208bd25ccdSJames Feist auto found = std::find_if( 7218bd25ccdSJames Feist endpoints->begin(), endpoints->end(), 7228bd25ccdSJames Feist [sensorsAsyncResp](const std::string& entry) { 7238bd25ccdSJames Feist return entry.find( 7248bd25ccdSJames Feist sensorsAsyncResp->chassisId) != 7258bd25ccdSJames Feist std::string::npos; 7268bd25ccdSJames Feist }); 7278bd25ccdSJames Feist 7288bd25ccdSJames Feist if (found == endpoints->end()) 7298bd25ccdSJames Feist { 7308bd25ccdSJames Feist return; 7318bd25ccdSJames Feist } 7328bd25ccdSJames Feist crow::connections::systemBus->async_method_call( 7338bd25ccdSJames Feist [path, sensorsAsyncResp]( 7348bd25ccdSJames Feist const boost::system::error_code ec, 7358bd25ccdSJames Feist const boost::container::flat_map< 7368bd25ccdSJames Feist std::string, 7378bd25ccdSJames Feist std::variant<uint8_t, 7388bd25ccdSJames Feist std::vector<std::string>, 7398bd25ccdSJames Feist std::string>>& ret) { 7408bd25ccdSJames Feist if (ec) 7418bd25ccdSJames Feist { 7428bd25ccdSJames Feist return; // don't have to have this 7438bd25ccdSJames Feist // interface 7448bd25ccdSJames Feist } 7458bd25ccdSJames Feist auto findFailures = ret.find("AllowedFailures"); 7468bd25ccdSJames Feist auto findCollection = ret.find("Collection"); 7478bd25ccdSJames Feist auto findStatus = ret.find("Status"); 7488bd25ccdSJames Feist 7498bd25ccdSJames Feist if (findFailures == ret.end() || 7508bd25ccdSJames Feist findCollection == ret.end() || 7518bd25ccdSJames Feist findStatus == ret.end()) 7528bd25ccdSJames Feist { 7538bd25ccdSJames Feist BMCWEB_LOG_ERROR 7548bd25ccdSJames Feist << "Invalid redundancy interface"; 7558bd25ccdSJames Feist messages::internalError( 7568bd25ccdSJames Feist sensorsAsyncResp->res); 7578bd25ccdSJames Feist return; 7588bd25ccdSJames Feist } 7598bd25ccdSJames Feist 7608bd25ccdSJames Feist auto allowedFailures = std::get_if<uint8_t>( 7618bd25ccdSJames Feist &(findFailures->second)); 7628bd25ccdSJames Feist auto collection = 7638bd25ccdSJames Feist std::get_if<std::vector<std::string>>( 7648bd25ccdSJames Feist &(findCollection->second)); 7658bd25ccdSJames Feist auto status = std::get_if<std::string>( 7668bd25ccdSJames Feist &(findStatus->second)); 7678bd25ccdSJames Feist 7688bd25ccdSJames Feist if (allowedFailures == nullptr || 7698bd25ccdSJames Feist collection == nullptr || status == nullptr) 7708bd25ccdSJames Feist { 7718bd25ccdSJames Feist 7728bd25ccdSJames Feist BMCWEB_LOG_ERROR 7738bd25ccdSJames Feist << "Invalid redundancy interface " 7748bd25ccdSJames Feist "types"; 7758bd25ccdSJames Feist messages::internalError( 7768bd25ccdSJames Feist sensorsAsyncResp->res); 7778bd25ccdSJames Feist return; 7788bd25ccdSJames Feist } 7798bd25ccdSJames Feist size_t lastSlash = path.rfind("/"); 7808bd25ccdSJames Feist if (lastSlash == std::string::npos) 7818bd25ccdSJames Feist { 7828bd25ccdSJames Feist // this should be impossible 7838bd25ccdSJames Feist messages::internalError( 7848bd25ccdSJames Feist sensorsAsyncResp->res); 7858bd25ccdSJames Feist return; 7868bd25ccdSJames Feist } 7878bd25ccdSJames Feist std::string name = path.substr(lastSlash + 1); 7888bd25ccdSJames Feist std::replace(name.begin(), name.end(), '_', 7898bd25ccdSJames Feist ' '); 7908bd25ccdSJames Feist 7918bd25ccdSJames Feist std::string health; 7928bd25ccdSJames Feist 7938bd25ccdSJames Feist if (boost::ends_with(*status, "Full")) 7948bd25ccdSJames Feist { 7958bd25ccdSJames Feist health = "OK"; 7968bd25ccdSJames Feist } 7978bd25ccdSJames Feist else if (boost::ends_with(*status, "Degraded")) 7988bd25ccdSJames Feist { 7998bd25ccdSJames Feist health = "Warning"; 8008bd25ccdSJames Feist } 8018bd25ccdSJames Feist else 8028bd25ccdSJames Feist { 8038bd25ccdSJames Feist health = "Critical"; 8048bd25ccdSJames Feist } 8058bd25ccdSJames Feist std::vector<nlohmann::json> redfishCollection; 8068bd25ccdSJames Feist const auto& fanRedfish = 8078bd25ccdSJames Feist sensorsAsyncResp->res.jsonValue["Fans"]; 8088bd25ccdSJames Feist for (const std::string& item : *collection) 8098bd25ccdSJames Feist { 8108bd25ccdSJames Feist lastSlash = item.rfind("/"); 8118bd25ccdSJames Feist // make a copy as collection is const 8128bd25ccdSJames Feist std::string itemName = 8138bd25ccdSJames Feist item.substr(lastSlash + 1); 8148bd25ccdSJames Feist /* 8158bd25ccdSJames Feist todo(ed): merge patch that fixes the names 8168bd25ccdSJames Feist std::replace(itemName.begin(), 8178bd25ccdSJames Feist itemName.end(), '_', ' ');*/ 8188bd25ccdSJames Feist auto schemaItem = std::find_if( 8198bd25ccdSJames Feist fanRedfish.begin(), fanRedfish.end(), 8208bd25ccdSJames Feist [itemName](const nlohmann::json& fan) { 8218bd25ccdSJames Feist return fan["MemberId"] == itemName; 8228bd25ccdSJames Feist }); 8238bd25ccdSJames Feist if (schemaItem != fanRedfish.end()) 8248bd25ccdSJames Feist { 8258bd25ccdSJames Feist redfishCollection.push_back( 8268bd25ccdSJames Feist {{"@odata.id", 8278bd25ccdSJames Feist (*schemaItem)["@odata.id"]}}); 8288bd25ccdSJames Feist } 8298bd25ccdSJames Feist else 8308bd25ccdSJames Feist { 8318bd25ccdSJames Feist BMCWEB_LOG_ERROR 8328bd25ccdSJames Feist << "failed to find fan in schema"; 8338bd25ccdSJames Feist messages::internalError( 8348bd25ccdSJames Feist sensorsAsyncResp->res); 8358bd25ccdSJames Feist return; 8368bd25ccdSJames Feist } 8378bd25ccdSJames Feist } 8388bd25ccdSJames Feist 8398bd25ccdSJames Feist auto& resp = sensorsAsyncResp->res 8408bd25ccdSJames Feist .jsonValue["Redundancy"]; 8418bd25ccdSJames Feist resp.push_back( 8428bd25ccdSJames Feist {{"@odata.id", 8438bd25ccdSJames Feist "/refish/v1/Chassis/" + 8448bd25ccdSJames Feist sensorsAsyncResp->chassisId + "/" + 8458bd25ccdSJames Feist sensorsAsyncResp->chassisSubNode + 8468bd25ccdSJames Feist "#/Redundancy/" + 8478bd25ccdSJames Feist std::to_string(resp.size())}, 8488bd25ccdSJames Feist {"@odata.type", 8498bd25ccdSJames Feist "#Redundancy.v1_3_2.Redundancy"}, 8508bd25ccdSJames Feist {"MinNumNeeded", 8518bd25ccdSJames Feist collection->size() - *allowedFailures}, 8528bd25ccdSJames Feist {"MemberId", name}, 8538bd25ccdSJames Feist {"Mode", "N+m"}, 8548bd25ccdSJames Feist {"Name", name}, 8558bd25ccdSJames Feist {"RedundancySet", redfishCollection}, 8568bd25ccdSJames Feist {"Status", 8578bd25ccdSJames Feist {{"Health", health}, 8588bd25ccdSJames Feist {"State", "Enabled"}}}}); 8598bd25ccdSJames Feist }, 8608bd25ccdSJames Feist owner, path, "org.freedesktop.DBus.Properties", 8618bd25ccdSJames Feist "GetAll", 8628bd25ccdSJames Feist "xyz.openbmc_project.Control.FanRedundancy"); 8638bd25ccdSJames Feist }, 8648bd25ccdSJames Feist "xyz.openbmc_project.ObjectMapper", path + "/inventory", 8658bd25ccdSJames Feist "org.freedesktop.DBus.Properties", "Get", 8668bd25ccdSJames Feist "xyz.openbmc_project.Association", "endpoints"); 8678bd25ccdSJames Feist } 8688bd25ccdSJames Feist }, 8698bd25ccdSJames Feist "xyz.openbmc_project.ObjectMapper", 8708bd25ccdSJames Feist "/xyz/openbmc_project/object_mapper", 8718bd25ccdSJames Feist "xyz.openbmc_project.ObjectMapper", "GetSubTree", 8728bd25ccdSJames Feist "/xyz/openbmc_project/control", 2, 8738bd25ccdSJames Feist std::array<const char*, 1>{ 8748bd25ccdSJames Feist "xyz.openbmc_project.Control.FanRedundancy"}); 8758bd25ccdSJames Feist } 8768bd25ccdSJames Feist 87749c53ac9SJohnathan Mantey void sortJSONResponse(std::shared_ptr<SensorsAsyncResp> SensorsAsyncResp) 87849c53ac9SJohnathan Mantey { 87949c53ac9SJohnathan Mantey nlohmann::json& response = SensorsAsyncResp->res.jsonValue; 88049c53ac9SJohnathan Mantey std::array<std::string, 2> sensorHeaders{"Temperatures", "Fans"}; 88149c53ac9SJohnathan Mantey if (SensorsAsyncResp->chassisSubNode == "Power") 88249c53ac9SJohnathan Mantey { 88349c53ac9SJohnathan Mantey sensorHeaders = {"Voltages", "PowerSupplies"}; 88449c53ac9SJohnathan Mantey } 88549c53ac9SJohnathan Mantey for (const std::string& sensorGroup : sensorHeaders) 88649c53ac9SJohnathan Mantey { 88749c53ac9SJohnathan Mantey nlohmann::json::iterator entry = response.find(sensorGroup); 88849c53ac9SJohnathan Mantey if (entry != response.end()) 88949c53ac9SJohnathan Mantey { 89049c53ac9SJohnathan Mantey std::sort(entry->begin(), entry->end(), 89149c53ac9SJohnathan Mantey [](nlohmann::json& c1, nlohmann::json& c2) { 89249c53ac9SJohnathan Mantey return c1["Name"] < c2["Name"]; 89349c53ac9SJohnathan Mantey }); 89449c53ac9SJohnathan Mantey 89549c53ac9SJohnathan Mantey // add the index counts to the end of each entry 89649c53ac9SJohnathan Mantey size_t count = 0; 89749c53ac9SJohnathan Mantey for (nlohmann::json& sensorJson : *entry) 89849c53ac9SJohnathan Mantey { 89949c53ac9SJohnathan Mantey nlohmann::json::iterator odata = sensorJson.find("@odata.id"); 90049c53ac9SJohnathan Mantey if (odata == sensorJson.end()) 90149c53ac9SJohnathan Mantey { 90249c53ac9SJohnathan Mantey continue; 90349c53ac9SJohnathan Mantey } 90449c53ac9SJohnathan Mantey std::string* value = odata->get_ptr<std::string*>(); 90549c53ac9SJohnathan Mantey if (value != nullptr) 90649c53ac9SJohnathan Mantey { 90749c53ac9SJohnathan Mantey *value += std::to_string(count); 90849c53ac9SJohnathan Mantey count++; 90949c53ac9SJohnathan Mantey } 91049c53ac9SJohnathan Mantey } 91149c53ac9SJohnathan Mantey } 91249c53ac9SJohnathan Mantey } 91349c53ac9SJohnathan Mantey } 91449c53ac9SJohnathan Mantey 91508777fb0SLewanczyk, Dawid /** 916*8fb49dd6SShawn McCarney * @brief Finds the JSON object for the specified sensor. 917*8fb49dd6SShawn McCarney * 918*8fb49dd6SShawn McCarney * Searches the JSON response in sensorsAsyncResp for an object corresponding to 919*8fb49dd6SShawn McCarney * the specified sensor. 920*8fb49dd6SShawn McCarney * 921*8fb49dd6SShawn McCarney * @param sensorsAsyncResp Pointer to object holding response data. 922*8fb49dd6SShawn McCarney * @param sensorName DBus object path to the sensor. 923*8fb49dd6SShawn McCarney * @return Pointer to JSON object, or nullptr if object not found. 924*8fb49dd6SShawn McCarney */ 925*8fb49dd6SShawn McCarney static nlohmann::json* 926*8fb49dd6SShawn McCarney findSensorJson(std::shared_ptr<SensorsAsyncResp> sensorsAsyncResp, 927*8fb49dd6SShawn McCarney const std::string& sensorName) 928*8fb49dd6SShawn McCarney { 929*8fb49dd6SShawn McCarney // Get base name of sensor 930*8fb49dd6SShawn McCarney std::size_t lastSlash = sensorName.rfind('/'); 931*8fb49dd6SShawn McCarney if (lastSlash != std::string::npos) 932*8fb49dd6SShawn McCarney { 933*8fb49dd6SShawn McCarney std::string baseSensorName = sensorName.substr(lastSlash + 1); 934*8fb49dd6SShawn McCarney 935*8fb49dd6SShawn McCarney // Loop through JSON sensor groups that could contain sensor 936*8fb49dd6SShawn McCarney nlohmann::json& response = sensorsAsyncResp->res.jsonValue; 937*8fb49dd6SShawn McCarney std::array<std::string, 4> sensorGroups{"Temperatures", "Fans", 938*8fb49dd6SShawn McCarney "Voltages", "PowerSupplies"}; 939*8fb49dd6SShawn McCarney for (const std::string& sensorGroup : sensorGroups) 940*8fb49dd6SShawn McCarney { 941*8fb49dd6SShawn McCarney nlohmann::json::iterator groupIt = response.find(sensorGroup); 942*8fb49dd6SShawn McCarney if (groupIt != response.end()) 943*8fb49dd6SShawn McCarney { 944*8fb49dd6SShawn McCarney // Loop through sensors in current group 945*8fb49dd6SShawn McCarney for (nlohmann::json& sensorJson : *groupIt) 946*8fb49dd6SShawn McCarney { 947*8fb49dd6SShawn McCarney // Check if this is the sensor we are looking for 948*8fb49dd6SShawn McCarney nlohmann::json::iterator memberIdIt = 949*8fb49dd6SShawn McCarney sensorJson.find("MemberId"); 950*8fb49dd6SShawn McCarney if (memberIdIt != sensorJson.end()) 951*8fb49dd6SShawn McCarney { 952*8fb49dd6SShawn McCarney std::string* memberId = 953*8fb49dd6SShawn McCarney memberIdIt->get_ptr<std::string*>(); 954*8fb49dd6SShawn McCarney if ((memberId != nullptr) && 955*8fb49dd6SShawn McCarney (*memberId == baseSensorName)) 956*8fb49dd6SShawn McCarney { 957*8fb49dd6SShawn McCarney return &sensorJson; 958*8fb49dd6SShawn McCarney } 959*8fb49dd6SShawn McCarney } 960*8fb49dd6SShawn McCarney } 961*8fb49dd6SShawn McCarney } 962*8fb49dd6SShawn McCarney } 963*8fb49dd6SShawn McCarney } 964*8fb49dd6SShawn McCarney 965*8fb49dd6SShawn McCarney // Unable to find JSON object for specified sensor 966*8fb49dd6SShawn McCarney return nullptr; 967*8fb49dd6SShawn McCarney } 968*8fb49dd6SShawn McCarney 969*8fb49dd6SShawn McCarney /** 970*8fb49dd6SShawn McCarney * @brief Updates sensor status in JSON response based on inventory item status. 971*8fb49dd6SShawn McCarney * 972*8fb49dd6SShawn McCarney * Updates the status of the specified sensor based on the status of a related 973*8fb49dd6SShawn McCarney * inventory item. 974*8fb49dd6SShawn McCarney * 975*8fb49dd6SShawn McCarney * Modifies the Redfish Status property in the JSON response if the inventory 976*8fb49dd6SShawn McCarney * item indicates the hardware is not present or not functional. 977*8fb49dd6SShawn McCarney * 978*8fb49dd6SShawn McCarney * The D-Bus Present and Functional properties are typically on the inventory 979*8fb49dd6SShawn McCarney * item rather than the sensor. 980*8fb49dd6SShawn McCarney * 981*8fb49dd6SShawn McCarney * @param sensorsAsyncResp Pointer to object holding response data. 982*8fb49dd6SShawn McCarney * @param sensorName DBus object path to the sensor. 983*8fb49dd6SShawn McCarney * @param interfacesDict Map containing the interfaces and properties of the 984*8fb49dd6SShawn McCarney * inventory item associated with this sensor. 985*8fb49dd6SShawn McCarney */ 986*8fb49dd6SShawn McCarney static void updateSensorStatus( 987*8fb49dd6SShawn McCarney std::shared_ptr<SensorsAsyncResp> sensorsAsyncResp, 988*8fb49dd6SShawn McCarney const std::string& sensorName, 989*8fb49dd6SShawn McCarney const boost::container::flat_map< 990*8fb49dd6SShawn McCarney std::string, boost::container::flat_map<std::string, SensorVariant>>& 991*8fb49dd6SShawn McCarney interfacesDict) 992*8fb49dd6SShawn McCarney { 993*8fb49dd6SShawn McCarney // Find the JSON object in the response for this sensor 994*8fb49dd6SShawn McCarney nlohmann::json* sensorJson = findSensorJson(sensorsAsyncResp, sensorName); 995*8fb49dd6SShawn McCarney if (sensorJson != nullptr) 996*8fb49dd6SShawn McCarney { 997*8fb49dd6SShawn McCarney // Get Inventory.Item.Present property of inventory item 998*8fb49dd6SShawn McCarney auto itemIt = interfacesDict.find("xyz.openbmc_project.Inventory.Item"); 999*8fb49dd6SShawn McCarney if (itemIt != interfacesDict.end()) 1000*8fb49dd6SShawn McCarney { 1001*8fb49dd6SShawn McCarney auto presentIt = itemIt->second.find("Present"); 1002*8fb49dd6SShawn McCarney if (presentIt != itemIt->second.end()) 1003*8fb49dd6SShawn McCarney { 1004*8fb49dd6SShawn McCarney const bool* present = std::get_if<bool>(&presentIt->second); 1005*8fb49dd6SShawn McCarney if ((present != nullptr) && (*present == false)) 1006*8fb49dd6SShawn McCarney { 1007*8fb49dd6SShawn McCarney // Inventory item is not present; update sensor State 1008*8fb49dd6SShawn McCarney (*sensorJson)["Status"]["State"] = "Absent"; 1009*8fb49dd6SShawn McCarney } 1010*8fb49dd6SShawn McCarney } 1011*8fb49dd6SShawn McCarney } 1012*8fb49dd6SShawn McCarney 1013*8fb49dd6SShawn McCarney // Get OperationalStatus.Functional property of inventory item 1014*8fb49dd6SShawn McCarney auto opStatusIt = interfacesDict.find( 1015*8fb49dd6SShawn McCarney "xyz.openbmc_project.State.Decorator.OperationalStatus"); 1016*8fb49dd6SShawn McCarney if (opStatusIt != interfacesDict.end()) 1017*8fb49dd6SShawn McCarney { 1018*8fb49dd6SShawn McCarney auto functionalIt = opStatusIt->second.find("Functional"); 1019*8fb49dd6SShawn McCarney if (functionalIt != opStatusIt->second.end()) 1020*8fb49dd6SShawn McCarney { 1021*8fb49dd6SShawn McCarney const bool* functional = 1022*8fb49dd6SShawn McCarney std::get_if<bool>(&functionalIt->second); 1023*8fb49dd6SShawn McCarney if ((functional != nullptr) && (*functional == false)) 1024*8fb49dd6SShawn McCarney { 1025*8fb49dd6SShawn McCarney // Inventory item is not functional; update sensor Health 1026*8fb49dd6SShawn McCarney (*sensorJson)["Status"]["Health"] = "Critical"; 1027*8fb49dd6SShawn McCarney } 1028*8fb49dd6SShawn McCarney } 1029*8fb49dd6SShawn McCarney } 1030*8fb49dd6SShawn McCarney } 1031*8fb49dd6SShawn McCarney } 1032*8fb49dd6SShawn McCarney 1033*8fb49dd6SShawn McCarney /** 1034*8fb49dd6SShawn McCarney * @brief Gets status of inventory items associated with sensors. 1035*8fb49dd6SShawn McCarney * 1036*8fb49dd6SShawn McCarney * Gets the D-Bus status properties for the inventory items associated with 1037*8fb49dd6SShawn McCarney * sensors. 1038*8fb49dd6SShawn McCarney * 1039*8fb49dd6SShawn McCarney * Updates the Redfish sensors status in the JSON response, if needed, based on 1040*8fb49dd6SShawn McCarney * the inventory items status. 1041*8fb49dd6SShawn McCarney * 1042*8fb49dd6SShawn McCarney * @param sensorsAsyncResp Pointer to object holding response data. 1043*8fb49dd6SShawn McCarney * @param sensorToInvMap Mappings from sensor object path to the associated 1044*8fb49dd6SShawn McCarney * inventory object path. 1045*8fb49dd6SShawn McCarney * @param invConnections Connections that provide the status 1046*8fb49dd6SShawn McCarney * interfaces/properties for the inventory items. 1047*8fb49dd6SShawn McCarney * @param objectMgrPaths Mappings from connection name to DBus object path that 1048*8fb49dd6SShawn McCarney * implements ObjectManager. 1049*8fb49dd6SShawn McCarney */ 1050*8fb49dd6SShawn McCarney static void getInventoryItemsStatus( 1051*8fb49dd6SShawn McCarney std::shared_ptr<SensorsAsyncResp> sensorsAsyncResp, 1052*8fb49dd6SShawn McCarney std::shared_ptr<boost::container::flat_map<std::string, std::string>> 1053*8fb49dd6SShawn McCarney sensorToInvMap, 1054*8fb49dd6SShawn McCarney std::shared_ptr<boost::container::flat_set<std::string>> invConnections, 1055*8fb49dd6SShawn McCarney std::shared_ptr<boost::container::flat_map<std::string, std::string>> 1056*8fb49dd6SShawn McCarney objectMgrPaths) 1057*8fb49dd6SShawn McCarney { 1058*8fb49dd6SShawn McCarney BMCWEB_LOG_DEBUG << "getInventoryItemsStatus enter"; 1059*8fb49dd6SShawn McCarney 1060*8fb49dd6SShawn McCarney // Loop through all connections providing inventory item status 1061*8fb49dd6SShawn McCarney for (const std::string& invConnection : *invConnections) 1062*8fb49dd6SShawn McCarney { 1063*8fb49dd6SShawn McCarney // Response handler for GetManagedObjects 1064*8fb49dd6SShawn McCarney auto respHandler = [sensorsAsyncResp, 1065*8fb49dd6SShawn McCarney sensorToInvMap](const boost::system::error_code ec, 1066*8fb49dd6SShawn McCarney ManagedObjectsVectorType& resp) { 1067*8fb49dd6SShawn McCarney BMCWEB_LOG_DEBUG << "getInventoryItemsStatus respHandler enter"; 1068*8fb49dd6SShawn McCarney if (ec) 1069*8fb49dd6SShawn McCarney { 1070*8fb49dd6SShawn McCarney BMCWEB_LOG_ERROR 1071*8fb49dd6SShawn McCarney << "getInventoryItemsStatus respHandler DBus error " << ec; 1072*8fb49dd6SShawn McCarney messages::internalError(sensorsAsyncResp->res); 1073*8fb49dd6SShawn McCarney return; 1074*8fb49dd6SShawn McCarney } 1075*8fb49dd6SShawn McCarney 1076*8fb49dd6SShawn McCarney // Loop through returned object paths 1077*8fb49dd6SShawn McCarney for (const auto& objDictEntry : resp) 1078*8fb49dd6SShawn McCarney { 1079*8fb49dd6SShawn McCarney const std::string& objPath = 1080*8fb49dd6SShawn McCarney static_cast<const std::string&>(objDictEntry.first); 1081*8fb49dd6SShawn McCarney 1082*8fb49dd6SShawn McCarney // Find all sensors associated with this inventory item 1083*8fb49dd6SShawn McCarney for (const std::pair<std::string, std::string>& pair : 1084*8fb49dd6SShawn McCarney *sensorToInvMap) 1085*8fb49dd6SShawn McCarney { 1086*8fb49dd6SShawn McCarney if (pair.second == objPath) 1087*8fb49dd6SShawn McCarney { 1088*8fb49dd6SShawn McCarney // Update sensor status based on inventory item status 1089*8fb49dd6SShawn McCarney updateSensorStatus(sensorsAsyncResp, pair.first, 1090*8fb49dd6SShawn McCarney objDictEntry.second); 1091*8fb49dd6SShawn McCarney } 1092*8fb49dd6SShawn McCarney } 1093*8fb49dd6SShawn McCarney } 1094*8fb49dd6SShawn McCarney 1095*8fb49dd6SShawn McCarney BMCWEB_LOG_DEBUG << "getInventoryItemsStatus respHandler exit"; 1096*8fb49dd6SShawn McCarney }; 1097*8fb49dd6SShawn McCarney 1098*8fb49dd6SShawn McCarney // Find DBus object path that implements ObjectManager for the current 1099*8fb49dd6SShawn McCarney // connection. If no mapping found, default to "/". 1100*8fb49dd6SShawn McCarney auto iter = objectMgrPaths->find(invConnection); 1101*8fb49dd6SShawn McCarney const std::string& objectMgrPath = 1102*8fb49dd6SShawn McCarney (iter != objectMgrPaths->end()) ? iter->second : "/"; 1103*8fb49dd6SShawn McCarney BMCWEB_LOG_DEBUG << "ObjectManager path for " << invConnection << " is " 1104*8fb49dd6SShawn McCarney << objectMgrPath; 1105*8fb49dd6SShawn McCarney 1106*8fb49dd6SShawn McCarney // Get all object paths and their interfaces for current connection 1107*8fb49dd6SShawn McCarney crow::connections::systemBus->async_method_call( 1108*8fb49dd6SShawn McCarney std::move(respHandler), invConnection, objectMgrPath, 1109*8fb49dd6SShawn McCarney "org.freedesktop.DBus.ObjectManager", "GetManagedObjects"); 1110*8fb49dd6SShawn McCarney } 1111*8fb49dd6SShawn McCarney 1112*8fb49dd6SShawn McCarney BMCWEB_LOG_DEBUG << "getInventoryItemsStatus exit"; 1113*8fb49dd6SShawn McCarney } 1114*8fb49dd6SShawn McCarney 1115*8fb49dd6SShawn McCarney /** 1116*8fb49dd6SShawn McCarney * @brief Gets connections that provide status information on inventory items. 1117*8fb49dd6SShawn McCarney * 1118*8fb49dd6SShawn McCarney * Gets the D-Bus connections (services) that provide the interfaces and 1119*8fb49dd6SShawn McCarney * properties containing status information for the inventory items. 1120*8fb49dd6SShawn McCarney * 1121*8fb49dd6SShawn McCarney * Finds the connections asynchronously. Invokes callback when information has 1122*8fb49dd6SShawn McCarney * been obtained. 1123*8fb49dd6SShawn McCarney * 1124*8fb49dd6SShawn McCarney * The callback must have the following signature: 1125*8fb49dd6SShawn McCarney * @code 1126*8fb49dd6SShawn McCarney * callback(std::shared_ptr<boost::container::flat_set<std::string>> 1127*8fb49dd6SShawn McCarney * invConnections) 1128*8fb49dd6SShawn McCarney * @endcode 1129*8fb49dd6SShawn McCarney * 1130*8fb49dd6SShawn McCarney * @param sensorsAsyncResp Pointer to object holding response data. 1131*8fb49dd6SShawn McCarney * @param sensorToInvMap Mappings from sensor object path to the associated 1132*8fb49dd6SShawn McCarney * inventory object path. 1133*8fb49dd6SShawn McCarney * @param callback Callback to invoke when connections have been obtained. 1134*8fb49dd6SShawn McCarney */ 1135*8fb49dd6SShawn McCarney template <typename Callback> 1136*8fb49dd6SShawn McCarney static void getInventoryItemsConnections( 1137*8fb49dd6SShawn McCarney std::shared_ptr<SensorsAsyncResp> sensorsAsyncResp, 1138*8fb49dd6SShawn McCarney std::shared_ptr<boost::container::flat_map<std::string, std::string>> 1139*8fb49dd6SShawn McCarney sensorToInvMap, 1140*8fb49dd6SShawn McCarney Callback&& callback) 1141*8fb49dd6SShawn McCarney { 1142*8fb49dd6SShawn McCarney BMCWEB_LOG_DEBUG << "getInventoryItemsConnections enter"; 1143*8fb49dd6SShawn McCarney 1144*8fb49dd6SShawn McCarney const std::string path = "/xyz/openbmc_project/inventory"; 1145*8fb49dd6SShawn McCarney const std::array<std::string, 2> interfaces = { 1146*8fb49dd6SShawn McCarney "xyz.openbmc_project.Inventory.Item", 1147*8fb49dd6SShawn McCarney "xyz.openbmc_project.State.Decorator.OperationalStatus"}; 1148*8fb49dd6SShawn McCarney 1149*8fb49dd6SShawn McCarney // Response handler for parsing output from GetSubTree 1150*8fb49dd6SShawn McCarney auto respHandler = [callback{std::move(callback)}, sensorsAsyncResp, 1151*8fb49dd6SShawn McCarney sensorToInvMap](const boost::system::error_code ec, 1152*8fb49dd6SShawn McCarney const GetSubTreeType& subtree) { 1153*8fb49dd6SShawn McCarney BMCWEB_LOG_DEBUG << "getInventoryItemsConnections respHandler enter"; 1154*8fb49dd6SShawn McCarney if (ec) 1155*8fb49dd6SShawn McCarney { 1156*8fb49dd6SShawn McCarney messages::internalError(sensorsAsyncResp->res); 1157*8fb49dd6SShawn McCarney BMCWEB_LOG_ERROR 1158*8fb49dd6SShawn McCarney << "getInventoryItemsConnections respHandler DBus error " << ec; 1159*8fb49dd6SShawn McCarney return; 1160*8fb49dd6SShawn McCarney } 1161*8fb49dd6SShawn McCarney 1162*8fb49dd6SShawn McCarney // Make unique list of connections for desired inventory items 1163*8fb49dd6SShawn McCarney std::shared_ptr<boost::container::flat_set<std::string>> 1164*8fb49dd6SShawn McCarney invConnections = 1165*8fb49dd6SShawn McCarney std::make_shared<boost::container::flat_set<std::string>>(); 1166*8fb49dd6SShawn McCarney invConnections->reserve(8); 1167*8fb49dd6SShawn McCarney 1168*8fb49dd6SShawn McCarney // Loop through objects from GetSubTree 1169*8fb49dd6SShawn McCarney for (const std::pair< 1170*8fb49dd6SShawn McCarney std::string, 1171*8fb49dd6SShawn McCarney std::vector<std::pair<std::string, std::vector<std::string>>>>& 1172*8fb49dd6SShawn McCarney object : subtree) 1173*8fb49dd6SShawn McCarney { 1174*8fb49dd6SShawn McCarney // Look for inventory item object path in the sensor->inventory map 1175*8fb49dd6SShawn McCarney const std::string& objPath = object.first; 1176*8fb49dd6SShawn McCarney for (const std::pair<std::string, std::string>& pair : 1177*8fb49dd6SShawn McCarney *sensorToInvMap) 1178*8fb49dd6SShawn McCarney { 1179*8fb49dd6SShawn McCarney if (pair.second == objPath) 1180*8fb49dd6SShawn McCarney { 1181*8fb49dd6SShawn McCarney // Store all connections to inventory item 1182*8fb49dd6SShawn McCarney for (const std::pair<std::string, std::vector<std::string>>& 1183*8fb49dd6SShawn McCarney objData : object.second) 1184*8fb49dd6SShawn McCarney { 1185*8fb49dd6SShawn McCarney const std::string& invConnection = objData.first; 1186*8fb49dd6SShawn McCarney invConnections->insert(invConnection); 1187*8fb49dd6SShawn McCarney } 1188*8fb49dd6SShawn McCarney break; 1189*8fb49dd6SShawn McCarney } 1190*8fb49dd6SShawn McCarney } 1191*8fb49dd6SShawn McCarney } 1192*8fb49dd6SShawn McCarney callback(invConnections); 1193*8fb49dd6SShawn McCarney BMCWEB_LOG_DEBUG << "getInventoryItemsConnections respHandler exit"; 1194*8fb49dd6SShawn McCarney }; 1195*8fb49dd6SShawn McCarney 1196*8fb49dd6SShawn McCarney // Make call to ObjectMapper to find all inventory items 1197*8fb49dd6SShawn McCarney crow::connections::systemBus->async_method_call( 1198*8fb49dd6SShawn McCarney std::move(respHandler), "xyz.openbmc_project.ObjectMapper", 1199*8fb49dd6SShawn McCarney "/xyz/openbmc_project/object_mapper", 1200*8fb49dd6SShawn McCarney "xyz.openbmc_project.ObjectMapper", "GetSubTree", path, 0, interfaces); 1201*8fb49dd6SShawn McCarney BMCWEB_LOG_DEBUG << "getInventoryItemsConnections exit"; 1202*8fb49dd6SShawn McCarney } 1203*8fb49dd6SShawn McCarney 1204*8fb49dd6SShawn McCarney /** 1205*8fb49dd6SShawn McCarney * @brief Gets inventory items associated with the specified sensors. 1206*8fb49dd6SShawn McCarney * 1207*8fb49dd6SShawn McCarney * Looks for ObjectMapper associations from the specified sensors to related 1208*8fb49dd6SShawn McCarney * inventory items. Builds map where key is sensor object path and value is 1209*8fb49dd6SShawn McCarney * inventory item object path. 1210*8fb49dd6SShawn McCarney * 1211*8fb49dd6SShawn McCarney * Finds the inventory items asynchronously. Invokes callback when information 1212*8fb49dd6SShawn McCarney * has been obtained. 1213*8fb49dd6SShawn McCarney * 1214*8fb49dd6SShawn McCarney * The callback must have the following signature: 1215*8fb49dd6SShawn McCarney * @code 1216*8fb49dd6SShawn McCarney * callback(std::shared_ptr<boost::container::flat_map< 1217*8fb49dd6SShawn McCarney std::string, std::string>> sensorToInvMap) 1218*8fb49dd6SShawn McCarney * @endcode 1219*8fb49dd6SShawn McCarney * 1220*8fb49dd6SShawn McCarney * @param sensorsAsyncResp Pointer to object holding response data. 1221*8fb49dd6SShawn McCarney * @param sensorNames All sensors within the current chassis. 1222*8fb49dd6SShawn McCarney * @param objectMgrPaths Mappings from connection name to DBus object path that 1223*8fb49dd6SShawn McCarney * implements ObjectManager. 1224*8fb49dd6SShawn McCarney * @param callback Callback to invoke when inventory items have been obtained. 1225*8fb49dd6SShawn McCarney */ 1226*8fb49dd6SShawn McCarney template <typename Callback> 1227*8fb49dd6SShawn McCarney static void getInventoryItems( 1228*8fb49dd6SShawn McCarney std::shared_ptr<SensorsAsyncResp> sensorsAsyncResp, 1229*8fb49dd6SShawn McCarney const std::shared_ptr<boost::container::flat_set<std::string>> sensorNames, 1230*8fb49dd6SShawn McCarney std::shared_ptr<boost::container::flat_map<std::string, std::string>> 1231*8fb49dd6SShawn McCarney objectMgrPaths, 1232*8fb49dd6SShawn McCarney Callback&& callback) 1233*8fb49dd6SShawn McCarney { 1234*8fb49dd6SShawn McCarney BMCWEB_LOG_DEBUG << "getInventoryItems enter"; 1235*8fb49dd6SShawn McCarney 1236*8fb49dd6SShawn McCarney // Response handler for GetManagedObjects 1237*8fb49dd6SShawn McCarney auto respHandler = [callback{std::move(callback)}, sensorsAsyncResp, 1238*8fb49dd6SShawn McCarney sensorNames](const boost::system::error_code ec, 1239*8fb49dd6SShawn McCarney dbus::utility::ManagedObjectType& resp) { 1240*8fb49dd6SShawn McCarney BMCWEB_LOG_DEBUG << "getInventoryItems respHandler enter"; 1241*8fb49dd6SShawn McCarney if (ec) 1242*8fb49dd6SShawn McCarney { 1243*8fb49dd6SShawn McCarney BMCWEB_LOG_ERROR << "getInventoryItems respHandler DBus error " 1244*8fb49dd6SShawn McCarney << ec; 1245*8fb49dd6SShawn McCarney messages::internalError(sensorsAsyncResp->res); 1246*8fb49dd6SShawn McCarney return; 1247*8fb49dd6SShawn McCarney } 1248*8fb49dd6SShawn McCarney 1249*8fb49dd6SShawn McCarney // Loop through returned object paths 1250*8fb49dd6SShawn McCarney std::shared_ptr<boost::container::flat_map<std::string, std::string>> 1251*8fb49dd6SShawn McCarney sensorToInvMap = std::make_shared< 1252*8fb49dd6SShawn McCarney boost::container::flat_map<std::string, std::string>>(); 1253*8fb49dd6SShawn McCarney std::string sensorAssocPath; 1254*8fb49dd6SShawn McCarney sensorAssocPath.reserve(128); // avoid memory allocations 1255*8fb49dd6SShawn McCarney for (const auto& objDictEntry : resp) 1256*8fb49dd6SShawn McCarney { 1257*8fb49dd6SShawn McCarney const std::string& objPath = 1258*8fb49dd6SShawn McCarney static_cast<const std::string&>(objDictEntry.first); 1259*8fb49dd6SShawn McCarney const boost::container::flat_map< 1260*8fb49dd6SShawn McCarney std::string, boost::container::flat_map< 1261*8fb49dd6SShawn McCarney std::string, dbus::utility::DbusVariantType>>& 1262*8fb49dd6SShawn McCarney interfacesDict = objDictEntry.second; 1263*8fb49dd6SShawn McCarney 1264*8fb49dd6SShawn McCarney // If path is inventory association for one of the specified sensors 1265*8fb49dd6SShawn McCarney for (const std::string& sensorName : *sensorNames) 1266*8fb49dd6SShawn McCarney { 1267*8fb49dd6SShawn McCarney sensorAssocPath = sensorName; 1268*8fb49dd6SShawn McCarney sensorAssocPath += "/inventory"; 1269*8fb49dd6SShawn McCarney if (objPath == sensorAssocPath) 1270*8fb49dd6SShawn McCarney { 1271*8fb49dd6SShawn McCarney // Get Association interface for object path 1272*8fb49dd6SShawn McCarney auto assocIt = 1273*8fb49dd6SShawn McCarney interfacesDict.find("xyz.openbmc_project.Association"); 1274*8fb49dd6SShawn McCarney if (assocIt != interfacesDict.end()) 1275*8fb49dd6SShawn McCarney { 1276*8fb49dd6SShawn McCarney // Get inventory item from end point 1277*8fb49dd6SShawn McCarney auto endpointsIt = assocIt->second.find("endpoints"); 1278*8fb49dd6SShawn McCarney if (endpointsIt != assocIt->second.end()) 1279*8fb49dd6SShawn McCarney { 1280*8fb49dd6SShawn McCarney const std::vector<std::string>* endpoints = 1281*8fb49dd6SShawn McCarney std::get_if<std::vector<std::string>>( 1282*8fb49dd6SShawn McCarney &endpointsIt->second); 1283*8fb49dd6SShawn McCarney if ((endpoints != nullptr) && !endpoints->empty()) 1284*8fb49dd6SShawn McCarney { 1285*8fb49dd6SShawn McCarney // Store sensor -> inventory item mapping 1286*8fb49dd6SShawn McCarney const std::string& invItem = endpoints->front(); 1287*8fb49dd6SShawn McCarney (*sensorToInvMap)[sensorName] = invItem; 1288*8fb49dd6SShawn McCarney } 1289*8fb49dd6SShawn McCarney } 1290*8fb49dd6SShawn McCarney } 1291*8fb49dd6SShawn McCarney break; 1292*8fb49dd6SShawn McCarney } 1293*8fb49dd6SShawn McCarney } 1294*8fb49dd6SShawn McCarney } 1295*8fb49dd6SShawn McCarney 1296*8fb49dd6SShawn McCarney // Call callback if at least one inventory item was found 1297*8fb49dd6SShawn McCarney if (!sensorToInvMap->empty()) 1298*8fb49dd6SShawn McCarney { 1299*8fb49dd6SShawn McCarney callback(sensorToInvMap); 1300*8fb49dd6SShawn McCarney } 1301*8fb49dd6SShawn McCarney BMCWEB_LOG_DEBUG << "getInventoryItems respHandler exit"; 1302*8fb49dd6SShawn McCarney }; 1303*8fb49dd6SShawn McCarney 1304*8fb49dd6SShawn McCarney // Find DBus object path that implements ObjectManager for ObjectMapper 1305*8fb49dd6SShawn McCarney std::string connection = "xyz.openbmc_project.ObjectMapper"; 1306*8fb49dd6SShawn McCarney auto iter = objectMgrPaths->find(connection); 1307*8fb49dd6SShawn McCarney const std::string& objectMgrPath = 1308*8fb49dd6SShawn McCarney (iter != objectMgrPaths->end()) ? iter->second : "/"; 1309*8fb49dd6SShawn McCarney BMCWEB_LOG_DEBUG << "ObjectManager path for " << connection << " is " 1310*8fb49dd6SShawn McCarney << objectMgrPath; 1311*8fb49dd6SShawn McCarney 1312*8fb49dd6SShawn McCarney // Call GetManagedObjects on the ObjectMapper to get all associations 1313*8fb49dd6SShawn McCarney crow::connections::systemBus->async_method_call( 1314*8fb49dd6SShawn McCarney std::move(respHandler), connection, objectMgrPath, 1315*8fb49dd6SShawn McCarney "org.freedesktop.DBus.ObjectManager", "GetManagedObjects"); 1316*8fb49dd6SShawn McCarney 1317*8fb49dd6SShawn McCarney BMCWEB_LOG_DEBUG << "getInventoryItems exit"; 1318*8fb49dd6SShawn McCarney } 1319*8fb49dd6SShawn McCarney 1320*8fb49dd6SShawn McCarney /** 1321*8fb49dd6SShawn McCarney * @brief Checks the status of inventory items associated with sensors. 1322*8fb49dd6SShawn McCarney * 1323*8fb49dd6SShawn McCarney * Finds the inventory items that are associated with the specified sensors. 1324*8fb49dd6SShawn McCarney * Gets the status of those inventory items. 1325*8fb49dd6SShawn McCarney * 1326*8fb49dd6SShawn McCarney * If the inventory items are not present or functional, the sensor status is 1327*8fb49dd6SShawn McCarney * updated in the JSON response. 1328*8fb49dd6SShawn McCarney * 1329*8fb49dd6SShawn McCarney * In D-Bus, the hardware present and functional properties are typically on the 1330*8fb49dd6SShawn McCarney * inventory item rather than the sensor. 1331*8fb49dd6SShawn McCarney * 1332*8fb49dd6SShawn McCarney * @param sensorsAsyncResp Pointer to object holding response data. 1333*8fb49dd6SShawn McCarney * @param sensorNames All sensors within the current chassis. 1334*8fb49dd6SShawn McCarney * @param objectMgrPaths Mappings from connection name to DBus object path that 1335*8fb49dd6SShawn McCarney * implements ObjectManager. 1336*8fb49dd6SShawn McCarney */ 1337*8fb49dd6SShawn McCarney static void checkInventoryItemsStatus( 1338*8fb49dd6SShawn McCarney std::shared_ptr<SensorsAsyncResp> sensorsAsyncResp, 1339*8fb49dd6SShawn McCarney const std::shared_ptr<boost::container::flat_set<std::string>> sensorNames, 1340*8fb49dd6SShawn McCarney std::shared_ptr<boost::container::flat_map<std::string, std::string>> 1341*8fb49dd6SShawn McCarney objectMgrPaths) 1342*8fb49dd6SShawn McCarney { 1343*8fb49dd6SShawn McCarney BMCWEB_LOG_DEBUG << "checkInventoryItemsStatus enter"; 1344*8fb49dd6SShawn McCarney auto getInventoryItemsCb = 1345*8fb49dd6SShawn McCarney [sensorsAsyncResp, 1346*8fb49dd6SShawn McCarney objectMgrPaths](std::shared_ptr< 1347*8fb49dd6SShawn McCarney boost::container::flat_map<std::string, std::string>> 1348*8fb49dd6SShawn McCarney sensorToInvMap) { 1349*8fb49dd6SShawn McCarney BMCWEB_LOG_DEBUG << "getInventoryItemsCb enter"; 1350*8fb49dd6SShawn McCarney auto getInventoryItemsConnectionsCb = 1351*8fb49dd6SShawn McCarney [sensorsAsyncResp, sensorToInvMap, objectMgrPaths]( 1352*8fb49dd6SShawn McCarney std::shared_ptr<boost::container::flat_set<std::string>> 1353*8fb49dd6SShawn McCarney invConnections) { 1354*8fb49dd6SShawn McCarney BMCWEB_LOG_DEBUG << "getInventoryItemsConnectionsCb enter"; 1355*8fb49dd6SShawn McCarney 1356*8fb49dd6SShawn McCarney // Get status of inventory items and update sensors 1357*8fb49dd6SShawn McCarney getInventoryItemsStatus(sensorsAsyncResp, sensorToInvMap, 1358*8fb49dd6SShawn McCarney invConnections, objectMgrPaths); 1359*8fb49dd6SShawn McCarney 1360*8fb49dd6SShawn McCarney BMCWEB_LOG_DEBUG << "getInventoryItemsConnectionsCb exit"; 1361*8fb49dd6SShawn McCarney }; 1362*8fb49dd6SShawn McCarney 1363*8fb49dd6SShawn McCarney // Get connections that provide status of inventory items 1364*8fb49dd6SShawn McCarney getInventoryItemsConnections( 1365*8fb49dd6SShawn McCarney sensorsAsyncResp, sensorToInvMap, 1366*8fb49dd6SShawn McCarney std::move(getInventoryItemsConnectionsCb)); 1367*8fb49dd6SShawn McCarney BMCWEB_LOG_DEBUG << "getInventoryItemsCb exit"; 1368*8fb49dd6SShawn McCarney }; 1369*8fb49dd6SShawn McCarney 1370*8fb49dd6SShawn McCarney // Get inventory items that are associated with specified sensors 1371*8fb49dd6SShawn McCarney getInventoryItems(sensorsAsyncResp, sensorNames, objectMgrPaths, 1372*8fb49dd6SShawn McCarney std::move(getInventoryItemsCb)); 1373*8fb49dd6SShawn McCarney BMCWEB_LOG_DEBUG << "checkInventoryItemsStatus exit"; 1374*8fb49dd6SShawn McCarney } 1375*8fb49dd6SShawn McCarney 1376*8fb49dd6SShawn McCarney /** 1377de629b6eSShawn McCarney * @brief Gets the values of the specified sensors. 1378de629b6eSShawn McCarney * 1379de629b6eSShawn McCarney * Stores the results as JSON in the SensorsAsyncResp. 1380de629b6eSShawn McCarney * 1381de629b6eSShawn McCarney * Gets the sensor values asynchronously. Stores the results later when the 1382de629b6eSShawn McCarney * information has been obtained. 1383de629b6eSShawn McCarney * 1384de629b6eSShawn McCarney * The sensorNames set contains all sensors for the current chassis. 1385de629b6eSShawn McCarney * SensorsAsyncResp contains the requested sensor types. Only sensors of a 1386de629b6eSShawn McCarney * requested type are included in the JSON output. 1387de629b6eSShawn McCarney * 1388de629b6eSShawn McCarney * To minimize the number of DBus calls, the DBus method 1389de629b6eSShawn McCarney * org.freedesktop.DBus.ObjectManager.GetManagedObjects() is used to get the 1390de629b6eSShawn McCarney * values of all sensors provided by a connection (service). 1391de629b6eSShawn McCarney * 1392de629b6eSShawn McCarney * The connections set contains all the connections that provide sensor values. 1393de629b6eSShawn McCarney * 1394de629b6eSShawn McCarney * The objectMgrPaths map contains mappings from a connection name to the 1395de629b6eSShawn McCarney * corresponding DBus object path that implements ObjectManager. 1396de629b6eSShawn McCarney * 1397de629b6eSShawn McCarney * @param SensorsAsyncResp Pointer to object holding response data. 1398de629b6eSShawn McCarney * @param sensorNames All sensors within the current chassis. 1399de629b6eSShawn McCarney * @param connections Connections that provide sensor values. 1400de629b6eSShawn McCarney * @param objectMgrPaths Mappings from connection name to DBus object path that 1401de629b6eSShawn McCarney * implements ObjectManager. 1402de629b6eSShawn McCarney */ 1403de629b6eSShawn McCarney void getSensorData( 1404de629b6eSShawn McCarney std::shared_ptr<SensorsAsyncResp> SensorsAsyncResp, 140549c53ac9SJohnathan Mantey const std::shared_ptr<boost::container::flat_set<std::string>> sensorNames, 1406de629b6eSShawn McCarney const boost::container::flat_set<std::string>& connections, 1407*8fb49dd6SShawn McCarney std::shared_ptr<boost::container::flat_map<std::string, std::string>> 1408*8fb49dd6SShawn McCarney objectMgrPaths) 1409de629b6eSShawn McCarney { 1410de629b6eSShawn McCarney BMCWEB_LOG_DEBUG << "getSensorData enter"; 1411de629b6eSShawn McCarney // Get managed objects from all services exposing sensors 1412de629b6eSShawn McCarney for (const std::string& connection : connections) 1413de629b6eSShawn McCarney { 1414de629b6eSShawn McCarney // Response handler to process managed objects 1415*8fb49dd6SShawn McCarney auto getManagedObjectsCb = [SensorsAsyncResp, sensorNames, 1416*8fb49dd6SShawn McCarney objectMgrPaths]( 1417de629b6eSShawn McCarney const boost::system::error_code ec, 1418de629b6eSShawn McCarney ManagedObjectsVectorType& resp) { 1419de629b6eSShawn McCarney BMCWEB_LOG_DEBUG << "getManagedObjectsCb enter"; 1420de629b6eSShawn McCarney if (ec) 1421de629b6eSShawn McCarney { 1422de629b6eSShawn McCarney BMCWEB_LOG_ERROR << "getManagedObjectsCb DBUS error: " << ec; 1423de629b6eSShawn McCarney messages::internalError(SensorsAsyncResp->res); 1424de629b6eSShawn McCarney return; 1425de629b6eSShawn McCarney } 1426de629b6eSShawn McCarney // Go through all objects and update response with sensor data 1427de629b6eSShawn McCarney for (const auto& objDictEntry : resp) 1428de629b6eSShawn McCarney { 1429de629b6eSShawn McCarney const std::string& objPath = 1430de629b6eSShawn McCarney static_cast<const std::string&>(objDictEntry.first); 1431de629b6eSShawn McCarney BMCWEB_LOG_DEBUG << "getManagedObjectsCb parsing object " 1432de629b6eSShawn McCarney << objPath; 1433de629b6eSShawn McCarney 1434de629b6eSShawn McCarney std::vector<std::string> split; 1435de629b6eSShawn McCarney // Reserve space for 1436de629b6eSShawn McCarney // /xyz/openbmc_project/sensors/<name>/<subname> 1437de629b6eSShawn McCarney split.reserve(6); 1438de629b6eSShawn McCarney boost::algorithm::split(split, objPath, boost::is_any_of("/")); 1439de629b6eSShawn McCarney if (split.size() < 6) 1440de629b6eSShawn McCarney { 1441de629b6eSShawn McCarney BMCWEB_LOG_ERROR << "Got path that isn't long enough " 1442de629b6eSShawn McCarney << objPath; 1443de629b6eSShawn McCarney continue; 1444de629b6eSShawn McCarney } 1445de629b6eSShawn McCarney // These indexes aren't intuitive, as boost::split puts an empty 1446de629b6eSShawn McCarney // string at the beginning 1447de629b6eSShawn McCarney const std::string& sensorType = split[4]; 1448de629b6eSShawn McCarney const std::string& sensorName = split[5]; 1449de629b6eSShawn McCarney BMCWEB_LOG_DEBUG << "sensorName " << sensorName 1450de629b6eSShawn McCarney << " sensorType " << sensorType; 145149c53ac9SJohnathan Mantey if (sensorNames->find(objPath) == sensorNames->end()) 1452de629b6eSShawn McCarney { 1453de629b6eSShawn McCarney BMCWEB_LOG_ERROR << sensorName << " not in sensor list "; 1454de629b6eSShawn McCarney continue; 1455de629b6eSShawn McCarney } 1456de629b6eSShawn McCarney 1457de629b6eSShawn McCarney const char* fieldName = nullptr; 1458de629b6eSShawn McCarney if (sensorType == "temperature") 1459de629b6eSShawn McCarney { 1460de629b6eSShawn McCarney fieldName = "Temperatures"; 1461de629b6eSShawn McCarney } 1462de629b6eSShawn McCarney else if (sensorType == "fan" || sensorType == "fan_tach" || 1463de629b6eSShawn McCarney sensorType == "fan_pwm") 1464de629b6eSShawn McCarney { 1465de629b6eSShawn McCarney fieldName = "Fans"; 1466de629b6eSShawn McCarney } 1467de629b6eSShawn McCarney else if (sensorType == "voltage") 1468de629b6eSShawn McCarney { 1469de629b6eSShawn McCarney fieldName = "Voltages"; 1470de629b6eSShawn McCarney } 1471de629b6eSShawn McCarney else if (sensorType == "current") 1472de629b6eSShawn McCarney { 1473de629b6eSShawn McCarney fieldName = "PowerSupplies"; 1474de629b6eSShawn McCarney } 1475de629b6eSShawn McCarney else if (sensorType == "power") 1476de629b6eSShawn McCarney { 1477028f7ebcSEddie James if (!sensorName.compare("total_power")) 1478028f7ebcSEddie James { 1479028f7ebcSEddie James fieldName = "PowerControl"; 1480028f7ebcSEddie James } 1481028f7ebcSEddie James else 1482028f7ebcSEddie James { 1483de629b6eSShawn McCarney fieldName = "PowerSupplies"; 1484de629b6eSShawn McCarney } 1485028f7ebcSEddie James } 1486de629b6eSShawn McCarney else 1487de629b6eSShawn McCarney { 1488de629b6eSShawn McCarney BMCWEB_LOG_ERROR << "Unsure how to handle sensorType " 1489de629b6eSShawn McCarney << sensorType; 1490de629b6eSShawn McCarney continue; 1491de629b6eSShawn McCarney } 1492de629b6eSShawn McCarney 1493de629b6eSShawn McCarney nlohmann::json& tempArray = 1494de629b6eSShawn McCarney SensorsAsyncResp->res.jsonValue[fieldName]; 1495de629b6eSShawn McCarney 149649c53ac9SJohnathan Mantey if (fieldName == "PowerSupplies" && !tempArray.empty()) 149749c53ac9SJohnathan Mantey { 149849c53ac9SJohnathan Mantey // Power supplies put multiple "sensors" into a single power 149949c53ac9SJohnathan Mantey // supply entry, so only create the first one 150049c53ac9SJohnathan Mantey } 150149c53ac9SJohnathan Mantey else 150249c53ac9SJohnathan Mantey { 1503de629b6eSShawn McCarney tempArray.push_back( 150449c53ac9SJohnathan Mantey {{"@odata.id", "/redfish/v1/Chassis/" + 150549c53ac9SJohnathan Mantey SensorsAsyncResp->chassisId + "/" + 150649c53ac9SJohnathan Mantey SensorsAsyncResp->chassisSubNode + 150749c53ac9SJohnathan Mantey "#/" + fieldName + "/"}}); 150849c53ac9SJohnathan Mantey } 1509de629b6eSShawn McCarney nlohmann::json& sensorJson = tempArray.back(); 1510de629b6eSShawn McCarney 1511de629b6eSShawn McCarney objectInterfacesToJson(sensorName, sensorType, 1512de629b6eSShawn McCarney objDictEntry.second, sensorJson); 1513de629b6eSShawn McCarney } 151449c53ac9SJohnathan Mantey if (SensorsAsyncResp.use_count() == 1) 151549c53ac9SJohnathan Mantey { 151649c53ac9SJohnathan Mantey sortJSONResponse(SensorsAsyncResp); 1517*8fb49dd6SShawn McCarney checkInventoryItemsStatus(SensorsAsyncResp, sensorNames, 1518*8fb49dd6SShawn McCarney objectMgrPaths); 151949c53ac9SJohnathan Mantey if (SensorsAsyncResp->chassisSubNode == "Thermal") 15208bd25ccdSJames Feist { 15218bd25ccdSJames Feist populateFanRedundancy(SensorsAsyncResp); 15228bd25ccdSJames Feist } 152349c53ac9SJohnathan Mantey } 1524de629b6eSShawn McCarney BMCWEB_LOG_DEBUG << "getManagedObjectsCb exit"; 1525de629b6eSShawn McCarney }; 1526de629b6eSShawn McCarney 1527de629b6eSShawn McCarney // Find DBus object path that implements ObjectManager for the current 1528de629b6eSShawn McCarney // connection. If no mapping found, default to "/". 1529*8fb49dd6SShawn McCarney auto iter = objectMgrPaths->find(connection); 1530de629b6eSShawn McCarney const std::string& objectMgrPath = 1531*8fb49dd6SShawn McCarney (iter != objectMgrPaths->end()) ? iter->second : "/"; 1532de629b6eSShawn McCarney BMCWEB_LOG_DEBUG << "ObjectManager path for " << connection << " is " 1533de629b6eSShawn McCarney << objectMgrPath; 1534de629b6eSShawn McCarney 1535de629b6eSShawn McCarney crow::connections::systemBus->async_method_call( 1536de629b6eSShawn McCarney getManagedObjectsCb, connection, objectMgrPath, 1537de629b6eSShawn McCarney "org.freedesktop.DBus.ObjectManager", "GetManagedObjects"); 1538de629b6eSShawn McCarney }; 1539de629b6eSShawn McCarney BMCWEB_LOG_DEBUG << "getSensorData exit"; 1540de629b6eSShawn McCarney } 1541de629b6eSShawn McCarney 1542de629b6eSShawn McCarney /** 154308777fb0SLewanczyk, Dawid * @brief Entry point for retrieving sensors data related to requested 154408777fb0SLewanczyk, Dawid * chassis. 1545588c3f0dSKowalski, Kamil * @param SensorsAsyncResp Pointer to object holding response data 154608777fb0SLewanczyk, Dawid */ 15471abe55efSEd Tanous void getChassisData(std::shared_ptr<SensorsAsyncResp> SensorsAsyncResp) 15481abe55efSEd Tanous { 154955c7b7a2SEd Tanous BMCWEB_LOG_DEBUG << "getChassisData enter"; 155049c53ac9SJohnathan Mantey auto getChassisCb = 155149c53ac9SJohnathan Mantey [SensorsAsyncResp]( 155249c53ac9SJohnathan Mantey std::shared_ptr<boost::container::flat_set<std::string>> 155308777fb0SLewanczyk, Dawid sensorNames) { 155455c7b7a2SEd Tanous BMCWEB_LOG_DEBUG << "getChassisCb enter"; 1555*8fb49dd6SShawn McCarney auto getConnectionCb = [SensorsAsyncResp, sensorNames]( 1556*8fb49dd6SShawn McCarney const boost::container::flat_set< 1557*8fb49dd6SShawn McCarney std::string>& connections) { 155855c7b7a2SEd Tanous BMCWEB_LOG_DEBUG << "getConnectionCb enter"; 1559de629b6eSShawn McCarney auto getObjectManagerPathsCb = 156049c53ac9SJohnathan Mantey [SensorsAsyncResp, sensorNames, connections]( 1561*8fb49dd6SShawn McCarney std::shared_ptr<boost::container::flat_map<std::string, 1562*8fb49dd6SShawn McCarney std::string>> 1563*8fb49dd6SShawn McCarney objectMgrPaths) { 1564de629b6eSShawn McCarney BMCWEB_LOG_DEBUG << "getObjectManagerPathsCb enter"; 156549c53ac9SJohnathan Mantey // Get sensor data and store results in JSON 156649c53ac9SJohnathan Mantey // response 1567de629b6eSShawn McCarney getSensorData(SensorsAsyncResp, sensorNames, 1568de629b6eSShawn McCarney connections, objectMgrPaths); 1569de629b6eSShawn McCarney BMCWEB_LOG_DEBUG << "getObjectManagerPathsCb exit"; 157008777fb0SLewanczyk, Dawid }; 1571de629b6eSShawn McCarney 157249c53ac9SJohnathan Mantey // Get mapping from connection names to the DBus object 157349c53ac9SJohnathan Mantey // paths that implement the ObjectManager interface 1574de629b6eSShawn McCarney getObjectManagerPaths(SensorsAsyncResp, 1575de629b6eSShawn McCarney std::move(getObjectManagerPathsCb)); 157655c7b7a2SEd Tanous BMCWEB_LOG_DEBUG << "getConnectionCb exit"; 157708777fb0SLewanczyk, Dawid }; 1578de629b6eSShawn McCarney 1579de629b6eSShawn McCarney // Get set of connections that provide sensor values 15801abe55efSEd Tanous getConnections(SensorsAsyncResp, sensorNames, 15811abe55efSEd Tanous std::move(getConnectionCb)); 158255c7b7a2SEd Tanous BMCWEB_LOG_DEBUG << "getChassisCb exit"; 158308777fb0SLewanczyk, Dawid }; 15844f9a2130SJennifer Lee SensorsAsyncResp->res.jsonValue["Redundancy"] = nlohmann::json::array(); 158508777fb0SLewanczyk, Dawid 158626f03899SShawn McCarney // Get set of sensors in chassis 1587588c3f0dSKowalski, Kamil getChassis(SensorsAsyncResp, std::move(getChassisCb)); 158855c7b7a2SEd Tanous BMCWEB_LOG_DEBUG << "getChassisData exit"; 158908777fb0SLewanczyk, Dawid }; 159008777fb0SLewanczyk, Dawid 1591413961deSRichard Marian Thomaiyar /** 159249c53ac9SJohnathan Mantey * @brief Find the requested sensorName in the list of all sensors supplied by 159349c53ac9SJohnathan Mantey * the chassis node 159449c53ac9SJohnathan Mantey * 159549c53ac9SJohnathan Mantey * @param sensorName The sensor name supplied in the PATCH request 159649c53ac9SJohnathan Mantey * @param sensorsList The list of sensors managed by the chassis node 159749c53ac9SJohnathan Mantey * @param sensorsModified The list of sensors that were found as a result of 159849c53ac9SJohnathan Mantey * repeated calls to this function 159949c53ac9SJohnathan Mantey */ 160049c53ac9SJohnathan Mantey bool findSensorNameUsingSensorPath( 16010a86febdSRichard Marian Thomaiyar std::string_view sensorName, 160249c53ac9SJohnathan Mantey boost::container::flat_set<std::string>& sensorsList, 160349c53ac9SJohnathan Mantey boost::container::flat_set<std::string>& sensorsModified) 160449c53ac9SJohnathan Mantey { 16050a86febdSRichard Marian Thomaiyar for (std::string_view chassisSensor : sensorsList) 160649c53ac9SJohnathan Mantey { 16070a86febdSRichard Marian Thomaiyar std::size_t pos = chassisSensor.rfind("/"); 16080a86febdSRichard Marian Thomaiyar if (pos >= (chassisSensor.size() - 1)) 160949c53ac9SJohnathan Mantey { 161049c53ac9SJohnathan Mantey continue; 161149c53ac9SJohnathan Mantey } 16120a86febdSRichard Marian Thomaiyar std::string_view thisSensorName = chassisSensor.substr(pos + 1); 161349c53ac9SJohnathan Mantey if (thisSensorName == sensorName) 161449c53ac9SJohnathan Mantey { 161549c53ac9SJohnathan Mantey sensorsModified.emplace(chassisSensor); 161649c53ac9SJohnathan Mantey return true; 161749c53ac9SJohnathan Mantey } 161849c53ac9SJohnathan Mantey } 161949c53ac9SJohnathan Mantey return false; 162049c53ac9SJohnathan Mantey } 162149c53ac9SJohnathan Mantey 162249c53ac9SJohnathan Mantey /** 1623413961deSRichard Marian Thomaiyar * @brief Entry point for overriding sensor values of given sensor 1624413961deSRichard Marian Thomaiyar * 1625413961deSRichard Marian Thomaiyar * @param res response object 1626413961deSRichard Marian Thomaiyar * @param req request object 1627413961deSRichard Marian Thomaiyar * @param params parameter passed for CRUD 1628413961deSRichard Marian Thomaiyar * @param typeList TypeList of sensors for the resource queried 1629413961deSRichard Marian Thomaiyar * @param chassisSubNode Chassis Node for which the query has to happen 1630413961deSRichard Marian Thomaiyar */ 1631413961deSRichard Marian Thomaiyar void setSensorOverride(crow::Response& res, const crow::Request& req, 1632413961deSRichard Marian Thomaiyar const std::vector<std::string>& params, 1633b01bf299SEd Tanous const std::initializer_list<const char*> typeList, 1634413961deSRichard Marian Thomaiyar const std::string& chassisSubNode) 1635413961deSRichard Marian Thomaiyar { 1636413961deSRichard Marian Thomaiyar 1637413961deSRichard Marian Thomaiyar // TODO: Need to figure out dynamic way to restrict patch (Set Sensor 1638413961deSRichard Marian Thomaiyar // override) based on another d-bus announcement to be more generic. 1639413961deSRichard Marian Thomaiyar if (params.size() != 1) 1640413961deSRichard Marian Thomaiyar { 1641413961deSRichard Marian Thomaiyar messages::internalError(res); 1642413961deSRichard Marian Thomaiyar res.end(); 1643413961deSRichard Marian Thomaiyar return; 1644413961deSRichard Marian Thomaiyar } 1645f65af9e8SRichard Marian Thomaiyar 1646f65af9e8SRichard Marian Thomaiyar std::unordered_map<std::string, std::vector<nlohmann::json>> allCollections; 1647f65af9e8SRichard Marian Thomaiyar std::optional<std::vector<nlohmann::json>> temperatureCollections; 1648f65af9e8SRichard Marian Thomaiyar std::optional<std::vector<nlohmann::json>> fanCollections; 1649f65af9e8SRichard Marian Thomaiyar std::vector<nlohmann::json> voltageCollections; 1650f65af9e8SRichard Marian Thomaiyar BMCWEB_LOG_INFO << "setSensorOverride for subNode" << chassisSubNode 1651f65af9e8SRichard Marian Thomaiyar << "\n"; 1652f65af9e8SRichard Marian Thomaiyar 1653413961deSRichard Marian Thomaiyar if (chassisSubNode == "Thermal") 1654413961deSRichard Marian Thomaiyar { 1655f65af9e8SRichard Marian Thomaiyar if (!json_util::readJson(req, res, "Temperatures", 1656f65af9e8SRichard Marian Thomaiyar temperatureCollections, "Fans", 1657f65af9e8SRichard Marian Thomaiyar fanCollections)) 1658f65af9e8SRichard Marian Thomaiyar { 1659f65af9e8SRichard Marian Thomaiyar return; 1660f65af9e8SRichard Marian Thomaiyar } 1661f65af9e8SRichard Marian Thomaiyar if (!temperatureCollections && !fanCollections) 1662f65af9e8SRichard Marian Thomaiyar { 1663f65af9e8SRichard Marian Thomaiyar messages::resourceNotFound(res, "Thermal", 1664f65af9e8SRichard Marian Thomaiyar "Temperatures / Voltages"); 1665f65af9e8SRichard Marian Thomaiyar res.end(); 1666f65af9e8SRichard Marian Thomaiyar return; 1667f65af9e8SRichard Marian Thomaiyar } 1668f65af9e8SRichard Marian Thomaiyar if (temperatureCollections) 1669f65af9e8SRichard Marian Thomaiyar { 1670f65af9e8SRichard Marian Thomaiyar allCollections.emplace("Temperatures", 1671f65af9e8SRichard Marian Thomaiyar *std::move(temperatureCollections)); 1672f65af9e8SRichard Marian Thomaiyar } 1673f65af9e8SRichard Marian Thomaiyar if (fanCollections) 1674f65af9e8SRichard Marian Thomaiyar { 1675f65af9e8SRichard Marian Thomaiyar allCollections.emplace("Fans", *std::move(fanCollections)); 1676f65af9e8SRichard Marian Thomaiyar } 1677413961deSRichard Marian Thomaiyar } 1678413961deSRichard Marian Thomaiyar else if (chassisSubNode == "Power") 1679413961deSRichard Marian Thomaiyar { 1680f65af9e8SRichard Marian Thomaiyar if (!json_util::readJson(req, res, "Voltages", voltageCollections)) 1681f65af9e8SRichard Marian Thomaiyar { 1682f65af9e8SRichard Marian Thomaiyar return; 1683f65af9e8SRichard Marian Thomaiyar } 1684f65af9e8SRichard Marian Thomaiyar allCollections.emplace("Voltages", std::move(voltageCollections)); 1685413961deSRichard Marian Thomaiyar } 1686413961deSRichard Marian Thomaiyar else 1687413961deSRichard Marian Thomaiyar { 1688413961deSRichard Marian Thomaiyar res.result(boost::beast::http::status::not_found); 1689413961deSRichard Marian Thomaiyar res.end(); 1690413961deSRichard Marian Thomaiyar return; 1691413961deSRichard Marian Thomaiyar } 1692413961deSRichard Marian Thomaiyar 1693f65af9e8SRichard Marian Thomaiyar const char* propertyValueName; 1694f65af9e8SRichard Marian Thomaiyar std::unordered_map<std::string, std::pair<double, std::string>> overrideMap; 1695413961deSRichard Marian Thomaiyar std::string memberId; 1696413961deSRichard Marian Thomaiyar double value; 1697f65af9e8SRichard Marian Thomaiyar for (auto& collectionItems : allCollections) 1698f65af9e8SRichard Marian Thomaiyar { 1699f65af9e8SRichard Marian Thomaiyar if (collectionItems.first == "Temperatures") 1700f65af9e8SRichard Marian Thomaiyar { 1701f65af9e8SRichard Marian Thomaiyar propertyValueName = "ReadingCelsius"; 1702f65af9e8SRichard Marian Thomaiyar } 1703f65af9e8SRichard Marian Thomaiyar else if (collectionItems.first == "Fans") 1704f65af9e8SRichard Marian Thomaiyar { 1705f65af9e8SRichard Marian Thomaiyar propertyValueName = "Reading"; 1706f65af9e8SRichard Marian Thomaiyar } 1707f65af9e8SRichard Marian Thomaiyar else 1708f65af9e8SRichard Marian Thomaiyar { 1709f65af9e8SRichard Marian Thomaiyar propertyValueName = "ReadingVolts"; 1710f65af9e8SRichard Marian Thomaiyar } 1711f65af9e8SRichard Marian Thomaiyar for (auto& item : collectionItems.second) 1712f65af9e8SRichard Marian Thomaiyar { 1713f65af9e8SRichard Marian Thomaiyar if (!json_util::readJson(item, res, "MemberId", memberId, 1714413961deSRichard Marian Thomaiyar propertyValueName, value)) 1715413961deSRichard Marian Thomaiyar { 1716413961deSRichard Marian Thomaiyar return; 1717413961deSRichard Marian Thomaiyar } 1718f65af9e8SRichard Marian Thomaiyar overrideMap.emplace(memberId, 1719f65af9e8SRichard Marian Thomaiyar std::make_pair(value, collectionItems.first)); 1720f65af9e8SRichard Marian Thomaiyar } 1721f65af9e8SRichard Marian Thomaiyar } 1722413961deSRichard Marian Thomaiyar const std::string& chassisName = params[0]; 1723413961deSRichard Marian Thomaiyar auto sensorAsyncResp = std::make_shared<SensorsAsyncResp>( 1724413961deSRichard Marian Thomaiyar res, chassisName, typeList, chassisSubNode); 172549c53ac9SJohnathan Mantey auto getChassisSensorListCb = [sensorAsyncResp, 172649c53ac9SJohnathan Mantey overrideMap](const std::shared_ptr< 172749c53ac9SJohnathan Mantey boost::container::flat_set< 172849c53ac9SJohnathan Mantey std::string>> 172949c53ac9SJohnathan Mantey sensorsList) { 173049c53ac9SJohnathan Mantey // Match sensor names in the PATCH request to those managed by the 173149c53ac9SJohnathan Mantey // chassis node 173249c53ac9SJohnathan Mantey const std::shared_ptr<boost::container::flat_set<std::string>> 173349c53ac9SJohnathan Mantey sensorNames = 173449c53ac9SJohnathan Mantey std::make_shared<boost::container::flat_set<std::string>>(); 1735f65af9e8SRichard Marian Thomaiyar for (const auto& item : overrideMap) 1736413961deSRichard Marian Thomaiyar { 1737f65af9e8SRichard Marian Thomaiyar const auto& sensor = item.first; 173849c53ac9SJohnathan Mantey if (!findSensorNameUsingSensorPath(sensor, *sensorsList, 173949c53ac9SJohnathan Mantey *sensorNames)) 1740f65af9e8SRichard Marian Thomaiyar { 1741f65af9e8SRichard Marian Thomaiyar BMCWEB_LOG_INFO << "Unable to find memberId " << item.first; 1742413961deSRichard Marian Thomaiyar messages::resourceNotFound(sensorAsyncResp->res, 1743f65af9e8SRichard Marian Thomaiyar item.second.second, item.first); 1744413961deSRichard Marian Thomaiyar return; 1745413961deSRichard Marian Thomaiyar } 1746f65af9e8SRichard Marian Thomaiyar } 1747413961deSRichard Marian Thomaiyar // Get the connection to which the memberId belongs 1748413961deSRichard Marian Thomaiyar auto getObjectsWithConnectionCb = 1749f65af9e8SRichard Marian Thomaiyar [sensorAsyncResp, overrideMap]( 1750413961deSRichard Marian Thomaiyar const boost::container::flat_set<std::string>& connections, 1751413961deSRichard Marian Thomaiyar const std::set<std::pair<std::string, std::string>>& 1752413961deSRichard Marian Thomaiyar objectsWithConnection) { 1753f65af9e8SRichard Marian Thomaiyar if (objectsWithConnection.size() != overrideMap.size()) 1754413961deSRichard Marian Thomaiyar { 1755413961deSRichard Marian Thomaiyar BMCWEB_LOG_INFO 1756f65af9e8SRichard Marian Thomaiyar << "Unable to find all objects with proper connection " 1757f65af9e8SRichard Marian Thomaiyar << objectsWithConnection.size() << " requested " 1758f65af9e8SRichard Marian Thomaiyar << overrideMap.size() << "\n"; 1759413961deSRichard Marian Thomaiyar messages::resourceNotFound( 1760413961deSRichard Marian Thomaiyar sensorAsyncResp->res, 1761413961deSRichard Marian Thomaiyar sensorAsyncResp->chassisSubNode == "Thermal" 1762413961deSRichard Marian Thomaiyar ? "Temperatures" 1763413961deSRichard Marian Thomaiyar : "Voltages", 1764f65af9e8SRichard Marian Thomaiyar "Count"); 1765f65af9e8SRichard Marian Thomaiyar return; 1766f65af9e8SRichard Marian Thomaiyar } 1767f65af9e8SRichard Marian Thomaiyar for (const auto& item : objectsWithConnection) 1768f65af9e8SRichard Marian Thomaiyar { 1769f65af9e8SRichard Marian Thomaiyar 1770f65af9e8SRichard Marian Thomaiyar auto lastPos = item.first.rfind('/'); 1771f65af9e8SRichard Marian Thomaiyar if (lastPos == std::string::npos) 1772f65af9e8SRichard Marian Thomaiyar { 1773f65af9e8SRichard Marian Thomaiyar messages::internalError(sensorAsyncResp->res); 1774f65af9e8SRichard Marian Thomaiyar return; 1775f65af9e8SRichard Marian Thomaiyar } 1776f65af9e8SRichard Marian Thomaiyar std::string sensorName = item.first.substr(lastPos + 1); 1777f65af9e8SRichard Marian Thomaiyar 1778f65af9e8SRichard Marian Thomaiyar const auto& iterator = overrideMap.find(sensorName); 1779f65af9e8SRichard Marian Thomaiyar if (iterator == overrideMap.end()) 1780f65af9e8SRichard Marian Thomaiyar { 1781f65af9e8SRichard Marian Thomaiyar BMCWEB_LOG_INFO << "Unable to find sensor object" 1782f65af9e8SRichard Marian Thomaiyar << item.first << "\n"; 1783f65af9e8SRichard Marian Thomaiyar messages::internalError(sensorAsyncResp->res); 1784413961deSRichard Marian Thomaiyar return; 1785413961deSRichard Marian Thomaiyar } 1786413961deSRichard Marian Thomaiyar crow::connections::systemBus->async_method_call( 1787f65af9e8SRichard Marian Thomaiyar [sensorAsyncResp](const boost::system::error_code ec) { 1788413961deSRichard Marian Thomaiyar if (ec) 1789413961deSRichard Marian Thomaiyar { 1790413961deSRichard Marian Thomaiyar BMCWEB_LOG_DEBUG 1791f65af9e8SRichard Marian Thomaiyar << "setOverrideValueStatus DBUS error: " 1792413961deSRichard Marian Thomaiyar << ec; 1793413961deSRichard Marian Thomaiyar messages::internalError(sensorAsyncResp->res); 1794413961deSRichard Marian Thomaiyar return; 1795413961deSRichard Marian Thomaiyar } 1796413961deSRichard Marian Thomaiyar }, 1797f65af9e8SRichard Marian Thomaiyar item.second, item.first, 1798413961deSRichard Marian Thomaiyar "org.freedesktop.DBus.Properties", "Set", 1799413961deSRichard Marian Thomaiyar "xyz.openbmc_project.Sensor.Value", "Value", 1800f65af9e8SRichard Marian Thomaiyar sdbusplus::message::variant<double>( 1801f65af9e8SRichard Marian Thomaiyar iterator->second.first)); 1802f65af9e8SRichard Marian Thomaiyar } 1803413961deSRichard Marian Thomaiyar }; 1804413961deSRichard Marian Thomaiyar // Get object with connection for the given sensor name 1805413961deSRichard Marian Thomaiyar getObjectsWithConnection(sensorAsyncResp, sensorNames, 1806413961deSRichard Marian Thomaiyar std::move(getObjectsWithConnectionCb)); 1807413961deSRichard Marian Thomaiyar }; 1808413961deSRichard Marian Thomaiyar // get full sensor list for the given chassisId and cross verify the sensor. 1809413961deSRichard Marian Thomaiyar getChassis(sensorAsyncResp, std::move(getChassisSensorListCb)); 1810413961deSRichard Marian Thomaiyar } 1811413961deSRichard Marian Thomaiyar 181208777fb0SLewanczyk, Dawid } // namespace redfish 1813